Index: lld/trunk/COFF/Config.h =================================================================== --- lld/trunk/COFF/Config.h +++ lld/trunk/COFF/Config.h @@ -182,6 +182,12 @@ // Used for /thinlto-index-only: llvm::StringRef thinLTOIndexOnlyArg; + // Used for /thinlto-object-prefix-replace: + std::pair thinLTOPrefixReplace; + + // Used for /thinlto-object-suffix-replace: + std::pair thinLTOObjectSuffixReplace; + uint64_t imageBase = -1; uint64_t fileAlign = 512; uint64_t stackReserve = 1024 * 1024; Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -86,6 +86,20 @@ return !errorCount(); } +// Parse options of the form "old;new". +static std::pair getOldNewOptions(opt::InputArgList &args, + unsigned id) { + auto *arg = args.getLastArg(id); + if (!arg) + return {"", ""}; + + StringRef s = arg->getValue(); + std::pair ret = s.split(';'); + if (ret.second.empty()) + error(arg->getSpelling() + " expects 'old;new' format, but got " + s); + return ret; +} + // Drop directory components and replace extension with ".exe" or ".dll". static std::string getOutputPath(StringRef path) { auto p = path.find_last_of("\\/"); @@ -1446,6 +1460,10 @@ args.hasArg(OPT_thinlto_index_only_arg); config->thinLTOIndexOnlyArg = args.getLastArgValue(OPT_thinlto_index_only_arg); + config->thinLTOPrefixReplace = + getOldNewOptions(args, OPT_thinlto_prefix_replace); + config->thinLTOObjectSuffixReplace = + getOldNewOptions(args, OPT_thinlto_object_suffix_replace); // Handle miscellaneous boolean flags. config->allowBind = args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); config->allowIsolation = Index: lld/trunk/COFF/InputFiles.h =================================================================== --- lld/trunk/COFF/InputFiles.h +++ lld/trunk/COFF/InputFiles.h @@ -311,6 +311,8 @@ std::vector symbols; }; + +std::string replaceThinLTOSuffix(StringRef path); } // namespace coff std::string toString(const coff::InputFile *file); Index: lld/trunk/COFF/InputFiles.cpp =================================================================== --- lld/trunk/COFF/InputFiles.cpp +++ lld/trunk/COFF/InputFiles.cpp @@ -783,6 +783,8 @@ uint64_t offsetInArchive) : InputFile(BitcodeKind, mb) { std::string path = mb.getBufferIdentifier().str(); + if (config->thinLTOIndexOnly) + path = replaceThinLTOSuffix(mb.getBufferIdentifier()); // ThinLTO assumes that all MemoryBufferRefs given to it have a unique // name. If two archives define two members with the same name, this @@ -849,6 +851,15 @@ return IMAGE_FILE_MACHINE_UNKNOWN; } } + +std::string replaceThinLTOSuffix(StringRef path) { + StringRef suffix = config->thinLTOObjectSuffixReplace.first; + StringRef repl = config->thinLTOObjectSuffixReplace.second; + + if (path.consume_back(suffix)) + return (path + repl).str(); + return path; +} } // namespace coff } // namespace lld Index: lld/trunk/COFF/LTO.cpp =================================================================== --- lld/trunk/COFF/LTO.cpp +++ lld/trunk/COFF/LTO.cpp @@ -54,6 +54,12 @@ return ret; } +static std::string getThinLTOOutputFile(StringRef path) { + return lto::getThinLTOOutputFile(path, + config->thinLTOPrefixReplace.first, + config->thinLTOPrefixReplace.second); +} + static lto::Config createConfig() { lto::Config c; c.Options = initTargetOptionsFromCodeGenFlags(); @@ -93,7 +99,8 @@ if (config->thinLTOIndexOnly) { auto OnIndexWrite = [&](StringRef S) { thinIndices.erase(S); }; backend = lto::createWriteIndexesThinBackend( - "", "", config->thinLTOEmitImportsFiles, indexFile.get(), OnIndexWrite); + config->thinLTOPrefixReplace.first, config->thinLTOPrefixReplace.second, + config->thinLTOEmitImportsFiles, indexFile.get(), OnIndexWrite); } else if (config->thinLTOJobs != 0) { backend = lto::createInProcessThinBackend(config->thinLTOJobs); } @@ -159,11 +166,11 @@ cache)); // Emit empty index files for non-indexed files - for (StringRef S : thinIndices) { - std::string Path(S); - openFile(Path + ".thinlto.bc"); + for (StringRef s : thinIndices) { + std::string path = getThinLTOOutputFile(s); + openFile(path + ".thinlto.bc"); if (config->thinLTOEmitImportsFiles) - openFile(Path + ".imports"); + openFile(path + ".imports"); } // ThinLTO with index only option is required to generate only the index Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -185,6 +185,12 @@ def thinlto_index_only_arg : P< "thinlto-index-only", "-thinlto-index-only and also write native module names to file">; +def thinlto_object_suffix_replace : P< + "thinlto-object-suffix-replace", + "'old;new' replace old suffix with new suffix in ThinLTO index">; +def thinlto_prefix_replace: P< + "thinlto-prefix-replace", + "'old;new' replace old prefix with new prefix in ThinLTO outputs">; def dash_dash_version : Flag<["--"], "version">, HelpText<"Print version information">; defm threads: B<"threads", Index: lld/trunk/test/COFF/thinlto-object-suffix-replace.ll =================================================================== --- lld/trunk/test/COFF/thinlto-object-suffix-replace.ll +++ lld/trunk/test/COFF/thinlto-object-suffix-replace.ll @@ -0,0 +1,50 @@ +; REQUIRES: x86 + +; Test to make sure the thinlto-object-suffix-replace option is handled +; correctly. + +; Generate bitcode file with summary, as well as a minimized bitcode without +; the debug metadata for the thin link. +; RUN: opt -thinlto-bc %s -thin-link-bitcode-file=%t1.thinlink.bc -o %t1.obj + +; First perform the thin link on the normal bitcode file, and save the +; resulting index. +; RUN: lld-link -thinlto-index-only -entry:main %t1.obj -out:%t3.exe +; RUN: cp %t1.obj.thinlto.bc %t1.obj.thinlto.bc.orig + +; Next perform the thin link on the minimized bitcode file, and compare dump +; of the resulting index to the above dump to ensure they are identical. +; RUN: rm -f %t1.obj.thinlto.bc +; Make sure it isn't inadvertently using the regular bitcode file. +; RUN: rm -f %t1.obj +; RUN: lld-link -entry:main -thinlto-index-only \ +; RUN: -thinlto-object-suffix-replace:".thinlink.bc;.obj" \ +; RUN: %t1.thinlink.bc -out:%t3.exe +; RUN: diff %t1.obj.thinlto.bc.orig %t1.obj.thinlto.bc + +; Ensure lld generates error if suffix replace option not in 'old;new' format. +; RUN: rm -f %t1.obj.thinlto.bc +; RUN: not lld-link -entry:main -thinlto-index-only \ +; RUN: -thinlto-object-suffix-replace:"abc:def" %t1.thinlink.bc \ +; RUN: -out:%t3.exe 2>&1 | FileCheck %s --check-prefix=ERR1 +; ERR1: -thinlto-object-suffix-replace: expects 'old;new' format, but got abc:def + +; If filename does not end with old suffix, no suffix change should occur, +; so ".thinlto.bc" will simply be appended to the input file name. +; RUN: rm -f %t1.thinlink.bc.thinlto.bc +; RUN: lld-link -entry:main -thinlto-index-only \ +; RUN: -thinlto-object-suffix-replace:".abc;.obj" %t1.thinlink.bc -out:%t3.exe +; RUN: ls %t1.thinlink.bc.thinlto.bc + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.0.24215" + +define void @main() { +entry: + ret void +} + +!llvm.dbg.cu = !{} + +!1 = !{i32 2, !"Debug Info Version", i32 3} +!llvm.module.flags = !{!1} Index: lld/trunk/test/COFF/thinlto-prefix-replace.ll =================================================================== --- lld/trunk/test/COFF/thinlto-prefix-replace.ll +++ lld/trunk/test/COFF/thinlto-prefix-replace.ll @@ -0,0 +1,26 @@ +; REQUIRES: x86 +; Check that changing the output path via thinlto-prefix-replace works +; RUN: mkdir -p %t/oldpath +; RUN: opt -module-summary %s -o %t/oldpath/t.obj + +; Ensure that there is no existing file at the new path, so we properly +; test the creation of the new file there. +; RUN: rm -f %t/newpath/t.obj.thinlto.bc +; RUN: lld-link -entry:main -thinlto-index-only \ +; RUN: -thinlto-prefix-replace:"%t/oldpath/;%t/newpath/" %t/oldpath/t.obj \ +; RUN: -out:%t/t.exe +; RUN: ls %t/newpath/t.obj.thinlto.bc + +; Ensure that lld errors if prefix replace option is not in 'old;new' format. +; RUN: rm -f %t/newpath/t.obj.thinlto.bc +; RUN: not lld-link -entry:main -thinlto-index-only \ +; RUN: -thinlto-prefix-replace:"abc:def" %t/oldpath/t.obj \ +; RUN: -out:%t/t.exe 2>&1 | FileCheck --check-prefix=ERR %s +; ERR: -thinlto-prefix-replace: expects 'old;new' format, but got abc:def + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.0.24215" + +define void @main() { + ret void +}