Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -3422,6 +3422,64 @@ return ::SimplifyFCmpInst(Predicate, LHS, RHS, FMF, Q, RecursionLimit); } +static bool +IsSafeOverflowingBinaryOperator(const OverflowingBinaryOperator *OBO, + const SimplifyQuery &Q) { + const Instruction *I = dyn_cast_or_null(OBO); + if (!I) + return false; + if (I->getOpcode() != Instruction::Shl) + // TODO: Perhaps we can handle other instructions too + return false; + + Value *Op0 = I->getOperand(0), *Op1 = I->getOperand(1); + + const APInt *ShAmtAPInt; + if (!match(Op1, m_APInt(ShAmtAPInt))) + return false; + + unsigned ShAmt = ShAmtAPInt->getZExtValue(); + unsigned BitWidth = I->getType()->getScalarSizeInBits(); + + if (I->hasNoUnsignedWrap() && + !MaskedValueIsZero(Op0, APInt::getHighBitsSet(BitWidth, ShAmt), Q.DL, 0, + Q.AC, I, Q.DT)) + return false; + + if (I->hasNoSignedWrap() && + ComputeNumSignBits(Op0, Q.DL, 0, Q.AC, I, Q.DT) <= ShAmt) + return false; + + return true; +} + +static bool IsSafePossiblyExactOperator(const PossiblyExactOperator *PEO, + const SimplifyQuery &Q) { + const Instruction *I = dyn_cast_or_null(PEO); + if (!I) + return false; + if (I->getOpcode() != Instruction::LShr && + I->getOpcode() != Instruction::AShr) + // TODO: Perhaps we can handle other instructions too + return false; + + Value *Op0 = I->getOperand(0), *Op1 = I->getOperand(1); + + const APInt *ShAmtAPInt; + if (!match(Op1, m_APInt(ShAmtAPInt))) + return false; + + unsigned ShAmt = ShAmtAPInt->getZExtValue(); + unsigned BitWidth = I->getType()->getScalarSizeInBits(); + + if (I->isExact() && + !MaskedValueIsZero(Op0, APInt::getLowBitsSet(BitWidth, ShAmt), Q.DL, 0, + Q.AC, I, Q.DT)) + return false; + + return true; +} + /// See if V simplifies when its operand Op is replaced with RepOp. static const Value *SimplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp, const SimplifyQuery &Q, @@ -3446,11 +3504,11 @@ // %sel = select i1 %cmp, i32 -2147483648, i32 %add // // We can't replace %sel with %add unless we strip away the flags. - if (isa(B)) - if (B->hasNoSignedWrap() || B->hasNoUnsignedWrap()) + if (OverflowingBinaryOperator *OBO = dyn_cast(B)) + if (!IsSafeOverflowingBinaryOperator(OBO, Q)) return nullptr; - if (isa(B)) - if (B->isExact()) + if (PossiblyExactOperator *PEO = dyn_cast(B)) + if (!IsSafePossiblyExactOperator(PEO, Q)) return nullptr; if (MaxRecurse) { @@ -3475,6 +3533,17 @@ } } + if (CastInst *C = dyn_cast(I)) { + if (MaxRecurse) { + const Value *CastInstWithReplacement = SimplifyWithOpReplaced( + I->getOperand(0), Op, RepOp, Q, MaxRecurse - 1); + if (const Constant *Const = + dyn_cast_or_null(CastInstWithReplacement)) + return ConstantExpr::getCast( + C->getOpcode(), const_cast(Const), C->getType()); + } + } + // TODO: We could hand off more cases to instsimplify here. // If all operands are constant after substituting Op for RepOp then we can Index: test/Transforms/InstCombine/select-bitext-bitwise-ops.ll =================================================================== --- test/Transforms/InstCombine/select-bitext-bitwise-ops.ll +++ test/Transforms/InstCombine/select-bitext-bitwise-ops.ll @@ -2,13 +2,11 @@ define i64 @sel_false_val_is_a_masked_shl_of_true_val1(i32 %x, i64 %y) { ; CHECK-LABEL: @sel_false_val_is_a_masked_shl_of_true_val1( -; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 15 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 15 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 2 ; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP1]], 0 -; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i64 0, i64 [[TMP3]] -; CHECK-NEXT: [[TMP6:%.*]] = ashr i64 %y, [[TMP5]] -; CHECK-NEXT: ret i64 [[TMP6]] +; CHECK-NEXT: [[TMP4:%.*]] = ashr i64 %y, [[TMP3]] +; CHECK-NEXT: ret i64 [[TMP4]] ; %1 = and i32 %x, 15 %2 = shl nuw nsw i32 %1, 2 @@ -24,10 +22,8 @@ ; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 15 ; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[TMP1]], 2 ; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP1]], 0 -; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i64 0, i64 [[TMP3]] -; CHECK-NEXT: [[TMP6:%.*]] = ashr i64 %y, [[TMP5]] -; CHECK-NEXT: ret i64 [[TMP6]] +; CHECK-NEXT: [[TMP4:%.*]] = ashr i64 %y, [[TMP3]] +; CHECK-NEXT: ret i64 [[TMP4]] ; %1 = and i32 %x, 15 %2 = shl nuw nsw i32 %1, 2 @@ -40,13 +36,11 @@ define i64 @sel_false_val_is_a_masked_lshr_of_true_val1(i32 %x, i64 %y) { ; CHECK-LABEL: @sel_false_val_is_a_masked_lshr_of_true_val1( -; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, 60 -; CHECK-NEXT: [[TMP2:%.*]] = lshr exact i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 %x, 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 15 ; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP1]], 0 -; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i64 0, i64 [[TMP3]] -; CHECK-NEXT: [[TMP6:%.*]] = ashr i64 %y, [[TMP5]] -; CHECK-NEXT: ret i64 [[TMP6]] +; CHECK-NEXT: [[TMP4:%.*]] = ashr i64 %y, [[TMP3]] +; CHECK-NEXT: ret i64 [[TMP4]] ; %1 = and i32 %x, 60 %2 = lshr i32 %1, 2 @@ -76,13 +70,11 @@ define i64 @sel_false_val_is_a_masked_ashr_of_true_val1(i32 %x, i64 %y) { ; CHECK-LABEL: @sel_false_val_is_a_masked_ashr_of_true_val1( -; CHECK-NEXT: [[TMP1:%.*]] = and i32 %x, -2147483588 -; CHECK-NEXT: [[TMP2:%.*]] = ashr exact i32 [[TMP1]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 %x, 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], -536870897 ; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP1]], 0 -; CHECK-NEXT: [[TMP5:%.*]] = select i1 [[TMP4]], i64 0, i64 [[TMP3]] -; CHECK-NEXT: [[TMP6:%.*]] = ashr i64 %y, [[TMP5]] -; CHECK-NEXT: ret i64 [[TMP6]] +; CHECK-NEXT: [[TMP4:%.*]] = ashr i64 %y, [[TMP3]] +; CHECK-NEXT: ret i64 [[TMP4]] ; %1 = and i32 %x, -2147483588 %2 = ashr i32 %1, 2