Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -168,6 +168,7 @@ /// CFI and traditional whole program /// devirtualization that require whole /// program IR support. +CODEGENOPT(UnifiedLTO, 1, 0) ///< Use the unified LTO pipeline. CODEGENOPT(IncrementalLinkerCompatible, 1, 0) ///< Emit an object file which can ///< be used with an incremental ///< linker. Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2337,6 +2337,11 @@ Alias, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option, FC1Option, FlangOption]>, Group, Alias, AliasArgs<["full"]>, HelpText<"Enable LTO in 'full' mode">; +defm unified_lto : BoolFOption<"unified-lto", + CodeGenOpts<"UnifiedLTO">, DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[CC1Option], "">>; def fno_lto : Flag<["-"], "fno-lto">, Flags<[CoreOption, CC1Option]>, Group, HelpText<"Disable LTO mode (default)">; def foffload_lto_EQ : Joined<["-"], "foffload-lto=">, Flags<[CoreOption]>, Group, Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -825,6 +825,7 @@ // Only enable CGProfilePass when using integrated assembler, since // non-integrated assemblers don't recognize .cgprofile section. PTO.CallGraphProfile = !CodeGenOpts.DisableIntegratedAS; + PTO.UnifiedLTO = CodeGenOpts.UnifiedLTO; LoopAnalysisManager LAM; FunctionAnalysisManager FAM; @@ -1004,7 +1005,7 @@ }); } - if (IsThinLTO) { + if (IsThinLTO || (IsLTO && CodeGenOpts.UnifiedLTO)) { MPM = PB.buildThinLTOPreLinkDefaultPipeline(Level); } else if (IsLTO) { MPM = PB.buildLTOPreLinkDefaultPipeline(Level); @@ -1030,8 +1031,10 @@ if (!ThinLinkOS) return; } - MPM.addPass(ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &ThinLinkOS->os() - : nullptr)); + if (CodeGenOpts.UnifiedLTO) + TheModule->addModuleFlag(Module::Error, "UnifiedLTO", uint32_t(1)); + MPM.addPass(ThinLTOBitcodeWriterPass( + *OS, ThinLinkOS ? &ThinLinkOS->os() : nullptr)); } else { MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists, /*EmitLTOSummary=*/true)); @@ -1042,11 +1045,13 @@ // targets bool EmitLTOSummary = shouldEmitRegularLTOSummary(); if (EmitLTOSummary) { - if (!TheModule->getModuleFlag("ThinLTO")) + if (!TheModule->getModuleFlag("ThinLTO") && !CodeGenOpts.UnifiedLTO) TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", uint32_t(1)); + if (CodeGenOpts.UnifiedLTO) + TheModule->addModuleFlag(Module::Error, "UnifiedLTO", uint32_t(1)); } if (Action == Backend_EmitBC) MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists, Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4769,6 +4769,15 @@ // Select the appropriate action. RewriteKind rewriteKind = RK_None; + + bool UnifiedLTO = false; + if (IsUsingLTO) { + UnifiedLTO = Args.hasFlag(options::OPT_funified_lto, + options::OPT_fno_unified_lto, false); + if (UnifiedLTO) + CmdArgs.push_back("-funified-lto"); + } + // If CollectArgsForIntegratedAssembler() isn't called below, claim the args // it claims when not running an assembler. Otherwise, clang would emit // "argument unused" warnings for assembler flags when e.g. adding "-E" to @@ -4913,7 +4922,11 @@ assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); CmdArgs.push_back(Args.MakeArgString( Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); - CmdArgs.push_back("-flto-unit"); + // PS4 uses the legacy LTO API, which does not support some of the + // features enabled by -flto-unit. + if ((RawTriple.getOS() != llvm::Triple::PS4) || + (D.getLTOMode() == LTOK_Full) || !UnifiedLTO) + CmdArgs.push_back("-flto-unit"); } } } @@ -7290,17 +7303,24 @@ } if (WholeProgramVTables) { - // Propagate -fwhole-program-vtables if this is an LTO compile. - if (IsUsingLTO) - CmdArgs.push_back("-fwhole-program-vtables"); + // PS4 uses the legacy LTO API, which does not support this feature in + // ThinLTO mode. + bool IsPS4 = getToolChain().getTriple().isPS4(); + // Check if we passed LTO options but they were suppressed because this is a // device offloading action, or we passed device offload LTO options which // were suppressed because this is not the device offload action. + // Check if we are using PS4 in regular LTO mode. // Otherwise, issue an error. - else if (!D.isUsingLTO(!IsDeviceOffloadAction)) + if ((!IsUsingLTO && !D.isUsingLTO(!IsDeviceOffloadAction)) || + (IsPS4 && !UnifiedLTO && (D.getLTOMode() != LTOK_Full))) D.Diag(diag::err_drv_argument_only_allowed_with) << "-fwhole-program-vtables" - << "-flto"; + << ((IsPS4 && !UnifiedLTO) ? "-flto=full" : "-flto"); + + // Propagate -fwhole-program-vtables if this is an LTO compile. + if (IsUsingLTO) + CmdArgs.push_back("-fwhole-program-vtables"); } bool DefaultsSplitLTOUnit = Index: clang/lib/Driver/ToolChains/PS4CPU.cpp =================================================================== --- clang/lib/Driver/ToolChains/PS4CPU.cpp +++ clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -204,6 +204,13 @@ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) TC.addSanitizerArgs(Args, CmdArgs, "-l", ""); + if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) { + if (D.getLTOMode() == LTOK_Thin) + CmdArgs.push_back("--lto=thin"); + else if (D.getLTOMode() == LTOK_Full) + CmdArgs.push_back("--lto=full"); + } + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -1776,6 +1776,8 @@ Opts.PrepareForThinLTO = true; else if (S != "full") Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << S; + if (Args.hasArg(OPT_funified_lto)) + Opts.PrepareForThinLTO = true; } if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) { if (IK.getLanguage() != Language::LLVM_IR) Index: clang/test/CodeGen/asan-unified-lto.ll =================================================================== --- /dev/null +++ clang/test/CodeGen/asan-unified-lto.ll @@ -0,0 +1,18 @@ +; Verify that in the cases of explict distinct LTO piplines, +; explicit unified LTO pipelines, and the default LTO pipeline, +; there is no crash and the anonoymous global is named +; as expected. + +; RUN: %clang_cc1 -emit-llvm-bc -O1 -flto -fsanitize=address -o - -x ir < %s | llvm-dis -o - | FileCheck %s +; RUN: %clang_cc1 -emit-llvm-bc -O1 -flto -funified-lto -fsanitize=address -o - -x ir < %s | llvm-dis -o - | FileCheck %s +; CHECK: @anon.3ee0898e5200a57350fed5485ae5d237 + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-linux-gnu" + +@.str = private unnamed_addr constant [5 x i8] c"none\00", align 1 + +define ptr @f() { + %ptr = getelementptr inbounds [5 x i8], ptr @.str, i32 0, i32 0 + ret ptr %ptr +} Index: clang/test/CodeGen/emit-summary-index.c =================================================================== --- clang/test/CodeGen/emit-summary-index.c +++ clang/test/CodeGen/emit-summary-index.c @@ -14,4 +14,10 @@ // RUN: %clang_cc1 -flto -triple x86_64-pc-linux-gnu -emit-llvm-bc -disable-llvm-passes < %s -o %t.bc // RUN: %clang_cc1 -flto -triple x86_64-pc-linux-gnu -emit-llvm-bc -x ir < %t.bc | llvm-bcanalyzer -dump | FileCheck --check-prefix=LTOINDEX %s +/// Check that emitting bitcode works for Unified LTO, when either LTO mode is specified +// RUN: %clang_cc1 -flto=thin -funified-lto -emit-llvm-bc < %s | llvm-bcanalyzer -dump | FileCheck --check-prefix=UNITHIN %s +// RUN: %clang_cc1 -flto -funified-lto -emit-llvm-bc < %s | llvm-bcanalyzer -dump | FileCheck --check-prefix=UNITHIN %s + +// UNITHIN: &1 | FileCheck --check-prefix=THIN %s +// RUN: mv %t.0 %t.1 +// RUN: %clang --target=x86_64-unknown-unknown-linux -Xclang -fdebug-pass-manager -flto=full -funified-lto -O2 -c %s -o %t.0 2>&1 | FileCheck --check-prefix=THIN %s +// RUN: %clang --target=x86_64-unknown-unknown-linux -Xclang -fdebug-pass-manager -flto=thin -O2 -c %s -o %t.2 2>&1 | FileCheck --check-prefix=THIN %s +// RUN: mv %t.2 %t.3 +// RUN: %clang --target=x86_64-unknown-unknown-linux -Xclang -fdebug-pass-manager -flto=full -O2 -c %s -o %t.2 2>&1 | FileCheck --check-prefix=FULL %s +// RUN: cmp %t.0 %t.1 +// THIN: ThinLTOBitcodeWriterPass +// FULL-NOT: ThinLTOBitcodeWriterPass + +int foo() { + return 2 + 2; +} + +int bar() { + return foo() + 1; +} Index: clang/test/CodeGenCXX/unified-cfi-lto.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/unified-cfi-lto.cpp @@ -0,0 +1,21 @@ +// Ensure that the frontend adds the proper metadata when CFI is +// enabled. +// RUN: %clang --target=x86_64-scei-ps4 -funified-lto -flto -fsanitize=cfi -fvisibility=hidden -c %s -o %t.o +// RUN: llvm-dis %t.o + +typedef int (*FuncPtr)(); + +int a() { return 1; } +int b() { return 2; } +int c() { return 3; } + +FuncPtr func[3] = {a,b,c}; + +int +main(int argc, char *argv[]) { + // CHECK: call i1 @llvm.type.test + return func[argc](); + // CHECK-LABEL: trap +} + +// CHECK: typeTests: Index: clang/test/Driver/unified-lto.c =================================================================== --- /dev/null +++ clang/test/Driver/unified-lto.c @@ -0,0 +1,11 @@ +// RUN: %clang --target=x86_64-unknown-linux -### %s -flto=full -funified-lto 2>&1 | FileCheck --check-prefix=UNIT %s +// RUN: %clang --target=x86_64-unknown-linux -### %s -flto=thin -funified-lto 2>&1 | FileCheck --check-prefix=UNIT %s +// RUN: %clang --target=x86_64-scei-ps4 -### %s -flto=full -funified-lto 2>&1 | FileCheck --check-prefix=UNIT %s +// RUN: %clang --target=x86_64-scei-ps4 -### %s -flto=thin -funified-lto 2>&1 | FileCheck --check-prefix=NOUNIT %s + +// UNIT: "-flto-unit" +// NOUNIT-NOT: "-flto-unit" + +// RUN: %clang --target=x86_64-sie-prospero -### %s -funified-lto 2>&1 | FileCheck --check-prefix=NOUNILTO %s +// NOUNILTO-NOT: -funified-lto +// NOUNILTO: clang: warning: argument unused during compilation: '-funified-lto' Index: clang/test/Driver/whole-program-vtables.c =================================================================== --- clang/test/Driver/whole-program-vtables.c +++ clang/test/Driver/whole-program-vtables.c @@ -6,6 +6,9 @@ // RUN: %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -flto -### -- %s 2>&1 | FileCheck --check-prefix=LTO %s // LTO: "-fwhole-program-vtables" +// RUN: %clang --target=x86_64-pc-linux-gnu -fwhole-program-vtables -funified-lto -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s +// RUN: %clang --target=x86_64-pc-linux-gnu -fwhole-program-vtables -fno-unified-lto -### %s 2>&1 | FileCheck --check-prefix=NO-LTO %s + // RUN: %clang -target x86_64-unknown-linux -fwhole-program-vtables -fno-whole-program-vtables -flto -### %s 2>&1 | FileCheck --check-prefix=LTO-DISABLE %s // RUN: %clang_cl --target=x86_64-pc-win32 -fwhole-program-vtables -fno-whole-program-vtables -flto -### -- %s 2>&1 | FileCheck --check-prefix=LTO-DISABLE %s // LTO-DISABLE-NOT: "-fwhole-program-vtables"