OpenASIP  2.0
Classes | Public Types | Public Member Functions | Protected Member Functions | Static Protected Member Functions | Private Member Functions | List of all members
MemoryAliasAnalyzer Class Referenceabstract

#include <MemoryAliasAnalyzer.hh>

Inheritance diagram for MemoryAliasAnalyzer:
Inheritance graph
Collaboration diagram for MemoryAliasAnalyzer:
Collaboration graph

Classes

struct  TwoPartAddressOperandDetection
 

Public Types

enum  AliasingResult { ALIAS_FALSE = 0, ALIAS_TRUE = 1, ALIAS_UNKNOWN = 2, ALIAS_PARTIAL = 3 }
 

Public Member Functions

virtual void initProcedure (TTAProgram::Procedure &)
 
virtual AliasingResult analyze (DataDependenceGraph &ddg, const ProgramOperation &pop1, const ProgramOperation &pop2, MoveNodeUse::BBRelation bbInfo)=0
 
virtual bool isAddressTraceable (DataDependenceGraph &ddg, const ProgramOperation &pop)=0
 
virtual ~MemoryAliasAnalyzer ()
 

Protected Member Functions

AliasingResult compareIndeces (int index1, int index2, const ProgramOperation &pop1, const ProgramOperation &pop2)
 

Static Protected Member Functions

static const MoveNodeaddressOperandMove (const ProgramOperation &po)
 
static TwoPartAddressOperandDetection findTwoPartAddressOperands (const ProgramOperation &po)
 
static const MoveNodesearchLoopIndexBasedIncrement (DataDependenceGraph &ddg, const MoveNode &mn, long &loopIncrement)
 
static const MoveNodefindIncrement (const MoveNode &mn, long &increment)
 
static const MoveNodedetectConstantScale (const MoveNode &mn, int &shiftAmount)
 

Private Member Functions

unsigned int mausOfOperation (const Operation &op)
 

Detailed Description

Definition at line 47 of file MemoryAliasAnalyzer.hh.

Member Enumeration Documentation

◆ AliasingResult

Enumerator
ALIAS_FALSE 
ALIAS_TRUE 
ALIAS_UNKNOWN 
ALIAS_PARTIAL 

Definition at line 50 of file MemoryAliasAnalyzer.hh.

50  { ALIAS_FALSE = 0,
51  // Only Use ALIAS_TRUE if they really fully alias.
52  // It's used for transitivity optimizations.
53  ALIAS_TRUE = 1,
54  ALIAS_UNKNOWN = 2,
55  ALIAS_PARTIAL = 3};

Constructor & Destructor Documentation

◆ ~MemoryAliasAnalyzer()

virtual MemoryAliasAnalyzer::~MemoryAliasAnalyzer ( )
inlinevirtual

Definition at line 75 of file MemoryAliasAnalyzer.hh.

75 {}

Member Function Documentation

◆ addressOperandMove()

const MoveNode * MemoryAliasAnalyzer::addressOperandMove ( const ProgramOperation po)
staticprotected

Gets the direct address-writing move of a ProgramOperation which is a memory operation.

If none found, return null

Parameters
poprogramOperation whose address write move is being searched.
Returns
MoveNode which writes address to a mem operation or NULL.

Definition at line 147 of file MemoryAliasAnalyzer.cc.

148  {
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 }

References MoveNodeSet::at(), MoveNodeSet::count(), Operation::input(), ProgramOperation::inputNode(), Operand::isAddress(), Operation::numberOfInputs(), ProgramOperation::operation(), and Operation::usesMemory().

Here is the call graph for this function:

◆ analyze()

virtual AliasingResult MemoryAliasAnalyzer::analyze ( DataDependenceGraph ddg,
const ProgramOperation pop1,
const ProgramOperation pop2,
MoveNodeUse::BBRelation  bbInfo 
)
pure virtual

◆ compareIndeces()

