Skip to content

Commit

Permalink
[clang][llvm][fatlto] Avoid cloning modules in FatLTO (#72180)
Browse files Browse the repository at this point in the history
#70703 pointed out that
cloning LLVM modules could lead to miscompiles when using FatLTO.

This is due to an existing issue when cloning modules with labels (see
#55991 and #47769). Since this can lead to miscompilation, we can avoid
cloning the LLVM modules, which was desirable anyway.

This patch modifies the EmbedBitcodePass to no longer clone the module
or run an input pipeline over it. Further, it make FatLTO always perform
UnifiedLTO, so we can still defer the Thin/Full LTO decision to
link-time. Lastly, it removes dead/obsolete code related to now defunct
options that do not work with the EmbedBitcodePass implementation any
longer.
  • Loading branch information
ilovepi committed Dec 1, 2023
1 parent 51fc854 commit cfe1ece
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 116 deletions.
9 changes: 4 additions & 5 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,9 +996,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
}

if (CodeGenOpts.FatLTO) {
MPM.addPass(PB.buildFatLTODefaultPipeline(
Level, PrepareForThinLTO,
PrepareForThinLTO || shouldEmitRegularLTOSummary()));
assert(CodeGenOpts.UnifiedLTO && "FatLTO requires UnifiedLTO");
MPM.addPass(PB.buildFatLTODefaultPipeline(Level));
} else if (PrepareForThinLTO) {
MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(Level));
} else if (PrepareForLTO) {
Expand Down Expand Up @@ -1042,7 +1041,6 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists,
/*EmitLTOSummary=*/true));
}

} else {
// Emit a module summary by default for Regular LTO except for ld64
// targets
Expand Down Expand Up @@ -1073,7 +1071,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
if (!TheModule->getModuleFlag("EnableSplitLTOUnit"))
TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
uint32_t(CodeGenOpts.EnableSplitLTOUnit));
if (CodeGenOpts.UnifiedLTO && !TheModule->getModuleFlag("UnifiedLTO"))
// FatLTO always means UnifiedLTO
if (!TheModule->getModuleFlag("UnifiedLTO"))
TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1));
}

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4862,7 +4862,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
bool UnifiedLTO = false;
if (IsUsingLTO) {
UnifiedLTO = Args.hasFlag(options::OPT_funified_lto,
options::OPT_fno_unified_lto, Triple.isPS());
options::OPT_fno_unified_lto, Triple.isPS()) ||
Args.hasFlag(options::OPT_ffat_lto_objects,
options::OPT_fno_fat_lto_objects, false);
if (UnifiedLTO)
CmdArgs.push_back("-funified-lto");
}
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1861,6 +1861,20 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
if (Args.hasArg(OPT_funified_lto))
Opts.PrepareForThinLTO = true;
}
if (Arg *A = Args.getLastArg(options::OPT_ffat_lto_objects,
options::OPT_fno_fat_lto_objects)) {
if (A->getOption().matches(options::OPT_ffat_lto_objects)) {
if (Arg *Uni = Args.getLastArg(options::OPT_funified_lto,
options::OPT_fno_unified_lto)) {
if (Uni->getOption().matches(options::OPT_fno_unified_lto))
Diags.Report(diag::err_drv_incompatible_options)
<< A->getAsString(Args) << "-fno-unified-lto";
} else
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-funified-lto";
}
}

