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