Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -404,34 +404,47 @@ /// Z may be 0 if lshr is missing. /// Worst case scenario is that we will replace 5 instructions with 5 different /// instructions, but we got rid of select. +/// Caveat: the first and instruction operands are commutative, +/// so it can be one of *) and X, Y *) and Y, X static Instruction *foldSelectICmpAndAnd(Type *SelType, const ICmpInst *IC, Value *TrueVal, Value *FalseVal, InstCombiner::BuilderTy &Builder) { if (!(IC->hasOneUse() && IC->getOperand(0)->hasOneUse())) return nullptr; - Value *X, *Y; + // It would be very simple, but if the mask (Y) is not a constant, those + // two variables could be in any order in the instruction. + Value *A, *B; ICmpInst::Predicate EqPred; - if (!(match(IC, m_ICmp(EqPred, m_And(m_Value(X), m_Value(Y)), m_Zero())) && + if (!(match(IC, m_ICmp(EqPred, m_And(m_Value(A), m_Value(B)), m_Zero())) && ICmpInst::Predicate::ICMP_EQ == EqPred && match(FalseVal, m_One()))) return nullptr; // The TrueVal has general form of: - // and %B, 1 - Value *B; - if (!match(TrueVal, m_OneUse(m_And(m_Value(B), m_One())))) + // and %W, 1 + Value *W; + if (!match(TrueVal, m_OneUse(m_And(m_Value(W), m_One())))) return nullptr; - // Where %B can be one of: + // Where %W can be one of: // %X // or // lshr %X, %Z // Where %Z may or may not be a constant. - Value *MaskB, *Z; - if (match(B, m_Specific(X))) { - MaskB = ConstantInt::get(SelType, 1); - } else if (match(B, m_OneUse(m_LShr(m_Specific(X), m_Value(Z))))) { + Value *X, *MaskB, *Z; + if (match(W, m_OneUse(m_LShr(m_Value(X), m_Value(Z))))) { MaskB = Builder.CreateShl(ConstantInt::get(SelType, 1), Z); + } else if (match(W, m_Value(X))) { + MaskB = ConstantInt::get(SelType, 1); + } else + return nullptr; + + // And now, 'pick' Y. + Value *Y; + if (match(X, m_Specific(A))) { + Y = B; + } else if (match(X, m_Specific(B))) { + Y = A; } else return nullptr; Index: test/Transforms/InstCombine/select-of-bittest.ll =================================================================== --- test/Transforms/InstCombine/select-of-bittest.ll +++ test/Transforms/InstCombine/select-of-bittest.ll @@ -177,11 +177,10 @@ ; Should be exactly as the previous one define i32 @f_var0_commutative_and(i32 %arg, i32 %arg1) { ; CHECK-LABEL: @f_var0_commutative_and( -; CHECK-NEXT: [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP]], 0 -; CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[ARG]], 1 -; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP3]], 1 -; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP2]], i32 [[TMP4]], i32 1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 +; CHECK-NEXT: [[TMP5:%.*]] = zext i1 [[TMP3]] to i32 ; CHECK-NEXT: ret i32 [[TMP5]] ; %tmp = and i32 %arg1, %arg ; in different order @@ -259,10 +258,10 @@ ; Should be exactly as the previous one define i32 @f_var1_commutative_and(i32 %arg, i32 %arg1) { ; CHECK-LABEL: @f_var1_commutative_and( -; CHECK-NEXT: [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP]], 0 -; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[ARG]], 1 -; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 +; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i32 ; CHECK-NEXT: ret i32 [[TMP4]] ; %tmp = and i32 %arg1, %arg ; in different order @@ -398,11 +397,11 @@ ; Should be exactly as the previous one define i32 @f_var3_commutative_and(i32 %arg, i32 %arg1, i32 %arg2) { ; CHECK-LABEL: @f_var3_commutative_and( -; CHECK-NEXT: [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]] -; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP]], 0 -; CHECK-NEXT: [[TMP4:%.*]] = lshr i32 [[ARG]], [[ARG2:%.*]] -; CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 1 -; CHECK-NEXT: [[TMP6:%.*]] = select i1 [[TMP3]], i32 [[TMP5]], i32 1 +; CHECK-NEXT: [[TMP1:%.*]] = shl i32 1, [[ARG2:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[ARG1:%.*]] +; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[ARG:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0 +; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP4]] to i32 ; CHECK-NEXT: ret i32 [[TMP6]] ; %tmp = and i32 %arg1, %arg ; in different order