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