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 DebugDumpSymbols: |
63 | return std::make_unique<DebugDumpSymbolsAction>(); |
64 | case DebugDumpParseTree: |
65 | return std::make_unique<DebugDumpParseTreeAction>(); |
66 | case DebugDumpPFT: |
67 | return std::make_unique<DebugDumpPFTAction>(); |
68 | case DebugDumpParseTreeNoSema: |
69 | return std::make_unique<DebugDumpParseTreeNoSemaAction>(); |
70 | case DebugDumpAll: |
71 | return std::make_unique<DebugDumpAllAction>(); |
72 | case DebugDumpProvenance: |
73 | return std::make_unique<DebugDumpProvenanceAction>(); |
74 | case DebugDumpParsingLog: |
75 | return std::make_unique<DebugDumpParsingLogAction>(); |
76 | case DebugMeasureParseTree: |
77 | return std::make_unique<DebugMeasureParseTreeAction>(); |
78 | case DebugPreFIRTree: |
79 | return std::make_unique<DebugPreFIRTreeAction>(); |
80 | case GetDefinition: |
81 | return std::make_unique<GetDefinitionAction>(); |
82 | case GetSymbolsSources: |
83 | return std::make_unique<GetSymbolsSourcesAction>(); |
84 | case InitOnly: |
85 | return std::make_unique<InitOnlyAction>(); |
86 | case PluginAction: { |
87 | for (const FrontendPluginRegistry::entry &plugin : |
88 | FrontendPluginRegistry::entries()) { |
89 | if (plugin.getName() == ci.getFrontendOpts().actionName) { |
90 | std::unique_ptr<PluginParseTreeAction> p(plugin.instantiate()); |
91 | return std::move(p); |
92 | } |
93 | } |
94 | unsigned diagID = ci.getDiagnostics().getCustomDiagID( |
95 | clang::DiagnosticsEngine::Error, "unable to find plugin '%0'" ); |
96 | ci.getDiagnostics().Report(diagID) << ci.getFrontendOpts().actionName; |
97 | return nullptr; |
98 | } |
99 | } |
100 | |
101 | llvm_unreachable("Invalid program action!" ); |
102 | } |
103 | |
104 | static void emitUnknownDiagWarning(clang::DiagnosticsEngine &diags, |
105 | clang::diag::Flavor flavor, |
106 | llvm::StringRef prefix, |
107 | llvm::StringRef opt) { |
108 | llvm::StringRef suggestion = |
109 | clang::DiagnosticIDs::getNearestOption(Flavor: flavor, Group: opt); |
110 | diags.Report(clang::diag::warn_unknown_diag_option) |
111 | << (flavor == clang::diag::Flavor::WarningOrError ? 0 : 1) |
112 | << (prefix.str() += std::string(opt)) << !suggestion.empty() |
113 | << (prefix.str() += std::string(suggestion)); |
114 | } |
115 | |
116 | // Remarks are ignored by default in Diagnostic.td, hence, we have to |
117 | // enable them here before execution. Clang follows same idea using |
118 | // ProcessWarningOptions in Warnings.cpp |
119 | // This function is also responsible for emitting early warnings for |
120 | // invalid -R options. |
121 | static void |
122 | (clang::DiagnosticsEngine &diagsEng, |
123 | const clang::DiagnosticOptions &opts) { |
124 | llvm::SmallVector<clang::diag::kind, 10> diags; |
125 | const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs = |
126 | diagsEng.getDiagnosticIDs(); |
127 | |
128 | for (unsigned i = 0; i < opts.Remarks.size(); i++) { |
129 | llvm::StringRef = opts.Remarks[i]; |
130 | const auto flavor = clang::diag::Flavor::Remark; |
131 | |
132 | // Check to see if this opt starts with "no-", if so, this is a |
133 | // negative form of the option. |
134 | bool isPositive = !remarkOpt.starts_with(Prefix: "no-" ); |
135 | if (!isPositive) |
136 | remarkOpt = remarkOpt.substr(Start: 3); |
137 | |
138 | // Verify that this is a valid optimization remarks option |
139 | if (diagIDs->getDiagnosticsInGroup(Flavor: flavor, Group: remarkOpt, Diags&: diags)) { |
140 | emitUnknownDiagWarning(diags&: diagsEng, flavor, prefix: isPositive ? "-R" : "-Rno-" , |
141 | opt: remarkOpt); |
142 | return; |
143 | } |
144 | |
145 | diagsEng.setSeverityForGroup(Flavor: flavor, Group: remarkOpt, |
146 | Map: isPositive ? clang::diag::Severity::Remark |
147 | : clang::diag::Severity::Ignored); |
148 | } |
149 | } |
150 | |
151 | bool executeCompilerInvocation(CompilerInstance *flang) { |
152 | // Honor -help. |
153 | if (flang->getFrontendOpts().showHelp) { |
154 | clang::driver::getDriverOptTable().printHelp( |
155 | OS&: llvm::outs(), Usage: "flang-new -fc1 [options] file..." , |
156 | Title: "LLVM 'Flang' Compiler" , |
157 | /*ShowHidden=*/false, /*ShowAllAliases=*/false, |
158 | VisibilityMask: llvm::opt::Visibility(clang::driver::options::FC1Option)); |
159 | return true; |
160 | } |
161 | |
162 | // Honor -version. |
163 | if (flang->getFrontendOpts().showVersion) { |
164 | llvm::cl::PrintVersionMessage(); |
165 | return true; |
166 | } |
167 | |
168 | // Load any requested plugins. |
169 | for (const std::string &path : flang->getFrontendOpts().plugins) { |
170 | std::string error; |
171 | if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(path.c_str(), |
172 | &error)) { |
173 | unsigned diagID = flang->getDiagnostics().getCustomDiagID( |
174 | clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'" ); |
175 | flang->getDiagnostics().Report(diagID) << path << error; |
176 | } |
177 | } |
178 | |
179 | // Honor -mllvm. This should happen AFTER plugins have been loaded! |
180 | if (!flang->getFrontendOpts().llvmArgs.empty()) { |
181 | unsigned numArgs = flang->getFrontendOpts().llvmArgs.size(); |
182 | auto args = std::make_unique<const char *[]>(num: numArgs + 2); |
183 | args[0] = "flang (LLVM option parsing)" ; |
184 | |
185 | for (unsigned i = 0; i != numArgs; ++i) |
186 | args[i + 1] = flang->getFrontendOpts().llvmArgs[i].c_str(); |
187 | |
188 | args[numArgs + 1] = nullptr; |
189 | llvm::cl::ParseCommandLineOptions(argc: numArgs + 1, argv: args.get()); |
190 | } |
191 | |
192 | // Honor -mmlir. This should happen AFTER plugins have been loaded! |
193 | if (!flang->getFrontendOpts().mlirArgs.empty()) { |
194 | mlir::registerMLIRContextCLOptions(); |
195 | mlir::registerPassManagerCLOptions(); |
196 | mlir::registerAsmPrinterCLOptions(); |
197 | unsigned numArgs = flang->getFrontendOpts().mlirArgs.size(); |
198 | auto args = std::make_unique<const char *[]>(num: numArgs + 2); |
199 | args[0] = "flang (MLIR option parsing)" ; |
200 | |
201 | for (unsigned i = 0; i != numArgs; ++i) |
202 | args[i + 1] = flang->getFrontendOpts().mlirArgs[i].c_str(); |
203 | |
204 | args[numArgs + 1] = nullptr; |
205 | llvm::cl::ParseCommandLineOptions(argc: numArgs + 1, argv: args.get()); |
206 | } |
207 | |
208 | // If there were errors in processing arguments, don't do anything else. |
209 | if (flang->getDiagnostics().hasErrorOccurred()) { |
210 | return false; |
211 | } |
212 | |
213 | updateDiagEngineForOptRemarks(flang->getDiagnostics(), |
214 | flang->getDiagnosticOpts()); |
215 | |
216 | // Create and execute the frontend action. |
217 | std::unique_ptr<FrontendAction> act(createFrontendAction(*flang)); |
218 | if (!act) |
219 | return false; |
220 | |
221 | bool success = flang->executeAction(*act); |
222 | return success; |
223 | } |
224 | |
225 | } // namespace Fortran::frontend |
226 | |