Skip to content
46 changes: 46 additions & 0 deletions llvm/lib/Analysis/DemandedBits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdint>
Expand Down Expand Up @@ -183,6 +184,17 @@ void DemandedBits::determineLiveOperandBits(
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt+1);
else if (S->hasNoUnsignedWrap())
AB |= APInt::getHighBitsSet(BitWidth, ShiftAmt);
} else {
ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr);
unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
// similar to Lshr case
AB = (AOut.lshr(Min) | AOut.lshr(Max));
const auto *S = cast<ShlOperator>(UserI);
if (S->hasNoSignedWrap())
AB |= APInt::getHighBitsSet(BitWidth, Max + 1);
else if (S->hasNoUnsignedWrap())
AB |= APInt::getHighBitsSet(BitWidth, Max);
}
}
break;
Expand All @@ -197,6 +209,19 @@ void DemandedBits::determineLiveOperandBits(
// (they must be zero).
if (cast<LShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
} else {
ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr);
unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
// Suppose AOut == 0b0000 0011
// [min, max] = [1, 3]
// shift by 1 we get 0b0000 0110
// shift by 2 we get 0b0000 1100
// shift by 3 we get 0b0001 1000
// we take the or here because need to cover all the above possibilities
AB = (AOut.shl(Min) | AOut.shl(Max));
if (cast<LShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, Max);
}
}
break;
Expand All @@ -217,6 +242,27 @@ void DemandedBits::determineLiveOperandBits(
// (they must be zero).
if (cast<AShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, ShiftAmt);
} else {
ComputeKnownBits(BitWidth, UserI->getOperand(1), nullptr);
unsigned Min = Known.getMinValue().getLimitedValue(BitWidth - 1);
unsigned Max = Known.getMaxValue().getLimitedValue(BitWidth - 1);
AB = (AOut.shl(Min) | AOut.shl(Max));

if (Max) {
// Suppose AOut = 0011 1100
// [min, max] = [1, 3]
// ShiftAmount = 1 : Mask is 1000 0000
// ShiftAmount = 2 : Mask is 1100 0000
// ShiftAmount = 3 : Mask is 1110 0000
// The Mask with Max covers every case in [min, max],
// so we are done
if ((AOut & APInt::getHighBitsSet(BitWidth, Max)).getBoolValue())
AB.setSignBit();
}
// If the shift is exact, then the low bits are not dead
// (they must be zero).
if (cast<AShrOperator>(UserI)->isExact())
AB |= APInt::getLowBitsSet(BitWidth, Max);
}
}
break;
Expand Down
48 changes: 47 additions & 1 deletion llvm/test/Analysis/DemandedBits/shl.ll
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,56 @@ define i8 @test_shl(i32 %a, i32 %b) {
; CHECK-DAG: DemandedBits: 0xff for %shl.t = trunc i32 %shl to i8
; CHECK-DAG: DemandedBits: 0xff for %shl in %shl.t = trunc i32 %shl to i8
; CHECK-DAG: DemandedBits: 0xff for %shl = shl i32 %a, %b
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %shl = shl i32 %a, %b
; CHECK-DAG: DemandedBits: 0xff for %a in %shl = shl i32 %a, %b
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %shl = shl i32 %a, %b
;
%shl = shl i32 %a, %b
%shl.t = trunc i32 %shl to i8
ret i8 %shl.t
}

define i8 @test_shl_var_amount(i32 %a, i32 %b){
; CHECK-LABEL: 'test_shl_var_amount'
; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
; CHECK-DAG: DemandedBits: 0xff for %4 = shl i32 %1, %3
; CHECK-DAG: DemandedBits: 0xff for %1 in %4 = shl i32 %1, %3
; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = shl i32 %1, %3
; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
; CHECK-DAG: DemandedBits: 0xff for %1 = add nsw i32 %a, %b
; CHECK-DAG: DemandedBits: 0xff for %a in %1 = add nsw i32 %a, %b
; CHECK-DAG: DemandedBits: 0xff for %b in %1 = add nsw i32 %a, %b
;
%1 = add nsw i32 %a, %b
%2 = trunc i32 %1 to i8
%3 = zext i8 %2 to i32
%4 = shl i32 %1, %3
%5 = trunc i32 %4 to i8
ret i8 %5
}

define i8 @test_shl_var_amount_nsw(i32 %a, i32 %b){
; CHECK-LABEL 'test_shl_var_amount_nsw'
; CHECK-DAG: DemandedBits: 0xff for %5 = trunc i32 %4 to i8
; CHECK-DAG: DemandedBits: 0xff for %4 in %5 = trunc i32 %4 to i8
; CHECK-DAG: DemandedBits: 0xff for %4 = shl nsw i32 %1, %3
; CHECK-DAG: DemandedBits: 0xffffffff for %1 in %4 = shl nsw i32 %1, %3
; CHECK-DAG: DemandedBits: 0xffffffff for %3 in %4 = shl nsw i32 %1, %3
; CHECK-DAG: DemandedBits: 0xffffffff for %3 = zext i8 %2 to i32
; CHECK-DAG: DemandedBits: 0xff for %2 in %3 = zext i8 %2 to i32
; CHECK-DAG: DemandedBits: 0xff for %2 = trunc i32 %1 to i8
; CHECK-DAG: DemandedBits: 0xff for %1 in %2 = trunc i32 %1 to i8
; CHECK-DAG: DemandedBits: 0xffffffff for %1 = add nsw i32 %a, %b
; CHECK-DAG: DemandedBits: 0xffffffff for %a in %1 = add nsw i32 %a, %b
; CHECK-DAG: DemandedBits: 0xffffffff for %b in %1 = add nsw i32 %a, %b
;
%1 = add nsw i32 %a, %b
%2 = trunc i32 %1 to i8
%3 = zext i8 %2 to i32
%4 = shl nsw i32 %1, %3
%5 = trunc i32 %4 to i8
ret i8 %5
}
Loading