//===--- OptionUtils.cpp - Utilities for command line arguments -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/Options/OptionUtils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Options/Options.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" using namespace clang; using namespace llvm::opt; namespace { template IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, IntTy Default, DiagnosticsEngine *Diags, unsigned Base) { IntTy Res = Default; if (Arg *A = Args.getLastArg(Id)) { if (StringRef(A->getValue()).getAsInteger(Base, Res)) { if (Diags) Diags->Report(diag::err_drv_invalid_int_value) << A->getAsString(Args) << A->getValue(); } } return Res; } } // namespace int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, uint64_t Default, DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, const llvm::opt::ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); if (!A) return ""; StringRef Value = A->getValue(); unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; // Only "none" and Integer values are accepted by // -mprefer-vector-width=. if (Value != "none" && Value.getAsInteger(10, Width)) { Diags.Report(clang::diag::err_drv_invalid_value) << A->getOption().getName() << Value; return ""; } return Value; } // This is a helper function for validating the optional refinement step // parameter in reciprocal argument strings. Return false if there is an error // parsing the refinement step. Otherwise, return true and set the Position // of the refinement step in the input string. static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, const Arg &A, size_t &Position) { const char RefinementStepToken = ':'; Position = In.find(RefinementStepToken); if (Position != StringRef::npos) { StringRef Option = A.getOption().getName(); StringRef RefStep = In.substr(Position + 1); // Allow exactly one numeric character for the additional refinement // step parameter. This is reasonable for all currently-supported // operations and architectures because we would expect that a larger value // of refinement steps would cause the estimate "optimization" to // under-perform the native operation. Also, if the estimate does not // converge quickly, it probably will not ever converge, so further // refinement steps will not produce a better answer. if (RefStep.size() != 1) { Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; return false; } char RefStepChar = RefStep[0]; if (RefStepChar < '0' || RefStepChar > '9') { Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; return false; } } return true; } StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags, const ArgList &Args) { StringRef DisabledPrefixIn = "!"; StringRef DisabledPrefixOut = "!"; StringRef EnabledPrefixOut = ""; StringRef Out = ""; const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); if (!A) return ""; const unsigned NumOptions = A->getNumValues(); if (NumOptions == 0) { // No option is the same as "all". return "all"; } // Pass through "all", "none", or "default" with an optional refinement step. if (NumOptions == 1) { StringRef Val = A->getValue(0); size_t RefStepLoc; if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) return ""; StringRef ValBase = Val.slice(0, RefStepLoc); if (ValBase == "all" || ValBase == "none" || ValBase == "default") { return Val; } } // Each reciprocal type may be enabled or disabled individually. // Check each input value for validity, concatenate them all back together, // and pass through. llvm::StringMap OptionStrings; OptionStrings.insert(std::make_pair("divd", false)); OptionStrings.insert(std::make_pair("divf", false)); OptionStrings.insert(std::make_pair("divh", false)); OptionStrings.insert(std::make_pair("vec-divd", false)); OptionStrings.insert(std::make_pair("vec-divf", false)); OptionStrings.insert(std::make_pair("vec-divh", false)); OptionStrings.insert(std::make_pair("sqrtd", false)); OptionStrings.insert(std::make_pair("sqrtf", false)); OptionStrings.insert(std::make_pair("sqrth", false)); OptionStrings.insert(std::make_pair("vec-sqrtd", false)); OptionStrings.insert(std::make_pair("vec-sqrtf", false)); OptionStrings.insert(std::make_pair("vec-sqrth", false)); for (unsigned i = 0; i != NumOptions; ++i) { StringRef Val = A->getValue(i); bool IsDisabled = Val.starts_with(DisabledPrefixIn); // Ignore the disablement token for string matching. if (IsDisabled) Val = Val.substr(1); size_t RefStep; if (!getRefinementStep(Val, Diags, *A, RefStep)) return ""; StringRef ValBase = Val.slice(0, RefStep); llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); if (OptionIter == OptionStrings.end()) { // Try again specifying float suffix. OptionIter = OptionStrings.find(ValBase.str() + 'f'); if (OptionIter == OptionStrings.end()) { // The input name did not match any known option string. Diags.Report(diag::err_drv_unknown_argument) << Val; return ""; } // The option was specified without a half or float or double suffix. // Make sure that the double or half entry was not already specified. // The float entry will be checked below. if (OptionStrings[ValBase.str() + 'd'] || OptionStrings[ValBase.str() + 'h']) { Diags.Report(diag::err_drv_invalid_value) << A->getOption().getName() << Val; return ""; } } if (OptionIter->second == true) { // Duplicate option specified. Diags.Report(diag::err_drv_invalid_value) << A->getOption().getName() << Val; return ""; } // Mark the matched option as found. Do not allow duplicate specifiers. OptionIter->second = true; // If the precision was not specified, also mark the double and half entry // as found. if (ValBase.back() != 'f' && ValBase.back() != 'd' && ValBase.back() != 'h') { OptionStrings[ValBase.str() + 'd'] = true; OptionStrings[ValBase.str() + 'h'] = true; } // Build the output string. StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; Out = Args.MakeArgString(Out + Prefix + Val); if (i != NumOptions - 1) Out = Args.MakeArgString(Out + ","); } return Out; } std::string clang::GetResourcesPath(StringRef BinaryPath) { // Since the resource directory is embedded in the module hash, it's important // that all places that need it call this function, so that they get the // exact same string ("a/../b/" and "b/" get different hashes, for example). // Dir is bin/ or lib/, depending on where BinaryPath is. StringRef Dir = llvm::sys::path::parent_path(BinaryPath); SmallString<128> P(Dir); StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); if (!ConfiguredResourceDir.empty()) { // FIXME: We should fix the behavior of llvm::sys::path::append so we don't // need to check for absolute paths here. if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) P = ConfiguredResourceDir; else llvm::sys::path::append(P, ConfiguredResourceDir); } else { // On Windows, libclang.dll is in bin/. // On non-Windows, libclang.so/.dylib is in lib/. // With a static-library build of libclang, LibClangPath will contain the // path of the embedding binary, which for LLVM binaries will be in bin/. // ../lib gets us to lib/ in both cases. P = llvm::sys::path::parent_path(Dir); // This search path is also created in the COFF driver of lld, so any // changes here also needs to happen in lld/COFF/Driver.cpp llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", CLANG_VERSION_MAJOR_STRING); } return std::string(P); } std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) { const std::string ClangExecutable = llvm::sys::fs::getMainExecutable(Argv0, MainAddr); return GetResourcesPath(ClangExecutable); }