-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[InstCombine] Reduce nested logical operator if poison is implied #86823
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-transforms Author: XChy (XChy) ChangesFixes #76623 In most cases, Full diff: https://github.com/llvm/llvm-project/pull/86823.diff 3 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 9ab2bd8f70aa15..211c116f5a347d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2985,6 +2985,14 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
return BinaryOperator::CreateOr(CondVal, FalseVal);
}
+ if (match(CondVal, m_LogicalOr(m_Value(A), m_Value(B))) &&
+ isa<SelectInst>(CondVal) && impliesPoison(FalseVal, B)) {
+ // (A || B) || C --> A || (B | C)
+ return replaceInstUsesWith(
+ SI, Builder.CreateLogicalOp(Instruction::Or, A,
+ Builder.CreateOr(B, FalseVal)));
+ }
+
if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
if (auto *RHS = dyn_cast<FCmpInst>(FalseVal))
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ false,
@@ -3026,6 +3034,14 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
return BinaryOperator::CreateAnd(CondVal, TrueVal);
}
+ if (match(CondVal, m_LogicalAnd(m_Value(A), m_Value(B))) &&
+ isa<SelectInst>(CondVal) && impliesPoison(TrueVal, B)) {
+ // (A && B) && C --> A && (B & C)
+ return replaceInstUsesWith(
+ SI, Builder.CreateLogicalOp(Instruction::And, A,
+ Builder.CreateAnd(B, TrueVal)));
+ }
+
if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
if (auto *RHS = dyn_cast<FCmpInst>(TrueVal))
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ true,
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index c8d348df5f427c..63b11d0c0bc086 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -3038,3 +3038,63 @@ define i32 @icmp_slt_0_or_icmp_add_1_sge_100_i32_fail(i32 %x) {
%D = or i32 %C, %B
ret i32 %D
}
+
+define i1 @logical_and_icmps1(i32 %a, i1 %other_cond) {
+; CHECK-LABEL: @logical_and_icmps1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[A:%.*]], 10086
+; CHECK-NEXT: [[RET2:%.*]] = select i1 [[RET1:%.*]], i1 [[CMP3]], i1 false
+; CHECK-NEXT: ret i1 [[RET2]]
+;
+entry:
+ %cmp1 = icmp sgt i32 %a, -1
+ %logical_and = select i1 %other_cond, i1 %cmp1, i1 false
+ %cmp2 = icmp slt i32 %a, 10086
+ %ret = select i1 %logical_and, i1 %cmp2, i1 false
+ ret i1 %ret
+}
+
+define i1 @logical_and_icmps2(i32 %a, i1 %other_cond) {
+; CHECK-LABEL: @logical_and_icmps2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cmp1 = icmp slt i32 %a, -1
+ %logical_and = select i1 %other_cond, i1 %cmp1, i1 false
+ %cmp2 = icmp eq i32 %a, 10086
+ %ret = select i1 %logical_and, i1 %cmp2, i1 false
+ ret i1 %ret
+}
+
+define <4 x i1> @logical_and_icmps_vec1(<4 x i32> %a, <4 x i1> %other_cond) {
+; CHECK-LABEL: @logical_and_icmps_vec1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP3:%.*]] = icmp ult <4 x i32> [[A:%.*]], <i32 10086, i32 10086, i32 10086, i32 10086>
+; CHECK-NEXT: [[RET2:%.*]] = select <4 x i1> [[RET1:%.*]], <4 x i1> [[CMP3]], <4 x i1> zeroinitializer
+; CHECK-NEXT: ret <4 x i1> [[RET2]]
+;
+entry:
+ %cmp1 = icmp sgt <4 x i32> %a, <i32 -1, i32 -1, i32 -1, i32 -1 >
+ %logical_and = select <4 x i1> %other_cond, <4 x i1> %cmp1, <4 x i1> zeroinitializer
+ %cmp2 = icmp slt <4 x i32> %a, <i32 10086, i32 10086, i32 10086, i32 10086 >
+ %ret = select <4 x i1> %logical_and, <4 x i1> %cmp2, <4 x i1> zeroinitializer
+ ret <4 x i1> %ret
+}
+
+define i1 @logical_and_icmps_fail1(i32 %a, i32 %b, i1 %other_cond) {
+; CHECK-LABEL: @logical_and_icmps_fail1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -1
+; CHECK-NEXT: [[LOGICAL_AND:%.*]] = select i1 [[OTHER_COND:%.*]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = select i1 [[LOGICAL_AND]], i1 [[CMP2]], i1 false
+; CHECK-NEXT: ret i1 [[RET]]
+;
+entry:
+ %cmp1 = icmp sgt i32 %a, -1
+ %logical_and = select i1 %other_cond, i1 %cmp1, i1 false
+ %cmp2 = icmp slt i32 %a, %b
+ %ret = select i1 %logical_and, i1 %cmp2, i1 false
+ ret i1 %ret
+}
diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll
index f0ea09c0884744..834773544a5546 100644
--- a/llvm/test/Transforms/InstCombine/logical-select.ll
+++ b/llvm/test/Transforms/InstCombine/logical-select.ll
@@ -1303,3 +1303,168 @@ define i1 @logical_or_and_with_common_not_op_variant5(i1 %a) {
%or = select i1 %a, i1 true, i1 %and
ret i1 %or
}
+
+define i1 @reduce_logical_and1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP1]], [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp1, i1 false
+ %and2 = select i1 %and1, i1 %cmp, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and2(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @reduce_logical_and2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT: [[B:%.*]] = and i1 [[TMP0]], [[B1:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 [[B]], i1 false
+; CHECK-NEXT: ret i1 [[AND3]]
+;
+bb:
+ %or = xor i1 %c, %b
+ %and1 = select i1 %a, i1 %or, i1 false
+ %and2 = select i1 %and1, i1 %b, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and3(i1 %a, i32 %b, i32 noundef %c) {
+; CHECK-LABEL: @reduce_logical_and3(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp, i1 false
+ %and2 = select i1 %and1, i1 %cmp1, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_or1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP1]], [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %cmp1
+ %and2 = select i1 %and1, i1 true, i1 %cmp
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or2(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @reduce_logical_or2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[B:%.*]] = or i1 [[C:%.*]], [[B1:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 true, i1 [[B]]
+; CHECK-NEXT: ret i1 [[AND3]]
+;
+bb:
+ %or = xor i1 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %or
+ %and2 = select i1 %and1, i1 true, i1 %b
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or3(i1 %a, i32 %b, i32 noundef %c) {
+; CHECK-LABEL: @reduce_logical_or3(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %cmp
+ %and2 = select i1 %and1, i1 true, i1 %cmp1
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and_fail1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and_fail1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp, i1 false
+ %and2 = select i1 %and1, i1 %cmp1, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and_fail2(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and_fail2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, 7
+ %and1 = select i1 %a, i1 %cmp, i1 false
+ %and2 = select i1 %and1, i1 %cmp1, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or_fail1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_or_fail1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %cmp
+ %and2 = select i1 %and1, i1 true, i1 %cmp1
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or_fail2(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_or_fail2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, 7
+ %and1 = select i1 %a, i1 true, i1 %cmp
+ %and2 = select i1 %and1, i1 true, i1 %cmp1
+ ret i1 %and2
+}
|
8a8c008
to
9579807
Compare
@@ -2985,6 +2985,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) { | |||
return BinaryOperator::CreateOr(CondVal, FalseVal); | |||
} | |||
|
|||
if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_One(), m_Value(B)))) && | |||
impliesPoison(FalseVal, B)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check the compile time impact?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikic could you test the compile time impact of this patch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gently ping. @nikic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay, here are the results: https://llvm-compile-time-tracker.com/compare.php?from=03ffb82c9e0d363c97ca37ede46719236616c88e&to=79752c9ee833172600523f038a6f83d64f657f9d&stat=instructions:u
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. There is some small compile-time impact, but I think this is an important fold to have.
Fixes #76623
Alive2 proof: https://alive2.llvm.org/ce/z/gX6znJ (I'm not sure how to write a proof for such transform, maybe there are mistakes)
In most cases,
icmp(a, C1) && (other_cond && icmp(a, C2))
will be reduced toicmp(a, C1) & (other_cond && icmp(a, C2))
, since latter icmp always implies the poison of the former. After reduction, it's easier to simplify the icmp chain.Similarly, this patch does the same thing for
(A && B) && C --> A && (B & C)
. Maybe we could constraint such reduction only on icmps if there is regression in benchmarks.