OpenASIP 2.2
Loading...
Searching...
No Matches
MemoryAliasAnalyzer.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2009 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 MemoryAliasAnalyzer.cc
26 *
27 * Implementation of Memory Alias Analyzer interface
28 *
29 * @author Heikki Kultala 2009 (heikki.kultala-no.spam-tut.fi)
30 * @author Heikki Kultala 2010 (heikki.kultala-no.spam-tut.fi)
31 * @note rating: red
32 */
33
35#include "MoveNode.hh"
36#include "ProgramOperation.hh"
37#include "TCEString.hh"
38#include "Operand.hh"
39#include "OperationDAG.hh"
40#include "OperationNode.hh"
41#include "TerminalNode.hh"
42#include "MoveNodeSet.hh"
43#include "Operation.hh"
44#include "Move.hh"
45#include "Terminal.hh"
47
48/**
49 * Compares two indeces (memory addresses or part of memory address).
50 * Checks memory operand size and return unknown for partial alias.
51 *
52 * This methods takes care of checking memory access size and handling
53 * partial aliasing (returning unknown for those)
54 *
55 * @param index1 first index to compare
56 * @param index2 second index to compare
57 * @param mn1 first node
58 * @param mn2 second node
59 * @return true if alias, false if not alias, unknown for partial alias.
60 */
63 int index1, int index2, const ProgramOperation& pop1,
64 const ProgramOperation& pop2) {
65 const Operation& op1 = pop1.operation();
66 const Operation& op2 = pop2.operation();
67
68 int maus1 = mausOfOperation(op1);
69 int maus2 = mausOfOperation(op2);
70
71 // unknown op? don't know how much memory it touches.
72 if (maus1 == 0 || maus2 == 0) {
73 return ALIAS_UNKNOWN;
74 }
75
76 // if addresses are the same.
77 if (index1 == index2) {
78 // partial?
79 if (maus1 != maus2) {
80 return ALIAS_UNKNOWN;
81 } else {
82 return ALIAS_TRUE;
83 }
84 }
85
86 int maus = std::max(maus1, maus2);
87
88 // partial alias or not?
89 if ((index1 & (~(maus-1))) == (index2 & (~(maus-1)))) {
90 return ALIAS_UNKNOWN;
91 } else {
92 return ALIAS_FALSE;
93 }
94}
95/**
96 * Returns the size of memory operation memory access in mau's.
97 * if unknown, returns 0.
98 */
99unsigned int
101
102 // no mem address if does not use memory
103 if (!op.usesMemory()) {
104 throw InvalidData(__FILE__,__LINE__,__func__, "does not use mem!");
105 }
106
107 // loops thru all inputs, checks if it is address.
108 // the index for op.input() starts from 0
109 for (int i = 0; i < op.numberOfInputs(); i++) {
110 Operand& operand = op.input(i);
111 if (operand.isAddress()) {
112 return operand.memoryUnits();
113 }
114 }
115
116 // TODO: assumes only operation of dag uses memory.
117 // like base + offset stores/loads.
118 for (int i = 0; i < op.dagCount(); i++) {
119 OperationDAG& oDag = op.dag(i);
120 OperationDAG::NodeSet tailNodes = oDag.endNodes();
121 for (OperationDAG::NodeSet::iterator j = tailNodes.begin();
122 j != tailNodes.end(); j++) {
123 OperationDAGNode* n = *j;
124 OperationNode* on = dynamic_cast<OperationNode*>(n);
125 if (on != NULL) {
126 Operation& tailOp = on->referencedOperation();
127 if (tailOp.usesMemory()) {
128 return mausOfOperation(tailOp);
129 }
130 }
131 }
132 }
133 // unknown or no specified
134 return 0;
135}
136
137/**
138 * Gets the direct address-writing move of a ProgramOperation which is a memory
139 * operation.
140 *
141 * If none found, return null
142 *
143 * @param po programOperation whose address write move is being searched.
144 * @return MoveNode which writes address to a mem operation or NULL.
145 */
146const MoveNode*
148 const ProgramOperation& po) {
149 const Operation& op = po.operation();
150
151 // no mem address if does not use memory
152 if (!op.usesMemory()) {
153 return NULL;
154 }
155
156 // loops thru all inputs, checks if it is an address.
157 // the index for op.input() starts from 0
158 for (int i = 0, inputCount = op.numberOfInputs() ; i < inputCount; i++) {
159 Operand& operand = op.input(i);
160 if (operand.isAddress()) {
161 // the index for po.inpuNode starts from 0 , so add +1
162 MoveNodeSet& mns = po.inputNode(i+1);
163 if (mns.count() != 1) {
164 return NULL;
165 } else {
166 return &mns.at(0);
167 }
168 }
169 }
170 return NULL;
171}
172
173
176 const ProgramOperation& po) {
177
179 // std::set<int> operandIndeces;
180
181 const Operation& op = po.operation();
182 // TODO: assumes only one operation of dag uses memory.
183 // like base + offset stores/loads.
184 for (int i = 0; i < op.dagCount(); i++) {
185 OperationDAG& oDag = op.dag(i);
186 OperationDAG::NodeSet tailNodes = oDag.endNodes();
187 for (OperationDAG::NodeSet::iterator j = tailNodes.begin();
188 j != tailNodes.end(); j++) {
189 OperationDAGNode* n = *j;
190 OperationNode* on = dynamic_cast<OperationNode*>(n);
191 if (on == NULL) {
192 continue;
193 }
194 Operation& tailOp = on->referencedOperation();
195 if (!tailOp.usesMemory()) {
196 continue;
197 }
198 int addrOperandNum = 0;
199 for (int k = 0, inputCount = tailOp.numberOfInputs() ;
200 k < inputCount; k++) {
201 Operand& operand = tailOp.input(k);
202 if (operand.isAddress()) {
203 addrOperandNum = k+1;
204 }
205 }
206 if (addrOperandNum == 0) {
207 continue;
208 }
209
210 // now we know the address operand of the mem op in dag.
211
212 OperationDAGNode* addressSource = NULL;
213 for (int k = 0; k < oDag.inDegree(*n); k++) {
214 OperationDAGEdge& e = oDag.inEdge(*n,k);
215 if (e.dstOperand() == addrOperandNum) {
216 addressSource = &oDag.tailNode(e);
217 }
218 }
219 if (addressSource == NULL) {
220 continue;
221 }
222
223 OperationNode* addrSrcOn = dynamic_cast<OperationNode*>(
224 addressSource);
225 if (addrSrcOn == NULL) {
226 continue;
227 }
228 Operation& addrOp = addrSrcOn->referencedOperation();
229 if (addrOp.name() == "add" ||
230 addrOp.name() == "ADD") {
231 result.offsetOperation =
233 } else {
234 if (addrOp.name() == "sub" ||
235 addrOp.name() == "SUB") {
236 result.offsetOperation =
238 } else {
239 result.offsetOperation =
241 continue;
242 }
243 }
244 OperationDAG::NodeSet addrInputs = oDag.predecessors(
245 *addressSource);
246
247 if (addrInputs.size() != 2) {
248 result.clear();
249 continue;
250 }
251 for (OperationDAG::NodeSet::iterator k = addrInputs.begin();
252 k != addrInputs.end(); k++) {
253 TerminalNode* tn = dynamic_cast<TerminalNode*>(*k);
254 if (tn == NULL) {
255 break;
256 }
257 if (result.operand1 == 0) {
258 result.operand1 = tn->operandIndex();
259 } else {
260 result.operand2 = tn->operandIndex();
261 }
262 }
263 if (result.operand2 != 0) {
264 return result;
265 } else {
266 result.clear();
267 }
268 }
269 }
270 return result;
271}
272
273const MoveNode* MemoryAliasAnalyzer::findIncrement(const MoveNode& mn, long& increment) {
274 int myInc = 0;
275 if (!mn.isSourceOperation()) {
276 return NULL;
277 }
278
280 bool isSub = po.operation().name() == "SUB";
281 bool isAdd = po.operation().name() == "ADD";
282 if (!isSub && !isAdd) {
283 return NULL;
284 }
285
286 // is add or sub
287 MoveNodeSet& input1Set = po.inputNode(1);
288 MoveNodeSet& input2Set = po.inputNode(2);
289 if (input1Set.count() != 1 || input2Set.count() != 1) {
290 return NULL;
291 }
292 MoveNode& input1 = input1Set.at(0);
293 MoveNode& input2 = input2Set.at(0);
294 MoveNode *immMove = NULL;
295 MoveNode* varMove = NULL;
296 if (input1.move().source().isGPR() &&
297 input2.move().source().isImmediate()) {
298 immMove = &input2;
299 varMove = &input1;
300 } else if (input2.move().source().isGPR() &&
301 input1.move().source().isImmediate()) {
302 // no sub by variable
303 if (isSub) {
304 return NULL;
305 }
306 immMove = &input1;
307 varMove = &input2;
308 } else { // not yet supported.
309 return NULL;
310 }
311
312 myInc = immMove->move().source().value().intValue();
313 if (isSub) {
314 increment -= myInc;
315 } else {
316 increment += myInc;
317 }
318 return varMove;
319}
320
322 DataDependenceGraph& ddg, const MoveNode &mn, long& loopIncrement) {
323
325 if (po.operation().name() != "ADD") return NULL;
326
327 MoveNodeSet& input1Set = po.inputNode(1);
328 MoveNodeSet& input2Set = po.inputNode(2);
329 if (input1Set.count() != 1 || input2Set.count() != 1) {
330 return NULL;
331 }
332 const MoveNode& input1 = input1Set.at(0);
333 const MoveNode& input2 = input2Set.at(0);
334
335 if (!input1.isSourceVariable() || !input2.isSourceVariable()) {
336 return NULL;
337 }
338
339 const MoveNode* prevSrc2 = ddg.onlyRegisterRawSource(input2,2,2);
340 const MoveNode* loopSrc2 = ddg.onlyRegisterRawSource(input2,2,1);
341 if (prevSrc2 == NULL) {
342 return NULL;
343 }
344
345 int loopMul = 1;
346 if (!loopSrc2) {
347 int shiftAmount;
348 const MoveNode* loopIndex;
349 if (( loopIndex = detectConstantScale(*prevSrc2, shiftAmount))) {
350 prevSrc2 = ddg.onlyRegisterRawSource(*loopIndex,2,2);
351 if (prevSrc2 == NULL) {
352 return NULL;
353 }
354 loopMul <<= shiftAmount;
355 if (!(loopSrc2 = ddg.onlyRegisterRawSource(*loopIndex,2,1))) {
356 return NULL;
357 }
358 } else {
359 return NULL;
360 }
361 }
362
363 while (prevSrc2->isSourceVariable()) {
364 prevSrc2 = ddg.onlyRegisterRawSource(*prevSrc2);
365 if (prevSrc2 == NULL) {
366 return NULL;
367 }
368 }
369
370 // TODO: track over multiple copies
371 if (!prevSrc2->isSourceConstant()) {
372 return NULL;
373 }
374 int counterInit = prevSrc2->move().source().value().intValue();
375 if (counterInit != 0) {
376 return NULL;
377 }
378
379 long increment = 0;
380 const MoveNode* baseOfInc = findIncrement(*loopSrc2, increment);
381 if (!baseOfInc) {
382 return NULL;
383 }
384 loopIncrement = increment * loopMul;
385 // TODO: should check that the loop update really goes over the loop
386 return &input1;
387}
388
389const MoveNode* MemoryAliasAnalyzer::detectConstantScale(const MoveNode& mn, int &shiftAmount) {
390 if (!mn.isSourceOperation()) {
391 return NULL;
392 }
394 if (po.operation().name() != "SHL") {
395 return NULL;
396 }
397 MoveNodeSet& input1Set = po.inputNode(1);
398 MoveNodeSet& input2Set = po.inputNode(2);
399 if (input1Set.count() != 1 || input2Set.count() != 1) {
400 return NULL;
401 }
402 const MoveNode& input1 = input1Set.at(0);
403 const MoveNode& input2 = input2Set.at(0);
404 if (!input1.isSourceVariable() ||
405 !input2.isSourceConstant()) {
406 return NULL;
407 }
408 shiftAmount = input2.move().source().value().intValue();
409 return &input1;
410}
#define __func__
virtual Edge & inEdge(const Node &node, const int index) const
virtual int inDegree(const Node &node) const
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
virtual Node & tailNode(const Edge &edge) const
MoveNode * onlyRegisterRawSource(const MoveNode &mn, int allowGuardEdges=2, int backEdges=0) const
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
static const MoveNode * findIncrement(const MoveNode &mn, long &increment)
AliasingResult compareIndeces(int index1, int index2, const ProgramOperation &pop1, const ProgramOperation &pop2)
static const MoveNode * searchLoopIndexBasedIncrement(DataDependenceGraph &ddg, const MoveNode &mn, long &loopIncrement)
static const MoveNode * detectConstantScale(const MoveNode &mn, int &shiftAmount)
static const MoveNode * addressOperandMove(const ProgramOperation &po)
static TwoPartAddressOperandDetection findTwoPartAddressOperands(const ProgramOperation &po)
unsigned int mausOfOperation(const Operation &op)
int count() const
MoveNode & at(int index)
bool isSourceVariable() const
Definition MoveNode.cc:196
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
TTAProgram::Move & move()
bool isSourceOperation() const
Definition MoveNode.cc:168
bool isSourceConstant() const
Definition MoveNode.cc:238
virtual bool isAddress() const
Definition Operand.cc:328
virtual int memoryUnits() const
Definition Operand.cc:341
const OperationDAG::NodeSet & endNodes() const
Operation & referencedOperation() const
virtual OperationDAG & dag(int index) const
Definition Operation.cc:148
virtual TCEString name() const
Definition Operation.cc:93
virtual bool usesMemory() const
Definition Operation.cc:232
virtual Operand & input(int index) const
Definition Operation.cc:503
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual int dagCount() const
Definition Operation.cc:134
const Operation & operation() const
MoveNodeSet & inputNode(int in) const
int intValue() const
Definition SimValue.cc:895
Terminal & source() const
Definition Move.cc:302
virtual SimValue value() const
Definition Terminal.cc:178
virtual bool isGPR() const
Definition Terminal.cc:107
virtual bool isImmediate() const
Definition Terminal.cc:63
virtual int operandIndex() const