| 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..d1d2d179365dcb86138f0a52ee001a07800746ad
|
| --- /dev/null
|
| +++ b/lib/Transforms/NaCl/ReplacePtrsWithInts.cpp
|
| @@ -0,0 +1,627 @@
|
| +//===- 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).
|
| +//
|
| +// This pass relies on -simplify-allocas to transform allocas into arrays of
|
| +// bytes.
|
| +//
|
| +// 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.
|
| +//
|
| +// 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.
|
| +//
|
| +// This pass currently strips out lifetime markers (that is, calls to
|
| +// the llvm.lifetime.start/end intrinsics) and invariant markers
|
| +// (calls to llvm.invariant.start/end).
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#include "llvm/ADT/DenseMap.h"
|
| +#include "llvm/ADT/SmallPtrSet.h"
|
| +#include "llvm/IR/DataLayout.h"
|
| +#include "llvm/IR/DebugInfo.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);
|
| + };
|
| +
|
| + // 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(): Placeholder(NULL), NewIntVal(NULL) {}
|
| + Value *Placeholder;
|
| + Value *NewIntVal;
|
| + };
|
| + // Maps from old values (of pointer type) to converted values (of
|
| + // IntPtrType type).
|
| + DenseMap<Value *, RewrittenVal> RewriteMap;
|
| +
|
| + public:
|
| + FunctionConverter(Type *IntPtrType) : IntPtrType(IntPtrType) {}
|
| +
|
| + // 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'. If 'To'
|
| + // is not of pointer type, no type conversion is required, so this
|
| + // can take the short cut of replacing 'To' with 'From'.
|
| + void recordConverted(Value *From, Value *To);
|
| + void recordConvertedAndErase(Instruction *From, Value *To);
|
| +
|
| + // Returns Val with no-op casts (those that convert between
|
| + // IntPtrType and pointer types) stripped off.
|
| + Value *stripNoopCasts(Value *Val);
|
| +
|
| + // Returns the normalized version of the given value.
|
| + //
|
| + // If the conversion of Val has been deferred, this returns a
|
| + // placeholder object, which will later be replaceAllUsesWith'd to
|
| + // the final value. Since replaceAllUsesWith does not work on
|
| + // references by metadata nodes, this can be bypassed using
|
| + // BypassPlaceholder to get the real converted value, assuming it
|
| + // is available.
|
| + Value *convert(Value *Val, bool BypassPlaceholder = false);
|
| + // Returns the NormalizedPtr form of the given pointer value.
|
| + // Inserts conversion instructions at InsertPt.
|
| + Value *convertBackToPtr(Value *Val, Instruction *InsertPt);
|
| + // Returns the NormalizedPtr form of the given function pointer.
|
| + // Inserts conversion instructions at InsertPt.
|
| + Value *convertFunctionPtr(Value *Callee, Instruction *InsertPt);
|
| + // Converts an instruction without recreating it, by wrapping its
|
| + // operands and result.
|
| + void convertInPlace(Instruction *Inst);
|
| +
|
| + void eraseReplacedInstructions();
|
| +
|
| + // List of instructions whose deletion has been deferred.
|
| + SmallVector<Instruction *, 20> ToErase;
|
| + };
|
| +}
|
| +
|
| +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];
|
| + assert(!RV->NewIntVal);
|
| + 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::stripNoopCasts(Value *Val) {
|
| + SmallPtrSet<Value *, 4> Visited;
|
| + for (;;) {
|
| + if (!Visited.insert(Val).second) {
|
| + // It is possible to get a circular reference in unreachable
|
| + // basic blocks. Handle this case for completeness.
|
| + return UndefValue::get(Val->getType());
|
| + }
|
| + if (CastInst *Cast = dyn_cast<CastInst>(Val)) {
|
| + Value *Src = Cast->getOperand(0);
|
| + if ((isa<BitCastInst>(Cast) && Cast->getType()->isPointerTy()) ||
|
| + (isa<PtrToIntInst>(Cast) && Cast->getType() == IntPtrType) ||
|
| + (isa<IntToPtrInst>(Cast) && Src->getType() == IntPtrType)) {
|
| + Val = Src;
|
| + continue;
|
| + }
|
| + }
|
| + return Val;
|
| + }
|
| +}
|
| +
|
| +Value *FunctionConverter::convert(Value *Val, bool BypassPlaceholder) {
|
| + Val = stripNoopCasts(Val);
|
| + if (!Val->getType()->isPointerTy())
|
| + return Val;
|
| + if (Constant *C = dyn_cast<Constant>(Val))
|
| + return ConstantExpr::getPtrToInt(C, IntPtrType);
|
| + RewrittenVal *RV = &RewriteMap[Val];
|
| + if (BypassPlaceholder) {
|
| + assert(RV->NewIntVal);
|
| + return RV->NewIntVal;
|
| + }
|
| + if (!RV->Placeholder)
|
| + RV->Placeholder = new Argument(convertType(Val->getType()));
|
| + return RV->Placeholder;
|
| +}
|
| +
|
| +Value *FunctionConverter::convertBackToPtr(Value *Val, Instruction *InsertPt) {
|
| + Type *NewTy =
|
| + convertType(Val->getType()->getPointerElementType())->getPointerTo();
|
| + return new IntToPtrInst(convert(Val), NewTy, "", InsertPt);
|
| +}
|
| +
|
| +Value *FunctionConverter::convertFunctionPtr(Value *Callee,
|
| + Instruction *InsertPt) {
|
| + FunctionType *FuncType = cast<FunctionType>(
|
| + Callee->getType()->getPointerElementType());
|
| + return new IntToPtrInst(convert(Callee),
|
| + convertFuncType(FuncType)->getPointerTo(),
|
| + "", 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(Conv, Arg->getType(), "", 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() {
|
| + bool Error = false;
|
| + for (DenseMap<Value *, RewrittenVal>::iterator I = RewriteMap.begin(),
|
| + E = RewriteMap.end(); I != E; ++I) {
|
| + if (I->second.Placeholder) {
|
| + if (I->second.NewIntVal) {
|
| + I->second.Placeholder->replaceAllUsesWith(I->second.NewIntVal);
|
| + } else {
|
| + errs() << "Not converted: " << *I->first << "\n";
|
| + Error = true;
|
| + }
|
| + }
|
| + }
|
| + if (Error)
|
| + report_fatal_error("Case not handled in ReplacePtrsWithInts");
|
| +
|
| + // Delete the placeholders in a separate pass. This means that if
|
| + // one placeholder is accidentally rewritten to another, we will get
|
| + // a useful error message rather than accessing a dangling pointer.
|
| + for (DenseMap<Value *, RewrittenVal>::iterator I = RewriteMap.begin(),
|
| + E = RewriteMap.end(); I != E; ++I) {
|
| + delete I->second.Placeholder;
|
| + }
|
| +
|
| + // We must do dropAllReferences() before doing eraseFromParent(),
|
| + // otherwise we will try to erase instructions that are still
|
| + // referenced.
|
| + for (SmallVectorImpl<Instruction *>::iterator I = ToErase.begin(),
|
| + E = ToErase.end();
|
| + I != E; ++I) {
|
| + (*I)->dropAllReferences();
|
| + }
|
| + 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, /* BypassPlaceholder= */ true);
|
| + 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));
|
| + }
|
| +}
|
| +
|
| +// Remove attributes that only apply to pointer arguments. Returns
|
| +// the updated AttributeSet.
|
| +static AttributeSet RemovePointerAttrs(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) {
|
| + if (!Attr->isEnumAttribute()) {
|
| + continue;
|
| + }
|
| + switch (Attr->getKindAsEnum()) {
|
| + // ByVal and StructRet should already have been removed by the
|
| + // ExpandByVal pass.
|
| + case Attribute::ByVal:
|
| + case Attribute::StructRet:
|
| + case Attribute::Nest:
|
| + Attrs.dump();
|
| + report_fatal_error("ReplacePtrsWithInts cannot handle "
|
| + "byval, sret or nest attrs");
|
| + break;
|
| + // Strip these attributes because they apply only to pointers. This pass
|
| + // rewrites pointer arguments, thus these parameter attributes are
|
| + // meaningless. Also, they are rejected by the PNaCl module verifier.
|
| + case Attribute::NoCapture:
|
| + case Attribute::NoAlias:
|
| + case Attribute::ReadNone:
|
| + case Attribute::ReadOnly:
|
| + break;
|
| + default:
|
| + AB.addAttribute(*Attr);
|
| + }
|
| + }
|
| + AttrList.push_back(AttributeSet::get(Context, Index, AB));
|
| + }
|
| + return AttributeSet::get(Context, AttrList);
|
| +}
|
| +
|
| +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));
|
| + Type *ResultTy = FC->convertType(Inst->getType());
|
| + unsigned ArgSize = Arg->getType()->getIntegerBitWidth();
|
| + unsigned ResultSize = ResultTy->getIntegerBitWidth();
|
| + Value *Result;
|
| + // We avoid using IRBuilder's CreateZExtOrTrunc() here because it
|
| + // constant-folds ptrtoint ConstantExprs. This leads to creating
|
| + // ptrtoints of non-IntPtrType type, which is not what we want,
|
| + // because we want truncation/extension to be done explicitly by
|
| + // separate instructions.
|
| + if (ArgSize == ResultSize) {
|
| + Result = Arg;
|
| + } else {
|
| + Instruction::CastOps CastType =
|
| + ArgSize > ResultSize ? Instruction::Trunc : Instruction::ZExt;
|
| + Result = CopyDebug(CastInst::Create(CastType, Arg, ResultTy, "", Inst),
|
| + Inst);
|
| + }
|
| + if (Result != Arg)
|
| + Result->takeName(Inst);
|
| + FC->recordConvertedAndErase(Inst, Result);
|
| + } else if (isa<BitCastInst>(Inst)) {
|
| + if (Inst->getType()->isPointerTy()) {
|
| + FC->ToErase.push_back(Inst);
|
| + }
|
| + } 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::lifetime_start ||
|
| + ICall->getIntrinsicID() == Intrinsic::lifetime_end ||
|
| + ICall->getIntrinsicID() == Intrinsic::invariant_start) {
|
| + // Remove alloca lifetime markers for now. This is because
|
| + // the GVN pass can introduce lifetime markers taking PHI
|
| + // nodes as arguments. If ReplacePtrsWithInts converts the
|
| + // PHI node to int type, we will render those lifetime markers
|
| + // ineffective. But dropping a subset of lifetime markers is
|
| + // not safe in general. So, until LLVM better defines the
|
| + // semantics of lifetime markers, we drop them all. See:
|
| + // https://code.google.com/p/nativeclient/issues/detail?id=3443
|
| + // We do the same for invariant.start/end because they work in
|
| + // a similar way.
|
| + Inst->eraseFromParent();
|
| + } else {
|
| + 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(RemovePointerAttrs(Call->getContext(),
|
| + Call->getAttributes()));
|
| + NewCall->setCallingConv(Call->getCallingConv());
|
| + NewCall->setTailCall(Call->isTailCall());
|
| + 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(RemovePointerAttrs(Call->getContext(),
|
| + Call->getAttributes()));
|
| + NewCall->setCallingConv(Call->getCallingConv());
|
| + NewCall->takeName(Call);
|
| + FC->recordConvertedAndErase(Call, NewCall);
|
| + } else if (// 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<AllocaInst>(Inst) ||
|
| + isa<GetElementPtrInst>(Inst) ||
|
| + isa<VAArgInst>(Inst) ||
|
| + isa<IndirectBrInst>(Inst) ||
|
| + isa<ExtractValueInst>(Inst) ||
|
| + isa<InsertValueInst>(Inst) ||
|
| + // 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)) {
|
| + 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 (although we strip these out)
|
| +// * 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();
|
| + 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 pass.
|
| + 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++;
|
| + // Add names to inttoptrs to make the output more readable. The
|
| + // placeholder values get in the way of doing this earlier when
|
| + // the inttoptrs are created.
|
| + if (isa<IntToPtrInst>(Inst))
|
| + Inst->setName(Inst->getOperand(0)->getName() + ".asptr");
|
| + // Remove ptrtoints that were introduced for allocas but not used.
|
| + 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);
|
| + DenseMap<const Function *, DISubprogram> FunctionDIs = makeSubprogramMap(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());
|
| + OldFunc->setAttributes(RemovePointerAttrs(M.getContext(),
|
| + OldFunc->getAttributes()));
|
| + Function *NewFunc = RecreateFunction(OldFunc, NFTy);
|
| +
|
| + // 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);
|
| + }
|
| +
|
| + // invariant.end calls refer to invariant.start calls, so we must
|
| + // remove the former first.
|
| + for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
|
| + BB != E; ++BB) {
|
| + for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
|
| + Iter != E; ) {
|
| + if (IntrinsicInst *ICall = dyn_cast<IntrinsicInst>(Iter++)) {
|
| + if (ICall->getIntrinsicID() == Intrinsic::invariant_end)
|
| + ICall->eraseFromParent();
|
| + }
|
| + }
|
| + }
|
| +
|
| + // 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++);
|
| + }
|
| + }
|
| + // Now that all the replacement instructions have been created, we
|
| + // can update the debug intrinsic calls.
|
| + for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
|
| + BB != E; ++BB) {
|
| + for (BasicBlock::iterator Inst = BB->begin(), E = BB->end();
|
| + Inst != E; ++Inst) {
|
| + if (IntrinsicInst *Call = dyn_cast<IntrinsicInst>(Inst)) {
|
| + if (Call->getIntrinsicID() == Intrinsic::dbg_declare) {
|
| + ConvertMetadataOperand(&FC, Call, 0);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + FC.eraseReplacedInstructions();
|
| +
|
| + // Patch the pointer to LLVM function in debug info descriptor.
|
| + auto DI = FunctionDIs.find(OldFunc);
|
| + if (DI != FunctionDIs.end())
|
| + DI->second.replaceFunction(NewFunc);
|
| +
|
| + 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);
|
| + // Delete the now-unused bitcast ConstantExprs that we created so
|
| + // that they don't interfere with StripDeadPrototypes.
|
| + Func->removeDeadConstantUsers();
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +ModulePass *llvm::createReplacePtrsWithIntsPass() {
|
| + return new ReplacePtrsWithInts();
|
| +}
|
|
|