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..df5f07228eb7e0f9fe4720463ff54ba139da9d98 |
--- /dev/null |
+++ b/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp |
@@ -0,0 +1,527 @@ |
+//===- 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/IRBuilder.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); |
+ }; |
+ |
+ // FunctionConverter stores the state for mapping old instructions |
+ // (of pointer type) to converted instructions (of integer type) |
+ // within a function, and provides methods for doing the conversion. |
+ class FunctionConverter { |
+ // Int type that pointer types are to be replaced with, typically i32. |
+ Type *IntPtrType; |
+ |
+ struct RewrittenVal { |
+ RewrittenVal(): IsPlaceholder(true), NewIntVal(NULL) {} |
+ bool IsPlaceholder; |
+ Value *NewIntVal; |
+ }; |
+ // Maps from old values (of pointer type) to converted values (of |
+ // IntPtrType type). |
+ DenseMap<Value *, RewrittenVal> RewriteMap; |
+ // Number of placeholders; used for detecting unhandled cases. |
+ int PlaceholderCount; |
+ // List of instructions whose deletion has been deferred. |
+ SmallVector<Instruction *, 20> ToErase; |
+ |
+ public: |
+ FunctionConverter(Type *IntPtrType) |
+ : IntPtrType(IntPtrType), PlaceholderCount(0) {} |
+ |
+ // Returns the normalized version of the given type, converting |
+ // pointer types to IntPtrType. |
+ Type *convertType(Type *Ty); |
+ // Returns the normalized version of the given function type by |
+ // normalizing the function's argument types. |
+ FunctionType *convertFuncType(FunctionType *FTy); |
+ |
+ // Records that 'To' is the normalized version of 'From'. |
+ void recordConverted(Value *From, Value *To); |
+ void recordConvertedAndErase(Instruction *From, Value *To); |
+ |
+ // Returns the normalized version of the given value. |
+ Value *convert(Value *Val); |
+ // Returns the NormalizedPtr form of the given pointer value. |
eliben
2013/05/20 22:18:49
It also inserts the conversion instruction, not ju
Mark Seaborn
2013/05/21 23:12:07
Comment added.
|
+ Value *convertBackToPtr(Value *Val, Instruction *InsertPt); |
+ // Returns the NormalizedPtr form of the given function pointer. |
+ Value *convertFunctionPtr(Value *Callee, Instruction *InsertPt); |
+ // Converts an instruction without recreating it, by wrapping its |
+ // operands and result. |
+ void convertInPlace(Instruction *Inst); |
+ |
+ void eraseReplacedInstructions(); |
+ }; |
+} |
+ |
+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()) { |
eliben
2013/05/20 22:18:49
It's kind of unclear (definietely from the method
Mark Seaborn
2013/05/21 23:12:07
Added comment.
|
+ 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)) |
+ 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) { |
+ 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)) |
eliben
2013/05/20 22:18:49
Under what circumstances can we have inline asm?
Mark Seaborn
2013/05/21 23:12:07
PNaCl doesn't allow it, obviously. However, I hav
|
+ 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::eraseReplacedInstructions() { |
+ 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 (SmallVectorImpl<Instruction *>::iterator I = ToErase.begin(), |
+ E = ToErase.end(); |
+ I != E; ++I) { |
+ (*I)->dropAllReferences(); |
eliben
2013/05/20 22:18:49
Document why this is needed. Why would reference r
Mark Seaborn
2013/05/21 23:12:07
Comment added.
|
+ } |
+ for (SmallVectorImpl<Instruction *>::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) { |
eliben
2013/05/20 22:18:49
Document what kinds of attrs this removes
Mark Seaborn
2013/05/21 23:12:07
Added more commentary in the function.
|
+ 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(); |
eliben
2013/05/20 22:18:49
Can you clarify why you use recordConvertedAndEras
Mark Seaborn
2013/05/21 23:12:07
We don't erase:
* Arguments -- because you can't
|
+ } 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)); |
+ Type *ResultTy = FC->convertType(Inst->getType()); |
+ IRBuilder<> Builder(Inst); |
+ Builder.SetCurrentDebugLocation(Inst->getDebugLoc()); |
+ Value *Result = Builder.CreateZExtOrTrunc(Arg, ResultTy, ""); |
+ if (Result != Arg) |
+ 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)); |
+ unsigned Alignment = Alloca->getAlignment(); |
+ if (Alignment == 0) |
+ Alignment = DL->getPrefTypeAlignment(ElementTy); |
+ Value *Tmp = CopyDebug(new AllocaInst(ElementTy2, Alloca->getArraySize(), |
+ Alignment, "", 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 CleanUpFunction(Function *Func, Type *IntPtrType) { |
+ // Remove the ptrtoint/bitcast ConstantExprs we introduced for |
+ // referencing globals. |
+ FunctionPass *Pass = createExpandConstantExprPass(); |
eliben
2013/05/20 22:18:49
Wait, you planned to run the ConstExpr pass last p
Mark Seaborn
2013/05/21 23:12:07
ReplacePtrsWithInts needs to run after ExpandConst
|
+ Pass->runOnFunction(*Func); |
+ delete Pass; |
+ |
+ for (Function::iterator BB = Func->begin(), E = Func->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 = Func->begin(), E = Func->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()); |
+ |
+ for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) { |
+ Function *OldFunc = Iter++; |
+ // Intrinsics' types must be left alone. |
+ if (OldFunc->isIntrinsic()) |
+ continue; |
+ |
+ FunctionConverter FC(IntPtrType); |
+ FunctionType *NFTy = FC.convertFuncType(OldFunc->getFunctionType()); |
+ |
+ // In order to change the function's argument types, we have to |
+ // recreate the function. |
+ Function *NewFunc = Function::Create(NFTy, OldFunc->getLinkage()); |
+ NewFunc->copyAttributesFrom(OldFunc); |
+ NewFunc->setAttributes(RemoveAttrs(M.getContext(), |
+ NewFunc->getAttributes())); |
+ OldFunc->getParent()->getFunctionList().insert(OldFunc, NewFunc); |
eliben
2013/05/20 22:18:49
Can you use M instead of OldFunc->getParent() ?
Mark Seaborn
2013/05/21 23:12:07
Yes, done.
|
+ NewFunc->takeName(OldFunc); |
+ NewFunc->getBasicBlockList().splice(NewFunc->begin(), |
+ OldFunc->getBasicBlockList()); |
+ |
+ // Move the arguments across to the new function. |
+ for (Function::arg_iterator Arg = OldFunc->arg_begin(), |
+ E = OldFunc->arg_end(), NewArg = NewFunc->arg_begin(); |
+ Arg != E; ++Arg, ++NewArg) { |
+ FC.recordConverted(Arg, NewArg); |
+ NewArg->takeName(Arg); |
+ } |
+ |
+ // Convert the function body. |
+ 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.eraseReplacedInstructions(); |
+ OldFunc->replaceAllUsesWith(ConstantExpr::getBitCast(NewFunc, |
+ OldFunc->getType())); |
+ OldFunc->eraseFromParent(); |
+ } |
+ // Now that all functions have their normalized types, we can remove |
+ // various casts. |
+ for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) { |
+ CleanUpFunction(Func, IntPtrType); |
+ } |
+ return true; |
+} |
+ |
+ModulePass *llvm::createReplacePtrsWithIntsPass() { |
+ return new ReplacePtrsWithInts(); |
+} |