diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/BackendUtil.cpp | 90 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenAction.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Driver/Tools.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 39 |
5 files changed, 159 insertions, 9 deletions
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index c86eeaf8d3d..6c934a8e155 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/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" @@ -763,3 +765,91 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, } } } + +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()); + // Create a constant that contains the bitcode. + // In case of embedding a marker, ignore the input Buf and use the empty + // ArrayRef. It is also legal to create a bitcode marker even Buf is empty. + 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>((const 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>((const 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"); + } +} diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 98685539d35..848acb4fe07 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -173,6 +173,8 @@ namespace clang { return; } + EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef()); + EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts, C.getTargetInfo().getDataLayout(), getModule(), Action, AsmOutStream); @@ -831,9 +833,13 @@ void CodeGenAction::ExecuteAction() { TheModule->setTargetTriple(TargetOpts.Triple); } + EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(), + MainFile->getMemBufferRef()); + LLVMContext &Ctx = TheModule->getContext(); Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler, &CI.getDiagnostics()); + EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(), TargetOpts, CI.getLangOpts(), CI.getTarget().getDataLayout(), TheModule.get(), BA, OS); diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 111614f3a53..1f2c64eaf73 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -507,14 +507,23 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { // 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); diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index e45c5c55626..25f8880af65 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -3773,12 +3773,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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 @@ -5709,7 +5709,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // 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. + // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of + // pristine IR generated by the frontend. Ideally, a new compile action should + // be added so both IR can be captured. + if (C.getDriver().isSaveTempsEnabled() && + !C.getDriver().embedBitcodeEnabled() && isa<CompileJobAction>(JA)) CmdArgs.push_back("-disable-llvm-passes"); if (Output.getType() == types::TY_Dependencies) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a97dc92adfa..f11188d0ff9 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -634,6 +634,45 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } } + // 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 (const auto &A : Args) { + // 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 (const auto &arg : ASL) { + StringRef ArgStr(arg); + 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); |