OpenASIP 2.2
Loading...
Searching...
No Matches
Instruction.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2016 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 Instruction.cc
26 *
27 * Implementation of Instruction class.
28 *
29 * @author Ari Metsähalme 2005 (ari.metsahalme-no.spam-tut.fi)
30 * @author Pekka Jääskeläinen 2016
31 * @note rating: red
32 */
33
34#include <boost/format.hpp>
35
36#include "Instruction.hh"
37#include "NullInstruction.hh"
38#include "Procedure.hh"
39#include "ContainerTools.hh"
40#include "Move.hh"
41#include "Immediate.hh"
42#include "Terminal.hh"
43#include "TerminalImmediate.hh"
45#include "NullProcedure.hh"
46#include "POMDisassembler.hh"
47#include "Conversion.hh"
48#include "Bus.hh"
49
50#include "MathTools.hh"
51
52namespace TTAProgram {
53
54/////////////////////////////////////////////////////////////////////////////
55// Instruction
56/////////////////////////////////////////////////////////////////////////////
57
58/**
59 * The constructor.
60 *
61 * The default size of an instruction is 1 MAU.
62 */
64 const TTAMachine::InstructionTemplate& instructionTemplate) :
65 parent_(NULL), insTemplate_(&instructionTemplate),
66 positionInProcedure_((InstructionAddress)-1),
67 finalAddress_((InstructionAddress)-1),
68 size_(1), hasRegisterAccesses_(false), hasConditionalRegisterAccesses_(false) {
69}
70
71/**
72 * Constructor.
73 *
74 * Alternative constructor that takes the instruction size as a parameter.
75 *
76 * @param size The size of the instruction in MAU's.
77 */
79 int size,
80 const TTAMachine::InstructionTemplate& instructionTemplate) :
81 parent_(NULL), insTemplate_(&instructionTemplate),
82 positionInProcedure_((InstructionAddress)-1),
83 finalAddress_((InstructionAddress)-1),
84 size_(size), hasRegisterAccesses_(false), hasConditionalRegisterAccesses_(false) {
85 assert(size == 1 &&
86 "Instructions sizes other than 1 not supported in POM at the "
87 "moment.");
88}
89
90/**
91 * The destructor.
92 */
94 for (auto i : moves_) {
95 i->setParent(NullInstruction::instance());
96 }
97 moves_.clear();
98 immediates_.clear();
99}
100
101/**
102 * Return the parent that contains the instruction.
103 *
104 * @return The parent that contains the instruction.
105 * @exception IllegalRegistration If the instruction is not registered
106 * anywhere.
107 */
110 if (parent_ != NULL) {
111 return *parent_;
112 } else {
113 throw IllegalRegistration(__FILE__, __LINE__, __func__,
114 "Instruction is not registered.");
115 }
116}
117
118/**
119 * Sets the parent procedure of the instruction.
120 *
121 * @param proc The new parent procedure.
122 */
123void
125 parent_ = &proc;
126}
127
128/**
129 * Tells whether the instruction belongs to a procedure.
130 *
131 * @return True if the instruction belongs to a procedure (it is registered),
132 * false otherwise.
133 */
134bool
136 return (parent_ != NULL && parent_ != &NullProcedure::instance());
137}
138
139/**
140 * Adds a move to the instruction.
141 *
142 * The ownership of the move will be passed to the instruction.
143 *
144 * @param move The move to add.
145 */
146void
147Instruction::addMove(std::shared_ptr<Move> move) {
149 throw ObjectAlreadyExists(__FILE__, __LINE__, __func__,
150 "Move is already added.");
151 } else {
152 if (move->source().isGPR() || move->destination().isGPR()) {
154 if (!move->isUnconditional())
156 }
157 moves_.push_back(move);
158 move->setParent(*this);
159 }
160#if 0
162 if (insTemplate_->usesSlot(move->bus().name())) {
163 assert(false &&
164 "Instruction template already uses the move's slot");
165 }
166 }
167#endif
168}
169
170/**
171 * Returns the number of moves contained in this instruction.
172 *
173 * @return The number of moves contained in this instruction.
174 */
175int
177 return moves_.size();
178}
179
180/**
181 * Return the move at the given index in this instruction.
182 *
183 * The order of moves is arbitrary, no assumption should be made by
184 * clients. Anyways, order of moves in instruction does not change between
185 * calls to this method.
186 *
187 * @param i The index of the move.
188 * @return The move at the given index in this instruction.
189 * @exception OutOfRange if the given index is negative or greater than
190 * the number of moves in the instruction.
191 */
192Move&
193Instruction::move(int i) const {
194 if (i < 0 || static_cast<unsigned int>(i) >= moves_.size()) {
195 throw OutOfRange(__FILE__, __LINE__, __func__,
196 "No move in instruction for given index: " +
198 } else {
199 return *moves_.at(i);
200 }
201}
202
203/**
204 * Return the move at the given index in this instruction.
205 *
206 * The order of moves is arbitrary, no assumption should be made by
207 * clients. Anyways, order of moves in instruction does not change between
208 * calls to this method.
209 *
210 * @param i The index of the move.
211 * @return The move at the given index in this instruction.
212 * @exception OutOfRange if the given index is negative or greater than
213 * the number of moves in the instruction.
214 */
215std::shared_ptr<Move>
217 if (i < 0 || static_cast<unsigned int>(i) >= moves_.size()) {
218 throw OutOfRange(__FILE__, __LINE__, __func__,
219 "No move in instruction for given index: " +
221 } else {
222 return moves_.at(i);
223 }
224}
225
226/**
227 * Adds an immediate to the instruction.
228 *
229 * The ownership of the immediate will be passed to the instruction.
230 *
231 * @param imm The immediate to add.
232 */
233void
234Instruction::addImmediate(std::shared_ptr<Immediate> imm) {
236 throw ObjectAlreadyExists(__FILE__, __LINE__, __func__,
237 "Immediate is already added.");
238 } else {
239 immediates_.push_back(imm);
240 imm->setParent(this);
241 }
242
243#if 0
245 int requiredWidth = std::min(
246 MathTools::requiredBits(imm->value().value().unsignedValue()),
247 imm->value().value().width());
248
249 if (requiredWidth >
250 insTemplate_->supportedWidth(imm->destination().immediateUnit())) {
251 assert(false &&
252 "The immediate is wider than the instruction template can "
253 "transport.");
254 }
255 }
256#endif
257}
258
259/**
260 * Returns the number of immediate registers written by the
261 * instruction template of this instruction.
262 *
263 * @return The number of immediate registers written by the
264 * instruction template of this instruction.
265 */
266int
268 return immediates_.size();
269}
270
271/**
272 * Return the immediate write action at the given index in this
273 * instruction.
274 *
275 * The order of immediates is arbitrary, no assumption should be made
276 * by clients.
277 *
278 * @param i The index of the immediate.
279 * @return The immediate write action at the given index in this
280 * instruction.
281 * @exception OutOfRange if the index is negative or greater than the
282 * number of immediates in the instruction.
283 */
286 if (i < 0 || static_cast<unsigned int>(i) >= immediates_.size()) {
287 throw OutOfRange(__FILE__, __LINE__, __func__,
288 "No immediate in instruction with index: " +
290 } else {
291 return *immediates_.at(i);
292 }
293}
294
295/**
296 * Return the immediate write action at the given index in this
297 * instruction.
298 *
299 * The order of immediates is arbitrary, no assumption should be made
300 * by clients.
301 *
302 * @param i The index of the immediate.
303 * @return The immediate write action at the given index in this
304 * instruction.
305 * @exception OutOfRange if the index is negative or greater than the
306 * number of immediates in the instruction.
307 */
308std::shared_ptr<Immediate>
310 if (i < 0 || static_cast<unsigned int>(i) >= immediates_.size()) {
311 throw OutOfRange(__FILE__, __LINE__, __func__,
312 "No immediate in instruction with index: " +
314 } else {
315 return immediates_[i];
316 }
317}
318
319/**
320 * Returns the address of the instruction.
321 *
322 * @return The address of the instruction.
323 * @exception IllegalRegistration if the instruction does not belong
324 * to a procedure.
325 */
329 Address address(finalAddress_, parent().startAddress().space());
330 return address;
331 }
332
333 if (!isInProcedure()) {
334 TCEString msg = "Instruction is not registered in a procedure: ";
335 msg += POMDisassembler::disassemble(*this);
337 __FILE__, __LINE__, __func__,
338 msg);
339 }
340 // speed up by caching the Instruction's position in the Procedure
343 (InstructionAddress)parent().instructionCount() &&
344 &parent().instructionAtIndex(positionInProcedure_) == this) {
345 // the instruction has not moved in the Procedure, we
346 // can compute its address in constant time
347 // cannot cache the Address itself because the Procedure might
348 // have moved
350 parent().startAddress().location() + positionInProcedure_,
351 parent().startAddress().space());
352 return address;
353 } else {
354 Address address = parent().address(*this);
357 return address;
358 }
359}
360
361/**
362 * Returns the size of the instruction in MAU's.
363 */
364short
366 return size_;
367}
368
369/**
370 * Make a complete copy of the instruction.
371 *
372 * The copy is identical, except that it is not registered to the
373 * procedure of the original instruction (and therefore, any address
374 * it refers to is not meaningful).
375 *
376 * @return A complete copy of the instruction.
377 */
380 Instruction* newIns = new Instruction(size_, *insTemplate_);
381 for (int i = 0; i < moveCount(); i++) {
382 newIns->addMove(move(i).copy());
383 }
384 for (int i = 0; i < immediateCount(); i++) {
385 newIns->addImmediate(immediate(i).copy());
386 }
389 newIns->copyAnnotationsFrom(*this);
390 return newIns;
391}
392
393/**
394 * Returns true in case this Instruction contains moves that access registers.
395 *
396 * This method can be used to optimize register utilization analysis.
397 */
398bool
402
403/**
404 * Returns true in case this Instruction contains moves that access registers
405 * and are conditional.
406 *
407 * This method can be used to optimize register utilization analysis.
408 *
409 * @return True in case at least one conditional move accesses registers.
410 */
411bool
415
416/**
417 * Returns whether this instruction contains moves that are jumps.
418 *
419 * @return True in case at least one move in this instruction is a jump.
420 */
421bool
423
424 for (int i = 0; i < moveCount(); i++ ) {
425 if (move(i).isJump()) {
426 return true;
427 }
428 }
429 return false;
430}
431
432/**
433 * Returns whether this instruction contains moves that are calls.
434 *
435 * @return True in case at least one move in this instruction is a call.
436 */
437bool
439
440 for (int i = 0; i < moveCount(); i++ ) {
441 if (move(i).isCall()) {
442 return true;
443 }
444 }
445 return false;
446}
447
448/**
449 * Returns whether this instruction contains a procedure return move.
450 */
451bool
453
454 for (int i = 0; i < moveCount(); i++ ) {
455 if (move(i).isReturn()) {
456 return true;
457 }
458 }
459 return false;
460}
461
462
463/**
464 * Returns whether this instruction contains moves that affect the
465 * control flow (branches or calls).
466 *
467 * @return True in case at least one move in this instruction is a control
468 * flow move.
469 */
470bool
472 for (int i = 0; i < moveCount(); i++) {
473 if (move(i).isControlFlowMove()) {
474 return true;
475 }
476 }
477 return false;
478}
479
480
481
482/**
483 * Sets instruction template.
484 *
485 * @param insTemp Instruction template for the instruction.
486 */
487void
489 const TTAMachine::InstructionTemplate& insTemp) {
490 insTemplate_= &insTemp;
491
492#if 0
493 for (int i = 0; i < moveCount(); i++) {
494 if (insTemplate_->usesSlot(move(i).bus().name())) {
495 assert(false && "Instruction template conflicts with the "
496 "instruction's slot layout: Both the new template and a move "
497 "uses same slot.");
498 }
499 }
500
501 for (int i = 0; i < immediateCount(); i++) {
502 int requiredWidth = std::min(
504 immediate(i).value().value().unsignedValue()),
505 immediate(i).value().value().width());
506 if (requiredWidth >
508 immediate(i).destination().immediateUnit())) {
509 assert(false && "The instruction has an long immediate "
510 "not supported by the new instruction template.");
511 }
512 }
513#endif
514}
515
516
517/**
518 * Returns the instruction template of instruction.
519 *
520 * @return The instruction template of instruction.
521 */
526
527/**
528 * Remove move from instruction.
529 *
530 * Move may become deleted if last smart pointer to it gets removed.
531 *
532 * @param move Move to remove.
533 * @exception IllegalRegistration If move doesn't belong to instruction.
534 */
535void
537 if (&move.parent() != this) {
538 throw IllegalRegistration(__FILE__, __LINE__);
539 }
540
542 for (MoveList::iterator iter = moves_.begin();
543 iter != moves_.end(); iter++) {
544 if ((iter->get()) == &move) {
545 moves_.erase(iter);
546 break;
547 }
548 }
549}
550
551/**
552 * Remove immediate from instruction.
553 *
554 * Immediate may get deleted if use-count of smart pointer goes to zero.
555 *
556 * @param immediate Immediate to remove.
557 * @exception IllegalRegistration If immediate doesn't belong to instruction.
558 */
559void
561 for (ImmList::iterator iter = immediates_.begin();
562 iter != immediates_.end(); iter++) {
563 if ((*iter).get() == &imm) {
564 imm.setParent(nullptr);
565 immediates_.erase(iter);
566 return;
567 }
568 }
569 throw IllegalRegistration(__FILE__, __LINE__);
570}
571
572/**
573 * Returns the disassembly of the instruction.
574 */
575std::string
577 return POMDisassembler::disassemble(*this);
578}
579
580}
#define __func__
#define assert(condition)
UInt32 InstructionAddress
Definition BaseType.hh:175
find Finds info of the inner loops in the false
static bool containsValue(const ContainerType &aContainer, const ElementType &aKey)
static std::string toString(const T &source)
static int requiredBits(unsigned long int number)
static std::string disassemble(const TTAProgram::Move &move)
virtual TCEString name() const
virtual bool usesSlot(const std::string &slotName) const
static NullInstructionTemplate & instance()
InstructionAddress location() const
void copyAnnotationsFrom(const AnnotatedInstructionElement &other)
virtual Address address(const Instruction &ins) const
virtual Address startAddress() const
void setParent(Instruction *ins)
Definition Immediate.hh:68
std::shared_ptr< Immediate > copy() const
Definition Immediate.cc:131
CodeSnippet * parent_
Parent procedure.
const TTAMachine::InstructionTemplate * insTemplate_
Instruction template that is used for this instruction.
Instruction * copy() const
bool hasConditionalRegisterAccesses_
Set to true in case this instruction has moves that access registers and are conditional.
MoveList moves_
Moves contained in this instruction.
void removeImmediate(Immediate &imm)
Instruction(const TTAMachine::InstructionTemplate &instructionTemplate=TTAMachine::NullInstructionTemplate::instance())
std::string toString() const
void addImmediate(std::shared_ptr< Immediate > imm)
short size_
Size of instruction in MAU's.
std::shared_ptr< Move > movePtr(int i) const
Move & move(int i) const
Address address() const
InstructionAddress positionInProcedure_
Cache the instruction's index in the its procedure for faster address().
std::shared_ptr< Immediate > immediatePtr(int i) const
ImmList immediates_
Immediates contained in this instruction.
bool hasControlFlowMove() const
bool hasConditionalRegisterAccesses() const
Immediate & immediate(int i) const
void addMove(std::shared_ptr< Move > move)
InstructionAddress finalAddress_
In case the final instruction address is known (due to program not modified anymore),...
void removeMove(Move &move)
void setInstructionTemplate(const TTAMachine::InstructionTemplate &insTemp)
CodeSnippet & parent() const
const TTAMachine::InstructionTemplate & instructionTemplate() const
void setParent(CodeSnippet &proc)
bool hasRegisterAccesses_
Set to true in case this instruction has moves that access registers.
bool hasRegisterAccesses() const
bool isControlFlowMove() const
Definition Move.cc:233
bool isReturn() const
Definition Move.cc:259
bool isUnconditional() const
Definition Move.cc:154
Instruction & parent() const
Definition Move.cc:115
Terminal & source() const
Definition Move.cc:302
std::shared_ptr< Move > copy() const
Definition Move.cc:413
bool isJump() const
Definition Move.cc:164
bool isCall() const
Definition Move.cc:190
void setParent(Instruction &ins)
Definition Move.cc:130
Terminal & destination() const
Definition Move.cc:323
const TTAMachine::Bus & bus() const
Definition Move.cc:373
static NullInstruction & instance()
static NullProcedure & instance()
virtual bool isGPR() const
Definition Terminal.cc:107