[llvm] 5207cde - [InstCombine] Conditionally fold select i1 into and/or
Juneyoung Lee via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 3 22:16:08 PDT 2021
Author: Juneyoung Lee
Date: 2021-04-04T14:11:28+09:00
New Revision: 5207cde5cb4147155c469e1861427ea9d569bd5a
URL: https://github.com/llvm/llvm-project/commit/5207cde5cb4147155c469e1861427ea9d569bd5a
DIFF: https://github.com/llvm/llvm-project/commit/5207cde5cb4147155c469e1861427ea9d569bd5a.diff
LOG: [InstCombine] Conditionally fold select i1 into and/or
This patch fixes llvm.org/pr49688 by conditionally folding select i1 into and/or:
```
select cond, cond2, false
->
and cond, cond2
```
This is not safe if cond2 is poison whereas cond isn’t.
Unconditionally disabling this transformation affects later pipelines that depend on and/or i1s.
To minimize its impact, this patch conservatively checks whether cond2 is an instruction that
creates a poison or its operand creates a poison.
This approach is similar to what InstSimplify's SimplifyWithOpReplaced is doing.
Reviewed By: nikic
Differential Revision: https://reviews.llvm.org/D99674
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/test/Transforms/InstCombine/and-fcmp.ll
llvm/test/Transforms/InstCombine/onehot_merge.ll
llvm/test/Transforms/InstCombine/pr49688.ll
llvm/test/Transforms/InstCombine/signed-truncation-check.ll
llvm/test/Transforms/InstCombine/widenable-conditions.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index a1ec11e95081..24de693e547f 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2618,13 +2618,32 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (SelType->isIntOrIntVectorTy(1) &&
TrueVal->getType() == CondVal->getType()) {
- if (match(TrueVal, m_One()) &&
- (EnableUnsafeSelectTransform || impliesPoison(FalseVal, CondVal))) {
+ auto IsSafeToConvert = [&](Value *OtherVal) {
+ if (impliesPoison(OtherVal, CondVal))
+ return true;
+
+ if (!EnableUnsafeSelectTransform)
+ return false;
+
+ // We block this transformation if OtherVal or its operand can create
+ // poison. See PR49688
+ if (auto *Op = dyn_cast<Operator>(OtherVal)) {
+ if (canCreatePoison(Op))
+ return false;
+ if (propagatesPoison(Op) &&
+ llvm::any_of(Op->operand_values(), [](Value *V) {
+ return isa<Operator>(V) ? canCreatePoison(cast<Operator>(V))
+ : false;
+ }))
+ return false;
+ }
+ return true;
+ };
+ if (match(TrueVal, m_One()) && IsSafeToConvert(FalseVal)) {
// Change: A = select B, true, C --> A = or B, C
return BinaryOperator::CreateOr(CondVal, FalseVal);
}
- if (match(FalseVal, m_Zero()) &&
- (EnableUnsafeSelectTransform || impliesPoison(TrueVal, CondVal))) {
+ if (match(FalseVal, m_Zero()) && IsSafeToConvert(TrueVal)) {
// Change: A = select B, C, false --> A = and B, C
return BinaryOperator::CreateAnd(CondVal, TrueVal);
}
diff --git a/llvm/test/Transforms/InstCombine/and-fcmp.ll b/llvm/test/Transforms/InstCombine/and-fcmp.ll
index 18689c969bd0..41b490341d75 100644
--- a/llvm/test/Transforms/InstCombine/and-fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/and-fcmp.ll
@@ -73,10 +73,13 @@ define i1 @PR41069_commute(i1 %z, float %c, float %d) {
ret i1 %r
}
+; TODO: this should be fixed using freeze
define i1 @PR41069_commute_logical(i1 %z, float %c, float %d) {
; CHECK-LABEL: @PR41069_commute_logical(
-; CHECK-NEXT: [[TMP1:%.*]] = fcmp ninf ord float [[D:%.*]], [[C:%.*]]
-; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[Z:%.*]]
+; CHECK-NEXT: [[ORD1:%.*]] = fcmp ninf ord float [[C:%.*]], 0.000000e+00
+; CHECK-NEXT: [[AND:%.*]] = and i1 [[ORD1]], [[Z:%.*]]
+; CHECK-NEXT: [[ORD2:%.*]] = fcmp reassoc ninf ord float [[D:%.*]], 0.000000e+00
+; CHECK-NEXT: [[R:%.*]] = select i1 [[ORD2]], i1 [[AND]], i1 false
; CHECK-NEXT: ret i1 [[R]]
;
%ord1 = fcmp ninf ord float %c, 0.0
diff --git a/llvm/test/Transforms/InstCombine/onehot_merge.ll b/llvm/test/Transforms/InstCombine/onehot_merge.ll
index bc0047e7a84a..1092882d036d 100644
--- a/llvm/test/Transforms/InstCombine/onehot_merge.ll
+++ b/llvm/test/Transforms/InstCombine/onehot_merge.ll
@@ -468,7 +468,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_logical(i32 %k, i32 %c
; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -506,7 +506,7 @@ define i1 @foo1_or_signbit_lshr_without_shifting_signbit_logical(i32 %k, i32 %c1
; CHECK-NEXT: [[T2:%.*]] = icmp ne i32 [[T1]], 0
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp slt i32 [[T3]], 0
-; CHECK-NEXT: [[OR:%.*]] = and i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 [[T4]], i1 false
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -535,13 +535,15 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_both_sides(i32 %k, i32
ret i1 %or
}
+; %t2 can be poison where as %t0 isn't; merging these two is unsafe.
define i1 @foo1_and_signbit_lshr_without_shifting_signbit_both_sides_logical(i32 %k, i32 %c1, i32 %c2) {
; CHECK-LABEL: @foo1_and_signbit_lshr_without_shifting_signbit_both_sides_logical(
; CHECK-NEXT: [[T0:%.*]] = shl i32 [[K:%.*]], [[C1:%.*]]
+; CHECK-NEXT: [[T1:%.*]] = icmp sgt i32 [[T0]], -1
; CHECK-NEXT: [[T2:%.*]] = shl i32 [[K]], [[C2:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[T0]], [[T2]]
-; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[TMP1]], -1
-; CHECK-NEXT: ret i1 [[TMP2]]
+; CHECK-NEXT: [[T3:%.*]] = icmp sgt i32 [[T2]], -1
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T1]], i1 true, i1 [[T3]]
+; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 %k, %c1
%t1 = icmp sgt i32 %t0, -1
@@ -567,13 +569,15 @@ define i1 @foo1_or_signbit_lshr_without_shifting_signbit_both_sides(i32 %k, i32
ret i1 %or
}
+; %t2 can be poison where as %t0 isn't; merging these two is unsafe.
define i1 @foo1_or_signbit_lshr_without_shifting_signbit_both_sides_logical(i32 %k, i32 %c1, i32 %c2) {
; CHECK-LABEL: @foo1_or_signbit_lshr_without_shifting_signbit_both_sides_logical(
; CHECK-NEXT: [[T0:%.*]] = shl i32 [[K:%.*]], [[C1:%.*]]
+; CHECK-NEXT: [[T1:%.*]] = icmp slt i32 [[T0]], 0
; CHECK-NEXT: [[T2:%.*]] = shl i32 [[K]], [[C2:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[T0]], [[T2]]
-; CHECK-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0
-; CHECK-NEXT: ret i1 [[TMP2]]
+; CHECK-NEXT: [[T3:%.*]] = icmp slt i32 [[T2]], 0
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T1]], i1 [[T3]], i1 false
+; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 %k, %c1
%t1 = icmp slt i32 %t0, 0
@@ -886,7 +890,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_extra_use_shl1_logical
; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -929,7 +933,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_extra_use_and_logical(
; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -972,7 +976,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_extra_use_cmp1_logical
; CHECK-NEXT: store i1 [[T2]], i1* [[P:%.*]], align 1
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -1015,7 +1019,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_extra_use_shl2_logical
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: store i32 [[T3]], i32* [[P:%.*]], align 4
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -1058,7 +1062,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_extra_use_cmp2_logical
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
; CHECK-NEXT: store i1 [[T4]], i1* [[P:%.*]], align 1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 1, %c1
@@ -1100,7 +1104,7 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_not_pwr2_logical(i32 %
; CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
; CHECK-NEXT: [[T3:%.*]] = shl i32 [[K]], [[C2:%.*]]
; CHECK-NEXT: [[T4:%.*]] = icmp sgt i32 [[T3]], -1
-; CHECK-NEXT: [[OR:%.*]] = or i1 [[T2]], [[T4]]
+; CHECK-NEXT: [[OR:%.*]] = select i1 [[T2]], i1 true, i1 [[T4]]
; CHECK-NEXT: ret i1 [[OR]]
;
%t0 = shl i32 3, %c1
diff --git a/llvm/test/Transforms/InstCombine/pr49688.ll b/llvm/test/Transforms/InstCombine/pr49688.ll
index 0de6a7f67b07..1e4eb79bf5c6 100644
--- a/llvm/test/Transforms/InstCombine/pr49688.ll
+++ b/llvm/test/Transforms/InstCombine/pr49688.ll
@@ -1,12 +1,15 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instcombine -S | FileCheck %s
+; %cmp should not vanish
define i1 @f(i32 %i1) {
; CHECK-LABEL: @f(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[SHR:%.*]] = lshr i32 7, [[I1:%.*]]
-; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[SHR]], [[I1]]
-; CHECK-NEXT: ret i1 [[TMP0]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I1:%.*]], 0
+; CHECK-NEXT: [[SHR:%.*]] = lshr i32 7, [[I1]]
+; CHECK-NEXT: [[CMP4:%.*]] = icmp slt i32 [[SHR]], [[I1]]
+; CHECK-NEXT: [[I2:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP4]]
+; CHECK-NEXT: ret i1 [[I2]]
;
entry:
%cmp = icmp slt i32 %i1, 0
@@ -16,11 +19,14 @@ entry:
ret i1 %i2
}
+; %cmp should not vanish
define i32 @f2(i32 signext %g, i32 zeroext %h) {
; CHECK-LABEL: @f2(
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[G:%.*]], 0
; CHECK-NEXT: [[SHR:%.*]] = lshr i32 7, [[H:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[SHR]], [[G:%.*]]
-; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP1]] to i32
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[SHR]], [[G]]
+; CHECK-NEXT: [[DOT0:%.*]] = select i1 [[CMP]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[DOT0]] to i32
; CHECK-NEXT: ret i32 [[LOR_EXT]]
;
%cmp = icmp slt i32 %g, 0
diff --git a/llvm/test/Transforms/InstCombine/signed-truncation-check.ll b/llvm/test/Transforms/InstCombine/signed-truncation-check.ll
index 62a62b97e90d..3d90939142f4 100644
--- a/llvm/test/Transforms/InstCombine/signed-truncation-check.ll
+++ b/llvm/test/Transforms/InstCombine/signed-truncation-check.ll
@@ -606,7 +606,7 @@ define i1 @oneuse_shl_ashr_logical(i32 %arg) {
; CHECK-NEXT: call void @use32(i32 [[T4]])
; CHECK-NEXT: [[T5:%.*]] = icmp eq i32 [[T4]], [[ARG]]
; CHECK-NEXT: call void @use1(i1 [[T5]])
-; CHECK-NEXT: [[T6:%.*]] = and i1 [[T2]], [[T5]]
+; CHECK-NEXT: [[T6:%.*]] = select i1 [[T2]], i1 [[T5]], i1 false
; CHECK-NEXT: ret i1 [[T6]]
;
%t1 = trunc i32 %arg to i8
diff --git a/llvm/test/Transforms/InstCombine/widenable-conditions.ll b/llvm/test/Transforms/InstCombine/widenable-conditions.ll
index 31aa98ff998b..548ff3892a1c 100644
--- a/llvm/test/Transforms/InstCombine/widenable-conditions.ll
+++ b/llvm/test/Transforms/InstCombine/widenable-conditions.ll
@@ -20,7 +20,7 @@ define i1 @test1(i1 %a, i1 %b) {
define i1 @test1_logical(i1 %a, i1 %b) {
; CHECK-LABEL: @test1_logical(
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT: [[LHS:%.*]] = and i1 [[WC]], [[B:%.*]]
+; CHECK-NEXT: [[LHS:%.*]] = select i1 [[B:%.*]], i1 [[WC]], i1 false
; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[A:%.*]]
; CHECK-NEXT: ret i1 [[AND]]
;
@@ -49,7 +49,7 @@ define i1 @test1b(i1 %a, i1 %b) {
define i1 @test1b_logical(i1 %a, i1 %b) {
; CHECK-LABEL: @test1b_logical(
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT: [[LHS:%.*]] = and i1 [[WC]], [[B:%.*]]
+; CHECK-NEXT: [[LHS:%.*]] = select i1 [[B:%.*]], i1 [[WC]], i1 false
; CHECK-NEXT: call void @use(i1 [[LHS]])
; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[A:%.*]]
; CHECK-NEXT: ret i1 [[AND]]
@@ -87,7 +87,7 @@ define i1 @test1c_logical(i1 %a, i1 %b) {
; CHECK-NEXT: call void @use(i1 [[B:%.*]])
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: call void @use(i1 [[WC]])
-; CHECK-NEXT: [[LHS:%.*]] = and i1 [[WC]], [[B]]
+; CHECK-NEXT: [[LHS:%.*]] = select i1 [[B]], i1 [[WC]], i1 false
; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[A]]
; CHECK-NEXT: ret i1 [[AND]]
;
@@ -147,7 +147,7 @@ define i1 @test3_logical(i1 %a, i1 %b, i1 %c) {
; CHECK-LABEL: @test3_logical(
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: [[LHS:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[RHS:%.*]] = and i1 [[WC]], [[C:%.*]]
+; CHECK-NEXT: [[RHS:%.*]] = select i1 [[C:%.*]], i1 [[WC]], i1 false
; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[RHS]]
; CHECK-NEXT: ret i1 [[AND]]
;
@@ -178,7 +178,7 @@ define i1 @test4_logical(i1 %a, i1 %b, i1 %c) {
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: [[LHS:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[RHS:%.*]] = and i1 [[WC]], [[C:%.*]]
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[LHS]], [[RHS]]
+; CHECK-NEXT: [[AND:%.*]] = select i1 [[LHS]], i1 [[RHS]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%wc = call i1 @llvm.experimental.widenable.condition()
@@ -225,7 +225,7 @@ define i1 @test6_logical(i1 %a, i1 %b) {
; CHECK-LABEL: @test6_logical(
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[WC]], [[WC2]]
+; CHECK-NEXT: [[AND:%.*]] = select i1 [[WC]], i1 [[WC2]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%wc = call i1 @llvm.experimental.widenable.condition()
@@ -254,7 +254,7 @@ define i1 @test7_logical(i1 %a, i1 %b) {
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: call void @use(i1 [[WC]])
; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[WC]], [[WC2]]
+; CHECK-NEXT: [[AND:%.*]] = select i1 [[WC]], i1 [[WC2]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%wc = call i1 @llvm.experimental.widenable.condition()
@@ -284,7 +284,7 @@ define i1 @test8_logical(i1 %a, i1 %b) {
; CHECK-NEXT: [[WC:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: [[WC2:%.*]] = call i1 @llvm.experimental.widenable.condition()
; CHECK-NEXT: call void @use(i1 [[WC2]])
-; CHECK-NEXT: [[AND:%.*]] = and i1 [[WC]], [[WC2]]
+; CHECK-NEXT: [[AND:%.*]] = select i1 [[WC]], i1 [[WC2]], i1 false
; CHECK-NEXT: ret i1 [[AND]]
;
%wc = call i1 @llvm.experimental.widenable.condition()
More information about the llvm-commits
mailing list