steven_wu created this revision.
steven_wu added a subscriber: cfe-commits.
Herald added subscribers: dschuff, jfb.

Teach clang to embed bitcode inside bitcode. When -fembed-bitcode cc1
option is used, clang will embed both the input bitcode and cc1
commandline into the bitcode in special sections before compiling to
the object file.  Using -fembed-bitcode-marker will only introduce a
marker in both sections.

Don't emit uselist order for -fembed-bitcode

Embedded bitcode are embedded without serialization in their normal
flow. No uselist order need to be recorded.

Apply whitelist to options used in embedded bitcode

Add a whitelist for the options that are allowed to be used with
-fembed-bitcode. That is minimize the number of the cc1 command
that needs to be embedded in the object file.

http://reviews.llvm.org/D17389

Files:
  include/clang/Basic/DiagnosticDriverKinds.td
  include/clang/CodeGen/BackendUtil.h
  include/clang/Frontend/CodeGenOptions.def
  include/clang/Frontend/CodeGenOptions.h
  lib/CodeGen/BackendUtil.cpp
  lib/CodeGen/CodeGenAction.cpp
  lib/Driver/Tools.cpp
  lib/Driver/Tools.h
  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,48 @@
+; check .ll input
+; RUN: %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \
+; RUN:    -fembed-bitcode -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 -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 -x ir %t.bc -o - \
+; RUN:    | FileCheck %s
+; 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 -x ir %s -o - \
+; RUN: | %clang_cc1 -triple thumbv7-apple-ios8.0.0 -emit-llvm \
+; RUN:    -fembed-bitcode -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-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
@@ -5,6 +5,7 @@
 // RUN: %clang %s -fembed-bitcode 2>&1 -### | FileCheck %s -check-prefix=CHECK-CC
 // CHECK-CC: -cc1
 // CHECK-CC: -emit-llvm-bc
+// CHECK-CC-NOT: -emit-llvm-uselists
 // CHECK-CC: -cc1
 // CHECK-CC: -emit-obj
 // CHECK-CC: -fembed-bitcode
@@ -24,3 +25,62 @@
 // CHECK-MARKER: -fembed-bitcode-marker
 // CHECK-MARKER-NOT: -cc1
 
+// Check clang complains about ios version min if it is used to generate link command.
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=6.0 %s -fembed-bitcode -### 2>&1 | \
+// RUN:   FileCheck %s -check-prefix=CHECK-PLATFORM-SUPPORTED
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=5.0 %s -fembed-bitcode -### 2>&1 | \
+// RUN:   FileCheck %s -check-prefix=CHECK-PLATFORM-UNSUPPORTED
+// RUN: %clang -target armv7-apple-darwin -miphoneos-version-min=5.0 -c %s -fembed-bitcode -### 2>&1 | \
+// RUN:   FileCheck %s -check-prefix=CHECK-PLATFORM-SUPPORTED
+// CHECK-PLATFORM-SUPPORTED-NOT: -fembed-bitcode is not supported on versions of iOS prior to 6.0
+// CHECK-PLATFORM-UNSUPPORTED: -fembed-bitcode is not supported on versions of iOS prior to 6.0
+
+// RUN: %clang -c %s -fembed-bitcode -mkernel -fapple-kext -ffunction-sections \
+// RUN:   -fno-function-sections -fdata-sections -fno-data-sections \
+// RUN:   -funique-section-names -fno-unique-section-names -mrestrict-it \
+// RUN:   -mno-restrict-it -mstackrealgin -mno-stackrealign -mstack-alignment=8 \
+// RUN:   -mcmodel=small -mlong-calls -mno-long-calls -ggnu-pubnames \
+// RUN:   -gdwarf-arange -fdebug-types-section -fno-debug-types-section \
+// RUN:   -fdwarf-directory-asm -fno-dwarf-directory-asm \
+// RUN:   -mrelax-all -mno-relax-all -ftrap-function=trap \
+// RUN:   -ffixed-r9 -mfix-cortex-a53-835769 -mno-fix-cortex-a53-835769 \
+// RUN:   -ffixed-x18 -mglobal-merge -mno-global-merge -mred-zone -mno-red-zone \
+// RUN:   -Wa,-L -Xlinker,-L -mllvm -test -### 2>&1 | \
+// RUN:   FileCheck %s -check-prefix=CHECK-UNSUPPORTED-OPT
+// CHECK-UNSUPPORTED-OPT: -mkernel is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fapple-kext is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -ffunction-sections is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fno-function-sections is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fdata-sections is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fno-data-sections is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -funique-section-names is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fno-unique-section-names is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mrestrict-it is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-restrict-it is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-stackrealign is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mstack-alignment= is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mcmodel= is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mlong-calls is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-long-calls is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -ggnu-pubnames is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fdebug-types-section is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fno-debug-types-section is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fdwarf-directory-asm is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -fno-dwarf-directory-asm is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mrelax-all is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-relax-all is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -ftrap-function= is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -ffixed-r9 is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mfix-cortex-a53-835769 is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-fix-cortex-a53-835769 is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -ffixed-x18 is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mglobal-merge is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-global-merge is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mred-zone is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mno-red-zone is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -Wa, is not supported with -fembed-bitcode
+// CHECK-UNSUPPORTED-OPT: -mllvm is not supported with -fembed-bitcode
+
+// Check -mrelax-all is not passed as CC1 flag even with -O0.
+// RUN: %clang %s -fembed-bitcode -O0 2>&1 -### | FileCheck %s -check-prefix=CHECK-RELAX-ALL
+// CHECK-RELAX-ALL-NOT: -mrelax-all
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -616,6 +616,34 @@
       }
     }
   }