if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
if (IK.getLanguage() != Language::LLVM_IR)
Diags.Report(diag::err_drv_argument_only_allowed_with)
Expand Down
48 changes: 23 additions & 25 deletions clang/test/CodeGen/fat-lto-objects.c
Original file line number Diff line number Diff line change
@@ -1,49 +1,47 @@
// REQUIRES: x86-registered-target

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -fsplit-lto-unit -emit-llvm < %s | FileCheck %s --check-prefixes=FULL,SPLIT
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=FULL,SPLIT
// RUN: not %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -fsplit-lto-unit -emit-llvm < %s 2>&1 | FileCheck %s --check-prefixes=NO-UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -fsplit-lto-unit -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=THIN,SPLIT
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=THIN,NOSPLIT
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -funified-lto -ffat-lto-objects -fsplit-lto-unit -emit-llvm < %s | FileCheck %s --check-prefixes=FULL,SPLIT,UNIFIED
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -funified-lto -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=FULL,NOSPLIT,UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -fsplit-lto-unit -emit-obj < %s -o %t.full.split.o
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -funified-lto -fsplit-lto-unit -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=THIN,SPLIT,UNIFIED
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -funified-lto -ffat-lto-objects -emit-llvm < %s | FileCheck %s --check-prefixes=THIN,NOSPLIT,UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -funified-lto -ffat-lto-objects -fsplit-lto-unit -emit-obj < %s -o %t.full.split.o
// RUN: llvm-readelf -S %t.full.split.o | FileCheck %s --check-prefixes=ELF
// RUN: llvm-objcopy --dump-section=.llvm.lto=%t.full.split.bc %t.full.split.o
// RUN: llvm-dis %t.full.split.bc -o - | FileCheck %s --check-prefixes=FULL,SPLIT,NOUNIFIED
// RUN: llvm-dis %t.full.split.bc -o - | FileCheck %s --check-prefixes=THIN,SPLIT,UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -emit-obj < %s -o %t.full.nosplit.o
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -funified-lto -ffat-lto-objects -emit-obj < %s -o %t.full.nosplit.o
// RUN: llvm-readelf -S %t.full.nosplit.o | FileCheck %s --check-prefixes=ELF
// RUN: llvm-objcopy --dump-section=.llvm.lto=%t.full.nosplit.bc %t.full.nosplit.o
// RUN: llvm-dis %t.full.nosplit.bc -o - | FileCheck %s --check-prefixes=FULL,NOSPLIT,NOUNIFIED
// RUN: llvm-dis %t.full.nosplit.bc -o - | FileCheck %s --check-prefixes=THIN,NOSPLIT,UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -fsplit-lto-unit -ffat-lto-objects -emit-obj < %s -o %t.thin.split.o
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -funified-lto -fsplit-lto-unit -ffat-lto-objects -emit-obj < %s -o %t.thin.split.o
// RUN: llvm-readelf -S %t.thin.split.o | FileCheck %s --check-prefixes=ELF
// RUN: llvm-objcopy --dump-section=.llvm.lto=%t.thin.split.bc %t.thin.split.o
// RUN: llvm-dis %t.thin.split.bc -o - | FileCheck %s --check-prefixes=THIN,SPLIT,NOUNIFIED
// RUN: llvm-dis %t.thin.split.bc -o - | FileCheck %s --check-prefixes=THIN,SPLIT,UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -ffat-lto-objects -emit-obj < %s -o %t.thin.nosplit.o
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -funified-lto -ffat-lto-objects -emit-obj < %s -o %t.thin.nosplit.o
// RUN: llvm-readelf -S %t.thin.nosplit.o | FileCheck %s --check-prefixes=ELF
// RUN: llvm-objcopy --dump-section=.llvm.lto=%t.thin.nosplit.bc %t.thin.nosplit.o
// RUN: llvm-dis %t.thin.nosplit.bc -o - | FileCheck %s --check-prefixes=THIN,NOSPLIT,NOUNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=thin -funified-lto -ffat-lto-objects -emit-obj < %s -o %t.unified.o
// RUN: llvm-readelf -S %t.unified.o | FileCheck %s --check-prefixes=ELF
// RUN: llvm-objcopy --dump-section=.llvm.lto=%t.unified.bc %t.unified.o
// RUN: llvm-dis %t.unified.bc -o - | FileCheck %s --check-prefixes=THIN,NOSPLIT,UNIFIED
// RUN: llvm-dis %t.thin.nosplit.bc -o - | FileCheck %s --check-prefixes=THIN,NOSPLIT,UNIFIED

// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -ffat-lto-objects -fsplit-lto-unit -S < %s -o - \
// RUN: %clang -cc1 -triple x86_64-unknown-linux-gnu -flto=full -funified-lto -ffat-lto-objects -fsplit-lto-unit -S < %s -o - \
// RUN: | FileCheck %s --check-prefixes=ASM

/// Check that the ThinLTO metadata is only set false for full LTO.
// FULL: ![[#]] = !{i32 1, !"ThinLTO", i32 0}
// THIN-NOT: ![[#]] = !{i32 1, !"ThinLTO", i32 0}

/// Be sure we enable split LTO units correctly under -ffat-lto-objects.
// SPLIT: ![[#]] = !{i32 1, !"EnableSplitLTOUnit", i32 1}
// SPLIT: ![[#]] = !{i32 1, !"EnableSplitLTOUnit", i32 1}
// NOSPLIT: ![[#]] = !{i32 1, !"EnableSplitLTOUnit", i32 0}

