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

source code of flang/lib/Frontend/FrontendActions.cpp