Chromium Code Reviews| Index: lib/Transforms/NaCl/ReplacePtrsWithInts.cpp |
| diff --git a/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp b/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f6fd38e67b3ed8b01fad9e00b150aa7e07f8640b |
| --- /dev/null |
| +++ b/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp |
| @@ -0,0 +1,538 @@ |
| +//===- ReplacePtrsWithInts.cpp - Convert pointer values to integer values--===// |
| +// |
| +// The LLVM Compiler Infrastructure |
| +// |
| +// This file is distributed under the University of Illinois Open Source |
| +// License. See LICENSE.TXT for details. |
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// This pass strips out aggregate pointer types and replaces them with |
| +// the integer type iPTR, which is i32 for PNaCl (though this pass |
| +// will allow iPTR to be i64 if the DataLayout specifies 64-bit |
| +// pointers). |
| +// |
| +// The pass converts IR to the following normal form: |
| +// |
| +// All inttoptr and ptrtoint instructions use the same integer size |
| +// (iPTR), so they do not implicitly truncate or zero-extend. |
| +// |
| +// alloca always allocates an i8 array type. |
| +// |
| +// Pointer types only appear in the following instructions: |
| +// * loads and stores: the pointer operand is a NormalizedPtr. |
| +// * function calls: the function operand is a NormalizedPtr. |
| +// * intrinsic calls: any pointer arguments are NormalizedPtrs. |
| +// * alloca |
| +// * bitcast and inttoptr: only used as part of a NormalizedPtr. |
| +// * ptrtoint: the operand is an InherentPtr. |
| +// |
| +// Where an InherentPtr is defined as a pointer value that is: |
| +// * an alloca; |
| +// * a GlobalValue (a function or global variable); or |
| +// * an intrinsic call. |
| +// |
| +// And a NormalizedPtr is defined as a pointer value that is: |
| +// * an inttoptr instruction; |
| +// * an InherentPtr; or |
| +// * a bitcast of an InherentPtr. |
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +#include "llvm/ADT/DenseMap.h" |
| +#include "llvm/IR/DataLayout.h" |
| +#include "llvm/IR/DerivedTypes.h" |
| +#include "llvm/IR/Function.h" |
| +#include "llvm/IR/Instructions.h" |
| +#include "llvm/IR/IntrinsicInst.h" |
| +#include "llvm/IR/Module.h" |
| +#include "llvm/IR/Type.h" |
| +#include "llvm/Pass.h" |
| +#include "llvm/Support/raw_ostream.h" |
| +#include "llvm/Transforms/NaCl.h" |
| + |
| +using namespace llvm; |
| + |
| +namespace { |
| + // This is a ModulePass because the pass must recreate functions in |
| + // order to change their argument and return types. |
| + struct ReplacePtrsWithInts : public ModulePass { |
| + static char ID; // Pass identification, replacement for typeid |
| + ReplacePtrsWithInts() : ModulePass(ID) { |
| + initializeReplacePtrsWithIntsPass(*PassRegistry::getPassRegistry()); |
| + } |
| + |
| + virtual bool runOnModule(Module &M); |
| + }; |
| + |
| + typedef DenseMap<Function *, Function *> FunctionMap; |
| + |
| + class FunctionConverter { |
|
eliben
2013/05/15 22:11:21
Comment explaining what this class does, and what
Mark Seaborn
2013/05/16 02:08:40
Comments added.
|
| + Type *IntPtrType; |
| + FunctionMap *FuncMap; |
| + |
| + struct RewrittenVal { |
| + RewrittenVal(): IsPlaceholder(true), NewIntVal(NULL) {} |
| + bool IsPlaceholder; |
| + Value *NewIntVal; |
| + }; |
| + DenseMap<Value *, RewrittenVal> RewriteMap; |
| + int PlaceholderCount; |
| + SmallVector<Instruction *, 20> ToErase; |
| + |
| + public: |
| + FunctionConverter(Type *IntPtrType, FunctionMap *FuncMap) |
| + : IntPtrType(IntPtrType), FuncMap(FuncMap), PlaceholderCount(0) {} |
| + |
| + Type *ConvertType(Type *Ty); |
|
eliben
2013/05/15 22:11:21
According to the LLVM convention (http://llvm.org/
Mark Seaborn
2013/05/16 02:08:40
Oops, yes. Fixed the methods.
|
| + FunctionType *ConvertFuncType(FunctionType *FTy); |
| + |
| + void RecordConverted(Value *From, Value *To); |
| + void RecordConvertedAndErase(Instruction *From, Value *To); |
| + Value *Convert(Value *Val); |
| + Value *ConvertBackToPtr(Value *Val, Instruction *InsertPt); |
| + Value *ConvertFunctionPtr(Value *Callee, Instruction *InsertPt); |
| + void ConvertInPlace(Instruction *Inst); |
| + void Finish(); |
| + }; |
| +} |
| + |
| +static Instruction *CopyDebug(Instruction *NewInst, Instruction *Original) { |
|
eliben
2013/05/15 22:11:21
Hmm, this is being used in ExpandVarArgs too, so m
Mark Seaborn
2013/05/16 02:08:40
OK, done.
|
| + NewInst->setDebugLoc(Original->getDebugLoc()); |
| + return NewInst; |
| +} |
| + |
| +Type *FunctionConverter::ConvertType(Type *Ty) { |
| + if (Ty->isPointerTy()) |
| + return IntPtrType; |
| + return Ty; |
| +} |
| + |
| +FunctionType *FunctionConverter::ConvertFuncType(FunctionType *FTy) { |
| + SmallVector<Type *, 8> ArgTypes; |
| + for (FunctionType::param_iterator ArgTy = FTy->param_begin(), |
| + E = FTy->param_end(); ArgTy != E; ++ArgTy) { |
| + ArgTypes.push_back(ConvertType(*ArgTy)); |
| + } |
| + return FunctionType::get(ConvertType(FTy->getReturnType()), ArgTypes, |
| + FTy->isVarArg()); |
| +} |
| + |
| +void FunctionConverter::RecordConverted(Value *From, Value *To) { |
| + if (!From->getType()->isPointerTy()) { |
| + From->replaceAllUsesWith(To); |
| + return; |
| + } |
| + RewrittenVal *RV = &RewriteMap[From]; |
| + if (RV->NewIntVal) { |
| + assert(RV->IsPlaceholder); |
| + // Resolve placeholder. |
| + RV->NewIntVal->replaceAllUsesWith(To); |
| + delete RV->NewIntVal; |
| + RV->IsPlaceholder = false; |
| + --PlaceholderCount; |
| + } |
| + RV->NewIntVal = To; |
| +} |
| + |
| +void FunctionConverter::RecordConvertedAndErase(Instruction *From, Value *To) { |
| + RecordConverted(From, To); |
| + // There may still be references to this value, so defer deleting it. |
| + ToErase.push_back(From); |
| +} |
| + |
| +Value *FunctionConverter::Convert(Value *Val) { |
| + if (!Val->getType()->isPointerTy()) |
| + return Val; |
| + if (Constant *C = dyn_cast<Constant>(Val)) { |
| + if (Function *Func = dyn_cast<Function>(Val)) { |
| + assert(FuncMap->count(Func) == 1); |
| + C = (*FuncMap)[Func]; |
| + } |
| + return ConstantExpr::getPtrToInt(C, IntPtrType); |
| + } |
| + RewrittenVal *RV = &RewriteMap[Val]; |
| + if (!RV->NewIntVal) { |
| + // No converted value available yet, so create a placeholder. |
| + Argument *Placeholder = new Argument(ConvertType(Val->getType())); |
| + RV->NewIntVal = Placeholder; |
| + ++PlaceholderCount; |
| + } |
| + return RV->NewIntVal; |
| +} |
| + |
| +Value *FunctionConverter::ConvertBackToPtr(Value *Val, Instruction *InsertPt) { |
| + Type *NewTy = |
| + ConvertType(Val->getType()->getPointerElementType())->getPointerTo(); |
| + Value *Conv = Convert(Val); |
| + return new IntToPtrInst(Conv, NewTy, Conv->getName() + ".asptr", InsertPt); |
| +} |
| + |
| +Value *FunctionConverter::ConvertFunctionPtr(Value *Callee, |
| + Instruction *InsertPt) { |
| + // Avoid casts for direct calls. |
| + if (Function *CalleeF = dyn_cast<Function>(Callee)) { |
| + assert(FuncMap->count(CalleeF) == 1); |
| + return (*FuncMap)[CalleeF]; |
| + } |
| + FunctionType *FuncType = cast<FunctionType>( |
| + Callee->getType()->getPointerElementType()); |
| + Value *Conv = Convert(Callee); |
| + return new IntToPtrInst(Conv, ConvertFuncType(FuncType)->getPointerTo(), |
| + Conv->getName() + ".asfuncptr", InsertPt); |
| +} |
| + |
| +static bool ShouldLeaveAlone(Value *V) { |
| + if (Function *F = dyn_cast<Function>(V)) |
| + return F->isIntrinsic(); |
| + if (isa<InlineAsm>(V)) |
| + return true; |
| + return false; |
| +} |
| + |
| +void FunctionConverter::ConvertInPlace(Instruction *Inst) { |
| + // Convert operands. |
| + for (unsigned I = 0; I < Inst->getNumOperands(); ++I) { |
| + Value *Arg = Inst->getOperand(I); |
| + if (Arg->getType()->isPointerTy() && !ShouldLeaveAlone(Arg)) { |
| + Value *Conv = Convert(Arg); |
| + Inst->setOperand(I, new IntToPtrInst(Convert(Arg), Arg->getType(), |
| + Conv->getName() + ".asptr", Inst)); |
| + } |
| + } |
| + // Convert result. |
| + if (Inst->getType()->isPointerTy()) { |
| + Instruction *Cast = new PtrToIntInst( |
| + Inst, ConvertType(Inst->getType()), Inst->getName() + ".asint"); |
| + Cast->insertAfter(Inst); |
| + RecordConverted(Inst, Cast); |
| + } |
| +} |
| + |
| +void FunctionConverter::Finish() { |
| + if (PlaceholderCount) { |
| + for (DenseMap<Value *, RewrittenVal>::iterator I = RewriteMap.begin(), |
| + E = RewriteMap.end(); I != E; ++I) { |
| + if (I->second.IsPlaceholder) |
| + errs() << "Not converted: " << *I->first << "\n"; |
| + } |
| + report_fatal_error("Case not handled in ReplacePtrsWithInts"); |
| + } |
| + for (SmallVector<Instruction *, 10>::iterator I = ToErase.begin(), |
| + E = ToErase.end(); |
| + I != E; ++I) { |
| + (*I)->dropAllReferences(); |
| + } |
| + for (SmallVector<Instruction *, 10>::iterator I = ToErase.begin(), |
| + E = ToErase.end(); |
| + I != E; ++I) { |
| + (*I)->eraseFromParent(); |
| + } |
| +} |
| + |
| +static void ConvertMetadataOperand(FunctionConverter *FC, |
| + IntrinsicInst *Call, int Index) { |
| + MDNode *MD = cast<MDNode>(Call->getArgOperand(Index)); |
| + if (MD->getNumOperands() != 1) |
| + return; |
| + Value *MDArg = MD->getOperand(0); |
| + if (MDArg && (isa<Argument>(MDArg) || isa<Instruction>(MDArg))) { |
| + MDArg = FC->Convert(MDArg); |
| + if (PtrToIntInst *Cast = dyn_cast<PtrToIntInst>(MDArg)) { |
| + // Unwrapping this is necessary for llvm.dbg.declare to work. |
| + MDArg = Cast->getPointerOperand(); |
| + } |
| + SmallVector<Value *, 1> Args; |
| + Args.push_back(MDArg); |
| + Call->setArgOperand(Index, MDNode::get(Call->getContext(), Args)); |
| + } |
| +} |
| + |
| +static AttributeSet RemoveAttrs(LLVMContext &Context, AttributeSet Attrs) { |
| + SmallVector<AttributeSet, 8> AttrList; |
| + for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) { |
| + unsigned Index = Attrs.getSlotIndex(Slot); |
| + AttrBuilder AB; |
| + for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot); |
| + Attr != E; ++Attr) { |
| + switch (Attr->getKindAsEnum()) { |
| + case Attribute::ByVal: |
| + case Attribute::StructRet: |
| + case Attribute::Nest: |
| + Attrs.dump(); |
| + report_fatal_error("ReplacePtrsWithInts cannot handle " |
| + "byval, sret or nest attrs"); |
| + break; |
| + case Attribute::NoCapture: |
| + case Attribute::NoAlias: |
| + // Strip these attributes. |
| + break; |
| + default: |
| + AB.addAttribute(*Attr); |
| + } |
| + } |
| + AttrList.push_back(AttributeSet::get(Context, Index, AB)); |
| + } |
| + return AttributeSet::get(Context, AttrList); |
| +} |
| + |
| +template <class InstType> |
| +static void CopyLoadOrStoreAttrs(InstType *Dest, InstType *Src) { |
| + Dest->setVolatile(Src->isVolatile()); |
| + Dest->setAlignment(Src->getAlignment()); |
| + Dest->setOrdering(Src->getOrdering()); |
| + Dest->setSynchScope(Src->getSynchScope()); |
| +} |
| + |
| +static void ConvertInstruction(DataLayout *DL, Type *IntPtrType, |
| + FunctionConverter *FC, Instruction *Inst) { |
| + if (ReturnInst *Ret = dyn_cast<ReturnInst>(Inst)) { |
| + Value *Result = Ret->getReturnValue(); |
| + if (Result) |
| + Result = FC->Convert(Result); |
| + CopyDebug(ReturnInst::Create(Ret->getContext(), Result, Ret), Inst); |
| + Ret->eraseFromParent(); |
| + } else if (PHINode *Phi = dyn_cast<PHINode>(Inst)) { |
| + PHINode *Phi2 = PHINode::Create(FC->ConvertType(Phi->getType()), |
| + Phi->getNumIncomingValues(), |
| + "", Phi); |
| + CopyDebug(Phi2, Phi); |
| + for (unsigned I = 0; I < Phi->getNumIncomingValues(); ++I) { |
| + Phi2->addIncoming(FC->Convert(Phi->getIncomingValue(I)), |
| + Phi->getIncomingBlock(I)); |
| + } |
| + Phi2->takeName(Phi); |
| + FC->RecordConvertedAndErase(Phi, Phi2); |
| + } else if (SelectInst *Op = dyn_cast<SelectInst>(Inst)) { |
| + Instruction *Op2 = SelectInst::Create(Op->getCondition(), |
| + FC->Convert(Op->getTrueValue()), |
| + FC->Convert(Op->getFalseValue()), |
| + "", Op); |
| + CopyDebug(Op2, Op); |
| + Op2->takeName(Op); |
| + FC->RecordConvertedAndErase(Op, Op2); |
| + } else if (isa<PtrToIntInst>(Inst) || isa<IntToPtrInst>(Inst)) { |
| + Value *Arg = FC->Convert(Inst->getOperand(0)); |
| + unsigned ArgSize = Arg->getType()->getIntegerBitWidth(); |
| + Type *ResultTy = FC->ConvertType(Inst->getType()); |
| + unsigned ResultSize = ResultTy->getIntegerBitWidth(); |
| + Value *Result; |
| + if (ArgSize == ResultSize) { |
| + Result = Arg; |
| + } else { |
| + if (ArgSize > ResultSize) { |
| + Result = CopyDebug(new TruncInst(Arg, ResultTy, "", Inst), Inst); |
| + } else { |
| + Result = CopyDebug(new ZExtInst(Arg, ResultTy, "", Inst), Inst); |
| + } |
| + Result->takeName(Inst); |
| + } |
| + FC->RecordConvertedAndErase(Inst, Result); |
| + } else if (isa<BitCastInst>(Inst)) { |
| + if (Inst->getType()->isPointerTy()) { |
| + FC->RecordConvertedAndErase(Inst, FC->Convert(Inst->getOperand(0))); |
| + } |
| + } else if (ICmpInst *Cmp = dyn_cast<ICmpInst>(Inst)) { |
| + Value *Cmp2 = CopyDebug(new ICmpInst(Inst, Cmp->getPredicate(), |
| + FC->Convert(Cmp->getOperand(0)), |
| + FC->Convert(Cmp->getOperand(1)), ""), |
| + Inst); |
| + Cmp2->takeName(Cmp); |
| + Cmp->replaceAllUsesWith(Cmp2); |
| + Cmp->eraseFromParent(); |
| + } else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) { |
| + Value *Ptr = FC->ConvertBackToPtr(Load->getPointerOperand(), Inst); |
| + LoadInst *Result = new LoadInst(Ptr, "", Inst); |
| + Result->takeName(Inst); |
| + CopyDebug(Result, Inst); |
| + CopyLoadOrStoreAttrs(Result, Load); |
| + FC->RecordConvertedAndErase(Inst, Result); |
| + } else if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) { |
| + Value *Ptr = FC->ConvertBackToPtr(Store->getPointerOperand(), Inst); |
| + StoreInst *Result = new StoreInst(FC->Convert(Store->getValueOperand()), |
| + Ptr, Inst); |
| + CopyDebug(Result, Inst); |
| + CopyLoadOrStoreAttrs(Result, Store); |
| + Inst->eraseFromParent(); |
| + } else if (CallInst *Call = dyn_cast<CallInst>(Inst)) { |
| + if (IntrinsicInst *ICall = dyn_cast<IntrinsicInst>(Inst)) { |
| + if (ICall->getIntrinsicID() == Intrinsic::dbg_declare) { |
| + ConvertMetadataOperand(FC, ICall, 0); |
| + } |
| + FC->ConvertInPlace(Inst); |
| + } else if (isa<InlineAsm>(Call->getCalledValue())) { |
| + FC->ConvertInPlace(Inst); |
| + } else { |
| + SmallVector<Value *, 10> Args; |
| + for (unsigned I = 0; I < Call->getNumArgOperands(); ++I) |
| + Args.push_back(FC->Convert(Call->getArgOperand(I))); |
| + CallInst *NewCall = CallInst::Create( |
| + FC->ConvertFunctionPtr(Call->getCalledValue(), Call), |
| + Args, "", Inst); |
| + CopyDebug(NewCall, Call); |
| + NewCall->setAttributes(RemoveAttrs(Call->getContext(), |
| + Call->getAttributes())); |
| + NewCall->setCallingConv(Call->getCallingConv()); |
| + NewCall->takeName(Call); |
| + FC->RecordConvertedAndErase(Call, NewCall); |
| + } |
| + } else if (InvokeInst *Call = dyn_cast<InvokeInst>(Inst)) { |
| + SmallVector<Value *, 10> Args; |
| + for (unsigned I = 0; I < Call->getNumArgOperands(); ++I) |
| + Args.push_back(FC->Convert(Call->getArgOperand(I))); |
| + InvokeInst *NewCall = InvokeInst::Create( |
| + FC->ConvertFunctionPtr(Call->getCalledValue(), Call), |
| + Call->getNormalDest(), |
| + Call->getUnwindDest(), |
| + Args, "", Inst); |
| + CopyDebug(NewCall, Call); |
| + NewCall->setAttributes(RemoveAttrs(Call->getContext(), |
| + Call->getAttributes())); |
| + NewCall->setCallingConv(Call->getCallingConv()); |
| + NewCall->takeName(Call); |
| + FC->RecordConvertedAndErase(Call, NewCall); |
| + } else if (AllocaInst *Alloca = dyn_cast<AllocaInst>(Inst)) { |
| + Type *ElementTy = Inst->getType()->getPointerElementType(); |
| + Type *ElementTy2 = ArrayType::get(Type::getInt8Ty(Inst->getContext()), |
| + DL->getTypeAllocSize(ElementTy)); |
| + Value *Tmp = CopyDebug(new AllocaInst(ElementTy2, Alloca->getArraySize(), |
| + Alloca->getAlignment(), "", Inst), |
| + Inst); |
| + Tmp->takeName(Alloca); |
| + Value *Alloca2 = new PtrToIntInst(Tmp, IntPtrType, |
| + Tmp->getName() + ".asint", Inst); |
| + FC->RecordConvertedAndErase(Alloca, Alloca2); |
| + } else if (// These atomics only operate on integer pointers, not |
| + // other pointers, so we don't need to recreate the |
| + // instruction. |
| + isa<AtomicCmpXchgInst>(Inst) || |
| + isa<AtomicRMWInst>(Inst) || |
| + // Handle these instructions as a convenience to allow |
| + // the pass to be used in more situations, even though we |
| + // don't expect them in PNaCl's stable ABI. |
| + isa<GetElementPtrInst>(Inst) || |
| + isa<VAArgInst>(Inst) || |
| + isa<IndirectBrInst>(Inst) || |
| + isa<ExtractValueInst>(Inst) || |
| + isa<InsertValueInst>(Inst)) { |
| + FC->ConvertInPlace(Inst); |
| + } |
| +} |
| + |
| +// Convert ptrtoint+inttoptr to a bitcast because it's shorter and |
| +// because some intrinsics work on bitcasts but not on |
| +// ptrtoint+inttoptr, in particular: |
| +// * llvm.lifetime.start/end |
| +// * llvm.eh.typeid.for |
| +static void SimplifyCasts(Instruction *Inst, Type *IntPtrType) { |
| + if (IntToPtrInst *Cast1 = dyn_cast<IntToPtrInst>(Inst)) { |
| + if (PtrToIntInst *Cast2 = dyn_cast<PtrToIntInst>(Cast1->getOperand(0))) { |
| + assert(Cast2->getType() == IntPtrType); |
| + Value *V = Cast2->getPointerOperand(); |
| + if (V->getType() != Cast1->getType()) |
| + V = new BitCastInst(V, Cast1->getType(), V->getName() + ".bc", Cast1); |
| + Cast1->replaceAllUsesWith(V); |
| + if (Cast1->use_empty()) |
| + Cast1->eraseFromParent(); |
| + if (Cast2->use_empty()) |
| + Cast2->eraseFromParent(); |
| + } |
| + } |
| +} |
| + |
| +static void ConvertFunc(DataLayout *DL, FunctionMap *FuncMap, |
| + Function *Func, Function *NewFunc, Type *IntPtrType) { |
| + FunctionConverter FC(IntPtrType, FuncMap); |
| + |
| + // Move the arguments across to the new function. |
| + for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(), |
| + NewArg = NewFunc->arg_begin(); |
| + Arg != E; ++Arg, ++NewArg) { |
| + FC.RecordConverted(Arg, NewArg); |
| + NewArg->takeName(Arg); |
| + } |
| + |
| + for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end(); |
| + BB != E; ++BB) { |
| + for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); |
| + Iter != E; ) { |
| + ConvertInstruction(DL, IntPtrType, &FC, Iter++); |
| + } |
| + } |
| + FC.Finish(); |
| + |
| + // Remove the ConstantExpr bitcasts we introduced for referencing |
| + // global variables. |
| + FunctionPass *Pass = createExpandConstantExprPass(); |
| + Pass->runOnFunction(*NewFunc); |
| + delete Pass; |
| + |
| + for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end(); |
| + BB != E; ++BB) { |
| + for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); |
| + Iter != E; ) { |
| + SimplifyCasts(Iter++, IntPtrType); |
| + } |
| + } |
| + // Cleanup: Remove ptrtoints that were introduced for allocas but not used. |
| + for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end(); |
| + BB != E; ++BB) { |
| + for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); |
| + Iter != E; ) { |
| + Instruction *Inst = Iter++; |
| + if (isa<PtrToIntInst>(Inst) && Inst->use_empty()) |
| + Inst->eraseFromParent(); |
| + } |
| + } |
| +} |
| + |
| +char ReplacePtrsWithInts::ID = 0; |
| +INITIALIZE_PASS(ReplacePtrsWithInts, "replace-ptrs-with-ints", |
| + "Convert pointer values to integer values", |
| + false, false) |
| + |
| +bool ReplacePtrsWithInts::runOnModule(Module &M) { |
| + DataLayout DL(&M); |
| + Type *IntPtrType = DL.getIntPtrType(M.getContext()); |
| + FunctionMap FuncMap; |
| + |
| + // To avoid introducing bitcasts for direct function calls, we do |
| + // the conversion in three passes. |
|
eliben
2013/05/15 22:11:21
Explain what the three passes are/do?
Mark Seaborn
2013/05/16 02:08:40
In the course of adding comments, I realised that
|
| + for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) { |
| + Function *Func = Iter++; |
| + // Intrinsics' types must be left alone. |
| + if (Func->isIntrinsic()) |
| + continue; |
| + |
| + FunctionConverter FC(IntPtrType, NULL); |
| + FunctionType *NFTy = FC.ConvertFuncType(Func->getFunctionType()); |
| + |
| + // In order to change the function's arguments, we have to recreate |
| + // the function. |
| + Function *NewFunc = Function::Create(NFTy, Func->getLinkage()); |
| + NewFunc->copyAttributesFrom(Func); |
| + NewFunc->setAttributes(RemoveAttrs(M.getContext(), |
| + NewFunc->getAttributes())); |
| + Func->getParent()->getFunctionList().insert(Func, NewFunc); |
| + NewFunc->takeName(Func); |
| + NewFunc->getBasicBlockList().splice(NewFunc->begin(), |
| + Func->getBasicBlockList()); |
| + FuncMap[Func] = NewFunc; |
| + } |
| + for (FunctionMap::iterator Iter = FuncMap.begin(), E = FuncMap.end(); |
| + Iter != E; ++Iter) { |
| + ConvertFunc(&DL, &FuncMap, Iter->first, Iter->second, IntPtrType); |
| + } |
| + for (FunctionMap::iterator Iter = FuncMap.begin(), E = FuncMap.end(); |
| + Iter != E; ++Iter) { |
| + // Finally, rewrite references by global variable initializers. |
| + Iter->first->replaceAllUsesWith( |
| + ConstantExpr::getBitCast(Iter->second, Iter->first->getType())); |
| + Iter->first->eraseFromParent(); |
| + } |
| + return true; |
| +} |
| + |
| +ModulePass *llvm::createReplacePtrsWithIntsPass() { |
| + return new ReplacePtrsWithInts(); |
| +} |