// UNIFIED: ![[#]] = !{i32 1, !"UnifiedLTO", i32 1}
// NOUNIFIED-NOT: ![[#]] = !{i32 1, !"UnifiedLTO", i32 1}
/// Check that the ThinLTO metadata is set true for both full and thin LTO, since FatLTO is based on UnifiedLTO.
// FULL: ![[#]] = !{i32 1, !"ThinLTO", i32 1}
// THIN-NOT: ![[#]] = !{i32 1, !"ThinLTO", i32 0}

/// FatLTO always uses UnifiedLTO. It's an error if they aren't set together
// UNIFIED: ![[#]] = !{i32 1, !"UnifiedLTO", i32 1}
// NO-UNIFIED: error: invalid argument '-ffat-lto-objects' only allowed with '-funified-lto'

// ELF: .llvm.lto

Expand Down
12 changes: 12 additions & 0 deletions clang/test/Driver/fat-lto-objects.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang --target=x86_64-unknown-linux-gnu -flto -ffat-lto-objects -### %s -c 2>&1 | FileCheck %s -check-prefix=CHECK-CC
// CHECK-CC: -cc1
// CHECK-CC-SAME: -funified-lto
// CHECK-CC-SAME: -emit-obj
// CHECK-CC-SAME: -ffat-lto-objects

Expand All @@ -15,6 +16,7 @@
// RUN: %clang --target=x86_64-unknown-linux-gnu -flto -ffat-lto-objects -### %s -S 2>&1 | FileCheck %s -check-prefix=CHECK-CC-S-LTO
// RUN: %clang --target=x86_64-unknown-linux-gnu -flto -ffat-lto-objects -### %s -S -emit-llvm 2>&1 | FileCheck %s -check-prefix=CHECK-CC-S-LTO
// CHECK-CC-S-LTO: -cc1
// CHECK-CC-S-LTO-SAME: -funified-lto
// CHECK-CC-S-LTO-SAME: -emit-llvm
// CHECK-CC-S-LTO-SAME: -ffat-lto-objects

Expand All @@ -32,3 +34,13 @@
// RUN: -fuse-ld=lld -fno-lto -ffat-lto-objects -### 2>&1 | FileCheck --check-prefix=NOLTO %s
// LTO: "--fat-lto-objects"
// NOLTO-NOT: "--fat-lto-objects"

/// Make sure that incompatible options emit the correct diagnostics, since -ffat-lto-objects requires -funified-lto
// RUN: %clang -cc1 -triple=x86_64-unknown-linux-gnu -flto -ffat-lto-objects -funified-lto -emit-llvm-only %s 2>&1 | FileCheck %s -check-prefix=UNIFIED --allow-empty
// UNIFIED-NOT: error:

// RUN: not %clang -cc1 -triple=x86_64-unknown-linux-gnu -flto -ffat-lto-objects -emit-llvm-only %s 2>&1 | FileCheck %s -check-prefix=MISSING_UNIFIED
// MISSING_UNIFIED: error: invalid argument '-ffat-lto-objects' only allowed with '-funified-lto'

// RUN: not %clang -cc1 -triple=x86_64-unknown-linux-gnu -flto -fno-unified-lto -ffat-lto-objects -emit-llvm-only %s 2>&1 | FileCheck %s -check-prefix=NO-UNIFIED
// NO-UNIFIED: error: the combination of '-ffat-lto-objects' and '-fno-unified-lto' is incompatible
35 changes: 18 additions & 17 deletions llvm/docs/FatLTO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,31 @@ Overview
Within LLVM, FatLTO is supported by choosing the ``FatLTODefaultPipeline``.
This pipeline will:

#) Clone the IR module.
#) Run the pre-link (Thin)LTO pipeline using the cloned module.
#) Run the pre-link UnifiedLTO pipeline on the current module.
#) Embed the pre-link bitcode in a special ``.llvm.lto`` section.
#) Optimize the unmodified copy of the module using the normal compilation pipeline.
#) Finish optimizing the module using the post-link ThinLTO pipeline.
#) Emit the object file, including the new ``.llvm.lto`` section.

