Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -57,6 +57,9 @@ "Number of function with exact definitions"); STATISTIC(NumFnWithoutExactDefinition, "Number of function without exact definitions"); +STATISTIC(NumFnShallowWrapperCreated, "Number of shallow wrappers created"); +STATISTIC(NumAttrsRequiredDeepWrapper, + "Number of non-trivial attributes requiring a deep wrapper"); STATISTIC(NumAttributesTimedOut, "Number of abstract attributes timed out before fixpoint"); STATISTIC(NumAttributesValidFixpoint, @@ -184,6 +187,12 @@ static cl::opt MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128), cl::Hidden); +static cl::opt + AllowShallowWrappers("attributor-allow-shallow-wrappers", cl::Hidden, + cl::desc("Allow the Attributor to create shallow " + "wrappers for non-exact definitions."), + cl::init(false)); + /// Logic operators for the change status enum class. /// ///{ @@ -724,7 +733,6 @@ return HasAttr; } - void IRPosition::verify() { switch (KindOrArgNo) { default: @@ -5633,7 +5641,7 @@ createReplacementValues( PrivatizableType.getValue(), ACS, ACS.getCallArgOperand(ARI.getReplacedArg().getArgNo()), - NewArgOperands); + NewArgOperands); }; // Collect the types that will replace the privatizable type in the function @@ -8025,6 +8033,63 @@ return ManifestChange; } +/// Create a shallow wrapper for \p F such that \p F has internal linkage +/// afterwards. It also sets the original \p F 's name to anonymous +/// +/// A wrapper is a function with the same type (and attributes) as \p F +/// that will only call \p F and return the result, if any. +/// +/// Assuming the declaration of looks like: +/// rty F(aty0 arg0, ..., atyN argN); +/// +/// The wrapper will then look as follows: +/// rty wrapper(aty0 arg0, ..., atyN argN) { +/// return F(arg0, ..., argN); +/// } +/// +static void createShallowWrapper(Function &F) { + assert(!F.isDeclaration() && "Cannot create a wrapper around a declaration!"); + + Module &M = *F.getParent(); + LLVMContext &Ctx = M.getContext(); + FunctionType *FnTy = F.getFunctionType(); + + Function *Wrapper = + Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), F.getName()); + F.setName(""); // set the inside function anonymous + M.getFunctionList().insert(F.getIterator(), Wrapper); + + F.setLinkage(GlobalValue::InternalLinkage); + + // Move the COMDAT section to the wrapper. + // TODO: Check if we need to keep it for F as well. + Wrapper->setComdat(F.getComdat()); + F.setComdat(nullptr); + + // Copy all metadata and attributes but keep them on F as well. + SmallVector, 1> MDs; + F.getAllMetadata(MDs); + for (auto MDIt : MDs) + Wrapper->addMetadata(MDIt.first, *MDIt.second); + Wrapper->setAttributes(F.getAttributes()); + + // Create the call in the wrapper. + BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Wrapper); + + SmallVector Args; + auto FArgIt = F.arg_begin(); + for (Argument &Arg : Wrapper->args()) { + Args.push_back(&Arg); + Arg.setName((FArgIt++)->getName()); + } + + CallInst *CI = CallInst::Create(&F, Args, "", EntryBB); + CI->setTailCall(true); + ReturnInst::Create(Ctx, CI->getType()->isVoidTy() ? nullptr : CI, EntryBB); + + NumFnShallowWrapperCreated++; +} + bool Attributor::isValidFunctionSignatureRewrite( Argument &Arg, ArrayRef ReplacementTypes) { @@ -8650,6 +8715,12 @@ for (Function *F : Functions) A.initializeInformationCache(*F); + // Create shallow wrappers for all functions that are not IPO amendable + if (AllowShallowWrappers) + for (Function *F : Functions) + if (!A.isFunctionIPOAmendable(*F)) + createShallowWrapper(*F); + for (Function *F : Functions) { if (F->hasExactDefinition()) NumFnWithExactDefinition++;