247 lines · cpp
1//===--- OptionUtils.cpp - Utilities for command line arguments -----------===//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#include "clang/Options/OptionUtils.h"10#include "clang/Basic/Diagnostic.h"11#include "clang/Basic/DiagnosticDriver.h"12#include "clang/Basic/Version.h"13#include "clang/Config/config.h"14#include "clang/Options/Options.h"15#include "llvm/Option/ArgList.h"16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/Path.h"18 19using namespace clang;20using namespace llvm::opt;21 22namespace {23template <typename IntTy>24IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id,25 IntTy Default, DiagnosticsEngine *Diags,26 unsigned Base) {27 IntTy Res = Default;28 if (Arg *A = Args.getLastArg(Id)) {29 if (StringRef(A->getValue()).getAsInteger(Base, Res)) {30 if (Diags)31 Diags->Report(diag::err_drv_invalid_int_value)32 << A->getAsString(Args) << A->getValue();33 }34 }35 return Res;36}37} // namespace38 39int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default,40 DiagnosticsEngine *Diags, unsigned Base) {41 return getLastArgIntValueImpl<int>(Args, Id, Default, Diags, Base);42}43 44uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,45 uint64_t Default,46 DiagnosticsEngine *Diags, unsigned Base) {47 return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags, Base);48}49 50StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags,51 const llvm::opt::ArgList &Args) {52 const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ);53 if (!A)54 return "";55 56 StringRef Value = A->getValue();57 unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED;58 59 // Only "none" and Integer values are accepted by60 // -mprefer-vector-width=<value>.61 if (Value != "none" && Value.getAsInteger(10, Width)) {62 Diags.Report(clang::diag::err_drv_invalid_value)63 << A->getOption().getName() << Value;64 return "";65 }66 67 return Value;68}69 70// This is a helper function for validating the optional refinement step71// parameter in reciprocal argument strings. Return false if there is an error72// parsing the refinement step. Otherwise, return true and set the Position73// of the refinement step in the input string.74static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags,75 const Arg &A, size_t &Position) {76 const char RefinementStepToken = ':';77 Position = In.find(RefinementStepToken);78 if (Position != StringRef::npos) {79 StringRef Option = A.getOption().getName();80 StringRef RefStep = In.substr(Position + 1);81 // Allow exactly one numeric character for the additional refinement82 // step parameter. This is reasonable for all currently-supported83 // operations and architectures because we would expect that a larger value84 // of refinement steps would cause the estimate "optimization" to85 // under-perform the native operation. Also, if the estimate does not86 // converge quickly, it probably will not ever converge, so further87 // refinement steps will not produce a better answer.88 if (RefStep.size() != 1) {89 Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;90 return false;91 }92 char RefStepChar = RefStep[0];93 if (RefStepChar < '0' || RefStepChar > '9') {94 Diags.Report(diag::err_drv_invalid_value) << Option << RefStep;95 return false;96 }97 }98 return true;99}100 101StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags,102 const ArgList &Args) {103 StringRef DisabledPrefixIn = "!";104 StringRef DisabledPrefixOut = "!";105 StringRef EnabledPrefixOut = "";106 StringRef Out = "";107 108 const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ);109 if (!A)110 return "";111 112 const unsigned NumOptions = A->getNumValues();113 if (NumOptions == 0) {114 // No option is the same as "all".115 return "all";116 }117 118 // Pass through "all", "none", or "default" with an optional refinement step.119 if (NumOptions == 1) {120 StringRef Val = A->getValue(0);121 size_t RefStepLoc;122 if (!getRefinementStep(Val, Diags, *A, RefStepLoc))123 return "";124 StringRef ValBase = Val.slice(0, RefStepLoc);125 if (ValBase == "all" || ValBase == "none" || ValBase == "default") {126 return Val;127 }128 }129 130 // Each reciprocal type may be enabled or disabled individually.131 // Check each input value for validity, concatenate them all back together,132 // and pass through.133 134 llvm::StringMap<bool> OptionStrings;135 OptionStrings.insert(std::make_pair("divd", false));136 OptionStrings.insert(std::make_pair("divf", false));137 OptionStrings.insert(std::make_pair("divh", false));138 OptionStrings.insert(std::make_pair("vec-divd", false));139 OptionStrings.insert(std::make_pair("vec-divf", false));140 OptionStrings.insert(std::make_pair("vec-divh", false));141 OptionStrings.insert(std::make_pair("sqrtd", false));142 OptionStrings.insert(std::make_pair("sqrtf", false));143 OptionStrings.insert(std::make_pair("sqrth", false));144 OptionStrings.insert(std::make_pair("vec-sqrtd", false));145 OptionStrings.insert(std::make_pair("vec-sqrtf", false));146 OptionStrings.insert(std::make_pair("vec-sqrth", false));147 148 for (unsigned i = 0; i != NumOptions; ++i) {149 StringRef Val = A->getValue(i);150 151 bool IsDisabled = Val.starts_with(DisabledPrefixIn);152 // Ignore the disablement token for string matching.153 if (IsDisabled)154 Val = Val.substr(1);155 156 size_t RefStep;157 if (!getRefinementStep(Val, Diags, *A, RefStep))158 return "";159 160 StringRef ValBase = Val.slice(0, RefStep);161 llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase);162 if (OptionIter == OptionStrings.end()) {163 // Try again specifying float suffix.164 OptionIter = OptionStrings.find(ValBase.str() + 'f');165 if (OptionIter == OptionStrings.end()) {166 // The input name did not match any known option string.167 Diags.Report(diag::err_drv_unknown_argument) << Val;168 return "";169 }170 // The option was specified without a half or float or double suffix.171 // Make sure that the double or half entry was not already specified.172 // The float entry will be checked below.173 if (OptionStrings[ValBase.str() + 'd'] ||174 OptionStrings[ValBase.str() + 'h']) {175 Diags.Report(diag::err_drv_invalid_value)176 << A->getOption().getName() << Val;177 return "";178 }179 }180 181 if (OptionIter->second == true) {182 // Duplicate option specified.183 Diags.Report(diag::err_drv_invalid_value)184 << A->getOption().getName() << Val;185 return "";186 }187 188 // Mark the matched option as found. Do not allow duplicate specifiers.189 OptionIter->second = true;190 191 // If the precision was not specified, also mark the double and half entry192 // as found.193 if (ValBase.back() != 'f' && ValBase.back() != 'd' &&194 ValBase.back() != 'h') {195 OptionStrings[ValBase.str() + 'd'] = true;196 OptionStrings[ValBase.str() + 'h'] = true;197 }198 199 // Build the output string.200 StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut;201 Out = Args.MakeArgString(Out + Prefix + Val);202 if (i != NumOptions - 1)203 Out = Args.MakeArgString(Out + ",");204 }205 206 return Out;207}208 209std::string clang::GetResourcesPath(StringRef BinaryPath) {210 // Since the resource directory is embedded in the module hash, it's important211 // that all places that need it call this function, so that they get the212 // exact same string ("a/../b/" and "b/" get different hashes, for example).213 214 // Dir is bin/ or lib/, depending on where BinaryPath is.215 StringRef Dir = llvm::sys::path::parent_path(BinaryPath);216 SmallString<128> P(Dir);217 218 StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR);219 if (!ConfiguredResourceDir.empty()) {220 // FIXME: We should fix the behavior of llvm::sys::path::append so we don't221 // need to check for absolute paths here.222 if (llvm::sys::path::is_absolute(ConfiguredResourceDir))223 P = ConfiguredResourceDir;224 else225 llvm::sys::path::append(P, ConfiguredResourceDir);226 } else {227 // On Windows, libclang.dll is in bin/.228 // On non-Windows, libclang.so/.dylib is in lib/.229 // With a static-library build of libclang, LibClangPath will contain the230 // path of the embedding binary, which for LLVM binaries will be in bin/.231 // ../lib gets us to lib/ in both cases.232 P = llvm::sys::path::parent_path(Dir);233 // This search path is also created in the COFF driver of lld, so any234 // changes here also needs to happen in lld/COFF/Driver.cpp235 llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang",236 CLANG_VERSION_MAJOR_STRING);237 }238 239 return std::string(P);240}241 242std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) {243 const std::string ClangExecutable =244 llvm::sys::fs::getMainExecutable(Argv0, MainAddr);245 return GetResourcesPath(ClangExecutable);246}247