Skip to content

Commit fff4a19

Browse files
committed
[IPSCCP] Add range attribute handling.
1 parent 2cc6f67 commit fff4a19

File tree

4 files changed

+56
-27
lines changed

4 files changed

+56
-27
lines changed

llvm/include/llvm/Transforms/Utils/SCCPSolver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ class SCCPSolver {
151151
/// works with both scalars and structs.
152152
void markOverdefined(Value *V);
153153

154+
/// trackValueOfArgument - Mark the specified argument overdefined unless it
155+
/// have range attribute. This works with both scalars and structs.
156+
void trackValueOfArgument(Argument *V);
157+
154158
// isStructLatticeConstant - Return true if all the lattice values
155159
// corresponding to elements of the structure are constants,
156160
// false otherwise.

llvm/lib/Transforms/IPO/SCCP.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,8 @@ static bool runIPSCCP(
144144
// Assume the function is called.
145145
Solver.markBlockExecutable(&F.front());
146146

147-
// Assume nothing about the incoming arguments.
148147
for (Argument &AI : F.args())
149-
Solver.markOverdefined(&AI);
148+
Solver.trackValueOfArgument(&AI);
150149
}
151150

152151
// Determine if we can track any of the module's global variables. If so, add

llvm/lib/Transforms/Utils/SCCPSolver.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,12 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
428428
return markConstant(ValueState[V], V, C);
429429
}
430430

431+
/// markConstantRange - Mark the object as constant range with \p CR. If the
432+
/// object is not a constant range with the range \p CR, add it to the
433+
/// instruction work list so that the users of the instruction are updated
434+
/// later.
435+
bool markConstantRange(ValueLatticeElement &IV, Value *V, ConstantRange &CR);
436+
431437
// markOverdefined - Make a value be marked as "overdefined". If the
432438
// value is not already overdefined, add it to the overdefined instruction
433439
// work list so that the users of the instruction are updated later.
@@ -788,6 +794,17 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
788794
markOverdefined(ValueState[V], V);
789795
}
790796

797+
void trackValueOfArgument(Argument *A) {
798+
if (A->getType()->isIntegerTy()) {
799+
if (std::optional<ConstantRange> Range = A->getRange()) {
800+
markConstantRange(ValueState[A], A, *Range);
801+
return;
802+
}
803+
}
804+
// Assume nothing about the incoming arguments without range.
805+
markOverdefined(A);
806+
}
807+
791808
bool isStructLatticeConstant(Function *F, StructType *STy);
792809

793810
Constant *getConstant(const ValueLatticeElement &LV, Type *Ty) const;
@@ -873,6 +890,15 @@ bool SCCPInstVisitor::markConstant(ValueLatticeElement &IV, Value *V,
873890
return true;
874891
}
875892