MemoryAliasAnalyzer::AliasingResult MemoryAliasAnalyzer::compareIndeces ( int  index1,
int  index2,
const ProgramOperation pop1,
const ProgramOperation pop2 
)
protected

Compares two indeces (memory addresses or part of memory address). Checks memory operand size and return unknown for partial alias.

This methods takes care of checking memory access size and handling partial aliasing (returning unknown for those)

Parameters
index1first index to compare
index2second index to compare
mn1first node
mn2second node
Returns
true if alias, false if not alias, unknown for partial alias.

Definition at line 62 of file MemoryAliasAnalyzer.cc.

64  {
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 }

References ALIAS_FALSE, ALIAS_TRUE, ALIAS_UNKNOWN, mausOfOperation(), and ProgramOperation::operation().

Here is the call graph for this function:

◆ detectConstantScale()

const MoveNode * MemoryAliasAnalyzer::detectConstantScale ( const MoveNode mn,
int &  shiftAmount 
)
staticprotected

Definition at line 389 of file MemoryAliasAnalyzer.cc.

389  {
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 }

References MoveNodeSet::at(), MoveNodeSet::count(), ProgramOperation::inputNode(), SimValue::intValue(), MoveNode::isSourceConstant(), MoveNode::isSourceOperation(), MoveNode::isSourceVariable(), MoveNode::move(), Operation::name(), ProgramOperation::operation(), TTAProgram::Move::source(), MoveNode::sourceOperation(), and TTAProgram::Terminal::value().

Referenced by searchLoopIndexBasedIncrement().

Here is the call graph for this function:

◆ findIncrement()

const MoveNode * MemoryAliasAnalyzer::findIncrement ( const MoveNode mn,
long &  increment 
)
staticprotected

Definition at line 273 of file MemoryAliasAnalyzer.cc.

273  {
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 }

References MoveNodeSet::at(), MoveNodeSet::count(), ProgramOperation::inputNode(), SimValue::intValue(), TTAProgram::Terminal::isGPR(), TTAProgram::Terminal::isImmediate(), MoveNode::isSourceOperation(), MoveNode::move(), Operation::name(), ProgramOperation::operation(), TTAProgram::Move::source(), MoveNode::sourceOperation(), and TTAProgram::Terminal::value().

Referenced by OffsetAliasAnalyzer::analyzeLoopPtrIncrease(), and searchLoopIndexBasedIncrement().

Here is the call graph for this function:

◆ findTwoPartAddressOperands()

MemoryAliasAnalyzer::TwoPartAddressOperandDetection MemoryAliasAnalyzer::findTwoPartAddressOperands ( const ProgramOperation po)
staticprotected

Definition at line 175 of file MemoryAliasAnalyzer.cc.

176  {
177 
178  TwoPartAddressOperandDetection result;
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 }

References MemoryAliasAnalyzer::TwoPartAddressOperandDetection::ADD, MemoryAliasAnalyzer::TwoPartAddressOperandDetection::clear(), Operation::dag(), Operation::dagCount(), OperationDAGEdge::dstOperand(), OperationDAG::endNodes(), BoostGraph< GraphNode, GraphEdge >::inDegree(), BoostGraph< GraphNode, GraphEdge >::inEdge(), Operation::input(), Operand::isAddress(), Operation::name(), MemoryAliasAnalyzer::TwoPartAddressOperandDetection::NOT_FOUND, Operation::numberOfInputs(), MemoryAliasAnalyzer::TwoPartAddressOperandDetection::offsetOperation, MemoryAliasAnalyzer::TwoPartAddressOperandDetection::operand1, MemoryAliasAnalyzer::TwoPartAddressOperandDetection::operand2, TerminalNode::operandIndex(), ProgramOperation::operation(), BoostGraph< GraphNode, GraphEdge >::predecessors(), OperationNode::referencedOperation(), MemoryAliasAnalyzer::TwoPartAddressOperandDetection::SUB, BoostGraph< GraphNode, GraphEdge >::tailNode(), and Operation::usesMemory().

