Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -5059,12 +5059,12 @@ in ``op2``. If the ``nuw`` keyword is present, then the shift produces a :ref:`poison -value ` if it shifts out any non-zero bits. If the -``nsw`` keyword is present, then the shift produces a :ref:`poison -value ` if it shifts out any bits that disagree with the -resultant sign bit. As such, NUW/NSW have the same semantics as they -would if the shift were expressed as a mul instruction with the same -nsw/nuw bits in (mul %op1, (shl 1, %op2)). +value ` if and only if ``op1`` \* ``1 << op2`` results in unsigned +overflow. + +If the ``nsw`` keyword is present, then the shift produces a :ref:`poison +value ` if and only if ``op1`` \* ``1 << op2`` results in signed +overflow. Example: """""""" @@ -5075,6 +5075,8 @@ = shl i32 4, 2 ; yields i32: 16 = shl i32 1, 10 ; yields i32: 1024 = shl i32 1, 32 ; undefined + = shl nsw i32 1, 31 ; yields i32: -2147483648 + = shl nsw i32 2, 30 ; poison = shl <2 x i32> < i32 1, i32 1>, < i32 1, i32 2> ; yields: result=<2 x i32> < i32 2, i32 4> '``lshr``' Instruction Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -2296,14 +2296,27 @@ Lower = CI2->getValue(); Upper = Lower.shl(Lower.countLeadingZeros()) + 1; } else if (match(LHS, m_NSWShl(m_ConstantInt(CI2), m_Value()))) { + assert(Width > 1 && "i1 should've been handled earlier!"); if (CI2->isNegative()) { - // 'shl nsw CI2, x' produces [CI2 << CLO(CI2)-1, CI2] - unsigned ShiftAmount = CI2->getValue().countLeadingOnes() - 1; + unsigned ShiftAmount; + if (CI2->isMinusOne()) { + // 'shl nsw -1, x' produces [-1 << (Width-2), -1] + ShiftAmount = Width - 2; + } else { + // 'shl nsw CI2, x' produces [CI2 << CLO(CI2)-1, CI2] + ShiftAmount = CI2->getValue().countLeadingOnes() - 1; + } Lower = CI2->getValue().shl(ShiftAmount); Upper = CI2->getValue() + 1; } else { - // 'shl nsw CI2, x' produces [CI2, CI2 << CLZ(CI2)-1] - unsigned ShiftAmount = CI2->getValue().countLeadingZeros() - 1; + unsigned ShiftAmount; + if (CI2->isOne()) { + // 'shl nsw 1, x' produces [1, 1 << (Width-1)] + ShiftAmount = Width - 1; + } else { + // 'shl nsw CI2, x' produces [CI2, CI2 << CLZ(CI2)-1] + ShiftAmount = CI2->getValue().countLeadingZeros() - 1; + } Lower = CI2->getValue(); Upper = CI2->getValue().shl(ShiftAmount) + 1; } Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -200,8 +200,7 @@ BinaryOperator *BO = BinaryOperator::CreateMul(NewOp, Shl); if (I.hasNoUnsignedWrap() && Mul->hasNoUnsignedWrap()) BO->setHasNoUnsignedWrap(); - if (I.hasNoSignedWrap() && Mul->hasNoSignedWrap() && - Shl->isNotMinSignedValue()) + if (I.hasNoSignedWrap() && Mul->hasNoSignedWrap()) BO->setHasNoSignedWrap(); return BO; } @@ -221,7 +220,7 @@ if (I.hasNoUnsignedWrap()) Shl->setHasNoUnsignedWrap(); - if (I.hasNoSignedWrap() && NewCst->isNotMinSignedValue()) + if (I.hasNoSignedWrap()) Shl->setHasNoSignedWrap(); return Shl; Index: test/Transforms/InstCombine/2011-06-13-nsw-alloca.ll =================================================================== --- test/Transforms/InstCombine/2011-06-13-nsw-alloca.ll +++ test/Transforms/InstCombine/2011-06-13-nsw-alloca.ll @@ -15,7 +15,7 @@ ;