Index: lib/Transforms/NaCl/ExpandGetElementPtr.cpp |
diff --git a/lib/Transforms/NaCl/ExpandGetElementPtr.cpp b/lib/Transforms/NaCl/ExpandGetElementPtr.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0718b6e429b997b6097a1e17b616781d1a912b39 |
--- /dev/null |
+++ b/lib/Transforms/NaCl/ExpandGetElementPtr.cpp |
@@ -0,0 +1,151 @@ |
+//===- ExpandGetElementPtr.cpp - Expand GetElementPtr into arithmetic------===// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// This pass expands out GetElementPtr instructions into ptrtoint, |
+// inttoptr and arithmetic instructions. |
+// |
+// This simplifies the language so that the PNaCl translator does not |
+// need to handle GetElementPtr and struct types as part of a stable |
+// wire format for PNaCl. |
+// |
+// Note that we drop the "inbounds" attribute of GetElementPtr. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "llvm/IR/BasicBlock.h" |
+#include "llvm/IR/Constants.h" |
+#include "llvm/IR/DataLayout.h" |
+#include "llvm/IR/Function.h" |
+#include "llvm/IR/InstrTypes.h" |
+#include "llvm/IR/Instructions.h" |
+#include "llvm/IR/Module.h" |
+#include "llvm/IR/Type.h" |
+#include "llvm/Pass.h" |
+#include "llvm/Transforms/NaCl.h" |
+ |
+using namespace llvm; |
+ |
+namespace { |
+ class ExpandGetElementPtr : public BasicBlockPass { |
+ public: |
+ static char ID; // Pass identification, replacement for typeid |
+ ExpandGetElementPtr() : BasicBlockPass(ID) { |
+ initializeExpandGetElementPtrPass(*PassRegistry::getPassRegistry()); |
+ } |
+ |
+ virtual bool runOnBasicBlock(BasicBlock &BB); |
+ }; |
+} |
+ |
+char ExpandGetElementPtr::ID = 0; |
+INITIALIZE_PASS(ExpandGetElementPtr, "expand-getelementptr", |
+ "Expand out GetElementPtr instructions into arithmetic", |
+ false, false) |
+ |
+static Value *CastToPtrSize(Value *Val, Instruction *InsertPt, |
+ const DebugLoc &Debug, Type *PtrType) { |
+ unsigned ValSize = Val->getType()->getIntegerBitWidth(); |
+ unsigned PtrSize = PtrType->getIntegerBitWidth(); |
+ if (ValSize == PtrSize) |
+ return Val; |
+ Instruction *Inst; |
+ if (ValSize > PtrSize) { |
+ Inst = new TruncInst(Val, PtrType, "gep_trunc", InsertPt); |
+ } else { |
+ // GEP indexes must be sign-extended. |
+ Inst = new SExtInst(Val, PtrType, "gep_sext", InsertPt); |
+ } |
+ Inst->setDebugLoc(Debug); |
+ return Inst; |
+} |
+ |
+static void FlushOffset(Instruction **Ptr, uint64_t *CurrentOffset, |
+ Instruction *InsertPt, const DebugLoc &Debug, |
+ Type *PtrType) { |
+ if (*CurrentOffset) { |
+ *Ptr = BinaryOperator::Create(Instruction::Add, *Ptr, |
+ ConstantInt::get(PtrType, *CurrentOffset), |
+ "gep", InsertPt); |
+ (*Ptr)->setDebugLoc(Debug); |
+ *CurrentOffset = 0; |
+ } |
+} |
+ |
+static void ExpandGEP(GetElementPtrInst *GEP, DataLayout *DL, Type *PtrType) { |
+ const DebugLoc &Debug = GEP->getDebugLoc(); |
+ Instruction *Ptr = new PtrToIntInst(GEP->getPointerOperand(), PtrType, |
+ "gep_int", GEP); |
+ Ptr->setDebugLoc(Debug); |
+ |
+ Type *CurrentTy = GEP->getPointerOperand()->getType(); |
+ // We do some limited constant folding ourselves. An alternative |
+ // would be to generate verbose, unfolded output (e.g. multiple |
+ // adds; adds of zero constants) and use a later pass such as |
+ // "-instcombine" to clean that up. However, "-instcombine" can |
+ // reintroduce GetElementPtr instructions. |
+ uint64_t CurrentOffset = 0; |
+ |
+ for (GetElementPtrInst::op_iterator Op = GEP->op_begin() + 1; |
+ Op != GEP->op_end(); |
+ ++Op) { |
+ Value *Index = *Op; |
+ if (StructType *StTy = dyn_cast<StructType>(CurrentTy)) { |
+ uint64_t Field = cast<ConstantInt>(Op)->getZExtValue(); |
+ CurrentTy = StTy->getElementType(Field); |
+ CurrentOffset += DL->getStructLayout(StTy)->getElementOffset(Field); |
+ } else { |
+ CurrentTy = cast<SequentialType>(CurrentTy)->getElementType(); |
+ uint64_t ElementSize = DL->getTypeAllocSize(CurrentTy); |
+ if (ConstantInt *C = dyn_cast<ConstantInt>(Index)) { |
+ CurrentOffset += C->getSExtValue() * ElementSize; |
+ } else { |
+ FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType); |
+ Index = CastToPtrSize(Index, GEP, Debug, PtrType); |
+ if (ElementSize != 1) { |
+ Index = CopyDebug( |
+ BinaryOperator::Create(Instruction::Mul, Index, |
+ ConstantInt::get(PtrType, ElementSize), |
+ "gep_array", GEP), |
+ GEP); |
+ } |
+ Ptr = BinaryOperator::Create(Instruction::Add, Ptr, |
+ Index, "gep", GEP); |
+ Ptr->setDebugLoc(Debug); |
+ } |
+ } |
+ } |
+ FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType); |
+ |
+ assert(CurrentTy == GEP->getType()->getElementType()); |
+ Instruction *Result = new IntToPtrInst(Ptr, GEP->getType(), "", GEP); |
+ Result->setDebugLoc(Debug); |
+ Result->takeName(GEP); |
+ GEP->replaceAllUsesWith(Result); |
+ GEP->eraseFromParent(); |
+} |
+ |
+bool ExpandGetElementPtr::runOnBasicBlock(BasicBlock &BB) { |
+ bool Modified = false; |
+ DataLayout DL(BB.getParent()->getParent()); |
+ Type *PtrType = DL.getIntPtrType(BB.getContext()); |
+ |
+ for (BasicBlock::InstListType::iterator Iter = BB.begin(); |
+ Iter != BB.end(); ) { |
+ Instruction *Inst = Iter++; |
+ if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) { |
+ Modified = true; |
+ ExpandGEP(GEP, &DL, PtrType); |
+ } |
+ } |
+ return Modified; |
+} |
+ |
+BasicBlockPass *llvm::createExpandGetElementPtrPass() { |
+ return new ExpandGetElementPtr(); |
+} |