Skip to content

Commit d6b3107

Browse files
Complete first version of value-range analysis
1 parent 1cb6845 commit d6b3107

31 files changed

+1046
-346
lines changed

Hpps.cpp renamed to ConstantRange.cpp

Lines changed: 81 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,33 @@ namespace
2121
static char ID;
2222
Hpps() : FunctionPass(ID) {}
2323

24-
// Run over a single function
24+
// Run over a single function (main)
2525
bool runOnFunction(Function &Func) override
2626
{
27-
// Null Value reference
27+
// Create a Null Value reference
28+
// Assigned as placeholder when no variable reference available
2829
LLVMContext &context = Func.getContext();
2930
Value *nullValue = ConstantInt::get(Type::getInt32Ty(context), -1);
3031

31-
// Keep reference of value still left to find the ranges
32-
// 'from' is unknown, it depends on 'to', 'toValue', and 'toOps' ('+' or '-')
32+
// Keep reference of values still left to find the ranges
33+
// 'from' is unknown, it depends on 'to', 'to2', 'toValue', and 'toOps' ('+' or '-')
34+
//
3335
// from = to toOps toValue (a = b + 1)
34-
// from = toValue toOps to (a = 1 + b)
36+
// from = toValue toOps to2 (a = 1 + b)
3537
// from = to toOps to2 (a = b + c)
3638
std::vector<Value *> from;
3739
std::vector<Value *> to;
3840
std::vector<Value *> to2;
3941
std::vector<int> toValue;
4042
std::vector<unsigned> toOps;
4143

42-
// Reference of variabiles for which range has been found
43-
std::vector<Value *> ranged; // Reference to the variable
44+
// Reference of variables for which range has been found
45+
// Note: Since no branches, minRange = maxRange (constant values)
46+
std::vector<Value *> ranged; // Reference to the variable (name)
4447
std::vector<int> minRange; // Min range of variable
4548
std::vector<int> maxRange; // Max range of variable
4649

47-
// Keep reference of variables in load instructions
50+
// Keep reference of variables (alias) from load instructions
4851
std::vector<Value *> loadRef;
4952

5053
// Run over all basic blocks in the function
@@ -56,9 +59,11 @@ namespace
5659
// Print instruction
5760
errs() << I << "\n";
5861

59-
// When instruction is load, store reference to its variables
62+
// When instruction is load, store reference (alias) to its real variables
6063
if (auto *loadInst = dyn_cast<LoadInst>(&I))
6164
{
65+
// Cycle over all the operands and store them for later use in 'loadRef'
66+
// Used to identify references in binary operations
6267
for (Use &U : loadInst->operands())
6368
{
6469
Value *v = U.get();
@@ -71,24 +76,37 @@ namespace
7176
// Save operand0 (reference/constant) and operand1 (reference/constant)
7277
if (auto *operInst = dyn_cast<BinaryOperator>(&I))
7378
{
79+
// Get operands from binary operation
7480
Value *oper0 = operInst->getOperand(0);
7581
Value *oper1 = operInst->getOperand(1);
7682

7783
// Store reference of variable still to find range
7884
from.push_back(operInst); // left-hand side of the operation
7985
toOps.push_back(operInst->getOpcode()); // '+' ot '-'
8086

81-
// Store constants/references
82-
errs() << " -Operation: " << operInst->getName() << "\n";
87+
// Print variable assigned and name of operands
88+
errs() << " -Var: " << operInst->getName() << "\n";
89+
errs() << " -Op0: " << oper0->getName() << "\n";
90+
errs() << " -Op1: " << oper1->getName() << "\n";
8391

8492
// a = b + 1 (variable + constant)
8593
// Get reference from previous load instruction
8694
if (ConstantInt *CI = dyn_cast<ConstantInt>(oper1))
8795
{
8896
toValue.push_back(CI->getZExtValue());
89-
to.push_back(loadRef.at(0));
9097
to2.push_back(nullValue);
91-
loadRef.pop_back();
98+
99+
// If operand0 is reference (and not an alias) store it
100+
if (oper0->hasName())
101+
{
102+
to.push_back(oper0);
103+
}
104+
// Otherwise get value from previous load instruction (alias)
105+
else
106+
{
107+
to.push_back(loadRef.at(0));
108+
loadRef.pop_back();
109+
}
92110
}
93111

94112
// a = 1 + b (constant + variable)
@@ -97,30 +115,54 @@ namespace
97115
{
98116
toValue.push_back(CI->getZExtValue());
99117
to.push_back(nullValue);
100-
to2.push_back(loadRef.at(0));
101-
loadRef.pop_back();
118+
119+
// If operand1 is reference (and not an alias) store it
120+
if (oper1->hasName())
121+
{
122+
to2.push_back(oper1);
123+
}
124+
// Otherwise get value from previous load instruction (alias)
125+
else
126+
{
127+
to2.push_back(loadRef.at(0));
128+
loadRef.pop_back();
129+
}
102130
}
103131

104132
// a = b + c (variable + variable)
105133
// Get reference from two previous load instructions
106134
else
107135
{
108-
// It may be that there are x2 'to'
109-
toValue.push_back(0);
110-
to.push_back(loadRef.at(0));
111-
112-
// TODO: When a = a + b + 3, the IR creates two loads for a and b, then
113-
// it does the 'add' = a + b, and then uses 'add1' = 'add' + 3. The problem
114-
// is that 'add' is not in loadRef, so there is an error!
115-
//
116-
// Same with a = a + b + c, 'add' = a + b, then load of c and 'add1' = 'add' + c,
117-
// but since those are both variables, and loadRef contains only c, calling
118-
// loadRef.at(1) gives error!
119-
to2.push_back(loadRef.at(1));
120-
121-
// Remove previous used load instruction value
122-
loadRef.pop_back();
123-
loadRef.pop_back();
136+
toValue.push_back(0); // Placeholder
137+
138+
// Both operand0 and operand1 as reference
139+
if (oper0->hasName() && oper1->hasName())
140+
{
141+
to.push_back(oper0);
142+
to2.push_back(oper1);
143+
}
144+
// Operand0 from load and operand1 as reference
145+
else if (!oper0->hasName() && oper1->hasName())
146+
{
147+
to.push_back(loadRef.at(0));
148+
to2.push_back(oper1);
149+
loadRef.pop_back();
150+
}
151+
// Operand1 from load and operand0 as reference
152+
else if (oper0->hasName() && !oper1->hasName())
153+
{
154+
to.push_back(oper0);
155+
to2.push_back(loadRef.at(0));
156+
loadRef.pop_back();
157+
}
158+
// Both operand0 and operand1 from load (alias)
159+
else
160+
{
161+
to.push_back(loadRef.at(0));
162+
to2.push_back(loadRef.at(1));
163+
loadRef.pop_back();
164+
loadRef.pop_back();
165+
}
124166
}
125167
}
126168

@@ -146,12 +188,14 @@ namespace
146188
}
147189

148190
// Store constant range value (Value-Range Found!)
149-
// a = 1
191+
// a = 1 (variable assigned constant value)
150192
else
151193
{
152194
if (ConstantInt *CI = dyn_cast<ConstantInt>(oper0))
153195
{
154196
errs() << " -Range found: " << CI->getZExtValue() << "\n";
197+
198+
// Store found value-range
155199
ranged.push_back(oper1);
156200
minRange.push_back(CI->getZExtValue());
157201
maxRange.push_back(CI->getZExtValue());
@@ -163,7 +207,7 @@ namespace
163207
}
164208
}
165209

166-
// Resolve references
210+
// Resolve references/dependencies
167211
errs() << "\n--- REFERENCES ---\n";
168212
for (unsigned i = 0; i < from.size(); ++i)
169213
{
@@ -190,16 +234,16 @@ namespace
190234
int refValue1 = -1;
191235
int refValue2 = -1;
192236

237+
// If 'to' is placeholder, then value is constant number
193238
if (to.at(i) == nullValue)
194239
{
195240
refValue1 = toValue.at(i);
196-
// errs() << "- F(const):" << refValue1 << "\n";
197241
}
198242

243+
// If 'to2' is placeholder, then value is constant number
199244
if (to2.at(i) == nullValue)
200245
{
201246
refValue2 = toValue.at(i);
202-
// errs() << "- F(const):" << refValue2 << "\n";
203247
}
204248

205249
// Search variable reference inside already found ranges
@@ -210,18 +254,17 @@ namespace
210254
{
211255
// When range found, add a new found range
212256
refValue1 = minRange.at(v);
213-
// errs() << "- F(to):" << ranged.at(v)->getName() << " (" << refValue1 << "\n\n";
214257
}
215258

216259
// When found value of 'to2' in 'ranged'
217260
if (to2.at(i) == ranged.at(v))
218261
{
219262
// When range found, add a new found range
220263
refValue2 = minRange.at(v);
221-
// errs() << "- F(to2):" << ranged.at(v)->getName() << " (" << refValue2 << "\n\n";
222264
}
223265
}
224266

267+
// Compute found value-range from resolved dependencies
225268
if (toOps.at(i) == Instruction::Add)
226269
{
227270
minRange.push_back(refValue1 + refValue2);
@@ -251,7 +294,7 @@ namespace
251294
} // end of anonymous namespace
252295

253296
char Hpps::ID = 0;
254-
static RegisterPass<Hpps> X("hpps", "Hpps World Pass",
297+
static RegisterPass<Hpps> X("const-range", "Constant Range Pass",
255298
false /* Only looks at CFG */,
256299
false /* Analysis Pass */);
257300

IR/interm.txt

Lines changed: 0 additions & 63 deletions
This file was deleted.

IR/simple5.ll

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ entry:
1818
store i32 %sub, i32* %b, align 4
1919
store i32 2, i32* %c, align 4
2020
%1 = load i32, i32* %a, align 4
21-
%2 = load i32, i32* %b, align 4
22-
%add = add nsw i32 %1, %2
23-
%3 = load i32, i32* %c, align 4
24-
%add1 = add nsw i32 %add, %3
25-
store i32 %add1, i32* %d, align 4
21+
%add = add nsw i32 %1, 2
22+
%2 = load i32, i32* %c, align 4
23+
%add1 = add nsw i32 %add, %2
24+
%3 = load i32, i32* %b, align 4
25+
%add2 = add nsw i32 %add1, %3
26+
%add3 = add nsw i32 %add2, 1
27+
%4 = load i32, i32* %a, align 4
28+
%sub4 = sub nsw i32 %add3, %4
29+
store i32 %sub4, i32* %d, align 4
2630
ret i32 0
2731
}
2832

IR/interm.ll renamed to IR/simple6.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
; ModuleID = '../../../code/interm.c'
2-
source_filename = "../../../code/interm.c"
1+
; ModuleID = '../../../code/simple6.c'
2+
source_filename = "../../../code/simple6.c"
33
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
44
target triple = "x86_64-unknown-linux-gnu"
55

IR/simple7.ll

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
; ModuleID = '../../../code/simple7.c'
2+
source_filename = "../../../code/simple7.c"
3+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
; Function Attrs: noinline nounwind optnone uwtable
7+
define dso_local i32 @main() #0 {
8+
entry:
9+
%retval = alloca i32, align 4
10+
%a = alloca i32, align 4
11+
%b = alloca i32, align 4
12+
%c = alloca i32, align 4
13+
store i32 0, i32* %retval, align 4
14+
store i32 0, i32* %a, align 4
15+
store i32 10, i32* %b, align 4
16+
%0 = load i32, i32* %a, align 4
17+
%add = add nsw i32 3, %0
18+
store i32 %add, i32* %c, align 4
19+
%1 = load i32, i32* %b, align 4
20+
%2 = load i32, i32* %c, align 4
21+
%sub = sub nsw i32 %1, %2
22+
store i32 %sub, i32* %a, align 4
23+
%3 = load i32, i32* %a, align 4
24+
%add1 = add nsw i32 %3, 7
25+
%add2 = add nsw i32 %add1, 3
26+
store i32 %add2, i32* %c, align 4
27+
%4 = load i32, i32* %b, align 4
28+
%5 = load i32, i32* %b, align 4
29+
%add3 = add nsw i32 %4, %5
30+
%sub4 = sub nsw i32 %add3, 1
31+
%6 = load i32, i32* %a, align 4
32+
%sub5 = sub nsw i32 %sub4, %6
33+
store i32 %sub5, i32* %b, align 4
34+
ret i32 0
35+
}
36+
37+
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
38+
39+
!llvm.module.flags = !{!0}
40+
!llvm.ident = !{!1}
41+
42+
!0 = !{i32 1, !"wchar_size", i32 4}
43+
!1 = !{!"clang version 7.1.0 "}

0 commit comments

Comments
 (0)