aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/InstrSelection/InstrForest.cpp
blob: 20cbe8d71bfa7ba086aedcdc32b0deee27f88797 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
// $Id$
//---------------------------------------------------------------------------
// File:
//	InstrForest.cpp
// 
// Purpose:
//	Convert SSA graph to instruction trees for instruction selection.
// 
// Strategy:
//  The key goal is to group instructions into a single
//  tree if one or more of them might be potentially combined into a single
//  complex instruction in the target machine.
//  Since this grouping is completely machine-independent, we do it as
//  aggressive as possible to exploit any possible taret instructions.
//  In particular, we group two instructions O and I if:
//      (1) Instruction O computes an operand used by instruction I,
//  and (2) O and I are part of the same basic block,
//  and (3) O has only a single use, viz., I.
// 
// History:
//	6/28/01	 -  Vikram Adve  -  Created
// 
//---------------------------------------------------------------------------

#include "llvm/CodeGen/InstrForest.h"
#include "llvm/Method.h"
#include "llvm/iTerminators.h"
#include "llvm/iMemory.h"
#include "llvm/iPHINode.h"
#include "llvm/ConstantVals.h"
#include "llvm/BasicBlock.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "Support/STLExtras.h"
#include <iostream>
using std::cerr;
using std::vector;

//------------------------------------------------------------------------ 
// class InstrTreeNode
//------------------------------------------------------------------------ 

void
InstrTreeNode::dump(int dumpChildren, int indent) const
{
  dumpNode(indent);
  
  if (dumpChildren)
    {
      if (LeftChild)
	LeftChild->dump(dumpChildren, indent+1);
      if (RightChild)
	RightChild->dump(dumpChildren, indent+1);
    }
}


InstructionNode::InstructionNode(Instruction* I)
  : InstrTreeNode(NTInstructionNode, I)
{
  opLabel = I->getOpcode();

  // Distinguish special cases of some instructions such as Ret and Br
  // 
  if (opLabel == Instruction::Ret && cast<ReturnInst>(I)->getReturnValue())
    {
      opLabel = RetValueOp;              	 // ret(value) operation
    }
  else if (opLabel ==Instruction::Br && !cast<BranchInst>(I)->isUnconditional())
    {
      opLabel = BrCondOp;		// br(cond) operation
    }
  else if (opLabel >= Instruction::SetEQ && opLabel <= Instruction::SetGT)
    {
      opLabel = SetCCOp;		// common label for all SetCC ops
    }
  else if (opLabel == Instruction::Alloca && I->getNumOperands() > 0)
    {
      opLabel = AllocaN;		 // Alloca(ptr, N) operation
    }
  else if ((opLabel == Instruction::Load ||
	    opLabel == Instruction::GetElementPtr) &&
	   cast<MemAccessInst>(I)->hasIndices())
    {
      opLabel = opLabel + 100;		 // load/getElem with index vector
    }
  else if (opLabel == Instruction::And ||
           opLabel == Instruction::Or ||
           opLabel == Instruction::Xor ||
           opLabel == Instruction::Not)
    {
      // Distinguish bitwise operators from logical operators!
      if (I->getType() != Type::BoolTy)
        opLabel = opLabel + 100;	 // bitwise operator
    }
  else if (opLabel == Instruction::Cast)
    {
      const Type *ITy = I->getType();
      switch(ITy->getPrimitiveID())
	{
	case Type::BoolTyID:    opLabel = ToBoolTy;    break;
	case Type::UByteTyID:   opLabel = ToUByteTy;   break;
	case Type::SByteTyID:   opLabel = ToSByteTy;   break;
	case Type::UShortTyID:  opLabel = ToUShortTy;  break;
	case Type::ShortTyID:   opLabel = ToShortTy;   break;
	case Type::UIntTyID:    opLabel = ToUIntTy;    break;
	case Type::IntTyID:     opLabel = ToIntTy;     break;
	case Type::ULongTyID:   opLabel = ToULongTy;   break;
	case Type::LongTyID:    opLabel = ToLongTy;    break;
	case Type::FloatTyID:   opLabel = ToFloatTy;   break;
	case Type::DoubleTyID:  opLabel = ToDoubleTy;  break;
	case Type::ArrayTyID:   opLabel = ToArrayTy;   break;
	case Type::PointerTyID: opLabel = ToPointerTy; break;
	default:
	  // Just use `Cast' opcode otherwise. It's probably ignored.
	  break;
	}
    }
}