+	// Handle -fembed-bitcode option.
+  Opts.EmbedBitcode = Args.hasArg(OPT_fembed_bitcode);
+  Opts.EmbedMarkerOnly = Args.hasArg(OPT_fembed_bitcode_marker);
+  // 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.EmbedBitcode) {
+    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.h
===================================================================
--- lib/Driver/Tools.h
+++ lib/Driver/Tools.h
@@ -91,6 +91,10 @@
                                  llvm::opt::ArgStringList &cmdArgs,
                                  RewriteKind rewrite) const;
 
+  void RenderEmbeddedBitcodeOptions(const llvm::Triple &Triple,
+                                    const llvm::opt::ArgList &Args,
+                                    llvm::opt::ArgStringList &CmdArgs) const;
+
   void AddClangCLArgs(const llvm::opt::ArgList &Args,
                       llvm::opt::ArgStringList &CmdArgs,
                       codegenoptions::DebugInfoKind *DebugInfoKind,
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -2481,6 +2481,11 @@
 /// \brief Check if -relax-all should be passed to the internal assembler.
 /// This is done by default when compiling non-assembler source with -O0.
 static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
+  // If embed bitcode, RelaxAll is not allowed.
+  if (C.getDriver().embedBitcodeEnabled() ||
+      C.getDriver().embedBitcodeMarkerOnly())
+    return false;
+
   bool RelaxDefault = true;
 
   if (Arg *A = Args.getLastArg(options::OPT_O_Group))
@@ -3470,6 +3475,184 @@
     CmdArgs.push_back("-KPIC");
 }
 
