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::make_unique
<mlir::ModuleOp
>(module
.release());
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 // Fetch module from lb, so we can set
307 mlirModule
= std::make_unique
<mlir::ModuleOp
>(lb
.getModule());
309 if (ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
310 Fortran::common::LanguageFeature::OpenMP
)) {
311 setOffloadModuleInterfaceAttributes(*mlirModule
,
312 ci
.getInvocation().getLangOpts());
313 setOpenMPVersionAttribute(*mlirModule
,
314 ci
.getInvocation().getLangOpts().OpenMPVersion
);
317 // Create a parse tree and lower it to FIR
318 Fortran::parser::Program
&parseTree
{*ci
.getParsing().parseTree()};
319 lb
.lower(parseTree
, ci
.getSemanticsContext());
321 // Add target specific items like dependent libraries, target specific
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().messages().empty() &&
570 (ci
.getInvocation().getWarnAsErr() ||
571 ci
.getParsing().messages().AnyFatalError())) {
572 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
573 clang::DiagnosticsEngine::Error
, "Could not parse %0");
574 ci
.getDiagnostics().Report(diagID
) << getCurrentFileOrBufferName();
576 ci
.getParsing().messages().Emit(llvm::errs(),
577 this->getInstance().getAllCookedSources());
581 // Report the getDiagnostics from parsing
582 ci
.getParsing().messages().Emit(llvm::errs(), ci
.getAllCookedSources());
584 auto &parseTree
{*ci
.getParsing().parseTree()};
586 // Measure the parse tree
587 MeasurementVisitor visitor
;
588 Fortran::parser::Walk(parseTree
, visitor
);
589 llvm::outs() << "Parse tree comprises " << visitor
.objects
590 << " objects and occupies " << visitor
.bytes
591 << " total bytes.\n";
594 void DebugPreFIRTreeAction::executeAction() {
595 CompilerInstance
&ci
= this->getInstance();
596 // Report and exit if fatal semantic errors are present
597 if (reportFatalSemanticErrors()) {
601 auto &parseTree
{*ci
.getParsing().parseTree()};
605 Fortran::lower::createPFT(parseTree
, ci
.getSemanticsContext())}) {
606 Fortran::lower::dumpPFT(llvm::outs(), *ast
);
608 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
609 clang::DiagnosticsEngine::Error
, "Pre FIR Tree is NULL.");
610 ci
.getDiagnostics().Report(diagID
);
614 void DebugDumpParsingLogAction::executeAction() {
615 CompilerInstance
&ci
= this->getInstance();
617 ci
.getParsing().Parse(llvm::errs());
618 ci
.getParsing().DumpParsingLog(llvm::outs());
621 void GetDefinitionAction::executeAction() {
622 CompilerInstance
&ci
= this->getInstance();
624 // Report and exit if fatal semantic errors are present
625 if (reportFatalSemanticErrors()) {
629 parser::AllCookedSources
&cs
= ci
.getAllCookedSources();
630 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
631 clang::DiagnosticsEngine::Error
, "Symbol not found");
633 auto gdv
= ci
.getInvocation().getFrontendOpts().getDefVals
;
634 auto charBlock
{cs
.GetCharBlockFromLineAndColumns(gdv
.line
, gdv
.startColumn
,
637 ci
.getDiagnostics().Report(diagID
);
641 llvm::outs() << "String range: >" << charBlock
->ToString() << "<\n";
644 ci
.getSemanticsContext().FindScope(*charBlock
).FindSymbol(*charBlock
)};
646 ci
.getDiagnostics().Report(diagID
);
650 llvm::outs() << "Found symbol name: " << symbol
->name().ToString() << "\n";
652 auto sourceInfo
{cs
.GetSourcePositionRange(symbol
->name())};
655 "Failed to obtain SourcePosition."
656 "TODO: Please, write a test and replace this with a diagnostic!");
660 llvm::outs() << "Found symbol name: " << symbol
->name().ToString() << "\n";
661 llvm::outs() << symbol
->name().ToString() << ": " << sourceInfo
->first
.path
662 << ", " << sourceInfo
->first
.line
<< ", "
663 << sourceInfo
->first
.column
<< "-" << sourceInfo
->second
.column
667 void GetSymbolsSourcesAction::executeAction() {
668 CompilerInstance
&ci
= this->getInstance();
670 // Report and exit if fatal semantic errors are present
671 if (reportFatalSemanticErrors()) {
675 ci
.getSemantics().DumpSymbolsSources(llvm::outs());
678 //===----------------------------------------------------------------------===//
680 //===----------------------------------------------------------------------===//
682 CodeGenAction::~CodeGenAction() = default;
684 static llvm::OptimizationLevel
685 mapToLevel(const Fortran::frontend::CodeGenOptions
&opts
) {
686 switch (opts
.OptimizationLevel
) {
688 llvm_unreachable("Invalid optimization level!");
690 return llvm::OptimizationLevel::O0
;
692 return llvm::OptimizationLevel::O1
;
694 return llvm::OptimizationLevel::O2
;
696 return llvm::OptimizationLevel::O3
;
700 // Lower using HLFIR then run the FIR to HLFIR pipeline
701 void CodeGenAction::lowerHLFIRToFIR() {
702 assert(mlirModule
&& "The MLIR module has not been generated yet.");
704 CompilerInstance
&ci
= this->getInstance();
705 auto opts
= ci
.getInvocation().getCodeGenOpts();
706 llvm::OptimizationLevel level
= mapToLevel(opts
);
708 fir::support::loadDialects(*mlirCtx
);
710 // Set-up the MLIR pass manager
711 mlir::PassManager
pm((*mlirModule
)->getName(),
712 mlir::OpPassManager::Nesting::Implicit
);
714 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
715 pm
.enableVerifier(/*verifyPasses=*/true);
717 // Create the pass pipeline
718 fir::createHLFIRToFIRPassPipeline(
720 ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
721 Fortran::common::LanguageFeature::OpenMP
),
723 (void)mlir::applyPassManagerCLOptions(pm
);
725 if (!mlir::succeeded(pm
.run(*mlirModule
))) {
726 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
727 clang::DiagnosticsEngine::Error
, "Lowering to FIR failed");
728 ci
.getDiagnostics().Report(diagID
);
732 static std::optional
<std::pair
<unsigned, unsigned>>
733 getAArch64VScaleRange(CompilerInstance
&ci
) {
734 const auto &langOpts
= ci
.getInvocation().getLangOpts();
736 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
)
737 return std::pair
<unsigned, unsigned>(
738 langOpts
.VScaleMin
? langOpts
.VScaleMin
: 1, langOpts
.VScaleMax
);
740 std::string featuresStr
= ci
.getTargetFeatures();
741 if (featuresStr
.find("+sve") != std::string::npos
)
742 return std::pair
<unsigned, unsigned>(1, 16);
747 static std::optional
<std::pair
<unsigned, unsigned>>
748 getRISCVVScaleRange(CompilerInstance
&ci
) {
749 const auto &langOpts
= ci
.getInvocation().getLangOpts();
750 const auto targetOpts
= ci
.getInvocation().getTargetOpts();
751 const llvm::Triple
triple(targetOpts
.triple
);
753 auto parseResult
= llvm::RISCVISAInfo::parseFeatures(
754 triple
.isRISCV64() ? 64 : 32, targetOpts
.featuresAsWritten
);
757 llvm::raw_string_ostream
outputErrMsg(buffer
);
758 handleAllErrors(parseResult
.takeError(), [&](llvm::StringError
&errMsg
) {
759 outputErrMsg
<< errMsg
.getMessage();
761 ci
.getDiagnostics().Report(clang::diag::err_invalid_feature_combination
)
766 llvm::RISCVISAInfo
*const isaInfo
= parseResult
->get();
768 // RISCV::RVVBitsPerBlock is 64.
769 unsigned vscaleMin
= isaInfo
->getMinVLen() / llvm::RISCV::RVVBitsPerBlock
;
771 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
) {
772 // Treat Zvl*b as a lower bound on vscale.
773 vscaleMin
= std::max(vscaleMin
, langOpts
.VScaleMin
);
774 unsigned vscaleMax
= langOpts
.VScaleMax
;
775 if (vscaleMax
!= 0 && vscaleMax
< vscaleMin
)
776 vscaleMax
= vscaleMin
;
777 return std::pair
<unsigned, unsigned>(vscaleMin
? vscaleMin
: 1, vscaleMax
);
781 unsigned vscaleMax
= isaInfo
->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock
;
782 return std::make_pair(vscaleMin
, vscaleMax
);
788 // TODO: We should get this from TargetInfo. However, that depends on
789 // too much of clang, so for now, replicate the functionality.
790 static std::optional
<std::pair
<unsigned, unsigned>>
791 getVScaleRange(CompilerInstance
&ci
) {
792 const llvm::Triple
triple(ci
.getInvocation().getTargetOpts().triple
);
794 if (triple
.isAArch64())
795 return getAArch64VScaleRange(ci
);
796 if (triple
.isRISCV())
797 return getRISCVVScaleRange(ci
);
799 // All other architectures that don't support scalable vectors (i.e. don't
804 // Lower the previously generated MLIR module into an LLVM IR module
805 void CodeGenAction::generateLLVMIR() {
806 assert(mlirModule
&& "The MLIR module has not been generated yet.");
808 CompilerInstance
&ci
= this->getInstance();
809 auto opts
= ci
.getInvocation().getCodeGenOpts();
810 auto mathOpts
= ci
.getInvocation().getLoweringOpts().getMathOptions();
811 llvm::OptimizationLevel level
= mapToLevel(opts
);
813 fir::support::loadDialects(*mlirCtx
);
814 mlir::DialectRegistry registry
;
815 fir::support::registerNonCodegenDialects(registry
);
816 fir::support::addFIRExtensions(registry
);
817 mlirCtx
->appendDialectRegistry(registry
);
818 fir::support::registerLLVMTranslation(*mlirCtx
);
820 // Set-up the MLIR pass manager
821 mlir::PassManager
pm((*mlirModule
)->getName(),
822 mlir::OpPassManager::Nesting::Implicit
);
824 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
825 pm
.enableVerifier(/*verifyPasses=*/true);
827 MLIRToLLVMPassPipelineConfig
config(level
, opts
, mathOpts
);
828 fir::registerDefaultInlinerPass(config
);
830 if (auto vsr
= getVScaleRange(ci
)) {
831 config
.VScaleMin
= vsr
->first
;
832 config
.VScaleMax
= vsr
->second
;
835 if (ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
836 Fortran::common::LanguageFeature::OpenMP
))
837 config
.EnableOpenMP
= true;
839 if (ci
.getInvocation().getLoweringOpts().getNSWOnLoopVarInc())
840 config
.NSWOnLoopVarInc
= true;
842 // Create the pass pipeline
843 fir::createMLIRToLLVMPassPipeline(pm
, config
, getCurrentFile());
844 (void)mlir::applyPassManagerCLOptions(pm
);
846 // run the pass manager
847 if (!mlir::succeeded(pm
.run(*mlirModule
))) {
848 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
849 clang::DiagnosticsEngine::Error
, "Lowering to LLVM IR failed");
850 ci
.getDiagnostics().Report(diagID
);
853 // Print final MLIR module, just before translation into LLVM IR, if
854 // -save-temps has been specified.
855 if (!saveMLIRTempFile(ci
.getInvocation(), *mlirModule
, getCurrentFile(),
857 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
858 clang::DiagnosticsEngine::Error
, "Saving MLIR temp file failed");
859 ci
.getDiagnostics().Report(diagID
);
863 // Translate to LLVM IR
864 std::optional
<llvm::StringRef
> moduleName
= mlirModule
->getName();
865 llvmModule
= mlir::translateModuleToLLVMIR(
866 *mlirModule
, *llvmCtx
, moduleName
? *moduleName
: "FIRModule");
869 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
870 clang::DiagnosticsEngine::Error
, "failed to create the LLVM module");
871 ci
.getDiagnostics().Report(diagID
);
875 // Set PIC/PIE level LLVM module flags.
876 if (opts
.PICLevel
> 0) {
877 llvmModule
->setPICLevel(static_cast<llvm::PICLevel::Level
>(opts
.PICLevel
));
879 llvmModule
->setPIELevel(
880 static_cast<llvm::PIELevel::Level
>(opts
.PICLevel
));
883 // Set mcmodel level LLVM module flags
884 std::optional
<llvm::CodeModel::Model
> cm
= getCodeModel(opts
.CodeModel
);
885 if (cm
.has_value()) {
886 const llvm::Triple
triple(ci
.getInvocation().getTargetOpts().triple
);
887 llvmModule
->setCodeModel(*cm
);
888 if ((cm
== llvm::CodeModel::Medium
|| cm
== llvm::CodeModel::Large
) &&
889 triple
.getArch() == llvm::Triple::x86_64
) {
890 llvmModule
->setLargeDataThreshold(opts
.LargeDataThreshold
);
895 static std::unique_ptr
<llvm::raw_pwrite_stream
>
896 getOutputStream(CompilerInstance
&ci
, llvm::StringRef inFile
,
897 BackendActionTy action
) {
899 case BackendActionTy::Backend_EmitAssembly
:
900 return ci
.createDefaultOutputFile(
901 /*Binary=*/false, inFile
, /*extension=*/"s");
902 case BackendActionTy::Backend_EmitLL
:
903 return ci
.createDefaultOutputFile(
904 /*Binary=*/false, inFile
, /*extension=*/"ll");
905 case BackendActionTy::Backend_EmitFIR
:
906 case BackendActionTy::Backend_EmitHLFIR
:
907 return ci
.createDefaultOutputFile(
908 /*Binary=*/false, inFile
, /*extension=*/"mlir");
909 case BackendActionTy::Backend_EmitBC
:
910 return ci
.createDefaultOutputFile(
911 /*Binary=*/true, inFile
, /*extension=*/"bc");
912 case BackendActionTy::Backend_EmitObj
:
913 return ci
.createDefaultOutputFile(
914 /*Binary=*/true, inFile
, /*extension=*/"o");
917 llvm_unreachable("Invalid action!");
920 /// Generate target-specific machine-code or assembly file from the input LLVM
923 /// \param [in] diags Diagnostics engine for reporting errors
924 /// \param [in] tm Target machine to aid the code-gen pipeline set-up
925 /// \param [in] act Backend act to run (assembly vs machine-code generation)
926 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code
927 /// \param [in] codeGenOpts options configuring codegen pipeline
928 /// \param [out] os Output stream to emit the generated code to
929 static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine
&diags
,
930 llvm::TargetMachine
&tm
,
932 llvm::Module
&llvmModule
,
933 const CodeGenOptions
&codeGenOpts
,
934 llvm::raw_pwrite_stream
&os
) {
935 assert(((act
== BackendActionTy::Backend_EmitObj
) ||
936 (act
== BackendActionTy::Backend_EmitAssembly
)) &&
937 "Unsupported action");
939 // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline.
940 // Currently only the legacy pass manager is supported.
941 // TODO: Switch to the new PM once it's available in the backend.
942 llvm::legacy::PassManager codeGenPasses
;
944 createTargetTransformInfoWrapperPass(tm
.getTargetIRAnalysis()));
946 llvm::Triple
triple(llvmModule
.getTargetTriple());
947 llvm::TargetLibraryInfoImpl
*tlii
=
948 llvm::driver::createTLII(triple
, codeGenOpts
.getVecLib());
949 codeGenPasses
.add(new llvm::TargetLibraryInfoWrapperPass(*tlii
));
951 llvm::CodeGenFileType cgft
= (act
== BackendActionTy::Backend_EmitAssembly
)
952 ? llvm::CodeGenFileType::AssemblyFile
953 : llvm::CodeGenFileType::ObjectFile
;
954 if (tm
.addPassesToEmitFile(codeGenPasses
, os
, nullptr, cgft
)) {
956 diags
.getCustomDiagID(clang::DiagnosticsEngine::Error
,
957 "emission of this file type is not supported");
958 diags
.Report(diagID
);
963 codeGenPasses
.run(llvmModule
);
966 void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream
&os
) {
967 auto opts
= getInstance().getInvocation().getCodeGenOpts();
968 auto &diags
= getInstance().getDiagnostics();
969 llvm::OptimizationLevel level
= mapToLevel(opts
);
971 llvm::TargetMachine
*targetMachine
= &getInstance().getTargetMachine();
972 // Create the analysis managers.
973 llvm::LoopAnalysisManager lam
;
974 llvm::FunctionAnalysisManager fam
;
975 llvm::CGSCCAnalysisManager cgam
;
976 llvm::ModuleAnalysisManager mam
;
978 // Create the pass manager builder.
979 llvm::PassInstrumentationCallbacks pic
;
980 llvm::PipelineTuningOptions pto
;
981 std::optional
<llvm::PGOOptions
> pgoOpt
;
982 llvm::StandardInstrumentations
si(llvmModule
->getContext(),
983 opts
.DebugPassManager
);
984 si
.registerCallbacks(pic
, &mam
);
985 llvm::PassBuilder
pb(targetMachine
, pto
, pgoOpt
, &pic
);
987 // Attempt to load pass plugins and register their callbacks with PB.
988 for (auto &pluginFile
: opts
.LLVMPassPlugins
) {
989 auto passPlugin
= llvm::PassPlugin::Load(pluginFile
);
991 passPlugin
->registerPassBuilderCallbacks(pb
);
993 diags
.Report(clang::diag::err_fe_unable_to_load_plugin
)
994 << pluginFile
<< passPlugin
.takeError();
997 // Register static plugin extensions.
998 #define HANDLE_EXTENSION(Ext) \
999 get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
1000 #include "llvm/Support/Extension.def"
1002 // Register the target library analysis directly and give it a customized
1003 // preset TLI depending on -fveclib
1004 llvm::Triple
triple(llvmModule
->getTargetTriple());
1005 llvm::TargetLibraryInfoImpl
*tlii
=
1006 llvm::driver::createTLII(triple
, opts
.getVecLib());
1007 fam
.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii
); });
1009 // Register all the basic analyses with the managers.
1010 pb
.registerModuleAnalyses(mam
);
1011 pb
.registerCGSCCAnalyses(cgam
);
1012 pb
.registerFunctionAnalyses(fam
);
1013 pb
.registerLoopAnalyses(lam
);
1014 pb
.crossRegisterProxies(lam
, fam
, cgam
, mam
);
1016 // Create the pass manager.
1017 llvm::ModulePassManager mpm
;
1018 if (opts
.PrepareForFullLTO
)
1019 mpm
= pb
.buildLTOPreLinkDefaultPipeline(level
);
1020 else if (opts
.PrepareForThinLTO
)
1021 mpm
= pb
.buildThinLTOPreLinkDefaultPipeline(level
);
1023 mpm
= pb
.buildPerModuleDefaultPipeline(level
);
1025 if (action
== BackendActionTy::Backend_EmitBC
)
1026 mpm
.addPass(llvm::BitcodeWriterPass(os
));
1027 else if (action
== BackendActionTy::Backend_EmitLL
)
1028 mpm
.addPass(llvm::PrintModulePass(os
));
1030 // FIXME: This should eventually be replaced by a first-class driver option.
1031 // This should be done for both flang and clang simultaneously.
1032 // Print a textual, '-passes=' compatible, representation of pipeline if
1033 // requested. In this case, don't run the passes. This mimics the behavior of
1035 if (llvm::PrintPipelinePasses
) {
1036 mpm
.printPipeline(llvm::outs(), [&pic
](llvm::StringRef className
) {
1037 auto passName
= pic
.getPassNameForClassName(className
);
1038 return passName
.empty() ? className
: passName
;
1040 llvm::outs() << "\n";
1045 mpm
.run(*llvmModule
, mam
);
1048 // This class handles optimization remark messages requested if
1049 // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided
1050 class BackendRemarkConsumer
: public llvm::DiagnosticHandler
{
1052 const CodeGenOptions
&codeGenOpts
;
1053 clang::DiagnosticsEngine
&diags
;
1056 BackendRemarkConsumer(clang::DiagnosticsEngine
&diags
,
1057 const CodeGenOptions
&codeGenOpts
)
1058 : codeGenOpts(codeGenOpts
), diags(diags
) {}
1060 bool isAnalysisRemarkEnabled(llvm::StringRef passName
) const override
{
1061 return codeGenOpts
.OptimizationRemarkAnalysis
.patternMatches(passName
);
1063 bool isMissedOptRemarkEnabled(llvm::StringRef passName
) const override
{
1064 return codeGenOpts
.OptimizationRemarkMissed
.patternMatches(passName
);
1066 bool isPassedOptRemarkEnabled(llvm::StringRef passName
) const override
{
1067 return codeGenOpts
.OptimizationRemark
.patternMatches(passName
);
1070 bool isAnyRemarkEnabled() const override
{
1071 return codeGenOpts
.OptimizationRemarkAnalysis
.hasValidPattern() ||
1072 codeGenOpts
.OptimizationRemarkMissed
.hasValidPattern() ||
1073 codeGenOpts
.OptimizationRemark
.hasValidPattern();
1077 emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase
&diagInfo
,
1079 // We only support warnings and remarks.
1080 assert(diagInfo
.getSeverity() == llvm::DS_Remark
||
1081 diagInfo
.getSeverity() == llvm::DS_Warning
);
1084 llvm::raw_string_ostream
msgStream(msg
);
1086 if (diagInfo
.isLocationAvailable()) {
1087 // Clang contains a SourceManager class which handles loading
1088 // and caching of source files into memory and it can be used to
1089 // query SourceLocation data. The SourceLocation data is what is
1090 // needed here as it contains the full include stack which gives
1091 // line and column number as well as file name and location.
1092 // Since Flang doesn't have SourceManager, send file name and absolute
1093 // path through msgStream, to use for printing.
1094 msgStream
<< diagInfo
.getLocationStr() << ";;"
1095 << diagInfo
.getAbsolutePath() << ";;";
1098 msgStream
<< diagInfo
.getMsg();
1101 diags
.Report(diagID
) << clang::AddFlagValue(diagInfo
.getPassName()) << msg
;
1104 void optimizationRemarkHandler(
1105 const llvm::DiagnosticInfoOptimizationBase
&diagInfo
) {
1106 auto passName
= diagInfo
.getPassName();
1107 if (diagInfo
.isPassed()) {
1108 if (codeGenOpts
.OptimizationRemark
.patternMatches(passName
))
1109 // Optimization remarks are active only if the -Rpass flag has a regular
1110 // expression that matches the name of the pass name in \p d.
1111 emitOptimizationMessage(
1112 diagInfo
, clang::diag::remark_fe_backend_optimization_remark
);
1117 if (diagInfo
.isMissed()) {
1118 if (codeGenOpts
.OptimizationRemarkMissed
.patternMatches(passName
))
1119 // Missed optimization remarks are active only if the -Rpass-missed
1120 // flag has a regular expression that matches the name of the pass
1122 emitOptimizationMessage(
1124 clang::diag::remark_fe_backend_optimization_remark_missed
);
1129 assert(diagInfo
.isAnalysis() && "Unknown remark type");
1131 bool shouldAlwaysPrint
= false;
1132 auto *ora
= llvm::dyn_cast
<llvm::OptimizationRemarkAnalysis
>(&diagInfo
);
1134 shouldAlwaysPrint
= ora
->shouldAlwaysPrint();
1136 if (shouldAlwaysPrint
||
1137 codeGenOpts
.OptimizationRemarkAnalysis
.patternMatches(passName
))
1138 emitOptimizationMessage(
1140 clang::diag::remark_fe_backend_optimization_remark_analysis
);
1143 bool handleDiagnostics(const llvm::DiagnosticInfo
&di
) override
{
1144 switch (di
.getKind()) {
1145 case llvm::DK_OptimizationRemark
:
1146 optimizationRemarkHandler(llvm::cast
<llvm::OptimizationRemark
>(di
));
1148 case llvm::DK_OptimizationRemarkMissed
:
1149 optimizationRemarkHandler(llvm::cast
<llvm::OptimizationRemarkMissed
>(di
));
1151 case llvm::DK_OptimizationRemarkAnalysis
:
1152 optimizationRemarkHandler(
1153 llvm::cast
<llvm::OptimizationRemarkAnalysis
>(di
));
1155 case llvm::DK_MachineOptimizationRemark
:
1156 optimizationRemarkHandler(
1157 llvm::cast
<llvm::MachineOptimizationRemark
>(di
));
1159 case llvm::DK_MachineOptimizationRemarkMissed
:
1160 optimizationRemarkHandler(
1161 llvm::cast
<llvm::MachineOptimizationRemarkMissed
>(di
));
1163 case llvm::DK_MachineOptimizationRemarkAnalysis
:
1164 optimizationRemarkHandler(
1165 llvm::cast
<llvm::MachineOptimizationRemarkAnalysis
>(di
));
1174 void CodeGenAction::embedOffloadObjects() {
1175 CompilerInstance
&ci
= this->getInstance();
1176 const auto &cgOpts
= ci
.getInvocation().getCodeGenOpts();
1178 for (llvm::StringRef offloadObject
: cgOpts
.OffloadObjects
) {
1179 llvm::ErrorOr
<std::unique_ptr
<llvm::MemoryBuffer
>> objectOrErr
=
1180 llvm::MemoryBuffer::getFileOrSTDIN(offloadObject
);
1181 if (std::error_code ec
= objectOrErr
.getError()) {
1182 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1183 clang::DiagnosticsEngine::Error
, "could not open '%0' for embedding");
1184 ci
.getDiagnostics().Report(diagID
) << offloadObject
;
1187 llvm::embedBufferInModule(
1188 *llvmModule
, **objectOrErr
, ".llvm.offloading",
1189 llvm::Align(llvm::object::OffloadBinary::getAlignment()));
1193 void CodeGenAction::linkBuiltinBCLibs() {
1194 auto options
= clang::FileSystemOptions();
1195 clang::FileManager
fileManager(options
);
1196 CompilerInstance
&ci
= this->getInstance();
1197 const auto &cgOpts
= ci
.getInvocation().getCodeGenOpts();
1199 std::vector
<std::unique_ptr
<llvm::Module
>> modules
;
1201 // Load LLVM modules
1202 for (llvm::StringRef bcLib
: cgOpts
.BuiltinBCLibs
) {
1203 auto BCBuf
= fileManager
.getBufferForFile(bcLib
);
1205 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1206 clang::DiagnosticsEngine::Error
, "could not open '%0' for linking");
1207 ci
.getDiagnostics().Report(diagID
) << bcLib
;
1211 llvm::Expected
<std::unique_ptr
<llvm::Module
>> ModuleOrErr
=
1212 getOwningLazyBitcodeModule(std::move(*BCBuf
), *llvmCtx
);
1214 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1215 clang::DiagnosticsEngine::Error
, "error loading '%0' for linking");
1216 ci
.getDiagnostics().Report(diagID
) << bcLib
;
1219 modules
.push_back(std::move(ModuleOrErr
.get()));
1222 // Link modules and internalize functions
1223 for (auto &module
: modules
) {
1225 Err
= llvm::Linker::linkModules(
1226 *llvmModule
, std::move(module
), llvm::Linker::Flags::LinkOnlyNeeded
,
1227 [](llvm::Module
&M
, const llvm::StringSet
<> &GVS
) {
1228 llvm::internalizeModule(M
, [&GVS
](const llvm::GlobalValue
&GV
) {
1229 return !GV
.hasName() || (GVS
.count(GV
.getName()) == 0);
1233 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1234 clang::DiagnosticsEngine::Error
, "link error when linking '%0'");
1235 ci
.getDiagnostics().Report(diagID
) << module
->getSourceFileName();
1241 static void reportOptRecordError(llvm::Error e
, clang::DiagnosticsEngine
&diags
,
1242 const CodeGenOptions
&codeGenOpts
) {
1245 [&](const llvm::LLVMRemarkSetupFileError
&e
) {
1246 diags
.Report(clang::diag::err_cannot_open_file
)
1247 << codeGenOpts
.OptRecordFile
<< e
.message();
1249 [&](const llvm::LLVMRemarkSetupPatternError
&e
) {
1250 diags
.Report(clang::diag::err_drv_optimization_remark_pattern
)
1251 << e
.message() << codeGenOpts
.OptRecordPasses
;
1253 [&](const llvm::LLVMRemarkSetupFormatError
&e
) {
1254 diags
.Report(clang::diag::err_drv_optimization_remark_format
)
1255 << codeGenOpts
.OptRecordFormat
;
1259 void CodeGenAction::executeAction() {
1260 CompilerInstance
&ci
= this->getInstance();
1262 clang::DiagnosticsEngine
&diags
= ci
.getDiagnostics();
1263 const CodeGenOptions
&codeGenOpts
= ci
.getInvocation().getCodeGenOpts();
1264 Fortran::lower::LoweringOptions
&loweringOpts
=
1265 ci
.getInvocation().getLoweringOpts();
1267 // If the output stream is a file, generate it and define the corresponding
1268 // output stream. If a pre-defined output stream is available, we will use
1271 // NOTE: `os` is a smart pointer that will be destroyed at the end of this
1272 // method. However, it won't be written to until `codeGenPasses` is
1273 // destroyed. By defining `os` before `codeGenPasses`, we make sure that the
1274 // output stream won't be destroyed before it is written to. This only
1275 // applies when an output file is used (i.e. there is no pre-defined output
1277 // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is
1278 // updated to use it).
1279 std::unique_ptr
<llvm::raw_pwrite_stream
> os
;
1280 if (ci
.isOutputStreamNull()) {
1281 os
= getOutputStream(ci
, getCurrentFileOrBufferName(), action
);
1284 unsigned diagID
= diags
.getCustomDiagID(
1285 clang::DiagnosticsEngine::Error
, "failed to create the output file");
1286 diags
.Report(diagID
);
1291 if (action
== BackendActionTy::Backend_EmitFIR
) {
1292 if (loweringOpts
.getLowerToHighLevelFIR()) {
1295 mlirModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1299 if (action
== BackendActionTy::Backend_EmitHLFIR
) {
1300 assert(loweringOpts
.getLowerToHighLevelFIR() &&
1301 "Lowering must have been configured to emit HLFIR");
1302 mlirModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1306 // Generate an LLVM module if it's not already present (it will already be
1307 // present if the input file is an LLVM IR/BC file).
1311 // If generating the LLVM module failed, abort! No need for further error
1312 // reporting since generateLLVMIR() does this already.
1316 // Set the triple based on the targetmachine (this comes compiler invocation
1317 // and the command-line target option if specified, or the default if not
1318 // given on the command-line).
1319 llvm::TargetMachine
&targetMachine
= ci
.getTargetMachine();
1321 const std::string
&theTriple
= targetMachine
.getTargetTriple().str();
1323 if (llvmModule
->getTargetTriple() != theTriple
) {
1324 diags
.Report(clang::diag::warn_fe_override_module
) << theTriple
;
1327 // Always set the triple and data layout, to make sure they match and are set.
1328 // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
1329 // an assert for incompatible data layout when the code-generation happens.
1330 llvmModule
->setTargetTriple(theTriple
);
1331 llvmModule
->setDataLayout(targetMachine
.createDataLayout());
1333 // Link in builtin bitcode libraries
1334 if (!codeGenOpts
.BuiltinBCLibs
.empty())
1335 linkBuiltinBCLibs();
1337 // Embed offload objects specified with -fembed-offload-object
1338 if (!codeGenOpts
.OffloadObjects
.empty())
1339 embedOffloadObjects();
1341 BackendRemarkConsumer
remarkConsumer(diags
, codeGenOpts
);
1343 llvmModule
->getContext().setDiagnosticHandler(
1344 std::make_unique
<BackendRemarkConsumer
>(remarkConsumer
));
1346 // write optimization-record
1347 llvm::Expected
<std::unique_ptr
<llvm::ToolOutputFile
>> optRecordFileOrErr
=
1348 setupLLVMOptimizationRemarks(
1349 llvmModule
->getContext(), codeGenOpts
.OptRecordFile
,
1350 codeGenOpts
.OptRecordPasses
, codeGenOpts
.OptRecordFormat
,
1351 /*DiagnosticsWithHotness=*/false,
1352 /*DiagnosticsHotnessThreshold=*/0);
1354 if (llvm::Error e
= optRecordFileOrErr
.takeError()) {
1355 reportOptRecordError(std::move(e
), diags
, codeGenOpts
);
1359 std::unique_ptr
<llvm::ToolOutputFile
> optRecordFile
=
1360 std::move(*optRecordFileOrErr
);
1362 if (optRecordFile
) {
1363 optRecordFile
->keep();
1364 optRecordFile
->os().flush();
1367 // Run LLVM's middle-end (i.e. the optimizer).
1368 runOptimizationPipeline(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1370 if (action
== BackendActionTy::Backend_EmitLL
||
1371 action
== BackendActionTy::Backend_EmitBC
) {
1372 // This action has effectively been completed in runOptimizationPipeline.
1376 // Run LLVM's backend and generate either assembly or machine code
1377 if (action
== BackendActionTy::Backend_EmitAssembly
||
1378 action
== BackendActionTy::Backend_EmitObj
) {
1379 generateMachineCodeOrAssemblyImpl(
1380 diags
, targetMachine
, action
, *llvmModule
, codeGenOpts
,
1381 ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1386 void InitOnlyAction::executeAction() {
1387 CompilerInstance
&ci
= this->getInstance();
1388 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
1389 clang::DiagnosticsEngine::Warning
,
1390 "Use `-init-only` for testing purposes only");
1391 ci
.getDiagnostics().Report(diagID
);
1394 void PluginParseTreeAction::executeAction() {}
1396 void DebugDumpPFTAction::executeAction() {
1397 CompilerInstance
&ci
= this->getInstance();
1399 if (auto ast
= Fortran::lower::createPFT(*ci
.getParsing().parseTree(),
1400 ci
.getSemantics().context())) {
1401 Fortran::lower::dumpPFT(llvm::outs(), *ast
);
1405 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
1406 clang::DiagnosticsEngine::Error
, "Pre FIR Tree is NULL.");
1407 ci
.getDiagnostics().Report(diagID
);
1410 Fortran::parser::Parsing
&PluginParseTreeAction::getParsing() {
1411 return getInstance().getParsing();
1414 std::unique_ptr
<llvm::raw_pwrite_stream
>
1415 PluginParseTreeAction::createOutputFile(llvm::StringRef extension
= "") {
1417 std::unique_ptr
<llvm::raw_pwrite_stream
> os
{
1418 getInstance().createDefaultOutputFile(
1419 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(),