Here is the call graph for this function:

◆ initProcedure()

virtual void MemoryAliasAnalyzer::initProcedure ( TTAProgram::Procedure )
inlinevirtual

Definition at line 57 of file MemoryAliasAnalyzer.hh.

57 {}

◆ isAddressTraceable()

virtual bool MemoryAliasAnalyzer::isAddressTraceable ( DataDependenceGraph ddg,
const ProgramOperation pop 
)
pure virtual

Checks whether the analyzer knows anything about the address.

ie. if it can return true or false to some query concerning this address.

Returns
true if analyzer can know something about the address.

Implemented in FalseAliasAnalyzer, LLVMAliasAnalyzer, OffsetAliasAnalyzer, StackAliasAnalyzer, ConstantAliasAnalyzer, PRegionAliasAnalyzer, and GlobalVsStackAA.

◆ mausOfOperation()

unsigned int MemoryAliasAnalyzer::mausOfOperation ( const Operation op)
private

Returns the size of memory operation memory access in mau's. if unknown, returns 0.

Definition at line 100 of file MemoryAliasAnalyzer.cc.

100  {
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 }

References __func__, Operation::dag(), Operation::dagCount(), OperationDAG::endNodes(), Operation::input(), Operand::isAddress(), Operand::memoryUnits(), Operation::numberOfInputs(), OperationNode::referencedOperation(), and Operation::usesMemory().

Referenced by compareIndeces().

Here is the call graph for this function:

◆ searchLoopIndexBasedIncrement()

const MoveNode * MemoryAliasAnalyzer::searchLoopIndexBasedIncrement ( DataDependenceGraph ddg,
const MoveNode mn,
long &  loopIncrement 
)
staticprotected

Definition at line 321 of file MemoryAliasAnalyzer.cc.

322  {
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 }

References MoveNodeSet::at(), MoveNodeSet::count(), detectConstantScale(), findIncrement(), ProgramOperation::inputNode(), SimValue::intValue(), MoveNode::isSourceConstant(), MoveNode::isSourceVariable(), MoveNode::move(), Operation::name(), DataDependenceGraph::onlyRegisterRawSource(), ProgramOperation::operation(), TTAProgram::Move::source(), MoveNode::sourceOperation(), and TTAProgram::Terminal::value().

Here is the call graph for this function:

