xref: /llvm-project/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (revision e8af24736ada1ecc2495ada73225370be8a551a5)
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, 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 updateDiagEngineForOptRemarks(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.startswith("no-");
135     if (!isPositive)
136       remarkOpt = remarkOpt.substr(3);
137 
138     // Verify that this is a valid optimization remarks option
139     if (diagIDs->getDiagnosticsInGroup(flavor, remarkOpt, diags)) {
140       emitUnknownDiagWarning(diagsEng, flavor, isPositive ? "-R" : "-Rno-",
141                              remarkOpt);
142       return;
143     }
144 
145     diagsEng.setSeverityForGroup(flavor, remarkOpt,
146                                  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         llvm::outs(), "flang-new -fc1 [options] file...",
156         "LLVM 'Flang' Compiler",
157         /*ShowHidden=*/false, /*ShowAllAliases=*/false,
158         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 *[]>(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(numArgs + 1, 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 *[]>(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(numArgs + 1, 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