Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(333)

Unified Diff: lib/Transforms/NaCl/NormalizeStructRegSignatures.cpp

Issue 992493002: Lower signatures exposing struct registers to byval struct pointers (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: First draft Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/Transforms/NaCl/NormalizeStructRegSignatures.cpp
diff --git a/lib/Transforms/NaCl/NormalizeStructRegSignatures.cpp b/lib/Transforms/NaCl/NormalizeStructRegSignatures.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a9a4bd1912cc4c852824842936e67c0765a96c89
--- /dev/null
+++ b/lib/Transforms/NaCl/NormalizeStructRegSignatures.cpp
@@ -0,0 +1,610 @@
+//===- NormalizeStructRegSignatures.cpp - Change struct regs to struct ----===//
+// pointers
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// We do not support struct registers in PNaCl. We remove them in 2 stages.
+// In the first stage (this pass), we replace function signatures exposing them
+// to byval pointer-based signatures:
+//
+// @foo(%some_struct %val) -> @foo(%some_struct* byval %val)
+// or
+// %someStruct @bar(<other_args>) -> void @bar(%someStruct* sret, <other_args>)
+//
+// We also adjust such a function's body and call sites by creating locals to
+// convert to/from struct reg and struct* byval
+//
+// This affects more than function signatures. For example:
+//
+// %other_struct = type { i32, i32 }
+// %struct = type { void (%other_struct)* }
+// void %func(%struct* byval %s)
+//
+// must become:
+// %other_struct = type {i32, i32}
+// %struct.1 = type {void (%other_struct*)*}
+// void %func(%struct.1* byval %s)
+//
+// The second removal stage happens in the ExpandStructRegs.cpp phase.
+//===----------------------------------------------------------------------===//
+
+#include <stddef.h>
JF 2015/03/08 22:04:38 <cstddef> is more common.
Mircea Trofin 2015/03/09 21:21:29 Acknowledged.
+#include <cassert>
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/Argument.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Pass.h"
+#include "llvm/PassInfo.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/PassSupport.h"
+#include "llvm/Transforms/NaCl.h"
JF 2015/03/08 22:04:38 You should sort these.
Mircea Trofin 2015/03/09 21:21:29 Done.
+
+using namespace llvm;
+
+class MappingResult {
JF 2015/03/08 22:04:38 This should be in an anonymous namespace.
Mircea Trofin 2015/03/09 21:21:29 Done.
+public:
+
+ MappingResult(Type *ATy, bool Chg) {
+ Ty = ATy;
+ Changed = Chg;
+ }
+
+ bool isChanged() {
+ return Changed;
+ }
+
+ Type *operator->() {
+ return Ty;
+ }
+
+ operator Type*() {
+ return Ty;
+ }
+private:
+ Type *Ty;
+ bool Changed;
+};
+
+// utility class. For any given type, get the associated type that is struct
+// reg argument - free.
+class TypeMapper {
+public:
+ Type *getCompliantType(Type *Ty);
+private:
+ DenseMap<Type*, Type*> MappedTypes;
+ MappingResult getCompliantArgumentType(Type *Ty);
+ MappingResult getCompliantAggregateTypeInternal(Type *Ty);
+};
+
+namespace {
+ // This is a ModulePass because the pass recreates functions in
+ // order to change their signatures.
+ class NormalizeStructRegSignatures : public ModulePass {
+ public:
+ static char ID;
+
+ NormalizeStructRegSignatures() :
+ ModulePass(ID) {
+ initializeNormalizeStructRegSignaturesPass(
+ *PassRegistry::getPassRegistry());
+ }
+ virtual bool runOnModule(Module &M);
+ private:
+ TypeMapper Mapper;
+ DenseSet<Function*> FunctionsToDelete;
+ DenseSet<CallInst*> CallsToPatch;
+ DenseSet<InvokeInst*> InvokesToPatch;
+ DenseMap<Function*, Function*> FunctionMap;
+ bool ensurePNaClComplyingFunction(Function *OldFunc, Module &M);
JF 2015/03/08 22:04:38 I'd avoid putting "PNaCl" in the name: when we ups
Mircea Trofin 2015/03/09 21:21:29 Done.
+ void FixFunctionBody(Function *OldFunc, Function *NewFunc);
+ void ScheduleCallsForCleanup(Function *NewFunc);
+ template <class TCall> void FixCallSite(TCall *Call);
+ };
+}
+
+const unsigned int TypicalArity = 8;
JF 2015/03/08 22:04:38 static
Mircea Trofin 2015/03/09 21:21:29 Done.
+
+char NormalizeStructRegSignatures::ID = 0;
+
+INITIALIZE_PASS(NormalizeStructRegSignatures, "normalize-struct-reg-signatures",
+ "Normalize function signatures by removing struct register parameters",
+ false,
+ false)
+
+// The type is "compliant" if it does not recursively reference a
+// function type with at least an operand (arg or return) typed as struct
+// register
+Type *TypeMapper::getCompliantType(Type *Ty) {
+ if (MappedTypes.count(Ty))
+ return MappedTypes[Ty];
+ return MappedTypes[Ty] = getCompliantAggregateTypeInternal(Ty);
+}
+
+// transforms any type that could transitively reference a function pointer
+// into a compliant type.
+MappingResult TypeMapper::
+getCompliantAggregateTypeInternal(Type *Ty) {
+ LLVMContext &Ctx = Ty->getContext();
+ if (Ty->isFunctionTy()) {
+ FunctionType *OldFnTy = dyn_cast<FunctionType>(Ty);
JF 2015/03/08 22:04:38 The LLVM-idiomatic way is: if (FunctionType *Old
Mircea Trofin 2015/03/09 21:21:29 Done.
+ Type *OldRetType = OldFnTy->getReturnType();
+ Type *NewRetType = OldRetType;
+ Type *Void = Type::getVoidTy(Ctx);
+ SmallVector<Type*, TypicalArity> NewArgs;
+ bool HasChanges = false;
+ // struct register returns become the first parameter of the new FT.
+ // the new FT has void for the return type
+ if (OldRetType->isAggregateType()) {
+ NewRetType = Void;
+ HasChanges = true;
+ NewArgs.push_back(getCompliantArgumentType(OldRetType));
+ }
+ for (auto OldParam = OldFnTy->param_begin(), E = OldFnTy->param_end();
+ OldParam != E; ++OldParam) {
+ auto NewType = getCompliantArgumentType(*OldParam);
+ HasChanges |= NewType.isChanged();
+ NewArgs.push_back(NewType);
+ }
+ Type *NewFuncType = FunctionType::get(NewRetType, NewArgs, false);
+ return MappingResult(NewFuncType, HasChanges);
+ }
+
+ if (Ty->isPointerTy()) {
+ auto NewTy = getCompliantAggregateTypeInternal(
+ Ty->getPointerElementType());
+
+ return MappingResult(
+ NewTy->getPointerTo(),
+ NewTy.isChanged());
+ }
+
+ if (Ty->isArrayTy()) {
+ auto NewTy = getCompliantAggregateTypeInternal(
+ Ty->getArrayElementType());
+ return MappingResult(
+ ArrayType::get(
+ NewTy,
+ Ty->getArrayNumElements()),
+ NewTy.isChanged());
+ }
+
+ if (Ty->isVectorTy()) {
+ auto NewTy = getCompliantAggregateTypeInternal(
+ Ty->getVectorElementType());
+ return MappingResult(
+ VectorType::get(
+ NewTy,
+ Ty->getVectorNumElements()),
+ NewTy.isChanged());
+ }
+
+ if (Ty->isAggregateType()) {
+ StructType *StructTy = dyn_cast<StructType>(Ty);
+ if (!StructTy->isLiteral()) {
+ // LLVM doesn't intern identified structs (the ones with a name). This,
+ // together with the fact that such structs can be recursive,
+ // complicates things a bit. We want to make sure that we only change
+ // "problem" structs (those that somehow reference noncompliant funcs).
+ // We don't want to change compliant structs, otherwise converting
+ // instruction types will become trickier.
+ Type* &Loc = MappedTypes[StructTy];
JF 2015/03/08 22:04:38 Pointer ref is pretty unusual. Could you instead g
Mircea Trofin 2015/03/09 21:21:29 Yes, but then we spend twice on the hash map locat
+ if (!Loc) {
+ // We don't have a mapping, and we don't know if the struct is recursive
+ // so we create an empty one and hypothesize that it is the
+ // mapping.
+ Loc = StructType::create(Ctx, StructTy->getStructName());
+ } else {
+ // we either have a finished mapping or this is the empty placeholder
+ // created above, and we are in the process of finalizing it.
+ // 1) if this is a mapping, it must have the same element count
+ // as the original struct, so we mark a change if the types are
+ // different objects
+ // 2) if this is a placeholder, the element count will differ.
+ // Since we don't know yet if this is a change or not - because we
+ // are constructing the mapping - we don't mark as change. We decide
+ // if it is a change below, based on the other struct elements.
+ bool hasChanged =
+ StructTy != Loc &&
+ StructTy->getStructNumElements() == Loc->getStructNumElements();
+ return MappingResult(Loc, hasChanged);
+ }
+ }
+
+ SmallVector<Type*, 8> ElemTypes;
JF 2015/03/08 22:04:38 TypicalArity?
Mircea Trofin 2015/03/09 21:21:29 Only I meant TypicalArity to be for functions :) B
+ bool HasChanges = false;
+ for (unsigned I = 0; I < Ty->getStructNumElements(); I++) {
JF 2015/03/08 22:04:38 I'd cache getStructNumElements. It's not expensive
Mircea Trofin 2015/03/09 21:21:29 Done.
+ auto NewElem =
+ getCompliantAggregateTypeInternal(
+ Ty->getStructElementType(I));
+ ElemTypes.push_back(NewElem);
+ HasChanges |= NewElem.isChanged();
+ }
+ if (!HasChanges) {
+ // we are leaking the created struct here, but there is no way to
+ // correctly delete it
JF 2015/03/08 22:04:38 Missing period
+ return MappingResult(MappedTypes[Ty] = Ty, false);
+ }
+
+ if (StructTy->isLiteral()) {
+ return MappingResult(
+ MappedTypes[Ty] = StructType::get(
+ Ctx, ElemTypes, StructTy->isPacked()),
+ HasChanges);
+ } else {
+ Type* &Loc = MappedTypes[StructTy];
JF 2015/03/08 22:04:38 Ditto on ptr ref.
Mircea Trofin 2015/03/09 21:21:29 Ack, but see the comment before.
+ assert(Loc);
+ StructType *NewStruct = dyn_cast<StructType>(Loc);
+ NewStruct->setBody(ElemTypes, StructTy->isPacked());
+ return MappingResult(MappedTypes[Ty] = NewStruct, true);
+ }
+ }
+
+ // anything else stays the same.
+ return MappingResult(Ty, false);
+}
+
+// get the PNaCl-compliant type of a function argument.
+MappingResult TypeMapper::getCompliantArgumentType(Type *Ty) {
+ // struct registers become pointers to compliant structs
+ if (Ty->isAggregateType()) {
+ return MappingResult(
+ PointerType::get(
+ getCompliantAggregateTypeInternal(Ty), 0),
+ true);
+ }
+
+ return getCompliantAggregateTypeInternal(Ty);
+}
+
+// apply 'byval' to func arguments that used to be struct regs.
+// apply 'sret' to the argument corresponding to the return in the old signature
+static void ApplyByValAndSRet(Function *OldFunc, Function *NewFunc) {
+ auto const &OldArgList = OldFunc->getArgumentList();
+ auto &NewArgList = NewFunc->getArgumentList();
+
+ // when calling addAttribute, the first one refers to the function, so we
+ // skip past that.
+ unsigned ArgOffset = 1;
+ if (OldFunc->getReturnType()->isAggregateType()) {
+ NewFunc->addAttribute(1, Attribute::AttrKind::StructRet);
+ ArgOffset++;
+ }
+
+ auto NewArg = NewArgList.begin();
+ for (const Argument &OldArg : OldArgList) {
+ if (OldArg.getType()->isAggregateType()) {
+ NewFunc->addAttribute(NewArg->getArgNo() + ArgOffset,
+ Attribute::AttrKind::ByVal);
+ }
+ NewArg++;
+ }
+}
+
+// update the arg names for a newly created function
+static void UpdateArgNames(Function *OldFunc, Function *NewFunc) {
+ auto NewArgIter = NewFunc->arg_begin();
+ auto const &OldFuncArgs = OldFunc->args();
+ if (OldFunc->getReturnType()->isAggregateType()) {
+ NewArgIter->setName("retVal");
+ NewArgIter++;
+ }
+
+ for (const Argument &OldArg : OldFuncArgs) {
+ Argument *NewArg = NewArgIter++;
+ if (OldArg.getType()->isAggregateType()) {
+ NewArg->setName(OldArg.getName() + ".ptr");
+ } else {
+ NewArg->setName(OldArg.getName());
+ }
+ }
+}
+
+// replace all uses of an old value with a new one, disregarding the type. We
+// correct the types separately
+static void BlindReplace(Value *Old, Value *New) {
+ for (auto UseIter = Old->use_begin(), E = Old->use_end(); E != UseIter;) {
+ Use &AUse = *(UseIter++);
+ AUse.set(New);
+ }
+}
+
+// adapt the body of a function for the new arguments
+static void ConvertArgumentValue(Value *Old,
+ Value *New, Instruction *InsPoint) {
+ if (Old == New)
+ return;
+
+ if (Old->getType() == New->getType()) {
+ Old->replaceAllUsesWith(New);
+ New->takeName(Old);
+ return;
+ }
+
+ if (Old->getType()->isAggregateType() &&
+ New->getType()->isPointerTy()) {
+ Value *Load = new LoadInst(New, Old->getName() + ".sreg", InsPoint);
+ BlindReplace(Old, Load);
+ } else {
+ BlindReplace(Old, New);
+ }
+}
+
+// fix returns. Return true if fixes were needed
+static void FixReturn(Function *OldFunc, Function *NewFunc) {
+
+ Argument *FirstNewArg = NewFunc->getArgumentList().begin();
+
+ for (auto BIter = NewFunc->begin(), LastBlock = NewFunc->end();
+ LastBlock != BIter;) {
+ BasicBlock *BB = BIter++;
+ for (auto IIter = BB->begin(), LastI = BB->end(); LastI != IIter;) {
+ Instruction *Instr = IIter++;
+ if (ReturnInst * Ret = dyn_cast<ReturnInst>(Instr)) {
+ auto &Ctx = Ret->getContext();
+ auto RetVal = Ret->getReturnValue();
+ ReturnInst *NewRet =
+ ReturnInst::Create(Ctx, nullptr, Ret);
+ Ret->eraseFromParent();
+ Ret = nullptr;
+ new StoreInst(RetVal, FirstNewArg, NewRet);
+ }
+ }
+ }
+}
+
+template <class TCall>
+void CopyCallAttributesAndMetadata(TCall* Orig, TCall* NewCall) {
+ NewCall->setCallingConv(Orig->getCallingConv());
+ NewCall->setAttributes(
+ NewCall->getAttributes().addAttributes(Orig->getContext(),
+ AttributeSet::FunctionIndex,
+ Orig->getAttributes().getFnAttributes()));
+ NewCall->setDebugLoc(Orig->getDebugLoc());
+}
+
+static InvokeInst *CreateCallFrom(InvokeInst *Orig,
+ Value *Target, ArrayRef<Value*> &Args) {
+ InvokeInst *Ret = InvokeInst::Create(Target,
+ Orig->getNormalDest(), Orig->getUnwindDest(), Args);
+ CopyCallAttributesAndMetadata(Orig, Ret);
+ return Ret;
+}
+
+static CallInst *CreateCallFrom(CallInst *Orig,
+ Value *Target, ArrayRef<Value*> &Args) {
+
+ CallInst *Ret = CallInst::Create(Target, Args);
+
+ Ret->setTailCallKind(Orig->getTailCallKind());
+ CopyCallAttributesAndMetadata(Orig, Ret);
+ return Ret;
+}
+
+// fix a call site by handing return type changes and/or parameter type and
+// attribute changes
+template<class TCall>
+void NormalizeStructRegSignatures::FixCallSite(TCall *OldCall) {
+ Value *NewTarget = OldCall->getCalledValue();
+
+ if (Function * CalledFunc = dyn_cast<Function>(NewTarget)) {
+ NewTarget = this->FunctionMap[CalledFunc];
+ }
+ assert(NewTarget);
+
+ FunctionType *NewType =
+ dyn_cast<FunctionType>(
+ Mapper.getCompliantType(NewTarget->getType())->
+ getPointerElementType());
+
+ Type *OldRetType = OldCall->getType();
+ const bool isSRet = !OldCall->getType()->isVoidTy() &&
+ NewType->getReturnType()->isVoidTy();
+
+ const unsigned argOffset = isSRet ? 1 : 0;
+
+ SmallVector<Value*, TypicalArity> NewArgs;
+
+ if (isSRet) {
+ AllocaInst *Alloca =
+ new AllocaInst(OldRetType);
+ NewArgs.push_back(Alloca);
+ Alloca->insertBefore(OldCall);
+
+ LoadInst *Load =
+ new LoadInst(Alloca, OldCall->getName() + ".sreg",
+ (Instruction*) nullptr);
+ Load->insertAfter(OldCall);
+ OldCall->replaceAllUsesWith(Load);
+ }
+
+ SmallSetVector<unsigned, TypicalArity> ByRefPlaces;
+
+ for (unsigned ArgPos = 0;
+ ArgPos < NewType->getFunctionNumParams() - argOffset; ArgPos++) {
+
+ Use &OldArgUse = OldCall->getOperandUse(ArgPos);
+ Value *OldArg = OldArgUse;
+ Type *OldArgType = OldArg->getType();
+ unsigned NewArgPos = OldArgUse.getOperandNo() + argOffset;
+ Type *NewArgType = NewType->getFunctionParamType(NewArgPos);
+
+ if (OldArgType != NewArgType && OldArgType->isAggregateType()) {
+ AllocaInst *Alloca =
+ new AllocaInst(OldArgType, OldArg->getName() + ".ptr", OldCall);
+ new StoreInst(OldArg, Alloca, OldCall);
+ ByRefPlaces.insert(NewArgPos);
+ NewArgs.push_back(Alloca);
+ } else {
+ NewArgs.push_back(OldArg);
+ }
+ }
+
+ ArrayRef<Value*> ArrRef = NewArgs;
+ TCall *NewCall = CreateCallFrom(OldCall, NewTarget, ArrRef);
+
+ // copy the attributes over, and add byref/sret as necessary
+ const AttributeSet &OldAttrSet = OldCall->getAttributes();
+ const AttributeSet &NewAttrSet = NewCall->getAttributes();
+ LLVMContext &Ctx = OldCall->getContext();
+ AttrBuilder Builder(OldAttrSet, 0);
+
+ for (unsigned I = 0; I < NewCall->getNumArgOperands(); I++) {
+ NewCall->setAttributes(
+ NewAttrSet.addAttributes(Ctx, I + argOffset + 1,
+ OldAttrSet.getParamAttributes(I + 1)));
+ if (ByRefPlaces.count(I)) {
+ NewCall->addAttribute(I + 1, Attribute::AttrKind::ByVal);
+ }
+ }
+
+ if (isSRet) {
+ NewAttrSet.addAttributes(Ctx, 1, OldAttrSet.getRetAttributes());
+ NewCall->addAttribute(1, Attribute::AttrKind::StructRet);
+ } else {
+ NewCall->setAttributes(
+ NewAttrSet.addAttributes(Ctx,
+ AttributeSet::ReturnIndex, OldAttrSet.getRetAttributes()));
+ // if we still return something, this is the value to replace the old
+ // call with
+ OldCall->replaceAllUsesWith(NewCall);
+ }
+
+ NewCall->insertBefore(OldCall);
+ OldCall->eraseFromParent();
+ OldCall = NULL;
+}
+
+void NormalizeStructRegSignatures::ScheduleCallsForCleanup(Function *NewFunc) {
+ for (auto &BBIter : NewFunc->getBasicBlockList()) {
+ for (auto &IIter : BBIter.getInstList()) {
+ if (CallInst * Call = dyn_cast<CallInst>(&IIter)) {
+ CallsToPatch.insert(Call);
+ } else if (InvokeInst * Invoke = dyn_cast<InvokeInst>(&IIter)) {
+ InvokesToPatch.insert(Invoke);
+ }
+ }
+ }
+}
+
+// change function body in the light of type changes
+void NormalizeStructRegSignatures::
+FixFunctionBody(Function *OldFunc, Function *NewFunc) {
+ if (NewFunc->empty())
+ return;
+
+ bool returnWasFixed = OldFunc->getReturnType()->isAggregateType();
+
+ Instruction *InsPoint = NewFunc->begin()->begin();
+ auto NewArgIter = NewFunc->arg_begin();
+ // advance one more if we used to return a struct register
+ if (returnWasFixed)
+ NewArgIter++;
+
+ // wire new parameters in
+ for (auto ArgIter = OldFunc->arg_begin(), E = OldFunc->arg_end();
+ E != ArgIter;) {
+ Argument *OldArg = ArgIter++;
+ Argument *NewArg = NewArgIter++;
+ ConvertArgumentValue(OldArg, NewArg, InsPoint);
+ }
+
+ // now fix instruction types. Calls are dealt with separately, but we still
+ // update the types here. We know that each value could only possibly be
+ // of a compliant type. At the end of this, call sites will be invalid, but
+ // we handle that afterwards, to make sure we have all the functions changed
+ // first (so that calls have valid targets)
+ for (auto BBIter = NewFunc->begin(), LBlock = NewFunc->end();
+ LBlock != BBIter;) {
+ auto Block = BBIter++;
+ for (auto IIter = Block->begin(), LIns = Block->end(); LIns != IIter;) {
+ auto Instr = IIter++;
+ Instr->mutateType(Mapper.getCompliantType(Instr->getType()));
+ }
+ }
+ if (returnWasFixed)
+ FixReturn(OldFunc, NewFunc);
+}
+
+// Ensure function is PNaCl compliant, returning true if the function
+// changed.
+bool NormalizeStructRegSignatures::
+ensurePNaClComplyingFunction(Function *OldFunc, Module &M) {
+ FunctionType *OldFT = OldFunc->getFunctionType();
+ FunctionType *NewFT =
+ dyn_cast<FunctionType>(Mapper.getCompliantType(OldFT));
+ assert(NewFT);
+
+ Function* &AssociatedFctLoc = FunctionMap[OldFunc];
+ if (NewFT != OldFT) {
+ Function *NewFunc = Function::Create(NewFT, OldFunc->getLinkage());
+ AssociatedFctLoc = NewFunc;
+
+ NewFunc->copyAttributesFrom(OldFunc);
+ OldFunc->getParent()->getFunctionList().insert(OldFunc, NewFunc);
+ NewFunc->takeName(OldFunc);
+
+ UpdateArgNames(OldFunc, NewFunc);
+ ApplyByValAndSRet(OldFunc, NewFunc);
+
+ NewFunc->getBasicBlockList().
+ splice(NewFunc->begin(), OldFunc->getBasicBlockList());
+
+ FixFunctionBody(OldFunc, NewFunc);
+ FunctionsToDelete.insert(OldFunc);
+ } else {
+ AssociatedFctLoc = OldFunc;
+ }
+ ScheduleCallsForCleanup(AssociatedFctLoc);
+ return NewFT != OldFT;
+}
+
+bool NormalizeStructRegSignatures::runOnModule(Module &M) {
+ bool Changed = false;
+
+ // change function signatures and fix a changed function body by
+ // wiring the new arguments. Call sites are unchanged at this point
+ for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E;) {
+ Function *Func = Iter++;
+ Changed |= ensurePNaClComplyingFunction(Func, M);
+ }
+
+ // fix call sites
+ for (auto &CallToFix : CallsToPatch) {
+ FixCallSite(CallToFix);
+ }
+
+ for (auto &InvokeToFix : InvokesToPatch) {
+ FixCallSite(InvokeToFix);
+ }
+
+ // delete leftover functions - the ones with old signatures
+ for (auto &ToDelete : FunctionsToDelete) {
+ // this also frees the memory
+ ToDelete->eraseFromParent();
+ }
+ return Changed;
+}
+
+ModulePass *llvm::createNormalizeStructRegSignaturesPass() {
+ return new NormalizeStructRegSignatures();
+}

Powered by Google App Engine
This is Rietveld 408576698