@@ -1917,22 +1917,27 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
1917
1917
const APSInt &Size =
1918
1918
peekToAPSInt (S.Stk , *S.getContext ().classify (Call->getArg (2 )));
1919
1919
1920
- if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp)
1920
+ if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp ||
1921
+ ID == Builtin::BIwmemcmp)
1921
1922
diagnoseNonConstexprBuiltin (S, OpPC, ID);
1922
1923
1923
1924
if (Size .isZero ()) {
1924
1925
pushInteger (S, 0 , Call->getType ());
1925
1926
return true ;
1926
1927
}
1927
1928
1929
+ bool IsWide =
1930
+ (ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp);
1931
+
1932
+ const ASTContext &ASTCtx = S.getASTContext ();
1928
1933
// FIXME: This is an arbitrary limitation the current constant interpreter
1929
1934
// had. We could remove this.
1930
- if (!isOneByteCharacterType (PtrA.getType ()) ||
1931
- !isOneByteCharacterType (PtrB.getType ())) {
1935
+ if (!IsWide && (! isOneByteCharacterType (PtrA.getType ()) ||
1936
+ !isOneByteCharacterType (PtrB.getType () ))) {
1932
1937
S.FFDiag (S.Current ->getSource (OpPC),
1933
1938
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 ();
1936
1941
return false ;
1937
1942
}
1938
1943
@@ -1941,42 +1946,62 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
1941
1946
1942
1947
// Now, read both pointers to a buffer and compare those.
1943
1948
BitcastBuffer BufferA (
1944
- Bits (S. getASTContext () .getTypeSize (PtrA.getFieldDesc ()->getType ())));
1949
+ Bits (ASTCtx .getTypeSize (PtrA.getFieldDesc ()->getType ())));
1945
1950
readPointerToBuffer (S.getContext (), PtrA, BufferA, false );
1946
1951
// FIXME: The swapping here is UNDOING something we do when reading the
1947
1952
// data into the buffer.
1948
- if (S. getASTContext () .getTargetInfo ().isBigEndian ())
1953
+ if (ASTCtx .getTargetInfo ().isBigEndian ())
1949
1954
swapBytes (BufferA.Data .get (), BufferA.byteSize ().getQuantity ());
1950
1955
1951
1956
BitcastBuffer BufferB (
1952
- Bits (S. getASTContext () .getTypeSize (PtrB.getFieldDesc ()->getType ())));
1957
+ Bits (ASTCtx .getTypeSize (PtrB.getFieldDesc ()->getType ())));
1953
1958
readPointerToBuffer (S.getContext (), PtrB, BufferB, false );
1954
1959
// FIXME: The swapping here is UNDOING something we do when reading the
1955
1960
// data into the buffer.
1956
- if (S. getASTContext () .getTargetInfo ().isBigEndian ())
1961
+ if (ASTCtx .getTargetInfo ().isBigEndian ())
1957
1962
swapBytes (BufferB.Data .get (), BufferB.byteSize ().getQuantity ());
1958
1963
1959
1964
size_t MinBufferSize = std::min (BufferA.byteSize ().getQuantity (),
1960
1965
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];
1967
1966
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
+ }
1974
1999
}
1975
2000
}
1976
2001
1977
2002
// We compared CmpSize bytes above. If the limiting factor was the Size
1978
2003
// passed, we're done and the result is equality (0).
1979
- if (Size . getZExtValue () <= CmpSize) {
2004
+ if (ByteSize <= CmpSize) {
1980
2005
pushInteger (S, 0 , Call->getType ());
1981
2006
return true ;
1982
2007
}
@@ -2467,6 +2492,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
2467
2492
case Builtin::BImemcmp:
2468
2493
case Builtin::BI__builtin_bcmp:
2469
2494
case Builtin::BIbcmp:
2495
+ case Builtin::BI__builtin_wmemcmp:
2496
+ case Builtin::BIwmemcmp:
2470
2497
if (!interp__builtin_memcmp (S, OpPC, Frame, F, Call))
2471
2498
return false ;
2472
2499
break ;
0 commit comments