25#include "llvm/Config/config.h"
66#include <system_error>
70 return PACKAGE_NAME
" version " PACKAGE_VERSION;
75 "lto-discard-value-names",
76 cl::desc(
"Strip names from Value during LTO (other than GlobalValue)."),
85 "lto-pass-remarks-with-hotness",
86 cl::desc(
"With PGO, include profile count in optimization remarks"),
91 "lto-pass-remarks-hotness-threshold",
92 cl::desc(
"Minimum profile count required for an "
93 "optimization remark to be output."
94 " Use 'auto' to apply the threshold from profile summary."),
99 cl::desc(
"Output filename for pass remarks"),
104 cl::desc(
"Only record optimization remarks from passes whose "
105 "names match the given regular expression"),
109 "lto-pass-remarks-format",
110 cl::desc(
"The format used for serializing remarks (default: YAML)"),
115 cl::desc(
"Save statistics to the specified file"),
119 "lto-aix-system-assembler",
120 cl::desc(
"Path to a system assembler, picked up on AIX only"),
125 cl::desc(
"Perform context sensitive PGO instrumentation"));
129 cl::desc(
"Context sensitive profile file path"));
134 TheLinker(new
Linker(*MergedModule)) {
151 for (
const StringRef &Undef :
Mod->getAsmUndefinedRefs())
152 AsmUndefinedRefs.
insert(Undef);
156 assert(&
Mod->getModule().getContext() == &Context &&
157 "Expected module in same context");
159 bool ret = TheLinker->linkInModule(
Mod->takeModule());
163 HasVerifiedInput =
false;
169 assert(&
Mod->getModule().getContext() == &Context &&
170 "Expected module in same context");
172 AsmUndefinedRefs.
clear();
174 MergedModule =
Mod->takeModule();
175 TheLinker = std::make_unique<Linker>(*MergedModule);
179 HasVerifiedInput =
false;
189 EmitDwarfDebugInfo =
false;
193 EmitDwarfDebugInfo =
true;
203 std::optional<CodeGenOpt::Level> CGOptLevelOrNone =
205 assert(CGOptLevelOrNone &&
"Unknown optimization level!");
210 if (!determineTarget())
214 verifyMergedModuleOnce();
217 applyScopeRestrictions();
223 std::string ErrMsg =
"could not open bitcode file for writing: ";
224 ErrMsg += Path.str() +
": " + EC.message();
234 std::string ErrMsg =
"could not write bitcode file: ";
235 ErrMsg += Path.str() +
": " + Out.
os().
error().message();
245bool LTOCodeGenerator::useAIXSystemAssembler() {
246 const auto &
Triple = TargetMach->getTargetTriple();
250bool LTOCodeGenerator::runAIXSystemAssembler(
SmallString<128> &AssemblyFile) {
251 assert(useAIXSystemAssembler() &&
252 "Runing AIX system assembler when integrated assembler is available!");
260 "Cannot find the assembler specified by lto-aix-system-assembler");
266 std::string LDR_CNTRL_var =
"LDR_CNTRL=MAXDATA32=0xA0000000@DSA";
268 LDR_CNTRL_var += (
"@" + *
V);
271 const auto &
Triple = TargetMach->getTargetTriple();
273 std::string ObjectFileName(AssemblyFile);
274 ObjectFileName[ObjectFileName.size() - 1] =
'o';
276 "/bin/env", LDR_CNTRL_var,
279 ObjectFileName, AssemblyFile};
286 emitError(
"LTO assembler exited abnormally");
290 emitError(
"Unable to invoke LTO assembler");
294 emitError(
"LTO assembler invocation returned non-zero");
302 AssemblyFile = ObjectFileName;
307bool LTOCodeGenerator::compileOptimizedToFile(
const char **
Name) {
308 if (useAIXSystemAssembler())
323 emitError(
EC.message());
325 return std::make_unique<CachedFileStream>(
326 std::make_unique<llvm::raw_fd_ostream>(FD,
true));
343 if (useAIXSystemAssembler())
344 if (!runAIXSystemAssembler(Filename))
347 NativeObjectPath =
Filename.c_str();
348 *
Name = NativeObjectPath.c_str();
352std::unique_ptr<MemoryBuffer>
355 if (!compileOptimizedToFile(&
name))
361 if (std::error_code EC = BufferOrErr.
getError()) {
362 emitError(EC.message());
370 return std::move(*BufferOrErr);
377 return compileOptimizedToFile(
Name);
387bool LTOCodeGenerator::determineTarget() {
391 TripleStr = MergedModule->getTargetTriple();
392 if (TripleStr.empty()) {
394 MergedModule->setTargetTriple(TripleStr);
409 Features.getDefaultSubtargetFeatures(
Triple);
410 FeatureStr = Features.getString();
414 Config.
CPU =
"core2";
416 Config.
CPU =
"yonah";
418 Config.
CPU =
"apple-a12";
421 Config.
CPU =
"cyclone";
429 TargetMach = createTargetMachine();
430 assert(TargetMach &&
"Unable to create target machine");
435std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() {
436 assert(MArch &&
"MArch is not set!");
445void LTOCodeGenerator::preserveDiscardableGVs(
448 std::vector<GlobalValue *>
Used;
450 if (!GV.isDiscardableIfUnused() || GV.isDeclaration() ||
453 if (GV.hasAvailableExternallyLinkage())
455 (
Twine(
"Linker asked to preserve available_externally global: '") +
456 GV.getName() +
"'").str());
457 if (GV.hasInternalLinkage())
458 return emitWarning((
Twine(
"Linker asked to preserve internal global: '") +
459 GV.getName() +
"'").str());
462 for (
auto &GV : TheModule)
463 mayPreserveGlobal(GV);
464 for (
auto &GV : TheModule.globals())
465 mayPreserveGlobal(GV);
466 for (
auto &GV : TheModule.aliases())
467 mayPreserveGlobal(GV);
475void LTOCodeGenerator::applyScopeRestrictions() {
476 if (ScopeRestrictionsDone)
492 MangledName.
reserve(GV.getName().size() + 1);
494 return MustPreserveSymbols.
count(MangledName);
500 if (!ShouldInternalize)
503 if (ShouldRestoreGlobalsLinkage) {
508 if (!GV.hasAvailableExternallyLinkage() && !GV.hasLocalLinkage() &&
510 ExternalSymbols.
insert(std::make_pair(GV.getName(), GV.getLinkage()));
512 for (
auto &GV : *MergedModule)
514 for (
auto &GV : MergedModule->globals())
516 for (
auto &GV : MergedModule->aliases())
526 ScopeRestrictionsDone =
true;
530void LTOCodeGenerator::restoreLinkageForExternals() {
531 if (!ShouldInternalize || !ShouldRestoreGlobalsLinkage)
534 assert(ScopeRestrictionsDone &&
535 "Cannot externalize without internalization!");
537 if (ExternalSymbols.
empty())
541 if (!GV.hasLocalLinkage() || !GV.hasName())
544 auto I = ExternalSymbols.
find(GV.getName());
545 if (
I == ExternalSymbols.
end())
548 GV.setLinkage(
I->second);
556void LTOCodeGenerator::verifyMergedModuleOnce() {
558 if (HasVerifiedInput)
560 HasVerifiedInput =
true;
562 bool BrokenDebugInfo =
false;
565 if (BrokenDebugInfo) {
566 emitWarning(
"Invalid debug info found, debug info will be stripped");
571void LTOCodeGenerator::finishOptimizationRemarks() {
572 if (DiagnosticOutputFile) {
573 DiagnosticOutputFile->keep();
575 DiagnosticOutputFile->os().flush();
581 if (!this->determineTarget())
587 if (!DiagFileOrErr) {
588 errs() <<
"Error: " <<
toString(DiagFileOrErr.takeError()) <<
"\n";
591 DiagnosticOutputFile = std::move(*DiagFileOrErr);
595 if (!StatsFileOrErr) {
596 errs() <<
"Error: " <<
toString(StatsFileOrErr.takeError()) <<
"\n";
599 StatsFile = std::move(StatsFileOrErr.get());
615 verifyMergedModuleOnce();
618 this->applyScopeRestrictions();
621 MergedModule->addModuleFlag(
Module::Error,
"LTOPostLink", 1);
624 MergedModule->setDataLayout(TargetMach->createDataLayout());
626 if (!SaveIRBeforeOptPath.empty()) {
631 " to save optimized bitcode\n");
637 TargetMach = createTargetMachine();
638 if (!
opt(Config, TargetMach.get(), 0, *MergedModule,
false,
639 &CombinedIndex,
nullptr,
640 std::vector<uint8_t>())) {
641 emitError(
"LTO middle-end optimizations failed");
649 unsigned ParallelismLevel) {
650 if (!this->determineTarget())
655 verifyMergedModuleOnce();
659 restoreLinkageForExternals();
664 Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule,
666 assert(!Err &&
"unexpected code-generation failure");
678 finishOptimizationRemarks();
685 CodegenOptions.push_back(Option.str());
689 if (!CodegenOptions.empty())
696 std::vector<const char *> CodegenArgv(1,
"libLLVMLTO");
698 CodegenArgv.push_back(
Arg.c_str());
721 std::string MsgStorage;
729 assert(DiagHandler &&
"Invalid diagnostic handler");
730 (*DiagHandler)(Severity, MsgStorage.c_str(), DiagContext);
737 : CodeGenerator(CodeGenPtr) {}
748 this->DiagHandler = DiagHandler;
749 this->DiagContext = Ctxt;
768void LTOCodeGenerator::emitError(
const std::string &ErrMsg) {
770 (*DiagHandler)(
LTO_DS_ERROR, ErrMsg.c_str(), DiagContext);
772 Context.
diagnose(LTODiagnosticInfo(ErrMsg));
775void LTOCodeGenerator::emitWarning(
const std::string &ErrMsg) {
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
static bool mustPreserveGV(const GlobalValue &GV)
Predicate for Internalize pass.
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file implements a simple parser to decode commandline option for remarks hotness threshold that ...
Module.h This file contains the declarations for the Module class.
This header defines classes/functions to handle pass execution timing information with interfaces for...
Provides a library for accessing information about this process and other processes on the operating ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void externalize(GlobalValue *GV)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
static void DiagHandler(const SMDiagnostic &Diag, void *Context)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
This is the base abstract class for diagnostic reporting in the backend.
DiagnosticSeverity getSeverity() const
virtual void print(DiagnosticPrinter &DP) const =0
Print using the given DP a user-friendly message.
Basic diagnostic printer that uses an underlying raw_ostream.
Interface for custom diagnostic printing.
Represents either an error or a value T.
std::error_code getError() const
Lightweight error class with error context and mandatory checking.
This is an important class for using LLVM in a threaded context.
void enableDebugTypeODRUniquing()
void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
void setDiscardValueNames(bool Discard)
Set the Context runtime configuration to discard all value name (but GlobalValue).
void setDiagnosticHandler(std::unique_ptr< DiagnosticHandler > &&DH, bool RespectFilters=false)
setDiagnosticHandler - This method sets unique_ptr to object of DiagnosticHandler to provide custom d...
This class provides the core functionality of linking in LLVM.
void getNameWithPrefix(raw_ostream &OS, const GlobalValue *GV, bool CannotUsePrivateLabel) const
Print the appropriate prefix and the specified global variable's name.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
Class to hold module path string table and global value map, and encapsulate methods for operating on...
A Module instance is used to store all the information related to an LLVM module.
@ Error
Emits an error if two values disagree, otherwise the resulting value is that of the operands.
bool SLPVectorization
Tuning option to enable/disable slp loop vectorization, set based on opt level.
bool LoopVectorization
Tuning option to enable/disable loop vectorization, set based on opt level.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void reserve(size_type N)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
iterator find(StringRef Key)
size_type count(StringRef Key) const
count - Return 1 if the element is in the map, 0 otherwise.
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
StringRef - Represent a constant reference to a string, i.e.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Manages the enabling and disabling of subtarget specific features.
unsigned DataSections
Emit data into separate sections.
TargetMachine * createTargetMachine(StringRef TT, StringRef CPU, StringRef Features, const TargetOptions &Options, std::optional< Reloc::Model > RM, std::optional< CodeModel::Model > CM=std::nullopt, CodeGenOpt::Level OL=CodeGenOpt::Default, bool JIT=false) const
createTargetMachine - Create a target specific machine implementation for the specified Triple.
Triple - Helper class for working with autoconf configuration names.
bool isArm64e() const
Tests whether the target is the Apple "arm64e" AArch64 subarch.
ArchType getArch() const
Get the parsed architecture type of this triple.
bool isOSAIX() const
Tests whether the OS is AIX.
bool isArch64Bit() const
Test whether the architecture is 64-bit.
bool isOSDarwin() const
Is this a "Darwin" OS (macOS, iOS, tvOS, watchOS, or DriverKit).
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
An efficient, type-erasing, non-owning reference to a callable.
PassManager manages ModulePassManagers.
A raw_ostream that writes to a file descriptor.
bool has_error() const
Return the value of the flag in this raw_fd_ostream indicating whether an output error has been encou...
std::error_code error() const
void close()
Manually flush the stream and close the file.
void clear_error()
Set the flag read by has_error() to false.
A raw_ostream that writes to an std::string.
static std::optional< std::string > GetEnv(StringRef name)
lto_codegen_diagnostic_severity_t
Diagnostic severity.
void(* lto_diagnostic_handler_t)(lto_codegen_diagnostic_severity_t severity, const char *diag, void *ctxt)
Diagnostic handler type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
std::optional< Level > getLevel(IDType ID)
Get the Level identified by the integer ID.
bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview="", raw_ostream *Errs=nullptr, const char *EnvVar=nullptr, bool LongOptionsUseDoubleDash=false)
initializer< Ty > init(const Ty &Val)
std::optional< bool > getExplicitDataSections()
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
Expected< std::unique_ptr< ToolOutputFile > > setupStatsFile(StringRef StatsFilename)
Setups the output file for saving statistics.
Expected< std::unique_ptr< ToolOutputFile > > setupLLVMOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses, StringRef RemarksFormat, bool RemarksWithHotness, std::optional< uint64_t > RemarksHotnessThreshold=0, int Count=-1)
Setup optimization remarks.
std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, SmallVectorImpl< char > &ResultPath, OpenFlags Flags=OF_None)
Create a file in the system temporary directory.
int ExecuteAndWait(StringRef Program, ArrayRef< StringRef > Args, std::optional< ArrayRef< StringRef > > Env=std::nullopt, ArrayRef< std::optional< StringRef > > Redirects={}, unsigned SecondsToWait=0, unsigned MemoryLimit=0, std::string *ErrMsg=nullptr, bool *ExecutionFailed=nullptr, std::optional< ProcessStatistics > *ProcStat=nullptr, BitVector *AffinityMask=nullptr)
This function executes the program using the arguments provided.
std::string getDefaultTargetTriple()
getDefaultTargetTriple() - Return the default target triple the compiler has been configured to produ...
This is an optimization pass for GlobalISel generic memory operations.
cl::opt< std::string > RemarksFormat("lto-pass-remarks-format", cl::desc("The format used for serializing remarks (default: YAML)"), cl::value_desc("format"), cl::init("yaml"))
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
cl::opt< bool > LTODiscardValueNames("lto-discard-value-names", cl::desc("Strip names from Value during LTO (other than GlobalValue)."), cl::init(false), cl::Hidden)
void WriteBitcodeToFile(const Module &M, raw_ostream &Out, bool ShouldPreserveUseListOrder=false, const ModuleSummaryIndex *Index=nullptr, bool GenerateHash=false, ModuleHash *ModHash=nullptr)
Write the specified module to the specified raw output stream.
bool internalizeModule(Module &TheModule, std::function< bool(const GlobalValue &)> MustPreserveGV)
Helper function to internalize functions and variables in a Module.
cl::opt< std::string > LTOCSIRProfile("cs-profile-path", cl::desc("Context sensitive profile file path"))
void updateVCallVisibilityInModule(Module &M, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols)
If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...
cl::opt< std::string > RemarksPasses("lto-pass-remarks-filter", cl::desc("Only record optimization remarks from passes whose " "names match the given regular expression"), cl::value_desc("regex"))
std::function< Expected< std::unique_ptr< CachedFileStream > >(unsigned Task, const Twine &ModuleName)> AddStreamFn
This type defines the callback to add a file that is generated on the fly.
void updateCompilerUsed(Module &TheModule, const TargetMachine &TM, const StringSet<> &AsmUndefinedRefs)
Find all globals in TheModule that are referenced in AsmUndefinedRefs, as well as the user-supplied f...
void reportAndResetTimings(raw_ostream *OutStream=nullptr)
If -time-passes has been specified, report the timings immediately and then reset the timers to zero.
cl::opt< std::string > AIXSystemAssemblerPath("lto-aix-system-assembler", cl::desc("Path to a system assembler, picked up on AIX only"), cl::value_desc("path"))
void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
bool AreStatisticsEnabled()
Check if statistics are enabled.
cl::opt< bool > RemarksWithHotness("lto-pass-remarks-with-hotness", cl::desc("With PGO, include profile count in optimization remarks"), cl::Hidden)
cl::opt< std::string > RemarksFilename("lto-pass-remarks-output", cl::desc("Output filename for pass remarks"), cl::value_desc("filename"))
void parseCommandLineOptions(std::vector< std::string > &Options)
A convenience function that calls cl::ParseCommandLineOptions on the given set of options.
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
bool StripDebugInfo(Module &M)
Strip debug info in the module if it exists.
@ Mod
The access may modify the value stored in memory.
void PrintStatistics()
Print statistics to the file returned by CreateInfoOutputFile().
void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
DiagnosticSeverity
Defines the different supported severity of a diagnostic.
cl::opt< std::optional< uint64_t >, false, remarks::HotnessThresholdParser > RemarksHotnessThreshold("lto-pass-remarks-hotness-threshold", cl::desc("Minimum profile count required for an " "optimization remark to be output." " Use 'auto' to apply the threshold from profile summary."), cl::value_desc("uint or 'auto'"), cl::init(0), cl::Hidden)
cl::opt< std::string > LTOStatsFile("lto-stats-file", cl::desc("Save statistics to the specified file"), cl::Hidden)
Pass * createObjCARCContractPass()
void PrintStatisticsJSON(raw_ostream &OS)
Print statistics in JSON format.
cl::opt< bool > LTORunCSIRInstr("cs-profile-generate", cl::desc("Perform context sensitive PGO instrumentation"))
bool verifyModule(const Module &M, raw_ostream *OS=nullptr, bool *BrokenDebugInfo=nullptr)
Check a module for errors.
This is the base class for diagnostic handling in LLVM.
C++ class which implements the opaque lto_code_gen_t type.
bool optimize()
Optimizes the merged module.
std::unique_ptr< MemoryBuffer > compile()
As with compile_to_file(), this function compiles the merged module into single output file.
void setModule(std::unique_ptr< LTOModule > M)
Set the destination module.
bool compile_to_file(const char **Name)
Compile the merged module into a single output file; the path to output file is returned to the calle...
void parseCodeGenDebugOptions()
Parse the options set in setCodeGenDebugOptions.
void setOptLevel(unsigned OptLevel)
void setAsmUndefinedRefs(struct LTOModule *)
void setDiagnosticHandler(lto_diagnostic_handler_t, void *)
void setFileType(CodeGenFileType FT)
Set the file type to be emitted (assembly or object code).
void setTargetOptions(const TargetOptions &Options)
void setCodeGenDebugOptions(ArrayRef< StringRef > Opts)
Pass options to the driver and optimization passes.
LTOCodeGenerator(LLVMContext &Context)
std::unique_ptr< MemoryBuffer > compileOptimized()
Compiles the merged optimized module into a single output file.
bool addModule(struct LTOModule *)
Merge given module.
void setDebugInfo(lto_debug_model)
bool writeMergedModules(StringRef Path)
Write the merged module to the file specified by the given path.
void DiagnosticHandler(const DiagnosticInfo &DI)
static const char * getVersionString()
C++ class which implements the opaque lto_module_t type.
static const Target * lookupTarget(StringRef Triple, std::string &Error)
lookupTarget - Lookup a target based on a target triple.
std::string StatsFile
Statistics output file path.
std::optional< CodeModel::Model > CodeModel
std::function< void(legacy::PassManager &)> PreCodeGenPassesHook
For adding passes that run right before codegen.
bool CodeGenOnly
Disable entirely the optimizer, including importing for ThinLTO.
std::vector< std::string > MAttrs
PipelineTuningOptions PTO
Tunable parameters for passes in the default pipelines.
CodeGenOpt::Level CGOptLevel
bool RunCSIRInstr
Run PGO context sensitive IR instrumentation.
std::string CSIRProfile
Context Sensitive PGO profile path.
std::optional< Reloc::Model > RelocModel
CodeGenFileType CGFileType