This relands #165277 by reverting #169397. This also relands the corresponding Bazel port by reverting #169410. The original revert was due to a report of a broken build, which was later resolved by fully clearing the build directory.
247 lines
9.2 KiB
C++
247 lines
9.2 KiB
C++
//===--- 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 <typename IntTy>
|
|
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<int>(Args, Id, Default, Diags, Base);
|
|
}
|
|
|
|
uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id,
|
|
uint64_t Default,
|
|
DiagnosticsEngine *Diags, unsigned Base) {
|
|
return getLastArgIntValueImpl<uint64_t>(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=<value>.
|
|
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<bool> 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<bool>::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);
|
|
}
|