[llvm] [Attributor] Swap range metadata to attribute for calls. (PR #108835)
Andreas Jonson via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 16 07:33:57 PDT 2024
https://github.com/andjo403 created https://github.com/llvm/llvm-project/pull/108835
This is the last usage of range metadata for calls that I can find so after this we can deprecate range metadata for calls.
>From 7f519b1657a49e4b1f785f922dbbdeff05ca84fe Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 14 Sep 2024 12:51:56 +0200
Subject: [PATCH] [Attributor] Swap range metadata to attribute for calls.
---
llvm/lib/Transforms/IPO/Attributor.cpp | 7 ++
.../Transforms/IPO/AttributorAttributes.cpp | 81 ++++++++++++-------
.../Attributor/IPConstantProp/PR16052.ll | 8 +-
llvm/test/Transforms/Attributor/range.ll | 45 +++++++++--
.../Transforms/Attributor/value-simplify.ll | 4 +-
5 files changed, 100 insertions(+), 45 deletions(-)
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 56d1133b25549a..76043fcc8984ea 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -989,6 +989,13 @@ static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
AB.addAttribute(Attr);
return true;
}
+ if (Attr.isConstantRangeAttribute()) {
+ Attribute::AttrKind Kind = Attr.getKindAsEnum();
+ if (!ForceReplace && AttrSet.hasAttribute(Kind))
+ return false;
+ AB.addAttribute(Attr);
+ return true;
+ }
llvm_unreachable("Expected enum or string attribute!");
}
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 217c7cccb5775a..f8f0f0074305ea 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -9161,44 +9161,58 @@ struct AAValueConstantRangeImpl : AAValueConstantRange {
return MDNode::get(Ctx, LowAndHigh);
}
- /// Return true if \p Assumed is included in \p KnownRanges.
- static bool isBetterRange(const ConstantRange &Assumed, MDNode *KnownRanges) {
-
+ /// Return true if \p Assumed is included in ranges from instruction \p I.
+ static bool isBetterRange(const ConstantRange &Assumed,
+ const Instruction &I) {
if (Assumed.isFullSet())
return false;
- if (!KnownRanges)
- return true;
-
- // If multiple ranges are annotated in IR, we give up to annotate assumed
- // range for now.
+ std::optional<ConstantRange> Known;
- // TODO: If there exists a known range which containts assumed range, we
- // can say assumed range is better.
- if (KnownRanges->getNumOperands() > 2)
- return false;
+ if (const auto *CB = dyn_cast<CallBase>(&I)) {
+ Known = CB->getRange();
+ } else if (MDNode *KnownRanges = I.getMetadata(LLVMContext::MD_range)) {
+ // If multiple ranges are annotated in IR, we give up to annotate assumed
+ // range for now.
+
+ // TODO: If there exists a known range which containts assumed range, we
+ // can say assumed range is better.
+ if (KnownRanges->getNumOperands() > 2)
+ return false;
- ConstantInt *Lower =
- mdconst::extract<ConstantInt>(KnownRanges->getOperand(0));
- ConstantInt *Upper =
- mdconst::extract<ConstantInt>(KnownRanges->getOperand(1));
+ ConstantInt *Lower =
+ mdconst::extract<ConstantInt>(KnownRanges->getOperand(0));
+ ConstantInt *Upper =
+ mdconst::extract<ConstantInt>(KnownRanges->getOperand(1));
- ConstantRange Known(Lower->getValue(), Upper->getValue());
- return Known.contains(Assumed) && Known != Assumed;
+ Known.emplace(Lower->getValue(), Upper->getValue());
+ }
+ return !Known || (*Known != Assumed && Known->contains(Assumed));
}
/// Helper function to set range metadata.
static bool
setRangeMetadataIfisBetterRange(Instruction *I,
const ConstantRange &AssumedConstantRange) {
- auto *OldRangeMD = I->getMetadata(LLVMContext::MD_range);
- if (isBetterRange(AssumedConstantRange, OldRangeMD)) {
- if (!AssumedConstantRange.isEmptySet()) {
- I->setMetadata(LLVMContext::MD_range,
- getMDNodeForConstantRange(I->getType(), I->getContext(),
- AssumedConstantRange));
- return true;
- }
+ if (isBetterRange(AssumedConstantRange, *I)) {
+ I->setMetadata(LLVMContext::MD_range,
+ getMDNodeForConstantRange(I->getType(), I->getContext(),
+ AssumedConstantRange));
+ return true;
+ }
+ return false;
+ }
+ /// Helper function to set range return attribute.
+ static bool
+ setRangeRetAttrIfisBetterRange(Attributor &A, const IRPosition &IRP,
+ Instruction *I,
+ const ConstantRange &AssumedConstantRange) {
+ if (isBetterRange(AssumedConstantRange, *I)) {
+ A.manifestAttrs(IRP,
+ Attribute::get(I->getContext(), Attribute::Range,
+ AssumedConstantRange),
+ /*ForceReplace*/ true);
+ return true;
}
return false;
}
@@ -9215,9 +9229,13 @@ struct AAValueConstantRangeImpl : AAValueConstantRange {
if (Instruction *I = dyn_cast<Instruction>(&V)) {
assert(I == getCtxI() && "Should not annotate an instruction which is "
"not the context instruction");
- if (isa<CallInst>(I) || isa<LoadInst>(I))
+ if (isa<LoadInst>(I))
if (setRangeMetadataIfisBetterRange(I, AssumedConstantRange))
Changed = ChangeStatus::CHANGED;
+ if (isa<CallInst>(I))
+ if (setRangeRetAttrIfisBetterRange(A, getIRPosition(), I,
+ AssumedConstantRange))
+ Changed = ChangeStatus::CHANGED;
}
}
@@ -9613,10 +9631,11 @@ struct AAValueConstantRangeCallSiteReturned
/// See AbstractAttribute::initialize(...).
void initialize(Attributor &A) override {
- // If it is a load instruction with range metadata, use the metadata.
- if (CallInst *CI = dyn_cast<CallInst>(&getAssociatedValue()))
- if (auto *RangeMD = CI->getMetadata(LLVMContext::MD_range))
- intersectKnown(getConstantRangeFromMetadata(*RangeMD));
+ // If it is a call instruction with range attribute, use the range.
+ if (CallInst *CI = dyn_cast<CallInst>(&getAssociatedValue())) {
+ if (std::optional<ConstantRange> Range = CI->getRange())
+ intersectKnown(*Range);
+ }
AAValueConstantRangeImpl::initialize(A);
}
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
index b0446479dac4ba..6641fdb9b4ffeb 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
@@ -68,7 +68,7 @@ define i64 @fn2c() {
; CGSCC-NEXT: entry:
; CGSCC-NEXT: [[CONV:%.*]] = sext i32 undef to i64
; CGSCC-NEXT: [[ADD:%.*]] = add i64 42, [[CONV]]
-; CGSCC-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 [[ADD]]) #[[ATTR2]], !range [[RNG0:![0-9]+]]
+; CGSCC-NEXT: [[CALL2:%.*]] = call range(i64 -2147483606, 2147483690) i64 @fn1(i64 [[ADD]]) #[[ATTR2]]
; CGSCC-NEXT: ret i64 [[CALL2]]
;
entry:
@@ -91,13 +91,11 @@ entry:
ret i64 %cond
}
;.
+; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
+;.
; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR2]] = { nofree nosync willreturn }
;.
-; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
-;.
-; CGSCC: [[RNG0]] = !{i64 -2147483606, i64 2147483690}
-;.
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}
diff --git a/llvm/test/Transforms/Attributor/range.ll b/llvm/test/Transforms/Attributor/range.ll
index 48040fec772dc0..455de49c9e72b8 100644
--- a/llvm/test/Transforms/Attributor/range.ll
+++ b/llvm/test/Transforms/Attributor/range.ll
@@ -19,7 +19,7 @@ define i32 @test0-range-check(ptr %p) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@test0-range-check
; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) #[[ATTR0]] {
-; TUNIT-NEXT: [[A:%.*]] = tail call i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3:[0-9]+]], !range [[RNG0]]
+; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3:[0-9]+]]
; TUNIT-NEXT: ret i32 [[A]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
@@ -32,6 +32,40 @@ define i32 @test0-range-check(ptr %p) {
ret i32 %a
}
+define i32 @test0-range-check-smaller-current-range-attr(ptr %p) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; TUNIT-LABEL: define {{[^@]+}}@test0-range-check-smaller-current-range-attr
+; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) #[[ATTR0]] {
+; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 2, 5) i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]]
+; TUNIT-NEXT: ret i32 [[A]]
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
+; CGSCC-LABEL: define {{[^@]+}}@test0-range-check-smaller-current-range-attr
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT: [[A:%.*]] = tail call range(i32 2, 5) i32 @test0(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P]]) #[[ATTR5]]
+; CGSCC-NEXT: ret i32 [[A]]
+;
+ %a = tail call range(i32 2, 5) i32 @test0(ptr %p)
+ ret i32 %a
+}
+
+define i32 @test0-range-check-larger-current-range-attr(ptr %p) {
+; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
+; TUNIT-LABEL: define {{[^@]+}}@test0-range-check-larger-current-range-attr
+; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) #[[ATTR0]] {
+; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]]
+; TUNIT-NEXT: ret i32 [[A]]
+;
+; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
+; CGSCC-LABEL: define {{[^@]+}}@test0-range-check-larger-current-range-attr
+; CGSCC-SAME: (ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
+; CGSCC-NEXT: [[A:%.*]] = tail call range(i32 0, 100) i32 @test0(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[P]]) #[[ATTR5]]
+; CGSCC-NEXT: ret i32 [[A]]
+;
+ %a = tail call range(i32 0, 100) i32 @test0(ptr %p)
+ ret i32 %a
+}
+
declare void @use3-dummy(i1, i1, i1)
define void @use3(i1, i1, i1) {
; CHECK-LABEL: define {{[^@]+}}@use3
@@ -48,7 +82,7 @@ define void @test0-icmp-check(ptr %p){
; ret = [0, 10)
; TUNIT-LABEL: define {{[^@]+}}@test0-icmp-check
; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) {
-; TUNIT-NEXT: [[RET:%.*]] = tail call i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]]
+; TUNIT-NEXT: [[RET:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]]
; TUNIT-NEXT: [[CMP_EQ_1:%.*]] = icmp eq i32 [[RET]], 10
; TUNIT-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9
; TUNIT-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8
@@ -284,7 +318,7 @@ define i1 @test1-check(ptr %p) {
; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read)
; TUNIT-LABEL: define {{[^@]+}}@test1-check
; TUNIT-SAME: (ptr nocapture nofree readonly align 4 [[P:%.*]]) #[[ATTR0]] {
-; TUNIT-NEXT: [[RES:%.*]] = tail call i32 @test1(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]], !range [[RNG2:![0-9]+]]
+; TUNIT-NEXT: [[RES:%.*]] = tail call range(i32 200, 1091) i32 @test1(ptr nocapture nofree noundef readonly align 4 [[P]]) #[[ATTR3]]
; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; TUNIT-NEXT: ret i1 [[CMP]]
;
@@ -624,7 +658,7 @@ define dso_local i32 @test4-g2(i32 %u) {
; TUNIT-LABEL: define {{[^@]+}}@test4-g2
; TUNIT-SAME: (i32 [[U:%.*]]) #[[ATTR1]] {
; TUNIT-NEXT: entry:
-; TUNIT-NEXT: [[CALL:%.*]] = tail call i32 @test4-f2(i32 [[U]]) #[[ATTR4]], !range [[RNG3:![0-9]+]]
+; TUNIT-NEXT: [[CALL:%.*]] = tail call range(i32 1, -2147483648) i32 @test4-f2(i32 [[U]]) #[[ATTR4]]
; TUNIT-NEXT: ret i32 [[CALL]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none)
@@ -1760,6 +1794,7 @@ declare void @barney(i32 signext, i32 signext)
!0 = !{i32 0, i32 10}
!1 = !{i32 10, i32 100}
+!2 = !{i32 2, i32 5}
;.
; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) }
; TUNIT: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
@@ -1778,8 +1813,6 @@ declare void @barney(i32 signext, i32 signext)
;.
; TUNIT: [[RNG0]] = !{i32 0, i32 10}
; TUNIT: [[RNG1]] = !{i32 10, i32 100}
-; TUNIT: [[RNG2]] = !{i32 200, i32 1091}
-; TUNIT: [[RNG3]] = !{i32 1, i32 -2147483648}
;.
; CGSCC: [[RNG0]] = !{i32 0, i32 10}
; CGSCC: [[RNG1]] = !{i32 10, i32 100}
diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll
index 68f179c88116e4..d7edff382df84f 100644
--- a/llvm/test/Transforms/Attributor/value-simplify.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify.ll
@@ -1113,7 +1113,7 @@ define i32 @test(i1 %c) {
; TUNIT-LABEL: define {{[^@]+}}@test
; TUNIT-SAME: (i1 [[C:%.*]]) {
; TUNIT-NEXT: [[R1:%.*]] = call i32 @ctx_test1(i1 noundef [[C]])
-; TUNIT-NEXT: [[R2:%.*]] = call i32 @ctx_test2(i1 noundef [[C]]), !range [[RNG0:![0-9]+]]
+; TUNIT-NEXT: [[R2:%.*]] = call range(i32 0, -2147483648) i32 @ctx_test2(i1 noundef [[C]])
; TUNIT-NEXT: [[ADD:%.*]] = add i32 [[R1]], [[R2]]
; TUNIT-NEXT: ret i32 [[ADD]]
;
@@ -1671,8 +1671,6 @@ define i32 @readWeakOdrConst() {
; TUNIT: attributes #[[ATTR15]] = { nosync nounwind memory(read) }
; TUNIT: attributes #[[ATTR16]] = { nounwind memory(write) }
;.
-; TUNIT: [[RNG0]] = !{i32 0, i32 -2147483648}
-;.
; CGSCC: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
; CGSCC: attributes #[[ATTR2]] = { memory(readwrite, argmem: none) }
More information about the llvm-commits
mailing list