+void Clang::RenderEmbeddedBitcodeOptions(const llvm::Triple &Triple,
+                                         const ArgList &Args,
+                                         ArgStringList &CmdArgs) const {
+  const Driver &D = getToolChain().getDriver();
+  // reject options that shouldn't be supported in bitcode
+  // also reject kernel/kext.
+  for (const auto &A : Args) {
+    if (A->getOption().getID() == options::OPT_mkernel ||
+        A->getOption().getID() == options::OPT_fapple_kext ||
+        A->getOption().getID() == options::OPT_ffunction_sections ||
+        A->getOption().getID() == options::OPT_fno_function_sections ||
+        A->getOption().getID() == options::OPT_fdata_sections ||
+        A->getOption().getID() == options::OPT_fno_data_sections ||
+        A->getOption().getID() == options::OPT_funique_section_names ||
+        A->getOption().getID() == options::OPT_fno_unique_section_names ||
+        A->getOption().getID() == options::OPT_mrestrict_it ||
+        A->getOption().getID() == options::OPT_mno_restrict_it ||
+        A->getOption().getID() == options::OPT_mstackrealign ||
+        A->getOption().getID() == options::OPT_mno_stackrealign ||
+        A->getOption().getID() == options::OPT_mstack_alignment ||
+        A->getOption().getID() == options::OPT_mcmodel_EQ ||
+        A->getOption().getID() == options::OPT_mlong_calls ||
+        A->getOption().getID() == options::OPT_mno_long_calls ||
+        A->getOption().getID() == options::OPT_ggnu_pubnames ||
+        A->getOption().getID() == options::OPT_gdwarf_aranges ||
+        A->getOption().getID() == options::OPT_fdebug_types_section ||
+        A->getOption().getID() == options::OPT_fno_debug_types_section ||
+        A->getOption().getID() == options::OPT_fdwarf_directory_asm ||
+        A->getOption().getID() == options::OPT_fno_dwarf_directory_asm ||
+        A->getOption().getID() == options::OPT_mrelax_all ||
+        A->getOption().getID() == options::OPT_mno_relax_all ||
+        A->getOption().getID() == options::OPT_ftrap_function_EQ ||
+        A->getOption().getID() == options::OPT_ffixed_r9 ||
+        A->getOption().getID() == options::OPT_mfix_cortex_a53_835769 ||
+        A->getOption().getID() == options::OPT_mno_fix_cortex_a53_835769 ||
+        A->getOption().getID() == options::OPT_ffixed_x18 ||
+        A->getOption().getID() == options::OPT_mglobal_merge ||
+        A->getOption().getID() == options::OPT_mno_global_merge ||
+        A->getOption().getID() == options::OPT_mred_zone ||
+        A->getOption().getID() == options::OPT_mno_red_zone ||
+        A->getOption().getID() == options::OPT_Wa_COMMA ||
+        A->getOption().getID() == options::OPT_Xassembler ||
+        A->getOption().getID() == options::OPT_mllvm)
+      D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling();
+  }
+
+  // render float point related args
+  if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
+    CmdArgs.push_back("-mlimit-float-precision");
+    CmdArgs.push_back(A->getValue());
+  }
+  bool OFastEnabled = isOptimizationLevelFast(Args);
+  OptSpecifier FastMathAliasOption =
+      OFastEnabled ? options::OPT_Ofast : options::OPT_ffast_math;
+  bool MathErrno = getToolChain().IsMathErrnoDefault();
+  if (Arg *A =
+          Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
+                          options::OPT_fno_fast_math, options::OPT_fmath_errno,
+                          options::OPT_fno_math_errno)) {
+    // Turning on -ffast_math (with either flag) removes the need for MathErrno.
+    // However, turning *off* -ffast_math merely restores the toolchain default
+    // (which may be false).
+    if (A->getOption().getID() == options::OPT_fno_math_errno ||
+        A->getOption().getID() == options::OPT_ffast_math ||
+        A->getOption().getID() == options::OPT_Ofast)
+      MathErrno = false;
+    else if (A->getOption().getID() == options::OPT_fmath_errno)
+      MathErrno = true;
+  }
+  if (MathErrno)
+    CmdArgs.push_back("-fmath-errno");
+  bool ReciprocalMath = false;
+  if (Arg *A = Args.getLastArg(
+          options::OPT_ffast_math, FastMathAliasOption,
+          options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations,
+          options::OPT_fno_unsafe_math_optimizations,
+          options::OPT_freciprocal_math, options::OPT_fno_reciprocal_math))
+    if (A->getOption().getID() != options::OPT_fno_fast_math &&
+        A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+        A->getOption().getID() != options::OPT_fno_reciprocal_math)
+      ReciprocalMath = true;
+  bool SignedZeros = true;
+  if (Arg *A = Args.getLastArg(
+          options::OPT_ffast_math, FastMathAliasOption,
+          options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations,
+          options::OPT_fno_unsafe_math_optimizations,
+          options::OPT_fsigned_zeros, options::OPT_fno_signed_zeros))
+    if (A->getOption().getID() != options::OPT_fno_fast_math &&
+        A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations &&
+        A->getOption().getID() != options::OPT_fsigned_zeros)
+      SignedZeros = false;
+
+  if (!SignedZeros)
+    CmdArgs.push_back("-fno-signed-zeros");
+
+  if (ReciprocalMath)
+    CmdArgs.push_back("-freciprocal-math");
+
+  if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption,
+                               options::OPT_fno_fast_math,
+                               options::OPT_ffp_contract)) {
+    if (A->getOption().getID() == options::OPT_ffp_contract) {
+      StringRef Val = A->getValue();
+      if (Val == "fast" || Val == "on" || Val == "off") {
+        CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val));
+      } else {
+        D.Diag(diag::err_drv_unsupported_option_argument)
+            << A->getOption().getName() << Val;
+      }
+    } else if (A->getOption().matches(options::OPT_ffast_math) ||
+               (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) {
+      CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast"));
+    }
+  }
+
+  // Add target specific flags.
+  switch (getToolChain().getArch()) {
+  default:
+    break;
+
+  case llvm::Triple::arm:
+  case llvm::Triple::armeb:
+  case llvm::Triple::thumb:
+  case llvm::Triple::thumbeb:
+    // Use the effective triple, which takes into account the deployment target.
+    AddARMTargetArgs(Triple, Args, CmdArgs, false);
+    break;
+
+  case llvm::Triple::aarch64:
+  case llvm::Triple::aarch64_be:
+    AddAArch64TargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::mips:
+  case llvm::Triple::mipsel:
+  case llvm::Triple::mips64:
+  case llvm::Triple::mips64el:
+    AddMIPSTargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::ppc:
+  case llvm::Triple::ppc64:
+  case llvm::Triple::ppc64le:
+    AddPPCTargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::sparc:
+  case llvm::Triple::sparcel:
+  case llvm::Triple::sparcv9:
+    AddSparcTargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    AddX86TargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::hexagon:
+    AddHexagonTargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::wasm32:
+  case llvm::Triple::wasm64:
+    AddWebAssemblyTargetArgs(Args, CmdArgs);
+    break;
+  }
+
+  // Optimization level for CodeGen.
+  if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
+    if (A->getOption().matches(options::OPT_O4)) {
+      CmdArgs.push_back("-O3");
+      D.Diag(diag::warn_O4_is_O3);
+    } else {
+      A->render(Args, CmdArgs);
+    }
+  }
+}
+
 void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                          const InputInfo &Output, const InputInfoList &Inputs,
                          const ArgList &Args, const char *LinkingOutput) const {
@@ -3534,11 +3717,6 @@
                                                 << TripleStr;
   }
 
