diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 831ff2f09b1..a1b5b462b77 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -1328,6 +1328,32 @@ static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1, return nullptr; } +/// \brief Given operands for an Shl, LShr or AShr, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyRightShift(unsigned Opcode, Value *Op0, Value *Op1, + bool isExact, const Query &Q, + unsigned MaxRecurse) { + if (Value *V = SimplifyShift(Opcode, Op0, Op1, Q, MaxRecurse)) + return V; + + // X >> X -> 0 + if (Op0 == Op1) + return Constant::getNullValue(Op0->getType()); + + // The low bit cannot be shifted out of an exact shift if it is set. + if (isExact) { + unsigned BitWidth = Op0->getType()->getScalarSizeInBits(); + APInt Op0KnownZero(BitWidth, 0); + APInt Op0KnownOne(BitWidth, 0); + computeKnownBits(Op0, Op0KnownZero, Op0KnownOne, Q.DL, /*Depth=*/0, Q.AT, Q.CxtI, + Q.DT); + if (Op0KnownOne[0]) + return Op0; + } + + return nullptr; +} + /// SimplifyShlInst - Given operands for an Shl, see if we can /// fold the result. If not, this returns null. static Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, @@ -1358,12 +1384,9 @@ Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, /// fold the result. If not, this returns null. static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, const Query &Q, unsigned MaxRecurse) { - if (Value *V = SimplifyShift(Instruction::LShr, Op0, Op1, Q, MaxRecurse)) - return V; - - // X >> X -> 0 - if (Op0 == Op1) - return Constant::getNullValue(Op0->getType()); + if (Value *V = SimplifyRightShift(Instruction::LShr, Op0, Op1, isExact, Q, + MaxRecurse)) + return V; // undef >>l X -> 0 if (match(Op0, m_Undef())) @@ -1391,13 +1414,10 @@ Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, /// fold the result. If not, this returns null. static Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, const Query &Q, unsigned MaxRecurse) { - if (Value *V = SimplifyShift(Instruction::AShr, Op0, Op1, Q, MaxRecurse)) + if (Value *V = SimplifyRightShift(Instruction::AShr, Op0, Op1, isExact, Q, + MaxRecurse)) return V; - // X >> X -> 0 - if (Op0 == Op1) - return Constant::getNullValue(Op0->getType()); - // all ones >>a X -> all ones if (match(Op0, m_AllOnes())) return Op0; diff --git a/test/Transforms/InstSimplify/shr-nop.ll b/test/Transforms/InstSimplify/shr-nop.ll index 86917ad8fba..b0dc8731a11 100644 --- a/test/Transforms/InstSimplify/shr-nop.ll +++ b/test/Transforms/InstSimplify/shr-nop.ll @@ -330,3 +330,17 @@ define i1 @exact_lshr_ne_noexactlog(i8 %a) { %cmp = icmp ne i8 %shr, 30 ret i1 %cmp } + +; CHECK-LABEL: @exact_lshr_lowbit +; CHECK-NEXT: ret i32 7 +define i32 @exact_lshr_lowbit(i32 %shiftval) { + %shr = lshr exact i32 7, %shiftval + ret i32 %shr +} + +; CHECK-LABEL: @exact_ashr_lowbit +; CHECK-NEXT: ret i32 7 +define i32 @exact_ashr_lowbit(i32 %shiftval) { + %shr = ashr exact i32 7, %shiftval + ret i32 %shr +}