Skip to content

Commit a40f365

Browse files
committed
Recommit r315288: [SCCP] Propagate integer range info for parameters in IPSCCP.
This version of the patch includes a fix addressing a stage2 LTO buildbot failure and addressed some additional nits. Original commit message: This updates the SCCP solver to use of the ValueElement lattice for parameters, which provides integer range information. The range information is used to remove unneeded icmp instructions. For the following function, f() can be optimized to ret i32 2 with this change source_filename = "sccp.c" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" ; Function Attrs: norecurse nounwind readnone uwtable define i32 @main() local_unnamed_addr #0 { entry: %call = tail call fastcc i32 @f(i32 1) %call1 = tail call fastcc i32 @f(i32 47) %add3 = add nsw i32 %call, %call1 ret i32 %add3 } ; Function Attrs: noinline norecurse nounwind readnone uwtable define internal fastcc i32 @f(i32 %x) unnamed_addr #1 { entry: %c1 = icmp sle i32 %x, 100 %cmp = icmp sgt i32 %x, 300 %. = select i1 %cmp, i32 1, i32 2 ret i32 %. } attributes #1 = { noinline } Reviewers: davide, sanjoy, efriedma, dberlin Reviewed By: davide, dberlin Subscribers: mcrosier, gberry, mssimpso, dberlin, llvm-commits Differential Revision: https://reviews.llvm.org/D36656 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316891 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent e3ef547 commit a40f365

File tree

2 files changed

+238
-7
lines changed

2 files changed

+238
-7
lines changed

lib/Transforms/Scalar/SCCP.cpp

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/Analysis/ConstantFolding.h"
3131
#include "llvm/Analysis/GlobalsModRef.h"
3232
#include "llvm/Analysis/TargetLibraryInfo.h"
33+
#include "llvm/Analysis/ValueLattice.h"
3334
#include "llvm/Analysis/ValueLatticeUtils.h"
3435
#include "llvm/IR/BasicBlock.h"
3536
#include "llvm/IR/CallSite.h"
@@ -70,6 +71,8 @@ STATISTIC(NumDeadBlocks , "Number of basic blocks unreachable");
7071
STATISTIC(IPNumInstRemoved, "Number of instructions removed by IPSCCP");
7172
STATISTIC(IPNumArgsElimed ,"Number of arguments constant propagated by IPSCCP");
7273
STATISTIC(IPNumGlobalConst, "Number of globals found to be constant by IPSCCP");
74+
STATISTIC(IPNumRangeInfoUsed, "Number of times constant range info was used by"
75+
"IPSCCP");
7376

7477
namespace {
7578

@@ -174,6 +177,14 @@ class LatticeVal {
174177
Val.setInt(forcedconstant);
175178
Val.setPointer(V);
176179
}
180+
181+
ValueLatticeElement toValueLattice() const {
182+
if (isOverdefined())
183+
return ValueLatticeElement::getOverdefined();
184+
if (isConstant())
185+
return ValueLatticeElement::get(getConstant());
186+
return ValueLatticeElement();
187+
}
177188
};
178189

179190
//===----------------------------------------------------------------------===//
@@ -186,6 +197,8 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
186197
const TargetLibraryInfo *TLI;
187198
SmallPtrSet<BasicBlock *, 8> BBExecutable; // The BBs that are executable.
188199
DenseMap<Value *, LatticeVal> ValueState; // The state each value is in.
200+
// The state each parameter is in.
201+
DenseMap<Value *, ValueLatticeElement> ParamState;
189202

190203
/// StructValueState - This maintains ValueState for values that have
191204
/// StructType, for example for formal arguments, calls, insertelement, etc.
@@ -312,10 +325,20 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
312325
return StructValues;
313326
}
314327