void
InstructionNode::dumpNode(int indent) const
{
  for (int i=0; i < indent; i++)
    cerr << "    ";
  
  cerr << getInstruction()->getOpcodeName();
  
  const vector<MachineInstr*> &mvec = getInstruction()->getMachineInstrVec();
  if (mvec.size() > 0)
    cerr << "\tMachine Instructions:  ";
  for (unsigned int i=0; i < mvec.size(); i++)
    {
      mvec[i]->dump(0);
      if (i < mvec.size() - 1)
	cerr << ";  ";
    }
  
  cerr << "\n";
}


void
VRegListNode::dumpNode(int indent) const
{
  for (int i=0; i < indent; i++)
    cerr << "    ";
  
  cerr << "List" << "\n";
}


void
VRegNode::dumpNode(int indent) const
{
  for (int i=0; i < indent; i++)
    cerr << "    ";
  
  cerr << "VReg " << getValue() << "\t(type "
       << (int) getValue()->getValueType() << ")" << "\n";
}

void
ConstantNode::dumpNode(int indent) const
{
  for (int i=0; i < indent; i++)
    cerr << "    ";
  
  cerr << "Constant " << getValue() << "\t(type "
       << (int) getValue()->getValueType() << ")" << "\n";
}

void
LabelNode::dumpNode(int indent) const
{
  for (int i=0; i < indent; i++)
    cerr << "    ";
  
  cerr << "Label " << getValue() << "\n";
}

//------------------------------------------------------------------------
// class InstrForest
// 
// A forest of instruction trees, usually for a single method.
//------------------------------------------------------------------------ 

InstrForest::InstrForest(Method *M)
{
  for (Method::inst_iterator I = M->inst_begin(); I != M->inst_end(); ++I)
    this->buildTreeForInstruction(*I);
}

InstrForest::~InstrForest()
{
  for (std::hash_map<const Instruction*,InstructionNode*>::iterator I = begin();
       I != end(); ++I)
      delete (*I).second;
}

void
InstrForest::dump() const
{
  for (std::hash_set<InstructionNode*>::const_iterator I = treeRoots.begin();
       I != treeRoots.end(); ++I)
    (*I)->dump(/*dumpChildren*/ 1, /*indent*/ 0);
}

inline void
InstrForest::noteTreeNodeForInstr(Instruction *instr,
				  InstructionNode *treeNode)
{
  assert(treeNode->getNodeType() == InstrTreeNode::NTInstructionNode);
  (*this)[instr] = treeNode;
  treeRoots.insert(treeNode);		// mark node as root of a new tree
}


inline void
InstrForest::setLeftChild(InstrTreeNode *Par, InstrTreeNode *Chld)
{
  Par->LeftChild = Chld;
  Chld->Parent = Par;
  if (Chld->getNodeType() == InstrTreeNode::NTInstructionNode)
    treeRoots.erase((InstructionNode*)Chld); // no longer a tree root
}

inline void
InstrForest::setRightChild(InstrTreeNode *Par, InstrTreeNode *Chld)
{
  Par->RightChild = Chld;
  Chld->Parent = Par;
  if (Chld->getNodeType() == InstrTreeNode::NTInstructionNode)
    treeRoots.erase((InstructionNode*)Chld); // no longer a tree root
}


