Skip to content

Commit 0a067dc

Browse files
authored
[Attributor] Swap range metadata to attribute for calls. (#108835)
1 parent 9d994d1 commit 0a067dc

File tree

5 files changed

+100
-45
lines changed

5 files changed

+100
-45
lines changed

llvm/lib/Transforms/IPO/Attributor.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,13 @@ static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
990990
AB.addAttribute(Attr);
991991
return true;
992992
}
993+
if (Attr.isConstantRangeAttribute()) {
994+
Attribute::AttrKind Kind = Attr.getKindAsEnum();
995+
if (!ForceReplace && AttrSet.hasAttribute(Kind))
996+
return false;
997+
AB.addAttribute(Attr);
998+
return true;
999+
}
9931000

9941001
llvm_unreachable("Expected enum or string attribute!");
9951002
}

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9172,44 +9172,58 @@ struct AAValueConstantRangeImpl : AAValueConstantRange {
91729172
return MDNode::get(Ctx, LowAndHigh);
91739173
}
91749174

9175-
/// Return true if \p Assumed is included in \p KnownRanges.
9176-
static bool isBetterRange(const ConstantRange &Assumed, MDNode *KnownRanges) {
9177-
9175+
/// Return true if \p Assumed is included in ranges from instruction \p I.
9176+
static bool isBetterRange(const ConstantRange &Assumed,
9177+
const Instruction &I) {
91789178
if (Assumed.isFullSet())
91799179
return false;
91809180

9181-
if (!KnownRanges)
9182-
return true;
9183-
9184-
// If multiple ranges are annotated in IR, we give up to annotate assumed
9185-
// range for now.
9181+
std::optional<ConstantRange> Known;
91869182

9187-
// TODO: If there exists a known range which containts assumed range, we
9188-
// can say assumed range is better.
9189-
if (KnownRanges->getNumOperands() > 2)
9190-
return false;
9183+
if (const auto *CB = dyn_cast<CallBase>(&I)) {
9184+
Known = CB->getRange();
9185+
} else if (MDNode *KnownRanges = I.getMetadata(LLVMContext::MD_range)) {
9186+
// If multiple ranges are annotated in IR, we give up to annotate assumed
9187+
// range for now.
9188+
9189+
// TODO: If there exists a known range which containts assumed range, we
9190+
// can say assumed range is better.
9191+
if (KnownRanges->getNumOperands() > 2)
9192+
return false;
91919193

9192-
ConstantInt *Lower =
9193-
mdconst::extract<ConstantInt>(KnownRanges->getOperand(0));
9194-
ConstantInt *Upper =
9195-
mdconst::extract<ConstantInt>(KnownRanges->getOperand(1));
9194+
ConstantInt *Lower =
9195+
mdconst::extract<ConstantInt>(KnownRanges->getOperand(0));
9196+
ConstantInt *Upper =
9197+
mdconst::extract<ConstantInt>(KnownRanges->getOperand(1));
91969198

9197-
ConstantRange Known(Lower->getValue(), Upper->getValue());
9198-
return Known.contains(Assumed) && Known != Assumed;
9199+
Known.emplace(Lower->getValue(), Upper->getValue());
9200+
}
9201+
return !Known || (*Known != Assumed && Known->contains(Assumed));
91999202
}
92009203

92019204
/// Helper function to set range metadata.
92029205
static bool
92039206
setRangeMetadataIfisBetterRange(Instruction *I,
92049207
const ConstantRange &AssumedConstantRange) {
9205-
auto *OldRangeMD = I->getMetadata(LLVMContext::MD_range);
9206-
if (isBetterRange(AssumedConstantRange, OldRangeMD)) {
9207-
if (!AssumedConstantRange.isEmptySet()) {
9208-
I->setMetadata(LLVMContext::MD_range,
9209-
getMDNodeForConstantRange(I->getType(), I->getContext(),
9210-
AssumedConstantRange));
9211-
return true;
9212-
}
9208+
if (isBetterRange(AssumedConstantRange, *I)) {
9209+
I->setMetadata(LLVMContext::MD_range,
9210+
getMDNodeForConstantRange(I->getType(), I->getContext(),
9211+
AssumedConstantRange));
9212+
return true;
9213+
}
9214+
return false;
9215+
}
9216+
/// Helper function to set range return attribute.
9217+
static bool
9218+
setRangeRetAttrIfisBetterRange(Attributor &A, const IRPosition &IRP,
9219+
Instruction *I,
9220+
const ConstantRange &AssumedConstantRange) {
9221+
if (isBetterRange(AssumedConstantRange, *I)) {
9222+
A.manifestAttrs(IRP,
9223+
Attribute::get(I->getContext(), Attribute::Range,
9224+
AssumedConstantRange),
9225+
/*ForceReplace*/ true);
9226+
return true;
92139227
}
92149228
return false;
92159229
}
@@ -9226,9 +9240,13 @@ struct AAValueConstantRangeImpl : AAValueConstantRange {
92269240
if (Instruction *I = dyn_cast<Instruction>(&V)) {
92279241
assert(I == getCtxI() && "Should not annotate an instruction which is "
92289242
"not the context instruction");
9229-
if (isa<CallInst>(I) || isa<LoadInst>(I))
9243+
if (isa<LoadInst>(I))
92309244
if (setRangeMetadataIfisBetterRange(I, AssumedConstantRange))
92319245
Changed = ChangeStatus::CHANGED;
9246+
if (isa<CallInst>(I))
9247+
if (setRangeRetAttrIfisBetterRange(A, getIRPosition(), I,
9248+
AssumedConstantRange))
9249+
Changed = ChangeStatus::CHANGED;
92329250
}
92339251
}
92349252

@@ -9624,10 +9642,11 @@ struct AAValueConstantRangeCallSiteReturned
96249642

96259643
/// See AbstractAttribute::initialize(...).
96269644
void initialize(Attributor &A) override {
9627-
// If it is a load instruction with range metadata, use the metadata.
9628-
if (CallInst *CI = dyn_cast<CallInst>(&getAssociatedValue()))
9629-
if (auto *RangeMD = CI->getMetadata(LLVMContext::MD_range))
9630-
intersectKnown(getConstantRangeFromMetadata(*RangeMD));
9645+
// If it is a call instruction with range attribute, use the range.
9646+
if (CallInst *CI = dyn_cast<CallInst>(&getAssociatedValue())) {
9647+
if (std::optional<ConstantRange> Range = CI->getRange())
9648+
intersectKnown(*Range);
9649+
}
96319650

96329651
AAValueConstantRangeImpl::initialize(A);
96339652
}

llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ define i64 @fn2c() {
6868
; CGSCC-NEXT: entry:
6969
; CGSCC-NEXT: [[CONV:%.*]] = sext i32 undef to i64
7070
; CGSCC-NEXT: [[ADD:%.*]] = add i64 42, [[CONV]]
71-
; CGSCC-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[ADD]]) #[[ATTR2]], !range [[RNG0:![0-9]+]]
71+
; CGSCC-NEXT: [[CALL2:%.*]] = call range(i64 -2147483606, 2147483690) i64 @fn1(i64 [[ADD]]) #[[ATTR2]]
7272
; CGSCC-NEXT: ret i64 [[CALL2]]
7373
;
7474
entry:
@@ -91,13 +91,11 @@ entry:
9191
ret i64 %cond
9292
}
9393
;.
94+
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
95+
;.
9496
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
9597
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
9698
; CGSCC: attributes #[[ATTR2]] = { nofree nosync willreturn }
9799
;.
98-
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
99-
;.
100-
; CGSCC: [[RNG0]] = !{i64 -2147483606, i64 2147483690}
101-
;.
102100
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
103101
; CHECK: {{.*}}