.. NOTE
At the time of writing, we conservatively run independent pipelines to
generate the bitcode section and the object code, which happen to be
identical to those used outside of FatLTO. This results in compiled
artifacts that are identical to those produced by the default and (Thin)LTO
pipelines. However, this is not a guarantee, and we reserve the right to
change this at any time. Explicitly, users should not rely on the produced
bitcode or object code to mach their non-LTO counterparts precisely. They
will exhibit similar performance characteristics, but may not be bit-for-bit
the same.
Previously, we conservatively ran independent pipelines on separate copies
of the LLVM module to generate the bitcode section and the object code,
which happen to be identical to those used outside of FatLTO. While that
resulted in compiled artifacts that were identical to those produced by the
default and (Thin)LTO pipelines, module cloning led to some cases of
miscompilation, and we have moved away from trying to keep bitcode
generation and optimization completely disjoint.
Bit-for-bit compatibility is not (and never was) a guarantee, and we reserve
the right to change this at any time. Explicitly, users should not rely on
the produced bitcode or object code to match their non-LTO counterparts
precisely. They will exhibit similar performance characteristics, but may
not be bit-for-bit the same.
Internally, the ``.llvm.lto`` section is created by running the
``EmbedBitcodePass`` at the start of the ``PerModuleDefaultPipeline``. This
pass is responsible for cloning and optimizing the module with the appropriate
LTO pipeline and emitting the ``.llvm.lto`` section. Afterwards, the
``PerModuleDefaultPipeline`` runs normally and the compiler can emit the fat
object file.
``EmbedBitcodePass`` after the ``ThinLTOPreLinkDefaultPipeline``. This pass is
responsible for emitting the ``.llvm.lto`` section. Afterwards, the
``ThinLTODefaultPipeline`` runs and the compiler can emit the fat object file.

