OpenASIP 2.2
Loading...
Searching...
No Matches
DataDependenceGraphBuilder.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2021 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 DataDependenceGraphBuilder.cc
26 *
27 * Implementation of data dependence graph builder.
28 *
29 * DDG's can be built only from unscheduled code. Registers can
30 * however have been allocated.
31 *
32 * @author Heikki Kultala 2006-2009 (heikki.kultala-no.spam-tut.fi)
33 * @author Pekka Jääskeläinen 2021 (pekka.jaaskelainen tuni fi)
34 * @note rating: red
35 */
36
37#include "CompilerWarnings.hh"
38IGNORE_COMPILER_WARNING("-Wunused-parameter")
39
40#include <llvm/CodeGen/MachineInstr.h>
41#include <llvm/CodeGen/MachineMemOperand.h>
42
43#include "AssocTools.hh"
44#include "ContainerTools.hh"
45#include "TCEString.hh"
46#include "SequenceTools.hh"
47
48#include "Program.hh"
49#include "Procedure.hh"
50#include "Instruction.hh"
51#include "Operation.hh"
53#include "Move.hh"
54#include "ProgramOperation.hh"
55#include "RegisterFile.hh"
56#include "Machine.hh"
57#include "UniversalMachine.hh"
58#include "Exception.hh"
60#include "MoveGuard.hh"
61#include "Guard.hh"
62#include "MoveNodeSet.hh"
63#include "Operand.hh"
64#include "POMDisassembler.hh"
66#include "Move.hh"
67#include "ControlFlowGraph.hh"
68#include "ControlFlowEdge.hh"
69#include "BasicBlockNode.hh"
70#include "BasicBlock.hh"
72#include "DataDependenceEdge.hh"
75
76#include "TerminalRegister.hh"
77#include "TerminalFUPort.hh"
78
80#include "FalseAliasAnalyzer.hh"
81#include "StackAliasAnalyzer.hh"
83#include "GlobalVsStackAA.hh"
84#include "LLVMAliasAnalyzer.hh"
86
87#include "InterPassData.hh"
88#include "InterPassDatum.hh"
90
91#include "MachineInfo.hh"
92
93using namespace TTAProgram;
94using namespace TTAMachine;
95
96using std::list;
97
98
99static const int REG_RV_HIGH = -1;
100static const int REG_SP = 1;
101static const int REG_RV = 0;
102static const int REG_IPARAM = 2;
103
104static const int REG_VRV = -3;
105static const int REG_FP = -2;
106
108
109//#define USE_FALSE_AA
110
111/**
112 * Constructor of Data Dependence graph builder.
113 *
114 * This constructor does not take special registers from
115 * interpass data, so it must analyze them from the
116 * code annotations. Used with old frontend.
117 */
119 interPassData_(NULL), cfg_(NULL), rvIsParamReg_(false) {
120
121 /// constant alias AA check aa between global variables.
123
124#ifdef USE_FALSE_AA
125 /// defining USE_FALSE_AA results in faster but
126 /// broken code. just for testing theoretical benefits.
128#endif
130
131 LLVMTCECmdLineOptions* llvmOptions =
132 dynamic_cast<LLVMTCECmdLineOptions*>(
134 if (llvmOptions != NULL && llvmOptions->disableLLVMAA() == false) {
136 }
137}
138
139/**
140 * Constructor of Data Dependence graph builder.
141 *
142 * This constructor takes special registers from
143 * interpass data.
144 */
146 // TODO: when param reg thing works, rvIsParamReg becomes true here
147 interPassData_(&ipd), cfg_(NULL), rvIsParamReg_(true) {
148
149 // Need to store data about special registers which have semantics
150 // between function calls and exits. These are stack pointer,
151 // return value register and the secondary "hi bits"
152 // return value register.
153
154 static const TCEString SP_DATUM = "STACK_POINTER";
155 static const TCEString FP_DATUM = "FRAME_POINTER";
156 static const TCEString RV_DATUM = "RV_REGISTER";
157 // high part of 64-bit return values.
158 static const TCEString RV_HIGH_DATUM = "RV_HIGH_REGISTER";
159
160 static const TCEString IPARAM_DATUM_PREFIX = "IPARAM";
161 static const TCEString VECTOR_RV_PREFIX="VRV_REGISTER";
162
164 dynamic_cast<SchedulerCmdLineOptions*>(
166
167 if (ipd.hasDatum(SP_DATUM)) {
168 RegDatum& sp = dynamic_cast<RegDatum&>(ipd.datum(SP_DATUM));
169 TCEString spName = sp.first + '.' + Conversion::toString(sp.second);
170 specialRegisters_[REG_SP] = spName;
171
172 // create stack alias analyzer if enabled.
173 if ((options != NULL && options->enableStackAA())) {
175 }
176
177 if (options != NULL && options->enableOffsetAA()) {
179 }
180
182
183 } else {
187 << "Warning: Stack pointer datum not found "
188 << "in interpassdata given to ddg builder. "
189 << "May generate invalid code if stack used."
190 << std::endl;
191 }
192 }
193
194 if (ipd.hasDatum(RV_DATUM)) {
195 RegDatum& rv = dynamic_cast<RegDatum&>(ipd.datum(RV_DATUM));
196 TCEString reg = rv.first + '.' + Conversion::toString(rv.second);
198 if (rvIsParamReg_) {
199 allParamRegs_.insert(reg);
200 }
201
202 } else {
206 << "Warning: Return value register datum not found "
207 << "in interpassdata given to ddg builder. "
208 << "May generate invalid code if return values used."
209 << std::endl;
210 }
211 }
212
213 for(int i = 2;;i++) {
214 TCEString datum = IPARAM_DATUM_PREFIX; datum << i;
215 if (ipd.hasDatum(datum)) {
216 RegDatum& p = dynamic_cast<RegDatum&>(ipd.datum(datum));
217 TCEString reg = p.first + '.' + Conversion::toString(p.second);
218 specialRegisters_[REG_IPARAM+i-1] = reg;
219 } else {
220 break;
221 }
222 }
223
224 for (int i = 0;;i++) {
225 TCEString datum = VECTOR_RV_PREFIX; datum << i;
226 if (ipd.hasDatum(datum)) {
227 RegDatum& p = dynamic_cast<RegDatum&>(ipd.datum(datum));
228 TCEString reg = p.first + '.' + Conversion::toString(p.second);
229 specialRegisters_[REG_VRV-i] = reg;
230 } else {
231 break;
232 }
233
234 }
235
236 if (ipd.hasDatum(FP_DATUM)) {
237 RegDatum& fp = dynamic_cast<RegDatum&>(ipd.datum(FP_DATUM));
238 TCEString reg = fp.first + '.' + Conversion::toString(fp.second);
240 } else {
244 << "Warning: Frame Pointer Register datum not found "
245 << "in interpassdata given to ddg builder. "
246 << "May generate invalid code."
247 << std::endl;
248 }
249 }
250
251 if (ipd.hasDatum(RV_HIGH_DATUM)) {
252 RegDatum& rvh = dynamic_cast<RegDatum&>(ipd.datum(RV_HIGH_DATUM));
254 rvh.first + '.' + Conversion::toString(rvh.second);
255 }
256
257 // constant alias AA check aa between global variables.
259
260 LLVMTCECmdLineOptions* llvmOptions =
261 dynamic_cast<LLVMTCECmdLineOptions*>(
263 if (llvmOptions != NULL && llvmOptions->disableLLVMAA() == false) {
265 }
267
268#ifdef USE_FALSE_AA
269 /// defining USE_FALSE_AA results in faster but
270 /// broken code. just for testing theoretical benefits.
272#else
273 if ((options != NULL && options->noaliasFunctions() &&
274 !options->noaliasFunctions()->empty())) {
275 addAliasAnalyzer(new FalseAliasAnalyzer(options->noaliasFunctions()));
276 }
277#endif
278}
279
280/**
281 * Destructor of DataDependenceGraphBuilder
282 */
286
287/**
288 * Adds a memory alias analyzer to the DDG builder.
289 *
290 * @param analyzer object which will analyze memory accesses.
291 */
292void
296
297/**
298 * Tries to find annotations which tell the static registers
299 * from a program.
300 *
301 * Used only with the old gcc frontend.
302 *
303 * @param cs codesnippet where to search the annotations.
304 */
305void
308 std::map<int,TCEString>& registers) {
309 for (int i = 0; i < cs.instructionCount(); i++) {
310 Instruction& ins = cs.instructionAtIndex(i);
311 findStaticRegisters(ins, registers);
312 }
313}
314
315/**
316 * Tries to find annotations which tell the static registers
317 * from a program.
318 *
319 * Used only with the old gcc frontend.
320 *
321 * @param cfg cfg where to search the annotations.
322 */
323void
325 ControlFlowGraph& cfg,
326 std::map<int,TCEString>& registers) {
327 for (int i = 0; i < cfg.nodeCount(); i++) {
328 BasicBlockNode& bbn = cfg.node(i);
329 if (bbn.isNormalBB()) {
330 findStaticRegisters(bbn.basicBlock(), registers);
331 }
332 }
333}
334
335/**
336 * Tries to find annotations which tell the static registers
337 * from a program.
338 *
339 * Used only with the old gcc frontend.
340 *
341 * @param ins instruction where to search the annotations.
342 */
343void
346 std::map<int,TCEString>& registers) {
347
348 try {
349 for (int i = 0; i < ins.moveCount(); i++) {
350 Move& move = ins.move(i);
351 for (int j = 0; j < move.annotationCount(); j++) {
352 ProgramAnnotation anno = move.annotation(j);
353 switch (anno.id()) {
356 move.source());
357 break;
358 }
361 move.destination());
362 break;
363 }
366 move.source());
367 break;
368 }
371 move.destination());
372 break;
373 }
375/* this fixes one unit test silent breakage but another will then happen - unit test
376 tpef's seem to contain a bit broken code
377 Terminal& src = move.source();
378 if (!src.isGPR()) {
379 break;
380 }
381*/
382 TCEString reg =
384 registers[
386 reg;
387 allParamRegs_.insert(reg);
388 break;
389 }
391 TCEString reg =
393 registers[
395 reg;
396 allParamRegs_.insert(reg);
397 break;
398 }
399 default:
400 //TODO: frame pointer, not yet implemented
401 break;
402 }
403 }
404 }
405 } catch (std::bad_cast& e) {
406 throw IllegalProgram(__FILE__,__LINE__, __func__, "Illegal annotation");
407 }
408}
409
410/**
411 * Initializes the static register table from register from
412 * UniversalMachine.
413 *
414 * Needed for analysis of data dependencies of parameter registers,
415 * SP, RV etc.
416 *
417 * @param um UniversalMachine
418 * @param registers map where to store those registers.
419 */
420void
422 const UniversalMachine& um, std::map<int,TCEString>& registers) {
424
425 for (int i = 0; i < 6; i++) {
426 TerminalRegister tr(*rf.port(0), i);
428 registers[i] = reg;
429 if (i > REG_SP) {
430 allParamRegs_.insert(reg);
431 }
432 }
433}
434
435///////////////////////////////////////////////////////////////////////////////
436// End of initializations
437///////////////////////////////////////////////////////////////////////////////
438
439///////////////////////////////////////////////////////////////////////////////
440// Single-BB DDG construction
441///////////////////////////////////////////////////////////////////////////////
442
443/**
444 * Creates new Data Dependence Graph for the given basic block.
445 *
446 * Client has to delete the graph when it is not anymore used.
447 *
448 * @param bb BasicBlockNode whose data dependence graph to build.
449 * @param registerAntidependenceLevel which reg antidependencies to create
450 * @param createMemAndFUDeps whether to create also memory and
451 * fu state(side effect) dependencies or only register deps.
452 * @return new DataDependence Graph.
453 *
454 */
457 BasicBlock& bb,
458 DataDependenceGraph::AntidependenceLevel registerAntidependenceLevel,
459 const TTAMachine::Machine& mach,
460 const TCEString& ddgName,
461 const UniversalMachine* um,
462 bool createMemAndFUDeps,
464
465 mach_ = &mach;
466 if (AA) {
467 for (unsigned int i = 0; i < aliasAnalyzers_.size(); i++) {
468 LLVMAliasAnalyzer* llvmaa =
469 dynamic_cast<LLVMAliasAnalyzer*>(aliasAnalyzers_[i]);
470 if (llvmaa != NULL) {
471 llvmaa->setLLVMAA(AA);
472 }
473 }
474 }
475 if (bb.liveRangeData_ == NULL) {
477 }
478
479 currentBB_ = new BasicBlockNode(bb);
481 allParamRegs_, ddgName, registerAntidependenceLevel, currentBB_,
482 false,true);
483 // GRR, start and end addresses are lost..
484
486
487 if (um != NULL) {
489 } else {
491 }
492 try {
493 // first phase. registers , ops and PO's.
496 if (createMemAndFUDeps) {
497 //second phase. mem and fu state deps
500 }
501 } catch (Exception&) {
502 delete currentDDG_; currentDDG_ = NULL;
503 delete currentData_; currentData_ = NULL;
504 delete currentBB_; currentBB_ = NULL;
505 throw;
506 }
507
508 clearUnneededBookkeeping(bb, false);
509
510 delete currentData_;
511 currentData_ = NULL;
512 currentDDG_->setMachine(mach);
513 return currentDDG_;
514}
515
516/**
517 * Constructs a Data Dependence Graph for a single basic block.
518 *
519 * Goes thru all moves in the basic block and analyzes their dependencies,
520 * creates their ProgramOperations, MoveNodes and Edges,
521 * and adds the nodes and edges to the graph.
522 * Also used inside implementation of multi-BB-DDG-code.
523 * BB being analyzed has to be already set in member variable currentBB_,
524 * and the graph created and set into member variable currentBB_.
525 *
526 * @param bbd basic block to constructs.
527 * @param phase whether to handle register& operation deps or
528 * memory and side-effect dependencies.
529 */
530void
532 BBData& bbd, ConstructionPhase phase) {
533
534 currentData_ = &bbd;
535 currentBB_ = bbd.bblock_;
536
537 // Parallel inline asm block are already marked as scheduled
538 // TODO: should BBN have isInlineAsm() method?
539 if (currentBB_->isScheduled()) {
541 } else {
543 }
544}
545
546/**
547 * Constructs a Data Dependence Graph for a single basic block.
548 *
549 * Goes thru all moves in the basic block and analyzes their dependencies,
550 * creates their ProgramOperations, MoveNodes and Edges,
551 * and adds the nodes and edges to the graph.
552 * Also used inside implementation of multi-BB-DDG-code.
553 * BB being analyzed has to be already set in member variable currentBB_,
554 * and the graph created and set into member variable currentBB_.
555 *
556 * @param phase whether to handle register& operation deps or
557 * memory and side-effect dependencies.
558 */
559void
561 ConstructionPhase phase) {
562
563 for (int ia = 0; ia < currentBB_->basicBlock().instructionCount(); ia++) {
565
566 for (int i = 0; i < ins.moveCount(); i++) {
567 auto movePtr = ins.movePtr(i);
568 Move& move = *movePtr;
569
570 MoveNode* moveNode = NULL;
571
572 // if phase is 0, create the movenode, and handle guard.
574 /* In case using the LLVMTCEIRBuilder, the POs have been built already
575 and set to corresponding TerminalFUPorts. Use those MoveNodes and
576 ProgramOperations instead of creating new ones here. NOTE: the
577 ownership of the MoveNodes is transferred to the DDG.
578 */
579 if (move.destination().isFUPort() &&
580 dynamic_cast<TerminalFUPort&>(move.destination()).
581 hasProgramOperation()) {
583 dynamic_cast<TerminalFUPort&>(move.destination()).
584 programOperation();
585 if (po->hasMoveNodeForMove(move)) {
586 moveNode = &po->moveNode(move);
587 } else {
588 // the po might be corrupted and point to an old POM's Moves
589 moveNode = new MoveNode(movePtr);
590 }
591 } else if (move.source().isFUPort() &&
592 dynamic_cast<TerminalFUPort&>(move.source()).
593 hasProgramOperation()) {
595 dynamic_cast<TerminalFUPort&>(move.source()).
596 programOperation();
597 if (po->hasMoveNodeForMove(move)) {
598 moveNode = &po->moveNode(move);
599 } else {
600 // the po might be corrupted and point to an old POM's Moves
601 moveNode = new MoveNode(movePtr);
602 }
603 } else {
604 moveNode = new MoveNode(movePtr);
605 }
606 currentDDG_->addNode(*moveNode, *currentBB_);
607
608 if (!move.isUnconditional()) {
609 processGuard(*moveNode);
610 }
611
612 processSource(*moveNode);
613
614 } else {
615 // on phase 2, just find the already created movenode.
616 moveNode = &currentDDG_->nodeOfMove(move);
617 }
618
619 // destinaition need to be processed in both phases 0 and 1.
620 processDestination(*moveNode, phase);
621 }
622 }
623
624 // these are needed no more.
626
627 // Checks if we have some unready program operations at the end
628 // of a basic block.
629 if (currentData_->destPending_ != NULL ||
630 currentData_->readPending_ != NULL) {
631
632 TCEString msg = TCEString("Basic block ")
634 + TCEString(" - ")
636 + TCEString(", size : ")
639 + TCEString(" handled but we have unready PO at: ")
640 + currentDDG_->name()
641 + TCEString(", probably an operation without result move?");
642
643 if (currentData_->readPending_ != NULL) {
644 msg += "\n\tmissing read: " +
645 TCEString(currentData_->readPending_->operation().name());
646 }
647
648 if (currentData_->destPending_ != NULL) {
649 msg += "\n\tmissing dest: " +
650 TCEString(currentData_->destPending_->operation().name());
651 }
652
653 if (cfg_ != NULL) {
654 cfg_->writeToDotFile("constructBBbroken_cfg.dot");
655 }
656
657 throw IllegalProgram(__FILE__,__LINE__,__func__, msg);
658 }
659}
660
661/**
662 * Same as constructIndividualBB() but for already fully scheduled and inline
663 * asm BB.
664 *
665 * @Note: currently, this does not really construct DDG - just creates
666 * dummy MoveNodes.
667 */
668void
670 ConstructionPhase phase) {
671
673 return;
674 }
675 auto& bb = currentBB_->basicBlock();
677 for (int ia = 0; ia < bb.instructionCount(); ia++) {
678 Instruction& ins = bb.instructionAtIndex(ia);
679 for (int i = 0; i < ins.moveCount(); i++) {
680 MoveNode* moveNode = new MoveNode(ins.movePtr(i));
681 currentDDG_->addNode(*moveNode, *currentBB_);
682 }
683 }
684
685 // Process live range with dummy move nodes.
686 assert(bb.liveRangeData_);
687 LiveRangeData& liveRangeData = *bb.liveRangeData_;
688 std::set<TCEString> actualRegUses;
689 std::set<TCEString> actualRegDefs;
690 for (int i = 0; i < bb.instructionCount(); i++) {
691 auto& ins = bb.instructionAtIndex(i);
692 for (int m = 0; m < ins.moveCount(); m++) {
693 auto& move = ins.move(m);
694
695 auto rdReg = move.source().isGPR() ? move.source().toString()
696 : TCEString("");
697 if (!rdReg.empty()) actualRegUses.insert(rdReg);
698
699 if (move.isConditional()) {
700 const Guard& grd = move.guard().guard();
701 const RegisterGuard* grdReg =
702 dynamic_cast<const RegisterGuard*>(&grd);
703 if (grdReg) {
704 TCEString regName = grdReg->registerFile()->name() + '.' +
706 actualRegUses.insert(regName);
707 }
708 }
709
710 auto wrReg = move.destination().isGPR()
711 ? move.destination().toString()
712 : TCEString("");
713 if (!wrReg.empty()) actualRegDefs.insert(wrReg);
714 }
715 }
716
717 auto& iaRegUses = liveRangeData.inlineAsmRegUses_;
718 auto effectiveRegUses = SetTools::intersection(iaRegUses, actualRegUses);
719 for (auto reg : effectiveRegUses) {
720 MoveNode* moveNode = new MoveNode();
721 currentDDG_->addNode(*moveNode, *currentBB_);
722 liveRangeData.regFirstUses_[reg].insert(*moveNode);
723 currentDDG_->updateRegUse(*moveNode, reg, bb);
724 }
725
726 auto& iaRegDefs = liveRangeData.inlineAsmRegDefs_;
727 auto effectiveRegDefs = SetTools::intersection(iaRegDefs, actualRegDefs);
728 for (auto reg : effectiveRegDefs) {
729 MoveNode* moveNode = new MoveNode();
730 currentDDG_->addNode(*moveNode, *currentBB_);
731 liveRangeData.regDefines_[reg].insert(*moveNode);
732 MoveNodeUse mnd(*moveNode);
733 liveRangeData.regKills_[reg] = std::make_pair(mnd, mnd);
734 }
735
736 for (auto& reg : liveRangeData.inlineAsmClobbers_) {
737 MoveNode* moveNode = new MoveNode();
738 currentDDG_->addNode(*moveNode, *currentBB_);
739 liveRangeData.regDefines_[reg].insert(*moveNode);
740 MoveNodeUse mnd(*moveNode);
741 liveRangeData.regKills_[reg] = std::make_pair(mnd, mnd);
742 }
743
744 // Not needed anymore.
745 liveRangeData.inlineAsmRegUses_.clear();
746 liveRangeData.inlineAsmRegDefs_.clear();
747 liveRangeData.inlineAsmClobbers_.clear();
748}
749
750/**
751 * Analyzes dependencies related to guard usage.
752 *
753 * Finds the guard register used for the guard and the move
754 * Which writes the guard register, and creates a guard egde
755 * between them.
756 *
757 * @param moveNode MNData of move containing guarded move.
758 */
759void
761
762 // new code
763 const Guard& g = moveNode.move().guard().guard();
764 const RegisterGuard* rg = dynamic_cast<const RegisterGuard*>(&g);
765 if (rg != NULL) {
766 TCEString regName = rg->registerFile()->name() + '.' +
768 processRegUse(MoveNodeUse(moveNode, true),regName);
769 } else {
770 throw IllegalProgram(
771 __FILE__,__LINE__,__func__,
772 "Analysis for port guards not supported! used in: "
773 + moveNode.toString());
774 }
775}
776
777/**
778 * Analysis a source of a move and processes it's dependencies,
779 * and if it's a result read then also participates in ProgramOperation
780 * creation.
781 *
782 * @param moveNode Movenode being analyzed.
783 */
784void
786 Terminal& source = moveNode.move().source();
787
788 // is this result move of an operation?
789 if (source.isFUPort()) {
790 if (!(dynamic_cast<const SpecialRegisterPort*>(&source.port()))) {
791 processResultRead(moveNode);
792 } else {
793 // handle read from RA.
794 processRegUse(MoveNodeUse(moveNode, false, true), RA_NAME);
795
796 if (moveNode.move().isReturn()) {
797 processReturn(moveNode);
798 }
799 }
800 } else {
801 if (source.isGPR()) {
802 TerminalRegister& tr = dynamic_cast<TerminalRegister&>(source);
804 processRegUse(MoveNodeUse(moveNode), regName);
805 }
806 }
807}
808
809
811 int destIndex = mn.move().destination().operationIndex();
812 const Operation& op = mn.destinationOperation().operation();
813 int triggerIndex = MachineInfo::triggerIndex(*mach_, op);
814 switch (triggerIndex) {
815 case -1: {
816 TCEString msg = "Trigger index ambiguous for operation: ";
817 msg << op.name() << " in the machine.";
818 throw IllegalMachine(__FILE__,__LINE__,__func__, msg);
819 break;
820 }
821 case 0: {
822 TCEString msg = "Operation: ";
823 msg << op.name() << " Not found from the machine";
824 throw CompileError(__FILE__,__LINE__,__func__, msg);
825 break;
826 }
827 default:
828 return triggerIndex == destIndex;
829 }
830}
831
832/**
833 * Analyzes destination of a move.
834 * Updates bookkeeping and handles WaW and WaR dependencies of the move.
835 *
836 * Checks whether destination is operation or register and calls other
837 * functions to do the actual dependence checks etc.
838 *
839 * @param moveNode MoveNode whose destination is being processed.
840 * @param phase whether to handle register& operation deps or
841 * memory and side-effect dependencies.
842 */
843void
845 MoveNode& moveNode, ConstructionPhase phase) {
846 Terminal& dest = moveNode.move().destination();
847
848 // is this a operand to an operation?
849 if (dest.isFUPort()) {
850 if (!(dynamic_cast<const SpecialRegisterPort*>(&dest.port()))) {
851 TerminalFUPort& tfpd = dynamic_cast<TerminalFUPort&>(dest);
852 Operation &dop = tfpd.hintOperation();
853
855 if (tfpd.isOpcodeSetting()) {
857 moveNode, dop);
858 } else {
859 processOperand(moveNode, dop);
860 }
861 } else { // memory and fu state deps
862 if (dop.usesMemory() || dop.hasSideEffects() ||
863 dop.affectsCount() || dop.affectedByCount() ||
864 moveNode.move().isControlFlowMove()) {
865 if (isTriggering(moveNode)) {
866 processTriggerMemoryAndFUStates(moveNode, dop);
867 }
868 }
869 }
870 } else { // RA write
872 processRegWrite(MoveNodeUse(moveNode,false,true), RA_NAME);
873 }
874 }
875 } else {
876 if (dest.isGPR()) {
877 // we do not care about register reads in second phase
879 TerminalRegister& tr = dynamic_cast<TerminalRegister&>(dest);
881 processRegWrite(MoveNodeUse(moveNode), regName);
882 }
883 } else { // something else
884 throw IllegalProgram(__FILE__,__LINE__,__func__,
885 "Move has illegal destination" +
886 moveNode.toString());
887 }
888 }
889}
890
891/**
892 * Clears bookkeeping which is only needed during ddg construction.
893 *
894 * @param BB containing basic blocks which contain the bookkeeping.
895 * @param interBBInformation needed whether information about inter-bb-
896 * dependencies need to be left intact.
897 */
898void
900 BasicBlock& bb, bool interBBInformationNeeded) {
901
902 if (!interBBInformationNeeded) {
903 //used by regcopyadder.
905 bb.liveRangeData_->regLastUses_.clear();
906
907 // used by both
908 bb.liveRangeData_->regDefines_.clear();
909
910 // these are neede for live range things
911 bb.liveRangeData_->regDefReaches_.clear();
913 bb.liveRangeData_->regFirstUses_.clear();
914 }
915 bb.liveRangeData_->regUseReaches_.clear();
916 bb.liveRangeData_->regLastKills_.clear();
917
918 bb.liveRangeData_->regDefAfter_.clear();
919 bb.liveRangeData_->regUseAfter_.clear();
920
921 bb.liveRangeData_->memDefines_.clear();
922 bb.liveRangeData_->memLastUses_.clear();
923
924 bb.liveRangeData_->memFirstUses_.clear();
926
927 bb.liveRangeData_->memDefReaches_.clear();
928 bb.liveRangeData_->memUseReaches_.clear();
929
930 bb.liveRangeData_->fuDepReaches_.clear();
931 bb.liveRangeData_->fuDeps_.clear();
932 bb.liveRangeData_->fuDepAfter_.clear();
933
935}
936
937///////////////////////////////////////////////////////////////////////////////
938// ProgramOperation and Operation edges.
939///////////////////////////////////////////////////////////////////////////////
940
941/**
942 * Handles ProgramOperation creation for a triggering move.
943 *
944 * @param moveNode triggering movenode.
945 * @param dop operation which is being triggered by the movenode.
946 */
947void
949 MoveNode& moveNode, Operation& dop) {
950 if (currentData_->destPending_ != NULL) {
952
953 if (&dop != &po->operation()) {
954 std::cerr << "pending po: " << po->toString() << std::endl;
955 std::cerr << "current dop: " << dop.name() << std::endl;
956 currentDDG_->writeToDotFile("build_fail_po.dot");
957 }
958 assert(&dop == &po->operation());
959 if (!po->isComplete()) {
960 po->addInputNode(moveNode);
961 moveNode.addDestinationOperationPtr(po);
962 }
963 if (po->isReady()) {
965 if (dop.numberOfOutputs() > 0) {
969 } else {
971 }
972 } else {
973 throw IllegalProgram(
974 __FILE__, __LINE__, __func__,
975 "Trigger before all operands.");
976 }
977 return;
978 }
979 // only one triggering input?
980 if (dop.numberOfInputs() == 1) {
981 TerminalFUPort& tfpd =
982 dynamic_cast<TerminalFUPort&>(moveNode.move().destination());
984 if (tfpd.hasProgramOperation()) {
985 po = tfpd.programOperation();
986 } else {
988 moveNode.addDestinationOperationPtr(po);
989 po->addInputNode(moveNode);
990 }
991 if (dop.numberOfOutputs()) {
994 } else {
996 }
997 } else { // trigger came too early
998 const TCEString moveDisasm =
1000 throw IllegalProgram(
1001 __FILE__,__LINE__, __func__,
1002 TCEString("Trigger without operand in ") + moveDisasm);
1003 }
1004}
1005
1006/**
1007 * Analyze write to a trigger of an operation.
1008 *
1009 * Participates in ProgramOperation building. Calls
1010 * createTriggerDependencies(moveNode, dop) to create the register and
1011 * operation dependence egdes of the operation. Checks if operation is
1012 * call and if it is, processes the call-related register dependencies.
1013 *
1014 * @param moveNode mnData related to a move which triggers an operation
1015 * @param dop Operation being triggered
1016 */
1017void
1019 MoveNode& moveNode, Operation& dop) {
1020
1021 processTriggerPO(moveNode, dop);
1022
1023 if (moveNode.move().isFunctionCall()) {
1024 processCall(moveNode);
1025 }
1026}
1027
1028/**
1029 * Analyze write to a trigger of an operation.
1030 *
1031 * Participates in ProgramOperation building. Calls
1032 * createTriggerDependencies(moveNode, dop) to create the memory and
1033 * fu state dependence egdes of the operation. Checks if operation is
1034 * call and if it is, processes the call-related memory dependencies.
1035 *
1036 * @param moveNode mnData related to a move which triggers an operation
1037 * @param dop Operation being triggered
1038 */
1039void
1041 MoveNode& moveNode, Operation &dop) {
1042
1043 createTriggerDependencies(moveNode, dop);
1044
1045 // handle call mem deps
1046 if (moveNode.move().isFunctionCall()) {
1047 // no guard, is not ra, is pseudo.
1048 MoveNodeUse mnd2(moveNode, false, false, true);
1049 processMemWrite(mnd2);
1050 }
1051}
1052
1053/**
1054 * Analyzes operand writes.
1055 *
1056 * Part of ProgramOperation creation.
1057 *
1058 * @param moveNode mnData related to a move which writes a parameter.
1059 * @param dop Operation whose parameter is being written.
1060 */
1061void
1063 MoveNode& moveNode, Operation &dop) {
1064
1065 // first operands already analyzed for PO?
1066 // then update existing.
1067 if (currentData_->destPending_ != NULL) {
1069
1070 assert(&dop == &po->operation());
1071
1072 if (!po->isComplete()) {
1073 po->addInputNode(moveNode);
1074 moveNode.addDestinationOperationPtr(po);
1075 } else {
1076 // The MoveNode and the PO has been created before entering DDG
1077 // building (in LLVMTCEBuilder.cc).
1078 }
1079 return;
1080 }
1081
1082 // create a new ProgramOperation
1083 TerminalFUPort& tfpd =
1084 dynamic_cast<TerminalFUPort&>(moveNode.move().destination());
1086 if (tfpd.hasProgramOperation()) {
1087 po = tfpd.programOperation();
1088 } else {
1090 moveNode.addDestinationOperationPtr(po);
1091 po->addInputNode(moveNode);
1092 }
1094}
1095
1096/**
1097 * Analyzes a source of a result read.
1098 *
1099 * Handles program operation creation and operation dependence creation.
1100 *
1101 * @param moveNode MoveNode of the move being analyzed.
1102 */
1103void
1105
1106 // Goes thru all programoperations lacking result read.
1107 // There should be only one if well-behaving
1108 // universalmachine code.
1109 if (currentData_->readPending_ != NULL) {
1112
1113 if (!po->isComplete()) {
1114 po->addOutputNode(moveNode);
1115 moveNode.setSourceOperationPtr(po);
1116 }
1117
1118 // if this PO is ready, remove from list of incomplete ones
1120 po->operation().numberOfOutputs()) {
1125 }
1126 return;
1127 }
1128 throw IllegalProgram(
1129 __FILE__, __LINE__, __func__,
1130 (boost::format("Result move '%s' without operands") %
1131 moveNode.move().toString()).str());
1132}
1133
1134/**
1135 * Creates operand edges between input and output moves of a
1136 * programoperation.
1137 *
1138 * @param po ProgramOperation whose egdes we are creating.
1139 */
1140void
1143
1144 const Operation& op = po->operation();
1145
1146 // loop over all input nodes
1147 for (int i = 0; i < po->inputMoveCount(); i++) {
1148 MoveNode& inputNode = po->inputMove(i);
1149 // loop over all output nodes.
1150 for (int j = 0; j < po->outputMoveCount(); j++) {
1151 MoveNode& outputNode = po->outputMove(j);
1152
1153 // and create operation edges
1154 // from all input nodes to all
1155 // output nodes.
1156 DataDependenceEdge* dde =
1160 op.name());
1161
1163 inputNode, outputNode, dde);
1164 }
1165 }
1166}
1167
1168///////////////////////////////////////////////////////////////////////////////
1169// Register edge creation.
1170///////////////////////////////////////////////////////////////////////////////
1171
1172/**
1173 * Checks whether there is a previous alive write with same guard than
1174 * given node.
1175 *
1176 * The origin of the guard value is tracked from DDG, not only plain guard
1177 * is done.
1178 *
1179 * @param mnd MoveNode containing the guard.
1180 * @param defines set of earlier writes which to check.
1181 */
1182bool
1184 MoveNodeUse& mnd, std::set<MoveNodeUse>& defines) {
1185
1186 // first just check if there is earlier write to this reg with same guard..
1187 for (std::set<MoveNodeUse>::iterator i = defines.begin();
1188 i != defines.end(); i++) {
1189 // if earlier write to this reg with same guard..
1190 if (!mnd.guard() &&
1191 !i->mn()->move().isUnconditional() &&
1192 currentDDG_->sameGuards(*(i->mn()), *(mnd.mn()))) {
1193 return true;
1194 }
1195 }
1196 return false;
1197}
1198
1199std::set<MoveNodeUse>
1201 MoveNodeUse& mnd, std::set<MoveNodeUse>& defines) {
1202
1203 std::set<MoveNodeUse> results;
1204 // first just check if there is earlier write to this reg with same guard..
1205 for (std::set<MoveNodeUse>::iterator i = defines.begin();
1206 i != defines.end(); i++) {
1207 // if earlier write to this reg with same guard..
1208 if (!mnd.guard() &&
1209 !i->mn()->move().isUnconditional() &&
1210 currentDDG_->sameGuards(*(i->mn()), *(mnd.mn()))) {
1211 results.insert(*i);
1212 }
1213 }
1214 return results;
1215}
1216
1217
1218/**
1219 * Handles a usage of a register value.
1220 *
1221 * The usage can be either register read or guard usage.
1222 * Creates the incoming edges and handles bookkeping related to the
1223 * register read.
1224 *
1225 * @param mnd Data about the register use
1226 * @param reg Register containing the value being used.
1227 */
1228void
1230 MoveNodeUse mnd, const TCEString& reg) {
1231
1232 // We may have multiple definitions to a register alive
1233 // (statically) at same time if some of the writes were guarded,
1234 // so we don't know which of them were actually executed,
1235 // so we have a set instead of single value.
1236 std::set<MoveNodeUse>& defines =
1238
1239 std::set<MoveNodeUse> sameGuardDefines = earlierWritesWithSameGuard(mnd, defines);
1240 // find if we have a earlier write with same guard. In this case
1241 // no need to draw dependencies over it.
1242 bool guardedKillFound = !sameGuardDefines.empty();
1243
1244 // then create the edges. if no guarded kill found,
1245 // all non-exclusive. if guarded kill found, not to uncond move.
1246 for (std::set<MoveNodeUse>::iterator i = defines.begin();
1247 i != defines.end(); i++) {
1248 // If we do not have a guarded kill, draw edges from all defines.
1249 // If we have a guarded kill, only draw edges from
1250 // unconditional moves, as the guarded kill overshadows the
1251 // inconditional writes.
1252 if (!guardedKillFound || (!i->mn()->move().isUnconditional() &&
1253 !currentDDG_->hasRegWaw(*i, sameGuardDefines))) {
1254 if (!currentDDG_->exclusingGuards(*(i->mn()), *(mnd.mn()))) {
1255 DataDependenceEdge* dde =
1259 DataDependenceEdge::DEP_RAW, reg, mnd.guard(), false,
1260 i->pseudo(), mnd.pseudo(), i->loop());
1261
1262 currentDDG_->connectOrDeleteEdge(*i->mn(), *mnd.mn(), dde);
1263 }
1264 }
1265 }
1266
1267 // writes in previous BB's killed or not?
1268 // if not(this bb has a kill), has to check deps from incoming BB's.
1269 if (currentBB_->basicBlock().liveRangeData_->regKills_.find(reg) ==
1271
1272 if (!guardedKillFound) {
1273 // process dependencies from previous BB's
1275 insert(mnd);
1276
1278 }
1279 }
1280 currentBB_->basicBlock().liveRangeData_->regLastUses_[reg].insert(mnd);
1281
1282 // Two writes to opposite guard may create a combined kill-pair.
1283 // But if this is a read between them, it has to be marked in order
1284 // to save bookkeeping about this move when the another write occurs.
1285 // So mark here that we have a read if we have one guarded write
1286 // in our bookkeeping as potential half of a kill pair.
1287 std::map<TCEString, std::pair<MoveNodeUse, bool> >::iterator iter =
1290 iter->second.second = true;
1291 }
1292}
1293
1294/**
1295 * Creates register antidependencies from set of movenodeuses to one movenode.
1296 *
1297 * @param mnd Movenode which to creat those dependencies
1298 * @param predecessorNodes Nodes where to create dependencies from
1299 * @param depType whether to create WAR or WAW antidependencies
1300 * @param guardedKillFound if there is a write with same guard to the reg.
1301 */
1302void
1304 const TCEString& reg, MoveNodeUse& mnd,
1305 MoveNodeUseSet& predecessorNodes,
1307 bool guardedKillFound) {
1308
1309 // create dep to another in own bb
1310 for (std::set<MoveNodeUse>::iterator i = predecessorNodes.begin();
1311 i != predecessorNodes.end();) {
1312
1313 if (depType == DataDependenceEdge::DEP_WAW) {
1314 // If we do not have a guarded kill, draw edges from all defines.
1315 // If we have a guarded kill, only draw edges from
1316 // unconditional moves, as the guarded kill overshadows the
1317 // inconditional writes.
1318 if (guardedKillFound && i->mn()->move().isUnconditional()) {
1319 i++;
1320 continue;
1321 }
1322 } else {
1324 // skip if war to itself, ie move foo.1 -> foo.1
1325 if (i->mn() == mnd.mn()) {
1326 i++;
1327 continue;
1328 }
1329 }
1330
1331 // Do not create antideps if have excluding guards
1332 // But always create antidep if this writes to a reg which is
1333 // used as guard for the previous move.
1334 if (!currentDDG_->exclusingGuards(*(i->mn()), *(mnd.mn())) ||
1335 i->guard()) {
1336
1337 // create dependency edge
1338 DataDependenceEdge* dde =
1342 depType, reg, i->guard(), false,
1343 i->pseudo(), mnd.pseudo(), i->loop());
1344
1345 // and connect
1346 currentDDG_->connectOrDeleteEdge(*i->mn(), *mnd.mn(), dde);
1347
1348 // if have same guards, remove the old from bookkeeping
1349 // this completely overshadows it
1350 if (currentDDG_->sameGuards(*(i->mn()), *(mnd.mn()))) {
1351 predecessorNodes.erase(i++);
1352 continue;
1353 }
1354 }
1355 i++;
1356 }
1357}
1358
1359
1360/**
1361 * Analyzes a write to a register.
1362 *
1363 * Creates dependence edges and updates bookkeeping.
1364 *
1365 * @param mnd MoveNodeUse containing MoveNode that writes a register
1366 * @param reg register being written by the given movenode.
1367 */
1368void
1370 MoveNodeUse mnd, const TCEString& reg) {
1371
1372 // We may have multiple definitions to a register alive
1373 // (statically) at same time if some of the writes were guarded,
1374 // so we don't know which of them were actually executed,
1375 // so we have a set instead of single value.
1376 std::set<MoveNodeUse>& defines =
1378
1379 // Set of register reads which after last kill.
1380 std::set<MoveNodeUse>& lastUses =
1382
1383 // find if we have a earlier write with same guard. In this case
1384 // no need to draw dependencies over it.
1385 bool guardedKillFound = hasEarlierWriteWithSameGuard(mnd, defines);
1386
1387 // if no kills to this reg in this BB, this one kills it.
1388 if (currentBB_->basicBlock().liveRangeData_->regKills_.find(reg) ==
1390
1391 // is this alone a kill?
1392 if (mnd.mn()->move().isUnconditional()) {
1393 currentBB_->basicBlock().liveRangeData_->regKills_[reg].first = mnd;
1395 } else {
1396 // two guarded moves with opposite guards together may be a kill.
1397 // Check if we have such previous guarded write with opposite
1398 // guard.
1399 std::map<TCEString, std::pair<MoveNodeUse, bool> >::iterator
1400 iter =
1404 *(iter->second.first.mn()), *(mnd.mn()))) {
1406 iter->second.first;
1407 currentBB_->basicBlock().liveRangeData_->regKills_[reg].second = mnd;
1408 }
1409 }
1410 if (!guardedKillFound) {
1411 // may have incoming WaW's / WaRs to this
1412 // insert to bookkeeping for further analysis.
1414
1415 // do we need to create some inter-bb-antideps?
1417 // deps from other BB.LIVERANGEDATA_->
1419 mnd, reg, currentBB_->basicBlock());
1420 }
1421 }
1422 }
1423
1424 // Create antideps to defines and uses in this same BB.LIVERANGEDATA_->
1427 reg, mnd, defines, DataDependenceEdge::DEP_WAW, guardedKillFound);
1428
1430 reg, mnd, lastUses, DataDependenceEdge::DEP_WAR,
1431 guardedKillFound);
1432 }
1433
1434 // if unconditional, this kills previous deps.
1435 if (mnd.mn()->move().isUnconditional()) {
1436 defines.clear();
1437
1440
1441 // clear reads to given reg.
1442 lastUses.clear();
1444 } else {
1445 // two guarded moves with opposite guards together may be a kill.
1446 // Check if we have such previous guarded write with opposite
1447 // guard.
1448 std::map<TCEString, std::pair<MoveNodeUse, bool> >::iterator iter =
1452 *(iter->second.first.mn()), *(mnd.mn()))) {
1453
1454 // found earlier write which is exclusive with this one.
1455 // mark that these two together are a kill.
1457 iter->second.first;
1458 currentBB_->basicBlock().liveRangeData_->regLastKills_[reg].second = mnd;
1459
1460 // If we have no usage of the register between these two
1461 // writes forming the kill pair, we can clear our bookkeeping.
1462
1463 // only leave the other part of the kill to defines.
1464 defines.clear();
1465 defines.insert(iter->second.first);
1466
1467 if (!iter->second.second) {
1468 // clear reads to given reg.
1469 lastUses.clear();
1470 }
1471 }
1473 std::pair<MoveNodeUse, bool>(mnd, false);
1474 }
1475 defines.insert(mnd);
1476}
1477
1478/**
1479 * Processes a return from a function.
1480 *
1481 * Creates pseudo-read-deps to SP and RV registers.
1482 *
1483 * @param moveNode moveNode containg the return move.
1484 */
1485void
1488
1489 // return is considered as read of sp;
1490 // sp must be correct at the end of the procedure.
1491 if (sp != "") {
1492 processRegUse(MoveNodeUse(moveNode,false,false,true),sp);
1493 }
1494
1495 // return is considered as read of RV.
1497 if (rv != "") {
1498 processRegUse(MoveNodeUse(moveNode,false,false,true),rv);
1499 }
1500
1501 // process all vector rv values
1502 for (int i = REG_VRV;;i--) {
1503 auto vrvIt = specialRegisters_.find(i);
1504 if (vrvIt != specialRegisters_.end()) {
1506 MoveNodeUse(moveNode,false,false,true),vrvIt->second);
1507 } else {
1508 break;
1509 }
1510 }
1511
1512 // return is also considered as read of RV high(for 64-bit RV's)
1514 if (rvh != "") {
1515 processRegUse(MoveNodeUse(moveNode,false,false,true),rvh);
1516 }
1517
1519 if (fp != "") {
1520 processRegUse(MoveNodeUse(moveNode,false,false,true),fp);
1521 }
1522}
1523
1524/**
1525 * Processes a call of a function.
1526 *
1527 * Pseudo-reads from parameter registers and SP, writes to RV and RA.
1528 *
1529 * @param mn MoveNode containg the function call move.
1530 */
1531void
1533
1534 // calls mess up RA. But immediately, not after delay slots?
1536 MoveNodeUse(mn, false, true, false), RA_NAME);
1537
1538 // MoveNodeUse for sp and rv(not guard, not ra, is pseudo)
1539 MoveNodeUse mnd2(mn, false,false, true);
1540
1541 // call is considered read of sp
1543 if (sp != "") {
1544 processRegUse(mnd2,sp);
1545 }
1546
1547 // call is considered as write of RV
1549 if (rv != "") {
1550 if (rvIsParamReg_) {
1551 processRegUse(mnd2,rv);
1552 }
1553 processRegWrite(mnd2,rv);
1554 }
1555
1556 // process all vector rv values
1557 for (int i = REG_VRV;;i--) {
1558 auto vrvIt = specialRegisters_.find(i);
1559 if (vrvIt != specialRegisters_.end()) {
1560 processRegWrite(mnd2, vrvIt->second);
1561 } else {
1562 break;
1563 }
1564 }
1565
1566 // call is considered as write of RV high (64-bit return values)
1568 if (rvh != "") {
1569 processRegWrite(mnd2, rvh);
1570 }
1571
1572 // params
1573 for (int i = 0; i < 4;i++) {
1575 if (paramReg != "") {
1576 processRegUse(mnd2, paramReg);
1577 }
1578 }
1579}
1580
1581///////////////////////////////////////////////////////////////////////////////
1582// Side-Effects of triggers.
1583///////////////////////////////////////////////////////////////////////////////
1584
1585/**
1586 * Analyzes operation of a trigger write.
1587 *
1588 * If memory read, calls processMemRead to manage memory read dependencies.
1589 * Manages FU State dependencies between operations.
1590 *
1591 * @param moveNode mnData related to a move which triggers an operation
1592 * @param dop Operation being triggered
1593 *
1594 */
1595void
1597 MoveNode& moveNode, Operation& dop) {
1598
1599 if (dop.readsMemory()) {
1600 processMemUse(MoveNodeUse(moveNode));
1601 } //TODO: avoid drawing antidep to itself
1602
1603 if (dop.writesMemory()) {
1604 processMemWrite(MoveNodeUse(moveNode));
1605 }
1606
1610
1611 OperationPool pool;
1612 if (dop.hasSideEffects() || pool.sharesState(dop)) {
1613
1614 // remove old same op from bookkeeping.
1615 // this should prevent exponential explosion of edge count.
1616 if (dop.hasSideEffects() && moveNode.move().isUnconditional()) {
1617 for (MoveNodeUseSet::iterator iter =
1619 iter != currentBB_->basicBlock().liveRangeData_->fuDeps_.end(); iter++) {
1620
1621 const Operation& o =
1622 iter->mn()->destinationOperation().operation();
1623 if (&o == &dop) {
1625 break;
1626 }
1627 }
1628 }
1629 // add the new one to bookkeeping
1631 }
1632}
1633
1634/*
1635 * Creates operation side effect.
1636 *
1637 * Checks the given MoveNode against list of possible side effect
1638 * dependence sources, and creates side effect edges if there is
1639 * a side effect/fu state dependence.
1640 *
1641 * @param prevMoves moves to check side effects against.
1642 * @param mn moveNode that is the destination of the dependencies.
1643 * @param dop Operation that mn triggers.
1644 */
1645void
1647 MoveNodeUseSet& prevMoves, const MoveNode& mn, Operation& dop) {
1648
1649 OperationPool pool;
1650 if (pool.sharesState(dop) || dop.hasSideEffects()) {
1651 for (MoveNodeUseSet::iterator i = prevMoves.begin();
1652 i != prevMoves.end(); i++) {
1653 const Operation& o = i->mn()->destinationOperation().operation();
1654
1655 // mem writes are handled by memory deps so exclude here
1656 if ((&dop == &o && o.hasSideEffects()) ||
1657 dop.dependsOn(o) || o.dependsOn(dop)) {
1658 // if operations are always assigned to differnt FU,
1659 // skip creating dependency edge
1660 if (isAlwaysDifferentFU(&mn, i->mn())) continue;
1661
1662 if (!currentDDG_->exclusingGuards(*(i->mn()), mn)) {
1663 DataDependenceEdge* dde =
1666 DataDependenceEdge::DEP_UNKNOWN, false,false,false,
1667 false, static_cast<int>(i->loop()));
1669 *(i->mn()), mn, dde);
1670 }
1671 }
1672 }
1673 }
1674}
1675
1676
1677///////////////////////////////////////////////////////////////////////////////
1678// Memory edge creation.
1679///////////////////////////////////////////////////////////////////////////////
1680
1681/**
1682 * Checks if there is an earlier write to same address or with same guard.
1683 *
1684 * @param mnd the current node dictating guard and mem address to check.
1685 * @param defines set of earlier writes to check for the write.
1686 */
1687bool
1689 MoveNodeUse& mnd, std::set<MoveNodeUse>& defines) {
1690 // first just check if there is earlier write to this mem address
1691 // with same guard.
1692 for (std::set<MoveNodeUse>::iterator i = defines.begin();
1693 i != defines.end(); i++) {
1694 // if earlier write to this reg with same guard..
1695 if (currentDDG_->sameGuards(*(i->mn()), *(mnd.mn()))) {
1696 ProgramOperation& curPop = mnd.mn()->destinationOperation();
1697 ProgramOperation& prevPop = (i->mn())->destinationOperation();
1698// MoveNode* currentAddress = addressMove(*mnd.mn());
1699// MoveNode* prevAddress = addressMove(*(i->mn()));
1700 if (!isAddressTraceable(prevPop) ||
1701 analyzeMemoryAlias(prevPop, curPop, i->bbRelation()) ==
1703 return true;
1704 }
1705 }
1706 }
1707 return false;
1708}
1709
1710/**
1711 * Creates memory dependencies from set of nodes to given nodes.
1712 *
1713 * Does not create if gaurds of aliasing dictate edge not needed.
1714 * If both guard and aliasing indicate fully transitive case for some
1715 * prev nodes, then remove these previous nodes from the bookkeeping.
1716 */
1717void
1719 MoveNodeUse& mnd, std::set<MoveNodeUse>& prevNodes,
1721 bool traceable) {
1722 // create WaW to another in own bb
1723 for (MoveNodeUseSet::iterator iter =
1724 prevNodes.begin(); iter != prevNodes.end();) {
1725 if ((checkAndCreateMemDep(*iter, mnd, depType) || !traceable) &&
1726 (mnd.mn()->move().isUnconditional() ||
1727 currentDDG_->sameGuards(*(iter->mn()), *(mnd.mn())))) {
1728 // remove current element and update iterator to next.
1729 prevNodes.erase(iter++);
1730 } else { // just take next from the set
1731 iter++;
1732 }
1733 }
1734}
1735
1736/**
1737 * Updates memory operation bookkeeping and creates WaR and WaW
1738 * memory dependencies.
1739 *
1740 * @param moveNode MoveNodeUse related to Move whose memory write to are
1741 * processing.
1742 */
1743void
1745
1746 TCEString category = memoryCategory(mnd);
1747
1748 std::set<MoveNodeUse>& defines =
1750
1751 std::set<MoveNodeUse>& lastUses =
1753
1754 // check if no earlier barriers/kills to this one in this bb?
1755 if (currentBB_->basicBlock().liveRangeData_->memKills_[category].mn() == NULL) {
1756
1757 // is this a kill?
1758 if (mnd.mn()->move().isUnconditional() &&
1760 currentBB_->basicBlock().liveRangeData_->memKills_[category] = mnd;
1761 }
1762
1763 // check if there is "guarded kill" to this mem address
1764 bool guardedKillFound =
1766
1767 if (!guardedKillFound) {
1768 // may have incoming WaW's / WaRs to this
1769 currentBB_->basicBlock().liveRangeData_->memFirstDefines_[category].insert(mnd);
1770 updateMemWrite(mnd, category);
1771 }
1772 }
1773
1774 bool traceable = isAddressTraceable(mnd.mn()->destinationOperation());
1775
1777 mnd, defines, DataDependenceEdge::DEP_WAW, traceable);
1778
1780 mnd, lastUses, DataDependenceEdge::DEP_WAR, traceable);
1781
1782 // does this kill previous deps?
1783 if (mnd.mn()->move().isUnconditional() && !traceable) {
1785 defines.clear();
1786 lastUses.clear();
1787 }
1788
1789 defines.insert(mnd);
1790}
1791
1792/**
1793 * Processes a memory read.
1794 *
1795 * Creates dependence edges and updates bookkeeping.
1796 *
1797 * @param mnd MoveNodeUse of MoveNode being processed.
1798 */
1799void
1801
1802 TCEString category = memoryCategory(mnd);
1803
1804 // can be multiple if some write predicated
1805 std::set<MoveNodeUse>& defines =
1807
1808 // no kills/barriers to this one in this basic block.
1809 if (currentBB_->basicBlock().liveRangeData_->memKills_[category].mn() == NULL) {
1810
1811 // check if there is "guarded kill" to this mem address
1812 bool guardedKillFound =
1814
1815 if (!guardedKillFound) {
1816 currentBB_->basicBlock().liveRangeData_->memFirstUses_[category].insert(mnd);
1817 // so create deps from previous BB's
1818 updateMemUse(mnd, category);
1819 }
1820 }
1821
1822 // create deps from writes in this BB.LIVERANGEDATA_->
1823 for (MoveNodeUseSet::iterator iter =
1824 defines.begin(); iter != defines.end(); iter++) {
1826 }
1827 // update bookkeeping.
1828 currentBB_->basicBlock().liveRangeData_->memLastUses_[category].insert(mnd);
1829}
1830
1831/**
1832 * Compares a memory op against one previous memory ops and
1833 * creates dependence if may alias.
1834 *
1835 * @param prev Previous Memory write movenode
1836 * @param mn Current memory write movenode
1837 * @param depType dependence type which to create.
1838 * @return true if true alias.
1839 */
1840bool
1842 MoveNodeUse prev, MoveNodeUse mnd,
1844
1845 // cannot be dep if opposite guards.
1846 if (currentDDG_->exclusingGuards(*(prev.mn()), *(mnd.mn()))) {
1847 return false;
1848 }
1849
1852
1853 // only for true stores and loads; we cannot analyze aliasing
1854 // of pseudo dependencies caused by call/return.
1855 if (!prev.pseudo() && !mnd.pseudo()) {
1856 ProgramOperation& currPop = mnd.mn()->destinationOperation();
1857 ProgramOperation& prevPop = prev.mn()->destinationOperation();
1858
1859 const llvm::MachineInstr* instr1 = currPop.machineInstr();
1860 const llvm::MachineInstr* instr2 = prevPop.machineInstr();
1861
1862 // The LLVM MachineInstructions are not connected to
1863 // all memory operands, at least not to those in inline
1864 // assembly blocks (from custom operation calls).
1865 if (instr1 != NULL && instr2 != NULL) {
1866 llvm::MachineInstr::mmo_iterator begin1 =
1867 instr1->memoperands_begin();
1868 // Machine instruction could in theory have several memory operands.
1869 // In practice it is usually just one.
1870 while (begin1 != instr1->memoperands_end()) {
1871 llvm::MachineInstr::mmo_iterator begin2 =
1872 instr2->memoperands_begin();
1873
1874 while (begin2 != instr2->memoperands_end()) {
1875 // Force program ordering between volatile mem accesses.
1876 if ((*begin1)->isVolatile() && (*begin2)->isVolatile()) {
1877#if 0
1878 Application::logStream() << "MemDep >> volatile \n";
1879 PRINT_VAR(currPop.toString());
1880 PRINT_VAR(prevPop.toString());
1881 (*begin1)->getValue()->dump();
1882 (*begin2)->getValue()->dump();
1883#endif
1885 }
1886 begin2++;
1887 }
1888 begin1++;
1889 }
1890 }
1891 if (aliasResult == MemoryAliasAnalyzer::ALIAS_UNKNOWN)
1892 aliasResult = analyzeMemoryAlias(prevPop, currPop, prev.bbRelation());
1893 }
1894
1895 if (aliasResult != MemoryAliasAnalyzer::ALIAS_FALSE) {
1896 // if not alias false , have to create mem edge.
1897 bool trueAlias = (aliasResult == MemoryAliasAnalyzer::ALIAS_TRUE);
1898 ProgramOperation& prevPo = prev.mn()->destinationOperation();
1899 for (int i = 0; i < prevPo.inputMoveCount(); i++) {
1900 if (prev.loop() || &prevPo.inputMove(i) != mnd.mn()) {
1901 // if operations are always assigned to differnt FU,
1902 // then skip creating memroy dependency edge
1903 if (isAlwaysDifferentFU(prev.mn(), mnd.mn())) {
1904 continue;
1905 }
1906 DataDependenceEdge* dde2 =
1908 DataDependenceEdge::EDGE_MEMORY, depType, false,
1909 trueAlias, prev.pseudo(), mnd.pseudo(),
1910 static_cast<int>(prev.loop()));
1912 prevPo.inputMove(i), *mnd.mn(), dde2);
1913 }
1914 }
1915 return trueAlias;
1916 }
1917 return false;
1918}
1919
1920///////////////////////////////////////////////////////////////////////////////
1921// Alias analysis - related things.
1922///////////////////////////////////////////////////////////////////////////////
1923
1924/**
1925 * Gets the address-writing move of a move which is a trigger or operand
1926 * to a memory operation.
1927 *
1928 * If none found, return null
1929 *
1930 * @param mn moveNode whose address write move is being searched.
1931 * @return MoveNode which writes address to a mem operation or NULL.
1932
1933MoveNode*
1934DataDependenceGraphBuilder::addressMove(const MoveNode& mn) {
1935 if (mn.isDestinationOperation()) {
1936 return addressOperandMove(mn.destinationOperation());
1937 }
1938 return NULL;
1939}
1940*/
1941
1942/**
1943 * Delegates the call to all registered memory address alias analyzers.
1944 *
1945 * Returns the first non-unknown result.
1946 * If no alias analyzer can analyze these, returns ALIAS_UNKNOWN
1947 *
1948 * @return Whether the memory accesses in the given moves alias.
1949 */
1952 const ProgramOperation& pop1, const ProgramOperation& pop2,
1953 MoveNodeUse::BBRelation bbInfo) {
1954
1955 for (unsigned int i = 0; i < aliasAnalyzers_.size(); i++) {
1956 MemoryAliasAnalyzer* analyzer = aliasAnalyzers_[i];
1958 analyzer->analyze(*currentDDG_, pop1, pop2, bbInfo);
1960 return res;
1961 }
1962 }
1964}
1965
1966/**
1967 * Can some analyzer say something about this address?
1968 *
1969 * @param mn Movenode containing memory address write.
1970 * @return true if some alias analyzer knows something about the address,
1971 * ie can return something else than ALIAS_UNKNOWN.
1972 */
1973bool
1975
1976 for (unsigned int i = 0; i < aliasAnalyzers_.size(); i++) {
1977 if (aliasAnalyzers_.at(i)->isAddressTraceable(*currentDDG_, pop)) {
1978 return true;
1979 }
1980 }
1981 return false;
1982}
1983
1984/**
1985 * Checks into which category this memory address belongs.
1986 *
1987 * Memory accesses in different categories cannot alias, and there is
1988 * separate bookkeeping for every category. Current implementation separates
1989 * spills, different alias spaces, restrict keywords and opencl work items.
1990 *
1991 * @param mnd MoveNodeUse which transfers the address of the memory operation.
1992 * @return string which is then used as key for map.
1993 * unique for different categories, empty for the default category.
1994 *
1995 * @TODO: create some memorycategorizer interface for this analysis?
1996 */
1997
2000
2001 TCEString category;
2002
2003// MoveNode* addressNode = addressMove(*mnd.mn());
2004// if (addressNode != NULL && addressNode->isMove()) {
2005 const TTAProgram::Move& move = mnd.mn()->move();//addressNode->move();
2006
2007 // spill annotations are in all operands.
2008 for (int j = 0; j < move.annotationCount(); j++) {
2010 if (anno.id() ==
2012 return "_SPILL";
2013 }
2014 if (anno.id() ==
2016 return "_RA";
2017 }
2018 if (anno.id() ==
2020 return "_FP";
2021 }
2022 if (anno.id() ==
2024 return "_CONSTANT";
2025 }
2026 }
2027 if (!mnd.mn()->isDestinationOperation()) {
2028 PRINT_VAR(mnd.mn()->toString());
2029 abortWithError("Not destination operation!");
2030 }
2032
2033 LLVMTCECmdLineOptions* llvmOptions =
2034 dynamic_cast<LLVMTCECmdLineOptions*>(
2036 if (llvmOptions == NULL || !llvmOptions->disableAddressSpaceAA()) {
2037 // address space
2038 for (int i = 0; i < po.inputMoveCount(); i++) {
2039 MoveNode& mn = po.inputMove(i);
2040 Move& m = mn.move();
2041 if (m.hasAnnotations(
2043 if (m.annotation(
2045 != "0") {
2046 category +=
2047 "_AS:" +
2048 m.annotation(
2050 .stringValue();
2051 break;
2052 }
2053 }
2054 }
2055 }
2056 for (int i = 0; i < po.inputMoveCount(); i++) {
2057 MoveNode& mn = po.inputMove(i);
2058 Move& m = mn.move();
2059 TCEString pointerName = "";
2060 // restrict keyword.
2061 if (m.hasAnnotations(
2065 pointerName =
2066 m.annotation(
2068 category += "_RESTRICT:" + pointerName;
2069 break;
2070 }
2071 }
2072
2073 /* OpenCL work item variable access.
2074
2075 OpenCL kernels enforce memory consistency for local and global
2076 memory only at explicit barrier() calls within a work group.
2077 Thus, all memory accesses between work items can be considered
2078 independent in alias analysis in the regions between barrier
2079 calls.
2080 */
2081 for (int i = 0; i < po.inputMoveCount(); i++) {
2082 MoveNode& mn = po.inputMove(i);
2083 Move& m = mn.move();
2085 category +=
2086 "_OPENCL_WI:" +
2088 m.annotation(
2090 intValue(), 8);
2091 break;
2092 }
2093 }
2094 return category;
2095}
2096
2097///////////////////////////////////////////////////////////////////////////////
2098// Multi-BB DDG construction
2099///////////////////////////////////////////////////////////////////////////////
2100
2101///////////////////////////////////////////////////////////////////////////////
2102// High-level Multi-BB DDG construction
2103///////////////////////////////////////////////////////////////////////////////
2104
2105/**
2106 * Builds a DDG from a CFG.
2107 *
2108 * @param cfg Control flow graph where the ddg is built from.
2109 * @param antidependenceLevel level of register antidependencies to create.
2110 * @param um universalmachine used for the code if registers unallocated.
2111 * if null, assumed that registers allready allocated.
2112 * @param createMemAndFUDeps whether to create also memory and
2113 * fu state(side effect) dependencies or only register deps.
2114 * @param createDeathInformation whether to search the last usage
2115 * of all liveranges. This is needed for things like register renamer
2116 * and threading.
2117 * @return pointer to the ddg which is created.
2118 */
2121 ControlFlowGraph& cfg,
2122 DataDependenceGraph::AntidependenceLevel antidependenceLevel,
2123 const TTAMachine::Machine& mach,
2124 const UniversalMachine* um,
2125 bool createMemAndFUDeps, bool createDeathInformation,
2126 llvm::AliasAnalysis* AA) {
2127
2128 mach_ = &mach;
2129 if (AA) {
2130 for (unsigned int i = 0; i < aliasAnalyzers_.size(); i++) {
2131 LLVMAliasAnalyzer* llvmaa =
2132 dynamic_cast<LLVMAliasAnalyzer*>(aliasAnalyzers_[i]);
2133 if (llvmaa != NULL) {
2134 llvmaa->setLLVMAA(AA);
2135 }
2136 }
2137 }
2138
2139 cfg_ = &cfg;
2140
2141 // @TODO: when CFG subgraphs are in use, 2nd param not always true
2143 allParamRegs_, cfg.name(), antidependenceLevel, NULL, true,
2144 false);
2145 try {
2146 // this is just for old frontend code.
2147 if (um != NULL) {
2149 } else {
2151 }
2152
2153 currentDDG_ = ddg;
2154
2155 // do the first phase (register dependencies and operation edges)
2157
2158 // then do the second phase - mem and fu deps.
2159 if (createMemAndFUDeps) {
2161 }
2162
2163 // search when registers are used for last time.
2164 // this live range information is used by register renamer and
2165 // threading.
2166 if (createDeathInformation) {
2168 }
2169
2170 // clear bookkeeping which is not needed anymore.
2172 } catch (const Exception& e) {
2174 << e.fileName() << ": " << e.lineNum() << ": " << e.errorMessageStack()
2175 << std::endl;
2176 delete ddg;
2177 throw;
2178 } catch (...) {
2179 delete ddg;
2180 throw;
2181 }
2182 ddg->setMachine(mach);
2183 return ddg;
2184}
2185
2186/**
2187 * Initializes states of all BB's to unreached
2188 *
2189 */
2190void
2192
2193 // initialize state lists
2194 for (int bbi = 0; bbi < cfg_->nodeCount(); bbi++) {
2195 BasicBlockNode& bbn = cfg_->node(bbi);
2196 BasicBlock& bb = bbn.basicBlock();
2197 if (bb.liveRangeData_ == NULL) {
2199 }
2200 BBData* bbd = new BBData(bbn);
2201 bbData_[&bbn] = bbd;
2202 // in the beginning all are unreached
2203 if (bbn.isNormalBB()) {
2204 blocksByState_[BB_UNREACHED].push_back(bbd);
2205 }
2206 }
2207}
2208
2209/**
2210 * Changes state of a basic block in processing.
2211 * Move BBData into a diffefent list and changes the state data in BBData.
2212 *
2213 * @param bbd BBData of basic block whose state is being changed
2214 * @param newState the new state of the basic block.
2215*/
2216void
2218 BBData& bbd, BBState newState, bool priorize) {
2219
2220 BBState oldState = bbd.state_;
2221 if (newState != oldState) {
2223 bbd.state_ = newState;
2224 if (priorize) {
2225 blocksByState_[newState].push_front(&bbd);
2226 } else {
2227 blocksByState_[newState].push_back(&bbd);
2228 }
2229 }
2230}
2231
2232/**
2233 * Queues first basic block to be processed.
2234 *
2235 * @return the first basic block node
2236 */
2239 // get first BB where to start
2241 assert(firstBBs.size() == 1);
2242 BasicBlockNode* firstBB = *firstBBs.begin();
2243 changeState(*(bbData_[firstBB]), BB_QUEUED);
2244 return firstBB;
2245}
2246
2247/**
2248 * Clears bookkeeping which is only needed during ddg construction.
2249 */
2250void
2252
2253 for (int i = 0; i < cfg_->nodeCount();i++) {
2254 BasicBlockNode& bbn = cfg_->node(i);
2255 if (bbn.isNormalBB()) {
2256 BasicBlock& bb = bbn.basicBlock();
2257 clearUnneededBookkeeping(bb, true);
2258 }
2259 }
2260}
2261
2262/**
2263 * Does the first phase of ddg construction. handles register deps.
2264 *
2265 * @param cfg control flow graph containing the code.
2266 */
2267void
2269
2270 // initializes states of all BB's to unreached.
2272
2273 // queues first bb for processing
2274 BasicBlockNode* firstBB = queueFirstBB();
2275
2276 // currentBB need to be set for entry node processing
2277 currentBB_ = firstBB;
2278
2279 // set entry deps. ( procedure parameter edges )
2280 MoveNode* entryNode = new MoveNode();
2281 currentDDG_->addNode(*entryNode, cfg_->entryNode());
2282
2283 processEntryNode(*entryNode);
2284
2285 // iterate over BB's. Loop as long as there are queued BB's.
2286
2288
2289 // all should be constructed, but if there are unreachable BB's
2290 // we handle those also
2291 while (!blocksByState_[BB_UNREACHED].empty()) {
2293 Application::logStream() << "Warning: Unreachable Basic Block!"
2294 << std::endl;
2295 Application::logStream() << "In procedure: " << cfg_->name() <<
2296 std::endl;
2297// cfg.writeToDotFile("unreachable_bb.dot");
2298 }
2301 }
2302 // free bb data
2304}
2305
2306/**
2307 * Does the second phase of ddg construction.
2308 *
2309 * handles mem deps and fu state deps.
2310 */
2311void
2313
2314 // initializes states of all BB's to unreached.
2316
2317 // queues first bb for processing
2318 queueFirstBB();
2319
2320 // then iterates over all basic blocks.
2322
2323 // all should be constructed, but if there are unreachable BB's
2324 // we might want to handle those also
2325 while (!blocksByState_[BB_UNREACHED].empty()) {
2328 }
2329 // free bb data
2331}
2332
2333
2334/**
2335 * Iterates over basic blocks as long as there is some BB to process.
2336 *
2337 * Handles a BB, updates the live value lists of its successors.
2338 * If incoming live values of a BB change, it's scheduled for
2339 * reprocessing.
2340 *
2341 * @param phase whether to handle register& operation deps or
2342 * memory and side-effect dependencies.
2343 */
2344void
2346 ConstructionPhase phase) {
2347
2348 while (!blocksByState_[BB_QUEUED].empty()) {
2349 std::list<BBData*>::iterator bbIter =
2350 blocksByState_[BB_QUEUED].begin();
2351 BBData& bbd = **bbIter;
2352
2353 // construct or update BB
2354 if (bbd.constructed_) {
2355 updateBB(bbd, phase);
2356 } else {
2357 constructIndividualBB(bbd, phase);
2358 }
2359 // mark as ready
2360 changeState(bbd, BB_READY);
2361
2362 // create deps after and update that to succeeding BBs.
2363 // succeeding BB's are also queued to be scheduled here.
2364 // queue succeeding BB's in case either
2365 // * their input data has changed
2366 // * current BB was processed for the first time
2367 if (phase == REGISTERS_AND_PROGRAM_OPERATIONS) {
2368 if (updateRegistersAliveAfter(bbd) || !bbd.constructed_) {
2369 setSucceedingPredeps(bbd, !bbd.constructed_, phase);
2370 }
2371 } else {
2372 if (updateMemAndFuAliveAfter(bbd) || !bbd.constructed_) {
2373 setSucceedingPredeps(bbd, !bbd.constructed_, phase);
2374 }
2375 }
2376
2377 bbd.constructed_ = true;
2378 }
2379}
2380
2381/**
2382 * Updates bookkeeping used for calculating register deaths.
2383 *
2384 * Marks registers used at or after some BB to it's predecessor BB's.
2385 *
2386 * @param bbd basic block to process.
2387 * @param firstTime whether this BB is analyzer for the first time.
2388 */
2389void
2391 BBData& bbd, bool firstTime) {
2392 BasicBlockNode& bbn = *bbd.bblock_;
2393 BasicBlock& bb = bbn.basicBlock();
2394 BasicBlockNodeSet predecessors = cfg_->predecessors(bbn);
2395 for (BasicBlockNodeSet::iterator predIter = predecessors.begin();
2396 predIter != predecessors.end(); predIter++) {
2397 BasicBlockNode* pred = *predIter;
2398 BasicBlock& predBB = pred->basicBlock();
2399 BBData& predData = *bbData_[pred];
2400 size_t size = predBB.liveRangeData_->registersUsedAfter_.size();
2403
2404 // if updated, need to be handled again.
2405 if (predBB.liveRangeData_->registersUsedAfter_.size() > size || firstTime) {
2406 if (predData.state_ != BB_QUEUED) {
2407 changeState(predData, BB_QUEUED);
2408 }
2409 }
2410 }
2411}
2412
2413/**
2414 * Sets outgoing data from this BB to incoming data of successors.
2415 *
2416 * Also queues them to be reprocessed if they are changed.
2417 *
2418 * @param bbd BBD whose successors will be updated.
2419 * @param queueAll If true, queues all successors even if they do not change.
2420 * @param phase whether to handle register& operation deps or
2421 * memory and side-effect dependencies.
2422 */
2423void
2425 BBData& bbd, bool queueAll,
2426 ConstructionPhase phase) {
2427 BasicBlockNode& bbn = *bbd.bblock_;
2428 BasicBlock& bb = bbn.basicBlock();
2429
2430 BasicBlockNodeSet forwardSuccessors = cfg_->successors(bbn, true);
2431 for (BasicBlockNodeSet::iterator succIter = forwardSuccessors.begin();
2432 succIter != forwardSuccessors.end(); succIter++) {
2434 bb, **succIter, queueAll, false, phase);
2435 }
2436
2437 // successors over loop edges.
2438 BasicBlockNodeSet backwardSuccessors = cfg_->successors(bbn, false, true);
2439 for (BasicBlockNodeSet::iterator succIter = backwardSuccessors.begin();
2440 succIter != backwardSuccessors.end(); succIter++) {
2442 bb, **succIter, queueAll, true, phase);
2443 }
2444}
2445
2446/**
2447 * Sets outgoing data from this BB to incoming data of one successor.
2448 *
2449 * Also queues them to be reprocessed if they are changed.
2450 *
2451 * @param bb BB whose successor will be updated.
2452 * @param successor successor BB whose incoming data is being updated.
2453 * @param queueAll If true, queues all successors even if they do not change.
2454 * @param loop whether to add loop property to the copied
2455 * bookkeeping, ie create edges with loop property.
2456 * @param phase whether to handle register& operation deps or
2457 * memory and side-effect dependencies.
2458 */
2459void
2461 BasicBlock& bb, BasicBlockNode& successor, bool queueAll, bool loop,
2462 ConstructionPhase phase) {
2463
2464 BasicBlock& succBB = successor.basicBlock();
2465 BBData& succData = *bbData_[&successor];
2466 bool changed = false;
2467
2468 if (phase == REGISTERS_AND_PROGRAM_OPERATIONS) {
2471 succBB.liveRangeData_->regDefReaches_, loop);
2472
2474 (&bb == &succBB &&
2478 succBB.liveRangeData_->regUseReaches_, loop);
2479 }
2480 } else {
2481 // mem deps + fu state deps
2482
2485 succBB.liveRangeData_->memDefReaches_, loop);
2486
2489 succBB.liveRangeData_->memUseReaches_, loop);
2490
2491 size_t size = succBB.liveRangeData_->fuDepReaches_.size();
2494 succBB.liveRangeData_->fuDepReaches_, loop);
2495 if (succBB.liveRangeData_->fuDepReaches_.size() > size) {
2496 changed = true;
2497 }
2498 }
2499
2500 // need to queue successor for update?
2501 if (changed || queueAll) {
2502 changeState(succData, BB_QUEUED, loop);
2503 }
2504}
2505
2506///////////////////////////////////////////////////////////////////////////////
2507// Low-level of Multi-BB DDG construction
2508///////////////////////////////////////////////////////////////////////////////
2509
2510/**
2511 * Updates live register lists after a basic block has been processed.
2512 *
2513 * Copies use and define definitions from the basic block and
2514 * it's prodecessors to the after alive data structures.
2515 *
2516 * @param bbd BBData for bb being processed
2517 * @return true if the after alive data structures have been changed
2518 */
2520 BBData& bbd) {
2521 BasicBlock& bb = bbd.bblock_->basicBlock();
2522 bool changed = false;
2523
2524 // copy reg definitions that are alive
2525 for (MoveNodeUseMapSet::iterator iter =
2526 bb.liveRangeData_->regDefReaches_.begin();
2527 iter != bb.liveRangeData_->regDefReaches_.end(); iter++) {
2528
2529 TCEString reg = iter->first;
2530 std::set<MoveNodeUse>& preDefs = iter->second;
2531 // todo: clear or not?
2532 std::set<MoveNodeUse>& defAfter = bb.liveRangeData_->regDefAfter_[reg];
2533 size_t size = defAfter.size();
2534
2535 // only copy incomin dep if this has no unconditional writes
2536 if (bb.liveRangeData_->regKills_.find(reg) == bb.liveRangeData_->regKills_.end()) {
2537 for (std::set<MoveNodeUse>::iterator i = preDefs.begin();
2538 i != preDefs.end(); i++ ) {
2539 defAfter.insert(*i);
2540 }
2541 }
2542 // if size increased, the data has changed
2543 if (size < defAfter.size()) {
2544 changed = true;
2545 }
2546 }
2547 // own deps. need to do only once but now does after every.
2550 bb.liveRangeData_->regDefAfter_, false);
2551
2553 // copy uses that are alive
2554 for (MoveNodeUseMapSet::iterator iter =
2555 bb.liveRangeData_->regUseReaches_.begin(); iter != bb.liveRangeData_->regUseReaches_.end();
2556 iter++) {
2557 TCEString reg = iter->first;
2558 std::set<MoveNodeUse>& preUses = iter->second;
2559 std::set<MoveNodeUse>& useAfter = bb.liveRangeData_->regUseAfter_[reg];
2560 size_t size = useAfter.size();
2561 if (bb.liveRangeData_->regKills_.find(reg) == bb.liveRangeData_->regKills_.end()) {
2562 for (std::set<MoveNodeUse>::iterator i = preUses.begin();
2563 i != preUses.end(); i++ ) {
2564 useAfter.insert(*i);
2565 }
2566 }
2567 // if size increased, the data has changed
2568 if (size < useAfter.size()) {
2569 changed = true;
2570 }
2571 }
2572 }
2573
2574 // own deps. need to do only once but now does after every.
2577 bb.liveRangeData_->regUseAfter_, false);
2578 return changed;
2579}
2580
2581
2582/**
2583 * Updates live mem access lists and fu state usages after a basic block
2584 * has been processed.
2585 *
2586 * Copies use and write definitions from the basic block and
2587 * it's prodecessors to the after alive data structures.
2588 *
2589 * @param bbd BBData for bb being processed
2590 * @return true if the after alive data structures have been changed
2591 */
2593 BasicBlock& bb = bbd.bblock_->basicBlock();
2594 bool changed = false;
2595
2596 // copy mem definitions that are alive
2597 for (MoveNodeUseMapSet::iterator iter = bb.liveRangeData_->memDefReaches_.begin();
2598 iter != bb.liveRangeData_->memDefReaches_.end(); iter++) {
2599
2600 TCEString category = iter->first;
2601 std::set<MoveNodeUse>& preDefs = iter->second;
2602 std::set<MoveNodeUse>& defAfter = bb.liveRangeData_->memDefAfter_[category];
2603 std::set<MoveNodeUse>& ownDefines = bb.liveRangeData_->memDefines_[category];
2604 size_t size = defAfter.size();
2605
2606 // only copy incomin dep if this has no unconditional writes,
2607 if (bb.liveRangeData_->memKills_.find(category) == bb.liveRangeData_->memKills_.end()) {
2608 for (std::set<MoveNodeUse>::iterator i = preDefs.begin();
2609 i != preDefs.end(); i++ ) {
2610// MoveNode* preAddress = addressMove(*(i->mn()));
2611 ProgramOperation& prevPop = i->mn()->destinationOperation();
2612
2613 bool overWritten = false;
2614 for (std::set<MoveNodeUse>::iterator j = ownDefines.begin();
2615 j != ownDefines.end(); j++) {
2616 if (j->mn()->move().isUnconditional()) {
2617// MoveNode* ownAddress = addressMove(*(j->mn()));
2618 ProgramOperation& ownPop = j->mn()->destinationOperation();
2619 if (analyzeMemoryAlias(prevPop, ownPop, i->bbRelation()) ==
2621 overWritten = true;
2622 break;
2623 }
2624 }
2625 }
2626 if (!overWritten) {
2627 defAfter.insert(*i);
2628 }
2629 }
2630 }
2631 // if size increased, the data has changed
2632 if (size < defAfter.size()) {
2633 changed = true;
2634 }
2635 }
2636 // own deps. need to do only once but now does after every.
2639 bb.liveRangeData_->memDefAfter_, false);
2640
2641 // copy uses that are alive
2642 for (MoveNodeUseMapSet::iterator iter = bb.liveRangeData_->memUseReaches_.begin();
2643 iter != bb.liveRangeData_->memUseReaches_.end(); iter++) {
2644
2645 TCEString category = iter->first;
2646 std::set<MoveNodeUse>& preUses = iter->second;
2647 std::set<MoveNodeUse>& useAfter = bb.liveRangeData_->memUseAfter_[category];
2648 std::set<MoveNodeUse>& ownDefines = bb.liveRangeData_->memDefines_[category];
2649
2650 size_t size = useAfter.size();
2651 if (bb.liveRangeData_->memKills_.find(category) == bb.liveRangeData_->memKills_.end()) {
2652 for (std::set<MoveNodeUse>::iterator i = preUses.begin();
2653 i != preUses.end(); i++ ) {
2654// MoveNode* preAddress = addressMove(*(i->mn()));
2655 ProgramOperation& prevPop = i->mn()->destinationOperation();
2656 bool overWritten = false;
2657 for (std::set<MoveNodeUse>::iterator j =
2658 ownDefines.begin(); j != ownDefines.end(); j++) {
2659 if (j->mn()->move().isUnconditional()) {
2660 ProgramOperation& ownPop = j->mn()->destinationOperation();
2661 if (analyzeMemoryAlias(prevPop, ownPop, i->bbRelation()) ==
2663 overWritten = true;
2664 break;
2665 }
2666 }
2667 }
2668 if (!overWritten) {
2669 useAfter.insert(*i);
2670 }
2671 }
2672 }
2673 // if size increased, the data has changed
2674 if (size < useAfter.size()) {
2675 changed = true;
2676 }
2677 }
2678
2679 // fu deps
2680 size_t size = bb.liveRangeData_->fuDepAfter_.size();
2682 if (bb.liveRangeData_->fuDepAfter_.size() > size) {
2683 changed = true;
2684 }
2685 return changed;
2686}
2687
2688/**
2689 * Processes the pseudo deps from entry node.
2690 *
2691 * This procedure must be called when currentBB is the first real
2692 * BB of the procedure.
2693 */
2695
2696 // initializes RA
2698
2699 // sp
2700 MoveNodeUse mnd2(mn);
2702 if (sp != "") {
2704 }
2705
2706 if (rvIsParamReg_) {
2708 if (rv != "") {
2710 mnd2);
2711 }
2712 }
2713
2714 // params
2715 // this is for old frontend generated code.
2716 for (int i = 0;;i++) {
2718 if(paramReg != "") {
2719 currentBB_->basicBlock().liveRangeData_->regDefReaches_[paramReg].insert(mnd2);
2720 } else {
2721 break;
2722 }
2723 }
2724
2726 if (fp != "") {
2728 mnd2);
2729 }
2730}
2731
2732/**
2733 * Reprocesses a basic block which has already once been processed.
2734 *
2735 * Checks dependencies to first uses and definitions of registers,
2736 * does not recreate edges inside the basic block.
2737 *
2738 * @param bbd BBData for basic block which is being reprocessed.
2739 * @param phase whether to handle register& operation deps or
2740 * memory and side-effect dependencies.
2741 */
2742void
2744 BBData& bbd, ConstructionPhase phase) {
2745 currentData_ = &bbd;
2746 currentBB_ = bbd.bblock_;
2747 BasicBlock& bb = bbd.bblock_->basicBlock();
2748
2749 // register and operation dependencies
2750 if (phase == REGISTERS_AND_PROGRAM_OPERATIONS) {
2751 //loop all regs having ext deps and create reg edges
2752 for (MoveNodeUseMapSet::iterator firstUseIter =
2753 bb.liveRangeData_->regFirstUses_.begin();
2754 firstUseIter != bb.liveRangeData_->regFirstUses_.end();
2755 firstUseIter++) {
2756 TCEString reg = firstUseIter->first;
2757 std::set<MoveNodeUse>& firstUseSet = firstUseIter->second;
2758 for (std::set<MoveNodeUse>::iterator iter2 = firstUseSet.begin();
2759 iter2 != firstUseSet.end(); iter2++) {
2761 *iter2, reg, currentBB_->basicBlock());
2762 }
2763 }
2764
2766 // antidependencies to registers
2767 for (MoveNodeUseMapSet::iterator firstDefineIter =
2768 bb.liveRangeData_->regFirstDefines_.begin();
2769 firstDefineIter != bb.liveRangeData_->regFirstDefines_.end();
2770 firstDefineIter++) {
2771 TCEString reg = firstDefineIter->first;
2772 std::set<MoveNodeUse>& firstDefineSet =
2773 firstDefineIter->second;
2774 for (std::set<MoveNodeUse>::iterator iter2=
2775 firstDefineSet.begin();
2776 iter2 != firstDefineSet.end(); iter2++) {
2778 *iter2, reg, currentBB_->basicBlock());
2779 }
2780 }
2781 }
2782 } else {
2783 // phase 1 .. mem deps and fu state/side effect dependencies.
2784
2785 //loop all first mem uses having ext deps and create mem edges
2786 for (MoveNodeUseMapSet::iterator firstUseIter =
2787 bb.liveRangeData_->memFirstUses_.begin();
2788 firstUseIter != bb.liveRangeData_->memFirstUses_.end();
2789 firstUseIter++) {
2790 TCEString category = firstUseIter->first;
2791 std::set<MoveNodeUse>& firstUseSet = firstUseIter->second;
2792 for (std::set<MoveNodeUse>::iterator iter2 = firstUseSet.begin();
2793 iter2 != firstUseSet.end(); iter2++) {
2794 updateMemUse(*iter2, category);
2795 }
2796 }
2797
2798 // antidependencies to memory
2799 for (MoveNodeUseMapSet::iterator firstDefineIter =
2800 bb.liveRangeData_->memFirstDefines_.begin();
2801 firstDefineIter != bb.liveRangeData_->memFirstDefines_.end();
2802 firstDefineIter++) {
2803 TCEString category = firstDefineIter->first;
2804 std::set<MoveNodeUse>& firstDefineSet = firstDefineIter->second;
2805 for (std::set<MoveNodeUse>::iterator iter2=firstDefineSet.begin();
2806 iter2 != firstDefineSet.end(); iter2++) {
2807 updateMemWrite(*iter2, category);
2808 }
2809 }
2810
2811 // and fu state deps
2812 for (MoveNodeUseSet::iterator iter =
2813 bb.liveRangeData_->fuDeps_.begin();
2814 iter != bb.liveRangeData_->fuDeps_.end(); iter++) {
2815 Terminal& dest = iter->mn()->move().destination();
2816 TerminalFUPort& tfpd = dynamic_cast<TerminalFUPort&>(dest);
2817 Operation &dop = tfpd.hintOperation();
2820 *iter->mn(), dop);
2821 }
2822 }
2823}
2824
2825/**
2826 * Checks memory write against uses and defs in incoming basic blocks.
2827 * Creates the needed dependence edges.
2828 *
2829 * @param mnd MoveNodeUse of movenode being processed.
2830 * @param category which memory category this memory write belongs.
2831 */
2832void
2834 MoveNodeUse mnd, const TCEString& category) {
2835
2836 // create waw edges from all alive writes to this node.
2837 for (MoveNodeUseSet::iterator iter =
2838 currentBB_->basicBlock().liveRangeData_->memDefReaches_[category].begin();
2839 iter != currentBB_->basicBlock().liveRangeData_->memDefReaches_[category].end();) {
2841 }
2842
2843 // create war edges from all alive reads to this node.
2844 for (MoveNodeUseSet::iterator iter = currentBB_->basicBlock().liveRangeData_->
2845 memUseReaches_[category].begin();
2846 iter != currentBB_->basicBlock().liveRangeData_->memUseReaches_[category].end();) {
2848 }
2849}
2850
2851
2852/**
2853 * Checks memory read against uses and defs in incoming basic blocks.
2854 * Creates the needed dependence edges.
2855 *
2856 * @param mnd MoveNodeUse of movenode being processed.
2857 * @param category which memory category this memory write belongs.
2858 */
2860 MoveNodeUse mnd, const TCEString& category) {
2861
2862 for (MoveNodeUseSet::iterator iter =
2863 currentBB_->basicBlock().liveRangeData_->memDefReaches_[category].begin();
2864 iter != currentBB_->basicBlock().liveRangeData_->memDefReaches_[category].end();
2865 iter++) {
2867 }
2868}
2869
2870
2871///////////////////////////////////////////////////////////////////////////////
2872// Searching of ends of liveranges, ie last uses of values
2873///////////////////////////////////////////////////////////////////////////////
2874
2875/**
2876 * Searches the last usages a registers.
2877 *
2878 * This information is used for checking whether given register contains
2879 * live value at given cycle.
2880 */
2881void
2883
2884 // initializes states of all BB's to unreached.
2886
2887 // start from end of cfg. (sink nodes), queue them
2889 for (ControlFlowGraph::NodeSet::iterator iter =
2890 lastBBs.begin(); iter != lastBBs.end(); iter++) {
2891 changeState(*(bbData_[*iter]), BB_QUEUED);
2892 }
2893
2894 // then iterate over all BB's, going from BB to it's
2895 // predecessors.
2897
2898 // all should have gone thru, but if there are 4ever loop causing
2899 // BB's not reachable from the end.
2900 // we might want to handle those also.
2901 while (!blocksByState_[BB_UNREACHED].empty()) {
2903 Application::logStream() << "Warning: BB in 4ever loop!"
2904 << std::endl;
2905 Application::logStream() << "In procedure: " << cfg_->name() <<
2906 std::endl;
2907// cfg.writeToDotFile("4everloop_bb.dot");
2908 }
2910
2912 }
2913
2914 // free bb data
2916}
2917
2918/**
2919 * Iterates thru all queued BB's and find register deaths from them.
2920 *
2921 * Loops as long as something keeps changing.
2922 */
2923void
2925
2926 // loop as long as we have unprocessed/changed BB's
2927 while (!blocksByState_[BB_QUEUED].empty()) {
2928 std::list<BBData*>::iterator bbIter =
2929 blocksByState_[BB_QUEUED].begin();
2930 BBData& bbd = **bbIter;
2931
2932 // mark as ready
2933 changeState(bbd, BB_READY);
2934
2935 if (updateRegistersUsedInOrAfter(bbd) || (!bbd.constructed_)) {
2936 // if there asre more registers read after start of this BB,
2937 // have to update this information to preceedign BBs,
2938 // and check if they need to be reprocessed.
2940 }
2941 bbd.constructed_ = true;
2942 }
2943}
2944
2945/**
2946 * Updates bookkeeping about registers used in this or later BBs.
2947 *
2948 * This is a helper function used by searchRegisterDeaths() method.
2949 *
2950 * @param bbd Data about one basicblock.
2951 * @return whether the bookkeeping was changed,
2952 ie the predecessors of this BB need to be reprocessed.
2953 */
2954bool
2956 BBData& bbd) {
2957 BasicBlock& bb = bbd.bblock_->basicBlock();
2958 size_t size = bb.liveRangeData_->registersUsedInOrAfter_.size();
2959
2960 // if definition not here, it's earlier - copy.
2961 // if definition here, not alive unless read here.
2962 for (std::set<TCEString>::iterator i = bb.liveRangeData_->registersUsedAfter_.begin();
2963 i != bb.liveRangeData_->registersUsedAfter_.end(); i++) {
2964 // if not written in this, written earlier.
2965 if (bb.liveRangeData_->regKills_.find(*i) == bb.liveRangeData_->regKills_.end()) {
2967 }
2968 }
2969
2970 // reads in this BB.liveRangeData_-> Only reads whose defining value comes/can come
2971 // outside this BB.liveRangeData_->
2972 for (MoveNodeUseMapSet::iterator i = bb.liveRangeData_->regFirstUses_.begin();
2973 i != bb.liveRangeData_->regFirstUses_.end(); i++) {
2974 bb.liveRangeData_->registersUsedInOrAfter_.insert(i->first);
2975 }
2976 if (bb.liveRangeData_->registersUsedInOrAfter_.size() > size) {
2977 return true;
2978 }
2979 return false;
2980}
2981
2982/**
2983 * Check if operations are assigned to differnt FU
2984 *
2985 * Operations forced to different FUs are independent since
2986 * the operation state is per FU. Check if the moves have
2987 * forced set of FUs and if the sets overlap.
2988 *
2989 * @param srcMN MoveNode first node for dependency check
2990 * @param dstMN MoveNode for which dependency needs to be checked
2991 * @return Nodes are alawys mapped to different FU
2992 */
2993bool
2995 const MoveNode* srcMN, const MoveNode* dstMN) {
2996 if (srcMN->move().hasAnnotations(
2998 dstMN->move().hasAnnotations(
3000 bool alwaysDifferentFUs = true;
3001 for (int idx = 0;
3002 idx < srcMN->move().annotationCount(
3004 ++idx) {
3005 if (dstMN->move().hasAnnotation(
3007 srcMN->move()
3008 .annotation(
3010 ANN_ALLOWED_UNIT_DST)
3011 .stringValue())) {
3012 alwaysDifferentFUs = false;
3013 break;
3014 }
3015 }
3016 return alwaysDifferentFUs;
3017 }
3018 return false;
3019}
3020
3021/**
3022 * Internal constant for the name of the return address port
3023 */
3025
3026
3027///////////////////////////////////////////////////////////////////////////////
3028// BBData
3029///////////////////////////////////////////////////////////////////////////////
3030
3031/**
3032 * Constructor
3033 */
3035 poReadsHandled_(0),
3036 state_(BB_UNREACHED), constructed_(false), bblock_(&bb) {
3037}
3038
3039/**
3040 * Destructor.
3041 */
#define __func__
#define abortWithError(message)
#define PRINT_VAR(VARIABLE__)
#define assert(condition)
#define IGNORE_COMPILER_WARNING(X)
#define POP_COMPILER_DIAGS
static const int REG_SP
static const int REG_RV_HIGH
static const int REG_FP
static const int REG_RV
static const int REG_IPARAM
static const int REG_VRV
find Finds info of the inner loops in the false
static MachInfoCmdLineOptions options
Definition MachInfo.cc:46
std::shared_ptr< ProgramOperation > ProgramOperationPtr
Definition MoveNode.hh:53
static CmdLineOptions * cmdLineOptions()
static const int VERBOSE_LEVEL_DEFAULT
Default verbose level - do not print anything unnecessary.
static int verboseLevel()
static std::ostream & logStream()
static void append(const ContainerType &src, ContainerType &dest)
static void deleteAllValues(ContainerType &aMap)
TTAProgram::BasicBlock & basicBlock()
bool isNormalBB() const
InstructionAddress originalEndAddress() const
InstructionAddress originalStartAddress() const
bool isScheduled() const
int nodeCount() const
virtual NodeSet successors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
Node & node(const int index) const
virtual const TCEString & name() const
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
virtual NodeSet sinkNodes() const
static bool removeValueIfExists(ContainerType &aContainer, const ElementType &aKey)
BasicBlockNode & entryNode() const
static std::string toHexString(T source, std::size_t digits=0, bool include0x=true)
static std::string toString(const T &source)
static int toInt(const T &source)
LiveRangeData::MoveNodeUseSet MoveNodeUseSet
void checkAndCreateMemAntideps(MoveNodeUse &mnd, std::set< MoveNodeUse > &prevNodes, DataDependenceEdge::DependenceType depType, bool traceable)
void constructIndividualBB(ConstructionPhase phase)
void findStaticRegisters(TTAProgram::CodeSnippet &cs, std::map< int, TCEString > &registers)
find special register data from old frontend code
void createRegisterAntideps(const TCEString &reg, MoveNodeUse &mnd, MoveNodeUseSet &predecessorNodes, DataDependenceEdge::DependenceType depType, bool guardedKillFound)
void updateBB(BBData &bbd, ConstructionPhase phase)
bool hasEarlierWriteWithSameGuard(MoveNodeUse &mnd, std::set< MoveNodeUse > &defines)
void processOperand(class MoveNode &moveNode, Operation &dop)
void processTriggerMemoryAndFUStates(MoveNode &moveNode, Operation &dop)
void constructIndividualFromInlineAsmBB(ConstructionPhase phase)
void createSideEffectEdges(MoveNodeUseSet &prevMoves, const MoveNode &mn, Operation &dop)
std::set< MoveNodeUse > earlierWritesWithSameGuard(MoveNodeUse &mnd, std::set< MoveNodeUse > &defines)
void updatePreceedingRegistersUsedAfter(BBData &bbd, bool firstTime)
bool isAddressTraceable(const ProgramOperation &pop)
void setSucceedingPredeps(BBData &bbd, bool queueAll, ConstructionPhase phase)
ControlFlowGraph::NodeSet BasicBlockNodeSet
@ BB_QUEUED
Basic block we have not yet encountered.
@ BB_READY
BB which is queued to be processed.
void iterateBBs(ConstructionPhase phase)
bool hasEarlierMemWriteToSameAddressWithSameGuard(MoveNodeUse &mnd, std::set< MoveNodeUse > &defines)
void processTriggerRegistersAndOperations(MoveNode &moveNode, Operation &dop)
SpecialRegisters specialRegisters_
contains stack pointer, RV and parameter registers.
void processRegUse(MoveNodeUse mn, const TCEString &reg)
const TTAMachine::Machine * mach_
void processResultRead(MoveNode &moveNode)
void updateMemUse(MoveNodeUse mnd, const TCEString &category)
void setSucceedingPredepsForBB(TTAProgram::BasicBlock &processedBB, BasicBlockNode &successor, bool queueAll, bool loop, ConstructionPhase phase)
bool checkAndCreateMemDep(MoveNodeUse prev, MoveNodeUse mnd, DataDependenceEdge::DependenceType depType)
void createTriggerDependencies(class MoveNode &moveNode, class Operation &dop)
void processTriggerPO(class MoveNode &moveNode, Operation &dop)
MemoryAliasAnalyzer::AliasingResult analyzeMemoryAlias(const ProgramOperation &pop1, const ProgramOperation &pop2, MoveNodeUse::BBRelation bbInfo)
void processDestination(class MoveNode &moveNode, ConstructionPhase phase)
void changeState(BBData &bbd, BBState newState, bool priorize=false)
void addAliasAnalyzer(MemoryAliasAnalyzer *analyzer)
void processRegWrite(MoveNodeUse mn, const TCEString &reg)
void updateMemWrite(MoveNodeUse mnd, const TCEString &category)
void createOperationEdges(ProgramOperationPtr po)
virtual DataDependenceGraph * build(ControlFlowGraph &cGraph, DataDependenceGraph::AntidependenceLevel antidependenceLevel, const TTAMachine::Machine &mach, const UniversalMachine *um=NULL, bool createMemAndFUDeps=true, bool createDeathInformation=true, llvm::AliasAnalysis *AA=NULL)
bool isAlwaysDifferentFU(const MoveNode *srcMN, const MoveNode *dstMN)
TCEString memoryCategory(const MoveNodeUse &mnd)
bool hasRegWaw(const MoveNodeUse &mnu, std::set< MoveNodeUse > targets) const
void addNode(MoveNode &moveNode)
void addProgramOperation(ProgramOperationPtr po)
bool exclusingGuards(const MoveNode &mn1, const MoveNode &mn2) const
MoveNode & nodeOfMove(const TTAProgram::Move &move)
bool sameGuards(const MoveNode &mn1, const MoveNode &mn2) const
void updateRegUse(const MoveNodeUse &mnd, const TCEString &reg, TTAProgram::BasicBlock &bb)
void setMachine(const TTAMachine::Machine &machine)
bool connectOrDeleteEdge(const MoveNode &tailNode, const MoveNode &headNode, DataDependenceEdge *edge)
DataDependenceGraph::EdgeSet updateRegWrite(const MoveNodeUse &mnd, const TCEString &reg, TTAProgram::BasicBlock &bb)
static TCEString registerName(const TTAMachine::RegisterFile &rf, int index, char delim='.')
std::string errorMessageStack(bool messagesOnly=false) const
Definition Exception.cc:138
std::string fileName() const
int lineNum() const
virtual void writeToDotFile(const TCEString &fileName) const
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
bool hasDatum(const std::string &key) const
InterPassDatum & datum(const std::string &key)
virtual void setLLVMAA(llvm::AliasAnalysis *AA)
virtual bool disableLLVMAA() const
static int triggerIndex(const TTAMachine::Machine &machine, const Operation &op)
virtual AliasingResult analyze(DataDependenceGraph &ddg, const ProgramOperation &pop1, const ProgramOperation &pop2, MoveNodeUse::BBRelation bbInfo)=0
const MoveNode * mn() const
bool loop() const
bool guard() const
BBRelation bbRelation() const
bool ra() const
bool pseudo() const
void setSourceOperationPtr(ProgramOperationPtr po)
Definition MoveNode.cc:541
bool isDestinationOperation() const
std::string toString() const
Definition MoveNode.cc:576
TTAProgram::Move & move()
void addDestinationOperationPtr(ProgramOperationPtr po)
Definition MoveNode.cc:533
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual bool readsMemory() const
Definition Operation.cc:242
virtual TCEString name() const
Definition Operation.cc:93
virtual int affectedByCount() const
Definition Operation.cc:416
virtual bool dependsOn(const Operation &op) const
Definition Operation.cc:458
virtual bool usesMemory() const
Definition Operation.cc:232
virtual bool hasSideEffects() const
Definition Operation.cc:272
virtual int affectsCount() const
Definition Operation.cc:402
virtual bool writesMemory() const
Definition Operation.cc:252
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual int numberOfOutputs() const
Definition Operation.cc:202
static std::string disassemble(const TTAProgram::Move &move)
const Operation & operation() const
const llvm::MachineInstr * machineInstr() const
int inputMoveCount() const
std::string toString() const
MoveNode & inputMove(int index) const
static void deleteAllItems(SequenceType &aSequence)
static void intersection(const std::set< ValueType > &firstContainer, const std::set< ValueType > &secondContainer, std::set< ValueType > &intersection)
virtual RFPort * port(const std::string &name) const
virtual TCEString name() const
const RegisterFile * registerFile() const
int annotationCount(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
bool hasAnnotation(ProgramAnnotation::Id id, const TCEString &data) const
ProgramAnnotation annotation(int index, ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
bool hasAnnotations(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
LiveRangeData * liveRangeData_
virtual int instructionCount() const
virtual Instruction & instructionAtIndex(int index) const
std::shared_ptr< Move > movePtr(int i) const
Move & move(int i) const
const TTAMachine::Guard & guard() const
Definition MoveGuard.cc:86
bool isFunctionCall() const
Definition Move.cc:219
MoveGuard & guard() const
Definition Move.cc:345
bool isControlFlowMove() const
Definition Move.cc:233
bool isReturn() const
Definition Move.cc:259
bool isUnconditional() const
Definition Move.cc:154
std::string toString() const
Definition Move.cc:436
Terminal & source() const
Definition Move.cc:302
Terminal & destination() const
Definition Move.cc:323
ProgramAnnotation::Id id() const
@ ANN_REGISTER_SP_READ
Stack Pointer read.
@ ANN_REGISTER_IPARAM_READ
Read from int param.
@ ANN_REGISTER_IPARAM_SAVE
Save to int param reg.
@ ANN_REGISTER_SP_SAVE
save to Stack pointer
@ ANN_POINTER_NAME
information retrieved (from LLVM) about a pointer access
@ ANN_ALLOWED_UNIT_DST
Dst. unit candidate.
@ ANN_REGISTER_RV_SAVE
Save to RV register.
@ ANN_STACKUSE_FP_SAVE
frame ptr save/load
@ ANN_CONSTANT_MEM
Constant memory access.
@ ANN_REGISTER_RV_READ
Read from RV reg.
bool hasProgramOperation() const
these methods are used to group terminals belonging to a single program operation invocation
virtual Operation & hintOperation() const
ProgramOperationPtr programOperation() const
virtual bool isOpcodeSetting() const
virtual bool isGPR() const
Definition Terminal.cc:107
virtual int operationIndex() const
Definition Terminal.cc:364
virtual const TTAMachine::Port & port() const
Definition Terminal.cc:378
virtual bool isFUPort() const
Definition Terminal.cc:118
UnboundedRegisterFile & integerRegisterFile() const
AAResults AliasAnalysis
ProgramOperationPtr readPending_
ProgramOperations lacking result read.
bool constructed_
Whether the BB has been constructed or not.
ProgramOperationPtr destPending_
ProgramOperations lacking operands.
MoveNodeUseMapSet memFirstDefines_
static bool appendUseMapSets(const MoveNodeUseMapSet &srcMap, MoveNodeUseMapSet &dstMap, bool addLoopProperty)
MoveNodeUseMapSet memUseReaches_
MoveNodeUseMapSet regFirstUses_
MoveNodeUseMapSet regLastUses_
MoveNodeUseSet fuDepAfter_
MoveNodeUseMapSet memLastUses_
MoveNodeUseSet fuDepReaches_
MoveNodeUseMapSet regUseAfter_
MoveNodeUseMapSet regUseReaches_
std::set< TCEString > registersUsedAfter_
MoveNodeUseMapSet regFirstDefines_
std::set< TCEString > inlineAsmClobbers_
MoveNodeUseMapSet memDefines_
MoveNodeUseMapSet regDefAfter_
std::set< TCEString > registersUsedInOrAfter_
MoveNodeUseMapPair regKills_
MoveNodeUseSet fuDeps_
static void appendMoveNodeUse(const MoveNodeUseSet &src, MoveNodeUseSet &dst, bool setLoopProperty)
MoveNodeUseMapSet memDefAfter_
std::set< TCEString > inlineAsmRegDefs_
std::map< TCEString, std::pair< MoveNodeUse, bool > > potentialRegKills_
std::set< TCEString > inlineAsmRegUses_
MoveNodeUseMapPair regLastKills_
MoveNodeUseMapSet regDefines_
MoveNodeUseMap memKills_
MoveNodeUseMapSet memUseAfter_
MoveNodeUseMapSet memDefReaches_
MoveNodeUseMapSet memFirstUses_
MoveNodeUseMap memLastKill_
MoveNodeUseMapSet regDefReaches_