diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 902a28d60b349..1940f6fec9a40 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3171,10 +3171,11 @@ def fthin_link_bitcode_EQ : Joined<["-"], "fthin-link-bitcode=">, MarshallingInfoString>; defm fat_lto_objects : BoolFOption<"fat-lto-objects", CodeGenOpts<"FatLTO">, DefaultFalse, - PosFlag, - NegFlag, + PosFlag, + NegFlag, BothFlags<[], [ClangOption, CC1Option], " fat LTO object support">>; def flto_partitions_EQ : Joined<["-"], "flto-partitions=">, Group, + Visibility<[ClangOption, FlangOption]>, HelpText<"Number of partitions to use for parallel full LTO codegen, ld.lld only.">; def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group, Visibility<[ClangOption, CC1Option, CLOption]>, diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 1535f4cebf436..1cb5d793f12cd 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -182,6 +182,25 @@ void Flang::addCodegenOptions(const ArgList &Args, CmdArgs.push_back("-fcoarray"); } +void Flang::addLTOOptions(const ArgList &Args, ArgStringList &CmdArgs) const { + const ToolChain &TC = getToolChain(); + const Driver &D = TC.getDriver(); + DiagnosticsEngine &Diags = D.getDiags(); + LTOKind LTOMode = D.getLTOMode(); + // LTO mode is parsed by the Clang driver library. + assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); + if (LTOMode == LTOK_Full) + CmdArgs.push_back("-flto=full"); + else if (LTOMode == LTOK_Thin) { + Diags.Report( + Diags.getCustomDiagID(DiagnosticsEngine::Warning, + "the option '-flto=thin' is a work in progress")); + CmdArgs.push_back("-flto=thin"); + } + Args.addAllArgs(CmdArgs, {options::OPT_ffat_lto_objects, + options::OPT_fno_fat_lto_objects}); +} + void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of // (RelocationModel, PICLevel, IsPIE). @@ -821,7 +840,6 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = TC.getDriver(); ArgStringList CmdArgs; - DiagnosticsEngine &Diags = D.getDiags(); // Invoke ourselves in -fc1 mode. CmdArgs.push_back("-fc1"); @@ -884,17 +902,7 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, handleColorDiagnosticsArgs(D, Args, CmdArgs); - // LTO mode is parsed by the Clang driver library. - LTOKind LTOMode = D.getLTOMode(); - assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); - if (LTOMode == LTOK_Full) - CmdArgs.push_back("-flto=full"); - else if (LTOMode == LTOK_Thin) { - Diags.Report( - Diags.getCustomDiagID(DiagnosticsEngine::Warning, - "the option '-flto=thin' is a work in progress")); - CmdArgs.push_back("-flto=thin"); - } + addLTOOptions(Args, CmdArgs); // -fPIC and related options. addPicOptions(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h index 7c24a623af393..98167e1b75e15 100644 --- a/clang/lib/Driver/ToolChains/Flang.h +++ b/clang/lib/Driver/ToolChains/Flang.h @@ -40,6 +40,14 @@ class LLVM_LIBRARY_VISIBILITY Flang : public Tool { void addPreprocessingOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; + /// Extract LTO options from the driver arguments and add them to + /// the command arguments. + /// + /// \param [in] Args The list of input driver arguments + /// \param [out] CmdArgs The list of output command arguments + void addLTOOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + /// Extract PIC options from the driver arguments and add them to /// the command arguments. /// diff --git a/flang/include/flang/Frontend/CodeGenOptions.def b/flang/include/flang/Frontend/CodeGenOptions.def index cdeea93c9aecb..fa29b8ed79532 100644 --- a/flang/include/flang/Frontend/CodeGenOptions.def +++ b/flang/include/flang/Frontend/CodeGenOptions.def @@ -35,6 +35,7 @@ CODEGENOPT(InstrumentFunctions, 1, 0) ///< Set when -finstrument_functions is CODEGENOPT(IsPIE, 1, 0) ///< PIE level is the same as PIC Level. CODEGENOPT(PICLevel, 2, 0) ///< PIC level of the LLVM module. +CODEGENOPT(PrepareForFatLTO , 1, 0) ///< Set when -ffat-lto-objects is enabled. CODEGENOPT(PrepareForFullLTO , 1, 0) ///< Set when -flto is enabled on the ///< compile step. CODEGENOPT(PrepareForThinLTO , 1, 0) ///< Set when -flto=thin is enabled on the diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index fb3a132cae30e..e8a39b67f4f82 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -325,17 +325,6 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, if (args.hasArg(clang::driver::options::OPT_finstrument_functions)) opts.InstrumentFunctions = 1; - // -flto=full/thin option. - if (const llvm::opt::Arg *a = - args.getLastArg(clang::driver::options::OPT_flto_EQ)) { - llvm::StringRef s = a->getValue(); - assert((s == "full" || s == "thin") && "Unknown LTO mode."); - if (s == "full") - opts.PrepareForFullLTO = true; - else - opts.PrepareForThinLTO = true; - } - if (const llvm::opt::Arg *a = args.getLastArg( clang::driver::options::OPT_mcode_object_version_EQ)) { llvm::StringRef s = a->getValue(); @@ -1482,6 +1471,7 @@ static bool parseLinkerOptionsArgs(CompilerInvocation &invoc, llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) { llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple); + CodeGenOptions &opts = invoc.getCodeGenOpts(); // TODO: support --dependent-lib on other platforms when MLIR supports // !llvm.dependent.lib @@ -1494,8 +1484,35 @@ static bool parseLinkerOptionsArgs(CompilerInvocation &invoc, return false; } - invoc.getCodeGenOpts().DependentLibs = + opts.DependentLibs = args.getAllArgValues(clang::driver::options::OPT_dependent_lib); + + // -flto=full/thin option. + if (const llvm::opt::Arg *a = + args.getLastArg(clang::driver::options::OPT_flto_EQ)) { + llvm::StringRef s = a->getValue(); + assert((s == "full" || s == "thin") && "Unknown LTO mode."); + if (s == "full") + opts.PrepareForFullLTO = true; + else + opts.PrepareForThinLTO = true; + } + + // -ffat-lto-objects + if (const llvm::opt::Arg *arg = + args.getLastArg(clang::driver::options::OPT_ffat_lto_objects, + clang::driver::options::OPT_fno_fat_lto_objects)) { + opts.PrepareForFatLTO = + arg->getOption().matches(clang::driver::options::OPT_ffat_lto_objects); + if (opts.PrepareForFatLTO) { + assert((opts.PrepareForFullLTO || opts.PrepareForThinLTO) && + "Unknown LTO mode"); + + if (!triple.isOSBinFormatELF()) + diags.Report(clang::diag::err_drv_unsupported_opt_for_target) + << arg->getAsString(args) << triple.getTriple(); + } + } return true; } diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 3bef6b1c31825..6e5aa203d84a4 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -995,7 +995,14 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) { // Create the pass manager. llvm::ModulePassManager mpm; - if (opts.PrepareForFullLTO) + if (opts.PrepareForFatLTO) { + // The module summary should be emitted by default for regular LTO + // except for ld64 targets. + bool emitSummary = opts.PrepareForThinLTO || opts.PrepareForFullLTO || + triple.getVendor() != llvm::Triple::Apple; + mpm = pb.buildFatLTODefaultPipeline(level, opts.PrepareForThinLTO, + emitSummary); + } else if (opts.PrepareForFullLTO) mpm = pb.buildLTOPreLinkDefaultPipeline(level); else if (opts.PrepareForThinLTO) mpm = pb.buildThinLTOPreLinkDefaultPipeline(level); diff --git a/flang/test/Driver/fatlto-err.f90 b/flang/test/Driver/fatlto-err.f90 new file mode 100644 index 0000000000000..d11b4e47a5f7b --- /dev/null +++ b/flang/test/Driver/fatlto-err.f90 @@ -0,0 +1,6 @@ +! RUN: not %flang_fc1 -triple x86_64-apple-macos10.13 -flto -ffat-lto-objects -emit-llvm-bc %s 2>&1 | FileCheck %s --check-prefix=ERROR +! ERROR: error: unsupported option '-ffat-lto-objects' for target 'x86_64-apple-macos10.13' + +parameter(i=1) +integer :: j +end program diff --git a/flang/test/Driver/lto-fatlto.f90 b/flang/test/Driver/lto-fatlto.f90 new file mode 100644 index 0000000000000..c52d6e386ef0b --- /dev/null +++ b/flang/test/Driver/lto-fatlto.f90 @@ -0,0 +1,21 @@ +! REQUIRES: x86-registered-target +! checks fatlto objects: that valid bitcode is included in the object file generated. + +! RUN: %flang -fc1 -triple x86_64-unknown-linux-gnu -flto -ffat-lto-objects -emit-obj %s -o %t.o +! RUN: llvm-readelf -S %t.o | FileCheck %s --check-prefixes=ELF +! RUN: llvm-objcopy --dump-section=.llvm.lto=%t.bc %t.o +! RUN: llvm-dis %t.bc -o - | FileCheck %s --check-prefixes=DIS + +! ELF: .llvm.lto +! DIS: define void @_QQmain() +! DIS-NEXT: ret void +! DIS-NEXT: } + +! RUN: %flang -fc1 -triple x86_64-unknown-linux-gnu -flto -ffat-lto-objects -S %s -o - | FileCheck %s --check-prefixes=ASM + +! ASM: .section .llvm.lto,"e",@llvm_lto +! ASM-NEXT: .Lllvm.embedded.object: +! ASM-NEXT: .asciz "BC +! ASM-NEXT: .size .Lllvm.embedded.object +program test +end program diff --git a/flang/test/Driver/lto-lld-flags.f90 b/flang/test/Driver/lto-lld-flags.f90 new file mode 100644 index 0000000000000..055526ab02a9d --- /dev/null +++ b/flang/test/Driver/lto-lld-flags.f90 @@ -0,0 +1,20 @@ +! UNSUPPORTED: system-windows +! check flto-partitions is passed to lld, and not to fc1 +! RUN: %flang -### -fuse-ld=lld -flto=full -flto-partitions=16 %s 2>&1 | FileCheck %s --check-prefixes=LLD-PART,FC1-PART + +! FC1-PART: "-fc1" +! FC1-PART-SAME: "-flto=full" +! NOT-FC1-PART-SAME: "-flto-partitions=16" +! LLD-PART: ld.lld +! LLD-PART-SAME: "--lto-partitions=16" + +! check fat-lto-objects is passed to lld, fc1 +! RUN: %flang -### -fuse-ld=lld -flto -ffat-lto-objects %s 2>&1 | FileCheck %s --check-prefixes=LLD-FAT,FC1-FAT + +! FC1-FAT: "-fc1" +! FC1-FAT-SAME: "-flto=full" +! FC1-FAT-SAME: "-ffat-lto-objects" +! LLD-FAT: ld.lld +! LLD-FAT-SAME: "--fat-lto-objects" +program test +end program