315-
LatticeVal getLatticeValueFor(Value *V) const {
316-
DenseMap<Value*, LatticeVal>::const_iterator I = ValueState.find(V);
317-
assert(I != ValueState.end() && "V is not in valuemap!");
318-
return I->second;
328+
ValueLatticeElement getLatticeValueFor(Value *V) {
329+
assert(!V->getType()->isStructTy() &&
330+
"Should use getStructLatticeValueFor");
331+
std::pair<DenseMap<Value*, ValueLatticeElement>::iterator, bool>
332+
PI = ParamState.insert(std::make_pair(V, ValueLatticeElement()));
333+
ValueLatticeElement &LV = PI.first->second;
334+
if (PI.second) {
335+
DenseMap<Value*, LatticeVal>::const_iterator I = ValueState.find(V);
336+
assert(I != ValueState.end() &&
337+
"V not found in ValueState nor Paramstate map!");
338+
LV = I->second.toValueLattice();
339+
}
340+
341+
return LV;
319342
}
320343

321344
/// getTrackedRetVals - Get the inferred return value map.
@@ -444,6 +467,18 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
444467
return LV;
445468
}
446469

470+
ValueLatticeElement &getParamState(Value *V) {
471+
assert(!V->getType()->isStructTy() && "Should use getStructValueState");
472+
473+
std::pair<DenseMap<Value*, ValueLatticeElement>::iterator, bool>
474+
PI = ParamState.insert(std::make_pair(V, ValueLatticeElement()));
475+
ValueLatticeElement &LV = PI.first->second;
476+
if (PI.second)
477+
LV = getValueState(V).toValueLattice();
478+
479+
return LV;
480+
}
481+
447482
/// getStructValueState - Return the LatticeVal object that corresponds to the
448483
/// value/field pair. This function handles the case when the value hasn't
449484
/// been seen yet by properly seeding constants etc.
@@ -1170,6 +1205,9 @@ void SCCPSolver::visitCallSite(CallSite CS) {
11701205
mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg);
11711206
}
11721207
} else {
1208+
// Most other parts of the Solver still only use the simpler value
1209+
// lattice, so we propagate changes for parameters to both lattices.
1210+
getParamState(&*AI).mergeIn(getValueState(*CAI).toValueLattice(), DL);
11731211
mergeInValue(&*AI, getValueState(*CAI));
11741212
}
11751213
}
@@ -1560,6 +1598,43 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
15601598
return false;
15611599
}
15621600

