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/Support/DataLayout.h"
25 #include "flang/Optimizer/Support/InitFIR.h"
26 #include "flang/Optimizer/Support/Utils.h"
27 #include "flang/Optimizer/Transforms/Passes.h"
28 #include "flang/Parser/dump-parse-tree.h"
29 #include "flang/Parser/parsing.h"
30 #include "flang/Parser/provenance.h"
31 #include "flang/Parser/source.h"
32 #include "flang/Parser/unparse.h"
33 #include "flang/Semantics/runtime-type-info.h"
34 #include "flang/Semantics/semantics.h"
35 #include "flang/Semantics/unparse-with-symbols.h"
36 #include "flang/Tools/CrossToolHelpers.h"
38 #include "mlir/IR/Dialect.h"
39 #include "mlir/Parser/Parser.h"
40 #include "mlir/Pass/PassManager.h"
41 #include "mlir/Support/LLVM.h"
42 #include "mlir/Target/LLVMIR/Import.h"
43 #include "mlir/Target/LLVMIR/ModuleTranslation.h"
44 #include "clang/Basic/Diagnostic.h"
45 #include "clang/Basic/DiagnosticFrontend.h"
46 #include "clang/Driver/DriverDiagnostic.h"
47 #include "llvm/ADT/SmallString.h"
48 #include "llvm/ADT/StringRef.h"
49 #include "llvm/Analysis/TargetLibraryInfo.h"
50 #include "llvm/Analysis/TargetTransformInfo.h"
51 #include "llvm/Bitcode/BitcodeWriterPass.h"
52 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
53 #include "llvm/IR/LLVMRemarkStreamer.h"
54 #include "llvm/IR/LegacyPassManager.h"
55 #include "llvm/IR/Verifier.h"
56 #include "llvm/IRReader/IRReader.h"
57 #include "llvm/Object/OffloadBinary.h"
58 #include "llvm/Passes/PassBuilder.h"
59 #include "llvm/Passes/PassPlugin.h"
60 #include "llvm/Passes/StandardInstrumentations.h"
61 #include "llvm/Support/AMDGPUAddrSpace.h"
62 #include "llvm/Support/Error.h"
63 #include "llvm/Support/ErrorHandling.h"
64 #include "llvm/Support/FileSystem.h"
65 #include "llvm/Support/Path.h"
66 #include "llvm/Support/RISCVISAInfo.h"
67 #include "llvm/Support/SourceMgr.h"
68 #include "llvm/Support/ToolOutputFile.h"
69 #include "llvm/Target/TargetMachine.h"
70 #include "llvm/TargetParser/RISCVTargetParser.h"
71 #include "llvm/Transforms/Utils/ModuleUtils.h"
73 #include <system_error>
75 #include "flang/Tools/CLOptions.inc"
77 using namespace Fortran::frontend
;
79 // Declare plugin extension function declarations.
80 #define HANDLE_EXTENSION(Ext) \
81 llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
82 #include "llvm/Support/Extension.def"
84 /// Save the given \c mlirModule to a temporary .mlir file, in a location
85 /// decided by the -save-temps flag. No files are produced if the flag is not
87 static bool saveMLIRTempFile(const CompilerInvocation
&ci
,
88 mlir::ModuleOp mlirModule
,
89 llvm::StringRef inputFile
,
90 llvm::StringRef outputTag
) {
91 if (!ci
.getCodeGenOpts().SaveTempsDir
.has_value())
94 const llvm::StringRef compilerOutFile
= ci
.getFrontendOpts().outputFile
;
95 const llvm::StringRef saveTempsDir
= ci
.getCodeGenOpts().SaveTempsDir
.value();
96 auto dir
= llvm::StringSwitch
<llvm::StringRef
>(saveTempsDir
)
98 .Case("obj", llvm::sys::path::parent_path(compilerOutFile
))
99 .Default(saveTempsDir
);
101 // Build path from the compiler output file name, triple, cpu and OpenMP
103 llvm::SmallString
<256> path(dir
);
104 llvm::sys::path::append(path
, llvm::sys::path::stem(inputFile
) + "-" +
105 outputTag
+ ".mlir");
108 llvm::ToolOutputFile
out(path
, ec
, llvm::sys::fs::OF_Text
);
112 mlirModule
->print(out
.os());
119 //===----------------------------------------------------------------------===//
120 // Custom BeginSourceFileAction
121 //===----------------------------------------------------------------------===//
123 bool PrescanAction::beginSourceFileAction() { return runPrescan(); }
125 bool PrescanAndParseAction::beginSourceFileAction() {
126 return runPrescan() && runParse();
129 bool PrescanAndSemaAction::beginSourceFileAction() {
130 return runPrescan() && runParse() && runSemanticChecks() &&
131 generateRtTypeTables();
134 bool PrescanAndSemaDebugAction::beginSourceFileAction() {
135 // This is a "debug" action for development purposes. To facilitate this, the
136 // semantic checks are made to succeed unconditionally to prevent this action
137 // from exiting early (i.e. in the presence of semantic errors). We should
138 // never do this in actions intended for end-users or otherwise regular
139 // compiler workflows!
140 return runPrescan() && runParse() && (runSemanticChecks() || true) &&
141 (generateRtTypeTables() || true);
144 static void addDependentLibs(mlir::ModuleOp
&mlirModule
, CompilerInstance
&ci
) {
145 const std::vector
<std::string
> &libs
=
146 ci
.getInvocation().getCodeGenOpts().DependentLibs
;
150 // dependent-lib is currently only supported on Windows, so the list should be
151 // empty on non-Windows platforms
153 llvm::Triple(ci
.getInvocation().getTargetOpts().triple
).isOSWindows() &&
154 "--dependent-lib is only supported on Windows");
155 // Add linker options specified by --dependent-lib
156 auto builder
= mlir::OpBuilder(mlirModule
.getRegion());
157 for (const std::string
&lib
: libs
) {
158 builder
.create
<mlir::LLVM::LinkerOptionsOp
>(
159 mlirModule
.getLoc(), builder
.getStrArrayAttr({"/DEFAULTLIB:" + lib
}));
163 // Add to MLIR code target specific items which are dependent on target
164 // configuration specified by the user.
165 // Clang equivalent function: AMDGPUTargetCodeGenInfo::emitTargetGlobals
166 static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp
&mlirModule
,
167 CompilerInstance
&ci
) {
168 const TargetOptions
&targetOpts
= ci
.getInvocation().getTargetOpts();
169 const llvm::Triple
triple(targetOpts
.triple
);
170 const llvm::StringRef codeObjectVersionGlobalOpName
= "__oclc_ABI_version";
172 if (!triple
.isAMDGPU()) {
175 const CodeGenOptions
&codeGenOpts
= ci
.getInvocation().getCodeGenOpts();
176 if (codeGenOpts
.CodeObjectVersion
== llvm::CodeObjectVersionKind::COV_None
) {
180 mlir::ConversionPatternRewriter
builder(mlirModule
.getContext());
181 unsigned oclcABIVERsion
= codeGenOpts
.CodeObjectVersion
;
182 auto int32Type
= builder
.getI32Type();
184 std::optional
<mlir::LLVM::GlobalOp
> originalGV
;
186 mlirModule
.walk([&originalGV
, codeObjectVersionGlobalOpName
](
187 mlir::LLVM::GlobalOp globalOp
) {
188 if (globalOp
.getName() == codeObjectVersionGlobalOpName
)
189 originalGV
= globalOp
;
191 if (originalGV
.has_value()) {
192 mlir::LLVM::GlobalOp originalGVOp
= originalGV
.value();
193 if (originalGVOp
.getLinkage() != mlir::LLVM::Linkage::External
) {
196 // Update the variable if it is already present in MLIR but it was marked
197 // as external linkage variable
198 originalGVOp
.setLinkage(mlir::LLVM::Linkage::WeakODR
);
199 originalGVOp
.setValueAttr(
200 builder
.getIntegerAttr(int32Type
, oclcABIVERsion
));
201 originalGVOp
.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local
);
202 originalGVOp
.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS
);
203 originalGVOp
.setVisibility_(mlir::LLVM::Visibility::Hidden
);
207 mlir::LLVM::GlobalOp covInfo
= builder
.create
<mlir::LLVM::GlobalOp
>(
208 /* Location */ mlirModule
.getLoc(), /* Type */ int32Type
,
209 /* IsConstant */ true, /* Linkage */ mlir::LLVM::Linkage::WeakODR
,
210 /* Name */ codeObjectVersionGlobalOpName
,
211 /* Value */ builder
.getIntegerAttr(int32Type
, oclcABIVERsion
));
212 covInfo
.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local
);
213 covInfo
.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS
);
214 covInfo
.setVisibility_(mlir::LLVM::Visibility::Hidden
);
215 builder
.setInsertionPointToStart(mlirModule
.getBody());
216 builder
.insert(covInfo
);
219 bool CodeGenAction::beginSourceFileAction() {
220 llvmCtx
= std::make_unique
<llvm::LLVMContext
>();
221 CompilerInstance
&ci
= this->getInstance();
223 // If the input is an LLVM file, just parse it and return.
224 if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR
) {
225 llvm::SMDiagnostic err
;
226 llvmModule
= llvm::parseIRFile(getCurrentInput().getFile(), err
, *llvmCtx
);
227 if (!llvmModule
|| llvm::verifyModule(*llvmModule
, &llvm::errs())) {
228 err
.print("flang-new", llvm::errs());
229 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
230 clang::DiagnosticsEngine::Error
, "Could not parse IR");
231 ci
.getDiagnostics().Report(diagID
);
238 // Load the MLIR dialects required by Flang
239 mlir::DialectRegistry registry
;
240 mlirCtx
= std::make_unique
<mlir::MLIRContext
>(registry
);
241 fir::support::registerNonCodegenDialects(registry
);
242 fir::support::loadNonCodegenDialects(*mlirCtx
);
243 fir::support::loadDialects(*mlirCtx
);
244 fir::support::registerLLVMTranslation(*mlirCtx
);
246 const llvm::TargetMachine
&targetMachine
= ci
.getTargetMachine();
248 // If the input is an MLIR file, just parse it and return.
249 if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR
) {
250 llvm::SourceMgr sourceMgr
;
251 llvm::ErrorOr
<std::unique_ptr
<llvm::MemoryBuffer
>> fileOrErr
=
252 llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile());
253 sourceMgr
.AddNewSourceBuffer(std::move(*fileOrErr
), llvm::SMLoc());
254 mlir::OwningOpRef
<mlir::ModuleOp
> module
=
255 mlir::parseSourceFile
<mlir::ModuleOp
>(sourceMgr
, mlirCtx
.get());
257 if (!module
|| mlir::failed(module
->verifyInvariants())) {
258 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
259 clang::DiagnosticsEngine::Error
, "Could not parse FIR");
260 ci
.getDiagnostics().Report(diagID
);
264 mlirModule
= std::make_unique
<mlir::ModuleOp
>(module
.release());
265 const llvm::DataLayout
&dl
= targetMachine
.createDataLayout();
266 fir::support::setMLIRDataLayout(*mlirModule
, dl
);
270 // Otherwise, generate an MLIR module from the input Fortran source
271 if (getCurrentInput().getKind().getLanguage() != Language::Fortran
) {
272 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
273 clang::DiagnosticsEngine::Error
,
274 "Invalid input type - expecting a Fortran file");
275 ci
.getDiagnostics().Report(diagID
);
278 bool res
= runPrescan() && runParse() && runSemanticChecks() &&
279 generateRtTypeTables();
283 // Create a LoweringBridge
284 const common::IntrinsicTypeDefaultKinds
&defKinds
=
285 ci
.getSemanticsContext().defaultKinds();
286 fir::KindMapping
kindMap(mlirCtx
.get(), llvm::ArrayRef
<fir::KindTy
>{
287 fir::fromDefaultKinds(defKinds
)});
288 const llvm::DataLayout
&dl
= targetMachine
.createDataLayout();
290 lower::LoweringBridge lb
= Fortran::lower::LoweringBridge::create(
291 *mlirCtx
, ci
.getSemanticsContext(), defKinds
,
292 ci
.getSemanticsContext().intrinsics(),
293 ci
.getSemanticsContext().targetCharacteristics(),
294 ci
.getParsing().allCooked(), ci
.getInvocation().getTargetOpts().triple
,
295 kindMap
, ci
.getInvocation().getLoweringOpts(),
296 ci
.getInvocation().getFrontendOpts().envDefaults
,
297 ci
.getInvocation().getFrontendOpts().features
, &dl
);
299 // Fetch module from lb, so we can set
300 mlirModule
= std::make_unique
<mlir::ModuleOp
>(lb
.getModule());
302 if (ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
303 Fortran::common::LanguageFeature::OpenMP
)) {
304 setOffloadModuleInterfaceAttributes(*mlirModule
,
305 ci
.getInvocation().getLangOpts());
306 setOffloadModuleInterfaceTargetAttribute(
307 *mlirModule
, targetMachine
.getTargetCPU(),
308 targetMachine
.getTargetFeatureString());
309 setOpenMPVersionAttribute(*mlirModule
,
310 ci
.getInvocation().getLangOpts().OpenMPVersion
);
313 // Create a parse tree and lower it to FIR
314 Fortran::parser::Program
&parseTree
{*ci
.getParsing().parseTree()};
315 lb
.lower(parseTree
, ci
.getSemanticsContext());
317 // Add target specific items like dependent libraries, target specific
319 addDependentLibs(*mlirModule
, ci
);
320 addAMDGPUSpecificMLIRItems(*mlirModule
, ci
);
322 // run the default passes.
323 mlir::PassManager
pm((*mlirModule
)->getName(),
324 mlir::OpPassManager::Nesting::Implicit
);
325 // Add OpenMP-related passes
326 // WARNING: These passes must be run immediately after the lowering to ensure
327 // that the FIR is correct with respect to OpenMP operations/attributes.
328 if (ci
.getInvocation().getFrontendOpts().features
.IsEnabled(
329 Fortran::common::LanguageFeature::OpenMP
)) {
330 bool isDevice
= false;
331 if (auto offloadMod
= llvm::dyn_cast
<mlir::omp::OffloadModuleInterface
>(
332 mlirModule
->getOperation()))
333 isDevice
= offloadMod
.getIsTargetDevice();
334 // WARNING: This pipeline must be run immediately after the lowering to
335 // ensure that the FIR is correct with respect to OpenMP operations/
337 fir::createOpenMPFIRPassPipeline(pm
, isDevice
);
340 pm
.enableVerifier(/*verifyPasses=*/true);
341 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
343 if (mlir::failed(pm
.run(*mlirModule
))) {
344 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
345 clang::DiagnosticsEngine::Error
,
346 "verification of lowering to FIR failed");
347 ci
.getDiagnostics().Report(diagID
);
351 // Print initial full MLIR module, before lowering or transformations, if
352 // -save-temps has been specified.
353 if (!saveMLIRTempFile(ci
.getInvocation(), *mlirModule
, getCurrentFile(),
355 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
356 clang::DiagnosticsEngine::Error
, "Saving MLIR temp file failed");
357 ci
.getDiagnostics().Report(diagID
);
364 //===----------------------------------------------------------------------===//
365 // Custom ExecuteAction
366 //===----------------------------------------------------------------------===//
367 void InputOutputTestAction::executeAction() {
368 CompilerInstance
&ci
= getInstance();
370 // Create a stream for errors
372 llvm::raw_string_ostream errorStream
{buf
};
374 // Read the input file
375 Fortran::parser::AllSources
&allSources
{ci
.getAllSources()};
376 std::string path
{getCurrentFileOrBufferName()};
377 const Fortran::parser::SourceFile
*sf
;
379 sf
= allSources
.ReadStandardInput(errorStream
);
381 sf
= allSources
.Open(path
, errorStream
, std::optional
<std::string
>{"."s
});
382 llvm::ArrayRef
<char> fileContent
= sf
->content();
384 // Output file descriptor to receive the contents of the input file.
385 std::unique_ptr
<llvm::raw_ostream
> os
;
387 // Copy the contents from the input file to the output file
388 if (!ci
.isOutputStreamNull()) {
389 // An output stream (outputStream_) was set earlier
390 ci
.writeOutputStream(fileContent
.data());
392 // No pre-set output stream - create an output file
393 os
= ci
.createDefaultOutputFile(
394 /*binary=*/true, getCurrentFileOrBufferName(), "txt");
397 (*os
) << fileContent
.data();
401 void PrintPreprocessedAction::executeAction() {
403 llvm::raw_string_ostream outForPP
{buf
};
405 // Format or dump the prescanner's output
406 CompilerInstance
&ci
= this->getInstance();
407 if (ci
.getInvocation().getPreprocessorOpts().noReformat
) {
408 ci
.getParsing().DumpCookedChars(outForPP
);
410 ci
.getParsing().EmitPreprocessedSource(
411 outForPP
, !ci
.getInvocation().getPreprocessorOpts().noLineDirectives
);
414 // Print getDiagnostics from the prescanner
415 ci
.getParsing().messages().Emit(llvm::errs(), ci
.getAllCookedSources());
417 // If a pre-defined output stream exists, dump the preprocessed content there
418 if (!ci
.isOutputStreamNull()) {
419 // Send the output to the pre-defined output buffer.
420 ci
.writeOutputStream(outForPP
.str());
424 // Create a file and save the preprocessed output there
425 std::unique_ptr
<llvm::raw_pwrite_stream
> os
{ci
.createDefaultOutputFile(
426 /*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())};
431 (*os
) << outForPP
.str();
434 void DebugDumpProvenanceAction::executeAction() {
435 this->getInstance().getParsing().DumpProvenance(llvm::outs());
438 void ParseSyntaxOnlyAction::executeAction() {}
440 void DebugUnparseNoSemaAction::executeAction() {
441 auto &invoc
= this->getInstance().getInvocation();
442 auto &parseTree
{getInstance().getParsing().parseTree()};
444 // TODO: Options should come from CompilerInvocation
445 Unparse(llvm::outs(), *parseTree
,
446 /*encoding=*/Fortran::parser::Encoding::UTF_8
,
447 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
448 /*preStatement=*/nullptr,
449 invoc
.getUseAnalyzedObjectsForUnparse() ? &invoc
.getAsFortran()
453 void DebugUnparseAction::executeAction() {
454 auto &invoc
= this->getInstance().getInvocation();
455 auto &parseTree
{getInstance().getParsing().parseTree()};
457 CompilerInstance
&ci
= this->getInstance();
458 auto os
{ci
.createDefaultOutputFile(
459 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())};
461 // TODO: Options should come from CompilerInvocation
462 Unparse(*os
, *parseTree
,
463 /*encoding=*/Fortran::parser::Encoding::UTF_8
,
464 /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
465 /*preStatement=*/nullptr,
466 invoc
.getUseAnalyzedObjectsForUnparse() ? &invoc
.getAsFortran()
469 // Report fatal semantic errors
470 reportFatalSemanticErrors();
473 void DebugUnparseWithSymbolsAction::executeAction() {
474 auto &parseTree
{*getInstance().getParsing().parseTree()};
476 Fortran::semantics::UnparseWithSymbols(
477 llvm::outs(), parseTree
, /*encoding=*/Fortran::parser::Encoding::UTF_8
);
479 // Report fatal semantic errors
480 reportFatalSemanticErrors();
483 void DebugDumpSymbolsAction::executeAction() {
484 CompilerInstance
&ci
= this->getInstance();
486 if (!ci
.getRtTyTables().schemata
) {
487 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
488 clang::DiagnosticsEngine::Error
,
489 "could not find module file for __fortran_type_info");
490 ci
.getDiagnostics().Report(diagID
);
491 llvm::errs() << "\n";
496 ci
.getSemantics().DumpSymbols(llvm::outs());
499 void DebugDumpAllAction::executeAction() {
500 CompilerInstance
&ci
= this->getInstance();
503 auto &parseTree
{getInstance().getParsing().parseTree()};
504 llvm::outs() << "========================";
505 llvm::outs() << " Flang: parse tree dump ";
506 llvm::outs() << "========================\n";
507 Fortran::parser::DumpTree(llvm::outs(), parseTree
,
508 &ci
.getInvocation().getAsFortran());
510 if (!ci
.getRtTyTables().schemata
) {
511 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
512 clang::DiagnosticsEngine::Error
,
513 "could not find module file for __fortran_type_info");
514 ci
.getDiagnostics().Report(diagID
);
515 llvm::errs() << "\n";
520 llvm::outs() << "=====================";
521 llvm::outs() << " Flang: symbols dump ";
522 llvm::outs() << "=====================\n";
523 ci
.getSemantics().DumpSymbols(llvm::outs());
526 void DebugDumpParseTreeNoSemaAction::executeAction() {
527 auto &parseTree
{getInstance().getParsing().parseTree()};
530 Fortran::parser::DumpTree(
531 llvm::outs(), parseTree
,
532 &this->getInstance().getInvocation().getAsFortran());
535 void DebugDumpParseTreeAction::executeAction() {
536 auto &parseTree
{getInstance().getParsing().parseTree()};
539 Fortran::parser::DumpTree(
540 llvm::outs(), parseTree
,
541 &this->getInstance().getInvocation().getAsFortran());
543 // Report fatal semantic errors
544 reportFatalSemanticErrors();
547 void DebugMeasureParseTreeAction::executeAction() {
548 CompilerInstance
&ci
= this->getInstance();
550 // Parse. In case of failure, report and return.
551 ci
.getParsing().Parse(llvm::outs());
553 if (!ci
.getParsing().messages().empty() &&
554 (ci
.getInvocation().getWarnAsErr() ||
555 ci
.getParsing().messages().AnyFatalError())) {
556 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
557 clang::DiagnosticsEngine::Error
, "Could not parse %0");
558 ci
.getDiagnostics().Report(diagID
) << getCurrentFileOrBufferName();
560 ci
.getParsing().messages().Emit(llvm::errs(),
561 this->getInstance().getAllCookedSources());
565 // Report the getDiagnostics from parsing
566 ci
.getParsing().messages().Emit(llvm::errs(), ci
.getAllCookedSources());
568 auto &parseTree
{*ci
.getParsing().parseTree()};
570 // Measure the parse tree
571 MeasurementVisitor visitor
;
572 Fortran::parser::Walk(parseTree
, visitor
);
573 llvm::outs() << "Parse tree comprises " << visitor
.objects
574 << " objects and occupies " << visitor
.bytes
575 << " total bytes.\n";
578 void DebugPreFIRTreeAction::executeAction() {
579 CompilerInstance
&ci
= this->getInstance();
580 // Report and exit if fatal semantic errors are present
581 if (reportFatalSemanticErrors()) {
585 auto &parseTree
{*ci
.getParsing().parseTree()};
589 Fortran::lower::createPFT(parseTree
, ci
.getSemanticsContext())}) {
590 Fortran::lower::dumpPFT(llvm::outs(), *ast
);
592 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
593 clang::DiagnosticsEngine::Error
, "Pre FIR Tree is NULL.");
594 ci
.getDiagnostics().Report(diagID
);
598 void DebugDumpParsingLogAction::executeAction() {
599 CompilerInstance
&ci
= this->getInstance();
601 ci
.getParsing().Parse(llvm::errs());
602 ci
.getParsing().DumpParsingLog(llvm::outs());
605 void GetDefinitionAction::executeAction() {
606 CompilerInstance
&ci
= this->getInstance();
608 // Report and exit if fatal semantic errors are present
609 if (reportFatalSemanticErrors()) {
613 parser::AllCookedSources
&cs
= ci
.getAllCookedSources();
614 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
615 clang::DiagnosticsEngine::Error
, "Symbol not found");
617 auto gdv
= ci
.getInvocation().getFrontendOpts().getDefVals
;
618 auto charBlock
{cs
.GetCharBlockFromLineAndColumns(gdv
.line
, gdv
.startColumn
,
621 ci
.getDiagnostics().Report(diagID
);
625 llvm::outs() << "String range: >" << charBlock
->ToString() << "<\n";
628 ci
.getSemanticsContext().FindScope(*charBlock
).FindSymbol(*charBlock
)};
630 ci
.getDiagnostics().Report(diagID
);
634 llvm::outs() << "Found symbol name: " << symbol
->name().ToString() << "\n";
636 auto sourceInfo
{cs
.GetSourcePositionRange(symbol
->name())};
639 "Failed to obtain SourcePosition."
640 "TODO: Please, write a test and replace this with a diagnostic!");
644 llvm::outs() << "Found symbol name: " << symbol
->name().ToString() << "\n";
645 llvm::outs() << symbol
->name().ToString() << ": " << sourceInfo
->first
.path
646 << ", " << sourceInfo
->first
.line
<< ", "
647 << sourceInfo
->first
.column
<< "-" << sourceInfo
->second
.column
651 void GetSymbolsSourcesAction::executeAction() {
652 CompilerInstance
&ci
= this->getInstance();
654 // Report and exit if fatal semantic errors are present
655 if (reportFatalSemanticErrors()) {
659 ci
.getSemantics().DumpSymbolsSources(llvm::outs());
662 //===----------------------------------------------------------------------===//
664 //===----------------------------------------------------------------------===//
666 CodeGenAction::~CodeGenAction() = default;
668 static llvm::OptimizationLevel
669 mapToLevel(const Fortran::frontend::CodeGenOptions
&opts
) {
670 switch (opts
.OptimizationLevel
) {
672 llvm_unreachable("Invalid optimization level!");
674 return llvm::OptimizationLevel::O0
;
676 return llvm::OptimizationLevel::O1
;
678 return llvm::OptimizationLevel::O2
;
680 return llvm::OptimizationLevel::O3
;
684 // Lower using HLFIR then run the FIR to HLFIR pipeline
685 void CodeGenAction::lowerHLFIRToFIR() {
686 assert(mlirModule
&& "The MLIR module has not been generated yet.");
688 CompilerInstance
&ci
= this->getInstance();
689 auto opts
= ci
.getInvocation().getCodeGenOpts();
690 llvm::OptimizationLevel level
= mapToLevel(opts
);
692 fir::support::loadDialects(*mlirCtx
);
694 // Set-up the MLIR pass manager
695 mlir::PassManager
pm((*mlirModule
)->getName(),
696 mlir::OpPassManager::Nesting::Implicit
);
698 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
699 pm
.enableVerifier(/*verifyPasses=*/true);
701 // Create the pass pipeline
702 fir::createHLFIRToFIRPassPipeline(pm
, level
);
703 (void)mlir::applyPassManagerCLOptions(pm
);
705 if (!mlir::succeeded(pm
.run(*mlirModule
))) {
706 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
707 clang::DiagnosticsEngine::Error
, "Lowering to FIR failed");
708 ci
.getDiagnostics().Report(diagID
);
712 static std::optional
<std::pair
<unsigned, unsigned>>
713 getAArch64VScaleRange(CompilerInstance
&ci
) {
714 const auto &langOpts
= ci
.getInvocation().getLangOpts();
716 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
)
717 return std::pair
<unsigned, unsigned>(
718 langOpts
.VScaleMin
? langOpts
.VScaleMin
: 1, langOpts
.VScaleMax
);
720 std::string featuresStr
= ci
.getTargetFeatures();
721 if (featuresStr
.find("+sve") != std::string::npos
)
722 return std::pair
<unsigned, unsigned>(1, 16);
727 static std::optional
<std::pair
<unsigned, unsigned>>
728 getRISCVVScaleRange(CompilerInstance
&ci
) {
729 const auto &langOpts
= ci
.getInvocation().getLangOpts();
730 const auto targetOpts
= ci
.getInvocation().getTargetOpts();
731 const llvm::Triple
triple(targetOpts
.triple
);
733 auto parseResult
= llvm::RISCVISAInfo::parseFeatures(
734 triple
.isRISCV64() ? 64 : 32, targetOpts
.featuresAsWritten
);
737 llvm::raw_string_ostream
outputErrMsg(buffer
);
738 handleAllErrors(parseResult
.takeError(), [&](llvm::StringError
&errMsg
) {
739 outputErrMsg
<< errMsg
.getMessage();
741 ci
.getDiagnostics().Report(clang::diag::err_invalid_feature_combination
)
742 << outputErrMsg
.str();
746 llvm::RISCVISAInfo
*const isaInfo
= parseResult
->get();
748 // RISCV::RVVBitsPerBlock is 64.
749 unsigned vscaleMin
= isaInfo
->getMinVLen() / llvm::RISCV::RVVBitsPerBlock
;
751 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
) {
752 // Treat Zvl*b as a lower bound on vscale.
753 vscaleMin
= std::max(vscaleMin
, langOpts
.VScaleMin
);
754 unsigned vscaleMax
= langOpts
.VScaleMax
;
755 if (vscaleMax
!= 0 && vscaleMax
< vscaleMin
)
756 vscaleMax
= vscaleMin
;
757 return std::pair
<unsigned, unsigned>(vscaleMin
? vscaleMin
: 1, vscaleMax
);
761 unsigned vscaleMax
= isaInfo
->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock
;
762 return std::make_pair(vscaleMin
, vscaleMax
);
768 // TODO: We should get this from TargetInfo. However, that depends on
769 // too much of clang, so for now, replicate the functionality.
770 static std::optional
<std::pair
<unsigned, unsigned>>
771 getVScaleRange(CompilerInstance
&ci
) {
772 const auto &langOpts
= ci
.getInvocation().getLangOpts();
773 const llvm::Triple
triple(ci
.getInvocation().getTargetOpts().triple
);
775 if (triple
.isAArch64())
776 return getAArch64VScaleRange(ci
);
777 if (triple
.isRISCV())
778 return getRISCVVScaleRange(ci
);
780 if (langOpts
.VScaleMin
|| langOpts
.VScaleMax
)
781 return std::pair
<unsigned, unsigned>(
782 langOpts
.VScaleMin
? langOpts
.VScaleMin
: 1, langOpts
.VScaleMax
);
787 // Lower the previously generated MLIR module into an LLVM IR module
788 void CodeGenAction::generateLLVMIR() {
789 assert(mlirModule
&& "The MLIR module has not been generated yet.");
791 CompilerInstance
&ci
= this->getInstance();
792 auto opts
= ci
.getInvocation().getCodeGenOpts();
793 llvm::OptimizationLevel level
= mapToLevel(opts
);
795 fir::support::loadDialects(*mlirCtx
);
796 fir::support::registerLLVMTranslation(*mlirCtx
);
798 // Set-up the MLIR pass manager
799 mlir::PassManager
pm((*mlirModule
)->getName(),
800 mlir::OpPassManager::Nesting::Implicit
);
802 pm
.addPass(std::make_unique
<Fortran::lower::VerifierPass
>());
803 pm
.enableVerifier(/*verifyPasses=*/true);
805 MLIRToLLVMPassPipelineConfig
config(level
, opts
);
807 if (auto vsr
= getVScaleRange(ci
)) {
808 config
.VScaleMin
= vsr
->first
;
809 config
.VScaleMax
= vsr
->second
;
812 // Create the pass pipeline
813 fir::createMLIRToLLVMPassPipeline(pm
, config
);
814 (void)mlir::applyPassManagerCLOptions(pm
);
816 // run the pass manager
817 if (!mlir::succeeded(pm
.run(*mlirModule
))) {
818 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
819 clang::DiagnosticsEngine::Error
, "Lowering to LLVM IR failed");
820 ci
.getDiagnostics().Report(diagID
);
823 // Print final MLIR module, just before translation into LLVM IR, if
824 // -save-temps has been specified.
825 if (!saveMLIRTempFile(ci
.getInvocation(), *mlirModule
, getCurrentFile(),
827 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
828 clang::DiagnosticsEngine::Error
, "Saving MLIR temp file failed");
829 ci
.getDiagnostics().Report(diagID
);
833 // Translate to LLVM IR
834 std::optional
<llvm::StringRef
> moduleName
= mlirModule
->getName();
835 llvmModule
= mlir::translateModuleToLLVMIR(
836 *mlirModule
, *llvmCtx
, moduleName
? *moduleName
: "FIRModule");
839 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
840 clang::DiagnosticsEngine::Error
, "failed to create the LLVM module");
841 ci
.getDiagnostics().Report(diagID
);
845 // Set PIC/PIE level LLVM module flags.
846 if (opts
.PICLevel
> 0) {
847 llvmModule
->setPICLevel(static_cast<llvm::PICLevel::Level
>(opts
.PICLevel
));
849 llvmModule
->setPIELevel(
850 static_cast<llvm::PIELevel::Level
>(opts
.PICLevel
));
854 static std::unique_ptr
<llvm::raw_pwrite_stream
>
855 getOutputStream(CompilerInstance
&ci
, llvm::StringRef inFile
,
856 BackendActionTy action
) {
858 case BackendActionTy::Backend_EmitAssembly
:
859 return ci
.createDefaultOutputFile(
860 /*Binary=*/false, inFile
, /*extension=*/"s");
861 case BackendActionTy::Backend_EmitLL
:
862 return ci
.createDefaultOutputFile(
863 /*Binary=*/false, inFile
, /*extension=*/"ll");
864 case BackendActionTy::Backend_EmitFIR
:
866 case BackendActionTy::Backend_EmitHLFIR
:
867 return ci
.createDefaultOutputFile(
868 /*Binary=*/false, inFile
, /*extension=*/"mlir");
869 case BackendActionTy::Backend_EmitBC
:
870 return ci
.createDefaultOutputFile(
871 /*Binary=*/true, inFile
, /*extension=*/"bc");
872 case BackendActionTy::Backend_EmitObj
:
873 return ci
.createDefaultOutputFile(
874 /*Binary=*/true, inFile
, /*extension=*/"o");
877 llvm_unreachable("Invalid action!");
880 /// Generate target-specific machine-code or assembly file from the input LLVM
883 /// \param [in] diags Diagnostics engine for reporting errors
884 /// \param [in] tm Target machine to aid the code-gen pipeline set-up
885 /// \param [in] act Backend act to run (assembly vs machine-code generation)
886 /// \param [in] llvmModule LLVM module to lower to assembly/machine-code
887 /// \param [in] codeGenOpts options configuring codegen pipeline
888 /// \param [out] os Output stream to emit the generated code to
889 static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine
&diags
,
890 llvm::TargetMachine
&tm
,
892 llvm::Module
&llvmModule
,
893 const CodeGenOptions
&codeGenOpts
,
894 llvm::raw_pwrite_stream
&os
) {
895 assert(((act
== BackendActionTy::Backend_EmitObj
) ||
896 (act
== BackendActionTy::Backend_EmitAssembly
)) &&
897 "Unsupported action");
899 // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline.
900 // Currently only the legacy pass manager is supported.
901 // TODO: Switch to the new PM once it's available in the backend.
902 llvm::legacy::PassManager codeGenPasses
;
904 createTargetTransformInfoWrapperPass(tm
.getTargetIRAnalysis()));
906 llvm::Triple
triple(llvmModule
.getTargetTriple());
907 llvm::TargetLibraryInfoImpl
*tlii
=
908 llvm::driver::createTLII(triple
, codeGenOpts
.getVecLib());
909 codeGenPasses
.add(new llvm::TargetLibraryInfoWrapperPass(*tlii
));
911 llvm::CodeGenFileType cgft
= (act
== BackendActionTy::Backend_EmitAssembly
)
912 ? llvm::CodeGenFileType::AssemblyFile
913 : llvm::CodeGenFileType::ObjectFile
;
914 if (tm
.addPassesToEmitFile(codeGenPasses
, os
, nullptr, cgft
)) {
916 diags
.getCustomDiagID(clang::DiagnosticsEngine::Error
,
917 "emission of this file type is not supported");
918 diags
.Report(diagID
);
923 codeGenPasses
.run(llvmModule
);
926 void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream
&os
) {
927 auto opts
= getInstance().getInvocation().getCodeGenOpts();
928 auto &diags
= getInstance().getDiagnostics();
929 llvm::OptimizationLevel level
= mapToLevel(opts
);
931 llvm::TargetMachine
*targetMachine
= &getInstance().getTargetMachine();
932 // Create the analysis managers.
933 llvm::LoopAnalysisManager lam
;
934 llvm::FunctionAnalysisManager fam
;
935 llvm::CGSCCAnalysisManager cgam
;
936 llvm::ModuleAnalysisManager mam
;
938 // Create the pass manager builder.
939 llvm::PassInstrumentationCallbacks pic
;
940 llvm::PipelineTuningOptions pto
;
941 std::optional
<llvm::PGOOptions
> pgoOpt
;
942 llvm::StandardInstrumentations
si(llvmModule
->getContext(),
943 opts
.DebugPassManager
);
944 si
.registerCallbacks(pic
, &mam
);
945 llvm::PassBuilder
pb(targetMachine
, pto
, pgoOpt
, &pic
);
947 // Attempt to load pass plugins and register their callbacks with PB.
948 for (auto &pluginFile
: opts
.LLVMPassPlugins
) {
949 auto passPlugin
= llvm::PassPlugin::Load(pluginFile
);
951 passPlugin
->registerPassBuilderCallbacks(pb
);
953 diags
.Report(clang::diag::err_fe_unable_to_load_plugin
)
954 << pluginFile
<< passPlugin
.takeError();
957 // Register static plugin extensions.
958 #define HANDLE_EXTENSION(Ext) \
959 get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
960 #include "llvm/Support/Extension.def"
962 // Register the target library analysis directly and give it a customized
963 // preset TLI depending on -fveclib
964 llvm::Triple
triple(llvmModule
->getTargetTriple());
965 llvm::TargetLibraryInfoImpl
*tlii
=
966 llvm::driver::createTLII(triple
, opts
.getVecLib());
967 fam
.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii
); });
969 // Register all the basic analyses with the managers.
970 pb
.registerModuleAnalyses(mam
);
971 pb
.registerCGSCCAnalyses(cgam
);
972 pb
.registerFunctionAnalyses(fam
);
973 pb
.registerLoopAnalyses(lam
);
974 pb
.crossRegisterProxies(lam
, fam
, cgam
, mam
);
976 // Create the pass manager.
977 llvm::ModulePassManager mpm
;
978 if (opts
.PrepareForFullLTO
)
979 mpm
= pb
.buildLTOPreLinkDefaultPipeline(level
);
980 else if (opts
.PrepareForThinLTO
)
981 mpm
= pb
.buildThinLTOPreLinkDefaultPipeline(level
);
983 mpm
= pb
.buildPerModuleDefaultPipeline(level
);
985 if (action
== BackendActionTy::Backend_EmitBC
)
986 mpm
.addPass(llvm::BitcodeWriterPass(os
));
989 mpm
.run(*llvmModule
, mam
);
992 // This class handles optimization remark messages requested if
993 // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided
994 class BackendRemarkConsumer
: public llvm::DiagnosticHandler
{
996 const CodeGenOptions
&codeGenOpts
;
997 clang::DiagnosticsEngine
&diags
;
1000 BackendRemarkConsumer(clang::DiagnosticsEngine
&diags
,
1001 const CodeGenOptions
&codeGenOpts
)
1002 : codeGenOpts(codeGenOpts
), diags(diags
) {}
1004 bool isAnalysisRemarkEnabled(llvm::StringRef passName
) const override
{
1005 return codeGenOpts
.OptimizationRemarkAnalysis
.patternMatches(passName
);
1007 bool isMissedOptRemarkEnabled(llvm::StringRef passName
) const override
{
1008 return codeGenOpts
.OptimizationRemarkMissed
.patternMatches(passName
);
1010 bool isPassedOptRemarkEnabled(llvm::StringRef passName
) const override
{
1011 return codeGenOpts
.OptimizationRemark
.patternMatches(passName
);
1014 bool isAnyRemarkEnabled() const override
{
1015 return codeGenOpts
.OptimizationRemarkAnalysis
.hasValidPattern() ||
1016 codeGenOpts
.OptimizationRemarkMissed
.hasValidPattern() ||
1017 codeGenOpts
.OptimizationRemark
.hasValidPattern();
1021 emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase
&diagInfo
,
1023 // We only support warnings and remarks.
1024 assert(diagInfo
.getSeverity() == llvm::DS_Remark
||
1025 diagInfo
.getSeverity() == llvm::DS_Warning
);
1028 llvm::raw_string_ostream
msgStream(msg
);
1030 if (diagInfo
.isLocationAvailable()) {
1031 // Clang contains a SourceManager class which handles loading
1032 // and caching of source files into memory and it can be used to
1033 // query SourceLocation data. The SourceLocation data is what is
1034 // needed here as it contains the full include stack which gives
1035 // line and column number as well as file name and location.
1036 // Since Flang doesn't have SourceManager, send file name and absolute
1037 // path through msgStream, to use for printing.
1038 msgStream
<< diagInfo
.getLocationStr() << ";;"
1039 << diagInfo
.getAbsolutePath() << ";;";
1042 msgStream
<< diagInfo
.getMsg();
1045 diags
.Report(diagID
) << clang::AddFlagValue(diagInfo
.getPassName())
1049 void optimizationRemarkHandler(
1050 const llvm::DiagnosticInfoOptimizationBase
&diagInfo
) {
1051 auto passName
= diagInfo
.getPassName();
1052 if (diagInfo
.isPassed()) {
1053 if (codeGenOpts
.OptimizationRemark
.patternMatches(passName
))
1054 // Optimization remarks are active only if the -Rpass flag has a regular
1055 // expression that matches the name of the pass name in \p d.
1056 emitOptimizationMessage(
1057 diagInfo
, clang::diag::remark_fe_backend_optimization_remark
);
1062 if (diagInfo
.isMissed()) {
1063 if (codeGenOpts
.OptimizationRemarkMissed
.patternMatches(passName
))
1064 // Missed optimization remarks are active only if the -Rpass-missed
1065 // flag has a regular expression that matches the name of the pass
1067 emitOptimizationMessage(
1069 clang::diag::remark_fe_backend_optimization_remark_missed
);
1074 assert(diagInfo
.isAnalysis() && "Unknown remark type");
1076 bool shouldAlwaysPrint
= false;
1077 auto *ora
= llvm::dyn_cast
<llvm::OptimizationRemarkAnalysis
>(&diagInfo
);
1079 shouldAlwaysPrint
= ora
->shouldAlwaysPrint();
1081 if (shouldAlwaysPrint
||
1082 codeGenOpts
.OptimizationRemarkAnalysis
.patternMatches(passName
))
1083 emitOptimizationMessage(
1085 clang::diag::remark_fe_backend_optimization_remark_analysis
);
1088 bool handleDiagnostics(const llvm::DiagnosticInfo
&di
) override
{
1089 switch (di
.getKind()) {
1090 case llvm::DK_OptimizationRemark
:
1091 optimizationRemarkHandler(llvm::cast
<llvm::OptimizationRemark
>(di
));
1093 case llvm::DK_OptimizationRemarkMissed
:
1094 optimizationRemarkHandler(llvm::cast
<llvm::OptimizationRemarkMissed
>(di
));
1096 case llvm::DK_OptimizationRemarkAnalysis
:
1097 optimizationRemarkHandler(
1098 llvm::cast
<llvm::OptimizationRemarkAnalysis
>(di
));
1100 case llvm::DK_MachineOptimizationRemark
:
1101 optimizationRemarkHandler(
1102 llvm::cast
<llvm::MachineOptimizationRemark
>(di
));
1104 case llvm::DK_MachineOptimizationRemarkMissed
:
1105 optimizationRemarkHandler(
1106 llvm::cast
<llvm::MachineOptimizationRemarkMissed
>(di
));
1108 case llvm::DK_MachineOptimizationRemarkAnalysis
:
1109 optimizationRemarkHandler(
1110 llvm::cast
<llvm::MachineOptimizationRemarkAnalysis
>(di
));
1119 void CodeGenAction::embedOffloadObjects() {
1120 CompilerInstance
&ci
= this->getInstance();
1121 const auto &cgOpts
= ci
.getInvocation().getCodeGenOpts();
1123 for (llvm::StringRef offloadObject
: cgOpts
.OffloadObjects
) {
1124 llvm::ErrorOr
<std::unique_ptr
<llvm::MemoryBuffer
>> objectOrErr
=
1125 llvm::MemoryBuffer::getFileOrSTDIN(offloadObject
);
1126 if (std::error_code ec
= objectOrErr
.getError()) {
1127 auto diagID
= ci
.getDiagnostics().getCustomDiagID(
1128 clang::DiagnosticsEngine::Error
, "could not open '%0' for embedding");
1129 ci
.getDiagnostics().Report(diagID
) << offloadObject
;
1132 llvm::embedBufferInModule(
1133 *llvmModule
, **objectOrErr
, ".llvm.offloading",
1134 llvm::Align(llvm::object::OffloadBinary::getAlignment()));
1138 static void reportOptRecordError(llvm::Error e
, clang::DiagnosticsEngine
&diags
,
1139 const CodeGenOptions
&codeGenOpts
) {
1142 [&](const llvm::LLVMRemarkSetupFileError
&e
) {
1143 diags
.Report(clang::diag::err_cannot_open_file
)
1144 << codeGenOpts
.OptRecordFile
<< e
.message();
1146 [&](const llvm::LLVMRemarkSetupPatternError
&e
) {
1147 diags
.Report(clang::diag::err_drv_optimization_remark_pattern
)
1148 << e
.message() << codeGenOpts
.OptRecordPasses
;
1150 [&](const llvm::LLVMRemarkSetupFormatError
&e
) {
1151 diags
.Report(clang::diag::err_drv_optimization_remark_format
)
1152 << codeGenOpts
.OptRecordFormat
;
1156 void CodeGenAction::executeAction() {
1157 CompilerInstance
&ci
= this->getInstance();
1159 clang::DiagnosticsEngine
&diags
= ci
.getDiagnostics();
1160 const CodeGenOptions
&codeGenOpts
= ci
.getInvocation().getCodeGenOpts();
1161 Fortran::lower::LoweringOptions
&loweringOpts
=
1162 ci
.getInvocation().getLoweringOpts();
1164 // If the output stream is a file, generate it and define the corresponding
1165 // output stream. If a pre-defined output stream is available, we will use
1168 // NOTE: `os` is a smart pointer that will be destroyed at the end of this
1169 // method. However, it won't be written to until `codeGenPasses` is
1170 // destroyed. By defining `os` before `codeGenPasses`, we make sure that the
1171 // output stream won't be destroyed before it is written to. This only
1172 // applies when an output file is used (i.e. there is no pre-defined output
1174 // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is
1175 // updated to use it).
1176 std::unique_ptr
<llvm::raw_pwrite_stream
> os
;
1177 if (ci
.isOutputStreamNull()) {
1178 os
= getOutputStream(ci
, getCurrentFileOrBufferName(), action
);
1181 unsigned diagID
= diags
.getCustomDiagID(
1182 clang::DiagnosticsEngine::Error
, "failed to create the output file");
1183 diags
.Report(diagID
);
1188 if (action
== BackendActionTy::Backend_EmitFIR
) {
1189 if (loweringOpts
.getLowerToHighLevelFIR()) {
1192 mlirModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1196 if (action
== BackendActionTy::Backend_EmitHLFIR
) {
1197 assert(loweringOpts
.getLowerToHighLevelFIR() &&
1198 "Lowering must have been configured to emit HLFIR");
1199 mlirModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1203 // Generate an LLVM module if it's not already present (it will already be
1204 // present if the input file is an LLVM IR/BC file).
1208 // Set the triple based on the targetmachine (this comes compiler invocation
1209 // and the command-line target option if specified, or the default if not
1210 // given on the command-line).
1211 llvm::TargetMachine
&targetMachine
= ci
.getTargetMachine();
1212 const std::string
&theTriple
= targetMachine
.getTargetTriple().str();
1214 if (llvmModule
->getTargetTriple() != theTriple
) {
1215 diags
.Report(clang::diag::warn_fe_override_module
) << theTriple
;
1218 // Always set the triple and data layout, to make sure they match and are set.
1219 // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
1220 // an assert for incompatible data layout when the code-generation happens.
1221 llvmModule
->setTargetTriple(theTriple
);
1222 llvmModule
->setDataLayout(targetMachine
.createDataLayout());
1224 // Embed offload objects specified with -fembed-offload-object
1225 if (!codeGenOpts
.OffloadObjects
.empty())
1226 embedOffloadObjects();
1228 BackendRemarkConsumer
remarkConsumer(diags
, codeGenOpts
);
1230 llvmModule
->getContext().setDiagnosticHandler(
1231 std::make_unique
<BackendRemarkConsumer
>(remarkConsumer
));
1233 // write optimization-record
1234 llvm::Expected
<std::unique_ptr
<llvm::ToolOutputFile
>> optRecordFileOrErr
=
1235 setupLLVMOptimizationRemarks(
1236 llvmModule
->getContext(), codeGenOpts
.OptRecordFile
,
1237 codeGenOpts
.OptRecordPasses
, codeGenOpts
.OptRecordFormat
,
1238 /*DiagnosticsWithHotness=*/false,
1239 /*DiagnosticsHotnessThreshold=*/0);
1241 if (llvm::Error e
= optRecordFileOrErr
.takeError()) {
1242 reportOptRecordError(std::move(e
), diags
, codeGenOpts
);
1246 std::unique_ptr
<llvm::ToolOutputFile
> optRecordFile
=
1247 std::move(*optRecordFileOrErr
);
1249 if (optRecordFile
) {
1250 optRecordFile
->keep();
1251 optRecordFile
->os().flush();
1254 // Run LLVM's middle-end (i.e. the optimizer).
1255 runOptimizationPipeline(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1257 if (action
== BackendActionTy::Backend_EmitLL
) {
1258 llvmModule
->print(ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream(),
1259 /*AssemblyAnnotationWriter=*/nullptr);
1263 if (action
== BackendActionTy::Backend_EmitBC
) {
1264 // This action has effectively been completed in runOptimizationPipeline.
1268 // Run LLVM's backend and generate either assembly or machine code
1269 if (action
== BackendActionTy::Backend_EmitAssembly
||
1270 action
== BackendActionTy::Backend_EmitObj
) {
1271 generateMachineCodeOrAssemblyImpl(
1272 diags
, targetMachine
, action
, *llvmModule
, codeGenOpts
,
1273 ci
.isOutputStreamNull() ? *os
: ci
.getOutputStream());
1278 void InitOnlyAction::executeAction() {
1279 CompilerInstance
&ci
= this->getInstance();
1280 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
1281 clang::DiagnosticsEngine::Warning
,
1282 "Use `-init-only` for testing purposes only");
1283 ci
.getDiagnostics().Report(diagID
);
1286 void PluginParseTreeAction::executeAction() {}
1288 void DebugDumpPFTAction::executeAction() {
1289 CompilerInstance
&ci
= this->getInstance();
1291 if (auto ast
= Fortran::lower::createPFT(*ci
.getParsing().parseTree(),
1292 ci
.getSemantics().context())) {
1293 Fortran::lower::dumpPFT(llvm::outs(), *ast
);
1297 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
1298 clang::DiagnosticsEngine::Error
, "Pre FIR Tree is NULL.");
1299 ci
.getDiagnostics().Report(diagID
);
1302 Fortran::parser::Parsing
&PluginParseTreeAction::getParsing() {
1303 return getInstance().getParsing();
1306 std::unique_ptr
<llvm::raw_pwrite_stream
>
1307 PluginParseTreeAction::createOutputFile(llvm::StringRef extension
= "") {
1309 std::unique_ptr
<llvm::raw_pwrite_stream
> os
{
1310 getInstance().createDefaultOutputFile(
1311 /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(),