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