1 //===- tco.cpp - Tilikum Crossing Opt ---------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This is to be like LLVM's opt program, only for FIR. Such a program is
10 // required for roundtrip testing, etc.
12 //===----------------------------------------------------------------------===//
14 #include "flang/Optimizer/CodeGen/CodeGen.h"
15 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
16 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
17 #include "flang/Optimizer/Support/InitFIR.h"
18 #include "flang/Optimizer/Support/InternalNames.h"
19 #include "flang/Optimizer/Transforms/Passes.h"
20 #include "flang/Tools/CrossToolHelpers.h"
21 #include "mlir/IR/AsmState.h"
22 #include "mlir/IR/BuiltinOps.h"
23 #include "mlir/IR/MLIRContext.h"
24 #include "mlir/Parser/Parser.h"
25 #include "mlir/Pass/Pass.h"
26 #include "mlir/Pass/PassManager.h"
27 #include "mlir/Transforms/Passes.h"
28 #include "llvm/Passes/OptimizationLevel.h"
29 #include "llvm/Support/CommandLine.h"
30 #include "llvm/Support/ErrorOr.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/InitLLVM.h"
33 #include "llvm/Support/MemoryBuffer.h"
34 #include "llvm/Support/SourceMgr.h"
35 #include "llvm/Support/TargetSelect.h"
36 #include "llvm/Support/ToolOutputFile.h"
37 #include "llvm/Support/raw_ostream.h"
41 static cl::opt
<std::string
>
42 inputFilename(cl::Positional
, cl::desc("<input file>"), cl::init("-"));
44 static cl::opt
<std::string
> outputFilename("o",
45 cl::desc("Specify output filename"),
46 cl::value_desc("filename"),
49 static cl::opt
<bool> emitFir("emit-fir",
50 cl::desc("Parse and pretty-print the input"),
53 static cl::opt
<std::string
> targetTriple("target",
54 cl::desc("specify a target triple"),
57 static cl::opt
<bool> codeGenLLVM(
59 cl::desc("Run only CodeGen passes and translate FIR to LLVM IR"),
62 #include "flang/Tools/CLOptions.inc"
64 static void printModuleBody(mlir::ModuleOp mod
, raw_ostream
&output
) {
65 for (auto &op
: *mod
.getBody())
69 // compile a .fir file
70 static mlir::LogicalResult
71 compileFIR(const mlir::PassPipelineCLParser
&passPipeline
) {
72 // check that there is a file to load
73 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> fileOrErr
=
74 MemoryBuffer::getFileOrSTDIN(inputFilename
);
76 if (std::error_code EC
= fileOrErr
.getError()) {
77 errs() << "Could not open file: " << EC
.message() << '\n';
78 return mlir::failure();
81 // load the file into a module
83 sourceMgr
.AddNewSourceBuffer(std::move(*fileOrErr
), SMLoc());
84 mlir::DialectRegistry registry
;
85 fir::support::registerDialects(registry
);
86 mlir::MLIRContext
context(registry
);
87 fir::support::loadDialects(context
);
88 fir::support::registerLLVMTranslation(context
);
89 auto owningRef
= mlir::parseSourceFile
<mlir::ModuleOp
>(sourceMgr
, &context
);
92 errs() << "Error can't load file " << inputFilename
<< '\n';
93 return mlir::failure();
95 if (mlir::failed(owningRef
->verifyInvariants())) {
96 errs() << "Error verifying FIR module\n";
97 return mlir::failure();
101 ToolOutputFile
out(outputFilename
, ec
, sys::fs::OF_None
);
104 fir::KindMapping kindMap
{&context
};
105 fir::setTargetTriple(*owningRef
, targetTriple
);
106 fir::setKindMapping(*owningRef
, kindMap
);
107 mlir::PassManager
pm((*owningRef
)->getName(),
108 mlir::OpPassManager::Nesting::Implicit
);
109 pm
.enableVerifier(/*verifyPasses=*/true);
110 (void)mlir::applyPassManagerCLOptions(pm
);
112 // parse the input and pretty-print it back out
113 // -emit-fir intentionally disables all the passes
114 } else if (passPipeline
.hasAnyOccurrences()) {
115 auto errorHandler
= [&](const Twine
&msg
) {
116 mlir::emitError(mlir::UnknownLoc::get(pm
.getContext())) << msg
;
117 return mlir::failure();
119 if (mlir::failed(passPipeline
.addToPipeline(pm
, errorHandler
)))
120 return mlir::failure();
122 MLIRToLLVMPassPipelineConfig
config(llvm::OptimizationLevel::O2
);
124 // Run only CodeGen passes.
125 fir::createDefaultFIRCodeGenPassPipeline(pm
, config
);
127 // Run tco with O2 by default.
128 fir::createMLIRToLLVMPassPipeline(pm
, config
);
130 fir::addLLVMDialectToLLVMPass(pm
, out
.os());
133 // run the pass manager
134 if (mlir::succeeded(pm
.run(*owningRef
))) {
135 // passes ran successfully, so keep the output
136 if ((emitFir
|| passPipeline
.hasAnyOccurrences()) && !codeGenLLVM
)
137 printModuleBody(*owningRef
, out
.os());
139 return mlir::success();
142 // pass manager failed
143 printModuleBody(*owningRef
, errs());
144 errs() << "\n\nFAILED: " << inputFilename
<< '\n';
145 return mlir::failure();
148 int main(int argc
, char **argv
) {
149 // Disable the ExternalNameConversion pass by default until all the tests have
150 // been updated to pass with it enabled.
151 disableExternalNameConversion
= true;
153 [[maybe_unused
]] InitLLVM
y(argc
, argv
);
154 fir::support::registerMLIRPassesForFortranTools();
155 fir::registerOptCodeGenPasses();
156 fir::registerOptTransformPasses();
157 mlir::registerMLIRContextCLOptions();
158 mlir::registerPassManagerCLOptions();
159 mlir::PassPipelineCLParser
passPipe("", "Compiler passes to run");
160 cl::ParseCommandLineOptions(argc
, argv
, "Tilikum Crossing Optimizer\n");
161 return mlir::failed(compileFIR(passPipe
));