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