mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-26 13:26:22 +00:00
[flang][driver] Add support for -emit-llvm
This patch adds support for the `-emit-llvm` option in the frontend driver (i.e. `flang-new -fc1`). Similarly to Clang, `flang-new -fc1 -emit-llvm file.f` will generate a textual LLVM IR file. Depends on D118985 Differential Revision: https://reviews.llvm.org/D119012
This commit is contained in:
parent
b254a2a703
commit
e993b20c04
@ -1071,7 +1071,7 @@ def d_Flag : Flag<["-"], "d">, Group<d_Group>;
|
||||
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.">;
|
||||
|
@ -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 @@ protected:
|
||||
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;
|
||||
};
|
||||
|
@ -34,6 +34,9 @@ enum ActionKind {
|
||||
/// Emit a .mlir file
|
||||
EmitMLIR,
|
||||
|
||||
/// Emit an .ll file
|
||||
EmitLLVM,
|
||||
|
||||
/// Emit a .o file.
|
||||
EmitObj,
|
||||
|
||||
@ -84,9 +87,6 @@ enum ActionKind {
|
||||
|
||||
/// Run a plugin action
|
||||
PluginAction
|
||||
|
||||
/// TODO: RunPreprocessor, EmitLLVM, EmitLLVMOnly,
|
||||
/// EmitCodeGenOnly, EmitAssembly, (...)
|
||||
};
|
||||
|
||||
/// \param suffix The file extension
|
||||
|
@ -137,6 +137,9 @@ static bool ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
|
||||
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;
|
||||
|
@ -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 @@ void GetSymbolsSourcesAction::ExecuteAction() {
|
||||
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();
|
||||
|
||||
|
@ -35,6 +35,8 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(
|
||||
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:
|
||||
|
@ -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
|
||||
|
22
flang/test/Driver/emit-llvm.f90
Normal file
22
flang/test/Driver/emit-llvm.f90
Normal file
@ -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
|
@ -161,4 +161,31 @@ TEST_F(FrontendActionTest, ParseSyntaxOnly) {
|
||||
.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
|
||||
|
Loading…
x
Reference in New Issue
Block a user