Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions llvm/lib/Transforms/IPO/Attributor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,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!");
}
Expand Down
81 changes: 50 additions & 31 deletions llvm/lib/Transforms/IPO/AttributorAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9172,44 +9172,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;
}
Expand All @@ -9226,9 +9240,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;
}
}

Expand Down Expand Up @@ -9624,10 +9642,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);
}
Expand Down
8 changes: 3 additions & 5 deletions llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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: {{.*}}
45 changes: 39 additions & 6 deletions llvm/test/Transforms/Attributor/range.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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 nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[A:%.*]] = tail call i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3:[0-9]+]], !range [[RNG0]]
; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3:[0-9]+]]
; TUNIT-NEXT: ret i32 [[A]]
;
; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(argmem: read)
Expand All @@ -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 nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 2, 5) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[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 nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: [[A:%.*]] = tail call range(i32 2, 5) i32 @test0(ptr nofree noundef nonnull readonly align 4 captures(none) 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 nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[A:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[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 nofree noundef nonnull readonly align 4 captures(none) dereferenceable(4) [[P:%.*]]) #[[ATTR1]] {
; CGSCC-NEXT: [[A:%.*]] = tail call range(i32 0, 100) i32 @test0(ptr nofree noundef nonnull readonly align 4 captures(none) 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
Expand All @@ -48,7 +82,7 @@ define void @test0-icmp-check(ptr %p){
; ret = [0, 10)
; TUNIT-LABEL: define {{[^@]+}}@test0-icmp-check
; TUNIT-SAME: (ptr nofree readonly align 4 captures(none) [[P:%.*]]) {
; TUNIT-NEXT: [[RET:%.*]] = tail call i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]], !range [[RNG0]]
; TUNIT-NEXT: [[RET:%.*]] = tail call range(i32 0, 10) i32 @test0(ptr nofree noundef readonly align 4 captures(none) [[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
Expand Down Expand Up @@ -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 nofree readonly align 4 captures(none) [[P:%.*]]) #[[ATTR0]] {
; TUNIT-NEXT: [[RES:%.*]] = tail call i32 @test1(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]], !range [[RNG2:![0-9]+]]
; TUNIT-NEXT: [[RES:%.*]] = tail call range(i32 200, 1091) i32 @test1(ptr nofree noundef readonly align 4 captures(none) [[P]]) #[[ATTR3]]
; TUNIT-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500
; TUNIT-NEXT: ret i1 [[CMP]]
;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) }
Expand All @@ -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}
Expand Down
4 changes: 1 addition & 3 deletions llvm/test/Transforms/Attributor/value-simplify.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,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]]
;
Expand Down Expand Up @@ -1689,8 +1689,6 @@ define i32 @readExtInitZeroInit() {
; 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) }
Expand Down
Loading