Skip to content

Commit f7aea4d

Browse files
authored
[clang][bytecode] Implement __builtin_{wcscmp,wcsncmp} (#132723)
1 parent 7ada6f1 commit f7aea4d

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 26 additions & 2 deletions
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,6 +233,9 @@ 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

@@ -248,6 +253,21 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
248253
!CheckRange(S, OpPC, PB, AK_Read)) {
249254
return false;
250255
}
256+
257+
if (IsWide)
258+
INT_TYPE_SWITCH(
259+
*S.getContext().classify(S.getASTContext().getWCharType()), {
260+
T A = PA.deref<T>();
261+
T B = PB.deref<T>();
262+
if (A < B) {
263+
pushInteger(S, -1, Call->getType());
264+
return true;
265+
} else if (A > B) {
266+
pushInteger(S, 1, Call->getType());
267+
return true;
268+
}
269+
});
270+
251271
uint8_t CA = PA.deref<uint8_t>();
252272
uint8_t CB = PB.deref<uint8_t>();
253273

@@ -2120,6 +2140,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
21202140
case Builtin::BIstrcmp:
21212141
case Builtin::BI__builtin_strncmp:
21222142
case Builtin::BIstrncmp:
2143+
case Builtin::BI__builtin_wcsncmp:
2144+
case Builtin::BIwcsncmp:
2145+
case Builtin::BI__builtin_wcscmp:
2146+
case Builtin::BIwcscmp:
21232147
if (!interp__builtin_strcmp(S, OpPC, Frame, F, Call))
21242148
return false;
21252149
break;

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ extern "C" {
2222
extern char *strchr(const char *s, int c);
2323
extern wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n);
2424
extern wchar_t *wcschr(const wchar_t *s, wchar_t c);
25+
extern int wcscmp(const wchar_t *s1, const wchar_t *s2);
26+
extern int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n);
2527
}
2628

2729
namespace strcmp {
@@ -66,6 +68,50 @@ namespace strcmp {
6668
static_assert(__builtin_strncmp("abab\0banana", "abab\0canada", 100) == 0);
6769
}
6870

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

0 commit comments

Comments
 (0)