The documentation for this class was generated from the following files:
Operand
Definition: Operand.hh:52
OperationDAGEdge::dstOperand
int dstOperand() const
Definition: OperationDAGEdge.cc:54
ProgramOperation::operation
const Operation & operation() const
Definition: ProgramOperation.cc:590
SimValue::intValue
int intValue() const
Definition: SimValue.cc:895
BoostGraph::predecessors
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
MemoryAliasAnalyzer::ALIAS_UNKNOWN
@ ALIAS_UNKNOWN
Definition: MemoryAliasAnalyzer.hh:54
BoostGraph::tailNode
virtual Node & tailNode(const Edge &edge) const
MemoryAliasAnalyzer::mausOfOperation
unsigned int mausOfOperation(const Operation &op)
Definition: MemoryAliasAnalyzer.cc:100
MemoryAliasAnalyzer::ALIAS_FALSE
@ ALIAS_FALSE
Definition: MemoryAliasAnalyzer.hh:50
MemoryAliasAnalyzer::TwoPartAddressOperandDetection::NOT_FOUND
@ NOT_FOUND
Definition: MemoryAliasAnalyzer.hh:85
BoostGraph< OperationDAGNode, OperationDAGEdge >::NodeSet
std::set< OperationDAGNode *, typename OperationDAGNode ::Comparator > NodeSet
Definition: BoostGraph.hh:86
MemoryAliasAnalyzer::ALIAS_PARTIAL
@ ALIAS_PARTIAL
Definition: MemoryAliasAnalyzer.hh:55
TerminalNode
Definition: TerminalNode.hh:47
Operation::numberOfInputs
virtual int numberOfInputs() const
Definition: Operation.cc:192
ProgramOperation
Definition: ProgramOperation.hh:70
MoveNode
Definition: MoveNode.hh:65
MoveNode::isSourceConstant
bool isSourceConstant() const
Definition: MoveNode.cc:238
OperationNode::referencedOperation
Operation & referencedOperation() const
Definition: OperationNode.cc:70
OperationNode
Definition: OperationNode.hh:47
Operation::name
virtual TCEString name() const
Definition: Operation.cc:93
OperationDAGEdge
Definition: OperationDAGEdge.hh:38
DataDependenceGraph::onlyRegisterRawSource
MoveNode * onlyRegisterRawSource(const MoveNode &mn, int allowGuardEdges=2, int backEdges=0) const
Definition: DataDependenceGraph.cc:4083
MemoryAliasAnalyzer::detectConstantScale
static const MoveNode * detectConstantScale(const MoveNode &mn, int &shiftAmount)
Definition: MemoryAliasAnalyzer.cc:389
OperationDAG::endNodes
const OperationDAG::NodeSet & endNodes() const
Definition: OperationDAG.cc:137
MoveNode::sourceOperation
ProgramOperation & sourceOperation() const
Definition: MoveNode.cc:453
MemoryAliasAnalyzer::ALIAS_TRUE
@ ALIAS_TRUE
Definition: MemoryAliasAnalyzer.hh:53
InvalidData
Definition: Exception.hh:149
OperationDAGNode
Definition: OperationDAGNode.hh:45
MoveNodeSet::at
MoveNode & at(int index)
BoostGraph::inEdge
virtual Edge & inEdge(const Node &node, const int index) const
OperationDAG
Definition: OperationDAG.hh:43
__func__
#define __func__
Definition: Application.hh:67
TTAProgram::Terminal::isGPR
virtual bool isGPR() const
Definition: Terminal.cc:107
MoveNode::isSourceOperation
bool isSourceOperation() const
Definition: MoveNode.cc:168
TTAProgram::Terminal::value
virtual SimValue value() const
Definition: Terminal.cc:178
BoostGraph::inDegree
virtual int inDegree(const Node &node) const
MoveNodeSet
Definition: MoveNodeSet.hh:41
Operation
Definition: Operation.hh:59
MoveNodeSet::count
int count() const
Operation::input
virtual Operand & input(int index) const
Definition: Operation.cc:503
MoveNode::isSourceVariable
bool isSourceVariable() const
Definition: MoveNode.cc:196
Operation::usesMemory
virtual bool usesMemory() const
Definition: Operation.cc:232
MoveNode::move
TTAProgram::Move & move()
Operation::dagCount
virtual int dagCount() const
Definition: Operation.cc:134
MemoryAliasAnalyzer::findIncrement
static const MoveNode * findIncrement(const MoveNode &mn, long &increment)
Definition: MemoryAliasAnalyzer.cc:273
MemoryAliasAnalyzer::TwoPartAddressOperandDetection::SUB
@ SUB
Definition: MemoryAliasAnalyzer.hh:85
ProgramOperation::inputNode
MoveNodeSet & inputNode(int in) const
Definition: ProgramOperation.cc:513
Operand::memoryUnits
virtual int memoryUnits() const
Definition: Operand.cc:341
MemoryAliasAnalyzer::TwoPartAddressOperandDetection::ADD
@ ADD
Definition: MemoryAliasAnalyzer.hh:85
TTAProgram::Move::source
Terminal & source() const
Definition: Move.cc:302
Operand::isAddress
virtual bool isAddress() const
Definition: Operand.cc:328
TTAProgram::Terminal::isImmediate
virtual bool isImmediate() const
Definition: Terminal.cc:63
Operation::dag
virtual OperationDAG & dag(int index) const
Definition: Operation.cc:148
TerminalNode::operandIndex
virtual int operandIndex() const
Definition: TerminalNode.cc:60