@@ -1830,6 +1830,7 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
1830
1830
1831
1831
return true ;
1832
1832
}
1833
+
1833
1834
static bool interp__builtin_memcpy (InterpState &S, CodePtr OpPC,
1834
1835
const InterpFrame *Frame,
1835
1836
const Function *Func, const CallExpr *Call) {
@@ -1900,6 +1901,67 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
1900
1901
return true ;
1901
1902
}
1902
1903
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
+
1903
1965
bool InterpretBuiltin (InterpState &S, CodePtr OpPC, const Function *F,
1904
1966
const CallExpr *Call, uint32_t BuiltinID) {
1905
1967
const InterpFrame *Frame = S.Current ;
@@ -2373,6 +2435,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
2373
2435
return false ;
2374
2436
break ;
2375
2437
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
+
2376
2444
default :
2377
2445
S.FFDiag (S.Current ->getLocation (OpPC),
2378
2446
diag::note_invalid_subexpr_in_const_expr)
0 commit comments