diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1876,6 +1876,19 @@ if (Instruction *Z = narrowMaskedBinOp(I)) return Z; + if (I.getType()->isIntOrIntVectorTy(1)) { + if (auto *SI0 = dyn_cast(Op0)) { + if (auto *I = + foldAndOrOfSelectUsingImpliedCond(Op1, *SI0, /* IsAnd */ true)) + return I; + } + if (auto *SI1 = dyn_cast(Op1)) { + if (auto *I = + foldAndOrOfSelectUsingImpliedCond(Op0, *SI1, /* IsAnd */ true)) + return I; + } + } + if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I)) return FoldedLogic; @@ -2553,6 +2566,20 @@ if (Value *V = SimplifyBSwap(I, Builder)) return replaceInstUsesWith(I, V); + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + if (I.getType()->isIntOrIntVectorTy(1)) { + if (auto *SI0 = dyn_cast(Op0)) { + if (auto *I = + foldAndOrOfSelectUsingImpliedCond(Op1, *SI0, /* IsAnd */ false)) + return I; + } + if (auto *SI1 = dyn_cast(Op1)) { + if (auto *I = + foldAndOrOfSelectUsingImpliedCond(Op0, *SI1, /* IsAnd */ false)) + return I; + } + } + if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I)) return FoldedLogic; @@ -2577,7 +2604,6 @@ } // (A & C)|(B & D) - Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Value *A, *B, *C, *D; if (match(Op0, m_And(m_Value(A), m_Value(C))) && match(Op1, m_And(m_Value(B), m_Value(D)))) { diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -357,6 +357,13 @@ Instruction *foldIntrinsicWithOverflowCommon(IntrinsicInst *II); Instruction *foldFPSignBitOps(BinaryOperator &I); + // Optimize one of these forms: + // and i1 Op, SI / select i1 Op, i1 SI, i1 false (if IsAnd = true) + // or i1 Op, SI / select i1 Op, i1 true, i1 SI (if IsAnd = false) + // into simplier select instruction using isImpliedCondition. + Instruction *foldAndOrOfSelectUsingImpliedCond(Value *Op, SelectInst &SI, + bool IsAnd); + public: /// Inserts an instruction \p New before instruction \p Old /// diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2586,6 +2586,48 @@ return nullptr; } +Instruction *InstCombinerImpl::foldAndOrOfSelectUsingImpliedCond(Value *Op, + SelectInst &SI, + bool IsAnd) { + Value *CondVal = SI.getCondition(); + Value *A = SI.getTrueValue(); + Value *B = SI.getFalseValue(); + + assert(Op->getType()->isIntOrIntVectorTy(1) && + "Op must be either i1 or vector of i1."); + + Optional Res = isImpliedCondition(Op, CondVal, DL, IsAnd); + if (!Res) + return nullptr; + + Value *Zero = Constant::getNullValue(A->getType()); + Value *One = Constant::getAllOnesValue(A->getType()); + + if (*Res == true) { + if (IsAnd) + // select op, (select cond, A, B), false => select op, A, false + // and op, (select cond, A, B) => select op, A, false + // if op = true implies condval = true. + return SelectInst::Create(Op, A, Zero); + else + // select op, true, (select cond, A, B) => select op, true, A + // or op, (select cond, A, B) => select op, true, A + // if op = false implies condval = true. + return SelectInst::Create(Op, One, A); + } else { + if (IsAnd) + // select op, (select cond, A, B), false => select op, B, false + // and op, (select cond, A, B) => select op, B, false + // if op = true implies condval = false. + return SelectInst::Create(Op, B, Zero); + else + // select op, true, (select cond, A, B) => select op, true, B + // or op, (select cond, A, B) => select op, true, B + // if op = false implies condval = false. + return SelectInst::Create(Op, One, B); + } +} + Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); @@ -2709,6 +2751,11 @@ replaceUse(*Y, FI); return replaceInstUsesWith(SI, Op1); } + + if (auto *Op1SI = dyn_cast(Op1)) + if (auto *I = foldAndOrOfSelectUsingImpliedCond(CondVal, *Op1SI, + /* IsAnd */ IsAnd)) + return I; } // select (select a, true, b), c, false -> select a, c, false diff --git a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll --- a/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll +++ b/llvm/test/Transforms/InstCombine/select-safe-bool-transforms.ll @@ -49,9 +49,7 @@ ; (A land B) lor A define i1 @land_lor_left1(i1 %A, i1 %B) { ; CHECK-LABEL: @land_lor_left1( -; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false -; CHECK-NEXT: [[RES:%.*]] = or i1 [[C]], [[A]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[A:%.*]] ; %c = select i1 %A, i1 %B, i1 false %res = select i1 %c, i1 true, i1 %A @@ -71,9 +69,7 @@ ; (A land B) bor A define i1 @land_bor_left1(i1 %A, i1 %B) { ; CHECK-LABEL: @land_bor_left1( -; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false -; CHECK-NEXT: [[RES:%.*]] = or i1 [[C]], [[A]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[A:%.*]] ; %c = select i1 %A, i1 %B, i1 false %res = or i1 %c, %A @@ -129,9 +125,7 @@ ; (A lor B) land A define i1 @lor_land_left1(i1 %A, i1 %B) { ; CHECK-LABEL: @lor_land_left1( -; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[C]], [[A]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[A:%.*]] ; %c = select i1 %A, i1 true, i1 %B %res = select i1 %c, i1 %A, i1 false @@ -151,9 +145,7 @@ ; (A lor B) band A define i1 @lor_band_left1(i1 %A, i1 %B) { ; CHECK-LABEL: @lor_band_left1( -; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[C]], [[A]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[A:%.*]] ; %c = select i1 %A, i1 true, i1 %B %res = and i1 %c, %A @@ -309,9 +301,7 @@ ; A bor (A land B) define i1 @land_bor_right1(i1 %A, i1 %B) { ; CHECK-LABEL: @land_bor_right1( -; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 [[B:%.*]], i1 false -; CHECK-NEXT: [[RES:%.*]] = or i1 [[C]], [[A]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[A:%.*]] ; %c = select i1 %A, i1 %B, i1 false %res = or i1 %A, %c @@ -385,9 +375,7 @@ ; A band (A lor B) define i1 @lor_band_right1(i1 %A, i1 %B) { ; CHECK-LABEL: @lor_band_right1( -; CHECK-NEXT: [[C:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[B:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[C]], [[A]] -; CHECK-NEXT: ret i1 [[RES]] +; CHECK-NEXT: ret i1 [[A:%.*]] ; %c = select i1 %A, i1 true, i1 %B %res = and i1 %A, %c diff --git a/llvm/test/Transforms/InstCombine/select-safe-impliedcond-transforms.ll b/llvm/test/Transforms/InstCombine/select-safe-impliedcond-transforms.ll --- a/llvm/test/Transforms/InstCombine/select-safe-impliedcond-transforms.ll +++ b/llvm/test/Transforms/InstCombine/select-safe-impliedcond-transforms.ll @@ -4,9 +4,7 @@ define i1 @a_true_implies_b_true(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_true_implies_b_true( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 20 -; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[Z]], 10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[SEL]], i1 false +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[X:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 20 @@ -39,9 +37,7 @@ define i1 @a_true_implies_b_true2(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_true_implies_b_true2( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 20 -; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[Z]], 10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[A]], [[SEL]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[X:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 20 @@ -54,9 +50,7 @@ define i1 @a_true_implies_b_true2_comm(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_true_implies_b_true2_comm( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 20 -; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[Z]], 10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[SEL]], [[A]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[X:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 20 @@ -69,9 +63,7 @@ define i1 @a_true_implies_b_false(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_true_implies_b_false( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 20 -; CHECK-NEXT: [[B:%.*]] = icmp ult i8 [[Z]], 10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[SEL]], i1 false +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[Y:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 20 @@ -84,9 +76,7 @@ define i1 @a_true_implies_b_false2(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_true_implies_b_false2( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 20 -; CHECK-NEXT: [[B:%.*]] = icmp eq i8 [[Z]], 10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[A]], [[SEL]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[Y:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 20 @@ -99,9 +89,7 @@ define i1 @a_true_implies_b_false2_comm(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_true_implies_b_false2_comm( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 20 -; CHECK-NEXT: [[B:%.*]] = icmp eq i8 [[Z]], 10 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = and i1 [[SEL]], [[A]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 [[Y:%.*]], i1 false ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 20 @@ -114,9 +102,7 @@ define i1 @a_false_implies_b_true(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_false_implies_b_true( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 10 -; CHECK-NEXT: [[B:%.*]] = icmp ult i8 [[Z]], 20 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[SEL]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[X:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 10 @@ -129,9 +115,7 @@ define i1 @a_false_implies_b_true2(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_false_implies_b_true2( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 10 -; CHECK-NEXT: [[B:%.*]] = icmp ult i8 [[Z]], 20 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[A]], [[SEL]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[X:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 10 @@ -144,9 +128,7 @@ define i1 @a_false_implies_b_true2_comm(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_false_implies_b_true2_comm( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 10 -; CHECK-NEXT: [[B:%.*]] = icmp ult i8 [[Z]], 20 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[SEL]], [[A]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[X:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 10 @@ -159,9 +141,7 @@ define i1 @a_false_implies_b_false(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_false_implies_b_false( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 10 -; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[Z]], 20 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[SEL]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[Y:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 10 @@ -174,9 +154,7 @@ define i1 @a_false_implies_b_false2(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_false_implies_b_false2( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 10 -; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[Z]], 20 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[A]], [[SEL]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[Y:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 10 @@ -189,9 +167,7 @@ define i1 @a_false_implies_b_false2_comm(i8 %z, i1 %X, i1 %Y) { ; CHECK-LABEL: @a_false_implies_b_false2_comm( ; CHECK-NEXT: [[A:%.*]] = icmp ugt i8 [[Z:%.*]], 10 -; CHECK-NEXT: [[B:%.*]] = icmp ugt i8 [[Z]], 20 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[B]], i1 [[X:%.*]], i1 [[Y:%.*]] -; CHECK-NEXT: [[RES:%.*]] = or i1 [[SEL]], [[A]] +; CHECK-NEXT: [[RES:%.*]] = select i1 [[A]], i1 true, i1 [[Y:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; %a = icmp ugt i8 %z, 10