Index: lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineSelect.cpp +++ lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -602,16 +602,39 @@ if (SelType->isVectorTy() != IC->getType()->isVectorTy()) return nullptr; - if (!IC->isEquality()) - return nullptr; + Value *V; + unsigned AndZeros; + bool IsEqualZero; + bool CreateAnd = false; + if (IC->isEquality()) { + if (!match(IC->getOperand(1), m_Zero())) + return nullptr; - if (!match(IC->getOperand(1), m_Zero())) - return nullptr; + V = IC->getOperand(0); + + const APInt *AndRHS; + if (!match(V, m_And(m_Value(), m_Power2(AndRHS)))) + return nullptr; + + AndZeros = AndRHS->logBase2(); + 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(IC->getOperand(1), m_AllOnes())) || + (!IsEqualZero && !match(IC->getOperand(1), m_Zero()))) + return nullptr; + + if (!match(IC->getOperand(0), m_OneUse(m_Trunc(m_Value(V))))) + return nullptr; - const APInt *AndRHS; - Value *LHS = IC->getOperand(0); - if (!match(LHS, m_And(m_Value(), m_Power2(AndRHS)))) + AndZeros = IC->getOperand(0)->getType()->getScalarSizeInBits() - 1; + CreateAnd = true; + } else { return nullptr; + } // If both select arms are non-zero see if we have a select of the form // 'x ? 2^n + C : C'. Then we can offset both arms by C, use the logic @@ -638,11 +661,16 @@ // desired result. const APInt &ValC = !TrueVal.isNullValue() ? TrueVal : FalseVal; unsigned ValZeros = ValC.logBase2(); - unsigned AndZeros = AndRHS->logBase2(); + + if (CreateAnd) { + // Insert the AND instruction on the input to the truncate. + APInt C1 = APInt::getOneBitSet(V->getType()->getScalarSizeInBits(), + AndZeros); + V = Builder.CreateAnd(V, ConstantInt::get(V->getType(), C1)); + } // If types don't match we can still convert the select by introducing a zext // or a trunc of the 'and'. - Value *V = LHS; if (ValZeros > AndZeros) { V = Builder.CreateZExtOrTrunc(V, SelType); V = Builder.CreateShl(V, ValZeros - AndZeros); @@ -654,9 +682,7 @@ // Okay, now we know that everything is set up, we just don't know whether we // have a icmp_ne or icmp_eq and whether the true or false val is the zero. - bool ShouldNotVal = !TrueVal.isNullValue(); - ShouldNotVal ^= IC->getPredicate() == ICmpInst::ICMP_NE; - if (ShouldNotVal) + if (IsEqualZero != TrueVal.isNullValue()) V = Builder.CreateXor(V, ValC); // Apply an offset if needed. 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 @@ -384,6 +384,59 @@ ret i32 %select } +define i32 @test70(i32 %x) { +; CHECK-LABEL: @test70( +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], 42 +; CHECK-NEXT: ret i32 [[TMP3]] +; + %1 = and i32 %x, 128 + %2 = icmp ne i32 %1, 0 + %3 = select i1 %2, i32 40, i32 42 + ret i32 %3 +} + +define <2 x i32> @test70vec(<2 x i32> %x) { +; CHECK-LABEL: @test70vec( +; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], +; CHECK-NEXT: [[TMP3:%.*]] = or <2 x i32> [[TMP2]], +; CHECK-NEXT: [[TMP4:%.*]] = xor <2 x i32> [[TMP3]], +; CHECK-NEXT: ret <2 x i32> [[TMP4]] +; + %1 = and <2 x i32> %x, + %2 = icmp ne <2 x i32> %1, + %3 = select <2 x i1> %2, <2 x i32> , <2 x i32> + ret <2 x i32> %3 +} + +define i32 @test71(i32 %x) { +; CHECK-LABEL: @test71( +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], 40 +; CHECK-NEXT: ret i32 [[TMP3]] +; + %1 = and i32 %x, 128 + %2 = icmp eq i32 %1, 0 + %3 = select i1 %2, i32 40, i32 42 + ret i32 %3 +} + +define <2 x i32> @test71vec(<2 x i32> %x) { +; CHECK-LABEL: @test71vec( +; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i32> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], +; CHECK-NEXT: [[TMP3:%.*]] = or <2 x i32> [[TMP2]], +; CHECK-NEXT: ret <2 x i32> [[TMP3]] +; + %1 = and <2 x i32> %x, + %2 = icmp eq <2 x i32> %1, + %3 = select <2 x i1> %2, <2 x i32> , <2 x i32> + ret <2 x i32> %3 +} + define i32 @shift_no_xor_multiuse_or(i32 %x, i32 %y) { ; CHECK-LABEL: @shift_no_xor_multiuse_or( ; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], 2