steven_wu updated this revision to Diff 52435. steven_wu added a comment. Address the feedback from Richard: Break -fembed-bitcode option into multiple -fembed-bitcode= options. -fembed-bitcode=all will embed both bitcode and commandline and -fembed-bitcode=bitcode will embed only the bitcode in the object file.
http://reviews.llvm.org/D17392 Files: include/clang/CodeGen/BackendUtil.h include/clang/Driver/Options.td include/clang/Frontend/CodeGenOptions.def include/clang/Frontend/CodeGenOptions.h lib/CodeGen/BackendUtil.cpp lib/CodeGen/CodeGenAction.cpp lib/Driver/Driver.cpp lib/Driver/Tools.cpp lib/Frontend/CompilerInvocation.cpp test/Driver/embed-bitcode.c test/Frontend/embed-bitcode.ll
Index: test/Frontend/embed-bitcode.ll =================================================================== --- /dev/null +++ test/Frontend/embed-bitcode.ll @@ -0,0 +1,57 @@ +; check .ll input +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \ +; RUN: -fembed-bitcode=all -x ir %s -o - \ +; RUN: | FileCheck %s +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \ +; RUN: -fembed-bitcode=marker -x ir %s -o - \ +; RUN: | FileCheck %s -check-prefix=CHECK-MARKER +; RUN: %clang_cc1 -triple aarch64-unknown-linux-gnueabi -emit-llvm \ +; RUN: -fembed-bitcode=all -x ir %s -o - \ +; RUN: | FileCheck %s -check-prefix=CHECK-ELF + +; check .bc input +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm-bc \ +; RUN: -x ir %s -o %t.bc +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \ +; RUN: -fembed-bitcode=all -x ir %t.bc -o - \ +; RUN: | FileCheck %s +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \ +; RUN: -fembed-bitcode=bitcode -x ir %t.bc -o - \ +; RUN: | FileCheck %s -check-prefix=CHECK-ONLY-BITCODE +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \ +; RUN: -fembed-bitcode=marker -x ir %t.bc -o - \ +; RUN: | FileCheck %s -check-prefix=CHECK-MARKER + +; run through -fembed-bitcode twice and make sure it doesn't crash +; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm-bc \ +; RUN: -fembed-bitcode=all -x ir %s -o - \ +; RUN: | %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \ +; RUN: -fembed-bitcode=all -x ir - -o /dev/null + +; check the magic number of bitcode at the beginning of the string +; CHECK: @llvm.embedded.module +; CHECK: c"\DE\C0\17\0B +; CHECK: section "__LLVM,__bitcode" +; CHECK: @llvm.cmdline +; CHECK: section "__LLVM,__cmdline" + +; CHECK-ELF: @llvm.embedded.module +; CHECK-ELF: section ".llvmbc" +; CHECK-ELF: @llvm.cmdline +; CHECK-ELF: section ".llvmcmd" + +; CHECK-ONLY-BITCODE: @llvm.embedded.module +; CHECK-ONLY-BITCODE: c"\DE\C0\17\0B +; CHECK-ONLY-BITCODE: section "__LLVM,__bitcode" +; CHECK-ONLY-BITCODE-NOT: @llvm.cmdline +; CHECK-ONLY-BITCODE-NOT: section "__LLVM,__cmdline" + +; CHECK-MARKER: @llvm.embedded.module +; CHECK-MARKER: constant [0 x i8] zeroinitializer +; CHECK-MARKER: section "__LLVM,__bitcode" +; CHECK-MARKER: @llvm.cmdline +; CHECK-MARKER: section "__LLVM,__cmdline" + +define i32 @f0() { + ret i32 0 +} Index: test/Driver/embed-bitcode.c =================================================================== --- test/Driver/embed-bitcode.c +++ test/Driver/embed-bitcode.c @@ -7,28 +7,35 @@ // CHECK-CC: -emit-llvm-bc // CHECK-CC: -cc1 // CHECK-CC: -emit-obj -// CHECK-CC: -fembed-bitcode +// CHECK-CC: -fembed-bitcode=all +// RUN: %clang %s -c -fembed-bitcode=bitcode -fintegrated-as 2>&1 -### | FileCheck %s -check-prefix=CHECK-BITCODE +// CHECK-BITCODE: -cc1 +// CHECK-BITCODE: -emit-llvm-bc +// CHECK-BITCODE: -cc1 +// CHECK-BITCODE: -emit-obj +// CHECK-BITCODE: -fembed-bitcode=bitcode +// // RUN: %clang %s -c -save-temps -fembed-bitcode -fintegrated-as 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: -fembed-bitcode=all // CHECK-SAVE-TEMP: -cc1as // 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 +// CHECK-LTO-NOT: -fembed-bitcode=all // RUN: %clang -c %s -fembed-bitcode-marker -fintegrated-as 2>&1 -### | FileCheck %s -check-prefix=CHECK-MARKER // CHECK-MARKER: -cc1 // CHECK-MARKER: -emit-obj -// CHECK-MARKER: -fembed-bitcode-marker +// CHECK-MARKER: -fembed-bitcode=marker // CHECK-MARKER-NOT: -cc1 Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -646,6 +646,47 @@ } } } + // Handle -fembed-bitcode option. + if (Arg *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) { + StringRef Name = A->getValue(); + unsigned Model = llvm::StringSwitch<unsigned>(Name) + .Case("off", CodeGenOptions::Embed_Off) + .Case("all", CodeGenOptions::Embed_All) + .Case("bitcode", CodeGenOptions::Embed_Bitcode) + .Case("marker", CodeGenOptions::Embed_Marker) + .Default(~0U); + if (Model == ~0U) { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; + Success = false; + } else + Opts.setEmbedBitcode( + static_cast<CodeGenOptions::EmbedBitcodeKind>(Model)); + } + // FIXME: For backend options that are not yet recorded as function + // attributes in the IR, keep track of them so we can embed them in a + // separate data section and use them when building the bitcode. + if (Opts.getEmbedBitcode() == CodeGenOptions::Embed_All) { + for (ArgList::const_iterator A = Args.begin(), AE = Args.end(); + A != AE; ++ A) { + // Do not encode output and input. + if ((*A)->getOption().getID() == options::OPT_o || + (*A)->getOption().getID() == options::OPT_INPUT || + (*A)->getOption().getID() == options::OPT_x || + (*A)->getOption().getID() == options::OPT_fembed_bitcode || + ((*A)->getOption().getGroup().isValid() && + (*A)->getOption().getGroup().getID() == options::OPT_W_Group)) + continue; + ArgStringList ASL; + (*A)->render(Args, ASL); + for (ArgStringList::iterator it = ASL.begin(), ie = ASL.end(); + it != ie; ++ it) { + StringRef ArgStr(*it); + Opts.CmdArgs.insert(Opts.CmdArgs.end(), ArgStr.begin(), ArgStr.end()); + // using \00 to seperate each commandline options. + Opts.CmdArgs.push_back('\0'); + } + } + } Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3730,12 +3730,12 @@ if (C.getDriver().embedBitcodeEnabled() && (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { // Add flags implied by -fembed-bitcode. - CmdArgs.push_back("-fembed-bitcode"); + Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); // Disable all llvm IR level optimizations. CmdArgs.push_back("-disable-llvm-optzns"); } if (C.getDriver().embedBitcodeMarkerOnly()) - CmdArgs.push_back("-fembed-bitcode-marker"); + 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 @@ -5689,7 +5689,10 @@ // With -save-temps, we want to save the unoptimized bitcode output from the // CompileJobAction, use -disable-llvm-passes to get pristine IR generated // by the frontend. - if (C.getDriver().isSaveTempsEnabled() && isa<CompileJobAction>(JA)) + // When -fembed-bitcode is enabled, optimized bitcode is emitted because it + // has slightly different breakdown between stages. + if (C.getDriver().isSaveTempsEnabled() && + !C.getDriver().embedBitcodeEnabled() && isa<CompileJobAction>(JA)) CmdArgs.push_back("-disable-llvm-passes"); if (Output.getType() == types::TY_Dependencies) { Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -482,14 +482,23 @@ // 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; + if (Arg *A = Args.getLastArg(options::OPT_fembed_bitcode_EQ)) { + StringRef Name = A->getValue(); + unsigned Model = llvm::StringSwitch<unsigned>(Name) + .Case("off", EmbedNone) + .Case("all", EmbedBitcode) + .Case("bitcode", EmbedBitcode) + .Case("marker", EmbedMarker) + .Default(~0U); + if (Model == ~0U) { + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) + << Name; + } else + BitcodeEmbed = static_cast<BitcodeEmbedMode>(Model); + } } 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); + Args.ClaimAllArgs(options::OPT_fembed_bitcode_EQ); } setLTOMode(Args); Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -173,6 +173,8 @@ return; } + EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef()); + EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, C.getTargetInfo().getDataLayout(), getModule(), Action, AsmOutStream); @@ -804,6 +806,9 @@ TheModule->setTargetTriple(TargetOpts.Triple); } + EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(), + MainFile->getMemBufferRef()); + EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(), TargetOpts, CI.getLangOpts(), CI.getTarget().getDataLayout(), TheModule.get(), BA, OS); Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -16,9 +16,11 @@ #include "clang/Frontend/Utils.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/IR/DataLayout.h" @@ -730,3 +732,90 @@ } } } + +static const char* getSectionNameForBitcode(const Triple &T) { + switch (T.getObjectFormat()) { + case Triple::MachO: + return "__LLVM,__bitcode"; + case Triple::COFF: + case Triple::ELF: + case Triple::UnknownObjectFormat: + return ".llvmbc"; + } +} + +static const char* getSectionNameForCommandline(const Triple &T) { + switch (T.getObjectFormat()) { + case Triple::MachO: + return "__LLVM,__cmdline"; + case Triple::COFF: + case Triple::ELF: + case Triple::UnknownObjectFormat: + return ".llvmcmd"; + } +} + +// With -fembed-bitcode, save a copy of the llvm IR as data in the +// __LLVM,__bitcode section. +void clang::EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, + llvm::MemoryBufferRef Buf) +{ + if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Off) + return; + + // Embed the bitcode for the llvm module. + std::string Data; + ArrayRef<uint8_t> ModuleData; + Triple T(M->getTargetTriple()); + if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker) { + if (!isBitcode((const unsigned char*)Buf.getBufferStart(), + (const unsigned char*)Buf.getBufferEnd())) { + // If the input is LLVM Assembly, bitcode is produced by serializing + // the module. Use-lists order need to be perserved in this case. + llvm::raw_string_ostream OS(Data); + llvm::WriteBitcodeToFile(M, OS, /* ShouldPreserveUseListOrder */ true); + ModuleData = ArrayRef<uint8_t>((uint8_t*)OS.str().data(), + OS.str().size()); + } else { + // If the input is LLVM bitcode, write the input byte stream directly. + ModuleData = ArrayRef<uint8_t>((uint8_t*)Buf.getBufferStart(), + Buf.getBufferSize()); + } + } + llvm::Constant *ModuleConstant = + llvm::ConstantDataArray::get(M->getContext(), ModuleData); + // Use Appending linkage so it doesn't get optimized out. + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + *M, ModuleConstant->getType(), true, llvm::GlobalValue::AppendingLinkage, + ModuleConstant); + GV->setSection(getSectionNameForBitcode(T)); + if (llvm::GlobalVariable *Old = + M->getGlobalVariable("llvm.embedded.module")) { + assert(Old->use_empty() && "llvm.embedded.module must have no uses"); + GV->takeName(Old); + Old->eraseFromParent(); + } else { + GV->setName("llvm.embedded.module"); + } + + // Return if only bitcode needs to be embedded. + if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Bitcode) + return; + + // Embed command-line options. + ArrayRef<uint8_t> CmdData((uint8_t*)CGOpts.CmdArgs.data(), + CGOpts.CmdArgs.size()); + llvm::Constant *CmdConstant = + llvm::ConstantDataArray::get(M->getContext(), CmdData); + GV = new llvm::GlobalVariable(*M, CmdConstant->getType(), true, + llvm::GlobalValue::AppendingLinkage, + CmdConstant); + GV->setSection(getSectionNameForCommandline(T)); + if (llvm::GlobalVariable *Old = M->getGlobalVariable("llvm.cmdline")) { + assert(Old->use_empty() && "llvm.cmdline must have no uses"); + GV->takeName(Old); + Old->eraseFromParent(); + } else { + GV->setName("llvm.cmdline"); + } +} Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -86,6 +86,13 @@ ProfileIRInstr, // IR level PGO instrumentation in LLVM. }; + enum EmbedBitcodeKind { + Embed_Off, // No embedded bitcode. + Embed_All, // Embed both bitcode and commandline in the output. + Embed_Bitcode, // Embed just the bitcode in the output. + Embed_Marker // Embed a marker as a placeholder for bitcode. + }; + /// The code model to use (-mcmodel). std::string CodeModel; @@ -199,6 +206,9 @@ /// Set of sanitizer checks that trap rather than diagnose. SanitizerSet SanitizeTrap; + /// List of backend command-line options for -fembed-bitcode. + std::vector<uint8_t> CmdArgs; + /// \brief A list of all -fno-builtin-* function names (e.g., memset). std::vector<std::string> NoBuiltinFuncs; @@ -242,6 +252,7 @@ bool hasProfileIRUse() const { return getProfileUse() == ProfileIRInstr; } + }; } // end namespace clang Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -64,6 +64,8 @@ CODEGENOPT(EmulatedTLS , 1, 0) ///< Set when -femulated-tls is enabled. /// \brief FP_CONTRACT mode (on/off/fast). ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On) +/// \brief Embed Bitcode mode (off/all/bitcode/marker). +ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off) CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables ///< are required. CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -437,11 +437,14 @@ Flags<[DriverOption, CC1Option]>, HelpText<"Disable generation of linker directives for automatic library linking">; +def fembed_bitcode_EQ : Joined<["-"], "fembed-bitcode=">, + Group<f_Group>, Flags<[DriverOption, CC1Option]>, MetaVarName<"<option>">, + HelpText<"Embed LLVM bitcode (option: off, all, bitcode, marker)">; def fembed_bitcode : Flag<["-"], "fembed-bitcode">, Group<f_Group>, - Flags<[CC1Option, CC1AsOption]>, + Alias<fembed_bitcode_EQ>, AliasArgs<["all"]>, HelpText<"Embed LLVM IR bitcode as data">; def fembed_bitcode_marker : Flag<["-"], "fembed-bitcode-marker">, - Group<f_Group>, Flags<[CC1Option]>, + Alias<fembed_bitcode_EQ>, AliasArgs<["marker"]>, HelpText<"Embed placeholder LLVM IR data as a marker">; def fgnu_inline_asm : Flag<["-"], "fgnu-inline-asm">, Group<f_Group>, Flags<[DriverOption]>; def fno_gnu_inline_asm : Flag<["-"], "fno-gnu-inline-asm">, Group<f_Group>, Index: include/clang/CodeGen/BackendUtil.h =================================================================== --- include/clang/CodeGen/BackendUtil.h +++ include/clang/CodeGen/BackendUtil.h @@ -16,6 +16,7 @@ namespace llvm { class Module; + class MemoryBufferRef; } namespace clang { @@ -37,6 +38,9 @@ const TargetOptions &TOpts, const LangOptions &LOpts, const llvm::DataLayout &TDesc, llvm::Module *M, BackendAction Action, raw_pwrite_stream *OS); + + void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, + llvm::MemoryBufferRef Buf); } #endif
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits