diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -264,6 +264,9 @@ directory (``/tmp`` on \*NIX systems, if none of the environment variables TMPDIR, TMP, and TEMP are specified). +- ``-ffat-lto-objects`` can now be used to emit object files with both object + code and LLVM bitcode. Previously this flag was ignored for GCC compatibility. + Removed Compiler Flags ------------------------- - The deprecated flag `-fmodules-ts` is removed. Please use ``-std=c++20`` diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -164,6 +164,7 @@ ///< compile step. CODEGENOPT(LTOUnit, 1, 0) ///< Emit IR to support LTO unit features (CFI, whole ///< program vtable opt). +CODEGENOPT(FatLTO, 1, 0) ///< Set when -ffat-lto-objects is enabled. CODEGENOPT(EnableSplitLTOUnit, 1, 0) ///< Enable LTO unit splitting to support /// CFI and traditional whole program /// devirtualization that require whole diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2366,6 +2366,11 @@ Flags<[CoreOption, CC1Option]>, Group, HelpText<"Write minimized bitcode to for the ThinLTO thin link only">, MarshallingInfoString>; +defm fat_lto_objects : BoolFOption<"fat-lto-objects", + CodeGenOpts<"FatLTO">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[CC1Option], " fat LTO object support">>; def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group, Flags<[NoXarchOption, CC1Option, CoreOption]>, HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit)">, @@ -5136,7 +5141,6 @@ defm reorder_blocks : BooleanFFlag<"reorder-blocks">, Group; defm branch_count_reg : BooleanFFlag<"branch-count-reg">, Group; defm default_inline : BooleanFFlag<"default-inline">, Group; -defm fat_lto_objects : BooleanFFlag<"fat-lto-objects">, Group; defm float_store : BooleanFFlag<"float-store">, Group; defm friend_injection : BooleanFFlag<"friend-injection">, Group; defm function_attribute_list : BooleanFFlag<"function-attribute-list">, Group; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -55,6 +55,7 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/SubtargetFeature.h" #include "llvm/TargetParser/Triple.h" +#include "llvm/Transforms/IPO/EmbedBitcodePass.h" #include "llvm/Transforms/IPO/LowerTypeTests.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/InstCombine/InstCombine.h" @@ -1011,7 +1012,12 @@ }); } - if (IsThinLTO || (IsLTO && CodeGenOpts.UnifiedLTO)) { + bool IsThinOrUnifiedLTO = IsThinLTO || (IsLTO && CodeGenOpts.UnifiedLTO); + if (CodeGenOpts.FatLTO) { + MPM = PB.buildFatLTODefaultPipeline(Level, IsThinOrUnifiedLTO, + IsThinOrUnifiedLTO || + shouldEmitRegularLTOSummary()); + } else if (IsThinOrUnifiedLTO) { MPM = PB.buildThinLTOPreLinkDefaultPipeline(Level); } else if (IsLTO) { MPM = PB.buildLTOPreLinkDefaultPipeline(Level); @@ -1066,6 +1072,14 @@ MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists, EmitLTOSummary)); } + } else if (CodeGenOpts.FatLTO) { + // Set EnableSplitLTOUnit, since FatLTO uses a different action than + // Backend_EmitBC or Backend_EmitLL, and thus it won't be set correctly + if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) + TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + uint32_t(CodeGenOpts.EnableSplitLTOUnit)); + if (CodeGenOpts.UnifiedLTO) + TheModule->addModuleFlag(Module::Error, "UnifiedLTO", uint32_t(1)); } // Now that we have all of the passes ready, run them. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4729,8 +4729,13 @@ } case phases::Backend: { if (isUsingLTO() && TargetDeviceOffloadKind == Action::OFK_None) { - types::ID Output = - Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; + types::ID Output; + if (Args.hasArg(options::OPT_S)) + Output = types::TY_LTO_IR; + else if (Args.hasArg(options::OPT_ffat_lto_objects)) + Output = types::TY_PP_Asm; + else + Output = types::TY_LTO_BC; return C.MakeAction(Input, Output); } if (isUsingLTO(/* IsOffload */ true) && diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7353,6 +7353,22 @@ if (SplitLTOUnit) CmdArgs.push_back("-fsplit-lto-unit"); + if (Arg *A = Args.getLastArg(options::OPT_ffat_lto_objects, + options::OPT_fno_fat_lto_objects)) { + if (IsUsingLTO && A->getOption().matches(options::OPT_ffat_lto_objects)) { + assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); + if (!Triple.isOSBinFormatELF()) { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TC.getTripleString(); + } + CmdArgs.push_back(Args.MakeArgString( + Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); + CmdArgs.push_back("-flto-unit"); + CmdArgs.push_back("-ffat-lto-objects"); + A->render(Args, CmdArgs); + } + } + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, options::OPT_fno_global_isel)) { CmdArgs.push_back("-mllvm"); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -617,6 +617,10 @@ PluginName + Suffix, Plugin); CmdArgs.push_back(Args.MakeArgString(Twine(PluginPrefix) + Plugin)); + } else { + // For LLD we need to enable fat object support + if (Args.hasArg(options::OPT_ffat_lto_objects)) + CmdArgs.push_back("-fat-lto-objects"); } const char *PluginOptPrefix = IsOSAIX ? "-bplugin_opt:" : "-plugin-opt="; diff --git a/clang/test/CodeGen/embed-fat-lto-objects.c b/clang/test/CodeGen/embed-fat-lto-objects.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/embed-fat-lto-objects.c @@ -0,0 +1,17 @@ +// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -fsplit-lto-unit -emit-llvm < %s | FileCheck %s --check-prefixes=FULL,SPLIT +// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=FULL,SPLIT + +// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -fsplit-lto-unit -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=THIN,SPLIT +// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=THIN,NOSPLIT + +/// Check that the ThinLTO metadata is only set false for full LTO. +// FULL: ![[#]] = !{i32 1, !"ThinLTO", i32 0} +// THIN-NOT: ![[#]] = !{i32 1, !"ThinLTO", i32 0} + +/// Be sure we enable split LTO unints correctly under -ffat-lto-objects. +// SPLIT: ![[#]] = !{i32 1, !"EnableSplitLTOUnit", i32 1} +// NOSPLIT: ![[#]] = !{i32 1, !"EnableSplitLTOUnit", i32 0} + +int test(void) { + return 0xabcd; +} diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -424,7 +424,6 @@ // CHECK-WARNING-DAG: optimization flag '-fwhole-program' is not supported // CHECK-WARNING-DAG: optimization flag '-fcaller-saves' is not supported // CHECK-WARNING-DAG: optimization flag '-freorder-blocks' is not supported -// CHECK-WARNING-DAG: optimization flag '-ffat-lto-objects' is not supported // CHECK-WARNING-DAG: optimization flag '-fmerge-constants' is not supported // CHECK-WARNING-DAG: optimization flag '-finline-small-functions' is not supported // CHECK-WARNING-DAG: optimization flag '-ftree-dce' is not supported diff --git a/clang/test/Driver/fat-lto-objects.c b/clang/test/Driver/fat-lto-objects.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/fat-lto-objects.c @@ -0,0 +1,19 @@ +// RUN: %clang --target=x86_64-unknown-linux-gnu -flto -ffat-lto-objects -### %s -c 2>&1 | FileCheck %s -check-prefix=CHECK-CC +// CHECK-CC: -cc1 +// CHECK-CC-SAME: -emit-obj +// CHECK-CC-SAME: -ffat-lto-objects + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffat-lto-objects -### %s -c 2>&1 | FileCheck %s -check-prefix=CHECK-CC-NOLTO +// CHECK-CC-NOLTO: -cc1 +// CHECK-CC-NOLTO-SAME: -emit-obj +// CHECK-CC-NOLTO-NOT: -ffat-lto-objects +// CHECK-CC-NOLTO-NOT: warning: argument unused during compilation: '-ffat-lto-objects' + +/// We need to pass an additional flag to lld when linking w/ -flto -ffat-lto-objects +/// But it should not be there when LTO is disabled w/ -fno-lto +// RUN: %clang --target=x86_64-unknown-linux-gnu --sysroot=%S/Inputs/basic_cross_linux_tree %s \ +// RUN: -fuse-ld=lld -flto -ffat-lto-objects -### 2>&1 | FileCheck --check-prefix=LTO %s +// RUN: %clang --target=x86_64-unknown-linux-gnu --sysroot=%S/Inputs/basic_cross_linux_tree %s \ +// RUN: -fuse-ld=lld -fno-lto -ffat-lto-objects -### 2>&1 | FileCheck --check-prefix=NOLTO %s +// LTO: "-fat-lto-objects" +// NOLTO-NOT: "-fat-lto-objects"