diff --git a/flang/lib/Optimizer/CMakeLists.txt b/flang/lib/Optimizer/CMakeLists.txt --- a/flang/lib/Optimizer/CMakeLists.txt +++ b/flang/lib/Optimizer/CMakeLists.txt @@ -10,6 +10,8 @@ Support/InternalNames.cpp Support/KindMapping.cpp + CodeGen/CodeGen.cpp + Transforms/Inliner.cpp DEPENDS diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -0,0 +1,99 @@ +#include "flang/Optimizer/CodeGen/CodeGen.h" +#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" +#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Target/LLVMIR.h" +#include "mlir/Transforms/DialectConversion.h" +#include "llvm/IR/Module.h" + +using namespace llvm; + +static cl::opt + disableFirToLLVMIR("disable-fir2llvmir", + cl::desc("disable FIR to LLVM-IR dialect pass"), + cl::init(false), cl::Hidden); + +static cl::opt disableLLVM("disable-llvm", cl::desc("disable LLVM pass"), + cl::init(false), cl::Hidden); + +class FIRToLLVMTypeConverter : public mlir::LLVMTypeConverter { +public: + FIRToLLVMTypeConverter(mlir::MLIRContext *context, fir::NameUniquer &uniquer) + : LLVMTypeConverter(context) {} +}; +// Lower a SELECT operation into a cascade of conditional branches. The +// last case must be the `true` condition. +/// Convert FIR dialect to LLVM dialect +/// +/// This pass lowers all FIR dialect operations to LLVM IR dialect. An +/// MLIR pass is used to lower residual Std dialect to LLVM IR dialect. +struct FIRToLLVMLoweringPass + : public mlir::PassWrapper> { + FIRToLLVMLoweringPass(fir::NameUniquer &uniquer) : uniquer{uniquer} {} + + mlir::ModuleOp getModule() { return getOperation(); } + + void runOnOperation() override final { + if (disableFirToLLVMIR) + return; + + auto *context{&getContext()}; + FIRToLLVMTypeConverter typeConverter{context, uniquer}; + auto loc = mlir::UnknownLoc::get(context); + mlir::OwningRewritePatternList pattern; + mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); + mlir::ConversionTarget target{*context}; + target.addLegalDialect(); + + // required NOPs for applying a full conversion + target.addLegalOp(); + + // apply the patterns + if (mlir::failed(mlir::applyFullConversion(getModule(), target, + std::move(pattern)))) { + mlir::emitError(loc, "error in converting to LLVM-IR dialect\n"); + signalPassFailure(); + } + } + +private: + fir::NameUniquer &uniquer; +}; + +/// Lower from LLVM IR dialect to proper LLVM-IR and dump the module +struct LLVMIRLoweringPass + : public mlir::PassWrapper> { + LLVMIRLoweringPass(raw_ostream &output) : output{output} {} + + mlir::ModuleOp getModule() { return getOperation(); } + + void runOnOperation() override final { + if (disableLLVM) + return; + + if (auto llvmModule = mlir::translateModuleToLLVMIR(getModule())) { + llvmModule->print(output, nullptr); + return; + } + + auto *ctxt = getModule().getContext(); + mlir::emitError(mlir::UnknownLoc::get(ctxt), "could not emit LLVM-IR\n"); + signalPassFailure(); + } + +private: + llvm::raw_ostream &output; +}; + +std::unique_ptr +fir::createFIRToLLVMPass(fir::NameUniquer &nameUniquer) { + return std::make_unique(nameUniquer); +} + +std::unique_ptr +fir::createLLVMDialectToLLVMPass(llvm::raw_ostream &output) { + return std::make_unique(output); +} diff --git a/flang/test/Fir/empty-function.fir b/flang/test/Fir/empty-function.fir new file mode 100644 --- /dev/null +++ b/flang/test/Fir/empty-function.fir @@ -0,0 +1,7 @@ +// RUN: tco -o - %s | FileCheck %s + +// CHECK-LABEL: define void @f +func @f() { + // CHECK: ret void + return +} diff --git a/flang/tools/tco/CMakeLists.txt b/flang/tools/tco/CMakeLists.txt --- a/flang/tools/tco/CMakeLists.txt +++ b/flang/tools/tco/CMakeLists.txt @@ -20,3 +20,4 @@ add_flang_tool(tco tco.cpp) target_link_libraries(tco PRIVATE ${LIBS}) +add_dependencies(tco FIROptCodeGenPassIncGen) diff --git a/flang/tools/tco/tco.cpp b/flang/tools/tco/tco.cpp --- a/flang/tools/tco/tco.cpp +++ b/flang/tools/tco/tco.cpp @@ -11,7 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "flang/Optimizer/CodeGen/CodeGen.h" #include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Support/KindMapping.h" #include "mlir/IR/MLIRContext.h" #include "mlir/IR/Module.h" @@ -76,6 +78,7 @@ ToolOutputFile out(outputFilename, ec, sys::fs::OF_None); // run passes + fir::NameUniquer uniquer; mlir::PassManager pm{context.get()}; mlir::applyPassManagerCLOptions(pm); if (emitFir) { @@ -85,6 +88,8 @@ // TODO: Actually add passes when added to FIR code base // add all the passes // the user can disable them individually + pm.addPass(fir::createFIRToLLVMPass(uniquer)); + pm.addPass(fir::createLLVMDialectToLLVMPass(out.os())); } // run the pass manager