Skip to content

Commit dd6f6a0

Browse files
authored
[clang][bytecode] Handle builtin_wmemcmp (#120070)
1 parent 9096879 commit dd6f6a0

File tree

2 files changed

+64
-22
lines changed

2 files changed

+64
-22
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,22 +1917,27 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
19171917
const APSInt &Size =
19181918
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
19191919

1920-
if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp)
1920+
if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp ||
1921+
ID == Builtin::BIwmemcmp)
19211922
diagnoseNonConstexprBuiltin(S, OpPC, ID);
19221923

19231924
if (Size.isZero()) {
19241925
pushInteger(S, 0, Call->getType());
19251926
return true;
19261927
}
19271928

1929+
bool IsWide =
1930+
(ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp);
1931+
1932+
const ASTContext &ASTCtx = S.getASTContext();
19281933
// FIXME: This is an arbitrary limitation the current constant interpreter
19291934
// had. We could remove this.
1930-
if (!isOneByteCharacterType(PtrA.getType()) ||
1931-
!isOneByteCharacterType(PtrB.getType())) {
1935+
if (!IsWide && (!isOneByteCharacterType(PtrA.getType()) ||
1936+
!isOneByteCharacterType(PtrB.getType()))) {
19321937
S.FFDiag(S.Current->getSource(OpPC),
19331938
diag::note_constexpr_memcmp_unsupported)
1934-
<< ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str()
1935-
<< PtrA.getType() << PtrB.getType();
1939+
<< ("'" + ASTCtx.BuiltinInfo.getName(ID) + "'").str() << PtrA.getType()
1940+
<< PtrB.getType();
19361941
return false;
19371942
}
19381943

@@ -1941,42 +1946,62 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
19411946

19421947
// Now, read both pointers to a buffer and compare those.
19431948
BitcastBuffer BufferA(
1944-
Bits(S.getASTContext().getTypeSize(PtrA.getFieldDesc()->getType())));
1949+
Bits(ASTCtx.getTypeSize(PtrA.getFieldDesc()->getType())));
19451950
readPointerToBuffer(S.getContext(), PtrA, BufferA, false);
19461951
// FIXME: The swapping here is UNDOING something we do when reading the
19471952
// data into the buffer.
1948-
if (S.getASTContext().getTargetInfo().isBigEndian())
1953+
if (ASTCtx.getTargetInfo().isBigEndian())
19491954
swapBytes(BufferA.Data.get(), BufferA.byteSize().getQuantity());
19501955

19511956
BitcastBuffer BufferB(
1952-
Bits(S.getASTContext().getTypeSize(PtrB.getFieldDesc()->getType())));
1957+
Bits(ASTCtx.getTypeSize(PtrB.getFieldDesc()->getType())));
19531958
readPointerToBuffer(S.getContext(), PtrB, BufferB, false);
19541959
// FIXME: The swapping here is UNDOING something we do when reading the
19551960
// data into the buffer.
1956-
if (S.getASTContext().getTargetInfo().isBigEndian())
1961+
if (ASTCtx.getTargetInfo().isBigEndian())
19571962
swapBytes(BufferB.Data.get(), BufferB.byteSize().getQuantity());
19581963

19591964
size_t MinBufferSize = std::min(BufferA.byteSize().getQuantity(),
19601965
BufferB.byteSize().getQuantity());
1961-
size_t CmpSize =
1962-
std::min(MinBufferSize, static_cast<size_t>(Size.getZExtValue()));
1963-
1964-
for (size_t I = 0; I != CmpSize; ++I) {
1965-
std::byte A = BufferA.Data[I];
1966-
std::byte B = BufferB.Data[I];
19671966

1968-
if (A < B) {
1969-
pushInteger(S, -1, Call->getType());
1970-
return true;
1971-
} else if (A > B) {
1972-
pushInteger(S, 1, Call->getType());
1973-
return true;
1967+
unsigned ElemSize = 1;
1968+
if (IsWide)
1969+
ElemSize = ASTCtx.getTypeSizeInChars(ASTCtx.getWCharType()).getQuantity();
1970+
// The Size given for the wide variants is in wide-char units. Convert it
1971+
// to bytes.
1972+
size_t ByteSize = Size.getZExtValue() * ElemSize;
1973+
size_t CmpSize = std::min(MinBufferSize, ByteSize);
1974+
1975+
for (size_t I = 0; I != CmpSize; I += ElemSize) {
1976+
if (IsWide) {
1977+
INT_TYPE_SWITCH(*S.getContext().classify(ASTCtx.getWCharType()), {
1978+
T A = *reinterpret_cast<T *>(BufferA.Data.get() + I);
1979+
T B = *reinterpret_cast<T *>(BufferB.Data.get() + I);
1980+
if (A < B) {
1981+
pushInteger(S, -1, Call->getType());
1982+
return true;
1983+
} else if (A > B) {
1984+
pushInteger(S, 1, Call->getType());
1985+
return true;
1986+
}
1987+
});
1988+
} else {
1989+
std::byte A = BufferA.Data[I];
1990+
std::byte B = BufferB.Data[I];
1991+
1992+
if (A < B) {
1993+
pushInteger(S, -1, Call->getType());
1994+
return true;
1995+
} else if (A > B) {
1996+
pushInteger(S, 1, Call->getType());
1997+
return true;
1998+
}
19741999
}
19752000
}
19762001

19772002
// We compared CmpSize bytes above. If the limiting factor was the Size
19782003
// passed, we're done and the result is equality (0).
1979-
if (Size.getZExtValue() <= CmpSize) {
2004+
if (ByteSize <= CmpSize) {
19802005
pushInteger(S, 0, Call->getType());
19812006
return true;
19822007
}
@@ -2467,6 +2492,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
24672492
case Builtin::BImemcmp:
24682493
case Builtin::BI__builtin_bcmp:
24692494
case Builtin::BIbcmp:
2495+
case Builtin::BI__builtin_wmemcmp:
2496+
case Builtin::BIwmemcmp:
24702497
if (!interp__builtin_memcmp(S, OpPC, Frame, F, Call))
24712498
return false;
24722499
break;

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,4 +1270,19 @@ namespace Memcmp {
12701270
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
12711271
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0);
12721272
static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0);
1273+
1274+
1275+
static_assert(__builtin_wmemcmp(L"abaa", L"abba", 3) == -1);
1276+
static_assert(__builtin_wmemcmp(L"abaa", L"abba", 2) == 0);
1277+
static_assert(__builtin_wmemcmp(0, 0, 0) == 0);
1278+
#if __WCHAR_WIDTH__ == 32
1279+
static_assert(__builtin_wmemcmp(L"a\x83838383", L"aa", 2) ==
1280+
(wchar_t)-1U >> 31);
1281+
#endif
1282+
static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0banana", 100) == 0); // both-error {{not an integral constant}} \
1283+
// both-note {{dereferenced one-past-the-end}}
1284+
static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 100) == -1); // FIXME: Should we reject this?
1285+
static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 7) == -1);
1286+
static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 6) == -1);
1287+
static_assert(__builtin_wmemcmp(L"abab\0banana", L"abab\0canada", 5) == 0);
12731288
}

0 commit comments

Comments
 (0)