Limitations
===========
Expand Down
3 changes: 1 addition & 2 deletions llvm/include/llvm/Passes/PassBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,7 @@ class PassBuilder {
/// separately to avoid any inconsistencies with an ad-hoc pipeline that tries
/// to approximate the PerModuleDefaultPipeline from the pre-link LTO
/// pipelines.
ModulePassManager buildFatLTODefaultPipeline(OptimizationLevel Level,
bool ThinLTO, bool EmitSummary);
ModulePassManager buildFatLTODefaultPipeline(OptimizationLevel Level);

/// Build a pre-link, ThinLTO-targeting default optimization pipeline to
/// a pass manager.
Expand Down
17 changes: 1 addition & 16 deletions llvm/include/llvm/Transforms/IPO/EmbedBitcodePass.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,13 @@ class Module;
class ModulePass;
class Pass;

struct EmbedBitcodeOptions {
EmbedBitcodeOptions() : EmbedBitcodeOptions(false, false) {}
EmbedBitcodeOptions(bool IsThinLTO, bool EmitLTOSummary)
: IsThinLTO(IsThinLTO), EmitLTOSummary(EmitLTOSummary) {}
bool IsThinLTO;
bool EmitLTOSummary;
};

/// Pass embeds a copy of the module optimized with the provided pass pipeline
/// into a global variable.
class EmbedBitcodePass : public PassInfoMixin<EmbedBitcodePass> {
bool IsThinLTO;
bool EmitLTOSummary;
ModulePassManager MPM;

public:
EmbedBitcodePass(EmbedBitcodeOptions Opts)
: EmbedBitcodePass(Opts.IsThinLTO, Opts.EmitLTOSummary,
ModulePassManager()) {}
EmbedBitcodePass(bool IsThinLTO, bool EmitLTOSummary, ModulePassManager &&MPM)
: IsThinLTO(IsThinLTO), EmitLTOSummary(EmitLTOSummary),
MPM(std::move(MPM)) {}
EmbedBitcodePass() {}

PreservedAnalyses run(Module &M, ModuleAnalysisManager &);

Expand Down
20 changes: 0 additions & 20 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,26 +759,6 @@ Expected<HWAddressSanitizerOptions> parseHWASanPassOptions(StringRef Params) {
return Result;
}

Expected<EmbedBitcodeOptions> parseEmbedBitcodePassOptions(StringRef Params) {
EmbedBitcodeOptions Result;
while (!Params.empty()) {
StringRef ParamName;
std::tie(ParamName, Params) = Params.split(';');

if (ParamName == "thinlto") {
Result.IsThinLTO = true;
} else if (ParamName == "emit-summary") {
Result.EmitLTOSummary = true;
} else {
return make_error<StringError>(
formatv("invalid EmbedBitcode pass parameter '{0}' ", ParamName)
.str(),
inconvertibleErrorCode());
}
}
return Result;
}

Expected<MemorySanitizerOptions> parseMSanPassOptions(StringRef Params) {
MemorySanitizerOptions Result;
while (!Params.empty()) {
Expand Down
22 changes: 15 additions & 7 deletions llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1530,14 +1530,22 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
}

ModulePassManager
PassBuilder::buildFatLTODefaultPipeline(OptimizationLevel Level, bool ThinLTO,
bool EmitSummary) {
PassBuilder::buildFatLTODefaultPipeline(OptimizationLevel Level) {
ModulePassManager MPM;
MPM.addPass(EmbedBitcodePass(ThinLTO, EmitSummary,
ThinLTO
? buildThinLTOPreLinkDefaultPipeline(Level)
: buildLTOPreLinkDefaultPipeline(Level)));
MPM.addPass(buildPerModuleDefaultPipeline(Level));
// FatLTO always uses UnifiedLTO, so use the ThinLTOPreLink pipeline
MPM.addPass(buildThinLTOPreLinkDefaultPipeline(Level));
MPM.addPass(EmbedBitcodePass());

// Use the ThinLTO post-link pipeline with sample profiling, other
if (PGOOpt && PGOOpt->Action == PGOOptions::SampleUse)
MPM.addPass(buildThinLTODefaultPipeline(Level, /*ImportSummary=*/nullptr));
else {
// otherwise, just use module optimization
MPM.addPass(
buildModuleOptimizationPipeline(Level, ThinOrFullLTOPhase::None));
// Emit annotation remarks.
addAnnotationRemarksPass(MPM);
}
return MPM;
}

Expand Down
5 changes: 1 addition & 4 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ MODULE_PASS("dfsan", DataFlowSanitizerPass())
MODULE_PASS("dot-callgraph", CallGraphDOTPrinterPass())
MODULE_PASS("dxil-upgrade", DXILUpgradePass())
MODULE_PASS("elim-avail-extern", EliminateAvailableExternallyPass())
MODULE_PASS("embed-bitcode", EmbedBitcodePass())
MODULE_PASS("extract-blocks", BlockExtractorPass({}, false))
MODULE_PASS("forceattrs", ForceFunctionAttrsPass())
MODULE_PASS("function-import", FunctionImportPass())
Expand Down Expand Up @@ -145,10 +146,6 @@ MODULE_PASS_WITH_PARAMS(
"asan", "AddressSanitizerPass",
[](AddressSanitizerOptions Opts) { return AddressSanitizerPass(Opts); },
parseASanPassOptions, "kernel")
MODULE_PASS_WITH_PARAMS(
"embed-bitcode", "EmbedBitcodePass",
[](EmbedBitcodeOptions Opts) { return EmbedBitcodePass(Opts); },
parseEmbedBitcodePassOptions, "thinlto;emit-summary")
MODULE_PASS_WITH_PARAMS(
"globaldce", "GlobalDCEPass",
[](bool InLTOPostLink) { return GlobalDCEPass(InLTOPostLink); },
Expand Down
16 changes: 1 addition & 15 deletions llvm/lib/Transforms/IPO/EmbedBitcodePass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,15 @@
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/IPO/EmbedBitcodePass.h"
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"

#include <memory>
#include <string>

using namespace llvm;
Expand All @@ -34,19 +30,9 @@ PreservedAnalyses EmbedBitcodePass::run(Module &M, ModuleAnalysisManager &AM) {
report_fatal_error(
"EmbedBitcode pass currently only supports ELF object format",
/*gen_crash_diag=*/false);

std::unique_ptr<Module> NewModule = CloneModule(M);
MPM.run(*NewModule, AM);

std::string Data;
raw_string_ostream OS(Data);
if (IsThinLTO)
ThinLTOBitcodeWriterPass(OS, /*ThinLinkOS=*/nullptr).run(*NewModule, AM);
else
BitcodeWriterPass(OS, /*ShouldPreserveUseListOrder=*/false, EmitLTOSummary)
.run(*NewModule, AM);

ThinLTOBitcodeWriterPass(OS, /*ThinLinkOS=*/nullptr).run(M, AM);
embedBufferInModule(M, MemoryBufferRef(Data, "ModuleData"), ".llvm.lto");

return PreservedAnalyses::all();
}
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/X86/fat-lto-section.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
;; Ensure that the .llvm.lto section has SHT_EXCLUDE set.
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode<thinlto;emit-summary>" -S \
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode" -S \
; RUN: | llc --mtriple x86_64-unknown-linux-gnu -filetype=obj \
; RUN: | llvm-readelf - --sections \
; RUN: | FileCheck %s --check-prefix=EXCLUDE
Expand Down
3 changes: 0 additions & 3 deletions llvm/test/Transforms/EmbedBitcode/embed.ll
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode" -S | FileCheck %s
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode<thinlto>" -S | FileCheck %s
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode<emit-summary>" -S | FileCheck %s
; RUN: opt --mtriple x86_64-unknown-linux-gnu < %s -passes="embed-bitcode<thinlto;emit-summary>" -S | FileCheck %s

@a = global i32 1

Expand Down

0 comments on commit cfe1ece

Please sign in to comment.