clang 22.0.0git
OptionUtils.cpp
Go to the documentation of this file.
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-exception
6//
7//===----------------------------------------------------------------------===//
8
12#include "clang/Basic/Version.h"
13#include "clang/Config/config.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} // namespace
38
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
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 by
60 // -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 step
71// parameter in reciprocal argument strings. Return false if there is an error
72// parsing the refinement step. Otherwise, return true and set the Position
73// 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 refinement
82 // step parameter. This is reasonable for all currently-supported
83 // operations and architectures because we would expect that a larger value
84 // of refinement steps would cause the estimate "optimization" to
85 // under-perform the native operation. Also, if the estimate does not
86 // converge quickly, it probably will not ever converge, so further
87 // 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
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 entry
192 // 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 important
211 // that all places that need it call this function, so that they get the
212 // 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't
221 // need to check for absolute paths here.
222 if (llvm::sys::path::is_absolute(ConfiguredResourceDir))
223 P = ConfiguredResourceDir;
224 else
225 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 the
230 // 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 any
234 // changes here also needs to happen in lld/COFF/Driver.cpp
235 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}
Defines the Diagnostic-related interfaces.
static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, const Arg &A, size_t &Position)
Defines version macros and version-related utility functions for Clang.
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:232
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
The JSON file list parser is used to communicate input to InstallAPI.
StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, const llvm::opt::ArgList &Args)
uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, llvm::opt::OptSpecifier Id, uint64_t Default, DiagnosticsEngine *Diags=nullptr, unsigned Base=0)
std::string GetResourcesPath(StringRef BinaryPath)
Get the directory where the compiler headers reside, relative to the compiler binary path BinaryPath.
int getLastArgIntValue(const llvm::opt::ArgList &Args, llvm::opt::OptSpecifier Id, int Default, DiagnosticsEngine *Diags=nullptr, unsigned Base=0)
Return the value of the last argument as an integer, or a default.
StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, const llvm::opt::ArgList &Args)