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