1 //===--- FrontendActions.cpp ----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
79 #include <system_error>
82 extern cl::opt
<bool> PrintPipelinePasses
;
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
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())
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
)
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
111 llvm::SmallString
<256> path(dir
);
112 llvm::sys::path::append(path
, llvm::sys::path::stem(inputFile
) + "-" +
113 outputTag
+ ".mlir");
116 llvm::ToolOutputFile
out(path
, ec
, llvm::sys::fs::OF_Text
);
120 mlirModule
->print(out
.os());
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
;
158 // dependent-lib is currently only supported on Windows, so the list should be
159 // empty on non-Windows platforms
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()) {
183 const CodeGenOptions
&codeGenOpts
= ci
.getInvocation().getCodeGenOpts();
184 if (codeGenOpts
.CodeObjectVersion
== llvm::CodeObjectVersionKind::COV_None
) {
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
) {
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
);
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
);
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
);
272 mlirModule
= std::move(module
);
273 const llvm::DataLayout
&dl
= targetMachine
.createDataLayout();
274 fir::support::setMLIRDataLayout(*mlirModule
, dl
);
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
);
286 bool res
= runPrescan() && runParse(/*emitMessages=*/false) &&
287 runSemanticChecks() && generateRtTypeTables();
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 if (ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
307 Fortran::common::LanguageFeature::OpenMP
)) {
308 setOffloadModuleInterfaceAttributes(lb
.getModule(),
309 ci
.getInvocation().getLangOpts());
310 setOpenMPVersionAttribute(lb
.getModule(),
311 ci
.getInvocation().getLangOpts().OpenMPVersion
);
314 // Create a parse tree and lower it to FIR
315 Fortran::parser::Program
&parseTree
{*ci
.getParsing().parseTree()};
316 lb
.lower(parseTree
, ci
.getSemanticsContext());
318 // Fetch module from lb, so we can set
319 mlirModule
= lb
.getModuleAndRelease();
321 // Add target specific items like dependent libraries, target specific
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/
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
);
356 // Print initial full MLIR module, before lowering or transformations, if
357 // -save-temps has been specified.
358 if (!saveMLIRTempFile(ci
.getInvocation(), *mlirModule
, getCurrentFile(),
360 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
361 clang::DiagnosticsEngine::Error
, "Saving MLIR temp file failed");
362 ci
.getDiagnostics().Report(diagID
);
369 //===----------------------------------------------------------------------===//
370 // Custom ExecuteAction
371 //===----------------------------------------------------------------------===//
372 void InputOutputTestAction::executeAction() {
373 CompilerInstance
&ci
= getInstance();
375 // Create a stream for errors
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
;
384 sf
= allSources
.ReadStandardInput(errorStream
);
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());
397 // No pre-set output stream - create an output file
398 os
= ci
.createDefaultOutputFile(
399 /*binary=*/true, getCurrentFileOrBufferName(), "txt");
402 (*os
) << fileContent
.data();
406 void PrintPreprocessedAction::executeAction() {
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
);
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
);
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())};
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()
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()
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";
512 ci
.getSemantics().DumpSymbols(llvm::outs());
515 void DebugDumpAllAction::executeAction() {
516 CompilerInstance
&ci
= this->getInstance();
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";
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()};
546 Fortran::parser::DumpTree(
547 llvm::outs(), parseTree
,
548 &this->getInstance().getInvocation().getAsFortran());
551 void DebugDumpParseTreeAction::executeAction() {
552 auto &parseTree
{getInstance().getParsing().parseTree()};
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().parseTree().has_value() &&
570 !ci
.getParsing().consumedWholeFile()) ||
571 (!ci
.getParsing().messages().empty() &&
572 (ci
.getInvocation().getWarnAsErr() ||
573 ci
.getParsing().messages().AnyFatalError()))) {
574 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
575 clang::DiagnosticsEngine::Error
, "Could not parse %0");
576 ci
.getDiagnostics().Report(diagID
) << getCurrentFileOrBufferName();
578 ci
.getParsing().messages().Emit(llvm::errs(),
579 this->getInstance().getAllCookedSources());
583 // Report the getDiagnostics from parsing
584 ci
.getParsing().messages().Emit(llvm::errs(), ci
.getAllCookedSources());
586 auto &parseTree
{*ci
.getParsing().parseTree()};
588 // Measure the parse tree
589 MeasurementVisitor visitor
;
590 Fortran::parser::Walk(parseTree
, visitor
);
591 llvm::outs() << "Parse tree comprises " << visitor
.objects
592 << " objects and occupies " << visitor
.bytes
593 << " total bytes.\n";
596 void DebugPreFIRTreeAction::executeAction() {
597 CompilerInstance
&ci
= this->getInstance();
598 // Report and exit if fatal semantic errors are present
599 if (reportFatalSemanticErrors()) {
603 auto &parseTree
{*ci
.getParsing().parseTree()};
607 Fortran::lower::createPFT(parseTree
, ci
.getSemanticsContext())}) {
608 Fortran::lower::dumpPFT(llvm::outs(), *ast
);
610 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
611 clang::DiagnosticsEngine::Error
, "Pre FIR Tree is NULL.");
612 ci
.getDiagnostics().Report(diagID
);
616 void DebugDumpParsingLogAction::executeAction() {
617 CompilerInstance
&ci
= this->getInstance();
619 ci
.getParsing().Parse(llvm::errs());
620 ci
.getParsing().DumpParsingLog(llvm::outs());
623 void GetDefinitionAction::executeAction() {
624 CompilerInstance
&ci
= this->getInstance();
626 // Report and exit if fatal semantic errors are present
627 if (reportFatalSemanticErrors()) {
631 parser::AllCookedSources
&cs
= ci
.getAllCookedSources();
632 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
633 clang::DiagnosticsEngine::Error
, "Symbol not found");
635 auto gdv
= ci
.getInvocation().getFrontendOpts().getDefVals
;
636 auto charBlock
{cs
.GetCharBlockFromLineAndColumns(gdv
.line
, gdv
.startColumn
,
639 ci
.getDiagnostics().Report(diagID
);
643 llvm::outs() << "String range: >" << charBlock
->ToString() << "<\n";
646 ci
.getSemanticsContext().FindScope(*charBlock
).FindSymbol(*charBlock
)};
648 ci
.getDiagnostics().Report(diagID
);
652 llvm::outs() << "Found symbol name: " << symbol
->name().ToString() << "\n";
654 auto sourceInfo
{cs
.GetSourcePositionRange(symbol
->name())};
657 "Failed to obtain SourcePosition."
658 "TODO: Please, write a test and replace this with a diagnostic!");
662 llvm::outs() << "Found symbol name: " << symbol
->name().ToString() << "\n";
663 llvm::outs() << symbol
->name().ToString() << ": " << sourceInfo
->first
.path
664 << ", " << sourceInfo
->first
.line
<< ", "
665 << sourceInfo
->first
.column
<< "-" << sourceInfo
->second
.column
669 void GetSymbolsSourcesAction::executeAction() {
670 CompilerInstance
&ci
= this->getInstance();
672 // Report and exit if fatal semantic errors are present
673 if (reportFatalSemanticErrors()) {
677 ci
.getSemantics().DumpSymbolsSources(llvm::outs());
680 //===----------------------------------------------------------------------===//
682 //===----------------------------------------------------------------------===//
684 CodeGenAction::~CodeGenAction() = default;
686 static llvm::OptimizationLevel
687 mapToLevel(const Fortran::frontend::CodeGenOptions
&opts
) {
688 switch (opts
.OptimizationLevel
) {
690 llvm_unreachable("Invalid optimization level!");
692 return llvm::OptimizationLevel::O0
;
694 return llvm::OptimizationLevel::O1
;
696 return llvm::OptimizationLevel::O2
;
698 return llvm::OptimizationLevel::O3
;
702 // Lower using HLFIR then run the FIR to HLFIR pipeline
703 void CodeGenAction::lowerHLFIRToFIR() {
704 assert(mlirModule
&& "The MLIR module has not been generated yet.");
706 CompilerInstance
&ci
= this->getInstance();
707 auto opts
= ci
.getInvocation().getCodeGenOpts();
708 llvm::OptimizationLevel level
= mapToLevel(opts
);
710 fir::support::loadDialects(*mlirCtx
);
712 // Set-up the MLIR pass manager
713 mlir::PassManager
pm((*mlirModule
)->getName(),
714 mlir::OpPassManager::Nesting::Implicit
);
716 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
717 pm
.enableVerifier(/*verifyPasses=*/true);
719 // Create the pass pipeline
720 fir::createHLFIRToFIRPassPipeline(
722 ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
723 Fortran::common::LanguageFeature::OpenMP
),
725 (void)mlir::applyPassManagerCLOptions(pm
);
727 if (!mlir::succeeded(pm
.run(*mlirModule
))) {
728 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
729 clang::DiagnosticsEngine::Error
, "Lowering to FIR failed");
730 ci
.getDiagnostics().Report(diagID
);
734 static std::optional
<std::pair
<unsigned, unsigned>>
735 getAArch64VScaleRange(CompilerInstance
&ci
) {
736 const auto &langOpts
= ci
.getInvocation().getLangOpts();
738 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
)
739 return std::pair
<unsigned, unsigned>(
740 langOpts
.VScaleMin
? langOpts
.VScaleMin
: 1, langOpts
.VScaleMax
);
742 std::string featuresStr
= ci
.getTargetFeatures();
743 if (featuresStr
.find("+sve") != std::string::npos
)
744 return std::pair
<unsigned, unsigned>(1, 16);
749 static std::optional
<std::pair
<unsigned, unsigned>>
750 getRISCVVScaleRange(CompilerInstance
&ci
) {
751 const auto &langOpts
= ci
.getInvocation().getLangOpts();
752 const auto targetOpts
= ci
.getInvocation().getTargetOpts();
753 const llvm::Triple
triple(targetOpts
.triple
);
755 auto parseResult
= llvm::RISCVISAInfo::parseFeatures(
756 triple
.isRISCV64() ? 64 : 32, targetOpts
.featuresAsWritten
);
759 llvm::raw_string_ostream
outputErrMsg(buffer
);
760 handleAllErrors(parseResult
.takeError(), [&](llvm::StringError
&errMsg
) {
761 outputErrMsg
<< errMsg
.getMessage();
763 ci
.getDiagnostics().Report(clang::diag::err_invalid_feature_combination
)
768 llvm::RISCVISAInfo
*const isaInfo
= parseResult
->get();
770 // RISCV::RVVBitsPerBlock is 64.
771 unsigned vscaleMin
= isaInfo
->getMinVLen() / llvm::RISCV::RVVBitsPerBlock
;
773 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
) {
774 // Treat Zvl*b as a lower bound on vscale.
775 vscaleMin
= std::max(vscaleMin
, langOpts
.VScaleMin
);
776 unsigned vscaleMax
= langOpts
.VScaleMax
;
777 if (vscaleMax
!= 0 && vscaleMax
< vscaleMin
)
778 vscaleMax
= vscaleMin
;
779 return std::pair
<unsigned, unsigned>(vscaleMin
? vscaleMin
: 1, vscaleMax
);
783 unsigned vscaleMax
= isaInfo
->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock
;
784 return std::make_pair(vscaleMin
, vscaleMax
);
790 // TODO: We should get this from TargetInfo. However, that depends on
791 // too much of clang, so for now, replicate the functionality.
792 static std::optional
<std::pair
<unsigned, unsigned>>
793 getVScaleRange(CompilerInstance
&ci
) {
794 const llvm::Triple
triple(ci
.getInvocation().getTargetOpts().triple
);
796 if (triple
.isAArch64())
797 return getAArch64VScaleRange(ci
);
798 if (triple
.isRISCV())
799 return getRISCVVScaleRange(ci
);
801 // All other architectures that don't support scalable vectors (i.e. don't
806 // Lower the previously generated MLIR module into an LLVM IR module
807 void CodeGenAction::generateLLVMIR() {
808 assert(mlirModule
&& "The MLIR module has not been generated yet.");
810 CompilerInstance
&ci
= this->getInstance();
811 auto opts
= ci
.getInvocation().getCodeGenOpts();
812 auto mathOpts
= ci
.getInvocation().getLoweringOpts().getMathOptions();
813 llvm::OptimizationLevel level
= mapToLevel(opts
);
815 fir::support::loadDialects(*mlirCtx
);
816 mlir::DialectRegistry registry
;
817 fir::support::registerNonCodegenDialects(registry
);
818 fir::support::addFIRExtensions(registry
);
819 mlirCtx
->appendDialectRegistry(registry
);
820 fir::support::registerLLVMTranslation(*mlirCtx
);
822 // Set-up the MLIR pass manager
823 mlir::PassManager
pm((*mlirModule
)->getName(),
824 mlir::OpPassManager::Nesting::Implicit
);
826 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
827 pm
.enableVerifier(/*verifyPasses=*/true);
829 MLIRToLLVMPassPipelineConfig
config(level
, opts
, mathOpts
);
830 fir::registerDefaultInlinerPass(config
);
832 if (auto vsr
= getVScaleRange(ci
)) {
833 config
.VScaleMin
= vsr
->first
;
834 config
.VScaleMax
= vsr
->second
;
837 if (ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
838 Fortran::common::LanguageFeature::OpenMP
))
839 config
.EnableOpenMP
= true;
841 if (ci
.getInvocation().getLoweringOpts().getIntegerWrapAround())
842 config
.NSWOnLoopVarInc
= false;
844 // Create the pass pipeline
845 fir::createMLIRToLLVMPassPipeline(pm
, config
, getCurrentFile());
846 (void)mlir::applyPassManagerCLOptions(pm
);
848 // run the pass manager
849 if (!mlir::succeeded(pm
.run(*mlirModule
))) {
850 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
851 clang::DiagnosticsEngine::Error
, "Lowering to LLVM IR failed");
852 ci
.getDiagnostics().Report(diagID
);
855 // Print final MLIR module, just before translation into LLVM IR, if
856 // -save-temps has been specified.
857 if (!saveMLIRTempFile(ci
.getInvocation(), *mlirModule
, getCurrentFile(),
859 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
860 clang::DiagnosticsEngine::Error
, "Saving MLIR temp file failed");
861 ci
.getDiagnostics().Report(diagID
);
865 // Translate to LLVM IR
866 std::optional
<llvm::StringRef
> moduleName
= mlirModule
->getName();
867 llvmModule
= mlir::translateModuleToLLVMIR(
868 *mlirModule
, *llvmCtx
, moduleName
? *moduleName
: "FIRModule");
871 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
872 clang::DiagnosticsEngine::Error
, "failed to create the LLVM module");
873 ci
.getDiagnostics().Report(diagID
);
877 // Set PIC/PIE level LLVM module flags.
878 if (opts
.PICLevel
> 0) {
879 llvmModule
->setPICLevel(static_cast<llvm::PICLevel::Level
>(opts
.PICLevel
));
881 llvmModule
->setPIELevel(
882 static_cast<llvm::PIELevel::Level
>(opts
.PICLevel
));
885 // Set mcmodel level LLVM module flags
886 std::optional
<llvm::CodeModel::Model
> cm
= getCodeModel(opts
.CodeModel
);
887 if (cm
.has_value()) {
888 const llvm::Triple
triple(ci
.getInvocation().getTargetOpts().triple
);
889 llvmModule
->setCodeModel(*cm
);
890 if ((cm
== llvm::CodeModel::Medium
|| cm
== llvm::CodeModel::Large
) &&
891 triple
.getArch() == llvm::Triple::x86_64
) {
892 llvmModule
->setLargeDataThreshold(opts
.LargeDataThreshold
);
897 static std::unique_ptr
<llvm::raw_pwrite_stream
>
898 getOutputStream(CompilerInstance
&ci
, llvm::StringRef inFile
,
899 BackendActionTy action
) {
901 case BackendActionTy::Backend_EmitAssembly
:
902 return ci
.createDefaultOutputFile(
903 /*Binary=*/false, inFile
, /*extension=*/"s");
904 case BackendActionTy::Backend_EmitLL
:
905 return ci
.createDefaultOutputFile(
906 /*Binary=*/false, inFile
, /*extension=*/"ll");
907 case BackendActionTy::Backend_EmitFIR
:
908 case BackendActionTy::Backend_EmitHLFIR
:
909 return ci
.createDefaultOutputFile(
910 /*Binary=*/false, inFile
, /*extension=*/"mlir");
911 case BackendActionTy::Backend_EmitBC
:
912 return ci
.createDefaultOutputFile(
913 /*Binary=*/true, inFile
, /*extension=*/"bc");
914 case BackendActionTy::Backend_EmitObj
:
915 return ci
.createDefaultOutputFile(
916 /*Binary=*/true, inFile
, /*extension=*/"o");
919 llvm_unreachable("Invalid action!");
922 /// Generate target-specific machine-code or assembly file from the input LLVM
925 /// \param [in] diags Diagnostics engine for reporting errors
926 /// \param [in] tm Target machine to aid the code-gen pipeline set-up
927 /// \param [in] act Backend act to run (assembly vs machine-code generation)
928 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code
929 /// \param [in] codeGenOpts options configuring codegen pipeline
930 /// \param [out] os Output stream to emit the generated code to
931 static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine
&diags
,
932 llvm::TargetMachine
&tm
,
934 llvm::Module
&llvmModule
,
935 const CodeGenOptions
&codeGenOpts
,
936 llvm::raw_pwrite_stream
&os
) {
937 assert(((act
== BackendActionTy::Backend_EmitObj
) ||
938 (act
== BackendActionTy::Backend_EmitAssembly
)) &&
939 "Unsupported action");
941 // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline.
942 // Currently only the legacy pass manager is supported.
943 // TODO: Switch to the new PM once it's available in the backend.
944 llvm::legacy::PassManager codeGenPasses
;
946 createTargetTransformInfoWrapperPass(tm
.getTargetIRAnalysis()));
948 llvm::Triple
triple(llvmModule
.getTargetTriple());
949 llvm::TargetLibraryInfoImpl
*tlii
=
950 llvm::driver::createTLII(triple
, codeGenOpts
.getVecLib());
951 codeGenPasses
.add(new llvm::TargetLibraryInfoWrapperPass(*tlii
));
953 llvm::CodeGenFileType cgft
= (act
== BackendActionTy::Backend_EmitAssembly
)
954 ? llvm::CodeGenFileType::AssemblyFile
955 : llvm::CodeGenFileType::ObjectFile
;
956 if (tm
.addPassesToEmitFile(codeGenPasses
, os
, nullptr, cgft
)) {
958 diags
.getCustomDiagID(clang::DiagnosticsEngine::Error
,
959 "emission of this file type is not supported");
960 diags
.Report(diagID
);
965 codeGenPasses
.run(llvmModule
);
971 void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream
&os
) {
972 auto opts
= getInstance().getInvocation().getCodeGenOpts();
973 auto &diags
= getInstance().getDiagnostics();
974 llvm::OptimizationLevel level
= mapToLevel(opts
);
976 llvm::TargetMachine
*targetMachine
= &getInstance().getTargetMachine();
977 // Create the analysis managers.
978 llvm::LoopAnalysisManager lam
;
979 llvm::FunctionAnalysisManager fam
;
980 llvm::CGSCCAnalysisManager cgam
;
981 llvm::ModuleAnalysisManager mam
;
983 // Create the pass manager builder.
984 llvm::PassInstrumentationCallbacks pic
;
985 llvm::PipelineTuningOptions pto
;
986 std::optional
<llvm::PGOOptions
> pgoOpt
;
987 llvm::StandardInstrumentations
si(llvmModule
->getContext(),
988 opts
.DebugPassManager
);
989 si
.registerCallbacks(pic
, &mam
);
990 llvm::PassBuilder
pb(targetMachine
, pto
, pgoOpt
, &pic
);
992 // Attempt to load pass plugins and register their callbacks with PB.
993 for (auto &pluginFile
: opts
.LLVMPassPlugins
) {
994 auto passPlugin
= llvm::PassPlugin::Load(pluginFile
);
996 passPlugin
->registerPassBuilderCallbacks(pb
);
998 diags
.Report(clang::diag::err_fe_unable_to_load_plugin
)
999 << pluginFile
<< passPlugin
.takeError();
1002 // Register static plugin extensions.
1003 #define HANDLE_EXTENSION(Ext) \
1004 get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
1005 #include "llvm/Support/Extension.def"
1007 // Register the target library analysis directly and give it a customized
1008 // preset TLI depending on -fveclib
1009 llvm::Triple
triple(llvmModule
->getTargetTriple());
1010 llvm::TargetLibraryInfoImpl
*tlii
=
1011 llvm::driver::createTLII(triple
, opts
.getVecLib());
1012 fam
.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii
); });
1014 // Register all the basic analyses with the managers.
1015 pb
.registerModuleAnalyses(mam
);
1016 pb
.registerCGSCCAnalyses(cgam
);
1017 pb
.registerFunctionAnalyses(fam
);
1018 pb
.registerLoopAnalyses(lam
);
1019 pb
.crossRegisterProxies(lam
, fam
, cgam
, mam
);
1021 // Create the pass manager.
1022 llvm::ModulePassManager mpm
;
1023 if (opts
.PrepareForFullLTO
)
1024 mpm
= pb
.buildLTOPreLinkDefaultPipeline(level
);
1025 else if (opts
.PrepareForThinLTO
)
1026 mpm
= pb
.buildThinLTOPreLinkDefaultPipeline(level
);
1028 mpm
= pb
.buildPerModuleDefaultPipeline(level
);
1030 if (action
== BackendActionTy::Backend_EmitBC
)
1031 mpm
.addPass(llvm::BitcodeWriterPass(os
));
1032 else if (action
== BackendActionTy::Backend_EmitLL
)
1033 mpm
.addPass(llvm::PrintModulePass(os
));
1035 // FIXME: This should eventually be replaced by a first-class driver option.
1036 // This should be done for both flang and clang simultaneously.
1037 // Print a textual, '-passes=' compatible, representation of pipeline if
1038 // requested. In this case, don't run the passes. This mimics the behavior of
1040 if (llvm::PrintPipelinePasses
) {
1041 mpm
.printPipeline(llvm::outs(), [&pic
](llvm::StringRef className
) {
1042 auto passName
= pic
.getPassNameForClassName(className
);
1043 return passName
.empty() ? className
: passName
;
1045 llvm::outs() << "\n";
1050 mpm
.run(*llvmModule
, mam
);
1056 // This class handles optimization remark messages requested if
1057 // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided
1058 class BackendRemarkConsumer
: public llvm::DiagnosticHandler
{
1060 const CodeGenOptions
&codeGenOpts
;
1061 clang::DiagnosticsEngine
&diags
;
1064 BackendRemarkConsumer(clang::DiagnosticsEngine
&diags
,
1065 const CodeGenOptions
&codeGenOpts
)
1066 : codeGenOpts(codeGenOpts
), diags(diags
) {}
1068 bool isAnalysisRemarkEnabled(llvm::StringRef passName
) const override
{
1069 return codeGenOpts
.OptimizationRemarkAnalysis
.patternMatches(passName
);
1071 bool isMissedOptRemarkEnabled(llvm::StringRef passName
) const override
{
1072 return codeGenOpts
.OptimizationRemarkMissed
.patternMatches(passName
);
1074 bool isPassedOptRemarkEnabled(llvm::StringRef passName
) const override
{
1075 return codeGenOpts
.OptimizationRemark
.patternMatches(passName
);
1078 bool isAnyRemarkEnabled() const override
{
1079 return codeGenOpts
.OptimizationRemarkAnalysis
.hasValidPattern() ||
1080 codeGenOpts
.OptimizationRemarkMissed
.hasValidPattern() ||
1081 codeGenOpts
.OptimizationRemark
.hasValidPattern();
1085 emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase
&diagInfo
,
1087 // We only support warnings and remarks.
1088 assert(diagInfo
.getSeverity() == llvm::DS_Remark
||
1089 diagInfo
.getSeverity() == llvm::DS_Warning
);
1092 llvm::raw_string_ostream
msgStream(msg
);
1094 if (diagInfo
.isLocationAvailable()) {
1095 // Clang contains a SourceManager class which handles loading
1096 // and caching of source files into memory and it can be used to
1097 // query SourceLocation data. The SourceLocation data is what is
1098 // needed here as it contains the full include stack which gives
1099 // line and column number as well as file name and location.
1100 // Since Flang doesn't have SourceManager, send file name and absolute
1101 // path through msgStream, to use for printing.
1102 msgStream
<< diagInfo
.getLocationStr() << ";;"
1103 << diagInfo
.getAbsolutePath() << ";;";
1106 msgStream
<< diagInfo
.getMsg();
1109 diags
.Report(diagID
) << clang::AddFlagValue(diagInfo
.getPassName()) << msg
;
1112 void optimizationRemarkHandler(
1113 const llvm::DiagnosticInfoOptimizationBase
&diagInfo
) {
1114 auto passName
= diagInfo
.getPassName();
1115 if (diagInfo
.isPassed()) {
1116 if (codeGenOpts
.OptimizationRemark
.patternMatches(passName
))
1117 // Optimization remarks are active only if the -Rpass flag has a regular
1118 // expression that matches the name of the pass name in \p d.
1119 emitOptimizationMessage(
1120 diagInfo
, clang::diag::remark_fe_backend_optimization_remark
);
1125 if (diagInfo
.isMissed()) {
1126 if (codeGenOpts
.OptimizationRemarkMissed
.patternMatches(passName
))
1127 // Missed optimization remarks are active only if the -Rpass-missed
1128 // flag has a regular expression that matches the name of the pass
1130 emitOptimizationMessage(
1132 clang::diag::remark_fe_backend_optimization_remark_missed
);
1137 assert(diagInfo
.isAnalysis() && "Unknown remark type");
1139 bool shouldAlwaysPrint
= false;
1140 auto *ora
= llvm::dyn_cast
<llvm::OptimizationRemarkAnalysis
>(&diagInfo
);
1142 shouldAlwaysPrint
= ora
->shouldAlwaysPrint();
1144 if (shouldAlwaysPrint
||
1145 codeGenOpts
.OptimizationRemarkAnalysis
.patternMatches(passName
))
1146 emitOptimizationMessage(
1148 clang::diag::remark_fe_backend_optimization_remark_analysis
);
1151 bool handleDiagnostics(const llvm::DiagnosticInfo
&di
) override
{
1152 switch (di
.getKind()) {
1153 case llvm::DK_OptimizationRemark
:
1154 optimizationRemarkHandler(llvm::cast
<llvm::OptimizationRemark
>(di
));
1156 case llvm::DK_OptimizationRemarkMissed
:
1157 optimizationRemarkHandler(llvm::cast
<llvm::OptimizationRemarkMissed
>(di
));
1159 case llvm::DK_OptimizationRemarkAnalysis
:
1160 optimizationRemarkHandler(
1161 llvm::cast
<llvm::OptimizationRemarkAnalysis
>(di
));
1163 case llvm::DK_MachineOptimizationRemark
:
1164 optimizationRemarkHandler(
1165 llvm::cast
<llvm::MachineOptimizationRemark
>(di
));
1167 case llvm::DK_MachineOptimizationRemarkMissed
:
1168 optimizationRemarkHandler(
1169 llvm::cast
<llvm::MachineOptimizationRemarkMissed
>(di
));
1171 case llvm::DK_MachineOptimizationRemarkAnalysis
:
1172 optimizationRemarkHandler(
1173 llvm::cast
<llvm::MachineOptimizationRemarkAnalysis
>(di
));
1182 void CodeGenAction::embedOffloadObjects() {
1183 CompilerInstance
&ci
= this->getInstance();
1184 const auto &cgOpts
= ci
.getInvocation().getCodeGenOpts();
1186 for (llvm::StringRef offloadObject
: cgOpts
.OffloadObjects
) {
1187 llvm::ErrorOr
<std::unique_ptr
<llvm::MemoryBuffer
>> objectOrErr
=
1188 llvm::MemoryBuffer::getFileOrSTDIN(offloadObject
);
1189 if (std::error_code ec
= objectOrErr
.getError()) {
1190 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1191 clang::DiagnosticsEngine::Error
, "could not open '%0' for embedding");
1192 ci
.getDiagnostics().Report(diagID
) << offloadObject
;
1195 llvm::embedBufferInModule(
1196 *llvmModule
, **objectOrErr
, ".llvm.offloading",
1197 llvm::Align(llvm::object::OffloadBinary::getAlignment()));
1201 void CodeGenAction::linkBuiltinBCLibs() {
1202 auto options
= clang::FileSystemOptions();
1203 clang::FileManager
fileManager(options
);
1204 CompilerInstance
&ci
= this->getInstance();
1205 const auto &cgOpts
= ci
.getInvocation().getCodeGenOpts();
1207 std::vector
<std::unique_ptr
<llvm::Module
>> modules
;
1209 // Load LLVM modules
1210 for (llvm::StringRef bcLib
: cgOpts
.BuiltinBCLibs
) {
1211 auto BCBuf
= fileManager
.getBufferForFile(bcLib
);
1213 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1214 clang::DiagnosticsEngine::Error
, "could not open '%0' for linking");
1215 ci
.getDiagnostics().Report(diagID
) << bcLib
;
1219 llvm::Expected
<std::unique_ptr
<llvm::Module
>> ModuleOrErr
=
1220 getOwningLazyBitcodeModule(std::move(*BCBuf
), *llvmCtx
);
1222 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1223 clang::DiagnosticsEngine::Error
, "error loading '%0' for linking");
1224 ci
.getDiagnostics().Report(diagID
) << bcLib
;
1227 modules
.push_back(std::move(ModuleOrErr
.get()));
1230 // Link modules and internalize functions
1231 for (auto &module
: modules
) {
1233 Err
= llvm::Linker::linkModules(
1234 *llvmModule
, std::move(module
), llvm::Linker::Flags::LinkOnlyNeeded
,
1235 [](llvm::Module
&M
, const llvm::StringSet
<> &GVS
) {
1236 llvm::internalizeModule(M
, [&GVS
](const llvm::GlobalValue
&GV
) {
1237 return !GV
.hasName() || (GVS
.count(GV
.getName()) == 0);
1241 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1242 clang::DiagnosticsEngine::Error
, "link error when linking '%0'");
1243 ci
.getDiagnostics().Report(diagID
) << module
->getSourceFileName();
1249 static void reportOptRecordError(llvm::Error e
, clang::DiagnosticsEngine
&diags
,
1250 const CodeGenOptions
&codeGenOpts
) {
1253 [&](const llvm::LLVMRemarkSetupFileError
&e
) {
1254 diags
.Report(clang::diag::err_cannot_open_file
)
1255 << codeGenOpts
.OptRecordFile
<< e
.message();
1257 [&](const llvm::LLVMRemarkSetupPatternError
&e
) {
1258 diags
.Report(clang::diag::err_drv_optimization_remark_pattern
)
1259 << e
.message() << codeGenOpts
.OptRecordPasses
;
1261 [&](const llvm::LLVMRemarkSetupFormatError
&e
) {
1262 diags
.Report(clang::diag::err_drv_optimization_remark_format
)
1263 << codeGenOpts
.OptRecordFormat
;
1267 void CodeGenAction::executeAction() {
1268 CompilerInstance
&ci
= this->getInstance();
1270 clang::DiagnosticsEngine
&diags
= ci
.getDiagnostics();
1271 const CodeGenOptions
&codeGenOpts
= ci
.getInvocation().getCodeGenOpts();
1272 Fortran::lower::LoweringOptions
&loweringOpts
=
1273 ci
.getInvocation().getLoweringOpts();
1275 // If the output stream is a file, generate it and define the corresponding
1276 // output stream. If a pre-defined output stream is available, we will use
1279 // NOTE: `os` is a smart pointer that will be destroyed at the end of this
1280 // method. However, it won't be written to until `codeGenPasses` is
1281 // destroyed. By defining `os` before `codeGenPasses`, we make sure that the
1282 // output stream won't be destroyed before it is written to. This only
1283 // applies when an output file is used (i.e. there is no pre-defined output
1285 // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is
1286 // updated to use it).
1287 std::unique_ptr
<llvm::raw_pwrite_stream
> os
;
1288 if (ci
.isOutputStreamNull()) {
1289 os
= getOutputStream(ci
, getCurrentFileOrBufferName(), action
);
1292 unsigned diagID
= diags
.getCustomDiagID(
1293 clang::DiagnosticsEngine::Error
, "failed to create the output file");
1294 diags
.Report(diagID
);
1299 if (action
== BackendActionTy::Backend_EmitFIR
) {
1300 if (loweringOpts
.getLowerToHighLevelFIR()) {
1303 mlirModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1307 if (action
== BackendActionTy::Backend_EmitHLFIR
) {
1308 assert(loweringOpts
.getLowerToHighLevelFIR() &&
1309 "Lowering must have been configured to emit HLFIR");
1310 mlirModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1314 // Generate an LLVM module if it's not already present (it will already be
1315 // present if the input file is an LLVM IR/BC file).
1319 // If generating the LLVM module failed, abort! No need for further error
1320 // reporting since generateLLVMIR() does this already.
1324 // Set the triple based on the targetmachine (this comes compiler invocation
1325 // and the command-line target option if specified, or the default if not
1326 // given on the command-line).
1327 llvm::TargetMachine
&targetMachine
= ci
.getTargetMachine();
1329 const std::string
&theTriple
= targetMachine
.getTargetTriple().str();
1331 if (llvmModule
->getTargetTriple() != theTriple
) {
1332 diags
.Report(clang::diag::warn_fe_override_module
) << theTriple
;
1335 // Always set the triple and data layout, to make sure they match and are set.
1336 // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
1337 // an assert for incompatible data layout when the code-generation happens.
1338 llvmModule
->setTargetTriple(theTriple
);
1339 llvmModule
->setDataLayout(targetMachine
.createDataLayout());
1341 // Link in builtin bitcode libraries
1342 if (!codeGenOpts
.BuiltinBCLibs
.empty())
1343 linkBuiltinBCLibs();
1345 // Embed offload objects specified with -fembed-offload-object
1346 if (!codeGenOpts
.OffloadObjects
.empty())
1347 embedOffloadObjects();
1349 BackendRemarkConsumer
remarkConsumer(diags
, codeGenOpts
);
1351 llvmModule
->getContext().setDiagnosticHandler(
1352 std::make_unique
<BackendRemarkConsumer
>(remarkConsumer
));
1354 // write optimization-record
1355 llvm::Expected
<std::unique_ptr
<llvm::ToolOutputFile
>> optRecordFileOrErr
=
1356 setupLLVMOptimizationRemarks(
1357 llvmModule
->getContext(), codeGenOpts
.OptRecordFile
,
1358 codeGenOpts
.OptRecordPasses
, codeGenOpts
.OptRecordFormat
,
1359 /*DiagnosticsWithHotness=*/false,
1360 /*DiagnosticsHotnessThreshold=*/0);
1362 if (llvm::Error e
= optRecordFileOrErr
.takeError()) {
1363 reportOptRecordError(std::move(e
), diags
, codeGenOpts
);
1367 std::unique_ptr
<llvm::ToolOutputFile
> optRecordFile
=
1368 std::move(*optRecordFileOrErr
);
1370 if (optRecordFile
) {
1371 optRecordFile
->keep();
1372 optRecordFile
->os().flush();
1375 // Run LLVM's middle-end (i.e. the optimizer).
1376 runOptimizationPipeline(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1378 if (action
== BackendActionTy::Backend_EmitLL
||
1379 action
== BackendActionTy::Backend_EmitBC
) {
1380 // This action has effectively been completed in runOptimizationPipeline.
1384 // Run LLVM's backend and generate either assembly or machine code
1385 if (action
== BackendActionTy::Backend_EmitAssembly
||
1386 action
== BackendActionTy::Backend_EmitObj
) {
1387 generateMachineCodeOrAssemblyImpl(
1388 diags
, targetMachine
, action
, *llvmModule
, codeGenOpts
,
1389 ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1394 void InitOnlyAction::executeAction() {
1395 CompilerInstance
&ci
= this->getInstance();
1396 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
1397 clang::DiagnosticsEngine::Warning
,
1398 "Use `-init-only` for testing purposes only");
1399 ci
.getDiagnostics().Report(diagID
);
1402 void PluginParseTreeAction::executeAction() {}
1404 void DebugDumpPFTAction::executeAction() {
1405 CompilerInstance
&ci
= this->getInstance();
1407 if (auto ast
= Fortran::lower::createPFT(*ci
.getParsing().parseTree(),
1408 ci
.getSemantics().context())) {
1409 Fortran::lower::dumpPFT(llvm::outs(), *ast
);
1413 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
1414 clang::DiagnosticsEngine::Error
, "Pre FIR Tree is NULL.");
1415 ci
.getDiagnostics().Report(diagID
);
1418 Fortran::parser::Parsing
&PluginParseTreeAction::getParsing() {
1419 return getInstance().getParsing();
1422 std::unique_ptr
<llvm::raw_pwrite_stream
>
1423 PluginParseTreeAction::createOutputFile(llvm::StringRef extension
= "") {
1425 std::unique_ptr
<llvm::raw_pwrite_stream
> os
{
1426 getInstance().createDefaultOutputFile(
1427 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(),