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