InstructionNode*
InstrForest::buildTreeForInstruction(Instruction *instr)
{
  InstructionNode *treeNode = getTreeNodeForInstr(instr);
  if (treeNode)
    {
      // treeNode has already been constructed for this instruction
      assert(treeNode->getInstruction() == instr);
      return treeNode;
    }
  
  // Otherwise, create a new tree node for this instruction.
  // 
  treeNode = new InstructionNode(instr);
  noteTreeNodeForInstr(instr, treeNode);
  
  if (instr->getOpcode() == Instruction::Call)
    { // Operands of call instruction
      return treeNode;
    }
  
  // If the instruction has more than 2 instruction operands,
  // then we need to create artificial list nodes to hold them.
  // (Note that we only count operands that get tree nodes, and not
  // others such as branch labels for a branch or switch instruction.)
  //
  // To do this efficiently, we'll walk all operands, build treeNodes
  // for all appropriate operands and save them in an array.  We then
  // insert children at the end, creating list nodes where needed.
  // As a performance optimization, allocate a child array only
  // if a fixed array is too small.
  // 
  int numChildren = 0;
  const unsigned int MAX_CHILD = 8;
  static InstrTreeNode *fixedChildArray[MAX_CHILD];
  InstrTreeNode **childArray =
    (instr->getNumOperands() > MAX_CHILD)
    ? new (InstrTreeNode*)[instr->getNumOperands()] : fixedChildArray;
  
  //
  // Walk the operands of the instruction
  // 
  for (Instruction::op_iterator O = instr->op_begin(); O!=instr->op_end(); ++O)
    {
      Value* operand = *O;
      
      // Check if the operand is a data value, not an branch label, type,
      // method or module.  If the operand is an address type (i.e., label
      // or method) that is used in an non-branching operation, e.g., `add'.
      // that should be considered a data value.
    
      // Check latter condition here just to simplify the next IF.
      bool includeAddressOperand =
	(isa<BasicBlock>(operand) || isa<Method>(operand))
	&& !instr->isTerminator();
    
      if (includeAddressOperand || isa<Instruction>(operand) ||
	  isa<Constant>(operand) || isa<MethodArgument>(operand) ||
	  isa<GlobalVariable>(operand))
	{
	  // This operand is a data value
	
	  // An instruction that computes the incoming value is added as a
	  // child of the current instruction if:
	  //   the value has only a single use
	  //   AND both instructions are in the same basic block.
	  //   AND the current instruction is not a PHI (because the incoming
	  //		value is conceptually in a predecessor block,
	  //		even though it may be in the same static block)
	  // 
	  // (Note that if the value has only a single use (viz., `instr'),
	  //  the def of the value can be safely moved just before instr
	  //  and therefore it is safe to combine these two instructions.)
	  // 
	  // In all other cases, the virtual register holding the value
	  // is used directly, i.e., made a child of the instruction node.
	  // 
	  InstrTreeNode* opTreeNode;
	  if (isa<Instruction>(operand) && operand->use_size() == 1 &&
	      cast<Instruction>(operand)->getParent() == instr->getParent() &&
	      !isa<PHINode>(instr) &&
	      instr->getOpcode() != Instruction::Call)
	    {
	      // Recursively create a treeNode for it.
	      opTreeNode = buildTreeForInstruction((Instruction*)operand);
	    }
	  else if (Constant *CPV = dyn_cast<Constant>(operand))
	    {
	      // Create a leaf node for a constant
	      opTreeNode = new ConstantNode(CPV);
	    }
	  else
	    {
	      // Create a leaf node for the virtual register
	      opTreeNode = new VRegNode(operand);
	    }

	  childArray[numChildren++] = opTreeNode;
	}
    }
  
  //-------------------------------------------------------------------- 
  // Add any selected operands as children in the tree.
  // Certain instructions can have more than 2 in some instances (viz.,
  // a CALL or a memory access -- LOAD, STORE, and GetElemPtr -- to an
  // array or struct). Make the operands of every such instruction into
  // a right-leaning binary tree with the operand nodes at the leaves
  // and VRegList nodes as internal nodes.
  //-------------------------------------------------------------------- 
  
  InstrTreeNode *parent = treeNode;
  
  if (numChildren > 2)
    {
      unsigned instrOpcode = treeNode->getInstruction()->getOpcode();
      assert(instrOpcode == Instruction::PHINode ||
	     instrOpcode == Instruction::Call ||
	     instrOpcode == Instruction::Load ||
	     instrOpcode == Instruction::Store ||
	     instrOpcode == Instruction::GetElementPtr);
    }
  
  // Insert the first child as a direct child
  if (numChildren >= 1)
    setLeftChild(parent, childArray[0]);

  int n;
  
  // Create a list node for children 2 .. N-1, if any
  for (n = numChildren-1; n >= 2; n--)
    {
      // We have more than two children
      InstrTreeNode *listNode = new VRegListNode();
      setRightChild(parent, listNode);
      setLeftChild(listNode, childArray[numChildren - n]);
      parent = listNode;
    }
  
  // Now insert the last remaining child (if any).
  if (numChildren >= 2)
    {
      assert(n == 1);
      setRightChild(parent, childArray[numChildren - 1]);
    }
  
  if (childArray != fixedChildArray)
    delete [] childArray; 
  
  return treeNode;
}