1 | //===--- ExecuteCompilerInvocation.cpp ------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file holds ExecuteCompilerInvocation(). It is split into its own file to |
10 | // minimize the impact of pulling in essentially everything else in Flang. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | // |
14 | // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
15 | // |
16 | //===----------------------------------------------------------------------===// |
17 | |
18 | #include "flang/Frontend/CompilerInstance.h" |
19 | #include "flang/Frontend/FrontendActions.h" |
20 | #include "flang/Frontend/FrontendPluginRegistry.h" |
21 | |
22 | #include "mlir/IR/AsmState.h" |
23 | #include "mlir/IR/MLIRContext.h" |
24 | #include "mlir/Pass/PassManager.h" |
25 | #include "clang/Basic/DiagnosticFrontend.h" |
26 | #include "clang/Driver/Options.h" |
27 | #include "llvm/Option/OptTable.h" |
28 | #include "llvm/Option/Option.h" |
29 | #include "llvm/Support/BuryPointer.h" |
30 | #include "llvm/Support/CommandLine.h" |
31 | |
32 | namespace Fortran::frontend { |
33 | |
34 | static std::unique_ptr<FrontendAction> |
35 | createFrontendAction(CompilerInstance &ci) { |
36 | |
37 | switch (ci.getFrontendOpts().programAction) { |
38 | case InputOutputTest: |
39 | return std::make_unique<InputOutputTestAction>(); |
40 | case PrintPreprocessedInput: |
41 | return std::make_unique<PrintPreprocessedAction>(); |
42 | case ParseSyntaxOnly: |
43 | return std::make_unique<ParseSyntaxOnlyAction>(); |
44 | case EmitFIR: |
45 | return std::make_unique<EmitFIRAction>(); |
46 | case EmitHLFIR: |
47 | return std::make_unique<EmitHLFIRAction>(); |
48 | case EmitLLVM: |
49 | return std::make_unique<EmitLLVMAction>(); |
50 | case EmitLLVMBitcode: |
51 | return std::make_unique<EmitLLVMBitcodeAction>(); |
52 | case EmitObj: |
53 | return std::make_unique<EmitObjAction>(); |
54 | case EmitAssembly: |
55 | return std::make_unique<EmitAssemblyAction>(); |
56 | case DebugUnparse: |
57 | return std::make_unique<DebugUnparseAction>(); |
58 | case DebugUnparseNoSema: |
59 | return std::make_unique<DebugUnparseNoSemaAction>(); |
60 | case DebugUnparseWithSymbols: |
61 | return std::make_unique<DebugUnparseWithSymbolsAction>(); |
62 | case DebugUnparseWithModules: |
63 | return std::make_unique<DebugUnparseWithModulesAction>(); |
64 | case DebugDumpSymbols: |
65 | return std::make_unique<DebugDumpSymbolsAction>(); |
66 | case DebugDumpParseTree: |
67 | return std::make_unique<DebugDumpParseTreeAction>(); |
68 | case DebugDumpPFT: |
69 | return std::make_unique<DebugDumpPFTAction>(); |
70 | case DebugDumpParseTreeNoSema: |
71 | return std::make_unique<DebugDumpParseTreeNoSemaAction>(); |
72 | case DebugDumpAll: |
73 | return std::make_unique<DebugDumpAllAction>(); |
74 | case DebugDumpProvenance: |
75 | return std::make_unique<DebugDumpProvenanceAction>(); |
76 | case DebugDumpParsingLog: |
77 | return std::make_unique<DebugDumpParsingLogAction>(); |
78 | case DebugMeasureParseTree: |
79 | return std::make_unique<DebugMeasureParseTreeAction>(); |
80 | case DebugPreFIRTree: |
81 | return std::make_unique<DebugPreFIRTreeAction>(); |
82 | case GetDefinition: |
83 | return std::make_unique<GetDefinitionAction>(); |
84 | case GetSymbolsSources: |
85 | return std::make_unique<GetSymbolsSourcesAction>(); |
86 | case InitOnly: |
87 | return std::make_unique<InitOnlyAction>(); |
88 | case PluginAction: { |
89 | for (const FrontendPluginRegistry::entry &plugin : |
90 | FrontendPluginRegistry::entries()) { |
91 | if (plugin.getName() == ci.getFrontendOpts().actionName) { |
92 | std::unique_ptr<PluginParseTreeAction> p(plugin.instantiate()); |
93 | return std::move(p); |
94 | } |
95 | } |
96 | unsigned diagID = ci.getDiagnostics().getCustomDiagID( |
97 | clang::DiagnosticsEngine::Error, "unable to find plugin '%0'" ); |
98 | ci.getDiagnostics().Report(diagID) << ci.getFrontendOpts().actionName; |
99 | return nullptr; |
100 | } |
101 | } |
102 | |
103 | llvm_unreachable("Invalid program action!" ); |
104 | } |
105 | |
106 | static void emitUnknownDiagWarning(clang::DiagnosticsEngine &diags, |
107 | clang::diag::Flavor flavor, |
108 | llvm::StringRef prefix, |
109 | llvm::StringRef opt) { |
110 | llvm::StringRef suggestion = |
111 | clang::DiagnosticIDs::getNearestOption(Flavor: flavor, Group: opt); |
112 | diags.Report(clang::diag::warn_unknown_diag_option) |
113 | << (flavor == clang::diag::Flavor::WarningOrError ? 0 : 1) |
114 | << (prefix.str() += std::string(opt)) << !suggestion.empty() |
115 | << (prefix.str() += std::string(suggestion)); |
116 | } |
117 | |
118 | // Remarks are ignored by default in Diagnostic.td, hence, we have to |
119 | // enable them here before execution. Clang follows same idea using |
120 | // ProcessWarningOptions in Warnings.cpp |
121 | // This function is also responsible for emitting early warnings for |
122 | // invalid -R options. |
123 | static void |
124 | (clang::DiagnosticsEngine &diagsEng, |
125 | const clang::DiagnosticOptions &opts) { |
126 | llvm::SmallVector<clang::diag::kind, 10> diags; |
127 | const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs = |
128 | diagsEng.getDiagnosticIDs(); |
129 | |
130 | for (unsigned i = 0; i < opts.Remarks.size(); i++) { |
131 | llvm::StringRef = opts.Remarks[i]; |
132 | const auto flavor = clang::diag::Flavor::Remark; |
133 | |
134 | // Check to see if this opt starts with "no-", if so, this is a |
135 | // negative form of the option. |
136 | bool isPositive = !remarkOpt.starts_with(Prefix: "no-" ); |
137 | if (!isPositive) |
138 | remarkOpt = remarkOpt.substr(Start: 3); |
139 | |
140 | // Verify that this is a valid optimization remarks option |
141 | if (diagIDs->getDiagnosticsInGroup(Flavor: flavor, Group: remarkOpt, Diags&: diags)) { |
142 | emitUnknownDiagWarning(diags&: diagsEng, flavor, prefix: isPositive ? "-R" : "-Rno-" , |
143 | opt: remarkOpt); |
144 | return; |
145 | } |
146 | |
147 | diagsEng.setSeverityForGroup(Flavor: flavor, Group: remarkOpt, |
148 | Map: isPositive ? clang::diag::Severity::Remark |
149 | : clang::diag::Severity::Ignored); |
150 | } |
151 | } |
152 | |
153 | bool executeCompilerInvocation(CompilerInstance *flang) { |
154 | // Honor -help. |
155 | if (flang->getFrontendOpts().showHelp) { |
156 | clang::driver::getDriverOptTable().printHelp( |
157 | OS&: llvm::outs(), Usage: "flang -fc1 [options] file..." , Title: "LLVM 'Flang' Compiler" , |
158 | /*ShowHidden=*/false, /*ShowAllAliases=*/false, |
159 | VisibilityMask: llvm::opt::Visibility(clang::driver::options::FC1Option)); |
160 | return true; |
161 | } |
162 | |
163 | // Honor -version. |
164 | if (flang->getFrontendOpts().showVersion) { |
165 | llvm::cl::PrintVersionMessage(); |
166 | return true; |
167 | } |
168 | |
169 | // Load any requested plugins. |
170 | for (const std::string &path : flang->getFrontendOpts().plugins) { |
171 | std::string error; |
172 | if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(path.c_str(), |
173 | &error)) { |
174 | unsigned diagID = flang->getDiagnostics().getCustomDiagID( |
175 | clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'" ); |
176 | flang->getDiagnostics().Report(diagID) << path << error; |
177 | } |
178 | } |
179 | |
180 | // Honor -mllvm. This should happen AFTER plugins have been loaded! |
181 | if (!flang->getFrontendOpts().llvmArgs.empty()) { |
182 | unsigned numArgs = flang->getFrontendOpts().llvmArgs.size(); |
183 | auto args = std::make_unique<const char *[]>(num: numArgs + 2); |
184 | args[0] = "flang (LLVM option parsing)" ; |
185 | |
186 | for (unsigned i = 0; i != numArgs; ++i) |
187 | args[i + 1] = flang->getFrontendOpts().llvmArgs[i].c_str(); |
188 | |
189 | args[numArgs + 1] = nullptr; |
190 | llvm::cl::ParseCommandLineOptions(argc: numArgs + 1, argv: args.get()); |
191 | } |
192 | |
193 | // Honor -mmlir. This should happen AFTER plugins have been loaded! |
194 | if (!flang->getFrontendOpts().mlirArgs.empty()) { |
195 | mlir::registerMLIRContextCLOptions(); |
196 | mlir::registerPassManagerCLOptions(); |
197 | mlir::registerAsmPrinterCLOptions(); |
198 | unsigned numArgs = flang->getFrontendOpts().mlirArgs.size(); |
199 | auto args = std::make_unique<const char *[]>(num: numArgs + 2); |
200 | args[0] = "flang (MLIR option parsing)" ; |
201 | |
202 | for (unsigned i = 0; i != numArgs; ++i) |
203 | args[i + 1] = flang->getFrontendOpts().mlirArgs[i].c_str(); |
204 | |
205 | args[numArgs + 1] = nullptr; |
206 | llvm::cl::ParseCommandLineOptions(argc: numArgs + 1, argv: args.get()); |
207 | } |
208 | |
209 | // If there were errors in processing arguments, don't do anything else. |
210 | if (flang->getDiagnostics().hasErrorOccurred()) { |
211 | return false; |
212 | } |
213 | |
214 | updateDiagEngineForOptRemarks(flang->getDiagnostics(), |
215 | flang->getDiagnosticOpts()); |
216 | |
217 | // Create and execute the frontend action. |
218 | std::unique_ptr<FrontendAction> act(createFrontendAction(*flang)); |
219 | if (!act) |
220 | return false; |
221 | |
222 | bool success = flang->executeAction(*act); |
223 | return success; |
224 | } |
225 | |
226 | } // namespace Fortran::frontend |
227 | |