OpenASIP 2.2
Loading...
Searching...
No Matches
PreOptimizer.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2020 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 PreOptimizer.cc
26 *
27 * Implementation of GuardInverver class.
28 *
29 * This optimizer does some peephole optimizations before actual scheduling:
30 *
31 * Removes unneeded predicate arithmetic by using
32 * opposite guard instead where the guard is used.
33 *
34 * Changes registers of address calculations to eliminate entideps
35 *
36 * Removes adds of compile-time ocnstants
37 *
38 * @author Heikki Kultala 2009 (hkultala-no.spam-cs.tut.fi)
39 * @note rating: red
40 */
41
42#include "PreOptimizer.hh"
43#include "Procedure.hh"
44#include "Instruction.hh"
45#include "Move.hh"
46#include "ControlFlowGraph.hh"
48#include "ProgramOperation.hh"
49#include "Terminal.hh"
50#include "CodeGenerator.hh"
52#include "RegisterFile.hh"
54#include "Program.hh"
55#include "Operation.hh"
56#include "BasicBlock.hh"
58#include "Operand.hh"
59#include "TerminalImmediate.hh"
60#include "Bus.hh"
61
62static const int DEFAULT_LOWMEM_MODE_THRESHOLD = 200000;
63
64/**
65 * Constructor. Initializes interpassData.
66 *
67 * @param data InterPassData to store.
68 */
73
74/**
75 * Handles a program.
76 *
77 * @param program the program.
78 * @param targetMachine targetmachine. Not used at all.
79 */
80void
85
86bool
89
90 DataDependenceEdge* connectingEdge = NULL;
91
92 if (po.outputMoveCount() != 1 || po.inputMoveCount() != 1) {
93 return false;
94 }
95 MoveNode& address = po.inputMove(0);
96 MoveNode& result = po.outputMove(0);
97
98 DataDependenceGraph::EdgeSet iEdges = ddg.inEdges(address);
99
100 if (!result.move().destination().isGPR()) {
101 return false;
102 }
103
104 // do not put addresses to lane RF's
105 const TTAMachine::RegisterFile& rf =
106 result.move().destination().registerFile();
107 if (rf.name().find("L_") == 0) {
108 return false;
109 }
110
111 MoveNode* src = NULL;
112 // loop thru all inedges find who writes the address.
113 for (DataDependenceGraph::EdgeSet::iterator i = iEdges.begin();
114 i != iEdges.end(); i++) {
115 DataDependenceEdge& edge = **i;
117 !edge.guardUse()) {
119 return false;
120 }
121 if (edge.isBackEdge()) {
122 return false;
123 }
124 if (src == NULL) {
125 src = &ddg.tailNode(edge);
126 connectingEdge = &edge;
127 } else {
128 return false;
129 }
130 }
131 }
132 if (src == NULL) {
133 // load address missing
134 return false;
135 }
136
137 if (&ddg.getBasicBlockNode(address) != &ddg.getBasicBlockNode(*src)) {
138 return false;
139 }
140
141 // TODO: multi-threading might make this fail too often!
142 if (src->nodeID() != address.nodeID() - 1) {
143 // some other moves between these moves.
144 return false;
145 }
146
147 DataDependenceGraph::EdgeSet oEdges = ddg.outEdges(*src);
148 // loop thru all outedges.
149 for (DataDependenceGraph::EdgeSet::iterator i = oEdges.begin();
150 i != oEdges.end(); i++) {
151 DataDependenceEdge& edge = **i;
153 if (&ddg.headNode(edge) != &address) {
154 // same address used for some other operation.
155 return false;
156 }
157 }
158 }
159
160 // cannot use narrower reg for address.
161 if (address.move().source().registerFile().width() !=
162 result.move().destination().registerFile().width()) {
163 return false;
164 }
165
166 TCEString oldReg =
168 TCEString newReg =
170
171 address.move().setSource(result.move().destination().copy());
172 src->move().setDestination(result.move().destination().copy());
173
175 *src, address, result, *connectingEdge, oldReg, newReg);
176 return true;
177}
178
179/**
180 * Tries to remove an unnecessary guard value xor before a conditional jump.
181 *
182 * Tries to remove xor operation which is used for converting false boolean
183 * value into true boolean value which is then used for jump. The xor
184 * operation is removed and the jump predicate reversed.
185 *
186 * @param ddg The datadependence graph of the whole function
187 * @param po ProgramOperation which is a xor operation
188 * @param irm instructionreferencemanager of the program.
189 *
190 * @return Basic block whose output edge predicates need to be
191 * reversed of cfg or NULL if no need to change cfg.
192 */
193
198 if (po.outputMoveCount() != 1 || po.inputMoveCount() != 2) {
200 }
201 // check that it's or by 1.
202 MoveNode& operand2 = po.inputMove(1);
203 TTAProgram::Terminal& src2 = operand2.move().source();
204 if (!src2.isImmediate() || src2.value().intValue() != 1) {
206 }
207 // now we have a xor op which is a truth value reversal.
208 // find where the result is used.
209
210 return tryToRemoveGuardInversingOp(ddg, po, irm, cfg);
211}
212
213
218 if (po.outputMoveCount() != 1 || po.inputMoveCount() != 2) {
220 }
221 // check that it's or by 0.
222 MoveNode& operand1 = po.inputMove(0);
223 MoveNode& operand2 = po.inputMove(1);
224 TTAProgram::Terminal& src2 = operand2.move().source();
225 if (!src2.isImmediate() || src2.value().intValue() != 0) {
227 }
228 MoveNode* src = ddg.onlyRegisterRawSource(operand1);
229 if (src == NULL || !src->isSourceOperation()) {
231 }
232 ProgramOperation& srcOp = src->sourceOperation();
233 if (srcOp.operation().operand(
234 src->move().source().operationIndex()).type() == Operand::BOOL) {
235 // now we have a xor op which is a truth value reversal.
236 // find where the result is used.
237 return tryToRemoveGuardInversingOp(ddg, po, irm, cfg);
238 }
240}
241
242
247 ControlFlowGraph& cfg) {
248
249 MoveNode& operand1 = po.inputMove(0);
250 MoveNode& operand2 = po.inputMove(1);
251 MoveNode& result = po.outputMove(0);
252 TTAProgram::Move& resultMove = result.move();
253 DataDependenceGraph::EdgeSet oEdges = ddg.outEdges(result);
254
255 // some more complex things done with the guard.
256 // converting those not yet supported.
257 if (!checkGuardReversalAllowed(ddg, oEdges)) {
259 }
260
261 TTAProgram::Instruction& operand1Ins = operand1.move().parent();
262 TTAProgram::Instruction& operand2Ins = operand2.move().parent();
263 TTAProgram::Instruction& resultIns = resultMove.parent();
264
265 // cannot remove if has refs. TODO: move refs to next ins.
266 // if we don't have irm, assume we don't have irefs.
267 if (irm != NULL &&
268 (irm->hasReference(operand1Ins) || irm->hasReference(operand2Ins) ||
269 irm->hasReference(resultIns))) {
271 }
272
273 auto reverseJumpBBs = inverseGuardsOfHeads(ddg, oEdges);
274
275 // If cannot reverse jumps, have to undo and abort.
276 for ([[maybe_unused]] auto n: reverseJumpBBs) {
277 if (!cfgAllowsJumpReversal(operand1Ins, cfg)) {
278 inverseGuardsOfHeads(ddg, oEdges);
280 }
281 }
282
283 // need some copy from one predicate to another?
284 TTAProgram::Terminal& src1 = operand1.move().source();
285 TTAProgram::Terminal& dst = resultMove.destination();
286 if (!src1.equals(dst)) {
287 auto newMove = std::make_shared<TTAProgram::Move>(
288 src1.copy(), dst.copy(), operand1.move().bus());
289
291 newIns->addMove(newMove);
292 resultMove.parent().parent().insertAfter(
293 resultMove.parent(), newIns);
294 MoveNode* newMN = new MoveNode(newMove);
295 ddg.addNode(*newMN, operand1);
296 ddg.combineNodes(operand1, result, *newMN);
297
298 } else {
299 // the op just gets deleted.
300 ddg.copyDepsOver(operand1, result, true, true);
301 }
302
303 // delete the xor operation. (the moves and instructions.)
304 TTAProgram::CodeSnippet& parent = operand1Ins.parent();
305
306 assert(operand1Ins.moveCount() == 1);
307 ddg.deleteNode(operand1);
308 parent.remove(operand1Ins);
309 delete &operand1Ins;
310
311 assert(operand2Ins.moveCount() == 1);
312 ddg.deleteNode(operand2);
313 parent.remove(operand2Ins);
314 delete &operand2Ins;
315
316
317 assert(resultIns.moveCount() == 1);
318 ddg.deleteNode(result);
319 parent.remove(resultIns);
320 delete &resultIns;
321
322 return reverseJumpBBs;
323}
324
325
329
330 // loop through all outedges.
331 for (DataDependenceGraph::EdgeSet::iterator i = oEdges.begin();
332 i != oEdges.end(); i++) {
333 DataDependenceEdge& edge = **i;
334 bool dstOpIsSelect = false;
336 !edge.guardUse()) {
337 MoveNode& dstMN = ddg.headNode(edge);
338 if (!dstMN.isDestinationOperation()) {
339 return false;
340 }
341 ProgramOperation &dstOp = dstMN.destinationOperation();
342 if (dstOp.operation().name() != "SELECT") {
343 return false;
344 }
345 dstOpIsSelect = true;
346 }
347
348
349 // them checks that those guard usages cannot have some other
350 // movenode writing the guard, if some complex guard
351 // calculation where guard write itself is conditional
352 // or multiple guard sources in different BBs.
353 int gRawCount = 0;
354 MoveNode& head = ddg.headNode(edge);
355 DataDependenceGraph::EdgeSet iEdges = ddg.inEdges(head);
356 for (DataDependenceGraph::EdgeSet::iterator j = iEdges.begin();
357 j != iEdges.end(); j++) {
358 if ((**j).guardUse() &&
359 (**j).dependenceType() == DataDependenceEdge::DEP_RAW) {
360 gRawCount++;
361 if (gRawCount > 1) {
362 return false;
363 }
364 }
365
366 // Prevent select's condition to be reversed multiple times.
367 if ((**j).dependenceType() == DataDependenceEdge::DEP_RAW &&
368 dstOpIsSelect) {
369 gRawCount++;
370 if (gRawCount > 1) {
371 return false;
372 }
373 }
374 }
375 }
376 return true;
377}
378
383 ControlFlowGraph::NodeSet guardReverseBBs;
384 for (DataDependenceGraph::EdgeSet::iterator i = oEdges.begin();
385 i != oEdges.end(); i++) {
386 DataDependenceEdge& edge = **i;
388 continue;
389 }
390 MoveNode& head = ddg.headNode(edge);
391 if (edge.guardUse()) {
392 TTAProgram::Move& guardUseMove = head.move();
393 assert(!guardUseMove.isUnconditional());
394 guardUseMove.setGuard(
396 guardUseMove.guard()));
397 if (guardUseMove.isJump()) {
398 BasicBlockNode& jumpBBN = ddg.getBasicBlockNode(head);
399 guardReverseBBs.insert(&jumpBBN);
400 }
401 } else {
403 }
404 }
405 return guardReverseBBs;
406}
407
408/**
409 * Remove additions that can be removed staticly. LLVM leaves these when
410 * another ide of the addition is an address of a global variable.
411 */
414
415 if (po.operation().name() != "ADD" ) return;
416
417 MoveNode& result = po.outputMove(0);
418 if (po.inputMoveCount() != 2) {
419 return;
420 }
421 MoveNode& operand1 = po.inputMove(0);
422 MoveNode& operand2 = po.inputMove(1);
423 MoveNode* src1 = &operand1;
424 MoveNode* src2 = &operand2;
425
426 // allow hopping over regs
427 while (src1->isSourceVariable()) {
428 src1 = ddg.onlyRegisterRawSource(*src1,2);
429 if (src1 == nullptr) {
430 return;
431 }
432 }
433
434 // allow hopping over regs
435 while (src2->isSourceVariable()) {
436 src2 = ddg.onlyRegisterRawSource(*src2,2);
437 if (src2 == nullptr) {
438 return;
439 }
440 }
441 if (!src2->isSourceConstant() || !src1->isSourceConstant()) {
442 return;
443 }
444
445 auto& s1 = src1->move().source();
446 auto& s2 = src2->move().source();
447
448 if (s1.value().intValue() == 0 || s2.value().intValue() == 0) {
449 return;
450 }
451
452 // all tests ok, proceed and remove the add.
453 TTAProgram::Instruction& operand1Ins = operand1.move().parent();
454 TTAProgram::Instruction& operand2Ins = operand2.move().parent();
455 TTAProgram::CodeSnippet& parent = operand1Ins.parent();
456
457 int val = s1.value().intValue() + s2.value().intValue();
458 auto immTerm =
460
461 result.unsetSourceOperation();
462 po.removeOutputNode(result);
463
464 result.move().setSource(immTerm);
465
466 assert(operand1Ins.moveCount() == 1);
467 ddg.deleteNode(operand1);
468 parent.remove(operand1Ins);
469 delete &operand1Ins;
470
471 assert(operand2Ins.moveCount() == 1);
472 ddg.deleteNode(operand2);
473 parent.remove(operand2Ins);
474 delete &operand2Ins;
475}
476
477/**
478 * Handles a procedure.
479 *
480 * @param procedure the procedure.
481 * @param targetMachine targetmachine. Not used at all.
482 */
483void
485 TTAProgram::Procedure& procedure, const TTAMachine::Machine& mach) {
486 // If procedure has too many instructions, may run out of memory.
487 // so check the lowmem mode. in lowmem mode this optimiziation
488 // is disabled, so returns.
491 int lowMemThreshold = DEFAULT_LOWMEM_MODE_THRESHOLD;
492
493 if (opts != NULL && opts->lowMemModeThreshold() > -1) {
494 lowMemThreshold = opts->lowMemModeThreshold();
495 }
496
497 if (procedure.instructionCount() >=lowMemThreshold) {
498 return;
499 }
500
501 ControlFlowGraph cfg(procedure /*, ProcedurePass::interPassData()*/);
503
504 handleControlFlowGraph(cfg, mach);
505
506 // copy back to the program.
507 cfg.copyToProcedure(procedure);
508}
509
510void
512 ControlFlowGraph& cfg,
513 DataDependenceGraph& ddg) {
514
517 program == NULL ? NULL :
518 &program->instructionReferenceManager();
519
520 // Loop over all programoperations. find XOR's by 1.
521 for (int i = ddg.programOperationCount() - 1; i >= 0; i--) {
524 if (po.operation().name() == "XOR" ||
525 po.operation().name() == "XOR64") {
526 jumpNodes = tryToRemoveXor(ddg, po, irm, cfg);
527 }
528 if (po.operation().name() == "EQ") {
529 jumpNodes = tryToRemoveEq(ddg, po, irm, cfg);
530 }
531 for (auto bbn : jumpNodes) {
532 cfg.reverseGuardOnOutEdges(*bbn);
533 }
534 if (po.operation().readsMemory()) {
536 }
537
538 if (po.operation().name() == "ADD") {
540 }
541 }
542 // todo: remove also programoprations.
543}
544
545void
547 ControlFlowGraph& cfg, const TTAMachine::Machine& mach) {
549 // only RAW register edges and operation edges. no mem edges,
550 // no anti-edges.
551 DataDependenceGraph* ddg = ddgBuilder.build(
552 cfg, DataDependenceGraph::NO_ANTIDEPS, mach, NULL, false);
553
554 handleCFGDDG(cfg, *ddg);
555
556 delete ddg;
557}
558
559/** Check that we can revert the out edges of the cfg when reverting
560 * a jump guard */
561bool
564 TTAProgram::CodeSnippet* parent = &ins.parent();
565 for (int j = 0; j < cfg.nodeCount(); j++) {
566 BasicBlockNode& bbn = cfg.node(j);
567 if (&bbn.basicBlock() == parent) {
568 for (int i = 0; i < cfg.outDegree(bbn); i++) {
569 ControlFlowEdge& e = cfg.outEdge(bbn,i);
570 if (!e.isTrueEdge() && !e.isFalseEdge()) {
571 return false;
572 }
573 }
574 }
575 }
576 return true;
577}
#define assert(condition)
static const int DEFAULT_LOWMEM_MODE_THRESHOLD
find Finds info of the inner loops in the program
static const int DEFAULT_LOWMEM_MODE_THRESHOLD
static CmdLineOptions * cmdLineOptions()
TTAProgram::BasicBlock & basicBlock()
virtual Node & headNode(const Edge &edge) const
int nodeCount() const
virtual Edge & outEdge(const Node &node, const int index) const
Node & node(const int index) const
virtual int outDegree(const Node &node) const
virtual EdgeSet outEdges(const Node &node) const
virtual Node & tailNode(const Edge &edge) const
virtual EdgeSet inEdges(const Node &node) const
bool isFalseEdge() const
bool isTrueEdge() const
void copyToProcedure(TTAProgram::Procedure &proc, TTAProgram::InstructionReferenceManager *irm=NULL)
TTAProgram::Program * program() const
void reverseGuardOnOutEdges(const BasicBlockNode &bbn)
DependenceType dependenceType() const
EdgeReason edgeReason() const
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)
ProgramOperation & programOperation(int index)
void deleteNode(MoveNode &node)
void addNode(MoveNode &moveNode)
const BasicBlockNode & getBasicBlockNode(const MoveNode &mn) const
MoveNode * onlyRegisterRawSource(const MoveNode &mn, int allowGuardEdges=2, int backEdges=0) const
EdgeSet copyDepsOver(MoveNode &node, bool anti, bool raw)
void renamedSimpleLiveRange(MoveNode &src, MoveNode &dest, MoveNode &antidepPoint, DataDependenceEdge &lrEdge, const TCEString &oldReg, const TCEString &newReg)
void combineNodes(MoveNode &node1, MoveNode &node2, MoveNode &destination)
static TCEString registerName(const TTAMachine::RegisterFile &rf, int index, char delim='.')
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
std::set< GraphEdge *, typename GraphEdge::Comparator > EdgeSet
Definition Graph.hh:54
int nodeID() const
void unsetSourceOperation()
Definition MoveNode.cc:760
bool isSourceVariable() const
Definition MoveNode.cc:196
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
bool isDestinationOperation() const
TTAProgram::Move & move()
bool isSourceOperation() const
Definition MoveNode.cc:168
bool isSourceConstant() const
Definition MoveNode.cc:238
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual OperandType type() const
Definition Operand.cc:165
virtual bool readsMemory() const
Definition Operation.cc:242
virtual TCEString name() const
Definition Operation.cc:93
virtual Operand & operand(int id) const
Definition Operation.cc:541
ControlFlowGraph::NodeSet tryToRemoveGuardInversingOp(DataDependenceGraph &ddg, ProgramOperation &po, TTAProgram::InstructionReferenceManager *irm, ControlFlowGraph &cfg)
void tryToPrecalcConstantAdd(DataDependenceGraph &ddg, ProgramOperation &po)
bool checkGuardReversalAllowed(DataDependenceGraph &ddg, DataDependenceGraph::EdgeSet &oEdges)
PreOptimizer(InterPassData &data)
void handleControlFlowGraph(ControlFlowGraph &cfg, const TTAMachine::Machine &targetMachine)
ControlFlowGraph::NodeSet tryToRemoveEq(DataDependenceGraph &ddg, ProgramOperation &po, TTAProgram::InstructionReferenceManager *irm, ControlFlowGraph &cfg)
ControlFlowGraph::NodeSet inverseGuardsOfHeads(DataDependenceGraph &ddg, DataDependenceGraph::EdgeSet &oEdges)
ControlFlowGraph::NodeSet tryToRemoveXor(DataDependenceGraph &ddg, ProgramOperation &po, TTAProgram::InstructionReferenceManager *irm, ControlFlowGraph &cfg)
void handleProcedure(TTAProgram::Procedure &procedure, const TTAMachine::Machine &targetMachine)
void handleProgram(TTAProgram::Program &program, const TTAMachine::Machine &targetMachine)
bool tryToOptimizeAddressReg(DataDependenceGraph &ddg, ProgramOperation &po)
bool cfgAllowsJumpReversal(TTAProgram::Instruction &ins, ControlFlowGraph &cfg)
void handleCFGDDG(ControlFlowGraph &cfg, DataDependenceGraph &ddg)
int outputMoveCount() const
const Operation & operation() const
int inputMoveCount() const
MoveNode & inputMove(int index) const
void switchInputs(int idx1=1, int idx2=2)
void removeOutputNode(MoveNode &node, int outputIndex)
MoveNode & outputMove(int index) const
static void executeProcedurePass(TTAProgram::Program &program, const TTAMachine::Machine &targetMachine, ProcedurePass &procedurePass)
virtual int lowMemModeThreshold() const
InterPassData & interPassData()
int intValue() const
Definition SimValue.cc:895
virtual int width() const
virtual TCEString name() const
static TTAProgram::MoveGuard * createInverseGuard(const TTAProgram::MoveGuard &mg, const TTAMachine::Bus *bus=NULL)
virtual void insertAfter(const Instruction &pos, Instruction *ins)
virtual int instructionCount() const
virtual void remove(Instruction &ins)
void addMove(std::shared_ptr< Move > move)
CodeSnippet & parent() const
void setSource(Terminal *src)
Definition Move.cc:312
MoveGuard & guard() const
Definition Move.cc:345
bool isUnconditional() const
Definition Move.cc:154
Instruction & parent() const
Definition Move.cc:115
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
void setDestination(Terminal *dst)
Definition Move.cc:333
const TTAMachine::Bus & bus() const
Definition Move.cc:373
virtual SimValue value() const
Definition Terminal.cc:178
virtual bool equals(const Terminal &other) const =0
virtual Terminal * copy() const =0
virtual bool isGPR() const
Definition Terminal.cc:107
virtual int operationIndex() const
Definition Terminal.cc:364
virtual bool isImmediate() const
Definition Terminal.cc:63
virtual const TTAMachine::RegisterFile & registerFile() const
Definition Terminal.cc:225