Index: clang/include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticDriverKinds.td +++ clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -113,6 +113,9 @@ def warn_drv_unsupported_option_for_flang : Warning< "the argument '%0' is not supported for option '%1'. Mapping to '%1%2'">, InGroup; +def warn_thinlto_partially_supported_for_flang : Warning< + "the option '-flto=thin' is only partially supported for flang">, + InGroup; def err_drv_invalid_thread_model_for_target : Error< "invalid thread model '%0' in '%1' for this target">; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2194,13 +2194,13 @@ def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group; def fapple_link_rtlib : Flag<["-"], "fapple-link-rtlib">, Group, HelpText<"Force linking the clang builtins runtime library">; -def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group, +def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option, FC1Option, FlangOption]>, Group, HelpText<"Set LTO mode">, Values<"thin,full">; def flto_EQ_jobserver : Flag<["-"], "flto=jobserver">, Group, Alias, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; def flto_EQ_auto : Flag<["-"], "flto=auto">, Group, Alias, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; -def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group, +def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option, FC1Option, FlangOption]>, Group, Alias, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; def fno_lto : Flag<["-"], "fno-lto">, Flags<[CoreOption, CC1Option]>, Group, HelpText<"Disable LTO mode (default)">; Index: clang/lib/Driver/ToolChains/Flang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Flang.cpp +++ clang/lib/Driver/ToolChains/Flang.cpp @@ -294,6 +294,17 @@ if (D.getDiags().getDiagnosticOptions().ShowColors) CmdArgs.push_back("-fcolor-diagnostics"); + // LTO mode is parsed by clang driver library. + LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); + assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); + if (LTOMode == LTOK_Full) + CmdArgs.push_back("-flto=full"); + else if (LTOMode == LTOK_Thin) { + D.getDiags().Report( + clang::diag::warn_thinlto_partially_supported_for_flang); + CmdArgs.push_back("-flto=thin"); + } + // -fPIC and related options. addPicOptions(Args, CmdArgs); Index: flang/include/flang/Frontend/CodeGenOptions.def =================================================================== --- flang/include/flang/Frontend/CodeGenOptions.def +++ flang/include/flang/Frontend/CodeGenOptions.def @@ -24,8 +24,13 @@ CODEGENOPT(DebugPassManager, 1, 0) ///< Prints debug information for the new ///< pass manager. -CODEGENOPT(PICLevel, 2, 0) ///< PIC level of the LLVM module. CODEGENOPT(IsPIE, 1, 0) ///< PIE level is the same as PIC Level. +CODEGENOPT(PICLevel, 2, 0) ///< PIC level of the LLVM module. + +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 + ///< compile step. ENUM_CODEGENOPT(RelocationModel, llvm::Reloc::Model, 3, llvm::Reloc::PIC_) ///< Name of the relocation model to use. Index: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -129,35 +129,47 @@ for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ)) opts.LLVMPassPlugins.push_back(a->getValue()); + // -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; + } + // -mrelocation-model option. - if (const llvm::opt::Arg *A = + if (const llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_mrelocation_model)) { - llvm::StringRef ModelName = A->getValue(); - auto RM = llvm::StringSwitch>(ModelName) - .Case("static", llvm::Reloc::Static) - .Case("pic", llvm::Reloc::PIC_) - .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) - .Case("ropi", llvm::Reloc::ROPI) - .Case("rwpi", llvm::Reloc::RWPI) - .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) - .Default(std::nullopt); - if (RM.has_value()) - opts.setRelocationModel(*RM); + llvm::StringRef modelName = a->getValue(); + auto relocModel = + llvm::StringSwitch>(modelName) + .Case("static", llvm::Reloc::Static) + .Case("pic", llvm::Reloc::PIC_) + .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) + .Case("ropi", llvm::Reloc::ROPI) + .Case("rwpi", llvm::Reloc::RWPI) + .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) + .Default(std::nullopt); + if (relocModel.has_value()) + opts.setRelocationModel(*relocModel); else diags.Report(clang::diag::err_drv_invalid_value) - << A->getAsString(args) << ModelName; + << a->getAsString(args) << modelName; } // -pic-level and -pic-is-pie option. - if (int PICLevel = getLastArgIntValue( + if (int picLevel = getLastArgIntValue( args, clang::driver::options::OPT_pic_level, 0, diags)) { - if (PICLevel > 2) + if (picLevel > 2) diags.Report(clang::diag::err_drv_invalid_value) << args.getLastArg(clang::driver::options::OPT_pic_level) ->getAsString(args) - << PICLevel; + << picLevel; - opts.PICLevel = PICLevel; + opts.PICLevel = picLevel; if (args.hasArg(clang::driver::options::OPT_pic_is_pie)) opts.IsPIE = 1; } Index: flang/lib/Frontend/FrontendActions.cpp =================================================================== --- flang/lib/Frontend/FrontendActions.cpp +++ flang/lib/Frontend/FrontendActions.cpp @@ -714,7 +714,12 @@ // Create the pass manager. llvm::ModulePassManager mpm; if (opts.OptimizationLevel == 0) - mpm = pb.buildO0DefaultPipeline(level, false); + mpm = pb.buildO0DefaultPipeline(level, opts.PrepareForFullLTO || + opts.PrepareForThinLTO); + else if (opts.PrepareForFullLTO) + mpm = pb.buildLTOPreLinkDefaultPipeline(level); + else if (opts.PrepareForThinLTO) + mpm = pb.buildThinLTOPreLinkDefaultPipeline(level); else mpm = pb.buildPerModuleDefaultPipeline(level); Index: flang/test/Driver/default-optimization-pipelines.f90 =================================================================== --- flang/test/Driver/default-optimization-pipelines.f90 +++ flang/test/Driver/default-optimization-pipelines.f90 @@ -1,10 +1,18 @@ ! Verify that`-O{n}` is indeed taken into account when defining the LLVM optimization/middle-end pass pipeline. ! RUN: %flang -S -O0 %s -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0 +! RUN: %flang -S -O0 %s -flto -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0-ANYLTO +! RUN: %flang -S -O0 %s -flto=thin -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0-ANYLTO ! RUN: %flang_fc1 -S -O0 %s -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0 +! RUN: %flang_fc1 -S -O0 %s -flto=full -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0-ANYLTO +! RUN: %flang_fc1 -S -O0 %s -flto=thin -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0-ANYLTO ! RUN: %flang -S -O2 %s -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O2 +! RUN: %flang -S -O2 %s -flto -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O2-LTO +! RUN: %flang -S -O2 %s -flto=thin -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O2-THINLTO ! RUN: %flang_fc1 -S -O2 %s -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O2 +! RUN: %flang_fc1 -S -O2 %s -flto=full -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O2-LTO +! RUN: %flang_fc1 -S -O2 %s -flto=thin -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O2-THINLTO ! Verify that only the left-most `-O{n}` is used ! RUN: %flang -S -O2 -O0 %s -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-O0 @@ -12,9 +20,19 @@ ! CHECK-O0-NOT: Running pass: SimplifyCFGPass on simple_loop_ ! CHECK-O0: Running analysis: TargetLibraryAnalysis on simple_loop_ +! CHECK-O0-ANYLTO: Running pass: CanonicalizeAliasesPass on [module] +! CHECK-O0-ANYLTO: Running pass: NameAnonGlobalPass on [module] ! CHECK-O2: Running pass: SimplifyCFGPass on simple_loop_ +! CHECK-O2-LTO-NOT: Running pass: EliminateAvailableExternallyPass +! CHECK-O2-LTO: Running pass: CanonicalizeAliasesPass on [module] +! CHECK-O2-LTO: Running pass: NameAnonGlobalPass on [module] + +! CHECK-O2-THINLTO-NOT: Running pass: LoopVectorizePass +! CHECK-O2-THINLTO: Running pass: CanonicalizeAliasesPass on [module] +! CHECK-O2-THINLTO: Running pass: NameAnonGlobalPass on [module] + subroutine simple_loop integer :: i do i=1,5 Index: flang/test/Driver/driver-help-hidden.f90 =================================================================== --- flang/test/Driver/driver-help-hidden.f90 +++ flang/test/Driver/driver-help-hidden.f90 @@ -43,6 +43,8 @@ ! CHECK-NEXT: Enable support for generating executables (experimental) ! CHECK-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics ! CHECK-NEXT: -flogical-abbreviations Enable logical abbreviations +! CHECK-NEXT: -flto= Set LTO mode +! CHECK-NEXT: -flto Enable LTO in 'full' mode ! CHECK-NEXT: -fno-automatic Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE ! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics ! CHECK-NEXT: -fno-integrated-as Disable the integrated assembler Index: flang/test/Driver/driver-help.f90 =================================================================== --- flang/test/Driver/driver-help.f90 +++ flang/test/Driver/driver-help.f90 @@ -41,6 +41,8 @@ ! HELP-NEXT: Specify where to find the compiled intrinsic modules ! HELP-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics ! HELP-NEXT: -flogical-abbreviations Enable logical abbreviations +! HELP-NEXT: -flto= Set LTO mode +! HELP-NEXT: -flto Enable LTO in 'full' mode ! HELP-NEXT: -fno-automatic Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE ! HELP-NEXT: -fno-color-diagnostics Disable colors in diagnostics ! HELP-NEXT: -fno-integrated-as Disable the integrated assembler @@ -124,6 +126,8 @@ ! HELP-FC1-NEXT: Specify where to find the compiled intrinsic modules ! HELP-FC1-NEXT: -flarge-sizes Use INTEGER(KIND=8) for the result type in size-related intrinsics ! HELP-FC1-NEXT: -flogical-abbreviations Enable logical abbreviations +! HELP-FC1-NEXT: -flto= Set LTO mode +! HELP-FC1-NEXT: -flto Enable LTO in 'full' mode ! HELP-FC1-NEXT: -fno-analyzed-objects-for-unparse ! HELP-FC1-NEXT: Do not use the analyzed objects when unparsing ! HELP-FC1-NEXT: -fno-automatic Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE Index: flang/test/Driver/lto-flags.f90 =================================================================== --- /dev/null +++ flang/test/Driver/lto-flags.f90 @@ -0,0 +1,31 @@ +! RUN: %flang -### -S %s 2>&1 | FileCheck %s --check-prefix=NO-LTO +! RUN: %flang -### -S -fno-lto %s 2>&1 | FileCheck %s --check-prefix=NO-LTO + +! Full LTO and aliases. +! RUN: %flang -### -S -flto %s 2>&1 | FileCheck %s --check-prefix=FULL-LTO +! RUN: %flang -### -S -flto=full %s 2>&1 | FileCheck %s --check-prefix=FULL-LTO +! RUN: %flang -### -S -flto=auto %s 2>&1 | FileCheck %s --check-prefix=FULL-LTO +! RUN: %flang -### -S -flto=jobserver %s 2>&1 | FileCheck %s --check-prefix=FULL-LTO + +! Also check linker plugin opt for Thin LTO +! RUN: %flang -### -flto=thin %s 2>&1 | FileCheck %s --check-prefix=THIN-LTO + +! RUN: %flang -### -S -flto=somelto %s 2>&1 | FileCheck %s --check-prefix=ERROR + +! FC1 tests. Check that it does not crash. +! RUN: %flang_fc1 -S %s -flto -o /dev/null +! RUN: %flang_fc1 -S %s -flto=full -o /dev/null +! RUN: %flang_fc1 -S %s -flto=thin -o /dev/null + +! NO-LTO: "-fc1" +! NO-LTO-NOT: flto + +! FULL-LTO: "-fc1" +! FULL-LTO-SAME: "-flto=full" + +! THIN-LTO: flang-new: warning: the option '-flto=thin' is only partially supported for flang +! THIN-LTO: "-fc1" +! THIN-LTO-SAME: "-flto=thin" +! THIN-LTO: "-plugin-opt=thinlto" + +! ERROR: error: unsupported argument 'somelto' to option '-flto=