Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -317,20 +317,13 @@ Value *FalseVal, InstCombiner::BuilderTy *Builder) { const ICmpInst *IC = dyn_cast(SI.getCondition()); - if (!IC || !IC->isEquality() || !SI.getType()->isIntegerTy()) + if (!IC || !SI.getType()->isIntegerTy()) return nullptr; Value *CmpLHS = IC->getOperand(0); Value *CmpRHS = IC->getOperand(1); - if (!match(CmpRHS, m_Zero())) - return nullptr; - - Value *X; - const APInt *C1; - if (!match(CmpLHS, m_And(m_Value(X), m_Power2(C1)))) - return nullptr; - + // Check if the select uses a value and Or with the same value. const APInt *C2; bool OrOnTrueVal = false; bool OrOnFalseVal = match(FalseVal, m_Or(m_Specific(TrueVal), m_Power2(C2))); @@ -340,10 +333,42 @@ if (!OrOnFalseVal && !OrOnTrueVal) return nullptr; - Value *V = CmpLHS; + Value *V; + unsigned C1Log; + bool IsEqualZero; + if (IC->isEquality()) { + if (!match(CmpRHS, m_Zero())) + return nullptr; + + Value *X; + const APInt *C1; + if (!match(CmpLHS, m_And(m_Value(X), m_Power2(C1)))) + return nullptr; + C1Log = C1->logBase2(); + V = CmpLHS; + IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_EQ; + } else if (IC->getPredicate() == ICmpInst::ICMP_SLT || + IC->getPredicate() == ICmpInst::ICMP_SGT) { + // We also need to recognize (icmp slt (trunc (X)), 0) and + // (icmp sgt (trunc (X)), -1). + IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_SGT; + if ((IsEqualZero && !match(CmpRHS, m_AllOnes())) || + (!IsEqualZero && !match(CmpRHS, m_Zero()))) + return nullptr; + + Value *X; + if (!match(CmpLHS, m_OneUse(m_Trunc(m_Value(X))))) + return nullptr; + + C1Log = CmpLHS->getType()->getScalarSizeInBits() - 1; + // Insert the and instruction. + V = Builder->CreateAnd(X, ConstantInt::get(X->getType(), APInt::getOneBitSet(X->getType()->getScalarSizeInBits(), C1Log))); + } else { + return nullptr; + } + Value *Y = OrOnFalseVal ? TrueVal : FalseVal; - unsigned C1Log = C1->logBase2(); unsigned C2Log = C2->logBase2(); if (C2Log > C1Log) { V = Builder->CreateZExtOrTrunc(V, Y->getType()); @@ -354,9 +379,7 @@ } else V = Builder->CreateZExtOrTrunc(V, Y->getType()); - ICmpInst::Predicate Pred = IC->getPredicate(); - if ((Pred == ICmpInst::ICMP_NE && OrOnFalseVal) || - (Pred == ICmpInst::ICMP_EQ && OrOnTrueVal)) + if ((!IsEqualZero && OrOnFalseVal) || (IsEqualZero && OrOnTrueVal)) V = Builder->CreateXor(V, *C2); return Builder->CreateOr(V, Y); Index: test/Transforms/InstCombine/select-with-bitwise-ops.ll =================================================================== --- test/Transforms/InstCombine/select-with-bitwise-ops.ll +++ test/Transforms/InstCombine/select-with-bitwise-ops.ll @@ -299,11 +299,10 @@ define i32 @test68(i32 %x, i32 %y) { ; CHECK-LABEL: @test68( -; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]] -; CHECK-NEXT: ret i32 [[SELECT]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP3]] ; %and = and i32 %x, 128 %cmp = icmp eq i32 %and, 0 @@ -314,11 +313,11 @@ define i32 @test69(i32 %x, i32 %y) { ; CHECK-LABEL: @test69( -; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i8 -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 0 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[OR]] -; CHECK-NEXT: ret i32 [[SELECT]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], 2 +; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP3]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[TMP4]] ; %and = and i32 %x, 128 %cmp = icmp ne i32 %and, 0