227 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file holds ExecuteCompilerInvocation(). It is split into its own file to10// 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/Options/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 32namespace Fortran::frontend {33 34static std::unique_ptr<FrontendAction>35createFrontendAction(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 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>();68 case DebugDumpPFT:69 return std::make_unique<DebugDumpPFTAction>();70 case DebugDumpParseTreeNoSema:71 return std::make_unique<DebugDumpParseTreeNoSemaAction>();72 case DebugDumpAll: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>();80 case DebugPreFIRTree:81 return std::make_unique<DebugPreFIRTreeAction>();82 case GetDefinition:83 return std::make_unique<GetDefinitionAction>();84 case GetSymbolsSources:85 return std::make_unique<GetSymbolsSourcesAction>();86 case InitOnly:87 return std::make_unique<InitOnlyAction>();88 case PluginAction: {89 for (const FrontendPluginRegistry::entry &plugin :90 FrontendPluginRegistry::entries()) {91 if (plugin.getName() == ci.getFrontendOpts().actionName) {92 std::unique_ptr<PluginParseTreeAction> p(plugin.instantiate());93 return std::move(p);94 }95 }96 unsigned diagID = ci.getDiagnostics().getCustomDiagID(97 clang::DiagnosticsEngine::Error, "unable to find plugin '%0'");98 ci.getDiagnostics().Report(diagID) << ci.getFrontendOpts().actionName;99 return nullptr;100 }101 }102 103 llvm_unreachable("Invalid program action!");104}105 106static 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));116}117 118// Remarks are ignored by default in Diagnostic.td, hence, we have to119// enable them here before execution. Clang follows same idea using120// ProcessWarningOptions in Warnings.cpp121// This function is also responsible for emitting early warnings for122// invalid -R options.123static void124updateDiagEngineForOptRemarks(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();129 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;133 134 // Check to see if this opt starts with "no-", if so, this is a135 // negative form of the option.136 bool isPositive = !remarkOpt.starts_with("no-");137 if (!isPositive)138 remarkOpt = remarkOpt.substr(3);139 140 // Verify that this is a valid optimization remarks option141 if (diagIDs->getDiagnosticsInGroup(flavor, remarkOpt, diags)) {142 emitUnknownDiagWarning(diagsEng, flavor, isPositive ? "-R" : "-Rno-",143 remarkOpt);144 return;145 }146 147 diagsEng.setSeverityForGroup(flavor, remarkOpt,148 isPositive ? clang::diag::Severity::Remark149 : clang::diag::Severity::Ignored);150 }151}152 153bool executeCompilerInvocation(CompilerInstance *flang) {154 // Honor -help.155 if (flang->getFrontendOpts().showHelp) {156 clang::getDriverOptTable().printHelp(157 llvm::outs(), "flang -fc1 [options] file...", "LLVM 'Flang' Compiler",158 /*ShowHidden=*/false, /*ShowAllAliases=*/false,159 llvm::opt::Visibility(clang::options::FC1Option));160 return true;161 }162 163 // Honor -version.164 if (flang->getFrontendOpts().showVersion) {165 llvm::cl::PrintVersionMessage();166 return true;167 }168 169 // Load any requested plugins.170 for (const std::string &path : flang->getFrontendOpts().plugins) {171 std::string error;172 if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(path.c_str(),173 &error)) {174 unsigned diagID = flang->getDiagnostics().getCustomDiagID(175 clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'");176 flang->getDiagnostics().Report(diagID) << path << error;177 }178 }179 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)";185 186 for (unsigned i = 0; i != numArgs; ++i)187 args[i + 1] = flang->getFrontendOpts().llvmArgs[i].c_str();188 189 args[numArgs + 1] = nullptr;190 llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());191 }192 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)";201 202 for (unsigned i = 0; i != numArgs; ++i)203 args[i + 1] = flang->getFrontendOpts().mlirArgs[i].c_str();204 205 args[numArgs + 1] = nullptr;206 llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());207 }208 209 // If there were errors in processing arguments, don't do anything else.210 if (flang->getDiagnostics().hasErrorOccurred()) {211 return false;212 }213 214 updateDiagEngineForOptRemarks(flang->getDiagnostics(),215 flang->getDiagnosticOpts());216 217 // Create and execute the frontend action.218 std::unique_ptr<FrontendAction> act(createFrontendAction(*flang));219 if (!act)220 return false;221 222 bool success = flang->executeAction(*act);223 return success;224}225 226} // namespace Fortran::frontend227