xref: /llvm-project/flang/lib/Frontend/FrontendActions.cpp (revision 0195ec452e16a0ff4b4f4ff2e2ea5a1dd5a20563)
14c5906cfSCaroline Concatto //===--- FrontendActions.cpp ----------------------------------------------===//
24c5906cfSCaroline Concatto //
34c5906cfSCaroline Concatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44c5906cfSCaroline Concatto // See https://llvm.org/LICENSE.txt for license information.
54c5906cfSCaroline Concatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64c5906cfSCaroline Concatto //
74c5906cfSCaroline Concatto //===----------------------------------------------------------------------===//
81e462fafSAndrzej Warzynski //
91e462fafSAndrzej Warzynski // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
101e462fafSAndrzej Warzynski //
111e462fafSAndrzej Warzynski //===----------------------------------------------------------------------===//
12d28de0d7SCaroline Concatto 
134c5906cfSCaroline Concatto #include "flang/Frontend/FrontendActions.h"
147d246cb1SAndrzej Warzynski #include "flang/Common/default-kinds.h"
154c5906cfSCaroline Concatto #include "flang/Frontend/CompilerInstance.h"
1633be8341SSergio Afonso #include "flang/Frontend/CompilerInvocation.h"
1796d229c9SAndrzej Warzynski #include "flang/Frontend/FrontendOptions.h"
18b83a4450SAndrzej Warzynski #include "flang/Frontend/PreprocessorOptions.h"
1969c3309dSAndrzej Warzynski #include "flang/Lower/Bridge.h"
20529f7181SFaris Rehman #include "flang/Lower/PFTBuilder.h"
2169c3309dSAndrzej Warzynski #include "flang/Lower/Support/Verifier.h"
22b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/FIRContext.h"
23b07ef9e7SRenaud-K #include "flang/Optimizer/Dialect/Support/KindMapping.h"
24c3201ddaSTarun Prabhu #include "flang/Optimizer/Passes/Pipelines.h"
25e59e8488SjeanPerier #include "flang/Optimizer/Support/DataLayout.h"
2669c3309dSAndrzej Warzynski #include "flang/Optimizer/Support/InitFIR.h"
2769c3309dSAndrzej Warzynski #include "flang/Optimizer/Support/Utils.h"
2845a96044SJan Sjodin #include "flang/Optimizer/Transforms/Passes.h"
294bd08dabSFaris Rehman #include "flang/Parser/dump-parse-tree.h"
30d28de0d7SCaroline Concatto #include "flang/Parser/parsing.h"
31d28de0d7SCaroline Concatto #include "flang/Parser/provenance.h"
324c5906cfSCaroline Concatto #include "flang/Parser/source.h"
3396d229c9SAndrzej Warzynski #include "flang/Parser/unparse.h"
34eefda605SAndrzej Warzynski #include "flang/Semantics/runtime-type-info.h"
357d246cb1SAndrzej Warzynski #include "flang/Semantics/semantics.h"
3696d229c9SAndrzej Warzynski #include "flang/Semantics/unparse-with-symbols.h"
37132feb7cSAndrew Gozillon #include "flang/Tools/CrossToolHelpers.h"
3869c3309dSAndrzej Warzynski 
3969c3309dSAndrzej Warzynski #include "mlir/IR/Dialect.h"
40cc3c6b61SAndrzej Warzynski #include "mlir/Parser/Parser.h"
4169c3309dSAndrzej Warzynski #include "mlir/Pass/PassManager.h"
4281181089SMats Petersson #include "mlir/Support/LLVM.h"
4381181089SMats Petersson #include "mlir/Target/LLVMIR/Import.h"
44e993b20cSAndrzej Warzynski #include "mlir/Target/LLVMIR/ModuleTranslation.h"
451e462fafSAndrzej Warzynski #include "clang/Basic/Diagnostic.h"
4602fb5b77SAndrzej Warzynski #include "clang/Basic/DiagnosticFrontend.h"
47b75e7c61SJan Leyonberg #include "clang/Basic/FileManager.h"
48b75e7c61SJan Leyonberg #include "clang/Basic/FileSystemOptions.h"
49f04ccadfSVictor Kingi #include "clang/Driver/DriverDiagnostic.h"
5033be8341SSergio Afonso #include "llvm/ADT/SmallString.h"
514bd08dabSFaris Rehman #include "llvm/ADT/StringRef.h"
5238101b4eSAndrzej Warzynski #include "llvm/Analysis/TargetLibraryInfo.h"
5338101b4eSAndrzej Warzynski #include "llvm/Analysis/TargetTransformInfo.h"
54dd56939aSAndrzej Warzynski #include "llvm/Bitcode/BitcodeWriterPass.h"
55e87d2d2cSVictor Kingi #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
56f04ccadfSVictor Kingi #include "llvm/IR/LLVMRemarkStreamer.h"
5738101b4eSAndrzej Warzynski #include "llvm/IR/LegacyPassManager.h"
583e782ba2SAndrzej Warzynski #include "llvm/IR/Verifier.h"
599b468388SStephen Tozer #include "llvm/IRPrinter/IRPrintingPasses.h"
60bb177edcSAndrzej Warzynski #include "llvm/IRReader/IRReader.h"
61b75e7c61SJan Leyonberg #include "llvm/Linker/Linker.h"
6240d8c066SJan Sjodin #include "llvm/Object/OffloadBinary.h"
6338101b4eSAndrzej Warzynski #include "llvm/Passes/PassBuilder.h"
64c3821b8dSTarun Prabhu #include "llvm/Passes/PassPlugin.h"
65869385b1SAndrzej Warzynski #include "llvm/Passes/StandardInstrumentations.h"
66276a024bSDominik Adamski #include "llvm/Support/AMDGPUAddrSpace.h"
67f04ccadfSVictor Kingi #include "llvm/Support/Error.h"
68dc256a44SAndrzej Warzynski #include "llvm/Support/ErrorHandling.h"
6933be8341SSergio Afonso #include "llvm/Support/FileSystem.h"
7033be8341SSergio Afonso #include "llvm/Support/Path.h"
71bb177edcSAndrzej Warzynski #include "llvm/Support/SourceMgr.h"
7233be8341SSergio Afonso #include "llvm/Support/ToolOutputFile.h"
7338101b4eSAndrzej Warzynski #include "llvm/Target/TargetMachine.h"
74733a8778SCraig Topper #include "llvm/TargetParser/RISCVISAInfo.h"
75c4b591a1SLuke Lau #include "llvm/TargetParser/RISCVTargetParser.h"
76b75e7c61SJan Leyonberg #include "llvm/Transforms/IPO/Internalize.h"
7740d8c066SJan Sjodin #include "llvm/Transforms/Utils/ModuleUtils.h"
784bd08dabSFaris Rehman #include <memory>
7933be8341SSergio Afonso #include <system_error>
804c5906cfSCaroline Concatto 
81a1441ca7STarun Prabhu namespace llvm {
82a1441ca7STarun Prabhu extern cl::opt<bool> PrintPipelinePasses;
83a1441ca7STarun Prabhu } // namespace llvm
84a1441ca7STarun Prabhu 
854c5906cfSCaroline Concatto using namespace Fortran::frontend;
864c5906cfSCaroline Concatto 
87310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdParse = "Parse";
88310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdMLIRGen = "MLIR generation";
89310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdMLIRPasses =
90310c281bSmacurtis-amd     "MLIR translation/optimization";
91310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdLLVMIRGen = "LLVM IR generation";
92310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdLLVMIRPasses = "LLVM IR optimizations";
93310c281bSmacurtis-amd constexpr llvm::StringLiteral timingIdBackend =
94310c281bSmacurtis-amd     "Assembly/Object code generation";
95310c281bSmacurtis-amd 
96d34dce25SUsman Nadeem // Declare plugin extension function declarations.
97d34dce25SUsman Nadeem #define HANDLE_EXTENSION(Ext)                                                  \
98d34dce25SUsman Nadeem   llvm::PassPluginLibraryInfo get##Ext##PluginInfo();
99d34dce25SUsman Nadeem #include "llvm/Support/Extension.def"
100d34dce25SUsman Nadeem 
10133be8341SSergio Afonso /// Save the given \c mlirModule to a temporary .mlir file, in a location
10233be8341SSergio Afonso /// decided by the -save-temps flag. No files are produced if the flag is not
10333be8341SSergio Afonso /// specified.
10433be8341SSergio Afonso static bool saveMLIRTempFile(const CompilerInvocation &ci,
10533be8341SSergio Afonso                              mlir::ModuleOp mlirModule,
10633be8341SSergio Afonso                              llvm::StringRef inputFile,
10733be8341SSergio Afonso                              llvm::StringRef outputTag) {
10833be8341SSergio Afonso   if (!ci.getCodeGenOpts().SaveTempsDir.has_value())
10933be8341SSergio Afonso     return true;
11033be8341SSergio Afonso 
11133be8341SSergio Afonso   const llvm::StringRef compilerOutFile = ci.getFrontendOpts().outputFile;
11233be8341SSergio Afonso   const llvm::StringRef saveTempsDir = ci.getCodeGenOpts().SaveTempsDir.value();
11333be8341SSergio Afonso   auto dir = llvm::StringSwitch<llvm::StringRef>(saveTempsDir)
11433be8341SSergio Afonso                  .Case("cwd", "")
11533be8341SSergio Afonso                  .Case("obj", llvm::sys::path::parent_path(compilerOutFile))
11633be8341SSergio Afonso                  .Default(saveTempsDir);
11733be8341SSergio Afonso 
11833be8341SSergio Afonso   // Build path from the compiler output file name, triple, cpu and OpenMP
11933be8341SSergio Afonso   // information
12033be8341SSergio Afonso   llvm::SmallString<256> path(dir);
12133be8341SSergio Afonso   llvm::sys::path::append(path, llvm::sys::path::stem(inputFile) + "-" +
12233be8341SSergio Afonso                                     outputTag + ".mlir");
12333be8341SSergio Afonso 
12433be8341SSergio Afonso   std::error_code ec;
12533be8341SSergio Afonso   llvm::ToolOutputFile out(path, ec, llvm::sys::fs::OF_Text);
12633be8341SSergio Afonso   if (ec)
12733be8341SSergio Afonso     return false;
12833be8341SSergio Afonso 
12933be8341SSergio Afonso   mlirModule->print(out.os());
13033be8341SSergio Afonso   out.os().close();
13133be8341SSergio Afonso   out.keep();
13233be8341SSergio Afonso 
13333be8341SSergio Afonso   return true;
13433be8341SSergio Afonso }
13533be8341SSergio Afonso 
1364f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===//
1374f21e6aeSAndrzej Warzynski // Custom BeginSourceFileAction
1384f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===//
139bb177edcSAndrzej Warzynski 
1401e462fafSAndrzej Warzynski bool PrescanAction::beginSourceFileAction() { return runPrescan(); }
1414f21e6aeSAndrzej Warzynski 
1421e462fafSAndrzej Warzynski bool PrescanAndParseAction::beginSourceFileAction() {
143f2e80893SPeter Klausler   return runPrescan() && runParse(/*emitMessages=*/true);
1444bd08dabSFaris Rehman }
1454bd08dabSFaris Rehman 
1461e462fafSAndrzej Warzynski bool PrescanAndSemaAction::beginSourceFileAction() {
147f2e80893SPeter Klausler   return runPrescan() && runParse(/*emitMessages=*/false) &&
148f2e80893SPeter Klausler          runSemanticChecks() && generateRtTypeTables();
149dfce2909SAsher Mancinelli }
150dfce2909SAsher Mancinelli 
1511e462fafSAndrzej Warzynski bool PrescanAndSemaDebugAction::beginSourceFileAction() {
15216a91a1cSAndrzej Warzynski   // This is a "debug" action for development purposes. To facilitate this, the
15316a91a1cSAndrzej Warzynski   // semantic checks are made to succeed unconditionally to prevent this action
15416a91a1cSAndrzej Warzynski   // from exiting early (i.e. in the presence of semantic errors). We should
15516a91a1cSAndrzej Warzynski   // never do this in actions intended for end-users or otherwise regular
15616a91a1cSAndrzej Warzynski   // compiler workflows!
157f2e80893SPeter Klausler   return runPrescan() && runParse(/*emitMessages=*/false) &&
158f2e80893SPeter Klausler          (runSemanticChecks() || true) && (generateRtTypeTables() || true);
1596f8ef1d6SAndrzej Warzynski }
1606f8ef1d6SAndrzej Warzynski 
161c870632eSMatthias Springer static void addDependentLibs(mlir::ModuleOp mlirModule, CompilerInstance &ci) {
16277ecb9a4SDavid Truby   const std::vector<std::string> &libs =
16377ecb9a4SDavid Truby       ci.getInvocation().getCodeGenOpts().DependentLibs;
16477ecb9a4SDavid Truby   if (libs.empty()) {
16577ecb9a4SDavid Truby     return;
16677ecb9a4SDavid Truby   }
16777ecb9a4SDavid Truby   // dependent-lib is currently only supported on Windows, so the list should be
16877ecb9a4SDavid Truby   // empty on non-Windows platforms
16977ecb9a4SDavid Truby   assert(
17077ecb9a4SDavid Truby       llvm::Triple(ci.getInvocation().getTargetOpts().triple).isOSWindows() &&
17177ecb9a4SDavid Truby       "--dependent-lib is only supported on Windows");
17277ecb9a4SDavid Truby   // Add linker options specified by --dependent-lib
17377ecb9a4SDavid Truby   auto builder = mlir::OpBuilder(mlirModule.getRegion());
17477ecb9a4SDavid Truby   for (const std::string &lib : libs) {
17577ecb9a4SDavid Truby     builder.create<mlir::LLVM::LinkerOptionsOp>(
1765e36c64cSDavid Truby         mlirModule.getLoc(), builder.getStrArrayAttr({"/DEFAULTLIB:" + lib}));
17777ecb9a4SDavid Truby   }
17877ecb9a4SDavid Truby }
17977ecb9a4SDavid Truby 
18095943d2fSDominik Adamski // Add to MLIR code target specific items which are dependent on target
18195943d2fSDominik Adamski // configuration specified by the user.
18295943d2fSDominik Adamski // Clang equivalent function: AMDGPUTargetCodeGenInfo::emitTargetGlobals
183c870632eSMatthias Springer static void addAMDGPUSpecificMLIRItems(mlir::ModuleOp mlirModule,
18495943d2fSDominik Adamski                                        CompilerInstance &ci) {
18595943d2fSDominik Adamski   const TargetOptions &targetOpts = ci.getInvocation().getTargetOpts();
18695943d2fSDominik Adamski   const llvm::Triple triple(targetOpts.triple);
18795943d2fSDominik Adamski   const llvm::StringRef codeObjectVersionGlobalOpName = "__oclc_ABI_version";
18895943d2fSDominik Adamski 
18995943d2fSDominik Adamski   if (!triple.isAMDGPU()) {
19095943d2fSDominik Adamski     return;
19195943d2fSDominik Adamski   }
19295943d2fSDominik Adamski   const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts();
19395943d2fSDominik Adamski   if (codeGenOpts.CodeObjectVersion == llvm::CodeObjectVersionKind::COV_None) {
19495943d2fSDominik Adamski     return;
19595943d2fSDominik Adamski   }
19695943d2fSDominik Adamski 
197a622b21fSMatthias Springer   mlir::IRRewriter builder(mlirModule.getContext());
19895943d2fSDominik Adamski   unsigned oclcABIVERsion = codeGenOpts.CodeObjectVersion;
19995943d2fSDominik Adamski   auto int32Type = builder.getI32Type();
20095943d2fSDominik Adamski 
20195943d2fSDominik Adamski   std::optional<mlir::LLVM::GlobalOp> originalGV;
20295943d2fSDominik Adamski 
20395943d2fSDominik Adamski   mlirModule.walk([&originalGV, codeObjectVersionGlobalOpName](
20495943d2fSDominik Adamski                       mlir::LLVM::GlobalOp globalOp) {
20595943d2fSDominik Adamski     if (globalOp.getName() == codeObjectVersionGlobalOpName)
20695943d2fSDominik Adamski       originalGV = globalOp;
20795943d2fSDominik Adamski   });
20895943d2fSDominik Adamski   if (originalGV.has_value()) {
20995943d2fSDominik Adamski     mlir::LLVM::GlobalOp originalGVOp = originalGV.value();
21095943d2fSDominik Adamski     if (originalGVOp.getLinkage() != mlir::LLVM::Linkage::External) {
21195943d2fSDominik Adamski       return;
21295943d2fSDominik Adamski     }
21395943d2fSDominik Adamski     // Update the variable if it is already present in MLIR but it was marked
21495943d2fSDominik Adamski     // as external linkage variable
21595943d2fSDominik Adamski     originalGVOp.setLinkage(mlir::LLVM::Linkage::WeakODR);
21695943d2fSDominik Adamski     originalGVOp.setValueAttr(
21795943d2fSDominik Adamski         builder.getIntegerAttr(int32Type, oclcABIVERsion));
21895943d2fSDominik Adamski     originalGVOp.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local);
219276a024bSDominik Adamski     originalGVOp.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS);
22095943d2fSDominik Adamski     originalGVOp.setVisibility_(mlir::LLVM::Visibility::Hidden);
22195943d2fSDominik Adamski     return;
22295943d2fSDominik Adamski   }
22395943d2fSDominik Adamski 
22495943d2fSDominik Adamski   mlir::LLVM::GlobalOp covInfo = builder.create<mlir::LLVM::GlobalOp>(
22595943d2fSDominik Adamski       /* Location */ mlirModule.getLoc(), /* Type */ int32Type,
22695943d2fSDominik Adamski       /* IsConstant */ true, /* Linkage */ mlir::LLVM::Linkage::WeakODR,
22795943d2fSDominik Adamski       /* Name */ codeObjectVersionGlobalOpName,
22895943d2fSDominik Adamski       /* Value */ builder.getIntegerAttr(int32Type, oclcABIVERsion));
22995943d2fSDominik Adamski   covInfo.setUnnamedAddr(mlir::LLVM::UnnamedAddr::Local);
230276a024bSDominik Adamski   covInfo.setAddrSpace(llvm::AMDGPUAS::CONSTANT_ADDRESS);
23195943d2fSDominik Adamski   covInfo.setVisibility_(mlir::LLVM::Visibility::Hidden);
23295943d2fSDominik Adamski   builder.setInsertionPointToStart(mlirModule.getBody());
23395943d2fSDominik Adamski   builder.insert(covInfo);
23495943d2fSDominik Adamski }
23595943d2fSDominik Adamski 
2361e462fafSAndrzej Warzynski bool CodeGenAction::beginSourceFileAction() {
237b9f3b7f8SAndrzej Warzynski   llvmCtx = std::make_unique<llvm::LLVMContext>();
2383e782ba2SAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
239310c281bSmacurtis-amd   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
240310c281bSmacurtis-amd   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
241310c281bSmacurtis-amd 
242310c281bSmacurtis-amd   // This will provide timing information even when the input is an LLVM IR or
243310c281bSmacurtis-amd   // MLIR file. That is fine because those do have to be parsed, so the label
244310c281bSmacurtis-amd   // is still accurate.
245310c281bSmacurtis-amd   mlir::TimingScope timingScopeParse = timingScopeRoot.nest(
246310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdParse, timingMgr));
247b9f3b7f8SAndrzej Warzynski 
248b9f3b7f8SAndrzej Warzynski   // If the input is an LLVM file, just parse it and return.
2491e462fafSAndrzej Warzynski   if (this->getCurrentInput().getKind().getLanguage() == Language::LLVM_IR) {
250b9f3b7f8SAndrzej Warzynski     llvm::SMDiagnostic err;
2511e462fafSAndrzej Warzynski     llvmModule = llvm::parseIRFile(getCurrentInput().getFile(), err, *llvmCtx);
2523e782ba2SAndrzej Warzynski     if (!llvmModule || llvm::verifyModule(*llvmModule, &llvm::errs())) {
25306eb10daSBrad Richardson       err.print("flang", llvm::errs());
2543e782ba2SAndrzej Warzynski       unsigned diagID = ci.getDiagnostics().getCustomDiagID(
2553e782ba2SAndrzej Warzynski           clang::DiagnosticsEngine::Error, "Could not parse IR");
2563e782ba2SAndrzej Warzynski       ci.getDiagnostics().Report(diagID);
2573e782ba2SAndrzej Warzynski       return false;
2583e782ba2SAndrzej Warzynski     }
259b9f3b7f8SAndrzej Warzynski 
2603e782ba2SAndrzej Warzynski     return true;
261b9f3b7f8SAndrzej Warzynski   }
262b9f3b7f8SAndrzej Warzynski 
263cc3c6b61SAndrzej Warzynski   // Load the MLIR dialects required by Flang
264cc3c6b61SAndrzej Warzynski   mlir::DialectRegistry registry;
265cc3c6b61SAndrzej Warzynski   mlirCtx = std::make_unique<mlir::MLIRContext>(registry);
266cc3c6b61SAndrzej Warzynski   fir::support::registerNonCodegenDialects(registry);
267cc3c6b61SAndrzej Warzynski   fir::support::loadNonCodegenDialects(*mlirCtx);
268cc3c6b61SAndrzej Warzynski   fir::support::loadDialects(*mlirCtx);
269cc3c6b61SAndrzej Warzynski   fir::support::registerLLVMTranslation(*mlirCtx);
270cc3c6b61SAndrzej Warzynski 
271e59e8488SjeanPerier   const llvm::TargetMachine &targetMachine = ci.getTargetMachine();
272e59e8488SjeanPerier 
273cc3c6b61SAndrzej Warzynski   // If the input is an MLIR file, just parse it and return.
274cc3c6b61SAndrzej Warzynski   if (this->getCurrentInput().getKind().getLanguage() == Language::MLIR) {
275cc3c6b61SAndrzej Warzynski     llvm::SourceMgr sourceMgr;
276cc3c6b61SAndrzej Warzynski     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
277cc3c6b61SAndrzej Warzynski         llvm::MemoryBuffer::getFileOrSTDIN(getCurrentInput().getFile());
278cc3c6b61SAndrzej Warzynski     sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), llvm::SMLoc());
279cc3c6b61SAndrzej Warzynski     mlir::OwningOpRef<mlir::ModuleOp> module =
280cc3c6b61SAndrzej Warzynski         mlir::parseSourceFile<mlir::ModuleOp>(sourceMgr, mlirCtx.get());
281cc3c6b61SAndrzej Warzynski 
282cc3c6b61SAndrzej Warzynski     if (!module || mlir::failed(module->verifyInvariants())) {
283cc3c6b61SAndrzej Warzynski       unsigned diagID = ci.getDiagnostics().getCustomDiagID(
284cc3c6b61SAndrzej Warzynski           clang::DiagnosticsEngine::Error, "Could not parse FIR");
285cc3c6b61SAndrzej Warzynski       ci.getDiagnostics().Report(diagID);
286cc3c6b61SAndrzej Warzynski       return false;
287cc3c6b61SAndrzej Warzynski     }
288cc3c6b61SAndrzej Warzynski 
289c870632eSMatthias Springer     mlirModule = std::move(module);
290e59e8488SjeanPerier     const llvm::DataLayout &dl = targetMachine.createDataLayout();
291e59e8488SjeanPerier     fir::support::setMLIRDataLayout(*mlirModule, dl);
292cc3c6b61SAndrzej Warzynski     return true;
293cc3c6b61SAndrzej Warzynski   }
294cc3c6b61SAndrzej Warzynski 
295b9f3b7f8SAndrzej Warzynski   // Otherwise, generate an MLIR module from the input Fortran source
2963e782ba2SAndrzej Warzynski   if (getCurrentInput().getKind().getLanguage() != Language::Fortran) {
2973e782ba2SAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
2983e782ba2SAndrzej Warzynski         clang::DiagnosticsEngine::Error,
299b9f3b7f8SAndrzej Warzynski         "Invalid input type - expecting a Fortran file");
3003e782ba2SAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
3013e782ba2SAndrzej Warzynski     return false;
3023e782ba2SAndrzej Warzynski   }
303f2e80893SPeter Klausler   bool res = runPrescan() && runParse(/*emitMessages=*/false) &&
304f2e80893SPeter Klausler              runSemanticChecks() && generateRtTypeTables();
30569c3309dSAndrzej Warzynski   if (!res)
30669c3309dSAndrzej Warzynski     return res;
30769c3309dSAndrzej Warzynski 
308310c281bSmacurtis-amd   timingScopeParse.stop();
309310c281bSmacurtis-amd   mlir::TimingScope timingScopeMLIRGen = timingScopeRoot.nest(
310310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdMLIRGen, timingMgr));
311310c281bSmacurtis-amd 
31269c3309dSAndrzej Warzynski   // Create a LoweringBridge
31369c3309dSAndrzej Warzynski   const common::IntrinsicTypeDefaultKinds &defKinds =
314ae4d7ac9SAndrzej Warzyński       ci.getSemanticsContext().defaultKinds();
3158fc00247SValentin Clement   fir::KindMapping kindMap(mlirCtx.get(), llvm::ArrayRef<fir::KindTy>{
3168fc00247SValentin Clement                                               fir::fromDefaultKinds(defKinds)});
3171e462fafSAndrzej Warzynski   lower::LoweringBridge lb = Fortran::lower::LoweringBridge::create(
318ae4d7ac9SAndrzej Warzyński       *mlirCtx, ci.getSemanticsContext(), defKinds,
319ae4d7ac9SAndrzej Warzyński       ci.getSemanticsContext().intrinsics(),
320ae4d7ac9SAndrzej Warzyński       ci.getSemanticsContext().targetCharacteristics(),
3211e462fafSAndrzej Warzynski       ci.getParsing().allCooked(), ci.getInvocation().getTargetOpts().triple,
3220ec3ac9bSJonathon Penix       kindMap, ci.getInvocation().getLoweringOpts(),
3231c91d9bdSPeter Klausler       ci.getInvocation().getFrontendOpts().envDefaults,
324f1d3fe7aSAlexis Perry-Holby       ci.getInvocation().getFrontendOpts().features, targetMachine,
325839344f0STarun Prabhu       ci.getInvocation().getTargetOpts(), ci.getInvocation().getCodeGenOpts());
32669c3309dSAndrzej Warzynski 
327e002a38bSAndrew Gozillon   if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
328e002a38bSAndrew Gozillon           Fortran::common::LanguageFeature::OpenMP)) {
329c870632eSMatthias Springer     setOffloadModuleInterfaceAttributes(lb.getModule(),
33053152f12SAndrew Gozillon                                         ci.getInvocation().getLangOpts());
331c870632eSMatthias Springer     setOpenMPVersionAttribute(lb.getModule(),
332d93bdd8bSDominik Adamski                               ci.getInvocation().getLangOpts().OpenMPVersion);
333e002a38bSAndrew Gozillon   }
334e002a38bSAndrew Gozillon 
33569c3309dSAndrzej Warzynski   // Create a parse tree and lower it to FIR
3361e462fafSAndrzej Warzynski   Fortran::parser::Program &parseTree{*ci.getParsing().parseTree()};
337ae4d7ac9SAndrzej Warzyński   lb.lower(parseTree, ci.getSemanticsContext());
33869c3309dSAndrzej Warzynski 
339c870632eSMatthias Springer   // Fetch module from lb, so we can set
340c870632eSMatthias Springer   mlirModule = lb.getModuleAndRelease();
341c870632eSMatthias Springer 
34295943d2fSDominik Adamski   // Add target specific items like dependent libraries, target specific
34395943d2fSDominik Adamski   // constants etc.
34495943d2fSDominik Adamski   addDependentLibs(*mlirModule, ci);
34595943d2fSDominik Adamski   addAMDGPUSpecificMLIRItems(*mlirModule, ci);
346310c281bSmacurtis-amd   timingScopeMLIRGen.stop();
34777ecb9a4SDavid Truby 
3481e462fafSAndrzej Warzynski   // run the default passes.
34994a30928Srkayaith   mlir::PassManager pm((*mlirModule)->getName(),
35094a30928Srkayaith                        mlir::OpPassManager::Nesting::Implicit);
3510ea0ecd6SjeanPerier   (void)mlir::applyPassManagerCLOptions(pm);
35245a96044SJan Sjodin   // Add OpenMP-related passes
35345a96044SJan Sjodin   // WARNING: These passes must be run immediately after the lowering to ensure
35445a96044SJan Sjodin   // that the FIR is correct with respect to OpenMP operations/attributes.
35545a96044SJan Sjodin   if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
35645a96044SJan Sjodin           Fortran::common::LanguageFeature::OpenMP)) {
35745a96044SJan Sjodin     bool isDevice = false;
35845a96044SJan Sjodin     if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>(
35945a96044SJan Sjodin             mlirModule->getOperation()))
36045a96044SJan Sjodin       isDevice = offloadMod.getIsTargetDevice();
361fb4bdf36SSergio Afonso     // WARNING: This pipeline must be run immediately after the lowering to
362fb4bdf36SSergio Afonso     // ensure that the FIR is correct with respect to OpenMP operations/
363fb4bdf36SSergio Afonso     // attributes.
364fb4bdf36SSergio Afonso     fir::createOpenMPFIRPassPipeline(pm, isDevice);
36564f5a764SAndrew Gozillon   }
36645a96044SJan Sjodin 
36769c3309dSAndrzej Warzynski   pm.enableVerifier(/*verifyPasses=*/true);
36869c3309dSAndrzej Warzynski   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
369310c281bSmacurtis-amd   pm.enableTiming(timingScopeMLIRGen);
37069c3309dSAndrzej Warzynski 
37169c3309dSAndrzej Warzynski   if (mlir::failed(pm.run(*mlirModule))) {
3721e462fafSAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
3731e462fafSAndrzej Warzynski         clang::DiagnosticsEngine::Error,
37469c3309dSAndrzej Warzynski         "verification of lowering to FIR failed");
3751e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
37669c3309dSAndrzej Warzynski     return false;
37769c3309dSAndrzej Warzynski   }
378310c281bSmacurtis-amd   timingScopeMLIRGen.stop();
37969c3309dSAndrzej Warzynski 
38033be8341SSergio Afonso   // Print initial full MLIR module, before lowering or transformations, if
38133be8341SSergio Afonso   // -save-temps has been specified.
38233be8341SSergio Afonso   if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(),
38333be8341SSergio Afonso                         "fir")) {
38433be8341SSergio Afonso     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
38533be8341SSergio Afonso         clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed");
38633be8341SSergio Afonso     ci.getDiagnostics().Report(diagID);
38733be8341SSergio Afonso     return false;
38833be8341SSergio Afonso   }
38933be8341SSergio Afonso 
39069c3309dSAndrzej Warzynski   return true;
39169c3309dSAndrzej Warzynski }
39269c3309dSAndrzej Warzynski 
3934f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===//
3944f21e6aeSAndrzej Warzynski // Custom ExecuteAction
3954f21e6aeSAndrzej Warzynski //===----------------------------------------------------------------------===//
3961e462fafSAndrzej Warzynski void InputOutputTestAction::executeAction() {
3971e462fafSAndrzej Warzynski   CompilerInstance &ci = getInstance();
398ba000628SAndrzej Warzynski 
399ba000628SAndrzej Warzynski   // Create a stream for errors
4004c5906cfSCaroline Concatto   std::string buf;
4011e462fafSAndrzej Warzynski   llvm::raw_string_ostream errorStream{buf};
4024c5906cfSCaroline Concatto 
403ba000628SAndrzej Warzynski   // Read the input file
4041e462fafSAndrzej Warzynski   Fortran::parser::AllSources &allSources{ci.getAllSources()};
4051e462fafSAndrzej Warzynski   std::string path{getCurrentFileOrBufferName()};
4064c5906cfSCaroline Concatto   const Fortran::parser::SourceFile *sf;
407ba000628SAndrzej Warzynski   if (path == "-")
4081e462fafSAndrzej Warzynski     sf = allSources.ReadStandardInput(errorStream);
409ba000628SAndrzej Warzynski   else
4101e462fafSAndrzej Warzynski     sf = allSources.Open(path, errorStream, std::optional<std::string>{"."s});
4114c5906cfSCaroline Concatto   llvm::ArrayRef<char> fileContent = sf->content();
4124c5906cfSCaroline Concatto 
413ba000628SAndrzej Warzynski   // Output file descriptor to receive the contents of the input file.
4144c5906cfSCaroline Concatto   std::unique_ptr<llvm::raw_ostream> os;
4154c5906cfSCaroline Concatto 
416ba000628SAndrzej Warzynski   // Copy the contents from the input file to the output file
4171e462fafSAndrzej Warzynski   if (!ci.isOutputStreamNull()) {
418ba000628SAndrzej Warzynski     // An output stream (outputStream_) was set earlier
4191e462fafSAndrzej Warzynski     ci.writeOutputStream(fileContent.data());
420ba000628SAndrzej Warzynski   } else {
421ba000628SAndrzej Warzynski     // No pre-set output stream - create an output file
4221e462fafSAndrzej Warzynski     os = ci.createDefaultOutputFile(
4231e462fafSAndrzej Warzynski         /*binary=*/true, getCurrentFileOrBufferName(), "txt");
4244c5906cfSCaroline Concatto     if (!os)
4254c5906cfSCaroline Concatto       return;
4264c5906cfSCaroline Concatto     (*os) << fileContent.data();
4274c5906cfSCaroline Concatto   }
4284c5906cfSCaroline Concatto }
429d28de0d7SCaroline Concatto 
4301e462fafSAndrzej Warzynski void PrintPreprocessedAction::executeAction() {
431d28de0d7SCaroline Concatto   std::string buf;
432d28de0d7SCaroline Concatto   llvm::raw_string_ostream outForPP{buf};
433d28de0d7SCaroline Concatto 
4343338ef93Speter klausler   // Format or dump the prescanner's output
4351e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
4367d60232bSKrzysztof Parzyszek   if (ci.getInvocation().getPreprocessorOpts().showMacros) {
4377d60232bSKrzysztof Parzyszek     ci.getParsing().EmitPreprocessorMacros(outForPP);
4387d60232bSKrzysztof Parzyszek   } else if (ci.getInvocation().getPreprocessorOpts().noReformat) {
4391e462fafSAndrzej Warzynski     ci.getParsing().DumpCookedChars(outForPP);
4403338ef93Speter klausler   } else {
4411e462fafSAndrzej Warzynski     ci.getParsing().EmitPreprocessedSource(
4421e462fafSAndrzej Warzynski         outForPP, !ci.getInvocation().getPreprocessorOpts().noLineDirectives);
4433338ef93Speter klausler   }
444d28de0d7SCaroline Concatto 
4451e462fafSAndrzej Warzynski   // Print getDiagnostics from the prescanner
4461e462fafSAndrzej Warzynski   ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
447787c443aSAndrzej Warzynski 
448d28de0d7SCaroline Concatto   // If a pre-defined output stream exists, dump the preprocessed content there
4491e462fafSAndrzej Warzynski   if (!ci.isOutputStreamNull()) {
450d28de0d7SCaroline Concatto     // Send the output to the pre-defined output buffer.
45184d7f294SYoungsuk Kim     ci.writeOutputStream(buf);
452d28de0d7SCaroline Concatto     return;
453d28de0d7SCaroline Concatto   }
454d28de0d7SCaroline Concatto 
455316be03fSAndrzej Warzynski   // Create a file and save the preprocessed output there
4561e462fafSAndrzej Warzynski   std::unique_ptr<llvm::raw_pwrite_stream> os{ci.createDefaultOutputFile(
4571e462fafSAndrzej Warzynski       /*Binary=*/true, /*InFile=*/getCurrentFileOrBufferName())};
458787c443aSAndrzej Warzynski   if (!os) {
459787c443aSAndrzej Warzynski     return;
460316be03fSAndrzej Warzynski   }
461787c443aSAndrzej Warzynski 
46284d7f294SYoungsuk Kim   (*os) << buf;
463d28de0d7SCaroline Concatto }
4647d246cb1SAndrzej Warzynski 
4651e462fafSAndrzej Warzynski void DebugDumpProvenanceAction::executeAction() {
4661e462fafSAndrzej Warzynski   this->getInstance().getParsing().DumpProvenance(llvm::outs());
4674bd08dabSFaris Rehman }
4684bd08dabSFaris Rehman 
4691e462fafSAndrzej Warzynski void ParseSyntaxOnlyAction::executeAction() {}
4707d246cb1SAndrzej Warzynski 
4711e462fafSAndrzej Warzynski void DebugUnparseNoSemaAction::executeAction() {
4721e462fafSAndrzej Warzynski   auto &invoc = this->getInstance().getInvocation();
4731e462fafSAndrzej Warzynski   auto &parseTree{getInstance().getParsing().parseTree()};
474e81b3401SAndrzej Warzynski 
475e81b3401SAndrzej Warzynski   // TODO: Options should come from CompilerInvocation
476e81b3401SAndrzej Warzynski   Unparse(llvm::outs(), *parseTree,
477e81b3401SAndrzej Warzynski           /*encoding=*/Fortran::parser::Encoding::UTF_8,
478e81b3401SAndrzej Warzynski           /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
4792a7bb849SAndrzej Warzynski           /*preStatement=*/nullptr,
4801e462fafSAndrzej Warzynski           invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()
4811e462fafSAndrzej Warzynski                                                   : nullptr);
482e81b3401SAndrzej Warzynski }
483e81b3401SAndrzej Warzynski 
4841e462fafSAndrzej Warzynski void DebugUnparseAction::executeAction() {
4851e462fafSAndrzej Warzynski   auto &invoc = this->getInstance().getInvocation();
4861e462fafSAndrzej Warzynski   auto &parseTree{getInstance().getParsing().parseTree()};
487e49dc298SAndrzej Warzynski 
4881e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
4891e462fafSAndrzej Warzynski   auto os{ci.createDefaultOutputFile(
4901e462fafSAndrzej Warzynski       /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName())};
491e77191c3SAndrzej Warzynski 
49296d229c9SAndrzej Warzynski   // TODO: Options should come from CompilerInvocation
493e77191c3SAndrzej Warzynski   Unparse(*os, *parseTree,
49496d229c9SAndrzej Warzynski           /*encoding=*/Fortran::parser::Encoding::UTF_8,
49596d229c9SAndrzej Warzynski           /*capitalizeKeywords=*/true, /*backslashEscapes=*/false,
4962a7bb849SAndrzej Warzynski           /*preStatement=*/nullptr,
4971e462fafSAndrzej Warzynski           invoc.getUseAnalyzedObjectsForUnparse() ? &invoc.getAsFortran()
4981e462fafSAndrzej Warzynski                                                   : nullptr);
4994bd08dabSFaris Rehman 
5004bd08dabSFaris Rehman   // Report fatal semantic errors
5014f21e6aeSAndrzej Warzynski   reportFatalSemanticErrors();
502e49dc298SAndrzej Warzynski }
503e49dc298SAndrzej Warzynski 
5041e462fafSAndrzej Warzynski void DebugUnparseWithSymbolsAction::executeAction() {
5051e462fafSAndrzej Warzynski   auto &parseTree{*getInstance().getParsing().parseTree()};
506a8f51ea2SFaris Rehman 
50796d229c9SAndrzej Warzynski   Fortran::semantics::UnparseWithSymbols(
50896d229c9SAndrzej Warzynski       llvm::outs(), parseTree, /*encoding=*/Fortran::parser::Encoding::UTF_8);
5094bd08dabSFaris Rehman 
5104bd08dabSFaris Rehman   // Report fatal semantic errors
5114f21e6aeSAndrzej Warzynski   reportFatalSemanticErrors();
5124bd08dabSFaris Rehman }
5134bd08dabSFaris Rehman 
514e00a3ccfSPeter Klausler void DebugUnparseWithModulesAction::executeAction() {
515e00a3ccfSPeter Klausler   auto &parseTree{*getInstance().getParsing().parseTree()};
516e00a3ccfSPeter Klausler   CompilerInstance &ci{getInstance()};
517e00a3ccfSPeter Klausler   Fortran::semantics::UnparseWithModules(
518e00a3ccfSPeter Klausler       llvm::outs(), ci.getSemantics().context(), parseTree,
519e00a3ccfSPeter Klausler       /*encoding=*/Fortran::parser::Encoding::UTF_8);
520e00a3ccfSPeter Klausler   reportFatalSemanticErrors();
521e00a3ccfSPeter Klausler }
522e00a3ccfSPeter Klausler 
5231e462fafSAndrzej Warzynski void DebugDumpSymbolsAction::executeAction() {
5241e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
5254bd08dabSFaris Rehman 
52616a91a1cSAndrzej Warzynski   if (!ci.getRtTyTables().schemata) {
5271e462fafSAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
5281e462fafSAndrzej Warzynski         clang::DiagnosticsEngine::Error,
529499f1ed5SAndrzej Warzynski         "could not find module file for __fortran_type_info");
5301e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
531499f1ed5SAndrzej Warzynski     llvm::errs() << "\n";
53216a91a1cSAndrzej Warzynski     return;
533499f1ed5SAndrzej Warzynski   }
534499f1ed5SAndrzej Warzynski 
5354bd08dabSFaris Rehman   // Dump symbols
5361e462fafSAndrzej Warzynski   ci.getSemantics().DumpSymbols(llvm::outs());
5374bd08dabSFaris Rehman }
5384bd08dabSFaris Rehman 
5391e462fafSAndrzej Warzynski void DebugDumpAllAction::executeAction() {
5401e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
541a6be6e31SAndrzej Warzynski 
542a6be6e31SAndrzej Warzynski   // Dump parse tree
5431e462fafSAndrzej Warzynski   auto &parseTree{getInstance().getParsing().parseTree()};
544a6be6e31SAndrzej Warzynski   llvm::outs() << "========================";
545a6be6e31SAndrzej Warzynski   llvm::outs() << " Flang: parse tree dump ";
546a6be6e31SAndrzej Warzynski   llvm::outs() << "========================\n";
5471e462fafSAndrzej Warzynski   Fortran::parser::DumpTree(llvm::outs(), parseTree,
5481e462fafSAndrzej Warzynski                             &ci.getInvocation().getAsFortran());
549a6be6e31SAndrzej Warzynski 
55016a91a1cSAndrzej Warzynski   if (!ci.getRtTyTables().schemata) {
5511e462fafSAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
5521e462fafSAndrzej Warzynski         clang::DiagnosticsEngine::Error,
553a6be6e31SAndrzej Warzynski         "could not find module file for __fortran_type_info");
5541e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
555a6be6e31SAndrzej Warzynski     llvm::errs() << "\n";
55616a91a1cSAndrzej Warzynski     return;
557a6be6e31SAndrzej Warzynski   }
558a6be6e31SAndrzej Warzynski 
559a6be6e31SAndrzej Warzynski   // Dump symbols
560a6be6e31SAndrzej Warzynski   llvm::outs() << "=====================";
561a6be6e31SAndrzej Warzynski   llvm::outs() << " Flang: symbols dump ";
562a6be6e31SAndrzej Warzynski   llvm::outs() << "=====================\n";
5631e462fafSAndrzej Warzynski   ci.getSemantics().DumpSymbols(llvm::outs());
564a6be6e31SAndrzej Warzynski }
565a6be6e31SAndrzej Warzynski 
5661e462fafSAndrzej Warzynski void DebugDumpParseTreeNoSemaAction::executeAction() {
5671e462fafSAndrzej Warzynski   auto &parseTree{getInstance().getParsing().parseTree()};
568e81b3401SAndrzej Warzynski 
569e81b3401SAndrzej Warzynski   // Dump parse tree
5702a7bb849SAndrzej Warzynski   Fortran::parser::DumpTree(
5711e462fafSAndrzej Warzynski       llvm::outs(), parseTree,
5721e462fafSAndrzej Warzynski       &this->getInstance().getInvocation().getAsFortran());
573e81b3401SAndrzej Warzynski }
574e81b3401SAndrzej Warzynski 
5751e462fafSAndrzej Warzynski void DebugDumpParseTreeAction::executeAction() {
5761e462fafSAndrzej Warzynski   auto &parseTree{getInstance().getParsing().parseTree()};
5774bd08dabSFaris Rehman 
5784bd08dabSFaris Rehman   // Dump parse tree
5792a7bb849SAndrzej Warzynski   Fortran::parser::DumpTree(
5801e462fafSAndrzej Warzynski       llvm::outs(), parseTree,
5811e462fafSAndrzej Warzynski       &this->getInstance().getInvocation().getAsFortran());
5822a7bb849SAndrzej Warzynski 
5834bd08dabSFaris Rehman   // Report fatal semantic errors
5844f21e6aeSAndrzej Warzynski   reportFatalSemanticErrors();
5857d246cb1SAndrzej Warzynski }
586e5cdb6c5SAndrzej Warzynski 
5871e462fafSAndrzej Warzynski void DebugMeasureParseTreeAction::executeAction() {
5881e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
589529f7181SFaris Rehman 
590529f7181SFaris Rehman   // Parse. In case of failure, report and return.
5911e462fafSAndrzej Warzynski   ci.getParsing().Parse(llvm::outs());
592529f7181SFaris Rehman 
593d1ea605eSPeter Klausler   if ((ci.getParsing().parseTree().has_value() &&
594d1ea605eSPeter Klausler        !ci.getParsing().consumedWholeFile()) ||
595d1ea605eSPeter Klausler       (!ci.getParsing().messages().empty() &&
5961e462fafSAndrzej Warzynski        (ci.getInvocation().getWarnAsErr() ||
597d1ea605eSPeter Klausler         ci.getParsing().messages().AnyFatalError()))) {
5981e462fafSAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
599529f7181SFaris Rehman         clang::DiagnosticsEngine::Error, "Could not parse %0");
6001e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID) << getCurrentFileOrBufferName();
601529f7181SFaris Rehman 
6021e462fafSAndrzej Warzynski     ci.getParsing().messages().Emit(llvm::errs(),
6031e462fafSAndrzej Warzynski                                     this->getInstance().getAllCookedSources());
604529f7181SFaris Rehman     return;
605529f7181SFaris Rehman   }
606529f7181SFaris Rehman 
6071e462fafSAndrzej Warzynski   // Report the getDiagnostics from parsing
6081e462fafSAndrzej Warzynski   ci.getParsing().messages().Emit(llvm::errs(), ci.getAllCookedSources());
609529f7181SFaris Rehman 
6101e462fafSAndrzej Warzynski   auto &parseTree{*ci.getParsing().parseTree()};
611529f7181SFaris Rehman 
612529f7181SFaris Rehman   // Measure the parse tree
613529f7181SFaris Rehman   MeasurementVisitor visitor;
614529f7181SFaris Rehman   Fortran::parser::Walk(parseTree, visitor);
615529f7181SFaris Rehman   llvm::outs() << "Parse tree comprises " << visitor.objects
616529f7181SFaris Rehman                << " objects and occupies " << visitor.bytes
617529f7181SFaris Rehman                << " total bytes.\n";
618529f7181SFaris Rehman }
619529f7181SFaris Rehman 
6201e462fafSAndrzej Warzynski void DebugPreFIRTreeAction::executeAction() {
6211e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
622529f7181SFaris Rehman   // Report and exit if fatal semantic errors are present
6234f21e6aeSAndrzej Warzynski   if (reportFatalSemanticErrors()) {
624529f7181SFaris Rehman     return;
625529f7181SFaris Rehman   }
626529f7181SFaris Rehman 
6271e462fafSAndrzej Warzynski   auto &parseTree{*ci.getParsing().parseTree()};
628529f7181SFaris Rehman 
629529f7181SFaris Rehman   // Dump pre-FIR tree
630ae4d7ac9SAndrzej Warzyński   if (auto ast{
631ae4d7ac9SAndrzej Warzyński           Fortran::lower::createPFT(parseTree, ci.getSemanticsContext())}) {
632529f7181SFaris Rehman     Fortran::lower::dumpPFT(llvm::outs(), *ast);
633529f7181SFaris Rehman   } else {
6341e462fafSAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
635529f7181SFaris Rehman         clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
6361e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
637529f7181SFaris Rehman   }
638529f7181SFaris Rehman }
639529f7181SFaris Rehman 
6401e462fafSAndrzej Warzynski void DebugDumpParsingLogAction::executeAction() {
6411e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
642523d7bc6SAndrzej Warzynski 
6431e462fafSAndrzej Warzynski   ci.getParsing().Parse(llvm::errs());
6441e462fafSAndrzej Warzynski   ci.getParsing().DumpParsingLog(llvm::outs());
645523d7bc6SAndrzej Warzynski }
646523d7bc6SAndrzej Warzynski 
6471e462fafSAndrzej Warzynski void GetDefinitionAction::executeAction() {
6481e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
649265a9961SAndrzej Warzynski 
650dc256a44SAndrzej Warzynski   // Report and exit if fatal semantic errors are present
6514f21e6aeSAndrzej Warzynski   if (reportFatalSemanticErrors()) {
652dc256a44SAndrzej Warzynski     return;
6534f21e6aeSAndrzej Warzynski   }
654dc256a44SAndrzej Warzynski 
6551e462fafSAndrzej Warzynski   parser::AllCookedSources &cs = ci.getAllCookedSources();
6561e462fafSAndrzej Warzynski   unsigned diagID = ci.getDiagnostics().getCustomDiagID(
657dc256a44SAndrzej Warzynski       clang::DiagnosticsEngine::Error, "Symbol not found");
658dc256a44SAndrzej Warzynski 
6591e462fafSAndrzej Warzynski   auto gdv = ci.getInvocation().getFrontendOpts().getDefVals;
6608fc00247SValentin Clement   auto charBlock{cs.GetCharBlockFromLineAndColumns(gdv.line, gdv.startColumn,
6618fc00247SValentin Clement                                                    gdv.endColumn)};
662dc256a44SAndrzej Warzynski   if (!charBlock) {
6631e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
664dc256a44SAndrzej Warzynski     return;
665dc256a44SAndrzej Warzynski   }
666dc256a44SAndrzej Warzynski 
667dc256a44SAndrzej Warzynski   llvm::outs() << "String range: >" << charBlock->ToString() << "<\n";
668dc256a44SAndrzej Warzynski 
669ae4d7ac9SAndrzej Warzyński   auto *symbol{
670ae4d7ac9SAndrzej Warzyński       ci.getSemanticsContext().FindScope(*charBlock).FindSymbol(*charBlock)};
671dc256a44SAndrzej Warzynski   if (!symbol) {
6721e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
673dc256a44SAndrzej Warzynski     return;
674dc256a44SAndrzej Warzynski   }
675dc256a44SAndrzej Warzynski 
676dc256a44SAndrzej Warzynski   llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
677dc256a44SAndrzej Warzynski 
678dc256a44SAndrzej Warzynski   auto sourceInfo{cs.GetSourcePositionRange(symbol->name())};
679dc256a44SAndrzej Warzynski   if (!sourceInfo) {
680dc256a44SAndrzej Warzynski     llvm_unreachable(
681dc256a44SAndrzej Warzynski         "Failed to obtain SourcePosition."
682dc256a44SAndrzej Warzynski         "TODO: Please, write a test and replace this with a diagnostic!");
683dc256a44SAndrzej Warzynski     return;
684dc256a44SAndrzej Warzynski   }
685dc256a44SAndrzej Warzynski 
686dc256a44SAndrzej Warzynski   llvm::outs() << "Found symbol name: " << symbol->name().ToString() << "\n";
687e12ffe6aSPeter Klausler   llvm::outs() << symbol->name().ToString() << ": " << sourceInfo->first.path
688e12ffe6aSPeter Klausler                << ", " << sourceInfo->first.line << ", "
689e12ffe6aSPeter Klausler                << sourceInfo->first.column << "-" << sourceInfo->second.column
690e12ffe6aSPeter Klausler                << "\n";
691dc256a44SAndrzej Warzynski }
692dc256a44SAndrzej Warzynski 
6931e462fafSAndrzej Warzynski void GetSymbolsSourcesAction::executeAction() {
6941e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
695265a9961SAndrzej Warzynski 
696eefda605SAndrzej Warzynski   // Report and exit if fatal semantic errors are present
6974f21e6aeSAndrzej Warzynski   if (reportFatalSemanticErrors()) {
698eefda605SAndrzej Warzynski     return;
6994f21e6aeSAndrzej Warzynski   }
700eefda605SAndrzej Warzynski 
7011e462fafSAndrzej Warzynski   ci.getSemantics().DumpSymbolsSources(llvm::outs());
702eefda605SAndrzej Warzynski }
703eefda605SAndrzej Warzynski 
704bb177edcSAndrzej Warzynski //===----------------------------------------------------------------------===//
705bb177edcSAndrzej Warzynski // CodeGenActions
706bb177edcSAndrzej Warzynski //===----------------------------------------------------------------------===//
707bb177edcSAndrzej Warzynski 
708bb177edcSAndrzej Warzynski CodeGenAction::~CodeGenAction() = default;
709bb177edcSAndrzej Warzynski 
7109c0acc42SSlava Zakharin static llvm::OptimizationLevel
7119c0acc42SSlava Zakharin mapToLevel(const Fortran::frontend::CodeGenOptions &opts) {
7129c0acc42SSlava Zakharin   switch (opts.OptimizationLevel) {
7139c0acc42SSlava Zakharin   default:
7149c0acc42SSlava Zakharin     llvm_unreachable("Invalid optimization level!");
7159c0acc42SSlava Zakharin   case 0:
7169c0acc42SSlava Zakharin     return llvm::OptimizationLevel::O0;
7179c0acc42SSlava Zakharin   case 1:
7189c0acc42SSlava Zakharin     return llvm::OptimizationLevel::O1;
7199c0acc42SSlava Zakharin   case 2:
7209c0acc42SSlava Zakharin     return llvm::OptimizationLevel::O2;
7219c0acc42SSlava Zakharin   case 3:
7229c0acc42SSlava Zakharin     return llvm::OptimizationLevel::O3;
7239c0acc42SSlava Zakharin   }
7249c0acc42SSlava Zakharin }
7259c0acc42SSlava Zakharin 
72639ecf9d8STom Eccles // Lower using HLFIR then run the FIR to HLFIR pipeline
72739ecf9d8STom Eccles void CodeGenAction::lowerHLFIRToFIR() {
72839ecf9d8STom Eccles   assert(mlirModule && "The MLIR module has not been generated yet.");
72939ecf9d8STom Eccles 
73039ecf9d8STom Eccles   CompilerInstance &ci = this->getInstance();
731310c281bSmacurtis-amd   const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
73239ecf9d8STom Eccles   llvm::OptimizationLevel level = mapToLevel(opts);
733310c281bSmacurtis-amd   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
734310c281bSmacurtis-amd   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
73539ecf9d8STom Eccles 
73639ecf9d8STom Eccles   fir::support::loadDialects(*mlirCtx);
73739ecf9d8STom Eccles 
73839ecf9d8STom Eccles   // Set-up the MLIR pass manager
73939ecf9d8STom Eccles   mlir::PassManager pm((*mlirModule)->getName(),
74039ecf9d8STom Eccles                        mlir::OpPassManager::Nesting::Implicit);
74139ecf9d8STom Eccles 
74239ecf9d8STom Eccles   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
74339ecf9d8STom Eccles   pm.enableVerifier(/*verifyPasses=*/true);
74439ecf9d8STom Eccles 
74539ecf9d8STom Eccles   // Create the pass pipeline
746e7e55416SIvan R. Ivanov   fir::createHLFIRToFIRPassPipeline(
747e7e55416SIvan R. Ivanov       pm,
748e7e55416SIvan R. Ivanov       ci.getInvocation().getFrontendOpts().features.IsEnabled(
749e7e55416SIvan R. Ivanov           Fortran::common::LanguageFeature::OpenMP),
750e7e55416SIvan R. Ivanov       level);
75139ecf9d8STom Eccles   (void)mlir::applyPassManagerCLOptions(pm);
75239ecf9d8STom Eccles 
753310c281bSmacurtis-amd   mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
754310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
755310c281bSmacurtis-amd   pm.enableTiming(timingScopeMLIRPasses);
75639ecf9d8STom Eccles   if (!mlir::succeeded(pm.run(*mlirModule))) {
75739ecf9d8STom Eccles     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
75839ecf9d8STom Eccles         clang::DiagnosticsEngine::Error, "Lowering to FIR failed");
75939ecf9d8STom Eccles     ci.getDiagnostics().Report(diagID);
76039ecf9d8STom Eccles   }
76139ecf9d8STom Eccles }
76239ecf9d8STom Eccles 
7636180964aSMats Petersson static std::optional<std::pair<unsigned, unsigned>>
764c4b591a1SLuke Lau getAArch64VScaleRange(CompilerInstance &ci) {
765898db113SPhilip Reames   const auto &langOpts = ci.getInvocation().getLangOpts();
766c4b591a1SLuke Lau 
7676180964aSMats Petersson   if (langOpts.VScaleMin || langOpts.VScaleMax)
7686180964aSMats Petersson     return std::pair<unsigned, unsigned>(
7696180964aSMats Petersson         langOpts.VScaleMin ? langOpts.VScaleMin : 1, langOpts.VScaleMax);
7706180964aSMats Petersson 
771e59e8488SjeanPerier   std::string featuresStr = ci.getTargetFeatures();
7726180964aSMats Petersson   if (featuresStr.find("+sve") != std::string::npos)
7736180964aSMats Petersson     return std::pair<unsigned, unsigned>(1, 16);
7746180964aSMats Petersson 
7756180964aSMats Petersson   return std::nullopt;
7766180964aSMats Petersson }
7776180964aSMats Petersson 
778c4b591a1SLuke Lau static std::optional<std::pair<unsigned, unsigned>>
779c4b591a1SLuke Lau getRISCVVScaleRange(CompilerInstance &ci) {
780c4b591a1SLuke Lau   const auto &langOpts = ci.getInvocation().getLangOpts();
781c4b591a1SLuke Lau   const auto targetOpts = ci.getInvocation().getTargetOpts();
782c4b591a1SLuke Lau   const llvm::Triple triple(targetOpts.triple);
783c4b591a1SLuke Lau 
784c4b591a1SLuke Lau   auto parseResult = llvm::RISCVISAInfo::parseFeatures(
785c4b591a1SLuke Lau       triple.isRISCV64() ? 64 : 32, targetOpts.featuresAsWritten);
786c4b591a1SLuke Lau   if (!parseResult) {
787c4b591a1SLuke Lau     std::string buffer;
788c4b591a1SLuke Lau     llvm::raw_string_ostream outputErrMsg(buffer);
789c4b591a1SLuke Lau     handleAllErrors(parseResult.takeError(), [&](llvm::StringError &errMsg) {
790c4b591a1SLuke Lau       outputErrMsg << errMsg.getMessage();
791c4b591a1SLuke Lau     });
792c4b591a1SLuke Lau     ci.getDiagnostics().Report(clang::diag::err_invalid_feature_combination)
79384d7f294SYoungsuk Kim         << buffer;
794c4b591a1SLuke Lau     return std::nullopt;
795c4b591a1SLuke Lau   }
796c4b591a1SLuke Lau 
797c4b591a1SLuke Lau   llvm::RISCVISAInfo *const isaInfo = parseResult->get();
798c4b591a1SLuke Lau 
799c4b591a1SLuke Lau   // RISCV::RVVBitsPerBlock is 64.
800c4b591a1SLuke Lau   unsigned vscaleMin = isaInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
801c4b591a1SLuke Lau 
802c4b591a1SLuke Lau   if (langOpts.VScaleMin || langOpts.VScaleMax) {
803c4b591a1SLuke Lau     // Treat Zvl*b as a lower bound on vscale.
804c4b591a1SLuke Lau     vscaleMin = std::max(vscaleMin, langOpts.VScaleMin);
805c4b591a1SLuke Lau     unsigned vscaleMax = langOpts.VScaleMax;
806c4b591a1SLuke Lau     if (vscaleMax != 0 && vscaleMax < vscaleMin)
807c4b591a1SLuke Lau       vscaleMax = vscaleMin;
808c4b591a1SLuke Lau     return std::pair<unsigned, unsigned>(vscaleMin ? vscaleMin : 1, vscaleMax);
809c4b591a1SLuke Lau   }
810c4b591a1SLuke Lau 
811c4b591a1SLuke Lau   if (vscaleMin > 0) {
812c4b591a1SLuke Lau     unsigned vscaleMax = isaInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
813c4b591a1SLuke Lau     return std::make_pair(vscaleMin, vscaleMax);
814c4b591a1SLuke Lau   }
815c4b591a1SLuke Lau 
816c4b591a1SLuke Lau   return std::nullopt;
817c4b591a1SLuke Lau }
818c4b591a1SLuke Lau 
819c4b591a1SLuke Lau // TODO: We should get this from TargetInfo. However, that depends on
820c4b591a1SLuke Lau // too much of clang, so for now, replicate the functionality.
821c4b591a1SLuke Lau static std::optional<std::pair<unsigned, unsigned>>
822c4b591a1SLuke Lau getVScaleRange(CompilerInstance &ci) {
823c4b591a1SLuke Lau   const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple);
824c4b591a1SLuke Lau 
825c4b591a1SLuke Lau   if (triple.isAArch64())
826c4b591a1SLuke Lau     return getAArch64VScaleRange(ci);
827c4b591a1SLuke Lau   if (triple.isRISCV())
828c4b591a1SLuke Lau     return getRISCVVScaleRange(ci);
829c4b591a1SLuke Lau 
830219c14a2SLuke Lau   // All other architectures that don't support scalable vectors (i.e. don't
831219c14a2SLuke Lau   // need vscale)
832c4b591a1SLuke Lau   return std::nullopt;
833c4b591a1SLuke Lau }
834c4b591a1SLuke Lau 
835e993b20cSAndrzej Warzynski // Lower the previously generated MLIR module into an LLVM IR module
8361e462fafSAndrzej Warzynski void CodeGenAction::generateLLVMIR() {
837e993b20cSAndrzej Warzynski   assert(mlirModule && "The MLIR module has not been generated yet.");
838e993b20cSAndrzej Warzynski 
8391e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
840310c281bSmacurtis-amd   CompilerInvocation &invoc = ci.getInvocation();
841310c281bSmacurtis-amd   const CodeGenOptions &opts = invoc.getCodeGenOpts();
842310c281bSmacurtis-amd   const auto &mathOpts = invoc.getLoweringOpts().getMathOptions();
8439c0acc42SSlava Zakharin   llvm::OptimizationLevel level = mapToLevel(opts);
844310c281bSmacurtis-amd   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
845310c281bSmacurtis-amd   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
846e993b20cSAndrzej Warzynski 
847e993b20cSAndrzej Warzynski   fir::support::loadDialects(*mlirCtx);
848369b8221SVijay Kandiah   mlir::DialectRegistry registry;
849369b8221SVijay Kandiah   fir::support::registerNonCodegenDialects(registry);
850369b8221SVijay Kandiah   fir::support::addFIRExtensions(registry);
851369b8221SVijay Kandiah   mlirCtx->appendDialectRegistry(registry);
852e993b20cSAndrzej Warzynski   fir::support::registerLLVMTranslation(*mlirCtx);
853e993b20cSAndrzej Warzynski 
854e993b20cSAndrzej Warzynski   // Set-up the MLIR pass manager
85594a30928Srkayaith   mlir::PassManager pm((*mlirModule)->getName(),
85694a30928Srkayaith                        mlir::OpPassManager::Nesting::Implicit);
857e993b20cSAndrzej Warzynski 
858e993b20cSAndrzej Warzynski   pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
859e993b20cSAndrzej Warzynski   pm.enableVerifier(/*verifyPasses=*/true);
860e993b20cSAndrzej Warzynski 
86122544e2aSAlex Bradbury   MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts);
86286ab10c4SVijay Kandiah   fir::registerDefaultInlinerPass(config);
8637006b90aSMats Petersson 
864898db113SPhilip Reames   if (auto vsr = getVScaleRange(ci)) {
8656180964aSMats Petersson     config.VScaleMin = vsr->first;
8666180964aSMats Petersson     config.VScaleMax = vsr->second;
8676180964aSMats Petersson   }
8686180964aSMats Petersson 
869e7e55416SIvan R. Ivanov   if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
870e7e55416SIvan R. Ivanov           Fortran::common::LanguageFeature::OpenMP))
871e7e55416SIvan R. Ivanov     config.EnableOpenMP = true;
872e7e55416SIvan R. Ivanov 
873a88677edSYusuke MINATO   if (ci.getInvocation().getLoweringOpts().getIntegerWrapAround())
874a88677edSYusuke MINATO     config.NSWOnLoopVarInc = false;
875526553b2SYusuke MINATO 
876e993b20cSAndrzej Warzynski   // Create the pass pipeline
8775f3f9d1aSAbid Qadeer   fir::createMLIRToLLVMPassPipeline(pm, config, getCurrentFile());
878d270d363SJie Fu   (void)mlir::applyPassManagerCLOptions(pm);
879e993b20cSAndrzej Warzynski 
8801e462fafSAndrzej Warzynski   // run the pass manager
881310c281bSmacurtis-amd   mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
882310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdMLIRPasses, timingMgr));
883310c281bSmacurtis-amd   pm.enableTiming(timingScopeMLIRPasses);
884e993b20cSAndrzej Warzynski   if (!mlir::succeeded(pm.run(*mlirModule))) {
8851e462fafSAndrzej Warzynski     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
886e993b20cSAndrzej Warzynski         clang::DiagnosticsEngine::Error, "Lowering to LLVM IR failed");
8871e462fafSAndrzej Warzynski     ci.getDiagnostics().Report(diagID);
888e993b20cSAndrzej Warzynski   }
889310c281bSmacurtis-amd   timingScopeMLIRPasses.stop();
890e993b20cSAndrzej Warzynski 
89133be8341SSergio Afonso   // Print final MLIR module, just before translation into LLVM IR, if
89233be8341SSergio Afonso   // -save-temps has been specified.
89333be8341SSergio Afonso   if (!saveMLIRTempFile(ci.getInvocation(), *mlirModule, getCurrentFile(),
89433be8341SSergio Afonso                         "llvmir")) {
89533be8341SSergio Afonso     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
89633be8341SSergio Afonso         clang::DiagnosticsEngine::Error, "Saving MLIR temp file failed");
89733be8341SSergio Afonso     ci.getDiagnostics().Report(diagID);
89833be8341SSergio Afonso     return;
89933be8341SSergio Afonso   }
90033be8341SSergio Afonso 
901e993b20cSAndrzej Warzynski   // Translate to LLVM IR
902310c281bSmacurtis-amd   mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest(
903310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr));
90422426110SRamkumar Ramachandra   std::optional<llvm::StringRef> moduleName = mlirModule->getName();
905e993b20cSAndrzej Warzynski   llvmModule = mlir::translateModuleToLLVMIR(
906e993b20cSAndrzej Warzynski       *mlirModule, *llvmCtx, moduleName ? *moduleName : "FIRModule");
907e993b20cSAndrzej Warzynski 
908723cd2e9SMehdi Amini   if (!llvmModule) {
909723cd2e9SMehdi Amini     unsigned diagID = ci.getDiagnostics().getCustomDiagID(
910723cd2e9SMehdi Amini         clang::DiagnosticsEngine::Error, "failed to create the LLVM module");
911723cd2e9SMehdi Amini     ci.getDiagnostics().Report(diagID);
912723cd2e9SMehdi Amini     return;
913723cd2e9SMehdi Amini   }
914723cd2e9SMehdi Amini 
915ef5ede52SUsman Nadeem   // Set PIC/PIE level LLVM module flags.
916ef5ede52SUsman Nadeem   if (opts.PICLevel > 0) {
917ef5ede52SUsman Nadeem     llvmModule->setPICLevel(static_cast<llvm::PICLevel::Level>(opts.PICLevel));
918ef5ede52SUsman Nadeem     if (opts.IsPIE)
919ef5ede52SUsman Nadeem       llvmModule->setPIELevel(
920ef5ede52SUsman Nadeem           static_cast<llvm::PIELevel::Level>(opts.PICLevel));
921ef5ede52SUsman Nadeem   }
9229e6b46a9SDavid Truby 
9239e6b46a9SDavid Truby   // Set mcmodel level LLVM module flags
9249e6b46a9SDavid Truby   std::optional<llvm::CodeModel::Model> cm = getCodeModel(opts.CodeModel);
9259e6b46a9SDavid Truby   if (cm.has_value()) {
9269e6b46a9SDavid Truby     const llvm::Triple triple(ci.getInvocation().getTargetOpts().triple);
9279e6b46a9SDavid Truby     llvmModule->setCodeModel(*cm);
9289e6b46a9SDavid Truby     if ((cm == llvm::CodeModel::Medium || cm == llvm::CodeModel::Large) &&
9299e6b46a9SDavid Truby         triple.getArch() == llvm::Triple::x86_64) {
9309e6b46a9SDavid Truby       llvmModule->setLargeDataThreshold(opts.LargeDataThreshold);
9319e6b46a9SDavid Truby     }
9329e6b46a9SDavid Truby   }
933e993b20cSAndrzej Warzynski }
934e993b20cSAndrzej Warzynski 
935bb177edcSAndrzej Warzynski static std::unique_ptr<llvm::raw_pwrite_stream>
9361e462fafSAndrzej Warzynski getOutputStream(CompilerInstance &ci, llvm::StringRef inFile,
937bb177edcSAndrzej Warzynski                 BackendActionTy action) {
938bb177edcSAndrzej Warzynski   switch (action) {
939bb177edcSAndrzej Warzynski   case BackendActionTy::Backend_EmitAssembly:
9401e462fafSAndrzej Warzynski     return ci.createDefaultOutputFile(
941bb177edcSAndrzej Warzynski         /*Binary=*/false, inFile, /*extension=*/"s");
942bb177edcSAndrzej Warzynski   case BackendActionTy::Backend_EmitLL:
9431e462fafSAndrzej Warzynski     return ci.createDefaultOutputFile(
944bb177edcSAndrzej Warzynski         /*Binary=*/false, inFile, /*extension=*/"ll");
94539ecf9d8STom Eccles   case BackendActionTy::Backend_EmitFIR:
94639ecf9d8STom Eccles   case BackendActionTy::Backend_EmitHLFIR:
9471e462fafSAndrzej Warzynski     return ci.createDefaultOutputFile(
948bb177edcSAndrzej Warzynski         /*Binary=*/false, inFile, /*extension=*/"mlir");
949bb177edcSAndrzej Warzynski   case BackendActionTy::Backend_EmitBC:
9501e462fafSAndrzej Warzynski     return ci.createDefaultOutputFile(
951bb177edcSAndrzej Warzynski         /*Binary=*/true, inFile, /*extension=*/"bc");
952bb177edcSAndrzej Warzynski   case BackendActionTy::Backend_EmitObj:
9531e462fafSAndrzej Warzynski     return ci.createDefaultOutputFile(
954bb177edcSAndrzej Warzynski         /*Binary=*/true, inFile, /*extension=*/"o");
955bb177edcSAndrzej Warzynski   }
956bb177edcSAndrzej Warzynski 
957bb177edcSAndrzej Warzynski   llvm_unreachable("Invalid action!");
958bb177edcSAndrzej Warzynski }
959bb177edcSAndrzej Warzynski 
960bb177edcSAndrzej Warzynski /// Generate target-specific machine-code or assembly file from the input LLVM
961bb177edcSAndrzej Warzynski /// module.
962bb177edcSAndrzej Warzynski ///
963bb177edcSAndrzej Warzynski /// \param [in] diags Diagnostics engine for reporting errors
9641e462fafSAndrzej Warzynski /// \param [in] tm Target machine to aid the code-gen pipeline set-up
965bb177edcSAndrzej Warzynski /// \param [in] act Backend act to run (assembly vs machine-code generation)
966bb177edcSAndrzej Warzynski /// \param [in] llvmModule LLVM module to lower to assembly/machine-code
967a207e630STom Eccles /// \param [in] codeGenOpts options configuring codegen pipeline
968bb177edcSAndrzej Warzynski /// \param [out] os Output stream to emit the generated code to
9691e462fafSAndrzej Warzynski static void generateMachineCodeOrAssemblyImpl(clang::DiagnosticsEngine &diags,
9701e462fafSAndrzej Warzynski                                               llvm::TargetMachine &tm,
971bb177edcSAndrzej Warzynski                                               BackendActionTy act,
972bb177edcSAndrzej Warzynski                                               llvm::Module &llvmModule,
973a207e630STom Eccles                                               const CodeGenOptions &codeGenOpts,
974bb177edcSAndrzej Warzynski                                               llvm::raw_pwrite_stream &os) {
975c12ef70dSAndrzej Warzynski   assert(((act == BackendActionTy::Backend_EmitObj) ||
976c12ef70dSAndrzej Warzynski           (act == BackendActionTy::Backend_EmitAssembly)) &&
977bb177edcSAndrzej Warzynski          "Unsupported action");
978bb177edcSAndrzej Warzynski 
979bb177edcSAndrzej Warzynski   // Set-up the pass manager, i.e create an LLVM code-gen pass pipeline.
980bb177edcSAndrzej Warzynski   // Currently only the legacy pass manager is supported.
981bb177edcSAndrzej Warzynski   // TODO: Switch to the new PM once it's available in the backend.
9821e462fafSAndrzej Warzynski   llvm::legacy::PassManager codeGenPasses;
9831e462fafSAndrzej Warzynski   codeGenPasses.add(
9841e462fafSAndrzej Warzynski       createTargetTransformInfoWrapperPass(tm.getTargetIRAnalysis()));
985bb177edcSAndrzej Warzynski 
986bb177edcSAndrzej Warzynski   llvm::Triple triple(llvmModule.getTargetTriple());
987a207e630STom Eccles   llvm::TargetLibraryInfoImpl *tlii =
988a207e630STom Eccles       llvm::driver::createTLII(triple, codeGenOpts.getVecLib());
9891e462fafSAndrzej Warzynski   codeGenPasses.add(new llvm::TargetLibraryInfoWrapperPass(*tlii));
990bb177edcSAndrzej Warzynski 
991bb177edcSAndrzej Warzynski   llvm::CodeGenFileType cgft = (act == BackendActionTy::Backend_EmitAssembly)
9920a1aa6cdSArthur Eubanks                                    ? llvm::CodeGenFileType::AssemblyFile
9930a1aa6cdSArthur Eubanks                                    : llvm::CodeGenFileType::ObjectFile;
9941e462fafSAndrzej Warzynski   if (tm.addPassesToEmitFile(codeGenPasses, os, nullptr, cgft)) {
995bb177edcSAndrzej Warzynski     unsigned diagID =
996bb177edcSAndrzej Warzynski         diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
997bb177edcSAndrzej Warzynski                               "emission of this file type is not supported");
998bb177edcSAndrzej Warzynski     diags.Report(diagID);
999bb177edcSAndrzej Warzynski     return;
1000bb177edcSAndrzej Warzynski   }
1001bb177edcSAndrzej Warzynski 
1002bb177edcSAndrzej Warzynski   // Run the passes
10031e462fafSAndrzej Warzynski   codeGenPasses.run(llvmModule);
1004c870632eSMatthias Springer 
1005c870632eSMatthias Springer   // Cleanup
1006c870632eSMatthias Springer   delete tlii;
1007bb177edcSAndrzej Warzynski }
1008bb177edcSAndrzej Warzynski 
1009869385b1SAndrzej Warzynski void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
1010310c281bSmacurtis-amd   CompilerInstance &ci = getInstance();
1011310c281bSmacurtis-amd   const CodeGenOptions &opts = ci.getInvocation().getCodeGenOpts();
1012310c281bSmacurtis-amd   clang::DiagnosticsEngine &diags = ci.getDiagnostics();
1013869385b1SAndrzej Warzynski   llvm::OptimizationLevel level = mapToLevel(opts);
1014869385b1SAndrzej Warzynski 
1015310c281bSmacurtis-amd   llvm::TargetMachine *targetMachine = &ci.getTargetMachine();
1016869385b1SAndrzej Warzynski   // Create the analysis managers.
1017869385b1SAndrzej Warzynski   llvm::LoopAnalysisManager lam;
1018869385b1SAndrzej Warzynski   llvm::FunctionAnalysisManager fam;
1019869385b1SAndrzej Warzynski   llvm::CGSCCAnalysisManager cgam;
10201e462fafSAndrzej Warzynski   llvm::ModuleAnalysisManager mam;
1021869385b1SAndrzej Warzynski 
1022869385b1SAndrzej Warzynski   // Create the pass manager builder.
1023869385b1SAndrzej Warzynski   llvm::PassInstrumentationCallbacks pic;
1024869385b1SAndrzej Warzynski   llvm::PipelineTuningOptions pto;
102512f6ac39SFangrui Song   std::optional<llvm::PGOOptions> pgoOpt;
1026eef02107SKiran Chandramohan   llvm::StandardInstrumentations si(llvmModule->getContext(),
1027eef02107SKiran Chandramohan                                     opts.DebugPassManager);
10286a6994ccSArthur Eubanks   si.registerCallbacks(pic, &mam);
1029310c281bSmacurtis-amd   if (ci.isTimingEnabled())
1030310c281bSmacurtis-amd     si.getTimePasses().setOutStream(ci.getTimingStreamLLVM());
1031*0195ec45SDavid Truby   pto.LoopUnrolling = opts.UnrollLoops;
1032*0195ec45SDavid Truby   pto.LoopInterleaving = opts.UnrollLoops;
1033e59e8488SjeanPerier   llvm::PassBuilder pb(targetMachine, pto, pgoOpt, &pic);
1034869385b1SAndrzej Warzynski 
1035c3821b8dSTarun Prabhu   // Attempt to load pass plugins and register their callbacks with PB.
1036c3821b8dSTarun Prabhu   for (auto &pluginFile : opts.LLVMPassPlugins) {
1037c3821b8dSTarun Prabhu     auto passPlugin = llvm::PassPlugin::Load(pluginFile);
1038c3821b8dSTarun Prabhu     if (passPlugin) {
1039c3821b8dSTarun Prabhu       passPlugin->registerPassBuilderCallbacks(pb);
1040c3821b8dSTarun Prabhu     } else {
1041c3821b8dSTarun Prabhu       diags.Report(clang::diag::err_fe_unable_to_load_plugin)
1042c3821b8dSTarun Prabhu           << pluginFile << passPlugin.takeError();
1043c3821b8dSTarun Prabhu     }
1044c3821b8dSTarun Prabhu   }
1045d34dce25SUsman Nadeem   // Register static plugin extensions.
1046d34dce25SUsman Nadeem #define HANDLE_EXTENSION(Ext)                                                  \
1047d34dce25SUsman Nadeem   get##Ext##PluginInfo().RegisterPassBuilderCallbacks(pb);
1048d34dce25SUsman Nadeem #include "llvm/Support/Extension.def"
1049c3821b8dSTarun Prabhu 
1050a207e630STom Eccles   // Register the target library analysis directly and give it a customized
1051a207e630STom Eccles   // preset TLI depending on -fveclib
1052a207e630STom Eccles   llvm::Triple triple(llvmModule->getTargetTriple());
1053a207e630STom Eccles   llvm::TargetLibraryInfoImpl *tlii =
1054a207e630STom Eccles       llvm::driver::createTLII(triple, opts.getVecLib());
1055a207e630STom Eccles   fam.registerPass([&] { return llvm::TargetLibraryAnalysis(*tlii); });
1056a207e630STom Eccles 
1057869385b1SAndrzej Warzynski   // Register all the basic analyses with the managers.
10581e462fafSAndrzej Warzynski   pb.registerModuleAnalyses(mam);
1059869385b1SAndrzej Warzynski   pb.registerCGSCCAnalyses(cgam);
1060869385b1SAndrzej Warzynski   pb.registerFunctionAnalyses(fam);
1061869385b1SAndrzej Warzynski   pb.registerLoopAnalyses(lam);
1062869385b1SAndrzej Warzynski   pb.crossRegisterProxies(lam, fam, cgam, mam);
1063869385b1SAndrzej Warzynski 
1064869385b1SAndrzej Warzynski   // Create the pass manager.
1065869385b1SAndrzej Warzynski   llvm::ModulePassManager mpm;
1066a8f6b576SNikita Popov   if (opts.PrepareForFullLTO)
10670fdfb65eSNadeem, Usman     mpm = pb.buildLTOPreLinkDefaultPipeline(level);
10680fdfb65eSNadeem, Usman   else if (opts.PrepareForThinLTO)
10690fdfb65eSNadeem, Usman     mpm = pb.buildThinLTOPreLinkDefaultPipeline(level);
1070869385b1SAndrzej Warzynski   else
1071869385b1SAndrzej Warzynski     mpm = pb.buildPerModuleDefaultPipeline(level);
1072869385b1SAndrzej Warzynski 
1073869385b1SAndrzej Warzynski   if (action == BackendActionTy::Backend_EmitBC)
10741e462fafSAndrzej Warzynski     mpm.addPass(llvm::BitcodeWriterPass(os));
10759b468388SStephen Tozer   else if (action == BackendActionTy::Backend_EmitLL)
10769b468388SStephen Tozer     mpm.addPass(llvm::PrintModulePass(os));
1077bb177edcSAndrzej Warzynski 
1078a1441ca7STarun Prabhu   // FIXME: This should eventually be replaced by a first-class driver option.
1079a1441ca7STarun Prabhu   // This should be done for both flang and clang simultaneously.
1080a1441ca7STarun Prabhu   // Print a textual, '-passes=' compatible, representation of pipeline if
1081a1441ca7STarun Prabhu   // requested. In this case, don't run the passes. This mimics the behavior of
1082a1441ca7STarun Prabhu   // clang.
1083a1441ca7STarun Prabhu   if (llvm::PrintPipelinePasses) {
1084a1441ca7STarun Prabhu     mpm.printPipeline(llvm::outs(), [&pic](llvm::StringRef className) {
1085a1441ca7STarun Prabhu       auto passName = pic.getPassNameForClassName(className);
1086a1441ca7STarun Prabhu       return passName.empty() ? className : passName;
1087a1441ca7STarun Prabhu     });
1088a1441ca7STarun Prabhu     llvm::outs() << "\n";
1089a1441ca7STarun Prabhu     return;
1090a1441ca7STarun Prabhu   }
1091a1441ca7STarun Prabhu 
1092869385b1SAndrzej Warzynski   // Run the passes.
1093869385b1SAndrzej Warzynski   mpm.run(*llvmModule, mam);
1094c870632eSMatthias Springer 
1095310c281bSmacurtis-amd   // Print the timers to the associated output stream and reset them.
1096310c281bSmacurtis-amd   if (ci.isTimingEnabled())
1097310c281bSmacurtis-amd     si.getTimePasses().print();
1098310c281bSmacurtis-amd 
1099c870632eSMatthias Springer   // Cleanup
1100c870632eSMatthias Springer   delete tlii;
1101bb177edcSAndrzej Warzynski }
1102bb177edcSAndrzej Warzynski 
110391989c67SVictor Kingi // This class handles optimization remark messages requested if
110491989c67SVictor Kingi // any of -Rpass, -Rpass-analysis or -Rpass-missed flags were provided
110591989c67SVictor Kingi class BackendRemarkConsumer : public llvm::DiagnosticHandler {
110691989c67SVictor Kingi 
110791989c67SVictor Kingi   const CodeGenOptions &codeGenOpts;
110891989c67SVictor Kingi   clang::DiagnosticsEngine &diags;
110991989c67SVictor Kingi 
111091989c67SVictor Kingi public:
111191989c67SVictor Kingi   BackendRemarkConsumer(clang::DiagnosticsEngine &diags,
111291989c67SVictor Kingi                         const CodeGenOptions &codeGenOpts)
111391989c67SVictor Kingi       : codeGenOpts(codeGenOpts), diags(diags) {}
111491989c67SVictor Kingi 
111591989c67SVictor Kingi   bool isAnalysisRemarkEnabled(llvm::StringRef passName) const override {
111691989c67SVictor Kingi     return codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName);
111791989c67SVictor Kingi   }
111891989c67SVictor Kingi   bool isMissedOptRemarkEnabled(llvm::StringRef passName) const override {
111991989c67SVictor Kingi     return codeGenOpts.OptimizationRemarkMissed.patternMatches(passName);
112091989c67SVictor Kingi   }
112191989c67SVictor Kingi   bool isPassedOptRemarkEnabled(llvm::StringRef passName) const override {
112291989c67SVictor Kingi     return codeGenOpts.OptimizationRemark.patternMatches(passName);
112391989c67SVictor Kingi   }
112491989c67SVictor Kingi 
112591989c67SVictor Kingi   bool isAnyRemarkEnabled() const override {
112691989c67SVictor Kingi     return codeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() ||
112791989c67SVictor Kingi            codeGenOpts.OptimizationRemarkMissed.hasValidPattern() ||
112891989c67SVictor Kingi            codeGenOpts.OptimizationRemark.hasValidPattern();
112991989c67SVictor Kingi   }
113091989c67SVictor Kingi 
113191989c67SVictor Kingi   void
113291989c67SVictor Kingi   emitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &diagInfo,
113391989c67SVictor Kingi                           unsigned diagID) {
113491989c67SVictor Kingi     // We only support warnings and remarks.
113591989c67SVictor Kingi     assert(diagInfo.getSeverity() == llvm::DS_Remark ||
113691989c67SVictor Kingi            diagInfo.getSeverity() == llvm::DS_Warning);
113791989c67SVictor Kingi 
113891989c67SVictor Kingi     std::string msg;
113991989c67SVictor Kingi     llvm::raw_string_ostream msgStream(msg);
114012da8ef0SVictor Kingi 
114112da8ef0SVictor Kingi     if (diagInfo.isLocationAvailable()) {
114212da8ef0SVictor Kingi       // Clang contains a SourceManager class which handles loading
114312da8ef0SVictor Kingi       // and caching of source files into memory and it can be used to
114412da8ef0SVictor Kingi       // query SourceLocation data. The SourceLocation data is what is
114512da8ef0SVictor Kingi       // needed here as it contains the full include stack which gives
114612da8ef0SVictor Kingi       // line and column number as well as file name and location.
114712da8ef0SVictor Kingi       // Since Flang doesn't have SourceManager, send file name and absolute
114812da8ef0SVictor Kingi       // path through msgStream, to use for printing.
114912da8ef0SVictor Kingi       msgStream << diagInfo.getLocationStr() << ";;"
115012da8ef0SVictor Kingi                 << diagInfo.getAbsolutePath() << ";;";
115112da8ef0SVictor Kingi     }
115212da8ef0SVictor Kingi 
115391989c67SVictor Kingi     msgStream << diagInfo.getMsg();
115491989c67SVictor Kingi 
115591989c67SVictor Kingi     // Emit message.
115684d7f294SYoungsuk Kim     diags.Report(diagID) << clang::AddFlagValue(diagInfo.getPassName()) << msg;
115791989c67SVictor Kingi   }
115891989c67SVictor Kingi 
115991989c67SVictor Kingi   void optimizationRemarkHandler(
116091989c67SVictor Kingi       const llvm::DiagnosticInfoOptimizationBase &diagInfo) {
116191989c67SVictor Kingi     auto passName = diagInfo.getPassName();
116291989c67SVictor Kingi     if (diagInfo.isPassed()) {
116391989c67SVictor Kingi       if (codeGenOpts.OptimizationRemark.patternMatches(passName))
116491989c67SVictor Kingi         // Optimization remarks are active only if the -Rpass flag has a regular
116591989c67SVictor Kingi         // expression that matches the name of the pass name in \p d.
116691989c67SVictor Kingi         emitOptimizationMessage(
116791989c67SVictor Kingi             diagInfo, clang::diag::remark_fe_backend_optimization_remark);
116891989c67SVictor Kingi 
116991989c67SVictor Kingi       return;
117091989c67SVictor Kingi     }
117191989c67SVictor Kingi 
117291989c67SVictor Kingi     if (diagInfo.isMissed()) {
117391989c67SVictor Kingi       if (codeGenOpts.OptimizationRemarkMissed.patternMatches(passName))
117491989c67SVictor Kingi         // Missed optimization remarks are active only if the -Rpass-missed
117591989c67SVictor Kingi         // flag has a regular expression that matches the name of the pass
117691989c67SVictor Kingi         // name in \p d.
117791989c67SVictor Kingi         emitOptimizationMessage(
117891989c67SVictor Kingi             diagInfo,
117991989c67SVictor Kingi             clang::diag::remark_fe_backend_optimization_remark_missed);
118091989c67SVictor Kingi 
118191989c67SVictor Kingi       return;
118291989c67SVictor Kingi     }
118391989c67SVictor Kingi 
118491989c67SVictor Kingi     assert(diagInfo.isAnalysis() && "Unknown remark type");
118591989c67SVictor Kingi 
118691989c67SVictor Kingi     bool shouldAlwaysPrint = false;
118791989c67SVictor Kingi     auto *ora = llvm::dyn_cast<llvm::OptimizationRemarkAnalysis>(&diagInfo);
118891989c67SVictor Kingi     if (ora)
118991989c67SVictor Kingi       shouldAlwaysPrint = ora->shouldAlwaysPrint();
119091989c67SVictor Kingi 
119191989c67SVictor Kingi     if (shouldAlwaysPrint ||
119291989c67SVictor Kingi         codeGenOpts.OptimizationRemarkAnalysis.patternMatches(passName))
119391989c67SVictor Kingi       emitOptimizationMessage(
119491989c67SVictor Kingi           diagInfo,
119591989c67SVictor Kingi           clang::diag::remark_fe_backend_optimization_remark_analysis);
119691989c67SVictor Kingi   }
119791989c67SVictor Kingi 
119891989c67SVictor Kingi   bool handleDiagnostics(const llvm::DiagnosticInfo &di) override {
119991989c67SVictor Kingi     switch (di.getKind()) {
120091989c67SVictor Kingi     case llvm::DK_OptimizationRemark:
120191989c67SVictor Kingi       optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemark>(di));
120291989c67SVictor Kingi       break;
120391989c67SVictor Kingi     case llvm::DK_OptimizationRemarkMissed:
120491989c67SVictor Kingi       optimizationRemarkHandler(llvm::cast<llvm::OptimizationRemarkMissed>(di));
120591989c67SVictor Kingi       break;
120691989c67SVictor Kingi     case llvm::DK_OptimizationRemarkAnalysis:
120791989c67SVictor Kingi       optimizationRemarkHandler(
120891989c67SVictor Kingi           llvm::cast<llvm::OptimizationRemarkAnalysis>(di));
120991989c67SVictor Kingi       break;
1210e87d2d2cSVictor Kingi     case llvm::DK_MachineOptimizationRemark:
1211e87d2d2cSVictor Kingi       optimizationRemarkHandler(
1212e87d2d2cSVictor Kingi           llvm::cast<llvm::MachineOptimizationRemark>(di));
1213e87d2d2cSVictor Kingi       break;
1214e87d2d2cSVictor Kingi     case llvm::DK_MachineOptimizationRemarkMissed:
1215e87d2d2cSVictor Kingi       optimizationRemarkHandler(
1216e87d2d2cSVictor Kingi           llvm::cast<llvm::MachineOptimizationRemarkMissed>(di));
1217e87d2d2cSVictor Kingi       break;
1218e87d2d2cSVictor Kingi     case llvm::DK_MachineOptimizationRemarkAnalysis:
1219e87d2d2cSVictor Kingi       optimizationRemarkHandler(
1220e87d2d2cSVictor Kingi           llvm::cast<llvm::MachineOptimizationRemarkAnalysis>(di));
1221e87d2d2cSVictor Kingi       break;
122291989c67SVictor Kingi     default:
122391989c67SVictor Kingi       break;
122491989c67SVictor Kingi     }
122591989c67SVictor Kingi     return true;
122691989c67SVictor Kingi   }
122791989c67SVictor Kingi };
122891989c67SVictor Kingi 
122940d8c066SJan Sjodin void CodeGenAction::embedOffloadObjects() {
123040d8c066SJan Sjodin   CompilerInstance &ci = this->getInstance();
123140d8c066SJan Sjodin   const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
123240d8c066SJan Sjodin 
123340d8c066SJan Sjodin   for (llvm::StringRef offloadObject : cgOpts.OffloadObjects) {
123440d8c066SJan Sjodin     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> objectOrErr =
123540d8c066SJan Sjodin         llvm::MemoryBuffer::getFileOrSTDIN(offloadObject);
123640d8c066SJan Sjodin     if (std::error_code ec = objectOrErr.getError()) {
123740d8c066SJan Sjodin       auto diagID = ci.getDiagnostics().getCustomDiagID(
123840d8c066SJan Sjodin           clang::DiagnosticsEngine::Error, "could not open '%0' for embedding");
123940d8c066SJan Sjodin       ci.getDiagnostics().Report(diagID) << offloadObject;
124040d8c066SJan Sjodin       return;
124140d8c066SJan Sjodin     }
124240d8c066SJan Sjodin     llvm::embedBufferInModule(
124340d8c066SJan Sjodin         *llvmModule, **objectOrErr, ".llvm.offloading",
124440d8c066SJan Sjodin         llvm::Align(llvm::object::OffloadBinary::getAlignment()));
124540d8c066SJan Sjodin   }
124640d8c066SJan Sjodin }
124740d8c066SJan Sjodin 
1248b75e7c61SJan Leyonberg void CodeGenAction::linkBuiltinBCLibs() {
1249b75e7c61SJan Leyonberg   auto options = clang::FileSystemOptions();
1250b75e7c61SJan Leyonberg   clang::FileManager fileManager(options);
1251b75e7c61SJan Leyonberg   CompilerInstance &ci = this->getInstance();
1252b75e7c61SJan Leyonberg   const auto &cgOpts = ci.getInvocation().getCodeGenOpts();
1253b75e7c61SJan Leyonberg 
1254b75e7c61SJan Leyonberg   std::vector<std::unique_ptr<llvm::Module>> modules;
1255b75e7c61SJan Leyonberg 
1256b75e7c61SJan Leyonberg   // Load LLVM modules
1257b75e7c61SJan Leyonberg   for (llvm::StringRef bcLib : cgOpts.BuiltinBCLibs) {
1258b75e7c61SJan Leyonberg     auto BCBuf = fileManager.getBufferForFile(bcLib);
1259b75e7c61SJan Leyonberg     if (!BCBuf) {
1260b75e7c61SJan Leyonberg       auto diagID = ci.getDiagnostics().getCustomDiagID(
1261b75e7c61SJan Leyonberg           clang::DiagnosticsEngine::Error, "could not open '%0' for linking");
1262b75e7c61SJan Leyonberg       ci.getDiagnostics().Report(diagID) << bcLib;
1263b75e7c61SJan Leyonberg       return;
1264b75e7c61SJan Leyonberg     }
1265b75e7c61SJan Leyonberg 
1266b75e7c61SJan Leyonberg     llvm::Expected<std::unique_ptr<llvm::Module>> ModuleOrErr =
1267b75e7c61SJan Leyonberg         getOwningLazyBitcodeModule(std::move(*BCBuf), *llvmCtx);
1268b75e7c61SJan Leyonberg     if (!ModuleOrErr) {
1269b75e7c61SJan Leyonberg       auto diagID = ci.getDiagnostics().getCustomDiagID(
1270b75e7c61SJan Leyonberg           clang::DiagnosticsEngine::Error, "error loading '%0' for linking");
1271b75e7c61SJan Leyonberg       ci.getDiagnostics().Report(diagID) << bcLib;
1272b75e7c61SJan Leyonberg       return;
1273b75e7c61SJan Leyonberg     }
1274b75e7c61SJan Leyonberg     modules.push_back(std::move(ModuleOrErr.get()));
1275b75e7c61SJan Leyonberg   }
1276b75e7c61SJan Leyonberg 
1277b75e7c61SJan Leyonberg   // Link modules and internalize functions
1278b75e7c61SJan Leyonberg   for (auto &module : modules) {
1279b75e7c61SJan Leyonberg     bool Err;
1280b75e7c61SJan Leyonberg     Err = llvm::Linker::linkModules(
1281b75e7c61SJan Leyonberg         *llvmModule, std::move(module), llvm::Linker::Flags::LinkOnlyNeeded,
1282b75e7c61SJan Leyonberg         [](llvm::Module &M, const llvm::StringSet<> &GVS) {
1283b75e7c61SJan Leyonberg           llvm::internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) {
1284b75e7c61SJan Leyonberg             return !GV.hasName() || (GVS.count(GV.getName()) == 0);
1285b75e7c61SJan Leyonberg           });
1286b75e7c61SJan Leyonberg         });
1287b75e7c61SJan Leyonberg     if (Err) {
1288b75e7c61SJan Leyonberg       auto diagID = ci.getDiagnostics().getCustomDiagID(
1289b75e7c61SJan Leyonberg           clang::DiagnosticsEngine::Error, "link error when linking '%0'");
1290b75e7c61SJan Leyonberg       ci.getDiagnostics().Report(diagID) << module->getSourceFileName();
1291b75e7c61SJan Leyonberg       return;
1292b75e7c61SJan Leyonberg     }
1293b75e7c61SJan Leyonberg   }
1294b75e7c61SJan Leyonberg }
1295b75e7c61SJan Leyonberg 
1296f04ccadfSVictor Kingi static void reportOptRecordError(llvm::Error e, clang::DiagnosticsEngine &diags,
1297f04ccadfSVictor Kingi                                  const CodeGenOptions &codeGenOpts) {
1298f04ccadfSVictor Kingi   handleAllErrors(
1299f04ccadfSVictor Kingi       std::move(e),
1300f04ccadfSVictor Kingi       [&](const llvm::LLVMRemarkSetupFileError &e) {
1301f04ccadfSVictor Kingi         diags.Report(clang::diag::err_cannot_open_file)
1302f04ccadfSVictor Kingi             << codeGenOpts.OptRecordFile << e.message();
1303f04ccadfSVictor Kingi       },
1304f04ccadfSVictor Kingi       [&](const llvm::LLVMRemarkSetupPatternError &e) {
1305f04ccadfSVictor Kingi         diags.Report(clang::diag::err_drv_optimization_remark_pattern)
1306f04ccadfSVictor Kingi             << e.message() << codeGenOpts.OptRecordPasses;
1307f04ccadfSVictor Kingi       },
1308f04ccadfSVictor Kingi       [&](const llvm::LLVMRemarkSetupFormatError &e) {
1309f04ccadfSVictor Kingi         diags.Report(clang::diag::err_drv_optimization_remark_format)
1310f04ccadfSVictor Kingi             << codeGenOpts.OptRecordFormat;
1311f04ccadfSVictor Kingi       });
1312f04ccadfSVictor Kingi }
1313f04ccadfSVictor Kingi 
13141e462fafSAndrzej Warzynski void CodeGenAction::executeAction() {
13151e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
131638101b4eSAndrzej Warzynski 
1317f04ccadfSVictor Kingi   clang::DiagnosticsEngine &diags = ci.getDiagnostics();
1318f04ccadfSVictor Kingi   const CodeGenOptions &codeGenOpts = ci.getInvocation().getCodeGenOpts();
1319f04ccadfSVictor Kingi   Fortran::lower::LoweringOptions &loweringOpts =
1320f04ccadfSVictor Kingi       ci.getInvocation().getLoweringOpts();
1321310c281bSmacurtis-amd   mlir::DefaultTimingManager &timingMgr = ci.getTimingManager();
1322310c281bSmacurtis-amd   mlir::TimingScope &timingScopeRoot = ci.getTimingScopeRoot();
1323f04ccadfSVictor Kingi 
132438101b4eSAndrzej Warzynski   // If the output stream is a file, generate it and define the corresponding
132538101b4eSAndrzej Warzynski   // output stream. If a pre-defined output stream is available, we will use
132638101b4eSAndrzej Warzynski   // that instead.
132738101b4eSAndrzej Warzynski   //
132838101b4eSAndrzej Warzynski   // NOTE: `os` is a smart pointer that will be destroyed at the end of this
13291e462fafSAndrzej Warzynski   // method. However, it won't be written to until `codeGenPasses` is
13301e462fafSAndrzej Warzynski   // destroyed. By defining `os` before `codeGenPasses`, we make sure that the
133138101b4eSAndrzej Warzynski   // output stream won't be destroyed before it is written to. This only
133238101b4eSAndrzej Warzynski   // applies when an output file is used (i.e. there is no pre-defined output
133338101b4eSAndrzej Warzynski   // stream).
13341e462fafSAndrzej Warzynski   // TODO: Revisit once the new PM is ready (i.e. when `codeGenPasses` is
133538101b4eSAndrzej Warzynski   // updated to use it).
133638101b4eSAndrzej Warzynski   std::unique_ptr<llvm::raw_pwrite_stream> os;
13371e462fafSAndrzej Warzynski   if (ci.isOutputStreamNull()) {
13381e462fafSAndrzej Warzynski     os = getOutputStream(ci, getCurrentFileOrBufferName(), action);
1339bb177edcSAndrzej Warzynski 
134038101b4eSAndrzej Warzynski     if (!os) {
1341f04ccadfSVictor Kingi       unsigned diagID = diags.getCustomDiagID(
134238101b4eSAndrzej Warzynski           clang::DiagnosticsEngine::Error, "failed to create the output file");
1343f04ccadfSVictor Kingi       diags.Report(diagID);
134438101b4eSAndrzej Warzynski       return;
134538101b4eSAndrzej Warzynski     }
134638101b4eSAndrzej Warzynski   }
134738101b4eSAndrzej Warzynski 
134839ecf9d8STom Eccles   if (action == BackendActionTy::Backend_EmitFIR) {
1349f04ccadfSVictor Kingi     if (loweringOpts.getLowerToHighLevelFIR()) {
135039ecf9d8STom Eccles       lowerHLFIRToFIR();
135139ecf9d8STom Eccles     }
135239ecf9d8STom Eccles     mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
135339ecf9d8STom Eccles     return;
135439ecf9d8STom Eccles   }
135539ecf9d8STom Eccles 
135639ecf9d8STom Eccles   if (action == BackendActionTy::Backend_EmitHLFIR) {
1357f04ccadfSVictor Kingi     assert(loweringOpts.getLowerToHighLevelFIR() &&
135839ecf9d8STom Eccles            "Lowering must have been configured to emit HLFIR");
13591e462fafSAndrzej Warzynski     mlirModule->print(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
136038101b4eSAndrzej Warzynski     return;
136138101b4eSAndrzej Warzynski   }
136238101b4eSAndrzej Warzynski 
1363869385b1SAndrzej Warzynski   // Generate an LLVM module if it's not already present (it will already be
1364bb177edcSAndrzej Warzynski   // present if the input file is an LLVM IR/BC file).
1365bb177edcSAndrzej Warzynski   if (!llvmModule)
13661e462fafSAndrzej Warzynski     generateLLVMIR();
1367bb177edcSAndrzej Warzynski 
1368310c281bSmacurtis-amd   // This will already have been started in generateLLVMIR(). But we need to
1369310c281bSmacurtis-amd   // continue operating on the module, so we continue timing it.
1370310c281bSmacurtis-amd   mlir::TimingScope timingScopeLLVMIRGen = timingScopeRoot.nest(
1371310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdLLVMIRGen, timingMgr));
1372310c281bSmacurtis-amd 
137310317da2SKareem Ergawy   // If generating the LLVM module failed, abort! No need for further error
137410317da2SKareem Ergawy   // reporting since generateLLVMIR() does this already.
137510317da2SKareem Ergawy   if (!llvmModule)
137610317da2SKareem Ergawy     return;
137710317da2SKareem Ergawy 
137881181089SMats Petersson   // Set the triple based on the targetmachine (this comes compiler invocation
137981181089SMats Petersson   // and the command-line target option if specified, or the default if not
138081181089SMats Petersson   // given on the command-line).
1381e59e8488SjeanPerier   llvm::TargetMachine &targetMachine = ci.getTargetMachine();
13829e6b46a9SDavid Truby 
1383e59e8488SjeanPerier   const std::string &theTriple = targetMachine.getTargetTriple().str();
138481181089SMats Petersson 
138581181089SMats Petersson   if (llvmModule->getTargetTriple() != theTriple) {
1386f04ccadfSVictor Kingi     diags.Report(clang::diag::warn_fe_override_module) << theTriple;
138781181089SMats Petersson   }
138840d8c066SJan Sjodin 
138981181089SMats Petersson   // Always set the triple and data layout, to make sure they match and are set.
139081181089SMats Petersson   // Note that this overwrites any datalayout stored in the LLVM-IR. This avoids
139181181089SMats Petersson   // an assert for incompatible data layout when the code-generation happens.
139281181089SMats Petersson   llvmModule->setTargetTriple(theTriple);
1393e59e8488SjeanPerier   llvmModule->setDataLayout(targetMachine.createDataLayout());
139481181089SMats Petersson 
1395b75e7c61SJan Leyonberg   // Link in builtin bitcode libraries
1396b75e7c61SJan Leyonberg   if (!codeGenOpts.BuiltinBCLibs.empty())
1397b75e7c61SJan Leyonberg     linkBuiltinBCLibs();
1398b75e7c61SJan Leyonberg 
139940d8c066SJan Sjodin   // Embed offload objects specified with -fembed-offload-object
1400f04ccadfSVictor Kingi   if (!codeGenOpts.OffloadObjects.empty())
140140d8c066SJan Sjodin     embedOffloadObjects();
1402310c281bSmacurtis-amd   timingScopeLLVMIRGen.stop();
140340d8c066SJan Sjodin 
140491989c67SVictor Kingi   BackendRemarkConsumer remarkConsumer(diags, codeGenOpts);
140591989c67SVictor Kingi 
140691989c67SVictor Kingi   llvmModule->getContext().setDiagnosticHandler(
140791989c67SVictor Kingi       std::make_unique<BackendRemarkConsumer>(remarkConsumer));
140891989c67SVictor Kingi 
1409f04ccadfSVictor Kingi   // write optimization-record
1410f04ccadfSVictor Kingi   llvm::Expected<std::unique_ptr<llvm::ToolOutputFile>> optRecordFileOrErr =
1411f04ccadfSVictor Kingi       setupLLVMOptimizationRemarks(
1412f04ccadfSVictor Kingi           llvmModule->getContext(), codeGenOpts.OptRecordFile,
1413f04ccadfSVictor Kingi           codeGenOpts.OptRecordPasses, codeGenOpts.OptRecordFormat,
1414f04ccadfSVictor Kingi           /*DiagnosticsWithHotness=*/false,
1415f04ccadfSVictor Kingi           /*DiagnosticsHotnessThreshold=*/0);
1416f04ccadfSVictor Kingi 
1417f04ccadfSVictor Kingi   if (llvm::Error e = optRecordFileOrErr.takeError()) {
1418f04ccadfSVictor Kingi     reportOptRecordError(std::move(e), diags, codeGenOpts);
1419f04ccadfSVictor Kingi     return;
1420f04ccadfSVictor Kingi   }
1421f04ccadfSVictor Kingi 
1422f04ccadfSVictor Kingi   std::unique_ptr<llvm::ToolOutputFile> optRecordFile =
1423f04ccadfSVictor Kingi       std::move(*optRecordFileOrErr);
1424f04ccadfSVictor Kingi 
1425f04ccadfSVictor Kingi   if (optRecordFile) {
1426f04ccadfSVictor Kingi     optRecordFile->keep();
1427f04ccadfSVictor Kingi     optRecordFile->os().flush();
1428f04ccadfSVictor Kingi   }
1429f04ccadfSVictor Kingi 
1430869385b1SAndrzej Warzynski   // Run LLVM's middle-end (i.e. the optimizer).
1431310c281bSmacurtis-amd   mlir::TimingScope timingScopeLLVMIRPasses = timingScopeRoot.nest(
1432310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdLLVMIRPasses, timingMgr));
1433e054e0daSSlava Zakharin   runOptimizationPipeline(ci.isOutputStreamNull() ? *os : ci.getOutputStream());
1434310c281bSmacurtis-amd   timingScopeLLVMIRPasses.stop();
1435869385b1SAndrzej Warzynski 
14369b468388SStephen Tozer   if (action == BackendActionTy::Backend_EmitLL ||
14379b468388SStephen Tozer       action == BackendActionTy::Backend_EmitBC) {
1438869385b1SAndrzej Warzynski     // This action has effectively been completed in runOptimizationPipeline.
1439bb177edcSAndrzej Warzynski     return;
1440bb177edcSAndrzej Warzynski   }
1441bb177edcSAndrzej Warzynski 
1442869385b1SAndrzej Warzynski   // Run LLVM's backend and generate either assembly or machine code
1443310c281bSmacurtis-amd   mlir::TimingScope timingScopeBackend = timingScopeRoot.nest(
1444310c281bSmacurtis-amd       mlir::TimingIdentifier::get(timingIdBackend, timingMgr));
1445bb177edcSAndrzej Warzynski   if (action == BackendActionTy::Backend_EmitAssembly ||
1446bb177edcSAndrzej Warzynski       action == BackendActionTy::Backend_EmitObj) {
14471e462fafSAndrzej Warzynski     generateMachineCodeOrAssemblyImpl(
1448e59e8488SjeanPerier         diags, targetMachine, action, *llvmModule, codeGenOpts,
14491e462fafSAndrzej Warzynski         ci.isOutputStreamNull() ? *os : ci.getOutputStream());
1450310c281bSmacurtis-amd     if (timingMgr.isEnabled())
1451310c281bSmacurtis-amd       llvm::reportAndResetTimings(&ci.getTimingStreamCodeGen());
1452bb177edcSAndrzej Warzynski     return;
1453bb177edcSAndrzej Warzynski   }
1454e5cdb6c5SAndrzej Warzynski }
1455e1da3297SStuart Ellis 
14561e462fafSAndrzej Warzynski void InitOnlyAction::executeAction() {
14571e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
14581e462fafSAndrzej Warzynski   unsigned diagID = ci.getDiagnostics().getCustomDiagID(
14591e462fafSAndrzej Warzynski       clang::DiagnosticsEngine::Warning,
1460e1da3297SStuart Ellis       "Use `-init-only` for testing purposes only");
14611e462fafSAndrzej Warzynski   ci.getDiagnostics().Report(diagID);
1462e1da3297SStuart Ellis }
1463f52fc591SStuart Ellis 
14641e462fafSAndrzej Warzynski void PluginParseTreeAction::executeAction() {}
14658321579bSAndrzej Warzynski 
14661e462fafSAndrzej Warzynski void DebugDumpPFTAction::executeAction() {
14671e462fafSAndrzej Warzynski   CompilerInstance &ci = this->getInstance();
14688321579bSAndrzej Warzynski 
14691e462fafSAndrzej Warzynski   if (auto ast = Fortran::lower::createPFT(*ci.getParsing().parseTree(),
14701e462fafSAndrzej Warzynski                                            ci.getSemantics().context())) {
14718321579bSAndrzej Warzynski     Fortran::lower::dumpPFT(llvm::outs(), *ast);
14728321579bSAndrzej Warzynski     return;
14738321579bSAndrzej Warzynski   }
14748321579bSAndrzej Warzynski 
14751e462fafSAndrzej Warzynski   unsigned diagID = ci.getDiagnostics().getCustomDiagID(
14768321579bSAndrzej Warzynski       clang::DiagnosticsEngine::Error, "Pre FIR Tree is NULL.");
14771e462fafSAndrzej Warzynski   ci.getDiagnostics().Report(diagID);
14788321579bSAndrzej Warzynski }
14792186a4aeSAndrzej Warzynski 
14802186a4aeSAndrzej Warzynski Fortran::parser::Parsing &PluginParseTreeAction::getParsing() {
14811e462fafSAndrzej Warzynski   return getInstance().getParsing();
14822186a4aeSAndrzej Warzynski }
14832186a4aeSAndrzej Warzynski 
14842186a4aeSAndrzej Warzynski std::unique_ptr<llvm::raw_pwrite_stream>
14852186a4aeSAndrzej Warzynski PluginParseTreeAction::createOutputFile(llvm::StringRef extension = "") {
14862186a4aeSAndrzej Warzynski 
14871e462fafSAndrzej Warzynski   std::unique_ptr<llvm::raw_pwrite_stream> os{
14881e462fafSAndrzej Warzynski       getInstance().createDefaultOutputFile(
14891e462fafSAndrzej Warzynski           /*Binary=*/false, /*InFile=*/getCurrentFileOrBufferName(),
14902186a4aeSAndrzej Warzynski           extension)};
14911e462fafSAndrzej Warzynski   return os;
14922186a4aeSAndrzej Warzynski }
1493