diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5652,8 +5652,6 @@ HelpText<"Generate C++20 header units from header files">; def emit_pch : Flag<["-"], "emit-pch">, HelpText<"Generate pre-compiled header file">; -def emit_llvm_bc : Flag<["-"], "emit-llvm-bc">, - HelpText<"Build ASTs then convert to LLVM, emit .bc file">; def emit_llvm_only : Flag<["-"], "emit-llvm-only">, HelpText<"Build ASTs and convert to LLVM, discarding output">; def emit_codegen_only : Flag<["-"], "emit-codegen-only">, @@ -6100,6 +6098,8 @@ HelpText<"Emit native object files">; def init_only : Flag<["-"], "init-only">, HelpText<"Only execute frontend initialization">; +def emit_llvm_bc : Flag<["-"], "emit-llvm-bc">, + HelpText<"Build ASTs then convert to LLVM, emit .bc file">; } // let Group = Action_Group diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h --- a/flang/include/flang/Frontend/FrontendActions.h +++ b/flang/include/flang/Frontend/FrontendActions.h @@ -192,6 +192,10 @@ void ExecuteAction() override; }; +class EmitLLVMBitcodeAction : public CodeGenAction { + void ExecuteAction() override; +}; + class BackendAction : public CodeGenAction { public: enum class BackendActionTy { diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h --- a/flang/include/flang/Frontend/FrontendOptions.h +++ b/flang/include/flang/Frontend/FrontendOptions.h @@ -37,6 +37,9 @@ /// Emit an .ll file EmitLLVM, + /// Emit a .bc file + EmitLLVMBitcode, + /// Emit a .o file. EmitObj, diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -32,6 +32,7 @@ FIRBuilder FIRCodeGen FIRTransforms + LLVMPasses MLIRTransforms MLIRLLVMToLLVMIRTranslation MLIRSCFToControlFlow diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -150,6 +150,9 @@ case clang::driver::options::OPT_emit_llvm: opts.programAction = EmitLLVM; break; + case clang::driver::options::OPT_emit_llvm_bc: + opts.programAction = EmitLLVMBitcode; + break; case clang::driver::options::OPT_emit_obj: opts.programAction = EmitObj; break; diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -33,6 +33,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassBuilder.h" @@ -472,6 +473,50 @@ llvmModule->print(*os, /*AssemblyAnnotationWriter=*/nullptr); } +void EmitLLVMBitcodeAction::ExecuteAction() { + CompilerInstance &ci = this->instance(); + // Generate an LLVM module if it's not already present (it will already be + // present if the input file is an LLVM IR/BC file). + if (!llvmModule) + GenerateLLVMIR(); + + llvm::ModulePassManager MPM; + llvm::ModuleAnalysisManager MAM; + + // Create and configure `Target` + std::string error; + std::string theTriple = llvmModule->getTargetTriple(); + const llvm::Target *theTarget = + llvm::TargetRegistry::lookupTarget(theTriple, error); + assert(theTarget && "Failed to create Target"); + + // Create and configure `TargetMachine` + std::unique_ptr TM; + + TM.reset(theTarget->createTargetMachine(theTriple, /*CPU=*/"", + /*Features=*/"", llvm::TargetOptions(), llvm::None)); + llvmModule->setDataLayout(TM->createDataLayout()); + assert(TM && "Failed to create TargetMachine"); + + // Generate an output file + std::unique_ptr os = ci.CreateDefaultOutputFile( + /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "bc"); + if (!os) { + unsigned diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "failed to create the output file"); + ci.diagnostics().Report(diagID); + return; + } + + // Set-up the pass manager + llvm::PassBuilder PB(TM.get()); + PB.registerModuleAnalyses(MAM); + MPM.addPass(llvm::BitcodeWriterPass(*os)); + + // Run the passes + MPM.run(*llvmModule, MAM); +} + void EmitMLIRAction::ExecuteAction() { CompilerInstance &ci = this->instance(); diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -37,6 +37,8 @@ return std::make_unique(); case EmitLLVM: return std::make_unique(); + case EmitLLVMBitcode: + return std::make_unique(); case EmitObj: return std::make_unique( BackendAction::BackendActionTy::Backend_EmitObj); diff --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt --- a/flang/test/CMakeLists.txt +++ b/flang/test/CMakeLists.txt @@ -55,6 +55,7 @@ fir-opt tco bbc + llvm-dis llvm-objdump split-file ) diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90 --- a/flang/test/Driver/driver-help.f90 +++ b/flang/test/Driver/driver-help.f90 @@ -71,6 +71,7 @@ ! HELP-FC1-NEXT:OPTIONS: ! HELP-FC1-NEXT: -cpp Enable predefined and command line preprocessor macros ! HELP-FC1-NEXT: -D = Define to (or 1 if omitted) +! HELP-FC1-NEXT: -emit-llvm-bc Build ASTs then convert to LLVM, emit .bc file ! HELP-FC1-NEXT: -emit-llvm Use the LLVM representation for assembler and object files ! HELP-FC1-NEXT: -emit-mlir Build the parse tree, then lower it to MLIR ! HELP-FC1-NEXT: -emit-obj Emit native object files