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