Index: clang/docs/UsersManual.rst =================================================================== --- clang/docs/UsersManual.rst +++ clang/docs/UsersManual.rst @@ -360,6 +360,11 @@ serialization format is specified, the file will be named "foo.opt.". + On Darwin platforms, if ``-flto`` is used and the file path is not provided, + the output file will be chosen according to the linker argument + ``-object_path_lto`` if present, or according to the output file specified + through ``-o`` otherwise. + .. _opt_foptimization-record-passes: **-foptimization-record-passes** Index: clang/lib/Driver/ToolChains/Darwin.cpp =================================================================== --- clang/lib/Driver/ToolChains/Darwin.cpp +++ clang/lib/Driver/ToolChains/Darwin.cpp @@ -427,6 +427,40 @@ return Args.hasArg(options::OPT_fobjc_link_runtime); } +/// Check if the link command contains a path for the lto'd object file. +static Optional getObjectPathLTO(const ArgList &Args) { + bool ExpectPathNext = false; + for (Arg *A : Args) { + if (ExpectPathNext) { + // Expecting -Xlinker , but it's not there. + if (!A->getOption().matches(options::OPT_Xlinker)) + return None; + return StringRef(A->getValue(0)); + } + + bool isWl = A->getOption().matches(options::OPT_Wl_COMMA); + bool isXlinker = A->getOption().matches(options::OPT_Xlinker); + // We're looking for either: + // * -Wl,-object_path_lto, + // or + // * -Xlinker -object_path_lto -Xlinker + if (!isWl && !isXlinker) + continue; + + if (!A->containsValue("-object_path_lto")) + continue; + + // In case of -Wl, the path is in the same argument. + if (isWl) + return StringRef(A->getValue(1)); + + // In case of -Xlinker, we need to catch the next -Xlinker option and get + // the path from there. + ExpectPathNext = true; + } + return None; +} + void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -471,7 +505,11 @@ CmdArgs.push_back("-mllvm"); SmallString<128> F; - F = Output.getFilename(); + if (Optional Filename = getObjectPathLTO(Args)) + F = *Filename; + else + F = Output.getFilename(); + F += ".opt."; if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) Index: clang/test/Driver/darwin-ld.c =================================================================== --- clang/test/Driver/darwin-ld.c +++ clang/test/Driver/darwin-ld.c @@ -315,6 +315,20 @@ // PASS_REMARKS_OUTPUT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" // PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks-with-hotness +// Check that when -object_path_lto is used, we're passing the right path to -lto-pass-remarks-output. +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out -Wl,-object_path_lto,foo/bar_lto.o 2> %t.log +// RUN: FileCheck -check-prefix=REMARKS_OBJECT_PATH_LTO_WL %s < %t.log +// REMARKS_OBJECT_PATH_LTO_WL: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar_lto.o.opt.yaml" +// Also check for -Xlinker. +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out -Xlinker -object_path_lto -Xlinker foo/bar_lto.o 2> %t.log +// RUN: FileCheck -check-prefix=REMARKS_OBJECT_PATH_LTO_XLINKER %s < %t.log +// REMARKS_OBJECT_PATH_LTO_XLINKER: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar_lto.o.opt.yaml" +// Make sure that we pick the path based on -o if there is no second -Xlinker +// with the path after -object_path_lto. +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out -Xlinker -object_path_lto 2> %t.log +// RUN: FileCheck -check-prefix=REMARKS_OBJECT_PATH_LTO_XLINKER_MISSING %s < %t.log +// REMARKS_OBJECT_PATH_LTO_XLINKER_MISSING: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" + // RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### 2> %t.log // RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT_NO_O %s < %t.log // PASS_REMARKS_OUTPUT_NO_O: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "a.out.opt.yaml"