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