1601+
static bool tryToReplaceWithConstantRange(SCCPSolver &Solver, Value *V) {
1602+
bool Changed = false;
1603+
1604+
// Currently we only use range information for integer values.
1605+
if (!V->getType()->isIntegerTy())
1606+
return false;
1607+
1608+
const ValueLatticeElement &IV = Solver.getLatticeValueFor(V);
1609+
if (!IV.isConstantRange())
1610+
return false;
1611+
1612+
for (auto UI = V->uses().begin(), E = V->uses().end(); UI != E;) {
1613+
const Use &U = *UI++;
1614+
auto *Icmp = dyn_cast<ICmpInst>(U.getUser());
1615+
if (!Icmp || !Solver.isBlockExecutable(Icmp->getParent()))
1616+
continue;
1617+
1618+
auto A = Solver.getLatticeValueFor(Icmp->getOperand(0));
1619+
auto B = Solver.getLatticeValueFor(Icmp->getOperand(1));
1620+
Constant *C = nullptr;
1621+
if (A.satisfiesPredicate(Icmp->getPredicate(), B))
1622+
C = ConstantInt::getTrue(Icmp->getType());
1623+
else if (A.satisfiesPredicate(Icmp->getInversePredicate(), B))
1624+
C = ConstantInt::getFalse(Icmp->getType());
1625+
1626+
if (C) {
1627+
Icmp->replaceAllUsesWith(C);
1628+
DEBUG(dbgs() << "Replacing " << *Icmp << " with " << *C
1629+
<< ", because of range information " << A << " " << B
1630+
<< "\n");
1631+
Icmp->eraseFromParent();
1632+
Changed = true;
1633+
}
1634+
}
1635+
return Changed;
1636+
}
1637+
15631638
static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
15641639
Constant *Const = nullptr;
15651640
if (V->getType()->isStructTy()) {
@@ -1577,10 +1652,19 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
15771652
}
15781653
Const = ConstantStruct::get(ST, ConstVals);
15791654
} else {
1580-
LatticeVal IV = Solver.getLatticeValueFor(V);
1655+
const ValueLatticeElement &IV = Solver.getLatticeValueFor(V);
15811656
if (IV.isOverdefined())
15821657
return false;
1583-
Const = IV.isConstant() ? IV.getConstant() : UndefValue::get(V->getType());
1658+
1659+
if (IV.isConstantRange()) {
1660+
if (IV.getConstantRange().isSingleElement())
1661+
Const =
1662+
ConstantInt::get(V->getType(), IV.asConstantInteger().getValue());
1663+
else
1664+
return false;
1665+
} else
1666+
Const =
1667+
IV.isConstant() ? IV.getConstant() : UndefValue::get(V->getType());
15841668
}
15851669
assert(Const && "Constant is nullptr here!");
15861670
DEBUG(dbgs() << " Constant: " << *Const << " = " << *V << '\n');
@@ -1781,10 +1865,14 @@ static bool runIPSCCP(Module &M, const DataLayout &DL,
17811865

17821866
if (Solver.isBlockExecutable(&F.front()))
17831867
for (Function::arg_iterator AI = F.arg_begin(), E = F.arg_end(); AI != E;
1784-
++AI)
1868+
++AI) {
17851869
if (!AI->use_empty() && tryToReplaceWithConstant(Solver, &*AI))
17861870
++IPNumArgsElimed;
17871871

1872+
if (!AI->use_empty() && tryToReplaceWithConstantRange(Solver, &*AI))
1873+
++IPNumRangeInfoUsed;
1874+
}
1875+
17881876
for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
17891877
if (!Solver.isBlockExecutable(&*BB)) {
17901878
DEBUG(dbgs() << " BasicBlock Dead:" << *BB);
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
; RUN: opt < %s -ipsccp -S | FileCheck %s
2+
3+
; Constant range for %a is [1, 48) and for %b is [301, 1000)
4+
; CHECK-LABEL: f1
5+
; CHECK-NOT: icmp
6+
; CHECK: %a.1 = select i1 false, i32 1, i32 2
7+
; CHECK: %b.1 = select i1 true, i32 1, i32 2
8+
; CHECK: %a.2 = select i1 false, i32 1, i32 2
9+
; CHECK: %b.2 = select i1 true, i32 1, i32 2
10+
define internal i32 @f1(i32 %a, i32 %b) {
11+
entry:
12+
%cmp.a = icmp sgt i32 %a, 300
13+
%cmp.b = icmp sgt i32 %b, 300
14+
%cmp.a2 = icmp ugt i32 %a, 300
15+
%cmp.b2 = icmp ugt i32 %b, 300
16+
17+
%a.1 = select i1 %cmp.a, i32 1, i32 2
18+
%b.1 = select i1 %cmp.b, i32 1, i32 2
19+
%a.2 = select i1 %cmp.a2, i32 1, i32 2
20+
%b.2 = select i1 %cmp.b2, i32 1, i32 2
21+
%res1 = add i32 %a.1, %b.1
22+
%res2 = add i32 %a.2, %b.2
23+
%res3 = add i32 %res1, %res2
24+
ret i32 %res3
25+
}
26+
27+
; Constant range for %x is [47, 302)
28+
; CHECK-LABEL: f2
29+
; CHECK: %cmp = icmp sgt i32 %x, 300
30+
; CHECK: %res1 = select i1 %cmp, i32 1, i32 2
31+
; CHECK-NEXT: %res2 = select i1 true, i32 3, i32 4
32+
; CHECK-NEXT: %res3 = select i1 true, i32 5, i32 6
33+
; CHECK-NEXT: %res4 = select i1 %cmp4, i32 3, i32 4
34+
; CHECK-NEXT: %res5 = select i1 true, i32 5, i32 6
35+
define internal i32 @f2(i32 %x) {
36+
entry:
37+
%cmp = icmp sgt i32 %x, 300
38+
%cmp2 = icmp ne i32 %x, 10
39+
%cmp3 = icmp sge i32 %x, 47
40+
%cmp4 = icmp ugt i32 %x, 300
41+
%cmp5 = icmp uge i32 %x, 47
42+
%res1 = select i1 %cmp, i32 1, i32 2
43+
%res2 = select i1 %cmp2, i32 3, i32 4
44+
%res3 = select i1 %cmp3, i32 5, i32 6
45+
%res4 = select i1 %cmp4, i32 3, i32 4
46+
%res5 = select i1 %cmp5, i32 5, i32 6
47+
48+
%res6 = add i32 %res1, %res2
49+
%res7 = add i32 %res3, %res4
50+
%res = add i32 %res6, %res5
51+
ret i32 %res
52+
}
53+
54+
define i32 @caller1() {
55+
entry:
56+
%call1 = tail call i32 @f1(i32 1, i32 301)
57+
%call2 = tail call i32 @f1(i32 47, i32 999)
58+
%call3 = tail call i32 @f2(i32 47)
59+
%call4 = tail call i32 @f2(i32 301)
60+
%res = add nsw i32 %call1, %call2
61+
%res.1 = add nsw i32 %res, %call3
62+
%res.2 = add nsw i32 %res.1, %call4
63+
ret i32 %res.2
64+
}
65+
66+
; x is overdefined, because constant ranges are only used for parameter
67+
; values.
68+
; CHECK-LABEL: f3
69+
; CHECK: %cmp = icmp sgt i32 %x, 300
70+
; CHECK: %res = select i1 %cmp, i32 1, i32 2
71+
; CHECK: ret i32 %res
72+
define internal i32 @f3(i32 %x) {
73+
entry:
74+
%cmp = icmp sgt i32 %x, 300
75+
%res = select i1 %cmp, i32 1, i32 2
76+
ret i32 %res
77+
}
78+
79+
; The phi node could be converted in a ConstantRange.
80+
define i32 @caller2(i1 %cmp) {
81+
entry:
82+
br i1 %cmp, label %if.true, label %end
83+
84+
if.true:
85+
br label %end
86+
87+
end:
88+
%res = phi i32 [ 0, %entry], [ 1, %if.true ]
89+
%call1 = tail call i32 @f3(i32 %res)
90+
ret i32 %call1
91+
}
92+
93+
; CHECK-LABEL: f4
94+
; CHECK: %cmp = icmp sgt i32 %x, 300
95+
; CHECK: %res = select i1 %cmp, i32 1, i32 2
96+
; CHECK: ret i32 %res
97+
define internal i32 @f4(i32 %x) {
98+
entry:
99+
%cmp = icmp sgt i32 %x, 300
100+
%res = select i1 %cmp, i32 1, i32 2
101+
ret i32 %res
102+
}
103+
104+
; ICmp could introduce bounds on ConstantRanges.
105+
define i32 @caller3(i32 %x) {
106+
entry:
107+
%cmp = icmp sgt i32 %x, 300
108+
br i1 %cmp, label %if.true, label %end
109+
110+
if.true:
111+
%x.1 = tail call i32 @f4(i32 %x)
112+
br label %end
113+
114+
end:
115+
%res = phi i32 [ 0, %entry], [ %x.1, %if.true ]
116+
ret i32 %res
117+
}
118+
119+
; Check to make sure we do not attempt to access lattice values in unreachable
120+
; blocks.
121+
define i32 @test_unreachable() {
122+
entry:
123+
call i1 @test_unreachable_callee(i32 1)
124+
call i1 @test_unreachable_callee(i32 2)
125+
ret i32 1
126+
}
127+
128+
define internal i1 @test_unreachable_callee(i32 %a) {
129+
entry:
130+
ret i1 true
131+
132+
unreachablebb:
133+
%cmp = icmp eq i32 undef, %a
134+
unreachable
135+
}
136+
137+
; Check that we do not attempt to get range info for non-integer types and
138+
; crash.
139+
define double @test_struct({ double, double } %test) {
140+
%v = extractvalue { double, double } %test, 0
141+
%r = fmul double %v, %v
142+
ret double %r
143+
}

0 commit comments

Comments
 (0)