diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -1855,6 +1855,10 @@ /// static void createShallowWrapper(Function &F); + /// Returns true if the function \p F can be internalized. i.e. it has a + /// compatible linkage. + static bool isInternalizable(Function &F); + /// Make another copy of the function \p F such that the copied version has /// internal linkage afterwards and can be analysed. Then we replace all uses /// of the original function to the copied one @@ -1870,6 +1874,20 @@ /// null pointer. static Function *internalizeFunction(Function &F, bool Force = false); + /// Make copies of each function in the set \p FnSet such that the copied + /// version has / internal linkage afterwards and can be analysed. Then we + /// replace all uses / of the original function to the copied one. + /// + /// Only non-locally linked functions that have `linkonce_odr` or `weak_odr` + /// linkage can be internalized because these linkages guarantee that other + /// definitions with the same name have the same semantics as this one. + /// + /// This version will internalize all the functions in the set \p FnSet at + /// once and then replace the uses. This prevents internalized functions being + /// called by external functions when there is an internalized version in the + /// module. + static bool internalizeFunctions(SmallPtrSetImpl &FnSet); + /// Return the data layout associated with the anchor scope. const DataLayout &getDataLayout() const { return InfoCache.DL; } diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -1925,49 +1925,87 @@ NumFnShallowWrappersCreated++; } +bool Attributor::isInternalizable(Function &F) { + if (F.isDeclaration() || F.hasLocalLinkage() || + GlobalValue::isInterposableLinkage(F.getLinkage())) + return false; + return true; +} + Function *Attributor::internalizeFunction(Function &F, bool Force) { if (!AllowDeepWrapper && !Force) return nullptr; - if (F.isDeclaration() || F.hasLocalLinkage() || - GlobalValue::isInterposableLinkage(F.getLinkage())) + if (!isInternalizable(F)) return nullptr; - Module &M = *F.getParent(); - FunctionType *FnTy = F.getFunctionType(); - - // create a copy of the current function - Function *Copied = Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), - F.getName() + ".internalized"); - ValueToValueMapTy VMap; - auto *NewFArgIt = Copied->arg_begin(); - for (auto &Arg : F.args()) { - auto ArgName = Arg.getName(); - NewFArgIt->setName(ArgName); - VMap[&Arg] = &(*NewFArgIt++); - } - SmallVector Returns; + SmallPtrSet FnSet = {&F}; + internalizeFunctions(FnSet); - // Copy the body of the original function to the new one - CloneFunctionInto(Copied, &F, VMap, CloneFunctionChangeType::LocalChangesOnly, - Returns); - - // Set the linakage and visibility late as CloneFunctionInto has some implicit - // requirements. - Copied->setVisibility(GlobalValue::DefaultVisibility); - Copied->setLinkage(GlobalValue::PrivateLinkage); + Twine InternalizedName = F.getName() + ".internalized"; + return F.getParent()->getFunction(InternalizedName.str()); +} - // Copy metadata - SmallVector, 1> MDs; - F.getAllMetadata(MDs); - for (auto MDIt : MDs) - if (!Copied->hasMetadata()) - Copied->addMetadata(MDIt.first, *MDIt.second); +bool Attributor::internalizeFunctions(SmallPtrSetImpl &FnSet) { + for (Function *F : FnSet) + if (!Attributor::isInternalizable(*F)) + return false; - M.getFunctionList().insert(F.getIterator(), Copied); - F.replaceAllUsesWith(Copied); - Copied->setDSOLocal(true); + DenseMap InternalizedFns; + + // Generate the internalized version of each function. + for (Function *F : FnSet) { + Module &M = *F->getParent(); + Function *&InternalizedFn = InternalizedFns[F]; + FunctionType *FnTy = F->getFunctionType(); + + // Create a copy of the current function + Function *Copied = + Function::Create(FnTy, F->getLinkage(), F->getAddressSpace(), + F->getName() + ".internalized"); + ValueToValueMapTy VMap; + auto *NewFArgIt = Copied->arg_begin(); + for (auto &Arg : F->args()) { + auto ArgName = Arg.getName(); + NewFArgIt->setName(ArgName); + VMap[&Arg] = &(*NewFArgIt++); + } + SmallVector Returns; + + // Copy the body of the original function to the new one + CloneFunctionInto(Copied, F, VMap, + CloneFunctionChangeType::LocalChangesOnly, Returns); + + // Set the linakage and visibility late as CloneFunctionInto has some + // implicit requirements. + Copied->setVisibility(GlobalValue::DefaultVisibility); + Copied->setLinkage(GlobalValue::PrivateLinkage); + + // Copy metadata + SmallVector, 1> MDs; + F->getAllMetadata(MDs); + for (auto MDIt : MDs) + if (!Copied->hasMetadata()) + Copied->addMetadata(MDIt.first, *MDIt.second); + + M.getFunctionList().insert(F->getIterator(), Copied); + InternalizedFn = Copied; + } + + // Replace all uses of the old function with the new internalized function + // unless the caller is a function that was just internalized. + for (Function *F : FnSet) { + auto &InternalizedFn = InternalizedFns[F]; + auto IsNotInternalized = [&](Use &U) -> bool { + if (auto *CB = dyn_cast(U.getUser())) + if (!InternalizedFns[CB->getCaller()]) + return true; + return false; + }; + F->replaceUsesWithIf(InternalizedFn, IsNotInternalized); + InternalizedFn->setDSOLocal(true); + } - return Copied; + return true; } bool Attributor::isValidFunctionSignatureRewrite( diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -4157,17 +4157,21 @@ // Create internal copies of each function if this is a kernel Module. This // allows iterprocedural passes to see every call edge. - DenseSet InternalizedFuncs; - if (isOpenMPDevice(M)) - for (Function &F : M) + SmallPtrSet InternalizedFuncs; + if (isOpenMPDevice(M)) { + for (Function &F : M) { if (!F.isDeclaration() && !Kernels.contains(&F) && IsCalled(F) && !DisableInternalization) { - if (Attributor::internalizeFunction(F, /* Force */ true)) { + if (Attributor::isInternalizable(F)) { InternalizedFuncs.insert(&F); } else if (!F.hasLocalLinkage() && !F.hasFnAttribute(Attribute::Cold)) { EmitRemark(F); } } + } + + Attributor::internalizeFunctions(InternalizedFuncs); + } // Look at every function in the Module unless it was internalized. SmallVector SCC;