-  // Push all default warning arguments that are specific to
-  // the given target.  These come before user provided warning options
-  // are provided.
-  getToolChain().addClangWarningOptions(CmdArgs);
-
   // Select the appropriate action.
   RewriteKind rewriteKind = RK_None;
 
@@ -3606,7 +3784,9 @@
     // loading the bitcode up in 'opt' or 'llc' and running passes gives the
     // same result as running passes here.  For LTO, we don't need to preserve
     // the use-list order, since serialization to bitcode is part of the flow.
-    if (JA.getType() == types::TY_LLVM_BC)
+    // For embed-bitcode, bitcode is directly embedded without serialization.
+    if (JA.getType() == types::TY_LLVM_BC &&
+        !C.getDriver().embedBitcodeEnabled())
       CmdArgs.push_back("-emit-llvm-uselists");
 
     if (D.isUsingLTO())
@@ -3627,6 +3807,30 @@
     CmdArgs.push_back("-fembed-bitcode");
     // Disable all llvm IR level optimizations.
     CmdArgs.push_back("-disable-llvm-optzns");
+
+    RenderEmbeddedBitcodeOptions(Triple, Args, CmdArgs);
+
+    // Input/Output file.
+    if (Output.getType() == types::TY_Dependencies) {
+      // Handled with other dependency code.
+    } else if (Output.isFilename()) {
+      CmdArgs.push_back("-o");
+      CmdArgs.push_back(Output.getFilename());
+    } else {
+      assert(Output.isNothing() && "Invalid output.");
+    }
+
+    for (const auto &II : Inputs) {
+      addDashXForInput(Args, II, CmdArgs);
+
+      if (II.isFilename())
+        CmdArgs.push_back(II.getFilename());
+      else
+        II.getInputArg().renderAsInput(Args, CmdArgs);
+    }
+    const char *Exec = getToolChain().getDriver().getClangProgramPath();
+    C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+    return;
   }
   if (C.getDriver().embedBitcodeMarkerOnly())
     CmdArgs.push_back("-fembed-bitcode-marker");
