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