-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[InstCombine] Simplify nested selects with implied condition #83739
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
[InstCombine] Simplify nested selects with implied condition #83739
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesThis patch does the following simplification:
Alive2: https://alive2.llvm.org/ce/z/9A_arU It cannot be done in CVP/SCCP since we should guarantee that Full diff: https://github.com/llvm/llvm-project/pull/83739.diff 3 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 71fa9b9ba41ebb..dc4347fdd713c6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3867,5 +3867,22 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
}
}
+ // Fold nested selects if the inner condition can be implied by the outer
+ // condition.
+ Value *InnerCondVal;
+ const DataLayout &DL = getDataLayout();
+ if (match(TrueVal,
+ m_Select(m_Value(InnerCondVal), m_Value(LHS), m_Value(RHS))) &&
+ CondVal->getType() == InnerCondVal->getType())
+ if (auto Implied =
+ isImpliedCondition(CondVal, InnerCondVal, DL, /*LHSIsTrue=*/true))
+ return replaceOperand(SI, 1, *Implied ? LHS : RHS);
+ if (match(FalseVal,
+ m_Select(m_Value(InnerCondVal), m_Value(LHS), m_Value(RHS))) &&
+ CondVal->getType() == InnerCondVal->getType())
+ if (auto Implied =
+ isImpliedCondition(CondVal, InnerCondVal, DL, /*LHSIsTrue=*/false))
+ return replaceOperand(SI, 2, *Implied ? LHS : RHS);
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-clamp-like-pattern-between-negative-and-positive-thresholds.ll b/llvm/test/Transforms/InstCombine/canonicalize-clamp-like-pattern-between-negative-and-positive-thresholds.ll
index d03e22bc4c9fbf..b5ef1f466958d7 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-clamp-like-pattern-between-negative-and-positive-thresholds.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-clamp-like-pattern-between-negative-and-positive-thresholds.ll
@@ -189,10 +189,8 @@ define i32 @n9_ult_slt_neg17(i32 %x, i32 %replacement_low, i32 %replacement_high
; Regression test for PR53252.
define i32 @n10_ugt_slt(i32 %x, i32 %replacement_low, i32 %replacement_high) {
; CHECK-LABEL: @n10_ugt_slt(
-; CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[X:%.*]], 0
-; CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 [[REPLACEMENT_LOW:%.*]], i32 [[REPLACEMENT_HIGH:%.*]]
-; CHECK-NEXT: [[T2:%.*]] = icmp ugt i32 [[X]], 128
-; CHECK-NEXT: [[R:%.*]] = select i1 [[T2]], i32 [[X]], i32 [[T1]]
+; CHECK-NEXT: [[T2:%.*]] = icmp ugt i32 [[X:%.*]], 128
+; CHECK-NEXT: [[R:%.*]] = select i1 [[T2]], i32 [[X]], i32 [[REPLACEMENT_HIGH:%.*]]
; CHECK-NEXT: ret i32 [[R]]
;
%t0 = icmp slt i32 %x, 0
@@ -204,10 +202,8 @@ define i32 @n10_ugt_slt(i32 %x, i32 %replacement_low, i32 %replacement_high) {
define i32 @n11_uge_slt(i32 %x, i32 %replacement_low, i32 %replacement_high) {
; CHECK-LABEL: @n11_uge_slt(
-; CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[X:%.*]], 0
-; CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 [[REPLACEMENT_LOW:%.*]], i32 [[REPLACEMENT_HIGH:%.*]]
-; CHECK-NEXT: [[T2:%.*]] = icmp ult i32 [[X]], 129
-; CHECK-NEXT: [[R:%.*]] = select i1 [[T2]], i32 [[T1]], i32 [[X]]
+; CHECK-NEXT: [[T2:%.*]] = icmp ult i32 [[X:%.*]], 129
+; CHECK-NEXT: [[R:%.*]] = select i1 [[T2]], i32 [[REPLACEMENT_HIGH:%.*]], i32 [[X]]
; CHECK-NEXT: ret i32 [[R]]
;
%t0 = icmp slt i32 %x, 0
diff --git a/llvm/test/Transforms/InstCombine/nested-select.ll b/llvm/test/Transforms/InstCombine/nested-select.ll
index 42a0f81e7b85a2..d4bbf0ae48590a 100644
--- a/llvm/test/Transforms/InstCombine/nested-select.ll
+++ b/llvm/test/Transforms/InstCombine/nested-select.ll
@@ -498,3 +498,87 @@ define i1 @orcond.111.inv.all.conds(i1 %inner.cond, i1 %alt.cond, i1 %inner.sel.
%outer.sel = select i1 %not.outer.cond, i1 true, i1 %inner.sel
ret i1 %outer.sel
}
+
+define i8 @test_implied_true(i8 %x) {
+; CHECK-LABEL: @test_implied_true(
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 0, i8 20
+; CHECK-NEXT: ret i8 [[SEL2]]
+;
+ %cmp1 = icmp slt i8 %x, 10
+ %cmp2 = icmp slt i8 %x, 0
+ %sel1 = select i1 %cmp1, i8 0, i8 5
+ %sel2 = select i1 %cmp2, i8 %sel1, i8 20
+ ret i8 %sel2
+}
+
+define <2 x i8> @test_implied_true_vec(<2 x i8> %x) {
+; CHECK-LABEL: @test_implied_true_vec(
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
+; CHECK-NEXT: [[SEL2:%.*]] = select <2 x i1> [[CMP2]], <2 x i8> zeroinitializer, <2 x i8> <i8 20, i8 20>
+; CHECK-NEXT: ret <2 x i8> [[SEL2]]
+;
+ %cmp1 = icmp slt <2 x i8> %x, <i8 10, i8 10>
+ %cmp2 = icmp slt <2 x i8> %x, zeroinitializer
+ %sel1 = select <2 x i1> %cmp1, <2 x i8> zeroinitializer, <2 x i8> <i8 5, i8 5>
+ %sel2 = select <2 x i1> %cmp2, <2 x i8> %sel1, <2 x i8> <i8 20, i8 20>
+ ret <2 x i8> %sel2
+}
+
+define i8 @test_implied_true_falseval(i8 %x) {
+; CHECK-LABEL: @test_implied_true_falseval(
+; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i8 [[X:%.*]], 0
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 20, i8 0
+; CHECK-NEXT: ret i8 [[SEL2]]
+;
+ %cmp1 = icmp slt i8 %x, 10
+ %cmp2 = icmp sgt i8 %x, 0
+ %sel1 = select i1 %cmp1, i8 0, i8 5
+ %sel2 = select i1 %cmp2, i8 20, i8 %sel1
+ ret i8 %sel2
+}
+
+define i8 @test_implied_false(i8 %x) {
+; CHECK-LABEL: @test_implied_false(
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[X:%.*]], 0
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 5, i8 20
+; CHECK-NEXT: ret i8 [[SEL2]]
+;
+ %cmp1 = icmp sgt i8 %x, 10
+ %cmp2 = icmp slt i8 %x, 0
+ %sel1 = select i1 %cmp1, i8 0, i8 5
+ %sel2 = select i1 %cmp2, i8 %sel1, i8 20
+ ret i8 %sel2
+}
+
+; Negative tests
+
+define i8 @test_imply_fail(i8 %x) {
+; CHECK-LABEL: @test_imply_fail(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i8 [[X:%.*]], -10
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[X]], 0
+; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i8 0, i8 5
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 [[SEL1]], i8 20
+; CHECK-NEXT: ret i8 [[SEL2]]
+;
+ %cmp1 = icmp slt i8 %x, -10
+ %cmp2 = icmp slt i8 %x, 0
+ %sel1 = select i1 %cmp1, i8 0, i8 5
+ %sel2 = select i1 %cmp2, i8 %sel1, i8 20
+ ret i8 %sel2
+}
+
+define <2 x i8> @test_imply_type_mismatch(<2 x i8> %x, i8 %y) {
+; CHECK-LABEL: @test_imply_type_mismatch(
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 10, i8 10>
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i8 [[Y:%.*]], 0
+; CHECK-NEXT: [[SEL1:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> zeroinitializer, <2 x i8> <i8 5, i8 5>
+; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], <2 x i8> [[SEL1]], <2 x i8> <i8 20, i8 20>
+; CHECK-NEXT: ret <2 x i8> [[SEL2]]
+;
+ %cmp1 = icmp slt <2 x i8> %x, <i8 10, i8 10>
+ %cmp2 = icmp slt i8 %y, 0
+ %sel1 = select <2 x i1> %cmp1, <2 x i8> zeroinitializer, <2 x i8> <i8 5, i8 5>
+ %sel2 = select i1 %cmp2, <2 x i8> %sel1, <2 x i8> <i8 20, i8 20>
+ ret <2 x i8> %sel2
+}
|
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.
This looks basically fine, but I think it may subsume some existing folds?
For example, what about this one?
llvm-project/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Lines 3646 to 3651 in 27ce512
// select(C, select(C, a, b), c) -> select(C, a, c) | |
if (TrueSI->getCondition() == CondVal) { | |
if (SI.getTrueValue() == TrueSI->getTrueValue()) | |
return nullptr; | |
return replaceOperand(SI, 1, TrueSI->getTrueValue()); | |
} |
There's also foldAndOrOfSelectUsingImpliedCond() -- I think your fold may be the same, but without the limitation that the top-level select is a logical one?
We can further remove the following logic if we fold it recursively. llvm-project/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp Lines 3682 to 3723 in d052148
|
Done. |
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
The compile-time improvement looks good: |
This patch does the following simplification:
Alive2: https://alive2.llvm.org/ce/z/9A_arU
It cannot be done in CVP/SCCP since we should guarantee that
cond2
is not an undef.