@@ -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 ;
0 commit comments