1 //===--- FrontendActions.cpp ----------------------------------------------===// 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 #include "flang/Frontend/FrontendActions.h" 10 #include "flang/Common/default-kinds.h" 11 #include "flang/Frontend/CompilerInstance.h" 12 #include "flang/Frontend/FrontendOptions.h" 13 #include "flang/Frontend/PreprocessorOptions.h" 14 #include "flang/Lower/Bridge.h" 15 #include "flang/Lower/PFTBuilder.h" 16 #include "flang/Lower/Support/Verifier.h" 17 #include "flang/Optimizer/Support/FIRContext.h" 18 #include "flang/Optimizer/Support/InitFIR.h" 19 #include "flang/Optimizer/Support/KindMapping.h" 20 #include "flang/Optimizer/Support/Utils.h" 21 #include "flang/Parser/dump-parse-tree.h" 22 #include "flang/Parser/parsing.h" 23 #include "flang/Parser/provenance.h" 24 #include "flang/Parser/source.h" 25 #include "flang/Parser/unparse.h" 26 #include "flang/Semantics/runtime-type-info.h" 27 #include "flang/Semantics/semantics.h" 28 #include "flang/Semantics/unparse-with-symbols.h" 29 30 #include "mlir/IR/Dialect.h" 31 #include "mlir/Pass/PassManager.h" 32 #include "mlir/Target/LLVMIR/ModuleTranslation.h" 33 #include "llvm/ADT/StringRef.h" 34 #include "llvm/Analysis/TargetLibraryInfo.h" 35 #include "llvm/Analysis/TargetTransformInfo.h" 36 #include "llvm/IR/LegacyPassManager.h" 37 #include "llvm/MC/TargetRegistry.h" 38 #include "llvm/Passes/PassBuilder.h" 39 #include "llvm/Support/ErrorHandling.h" 40 #include "llvm/Target/TargetMachine.h" 41 #include <clang/Basic/Diagnostic.h> 42 #include <memory> 43 44 using namespace Fortran::frontend; 45 46 //===----------------------------------------------------------------------===// 47 // Custom BeginSourceFileAction 48 //===----------------------------------------------------------------------===// 49 bool PrescanAction::BeginSourceFileAction() { return RunPrescan(); } 50 51 bool PrescanAndParseAction::BeginSourceFileAction() { 52 return RunPrescan() && RunParse(); 53 } 54 55 bool PrescanAndSemaAction::BeginSourceFileAction() { 56 return RunPrescan() && RunParse() && RunSemanticChecks() && 57 GenerateRtTypeTables(); 58 } 59 60 bool PrescanAndSemaDebugAction::BeginSourceFileAction() { 61 // This is a "debug" action for development purposes. To facilitate this, the 62 // semantic checks are made to succeed unconditionally to prevent this action 63 // from exiting early (i.e. in the presence of semantic errors). We should 64 // never do this in actions intended for end-users or otherwise regular 65 // compiler workflows! 66 return RunPrescan() && RunParse() && (RunSemanticChecks() || true) && 67 (GenerateRtTypeTables() || true); 68 } 69 70 bool CodeGenAction::BeginSourceFileAction() { 71 bool res = RunPrescan() && RunParse() && RunSemanticChecks(); 72 if (!res) 73 return res; 74 75 CompilerInstance &ci = this->instance(); 76 77 // Load the MLIR dialects required by Flang 78 mlir::DialectRegistry registry; 79 mlirCtx = std::make_unique<mlir::MLIRContext>(registry); 80 fir::support::registerNonCodegenDialects(registry); 81 fir::support::loadNonCodegenDialects(*mlirCtx); 82 83 // Create a LoweringBridge 84 const common::IntrinsicTypeDefaultKinds &defKinds = 85 ci.invocation().semanticsContext().defaultKinds(); 86 fir::KindMapping kindMap(mlirCtx.get(), 87 llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)}); 88 lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create(*mlirCtx, 89 defKinds, ci.invocation().semanticsContext().intrinsics(), 90 ci.parsing().allCooked(), ci.invocation().targetOpts().triple, kindMap); 91 92 // Create a parse tree and lower it to FIR 93 Fortran::parser::Program &parseTree{*ci.parsing().parseTree()}; 94 lb.lower(parseTree, ci.invocation().semanticsContext()); 95 mlirModule = std::make_unique<mlir::ModuleOp>(lb.getModule()); 96 97 // Run the default passes. 98 mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit); 99 pm.enableVerifier(/*verifyPasses=*/true); 100 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 101 102 if (mlir::failed(pm.run(*mlirModule))) { 103 unsigned diagID = 104 ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, 105 "verification of lowering to FIR failed"); 106 ci.diagnostics().Report(diagID); 107 return false; 108 } 109 110 return true; 111 } 112 113 //===----------------------------------------------------------------------===// 114 // Custom ExecuteAction 115 //===----------------------------------------------------------------------===// 116 void InputOutputTestAction::ExecuteAction() { 117 CompilerInstance &ci = instance(); 118 119 // Create a stream for errors 120 std::string buf; 121 llvm::raw_string_ostream error_stream{buf}; 122 123 // Read the input file 124 Fortran::parser::AllSources &allSources{ci.allSources()}; 125 std::string path{GetCurrentFileOrBufferName()}; 126 const Fortran::parser::SourceFile *sf; 127 if (path == "-") 128 sf = allSources.ReadStandardInput(error_stream); 129 else 130 sf = allSources.Open(path, error_stream, std::optional<std::string>{"."s}); 131 llvm::ArrayRef<char> fileContent = sf->content(); 132 133 // Output file descriptor to receive the contents of the input file. 134 std::unique_ptr<llvm::raw_ostream> os; 135 136 // Copy the contents from the input file to the output file 137 if (!ci.IsOutputStreamNull()) { 138 // An output stream (outputStream_) was set earlier 139 ci.WriteOutputStream(fileContent.data()); 140 } else { 141 // No pre-set output stream - create an output file 142 os = ci.CreateDefaultOutputFile( 143 /*binary=*/true, GetCurrentFileOrBufferName(), "txt"); 144 if (!os) 145 return; 146 (*os) << fileContent.data(); 147 } 148 } 149 150 void PrintPreprocessedAction::ExecuteAction() { 151 std::string buf; 152 llvm::raw_string_ostream outForPP{buf}; 153 154 // Format or dump the prescanner's output 155 CompilerInstance &ci = this->instance(); 156 if (ci.invocation().preprocessorOpts().noReformat) { 157 ci.parsing().DumpCookedChars(outForPP); 158 } else { 159 ci.parsing().EmitPreprocessedSource( 160 outForPP, !ci.invocation().preprocessorOpts().noLineDirectives); 161 } 162 163 // Print diagnostics from the prescanner 164 ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources()); 165 166 // If a pre-defined output stream exists, dump the preprocessed content there 167 if (!ci.IsOutputStreamNull()) { 168 // Send the output to the pre-defined output buffer. 169 ci.WriteOutputStream(outForPP.str()); 170 return; 171 } 172 173 // Create a file and save the preprocessed output there 174 std::unique_ptr<llvm::raw_pwrite_stream> os{ci.CreateDefaultOutputFile( 175 /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName())}; 176 if (!os) { 177 return; 178 } 179 180 (*os) << outForPP.str(); 181 } 182 183 void DebugDumpProvenanceAction::ExecuteAction() { 184 this->instance().parsing().DumpProvenance(llvm::outs()); 185 } 186 187 void ParseSyntaxOnlyAction::ExecuteAction() { 188 } 189 190 void DebugUnparseNoSemaAction::ExecuteAction() { 191 auto &invoc = this->instance().invocation(); 192 auto &parseTree{instance().parsing().parseTree()}; 193 194 // TODO: Options should come from CompilerInvocation 195 Unparse(llvm::outs(), *parseTree, 196 /*encoding=*/Fortran::parser::Encoding::UTF_8, 197 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 198 /*preStatement=*/nullptr, 199 invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr); 200 } 201 202 void DebugUnparseAction::ExecuteAction() { 203 auto &invoc = this->instance().invocation(); 204 auto &parseTree{instance().parsing().parseTree()}; 205 206 CompilerInstance &ci = this->instance(); 207 auto os{ci.CreateDefaultOutputFile( 208 /*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName())}; 209 210 // TODO: Options should come from CompilerInvocation 211 Unparse(*os, *parseTree, 212 /*encoding=*/Fortran::parser::Encoding::UTF_8, 213 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false, 214 /*preStatement=*/nullptr, 215 invoc.useAnalyzedObjectsForUnparse() ? &invoc.asFortran() : nullptr); 216 217 // Report fatal semantic errors 218 reportFatalSemanticErrors(); 219 } 220 221 void DebugUnparseWithSymbolsAction::ExecuteAction() { 222 auto &parseTree{*instance().parsing().parseTree()}; 223 224 Fortran::semantics::UnparseWithSymbols( 225 llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8); 226 227 // Report fatal semantic errors 228 reportFatalSemanticErrors(); 229 } 230 231 void DebugDumpSymbolsAction::ExecuteAction() { 232 CompilerInstance &ci = this->instance(); 233 234 if (!ci.getRtTyTables().schemata) { 235 unsigned DiagID = 236 ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, 237 "could not find module file for __fortran_type_info"); 238 ci.diagnostics().Report(DiagID); 239 llvm::errs() << "\n"; 240 return; 241 } 242 243 // Dump symbols 244 ci.semantics().DumpSymbols(llvm::outs()); 245 } 246 247 void DebugDumpAllAction::ExecuteAction() { 248 CompilerInstance &ci = this->instance(); 249 250 // Dump parse tree 251 auto &parseTree{instance().parsing().parseTree()}; 252 llvm::outs() << "========================"; 253 llvm::outs() << " Flang: parse tree dump "; 254 llvm::outs() << "========================\n"; 255 Fortran::parser::DumpTree( 256 llvm::outs(), parseTree, &ci.invocation().asFortran()); 257 258 if (!ci.getRtTyTables().schemata) { 259 unsigned DiagID = 260 ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, 261 "could not find module file for __fortran_type_info"); 262 ci.diagnostics().Report(DiagID); 263 llvm::errs() << "\n"; 264 return; 265 } 266 267 // Dump symbols 268 llvm::outs() << "====================="; 269 llvm::outs() << " Flang: symbols dump "; 270 llvm::outs() << "=====================\n"; 271 ci.semantics().DumpSymbols(llvm::outs()); 272 } 273 274 void DebugDumpParseTreeNoSemaAction::ExecuteAction() { 275 auto &parseTree{instance().parsing().parseTree()}; 276 277 // Dump parse tree 278 Fortran::parser::DumpTree( 279 llvm::outs(), parseTree, &this->instance().invocation().asFortran()); 280 } 281 282 void DebugDumpParseTreeAction::ExecuteAction() { 283 auto &parseTree{instance().parsing().parseTree()}; 284 285 // Dump parse tree 286 Fortran::parser::DumpTree( 287 llvm::outs(), parseTree, &this->instance().invocation().asFortran()); 288 289 // Report fatal semantic errors 290 reportFatalSemanticErrors(); 291 } 292 293 void DebugMeasureParseTreeAction::ExecuteAction() { 294 CompilerInstance &ci = this->instance(); 295 296 // Parse. In case of failure, report and return. 297 ci.parsing().Parse(llvm::outs()); 298 299 if (!ci.parsing().messages().empty() && 300 (ci.invocation().warnAsErr() || 301 ci.parsing().messages().AnyFatalError())) { 302 unsigned diagID = ci.diagnostics().getCustomDiagID( 303 clang::DiagnosticsEngine::Error, "Could not parse %0"); 304 ci.diagnostics().Report(diagID) << GetCurrentFileOrBufferName(); 305 306 ci.parsing().messages().Emit( 307 llvm::errs(), this->instance().allCookedSources()); 308 return; 309 } 310 311 // Report the diagnostics from parsing 312 ci.parsing().messages().Emit(llvm::errs(), ci.allCookedSources()); 313 314 auto &parseTree{*ci.parsing().parseTree()}; 315 316 // Measure the parse tree 317 MeasurementVisitor visitor; 318 Fortran::parser::Walk(parseTree, visitor); 319 llvm::outs() << "Parse tree comprises " << visitor.objects 320 << " objects and occupies " << visitor.bytes 321 << " total bytes.\n"; 322 } 323 324 void DebugPreFIRTreeAction::ExecuteAction() { 325 CompilerInstance &ci = this->instance(); 326 // Report and exit if fatal semantic errors are present 327 if (reportFatalSemanticErrors()) { 328 return; 329 } 330 331 auto &parseTree{*ci.parsing().parseTree()}; 332 333 // Dump pre-FIR tree 334 if (auto ast{Fortran::lower::createPFT( 335 parseTree, ci.invocation().semanticsContext())}) { 336 Fortran::lower::dumpPFT(llvm::outs(), *ast); 337 } else { 338 unsigned diagID = ci.diagnostics().getCustomDiagID( 339 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 340 ci.diagnostics().Report(diagID); 341 } 342 } 343 344 void DebugDumpParsingLogAction::ExecuteAction() { 345 CompilerInstance &ci = this->instance(); 346 347 ci.parsing().Parse(llvm::errs()); 348 ci.parsing().DumpParsingLog(llvm::outs()); 349 } 350 351 void GetDefinitionAction::ExecuteAction() { 352 CompilerInstance &ci = this->instance(); 353 354 // Report and exit if fatal semantic errors are present 355 if (reportFatalSemanticErrors()) { 356 return; 357 } 358 359 parser::AllCookedSources &cs = ci.allCookedSources(); 360 unsigned diagID = ci.diagnostics().getCustomDiagID( 361 clang::DiagnosticsEngine::Error, "Symbol not found"); 362 363 auto gdv = ci.invocation().frontendOpts().getDefVals; 364 auto charBlock{cs.GetCharBlockFromLineAndColumns( 365 gdv.line, gdv.startColumn, gdv.endColumn)}; 366 if (!charBlock) { 367 ci.diagnostics().Report(diagID); 368 return; 369 } 370 371 llvm::outs() << "String range: >" << charBlock->ToString() << "<\n"; 372 373 auto *symbol{ci.invocation() 374 .semanticsContext() 375 .FindScope(*charBlock) 376 .FindSymbol(*charBlock)}; 377 if (!symbol) { 378 ci.diagnostics().Report(diagID); 379 return; 380 } 381 382 llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 383 384 auto sourceInfo{cs.GetSourcePositionRange(symbol->name())}; 385 if (!sourceInfo) { 386 llvm_unreachable( 387 "Failed to obtain SourcePosition." 388 "TODO: Please, write a test and replace this with a diagnostic!"); 389 return; 390 } 391 392 llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n"; 393 llvm::outs() << symbol->name().ToString() << ": " 394 << sourceInfo->first.file.path() << ", " 395 << sourceInfo->first.line << ", " << sourceInfo->first.column 396 << "-" << sourceInfo->second.column << "\n"; 397 } 398 399 void GetSymbolsSourcesAction::ExecuteAction() { 400 CompilerInstance &ci = this->instance(); 401 402 // Report and exit if fatal semantic errors are present 403 if (reportFatalSemanticErrors()) { 404 return; 405 } 406 407 ci.semantics().DumpSymbolsSources(llvm::outs()); 408 } 409 410 #include "flang/Tools/CLOptions.inc" 411 412 // Lower the previously generated MLIR module into an LLVM IR module 413 void CodeGenAction::GenerateLLVMIR() { 414 assert(mlirModule && "The MLIR module has not been generated yet."); 415 416 CompilerInstance &ci = this->instance(); 417 418 fir::support::loadDialects(*mlirCtx); 419 fir::support::registerLLVMTranslation(*mlirCtx); 420 421 // Set-up the MLIR pass manager 422 mlir::PassManager pm(mlirCtx.get(), mlir::OpPassManager::Nesting::Implicit); 423 424 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); 425 pm.enableVerifier(/*verifyPasses=*/true); 426 427 // Create the pass pipeline 428 fir::createMLIRToLLVMPassPipeline(pm); 429 430 // Run the pass manager 431 if (!mlir::succeeded(pm.run(*mlirModule))) { 432 unsigned diagID = ci.diagnostics().getCustomDiagID( 433 clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed"); 434 ci.diagnostics().Report(diagID); 435 } 436 437 // Translate to LLVM IR 438 llvm::Optional<llvm::StringRef> moduleName = mlirModule->getName(); 439 llvmCtx = std::make_unique<llvm::LLVMContext>(); 440 llvmModule = mlir::translateModuleToLLVMIR( 441 *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule"); 442 443 if (!llvmModule) { 444 unsigned diagID = ci.diagnostics().getCustomDiagID( 445 clang::DiagnosticsEngine::Error, "failed to create the LLVM module"); 446 ci.diagnostics().Report(diagID); 447 return; 448 } 449 } 450 451 void EmitLLVMAction::ExecuteAction() { 452 CompilerInstance &ci = this->instance(); 453 GenerateLLVMIR(); 454 455 // If set, use the predefined outupt stream to print the generated module. 456 if (!ci.IsOutputStreamNull()) { 457 llvmModule->print( 458 ci.GetOutputStream(), /*AssemblyAnnotationWriter=*/nullptr); 459 return; 460 } 461 462 // No predefined output stream was set. Create an output file and dump the 463 // generated module there. 464 std::unique_ptr<llvm::raw_ostream> os = ci.CreateDefaultOutputFile( 465 /*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "ll"); 466 if (!os) { 467 unsigned diagID = ci.diagnostics().getCustomDiagID( 468 clang::DiagnosticsEngine::Error, "failed to create the output file"); 469 ci.diagnostics().Report(diagID); 470 return; 471 } 472 llvmModule->print(*os, /*AssemblyAnnotationWriter=*/nullptr); 473 } 474 475 void EmitMLIRAction::ExecuteAction() { 476 CompilerInstance &ci = this->instance(); 477 478 // Print the output. If a pre-defined output stream exists, dump the MLIR 479 // content there. 480 if (!ci.IsOutputStreamNull()) { 481 mlirModule->print(ci.GetOutputStream()); 482 return; 483 } 484 485 // ... otherwise, print to a file. 486 std::unique_ptr<llvm::raw_pwrite_stream> os{ci.CreateDefaultOutputFile( 487 /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "mlir")}; 488 if (!os) { 489 unsigned diagID = ci.diagnostics().getCustomDiagID( 490 clang::DiagnosticsEngine::Error, "failed to create the output file"); 491 ci.diagnostics().Report(diagID); 492 return; 493 } 494 495 mlirModule->print(*os); 496 } 497 498 void BackendAction::ExecuteAction() { 499 CompilerInstance &ci = this->instance(); 500 // Generate an LLVM module if it's not already present (it will already be 501 // present if the input file is an LLVM IR/BC file). 502 if (!llvmModule) 503 GenerateLLVMIR(); 504 505 // Create `Target` 506 std::string error; 507 const std::string &theTriple = llvmModule->getTargetTriple(); 508 const llvm::Target *theTarget = 509 llvm::TargetRegistry::lookupTarget(theTriple, error); 510 // TODO: Make this a diagnostic once `flang-new` can consume LLVM IR files 511 // (in which users could use unsupported triples) 512 assert(theTarget && "Failed to create Target"); 513 514 // Create `TargetMachine` 515 std::unique_ptr<llvm::TargetMachine> TM; 516 TM.reset(theTarget->createTargetMachine(theTriple, /*CPU=*/"", 517 /*Features=*/"", llvm::TargetOptions(), llvm::None)); 518 assert(TM && "Failed to create TargetMachine"); 519 llvmModule->setDataLayout(TM->createDataLayout()); 520 521 // If the output stream is a file, generate it and define the corresponding 522 // output stream. If a pre-defined output stream is available, we will use 523 // that instead. 524 // 525 // NOTE: `os` is a smart pointer that will be destroyed at the end of this 526 // method. However, it won't be written to until `CodeGenPasses` is 527 // destroyed. By defining `os` before `CodeGenPasses`, we make sure that the 528 // output stream won't be destroyed before it is written to. This only 529 // applies when an output file is used (i.e. there is no pre-defined output 530 // stream). 531 // TODO: Revisit once the new PM is ready (i.e. when `CodeGenPasses` is 532 // updated to use it). 533 std::unique_ptr<llvm::raw_pwrite_stream> os; 534 if (ci.IsOutputStreamNull()) { 535 // Get the output buffer/file 536 switch (action) { 537 case BackendActionTy::Backend_EmitAssembly: 538 os = ci.CreateDefaultOutputFile( 539 /*Binary=*/false, /*InFile=*/GetCurrentFileOrBufferName(), "s"); 540 break; 541 case BackendActionTy::Backend_EmitObj: 542 os = ci.CreateDefaultOutputFile( 543 /*Binary=*/true, /*InFile=*/GetCurrentFileOrBufferName(), "o"); 544 break; 545 } 546 if (!os) { 547 unsigned diagID = ci.diagnostics().getCustomDiagID( 548 clang::DiagnosticsEngine::Error, "failed to create the output file"); 549 ci.diagnostics().Report(diagID); 550 return; 551 } 552 } 553 554 // Create an LLVM code-gen pass pipeline. Currently only the legacy pass 555 // manager is supported. 556 // TODO: Switch to the new PM once it's available in the backend. 557 llvm::legacy::PassManager CodeGenPasses; 558 CodeGenPasses.add( 559 createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); 560 llvm::Triple triple(theTriple); 561 562 std::unique_ptr<llvm::TargetLibraryInfoImpl> TLII = 563 std::make_unique<llvm::TargetLibraryInfoImpl>(triple); 564 assert(TLII && "Failed to create TargetLibraryInfo"); 565 CodeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*TLII)); 566 567 llvm::CodeGenFileType cgft = (action == BackendActionTy::Backend_EmitAssembly) 568 ? llvm::CodeGenFileType::CGFT_AssemblyFile 569 : llvm::CodeGenFileType::CGFT_ObjectFile; 570 if (TM->addPassesToEmitFile(CodeGenPasses, 571 ci.IsOutputStreamNull() ? *os : ci.GetOutputStream(), nullptr, 572 cgft)) { 573 unsigned diagID = 574 ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, 575 "emission of this file type is not supported"); 576 ci.diagnostics().Report(diagID); 577 return; 578 } 579 580 // Run the code-gen passes 581 CodeGenPasses.run(*llvmModule); 582 } 583 584 void InitOnlyAction::ExecuteAction() { 585 CompilerInstance &ci = this->instance(); 586 unsigned DiagID = 587 ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning, 588 "Use `-init-only` for testing purposes only"); 589 ci.diagnostics().Report(DiagID); 590 } 591 592 void PluginParseTreeAction::ExecuteAction() {} 593 594 void DebugDumpPFTAction::ExecuteAction() { 595 CompilerInstance &ci = this->instance(); 596 597 if (auto ast = Fortran::lower::createPFT( 598 *ci.parsing().parseTree(), ci.semantics().context())) { 599 Fortran::lower::dumpPFT(llvm::outs(), *ast); 600 return; 601 } 602 603 unsigned DiagID = ci.diagnostics().getCustomDiagID( 604 clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL."); 605 ci.diagnostics().Report(DiagID); 606 } 607