xref: /llvm-project/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (revision 8e315c6ce558a25f7cadab57bd8a14ff958ae517)
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 // Remarks are ignored by default in Diagnostic.td, hence, we have to
105 // enable them here before execution. Clang follows same idea using
106 // ProcessWarningOptions in Warnings.cpp
107 // This function is also responsible for emitting early warnings for
108 // invalid -R options.
109 static void
110 updateDiagEngineForOptRemarks(clang::DiagnosticsEngine &diagsEng,
111                               const clang::DiagnosticOptions &opts) {
112   llvm::SmallVector<clang::diag::kind, 10> diags;
113   const llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagIDs =
114       diagsEng.getDiagnosticIDs();
115 
116   for (unsigned i = 0; i < opts.Remarks.size(); i++) {
117     llvm::StringRef remarkOpt = opts.Remarks[i];
118     const auto flavor = clang::diag::Flavor::Remark;
119 
120     // Check to see if this opt starts with "no-", if so, this is a
121     // negative form of the option.
122     bool isPositive = !remarkOpt.startswith("no-");
123     if (!isPositive)
124       remarkOpt = remarkOpt.substr(3);
125 
126     diagsEng.setSeverityForGroup(flavor, remarkOpt,
127                                  isPositive ? clang::diag::Severity::Remark
128                                             : clang::diag::Severity::Ignored);
129   }
130 }
131 
132 bool executeCompilerInvocation(CompilerInstance *flang) {
133   // Honor -help.
134   if (flang->getFrontendOpts().showHelp) {
135     clang::driver::getDriverOptTable().printHelp(
136         llvm::outs(), "flang-new -fc1 [options] file...",
137         "LLVM 'Flang' Compiler",
138         /*ShowHidden=*/false, /*ShowAllAliases=*/false,
139         llvm::opt::Visibility(clang::driver::options::FC1Option));
140     return true;
141   }
142 
143   // Honor -version.
144   if (flang->getFrontendOpts().showVersion) {
145     llvm::cl::PrintVersionMessage();
146     return true;
147   }
148 
149   // Load any requested plugins.
150   for (const std::string &path : flang->getFrontendOpts().plugins) {
151     std::string error;
152     if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(path.c_str(),
153                                                           &error)) {
154       unsigned diagID = flang->getDiagnostics().getCustomDiagID(
155           clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'");
156       flang->getDiagnostics().Report(diagID) << path << error;
157     }
158   }
159 
160   // Honor -mllvm. This should happen AFTER plugins have been loaded!
161   if (!flang->getFrontendOpts().llvmArgs.empty()) {
162     unsigned numArgs = flang->getFrontendOpts().llvmArgs.size();
163     auto args = std::make_unique<const char *[]>(numArgs + 2);
164     args[0] = "flang (LLVM option parsing)";
165 
166     for (unsigned i = 0; i != numArgs; ++i)
167       args[i + 1] = flang->getFrontendOpts().llvmArgs[i].c_str();
168 
169     args[numArgs + 1] = nullptr;
170     llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());
171   }
172 
173   // Honor -mmlir. This should happen AFTER plugins have been loaded!
174   if (!flang->getFrontendOpts().mlirArgs.empty()) {
175     mlir::registerMLIRContextCLOptions();
176     mlir::registerPassManagerCLOptions();
177     mlir::registerAsmPrinterCLOptions();
178     unsigned numArgs = flang->getFrontendOpts().mlirArgs.size();
179     auto args = std::make_unique<const char *[]>(numArgs + 2);
180     args[0] = "flang (MLIR option parsing)";
181 
182     for (unsigned i = 0; i != numArgs; ++i)
183       args[i + 1] = flang->getFrontendOpts().mlirArgs[i].c_str();
184 
185     args[numArgs + 1] = nullptr;
186     llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());
187   }
188 
189   // If there were errors in processing arguments, don't do anything else.
190   if (flang->getDiagnostics().hasErrorOccurred()) {
191     return false;
192   }
193 
194   updateDiagEngineForOptRemarks(flang->getDiagnostics(),
195                                 flang->getDiagnosticOpts());
196 
197   // Create and execute the frontend action.
198   std::unique_ptr<FrontendAction> act(createFrontendAction(*flang));
199   if (!act)
200     return false;
201 
202   bool success = flang->executeAction(*act);
203   return success;
204 }
205 
206 } // namespace Fortran::frontend
207