34 #include <sys/types.h>
42 #include <llvm-c/Core.h>
43 #include <llvm-c/BitReader.h>
48 #include <llvm/ADT/SetVector.h>
49 #include <llvm/ADT/StringSet.h>
50 #include <llvm/ADT/StringMap.h>
51 #include <llvm/Analysis/ModuleSummaryAnalysis.h>
52 #include <llvm/Bitcode/BitcodeReader.h>
53 #include <llvm/IR/Attributes.h>
54 #include <llvm/IR/DebugInfo.h>
55 #include <llvm/IR/IntrinsicInst.h>
56 #include <llvm/IR/IRBuilder.h>
57 #include <llvm/IR/ModuleSummaryIndex.h>
58 #include <llvm/Linker/IRMover.h>
59 #include <llvm/Support/ManagedStatic.h>
60 #include <llvm/Support/MemoryBuffer.h>
75 llvm::SmallVector<llvm::ModuleSummaryIndex *, 2>
searchpath;
106 typedef llvm::StringMap<std::unique_ptr<llvm::Module> >
ModuleCache;
108 typedef llvm::StringMap<std::unique_ptr<llvm::ModuleSummaryIndex> >
SummaryCache;
117 static std::unique_ptr<llvm::Module>
load_module(LLVMContextRef
c, llvm::StringRef Identifier);
118 static std::unique_ptr<llvm::ModuleSummaryIndex>
llvm_load_summary(llvm::StringRef path);
123 llvm::StringRef
Name);
130 llvm::SmallPtrSet<const llvm::Function *, 8> &visitedFunctions,
131 int &running_instcount,
132 llvm::StringSet<> &importVars);
134 int &running_instcount,
135 llvm::SmallPtrSet<llvm::GlobalVariable *, 8> &referencedVars,
136 llvm::SmallPtrSet<llvm::Function *, 8> &referencedFunctions);
139 static llvm::SmallVector<llvm::GlobalValueSummary *, 1>
147 #define ilog(...) (void) 0
169 LLVMContextRef lc = LLVMGetModuleContext(M);
170 llvm::Module *mod = llvm::unwrap(M);
173 if (!globalsToInline)
182 static std::unique_ptr<ImportMapTy>
185 std::unique_ptr<ImportMapTy> globalsToInline(
new ImportMapTy());
194 if (defaultSearchPath.empty())
203 for (
const llvm::Function &funcDecl : mod->functions())
209 if (!funcDecl.isDeclaration())
213 if (funcDecl.isIntrinsic())
218 worklist.push_back(item);
223 functionStates[funcDecl.getName()] = inlineState;
230 while (!worklist.empty())
237 llvm::GlobalValue::GUID funcGUID;
241 funcGUID = llvm::GlobalValue::getGUID(cfuncname);
258 const llvm::FunctionSummary *fs;
259 llvm::StringRef modPath = gvs->modulePath();
260 llvm::Module *defMod;
261 llvm::Function *funcDef;
263 fs = llvm::cast<llvm::FunctionSummary>(gvs);
265 if (gvs->notEligibleToImport())
267 ilog(
DEBUG1,
"ineligibile to import %s due to summary",
272 if ((
int) fs->instCount() > inlineState.
costLimit)
274 ilog(
DEBUG1,
"ineligibile to import %s due to early threshold: %u vs %u",
275 symbolName.data(), fs->instCount(), inlineState.
costLimit);
281 if (defMod->materializeMetadata())
282 elog(
FATAL,
"failed to materialize metadata");
284 funcDef = defMod->getFunction(cfuncname);
293 if (funcDef->materialize())
294 elog(
FATAL,
"failed to materialize metadata");
296 Assert(!funcDef->isDeclaration());
297 Assert(funcDef->hasExternalLinkage());
299 llvm::StringSet<> importVars;
300 llvm::SmallPtrSet<const llvm::Function *, 8> visitedFunctions;
301 int running_instcount = 0;
323 if (running_instcount > inlineState.
costLimit)
325 ilog(
DEBUG1,
"skipping inlining of %s due to late threshold %d vs %d",
326 symbolName.data(), running_instcount, inlineState.
costLimit);
331 ilog(
DEBUG1,
"inline top function %s total_instcount: %d, partial: %d",
332 symbolName.data(), running_instcount, fs->instCount());
335 importVars.insert(symbolName);
338 llvm::StringSet<> &modGlobalsToInline = (*globalsToInline)[modPath];
339 for (
auto& importVar : importVars)
340 modGlobalsToInline.insert(importVar.first());
341 Assert(modGlobalsToInline.size() > 0);
369 return globalsToInline;
379 llvm::IRMover Mover(*mod);
381 for (
const auto& toInline : *globalsToInline)
383 const llvm::StringRef& modPath = toInline.first();
384 const llvm::StringSet<>& modGlobalsToInline = toInline.second;
385 llvm::SetVector<llvm::GlobalValue *> GlobalsToImport;
388 std::unique_ptr<llvm::Module> importMod(std::move((*
module_cache)[modPath]));
391 if (modGlobalsToInline.empty())
394 for (
auto &glob: modGlobalsToInline)
396 llvm::StringRef SymbolName = glob.first();
402 llvm::GlobalValue *valueToImport = importMod->getNamedValue(
funcname);
405 elog(
FATAL,
"didn't refind value %s to import", SymbolName.data());
413 if (llvm::isa<llvm::Function>(valueToImport))
415 llvm::Function *
F = llvm::dyn_cast<llvm::Function>(valueToImport);
416 typedef llvm::GlobalValue::LinkageTypes LinkageTypes;
422 llvm::stripDebugInfo(*
F);
438 GlobalsToImport.insert(AF);
439 llvm::stripDebugInfo(*AF);
442 if (valueToImport->hasExternalLinkage())
444 valueToImport->setLinkage(LinkageTypes::AvailableExternallyLinkage);
448 GlobalsToImport.insert(valueToImport);
450 modPath.data(), SymbolName.data());
454 if (Mover.move(std::move(importMod), GlobalsToImport.getArrayRef(),
455 [](llvm::GlobalValue &, llvm::IRMover::ValueAdder) {},
457 elog(
FATAL,
"function import failed with linker error");
474 std::make_pair(modPath,
load_module(lc, modPath))).first;
477 return it->second.get();
480 static std::unique_ptr<llvm::Module>
483 LLVMMemoryBufferRef
buf;
490 if (LLVMCreateMemoryBufferWithContentsOfFile(path, &
buf, &msg))
491 elog(
FATAL,
"failed to open bitcode file \"%s\": %s",
493 if (LLVMGetBitcodeModuleInContext2(lc,
buf, &mod))
494 elog(
FATAL,
"failed to parse bitcode in file \"%s\"", path);
501 llvm::StripDebugInfo(*llvm::unwrap(mod));
503 return std::unique_ptr<llvm::Module>(llvm::unwrap(mod));
512 int &running_instcount,
513 llvm::SmallPtrSet<llvm::GlobalVariable *, 8> &referencedVars,
514 llvm::SmallPtrSet<llvm::Function *, 8> &referencedFunctions)
516 llvm::SmallPtrSet<const llvm::User *, 32> Visited;
518 for (llvm::BasicBlock &BB :
F)
520 for (llvm::Instruction &
I : BB)
522 if (llvm::isa<llvm::DbgInfoIntrinsic>(
I))
525 llvm::SmallVector<llvm::User *, 8> Worklist;
526 Worklist.push_back(&
I);
530 while (!Worklist.empty()) {
531 llvm::User *U = Worklist.pop_back_val();
534 if (!Visited.insert(U).second)
537 for (
auto &OI : U->operands()) {
538 llvm::User *Operand = llvm::dyn_cast<llvm::User>(OI);
541 if (llvm::isa<llvm::BlockAddress>(Operand))
543 if (
auto *GV = llvm::dyn_cast<llvm::GlobalVariable>(Operand)) {
544 referencedVars.insert(GV);
545 if (GV->hasInitializer())
546 Worklist.push_back(GV->getInitializer());
549 if (
auto *CF = llvm::dyn_cast<llvm::Function>(Operand)) {
550 referencedFunctions.insert(CF);
553 Worklist.push_back(Operand);
573 llvm::SmallPtrSet<const llvm::Function *, 8> &visitedFunctions,
574 int &running_instcount,
575 llvm::StringSet<> &importVars)
578 llvm::SmallPtrSet<llvm::GlobalVariable *, 8> referencedVars;
579 llvm::SmallPtrSet<llvm::Function *, 8> referencedFunctions;
582 if (
F.isInterposable())
589 if (
F.hasAvailableExternallyLinkage())
592 ilog(
DEBUG1,
"checking inlinability of %s",
F.getName().data());
595 elog(
FATAL,
"failed to materialize metadata");
597 if (
F.getAttributes().hasFnAttr(llvm::Attribute::NoInline))
599 ilog(
DEBUG1,
"ineligibile to import %s due to noinline",
606 for (llvm::GlobalVariable* rv: referencedVars)
608 if (rv->materialize())
609 elog(
FATAL,
"failed to materialize metadata");
615 if (rv->isThreadLocal())
617 ilog(
DEBUG1,
"cannot inline %s due to thread-local variable %s",
618 F.getName().data(), rv->getName().data());
626 if (rv->hasExternalLinkage() || rv->hasAvailableExternallyLinkage())
637 if (!rv->isConstant())
639 ilog(
DEBUG1,
"cannot inline %s due to uncloneable variable %s",
640 F.getName().data(), rv->getName().data());
644 ilog(
DEBUG1,
"memorizing global var %s linkage %d for inlining",
645 rv->getName().data(), (
int)rv->getLinkage());
647 importVars.insert(rv->getName());
649 running_instcount += 5;
652 visitedFunctions.insert(&
F);
658 for (llvm::Function* referencedFunction: referencedFunctions)
660 llvm::StringSet<> recImportVars;
662 if (referencedFunction->materialize())
663 elog(
FATAL,
"failed to materialize metadata");
665 if (referencedFunction->isIntrinsic())
669 if (!visitedFunctions.insert(referencedFunction).second)
677 if (referencedFunction->hasExternalLinkage())
679 llvm::StringRef funcName = referencedFunction->getName();
685 if (subThreshold < 5)
688 auto it = functionStates.find(funcName);
689 if (it == functionStates.end())
698 functionStates[funcName] = inlineState;
699 worklist.push_back({funcName, searchpath});
702 "considering extern function %s at %d for inlining",
703 funcName.data(), subThreshold);
705 else if (!it->second.inlined &&
706 (!it->second.processed || it->second.allowReconsidering) &&
707 it->second.costLimit < subThreshold)
714 if (it->second.processed)
717 "reconsidering extern function %s at %d for inlining, increasing from %d",
718 funcName.data(), subThreshold, it->second.costLimit);
720 it->second.processed =
false;
721 it->second.allowReconsidering =
false;
722 worklist.push_back({funcName, searchpath});
724 it->second.costLimit = subThreshold;
730 if (referencedFunction->isInterposable())
743 "cannot inline %s due to required function %s not being inlinable",
744 F.getName().data(), referencedFunction->getName().data());
749 importVars.insert(referencedFunction->getName());
752 for (
auto& recImportVar : recImportVars)
753 importVars.insert(recImportVar.first());
763 static std::unique_ptr<llvm::ModuleSummaryIndex>
766 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer> > MBOrErr =
767 llvm::MemoryBuffer::getFile(path);
769 if (std::error_code EC = MBOrErr.getError())
771 ilog(
DEBUG1,
"failed to open %s: %s", path.data(),
772 EC.message().c_str());
776 llvm::MemoryBufferRef ref(*MBOrErr.get().get());
778 llvm::Expected<std::unique_ptr<llvm::ModuleSummaryIndex> > IndexOrErr =
779 llvm::getModuleSummaryIndex(ref);
781 return std::move(IndexOrErr.get());
782 elog(
FATAL,
"failed to load summary \"%s\": %s",
784 toString(IndexOrErr.takeError()).c_str());
796 #if LLVM_VERSION_MAJOR < 16
797 #define starts_with startswith
799 if (!modpath.starts_with(
"$libdir/"))
817 searchpath.push_back(it->second.get());
824 static llvm::SmallVector<llvm::GlobalValueSummary *, 1>
827 llvm::SmallVector<llvm::GlobalValueSummary *, 1> matches;
829 for (
auto index : path)
831 llvm::ValueInfo funcVI =
index->getValueInfo(guid);
835 for (
auto &gv : funcVI.getSummaryList())
836 matches.push_back(gv.get());
845 static llvm::Function*
848 llvm::StringRef
Name)
850 typedef llvm::GlobalValue::LinkageTypes LinkageTypes;
852 llvm::LLVMContext &Context =
F->getContext();
853 llvm::IRBuilder<> Builder(Context);
855 llvm::BasicBlock *BB;
856 llvm::CallInst *fwdcall;
858 AF = llvm::Function::Create(
F->getFunctionType(),
859 LinkageTypes::AvailableExternallyLinkage,
860 Name, importMod.get());
861 BB = llvm::BasicBlock::Create(Context,
"entry", AF);
863 Builder.SetInsertPoint(BB);
864 fwdcall = Builder.CreateCall(
F, &*AF->arg_begin());
865 fwdcall->addFnAttr(llvm::Attribute::AlwaysInline);
866 Builder.CreateRet(fwdcall);
#define Assert(condition)
char pkglib_path[MAXPGPATH]
void llvm_split_symbol_name(const char *name, char **modname, char **funcname)
void llvm_inline(LLVMModuleRef M)
llvm::SmallVector< InlineWorkListItem, 128 > InlineWorkList
const int inline_initial_cost
static std::unique_ptr< llvm::ModuleSummaryIndex > llvm_load_summary(llvm::StringRef path)
void llvm_inline_reset_caches(void)
llvm::SmallVector< llvm::ModuleSummaryIndex *, 2 > InlineSearchPath
struct FunctionInlineState FunctionInlineState
static llvm::SmallVector< llvm::GlobalValueSummary *, 1 > summaries_for_guid(const InlineSearchPath &path, llvm::GlobalValue::GUID guid)
const float inline_cost_decay_factor
llvm::StringMap< llvm::StringSet<> > ImportMapTy
static std::unique_ptr< llvm::Module > load_module(LLVMContextRef c, llvm::StringRef Identifier)
struct InlineWorkListItem InlineWorkListItem
static void function_references(llvm::Function &F, int &running_instcount, llvm::SmallPtrSet< llvm::GlobalVariable *, 8 > &referencedVars, llvm::SmallPtrSet< llvm::Function *, 8 > &referencedFunctions)
static void add_module_to_inline_search_path(InlineSearchPath &path, llvm::StringRef modpath)
static llvm::Module * load_module_cached(LLVMContextRef c, llvm::StringRef modPath)
llvm::StringMap< FunctionInlineState > FunctionInlineStates
static llvm::Function * create_redirection_function(std::unique_ptr< llvm::Module > &importMod, llvm::Function *F, llvm::StringRef Name)
llvm::StringMap< std::unique_ptr< llvm::ModuleSummaryIndex > > SummaryCache
llvm::StringMap< std::unique_ptr< llvm::Module > > ModuleCache
llvm::ManagedStatic< ModuleCache > module_cache
llvm::ManagedStatic< SummaryCache > summary_cache
static std::unique_ptr< ImportMapTy > llvm_build_inline_plan(LLVMContextRef lc, llvm::Module *mod)
static void llvm_execute_inline_plan(llvm::Module *mod, ImportMapTy *globalsToInline)
static bool function_inlinable(llvm::Function &F, int threshold, FunctionInlineStates &functionState, InlineWorkList &worklist, InlineSearchPath &searchpath, llvm::SmallPtrSet< const llvm::Function *, 8 > &visitedFunctions, int &running_instcount, llvm::StringSet<> &importVars)
llvm::StringRef symbolName
llvm::SmallVector< llvm::ModuleSummaryIndex *, 2 > searchpath