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
32namespace Fortran::frontend {
33
34static std::unique_ptr<FrontendAction>
35createFrontendAction(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
104static 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.
121static void
122updateDiagEngineForOptRemarks(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 remarkOpt = 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
151bool 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

source code of flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp