Skip to content

Commit 0bc2c5b

Browse files
authored
Reapply "[clang][bytecode] Implement __builtin_{wcscmp,wcsncmp} (rust-lang#132… (llvm#132963)
…723)" This reverts commit 1e2ad67. Fix the previous commit on big-endian hosts by _not_ falling through to the `uint8_t` code path.
1 parent ab5de9a commit 0bc2c5b

File tree

2 files changed

+86
-13
lines changed

2 files changed

+86
-13
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

+40-13
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,13 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
212212
const Pointer &A = getParam<Pointer>(Frame, 0);
213213
const Pointer &B = getParam<Pointer>(Frame, 1);
214214

215-
if (ID == Builtin::BIstrcmp || ID == Builtin::BIstrncmp)
215+
if (ID == Builtin::BIstrcmp || ID == Builtin::BIstrncmp ||
216+
ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp)
216217
diagnoseNonConstexprBuiltin(S, OpPC, ID);
217218

218219
uint64_t Limit = ~static_cast<uint64_t>(0);
219-
if (ID == Builtin::BIstrncmp || ID == Builtin::BI__builtin_strncmp)
220+
if (ID == Builtin::BIstrncmp || ID == Builtin::BI__builtin_strncmp ||
221+
ID == Builtin::BIwcsncmp || ID == Builtin::BI__builtin_wcsncmp)
220222
Limit = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)))
221223
.getZExtValue();
222224

@@ -231,12 +233,22 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
231233
if (A.isDummy() || B.isDummy())
232234
return false;
233235

236+
bool IsWide = ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp ||
237+
ID == Builtin::BI__builtin_wcscmp ||
238+
ID == Builtin::BI__builtin_wcsncmp;
234239
assert(A.getFieldDesc()->isPrimitiveArray());
235240
assert(B.getFieldDesc()->isPrimitiveArray());
236241

242+
assert(getElemType(A).getTypePtr() == getElemType(B).getTypePtr());
243+
PrimType ElemT = *S.getContext().classify(getElemType(A));
244+
245+
auto returnResult = [&](int V) -> bool {
246+
pushInteger(S, V, Call->getType());
247+
return true;
248+
};
249+
237250
unsigned IndexA = A.getIndex();
238251
unsigned IndexB = B.getIndex();
239-
int32_t Result = 0;
240252
uint64_t Steps = 0;
241253
for (;; ++IndexA, ++IndexB, ++Steps) {
242254

@@ -248,22 +260,33 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
248260
!CheckRange(S, OpPC, PB, AK_Read)) {
249261
return false;
250262
}
263+
264+
if (IsWide) {
265+
INT_TYPE_SWITCH(ElemT, {
266+
T CA = PA.deref<T>();
267+
T CB = PB.deref<T>();
268+
if (CA > CB)
269+
return returnResult(1);
270+
else if (CA < CB)
271+
return returnResult(-1);
272+
else if (CA.isZero() || CB.isZero())
273+
return returnResult(0);
274+
});
275+
continue;
276+
}
277+
251278
uint8_t CA = PA.deref<uint8_t>();
252279
uint8_t CB = PB.deref<uint8_t>();
253280

254-
if (CA > CB) {
255-
Result = 1;
256-
break;
257-
} else if (CA < CB) {
258-
Result = -1;
259-
break;
260-
}
281+
if (CA > CB)
282+
return returnResult(1);
283+
else if (CA < CB)
284+
return returnResult(-1);
261285
if (CA == 0 || CB == 0)
262-
break;
286+
return returnResult(0);
263287
}
264288

265-
pushInteger(S, Result, Call->getType());
266-
return true;
289+
return returnResult(0);
267290
}
268291

269292
static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
@@ -2120,6 +2143,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
21202143
case Builtin::BIstrcmp:
21212144
case Builtin::BI__builtin_strncmp:
21222145
case Builtin::BIstrncmp:
2146+
case Builtin::BI__builtin_wcsncmp:
2147+
case Builtin::BIwcsncmp:
2148+
case Builtin::BI__builtin_wcscmp:
2149+
case Builtin::BIwcscmp:
21232150
if (!interp__builtin_strcmp(S, OpPC, Frame, F, Call))
21242151
return false;
21252152
break;

clang/test/AST/ByteCode/builtin-functions.cpp