893+
bool SCCPInstVisitor::markConstantRange(ValueLatticeElement &IV, Value *V,
894+
ConstantRange &CR) {
895+
if (!IV.markConstantRange(CR))
896+
return false;
897+
LLVM_DEBUG(dbgs() << "markConstantRange: " << CR << ": " << *V << '\n');
898+
pushToWorkList(IV, V);
899+
return true;
900+
}
901+
876902
bool SCCPInstVisitor::markOverdefined(ValueLatticeElement &IV, Value *V) {
877903
if (!IV.markOverdefined())
878904
return false;
@@ -1581,10 +1607,15 @@ void SCCPInstVisitor::visitStoreInst(StoreInst &SI) {
15811607
}
15821608

15831609
static ValueLatticeElement getValueFromMetadata(const Instruction *I) {
1584-
if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
1585-
if (I->getType()->isIntegerTy())
1610+
if (I->getType()->isIntegerTy()) {
1611+
if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
15861612
return ValueLatticeElement::getRange(
15871613
getConstantRangeFromMetadata(*Ranges));
1614+
1615+
if (const auto *CB = dyn_cast<CallBase>(I))
1616+
if (std::optional<ConstantRange> Range = CB->getRange())
1617+
return ValueLatticeElement::getRange(*Range);
1618+
}
15881619
if (I->hasMetadata(LLVMContext::MD_nonnull))
15891620
return ValueLatticeElement::getNot(
15901621
ConstantPointerNull::get(cast<PointerType>(I->getType())));
@@ -2090,6 +2121,10 @@ const SmallPtrSet<Function *, 16> SCCPSolver::getMRVFunctionsTracked() {
20902121

20912122
void SCCPSolver::markOverdefined(Value *V) { Visitor->markOverdefined(V); }
20922123

2124+
void SCCPSolver::trackValueOfArgument(Argument *V) {
2125+
Visitor->trackValueOfArgument(V);
2126+
}
2127+
20932128
bool SCCPSolver::isStructLatticeConstant(Function *F, StructType *STy) {
20942129
return Visitor->isStructLatticeConstant(F, STy);
20952130
}

llvm/test/Transforms/SCCP/range-attribute.ll

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ declare i32 @get_i32()
66

77
define void @range_attribute(i32 range(i32 0, 10) %v) {
88
; CHECK-LABEL: @range_attribute(
9-
; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V:%.*]], 10
10-
; CHECK-NEXT: call void @use(i1 [[C1]])
11-
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
9+
; CHECK-NEXT: call void @use(i1 true)
10+
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V:%.*]], 9
1211
; CHECK-NEXT: call void @use(i1 [[C2]])
13-
; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
14-
; CHECK-NEXT: call void @use(i1 [[C3]])
12+
; CHECK-NEXT: call void @use(i1 false)
1513
; CHECK-NEXT: [[C4:%.*]] = icmp ugt i32 [[V]], 8
1614
; CHECK-NEXT: call void @use(i1 [[C4]])
1715
; CHECK-NEXT: ret void
@@ -29,20 +27,18 @@ define void @range_attribute(i32 range(i32 0, 10) %v) {
2927

3028
define i32 @range_attribute_single(i32 range(i32 0, 1) %v) {
3129
; CHECK-LABEL: @range_attribute_single(
32-
; CHECK-NEXT: ret i32 [[V:%.*]]
30+
; CHECK-NEXT: ret i32 0
3331
;
3432
ret i32 %v
3533
}
3634

3735
define void @call_range_attribute() {
3836
; CHECK-LABEL: @call_range_attribute(
3937
; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
40-
; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V]], 10
41-
; CHECK-NEXT: call void @use(i1 [[C1]])
38+
; CHECK-NEXT: call void @use(i1 true)
4239
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
4340
; CHECK-NEXT: call void @use(i1 [[C2]])
44-
; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
45-
; CHECK-NEXT: call void @use(i1 [[C3]])
41+
; CHECK-NEXT: call void @use(i1 false)
4642
; CHECK-NEXT: [[C4:%.*]] = icmp ugt i32 [[V]], 8
4743
; CHECK-NEXT: call void @use(i1 [[C4]])
4844
; CHECK-NEXT: ret void
@@ -65,12 +61,10 @@ declare range(i32 0, 10) i32 @get_i32_in_range()
6561
define void @call_range_result() {
6662
; CHECK-LABEL: @call_range_result(
6763
; CHECK-NEXT: [[V:%.*]] = call i32 @get_i32_in_range()
68-
; CHECK-NEXT: [[C1:%.*]] = icmp ult i32 [[V]], 10
69-
; CHECK-NEXT: call void @use(i1 [[C1]])
64+
; CHECK-NEXT: call void @use(i1 true)
7065
; CHECK-NEXT: [[C2:%.*]] = icmp ult i32 [[V]], 9
7166
; CHECK-NEXT: call void @use(i1 [[C2]])
72-
; CHECK-NEXT: [[C3:%.*]] = icmp ugt i32 [[V]], 9
73-
; CHECK-NEXT: call void @use(i1 [[C3]])
67+
; CHECK-NEXT: call void @use(i1 false)
7468
; CHECK-NEXT: [[C4:%.*]] = icmp ugt i32 [[V]], 8
7569
; CHECK-NEXT: call void @use(i1 [[C4]])
7670
; CHECK-NEXT: ret void
@@ -89,8 +83,7 @@ define void @call_range_result() {
8983

9084
define internal i1 @ip_cmp_range_attribute(i32 %v) {
9185
; CHECK-LABEL: @ip_cmp_range_attribute(
92-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[V:%.*]], 10
93-
; CHECK-NEXT: ret i1 [[C]]
86+
; CHECK-NEXT: ret i1 undef
9487
;
9588
%c = icmp ult i32 %v, 10
9689
ret i1 %c
@@ -99,16 +92,15 @@ define internal i1 @ip_cmp_range_attribute(i32 %v) {
9992
define i1 @ip_range_attribute(i32 range(i32 0, 10) %v) {
10093
; CHECK-LABEL: @ip_range_attribute(
10194
; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_range_attribute(i32 [[V:%.*]])
102-
; CHECK-NEXT: ret i1 [[C]]
95+
; CHECK-NEXT: ret i1 true
10396
;
10497
%c = call i1 @ip_cmp_range_attribute(i32 %v)
10598
ret i1 %c
10699
}
107100

108101
define internal i1 @ip_cmp_range_call(i32 %v) {
109102
; CHECK-LABEL: @ip_cmp_range_call(
110-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[V:%.*]], 10
111-
; CHECK-NEXT: ret i1 [[C]]
103+
; CHECK-NEXT: ret i1 undef
112104
;
113105
%c = icmp ult i32 %v, 10
114106
ret i1 %c
@@ -118,7 +110,7 @@ define i1 @ip_range_call() {
118110
; CHECK-LABEL: @ip_range_call(
119111
; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
120112
; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_range_call(i32 [[V]])
121-
; CHECK-NEXT: ret i1 [[C]]
113+
; CHECK-NEXT: ret i1 true
122114
;
123115
%v = call range(i32 0, 10) i32 @get_i32()
124116
%c = call i1 @ip_cmp_range_call(i32 %v)
@@ -127,8 +119,7 @@ define i1 @ip_range_call() {
127119

128120
define internal i1 @ip_cmp_range_result(i32 %v) {
129121
; CHECK-LABEL: @ip_cmp_range_result(
130-
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[V:%.*]], 10
131-
; CHECK-NEXT: ret i1 [[C]]
122+
; CHECK-NEXT: ret i1 undef
132123
;
133124
%c = icmp ult i32 %v, 10
134125
ret i1 %c
@@ -138,7 +129,7 @@ define i1 @ip_range_result() {
138129
; CHECK-LABEL: @ip_range_result(
139130
; CHECK-NEXT: [[V:%.*]] = call range(i32 0, 10) i32 @get_i32()
140131
; CHECK-NEXT: [[C:%.*]] = call i1 @ip_cmp_range_result(i32 [[V]])
141-
; CHECK-NEXT: ret i1 [[C]]
132+
; CHECK-NEXT: ret i1 true
142133
;
143134
%v = call range(i32 0, 10) i32 @get_i32()
144135
%c = call i1 @ip_cmp_range_result(i32 %v)

0 commit comments

Comments
 (0)