summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/BackendUtil.cpp90
-rw-r--r--clang/lib/CodeGen/CodeGenAction.cpp6
-rw-r--r--clang/lib/Driver/Driver.cpp21
-rw-r--r--clang/lib/Driver/Tools.cpp12
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp39
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);
OpenPOWER on IntegriCloud