xref: /llvm-project/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp (revision bb177edc44f412f368c4c5983df15b7364fc3122)
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 #include "flang/Frontend/CompilerInstance.h"
15 #include "flang/Frontend/FrontendActions.h"
16 #include "flang/Frontend/FrontendPluginRegistry.h"
17 #include "clang/Driver/Options.h"
18 #include "llvm/Option/OptTable.h"
19 #include "llvm/Option/Option.h"
20 #include "llvm/Support/BuryPointer.h"
21 #include "llvm/Support/CommandLine.h"
22 #include "mlir/IR/MLIRContext.h"
23 #include "mlir/Pass/PassManager.h"
24 
25 namespace Fortran::frontend {
26 
27 static std::unique_ptr<FrontendAction> CreateFrontendAction(
28     CompilerInstance &ci) {
29 
30   switch (ci.frontendOpts().programAction) {
31   case InputOutputTest:
32     return std::make_unique<InputOutputTestAction>();
33   case PrintPreprocessedInput:
34     return std::make_unique<PrintPreprocessedAction>();
35   case ParseSyntaxOnly:
36     return std::make_unique<ParseSyntaxOnlyAction>();
37   case EmitMLIR:
38     return std::make_unique<EmitMLIRAction>();
39   case EmitLLVM:
40     return std::make_unique<EmitLLVMAction>();
41   case EmitLLVMBitcode:
42     return std::make_unique<EmitLLVMBitcodeAction>();
43   case EmitObj:
44     return std::make_unique<EmitObjAction>();
45   case EmitAssembly:
46     return std::make_unique<EmitAssemblyAction>();
47   case DebugUnparse:
48     return std::make_unique<DebugUnparseAction>();
49   case DebugUnparseNoSema:
50     return std::make_unique<DebugUnparseNoSemaAction>();
51   case DebugUnparseWithSymbols:
52     return std::make_unique<DebugUnparseWithSymbolsAction>();
53   case DebugDumpSymbols:
54     return std::make_unique<DebugDumpSymbolsAction>();
55   case DebugDumpParseTree:
56     return std::make_unique<DebugDumpParseTreeAction>();
57   case DebugDumpPFT:
58     return std::make_unique<DebugDumpPFTAction>();
59   case DebugDumpParseTreeNoSema:
60     return std::make_unique<DebugDumpParseTreeNoSemaAction>();
61   case DebugDumpAll:
62     return std::make_unique<DebugDumpAllAction>();
63   case DebugDumpProvenance:
64     return std::make_unique<DebugDumpProvenanceAction>();
65   case DebugDumpParsingLog:
66     return std::make_unique<DebugDumpParsingLogAction>();
67   case DebugMeasureParseTree:
68     return std::make_unique<DebugMeasureParseTreeAction>();
69   case DebugPreFIRTree:
70     return std::make_unique<DebugPreFIRTreeAction>();
71   case GetDefinition:
72     return std::make_unique<GetDefinitionAction>();
73   case GetSymbolsSources:
74     return std::make_unique<GetSymbolsSourcesAction>();
75   case InitOnly:
76     return std::make_unique<InitOnlyAction>();
77   case PluginAction: {
78     for (const FrontendPluginRegistry::entry &plugin :
79         FrontendPluginRegistry::entries()) {
80       if (plugin.getName() == ci.frontendOpts().ActionName) {
81         std::unique_ptr<PluginParseTreeAction> p(plugin.instantiate());
82         return std::move(p);
83       }
84     }
85     unsigned diagID = ci.diagnostics().getCustomDiagID(
86         clang::DiagnosticsEngine::Error, "unable to find plugin '%0'");
87     ci.diagnostics().Report(diagID) << ci.frontendOpts().ActionName;
88     return nullptr;
89   }
90   }
91 
92   llvm_unreachable("Invalid program action!");
93 }
94 
95 bool ExecuteCompilerInvocation(CompilerInstance *flang) {
96   // Honor -help.
97   if (flang->frontendOpts().showHelp) {
98     clang::driver::getDriverOptTable().printHelp(llvm::outs(),
99         "flang-new -fc1 [options] file...", "LLVM 'Flang' Compiler",
100         /*Include=*/clang::driver::options::FC1Option,
101         /*Exclude=*/llvm::opt::DriverFlag::HelpHidden,
102         /*ShowAllAliases=*/false);
103     return true;
104   }
105 
106   // Honor -version.
107   if (flang->frontendOpts().showVersion) {
108     llvm::cl::PrintVersionMessage();
109     return true;
110   }
111 
112   // Load any requested plugins.
113   for (const std::string &Path : flang->frontendOpts().plugins) {
114     std::string Error;
115     if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(
116             Path.c_str(), &Error)) {
117       unsigned diagID = flang->diagnostics().getCustomDiagID(
118           clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'");
119       flang->diagnostics().Report(diagID) << Path << Error;
120     }
121   }
122 
123   // Honor -mllvm. This should happen AFTER plugins have been loaded!
124   if (!flang->frontendOpts().llvmArgs.empty()) {
125     unsigned numArgs = flang->frontendOpts().llvmArgs.size();
126     auto args = std::make_unique<const char *[]>(numArgs + 2);
127     args[0] = "flang (LLVM option parsing)";
128 
129     for (unsigned i = 0; i != numArgs; ++i)
130       args[i + 1] = flang->frontendOpts().llvmArgs[i].c_str();
131 
132     args[numArgs + 1] = nullptr;
133     llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());
134   }
135 
136   // Honor -mmlir. This should happen AFTER plugins have been loaded!
137   if (!flang->frontendOpts().mlirArgs.empty()) {
138     mlir::registerMLIRContextCLOptions();
139     mlir::registerPassManagerCLOptions();
140     unsigned numArgs = flang->frontendOpts().mlirArgs.size();
141     auto args = std::make_unique<const char *[]>(numArgs + 2);
142     args[0] = "flang (MLIR option parsing)";
143 
144     for (unsigned i = 0; i != numArgs; ++i)
145       args[i + 1] = flang->frontendOpts().mlirArgs[i].c_str();
146 
147     args[numArgs + 1] = nullptr;
148     llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());
149   }
150 
151   // If there were errors in processing arguments, don't do anything else.
152   if (flang->diagnostics().hasErrorOccurred()) {
153     return false;
154   }
155 
156   // Create and execute the frontend action.
157   std::unique_ptr<FrontendAction> act(CreateFrontendAction(*flang));
158   if (!act)
159     return false;
160 
161   bool success = flang->ExecuteAction(*act);
162   return success;
163 }
164 
165 } // namespace Fortran::frontend
166