[llvm] [IPSCCP] Add range attribute handling. (PR #86747)
Andreas Jonson via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 26 16:13:45 PDT 2024
https://github.com/andjo403 created https://github.com/llvm/llvm-project/pull/86747
None
>From d5989136b77cc8175ff7690f823de519ae7067ae Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Tue, 26 Mar 2024 23:51:00 +0100
Subject: [PATCH 1/2] [IPSCCP] add test for range attribute handling. NFC.
---
llvm/test/Transforms/SCCP/range-attribute.ll | 88 ++++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100644 llvm/test/Transforms/SCCP/range-attribute.ll
diff --git a/llvm/test/Transforms/SCCP/range-attribute.ll b/llvm/test/Transforms/SCCP/range-attribute.ll
new file mode 100644
index 00000000000000..bc3130d6726345
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/range-attribute.ll
@@ -0,0 +1,88 @@
+; 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: [[C1:%.*]] = icmp ult i32 [[V:%.*]], 10
+; CHECK-NEXT: call void @use(i1 [[C1]])
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C2]])
+; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C3]])
+; 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 [[V:%.*]]
+;
+ ret i32 %v
+}
+
+define void @call_range_attribute(ptr %p) {
+; CHECK-LABEL: @call_range_attribute(
+; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
+; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V]], 10
+; CHECK-NEXT: call void @use(i1 [[C1]])
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C2]])
+; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C3]])
+; 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(ptr %p) {
+; CHECK-LABEL: @call_range_result(
+; CHECK-NEXT: [[V:%.*]] = call i32 @get_i32_in_range()
+; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V]], 10
+; CHECK-NEXT: call void @use(i1 [[C1]])
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C2]])
+; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 [[C3]])
+; 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
+}
>From f7eef0e54f3406e7a9a6fef8ccc7ffd093808ae0 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Tue, 26 Mar 2024 23:55:39 +0100
Subject: [PATCH 2/2] [IPSCCP] Add range attribute handling.
---
.../llvm/Transforms/Utils/SCCPSolver.h | 4 ++
llvm/lib/Transforms/IPO/SCCP.cpp | 3 +-
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 39 ++++++++++++++++++-
llvm/test/Transforms/SCCP/range-attribute.ll | 22 ++++-------
4 files changed, 50 insertions(+), 18 deletions(-)
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..4867c7b204c841 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -428,6 +428,12 @@ 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, 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 +794,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 +890,15 @@ bool SCCPInstVisitor::markConstant(ValueLatticeElement &IV, Value *V,
return true;
}
+bool SCCPInstVisitor::markConstantRange(ValueLatticeElement &IV, Value *V,
+ 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 +1607,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 +2121,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
index bc3130d6726345..597f9246a577d7 100644
--- a/llvm/test/Transforms/SCCP/range-attribute.ll
+++ b/llvm/test/Transforms/SCCP/range-attribute.ll
@@ -6,12 +6,10 @@ declare i32 @get_i32()
define void @range_attribute(i32 range(i32 0, 10) %v) {
; CHECK-LABEL: @range_attribute(
-; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V:%.*]], 10
-; CHECK-NEXT: call void @use(i1 [[C1]])
-; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V:%.*]], 9
; CHECK-NEXT: call void @use(i1 [[C2]])
-; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
-; CHECK-NEXT: call void @use(i1 [[C3]])
+; 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
@@ -29,7 +27,7 @@ define void @range_attribute(i32 range(i32 0, 10) %v) {
define i32 @range_attribute_single(i32 range(i32 0, 1) %v) {
; CHECK-LABEL: @range_attribute_single(
-; CHECK-NEXT: ret i32 [[V:%.*]]
+; CHECK-NEXT: ret i32 0
;
ret i32 %v
}
@@ -37,12 +35,10 @@ define i32 @range_attribute_single(i32 range(i32 0, 1) %v) {
define void @call_range_attribute(ptr %p) {
; CHECK-LABEL: @call_range_attribute(
; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
-; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V]], 10
-; CHECK-NEXT: call void @use(i1 [[C1]])
+; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
; CHECK-NEXT: call void @use(i1 [[C2]])
-; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
-; CHECK-NEXT: call void @use(i1 [[C3]])
+; 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
@@ -65,12 +61,10 @@ declare range(i32 0, 10) i32 @get_i32_in_range()
define void @call_range_result(ptr %p) {
; CHECK-LABEL: @call_range_result(
; CHECK-NEXT: [[V:%.*]] = call i32 @get_i32_in_range()
-; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V]], 10
-; CHECK-NEXT: call void @use(i1 [[C1]])
+; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
; CHECK-NEXT: call void @use(i1 [[C2]])
-; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
-; CHECK-NEXT: call void @use(i1 [[C3]])
+; 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
More information about the llvm-commits
mailing list