-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[InstCombine] handle trunc to i1 in foldSelectICmpAndBinOp #127390
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: Andreas Jonson (andjo403) Changesfor proof: https://alive2.llvm.org/ce/z/a6QmyV Full diff: https://github.com/llvm/llvm-project/pull/127390.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 2e14145aef884..2a4bf82f1c070 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -742,39 +742,47 @@ static Value *foldSelectICmpLshrAshr(const ICmpInst *IC, Value *TrueVal,
/// 1. The icmp predicate is inverted
/// 2. The select operands are reversed
/// 3. The magnitude of C2 and C1 are flipped
-static Value *foldSelectICmpAndBinOp(const ICmpInst *IC, Value *TrueVal,
- Value *FalseVal,
- InstCombiner::BuilderTy &Builder) {
+static Value *foldSelectICmpAndBinOp(Value *CondVal, Value *TrueVal,
+ Value *FalseVal,
+ InstCombiner::BuilderTy &Builder) {
// Only handle integer compares. Also, if this is a vector select, we need a
// vector compare.
if (!TrueVal->getType()->isIntOrIntVectorTy() ||
- TrueVal->getType()->isVectorTy() != IC->getType()->isVectorTy())
+ TrueVal->getType()->isVectorTy() != CondVal->getType()->isVectorTy())
return nullptr;
- Value *CmpLHS = IC->getOperand(0);
- Value *CmpRHS = IC->getOperand(1);
-
unsigned C1Log;
bool NeedAnd = false;
- CmpInst::Predicate Pred = IC->getPredicate();
- if (IC->isEquality()) {
- if (!match(CmpRHS, m_Zero()))
- return nullptr;
+ CmpPredicate Pred;
+ Value *CmpLHS, *CmpRHS;
- const APInt *C1;
- if (!match(CmpLHS, m_And(m_Value(), m_Power2(C1))))
- return nullptr;
+ if (match(CondVal, m_ICmp(Pred, m_Value(CmpLHS), m_Value(CmpRHS)))) {
+ if (ICmpInst::isEquality(Pred)) {
+ if (!match(CmpRHS, m_Zero()))
+ return nullptr;
- C1Log = C1->logBase2();
- } else {
- auto Res = decomposeBitTestICmp(CmpLHS, CmpRHS, Pred);
- if (!Res || !Res->Mask.isPowerOf2())
- return nullptr;
+ const APInt *C1;
+ if (!match(CmpLHS, m_And(m_Value(), m_Power2(C1))))
+ return nullptr;
- CmpLHS = Res->X;
- Pred = Res->Pred;
- C1Log = Res->Mask.logBase2();
- NeedAnd = true;
+ C1Log = C1->logBase2();
+ } else {
+ auto Res = decomposeBitTestICmp(CmpLHS, CmpRHS, Pred);
+ if (!Res || !Res->Mask.isPowerOf2())
+ return nullptr;
+
+ CmpLHS = Res->X;
+ Pred = Res->Pred;
+ C1Log = Res->Mask.logBase2();
+ NeedAnd = true;
+ }
+ } else if (auto *Trunc = dyn_cast<TruncInst>(CondVal)) {
+ CmpLHS = Trunc->getOperand(0);
+ C1Log = 0;
+ Pred = ICmpInst::ICMP_NE;
+ NeedAnd = !Trunc->hasNoUnsignedWrap();
+ } else {
+ return nullptr;
}
Value *Y, *V = CmpLHS;
@@ -808,7 +816,7 @@ static Value *foldSelectICmpAndBinOp(const ICmpInst *IC, Value *TrueVal,
// Make sure we don't create more instructions than we save.
if ((NeedShift + NeedXor + NeedZExtTrunc + NeedAnd) >
- (IC->hasOneUse() + BinOp->hasOneUse()))
+ (CondVal->hasOneUse() + BinOp->hasOneUse()))
return nullptr;
if (NeedAnd) {
@@ -1983,9 +1991,6 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
if (Instruction *V = foldSelectZeroOrOnes(ICI, TrueVal, FalseVal, Builder))
return V;
- if (Value *V = foldSelectICmpAndBinOp(ICI, TrueVal, FalseVal, Builder))
- return replaceInstUsesWith(SI, V);
-
if (Value *V = foldSelectICmpLshrAshr(ICI, TrueVal, FalseVal, Builder))
return replaceInstUsesWith(SI, V);
@@ -3943,6 +3948,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Instruction *Result = foldSelectInstWithICmp(SI, ICI))
return Result;
+ if (Value *V = foldSelectICmpAndBinOp(CondVal, TrueVal, FalseVal, Builder))
+ return replaceInstUsesWith(SI, V);
+
if (Instruction *Add = foldAddSubSelect(SI, Builder))
return Add;
if (Instruction *Add = foldOverflowingAddSubSelect(SI, Builder))
diff --git a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
index 7c100f579399d..f46c506683c45 100644
--- a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
+++ b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
@@ -1712,9 +1712,9 @@ define i8 @select_icmp_eq_and_1_0_lshr_tv(i8 %x, i8 %y) {
define i8 @select_trunc_or_2(i8 %x, i8 %y) {
; CHECK-LABEL: @select_trunc_or_2(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X:%.*]] to i1
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], 2
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i8 [[OR]], i8 [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[X:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 2
+; CHECK-NEXT: [[SELECT:%.*]] = or i8 [[Y:%.*]], [[TMP2]]
; CHECK-NEXT: ret i8 [[SELECT]]
;
%trunc = trunc i8 %x to i1
@@ -1725,9 +1725,9 @@ define i8 @select_trunc_or_2(i8 %x, i8 %y) {
define i8 @select_not_trunc_or_2(i8 %x, i8 %y) {
; CHECK-LABEL: @select_not_trunc_or_2(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc i8 [[X:%.*]] to i1
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], 2
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i8 [[OR]], i8 [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[X:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 2
+; CHECK-NEXT: [[SELECT:%.*]] = or i8 [[Y:%.*]], [[TMP2]]
; CHECK-NEXT: ret i8 [[SELECT]]
;
%trunc = trunc i8 %x to i1
@@ -1739,9 +1739,8 @@ define i8 @select_not_trunc_or_2(i8 %x, i8 %y) {
define i8 @select_trunc_nuw_or_2(i8 %x, i8 %y) {
; CHECK-LABEL: @select_trunc_nuw_or_2(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i8 [[X:%.*]] to i1
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], 2
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i8 [[OR]], i8 [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[X:%.*]], 1
+; CHECK-NEXT: [[SELECT:%.*]] = or i8 [[Y:%.*]], [[TMP1]]
; CHECK-NEXT: ret i8 [[SELECT]]
;
%trunc = trunc nuw i8 %x to i1
@@ -1752,9 +1751,9 @@ define i8 @select_trunc_nuw_or_2(i8 %x, i8 %y) {
define i8 @select_trunc_nsw_or_2(i8 %x, i8 %y) {
; CHECK-LABEL: @select_trunc_nsw_or_2(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc nsw i8 [[X:%.*]] to i1
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[Y:%.*]], 2
-; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i8 [[OR]], i8 [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[X:%.*]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 2
+; CHECK-NEXT: [[SELECT:%.*]] = or i8 [[Y:%.*]], [[TMP2]]
; CHECK-NEXT: ret i8 [[SELECT]]
;
%trunc = trunc nsw i8 %x to i1
@@ -1765,9 +1764,9 @@ define i8 @select_trunc_nsw_or_2(i8 %x, i8 %y) {
define <2 x i8> @select_trunc_or_2_vec(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @select_trunc_or_2_vec(
-; CHECK-NEXT: [[TRUNC:%.*]] = trunc <2 x i8> [[X:%.*]] to <2 x i1>
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[Y:%.*]], splat (i8 2)
-; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[TRUNC]], <2 x i8> [[OR]], <2 x i8> [[Y]]
+; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i8> [[X:%.*]], splat (i8 1)
+; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i8> [[TMP1]], splat (i8 2)
+; CHECK-NEXT: [[SELECT:%.*]] = or <2 x i8> [[Y:%.*]], [[TMP2]]
; CHECK-NEXT: ret <2 x i8> [[SELECT]]
;
%trunc = trunc <2 x i8> %x to <2 x i1>
|
It is always safe to add poison-generating flags for `BinOp Y, Identity`. Proof: https://alive2.llvm.org/ce/z/8BLEpq and https://alive2.llvm.org/ce/z/584Bb4 Then we can propagate flags from one of the arms: ``` select Cond, Y, (BinOp flags Y, Z) -> select Cond, (BinOp flags Y, Identity), (BinOp flags Y, Z) -> BinOp flags Y, (select Cond, Identity, Z) ``` This patch is proposed to avoid information loss caused by #127390.
…(#127437) It is always safe to add poison-generating flags for `BinOp Y, Identity`. Proof: https://alive2.llvm.org/ce/z/8BLEpq and https://alive2.llvm.org/ce/z/584Bb4 Then we can propagate flags from one of the arms: ``` select Cond, Y, (BinOp flags Y, Z) -> select Cond, (BinOp flags Y, Identity), (BinOp flags Y, Z) -> BinOp flags Y, (select Cond, Identity, Z) ``` This patch is proposed to avoid information loss caused by llvm/llvm-project#127390.
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. Thank you!
a927bbe
to
8d61bc5
Compare
for
trunc nuw
saves a instruction and otherwise only other instructions without the select, same behavior as for bit test before.proof: https://alive2.llvm.org/ce/z/a6QmyV