awarzynski updated this revision to Diff 407130.
awarzynski added a comment.
Herald added a subscriber: mehdi_amini.
Updated `fir::CodeGenSpecifics::get` to see whether the unit tests pass on
Windows. If they do, I'll create a seperate patch with this change.
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/lib/Optimizer/CodeGen/Target.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/Optimizer/CodeGen/Target.cpp
===================================================================
--- flang/lib/Optimizer/CodeGen/Target.cpp
+++ flang/lib/Optimizer/CodeGen/Target.cpp
@@ -238,9 +238,7 @@
} // namespace
// Instantiate the overloaded target instance based on the triple value.
-// Currently, the implementation only instantiates `i386-unknown-linux-gnu`,
-// `x86_64-unknown-linux-gnu`, aarch64 and ppc64le like triples. Other targets
-// should be added to this file as needed.
+// TODO: Add other target to this file as needed.
std::unique_ptr<fir::CodeGenSpecifics>
fir::CodeGenSpecifics::get(mlir::MLIRContext *ctx, llvm::Triple &&trp,
KindMapping &&kindMap) {
@@ -253,6 +251,7 @@
break;
case llvm::Triple::OSType::Linux:
case llvm::Triple::OSType::Darwin:
+ case llvm::Triple::OSType::Win32:
return std::make_unique<TargetI386>(ctx, std::move(trp),
std::move(kindMap));
}
@@ -263,6 +262,7 @@
break;
case llvm::Triple::OSType::Linux:
case llvm::Triple::OSType::Darwin:
+ case llvm::Triple::OSType::Win32:
return std::make_unique<TargetX86_64>(ctx, std::move(trp),
std::move(kindMap));
}
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