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