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