brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.2 KiB · e5aefa0 Raw
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