@@ -1830,6 +1830,7 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
18301830
18311831 return true ;
18321832}
1833+
18331834static bool interp__builtin_memcpy (InterpState &S, CodePtr OpPC,
18341835 const InterpFrame *Frame,
18351836 const Function *Func, const CallExpr *Call) {
@@ -1900,6 +1901,67 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
19001901 return true ;
19011902}
19021903
1904+ // / Determine if T is a character type for which we guarantee that
1905+ // / sizeof(T) == 1.
1906+ static bool isOneByteCharacterType (QualType T) {
1907+ return T->isCharType () || T->isChar8Type ();
1908+ }
1909+
1910+ static bool interp__builtin_memcmp (InterpState &S, CodePtr OpPC,
1911+ const InterpFrame *Frame,
1912+ const Function *Func, const CallExpr *Call) {
1913+ assert (Call->getNumArgs () == 3 );
1914+ unsigned ID = Func->getBuiltinID ();
1915+ const Pointer &PtrA = getParam<Pointer>(Frame, 0 );
1916+ const Pointer &PtrB = getParam<Pointer>(Frame, 1 );
1917+ const APSInt &Size =
1918+ peekToAPSInt (S.Stk , *S.getContext ().classify (Call->getArg (2 )));
1919+
1920+ if (ID == Builtin::BImemcmp)
1921+ diagnoseNonConstexprBuiltin (S, OpPC, ID);
1922+
1923+ if (Size.isZero ()) {
1924+ pushInteger (S, 0 , Call->getType ());
1925+ return true ;
1926+ }
1927+
1928+ // FIXME: This is an arbitrary limitation the current constant interpreter
1929+ // had. We could remove this.
1930+ if (!isOneByteCharacterType (PtrA.getType ()) ||
1931+ !isOneByteCharacterType (PtrB.getType ())) {
1932+ S.FFDiag (S.Current ->getSource (OpPC),
1933+ diag::note_constexpr_memcmp_unsupported)
1934+ << (" '" + S.getASTContext ().BuiltinInfo .getName (ID) + " '" ).str ()
1935+ << PtrA.getType () << PtrB.getType ();
1936+ return false ;
1937+ }
1938+
1939+ if (PtrA.isDummy () || PtrB.isDummy ())
1940+ return false ;
1941+
1942+ // Now, read both pointers to a buffer and compare those.
1943+ BitcastBuffer BufferA (
1944+ Bits (S.getASTContext ().getTypeSize (PtrA.getFieldDesc ()->getType ())));
1945+ readPointerToBuffer (S.getContext (), PtrA, BufferA, false );
1946+
1947+ BitcastBuffer BufferB (
1948+ Bits (S.getASTContext ().getTypeSize (PtrB.getFieldDesc ()->getType ())));
1949+ readPointerToBuffer (S.getContext (), PtrB, BufferB, false );
1950+
1951+ size_t MinBufferSize = std::min (BufferA.byteSize ().getQuantity (),
1952+ BufferB.byteSize ().getQuantity ());
1953+ size_t CmpSize = std::min (MinBufferSize, Size.getZExtValue ());
1954+ int Result = std::memcmp (BufferA.Data .get (), BufferB.Data .get (), CmpSize);
1955+ if (Result == 0 )
1956+ pushInteger (S, 0 , Call->getType ());
1957+ else if (Result < 0 )
1958+ pushInteger (S, -1 , Call->getType ());
1959+ else
1960+ pushInteger (S, 1 , Call->getType ());
1961+
1962+ return true ;
1963+ }
1964+
19031965bool InterpretBuiltin (InterpState &S, CodePtr OpPC, const Function *F,
19041966 const CallExpr *Call, uint32_t BuiltinID) {
19051967 const InterpFrame *Frame = S.Current ;
@@ -2373,6 +2435,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
23732435 return false ;
23742436 break ;
23752437
2438+ case Builtin::BI__builtin_memcmp:
2439+ case Builtin::BImemcmp:
2440+ if (!interp__builtin_memcmp (S, OpPC, Frame, F, Call))
2441+ return false ;
2442+ break ;
2443+
23762444 default :
23772445 S.FFDiag (S.Current ->getLocation (OpPC),
23782446 diag::note_invalid_subexpr_in_const_expr)
0 commit comments