OpenASIP 2.2
Loading...
Searching...
No Matches
MachineInstrDDG.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2015 Tampere University.
3
4 This file is part of TTA-Based Codesign Environment (TCE).
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the "Software"),
8 to deal in the Software without restriction, including without limitation
9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 and/or sell copies of the Software, and to permit persons to whom the
11 Software is furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 DEALINGS IN THE SOFTWARE.
23 */
24/**
25 * @file MachineInstrDDG.cc
26 *
27 * @author Pekka Jääskeläinen 2012
28 * @note rating: red
29 */
30#ifdef NDEBUG
31#undef NDEBUG
32#endif
33
34#include "CompilerWarnings.hh"
35
36IGNORE_COMPILER_WARNING("-Wunused-parameter")
37
38#include "llvm/CodeGen/MachineInstr.h"
39#include "llvm/CodeGen/MachineBasicBlock.h"
40#include "llvm/CodeGen/MachineFunction.h"
41#include "tce_config.h"
42#include "llvm/CodeGen/TargetRegisterInfo.h"
43#include "llvm/IR/Function.h"
44#include <llvm/CodeGen/TargetSubtargetInfo.h>
45
46#include "MachineInstrDDG.hh"
47
48#include "AssocTools.hh"
49#include "Application.hh"
51#include "TCETargetMachine.hh"
52#include "OperationPool.hh"
53#include "Operation.hh"
54
55#include <utility>
56
58
59// #define DEBUG_MI_DDG
60
61/**
62 * Constructs a DDG out of MachineInstructions.
63 *
64 * Only true dependencies are supported at the moment.
65 */
67 llvm::MachineFunction& mf,
68 bool onlyTrueDeps) :
70 std::string(mf.getFunction().getName().str()) + "_middg", true),
71 onlyTrueDeps_(onlyTrueDeps), mf_(mf),
72 regInfo_(mf_.getTarget().getSubtargetImpl(
73 mf_.getFunction())->getRegisterInfo())
74 , printOnlyCriticalPath_(false) {
75 int instructions = 0;
76 for (llvm::MachineFunction::const_iterator bbi = mf.begin();
77 bbi != mf.end(); ++bbi) {
78 const llvm::MachineBasicBlock& bb = *bbi;
79 for (llvm::MachineBasicBlock::const_iterator ii = bb.begin();
80 ii != bb.end(); ++ii) {
81 const llvm::MachineInstr& i = *ii;
82 MIDDGNode* node = new MIDDGNode(i, instructions);
83 nodes_.insert(node);
84 addNode(*node);
86 ++instructions;
87 for (unsigned oi = 0; oi < i.getNumOperands(); ++oi) {
88 const llvm::MachineOperand& operand = i.getOperand(oi);
89 if (!operand.isReg())
90 continue;
91
92 if (operand.isUndef()) {
93 // this is probably a global register defined in some other
94 // function, thus it can be ignored (only reads from it in this func)
95 continue;
96 }
97 if (operand.isImplicit()) {
98 // the call clobbered regs
99 continue;
100 }
101
102 if (llvm::Register::isPhysicalRegister(
103 operand.getReg())) {
104
105 // only physical reg at this point should be the stack pointer,
106 // which is a global reg we can ignore
107#ifdef DEBUG_MI_DDG
109 << "found a phys reg " << operand.getReg()
110 << std::endl;
111 if (operand.getType() == llvm::MachineOperand::MO_FrameIndex)
112 Application::logStream() << "SP";
113#endif
114 continue;
115 }
116
117 if (operand.isUse()) {
118 users_[operand.getReg()].insert(node);
119#ifdef DEBUG_MI_DDG
121 << "uses: " << operand.getReg() << std::endl;
122#endif
123 } else if (operand.isDef()) {
124 if (definers_[operand.getReg()] != NULL) {
125 // in case we already have a definer, use the
126 // one from the different basic block to avoid loops
127 if (definers_[operand.getReg()]->machineInstr()->
128 getParent() != &bb) {
129#ifdef DEBUG_MI_DDG
131 << "found a potential back edge case, "
132 << "using the definer from another BB"
133 << std::endl;
134#endif
135 continue;
136 }
137 } else {
138 definers_[operand.getReg()] = node;
139 }
140 } else {
141#ifdef DEBUG_MI_DDG
143 << "unknown operand " << oi << std::endl;
144#endif
145 continue;
146 }
147 allRegisters_.insert(operand.getReg());
148 }
149 }
150 }
151
152
153 for (DefinerMap::iterator i = definers_.begin(); i != definers_.end();
154 ++i) {
155 Register reg = (*i).first;
156 MIDDGNode* source = (*i).second;
157 NodeSet& users = users_[reg];
158 for (std::set<MIDDGNode*>::iterator u = users.begin(); u != users.end();
159 ++u) {
160 MIDDGNode* dest = *u;
161
162 if (hasPath(*dest, *source)) {
163#ifdef DEBUG_MI_DDG
165 << "ignoring edge that would create a loop"
166 << std::endl;
167#endif
168 continue;
169 }
170
171 MIDDGEdge* edge = new MIDDGEdge(reg);
172 edges_.insert(edge);
173 connectNodes(*source, *dest, *edge);
174 }
175 }
176}
177
178/**
179 * Constructor for creating a subgraph.
180 */
183 std::string(parent.name(), true)),
184 onlyTrueDeps_(parent.onlyTrueDeps_), mf_(parent.mf_) {
185}
186
187
190
191
192/**
193 * Creates a false dependency edge introduced when the given virtual
194 * reg is assigned the given physical register.
195 *
196 * Does not add the edge to the graph. Note, only creates a single edge
197 * although in a multi-BB DDG there is usually many in case edge
198 * spans CFG branch points. Returns a pair with NULLs in case no false dep is
199 * introduced.
200 */
201std::pair<MIDDGNode*, MIDDGNode*>
203
204 MIDDGNode* null = NULL;
205 std::pair<MIDDGNode*, MIDDGNode*> none = std::make_pair(null, null);
206
207
208 if (lastPhysRegUsers_.find(physReg) == lastPhysRegUsers_.end()) {
209 return none;
210 }
211
212 MIDDGNode* lastPhysRegUser = (*lastPhysRegUsers_.find(physReg)).second;
213
214 if (this->vregDefiner(vreg) == NULL) {
215 // could not find a definer for the given vreg, thus probably
216 // a global register such as stack pointer, there won't be
217 // many assignment possibilities for them anyways
218 return none;
219 }
220 MIDDGNode* vregDefiner = this->vregDefiner(vreg);
221 MIDDGNode* lastVregUser = this->lastVregUser(vreg);
222
223 MIDDGNode* lastPhysRegDefiner = NULL;
224 if (lastPhysRegDefiners_.find(physReg) != lastPhysRegDefiners_.end()) {
225 lastPhysRegDefiner = (*lastPhysRegDefiners_.find(physReg)).second;
226 }
227
228 assert(vregDefiner != NULL);
229
230 // the source and destination nodes for the introduced antidep
231 MIDDGNode* source = NULL;
232 MIDDGNode* dest = NULL;
233
234 // the sequential instruction ordering defines the dep direction
236 lastPhysRegUser->sequentialAddress()) {
237 source = lastPhysRegUser;
238 dest = vregDefiner;
239 } else {
240 if (lastVregUser == NULL) {
241 // only writes to the vreg, thus it would be WaW
242 source = vregDefiner;
243 } else {
244 source = lastVregUser;
245 }
246
247 if (lastPhysRegDefiner != NULL) {
248 dest = lastPhysRegDefiner;
249 } else {
250 dest = lastPhysRegUser;
251 }
252 }
253
254 // ignore loop edges for now, but signal edges to itself as they are
255 // cheap false deps which should be treated as such
256 if (dest != source && hasPath(*dest, *source))
257 return none;
258
259 return std::make_pair(source, dest);
260}
261
262/**
263 * Returns the "height delta" of an antidep edge created in case the
264 * given virtual register is assigned the given physical register.
265 *
266 * Height delta is the difference between the DDG height of the source
267 * definer node and the DDG height of the latest read node of the physReg.
268 * The direction of the introduced false dep edge is determined from the
269 * sequential instruction order, direction is assumed to be from the
270 * earlier instruction to the later. Thus, an edge with 0 or greater height dep
271 * potentially constraints the schedule by potentially heightening the DDG.
272 * However, this is not generally the case in case the critical path length
273 * is not increased by the assignment.
274 *
275 * @param vreg The virtual register to test.
276 * @param physReg The physical register assigment to test.
277 * @return The height delta of the false dep from the assignment, or
278 * INT_MIN in case no false dep would be produced.
279 */
280int
282
283 std::pair<MIDDGNode*, MIDDGNode*> fdep =
284 createFalseDepEdge(vreg, physReg);
285
286 int hdelta = INT_MIN;
287 if (fdep.first != NULL && fdep.second != NULL) {
288 if (fdep.first == fdep.second)
289 return -1; // treat fdep to itself as the least harmful one
290 hdelta =
291 maxSourceDistance(*fdep.first) - maxSourceDistance(*fdep.second);
292 }
293 return hdelta;
294}
295
298 int lastUse = -1;
299 MIDDGNode* lastUser = NULL;
300 if (users_.find(vreg) == users_.end())
301 return NULL;
302
303 NodeSet& users = (*users_.find(vreg)).second;
304 for (NodeSet::const_iterator i = users.begin(); i != users.end();
305 ++i) {
306 MIDDGNode* node = *i;
307 if (lastUse < node->sequentialAddress()) {
308 lastUse = node->sequentialAddress();
309 lastUser = node;
310 }
311 }
312 return lastUser;
313}
314
315/**
316 * Checks if there is at least one preceeding node to the given node that
317 * defines or uses the given physical register.
318 *
319 * Also the uses in the same node are considered.
320 */
321bool
323 const MIDDGNode& node, Register physReg) const {
324
325 NodeSet pred = predecessors(node);
326 pred.insert(const_cast<MIDDGNode*>(&node));
327 for (NodeSet::const_iterator i = pred.begin(); i != pred.end(); ++i) {
328 MIDDGNode& p = (**i);
329 const llvm::MachineInstr* instr = p.machineInstr();
330 for (unsigned operand = 0; operand < instr->getNumOperands();
331 ++operand) {
332 const llvm::MachineOperand& mo = instr->getOperand(operand);
333 if (!mo.isReg())
334 continue;
335 if (mo.getReg() == physReg ||
336 (regAssignments_.find(mo.getReg()) != regAssignments_.end() &&
337 (*regAssignments_.find(mo.getReg())).second == physReg)) {
338 return true;
339 }
340 }
341
342 if (instr->readsRegister(physReg) ||
343 instr->modifiesRegister(physReg, regInfo_)) {
344 return true;
345 }
346 }
347 return false;
348}
349
350
351/**
352 * Computes optimal top-down schedule assuming infinite resources and that
353 * each operation completes in one cycle.
354 */
355void
357 smallestCycle_ = 0;
358 largestCycle_ = 0;
359 schedule_.clear();
360 for (int nc = 0; nc < nodeCount(); ++nc) {
361 MIDDGNode& n = node(nc);
362 int cycle = maxSourceDistance(n);
363 n.setOptimalCycle(cycle);
364 largestCycle_ = std::max(cycle, largestCycle_);
365 schedule_[cycle].push_back(&n);
366 }
367}
368
371 std::ostringstream s;
372 s << "digraph " << name() << " {" << std::endl;
373
374 const bool scheduled = nodeCount() > 1 && node(0).optimalCycle() != -1;
375
376 if (scheduled) {
377 // print the "time line" to visualize the schedule
378 s << "\t{" << std::endl
379 << "\t\tnode [shape=plaintext];" << std::endl
380 << "\t\t";
381 const int smallest = smallestCycle_;
382 const int largest = largestCycle_;
383 for (int c = smallest; c <= largest; ++c) {
384 s << "\"cycle " << c << "\" -> ";
385 }
386 s << "\"cycle " << largest + 1 << "\"; "
387 << std::endl << "\t}" << std::endl;
388
389 // print the nodes that have cycles
390 for (int c = smallest; c <= largest; ++c) {
391 std::list<MIDDGNode*> ops = schedule_[c];
392 if (ops.size() > 0) {
393 s << "\t{ rank = same; \"cycle " << c << "\"; ";
394 for (std::list<MIDDGNode*>::iterator i = ops.begin();
395 i != ops.end(); ++i) {
396 MIDDGNode& n = **i;
397 if (n.osalOperationName() == "llvm::DBG_VALUE")
398 continue;
400 continue;
401 s << "n" << n.nodeID() << "; ";
402 }
403 s << "}" << std::endl;
404 }
405 }
406
407
408 typedef std::map<TCEString, int> OpCountMap;
409 // Count how many times each operation could be potentially
410 // executed in parallel in an optimal schedule. This can direct
411 // the intial architecture design.
412 OpCountMap maxParallelOps;
413 // The operation mix. I.e., the static occurence of operations
414 // in the code.
415 OpCountMap operationMix;
416
417 for (int c = smallest; c <= largest; ++c) {
418 std::list<MIDDGNode*> ops = schedule_[c];
419 if (ops.size() == 0) continue;
420
421 std::map<TCEString, int> parallelOpsAtCycle;
422 for (std::list<MIDDGNode*>::iterator i = ops.begin();
423 i != ops.end(); ++i) {
424 MIDDGNode& n = **i;
425 TCEString opName = n.osalOperationName();
426 if (opName == "" || opName == "?jump") continue;
427 operationMix[opName]++;
428 parallelOpsAtCycle[opName]++;
429 }
430
431 for (OpCountMap::const_iterator i = parallelOpsAtCycle.begin();
432 i != parallelOpsAtCycle.end(); ++i) {
433 TCEString opName = (*i).first;
434 int count = (*i).second;
435 maxParallelOps[opName] =
436 std::max(maxParallelOps[opName], count);
437 }
438 }
439
440 const int COL_WIDTH = 14;
441 // print statistics of the graph as a comment
442 s << "/* statistics: " << std::endl << std::endl;
443 s << std::setw(COL_WIDTH) << std::right << "virtual regs: ";
444 s << definers_.size() << std::endl << std::endl;
445 s << std::setw(COL_WIDTH) << std::right << "operation stats: ";
446 s << std::endl << std::endl;
447
448 for (OpCountMap::const_iterator i = maxParallelOps.begin();
449 i != maxParallelOps.end(); ++i) {
450 TCEString opName = (*i).first;
451 int parCount = (*i).second;
452 int total = operationMix[opName];
453 s << std::setw(COL_WIDTH) << std::right << opName + ": ";
454 s << std::setw(COL_WIDTH) << std::right << total;
455 s << " total, " << std::setw(COL_WIDTH) << std::right
456 << parCount << " at most in parallel" << std::endl;
457 }
458 s << "*/" << std::endl;
459 }
460 // first print all the nodes and their properties
461 for (int i = 0; i < nodeCount(); ++i) {
462 Node& n = node(i);
463 if (n.osalOperationName() == "llvm::DBG_VALUE")
464 continue;
466 continue;
467
468 s << "\tn" << n.nodeID()
469 << " [" << n.dotString();
470 if (isInCriticalPath(n))
471 s << ",shape=box,color=\"red\"";
472 s << "]; " << std::endl;
473 }
474
475 // edges
476 for (int count = edgeCount(), i = 0; i < count ; ++i) {
477 Edge& e = edge(i);
478 Node& tail = tailNode(e);
479 Node& head = headNode(e);
480
482 !isInCriticalPath(head))
483 continue;
484
485 s << "\tn" << tail.nodeID() << " -> n"
486 << head.nodeID() << "["
487 << e.dotString();
488 if (isInCriticalPath(tail) && isInCriticalPath(head))
489 s << ",color=red";
490 s << "];" << std::endl;
491 }
492
493 s << "}" << std::endl;
494
495 return s.str();
496
497}
498
499/**
500 * Assigns the given physical register to the given virtual register.
501 *
502 * Does not yet add false dependence edges, just updates the last
503 * phys reg use bookkeeping.
504 */
505void
507
508 regAssignments_[vreg] = physReg;
509
510 MIDDGNode* lastDefiner = vregDefiner(vreg);
511
512 if (lastPhysRegDefiners_.find(physReg) != lastPhysRegDefiners_.end()) {
513 MIDDGNode* previousDefiner = lastPhysRegDefiners_[physReg];
514 if (lastDefiner == NULL ||
515 previousDefiner->sequentialAddress() >
516 lastDefiner->sequentialAddress()) {
517 lastDefiner = previousDefiner;
518 }
519 }
520 if (lastDefiner != NULL) {
521 lastPhysRegDefiners_[physReg] = lastDefiner;
522 }
523
524 MIDDGNode* lastUser = NULL;
525 if (lastPhysRegUsers_.find(physReg) != lastPhysRegUsers_.end()) {
526 lastUser = lastPhysRegUsers_[physReg];
527 }
528
529 MIDDGNode* lastVregUser = this->lastVregUser(vreg);
530 if (lastVregUser != NULL) {
531 if (lastUser == NULL ||
533 lastUser->sequentialAddress()) {
534 lastUser = lastVregUser;
535 }
536 }
537 if (lastUser != NULL) {
538 lastPhysRegUsers_[physReg] = lastUser;
539 }
540
541 std::pair<MIDDGNode*, MIDDGNode*> fdep =
542 createFalseDepEdge(vreg, physReg);
543
544 if (fdep.first != NULL && fdep.second != NULL &&
545 fdep.first != fdep.second) {
547 edges_.insert(edge);
548#if 0
550 << "adding edge: " << edge->toString() << " from "
551 << fdep.first->sequentialAddress() << " to "
552 << fdep.second->sequentialAddress() << std::endl;
553#endif
554 connectNodes(*fdep.first, *fdep.second, *edge);
555 }
556}
557
558/**
559 * Try to figure out the name of the instruction opcode in OSAL,
560 * if available.
561 *
562 * If the operation with the produced name is not found in OSAL,
563 * llvm: is prepended to the name string.
564 */
567 const llvm::TargetInstrInfo *TII =
568 machineInstr()->getParent()->getParent()->getTarget().
569 getSubtargetImpl(
570 machineInstr()->getParent()->getParent()->getFunction())->
571 getInstrInfo();
572 // If it's a custom operation call, try to figure out
573 // the called operation name and use it instead as the
574 // node label.
575 TCEString opName;
576 if (mi_->isInlineAsm()) {
577 unsigned numDefs = 0;
578 while (mi_->getOperand(numDefs).isReg() &&
579 mi_->getOperand(numDefs).isDef())
580 ++numDefs;
581 opName = mi_->getOperand(numDefs).getSymbolName();
582 } else {
583 opName = TII->getName(mi_->getOpcode()).str();
584 }
585
586 // Clean up the operand type string encoded as
587 // lower case letter at the end of the string.
588 TCEString upper = opName.upper();
589 TCEString cleaned;
590 for (size_t i = 0; i < opName.size(); ++i) {
591 if (upper[i] == opName[i])
592 cleaned += opName[i];
593 else
594 break;
595 }
596
597 OperationPool ops;
598 Operation& operation = ops.operation(cleaned.c_str());
599 if (operation.isNull())
600 return TCEString("llvm:") + opName;
601
602 return cleaned;
603}
604
605std::string
607 return (boost::format("label=\"%s\"") % osalOperationName()).str();
608}
609
#define assert(condition)
#define IGNORE_COMPILER_WARNING(X)
#define POP_COMPILER_DIAGS
find Finds info of the inner loops in the false
static std::ostream & logStream()
int maxSourceDistance(const MIDDGNode &node) const
virtual Node & headNode(const Edge &edge) const
virtual void addNode(Node &node)
Node & node(const int index) const
bool hasNode(const Node &) const
virtual const TCEString & name() const
bool hasPath(MIDDGNode &src, const MIDDGNode &dest) const
std::set< MIDDGNode *, typename GraphNode::Comparator > NodeSet
Definition BoostGraph.hh:86
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
bool isInCriticalPath(const MIDDGNode &node) const
virtual Node & tailNode(const Edge &edge) const
virtual Edge & edge(const int index) const
virtual void connectNodes(const Node &nTail, const Node &nHead, Edge &e)
virtual TCEString toString() const
Definition GraphEdge.cc:66
int nodeID() const
const llvm::TargetRegisterInfo * regInfo_
bool preceedingNodeUsesOrDefinesReg(const MIDDGNode &node, Register physReg) const
TCEString dotString() const
std::pair< MIDDGNode *, MIDDGNode * > createFalseDepEdge(Register vreg, Register physReg) const
int falseDepHeightDelta(Register vreg, Register physReg) const
std::map< int, std::list< MIDDGNode * > > schedule_
std::map< Register, MIDDGNode * > lastPhysRegDefiners_
MIDDGNode * lastVregUser(Register vreg) const
std::set< MIDDGEdge * > edges_
virtual ~MachineInstrDDG()
MachineInstrDDG(const MachineInstrDDG &parent)
RegisterMap regAssignments_
void assignPhysReg(Register vreg, Register physReg)
MIDDGNode * vregDefiner(Register vreg) const
std::map< Register, MIDDGNode * > lastPhysRegUsers_
RegisterSet allRegisters_
Operation & operation(const char *name)
bool isNull() const
TCEString upper() const
Definition TCEString.cc:86
TCEString dotString() const
int sequentialAddress() const
const llvm::MachineInstr * machineInstr() const
TCEString osalOperationName() const
std::string dotString() const
void setOptimalCycle(int cycle)
const llvm::MachineInstr * mi_