Index: include/llvm/CodeGen/ParallelCG.h =================================================================== --- include/llvm/CodeGen/ParallelCG.h +++ include/llvm/CodeGen/ParallelCG.h @@ -16,6 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Target/TargetMachine.h" namespace llvm { @@ -24,8 +25,8 @@ class raw_pwrite_stream; /// Split M into OSs.size() partitions, and generate code for each. Writes -/// OSs.size() object files to the output streams in OSs. The resulting object -/// files if linked together are intended to be equivalent to the single object +/// OSs.size() output files to the output streams in OSs. The resulting output +/// files if linked together are intended to be equivalent to the single output /// file that would have been code generated from M. /// /// \returns M if OSs.size() == 1, otherwise returns std::unique_ptr(). @@ -34,7 +35,8 @@ StringRef CPU, StringRef Features, const TargetOptions &Options, Reloc::Model RM = Reloc::Default, CodeModel::Model CM = CodeModel::Default, - CodeGenOpt::Level OL = CodeGenOpt::Default); + CodeGenOpt::Level OL = CodeGenOpt::Default, + TargetMachine::CodeGenFileType FT = TargetMachine::CGFT_ObjectFile); } // namespace llvm Index: include/llvm/LTO/LTOCodeGenerator.h =================================================================== --- include/llvm/LTO/LTOCodeGenerator.h +++ include/llvm/LTO/LTOCodeGenerator.h @@ -40,6 +40,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/Linker/Linker.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include #include @@ -74,6 +75,10 @@ void setTargetOptions(TargetOptions Options); void setDebugInfo(lto_debug_model); void setCodePICModel(Reloc::Model Model) { RelocModel = Model; } + + /// Set the file type to be emitted (assembly or object code). + /// The default is TargetMachine::CGFT_ObjectFile. + void setFileType(TargetMachine::CodeGenFileType FT) { FileType = FT; } void setCpu(const char *MCpu) { this->MCpu = MCpu; } void setAttr(const char *MAttr) { this->MAttr = MAttr; } @@ -103,21 +108,21 @@ /// true on success. bool writeMergedModules(const char *Path, std::string &ErrMsg); - /// Compile the merged module into a *single* object file; the path to object + /// Compile the merged module into a *single* output file; the path to output /// file is returned to the caller via argument "name". Return true on /// success. /// - /// \note It is up to the linker to remove the intermediate object file. Do + /// \note It is up to the linker to remove the intermediate output file. Do /// not try to remove the object file in LTOCodeGenerator's destructor as we - /// don't who (LTOCodeGenerator or the obj file) will last longer. + /// don't who (LTOCodeGenerator or the output file) will last longer. bool compile_to_file(const char **Name, bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE, bool DisableVectorization, std::string &ErrMsg); /// As with compile_to_file(), this function compiles the merged module into - /// single object file. Instead of returning the object-file-path to the - /// caller (linker), it brings the object to a buffer, and return the buffer - /// to the caller. This function should delete intermediate object file once + /// single output file. Instead of returning the output file path to the + /// caller (linker), it brings the output to a buffer, and returns the buffer + /// to the caller. This function should delete the intermediate file once /// its content is brought to memory. Return NULL if the compilation was not /// successful. std::unique_ptr compile(bool DisableVerify, bool DisableInline, @@ -129,15 +134,15 @@ bool optimize(bool DisableVerify, bool DisableInline, bool DisableGVNLoadPRE, bool DisableVectorization, std::string &ErrMsg); - /// Compiles the merged optimized module into a single object file. It brings - /// the object to a buffer, and returns the buffer to the caller. Return NULL + /// Compiles the merged optimized module into a single output file. It brings + /// the output to a buffer, and returns the buffer to the caller. Return NULL /// if the compilation was not successful. std::unique_ptr compileOptimized(std::string &ErrMsg); - /// Compile the merged optimized module into out.size() object files each + /// Compile the merged optimized module into out.size() output files each /// representing a linkable partition of the module. If out contains more /// than one element, code generation is done in parallel with out.size() - /// threads. Object files will be written to members of out. Returns true on + /// threads. Output files will be written to members of out. Returns true on /// success. bool compileOptimized(ArrayRef Out, std::string &ErrMsg); @@ -184,6 +189,7 @@ void *DiagContext = nullptr; bool ShouldInternalize = true; bool ShouldEmbedUselists = false; + TargetMachine::CodeGenFileType FileType = TargetMachine::CGFT_ObjectFile; }; } #endif Index: lib/CodeGen/ParallelCG.cpp =================================================================== --- lib/CodeGen/ParallelCG.cpp +++ lib/CodeGen/ParallelCG.cpp @@ -28,13 +28,13 @@ static void codegen(Module *M, llvm::raw_pwrite_stream &OS, const Target *TheTarget, StringRef CPU, StringRef Features, const TargetOptions &Options, Reloc::Model RM, - CodeModel::Model CM, CodeGenOpt::Level OL) { + CodeModel::Model CM, CodeGenOpt::Level OL, + TargetMachine::CodeGenFileType FileType) { std::unique_ptr TM(TheTarget->createTargetMachine( M->getTargetTriple(), CPU, Features, Options, RM, CM, OL)); legacy::PassManager CodeGenPasses; - if (TM->addPassesToEmitFile(CodeGenPasses, OS, - TargetMachine::CGFT_ObjectFile)) + if (TM->addPassesToEmitFile(CodeGenPasses, OS, FileType)) report_fatal_error("Failed to setup codegen"); CodeGenPasses.run(*M); } @@ -43,7 +43,8 @@ llvm::splitCodeGen(std::unique_ptr M, ArrayRef OSs, StringRef CPU, StringRef Features, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL) { + Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL, + TargetMachine::CodeGenFileType FileType) { StringRef TripleStr = M->getTargetTriple(); std::string ErrMsg; const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg); @@ -52,7 +53,7 @@ if (OSs.size() == 1) { codegen(M.get(), *OSs[0], TheTarget, CPU, Features, Options, RM, CM, - OL); + OL, FileType); return M; } @@ -69,7 +70,7 @@ llvm::raw_pwrite_stream *ThreadOS = OSs[Threads.size()]; Threads.emplace_back( - [TheTarget, CPU, Features, Options, RM, CM, OL, + [TheTarget, CPU, Features, Options, RM, CM, OL, FileType, ThreadOS](const SmallVector &BC) { LLVMContext Ctx; ErrorOr> MOrErr = @@ -81,7 +82,7 @@ std::unique_ptr MPartInCtx = std::move(MOrErr.get()); codegen(MPartInCtx.get(), *ThreadOS, TheTarget, CPU, Features, - Options, RM, CM, OL); + Options, RM, CM, OL, FileType); }, // Pass BC using std::move to ensure that it get moved rather than // copied into the thread's context. Index: lib/LTO/LTOCodeGenerator.cpp =================================================================== --- lib/LTO/LTOCodeGenerator.cpp +++ lib/LTO/LTOCodeGenerator.cpp @@ -206,11 +206,15 @@ bool LTOCodeGenerator::compileOptimizedToFile(const char **Name, std::string &ErrMsg) { - // make unique temp .o file to put generated object file + // make unique temp output file to put generated code SmallString<128> Filename; int FD; + + const char *Extension = + (FileType == TargetMachine::CGFT_AssemblyFile ? "s" : "o"); + std::error_code EC = - sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); + sys::fs::createTemporaryFile("lto-llvm", Extension, FD, Filename); if (EC) { ErrMsg = EC.message(); return false; @@ -515,7 +519,7 @@ // MergedModule. MergedModule = splitCodeGen(std::move(MergedModule), Out, MCpu, FeatureStr, Options, - RelocModel, CodeModel::Default, CGOptLevel); + RelocModel, CodeModel::Default, CGOptLevel, FileType); return true; } Index: test/LTO/X86/llvm-lto-output.ll =================================================================== --- /dev/null +++ test/LTO/X86/llvm-lto-output.ll @@ -0,0 +1,19 @@ +; Test the various output formats of the llvm-lto utility +; +; RUN: llvm-as < %s > %t1 +; +; RUN: llvm-lto -exported-symbol=main -save-merged-module -filetype=asm -o %t2 %t1 +; RUN: llvm-dis -o - %t2.merged.bc | FileCheck %s +; CHECK: @main() + +; RUN: FileCheck --check-prefix=ASM %s < %t2 +; RUN: llvm-lto -exported-symbol=main -filetype=obj -o %t2 %t1 +; RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=ASM %s +; ASM: main: +; + +define i32 @main() { +entry: + ret i32 23 +} + Index: tools/llvm-lto/llvm-lto.cpp =================================================================== --- tools/llvm-lto/llvm-lto.cpp +++ tools/llvm-lto/llvm-lto.cpp @@ -63,6 +63,10 @@ ThinLTO("thinlto", cl::init(false), cl::desc("Only write combined global index for ThinLTO backends")); +static cl::opt +SaveModuleFile("save-merged-module", cl::init(false), + cl::desc("Write merged LTO module to file before CodeGen")); + static cl::list InputFilenames(cl::Positional, cl::OneOrMore, cl::desc("")); @@ -317,6 +321,9 @@ if (!attrs.empty()) CodeGen.setAttr(attrs.c_str()); + if (FileType.getNumOccurrences()) + CodeGen.setFileType(FileType); + if (!OutputFilename.empty()) { std::string ErrorInfo; if (!CodeGen.optimize(DisableVerify, DisableInline, DisableGVNLoadPRE, @@ -325,6 +332,17 @@ return 1; } + if (SaveModuleFile) { + std::string ModuleFilename = OutputFilename; + ModuleFilename += ".merged.bc"; + std::string ErrMsg; + + if (!CodeGen.writeMergedModules(ModuleFilename.c_str(), ErrMsg)) { + errs() << argv[0] << ": " << ErrMsg << "\n"; + return 1; + } + } + std::list OSs; std::vector OSPtrs; for (unsigned I = 0; I != Parallelism; ++I) { @@ -354,6 +372,11 @@ return 1; } + if (SaveModuleFile) { + errs() << argv[0] << ": -save-merged-module must be specified with -o\n"; + return 1; + } + std::string ErrorInfo; const char *OutputName = nullptr; if (!CodeGen.compile_to_file(&OutputName, DisableVerify, DisableInline,