OpenASIP 2.2
Loading...
Searching...
No Matches
BFOptimization.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2014 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/**
26 * @file BFOptimization.cc
27 *
28 * Definition of BFOptimization class.
29 *
30 * Base class for all optimizations and scheudling operations the
31 * BF2 instruction scheduler can perform. Contains an undo-mechanism
32 * To undo everything, and contains handling for scheudling mirror move
33 * to prolog/epilog in case of loop scheduling.
34 *
35 * @author Heikki Kultala 2014-2020(heikki.kultala-no.spam-tuni.fi)
36 * @note rating: red
37 */
38
39#include "BFOptimization.hh"
40#include "BF2Scheduler.hh"
42#include "Move.hh"
43#include "MoveGuard.hh"
44#include "CodeGenerator.hh"
45#include "Guard.hh"
46#include "RegisterFile.hh"
47#include "MoveNodeDuplicator.hh"
48#include "Terminal.hh"
50#include "Operation.hh"
51#include "UniversalMachine.hh"
52#include "ControlUnit.hh"
53#include "Instruction.hh"
54#include "Bus.hh"
55#include "BF2ScheduleFront.hh"
57#include "HWOperation.hh"
58#include "FUPort.hh"
59#include "TerminalImmediate.hh"
60
61//#define DEBUG_BUBBLEFISH_SCHEDULER
62//#define DEBUG_LOOP_SCHEDULER
63//#define CHECK_PROLOG_DDG
64
65#ifdef DEBUG_BUBBLEFISH_SCHEDULER
66#include "POMDisassembler.hh"
67#define DEBUG_LOOP_SCHEDULER
68#endif
69
84
85unsigned int BFOptimization::ii() const { return 0; }
86
90
92 if (prologRM() == NULL) {
93 return false;
94 }
95 // TODO: better way to no prolog move for lbufc op
96 if (mn.move().isControlFlowMove() &&
97 !mn.move().isJump()) {
98 return false;
99 }
100 return true;
101}
102
104 const TTAMachine::Bus* bus,
105 const TTAMachine::FunctionUnit* srcFU,
106 const TTAMachine::FunctionUnit* dstFU,
107 const TTAMachine::Bus* prologBus,
108 int immWriteCycle,
109 int prologImmWriteCycle,
110 const TTAMachine::ImmediateUnit* immu,
111 int immRegIndex,
112 bool ignoreGWC) {
113
114 bool createdPrologCopy = false;
115#ifdef DEBUG_LOOP_SCHEDULER
116 if (ii() != 0) {
117 std::cerr << "\t\t\t\tAssigning in loop sched: " << mn.toString()
118 << " to cycle: " << cycle << " imm write cycle: "
119 << immWriteCycle << std::endl;
120 }
121#else
122#ifdef DEBUG_BUBBLEFISH_SCHEDULER
123 std::cerr << "\t\t\t\t\tAssigning mn: " << mn.toString()
124 << " imm write cycle: " << immWriteCycle << std::endl;
125#endif
126#endif
127 bool usePrologMN = usePrologMove(mn);
128 MoveNode* prologEpilogMN = NULL;
129 // TODO: why trying to assign all to prolog fails???
130 if (usePrologMN) {
131 auto a = createCopyForPrologEpilog(mn);
132 prologEpilogMN = a.first;
133 createdPrologCopy = a.second;
134 }
135
136 // TODO: assert if too early due the integrated epilog and guard.
137 if (!(addJumpGuardIfNeeded(mn, cycle, ignoreGWC))) {
138 std::cerr << "Adding jump guard failed for node: "
139 << mn.toString() << std::endl;
140 ddg().writeToDotFile("adding_jump_guard_fail.dot");
141 assert(false);
142 }
143
144#ifdef DEBUG_BUBBLEFISH_SCHEDULER
145 if (!rm().canAssign(
146 cycle, mn, bus, srcFU, dstFU, immWriteCycle, immu, immRegIndex)) {
147 std::cerr << "cannot assign move in assign: " << mn.toString()
148 << " cycle: " << cycle << std::endl;
149 TTAProgram::Move& m = mn.move();
150 std::cerr << "set bus: " << m.bus().name() << std::endl;
151 if (bus != NULL) {
152 std::cerr << "bus: " << bus->name() << std::endl;
153 }
154 if (srcFU != NULL) {
155 std::cerr << "src FU: " << srcFU->name() << std::endl;
156 }
157 if (dstFU != NULL) {
158 std::cerr << "dst FU: " << dstFU->name() << std::endl;
159 }
160
161 std::cerr << "annotations:" << std::endl;
162 for (int i = 0 ; i < m.annotationCount(); i++) {
163 const TTAProgram::ProgramAnnotation& anno = m.annotation(i);
164 std::cerr << "\thas anno, id: " << anno.id()
165 << " data: " << anno.stringValue() << std::endl;
166 }
167 if (mn.isSourceOperation()) {
168 std::cerr << "Source op: " << mn.sourceOperation().toString()
169 << std::endl;
170 }
171 if (mn.isDestinationOperation()) {
172 std::cerr << "Destination op: "
173 << mn.destinationOperation().toString() << std::endl;
174 }
175 ddg().writeToDotFile("cannot_assign_on_assign.dot");
176 assert(false);
177 }
178#endif
179
180 rm().assign(
181 cycle, mn, bus, srcFU, dstFU, immWriteCycle, immu, immRegIndex);
182#ifdef DEBUG_BUBBLEFISH_SCHEDULER
183 std::cerr << "\t\t\t\t\tAssigned mn: " << mn.toString() << std::endl;
184#endif
185 assert(bus == NULL || bus == &mn.move().bus());
186 if (usePrologMN) {
187 assignCopyToPrologEpilog(cycle, *prologEpilogMN, mn, prologBus,
188 prologImmWriteCycle);
189#ifdef CHECK_PROLOG_DDG
190 checkPrologDDG(*prologEpilogMN);
191#endif
192 }
193 return createdPrologCopy;
194}
195
196void BFOptimization::unassign(MoveNode& mn, bool disposePrologCopy) {
197#ifdef DEBUG_BUBBLEFISH_SCHEDULER
198 std::cerr << "\t\t\t\t\tUnassigning mn: " << mn.toString()
199 << "dispose: " << disposePrologCopy << std::endl;
200#endif
201 int cycle = mn.cycle();
202 rm().unassign(mn);
203 bool usePrologMN = usePrologMove(mn);
204 if (usePrologMN) {
205 unassignCopyFromPrologEpilog(mn, disposePrologCopy);
206 }
207 unsetJumpGuardIfNeeded(mn, cycle);
208#ifdef DEBUG_BUBBLEFISH_SCHEDULER
209 std::cerr << "\t\t\t\t\tUnassignined mn: " << mn.toString() << std::endl;
210#endif
211}
212
214 const TTAMachine::Bus* bus,
215 const TTAMachine::FunctionUnit* srcFU,
216 const TTAMachine::FunctionUnit* dstFU,
217 const TTAMachine::Bus* prologBus,
218 int immWriteCycle,
219 int prologImmWriteCycle,
220 const TTAMachine::ImmediateUnit* immu,
221 int immRegIndex) {
222#ifdef DEBUG_LOOP_SCHEDULER
223 if (ii()) {
224 std::cerr << "\t\t\t\t\tbfopt::rmec called, cycle: " << cycle
225 << " mn: " << mn.toString() <<
226 std::endl;
227
228 }
229#else
230#ifdef DEBUG_BUBBLEFISH_SCHEDULER
231 std::cerr << "\t\t\t\t\tCalling rmec for: " << mn.toString()
232 << " cycle: " << cycle << "dispose: "
233 << disposePrologCopy << std::endl;
234#endif
235#endif
236 if (!ii()) {
237 return rm().earliestCycle(
238 cycle, mn, bus, srcFU, dstFU, immWriteCycle, immu, immRegIndex);
239 }
240 // cannot add guard if already has guard. so limit cycle to 2nd round.
241 if (!mn.move().isUnconditional() && needJumpGuard(mn, cycle)) {
242 cycle = ii();
243 }
244
245 MoveNode* prologMN = nullptr;
246 bool createdCopy = false;
247 bool usePrologMN = usePrologMove(mn);
248 if (usePrologMN) {
249 auto a = duplicator().duplicateMoveNode(mn, false, false);
250 prologMN = a.first;
251 createdCopy = a.second;
252 }
253
254 bool setGuard = false;
255 int ec = rm().earliestCycle(
256 cycle, mn, bus, srcFU, dstFU, immWriteCycle, immu, immRegIndex);
257 if (ec == INT_MAX || ec == -1) {
258#ifdef DEBUG_BUBBLEFISH_SCHEDULER
259 std::cerr << "\t\t\t\t\trmec over with -1" << std::endl;
260#endif
261 if (createdCopy) {
262 duplicator().disposeMoveNode(prologMN);
263 }
264 return ec;
265 }
266
267 while (ec < (signed)(2*ii())) {
268 if (needJumpGuard(mn, ec)) {
269 if (ec < jumpGuardAvailableCycle(mn)) {
270 ec++;
271 continue;
272 }
273 if (!setGuard) {
275 setJumpGuard(mn);
276 setGuard = true;
277 continue;
278 }
279 } else { // no longer need jump guard.
280 if (setGuard) {
281 assert(!mn.move().isUnconditional());
282 unsetJumpGuard(mn);
283 setGuard = false;
284 continue;
285 }
286 }
287
288 if (!setGuard) {
289 ec = rm().earliestCycle(
290 ec, mn, bus, srcFU, dstFU, immWriteCycle, immu, immRegIndex);
291 if (ec == -1) {
292 break;
293 }
294 } else {
295 int newEC = rm().earliestCycle(
296 ec, mn, bus, srcFU, dstFU, immWriteCycle);
297 // if set guard, guard may reduce too much..
298 if (newEC > ec) {
299 ec = std::min(newEC, (signed)(ii()));
300 continue;
301 }
302 if (newEC == -1) {
303 ec = -1;
304 break;
305 }
306 }
307 if (ec == INT_MAX) {
308 break;
309 }
310
311
312 if (usePrologMN) {
313 bool assignedMN = false;
314 auto mySrcFU = srcFU;
315 auto myDstFU = dstFU;
316 auto myImmu = immu;
317 auto myImmReg = immRegIndex;
318 if (hasAmbiguousResources(mn)) {
319 rm().assign(ec, mn, bus, srcFU, dstFU, immWriteCycle, immu,
320 immRegIndex);
321 mySrcFU = sourceFU(mn);
322 myDstFU = destinationFU(mn);
323 if (mn.isSourceImmediateRegister()) {
324 myImmReg = mn.move().source().index();
325 myImmu = &mn.move().source().immediateUnit();
326 }
327 assignedMN = true;
328 }
329 bool ok = prologRM()->canAssign(
330 ec + BF2Scheduler::PROLOG_CYCLE_BIAS, *prologMN, prologBus,
331 mySrcFU, myDstFU, prologImmWriteCycle, myImmu, myImmReg);
332 if (assignedMN) {
333 rm().unassign(mn);
334 }
335 if (!ok) {
336 ec++;
337 continue;
338 } else {
339 break;
340 }
341 } else { // no prolog
342 if (createdCopy) {
343 duplicator().disposeMoveNode(prologMN);
344 }
345 if (setGuard) {
346 unsetJumpGuard(mn);
347 }
348 return ec;
349 }
350 }
351 if (createdCopy) {
352 duplicator().disposeMoveNode(prologMN);
353 }
354 if (setGuard) {
355 unsetJumpGuard(mn);
356 }
357#ifdef DEBUG_LOOP_SCHEDULER
358 std::cerr << "\t\t\t\t\trmec over" << std::endl;
359#endif
360 return ec;
361}
362
364 const TTAMachine::Bus* bus,
365 const TTAMachine::FunctionUnit* srcFU,
366 const TTAMachine::FunctionUnit* dstFU,
367 const TTAMachine::Bus* prologBus,
368 int immWriteCycle,
369 int prologImmWriteCycle,
370 const TTAMachine::ImmediateUnit* immu,
371 int immRegIndex) {
372#ifdef DEBUG_LOOP_SCHEDULER
373 if (ii()) {
374 std::cerr << "\t\t\t\t\tbfopt::rmlc called, cycle: " << cycle
375 << " mn: " << mn.toString() << std::endl;
376 }
377#else
378#ifdef DEBUG_BUBBLEFISH_SCHEDULER
379 std::cerr << "\t\t\t\t\tbfopt::rmlc called, cycle: " << cycle
380 << " mn: " << mn.toString() << std::endl;
381#endif
382#endif
383 int lc = cycle;
384 bool setGuard = false;
385 MoveNode* prologMN = NULL;
386 bool createdCopy = false;
387 bool usePrologMN = usePrologMove(mn);
388 if (usePrologMN) {
389 auto a = duplicator().duplicateMoveNode(mn, false, false);
390 prologMN = a.first;
391 createdCopy = a.second;
392 }
393
394 while (lc >= 0) {
395 lc = rm().latestCycle(lc,mn, bus, srcFU, dstFU, immWriteCycle);
396#ifdef DEBUG_LOOP_SCHEDULER
397 if (ii()) {
398 std::cerr << "\t\t\t\t\tgot lc from rm: " << lc << std::endl;
399 }
400#else
401#ifdef DEBUG_BUBBLEFISH_SCHEDULER
402 std::cerr << "\t\t\t\t\tgot lc from rm: " << lc << std::endl;
403#endif
404#endif
405 if (lc == -1) {
406 break;
407 }
408 if (needJumpGuard(mn, lc)) {
409#ifdef DEBUG_LOOP_SCHEDULER
410 std::cerr << "\t\t\t\t\tNeed jump guard for mn: "
411 << mn.toString() << " cycle: " << lc << std::endl;
412#endif
413 if (lc < jumpGuardAvailableCycle(mn)) {
414#ifdef DEBUG_LOOP_SCHEDULER
415 std::cerr << "\t\t\t\t\tjump guard not yet available so "
416 << "cannot schedule this ever" << std::endl;
417#endif
418 if (createdCopy) {
419 duplicator().disposeMoveNode(prologMN);
420 }
421 if (setGuard) {
422 unsetJumpGuard(mn);
423 }
424 return -1;
425 }
426 if (!setGuard) {
427 // cannot add guard if already has guard.
428 if (!mn.move().isUnconditional()) {
429 if (createdCopy) {
430 duplicator().disposeMoveNode(prologMN);
431 }
432 return -1;
433 }
434 setJumpGuard(mn);
435 setGuard = true;
436 continue;
437 }
438 }
439 if (usePrologMN) {
440 // then check that this can be assigned to prolog/epilog
441 // need to use the correct FU - only way to get it is to
442 // assign loop move first
443 bool assignedMN = false;
444 auto mySrcFU = srcFU;
445 auto myDstFU = dstFU;
446 auto myImmu = immu;
447 auto myImmReg = immRegIndex;
448
449 if (hasAmbiguousResources(mn)) {
450 rm().assign(lc, mn, bus, srcFU, dstFU, immWriteCycle);
451 mySrcFU = sourceFU(mn);
452 myDstFU = destinationFU(mn);
453 if (mn.isSourceImmediateRegister()) {
454 myImmReg = mn.move().source().index();
455 myImmu = &mn.move().source().immediateUnit();
456 }
457 assignedMN = true;
458 }
459 bool ok = prologRM()->canAssign(
460 lc + BF2Scheduler::PROLOG_CYCLE_BIAS, *prologMN, prologBus,
461 mySrcFU, myDstFU, prologImmWriteCycle, myImmu, myImmReg);
462 if (assignedMN) {
463 rm().unassign(mn);
464 }
465 if (!ok) {
466#ifdef DEBUG_LOOP_SCHEDULER
467 std::cerr << "prolog RM cannot assign to cycle: "
468 << lc << std::endl;
469 std::cerr << "instr in prolog rm: " <<
471 *prologRM()->instruction(
473#endif
474 lc--;
475 continue;
476 } else {
477 break;
478 }
479 } else { // not in a prolog.
480 if (createdCopy) {
481 duplicator().disposeMoveNode(prologMN);
482 }
483 return lc;
484 }
485 }
486 if (createdCopy) {
487 duplicator().disposeMoveNode(prologMN);
488 }
489 if (setGuard) {
490 unsetJumpGuard(mn);
491 }
492 return lc;
493}
494
496 const TTAMachine::Bus* bus,
497 const TTAMachine::FunctionUnit* srcFU,
498 const TTAMachine::FunctionUnit* dstFU,
499 const TTAMachine::Bus* prologBus,
500 int immWriteCycle,
501 int prologImmWriteCycle,
502 const TTAMachine::ImmediateUnit* immu,
503 int immRegIndex,
504 bool ignoreGuardWriteNode) {
505#ifdef DEBUG_BUBBLEFISH_SCHEDULER
506 if (ii()) {
507 std::cerr << "\t\t\t\t\tCalling BFOpt::canassign for: "
508 << mn.toString() << " cycle: " << cycle << std::endl;
509 } else {
510 std::cerr << "\t\t\t\t\tCalling BFOpt::canassign for: "
511 << mn.toString() << " cycle: " << cycle << std::endl;
512 }
513 if (bus) {
514 std::cerr << "\t\t\t\t\t\tBus: " << bus->name() << std::endl;
515 }
516 if (prologBus) {
517 std::cerr << "\t\t\t\t\t\tProlog bus: " << prologBus->name()
518 << std::endl;
519 }
520 if (srcFU) {
521 std::cerr << "\t\t\t\t\t\tSrc FU: " << srcFU->name() << std::endl;
522 }
523 if (dstFU) {
524 std::cerr << "\t\t\t\t\t\tDst FU: " << dstFU->name() << std::endl;
525 }
526 if (mn.isDestinationOperation()) {
527 std::cerr << "\t\t\t\t\t\tDst po: "
528 << mn.destinationOperation().toString() << std::endl;
529 }
530#endif
531 bool addGuard = needJumpGuard(mn, cycle);
532 if (addGuard) {
533#ifdef DEBUG_LOOP_SCHEDULER
534 std::cerr << "\t\t\t\t\t\tNeed jump guard, cycle: " << cycle
535 << "ii: " << ii() << std::endl;
536#endif
537 // cannot add guard if already has guard.
538 if (!mn.move().isUnconditional()) {
539#ifdef DEBUG_LOOP_SCHEDULER
540 std::cerr << "\t\t\t\t\tcanassin over with uncond" << std::endl;
541#endif
542 return false;
543 }
544 if (cycle < jumpGuardAvailableCycle(mn) && !ignoreGuardWriteNode) {
545#ifdef DEBUG_LOOP_SCHEDULER
546 std::cerr << "\t\t\t\t\tjump guard not yet available so"
547 << " cannot scheudle this." << std::endl;
548 std::cerr << "\t\t\t\t\t\tAvailable on cycle: "
549 << jumpGuardAvailableCycle(mn) << std::endl;
550#endif
551 return false;
552 }
553 setJumpGuard(mn);
554 }
555 bool ok = rm().canAssign(
556 cycle, mn, bus, srcFU, dstFU, immWriteCycle, immu, immRegIndex);
557#ifdef DEBUG_LOOP_SCHEDULER
558 if (ii()) {
559 std::cerr << "\t\t\t\t\t for this: " << ok << " , what about prolog?"
560 << std::endl;
561 }
562#endif
563
564 // then test assigning to prolog
565 bool usePrologMN = usePrologMove(mn);
566 if (ok && usePrologMN) {
567 // may not have the added jump guard when duplicating.
568 if (addGuard) unsetJumpGuard(mn);
569 auto a = duplicator().duplicateMoveNode(mn, false, false);
570 if (addGuard) setJumpGuard(mn);
571 MoveNode* prologMN = a.first;
572#ifdef DEBUG_LOOP_SCHEDULER
573 std::cerr << "\t\t\t\t\t\tProlog mn: " << prologMN->toString()
574 << std::endl;
575#endif
576 bool assignedMN = false;
577 if (hasAmbiguousResources(mn)) {
578 rm().assign(cycle, mn, bus, srcFU, dstFU, immWriteCycle, immu,
579 immRegIndex);
580 srcFU = sourceFU(mn);
581 dstFU = destinationFU(mn);
582 if (mn.isSourceImmediateRegister()) {
583 immRegIndex = mn.move().source().index();
584 immu = &mn.move().source().immediateUnit();
585 }
586 assignedMN = true;
587 }
588 ok &= prologRM()->canAssign(
589 BF2Scheduler::PROLOG_CYCLE_BIAS + cycle, *prologMN, prologBus,
590 srcFU, dstFU, prologImmWriteCycle, immu, immRegIndex);
591 if (assignedMN) {
592 rm().unassign(mn);
593 }
594 if (a.second) { //disposePrologCopy) {
595 duplicator().disposeMoveNode(prologMN);
596 }
597 }
598 unsetJumpGuardIfNeeded(mn, cycle);
599
600#ifdef DEBUG_LOOP_SCHEDULER
601 if (ii()) {
602 std::cerr << "\t\t\t\t\tcanassin over:" << ok << std::endl;
603 }
604#else
605#ifdef DEBUG_BUBBLEFISH_SCHEDULER
606 std::cerr << "\t\t\t\t\tcanassin over:" << ok << std::endl;
607#endif
608#endif
609 return ok;
610}
611
613#ifdef DEBUG_LOOP_SCHEDULER
614 std::cerr << "\t\t\t\t\tsetting jump guard to: " << mn.toString()
615 << std::endl;
616#endif
617
618 if (!mn.move().isUnconditional()) {
619 std::cerr << "Cannot set jump guard because already conditional: "
620 << mn.toString() << std::endl;
621 }
623
624 assert(!dynamic_cast<const TTAMachine::PortGuard*>(
625 &sched_.jumpGuard()->guard()));
626
628// TTAProgram::CodeGenerator::createInverseGuard(*sched_.jumpGuard());
629
630 mn.move().setGuard(newGuard);
631
632/*
633 TTAMachine::Guard& g = newGuard->guard();
634 TTAMachine::RegisterGuard* rg =
635 dynamic_cast<TTAMachine::RegisterGuard*>(&g);
636
637
638
639
640 TCEString regName;
641 regName << rg->registerFile()->name() << "." <<
642 rg->registerIndex();
643
644 DataDependenceEdge* e = new DataDependenceEdge(
645 DataDependenceEdge::EDGE_REGISTER,
646 DataDependenceEdge::DEP_RAW,
647 regName,
648 true, // guard
649 false, // true_alias mem dep
650 false, // tail pseudo
651 false, // head pseudo
652 1); // loop depth
653 ddg().connectNodes(*sched_.guardWriteNode(), mn,*e);
654
655*/
656#ifdef DEBUG_BUBBLEFISH_SCHEDULER
657 std::cerr << "\t\t\t\t\tset jump guard: " << mn.toString() << std::endl;
658#endif
659
660}
661
663#ifdef DEBUG_LOOP_SCHEDULER
664 std::cerr << "\t\t\t\t\tunsetting jump guard from: "
665 << mn.toString() << std::endl;
666#endif
668 mn.move().setGuard(NULL);
669#ifdef DEBUG_BUBBLEFISH_SCHEDULER
670 std::cerr << "\t\t\t\t\tunset jump guard: " << mn.toString() << std::endl;
671#endif
672}
673
675 MoveNode& mn) {
676 auto a = duplicator().duplicateMoveNode(mn, true, true);
677 prologMoves_[&mn] = a.first;
678 return a; //prologMN;
679}
680
682 TTAProgram::Move& m = prologMN.move();
683
684 if (loopMN.isSourceOperation()) {
687 TTAProgram::Terminal& source = loopMN.move().source();
688 assert(source.isFUPort());
689 std::string fuName = source.functionUnit().name();
690#ifdef DEBUG_LOOP_SCHEDULER
691 std::cerr << "\t\tSetting src Fu anno, loop MN: "
692 << loopMN.toString() << " prolog MN: "
693 << prologMN.toString() << std::endl;
694#endif
695 //TODO: which is the correct annotation here?
698 fuName);
699 m.setAnnotation(srcUnit);
700 }
701}
702
704 TTAProgram::Move& m = prologMN.move();
705
706 if (loopMN.isDestinationOperation()) {
709 TTAProgram::Terminal& dest = loopMN.move().destination();
710 assert(dest.isFUPort());
711 std::string fuName = dest.functionUnit().name();
712#ifdef DEBUG_LOOP_SCHEDULER
713 std::cerr << "\t\tSetting dst Fu anno, loop MN: "
714 << loopMN.toString() << " prolog MN: "
715 << prologMN.toString() << std::endl;
716#endif
717 //TODO: which is the correct annotation here?
720 fuName);
721 m.setAnnotation(dstUnit);
722 }
723}
724
727 return fuOfTerminal(mn.move().source());
728}
729
734
737 if (!t.isFUPort())
738 return NULL;
739 return &t.functionUnit();
740}
741
743 setPrologSrcFUAnno(prologMN, loopMN);
744 setPrologDstFUAnno(prologMN, loopMN);
745}
746
748 int cycle, MoveNode& prologMN, MoveNode& oldMN,
749 const TTAMachine::Bus* prologBus,
750 int prologImmWriteCycle) {
751
752 const TTAMachine::ImmediateUnit* immu = nullptr;
753 int immRegIndex = -1;
754 if (oldMN.isSourceImmediateRegister()) {
755 immRegIndex = oldMN.move().source().index();
756 immu = &oldMN.move().source().immediateUnit();
757 }
758
759#ifdef DEBUG_LOOP_SCHEDULER
760 std::cerr << "\t\t\t\t\tAssigning copy to prolog: " << cycle
761 << " " << prologMN.toString() <<
762 " prolog cycle: " << cycle + BF2Scheduler::PROLOG_CYCLE_BIAS
763 << std::endl;
764
765 if (!prologRM()->canAssign(
766 BF2Scheduler::PROLOG_CYCLE_BIAS + cycle, prologMN, prologBus,
767 sourceFU(oldMN), destinationFU(oldMN), prologImmWriteCycle,
768 immu, immRegIndex)) {
769 TTAProgram::Move& m = prologMN.move();
770
771 std::cerr << std::endl << "Cannot assign move to prolog! "
772 << prologMN.toString() << std::endl << std::endl;
773 std::cerr << "Preassigned bus: " << m.bus().name() << std::endl;
774 if (prologBus != nullptr) {
775 std::cerr << "prolog bus: " << prologBus->name() << std::endl;
776 }
777 std::cerr << "Cycle: " << cycle << " prolog cycle: "
778 << cycle + BF2Scheduler::PROLOG_CYCLE_BIAS << std::endl;
779
780 if (prologMN.isDestinationOperation()) {
781 std::cerr << "destpo: "
782 << prologMN.destinationOperation().toString()
783 << std::endl;
784 }
785
786 ddg().writeToDotFile("cannot_assign_prolog.dot");
787 prologDDG()->writeToDotFile("prologddg.dot");
788 int sc = prologRM()->smallestCycle();
789 int lc = prologRM()->largestCycle();
790 for (int i = sc; i <= lc; i++) {
791 std::cerr << "\t" << i << "\t"
792 << prologRM()->instruction(i)->toString() << std::endl;
793 }
794
795 assert(false && "Cannot asign copy to prolog");
796 }
797#endif
798
799 prologRM()->assign(
800 BF2Scheduler::PROLOG_CYCLE_BIAS + cycle, prologMN, prologBus,
801 sourceFU(oldMN), destinationFU(oldMN), prologImmWriteCycle,
802 immu, immRegIndex);
803#ifdef DEBUG_BUBBLEFISH_SCHEDULER
804 std::cerr << "\t\tAassigned copy to prolog, original mn: "
805 << oldMN.toString()
806 << " copy: " << prologMN.toString() << std::endl;
807#endif
808}
809
811 MoveNode& mn, bool disposePrologCopy) {
812#ifdef DEBUG_LOOP_SCHEDULER
813 std::cerr << "\t\tUnassigning copy from prolog, original mn: "
814 << mn.toString() << "dispose: "
815 << disposePrologCopy << std::endl;
816#endif
817 MoveNode* copy = prologMoves_[&mn];
818 if (copy != NULL) {
819 prologRM()->unassign(*copy);
820 prologMoves_.erase(&mn);
821#ifdef DEBUG_LOOP_SCHEDULER
822 std::cerr << "\t\t\tcopy after unassign: " << copy->toString()
823 << std::endl;
824#endif
825 if (disposePrologCopy) {
827 }
828 // TODO: program ops memory leak now
829#ifdef DEBUG_BUBBLEFISH_SCHEDULER
830 } else {
831 std::cerr << "\t\t\tCopy not found." << std::endl;
832#endif
833 }
834#ifdef DEBUG_BUBBLEFISH_SCHEDULER
835 std::cerr << "\t\tUnassigned copy from prolog, original mn: "
836 << mn.toString() << std::endl;
837#endif
838 prologMoves_.erase(&mn);
839}
840
841std::map<MoveNode*, MoveNode*, MoveNode::Comparator>
843
847
849 const MoveNode& mn, const TTAMachine::Machine& mach) {
850 if (!mn.isDestinationOperation()) {
851 return NULL;
852 }
854 return BasicBlockScheduler::findTrigger(po, mach);
855}
856
858 return
859 !op.usesMemory() &&
860 !op.hasSideEffects() &&
862 op.affectsCount() == 0;
863}
864
866 if (!mn.isDestinationOperation()) {
867 return false;
868 }
869 const MoveNode* trig = getSisterTrigger(mn, targetMachine());
870 // operand writes can be always speculated
871 if (&mn != trig && trig != NULL) {
872 return true;
873 }
874 const Operation& op = mn.destinationOperation().operation();
875 return canBeSpeculated(op);
876}
877
878bool BFOptimization::needJumpGuard(const MoveNode& mn, int cycle){
879 if (cycle >= (int)(ii())) {
880 return false;
881 }
882
883 return !canBeSpeculated(mn);
884}
885
886/**
887 * Returns false if needs guard but guard not available yet
888 */
890 bool ignoreGuardWriteCycle) {
891 if (needJumpGuard(mn, cycle)) {
892 if (jumpGuardAvailableCycle(mn) > cycle && !ignoreGuardWriteCycle) {
893#ifdef DEBUG_LOOP_SCHEDULER
894 std::cerr << "jump guard available at "
896 << " , not in cycle: " << cycle << std::endl;
897#endif
898 return false;
899 }
900 if (!mn.move().isUnconditional()) {
901#ifdef DEBUG_BUBBLEFISH_SCHEDULER
902 std::cerr << "Cannot add guard to already-conditional move "
903 << std::endl;
904#endif
905 return false;
906 }
907 setJumpGuard(mn);
908 }
909 return true;
910}
911
913 if (needJumpGuard(mn, cycle)) {
914 unsetJumpGuard(mn);
915 }
916}
917
919
921#ifdef DEBUG_LOOP_SCHEDULER
922 std::cerr << "jump node is null or guard operation!" << std::endl;
923#endif
924 return INT_MAX;
925 }
926 if (sched_.guardWriteNode() == NULL) {
927#ifdef DEBUG_LOOP_SCHEDULER
928 std::cerr << "Guard write node not known!" << std::endl;
929#endif
930 return INT_MAX;
931 }
932 if (&mn == sched_.guardWriteNode()) {
933#ifdef DEBUG_LOOP_SCHEDULER
934 std::cerr << "I AM guard write node!" << std::endl << std::endl;
935#endif
936 return 0;
937 }
939#ifdef DEBUG_LOOP_SCHEDULER
940 std::cerr << "guardwrite node is null or not sched:"
941 << sched_.guardWriteNode()->toString() << std::endl;
942#endif
943 return INT_MAX;
944 }
945
947 guardLatency()+
949
950 return glat+ sched_.guardWriteNode()->cycle() - ii();
951}
952
956
958 if (mn.isSourceOperation() &&
959 (mn.move().annotationCount(
961 && (mn.move().annotationCount(
963 return true;
964 }
965 if (mn.isDestinationOperation() &&
966 (mn.move().annotationCount(
968 && (mn.move().annotationCount(
970 return true;
971 }
972 // LIMM unit may be ambiguous resource
973 if (mn.isSourceConstant())
974 return true;
975
976 return false;
977}
978
980
981 auto& move = mn.move();
982 if (!move.source().isImmediate()) {
983 return false;
984 }
985
986 if (!mn.isDestinationOperation()) {
987 return false;
988 }
989
992
994 for (int i = 0; i < po.inputMoveCount(); i++) {
995 MoveNode& input = po.inputMove(i);
996 auto& inputMove = input.move();
997 if (input.move().destination().isFUPort() && input.isScheduled()) {
998 auto& fu = inputMove.destination().functionUnit();
999 auto hwop = fu.operation(po.operation().name());
1000 auto port = hwop->port(move.destination().operationIndex());
1001 if (!port->noRegister()) {
1002 return false;
1003 }
1004 if (inputMove.source().isImmediate()) {
1005 simmCount--;
1006 }
1007 if (inputMove.source().isImmediateRegister()) {
1008 limmCount--;
1009 }
1010 // all ways to transport immediate used.
1011 if (simmCount + limmCount < 1) {
1012 return true;
1013 }
1014 // needs LIMM but no LIMM available, only too narrow SIMMs available.
1015 if (limmCount < 1 &&
1017 static_cast<TTAProgram::TerminalImmediate&>(
1018 move.source()), *port,
1019 move.isUnconditional()
1020 ? nullptr
1021 : &move.guard().guard())) {
1022 return true;
1023 }
1024 }
1025 }
1026 return false;
1027}
1028
1031
1032 auto& move = mn.move();
1033 if (!move.source().isGPR()) {
1034 return nullptr;
1035 }
1036
1037 auto& rf = move.source().registerFile();
1038 int freeRFPorts = rf.maxReads();
1039
1040 if (!move.destination().isFUPort() || !mn.isDestinationOperation()) {
1041 return nullptr;
1042 }
1043
1045 for (int i = 0; i < po.inputMoveCount(); i++) {
1046 MoveNode& input = po.inputMove(i);
1047 auto& inputMove = input.move();
1048 if (input.move().destination().isFUPort() && input.isScheduled()) {
1049 auto& fu = inputMove.destination().functionUnit();
1050 auto hwop = fu.operation(po.operation().name());
1051 auto port = hwop->port(move.destination().operationIndex());
1052 if (!port->noRegister()) {
1053 return nullptr;
1054 }
1055 if (inputMove.source().isGPR() &&
1056 &inputMove.source().registerFile() == &rf) {
1057 freeRFPorts--;
1058 if (freeRFPorts < 1) {
1059 return &rf;
1060 }
1061 }
1062 }
1063 }
1064 return nullptr;
1065}
1066
1069 return false;
1071 return false;
1072 }
1074 return false;
1075 }
1076 return true;
1077}
1078
1080 auto oEdges = prologDDG()->outEdges(prologEpilogMN);
1081 auto iEdges = prologDDG()->inEdges(prologEpilogMN);
1082
1083 for (auto e: oEdges) {
1084 if (!e->isRAW())
1085 continue;
1086 MoveNode& head = prologDDG()->headNode(*e);
1087 if (head.isScheduled() && head.cycle() <= prologEpilogMN.cycle()) {
1088 prologDDG()->writeToDotFile("illegal_assign_in_prolog.dot");
1089
1090 ddg().writeToDotFile("mainddg.dot");
1091
1092 std::cerr << "Illegal assign of: " << prologEpilogMN.toString()
1093 << std::endl;
1094 assert(false);
1095 }
1096 }
1097
1098 for (auto e: iEdges) {
1099 if (!e->isRAW())
1100 continue;
1101 MoveNode& tail = prologDDG()->tailNode(*e);
1102 if (tail.isScheduled() && tail.cycle() >= prologEpilogMN.cycle()) {
1103 prologDDG()->writeToDotFile("illegal_assign_in_prolog.dot");
1104
1105 ddg().writeToDotFile("mainddg.dot");
1106
1107 std::cerr << "Illegal assign(2) of: " << prologEpilogMN.toString()
1108 << std::endl;
1109 assert(false);
1110 }
1111 }
1112}
1113
1114#ifdef CHECK_DDG_EQUALITY
1115void BFOptimization::getDDGSnapshot() {
1116 if (id() < CHECK_DDG_EQUALITY) {
1117 return;
1118 }
1119
1120 ddgECount_ = ddg().edgeCount();
1121 ddgString_ = ddg().dotString();
1122 if (prologDDG() != nullptr) {
1123 prologDDGString_ = prologDDG()->dotString();
1124 prologDDGECount_ = prologDDG()->edgeCount();
1125 prologDDGNCount_ = prologDDG()->nodeCount();
1126 }
1127}
1128
1129/**
1130 * Checks that DDG edge and node counts are same before the optimization
1131 * and after reverting it.
1132 */
1133void BFOptimization::checkDDGEquality() {
1134
1135 if (id() < CHECK_DDG_EQUALITY) {
1136 return;
1137 }
1138 int ddgECount = ddg().edgeCount();
1139 auto ddgst = ddg().dotString();
1140 if (ddgECount != ddgECount_ ) { //(ddgst != ddgString_) {
1141 std::cerr << "ddg changed! id:" << id() << std::endl;
1142
1143 std::ofstream output("before.dot");
1144 output << ddgString_;
1145 output.close();
1146
1147 ddg().writeToDotFile("after.dot");
1148 assert(false);
1149 }
1150 if (prologDDGString_ != "") {
1151 if (prologDDG()->edgeCount() != prologDDGECount_ ||
1152 prologDDG()->nodeCount() != prologDDGNCount_) {
1153
1154 std::cerr << "prolog ddg changed! id: " << id() << std::endl;
1155
1156 std::ofstream output("before.dot");
1157 output << prologDDGString_;
1158 output.close();
1159
1160 prologDDG()->writeToDotFile("after.dot");
1161 assert(false);
1162 }
1163 }
1164}
1165
1166void BFOptimization::undo() {
1168 checkDDGEquality();
1169}
1170#endif
#define assert(condition)
TTAMachine::Machine * machine
the architecture definition of the estimated processor
void mightBeReady(MoveNode &n) override
SimpleResourceManager & rm()
MoveNode * jumpNode()
DataDependenceGraph & ddg()
TTAProgram::MoveGuard * jumpGuard()
BUMoveNodeSelector & selector()
MoveNodeDuplicator & duplicator()
static const int PROLOG_CYCLE_BIAS
const TTAMachine::Machine & targetMachine() const
DataDependenceGraph * prologDDG()
MoveNode * guardWriteNode()
SimpleResourceManager * prologRM()
BF2ScheduleFront * currentFront()
bool usePrologMove(const MoveNode &mn)
void assignCopyToPrologEpilog(int cycle, MoveNode &mn, MoveNode &loopMN, const TTAMachine::Bus *prologBus, int prologImmWriteCycle)
bool needJumpGuard(const MoveNode &mn, int cycle)
DataDependenceGraph * prologDDG()
virtual void mightBeReady(MoveNode &mn)
const TTAMachine::FunctionUnit * sourceFU(const MoveNode &mn)
bool addJumpGuardIfNeeded(MoveNode &mn, int cycle, bool ignoreGuardWriteCycle=false)
unsigned int ii() const
BF2Scheduler & sched_
const TTAMachine::FunctionUnit * destinationFU(const MoveNode &mn)
virtual bool canAssign(int cycle, MoveNode &mn, const TTAMachine::Bus *bus=nullptr, const TTAMachine::FunctionUnit *srcFU=nullptr, const TTAMachine::FunctionUnit *dstFU=nullptr, const TTAMachine::Bus *prologBus=nullptr, int immWriteCycle=-1, int prologImmWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1, bool ignoreGWN=false)
void setJumpGuard(MoveNode &mn)
const TTAMachine::FunctionUnit * fuOfTerminal(const TTAProgram::Terminal &t)
void setPrologFUAnnos(MoveNode &prologMN, MoveNode &loopMN)
void unassignCopyFromPrologEpilog(MoveNode &mh, bool disposePrologCopy=true)
void setPrologSrcFUAnno(MoveNode &prologMN, MoveNode &loopMN)
static MoveNode * getSisterTrigger(const MoveNode &mn, const TTAMachine::Machine &mach)
void checkPrologDDG(MoveNode &prologEpilogMN)
SimpleResourceManager * prologRM() const
bool hasAmbiguousResources(MoveNode &mn) const
std::pair< MoveNode *, bool > createCopyForPrologEpilog(MoveNode &mn)
void setPrologDstFUAnno(MoveNode &prologMN, MoveNode &loopMN)
BUMoveNodeSelector & selector()
DataDependenceGraph & ddg()
const TTAMachine::RegisterFile * RFReadPortCountPreventsScheduling(const MoveNode &mn)
virtual void unassign(MoveNode &mn, bool disposePrologCopy=true)
DataDependenceGraph * rootDDG()
bool immCountPreventsScheduling(const MoveNode &mn)
int jumpGuardAvailableCycle(const MoveNode &mn)
virtual int rmLC(int cycle, MoveNode &mn, const TTAMachine::Bus *bus=nullptr, const TTAMachine::FunctionUnit *srcFU=nullptr, const TTAMachine::FunctionUnit *dstFU=nullptr, const TTAMachine::Bus *prologBus=nullptr, int immWriteCycle=-1, int prologImmWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1)
const TTAMachine::Machine & targetMachine() const
bool canBeScheduled(const MoveNode &mn)
virtual int rmEC(int cycle, MoveNode &mn, const TTAMachine::Bus *bus=nullptr, const TTAMachine::FunctionUnit *srcFU=nullptr, const TTAMachine::FunctionUnit *dstFU=nullptr, const TTAMachine::Bus *prologBus=nullptr, int immWriteCycle=-1, int prologImmWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1)
static void clearPrologMoves()
MoveNodeDuplicator & duplicator() const
SimpleResourceManager & rm() const
static std::map< MoveNode *, MoveNode *, MoveNode::Comparator > prologMoves_
virtual bool assign(int cycle, MoveNode &, const TTAMachine::Bus *bus=nullptr, const TTAMachine::FunctionUnit *srcFU_=nullptr, const TTAMachine::FunctionUnit *dstFU=nullptr, const TTAMachine::Bus *prologBus=nullptr, int immWriteCycle=-1, int prologImmWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1, bool ignoreGuardWriteCycle=false)
void unsetJumpGuard(MoveNode &mn)
bool canBeSpeculated(const Operation &op)
void unsetJumpGuardIfNeeded(MoveNode &mn, int cycle)
static MoveNode * findTrigger(const ProgramOperation &po, const TTAMachine::Machine &mach)
BoostGraph * rootGraph()
virtual Node & headNode(const Edge &edge) const
int nodeCount() const
int edgeCount() const
virtual EdgeSet outEdges(const Node &node) const
virtual Node & tailNode(const Edge &edge) const
virtual EdgeSet inEdges(const Node &node) const
virtual TCEString dotString() const
Dot printing related methods.
void removeIncomingGuardEdges(MoveNode &node)
virtual void writeToDotFile(const TCEString &fileName) const
static bool canTransportMove(const MoveNode &moveNode, const TTAMachine::Machine &machine, bool ignoreGuard=false)
static int maxLIMMCount(const TTAMachine::Machine &targetMachine)
static bool canTransportImmediate(const TTAProgram::TerminalImmediate &immediate, const TTAMachine::BaseRegisterFile &destRF, const TTAMachine::Guard *guard=NULL)
static int maxSIMMCount(const TTAMachine::Machine &targetMachine)
void disposeMoveNode(MoveNode *newMN)
std::pair< MoveNode *, bool > duplicateMoveNode(MoveNode &mn, bool addToDDG, bool ignoreSameBBBackEdges)
bool isGuardOperation() const
Definition MoveNode.cc:181
int cycle() const
Definition MoveNode.cc:421
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
bool isDestinationOperation() const
std::string toString() const
Definition MoveNode.cc:576
TTAProgram::Move & move()
bool isSourceOperation() const
Definition MoveNode.cc:168
bool isScheduled() const
Definition MoveNode.cc:409
bool isSourceImmediateRegister() const
Definition MoveNode.cc:223
bool isSourceConstant() const
Definition MoveNode.cc:238
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual TCEString name() const
Definition Operation.cc:93
virtual bool usesMemory() const
Definition Operation.cc:232
virtual bool isControlFlowOperation() const
Definition Operation.cc:294
virtual bool hasSideEffects() const
Definition Operation.cc:272
virtual int affectsCount() const
Definition Operation.cc:402
static std::string disassemble(const TTAProgram::Move &move)
const Operation & operation() const
int inputMoveCount() const
std::string toString() const
MoveNode & inputMove(int index) const
virtual void undo()
Definition Reversible.cc:69
virtual int smallestCycle() const override
virtual void assign(int cycle, MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) override
virtual int earliestCycle(MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
virtual void unassign(MoveNode &node) override
virtual bool canAssign(int cycle, MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
virtual TTAProgram::Instruction * instruction(int cycle) const override
virtual int largestCycle() const override
virtual int latestCycle(MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
virtual TCEString name() const
int globalGuardLatency() const
virtual HWOperation * operation(const std::string &name) const
virtual FUPort * port(int operand) const
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
virtual int maxReads() const
void removeAnnotations(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID)
int annotationCount(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
void setAnnotation(const ProgramAnnotation &annotation)
ProgramAnnotation annotation(int index, ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
std::string toString() const
MoveGuard * copy() const
Definition MoveGuard.cc:96
const TTAMachine::Guard & guard() const
Definition MoveGuard.cc:86
bool isControlFlowMove() const
Definition Move.cc:233
bool isUnconditional() const
Definition Move.cc:154
Terminal & source() const
Definition Move.cc:302
bool isJump() const
Definition Move.cc:164
void setGuard(MoveGuard *guard)
Definition Move.cc:360
Terminal & destination() const
Definition Move.cc:323
const TTAMachine::Bus & bus() const
Definition Move.cc:373
ProgramAnnotation::Id id() const
@ ANN_CONN_CANDIDATE_UNIT_DST
Dst. unit candidate.
@ ANN_CONN_CANDIDATE_UNIT_SRC
Src. unit candidate.
@ ANN_ALLOWED_UNIT_SRC
Candidate units can be passed for resource manager for choosing the source/destination unit of the mo...
virtual const TTAMachine::FunctionUnit & functionUnit() const
Definition Terminal.cc:251
virtual int index() const
Definition Terminal.cc:274
virtual const TTAMachine::ImmediateUnit & immediateUnit() const
Definition Terminal.cc:240
virtual const TTAMachine::RegisterFile & registerFile() const
Definition Terminal.cc:225
virtual bool isFUPort() const
Definition Terminal.cc:118