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