awarzynski updated this revision to Diff 407070. awarzynski added a comment.
Rebase on top of main Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D119012/new/ https://reviews.llvm.org/D119012 Files: clang/include/clang/Driver/Options.td flang/include/flang/Frontend/FrontendActions.h flang/include/flang/Frontend/FrontendOptions.h flang/lib/Frontend/CompilerInvocation.cpp flang/lib/Frontend/FrontendActions.cpp flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp flang/test/Driver/driver-help.f90 flang/test/Driver/emit-llvm.f90 flang/unittests/Frontend/FrontendActionTest.cpp
Index: flang/unittests/Frontend/FrontendActionTest.cpp =================================================================== --- flang/unittests/Frontend/FrontendActionTest.cpp +++ flang/unittests/Frontend/FrontendActionTest.cpp @@ -161,4 +161,31 @@ .contains( ":1:14: error: IF statement is not allowed in IF statement\n")); } + +TEST_F(FrontendActionTest, EmitLLVM) { + // Populate the input file with the pre-defined input and flush it. + *(inputFileOs_) << "end program"; + inputFileOs_.reset(); + + // Set-up the action kind. + compInst_.invocation().frontendOpts().programAction = EmitLLVM; + compInst_.invocation().preprocessorOpts().noReformat = true; + + // Set-up the output stream. We are using output buffer wrapped as an output + // stream, as opposed to an actual file (or a file descriptor). + llvm::SmallVector<char> outputFileBuffer; + std::unique_ptr<llvm::raw_pwrite_stream> outputFileStream( + new llvm::raw_svector_ostream(outputFileBuffer)); + compInst_.set_outputStream(std::move(outputFileStream)); + + // Execute the action. + bool success = ExecuteCompilerInvocation(&compInst_); + + // Validate the expected output. + EXPECT_TRUE(success); + EXPECT_TRUE(!outputFileBuffer.empty()); + + EXPECT_TRUE(llvm::StringRef(outputFileBuffer.data()) + .contains("define void @_QQmain()")); +} } // namespace Index: flang/test/Driver/emit-llvm.f90 =================================================================== --- /dev/null +++ flang/test/Driver/emit-llvm.f90 @@ -0,0 +1,22 @@ +! Test the `-emit-llvm` option + +! UNSUPPORTED: system-windows +! Windows is currently not supported in flang/lib/Optimizer/CodeGen/Target.cpp + +!------------ +! RUN COMMAND +!------------ +! RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s + +!---------------- +! EXPECTED OUTPUT +!---------------- +! CHECK: ; ModuleID = 'FIRModule' +! CHECK: define void @_QQmain() +! CHECK-NEXT: ret void +! CHECK-NEXT: } + +!------ +! INPUT +!------ +end program Index: flang/test/Driver/driver-help.f90 =================================================================== --- flang/test/Driver/driver-help.f90 +++ flang/test/Driver/driver-help.f90 @@ -65,6 +65,7 @@ ! HELP-FC1-NEXT:OPTIONS: ! HELP-FC1-NEXT: -cpp Enable predefined and command line preprocessor macros ! HELP-FC1-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted) +! 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 ! HELP-FC1-NEXT: -E Only run the preprocessor Index: flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp =================================================================== --- flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -35,6 +35,8 @@ return std::make_unique<ParseSyntaxOnlyAction>(); case EmitMLIR: return std::make_unique<EmitMLIRAction>(); + case EmitLLVM: + return std::make_unique<EmitLLVMAction>(); case EmitObj: return std::make_unique<EmitObjAction>(); case DebugUnparse: Index: flang/lib/Frontend/FrontendActions.cpp =================================================================== --- flang/lib/Frontend/FrontendActions.cpp +++ flang/lib/Frontend/FrontendActions.cpp @@ -14,6 +14,7 @@ #include "flang/Lower/Bridge.h" #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/Support/Verifier.h" +#include "flang/Optimizer/Support/FIRContext.h" #include "flang/Optimizer/Support/InitFIR.h" #include "flang/Optimizer/Support/KindMapping.h" #include "flang/Optimizer/Support/Utils.h" @@ -28,6 +29,7 @@ #include "mlir/IR/Dialect.h" #include "mlir/Pass/PassManager.h" +#include "mlir/Target/LLVMIR/ModuleTranslation.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include <clang/Basic/Diagnostic.h> @@ -407,6 +409,72 @@ ci.semantics().DumpSymbolsSources(llvm::outs()); } +#include "flang/Tools/CLOptions.inc" + +// Lower the previously generated MLIR module into an LLVM IR module +void CodeGenAction::GenerateLLVMIR() { + assert(mlirModule && "The MLIR module has not been generated yet."); + + CompilerInstance &ci = this->instance(); + + fir::support::loadDialects(*mlirCtx); + fir::support::registerLLVMTranslation(*mlirCtx); + + // Set-up the MLIR pass manager + mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit); + + pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); + pm.enableVerifier(/*verifyPasses=*/true); + mlir::PassPipelineCLParser passPipeline("", "Compiler passes to run"); + + // Create the pass pipeline + fir::createMLIRToLLVMPassPipeline(pm); + + // Run the pass manager + if (!mlir::succeeded(pm.run(*mlirModule))) { + unsigned diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed"); + ci.diagnostics().Report(diagID); + } + + // Translate to LLVM IR + llvm::Optional<llvm::StringRef> moduleName = mlirModule->getName(); + llvmCtx = std::make_unique<llvm::LLVMContext>(); + llvmModule = mlir::translateModuleToLLVMIR( + *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule"); + + if (!llvmModule) { + unsigned diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "failed to create the LLVM module"); + ci.diagnostics().Report(diagID); + return; + } +} + +void EmitLLVMAction::ExecuteAction() { + CompilerInstance &ci = this->instance(); + GenerateLLVMIR(); + + // If set, use the predefined outupt stream to print the generated module. + if (!ci.IsOutputStreamNull()) { + llvmModule->print( + ci.GetOutputStream(), /*AssemblyAnnotationWriter=*/nullptr); + return; + } + + // No predefined output stream was set. Create an output file and dump the + // generated module there. + std::unique_ptr<llvm::raw_ostream> os = ci.CreateDefaultOutputFile( + /*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "ll"); + if (!os) { + unsigned diagID = ci.diagnostics().getCustomDiagID( + clang::DiagnosticsEngine::Error, "failed to create the output file"); + ci.diagnostics().Report(diagID); + return; + } + llvmModule->print(*os, /*AssemblyAnnotationWriter=*/nullptr); +} + void EmitMLIRAction::ExecuteAction() { CompilerInstance &ci = this->instance(); Index: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -137,6 +137,9 @@ case clang::driver::options::OPT_emit_mlir: opts.programAction = EmitMLIR; break; + case clang::driver::options::OPT_emit_llvm: + opts.programAction = EmitLLVM; + break; case clang::driver::options::OPT_emit_obj: opts.programAction = EmitObj; break; Index: flang/include/flang/Frontend/FrontendOptions.h =================================================================== --- flang/include/flang/Frontend/FrontendOptions.h +++ flang/include/flang/Frontend/FrontendOptions.h @@ -34,6 +34,9 @@ /// Emit a .mlir file EmitMLIR, + /// Emit an .ll file + EmitLLVM, + /// Emit a .o file. EmitObj, @@ -84,9 +87,6 @@ /// Run a plugin action PluginAction - - /// TODO: RunPreprocessor, EmitLLVM, EmitLLVMOnly, - /// EmitCodeGenOnly, EmitAssembly, (...) }; /// \param suffix The file extension Index: flang/include/flang/Frontend/FrontendActions.h =================================================================== --- flang/include/flang/Frontend/FrontendActions.h +++ flang/include/flang/Frontend/FrontendActions.h @@ -13,6 +13,7 @@ #include "flang/Semantics/semantics.h" #include "mlir/IR/BuiltinOps.h" +#include "llvm/IR/Module.h" #include <memory> namespace Fortran::frontend { @@ -163,12 +164,25 @@ std::unique_ptr<mlir::ModuleOp> mlirModule; std::unique_ptr<mlir::MLIRContext> mlirCtx; /// } + + /// @name LLVM IR + std::unique_ptr<llvm::LLVMContext> llvmCtx; + std::unique_ptr<llvm::Module> llvmModule; + + /// Generates an LLVM IR module from CodeGenAction::mlirModule and saves it + /// in CodeGenAction::llvmModule. + void GenerateLLVMIR(); + /// } }; class EmitMLIRAction : public CodeGenAction { void ExecuteAction() override; }; +class EmitLLVMAction : public CodeGenAction { + void ExecuteAction() override; +}; + class EmitObjAction : public CodeGenAction { void ExecuteAction() override; }; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1071,7 +1071,7 @@ def d_Joined : Joined<["-"], "d">, Group<d_Group>; def emit_ast : Flag<["-"], "emit-ast">, HelpText<"Emit Clang AST files for source inputs">; -def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>, +def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option, FC1Option]>, Group<Action_Group>, HelpText<"Use the LLVM representation for assembler and object files">; def emit_interface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group<Action_Group>, HelpText<"Generate Interface Stub Files.">;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits