Add cannonicalization of shl X, 1 -> add X, X
[oota-llvm.git] / lib / Transforms / Scalar / DecomposeMultiDimRefs.cpp
1 //===- llvm/Transforms/DecomposeMultiDimRefs.cpp - Lower array refs to 1D -===//
2 //
3 // DecomposeMultiDimRefs - Convert multi-dimensional references consisting of
4 // any combination of 2 or more array and structure indices into a sequence of
5 // instructions (using getelementpr and cast) so that each instruction has at
6 // most one index (except structure references, which need an extra leading
7 // index of [0]).
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "llvm/Transforms/Scalar.h"
12 #include "llvm/DerivedTypes.h"
13 #include "llvm/Constants.h"
14 #include "llvm/Constant.h"
15 #include "llvm/iMemory.h"
16 #include "llvm/iOther.h"
17 #include "llvm/BasicBlock.h"
18 #include "llvm/Pass.h"
19 #include "Support/StatisticReporter.h"
20
21 namespace {
22   Statistic<> NumAdded("lowerrefs\t\t- # of getelementptr instructions added");
23
24   class DecomposePass : public BasicBlockPass {
25     static bool decomposeArrayRef(GetElementPtrInst &GEP);
26   public:
27     virtual bool runOnBasicBlock(BasicBlock &BB);
28   };
29
30   RegisterOpt<DecomposePass> X("lowerrefs", "Decompose multi-dimensional "
31                                "structure/array references");
32 }
33
34 Pass
35 *createDecomposeMultiDimRefsPass()
36 {
37   return new DecomposePass();
38 }
39
40
41 // runOnBasicBlock - Entry point for array or structure references with multiple
42 // indices.
43 //
44 bool
45 DecomposePass::runOnBasicBlock(BasicBlock &BB)
46 {
47   bool Changed = false;
48   for (BasicBlock::iterator II = BB.begin(); II != BB.end(); ) {
49     Instruction *I = II;
50     ++II;
51     if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(I))
52       if (GEP->getNumIndices() >= 2)
53         Changed |= decomposeArrayRef(*GEP); // always modifies II
54   }
55   return Changed;
56 }
57
58 // For any GetElementPtrInst with 2 or more array and structure indices:
59 // 
60 //      opCode CompositeType* P, [uint|ubyte] idx1, ..., [uint|ubyte] idxN
61 // 
62 // this function generates the foll sequence:
63 // 
64 //      ptr1   = getElementPtr P,         idx1
65 //      ptr2   = getElementPtr ptr1,   0, idx2
66 //      ...
67 //      ptrN-1 = getElementPtr ptrN-2, 0, idxN-1
68 //      opCode                 ptrN-1, 0, idxN  // New-MAI
69 // 
70 // Then it replaces the original instruction with this sequence,
71 // and replaces all uses of the original instruction with New-MAI.
72 // If idx1 is 0, we simply omit the first getElementPtr instruction.
73 // 
74 // On return: BBI points to the instruction after the current one
75 //            (whether or not *BBI was replaced).
76 // 
77 // Return value: true if the instruction was replaced; false otherwise.
78 // 
79 bool
80 DecomposePass::decomposeArrayRef(GetElementPtrInst &GEP)
81 {
82   BasicBlock *BB = GEP.getParent();
83   Value *LastPtr = GEP.getPointerOperand();
84   Instruction *InsertPoint = GEP.getNext(); // Insert before the next insn
85
86   // Process each index except the last one.
87   User::const_op_iterator OI = GEP.idx_begin(), OE = GEP.idx_end();
88   for (; OI+1 != OE; ++OI) {
89     std::vector<Value*> Indices;
90     
91     // If this is the first index and is 0, skip it and move on!
92     if (OI == GEP.idx_begin()) {
93       if (*OI == ConstantInt::getNullValue((*OI)->getType()))
94         continue;
95     } else {
96       // Not the first index: include initial [0] to deref the last ptr
97       Indices.push_back(Constant::getNullValue(Type::UIntTy));
98     }
99
100     Indices.push_back(*OI);
101
102     // New Instruction: nextPtr1 = GetElementPtr LastPtr, Indices
103     LastPtr = new GetElementPtrInst(LastPtr, Indices, "ptr1", InsertPoint);
104     ++NumAdded;
105   }
106
107   // Now create a new instruction to replace the original one
108   //
109   const PointerType *PtrTy = cast<PointerType>(LastPtr->getType());
110
111   // Get the final index vector, including an initial [0] as before.
112   std::vector<Value*> Indices;
113   Indices.push_back(Constant::getNullValue(Type::UIntTy));
114   Indices.push_back(*OI);
115
116   Value *NewVal = new GetElementPtrInst(LastPtr, Indices, GEP.getName(),
117                                         InsertPoint);
118
119   // Replace all uses of the old instruction with the new
120   GEP.replaceAllUsesWith(NewVal);
121
122   // Now remove and delete the old instruction...
123   BB->getInstList().erase(&GEP);
124   return true;
125 }