Skip to content

Commit fbe39e3

Browse files
committed
[ValueTracking] Handle range attributes
1 parent 3e6d566 commit fbe39e3

File tree

2 files changed

+180
-3
lines changed

2 files changed

+180
-3
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,14 +1467,21 @@ static void computeKnownBitsFromOperator(const Operator *I,
14671467
break;
14681468
}
14691469
case Instruction::Call:
1470-
case Instruction::Invoke:
1470+
case Instruction::Invoke: {
14711471
// If range metadata is attached to this call, set known bits from that,
14721472
// and then intersect with known bits based on other properties of the
14731473
// function.
14741474
if (MDNode *MD =
14751475
Q.IIQ.getMetadata(cast<Instruction>(I), LLVMContext::MD_range))
14761476
computeKnownBitsFromRangeMetadata(*MD, Known);
1477-
if (const Value *RV = cast<CallBase>(I)->getReturnedArgOperand()) {
1477+
1478+
const CallBase *CB = cast<CallBase>(I);
1479+
1480+
const Attribute RangeAttr = CB->getRetAttr(llvm::Attribute::Range);
1481+
if (RangeAttr.isValid())
1482+
Known = RangeAttr.getRange().toKnownBits();
1483+
1484+
if (const Value *RV = CB->getReturnedArgOperand()) {
14781485
if (RV->getType() == I->getType()) {
14791486
computeKnownBits(RV, Known2, Depth + 1, Q);
14801487
Known = Known.unionWith(Known2);
@@ -1646,6 +1653,7 @@ static void computeKnownBitsFromOperator(const Operator *I,
16461653
}
16471654
}
16481655
break;
1656+
}
16491657
case Instruction::ShuffleVector: {
16501658
auto *Shuf = dyn_cast<ShuffleVectorInst>(I);
16511659
// FIXME: Do we need to handle ConstantExpr involving shufflevectors?
@@ -1900,6 +1908,12 @@ void computeKnownBits(const Value *V, const APInt &DemandedElts,
19001908
// assumptions. Confirm that we've handled them all.
19011909
assert(!isa<ConstantData>(V) && "Unhandled constant data!");
19021910

1911+
if (const Argument *A = dyn_cast<Argument>(V)) {
1912+
Attribute Range = A->getAttribute(llvm::Attribute::Range);
1913+
if (Range.isValid())
1914+
Known = Range.getRange().toKnownBits();
1915+
}
1916+
19031917
// All recursive calls that increase depth must come after this.
19041918
if (Depth == MaxAnalysisRecursionDepth)
19051919
return;
@@ -2893,6 +2907,20 @@ bool isKnownNonZero(const Value *V, const APInt &DemandedElts, unsigned Depth,
28932907
}
28942908
}
28952909

2910+
Attribute RangeAttr;
2911+
if (const CallBase *CB = dyn_cast<CallBase>(V))
2912+
RangeAttr = CB->getRetAttr(llvm::Attribute::Range);
2913+
2914+
if (const Argument *A = dyn_cast<Argument>(V))
2915+
RangeAttr = A->getAttribute(llvm::Attribute::Range);
2916+
2917+
if (RangeAttr.isValid()) {
2918+
const ConstantRange Range = RangeAttr.getRange();
2919+
const APInt ZeroValue(Range.getBitWidth(), 0);
2920+
if (!Range.contains(ZeroValue))
2921+
return true;
2922+
}
2923+
28962924
if (!isa<Constant>(V) && isKnownNonZeroFromAssume(V, Q))
28972925
return true;
28982926

@@ -9114,12 +9142,24 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
91149142
// TODO: Return ConstantRange.
91159143
setLimitForFPToI(cast<Instruction>(V), Lower, Upper);
91169144
CR = ConstantRange::getNonEmpty(Lower, Upper);
9145+
} else if (const Argument *A = dyn_cast<Argument>(V)) {
9146+
const Attribute RangeAttr = A->getAttribute(llvm::Attribute::Range);
9147+
if (RangeAttr.isValid()) {
9148+
CR = RangeAttr.getRange();
9149+
}
91179150
}
91189151

9119-
if (auto *I = dyn_cast<Instruction>(V))
9152+
if (auto *I = dyn_cast<Instruction>(V)) {
91209153
if (auto *Range = IIQ.getMetadata(I, LLVMContext::MD_range))
91219154
CR = CR.intersectWith(getConstantRangeFromMetadata(*Range));
91229155

9156+
if (const CallBase *CB = dyn_cast<CallBase>(V)) {
9157+
const Attribute RangeAttr = CB->getRetAttr(llvm::Attribute::Range);
9158+
if (RangeAttr.isValid())
9159+
CR = CR.intersectWith(RangeAttr.getRange());
9160+
}
9161+
}
9162+
91239163
if (CtxI && AC) {
91249164
// Try to restrict the range based on information from assumptions.
91259165
for (auto &AssumeVH : AC->assumptionsFor(V)) {

llvm/unittests/Analysis/ValueTrackingTest.cpp

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2085,6 +2085,76 @@ TEST_F(ValueTrackingTest, KnownNonZeroFromDomCond2) {
20852085
EXPECT_EQ(isKnownNonZero(A, DL, 0, &AC, CxtI2, &DT), false);
20862086
}
20872087

2088+
TEST_F(ValueTrackingTest, KnownNonZeroFromRangeAttributeArgument) {
2089+
parseAssembly(R"(
2090+
define i8 @test(i8 range(i8 1, 5) %q) {
2091+
%A = bitcast i8 %q to i8
2092+
ret i8 %A
2093+
}
2094+
)");
2095+
const DataLayout &DL = M->getDataLayout();
2096+
EXPECT_TRUE(isKnownNonZero(A, DL, 0));
2097+
}
2098+
2099+
TEST_F(ValueTrackingTest, PossibleZeroFromRangeAttributeArgument) {
2100+
parseAssembly(R"(
2101+
define i8 @test(i8 range(i8 0, 5) %q) {
2102+
%A = bitcast i8 %q to i8
2103+
ret i8 %A
2104+
}
2105+
)");
2106+
const DataLayout &DL = M->getDataLayout();
2107+
EXPECT_FALSE(isKnownNonZero(A, DL, 0));
2108+
}
2109+
2110+
TEST_F(ValueTrackingTest, KnownNonZeroFromCallRangeAttribute) {
2111+
parseAssembly(R"(
2112+
declare i8 @f()
2113+
define i8 @test() {
2114+
%A = call range(i8 1, 5) i8 @f()
2115+
ret i8 %A
2116+
}
2117+
)");
2118+
const DataLayout &DL = M->getDataLayout();
2119+
EXPECT_TRUE(isKnownNonZero(A, DL, 0));
2120+
}
2121+
2122+
TEST_F(ValueTrackingTest, PossibleZeroFromCallRangeAttribute) {
2123+
parseAssembly(R"(
2124+
declare i8 @f()
2125+
define i8 @test() {
2126+
%A = call range(i8 0, 5) i8 @f()
2127+
ret i8 %A
2128+
}
2129+
)");
2130+
const DataLayout &DL = M->getDataLayout();
2131+
EXPECT_FALSE(isKnownNonZero(A, DL, 0));
2132+
}
2133+
2134+
TEST_F(ValueTrackingTest, KnownNonZeroFromRangeAttributeResult) {
2135+
parseAssembly(R"(
2136+
declare range(i8 1, 5) i8 @f()
2137+
define i8 @test() {
2138+
%A = call i8 @f()
2139+
ret i8 %A
2140+
}
2141+
)");
2142+
const DataLayout &DL = M->getDataLayout();
2143+
EXPECT_TRUE(isKnownNonZero(A, DL, 0));
2144+
}
2145+
2146+
TEST_F(ValueTrackingTest, PossibleZeroFromRangeAttributeResult) {
2147+
parseAssembly(R"(
2148+
declare range(i8 0, 5) i8 @f()
2149+
define i8 @test() {
2150+
%A = call i8 @f()
2151+
ret i8 %A
2152+
}
2153+
)");
2154+
const DataLayout &DL = M->getDataLayout();
2155+
EXPECT_FALSE(isKnownNonZero(A, DL, 0));
2156+
}
2157+
20882158
TEST_F(ValueTrackingTest, IsImpliedConditionAnd) {
20892159
parseAssembly(R"(
20902160
define void @test(i32 %x, i32 %y) {
@@ -2601,6 +2671,38 @@ TEST_F(ComputeKnownBitsTest, ComputeKnownBitsAbsoluteSymbol) {
26012671
EXPECT_EQ(0u, Known_0_256_Align8.countMinTrailingOnes());
26022672
}
26032673

2674+
TEST_F(ComputeKnownBitsTest, KnownBitsFromRangeAttributeArgument) {
2675+
parseAssembly(R"(
2676+
define i8 @test(i8 range(i8 80, 84) %q) {
2677+
%A = bitcast i8 %q to i8
2678+
ret i8 %A
2679+
}
2680+
)");
2681+
expectKnownBits(/*zero*/ 172u, /*one*/ 80u);
2682+
}
2683+
2684+
TEST_F(ComputeKnownBitsTest, KnownBitsFromCallRangeAttribute) {
2685+
parseAssembly(R"(
2686+
declare i8 @f()
2687+
define i8 @test() {
2688+
%A = call range(i8 80, 84) i8 @f()
2689+
ret i8 %A
2690+
}
2691+
)");
2692+
expectKnownBits(/*zero*/ 172u, /*one*/ 80u);
2693+
}
2694+
2695+
TEST_F(ComputeKnownBitsTest, KnownBitsFromRangeAttributeResult) {
2696+
parseAssembly(R"(
2697+
declare range(i8 80, 84) i8 @f()
2698+
define i8 @test() {
2699+
%A = call i8 @f()
2700+
ret i8 %A
2701+
}
2702+
)");
2703+
expectKnownBits(/*zero*/ 172u, /*one*/ 80u);
2704+
}
2705+
26042706
TEST_F(ValueTrackingTest, HaveNoCommonBitsSet) {
26052707
{
26062708
// Check for an inverted mask: (X & ~M) op (Y & M).
@@ -3125,6 +3227,41 @@ TEST_F(ValueTrackingTest, ComputeConstantRange) {
31253227
}
31263228
}
31273229

3230+
TEST_F(ValueTrackingTest, ComputeConstantRangeFromRangeAttributeArgument) {
3231+
parseAssembly(R"(
3232+
define i8 @test(i8 range(i8 32, 36) %q) {
3233+
%A = bitcast i8 %q to i8
3234+
ret i8 %A
3235+
}
3236+
)");
3237+
EXPECT_EQ(computeConstantRange(F->arg_begin(), false),
3238+
ConstantRange(APInt(8, 32), APInt(8, 36)));
3239+
}
3240+
3241+
TEST_F(ValueTrackingTest, ComputeConstantRangeFromCallRangeAttribute) {
3242+
parseAssembly(R"(
3243+
declare i8 @f()
3244+
define i8 @test() {
3245+
%A = call range(i8 32, 36) i8 @f()
3246+
ret i8 %A
3247+
}
3248+
)");
3249+
EXPECT_EQ(computeConstantRange(A, false),
3250+
ConstantRange(APInt(8, 32), APInt(8, 36)));
3251+
}
3252+
3253+
TEST_F(ValueTrackingTest, ComputeConstantRangeFromRangeAttributeResult) {
3254+
parseAssembly(R"(
3255+
declare range(i8 32, 36) i8 @f()
3256+
define i8 @test() {
3257+
%A = call i8 @f()
3258+
ret i8 %A
3259+
}
3260+
)");
3261+
EXPECT_EQ(computeConstantRange(A, false),
3262+
ConstantRange(APInt(8, 32), APInt(8, 36)));
3263+
}
3264+
31283265
struct FindAllocaForValueTestParams {
31293266
const char *IR;
31303267
bool AnyOffsetResult;

0 commit comments

Comments
 (0)