/// files if linked together are intended to be equivalent to the single output
/// file that would have been code generated from M.
///
+/// Writes bitcode for individual partitions into output streams in BCOSs, if
+/// BCOSs is not empty.
+///
/// \returns M if OSs.size() == 1, otherwise returns std::unique_ptr<Module>().
std::unique_ptr<Module>
splitCodeGen(std::unique_ptr<Module> M, ArrayRef<raw_pwrite_stream *> OSs,
- StringRef CPU, StringRef Features, const TargetOptions &Options,
+ ArrayRef<llvm::raw_pwrite_stream *> BCOSs, StringRef CPU,
+ StringRef Features, const TargetOptions &Options,
Reloc::Model RM = Reloc::Default,
CodeModel::Model CM = CodeModel::Default,
CodeGenOpt::Level OL = CodeGenOpt::Default,
CodeGenPasses.run(*M);
}
-std::unique_ptr<Module>
-llvm::splitCodeGen(std::unique_ptr<Module> M,
- ArrayRef<llvm::raw_pwrite_stream *> OSs, StringRef CPU,
- StringRef Features, const TargetOptions &Options,
- Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL,
- TargetMachine::CodeGenFileType FileType,
- bool PreserveLocals) {
+std::unique_ptr<Module> llvm::splitCodeGen(
+ std::unique_ptr<Module> M, ArrayRef<llvm::raw_pwrite_stream *> OSs,
+ ArrayRef<llvm::raw_pwrite_stream *> BCOSs, StringRef CPU,
+ StringRef Features, const TargetOptions &Options, Reloc::Model RM,
+ CodeModel::Model CM, CodeGenOpt::Level OL,
+ TargetMachine::CodeGenFileType FileType, bool PreserveLocals) {
StringRef TripleStr = M->getTargetTriple();
std::string ErrMsg;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
if (!TheTarget)
report_fatal_error(Twine("Target not found: ") + ErrMsg);
+ assert(BCOSs.empty() || BCOSs.size() == OSs.size());
+
if (OSs.size() == 1) {
- codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM,
- OL, FileType);
+ if (!BCOSs.empty())
+ WriteBitcodeToFile(M.get(), *BCOSs[0]);
+ codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM, OL,
+ FileType);
return M;
}
raw_svector_ostream BCOS(BC);
WriteBitcodeToFile(MPart.get(), BCOS);
+ if (!BCOSs.empty()) {
+ BCOSs[ThreadCount]->write(BC.begin(), BC.size());
+ BCOSs[ThreadCount]->flush();
+ }
+
llvm::raw_pwrite_stream *ThreadOS = OSs[ThreadCount++];
// Enqueue the task
CodegenThreadPool.async(
// parallelism level 1. This is achieved by having splitCodeGen return the
// original module at parallelism level 1 which we then assign back to
// MergedModule.
- MergedModule =
- splitCodeGen(std::move(MergedModule), Out, MCpu, FeatureStr, Options,
- RelocModel, CodeModel::Default, CGOptLevel, FileType,
- ShouldRestoreGlobalsLinkage);
+ MergedModule = splitCodeGen(
+ std::move(MergedModule), Out, {}, MCpu, FeatureStr, Options, RelocModel,
+ CodeModel::Default, CGOptLevel, FileType, ShouldRestoreGlobalsLinkage);
// If statistics were requested, print them out after codegen.
if (llvm::AreStatisticsEnabled())
; RUN: llvm-as -o %t.bc %s
; RUN: env LD_PRELOAD=%llvmshlibdir/LLVMgold.so %gold -plugin %llvmshlibdir/LLVMgold.so -u foo -u bar -plugin-opt jobs=2 -plugin-opt save-temps -m elf_x86_64 -o %t %t.bc
+; RUN: llvm-dis %t.opt.bc0 -o - | FileCheck --check-prefix=CHECK-BC0 %s
+; RUN: llvm-dis %t.opt.bc1 -o - | FileCheck --check-prefix=CHECK-BC1 %s
; RUN: llvm-nm %t.o0 | FileCheck --check-prefix=CHECK0 %s
; RUN: llvm-nm %t.o1 | FileCheck --check-prefix=CHECK1 %s
target triple = "x86_64-unknown-linux-gnu"
+; CHECK-BC0: define void @foo
+; CHECK-BC0: declare void @bar
; CHECK0-NOT: bar
; CHECK0: T foo
; CHECK0-NOT: bar
ret void
}
+; CHECK-BC1: declare void @foo
+; CHECK-BC1: define void @bar
; CHECK1-NOT: foo
; CHECK1: T bar
; CHECK1-NOT: foo
/// Sets up output files necessary to perform optional multi-threaded
/// split code generation, and invokes the code generation implementation.
- void runSplitCodeGen();
+ /// If BCFileName is not empty, saves bitcode for module partitions into
+ /// {BCFileName}0 .. {BCFileName}N.
+ void runSplitCodeGen(const SmallString<128> &BCFilename);
};
}
CodeGenPasses.run(*M);
}
-void CodeGen::runSplitCodeGen() {
+void CodeGen::runSplitCodeGen(const SmallString<128> &BCFilename) {
const std::string &TripleStr = M->getTargetTriple();
Triple TheTriple(TripleStr);
unsigned int MaxThreads = options::Parallelism ? options::Parallelism : 1;
std::vector<SmallString<128>> Filenames(MaxThreads);
+ std::vector<SmallString<128>> BCFilenames(MaxThreads);
bool TempOutFile = Filename.empty();
{
// Open a file descriptor for each backend task. This is done in a block
OSPtrs[I] = &OSs.back();
}
+ std::list<llvm::raw_fd_ostream> BCOSs;
+ std::vector<llvm::raw_pwrite_stream *> BCOSPtrs;
+ if (!BCFilename.empty() && MaxThreads > 1) {
+ for (unsigned I = 0; I != MaxThreads; ++I) {
+ int FD = openOutputFile(BCFilename, false, BCFilenames[I], I);
+ BCOSs.emplace_back(FD, true);
+ BCOSPtrs.push_back(&BCOSs.back());
+ }
+ }
+
// Run backend tasks.
- splitCodeGen(std::move(M), OSPtrs, options::mcpu, Features.getString(),
+ splitCodeGen(std::move(M), OSPtrs, BCOSPtrs, options::mcpu, Features.getString(),
Options, RelocationModel, CodeModel::Default, CGOptLevel);
}
void CodeGen::runAll() {
runLTOPasses();
+ SmallString<128> OptFilename;
if (options::TheOutputType == options::OT_SAVE_TEMPS) {
- std::string OptFilename = output_name;
+ OptFilename = output_name;
// If the CodeGen client provided a filename, use it. Always expect
// a provided filename if we are in a task (i.e. ThinLTO backend).
assert(!SaveTempsFilename.empty() || TaskID == -1);
if (!SaveTempsFilename.empty())
OptFilename = SaveTempsFilename;
- saveBCFile(OptFilename + ".opt.bc", *M);
+ OptFilename += ".opt.bc";
+ saveBCFile(OptFilename, *M);
}
// If we are already in a thread (i.e. ThinLTO), just perform
runCodegenPasses();
// Otherwise attempt split code gen.
else
- runSplitCodeGen();
+ runSplitCodeGen(OptFilename);
}
/// Links the module in \p View from file \p F into the combined module