+46
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ extern "C" {
2828
extern char *strchr(const char *s, int c);
2929
extern wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n);
3030
extern wchar_t *wcschr(const wchar_t *s, wchar_t c);
31+
extern int wcscmp(const wchar_t *s1, const wchar_t *s2);
32+
extern int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n);
3133
}
3234

3335
namespace strcmp {
@@ -72,6 +74,50 @@ namespace strcmp {
7274
static_assert(__builtin_strncmp("abab\0banana", "abab\0canada", 100) == 0);
7375
}
7476

77+
namespace WcsCmp {
78+
constexpr wchar_t kFoobar[6] = {L'f',L'o',L'o',L'b',L'a',L'r'};
79+
constexpr wchar_t kFoobazfoobar[12] = {L'f',L'o',L'o',L'b',L'a',L'z',L'f',L'o',L'o',L'b',L'a',L'r'};
80+
81+
static_assert(__builtin_wcscmp(L"abab", L"abab") == 0);
82+
static_assert(__builtin_wcscmp(L"abab", L"abba") == -1);
83+
static_assert(__builtin_wcscmp(L"abab", L"abaa") == 1);
84+
static_assert(__builtin_wcscmp(L"ababa", L"abab") == 1);
85+
static_assert(__builtin_wcscmp(L"abab", L"ababa") == -1);
86+
static_assert(__builtin_wcscmp(L"abab\0banana", L"abab") == 0);
87+
static_assert(__builtin_wcscmp(L"abab", L"abab\0banana") == 0);
88+
static_assert(__builtin_wcscmp(L"abab\0banana", L"abab\0canada") == 0);
89+
#if __WCHAR_WIDTH__ == 32
90+
static_assert(__builtin_wcscmp(L"a\x83838383", L"a") == (wchar_t)-1U >> 31);
91+
#endif
92+
static_assert(__builtin_wcscmp(0, L"abab") == 0); // both-error {{not an integral constant}} \
93+
// both-note {{dereferenced null}}
94+
static_assert(__builtin_wcscmp(L"abab", 0) == 0); // both-error {{not an integral constant}} \
95+
// both-note {{dereferenced null}}
96+
97+
static_assert(__builtin_wcscmp(kFoobar, kFoobazfoobar) == -1);
98+
static_assert(__builtin_wcscmp(kFoobar, kFoobazfoobar + 6) == 0); // both-error {{not an integral constant}} \
99+
// both-note {{dereferenced one-past-the-end}}
100+
101+
static_assert(__builtin_wcsncmp(L"abaa", L"abba", 5) == -1);
102+
static_assert(__builtin_wcsncmp(L"abaa", L"abba", 4) == -1);
103+
static_assert(__builtin_wcsncmp(L"abaa", L"abba", 3) == -1);
104+
static_assert(__builtin_wcsncmp(L"abaa", L"abba", 2) == 0);
105+
static_assert(__builtin_wcsncmp(L"abaa", L"abba", 1) == 0);
106+
static_assert(__builtin_wcsncmp(L"abaa", L"abba", 0) == 0);
107+
static_assert(__builtin_wcsncmp(0, 0, 0) == 0);
108+
static_assert(__builtin_wcsncmp(L"abab\0banana", L"abab\0canada", 100) == 0);
109+
#if __WCHAR_WIDTH__ == 32
110+
static_assert(__builtin_wcsncmp(L"a\x83838383", L"aa", 2) ==
111+
(wchar_t)-1U >> 31);
112+
#endif
113+
114+
static_assert(__builtin_wcsncmp(kFoobar, kFoobazfoobar, 6) == -1);
115+
static_assert(__builtin_wcsncmp(kFoobar, kFoobazfoobar, 7) == -1);
116+
static_assert(__builtin_wcsncmp(kFoobar, kFoobazfoobar + 6, 6) == 0);
117+
static_assert(__builtin_wcsncmp(kFoobar, kFoobazfoobar + 6, 7) == 0); // both-error {{not an integral constant}} \
118+
// both-note {{dereferenced one-past-the-end}}
119+
}
120+
75121
/// Copied from constant-expression-cxx11.cpp
76122
namespace strlen {
77123
constexpr const char *a = "foo\0quux";

0 commit comments

Comments
 (0)