@@ -4406,6 +4610,11 @@
     }
   }
 
+  // Push all default warning arguments that are specific to
+  // the given target.  These come before user provided warning options
+  // are provided.
+  getToolChain().addClangWarningOptions(CmdArgs);
+
   // Warn about ignored options to clang.
   for (const Arg *A :
        Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) {
@@ -5553,7 +5762,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/CodeGen/CodeGenAction.cpp
===================================================================
--- lib/CodeGen/CodeGenAction.cpp
+++ lib/CodeGen/CodeGenAction.cpp
@@ -173,6 +173,8 @@
           return;
       }
 
+      EmbedBitcode(TheModule.get(), CodeGenOpts, llvm::MemoryBufferRef());
+
       EmitBackendOutput(Diags, CodeGenOpts, TargetOpts, LangOpts,
                         C.getTargetInfo().getDataLayoutString(),
                         getModule(), Action, AsmOutStream);
@@ -823,6 +825,9 @@
       TheModule->setTargetTriple(TargetOpts.Triple);
     }
 
+    EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(),
+                 MainFile->getMemBufferRef());
+
     LLVMContext &Ctx = TheModule->getContext();
     Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler);
     EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(), TargetOpts,
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"
@@ -721,3 +723,86 @@
     }
   }
 }
+
+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.EmbedBitcode && !CGOpts.EmbedMarkerOnly)
+    return;
+
+  // Embed the bitcode for the llvm module.
+  std::string Data;
+  ArrayRef<uint8_t> ModuleData;
+  Triple T(M->getTargetTriple());
+  if (!CGOpts.EmbedMarkerOnly) {
+    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");
+  }
+
+  // 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
@@ -198,6 +198,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;
 
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def
+++ include/clang/Frontend/CodeGenOptions.def
@@ -53,6 +53,8 @@
                                      ///< frontend.
 CODEGENOPT(DisableRedZone    , 1, 0) ///< Set when -mno-red-zone is enabled.
 CODEGENOPT(DisableTailCalls  , 1, 0) ///< Do not emit tail calls.
+CODEGENOPT(EmbedBitcode      , 1, 0) ///< Embed LLVM IR bitcode as data.
+CODEGENOPT(EmbedMarkerOnly   , 1, 0) ///< Only create bitcode section as marker
 CODEGENOPT(EmitDeclMetadata  , 1, 0) ///< Emit special metadata indicating what
                                      ///< Decl* various IR entities came from. 
                                      ///< Only useful when running CodeGen as a
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,
                          StringRef TDesc, llvm::Module *M, BackendAction Action,
                          raw_pwrite_stream *OS);
+
+  void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts,
+                    llvm::MemoryBufferRef Buf);
 }
 
 #endif
Index: include/clang/Basic/DiagnosticDriverKinds.td
===================================================================
--- include/clang/Basic/DiagnosticDriverKinds.td
+++ include/clang/Basic/DiagnosticDriverKinds.td
@@ -136,6 +136,8 @@
   "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 err_drv_unsupported_embed_bitcode : Error<
+  "%0 is not supported with -fembed-bitcode">;
 
 def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>;
 def warn_drv_lto_libpath : Warning<"libLTO.dylib relative to clang installed dir not found; using 'ld' default search path instead">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to