1 //===- bbc.cpp - Burnside Bridge Compiler -----------------------*- C++ -*-===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10 // 11 //===----------------------------------------------------------------------===// 12 /// 13 /// This is a tool for translating Fortran sources to the FIR dialect of MLIR. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "flang/Common/Fortran-features.h" 18 #include "flang/Common/default-kinds.h" 19 #include "flang/Lower/Bridge.h" 20 #include "flang/Lower/PFTBuilder.h" 21 #include "flang/Lower/Support/Verifier.h" 22 #include "flang/Optimizer/Support/FIRContext.h" 23 #include "flang/Optimizer/Support/InitFIR.h" 24 #include "flang/Optimizer/Support/InternalNames.h" 25 #include "flang/Optimizer/Support/KindMapping.h" 26 #include "flang/Optimizer/Support/Utils.h" 27 #include "flang/Optimizer/Transforms/Passes.h" 28 #include "flang/Parser/characters.h" 29 #include "flang/Parser/dump-parse-tree.h" 30 #include "flang/Parser/message.h" 31 #include "flang/Parser/parse-tree-visitor.h" 32 #include "flang/Parser/parse-tree.h" 33 #include "flang/Parser/parsing.h" 34 #include "flang/Parser/provenance.h" 35 #include "flang/Parser/unparse.h" 36 #include "flang/Semantics/expression.h" 37 #include "flang/Semantics/runtime-type-info.h" 38 #include "flang/Semantics/semantics.h" 39 #include "flang/Semantics/unparse-with-symbols.h" 40 #include "flang/Version.inc" 41 #include "mlir/IR/AsmState.h" 42 #include "mlir/IR/BuiltinOps.h" 43 #include "mlir/IR/MLIRContext.h" 44 #include "mlir/Parser/Parser.h" 45 #include "mlir/Pass/Pass.h" 46 #include "mlir/Pass/PassManager.h" 47 #include "mlir/Pass/PassRegistry.h" 48 #include "mlir/Transforms/GreedyPatternRewriteDriver.h" 49 #include "mlir/Transforms/Passes.h" 50 #include "llvm/Support/CommandLine.h" 51 #include "llvm/Support/ErrorOr.h" 52 #include "llvm/Support/FileSystem.h" 53 #include "llvm/Support/InitLLVM.h" 54 #include "llvm/Support/MemoryBuffer.h" 55 #include "llvm/Support/Path.h" 56 #include "llvm/Support/SourceMgr.h" 57 #include "llvm/Support/TargetSelect.h" 58 #include "llvm/Support/ToolOutputFile.h" 59 #include "llvm/Support/raw_ostream.h" 60 61 //===----------------------------------------------------------------------===// 62 // Some basic command-line options 63 //===----------------------------------------------------------------------===// 64 65 static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional, 66 llvm::cl::Required, 67 llvm::cl::desc("<input file>")); 68 69 static llvm::cl::opt<std::string> 70 outputFilename("o", llvm::cl::desc("Specify the output filename"), 71 llvm::cl::value_desc("filename")); 72 73 static llvm::cl::opt<bool> 74 emitFIR("emit-fir", 75 llvm::cl::desc("Dump the FIR created by lowering and exit"), 76 llvm::cl::init(false)); 77 78 static llvm::cl::opt<bool> pftDumpTest( 79 "pft-test", 80 llvm::cl::desc("parse the input, create a PFT, dump it, and exit"), 81 llvm::cl::init(false)); 82 83 static llvm::cl::opt<bool> enableOpenMP("fopenmp", 84 llvm::cl::desc("enable openmp"), 85 llvm::cl::init(false)); 86 87 static llvm::cl::opt<bool> enableOpenACC("fopenacc", 88 llvm::cl::desc("enable openacc"), 89 llvm::cl::init(false)); 90 91 #define FLANG_EXCLUDE_CODEGEN 92 #include "flang/Tools/CLOptions.inc" 93 94 //===----------------------------------------------------------------------===// 95 96 using ProgramName = std::string; 97 98 // Print the module without the "module { ... }" wrapper. 99 static void printModule(mlir::ModuleOp mlirModule, llvm::raw_ostream &out) { 100 for (auto &op : *mlirModule.getBody()) 101 out << op << '\n'; 102 out << '\n'; 103 } 104 105 static void registerAllPasses() { 106 fir::support::registerMLIRPassesForFortranTools(); 107 fir::registerOptTransformPasses(); 108 } 109 110 //===----------------------------------------------------------------------===// 111 // Translate Fortran input to FIR, a dialect of MLIR. 112 //===----------------------------------------------------------------------===// 113 114 static mlir::LogicalResult convertFortranSourceToMLIR( 115 std::string path, Fortran::parser::Options options, 116 const ProgramName &programPrefix, 117 Fortran::semantics::SemanticsContext &semanticsContext, 118 const mlir::PassPipelineCLParser &passPipeline) { 119 120 // prep for prescan and parse 121 Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()}; 122 parsing.Prescan(path, options); 123 if (!parsing.messages().empty() && (parsing.messages().AnyFatalError())) { 124 llvm::errs() << programPrefix << "could not scan " << path << '\n'; 125 parsing.messages().Emit(llvm::errs(), parsing.allCooked()); 126 return mlir::failure(); 127 } 128 129 // parse the input Fortran 130 parsing.Parse(llvm::outs()); 131 parsing.messages().Emit(llvm::errs(), parsing.allCooked()); 132 if (!parsing.consumedWholeFile()) { 133 parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(), 134 "parser FAIL (final position)"); 135 return mlir::failure(); 136 } 137 if ((!parsing.messages().empty() && (parsing.messages().AnyFatalError())) || 138 !parsing.parseTree().has_value()) { 139 llvm::errs() << programPrefix << "could not parse " << path << '\n'; 140 return mlir::failure(); 141 } 142 143 // run semantics 144 auto &parseTree = *parsing.parseTree(); 145 Fortran::semantics::Semantics semantics(semanticsContext, parseTree); 146 semantics.Perform(); 147 semantics.EmitMessages(llvm::errs()); 148 if (semantics.AnyFatalError()) { 149 llvm::errs() << programPrefix << "semantic errors in " << path << '\n'; 150 return mlir::failure(); 151 } 152 Fortran::semantics::RuntimeDerivedTypeTables tables; 153 if (!semantics.AnyFatalError()) { 154 tables = 155 Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext); 156 if (!tables.schemata) 157 llvm::errs() << programPrefix 158 << "could not find module file for __fortran_type_info\n"; 159 } 160 161 if (pftDumpTest) { 162 if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) { 163 Fortran::lower::dumpPFT(llvm::outs(), *ast); 164 return mlir::success(); 165 } 166 llvm::errs() << "Pre FIR Tree is NULL.\n"; 167 return mlir::failure(); 168 } 169 170 // translate to FIR dialect of MLIR 171 mlir::DialectRegistry registry; 172 fir::support::registerNonCodegenDialects(registry); 173 mlir::MLIRContext ctx(registry); 174 fir::support::loadNonCodegenDialects(ctx); 175 auto &defKinds = semanticsContext.defaultKinds(); 176 fir::KindMapping kindMap( 177 &ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)}); 178 auto burnside = Fortran::lower::LoweringBridge::create( 179 ctx, defKinds, semanticsContext.intrinsics(), parsing.allCooked(), "", 180 kindMap); 181 burnside.lower(parseTree, semanticsContext); 182 mlir::ModuleOp mlirModule = burnside.getModule(); 183 std::error_code ec; 184 std::string outputName = outputFilename; 185 if (!outputName.size()) 186 outputName = llvm::sys::path::stem(inputFilename).str().append(".mlir"); 187 llvm::raw_fd_ostream out(outputName, ec); 188 if (ec) 189 return mlir::emitError(mlir::UnknownLoc::get(&ctx), 190 "could not open output file ") 191 << outputName; 192 193 // Otherwise run the default passes. 194 mlir::PassManager pm(&ctx, mlir::OpPassManager::Nesting::Implicit); 195 pm.enableVerifier(/*verifyPasses=*/true); 196 mlir::applyPassManagerCLOptions(pm); 197 if (passPipeline.hasAnyOccurrences()) { 198 // run the command-line specified pipeline 199 (void)passPipeline.addToPipeline(pm, [&](const llvm::Twine &msg) { 200 mlir::emitError(mlir::UnknownLoc::get(&ctx)) << msg; 201 return mlir::failure(); 202 }); 203 } else if (emitFIR) { 204 // --emit-fir: Build the IR, verify it, and dump the IR if the IR passes 205 // verification. Use --dump-module-on-failure to dump invalid IR. 206 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 207 if (mlir::failed(pm.run(mlirModule))) { 208 llvm::errs() << "FATAL: verification of lowering to FIR failed"; 209 return mlir::failure(); 210 } 211 printModule(mlirModule, out); 212 return mlir::success(); 213 } else { 214 // run the default canned pipeline 215 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 216 217 // Add default optimizer pass pipeline. 218 fir::createDefaultFIROptimizerPassPipeline(pm); 219 } 220 221 if (mlir::succeeded(pm.run(mlirModule))) { 222 // Emit MLIR and do not lower to LLVM IR. 223 printModule(mlirModule, out); 224 return mlir::success(); 225 } 226 // Something went wrong. Try to dump the MLIR module. 227 llvm::errs() << "oops, pass manager reported failure\n"; 228 return mlir::failure(); 229 } 230 231 int main(int argc, char **argv) { 232 [[maybe_unused]] llvm::InitLLVM y(argc, argv); 233 registerAllPasses(); 234 235 mlir::registerMLIRContextCLOptions(); 236 mlir::registerPassManagerCLOptions(); 237 mlir::PassPipelineCLParser passPipe("", "Compiler passes to run"); 238 llvm::cl::ParseCommandLineOptions(argc, argv, "Burnside Bridge Compiler\n"); 239 240 ProgramName programPrefix; 241 programPrefix = argv[0] + ": "s; 242 243 Fortran::parser::Options options; 244 options.predefinitions.emplace_back("__flang__"s, "1"s); 245 options.predefinitions.emplace_back("__flang_major__"s, 246 std::string{FLANG_VERSION_MAJOR_STRING}); 247 options.predefinitions.emplace_back("__flang_minor__"s, 248 std::string{FLANG_VERSION_MINOR_STRING}); 249 options.predefinitions.emplace_back( 250 "__flang_patchlevel__"s, std::string{FLANG_VERSION_PATCHLEVEL_STRING}); 251 252 // enable parsing of OpenMP 253 if (enableOpenMP) { 254 options.features.Enable(Fortran::common::LanguageFeature::OpenMP); 255 options.predefinitions.emplace_back("_OPENMP", "201511"); 256 } 257 258 // enable parsing of OpenACC 259 if (enableOpenACC) { 260 options.features.Enable(Fortran::common::LanguageFeature::OpenACC); 261 options.predefinitions.emplace_back("_OPENACC", "201911"); 262 } 263 264 Fortran::common::IntrinsicTypeDefaultKinds defaultKinds; 265 Fortran::parser::AllSources allSources; 266 Fortran::parser::AllCookedSources allCookedSources(allSources); 267 Fortran::semantics::SemanticsContext semanticsContext{ 268 defaultKinds, options.features, allCookedSources}; 269 270 return mlir::failed(convertFortranSourceToMLIR( 271 inputFilename, options, programPrefix, semanticsContext, passPipe)); 272 } 273