Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -1020,13 +1020,22 @@ } case Instruction::Shl: { // (shl X, C1) & C2 == 0 iff (X & C2 >>u C1) == 0 - auto KZF = [BitWidth](const APInt &KnownZero, unsigned ShiftAmt) { - return (KnownZero << ShiftAmt) | + bool NSW = cast(I)->hasNoSignedWrap(); + auto KZF = [BitWidth, NSW](const APInt &KnownZero, unsigned ShiftAmt) { + APInt KZResult = (KnownZero << ShiftAmt) | APInt::getLowBitsSet(BitWidth, ShiftAmt); // Low bits known 0. + // If this shift has "nsw" keyword, then the result is either a poison + // value or has the same sign bit as the first operand. + if (NSW && KnownZero.isNegative()) + KZResult.setBit(BitWidth - 1); + return KZResult; }; - auto KOF = [BitWidth](const APInt &KnownOne, unsigned ShiftAmt) { - return KnownOne << ShiftAmt; + auto KOF = [BitWidth, NSW](const APInt &KnownOne, unsigned ShiftAmt) { + APInt KOResult = KnownOne << ShiftAmt; + if (NSW && KnownOne.isNegative()) + KOResult.setBit(BitWidth - 1); + return KOResult; }; computeKnownBitsFromShiftOperator(I, KnownZero, KnownOne, Index: test/Analysis/ValueTracking/known-signbit-shift.ll =================================================================== --- test/Analysis/ValueTracking/known-signbit-shift.ll +++ test/Analysis/ValueTracking/known-signbit-shift.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +; Result of left shifting a non-negative integer +; with nsw flag should also be non-negative +define i1 @test_shift_nonnegative(i32 %a) { +; CHECK-LABEL: @test_shift_nonnegative( +; CHECK: ret i1 true + %b = lshr i32 %a, 2 + %shift = shl nsw i32 %b, 3 + %cmp = icmp sge i32 %shift, 0 + ret i1 %cmp +} + +; Result of left shifting a negative integer with +; nsw flag should also be negative +define i1 @test_shift_negative(i32 %a, i32 %b) { +; CHECK-LABEL: @test_shift_negative( +; CHECK: ret i1 true + %c = or i32 %a, -2147483648 + %d = and i32 %b, 7 + %shift = shl nsw i32 %c, %d + %cmp = icmp slt i32 %shift, 0 + ret i1 %cmp +}