xref: /llvm-project/flang/lib/Frontend/FrontendActions.cpp (revision 0195ec452e16a0ff4b4f4ff2e2ea5a1dd5a20563)
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/CompilerInvocation.h"
17 #include "flang/Frontend/FrontendOptions.h"
18 #include "flang/Frontend/PreprocessorOptions.h"
19 #include "flang/Lower/Bridge.h"
20 #include "flang/Lower/PFTBuilder.h"
21 #include "flang/Lower/Support/Verifier.h"
22 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
23 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
24 #include "flang/Optimizer/Passes/Pipelines.h"
25 #include "flang/Optimizer/Support/DataLayout.h"
26 #include "flang/Optimizer/Support/InitFIR.h"
27 #include "flang/Optimizer/Support/Utils.h"
28 #include "flang/Optimizer/Transforms/Passes.h"
29 #include "flang/Parser/dump-parse-tree.h"
30 #include "flang/Parser/parsing.h"
31 #include "flang/Parser/provenance.h"
32 #include "flang/Parser/source.h"
33 #include "flang/Parser/unparse.h"
34 #include "flang/Semantics/runtime-type-info.h"
35 #include "flang/Semantics/semantics.h"
36 #include "flang/Semantics/unparse-with-symbols.h"
37 #include "flang/Tools/CrossToolHelpers.h"
38 
39 #include "mlir/IR/Dialect.h"
40 #include "mlir/Parser/Parser.h"
41 #include "mlir/Pass/PassManager.h"
42 #include "mlir/Support/LLVM.h"
43 #include "mlir/Target/LLVMIR/Import.h"
44 #include "mlir/Target/LLVMIR/ModuleTranslation.h"
45 #include "clang/Basic/Diagnostic.h"
46 #include "clang/Basic/DiagnosticFrontend.h"
47 #include "clang/Basic/FileManager.h"
48 #include "clang/Basic/FileSystemOptions.h"
49 #include "clang/Driver/DriverDiagnostic.h"
50 #include "llvm/ADT/SmallString.h"
51 #include "llvm/ADT/StringRef.h"
52 #include "llvm/Analysis/TargetLibraryInfo.h"
53 #include "llvm/Analysis/TargetTransformInfo.h"
54 #include "llvm/Bitcode/BitcodeWriterPass.h"
55 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
56 #include "llvm/IR/LLVMRemarkStreamer.h"
57 #include "llvm/IR/LegacyPassManager.h"
58 #include "llvm/IR/Verifier.h"
59 #include "llvm/IRPrinter/IRPrintingPasses.h"
60 #include "llvm/IRReader/IRReader.h"
61 #include "llvm/Linker/Linker.h"
62 #include "llvm/Object/OffloadBinary.h"
63 #include "llvm/Passes/PassBuilder.h"
64 #include "llvm/Passes/PassPlugin.h"
65 #include "llvm/Passes/StandardInstrumentations.h"
66 #include "llvm/Support/AMDGPUAddrSpace.h"
67 #include "llvm/Support/Error.h"
68 #include "llvm/Support/ErrorHandling.h"
69 #include "llvm/Support/FileSystem.h"
70 #include "llvm/Support/Path.h"
71 #include "llvm/Support/SourceMgr.h"
72 #include "llvm/Support/ToolOutputFile.h"
73 #include "llvm/Target/TargetMachine.h"
74 #include "llvm/TargetParser/RISCVISAInfo.h"
75 #include "llvm/TargetParser/RISCVTargetParser.h"
76 #include "llvm/Transforms/IPO/Internalize.h"
77 #include "llvm/Transforms/Utils/ModuleUtils.h"
78 #include <memory>
79 #include <system_error>
80 
81 namespace llvm {
82 extern cl::opt<bool> PrintPipelinePasses;
83 } // namespace llvm
84 
85 using namespace Fortran::frontend;
86 
87 constexpr llvm::StringLiteral timingIdParse = "Parse";
88 constexpr llvm::StringLiteral timingIdMLIRGen = "MLIR generation";
89 constexpr llvm::StringLiteral timingIdMLIRPasses =
90     "MLIR translation/optimization";
91 constexpr llvm::StringLiteral timingIdLLVMIRGen = "LLVM IR generation";
92 constexpr llvm::StringLiteral timingIdLLVMIRPasses = "LLVM IR optimizations";
93 constexpr llvm::StringLiteral timingIdBackend =
94     "Assembly/Object code generation";
95 
96 // Declare plugin extension function declarations.
97 #define HANDLE_EXTENSION(Ext)                                                  \
98   llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
99 #include "llvm/Support/Extension.def"
100 
101 /// Save the given \c mlirModule to a temporary .mlir file, in a location
102 /// decided by the -save-temps flag. No files are produced if the flag is not
103 /// specified.
104 static bool saveMLIRTempFile(const CompilerInvocation &ci,
105                              mlir::ModuleOp mlirModule,
106                              llvm::StringRef inputFile,
107                              llvm::StringRef outputTag) {
108   if (!ci.getCodeGenOpts().SaveTempsDir.has_value())
109     return true;
110 
111   const llvm::StringRef compilerOutFile = ci.getFrontendOpts().outputFile;
112   const llvm::StringRef saveTempsDir = ci.getCodeGenOpts().SaveTempsDir.value();
113   auto dir = llvm::StringSwitch<llvm::StringRef>(saveTempsDir)
114                  .Case("cwd", "")
115                  .Case("obj", llvm::sys::path::parent_path(compilerOutFile))
116                  .Default(saveTempsDir);
117 
118   // Build path from the compiler output file name, triple, cpu and OpenMP
119   // information
120   llvm::SmallString<256> path(dir);
121   llvm::sys::path::append(path, llvm::sys::path::stem(inputFile) + "-" +
122                                     outputTag + ".mlir");
123 
124   std::error_code ec;
125   llvm::ToolOutputFile out(path, ec, llvm::sys::fs::OF_Text);
126   if (ec)
127     return false;
128 
129   mlirModule->print(out.os());
130   out.os().close();
131   out.keep();
132 
133   return true;
134 }
135 
136 //===----------------------------------------------------------------------===//
137 // Custom BeginSourceFileAction
138 //===----------------------------------------------------------------------===//
139 
140 bool PrescanAction::beginSourceFileAction() { return runPrescan(); }
141 
142 bool PrescanAndParseAction::beginSourceFileAction() {
143   return runPrescan() && runParse(/*emitMessages=*/true);
144 }
145 
146 bool PrescanAndSemaAction::beginSourceFileAction() {
147   return runPrescan() && runParse(/*emitMessages=*/false) &&
148          runSemanticChecks() && generateRtTypeTables();
149 }
150 
151 bool PrescanAndSemaDebugAction::beginSourceFileAction() {
152   // This is a "debug" action for development purposes. To facilitate this, the
153   // semantic checks are made to succeed unconditionally to prevent this action
154   // from exiting early (i.e. in the presence of semantic errors). We should
155   // never do this in actions intended for end-users or otherwise regular
156   // compiler workflows!
157   return runPrescan() && runParse(/*emitMessages=*/false) &&
158          (runSemanticChecks() || true) && (generateRtTypeTables() || true);
159 }
160 
161 static void addDependentLibs(mlir::ModuleOp mlirModule, CompilerInstance &ci) {
162   const std::vector<std::string> &libs =
163       ci.getInvocation().getCodeGenOpts().DependentLibs;
164   if (libs.empty()) {
165     return;
166   }
167   // dependent-lib is currently only supported on Windows, so the list should be
168   // empty on non-Windows platforms
169   assert(
170       llvm::Triple(ci.getInvocation().getTargetOpts().triple).isOSWindows() &&
171       "--dependent-lib is only supported on Windows");
172   // Add linker options specified by --dependent-lib
173   auto builder = mlir::OpBuilder(mlirModule.getRegion());
174   for (const std::string &lib : libs) {
175     builder.create<mlir::LLVM::LinkerOptionsOp>(
176         mlirModule.getLoc(), builder.getStrArrayAttr({"/DEFAULTLIB:" + lib}));
177   }
178 }
179 
180 // Add to MLIR code target specific items which are dependent on target
181 // configuration specified by the user.
182 // Clang equivalent function: AMDGPUTargetCodeGenInfo::emitTargetGlobals
183 static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp mlirModule,
184                                        CompilerInstance &ci) {
185   const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
186   const llvm::Triple triple(targetOpts.triple);
187   const llvm::StringRef codeObjectVersionGlobalOpName = "__oclc_ABI_version";
188 
189   if (!triple.isAMDGPU()) {
190     return;
191   }
192   const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts();
193   if (codeGenOpts.CodeObjectVersion == llvm::CodeObjectVersionKind::COV_None) {
194     return;
195   }
196 
197   mlir::IRRewriter builder(mlirModule.getContext());
198   unsigned oclcABIVERsion = codeGenOpts.CodeObjectVersion;
199   auto int32Type = builder.getI32Type();
200 
201   std::optional<mlir::LLVM::GlobalOp> originalGV;
202 
203   mlirModule.walk([&originalGV, codeObjectVersionGlobalOpName](
204                       mlir::LLVM::GlobalOp globalOp) {
205     if (globalOp.getName() == codeObjectVersionGlobalOpName)
206       originalGV = globalOp;
207   });
208   if (originalGV.has_value()) {
209     mlir::LLVM::GlobalOp originalGVOp = originalGV.value();
210     if (originalGVOp.getLinkage() != mlir::LLVM::Linkage::External) {
211       return;
212     }
213     // Update the variable if it is already present in MLIR but it was marked
214     // as external linkage variable
215     originalGVOp.setLinkage(mlir::LLVM::Linkage::WeakODR);
216     originalGVOp.setValueAttr(
217         builder.getIntegerAttr(int32Type, oclcABIVERsion));
218     originalGVOp.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local);
219     originalGVOp.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS);
220     originalGVOp.setVisibility_(mlir::LLVM::Visibility::Hidden);
221     return;
222   }
223 
224   mlir::LLVM::GlobalOp covInfo = builder.create<mlir::LLVM::GlobalOp>(
225       /* Location */ mlirModule.getLoc(), /* Type */ int32Type,
226       /* IsConstant */ true, /* Linkage */ mlir::LLVM::Linkage::WeakODR,
227       /* Name */ codeObjectVersionGlobalOpName,
228       /* Value */ builder.getIntegerAttr(int32Type, oclcABIVERsion));
229   covInfo.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local);
230   covInfo.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS);
231   covInfo.setVisibility_(mlir::LLVM::Visibility::Hidden);
232   builder.setInsertionPointToStart(mlirModule.getBody());
233   builder.insert(covInfo);
234 }
235 
236 bool CodeGenAction::beginSourceFileAction() {
237   llvmCtx = std::make_unique<llvm::LLVMContext>();
238   CompilerInstance &ci = this->getInstance();
239   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
240   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
241 
242   // This will provide timing information even when the input is an LLVM IR or
243   // MLIR file. That is fine because those do have to be parsed, so the label
244   // is still accurate.
245   mlir::TimingScope timingScopeParse = timingScopeRoot.nest(
246       mlir::TimingIdentifier::get(timingIdParse, timingMgr));
247 
248   // If the input is an LLVM file, just parse it and return.
249   if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) {
250     llvm::SMDiagnostic err;
251     llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx);
252     if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) {
253       err.print("flang", llvm::errs());
254       unsigned diagID = ci.getDiagnostics().getCustomDiagID(
255           clang::DiagnosticsEngine::Error, "Could not parse IR");
256       ci.getDiagnostics().Report(diagID);
257       return false;
258     }
259 
260     return true;
261   }
262 
263   // Load the MLIR dialects required by Flang
264   mlir::DialectRegistry registry;
265   mlirCtx = std::make_unique<mlir::MLIRContext>(registry);
266   fir::support::registerNonCodegenDialects(registry);
267   fir::support::loadNonCodegenDialects(*mlirCtx);
268   fir::support::loadDialects(*mlirCtx);
269   fir::support::registerLLVMTranslation(*mlirCtx);
270 
271   const llvm::TargetMachine &targetMachine = ci.getTargetMachine();
272 
273   // If the input is an MLIR file, just parse it and return.
274   if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) {
275     llvm::SourceMgr sourceMgr;
276     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
277         llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile());
278     sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
279     mlir::OwningOpRef<mlir::ModuleOp> module =
280         mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, mlirCtx.get());
281 
282     if (!module || mlir::failed(module->verifyInvariants())) {
283       unsigned diagID = ci.getDiagnostics().getCustomDiagID(
284           clang::DiagnosticsEngine::Error, "Could not parse FIR");
285       ci.getDiagnostics().Report(diagID);
286       return false;
287     }
288 
289     mlirModule = std::move(module);
290     const llvm::DataLayout &dl = targetMachine.createDataLayout();
291     fir::support::setMLIRDataLayout(*mlirModule, dl);
292     return true;
293   }
294 
295   // Otherwise, generate an MLIR module from the input Fortran source
296   if (getCurrentInput().getKind().getLanguage() != Language::Fortran) {
297     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
298         clang::DiagnosticsEngine::Error,
299         "Invalid input type - expecting a Fortran file");
300     ci.getDiagnostics().Report(diagID);
301     return false;
302   }
303   bool res = runPrescan() && runParse(/*emitMessages=*/false) &&
304              runSemanticChecks() && generateRtTypeTables();
305   if (!res)
306     return res;
307 
308   timingScopeParse.stop();
309   mlir::TimingScope timingScopeMLIRGen = timingScopeRoot.nest(
310       mlir::TimingIdentifier::get(timingIdMLIRGen, timingMgr));
311 
312   // Create a LoweringBridge
313   const common::IntrinsicTypeDefaultKinds &defKinds =
314       ci.getSemanticsContext().defaultKinds();
315   fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef<fir::KindTy>{
316                                               fir::fromDefaultKinds(defKinds)});
317   lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create(
318       *mlirCtx, ci.getSemanticsContext(), defKinds,
319       ci.getSemanticsContext().intrinsics(),
320       ci.getSemanticsContext().targetCharacteristics(),
321       ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
322       kindMap, ci.getInvocation().getLoweringOpts(),
323       ci.getInvocation().getFrontendOpts().envDefaults,
324       ci.getInvocation().getFrontendOpts().features, targetMachine,
325       ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts());
326 
327   if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
328           Fortran::common::LanguageFeature::OpenMP)) {
329     setOffloadModuleInterfaceAttributes(lb.getModule(),
330                                         ci.getInvocation().getLangOpts());
331     setOpenMPVersionAttribute(lb.getModule(),
332                               ci.getInvocation().getLangOpts().OpenMPVersion);
333   }
334 
335   // Create a parse tree and lower it to FIR
336   Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()};
337   lb.lower(parseTree, ci.getSemanticsContext());
338 
339   // Fetch module from lb, so we can set
340   mlirModule = lb.getModuleAndRelease();
341 
342   // Add target specific items like dependent libraries, target specific
343   // constants etc.
344   addDependentLibs(*mlirModule, ci);
345   addAMDGPUSpecificMLIRItems(*mlirModule, ci);
346   timingScopeMLIRGen.stop();
347 
348   // run the default passes.
349   mlir::PassManager pm((*mlirModule)->getName(),
350                        mlir::OpPassManager::Nesting::Implicit);
351   (void)mlir::applyPassManagerCLOptions(pm);
352   // Add OpenMP-related passes
353   // WARNING: These passes must be run immediately after the lowering to ensure
354   // that the FIR is correct with respect to OpenMP operations/attributes.
355   if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
356           Fortran::common::LanguageFeature::OpenMP)) {
357     bool isDevice = false;
358     if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>(
359             mlirModule->getOperation()))
360       isDevice = offloadMod.getIsTargetDevice();
361     // WARNING: This pipeline must be run immediately after the lowering to
362     // ensure that the FIR is correct with respect to OpenMP operations/
363     // attributes.
364     fir::createOpenMPFIRPassPipeline(pm, isDevice);
365   }
366 
367   pm.enableVerifier(/*verifyPasses=*/true);
368   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
369   pm.enableTiming(timingScopeMLIRGen);
370 
371   if (mlir::failed(pm.run(*mlirModule))) {
372     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
373         clang::DiagnosticsEngine::Error,
374         "verification of lowering to FIR failed");
375     ci.getDiagnostics().Report(diagID);
376     return false;
377   }
378   timingScopeMLIRGen.stop();
379 
380   // Print initial full MLIR module, before lowering or transformations, if
381   // -save-temps has been specified.
382   if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(),
383                         "fir")) {
384     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
385         clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed");
386     ci.getDiagnostics().Report(diagID);
387     return false;
388   }
389 
390   return true;
391 }
392 
393 //===----------------------------------------------------------------------===//
394 // Custom ExecuteAction
395 //===----------------------------------------------------------------------===//
396 void InputOutputTestAction::executeAction() {
397   CompilerInstance &ci = getInstance();
398 
399   // Create a stream for errors
400   std::string buf;
401   llvm::raw_string_ostream errorStream{buf};
402 
403   // Read the input file
404   Fortran::parser::AllSources &allSources{ci.getAllSources()};
405   std::string path{getCurrentFileOrBufferName()};
406   const Fortran::parser::SourceFile *sf;
407   if (path == "-")
408     sf = allSources.ReadStandardInput(errorStream);
409   else
410     sf = allSources.Open(path, errorStream, std::optional<std::string>{"."s});
411   llvm::ArrayRef<char> fileContent = sf->content();
412 
413   // Output file descriptor to receive the contents of the input file.
414   std::unique_ptr<llvm::raw_ostream> os;
415 
416   // Copy the contents from the input file to the output file
417   if (!ci.isOutputStreamNull()) {
418     // An output stream (outputStream_) was set earlier
419     ci.writeOutputStream(fileContent.data());
420   } else {
421     // No pre-set output stream - create an output file
422     os = ci.createDefaultOutputFile(
423         /*binary=*/true, getCurrentFileOrBufferName(), "txt");
424     if (!os)
425       return;
426     (*os) << fileContent.data();
427   }
428 }
429 
430 void PrintPreprocessedAction::executeAction() {
431   std::string buf;
432   llvm::raw_string_ostream outForPP{buf};
433 
434   // Format or dump the prescanner's output
435   CompilerInstance &ci = this->getInstance();
436   if (ci.getInvocation().getPreprocessorOpts().showMacros) {
437     ci.getParsing().EmitPreprocessorMacros(outForPP);
438   } else if (ci.getInvocation().getPreprocessorOpts().noReformat) {
439     ci.getParsing().DumpCookedChars(outForPP);
440   } else {
441     ci.getParsing().EmitPreprocessedSource(
442         outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives);
443   }
444 
445   // Print getDiagnostics from the prescanner
446   ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
447 
448   // If a pre-defined output stream exists, dump the preprocessed content there
449   if (!ci.isOutputStreamNull()) {
450     // Send the output to the pre-defined output buffer.
451     ci.writeOutputStream(buf);
452     return;
453   }
454 
455   // Create a file and save the preprocessed output there
456   std::unique_ptr<llvm::raw_pwrite_stream> os{ci.createDefaultOutputFile(
457       /*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())};
458   if (!os) {
459     return;
460   }
461 
462   (*os) << buf;
463 }
464 
465 void DebugDumpProvenanceAction::executeAction() {
466   this->getInstance().getParsing().DumpProvenance(llvm::outs());
467 }
468 
469 void ParseSyntaxOnlyAction::executeAction() {}
470 
471 void DebugUnparseNoSemaAction::executeAction() {
472   auto &invoc = this->getInstance().getInvocation();
473   auto &parseTree{getInstance().getParsing().parseTree()};
474 
475   // TODO: Options should come from CompilerInvocation
476   Unparse(llvm::outs(), *parseTree,
477           /*encoding=*/Fortran::parser::Encoding::UTF_8,
478           /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
479           /*preStatement=*/nullptr,
480           invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()
481                                                   : nullptr);
482 }
483 
484 void DebugUnparseAction::executeAction() {
485   auto &invoc = this->getInstance().getInvocation();
486   auto &parseTree{getInstance().getParsing().parseTree()};
487 
488   CompilerInstance &ci = this->getInstance();
489   auto os{ci.createDefaultOutputFile(
490       /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())};
491 
492   // TODO: Options should come from CompilerInvocation
493   Unparse(*os, *parseTree,
494           /*encoding=*/Fortran::parser::Encoding::UTF_8,
495           /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
496           /*preStatement=*/nullptr,
497           invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()
498                                                   : nullptr);
499 
500   // Report fatal semantic errors
501   reportFatalSemanticErrors();
502 }
503 
504 void DebugUnparseWithSymbolsAction::executeAction() {
505   auto &parseTree{*getInstance().getParsing().parseTree()};
506 
507   Fortran::semantics::UnparseWithSymbols(
508       llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8);
509 
510   // Report fatal semantic errors
511   reportFatalSemanticErrors();
512 }
513 
514 void DebugUnparseWithModulesAction::executeAction() {
515   auto &parseTree{*getInstance().getParsing().parseTree()};
516   CompilerInstance &ci{getInstance()};
517   Fortran::semantics::UnparseWithModules(
518       llvm::outs(), ci.getSemantics().context(), parseTree,
519       /*encoding=*/Fortran::parser::Encoding::UTF_8);
520   reportFatalSemanticErrors();
521 }
522 
523 void DebugDumpSymbolsAction::executeAction() {
524   CompilerInstance &ci = this->getInstance();
525 
526   if (!ci.getRtTyTables().schemata) {
527     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
528         clang::DiagnosticsEngine::Error,
529         "could not find module file for __fortran_type_info");
530     ci.getDiagnostics().Report(diagID);
531     llvm::errs() << "\n";
532     return;
533   }
534 
535   // Dump symbols
536   ci.getSemantics().DumpSymbols(llvm::outs());
537 }
538 
539 void DebugDumpAllAction::executeAction() {
540   CompilerInstance &ci = this->getInstance();
541 
542   // Dump parse tree
543   auto &parseTree{getInstance().getParsing().parseTree()};
544   llvm::outs() << "========================";
545   llvm::outs() << " Flang: parse tree dump ";
546   llvm::outs() << "========================\n";
547   Fortran::parser::DumpTree(llvm::outs(), parseTree,
548                             &ci.getInvocation().getAsFortran());
549 
550   if (!ci.getRtTyTables().schemata) {
551     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
552         clang::DiagnosticsEngine::Error,
553         "could not find module file for __fortran_type_info");
554     ci.getDiagnostics().Report(diagID);
555     llvm::errs() << "\n";
556     return;
557   }
558 
559   // Dump symbols
560   llvm::outs() << "=====================";
561   llvm::outs() << " Flang: symbols dump ";
562   llvm::outs() << "=====================\n";
563   ci.getSemantics().DumpSymbols(llvm::outs());
564 }
565 
566 void DebugDumpParseTreeNoSemaAction::executeAction() {
567   auto &parseTree{getInstance().getParsing().parseTree()};
568 
569   // Dump parse tree
570   Fortran::parser::DumpTree(
571       llvm::outs(), parseTree,
572       &this->getInstance().getInvocation().getAsFortran());
573 }
574 
575 void DebugDumpParseTreeAction::executeAction() {
576   auto &parseTree{getInstance().getParsing().parseTree()};
577 
578   // Dump parse tree
579   Fortran::parser::DumpTree(
580       llvm::outs(), parseTree,
581       &this->getInstance().getInvocation().getAsFortran());
582 
583   // Report fatal semantic errors
584   reportFatalSemanticErrors();
585 }
586 
587 void DebugMeasureParseTreeAction::executeAction() {
588   CompilerInstance &ci = this->getInstance();
589 
590   // Parse. In case of failure, report and return.
591   ci.getParsing().Parse(llvm::outs());
592 
593   if ((ci.getParsing().parseTree().has_value() &&
594        !ci.getParsing().consumedWholeFile()) ||
595       (!ci.getParsing().messages().empty() &&
596        (ci.getInvocation().getWarnAsErr() ||
597         ci.getParsing().messages().AnyFatalError()))) {
598     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
599         clang::DiagnosticsEngine::Error, "Could not parse %0");
600     ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
601 
602     ci.getParsing().messages().Emit(llvm::errs(),
603                                     this->getInstance().getAllCookedSources());
604     return;
605   }
606 
607   // Report the getDiagnostics from parsing
608   ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
609 
610   auto &parseTree{*ci.getParsing().parseTree()};
611 
612   // Measure the parse tree
613   MeasurementVisitor visitor;
614   Fortran::parser::Walk(parseTree, visitor);
615   llvm::outs() << "Parse tree comprises " << visitor.objects
616                << " objects and occupies " << visitor.bytes
617                << " total bytes.\n";
618 }
619 
620 void DebugPreFIRTreeAction::executeAction() {
621   CompilerInstance &ci = this->getInstance();
622   // Report and exit if fatal semantic errors are present
623   if (reportFatalSemanticErrors()) {
624     return;
625   }
626 
627   auto &parseTree{*ci.getParsing().parseTree()};
628 
629   // Dump pre-FIR tree
630   if (auto ast{
631           Fortran::lower::createPFT(parseTree, ci.getSemanticsContext())}) {
632     Fortran::lower::dumpPFT(llvm::outs(), *ast);
633   } else {
634     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
635         clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
636     ci.getDiagnostics().Report(diagID);
637   }
638 }
639 
640 void DebugDumpParsingLogAction::executeAction() {
641   CompilerInstance &ci = this->getInstance();
642 
643   ci.getParsing().Parse(llvm::errs());
644   ci.getParsing().DumpParsingLog(llvm::outs());
645 }
646 
647 void GetDefinitionAction::executeAction() {
648   CompilerInstance &ci = this->getInstance();
649 
650   // Report and exit if fatal semantic errors are present
651   if (reportFatalSemanticErrors()) {
652     return;
653   }
654 
655   parser::AllCookedSources &cs = ci.getAllCookedSources();
656   unsigned diagID = ci.getDiagnostics().getCustomDiagID(
657       clang::DiagnosticsEngine::Error, "Symbol not found");
658 
659   auto gdv = ci.getInvocation().getFrontendOpts().getDefVals;
660   auto charBlock{cs.GetCharBlockFromLineAndColumns(gdv.line, gdv.startColumn,
661                                                    gdv.endColumn)};
662   if (!charBlock) {
663     ci.getDiagnostics().Report(diagID);
664     return;
665   }
666 
667   llvm::outs() << "String range: >" << charBlock->ToString() << "<\n";
668 
669   auto *symbol{
670       ci.getSemanticsContext().FindScope(*charBlock).FindSymbol(*charBlock)};
671   if (!symbol) {
672     ci.getDiagnostics().Report(diagID);
673     return;
674   }
675 
676   llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
677 
678   auto sourceInfo{cs.GetSourcePositionRange(symbol->name())};
679   if (!sourceInfo) {
680     llvm_unreachable(
681         "Failed to obtain SourcePosition."
682         "TODO: Please, write a test and replace this with a diagnostic!");
683     return;
684   }
685 
686   llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
687   llvm::outs() << symbol->name().ToString() << ": " << sourceInfo->first.path
688                << ", " << sourceInfo->first.line << ", "
689                << sourceInfo->first.column << "-" << sourceInfo->second.column
690                << "\n";
691 }
692 
693 void GetSymbolsSourcesAction::executeAction() {
694   CompilerInstance &ci = this->getInstance();
695 
696   // Report and exit if fatal semantic errors are present
697   if (reportFatalSemanticErrors()) {
698     return;
699   }
700 
701   ci.getSemantics().DumpSymbolsSources(llvm::outs());
702 }
703 
704 //===----------------------------------------------------------------------===//
705 // CodeGenActions
706 //===----------------------------------------------------------------------===//
707 
708 CodeGenAction::~CodeGenAction() = default;
709 
710 static llvm::OptimizationLevel
711 mapToLevel(const Fortran::frontend::CodeGenOptions &opts) {
712   switch (opts.OptimizationLevel) {
713   default:
714     llvm_unreachable("Invalid optimization level!");
715   case 0:
716     return llvm::OptimizationLevel::O0;
717   case 1:
718     return llvm::OptimizationLevel::O1;
719   case 2:
720     return llvm::OptimizationLevel::O2;
721   case 3:
722     return llvm::OptimizationLevel::O3;
723   }
724 }
725 
726 // Lower using HLFIR then run the FIR to HLFIR pipeline
727 void CodeGenAction::lowerHLFIRToFIR() {
728   assert(mlirModule && "The MLIR module has not been generated yet.");
729 
730   CompilerInstance &ci = this->getInstance();
731   const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
732   llvm::OptimizationLevel level = mapToLevel(opts);
733   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
734   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
735 
736   fir::support::loadDialects(*mlirCtx);
737 
738   // Set-up the MLIR pass manager
739   mlir::PassManager pm((*mlirModule)->getName(),
740                        mlir::OpPassManager::Nesting::Implicit);
741 
742   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
743   pm.enableVerifier(/*verifyPasses=*/true);
744 
745   // Create the pass pipeline
746   fir::createHLFIRToFIRPassPipeline(
747       pm,
748       ci.getInvocation().getFrontendOpts().features.IsEnabled(
749           Fortran::common::LanguageFeature::OpenMP),
750       level);
751   (void)mlir::applyPassManagerCLOptions(pm);
752 
753   mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
754       mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
755   pm.enableTiming(timingScopeMLIRPasses);
756   if (!mlir::succeeded(pm.run(*mlirModule))) {
757     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
758         clang::DiagnosticsEngine::Error, "Lowering to FIR failed");
759     ci.getDiagnostics().Report(diagID);
760   }
761 }
762 
763 static std::optional<std::pair<unsigned, unsigned>>
764 getAArch64VScaleRange(CompilerInstance &ci) {
765   const auto &langOpts = ci.getInvocation().getLangOpts();
766 
767   if (langOpts.VScaleMin || langOpts.VScaleMax)
768     return std::pair<unsigned, unsigned>(
769         langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax);
770 
771   std::string featuresStr = ci.getTargetFeatures();
772   if (featuresStr.find("+sve") != std::string::npos)
773     return std::pair<unsigned, unsigned>(1, 16);
774 
775   return std::nullopt;
776 }
777 
778 static std::optional<std::pair<unsigned, unsigned>>
779 getRISCVVScaleRange(CompilerInstance &ci) {
780   const auto &langOpts = ci.getInvocation().getLangOpts();
781   const auto targetOpts = ci.getInvocation().getTargetOpts();
782   const llvm::Triple triple(targetOpts.triple);
783 
784   auto parseResult = llvm::RISCVISAInfo::parseFeatures(
785       triple.isRISCV64() ? 64 : 32, targetOpts.featuresAsWritten);
786   if (!parseResult) {
787     std::string buffer;
788     llvm::raw_string_ostream outputErrMsg(buffer);
789     handleAllErrors(parseResult.takeError(), [&](llvm::StringError &errMsg) {
790       outputErrMsg << errMsg.getMessage();
791     });
792     ci.getDiagnostics().Report(clang::diag::err_invalid_feature_combination)
793         << buffer;
794     return std::nullopt;
795   }
796 
797   llvm::RISCVISAInfo *const isaInfo = parseResult->get();
798 
799   // RISCV::RVVBitsPerBlock is 64.
800   unsigned vscaleMin = isaInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
801 
802   if (langOpts.VScaleMin || langOpts.VScaleMax) {
803     // Treat Zvl*b as a lower bound on vscale.
804     vscaleMin = std::max(vscaleMin, langOpts.VScaleMin);
805     unsigned vscaleMax = langOpts.VScaleMax;
806     if (vscaleMax != 0 && vscaleMax < vscaleMin)
807       vscaleMax = vscaleMin;
808     return std::pair<unsigned, unsigned>(vscaleMin ? vscaleMin : 1, vscaleMax);
809   }
810 
811   if (vscaleMin > 0) {
812     unsigned vscaleMax = isaInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
813     return std::make_pair(vscaleMin, vscaleMax);
814   }
815 
816   return std::nullopt;
817 }
818 
819 // TODO: We should get this from TargetInfo. However, that depends on
820 // too much of clang, so for now, replicate the functionality.
821 static std::optional<std::pair<unsigned, unsigned>>
822 getVScaleRange(CompilerInstance &ci) {
823   const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple);
824 
825   if (triple.isAArch64())
826     return getAArch64VScaleRange(ci);
827   if (triple.isRISCV())
828     return getRISCVVScaleRange(ci);
829 
830   // All other architectures that don't support scalable vectors (i.e. don't
831   // need vscale)
832   return std::nullopt;
833 }
834 
835 // Lower the previously generated MLIR module into an LLVM IR module
836 void CodeGenAction::generateLLVMIR() {
837   assert(mlirModule && "The MLIR module has not been generated yet.");
838 
839   CompilerInstance &ci = this->getInstance();
840   CompilerInvocation &invoc = ci.getInvocation();
841   const CodeGenOptions &opts = invoc.getCodeGenOpts();
842   const auto &mathOpts = invoc.getLoweringOpts().getMathOptions();
843   llvm::OptimizationLevel level = mapToLevel(opts);
844   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
845   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
846 
847   fir::support::loadDialects(*mlirCtx);
848   mlir::DialectRegistry registry;
849   fir::support::registerNonCodegenDialects(registry);
850   fir::support::addFIRExtensions(registry);
851   mlirCtx->appendDialectRegistry(registry);
852   fir::support::registerLLVMTranslation(*mlirCtx);
853 
854   // Set-up the MLIR pass manager
855   mlir::PassManager pm((*mlirModule)->getName(),
856                        mlir::OpPassManager::Nesting::Implicit);
857 
858   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
859   pm.enableVerifier(/*verifyPasses=*/true);
860 
861   MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts);
862   fir::registerDefaultInlinerPass(config);
863 
864   if (auto vsr = getVScaleRange(ci)) {
865     config.VScaleMin = vsr->first;
866     config.VScaleMax = vsr->second;
867   }
868 
869   if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
870           Fortran::common::LanguageFeature::OpenMP))
871     config.EnableOpenMP = true;
872 
873   if (ci.getInvocation().getLoweringOpts().getIntegerWrapAround())
874     config.NSWOnLoopVarInc = false;
875 
876   // Create the pass pipeline
877   fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile());
878   (void)mlir::applyPassManagerCLOptions(pm);
879 
880   // run the pass manager
881   mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
882       mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
883   pm.enableTiming(timingScopeMLIRPasses);
884   if (!mlir::succeeded(pm.run(*mlirModule))) {
885     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
886         clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed");
887     ci.getDiagnostics().Report(diagID);
888   }
889   timingScopeMLIRPasses.stop();
890 
891   // Print final MLIR module, just before translation into LLVM IR, if
892   // -save-temps has been specified.
893   if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(),
894                         "llvmir")) {
895     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
896         clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed");
897     ci.getDiagnostics().Report(diagID);
898     return;
899   }
900 
901   // Translate to LLVM IR
902   mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest(
903       mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr));
904   std::optional<llvm::StringRef> moduleName = mlirModule->getName();
905   llvmModule = mlir::translateModuleToLLVMIR(
906       *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule");
907 
908   if (!llvmModule) {
909     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
910         clang::DiagnosticsEngine::Error, "failed to create the LLVM module");
911     ci.getDiagnostics().Report(diagID);
912     return;
913   }
914 
915   // Set PIC/PIE level LLVM module flags.
916   if (opts.PICLevel > 0) {
917     llvmModule->setPICLevel(static_cast<llvm::PICLevel::Level>(opts.PICLevel));
918     if (opts.IsPIE)
919       llvmModule->setPIELevel(
920           static_cast<llvm::PIELevel::Level>(opts.PICLevel));
921   }
922 
923   // Set mcmodel level LLVM module flags
924   std::optional<llvm::CodeModel::Model> cm = getCodeModel(opts.CodeModel);
925   if (cm.has_value()) {
926     const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple);
927     llvmModule->setCodeModel(*cm);
928     if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) &&
929         triple.getArch() == llvm::Triple::x86_64) {
930       llvmModule->setLargeDataThreshold(opts.LargeDataThreshold);
931     }
932   }
933 }
934 
935 static std::unique_ptr<llvm::raw_pwrite_stream>
936 getOutputStream(CompilerInstance &ci, llvm::StringRef inFile,
937                 BackendActionTy action) {
938   switch (action) {
939   case BackendActionTy::Backend_EmitAssembly:
940     return ci.createDefaultOutputFile(
941         /*Binary=*/false, inFile, /*extension=*/"s");
942   case BackendActionTy::Backend_EmitLL:
943     return ci.createDefaultOutputFile(
944         /*Binary=*/false, inFile, /*extension=*/"ll");
945   case BackendActionTy::Backend_EmitFIR:
946   case BackendActionTy::Backend_EmitHLFIR:
947     return ci.createDefaultOutputFile(
948         /*Binary=*/false, inFile, /*extension=*/"mlir");
949   case BackendActionTy::Backend_EmitBC:
950     return ci.createDefaultOutputFile(
951         /*Binary=*/true, inFile, /*extension=*/"bc");
952   case BackendActionTy::Backend_EmitObj:
953     return ci.createDefaultOutputFile(
954         /*Binary=*/true, inFile, /*extension=*/"o");
955   }
956 
957   llvm_unreachable("Invalid action!");
958 }
959 
960 /// Generate target-specific machine-code or assembly file from the input LLVM
961 /// module.
962 ///
963 /// \param [in] diags Diagnostics engine for reporting errors
964 /// \param [in] tm Target machine to aid the code-gen pipeline set-up
965 /// \param [in] act Backend act to run (assembly vs machine-code generation)
966 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code
967 /// \param [in] codeGenOpts options configuring codegen pipeline
968 /// \param [out] os Output stream to emit the generated code to
969 static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
970                                               llvm::TargetMachine &tm,
971                                               BackendActionTy act,
972                                               llvm::Module &llvmModule,
973                                               const CodeGenOptions &codeGenOpts,
974                                               llvm::raw_pwrite_stream &os) {
975   assert(((act == BackendActionTy::Backend_EmitObj) ||
976           (act == BackendActionTy::Backend_EmitAssembly)) &&
977          "Unsupported action");
978 
979   // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline.
980   // Currently only the legacy pass manager is supported.
981   // TODO: Switch to the new PM once it's available in the backend.
982   llvm::legacy::PassManager codeGenPasses;
983   codeGenPasses.add(
984       createTargetTransformInfoWrapperPass(tm.getTargetIRAnalysis()));
985 
986   llvm::Triple triple(llvmModule.getTargetTriple());
987   llvm::TargetLibraryInfoImpl *tlii =
988       llvm::driver::createTLII(triple, codeGenOpts.getVecLib());
989   codeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*tlii));
990 
991   llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly)
992                                    ? llvm::CodeGenFileType::AssemblyFile
993                                    : llvm::CodeGenFileType::ObjectFile;
994   if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) {
995     unsigned diagID =
996         diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
997                               "emission of this file type is not supported");
998     diags.Report(diagID);
999     return;
1000   }
1001 
1002   // Run the passes
1003   codeGenPasses.run(llvmModule);
1004 
1005   // Cleanup
1006   delete tlii;
1007 }
1008 
1009 void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
1010   CompilerInstance &ci = getInstance();
1011   const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
1012   clang::DiagnosticsEngine &diags = ci.getDiagnostics();
1013   llvm::OptimizationLevel level = mapToLevel(opts);
1014 
1015   llvm::TargetMachine *targetMachine = &ci.getTargetMachine();
1016   // Create the analysis managers.
1017   llvm::LoopAnalysisManager lam;
1018   llvm::FunctionAnalysisManager fam;
1019   llvm::CGSCCAnalysisManager cgam;
1020   llvm::ModuleAnalysisManager mam;
1021 
1022   // Create the pass manager builder.
1023   llvm::PassInstrumentationCallbacks pic;
1024   llvm::PipelineTuningOptions pto;
1025   std::optional<llvm::PGOOptions> pgoOpt;
1026   llvm::StandardInstrumentations si(llvmModule->getContext(),
1027                                     opts.DebugPassManager);
1028   si.registerCallbacks(pic, &mam);
1029   if (ci.isTimingEnabled())
1030     si.getTimePasses().setOutStream(ci.getTimingStreamLLVM());
1031   pto.LoopUnrolling = opts.UnrollLoops;
1032   pto.LoopInterleaving = opts.UnrollLoops;
1033   llvm::PassBuilder pb(targetMachine, pto, pgoOpt, &pic);
1034 
1035   // Attempt to load pass plugins and register their callbacks with PB.
1036   for (auto &pluginFile : opts.LLVMPassPlugins) {
1037     auto passPlugin = llvm::PassPlugin::Load(pluginFile);
1038     if (passPlugin) {
1039       passPlugin->registerPassBuilderCallbacks(pb);
1040     } else {
1041       diags.Report(clang::diag::err_fe_unable_to_load_plugin)
1042           << pluginFile << passPlugin.takeError();
1043     }
1044   }
1045   // Register static plugin extensions.
1046 #define HANDLE_EXTENSION(Ext)                                                  \
1047   get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
1048 #include "llvm/Support/Extension.def"
1049 
1050   // Register the target library analysis directly and give it a customized
1051   // preset TLI depending on -fveclib
1052   llvm::Triple triple(llvmModule->getTargetTriple());
1053   llvm::TargetLibraryInfoImpl *tlii =
1054       llvm::driver::createTLII(triple, opts.getVecLib());
1055   fam.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii); });
1056 
1057   // Register all the basic analyses with the managers.
1058   pb.registerModuleAnalyses(mam);
1059   pb.registerCGSCCAnalyses(cgam);
1060   pb.registerFunctionAnalyses(fam);
1061   pb.registerLoopAnalyses(lam);
1062   pb.crossRegisterProxies(lam, fam, cgam, mam);
1063 
1064   // Create the pass manager.
1065   llvm::ModulePassManager mpm;
1066   if (opts.PrepareForFullLTO)
1067     mpm = pb.buildLTOPreLinkDefaultPipeline(level);
1068   else if (opts.PrepareForThinLTO)
1069     mpm = pb.buildThinLTOPreLinkDefaultPipeline(level);
1070   else
1071     mpm = pb.buildPerModuleDefaultPipeline(level);
1072 
1073   if (action == BackendActionTy::Backend_EmitBC)
1074     mpm.addPass(llvm::BitcodeWriterPass(os));
1075   else if (action == BackendActionTy::Backend_EmitLL)
1076     mpm.addPass(llvm::PrintModulePass(os));
1077 
1078   // FIXME: This should eventually be replaced by a first-class driver option.
1079   // This should be done for both flang and clang simultaneously.
1080   // Print a textual, '-passes=' compatible, representation of pipeline if
1081   // requested. In this case, don't run the passes. This mimics the behavior of
1082   // clang.
1083   if (llvm::PrintPipelinePasses) {
1084     mpm.printPipeline(llvm::outs(), [&pic](llvm::StringRef className) {
1085       auto passName = pic.getPassNameForClassName(className);
1086       return passName.empty() ? className : passName;
1087     });
1088     llvm::outs() << "\n";
1089     return;
1090   }
1091 
1092   // Run the passes.
1093   mpm.run(*llvmModule, mam);
1094 
1095   // Print the timers to the associated output stream and reset them.
1096   if (ci.isTimingEnabled())
1097     si.getTimePasses().print();
1098 
1099   // Cleanup
1100   delete tlii;
1101 }
1102 
1103 // This class handles optimization remark messages requested if
1104 // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided
1105 class BackendRemarkConsumer : public llvm::DiagnosticHandler {
1106 
1107   const CodeGenOptions &codeGenOpts;
1108   clang::DiagnosticsEngine &diags;
1109 
1110 public:
1111   BackendRemarkConsumer(clang::DiagnosticsEngine &diags,
1112                         const CodeGenOptions &codeGenOpts)
1113       : codeGenOpts(codeGenOpts), diags(diags) {}
1114 
1115   bool isAnalysisRemarkEnabled(llvm::StringRef passName) const override {
1116     return codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName);
1117   }
1118   bool isMissedOptRemarkEnabled(llvm::StringRef passName) const override {
1119     return codeGenOpts.OptimizationRemarkMissed.patternMatches(passName);
1120   }
1121   bool isPassedOptRemarkEnabled(llvm::StringRef passName) const override {
1122     return codeGenOpts.OptimizationRemark.patternMatches(passName);
1123   }
1124 
1125   bool isAnyRemarkEnabled() const override {
1126     return codeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() ||
1127            codeGenOpts.OptimizationRemarkMissed.hasValidPattern() ||
1128            codeGenOpts.OptimizationRemark.hasValidPattern();
1129   }
1130 
1131   void
1132   emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &diagInfo,
1133                           unsigned diagID) {
1134     // We only support warnings and remarks.
1135     assert(diagInfo.getSeverity() == llvm::DS_Remark ||
1136            diagInfo.getSeverity() == llvm::DS_Warning);
1137 
1138     std::string msg;
1139     llvm::raw_string_ostream msgStream(msg);
1140 
1141     if (diagInfo.isLocationAvailable()) {
1142       // Clang contains a SourceManager class which handles loading
1143       // and caching of source files into memory and it can be used to
1144       // query SourceLocation data. The SourceLocation data is what is
1145       // needed here as it contains the full include stack which gives
1146       // line and column number as well as file name and location.
1147       // Since Flang doesn't have SourceManager, send file name and absolute
1148       // path through msgStream, to use for printing.
1149       msgStream << diagInfo.getLocationStr() << ";;"
1150                 << diagInfo.getAbsolutePath() << ";;";
1151     }
1152 
1153     msgStream << diagInfo.getMsg();
1154 
1155     // Emit message.
1156     diags.Report(diagID) << clang::AddFlagValue(diagInfo.getPassName()) << msg;
1157   }
1158 
1159   void optimizationRemarkHandler(
1160       const llvm::DiagnosticInfoOptimizationBase &diagInfo) {
1161     auto passName = diagInfo.getPassName();
1162     if (diagInfo.isPassed()) {
1163       if (codeGenOpts.OptimizationRemark.patternMatches(passName))
1164         // Optimization remarks are active only if the -Rpass flag has a regular
1165         // expression that matches the name of the pass name in \p d.
1166         emitOptimizationMessage(
1167             diagInfo, clang::diag::remark_fe_backend_optimization_remark);
1168 
1169       return;
1170     }
1171 
1172     if (diagInfo.isMissed()) {
1173       if (codeGenOpts.OptimizationRemarkMissed.patternMatches(passName))
1174         // Missed optimization remarks are active only if the -Rpass-missed
1175         // flag has a regular expression that matches the name of the pass
1176         // name in \p d.
1177         emitOptimizationMessage(
1178             diagInfo,
1179             clang::diag::remark_fe_backend_optimization_remark_missed);
1180 
1181       return;
1182     }
1183 
1184     assert(diagInfo.isAnalysis() && "Unknown remark type");
1185 
1186     bool shouldAlwaysPrint = false;
1187     auto *ora = llvm::dyn_cast<llvm::OptimizationRemarkAnalysis>(&diagInfo);
1188     if (ora)
1189       shouldAlwaysPrint = ora->shouldAlwaysPrint();
1190 
1191     if (shouldAlwaysPrint ||
1192         codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName))
1193       emitOptimizationMessage(
1194           diagInfo,
1195           clang::diag::remark_fe_backend_optimization_remark_analysis);
1196   }
1197 
1198   bool handleDiagnostics(const llvm::DiagnosticInfo &di) override {
1199     switch (di.getKind()) {
1200     case llvm::DK_OptimizationRemark:
1201       optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemark>(di));
1202       break;
1203     case llvm::DK_OptimizationRemarkMissed:
1204       optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemarkMissed>(di));
1205       break;
1206     case llvm::DK_OptimizationRemarkAnalysis:
1207       optimizationRemarkHandler(
1208           llvm::cast<llvm::OptimizationRemarkAnalysis>(di));
1209       break;
1210     case llvm::DK_MachineOptimizationRemark:
1211       optimizationRemarkHandler(
1212           llvm::cast<llvm::MachineOptimizationRemark>(di));
1213       break;
1214     case llvm::DK_MachineOptimizationRemarkMissed:
1215       optimizationRemarkHandler(
1216           llvm::cast<llvm::MachineOptimizationRemarkMissed>(di));
1217       break;
1218     case llvm::DK_MachineOptimizationRemarkAnalysis:
1219       optimizationRemarkHandler(
1220           llvm::cast<llvm::MachineOptimizationRemarkAnalysis>(di));
1221       break;
1222     default:
1223       break;
1224     }
1225     return true;
1226   }
1227 };
1228 
1229 void CodeGenAction::embedOffloadObjects() {
1230   CompilerInstance &ci = this->getInstance();
1231   const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
1232 
1233   for (llvm::StringRef offloadObject : cgOpts.OffloadObjects) {
1234     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> objectOrErr =
1235         llvm::MemoryBuffer::getFileOrSTDIN(offloadObject);
1236     if (std::error_code ec = objectOrErr.getError()) {
1237       auto diagID = ci.getDiagnostics().getCustomDiagID(
1238           clang::DiagnosticsEngine::Error, "could not open '%0' for embedding");
1239       ci.getDiagnostics().Report(diagID) << offloadObject;
1240       return;
1241     }
1242     llvm::embedBufferInModule(
1243         *llvmModule, **objectOrErr, ".llvm.offloading",
1244         llvm::Align(llvm::object::OffloadBinary::getAlignment()));
1245   }
1246 }
1247 
1248 void CodeGenAction::linkBuiltinBCLibs() {
1249   auto options = clang::FileSystemOptions();
1250   clang::FileManager fileManager(options);
1251   CompilerInstance &ci = this->getInstance();
1252   const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
1253 
1254   std::vector<std::unique_ptr<llvm::Module>> modules;
1255 
1256   // Load LLVM modules
1257   for (llvm::StringRef bcLib : cgOpts.BuiltinBCLibs) {
1258     auto BCBuf = fileManager.getBufferForFile(bcLib);
1259     if (!BCBuf) {
1260       auto diagID = ci.getDiagnostics().getCustomDiagID(
1261           clang::DiagnosticsEngine::Error, "could not open '%0' for linking");
1262       ci.getDiagnostics().Report(diagID) << bcLib;
1263       return;
1264     }
1265 
1266     llvm::Expected<std::unique_ptr<llvm::Module>> ModuleOrErr =
1267         getOwningLazyBitcodeModule(std::move(*BCBuf), *llvmCtx);
1268     if (!ModuleOrErr) {
1269       auto diagID = ci.getDiagnostics().getCustomDiagID(
1270           clang::DiagnosticsEngine::Error, "error loading '%0' for linking");
1271       ci.getDiagnostics().Report(diagID) << bcLib;
1272       return;
1273     }
1274     modules.push_back(std::move(ModuleOrErr.get()));
1275   }
1276 
1277   // Link modules and internalize functions
1278   for (auto &module : modules) {
1279     bool Err;
1280     Err = llvm::Linker::linkModules(
1281         *llvmModule, std::move(module), llvm::Linker::Flags::LinkOnlyNeeded,
1282         [](llvm::Module &M, const llvm::StringSet<> &GVS) {
1283           llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
1284             return !GV.hasName() || (GVS.count(GV.getName()) == 0);
1285           });
1286         });
1287     if (Err) {
1288       auto diagID = ci.getDiagnostics().getCustomDiagID(
1289           clang::DiagnosticsEngine::Error, "link error when linking '%0'");
1290       ci.getDiagnostics().Report(diagID) << module->getSourceFileName();
1291       return;
1292     }
1293   }
1294 }
1295 
1296 static void reportOptRecordError(llvm::Error e, clang::DiagnosticsEngine &diags,
1297                                  const CodeGenOptions &codeGenOpts) {
1298   handleAllErrors(
1299       std::move(e),
1300       [&](const llvm::LLVMRemarkSetupFileError &e) {
1301         diags.Report(clang::diag::err_cannot_open_file)
1302             << codeGenOpts.OptRecordFile << e.message();
1303       },
1304       [&](const llvm::LLVMRemarkSetupPatternError &e) {
1305         diags.Report(clang::diag::err_drv_optimization_remark_pattern)
1306             << e.message() << codeGenOpts.OptRecordPasses;
1307       },
1308       [&](const llvm::LLVMRemarkSetupFormatError &e) {
1309         diags.Report(clang::diag::err_drv_optimization_remark_format)
1310             << codeGenOpts.OptRecordFormat;
1311       });
1312 }
1313 
1314 void CodeGenAction::executeAction() {
1315   CompilerInstance &ci = this->getInstance();
1316 
1317   clang::DiagnosticsEngine &diags = ci.getDiagnostics();
1318   const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts();
1319   Fortran::lower::LoweringOptions &loweringOpts =
1320       ci.getInvocation().getLoweringOpts();
1321   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
1322   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
1323 
1324   // If the output stream is a file, generate it and define the corresponding
1325   // output stream. If a pre-defined output stream is available, we will use
1326   // that instead.
1327   //
1328   // NOTE: `os` is a smart pointer that will be destroyed at the end of this
1329   // method. However, it won't be written to until `codeGenPasses` is
1330   // destroyed. By defining `os` before `codeGenPasses`, we make sure that the
1331   // output stream won't be destroyed before it is written to. This only
1332   // applies when an output file is used (i.e. there is no pre-defined output
1333   // stream).
1334   // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is
1335   // updated to use it).
1336   std::unique_ptr<llvm::raw_pwrite_stream> os;
1337   if (ci.isOutputStreamNull()) {
1338     os = getOutputStream(ci, getCurrentFileOrBufferName(), action);
1339 
1340     if (!os) {
1341       unsigned diagID = diags.getCustomDiagID(
1342           clang::DiagnosticsEngine::Error, "failed to create the output file");
1343       diags.Report(diagID);
1344       return;
1345     }
1346   }
1347 
1348   if (action == BackendActionTy::Backend_EmitFIR) {
1349     if (loweringOpts.getLowerToHighLevelFIR()) {
1350       lowerHLFIRToFIR();
1351     }
1352     mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
1353     return;
1354   }
1355 
1356   if (action == BackendActionTy::Backend_EmitHLFIR) {
1357     assert(loweringOpts.getLowerToHighLevelFIR() &&
1358            "Lowering must have been configured to emit HLFIR");
1359     mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
1360     return;
1361   }
1362 
1363   // Generate an LLVM module if it's not already present (it will already be
1364   // present if the input file is an LLVM IR/BC file).
1365   if (!llvmModule)
1366     generateLLVMIR();
1367 
1368   // This will already have been started in generateLLVMIR(). But we need to
1369   // continue operating on the module, so we continue timing it.
1370   mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest(
1371       mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr));
1372 
1373   // If generating the LLVM module failed, abort! No need for further error
1374   // reporting since generateLLVMIR() does this already.
1375   if (!llvmModule)
1376     return;
1377 
1378   // Set the triple based on the targetmachine (this comes compiler invocation
1379   // and the command-line target option if specified, or the default if not
1380   // given on the command-line).
1381   llvm::TargetMachine &targetMachine = ci.getTargetMachine();
1382 
1383   const std::string &theTriple = targetMachine.getTargetTriple().str();
1384 
1385   if (llvmModule->getTargetTriple() != theTriple) {
1386     diags.Report(clang::diag::warn_fe_override_module) << theTriple;
1387   }
1388 
1389   // Always set the triple and data layout, to make sure they match and are set.
1390   // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
1391   // an assert for incompatible data layout when the code-generation happens.
1392   llvmModule->setTargetTriple(theTriple);
1393   llvmModule->setDataLayout(targetMachine.createDataLayout());
1394 
1395   // Link in builtin bitcode libraries
1396   if (!codeGenOpts.BuiltinBCLibs.empty())
1397     linkBuiltinBCLibs();
1398 
1399   // Embed offload objects specified with -fembed-offload-object
1400   if (!codeGenOpts.OffloadObjects.empty())
1401     embedOffloadObjects();
1402   timingScopeLLVMIRGen.stop();
1403 
1404   BackendRemarkConsumer remarkConsumer(diags, codeGenOpts);
1405 
1406   llvmModule->getContext().setDiagnosticHandler(
1407       std::make_unique<BackendRemarkConsumer>(remarkConsumer));
1408 
1409   // write optimization-record
1410   llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
1411       setupLLVMOptimizationRemarks(
1412           llvmModule->getContext(), codeGenOpts.OptRecordFile,
1413           codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat,
1414           /*DiagnosticsWithHotness=*/false,
1415           /*DiagnosticsHotnessThreshold=*/0);
1416 
1417   if (llvm::Error e = optRecordFileOrErr.takeError()) {
1418     reportOptRecordError(std::move(e), diags, codeGenOpts);
1419     return;
1420   }
1421 
1422   std::unique_ptr<llvm::ToolOutputFile> optRecordFile =
1423       std::move(*optRecordFileOrErr);
1424 
1425   if (optRecordFile) {
1426     optRecordFile->keep();
1427     optRecordFile->os().flush();
1428   }
1429 
1430   // Run LLVM's middle-end (i.e. the optimizer).
1431   mlir::TimingScope timingScopeLLVMIRPasses = timingScopeRoot.nest(
1432       mlir::TimingIdentifier::get(timingIdLLVMIRPasses, timingMgr));
1433   runOptimizationPipeline(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
1434   timingScopeLLVMIRPasses.stop();
1435 
1436   if (action == BackendActionTy::Backend_EmitLL ||
1437       action == BackendActionTy::Backend_EmitBC) {
1438     // This action has effectively been completed in runOptimizationPipeline.
1439     return;
1440   }
1441 
1442   // Run LLVM's backend and generate either assembly or machine code
1443   mlir::TimingScope timingScopeBackend = timingScopeRoot.nest(
1444       mlir::TimingIdentifier::get(timingIdBackend, timingMgr));
1445   if (action == BackendActionTy::Backend_EmitAssembly ||
1446       action == BackendActionTy::Backend_EmitObj) {
1447     generateMachineCodeOrAssemblyImpl(
1448         diags, targetMachine, action, *llvmModule, codeGenOpts,
1449         ci.isOutputStreamNull() ? *os : ci.getOutputStream());
1450     if (timingMgr.isEnabled())
1451       llvm::reportAndResetTimings(&ci.getTimingStreamCodeGen());
1452     return;
1453   }
1454 }
1455 
1456 void InitOnlyAction::executeAction() {
1457   CompilerInstance &ci = this->getInstance();
1458   unsigned diagID = ci.getDiagnostics().getCustomDiagID(
1459       clang::DiagnosticsEngine::Warning,
1460       "Use `-init-only` for testing purposes only");
1461   ci.getDiagnostics().Report(diagID);
1462 }
1463 
1464 void PluginParseTreeAction::executeAction() {}
1465 
1466 void DebugDumpPFTAction::executeAction() {
1467   CompilerInstance &ci = this->getInstance();
1468 
1469   if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(),
1470                                            ci.getSemantics().context())) {
1471     Fortran::lower::dumpPFT(llvm::outs(), *ast);
1472     return;
1473   }
1474 
1475   unsigned diagID = ci.getDiagnostics().getCustomDiagID(
1476       clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
1477   ci.getDiagnostics().Report(diagID);
1478 }
1479 
1480 Fortran::parser::Parsing &PluginParseTreeAction::getParsing() {
1481   return getInstance().getParsing();
1482 }
1483 
1484 std::unique_ptr<llvm::raw_pwrite_stream>
1485 PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") {
1486 
1487   std::unique_ptr<llvm::raw_pwrite_stream> os{
1488       getInstance().createDefaultOutputFile(
1489           /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(),
1490           extension)};
1491   return os;
1492 }
1493