1 //===--- ExecuteCompilerInvocation.cpp ------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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.
12 //===----------------------------------------------------------------------===//
14 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
16 //===----------------------------------------------------------------------===//
18 #include "flang/Frontend/CompilerInstance.h"
19 #include "flang/Frontend/FrontendActions.h"
20 #include "flang/Frontend/FrontendPluginRegistry.h"
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"
32 namespace Fortran::frontend
{
34 static std::unique_ptr
<FrontendAction
>
35 createFrontendAction(CompilerInstance
&ci
) {
37 switch (ci
.getFrontendOpts().programAction
) {
39 return std::make_unique
<InputOutputTestAction
>();
40 case PrintPreprocessedInput
:
41 return std::make_unique
<PrintPreprocessedAction
>();
43 return std::make_unique
<ParseSyntaxOnlyAction
>();
45 return std::make_unique
<EmitFIRAction
>();
47 return std::make_unique
<EmitHLFIRAction
>();
49 return std::make_unique
<EmitLLVMAction
>();
51 return std::make_unique
<EmitLLVMBitcodeAction
>();
53 return std::make_unique
<EmitObjAction
>();
55 return std::make_unique
<EmitAssemblyAction
>();
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
>();
69 return std::make_unique
<DebugDumpPFTAction
>();
70 case DebugDumpParseTreeNoSema
:
71 return std::make_unique
<DebugDumpParseTreeNoSemaAction
>();
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
>();
81 return std::make_unique
<DebugPreFIRTreeAction
>();
83 return std::make_unique
<GetDefinitionAction
>();
84 case GetSymbolsSources
:
85 return std::make_unique
<GetSymbolsSourcesAction
>();
87 return std::make_unique
<InitOnlyAction
>();
89 for (const FrontendPluginRegistry::entry
&plugin
:
90 FrontendPluginRegistry::entries()) {
91 if (plugin
.getName() == ci
.getFrontendOpts().actionName
) {
92 std::unique_ptr
<PluginParseTreeAction
> p(plugin
.instantiate());
96 unsigned diagID
= ci
.getDiagnostics().getCustomDiagID(
97 clang::DiagnosticsEngine::Error
, "unable to find plugin '%0'");
98 ci
.getDiagnostics().Report(diagID
) << ci
.getFrontendOpts().actionName
;
103 llvm_unreachable("Invalid program action!");
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
, 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
));
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.
124 updateDiagEngineForOptRemarks(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();
130 for (unsigned i
= 0; i
< opts
.Remarks
.size(); i
++) {
131 llvm::StringRef remarkOpt
= opts
.Remarks
[i
];
132 const auto flavor
= clang::diag::Flavor::Remark
;
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("no-");
138 remarkOpt
= remarkOpt
.substr(3);
140 // Verify that this is a valid optimization remarks option
141 if (diagIDs
->getDiagnosticsInGroup(flavor
, remarkOpt
, diags
)) {
142 emitUnknownDiagWarning(diagsEng
, flavor
, isPositive
? "-R" : "-Rno-",
147 diagsEng
.setSeverityForGroup(flavor
, remarkOpt
,
148 isPositive
? clang::diag::Severity::Remark
149 : clang::diag::Severity::Ignored
);
153 bool executeCompilerInvocation(CompilerInstance
*flang
) {
155 if (flang
->getFrontendOpts().showHelp
) {
156 clang::driver::getDriverOptTable().printHelp(
157 llvm::outs(), "flang -fc1 [options] file...", "LLVM 'Flang' Compiler",
158 /*ShowHidden=*/false, /*ShowAllAliases=*/false,
159 llvm::opt::Visibility(clang::driver::options::FC1Option
));
164 if (flang
->getFrontendOpts().showVersion
) {
165 llvm::cl::PrintVersionMessage();
169 // Load any requested plugins.
170 for (const std::string
&path
: flang
->getFrontendOpts().plugins
) {
172 if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(path
.c_str(),
174 unsigned diagID
= flang
->getDiagnostics().getCustomDiagID(
175 clang::DiagnosticsEngine::Error
, "unable to load plugin '%0': '%1'");
176 flang
->getDiagnostics().Report(diagID
) << path
<< error
;
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 *[]>(numArgs
+ 2);
184 args
[0] = "flang (LLVM option parsing)";
186 for (unsigned i
= 0; i
!= numArgs
; ++i
)
187 args
[i
+ 1] = flang
->getFrontendOpts().llvmArgs
[i
].c_str();
189 args
[numArgs
+ 1] = nullptr;
190 llvm::cl::ParseCommandLineOptions(numArgs
+ 1, args
.get());
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 *[]>(numArgs
+ 2);
200 args
[0] = "flang (MLIR option parsing)";
202 for (unsigned i
= 0; i
!= numArgs
; ++i
)
203 args
[i
+ 1] = flang
->getFrontendOpts().mlirArgs
[i
].c_str();
205 args
[numArgs
+ 1] = nullptr;
206 llvm::cl::ParseCommandLineOptions(numArgs
+ 1, args
.get());
209 // If there were errors in processing arguments, don't do anything else.
210 if (flang
->getDiagnostics().hasErrorOccurred()) {
214 updateDiagEngineForOptRemarks(flang
->getDiagnostics(),
215 flang
->getDiagnosticOpts());
217 // Create and execute the frontend action.
218 std::unique_ptr
<FrontendAction
> act(createFrontendAction(*flang
));
222 bool success
= flang
->executeAction(*act
);
226 } // namespace Fortran::frontend