-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDFA.h
341 lines (300 loc) · 10.5 KB
/
DFA.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
#ifndef LLVM_TRANSFORMS_DFA_H
#define LLVM_TRANSFORMS_DFA_H
#include "llvm/IR/CFG.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/raw_ostream.h"
#include <queue>
#include <map>
#include <utility>
#include <vector>
using namespace std;
namespace llvm {
/*
* This is the base class to represent information in a dataflow analysis.
* For a specific analysis, you need to create a sublcass of it.
*/
class Info {
public:
Info(){}
Info(const Info &other){}
virtual ~Info(){};
/*
* Print out the information
*
* Direction:
* In your subclass you should implement this function according to the
* project specifications.
*/
virtual void print() = 0;
/*
* Compare two pieces of information
*
* Direction:
* In your subclass you need to implement this function.
*/
static bool equals(Info *info1, Info *info2);
/*
* Join two pieces of information.
* The third parameter points to the result.
*
* Direction:
* In your subclass you need to implement this function.
*/
static Info *join(Info *info1, Info *info2, Info *result);
};
/*
* This is the base template class to represent the generic dataflow analysis
* framework For a specific analysis, you need to create a sublcass of it.
*/
template <class Info, bool Direction> class DataFlowAnalysis {
public:
typedef std::pair<unsigned, unsigned> Edge;
// Index to instruction map
std::map<unsigned, Instruction *> IndexToInstr;
// Instruction to index map
std::map<Instruction *, unsigned> InstrToIndex;
// Edge to information map
std::map<Edge, Info *> EdgeToInfo;
// The bottom of the lattice
Info Bottom;
// The initial state of the analysis
Info InitialState;
// EntryInstr points to the first instruction to be processed in the
// analysis
Instruction *EntryInstr;
/*
* Assign an index to each instruction.
* The results are stored in InstrToIndex and IndexToInstr.
* A dummy node (nullptr) is added. It has index 0. This node has only one
* outgoing edge to EntryInstr. The information of this edge is
* InitialState. Any real instruction has an index > 0.
*
* Direction:
* Do *NOT* change this function.
* Both forward and backward analyses must use it to assign
* indices to the instructions of a function.
*/
void assignIndiceToInstrs(Function *F)
{
// Dummy instruction null has index 0;
// Any real instruction's index > 0.
InstrToIndex[nullptr] = 0;
IndexToInstr[0] = nullptr;
unsigned counter = 1;
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
Instruction *instr = &*I;
InstrToIndex[instr] = counter;
IndexToInstr[counter] = instr;
counter++;
}
}
/*
* Utility function:
* Get incoming edges of the instruction identified by index.
* IncomingEdges stores the indices of the source instructions of the
* incoming edges.
*/
void getIncomingEdges(unsigned index,
std::vector<unsigned> * IncomingEdges)
{
assert(IncomingEdges->size() == 0 && "IncomingEdges should be empty.");
for (auto const &it : EdgeToInfo)
if (it.first.second == index)
IncomingEdges->push_back(it.first.first);
}
/*
* Utility function:
* Get incoming edges of the instruction identified by index.
* OutgoingEdges stores the indices of the destination instructions of the
* outgoing edges.
*/
void getOutgoingEdges(unsigned index,
std::vector<unsigned> * OutgoingEdges)
{
assert(OutgoingEdges->size() == 0 && "OutgoingEdges should be empty.");
for (auto const &it : EdgeToInfo)
if (it.first.first == index)
OutgoingEdges->push_back(it.first.second);
}
/*
* Utility function:
* Insert an edge to EdgeToInfo.
* The default initial value for each edge is bottom.
*/
void addEdge(Instruction *src, Instruction *dst, Info *content)
{
Edge edge = std::make_pair(InstrToIndex[src], InstrToIndex[dst]);
if (EdgeToInfo.count(edge) == 0)
EdgeToInfo[edge] = content;
}
/*
* Initialize EdgeToInfo and EntryInstr for a forward analysis.
*/
void initializeForwardMap(Function *func)
{
assignIndiceToInstrs(func);
for (Function::iterator bi = func->begin(), e = func->end(); bi != e;
++bi) {
BasicBlock *block = &*bi;
Instruction *firstInstr = &(block->front());
// Initialize incoming edges to the basic block
for (auto pi = pred_begin(block), pe = pred_end(block); pi != pe;
++pi) {
BasicBlock *prev = *pi;
Instruction *src = (Instruction *)prev->getTerminator();
Instruction *dst = firstInstr;
addEdge(src, dst, &Bottom);
}
// If there is at least one phi node, add an edge from the first phi
// node to the first non-phi node instruction in the basic block.
if (isa<PHINode>(firstInstr))
addEdge(firstInstr, block->getFirstNonPHI(), &Bottom);
// Initialize edges within the basic block
for (auto ii = block->begin(), ie = block->end(); ii != ie; ++ii) {
Instruction *instr = &*ii;
if (isa<PHINode>(instr))
continue;
if (instr == (Instruction *)block->getTerminator())
break;
Instruction *next = instr->getNextNode();
addEdge(instr, next, &Bottom);
}
// Initialize outgoing edges of the basic block
Instruction *term = (Instruction *)block->getTerminator();
for (auto si = succ_begin(block), se = succ_end(block); si != se;
++si) {
BasicBlock *succ = *si;
Instruction *next = &(succ->front());
addEdge(term, next, &Bottom);
}
}
EntryInstr = (Instruction *)&((func->front()).front());
addEdge(nullptr, EntryInstr, &InitialState);
} // initializeForwardMap
/*
* Direction:
* Implement the following function in part 3 for backward analyses
*/
void initializeBackwardMap(Function *func)
{
assignIndiceToInstrs(func);
for (Function::iterator bi = func->begin(), e = func->end(); bi != e;
++bi) {
BasicBlock *block = &*bi;
Instruction *firstInstr = &(block->front());
// Initialize incoming edges to the basic block
for (auto pi = pred_begin(block), pe = pred_end(block); pi != pe;
++pi) {
BasicBlock *prev = *pi;
Instruction *dst = (Instruction *)prev->getTerminator();
Instruction *src = firstInstr;
addEdge(src, dst, &Bottom);
}
// If there is at least one phi node, add an edge from the first phi
// node to the first non-phi node instruction in the basic block.
if (isa<PHINode>(firstInstr))
addEdge(block->getFirstNonPHI(), firstInstr, &Bottom);
// Initialize edges within the basic block
for (auto ii = block->begin(), ie = block->end(); ii != ie; ++ii) {
Instruction *instr = &*ii;
if (isa<PHINode>(instr))
continue;
if (instr == (Instruction *)block->getTerminator())
break;
Instruction *next = instr->getNextNode();
addEdge(next, instr, &Bottom);
}
// Initialize outgoing edges of the basic block
Instruction *term = (Instruction *)block->getTerminator();
for (auto si = succ_begin(block), se = succ_end(block); si != se;
++si) {
BasicBlock *succ = *si;
Instruction *next = &(succ->front());
addEdge(next, term, &Bottom);
}
}
EntryInstr = (Instruction *)&((func->back()).back());
addEdge(nullptr, EntryInstr, &InitialState);
}
/*
* The flow function.
* Instruction I: the IR instruction to be processed.
* std::vector<unsigned> & IncomingEdges: the vector of the indices of the
* source instructions of the incoming edges. std::vector<unsigned> &
* IncomingEdges: the vector of indices of the source instructions of the
* outgoing edges. std::vector<Info *> & Infos: the vector of the newly
* computed information for each outgoing eages.
*
* Direction:
* Implement this function in subclasses.
*/
virtual void flowfunction(Instruction *I, std::vector<unsigned> &IncomingEdges, std::vector<unsigned> &OutgoingEdges, std::vector<Info *> &Infos) = 0;
DataFlowAnalysis(Info &bottom, Info &initialState)
: Bottom(bottom), InitialState(initialState), EntryInstr(nullptr){}
virtual ~DataFlowAnalysis(){}
/*
* Print out the analysis results.
*
* Direction:
* Do not change this funciton.
* The autograder will check the output of this function.
*/
void print(){
for (auto const &it : EdgeToInfo) {
errs() << "Edge " << it.first.first
<< "->"
"Edge "
<< it.first.second << ":";
(it.second)->print();
}
}
/*
* This function implements the work list algorithm in the following steps:
* (1) Initialize info of each edge to bottom
* (2) Initialize the worklist
* (3) Compute until the worklist is empty
*
* Direction:
* Implement the rest of the function.
* You may not change anything before "// (2) Initialize the worklist".
*/
void runWorklistAlgorithm(Function *func){
std::queue<unsigned> worklist;
// (1) Initialize info of each edge to bottom
if (Direction)
initializeForwardMap(func);
else
initializeBackwardMap(func);
assert(EntryInstr != nullptr && "Entry instruction is null.");
// (2) Initialize the work list
for (auto p : InstrToIndex)
if (p.first != NULL)
worklist.push(p.second);
// (3) Compute until the work list is empty
while (!worklist.empty()) {
unsigned instidx = worklist.front();
worklist.pop();
vector<unsigned> incomingEdges, outcomingEdges;
vector<Info *> infos;
getIncomingEdges(instidx, &incomingEdges);
getOutgoingEdges(instidx, &outcomingEdges);
flowfunction(IndexToInstr[instidx], incomingEdges, outcomingEdges, infos);
for (int i = 0; i < (int)outcomingEdges.size(); i++)
if (!Info::equals(EdgeToInfo[Edge(instidx, outcomingEdges[i])], infos[i])) {
EdgeToInfo[Edge(instidx, outcomingEdges[i])] = infos[i];
worklist.push(outcomingEdges[i]);
}
}
}
};
} // namespace llvm
#endif