llvm/test/Transforms/Attributor/range.ll

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ define i32 @test0-range-check(ptr %p) {
1919
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
2020
; TUNIT-LABEL: define {{[^@]+}}@test0-range-check
2121
; TUNIT-SAME: (ptr nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
22-
; TUNIT-NEXT: [[A:%.*]] = tail call i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3:[0-9]+]], !range [[RNG0]]
22+
; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3:[0-9]+]]
2323
; TUNIT-NEXT: ret i32 [[A]]
2424
;
2525
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
@@ -32,6 +32,40 @@ define i32 @test0-range-check(ptr %p) {
3232
ret i32 %a
3333
}
3434

35+
define i32 @test0-range-check-smaller-current-range-attr(ptr %p) {
36+
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
37+
; TUNIT-LABEL: define {{[^@]+}}@test0-range-check-smaller-current-range-attr
38+
; TUNIT-SAME: (ptr nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
39+
; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 2, 5) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]]
40+
; TUNIT-NEXT: ret i32 [[A]]
41+
;
42+
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
43+
; CGSCC-LABEL: define {{[^@]+}}@test0-range-check-smaller-current-range-attr
44+
; CGSCC-SAME: (ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
45+
; CGSCC-NEXT: [[A:%.*]] = tail call range(i32 2, 5) i32 @test0(ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[P]]) #[[ATTR5]]
46+
; CGSCC-NEXT: ret i32 [[A]]
47+
;
48+
%a = tail call range(i32 2, 5) i32 @test0(ptr %p)
49+
ret i32 %a
50+
}
51+
52+
define i32 @test0-range-check-larger-current-range-attr(ptr %p) {
53+
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
54+
; TUNIT-LABEL: define {{[^@]+}}@test0-range-check-larger-current-range-attr
55+
; TUNIT-SAME: (ptr nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
56+
; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]]
57+
; TUNIT-NEXT: ret i32 [[A]]
58+
;
59+
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
60+
; CGSCC-LABEL: define {{[^@]+}}@test0-range-check-larger-current-range-attr
61+
; CGSCC-SAME: (ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
62+
; CGSCC-NEXT: [[A:%.*]] = tail call range(i32 0, 100) i32 @test0(ptr nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[P]]) #[[ATTR5]]
63+
; CGSCC-NEXT: ret i32 [[A]]
64+
;
65+
%a = tail call range(i32 0, 100) i32 @test0(ptr %p)
66+
ret i32 %a
67+
}
68+
3569
declare void @use3-dummy(i1, i1, i1)
3670
define void @use3(i1, i1, i1) {
3771
; CHECK-LABEL: define {{[^@]+}}@use3
@@ -48,7 +82,7 @@ define void @test0-icmp-check(ptr %p){
4882
; ret = [0, 10)
4983
; TUNIT-LABEL: define {{[^@]+}}@test0-icmp-check
5084
; TUNIT-SAME: (ptr nofree readonly align 4 captures(none) [[P:%.*]]) {
51-
; TUNIT-NEXT: [[RET:%.*]] = tail call i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]], !range [[RNG0]]
85+
; TUNIT-NEXT: [[RET:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]]
5286
; TUNIT-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
5387
; TUNIT-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
5488
; TUNIT-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
@@ -284,7 +318,7 @@ define i1 @test1-check(ptr %p) {
284318
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
285319
; TUNIT-LABEL: define {{[^@]+}}@test1-check
286320
; TUNIT-SAME: (ptr nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
287-
; TUNIT-NEXT: [[RES:%.*]] = tail call i32 @test1(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]], !range [[RNG2:![0-9]+]]
321+
; TUNIT-NEXT: [[RES:%.*]] = tail call range(i32 200, 1091) i32 @test1(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]]
288322
; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
289323
; TUNIT-NEXT: ret i1 [[CMP]]
290324
;
@@ -624,7 +658,7 @@ define dso_local i32 @test4-g2(i32 %u) {
624658
; TUNIT-LABEL: define {{[^@]+}}@test4-g2
625659
; TUNIT-SAME: (i32 [[U:%.*]]) #[[ATTR1]] {
626660
; TUNIT-NEXT: entry:
627-
; TUNIT-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) #[[ATTR4]], !range [[RNG3:![0-9]+]]
661+
; TUNIT-NEXT: [[CALL:%.*]] = tail call range(i32 1, -2147483648) i32 @test4-f2(i32 [[U]]) #[[ATTR4]]
628662
; TUNIT-NEXT: ret i32 [[CALL]]
629663
;
630664
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
@@ -1760,6 +1794,7 @@ declare void @barney(i32 signext, i32 signext)
17601794

17611795
!0 = !{i32 0, i32 10}
17621796
!1 = !{i32 10, i32 100}
1797+
!2 = !{i32 2, i32 5}
17631798
;.
17641799
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
17651800
; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
@@ -1778,8 +1813,6 @@ declare void @barney(i32 signext, i32 signext)
17781813
;.
17791814
; TUNIT: [[RNG0]] = !{i32 0, i32 10}
17801815
; TUNIT: [[RNG1]] = !{i32 10, i32 100}
1781-
; TUNIT: [[RNG2]] = !{i32 200, i32 1091}
1782-
; TUNIT: [[RNG3]] = !{i32 1, i32 -2147483648}
17831816
;.
17841817
; CGSCC: [[RNG0]] = !{i32 0, i32 10}
17851818
; CGSCC: [[RNG1]] = !{i32 10, i32 100}

llvm/test/Transforms/Attributor/value-simplify.ll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,7 @@ define i32 @test(i1 %c) {
11141114
; TUNIT-LABEL: define {{[^@]+}}@test
11151115
; TUNIT-SAME: (i1 [[C:%.*]]) {
11161116
; TUNIT-NEXT: [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
1117-
; TUNIT-NEXT: [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]]), !range [[RNG0:![0-9]+]]
1117+
; TUNIT-NEXT: [[R2:%.*]] = call range(i32 0, -2147483648) i32 @ctx_test2(i1 noundef [[C]])
11181118
; TUNIT-NEXT: [[ADD:%.*]] = add i32 [[R1]], [[R2]]
11191119
; TUNIT-NEXT: ret i32 [[ADD]]
11201120
;
@@ -1689,8 +1689,6 @@ define i32 @readExtInitZeroInit() {
16891689
; TUNIT: attributes #[[ATTR15]] = { nosync nounwind memory(read) }
16901690
; TUNIT: attributes #[[ATTR16]] = { nounwind memory(write) }
16911691
;.
1692-
; TUNIT: [[RNG0]] = !{i32 0, i32 -2147483648}
1693-
;.
16941692
; CGSCC: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
16951693
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
16961694
; CGSCC: attributes #[[ATTR2]] = { memory(readwrite, argmem: none) }

0 commit comments

Comments
 (0)