Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -134,7 +134,9 @@ "The provided host compiler IR file '%0' is required to generate code for OpenMP target regions but cannot be found.">; def err_drv_omp_host_target_not_supported : Error< "The target '%0' is not a supported OpenMP host target.">; - +def err_drv_bitcode_unsupported_on_toolchain : Error< + "-fembed-bitcode is not supported on versions of iOS prior to 6.0">; + def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup; def warn_drv_lto_libpath : Warning<"libLTO.dylib relative to clang installed dir not found; using 'ld' default search path instead">, InGroup; Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h +++ include/clang/Driver/Driver.h @@ -83,6 +83,12 @@ SaveTempsObj } SaveTemps; + enum BitcodeEmbedMode { + EmbedNone, + EmbedMarker, + EmbedBitcode + } BitcodeEmbed; + /// LTO mode selected via -f(no-)?lto(=.*)? options. LTOKind LTOMode; @@ -262,6 +268,9 @@ bool isSaveTempsEnabled() const { return SaveTemps != SaveTempsNone; } bool isSaveTempsObj() const { return SaveTemps == SaveTempsObj; } + bool embedBitcodeEnabled() const { return BitcodeEmbed == EmbedBitcode; } + bool embedBitcodeMarkerOnly() const { return BitcodeEmbed == EmbedMarker; } + /// @} /// @name Primary Functionality /// @{ Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -437,6 +437,12 @@ Flags<[DriverOption, CC1Option]>, HelpText<"Disable generation of linker directives for automatic library linking">; +def fembed_bitcode : Flag<["-"], "fembed-bitcode">, Group, + Flags<[CC1Option, CC1AsOption]>, + HelpText<"Embed LLVM IR bitcode as data">; +def fembed_bitcode_marker : Flag<["-"], "fembed-bitcode-marker">, + Group, Flags<[CC1Option]>, + HelpText<"Embed placeholder LLVM IR data as a marker">; def fgnu_inline_asm : Flag<["-"], "fgnu-inline-asm">, Group, Flags<[DriverOption]>; def fno_gnu_inline_asm : Flag<["-"], "fno-gnu-inline-asm">, Group, Flags<[DriverOption, CC1Option]>, Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -319,6 +319,11 @@ return false; } + /// SupportsEmbeddedBitcode - Does this tool chain support embedded bitcode. + virtual bool SupportsEmbeddedBitcode() const { + return false; + } + /// getThreadModel() - Which thread model does this target use? virtual std::string getThreadModel() const { return "posix"; } Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -50,7 +50,7 @@ DiagnosticsEngine &Diags, IntrusiveRefCntPtr VFS) : Opts(createDriverOptTable()), Diags(Diags), VFS(VFS), Mode(GCCMode), - SaveTemps(SaveTempsNone), LTOMode(LTOK_None), + SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), @@ -479,6 +479,19 @@ .Default(SaveTempsCwd); } + // Ignore -fembed-bitcode options with LTO + // since the output will be bitcode anyway. + if (!Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false)) { + if (Args.hasArg(options::OPT_fembed_bitcode)) + BitcodeEmbed = EmbedBitcode; + else if (Args.hasArg(options::OPT_fembed_bitcode_marker)) + BitcodeEmbed = EmbedMarker; + } else { + // claim the bitcode option under LTO so no warning is issued. + Args.ClaimAllArgs(options::OPT_fembed_bitcode); + Args.ClaimAllArgs(options::OPT_fembed_bitcode_marker); + } + setLTOMode(Args); std::unique_ptr UArgs = @@ -1723,7 +1736,8 @@ // CudaHostAction, updates CollapsedCHA with the pointer to it so the // caller can deal with extra handling such action requires. static const Tool *selectToolForJob(Compilation &C, bool SaveTemps, - const ToolChain *TC, const JobAction *JA, + bool EmbedBitcode, const ToolChain *TC, + const JobAction *JA, const ActionList *&Inputs, const CudaHostAction *&CollapsedCHA) { const Tool *ToolForJob = nullptr; @@ -1739,10 +1753,12 @@ !C.getArgs().hasArg(options::OPT__SLASH_Fa) && isa(JA) && Inputs->size() == 1 && isa(*Inputs->begin())) { - // A BackendJob is always preceded by a CompileJob, and without - // -save-temps they will always get combined together, so instead of - // checking the backend tool, check if the tool for the CompileJob - // has an integrated assembler. + // A BackendJob is always preceded by a CompileJob, and without -save-temps + // or -fembed-bitcode, they will always get combined together, so instead of + // checking the backend tool, check if the tool for the CompileJob has an + // integrated assembler. For -fembed-bitcode, CompileJob is still used to + // look up tools for BackendJob, but they need to match before we can split + // them. const ActionList *BackendInputs = &(*Inputs)[0]->getInputs(); // Compile job may be wrapped in CudaHostAction, extract it if // that's the case and update CollapsedCHA if we combine phases. @@ -1753,6 +1769,14 @@ const Tool *Compiler = TC->SelectTool(*CompileJA); if (!Compiler) return nullptr; + // When using -fembed-bitcode, it is required to have the same tool (clang) + // for both CompilerJA and BackendJA. Otherwise, combine two stages. + if (EmbedBitcode) { + JobAction *InputJA = cast(*Inputs->begin()); + const Tool *BackendTool = TC->SelectTool(*InputJA); + if (BackendTool == Compiler) + CompileJA = InputJA; + } if (Compiler->hasIntegratedAssembler()) { Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; @@ -1761,8 +1785,8 @@ } // A backend job should always be combined with the preceding compile job - // unless OPT_save_temps is enabled and the compiler is capable of emitting - // LLVM IR as an intermediate output. + // unless OPT_save_temps or OPT_fembed_bitcode is enabled and the compiler is + // capable of emitting LLVM IR as an intermediate output. if (isa(JA)) { // Check if the compiler supports emitting LLVM IR. assert(Inputs->size() == 1); @@ -1775,7 +1799,8 @@ const Tool *Compiler = TC->SelectTool(*CompileJA); if (!Compiler) return nullptr; - if (!Compiler->canEmitIR() || !SaveTemps) { + if (!Compiler->canEmitIR() || + (!SaveTemps && !EmbedBitcode)) { Inputs = &CompileJA->getInputs(); ToolForJob = Compiler; CollapsedCHA = CHA; @@ -1889,7 +1914,8 @@ const JobAction *JA = cast(A); const CudaHostAction *CollapsedCHA = nullptr; const Tool *T = - selectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs, CollapsedCHA); + selectToolForJob(C, isSaveTempsEnabled(), embedBitcodeEnabled(), TC, JA, + Inputs, CollapsedCHA); if (!T) return InputInfo(); Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -542,6 +542,8 @@ bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + bool SupportsEmbeddedBitcode() const override; + SanitizerMask getSupportedSanitizers() const override; }; Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -1103,6 +1103,13 @@ return !Triple.isWatchABI(); } +bool Darwin::SupportsEmbeddedBitcode() const { + assert(TargetInitialized && "Target not initialized!"); + if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0)) + return false; + return true; +} + bool MachO::isPICDefault() const { return true; } bool MachO::isPIEDefault() const { return false; } Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3625,6 +3625,17 @@ Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + // Embed-bitcode option. + if (C.getDriver().embedBitcodeEnabled() && + (isa(JA) || isa(JA))) { + // Add flags implied by -fembed-bitcode. + CmdArgs.push_back("-fembed-bitcode"); + // Disable all llvm IR level optimizations. + CmdArgs.push_back("-disable-llvm-optzns"); + } + if (C.getDriver().embedBitcodeMarkerOnly()) + CmdArgs.push_back("-fembed-bitcode-marker"); + // We normally speed up the clang process a bit by skipping destructors at // exit, but when we're generating diagnostics we can rely on some of the // cleanup. @@ -7262,6 +7273,15 @@ else CmdArgs.push_back("-no_pie"); } + // for embed-bitcode, use -bitcode_bundle in linker command + if (C.getDriver().embedBitcodeEnabled() || + C.getDriver().embedBitcodeMarkerOnly()) { + // Check if the toolchain supports bitcode build flow. + if (MachOTC.SupportsEmbeddedBitcode()) + CmdArgs.push_back("-bitcode_bundle"); + else + D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain); + } Args.AddLastArg(CmdArgs, options::OPT_prebind); Args.AddLastArg(CmdArgs, options::OPT_noprebind); Index: test/Driver/embed-bitcode.c =================================================================== --- /dev/null +++ test/Driver/embed-bitcode.c @@ -0,0 +1,38 @@ +// RUN: %clang -ccc-print-bindings -c %s -fembed-bitcode 2>&1 | FileCheck %s +// CHECK: clang +// CHECK: clang + +// RUN: %clang %s -fembed-bitcode 2>&1 -### | FileCheck %s -check-prefix=CHECK-CC +// CHECK-CC: -cc1 +// CHECK-CC: -emit-llvm-bc +// CHECK-CC: -cc1 +// CHECK-CC: -emit-obj +// CHECK-CC: -fembed-bitcode +// CHECK-CC: ld +// CHECK-CC: -bitcode_bundle + +// RUN: %clang %s -save-temps -fembed-bitcode 2>&1 -### | FileCheck %s -check-prefix=CHECK-SAVE-TEMP +// CHECK-SAVE-TEMP: -cc1 +// CHECK-SAVE-TEMP: -E +// CHECK-SAVE-TEMP: -cc1 +// CHECK-SAVE-TEMP: -emit-llvm-bc +// CHECK-SAVE-TEMP: -cc1 +// CHECK-SAVE-TEMP: -S +// CHECK-SAVE-TEMP: -fembed-bitcode +// CHECK-SAVE-TEMP: -cc1as +// CHECK-SAVE-TEMP: ld +// CHECK-SAVE-TEMP: -bitcode_bundle + +// RUN: %clang -c %s -flto -fembed-bitcode 2>&1 -### | FileCheck %s -check-prefix=CHECK-LTO +// CHECK-LTO: -cc1 +// CHECK-LTO: -emit-llvm-bc +// CHECK-LTO-NOT: warning: argument unused during compilation: '-fembed-bitcode' +// CHECK-LTO-NOT: -cc1 +// CHECK-LTO-NOT: -fembed-bitcode + +// RUN: %clang -c %s -fembed-bitcode-marker 2>&1 -### | FileCheck %s -check-prefix=CHECK-MARKER +// CHECK-MARKER: -cc1 +// CHECK-MARKER: -emit-obj +// CHECK-MARKER: -fembed-bitcode-marker +// CHECK-MARKER-NOT: -cc1 +