OLD | NEW |
(Empty) | |
| 1 //===- ExpandGetElementPtr.cpp - Expand GetElementPtr into arithmetic------===// |
| 2 // |
| 3 // The LLVM Compiler Infrastructure |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // This pass expands out GetElementPtr instructions into ptrtoint, |
| 11 // inttoptr and arithmetic instructions. |
| 12 // |
| 13 // This simplifies the language so that the PNaCl translator does not |
| 14 // need to handle GetElementPtr and struct types as part of a stable |
| 15 // wire format for PNaCl. |
| 16 // |
| 17 // Note that we drop the "inbounds" attribute of GetElementPtr. |
| 18 // |
| 19 //===----------------------------------------------------------------------===// |
| 20 |
| 21 #include "llvm/IR/BasicBlock.h" |
| 22 #include "llvm/IR/Constants.h" |
| 23 #include "llvm/IR/DataLayout.h" |
| 24 #include "llvm/IR/Function.h" |
| 25 #include "llvm/IR/InstrTypes.h" |
| 26 #include "llvm/IR/Instructions.h" |
| 27 #include "llvm/IR/Module.h" |
| 28 #include "llvm/IR/Type.h" |
| 29 #include "llvm/Pass.h" |
| 30 #include "llvm/Transforms/NaCl.h" |
| 31 |
| 32 using namespace llvm; |
| 33 |
| 34 namespace { |
| 35 class ExpandGetElementPtr : public BasicBlockPass { |
| 36 public: |
| 37 static char ID; // Pass identification, replacement for typeid |
| 38 ExpandGetElementPtr() : BasicBlockPass(ID) { |
| 39 initializeExpandGetElementPtrPass(*PassRegistry::getPassRegistry()); |
| 40 } |
| 41 |
| 42 virtual bool runOnBasicBlock(BasicBlock &BB); |
| 43 }; |
| 44 } |
| 45 |
| 46 char ExpandGetElementPtr::ID = 0; |
| 47 INITIALIZE_PASS(ExpandGetElementPtr, "expand-getelementptr", |
| 48 "Expand out GetElementPtr instructions into arithmetic", |
| 49 false, false) |
| 50 |
| 51 static Value *CastToPtrSize(Value *Val, Instruction *InsertPt, |
| 52 const DebugLoc &Debug, Type *PtrType) { |
| 53 unsigned ValSize = Val->getType()->getIntegerBitWidth(); |
| 54 unsigned PtrSize = PtrType->getIntegerBitWidth(); |
| 55 if (ValSize == PtrSize) |
| 56 return Val; |
| 57 Instruction *Inst; |
| 58 if (ValSize > PtrSize) { |
| 59 Inst = new TruncInst(Val, PtrType, "gep_trunc", InsertPt); |
| 60 } else { |
| 61 // GEP indexes must be sign-extended. |
| 62 Inst = new SExtInst(Val, PtrType, "gep_sext", InsertPt); |
| 63 } |
| 64 Inst->setDebugLoc(Debug); |
| 65 return Inst; |
| 66 } |
| 67 |
| 68 static void FlushOffset(Instruction **Ptr, uint64_t *CurrentOffset, |
| 69 Instruction *InsertPt, const DebugLoc &Debug, |
| 70 Type *PtrType) { |
| 71 if (*CurrentOffset) { |
| 72 *Ptr = BinaryOperator::Create(Instruction::Add, *Ptr, |
| 73 ConstantInt::get(PtrType, *CurrentOffset), |
| 74 "gep", InsertPt); |
| 75 (*Ptr)->setDebugLoc(Debug); |
| 76 *CurrentOffset = 0; |
| 77 } |
| 78 } |
| 79 |
| 80 static void ExpandGEP(GetElementPtrInst *GEP, DataLayout *DL, Type *PtrType) { |
| 81 const DebugLoc &Debug = GEP->getDebugLoc(); |
| 82 Instruction *Ptr = new PtrToIntInst(GEP->getPointerOperand(), PtrType, |
| 83 "gep_int", GEP); |
| 84 Ptr->setDebugLoc(Debug); |
| 85 |
| 86 Type *CurrentTy = GEP->getPointerOperand()->getType(); |
| 87 // We do some limited constant folding ourselves. An alternative |
| 88 // would be to generate verbose, unfolded output (e.g. multiple |
| 89 // adds; adds of zero constants) and use a later pass such as |
| 90 // "-instcombine" to clean that up. However, "-instcombine" can |
| 91 // reintroduce GetElementPtr instructions. |
| 92 uint64_t CurrentOffset = 0; |
| 93 |
| 94 for (GetElementPtrInst::op_iterator Op = GEP->op_begin() + 1; |
| 95 Op != GEP->op_end(); |
| 96 ++Op) { |
| 97 Value *Index = *Op; |
| 98 if (StructType *StTy = dyn_cast<StructType>(CurrentTy)) { |
| 99 uint64_t Field = cast<ConstantInt>(Op)->getZExtValue(); |
| 100 CurrentTy = StTy->getElementType(Field); |
| 101 CurrentOffset += DL->getStructLayout(StTy)->getElementOffset(Field); |
| 102 } else { |
| 103 CurrentTy = cast<SequentialType>(CurrentTy)->getElementType(); |
| 104 uint64_t ElementSize = DL->getTypeAllocSize(CurrentTy); |
| 105 if (ConstantInt *C = dyn_cast<ConstantInt>(Index)) { |
| 106 CurrentOffset += C->getSExtValue() * ElementSize; |
| 107 } else { |
| 108 FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType); |
| 109 Index = CastToPtrSize(Index, GEP, Debug, PtrType); |
| 110 if (ElementSize != 1) { |
| 111 Index = CopyDebug( |
| 112 BinaryOperator::Create(Instruction::Mul, Index, |
| 113 ConstantInt::get(PtrType, ElementSize), |
| 114 "gep_array", GEP), |
| 115 GEP); |
| 116 } |
| 117 Ptr = BinaryOperator::Create(Instruction::Add, Ptr, |
| 118 Index, "gep", GEP); |
| 119 Ptr->setDebugLoc(Debug); |
| 120 } |
| 121 } |
| 122 } |
| 123 FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType); |
| 124 |
| 125 assert(CurrentTy == GEP->getType()->getElementType()); |
| 126 Instruction *Result = new IntToPtrInst(Ptr, GEP->getType(), "", GEP); |
| 127 Result->setDebugLoc(Debug); |
| 128 Result->takeName(GEP); |
| 129 GEP->replaceAllUsesWith(Result); |
| 130 GEP->eraseFromParent(); |
| 131 } |
| 132 |
| 133 bool ExpandGetElementPtr::runOnBasicBlock(BasicBlock &BB) { |
| 134 bool Modified = false; |
| 135 DataLayout DL(BB.getParent()->getParent()); |
| 136 Type *PtrType = DL.getIntPtrType(BB.getContext()); |
| 137 |
| 138 for (BasicBlock::InstListType::iterator Iter = BB.begin(); |
| 139 Iter != BB.end(); ) { |
| 140 Instruction *Inst = Iter++; |
| 141 if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) { |
| 142 Modified = true; |
| 143 ExpandGEP(GEP, &DL, PtrType); |
| 144 } |
| 145 } |
| 146 return Modified; |
| 147 } |
| 148 |
| 149 BasicBlockPass *llvm::createExpandGetElementPtrPass() { |
| 150 return new ExpandGetElementPtr(); |
| 151 } |
OLD | NEW |