Index: llvm/trunk/include/llvm/CodeGen/CommandFlags.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/CommandFlags.h +++ llvm/trunk/include/llvm/CodeGen/CommandFlags.h @@ -232,6 +232,11 @@ cl::desc("Use .ctors instead of .init_array."), cl::init(false)); +cl::opt RelaxELFRelocations( + "relax-elf-relocations", + cl::desc("Emit GOTPCRELX/REX_GOTPCRELX instead of GOTPCREL on x86-64 ELF"), + cl::init(false)); + cl::opt DataSections("data-sections", cl::desc("Emit data into separate sections"), cl::init(false)); @@ -288,6 +293,7 @@ Options.StackAlignmentOverride = OverrideStackAlignment; Options.StackSymbolOrdering = StackSymbolOrdering; Options.UseInitArray = !UseCtors; + Options.RelaxELFRelocations = RelaxELFRelocations; Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; Index: llvm/trunk/include/llvm/LTO/Config.h =================================================================== --- llvm/trunk/include/llvm/LTO/Config.h +++ llvm/trunk/include/llvm/LTO/Config.h @@ -33,6 +33,8 @@ /// LTO configuration. A linker can configure LTO by setting fields in this data /// structure and passing it to the lto::LTO constructor. struct Config { + // Note: when adding fields here, consider whether they need to be added to + // computeCacheKey in LTO.cpp. std::string CPU; TargetOptions Options; std::vector MAttrs; Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -50,8 +50,8 @@ // export/import and other global analysis results. // The hash is produced in \p Key. static void computeCacheKey( - SmallString<40> &Key, const ModuleSummaryIndex &Index, StringRef ModuleID, - const FunctionImporter::ImportMapTy &ImportList, + SmallString<40> &Key, const Config &Conf, const ModuleSummaryIndex &Index, + StringRef ModuleID, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals) { @@ -67,6 +67,39 @@ Hasher.update(LLVM_REVISION); #endif + // Include the parts of the LTO configuration that affect code generation. + auto AddString = [&](StringRef Str) { + Hasher.update(Str); + Hasher.update(ArrayRef{0}); + }; + auto AddUnsigned = [&](unsigned I) { + uint8_t Data[4]; + Data[0] = I; + Data[1] = I >> 8; + Data[2] = I >> 16; + Data[3] = I >> 24; + Hasher.update(ArrayRef{Data, 4}); + }; + AddString(Conf.CPU); + // FIXME: Hash more of Options. For now all clients initialize Options from + // command-line flags (which is unsupported in production), but may set + // RelaxELFRelocations. The clang driver can also pass FunctionSections, + // DataSections and DebuggerTuning via command line flags. + AddUnsigned(Conf.Options.RelaxELFRelocations); + AddUnsigned(Conf.Options.FunctionSections); + AddUnsigned(Conf.Options.DataSections); + AddUnsigned((unsigned)Conf.Options.DebuggerTuning); + for (auto &A : Conf.MAttrs) + AddString(A); + AddUnsigned(Conf.RelocModel); + AddUnsigned(Conf.CodeModel); + AddUnsigned(Conf.CGOptLevel); + AddUnsigned(Conf.OptLevel); + AddString(Conf.OptPipeline); + AddString(Conf.AAPipeline); + AddString(Conf.OverrideTriple); + AddString(Conf.DefaultTriple); + // Include the hash for the current module auto ModHash = Index.getModuleHash(ModuleID); Hasher.update(ArrayRef((uint8_t *)&ModHash[0], sizeof(ModHash))); @@ -562,7 +595,7 @@ SmallString<40> Key; // The module may be cached, this helps handling it. - computeCacheKey(Key, CombinedIndex, ModuleID, ImportList, ExportList, + computeCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, DefinedGlobals); if (AddStreamFn CacheAddStream = Cache(Task, Key)) return RunThinBackend(CacheAddStream); Index: llvm/trunk/test/ThinLTO/X86/cache-config.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/cache-config.ll +++ llvm/trunk/test/ThinLTO/X86/cache-config.ll @@ -0,0 +1,27 @@ +; RUN: rm -rf %t.cache && mkdir %t.cache +; RUN: opt -module-hash -module-summary %s -o %t.bc + +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -mcpu=yonah +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -relax-elf-relocations +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -function-sections +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -data-sections +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -debugger-tune=sce +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -mattr=+sse2 +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -relocation-model=static +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -code-model=large +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -cg-opt-level=0 +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -O1 +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -opt-pipeline=loweratomic +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -aa-pipeline=basic-aa +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -override-triple=x86_64-unknown-linux-gnu +; RUN: llvm-lto2 -o %t.o %t.bc -cache-dir %t.cache -r=%t.bc,globalfunc,plx -default-triple=x86_64-unknown-linux-gnu +; RUN: ls %t.cache | count 15 + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @globalfunc() { +entry: + ret void +} Index: llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp +++ llvm/trunk/tools/llvm-lto2/llvm-lto2.cpp @@ -17,6 +17,7 @@ //===----------------------------------------------------------------------===// #include "llvm/LTO/Caching.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/LTO/LTO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/TargetSelect.h" @@ -31,6 +32,11 @@ "(default = '-O2')"), cl::Prefix, cl::ZeroOrMore, cl::init('2')); +static cl::opt CGOptLevel( + "cg-opt-level", + cl::desc("Codegen optimization level (0, 1, 2 or 3, default = '2')"), + cl::init('2')); + static cl::list InputFilenames(cl::Positional, cl::OneOrMore, cl::desc("")); @@ -74,6 +80,15 @@ "A resolution for each symbol must be specified."), cl::ZeroOrMore); +static cl::opt OverrideTriple( + "override-triple", + cl::desc("Replace target triples in input files with this triple")); + +static cl::opt DefaultTriple( + "default-triple", + cl::desc( + "Replace unspecified target triples in input files with this triple")); + static void check(Error E, std::string Msg) { if (!E) return; @@ -146,6 +161,13 @@ exit(1); }; + Conf.CPU = MCPU; + Conf.Options = InitTargetOptionsFromCodeGenFlags(); + Conf.MAttrs = MAttrs; + if (auto RM = getRelocModel()) + Conf.RelocModel = *RM; + Conf.CodeModel = CMModel; + if (SaveTemps) check(Conf.addSaveTemps(OutputFilename + "."), "Config::addSaveTemps failed"); @@ -155,6 +177,26 @@ Conf.AAPipeline = AAPipeline; Conf.OptLevel = OptLevel - '0'; + switch (CGOptLevel) { + case '0': + Conf.CGOptLevel = CodeGenOpt::None; + break; + case '1': + Conf.CGOptLevel = CodeGenOpt::Less; + break; + case '2': + Conf.CGOptLevel = CodeGenOpt::Default; + break; + case '3': + Conf.CGOptLevel = CodeGenOpt::Aggressive; + break; + default: + llvm::errs() << "invalid cg optimization level: " << CGOptLevel << '\n'; + return 1; + } + + Conf.OverrideTriple = OverrideTriple; + Conf.DefaultTriple = DefaultTriple; ThinBackend Backend; if (ThinLTODistributedIndexes)