[llvm] e7bc537 - [IPSCCP] Add range attribute handling (#86747)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 11 02:43:02 PDT 2024
Author: Andreas Jonson
Date: 2024-04-11T18:42:59+09:00
New Revision: e7bc53726459bba3a48b1f529f1fd9472ad9051c
URL: https://github.com/llvm/llvm-project/commit/e7bc53726459bba3a48b1f529f1fd9472ad9051c
DIFF: https://github.com/llvm/llvm-project/commit/e7bc53726459bba3a48b1f529f1fd9472ad9051c.diff
LOG: [IPSCCP] Add range attribute handling (#86747)
Support the new range attribute to infer ConstantRanges in IPSCCP.
Added:
llvm/test/Transforms/SCCP/range-attribute.ll
Modified:
llvm/include/llvm/Transforms/Utils/SCCPSolver.h
llvm/lib/Transforms/IPO/SCCP.cpp
llvm/lib/Transforms/Utils/SCCPSolver.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
index 1a95f80812aabd..9f7ccd4a8a32cf 100644
--- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
+++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h
@@ -151,6 +151,10 @@ class SCCPSolver {
/// works with both scalars and structs.
void markOverdefined(Value *V);
+ /// trackValueOfArgument - Mark the specified argument overdefined unless it
+ /// have range attribute. This works with both scalars and structs.
+ void trackValueOfArgument(Argument *V);
+
// isStructLatticeConstant - Return true if all the lattice values
// corresponding to elements of the structure are constants,
// false otherwise.
diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp
index b1f9b827dcbaf3..f8920541e6fd64 100644
--- a/llvm/lib/Transforms/IPO/SCCP.cpp
+++ b/llvm/lib/Transforms/IPO/SCCP.cpp
@@ -144,9 +144,8 @@ static bool runIPSCCP(
// Assume the function is called.
Solver.markBlockExecutable(&F.front());
- // Assume nothing about the incoming arguments.
for (Argument &AI : F.args())
- Solver.markOverdefined(&AI);
+ Solver.trackValueOfArgument(&AI);
}
// Determine if we can track any of the module's global variables. If so, add
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 38fc7763c5b204..b82ed25a6d0cf5 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -428,6 +428,13 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
return markConstant(ValueState[V], V, C);
}
+ /// markConstantRange - Mark the object as constant range with \p CR. If the
+ /// object is not a constant range with the range \p CR, add it to the
+ /// instruction work list so that the users of the instruction are updated
+ /// later.
+ bool markConstantRange(ValueLatticeElement &IV, Value *V,
+ const ConstantRange &CR);
+
// markOverdefined - Make a value be marked as "overdefined". If the
// value is not already overdefined, add it to the overdefined instruction
// work list so that the users of the instruction are updated later.
@@ -788,6 +795,17 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
markOverdefined(ValueState[V], V);
}
+ void trackValueOfArgument(Argument *A) {
+ if (A->getType()->isIntegerTy()) {
+ if (std::optional<ConstantRange> Range = A->getRange()) {
+ markConstantRange(ValueState[A], A, *Range);
+ return;
+ }
+ }
+ // Assume nothing about the incoming arguments without range.
+ markOverdefined(A);
+ }
+
bool isStructLatticeConstant(Function *F, StructType *STy);
Constant *getConstant(const ValueLatticeElement &LV, Type *Ty) const;
@@ -873,6 +891,15 @@ bool SCCPInstVisitor::markConstant(ValueLatticeElement &IV, Value *V,
return true;
}
+bool SCCPInstVisitor::markConstantRange(ValueLatticeElement &IV, Value *V,
+ const ConstantRange &CR) {
+ if (!IV.markConstantRange(CR))
+ return false;
+ LLVM_DEBUG(dbgs() << "markConstantRange: " << CR << ": " << *V << '\n');
+ pushToWorkList(IV, V);
+ return true;
+}
+
bool SCCPInstVisitor::markOverdefined(ValueLatticeElement &IV, Value *V) {
if (!IV.markOverdefined())
return false;
@@ -1581,10 +1608,15 @@ void SCCPInstVisitor::visitStoreInst(StoreInst &SI) {
}
static ValueLatticeElement getValueFromMetadata(const Instruction *I) {
- if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
- if (I->getType()->isIntegerTy())
+ if (I->getType()->isIntegerTy()) {
+ if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
return ValueLatticeElement::getRange(
getConstantRangeFromMetadata(*Ranges));
+
+ if (const auto *CB = dyn_cast<CallBase>(I))
+ if (std::optional<ConstantRange> Range = CB->getRange())
+ return ValueLatticeElement::getRange(*Range);
+ }
if (I->hasMetadata(LLVMContext::MD_nonnull))
return ValueLatticeElement::getNot(
ConstantPointerNull::get(cast<PointerType>(I->getType())));
@@ -2090,6 +2122,10 @@ const SmallPtrSet<Function *, 16> SCCPSolver::getMRVFunctionsTracked() {
void SCCPSolver::markOverdefined(Value *V) { Visitor->markOverdefined(V); }
+void SCCPSolver::trackValueOfArgument(Argument *V) {
+ Visitor->trackValueOfArgument(V);
+}
+
bool SCCPSolver::isStructLatticeConstant(Function *F, StructType *STy) {
return Visitor->isStructLatticeConstant(F, STy);
}
diff --git a/llvm/test/Transforms/SCCP/range-attribute.ll b/llvm/test/Transforms/SCCP/range-attribute.ll
new file mode 100644
index 00000000000000..ae66af91bb8e35
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/range-attribute.ll
@@ -0,0 +1,154 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=ipsccp -S | FileCheck %s
+
+declare void @use(i1)
+declare i32 @get_i32()
+
+define void @range_attribute(i32 range(i32 0, 10) %v) {
+; CHECK-LABEL: @range_attribute(
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V:%.*]], 9
+; CHECK-NEXT: call void @use(i1 [[C2]])
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: [[C4:%.*]] = icmp ugt i32 [[V]], 8
+; CHECK-NEXT: call void @use(i1 [[C4]])
+; CHECK-NEXT: ret void
+;
+ %c1 = icmp ult i32 %v, 10
+ call void @use(i1 %c1)
+ %c2 = icmp ult i32 %v, 9
+ call void @use(i1 %c2)
+ %c3 = icmp ugt i32 %v, 9
+ call void @use(i1 %c3)
+ %c4 = icmp ugt i32 %v, 8
+ call void @use(i1 %c4)
+ ret void
+}
+
+define i32 @range_attribute_single(i32 range(i32 0, 1) %v) {
+; CHECK-LABEL: @range_attribute_single(
+; CHECK-NEXT: ret i32 0
+;
+ ret i32 %v
+}
+
+define void @call_range_attribute() {
+; CHECK-LABEL: @call_range_attribute(
+; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C2]])
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: [[C4:%.*]] = icmp ugt i32 [[V]], 8
+; CHECK-NEXT: call void @use(i1 [[C4]])
+; CHECK-NEXT: ret void
+;
+ %v = call range(i32 0, 10) i32 @get_i32()
+ %c1 = icmp ult i32 %v, 10
+ call void @use(i1 %c1)
+ %c2 = icmp ult i32 %v, 9
+ call void @use(i1 %c2)
+ %c3 = icmp ugt i32 %v, 9
+ call void @use(i1 %c3)
+ %c4 = icmp ugt i32 %v, 8
+ call void @use(i1 %c4)
+ ret void
+}
+
+
+declare range(i32 0, 10) i32 @get_i32_in_range()
+
+define void @call_range_result() {
+; CHECK-LABEL: @call_range_result(
+; CHECK-NEXT: [[V:%.*]] = call i32 @get_i32_in_range()
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C2]])
+; CHECK-NEXT: call void @use(i1 false)
+; CHECK-NEXT: [[C4:%.*]] = icmp ugt i32 [[V]], 8
+; CHECK-NEXT: call void @use(i1 [[C4]])
+; CHECK-NEXT: ret void
+;
+ %v = call i32 @get_i32_in_range()
+ %c1 = icmp ult i32 %v, 10
+ call void @use(i1 %c1)
+ %c2 = icmp ult i32 %v, 9
+ call void @use(i1 %c2)
+ %c3 = icmp ugt i32 %v, 9
+ call void @use(i1 %c3)
+ %c4 = icmp ugt i32 %v, 8
+ call void @use(i1 %c4)
+ ret void
+}
+
+define internal i1 @ip_cmp_range_attribute(i32 %v) {
+; CHECK-LABEL: @ip_cmp_range_attribute(
+; CHECK-NEXT: ret i1 undef
+;
+ %c = icmp ult i32 %v, 10
+ ret i1 %c
+}
+
+define i1 @ip_range_attribute(i32 range(i32 0, 10) %v) {
+; CHECK-LABEL: @ip_range_attribute(
+; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_range_attribute(i32 [[V:%.*]])
+; CHECK-NEXT: ret i1 true
+;
+ %c = call i1 @ip_cmp_range_attribute(i32 %v)
+ ret i1 %c
+}
+
+define internal i1 @ip_cmp_range_call(i32 %v) {
+; CHECK-LABEL: @ip_cmp_range_call(
+; CHECK-NEXT: ret i1 undef
+;
+ %c = icmp ult i32 %v, 10
+ ret i1 %c
+}
+
+define i1 @ip_range_call() {
+; CHECK-LABEL: @ip_range_call(
+; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
+; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_range_call(i32 [[V]])
+; CHECK-NEXT: ret i1 true
+;
+ %v = call range(i32 0, 10) i32 @get_i32()
+ %c = call i1 @ip_cmp_range_call(i32 %v)
+ ret i1 %c
+}
+
+define internal i1 @ip_cmp_range_result(i32 %v) {
+; CHECK-LABEL: @ip_cmp_range_result(
+; CHECK-NEXT: ret i1 undef
+;
+ %c = icmp ult i32 %v, 10
+ ret i1 %c
+}
+
+define i1 @ip_range_result() {
+; CHECK-LABEL: @ip_range_result(
+; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
+; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_range_result(i32 [[V]])
+; CHECK-NEXT: ret i1 true
+;
+ %v = call range(i32 0, 10) i32 @get_i32()
+ %c = call i1 @ip_cmp_range_result(i32 %v)
+ ret i1 %c
+}
+
+define internal i1 @ip_cmp_with_range_attribute(i32 range(i32 0, 10) %v) {
+; CHECK-LABEL: @ip_cmp_with_range_attribute(
+; CHECK-NEXT: ret i1 undef
+;
+ %c = icmp eq i32 %v, 5
+ ret i1 %c
+}
+
+define i1 @ip_range_attribute_constant() {
+; CHECK-LABEL: @ip_range_attribute_constant(
+; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_with_range_attribute(i32 5)
+; CHECK-NEXT: ret i1 true
+;
+ %c = call i1 @ip_cmp_with_range_attribute(i32 5)
+ ret i1 %c
+}
More information about the llvm-commits
mailing list