xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===--- InterpBuiltin.cpp - Interpreter for the constexpr VM ---*- C++ -*-===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric #include "../ExprConstShared.h"
906c3fb27SDimitry Andric #include "Boolean.h"
1006c3fb27SDimitry Andric #include "Interp.h"
1106c3fb27SDimitry Andric #include "PrimType.h"
12*0fca6ea1SDimitry Andric #include "clang/AST/OSLog.h"
135f757f3fSDimitry Andric #include "clang/AST/RecordLayout.h"
1406c3fb27SDimitry Andric #include "clang/Basic/Builtins.h"
155f757f3fSDimitry Andric #include "clang/Basic/TargetInfo.h"
16*0fca6ea1SDimitry Andric #include "llvm/Support/SipHash.h"
1706c3fb27SDimitry Andric 
1806c3fb27SDimitry Andric namespace clang {
1906c3fb27SDimitry Andric namespace interp {
2006c3fb27SDimitry Andric 
21*0fca6ea1SDimitry Andric static unsigned callArgSize(const InterpState &S, const CallExpr *C) {
22*0fca6ea1SDimitry Andric   unsigned O = 0;
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric   for (const Expr *E : C->arguments()) {
25*0fca6ea1SDimitry Andric     O += align(primSize(*S.getContext().classify(E)));
26*0fca6ea1SDimitry Andric   }
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric   return O;
29*0fca6ea1SDimitry Andric }
30*0fca6ea1SDimitry Andric 
315f757f3fSDimitry Andric template <typename T>
325f757f3fSDimitry Andric static T getParam(const InterpFrame *Frame, unsigned Index) {
335f757f3fSDimitry Andric   assert(Frame->getFunction()->getNumParams() > Index);
3406c3fb27SDimitry Andric   unsigned Offset = Frame->getFunction()->getParamOffset(Index);
3506c3fb27SDimitry Andric   return Frame->getParam<T>(Offset);
3606c3fb27SDimitry Andric }
3706c3fb27SDimitry Andric 
385f757f3fSDimitry Andric PrimType getIntPrimType(const InterpState &S) {
395f757f3fSDimitry Andric   const TargetInfo &TI = S.getCtx().getTargetInfo();
405f757f3fSDimitry Andric   unsigned IntWidth = TI.getIntWidth();
415f757f3fSDimitry Andric 
425f757f3fSDimitry Andric   if (IntWidth == 32)
435f757f3fSDimitry Andric     return PT_Sint32;
445f757f3fSDimitry Andric   else if (IntWidth == 16)
455f757f3fSDimitry Andric     return PT_Sint16;
465f757f3fSDimitry Andric   llvm_unreachable("Int isn't 16 or 32 bit?");
475f757f3fSDimitry Andric }
485f757f3fSDimitry Andric 
495f757f3fSDimitry Andric PrimType getLongPrimType(const InterpState &S) {
505f757f3fSDimitry Andric   const TargetInfo &TI = S.getCtx().getTargetInfo();
515f757f3fSDimitry Andric   unsigned LongWidth = TI.getLongWidth();
525f757f3fSDimitry Andric 
535f757f3fSDimitry Andric   if (LongWidth == 64)
545f757f3fSDimitry Andric     return PT_Sint64;
555f757f3fSDimitry Andric   else if (LongWidth == 32)
565f757f3fSDimitry Andric     return PT_Sint32;
575f757f3fSDimitry Andric   else if (LongWidth == 16)
585f757f3fSDimitry Andric     return PT_Sint16;
595f757f3fSDimitry Andric   llvm_unreachable("long isn't 16, 32 or 64 bit?");
605f757f3fSDimitry Andric }
615f757f3fSDimitry Andric 
625f757f3fSDimitry Andric /// Peek an integer value from the stack into an APSInt.
635f757f3fSDimitry Andric static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
645f757f3fSDimitry Andric   if (Offset == 0)
655f757f3fSDimitry Andric     Offset = align(primSize(T));
665f757f3fSDimitry Andric 
675f757f3fSDimitry Andric   APSInt R;
68*0fca6ea1SDimitry Andric   INT_TYPE_SWITCH(T, R = Stk.peek<T>(Offset).toAPSInt());
695f757f3fSDimitry Andric 
705f757f3fSDimitry Andric   return R;
715f757f3fSDimitry Andric }
725f757f3fSDimitry Andric 
73*0fca6ea1SDimitry Andric /// Pushes \p Val on the stack as the type given by \p QT.
74*0fca6ea1SDimitry Andric static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) {
75*0fca6ea1SDimitry Andric   assert(QT->isSignedIntegerOrEnumerationType() ||
76*0fca6ea1SDimitry Andric          QT->isUnsignedIntegerOrEnumerationType());
77*0fca6ea1SDimitry Andric   std::optional<PrimType> T = S.getContext().classify(QT);
78*0fca6ea1SDimitry Andric   assert(T);
79*0fca6ea1SDimitry Andric 
80*0fca6ea1SDimitry Andric   if (QT->isSignedIntegerOrEnumerationType()) {
81*0fca6ea1SDimitry Andric     int64_t V = Val.getSExtValue();
82*0fca6ea1SDimitry Andric     INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
83*0fca6ea1SDimitry Andric   } else {
84*0fca6ea1SDimitry Andric     assert(QT->isUnsignedIntegerOrEnumerationType());
85*0fca6ea1SDimitry Andric     uint64_t V = Val.getZExtValue();
86*0fca6ea1SDimitry Andric     INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
87*0fca6ea1SDimitry Andric   }
88*0fca6ea1SDimitry Andric }
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric template <typename T>
91*0fca6ea1SDimitry Andric static void pushInteger(InterpState &S, T Val, QualType QT) {
92*0fca6ea1SDimitry Andric   if constexpr (std::is_same_v<T, APInt>)
93*0fca6ea1SDimitry Andric     pushInteger(S, APSInt(Val, !std::is_signed_v<T>), QT);
945f757f3fSDimitry Andric   else
95*0fca6ea1SDimitry Andric     pushInteger(S,
96*0fca6ea1SDimitry Andric                 APSInt(APInt(sizeof(T) * 8, static_cast<uint64_t>(Val),
97*0fca6ea1SDimitry Andric                              std::is_signed_v<T>),
98*0fca6ea1SDimitry Andric                        !std::is_signed_v<T>),
99*0fca6ea1SDimitry Andric                 QT);
1005f757f3fSDimitry Andric }
1015f757f3fSDimitry Andric 
102*0fca6ea1SDimitry Andric static void assignInteger(Pointer &Dest, PrimType ValueT, const APSInt &Value) {
103*0fca6ea1SDimitry Andric   INT_TYPE_SWITCH_NO_BOOL(
104*0fca6ea1SDimitry Andric       ValueT, { Dest.deref<T>() = T::from(static_cast<T>(Value)); });
1055f757f3fSDimitry Andric }
1065f757f3fSDimitry Andric 
1075f757f3fSDimitry Andric static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
1085f757f3fSDimitry Andric                          std::optional<PrimType> &T) {
1095f757f3fSDimitry Andric   if (!T)
1105f757f3fSDimitry Andric     return RetVoid(S, OpPC, Result);
1115f757f3fSDimitry Andric 
1125f757f3fSDimitry Andric #define RET_CASE(X)                                                            \
1135f757f3fSDimitry Andric   case X:                                                                      \
1145f757f3fSDimitry Andric     return Ret<X>(S, OpPC, Result);
1155f757f3fSDimitry Andric   switch (*T) {
116297eecfbSDimitry Andric     RET_CASE(PT_Ptr);
117297eecfbSDimitry Andric     RET_CASE(PT_FnPtr);
1185f757f3fSDimitry Andric     RET_CASE(PT_Float);
1195f757f3fSDimitry Andric     RET_CASE(PT_Bool);
1205f757f3fSDimitry Andric     RET_CASE(PT_Sint8);
1215f757f3fSDimitry Andric     RET_CASE(PT_Uint8);
1225f757f3fSDimitry Andric     RET_CASE(PT_Sint16);
1235f757f3fSDimitry Andric     RET_CASE(PT_Uint16);
1245f757f3fSDimitry Andric     RET_CASE(PT_Sint32);
1255f757f3fSDimitry Andric     RET_CASE(PT_Uint32);
1265f757f3fSDimitry Andric     RET_CASE(PT_Sint64);
1275f757f3fSDimitry Andric     RET_CASE(PT_Uint64);
1285f757f3fSDimitry Andric   default:
1295f757f3fSDimitry Andric     llvm_unreachable("Unsupported return type for builtin function");
1305f757f3fSDimitry Andric   }
1315f757f3fSDimitry Andric #undef RET_CASE
1325f757f3fSDimitry Andric }
1335f757f3fSDimitry Andric 
134*0fca6ea1SDimitry Andric static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
135*0fca6ea1SDimitry Andric                                                   const InterpFrame *Frame,
136*0fca6ea1SDimitry Andric                                                   const CallExpr *Call) {
137*0fca6ea1SDimitry Andric   // The current frame is the one for __builtin_is_constant_evaluated.
138*0fca6ea1SDimitry Andric   // The one above that, potentially the one for std::is_constant_evaluated().
139*0fca6ea1SDimitry Andric   if (S.inConstantContext() && !S.checkingPotentialConstantExpression() &&
140*0fca6ea1SDimitry Andric       Frame->Caller && S.getEvalStatus().Diag) {
141*0fca6ea1SDimitry Andric     auto isStdCall = [](const FunctionDecl *F) -> bool {
142*0fca6ea1SDimitry Andric       return F && F->isInStdNamespace() && F->getIdentifier() &&
143*0fca6ea1SDimitry Andric              F->getIdentifier()->isStr("is_constant_evaluated");
144*0fca6ea1SDimitry Andric     };
145*0fca6ea1SDimitry Andric     const InterpFrame *Caller = Frame->Caller;
146*0fca6ea1SDimitry Andric 
147*0fca6ea1SDimitry Andric     if (Caller->Caller && isStdCall(Caller->getCallee())) {
148*0fca6ea1SDimitry Andric       const Expr *E = Caller->Caller->getExpr(Caller->getRetPC());
149*0fca6ea1SDimitry Andric       S.report(E->getExprLoc(),
150*0fca6ea1SDimitry Andric                diag::warn_is_constant_evaluated_always_true_constexpr)
151*0fca6ea1SDimitry Andric           << "std::is_constant_evaluated" << E->getSourceRange();
152*0fca6ea1SDimitry Andric     } else {
153*0fca6ea1SDimitry Andric       const Expr *E = Frame->Caller->getExpr(Frame->getRetPC());
154*0fca6ea1SDimitry Andric       S.report(E->getExprLoc(),
155*0fca6ea1SDimitry Andric                diag::warn_is_constant_evaluated_always_true_constexpr)
156*0fca6ea1SDimitry Andric           << "__builtin_is_constant_evaluated" << E->getSourceRange();
157*0fca6ea1SDimitry Andric     }
158*0fca6ea1SDimitry Andric   }
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric   S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
161*0fca6ea1SDimitry Andric   return true;
162*0fca6ea1SDimitry Andric }
163*0fca6ea1SDimitry Andric 
16406c3fb27SDimitry Andric static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
165*0fca6ea1SDimitry Andric                                    const InterpFrame *Frame,
166*0fca6ea1SDimitry Andric                                    const CallExpr *Call) {
16706c3fb27SDimitry Andric   const Pointer &A = getParam<Pointer>(Frame, 0);
16806c3fb27SDimitry Andric   const Pointer &B = getParam<Pointer>(Frame, 1);
16906c3fb27SDimitry Andric 
17006c3fb27SDimitry Andric   if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
17106c3fb27SDimitry Andric     return false;
17206c3fb27SDimitry Andric 
173*0fca6ea1SDimitry Andric   if (A.isDummy() || B.isDummy())
174*0fca6ea1SDimitry Andric     return false;
175*0fca6ea1SDimitry Andric 
17606c3fb27SDimitry Andric   assert(A.getFieldDesc()->isPrimitiveArray());
17706c3fb27SDimitry Andric   assert(B.getFieldDesc()->isPrimitiveArray());
17806c3fb27SDimitry Andric 
17906c3fb27SDimitry Andric   unsigned IndexA = A.getIndex();
18006c3fb27SDimitry Andric   unsigned IndexB = B.getIndex();
18106c3fb27SDimitry Andric   int32_t Result = 0;
18206c3fb27SDimitry Andric   for (;; ++IndexA, ++IndexB) {
18306c3fb27SDimitry Andric     const Pointer &PA = A.atIndex(IndexA);
18406c3fb27SDimitry Andric     const Pointer &PB = B.atIndex(IndexB);
18506c3fb27SDimitry Andric     if (!CheckRange(S, OpPC, PA, AK_Read) ||
18606c3fb27SDimitry Andric         !CheckRange(S, OpPC, PB, AK_Read)) {
18706c3fb27SDimitry Andric       return false;
18806c3fb27SDimitry Andric     }
18906c3fb27SDimitry Andric     uint8_t CA = PA.deref<uint8_t>();
19006c3fb27SDimitry Andric     uint8_t CB = PB.deref<uint8_t>();
19106c3fb27SDimitry Andric 
19206c3fb27SDimitry Andric     if (CA > CB) {
19306c3fb27SDimitry Andric       Result = 1;
19406c3fb27SDimitry Andric       break;
19506c3fb27SDimitry Andric     } else if (CA < CB) {
19606c3fb27SDimitry Andric       Result = -1;
19706c3fb27SDimitry Andric       break;
19806c3fb27SDimitry Andric     }
19906c3fb27SDimitry Andric     if (CA == 0 || CB == 0)
20006c3fb27SDimitry Andric       break;
20106c3fb27SDimitry Andric   }
20206c3fb27SDimitry Andric 
203*0fca6ea1SDimitry Andric   pushInteger(S, Result, Call->getType());
20406c3fb27SDimitry Andric   return true;
20506c3fb27SDimitry Andric }
20606c3fb27SDimitry Andric 
2075f757f3fSDimitry Andric static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
208*0fca6ea1SDimitry Andric                                    const InterpFrame *Frame,
209*0fca6ea1SDimitry Andric                                    const CallExpr *Call) {
2105f757f3fSDimitry Andric   const Pointer &StrPtr = getParam<Pointer>(Frame, 0);
2115f757f3fSDimitry Andric 
2125f757f3fSDimitry Andric   if (!CheckArray(S, OpPC, StrPtr))
2135f757f3fSDimitry Andric     return false;
2145f757f3fSDimitry Andric 
2155f757f3fSDimitry Andric   if (!CheckLive(S, OpPC, StrPtr, AK_Read))
2165f757f3fSDimitry Andric     return false;
2175f757f3fSDimitry Andric 
218*0fca6ea1SDimitry Andric   if (!CheckDummy(S, OpPC, StrPtr, AK_Read))
2195f757f3fSDimitry Andric     return false;
2205f757f3fSDimitry Andric 
2215f757f3fSDimitry Andric   assert(StrPtr.getFieldDesc()->isPrimitiveArray());
2225f757f3fSDimitry Andric 
2235f757f3fSDimitry Andric   size_t Len = 0;
2245f757f3fSDimitry Andric   for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
2255f757f3fSDimitry Andric     const Pointer &ElemPtr = StrPtr.atIndex(I);
2265f757f3fSDimitry Andric 
2275f757f3fSDimitry Andric     if (!CheckRange(S, OpPC, ElemPtr, AK_Read))
2285f757f3fSDimitry Andric       return false;
2295f757f3fSDimitry Andric 
2305f757f3fSDimitry Andric     uint8_t Val = ElemPtr.deref<uint8_t>();
2315f757f3fSDimitry Andric     if (Val == 0)
2325f757f3fSDimitry Andric       break;
2335f757f3fSDimitry Andric   }
2345f757f3fSDimitry Andric 
235*0fca6ea1SDimitry Andric   pushInteger(S, Len, Call->getType());
236*0fca6ea1SDimitry Andric 
2375f757f3fSDimitry Andric   return true;
2385f757f3fSDimitry Andric }
2395f757f3fSDimitry Andric 
2405f757f3fSDimitry Andric static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
2415f757f3fSDimitry Andric                                 const InterpFrame *Frame, const Function *F,
2425f757f3fSDimitry Andric                                 bool Signaling) {
2435f757f3fSDimitry Andric   const Pointer &Arg = getParam<Pointer>(Frame, 0);
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   if (!CheckLoad(S, OpPC, Arg))
2465f757f3fSDimitry Andric     return false;
2475f757f3fSDimitry Andric 
2485f757f3fSDimitry Andric   assert(Arg.getFieldDesc()->isPrimitiveArray());
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric   // Convert the given string to an integer using StringRef's API.
2515f757f3fSDimitry Andric   llvm::APInt Fill;
2525f757f3fSDimitry Andric   std::string Str;
2535f757f3fSDimitry Andric   assert(Arg.getNumElems() >= 1);
2545f757f3fSDimitry Andric   for (unsigned I = 0;; ++I) {
2555f757f3fSDimitry Andric     const Pointer &Elem = Arg.atIndex(I);
2565f757f3fSDimitry Andric 
2575f757f3fSDimitry Andric     if (!CheckLoad(S, OpPC, Elem))
2585f757f3fSDimitry Andric       return false;
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric     if (Elem.deref<int8_t>() == 0)
2615f757f3fSDimitry Andric       break;
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric     Str += Elem.deref<char>();
2645f757f3fSDimitry Andric   }
2655f757f3fSDimitry Andric 
2665f757f3fSDimitry Andric   // Treat empty strings as if they were zero.
2675f757f3fSDimitry Andric   if (Str.empty())
2685f757f3fSDimitry Andric     Fill = llvm::APInt(32, 0);
2695f757f3fSDimitry Andric   else if (StringRef(Str).getAsInteger(0, Fill))
2705f757f3fSDimitry Andric     return false;
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric   const llvm::fltSemantics &TargetSemantics =
2735f757f3fSDimitry Andric       S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
2745f757f3fSDimitry Andric 
2755f757f3fSDimitry Andric   Floating Result;
2765f757f3fSDimitry Andric   if (S.getCtx().getTargetInfo().isNan2008()) {
2775f757f3fSDimitry Andric     if (Signaling)
2785f757f3fSDimitry Andric       Result = Floating(
2795f757f3fSDimitry Andric           llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
2805f757f3fSDimitry Andric     else
2815f757f3fSDimitry Andric       Result = Floating(
2825f757f3fSDimitry Andric           llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
2835f757f3fSDimitry Andric   } else {
2845f757f3fSDimitry Andric     // Prior to IEEE 754-2008, architectures were allowed to choose whether
2855f757f3fSDimitry Andric     // the first bit of their significand was set for qNaN or sNaN. MIPS chose
2865f757f3fSDimitry Andric     // a different encoding to what became a standard in 2008, and for pre-
2875f757f3fSDimitry Andric     // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
2885f757f3fSDimitry Andric     // sNaN. This is now known as "legacy NaN" encoding.
2895f757f3fSDimitry Andric     if (Signaling)
2905f757f3fSDimitry Andric       Result = Floating(
2915f757f3fSDimitry Andric           llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
2925f757f3fSDimitry Andric     else
2935f757f3fSDimitry Andric       Result = Floating(
2945f757f3fSDimitry Andric           llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
2955f757f3fSDimitry Andric   }
2965f757f3fSDimitry Andric 
2975f757f3fSDimitry Andric   S.Stk.push<Floating>(Result);
2985f757f3fSDimitry Andric   return true;
2995f757f3fSDimitry Andric }
3005f757f3fSDimitry Andric 
3015f757f3fSDimitry Andric static bool interp__builtin_inf(InterpState &S, CodePtr OpPC,
3025f757f3fSDimitry Andric                                 const InterpFrame *Frame, const Function *F) {
3035f757f3fSDimitry Andric   const llvm::fltSemantics &TargetSemantics =
3045f757f3fSDimitry Andric       S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
3055f757f3fSDimitry Andric 
3065f757f3fSDimitry Andric   S.Stk.push<Floating>(Floating::getInf(TargetSemantics));
3075f757f3fSDimitry Andric   return true;
3085f757f3fSDimitry Andric }
3095f757f3fSDimitry Andric 
3105f757f3fSDimitry Andric static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC,
3115f757f3fSDimitry Andric                                      const InterpFrame *Frame,
3125f757f3fSDimitry Andric                                      const Function *F) {
3135f757f3fSDimitry Andric   const Floating &Arg1 = getParam<Floating>(Frame, 0);
3145f757f3fSDimitry Andric   const Floating &Arg2 = getParam<Floating>(Frame, 1);
3155f757f3fSDimitry Andric 
3165f757f3fSDimitry Andric   APFloat Copy = Arg1.getAPFloat();
3175f757f3fSDimitry Andric   Copy.copySign(Arg2.getAPFloat());
3185f757f3fSDimitry Andric   S.Stk.push<Floating>(Floating(Copy));
3195f757f3fSDimitry Andric 
3205f757f3fSDimitry Andric   return true;
3215f757f3fSDimitry Andric }
3225f757f3fSDimitry Andric 
3235f757f3fSDimitry Andric static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC,
3245f757f3fSDimitry Andric                                  const InterpFrame *Frame, const Function *F) {
3255f757f3fSDimitry Andric   const Floating &LHS = getParam<Floating>(Frame, 0);
3265f757f3fSDimitry Andric   const Floating &RHS = getParam<Floating>(Frame, 1);
3275f757f3fSDimitry Andric 
3285f757f3fSDimitry Andric   Floating Result;
3295f757f3fSDimitry Andric 
3305f757f3fSDimitry Andric   // When comparing zeroes, return -0.0 if one of the zeroes is negative.
3315f757f3fSDimitry Andric   if (LHS.isZero() && RHS.isZero() && RHS.isNegative())
3325f757f3fSDimitry Andric     Result = RHS;
3335f757f3fSDimitry Andric   else if (LHS.isNan() || RHS < LHS)
3345f757f3fSDimitry Andric     Result = RHS;
3355f757f3fSDimitry Andric   else
3365f757f3fSDimitry Andric     Result = LHS;
3375f757f3fSDimitry Andric 
3385f757f3fSDimitry Andric   S.Stk.push<Floating>(Result);
3395f757f3fSDimitry Andric   return true;
3405f757f3fSDimitry Andric }
3415f757f3fSDimitry Andric 
3425f757f3fSDimitry Andric static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC,
3435f757f3fSDimitry Andric                                  const InterpFrame *Frame,
3445f757f3fSDimitry Andric                                  const Function *Func) {
3455f757f3fSDimitry Andric   const Floating &LHS = getParam<Floating>(Frame, 0);
3465f757f3fSDimitry Andric   const Floating &RHS = getParam<Floating>(Frame, 1);
3475f757f3fSDimitry Andric 
3485f757f3fSDimitry Andric   Floating Result;
3495f757f3fSDimitry Andric 
3505f757f3fSDimitry Andric   // When comparing zeroes, return +0.0 if one of the zeroes is positive.
3515f757f3fSDimitry Andric   if (LHS.isZero() && RHS.isZero() && LHS.isNegative())
3525f757f3fSDimitry Andric     Result = RHS;
3535f757f3fSDimitry Andric   else if (LHS.isNan() || RHS > LHS)
3545f757f3fSDimitry Andric     Result = RHS;
3555f757f3fSDimitry Andric   else
3565f757f3fSDimitry Andric     Result = LHS;
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric   S.Stk.push<Floating>(Result);
3595f757f3fSDimitry Andric   return true;
3605f757f3fSDimitry Andric }
3615f757f3fSDimitry Andric 
3625f757f3fSDimitry Andric /// Defined as __builtin_isnan(...), to accommodate the fact that it can
3635f757f3fSDimitry Andric /// take a float, double, long double, etc.
3645f757f3fSDimitry Andric /// But for us, that's all a Floating anyway.
3655f757f3fSDimitry Andric static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
366*0fca6ea1SDimitry Andric                                   const InterpFrame *Frame, const Function *F,
367*0fca6ea1SDimitry Andric                                   const CallExpr *Call) {
3685f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
3695f757f3fSDimitry Andric 
370*0fca6ea1SDimitry Andric   pushInteger(S, Arg.isNan(), Call->getType());
3715f757f3fSDimitry Andric   return true;
3725f757f3fSDimitry Andric }
3735f757f3fSDimitry Andric 
3745f757f3fSDimitry Andric static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC,
3755f757f3fSDimitry Andric                                         const InterpFrame *Frame,
376*0fca6ea1SDimitry Andric                                         const Function *F,
377*0fca6ea1SDimitry Andric                                         const CallExpr *Call) {
3785f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
3795f757f3fSDimitry Andric 
380*0fca6ea1SDimitry Andric   pushInteger(S, Arg.isSignaling(), Call->getType());
3815f757f3fSDimitry Andric   return true;
3825f757f3fSDimitry Andric }
3835f757f3fSDimitry Andric 
3845f757f3fSDimitry Andric static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC,
3855f757f3fSDimitry Andric                                   const InterpFrame *Frame, const Function *F,
386*0fca6ea1SDimitry Andric                                   bool CheckSign, const CallExpr *Call) {
3875f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
3885f757f3fSDimitry Andric   bool IsInf = Arg.isInf();
3895f757f3fSDimitry Andric 
3905f757f3fSDimitry Andric   if (CheckSign)
391*0fca6ea1SDimitry Andric     pushInteger(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0, Call->getType());
3925f757f3fSDimitry Andric   else
393*0fca6ea1SDimitry Andric     pushInteger(S, Arg.isInf(), Call->getType());
3945f757f3fSDimitry Andric   return true;
3955f757f3fSDimitry Andric }
3965f757f3fSDimitry Andric 
3975f757f3fSDimitry Andric static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC,
3985f757f3fSDimitry Andric                                      const InterpFrame *Frame,
399*0fca6ea1SDimitry Andric                                      const Function *F, const CallExpr *Call) {
4005f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4015f757f3fSDimitry Andric 
402*0fca6ea1SDimitry Andric   pushInteger(S, Arg.isFinite(), Call->getType());
4035f757f3fSDimitry Andric   return true;
4045f757f3fSDimitry Andric }
4055f757f3fSDimitry Andric 
4065f757f3fSDimitry Andric static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC,
4075f757f3fSDimitry Andric                                      const InterpFrame *Frame,
408*0fca6ea1SDimitry Andric                                      const Function *F, const CallExpr *Call) {
4095f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4105f757f3fSDimitry Andric 
411*0fca6ea1SDimitry Andric   pushInteger(S, Arg.isNormal(), Call->getType());
4125f757f3fSDimitry Andric   return true;
4135f757f3fSDimitry Andric }
4145f757f3fSDimitry Andric 
4155f757f3fSDimitry Andric static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC,
4165f757f3fSDimitry Andric                                         const InterpFrame *Frame,
417*0fca6ea1SDimitry Andric                                         const Function *F,
418*0fca6ea1SDimitry Andric                                         const CallExpr *Call) {
4195f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4205f757f3fSDimitry Andric 
421*0fca6ea1SDimitry Andric   pushInteger(S, Arg.isDenormal(), Call->getType());
4225f757f3fSDimitry Andric   return true;
4235f757f3fSDimitry Andric }
4245f757f3fSDimitry Andric 
4255f757f3fSDimitry Andric static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
426*0fca6ea1SDimitry Andric                                    const InterpFrame *Frame, const Function *F,
427*0fca6ea1SDimitry Andric                                    const CallExpr *Call) {
4285f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4295f757f3fSDimitry Andric 
430*0fca6ea1SDimitry Andric   pushInteger(S, Arg.isZero(), Call->getType());
4315f757f3fSDimitry Andric   return true;
4325f757f3fSDimitry Andric }
4335f757f3fSDimitry Andric 
4345f757f3fSDimitry Andric /// First parameter to __builtin_isfpclass is the floating value, the
4355f757f3fSDimitry Andric /// second one is an integral value.
4365f757f3fSDimitry Andric static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
4375f757f3fSDimitry Andric                                       const InterpFrame *Frame,
4385f757f3fSDimitry Andric                                       const Function *Func,
4395f757f3fSDimitry Andric                                       const CallExpr *Call) {
4405f757f3fSDimitry Andric   PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType());
4415f757f3fSDimitry Andric   APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT);
4425f757f3fSDimitry Andric   const Floating &F =
4435f757f3fSDimitry Andric       S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float)));
4445f757f3fSDimitry Andric 
4455f757f3fSDimitry Andric   int32_t Result =
4465f757f3fSDimitry Andric       static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue());
447*0fca6ea1SDimitry Andric   pushInteger(S, Result, Call->getType());
4485f757f3fSDimitry Andric 
4495f757f3fSDimitry Andric   return true;
4505f757f3fSDimitry Andric }
4515f757f3fSDimitry Andric 
4525f757f3fSDimitry Andric /// Five int values followed by one floating value.
4535f757f3fSDimitry Andric static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC,
4545f757f3fSDimitry Andric                                        const InterpFrame *Frame,
455*0fca6ea1SDimitry Andric                                        const Function *Func,
456*0fca6ea1SDimitry Andric                                        const CallExpr *Call) {
4575f757f3fSDimitry Andric   const Floating &Val = S.Stk.peek<Floating>();
4585f757f3fSDimitry Andric 
4595f757f3fSDimitry Andric   unsigned Index;
4605f757f3fSDimitry Andric   switch (Val.getCategory()) {
4615f757f3fSDimitry Andric   case APFloat::fcNaN:
4625f757f3fSDimitry Andric     Index = 0;
4635f757f3fSDimitry Andric     break;
4645f757f3fSDimitry Andric   case APFloat::fcInfinity:
4655f757f3fSDimitry Andric     Index = 1;
4665f757f3fSDimitry Andric     break;
4675f757f3fSDimitry Andric   case APFloat::fcNormal:
4685f757f3fSDimitry Andric     Index = Val.isDenormal() ? 3 : 2;
4695f757f3fSDimitry Andric     break;
4705f757f3fSDimitry Andric   case APFloat::fcZero:
4715f757f3fSDimitry Andric     Index = 4;
4725f757f3fSDimitry Andric     break;
4735f757f3fSDimitry Andric   }
4745f757f3fSDimitry Andric 
4755f757f3fSDimitry Andric   // The last argument is first on the stack.
4765f757f3fSDimitry Andric   assert(Index <= 4);
4775f757f3fSDimitry Andric   unsigned IntSize = primSize(getIntPrimType(S));
4785f757f3fSDimitry Andric   unsigned Offset =
4795f757f3fSDimitry Andric       align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize));
4805f757f3fSDimitry Andric 
4815f757f3fSDimitry Andric   APSInt I = peekToAPSInt(S.Stk, getIntPrimType(S), Offset);
482*0fca6ea1SDimitry Andric   pushInteger(S, I, Call->getType());
4835f757f3fSDimitry Andric   return true;
4845f757f3fSDimitry Andric }
4855f757f3fSDimitry Andric 
4865f757f3fSDimitry Andric // The C standard says "fabs raises no floating-point exceptions,
4875f757f3fSDimitry Andric // even if x is a signaling NaN. The returned value is independent of
4885f757f3fSDimitry Andric // the current rounding direction mode."  Therefore constant folding can
4895f757f3fSDimitry Andric // proceed without regard to the floating point settings.
4905f757f3fSDimitry Andric // Reference, WG14 N2478 F.10.4.3
4915f757f3fSDimitry Andric static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
4925f757f3fSDimitry Andric                                  const InterpFrame *Frame,
4935f757f3fSDimitry Andric                                  const Function *Func) {
4945f757f3fSDimitry Andric   const Floating &Val = getParam<Floating>(Frame, 0);
4955f757f3fSDimitry Andric 
4965f757f3fSDimitry Andric   S.Stk.push<Floating>(Floating::abs(Val));
4975f757f3fSDimitry Andric   return true;
4985f757f3fSDimitry Andric }
4995f757f3fSDimitry Andric 
5005f757f3fSDimitry Andric static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
5015f757f3fSDimitry Andric                                      const InterpFrame *Frame,
5025f757f3fSDimitry Andric                                      const Function *Func,
5035f757f3fSDimitry Andric                                      const CallExpr *Call) {
5045f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5055f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
506*0fca6ea1SDimitry Andric   pushInteger(S, Val.popcount(), Call->getType());
5075f757f3fSDimitry Andric   return true;
5085f757f3fSDimitry Andric }
5095f757f3fSDimitry Andric 
5105f757f3fSDimitry Andric static bool interp__builtin_parity(InterpState &S, CodePtr OpPC,
5115f757f3fSDimitry Andric                                    const InterpFrame *Frame,
5125f757f3fSDimitry Andric                                    const Function *Func, const CallExpr *Call) {
5135f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5145f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
515*0fca6ea1SDimitry Andric   pushInteger(S, Val.popcount() % 2, Call->getType());
5165f757f3fSDimitry Andric   return true;
5175f757f3fSDimitry Andric }
5185f757f3fSDimitry Andric 
5195f757f3fSDimitry Andric static bool interp__builtin_clrsb(InterpState &S, CodePtr OpPC,
5205f757f3fSDimitry Andric                                   const InterpFrame *Frame,
5215f757f3fSDimitry Andric                                   const Function *Func, const CallExpr *Call) {
5225f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5235f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
524*0fca6ea1SDimitry Andric   pushInteger(S, Val.getBitWidth() - Val.getSignificantBits(), Call->getType());
5255f757f3fSDimitry Andric   return true;
5265f757f3fSDimitry Andric }
5275f757f3fSDimitry Andric 
5285f757f3fSDimitry Andric static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC,
5295f757f3fSDimitry Andric                                        const InterpFrame *Frame,
5305f757f3fSDimitry Andric                                        const Function *Func,
5315f757f3fSDimitry Andric                                        const CallExpr *Call) {
5325f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5335f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
534*0fca6ea1SDimitry Andric   pushInteger(S, Val.reverseBits(), Call->getType());
5355f757f3fSDimitry Andric   return true;
5365f757f3fSDimitry Andric }
5375f757f3fSDimitry Andric 
5385f757f3fSDimitry Andric static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC,
5395f757f3fSDimitry Andric                                           const InterpFrame *Frame,
5405f757f3fSDimitry Andric                                           const Function *Func,
5415f757f3fSDimitry Andric                                           const CallExpr *Call) {
5425f757f3fSDimitry Andric   // This is an unevaluated call, so there are no arguments on the stack.
5435f757f3fSDimitry Andric   assert(Call->getNumArgs() == 1);
5445f757f3fSDimitry Andric   const Expr *Arg = Call->getArg(0);
5455f757f3fSDimitry Andric 
5465f757f3fSDimitry Andric   GCCTypeClass ResultClass =
5475f757f3fSDimitry Andric       EvaluateBuiltinClassifyType(Arg->getType(), S.getLangOpts());
5485f757f3fSDimitry Andric   int32_t ReturnVal = static_cast<int32_t>(ResultClass);
549*0fca6ea1SDimitry Andric   pushInteger(S, ReturnVal, Call->getType());
5505f757f3fSDimitry Andric   return true;
5515f757f3fSDimitry Andric }
5525f757f3fSDimitry Andric 
5535f757f3fSDimitry Andric // __builtin_expect(long, long)
5545f757f3fSDimitry Andric // __builtin_expect_with_probability(long, long, double)
5555f757f3fSDimitry Andric static bool interp__builtin_expect(InterpState &S, CodePtr OpPC,
5565f757f3fSDimitry Andric                                    const InterpFrame *Frame,
5575f757f3fSDimitry Andric                                    const Function *Func, const CallExpr *Call) {
5585f757f3fSDimitry Andric   // The return value is simply the value of the first parameter.
5595f757f3fSDimitry Andric   // We ignore the probability.
5605f757f3fSDimitry Andric   unsigned NumArgs = Call->getNumArgs();
5615f757f3fSDimitry Andric   assert(NumArgs == 2 || NumArgs == 3);
5625f757f3fSDimitry Andric 
5635f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5645f757f3fSDimitry Andric   unsigned Offset = align(primSize(getLongPrimType(S))) * 2;
5655f757f3fSDimitry Andric   if (NumArgs == 3)
5665f757f3fSDimitry Andric     Offset += align(primSize(PT_Float));
5675f757f3fSDimitry Andric 
5685f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT, Offset);
569*0fca6ea1SDimitry Andric   pushInteger(S, Val, Call->getType());
5705f757f3fSDimitry Andric   return true;
5715f757f3fSDimitry Andric }
5725f757f3fSDimitry Andric 
5735f757f3fSDimitry Andric /// rotateleft(value, amount)
5745f757f3fSDimitry Andric static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC,
5755f757f3fSDimitry Andric                                    const InterpFrame *Frame,
5765f757f3fSDimitry Andric                                    const Function *Func, const CallExpr *Call,
5775f757f3fSDimitry Andric                                    bool Right) {
578*0fca6ea1SDimitry Andric   PrimType AmountT = *S.getContext().classify(Call->getArg(1)->getType());
579*0fca6ea1SDimitry Andric   PrimType ValueT = *S.getContext().classify(Call->getArg(0)->getType());
5805f757f3fSDimitry Andric 
581*0fca6ea1SDimitry Andric   APSInt Amount = peekToAPSInt(S.Stk, AmountT);
582*0fca6ea1SDimitry Andric   APSInt Value = peekToAPSInt(
583*0fca6ea1SDimitry Andric       S.Stk, ValueT, align(primSize(AmountT)) + align(primSize(ValueT)));
5845f757f3fSDimitry Andric 
5855f757f3fSDimitry Andric   APSInt Result;
5865f757f3fSDimitry Andric   if (Right)
5875f757f3fSDimitry Andric     Result = APSInt(Value.rotr(Amount.urem(Value.getBitWidth())),
5885f757f3fSDimitry Andric                     /*IsUnsigned=*/true);
5895f757f3fSDimitry Andric   else // Left.
5905f757f3fSDimitry Andric     Result = APSInt(Value.rotl(Amount.urem(Value.getBitWidth())),
5915f757f3fSDimitry Andric                     /*IsUnsigned=*/true);
5925f757f3fSDimitry Andric 
593*0fca6ea1SDimitry Andric   pushInteger(S, Result, Call->getType());
5945f757f3fSDimitry Andric   return true;
5955f757f3fSDimitry Andric }
5965f757f3fSDimitry Andric 
5975f757f3fSDimitry Andric static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC,
5985f757f3fSDimitry Andric                                 const InterpFrame *Frame, const Function *Func,
5995f757f3fSDimitry Andric                                 const CallExpr *Call) {
6005f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
6015f757f3fSDimitry Andric   APSInt Value = peekToAPSInt(S.Stk, ArgT);
6025f757f3fSDimitry Andric 
6035f757f3fSDimitry Andric   uint64_t N = Value.countr_zero();
604*0fca6ea1SDimitry Andric   pushInteger(S, N == Value.getBitWidth() ? 0 : N + 1, Call->getType());
6055f757f3fSDimitry Andric   return true;
6065f757f3fSDimitry Andric }
6075f757f3fSDimitry Andric 
608297eecfbSDimitry Andric static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC,
609297eecfbSDimitry Andric                                       const InterpFrame *Frame,
610297eecfbSDimitry Andric                                       const Function *Func,
611297eecfbSDimitry Andric                                       const CallExpr *Call) {
612*0fca6ea1SDimitry Andric   assert(Call->getArg(0)->isLValue());
613*0fca6ea1SDimitry Andric   PrimType PtrT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr);
614297eecfbSDimitry Andric 
615297eecfbSDimitry Andric   if (PtrT == PT_FnPtr) {
616297eecfbSDimitry Andric     const FunctionPointer &Arg = S.Stk.peek<FunctionPointer>();
617297eecfbSDimitry Andric     S.Stk.push<FunctionPointer>(Arg);
618297eecfbSDimitry Andric   } else if (PtrT == PT_Ptr) {
619297eecfbSDimitry Andric     const Pointer &Arg = S.Stk.peek<Pointer>();
620297eecfbSDimitry Andric     S.Stk.push<Pointer>(Arg);
621297eecfbSDimitry Andric   } else {
622297eecfbSDimitry Andric     assert(false && "Unsupported pointer type passed to __builtin_addressof()");
623297eecfbSDimitry Andric   }
624297eecfbSDimitry Andric   return true;
625297eecfbSDimitry Andric }
626297eecfbSDimitry Andric 
627*0fca6ea1SDimitry Andric static bool interp__builtin_move(InterpState &S, CodePtr OpPC,
628*0fca6ea1SDimitry Andric                                  const InterpFrame *Frame, const Function *Func,
629*0fca6ea1SDimitry Andric                                  const CallExpr *Call) {
630*0fca6ea1SDimitry Andric 
631*0fca6ea1SDimitry Andric   PrimType ArgT = S.getContext().classify(Call->getArg(0)).value_or(PT_Ptr);
632*0fca6ea1SDimitry Andric 
633*0fca6ea1SDimitry Andric   TYPE_SWITCH(ArgT, const T &Arg = S.Stk.peek<T>(); S.Stk.push<T>(Arg););
634*0fca6ea1SDimitry Andric 
635*0fca6ea1SDimitry Andric   return Func->getDecl()->isConstexpr();
636*0fca6ea1SDimitry Andric }
637*0fca6ea1SDimitry Andric 
638*0fca6ea1SDimitry Andric static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC,
639*0fca6ea1SDimitry Andric                                                  const InterpFrame *Frame,
640*0fca6ea1SDimitry Andric                                                  const Function *Func,
641*0fca6ea1SDimitry Andric                                                  const CallExpr *Call) {
642*0fca6ea1SDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
643*0fca6ea1SDimitry Andric   APSInt Arg = peekToAPSInt(S.Stk, ArgT);
644*0fca6ea1SDimitry Andric 
645*0fca6ea1SDimitry Andric   int Result =
646*0fca6ea1SDimitry Andric       S.getCtx().getTargetInfo().getEHDataRegisterNumber(Arg.getZExtValue());
647*0fca6ea1SDimitry Andric   pushInteger(S, Result, Call->getType());
648*0fca6ea1SDimitry Andric   return true;
649*0fca6ea1SDimitry Andric }
650*0fca6ea1SDimitry Andric 
651*0fca6ea1SDimitry Andric /// Just takes the first Argument to the call and puts it on the stack.
652*0fca6ea1SDimitry Andric static bool noopPointer(InterpState &S, CodePtr OpPC, const InterpFrame *Frame,
653*0fca6ea1SDimitry Andric                         const Function *Func, const CallExpr *Call) {
654*0fca6ea1SDimitry Andric   const Pointer &Arg = S.Stk.peek<Pointer>();
655*0fca6ea1SDimitry Andric   S.Stk.push<Pointer>(Arg);
656*0fca6ea1SDimitry Andric   return true;
657*0fca6ea1SDimitry Andric }
658*0fca6ea1SDimitry Andric 
659*0fca6ea1SDimitry Andric // Two integral values followed by a pointer (lhs, rhs, resultOut)
660*0fca6ea1SDimitry Andric static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC,
661*0fca6ea1SDimitry Andric                                        const InterpFrame *Frame,
662*0fca6ea1SDimitry Andric                                        const Function *Func,
663*0fca6ea1SDimitry Andric                                        const CallExpr *Call) {
664*0fca6ea1SDimitry Andric   Pointer &ResultPtr = S.Stk.peek<Pointer>();
665*0fca6ea1SDimitry Andric   if (ResultPtr.isDummy())
666*0fca6ea1SDimitry Andric     return false;
667*0fca6ea1SDimitry Andric 
668*0fca6ea1SDimitry Andric   unsigned BuiltinOp = Func->getBuiltinID();
669*0fca6ea1SDimitry Andric   PrimType RHST = *S.getContext().classify(Call->getArg(1)->getType());
670*0fca6ea1SDimitry Andric   PrimType LHST = *S.getContext().classify(Call->getArg(0)->getType());
671*0fca6ea1SDimitry Andric   APSInt RHS = peekToAPSInt(S.Stk, RHST,
672*0fca6ea1SDimitry Andric                             align(primSize(PT_Ptr)) + align(primSize(RHST)));
673*0fca6ea1SDimitry Andric   APSInt LHS = peekToAPSInt(S.Stk, LHST,
674*0fca6ea1SDimitry Andric                             align(primSize(PT_Ptr)) + align(primSize(RHST)) +
675*0fca6ea1SDimitry Andric                                 align(primSize(LHST)));
676*0fca6ea1SDimitry Andric   QualType ResultType = Call->getArg(2)->getType()->getPointeeType();
677*0fca6ea1SDimitry Andric   PrimType ResultT = *S.getContext().classify(ResultType);
678*0fca6ea1SDimitry Andric   bool Overflow;
679*0fca6ea1SDimitry Andric 
680*0fca6ea1SDimitry Andric   APSInt Result;
681*0fca6ea1SDimitry Andric   if (BuiltinOp == Builtin::BI__builtin_add_overflow ||
682*0fca6ea1SDimitry Andric       BuiltinOp == Builtin::BI__builtin_sub_overflow ||
683*0fca6ea1SDimitry Andric       BuiltinOp == Builtin::BI__builtin_mul_overflow) {
684*0fca6ea1SDimitry Andric     bool IsSigned = LHS.isSigned() || RHS.isSigned() ||
685*0fca6ea1SDimitry Andric                     ResultType->isSignedIntegerOrEnumerationType();
686*0fca6ea1SDimitry Andric     bool AllSigned = LHS.isSigned() && RHS.isSigned() &&
687*0fca6ea1SDimitry Andric                      ResultType->isSignedIntegerOrEnumerationType();
688*0fca6ea1SDimitry Andric     uint64_t LHSSize = LHS.getBitWidth();
689*0fca6ea1SDimitry Andric     uint64_t RHSSize = RHS.getBitWidth();
690*0fca6ea1SDimitry Andric     uint64_t ResultSize = S.getCtx().getTypeSize(ResultType);
691*0fca6ea1SDimitry Andric     uint64_t MaxBits = std::max(std::max(LHSSize, RHSSize), ResultSize);
692*0fca6ea1SDimitry Andric 
693*0fca6ea1SDimitry Andric     // Add an additional bit if the signedness isn't uniformly agreed to. We
694*0fca6ea1SDimitry Andric     // could do this ONLY if there is a signed and an unsigned that both have
695*0fca6ea1SDimitry Andric     // MaxBits, but the code to check that is pretty nasty.  The issue will be
696*0fca6ea1SDimitry Andric     // caught in the shrink-to-result later anyway.
697*0fca6ea1SDimitry Andric     if (IsSigned && !AllSigned)
698*0fca6ea1SDimitry Andric       ++MaxBits;
699*0fca6ea1SDimitry Andric 
700*0fca6ea1SDimitry Andric     LHS = APSInt(LHS.extOrTrunc(MaxBits), !IsSigned);
701*0fca6ea1SDimitry Andric     RHS = APSInt(RHS.extOrTrunc(MaxBits), !IsSigned);
702*0fca6ea1SDimitry Andric     Result = APSInt(MaxBits, !IsSigned);
703*0fca6ea1SDimitry Andric   }
704*0fca6ea1SDimitry Andric 
705*0fca6ea1SDimitry Andric   // Find largest int.
706*0fca6ea1SDimitry Andric   switch (BuiltinOp) {
707*0fca6ea1SDimitry Andric   default:
708*0fca6ea1SDimitry Andric     llvm_unreachable("Invalid value for BuiltinOp");
709*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_add_overflow:
710*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_sadd_overflow:
711*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_saddl_overflow:
712*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_saddll_overflow:
713*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_uadd_overflow:
714*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_uaddl_overflow:
715*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_uaddll_overflow:
716*0fca6ea1SDimitry Andric     Result = LHS.isSigned() ? LHS.sadd_ov(RHS, Overflow)
717*0fca6ea1SDimitry Andric                             : LHS.uadd_ov(RHS, Overflow);
718*0fca6ea1SDimitry Andric     break;
719*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_sub_overflow:
720*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ssub_overflow:
721*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ssubl_overflow:
722*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ssubll_overflow:
723*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_usub_overflow:
724*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_usubl_overflow:
725*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_usubll_overflow:
726*0fca6ea1SDimitry Andric     Result = LHS.isSigned() ? LHS.ssub_ov(RHS, Overflow)
727*0fca6ea1SDimitry Andric                             : LHS.usub_ov(RHS, Overflow);
728*0fca6ea1SDimitry Andric     break;
729*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_mul_overflow:
730*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_smul_overflow:
731*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_smull_overflow:
732*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_smulll_overflow:
733*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_umul_overflow:
734*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_umull_overflow:
735*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_umulll_overflow:
736*0fca6ea1SDimitry Andric     Result = LHS.isSigned() ? LHS.smul_ov(RHS, Overflow)
737*0fca6ea1SDimitry Andric                             : LHS.umul_ov(RHS, Overflow);
738*0fca6ea1SDimitry Andric     break;
739*0fca6ea1SDimitry Andric   }
740*0fca6ea1SDimitry Andric 
741*0fca6ea1SDimitry Andric   // In the case where multiple sizes are allowed, truncate and see if
742*0fca6ea1SDimitry Andric   // the values are the same.
743*0fca6ea1SDimitry Andric   if (BuiltinOp == Builtin::BI__builtin_add_overflow ||
744*0fca6ea1SDimitry Andric       BuiltinOp == Builtin::BI__builtin_sub_overflow ||
745*0fca6ea1SDimitry Andric       BuiltinOp == Builtin::BI__builtin_mul_overflow) {
746*0fca6ea1SDimitry Andric     // APSInt doesn't have a TruncOrSelf, so we use extOrTrunc instead,
747*0fca6ea1SDimitry Andric     // since it will give us the behavior of a TruncOrSelf in the case where
748*0fca6ea1SDimitry Andric     // its parameter <= its size.  We previously set Result to be at least the
749*0fca6ea1SDimitry Andric     // type-size of the result, so getTypeSize(ResultType) <= Resu
750*0fca6ea1SDimitry Andric     APSInt Temp = Result.extOrTrunc(S.getCtx().getTypeSize(ResultType));
751*0fca6ea1SDimitry Andric     Temp.setIsSigned(ResultType->isSignedIntegerOrEnumerationType());
752*0fca6ea1SDimitry Andric 
753*0fca6ea1SDimitry Andric     if (!APSInt::isSameValue(Temp, Result))
754*0fca6ea1SDimitry Andric       Overflow = true;
755*0fca6ea1SDimitry Andric     Result = Temp;
756*0fca6ea1SDimitry Andric   }
757*0fca6ea1SDimitry Andric 
758*0fca6ea1SDimitry Andric   // Write Result to ResultPtr and put Overflow on the stacl.
759*0fca6ea1SDimitry Andric   assignInteger(ResultPtr, ResultT, Result);
760*0fca6ea1SDimitry Andric   ResultPtr.initialize();
761*0fca6ea1SDimitry Andric   assert(Func->getDecl()->getReturnType()->isBooleanType());
762*0fca6ea1SDimitry Andric   S.Stk.push<Boolean>(Overflow);
763*0fca6ea1SDimitry Andric   return true;
764*0fca6ea1SDimitry Andric }
765*0fca6ea1SDimitry Andric 
766*0fca6ea1SDimitry Andric /// Three integral values followed by a pointer (lhs, rhs, carry, carryOut).
767*0fca6ea1SDimitry Andric static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
768*0fca6ea1SDimitry Andric                                     const InterpFrame *Frame,
769*0fca6ea1SDimitry Andric                                     const Function *Func,
770*0fca6ea1SDimitry Andric                                     const CallExpr *Call) {
771*0fca6ea1SDimitry Andric   unsigned BuiltinOp = Func->getBuiltinID();
772*0fca6ea1SDimitry Andric   PrimType LHST = *S.getContext().classify(Call->getArg(0)->getType());
773*0fca6ea1SDimitry Andric   PrimType RHST = *S.getContext().classify(Call->getArg(1)->getType());
774*0fca6ea1SDimitry Andric   PrimType CarryT = *S.getContext().classify(Call->getArg(2)->getType());
775*0fca6ea1SDimitry Andric   APSInt RHS = peekToAPSInt(S.Stk, RHST,
776*0fca6ea1SDimitry Andric                             align(primSize(PT_Ptr)) + align(primSize(CarryT)) +
777*0fca6ea1SDimitry Andric                                 align(primSize(RHST)));
778*0fca6ea1SDimitry Andric   APSInt LHS =
779*0fca6ea1SDimitry Andric       peekToAPSInt(S.Stk, LHST,
780*0fca6ea1SDimitry Andric                    align(primSize(PT_Ptr)) + align(primSize(RHST)) +
781*0fca6ea1SDimitry Andric                        align(primSize(CarryT)) + align(primSize(LHST)));
782*0fca6ea1SDimitry Andric   APSInt CarryIn = peekToAPSInt(
783*0fca6ea1SDimitry Andric       S.Stk, LHST, align(primSize(PT_Ptr)) + align(primSize(CarryT)));
784*0fca6ea1SDimitry Andric   APSInt CarryOut;
785*0fca6ea1SDimitry Andric 
786*0fca6ea1SDimitry Andric   APSInt Result;
787*0fca6ea1SDimitry Andric   // Copy the number of bits and sign.
788*0fca6ea1SDimitry Andric   Result = LHS;
789*0fca6ea1SDimitry Andric   CarryOut = LHS;
790*0fca6ea1SDimitry Andric 
791*0fca6ea1SDimitry Andric   bool FirstOverflowed = false;
792*0fca6ea1SDimitry Andric   bool SecondOverflowed = false;
793*0fca6ea1SDimitry Andric   switch (BuiltinOp) {
794*0fca6ea1SDimitry Andric   default:
795*0fca6ea1SDimitry Andric     llvm_unreachable("Invalid value for BuiltinOp");
796*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcb:
797*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcs:
798*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addc:
799*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcl:
800*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcll:
801*0fca6ea1SDimitry Andric     Result =
802*0fca6ea1SDimitry Andric         LHS.uadd_ov(RHS, FirstOverflowed).uadd_ov(CarryIn, SecondOverflowed);
803*0fca6ea1SDimitry Andric     break;
804*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcb:
805*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcs:
806*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subc:
807*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcl:
808*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcll:
809*0fca6ea1SDimitry Andric     Result =
810*0fca6ea1SDimitry Andric         LHS.usub_ov(RHS, FirstOverflowed).usub_ov(CarryIn, SecondOverflowed);
811*0fca6ea1SDimitry Andric     break;
812*0fca6ea1SDimitry Andric   }
813*0fca6ea1SDimitry Andric   // It is possible for both overflows to happen but CGBuiltin uses an OR so
814*0fca6ea1SDimitry Andric   // this is consistent.
815*0fca6ea1SDimitry Andric   CarryOut = (uint64_t)(FirstOverflowed | SecondOverflowed);
816*0fca6ea1SDimitry Andric 
817*0fca6ea1SDimitry Andric   Pointer &CarryOutPtr = S.Stk.peek<Pointer>();
818*0fca6ea1SDimitry Andric   QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType();
819*0fca6ea1SDimitry Andric   PrimType CarryOutT = *S.getContext().classify(CarryOutType);
820*0fca6ea1SDimitry Andric   assignInteger(CarryOutPtr, CarryOutT, CarryOut);
821*0fca6ea1SDimitry Andric   CarryOutPtr.initialize();
822*0fca6ea1SDimitry Andric 
823*0fca6ea1SDimitry Andric   assert(Call->getType() == Call->getArg(0)->getType());
824*0fca6ea1SDimitry Andric   pushInteger(S, Result, Call->getType());
825*0fca6ea1SDimitry Andric   return true;
826*0fca6ea1SDimitry Andric }
827*0fca6ea1SDimitry Andric 
828*0fca6ea1SDimitry Andric static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
829*0fca6ea1SDimitry Andric                                 const InterpFrame *Frame, const Function *Func,
830*0fca6ea1SDimitry Andric                                 const CallExpr *Call) {
831*0fca6ea1SDimitry Andric   unsigned CallSize = callArgSize(S, Call);
832*0fca6ea1SDimitry Andric   unsigned BuiltinOp = Func->getBuiltinID();
833*0fca6ea1SDimitry Andric   PrimType ValT = *S.getContext().classify(Call->getArg(0));
834*0fca6ea1SDimitry Andric   const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);
835*0fca6ea1SDimitry Andric 
836*0fca6ea1SDimitry Andric   // When the argument is 0, the result of GCC builtins is undefined, whereas
837*0fca6ea1SDimitry Andric   // for Microsoft intrinsics, the result is the bit-width of the argument.
838*0fca6ea1SDimitry Andric   bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 &&
839*0fca6ea1SDimitry Andric                          BuiltinOp != Builtin::BI__lzcnt &&
840*0fca6ea1SDimitry Andric                          BuiltinOp != Builtin::BI__lzcnt64;
841*0fca6ea1SDimitry Andric 
842*0fca6ea1SDimitry Andric   if (Val == 0) {
843*0fca6ea1SDimitry Andric     if (Func->getBuiltinID() == Builtin::BI__builtin_clzg &&
844*0fca6ea1SDimitry Andric         Call->getNumArgs() == 2) {
845*0fca6ea1SDimitry Andric       // We have a fallback parameter.
846*0fca6ea1SDimitry Andric       PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
847*0fca6ea1SDimitry Andric       const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
848*0fca6ea1SDimitry Andric       pushInteger(S, Fallback, Call->getType());
849*0fca6ea1SDimitry Andric       return true;
850*0fca6ea1SDimitry Andric     }
851*0fca6ea1SDimitry Andric 
852*0fca6ea1SDimitry Andric     if (ZeroIsUndefined)
853*0fca6ea1SDimitry Andric       return false;
854*0fca6ea1SDimitry Andric   }
855*0fca6ea1SDimitry Andric 
856*0fca6ea1SDimitry Andric   pushInteger(S, Val.countl_zero(), Call->getType());
857*0fca6ea1SDimitry Andric   return true;
858*0fca6ea1SDimitry Andric }
859*0fca6ea1SDimitry Andric 
860*0fca6ea1SDimitry Andric static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
861*0fca6ea1SDimitry Andric                                 const InterpFrame *Frame, const Function *Func,
862*0fca6ea1SDimitry Andric                                 const CallExpr *Call) {
863*0fca6ea1SDimitry Andric   unsigned CallSize = callArgSize(S, Call);
864*0fca6ea1SDimitry Andric   PrimType ValT = *S.getContext().classify(Call->getArg(0));
865*0fca6ea1SDimitry Andric   const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);
866*0fca6ea1SDimitry Andric 
867*0fca6ea1SDimitry Andric   if (Val == 0) {
868*0fca6ea1SDimitry Andric     if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg &&
869*0fca6ea1SDimitry Andric         Call->getNumArgs() == 2) {
870*0fca6ea1SDimitry Andric       // We have a fallback parameter.
871*0fca6ea1SDimitry Andric       PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
872*0fca6ea1SDimitry Andric       const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
873*0fca6ea1SDimitry Andric       pushInteger(S, Fallback, Call->getType());
874*0fca6ea1SDimitry Andric       return true;
875*0fca6ea1SDimitry Andric     }
876*0fca6ea1SDimitry Andric     return false;
877*0fca6ea1SDimitry Andric   }
878*0fca6ea1SDimitry Andric 
879*0fca6ea1SDimitry Andric   pushInteger(S, Val.countr_zero(), Call->getType());
880*0fca6ea1SDimitry Andric   return true;
881*0fca6ea1SDimitry Andric }
882*0fca6ea1SDimitry Andric 
883*0fca6ea1SDimitry Andric static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC,
884*0fca6ea1SDimitry Andric                                   const InterpFrame *Frame,
885*0fca6ea1SDimitry Andric                                   const Function *Func, const CallExpr *Call) {
886*0fca6ea1SDimitry Andric   PrimType ReturnT = *S.getContext().classify(Call->getType());
887*0fca6ea1SDimitry Andric   PrimType ValT = *S.getContext().classify(Call->getArg(0));
888*0fca6ea1SDimitry Andric   const APSInt &Val = peekToAPSInt(S.Stk, ValT);
889*0fca6ea1SDimitry Andric   assert(Val.getActiveBits() <= 64);
890*0fca6ea1SDimitry Andric 
891*0fca6ea1SDimitry Andric   INT_TYPE_SWITCH(ReturnT,
892*0fca6ea1SDimitry Andric                   { S.Stk.push<T>(T::from(Val.byteSwap().getZExtValue())); });
893*0fca6ea1SDimitry Andric   return true;
894*0fca6ea1SDimitry Andric }
895*0fca6ea1SDimitry Andric 
896*0fca6ea1SDimitry Andric /// bool __atomic_always_lock_free(size_t, void const volatile*)
897*0fca6ea1SDimitry Andric /// bool __atomic_is_lock_free(size_t, void const volatile*)
898*0fca6ea1SDimitry Andric /// bool __c11_atomic_is_lock_free(size_t)
899*0fca6ea1SDimitry Andric static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC,
900*0fca6ea1SDimitry Andric                                              const InterpFrame *Frame,
901*0fca6ea1SDimitry Andric                                              const Function *Func,
902*0fca6ea1SDimitry Andric                                              const CallExpr *Call) {
903*0fca6ea1SDimitry Andric   unsigned BuiltinOp = Func->getBuiltinID();
904*0fca6ea1SDimitry Andric 
905*0fca6ea1SDimitry Andric   PrimType ValT = *S.getContext().classify(Call->getArg(0));
906*0fca6ea1SDimitry Andric   unsigned SizeValOffset = 0;
907*0fca6ea1SDimitry Andric   if (BuiltinOp != Builtin::BI__c11_atomic_is_lock_free)
908*0fca6ea1SDimitry Andric     SizeValOffset = align(primSize(ValT)) + align(primSize(PT_Ptr));
909*0fca6ea1SDimitry Andric   const APSInt &SizeVal = peekToAPSInt(S.Stk, ValT, SizeValOffset);
910*0fca6ea1SDimitry Andric 
911*0fca6ea1SDimitry Andric   auto returnBool = [&S](bool Value) -> bool {
912*0fca6ea1SDimitry Andric     S.Stk.push<Boolean>(Value);
913*0fca6ea1SDimitry Andric     return true;
914*0fca6ea1SDimitry Andric   };
915*0fca6ea1SDimitry Andric 
916*0fca6ea1SDimitry Andric   // For __atomic_is_lock_free(sizeof(_Atomic(T))), if the size is a power
917*0fca6ea1SDimitry Andric   // of two less than or equal to the maximum inline atomic width, we know it
918*0fca6ea1SDimitry Andric   // is lock-free.  If the size isn't a power of two, or greater than the
919*0fca6ea1SDimitry Andric   // maximum alignment where we promote atomics, we know it is not lock-free
920*0fca6ea1SDimitry Andric   // (at least not in the sense of atomic_is_lock_free).  Otherwise,
921*0fca6ea1SDimitry Andric   // the answer can only be determined at runtime; for example, 16-byte
922*0fca6ea1SDimitry Andric   // atomics have lock-free implementations on some, but not all,
923*0fca6ea1SDimitry Andric   // x86-64 processors.
924*0fca6ea1SDimitry Andric 
925*0fca6ea1SDimitry Andric   // Check power-of-two.
926*0fca6ea1SDimitry Andric   CharUnits Size = CharUnits::fromQuantity(SizeVal.getZExtValue());
927*0fca6ea1SDimitry Andric   if (Size.isPowerOfTwo()) {
928*0fca6ea1SDimitry Andric     // Check against inlining width.
929*0fca6ea1SDimitry Andric     unsigned InlineWidthBits =
930*0fca6ea1SDimitry Andric         S.getCtx().getTargetInfo().getMaxAtomicInlineWidth();
931*0fca6ea1SDimitry Andric     if (Size <= S.getCtx().toCharUnitsFromBits(InlineWidthBits)) {
932*0fca6ea1SDimitry Andric 
933*0fca6ea1SDimitry Andric       // OK, we will inline appropriately-aligned operations of this size,
934*0fca6ea1SDimitry Andric       // and _Atomic(T) is appropriately-aligned.
935*0fca6ea1SDimitry Andric       if (BuiltinOp == Builtin::BI__c11_atomic_is_lock_free ||
936*0fca6ea1SDimitry Andric           Size == CharUnits::One())
937*0fca6ea1SDimitry Andric         return returnBool(true);
938*0fca6ea1SDimitry Andric 
939*0fca6ea1SDimitry Andric       // Same for null pointers.
940*0fca6ea1SDimitry Andric       assert(BuiltinOp != Builtin::BI__c11_atomic_is_lock_free);
941*0fca6ea1SDimitry Andric       const Pointer &Ptr = S.Stk.peek<Pointer>();
942*0fca6ea1SDimitry Andric       if (Ptr.isZero())
943*0fca6ea1SDimitry Andric         return returnBool(true);
944*0fca6ea1SDimitry Andric 
945*0fca6ea1SDimitry Andric       QualType PointeeType = Call->getArg(1)
946*0fca6ea1SDimitry Andric                                  ->IgnoreImpCasts()
947*0fca6ea1SDimitry Andric                                  ->getType()
948*0fca6ea1SDimitry Andric                                  ->castAs<PointerType>()
949*0fca6ea1SDimitry Andric                                  ->getPointeeType();
950*0fca6ea1SDimitry Andric       // OK, we will inline operations on this object.
951*0fca6ea1SDimitry Andric       if (!PointeeType->isIncompleteType() &&
952*0fca6ea1SDimitry Andric           S.getCtx().getTypeAlignInChars(PointeeType) >= Size)
953*0fca6ea1SDimitry Andric         return returnBool(true);
954*0fca6ea1SDimitry Andric     }
955*0fca6ea1SDimitry Andric   }
956*0fca6ea1SDimitry Andric 
957*0fca6ea1SDimitry Andric   if (BuiltinOp == Builtin::BI__atomic_always_lock_free)
958*0fca6ea1SDimitry Andric     return returnBool(false);
959*0fca6ea1SDimitry Andric 
960*0fca6ea1SDimitry Andric   return false;
961*0fca6ea1SDimitry Andric }
962*0fca6ea1SDimitry Andric 
963*0fca6ea1SDimitry Andric /// __builtin_complex(Float A, float B);
964*0fca6ea1SDimitry Andric static bool interp__builtin_complex(InterpState &S, CodePtr OpPC,
965*0fca6ea1SDimitry Andric                                     const InterpFrame *Frame,
966*0fca6ea1SDimitry Andric                                     const Function *Func,
967*0fca6ea1SDimitry Andric                                     const CallExpr *Call) {
968*0fca6ea1SDimitry Andric   const Floating &Arg2 = S.Stk.peek<Floating>();
969*0fca6ea1SDimitry Andric   const Floating &Arg1 = S.Stk.peek<Floating>(align(primSize(PT_Float)) * 2);
970*0fca6ea1SDimitry Andric   Pointer &Result = S.Stk.peek<Pointer>(align(primSize(PT_Float)) * 2 +
971*0fca6ea1SDimitry Andric                                         align(primSize(PT_Ptr)));
972*0fca6ea1SDimitry Andric 
973*0fca6ea1SDimitry Andric   Result.atIndex(0).deref<Floating>() = Arg1;
974*0fca6ea1SDimitry Andric   Result.atIndex(0).initialize();
975*0fca6ea1SDimitry Andric   Result.atIndex(1).deref<Floating>() = Arg2;
976*0fca6ea1SDimitry Andric   Result.atIndex(1).initialize();
977*0fca6ea1SDimitry Andric   Result.initialize();
978*0fca6ea1SDimitry Andric 
979*0fca6ea1SDimitry Andric   return true;
980*0fca6ea1SDimitry Andric }
981*0fca6ea1SDimitry Andric 
982*0fca6ea1SDimitry Andric /// __builtin_is_aligned()
983*0fca6ea1SDimitry Andric /// __builtin_align_up()
984*0fca6ea1SDimitry Andric /// __builtin_align_down()
985*0fca6ea1SDimitry Andric /// The first parameter is either an integer or a pointer.
986*0fca6ea1SDimitry Andric /// The second parameter is the requested alignment as an integer.
987*0fca6ea1SDimitry Andric static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
988*0fca6ea1SDimitry Andric                                                const InterpFrame *Frame,
989*0fca6ea1SDimitry Andric                                                const Function *Func,
990*0fca6ea1SDimitry Andric                                                const CallExpr *Call) {
991*0fca6ea1SDimitry Andric   unsigned BuiltinOp = Func->getBuiltinID();
992*0fca6ea1SDimitry Andric   unsigned CallSize = callArgSize(S, Call);
993*0fca6ea1SDimitry Andric 
994*0fca6ea1SDimitry Andric   PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1));
995*0fca6ea1SDimitry Andric   const APSInt &Alignment = peekToAPSInt(S.Stk, AlignmentT);
996*0fca6ea1SDimitry Andric 
997*0fca6ea1SDimitry Andric   if (Alignment < 0 || !Alignment.isPowerOf2()) {
998*0fca6ea1SDimitry Andric     S.FFDiag(Call, diag::note_constexpr_invalid_alignment) << Alignment;
999*0fca6ea1SDimitry Andric     return false;
1000*0fca6ea1SDimitry Andric   }
1001*0fca6ea1SDimitry Andric   unsigned SrcWidth = S.getCtx().getIntWidth(Call->getArg(0)->getType());
1002*0fca6ea1SDimitry Andric   APSInt MaxValue(APInt::getOneBitSet(SrcWidth, SrcWidth - 1));
1003*0fca6ea1SDimitry Andric   if (APSInt::compareValues(Alignment, MaxValue) > 0) {
1004*0fca6ea1SDimitry Andric     S.FFDiag(Call, diag::note_constexpr_alignment_too_big)
1005*0fca6ea1SDimitry Andric         << MaxValue << Call->getArg(0)->getType() << Alignment;
1006*0fca6ea1SDimitry Andric     return false;
1007*0fca6ea1SDimitry Andric   }
1008*0fca6ea1SDimitry Andric 
1009*0fca6ea1SDimitry Andric   // The first parameter is either an integer or a pointer (but not a function
1010*0fca6ea1SDimitry Andric   // pointer).
1011*0fca6ea1SDimitry Andric   PrimType FirstArgT = *S.Ctx.classify(Call->getArg(0));
1012*0fca6ea1SDimitry Andric 
1013*0fca6ea1SDimitry Andric   if (isIntegralType(FirstArgT)) {
1014*0fca6ea1SDimitry Andric     const APSInt &Src = peekToAPSInt(S.Stk, FirstArgT, CallSize);
1015*0fca6ea1SDimitry Andric     APSInt Align = Alignment.extOrTrunc(Src.getBitWidth());
1016*0fca6ea1SDimitry Andric     if (BuiltinOp == Builtin::BI__builtin_align_up) {
1017*0fca6ea1SDimitry Andric       APSInt AlignedVal =
1018*0fca6ea1SDimitry Andric           APSInt((Src + (Align - 1)) & ~(Align - 1), Src.isUnsigned());
1019*0fca6ea1SDimitry Andric       pushInteger(S, AlignedVal, Call->getType());
1020*0fca6ea1SDimitry Andric     } else if (BuiltinOp == Builtin::BI__builtin_align_down) {
1021*0fca6ea1SDimitry Andric       APSInt AlignedVal = APSInt(Src & ~(Align - 1), Src.isUnsigned());
1022*0fca6ea1SDimitry Andric       pushInteger(S, AlignedVal, Call->getType());
1023*0fca6ea1SDimitry Andric     } else {
1024*0fca6ea1SDimitry Andric       assert(*S.Ctx.classify(Call->getType()) == PT_Bool);
1025*0fca6ea1SDimitry Andric       S.Stk.push<Boolean>((Src & (Align - 1)) == 0);
1026*0fca6ea1SDimitry Andric     }
1027*0fca6ea1SDimitry Andric     return true;
1028*0fca6ea1SDimitry Andric   }
1029*0fca6ea1SDimitry Andric 
1030*0fca6ea1SDimitry Andric   assert(FirstArgT == PT_Ptr);
1031*0fca6ea1SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>(CallSize);
1032*0fca6ea1SDimitry Andric 
1033*0fca6ea1SDimitry Andric   unsigned PtrOffset = Ptr.getByteOffset();
1034*0fca6ea1SDimitry Andric   PtrOffset = Ptr.getIndex();
1035*0fca6ea1SDimitry Andric   CharUnits BaseAlignment =
1036*0fca6ea1SDimitry Andric       S.getCtx().getDeclAlign(Ptr.getDeclDesc()->asValueDecl());
1037*0fca6ea1SDimitry Andric   CharUnits PtrAlign =
1038*0fca6ea1SDimitry Andric       BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));
1039*0fca6ea1SDimitry Andric 
1040*0fca6ea1SDimitry Andric   if (BuiltinOp == Builtin::BI__builtin_is_aligned) {
1041*0fca6ea1SDimitry Andric     if (PtrAlign.getQuantity() >= Alignment) {
1042*0fca6ea1SDimitry Andric       S.Stk.push<Boolean>(true);
1043*0fca6ea1SDimitry Andric       return true;
1044*0fca6ea1SDimitry Andric     }
1045*0fca6ea1SDimitry Andric     // If the alignment is not known to be sufficient, some cases could still
1046*0fca6ea1SDimitry Andric     // be aligned at run time. However, if the requested alignment is less or
1047*0fca6ea1SDimitry Andric     // equal to the base alignment and the offset is not aligned, we know that
1048*0fca6ea1SDimitry Andric     // the run-time value can never be aligned.
1049*0fca6ea1SDimitry Andric     if (BaseAlignment.getQuantity() >= Alignment &&
1050*0fca6ea1SDimitry Andric         PtrAlign.getQuantity() < Alignment) {
1051*0fca6ea1SDimitry Andric       S.Stk.push<Boolean>(false);
1052*0fca6ea1SDimitry Andric       return true;
1053*0fca6ea1SDimitry Andric     }
1054*0fca6ea1SDimitry Andric 
1055*0fca6ea1SDimitry Andric     S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_compute)
1056*0fca6ea1SDimitry Andric         << Alignment;
1057*0fca6ea1SDimitry Andric     return false;
1058*0fca6ea1SDimitry Andric   }
1059*0fca6ea1SDimitry Andric 
1060*0fca6ea1SDimitry Andric   assert(BuiltinOp == Builtin::BI__builtin_align_down ||
1061*0fca6ea1SDimitry Andric          BuiltinOp == Builtin::BI__builtin_align_up);
1062*0fca6ea1SDimitry Andric 
1063*0fca6ea1SDimitry Andric   // For align_up/align_down, we can return the same value if the alignment
1064*0fca6ea1SDimitry Andric   // is known to be greater or equal to the requested value.
1065*0fca6ea1SDimitry Andric   if (PtrAlign.getQuantity() >= Alignment) {
1066*0fca6ea1SDimitry Andric     S.Stk.push<Pointer>(Ptr);
1067*0fca6ea1SDimitry Andric     return true;
1068*0fca6ea1SDimitry Andric   }
1069*0fca6ea1SDimitry Andric 
1070*0fca6ea1SDimitry Andric   // The alignment could be greater than the minimum at run-time, so we cannot
1071*0fca6ea1SDimitry Andric   // infer much about the resulting pointer value. One case is possible:
1072*0fca6ea1SDimitry Andric   // For `_Alignas(32) char buf[N]; __builtin_align_down(&buf[idx], 32)` we
1073*0fca6ea1SDimitry Andric   // can infer the correct index if the requested alignment is smaller than
1074*0fca6ea1SDimitry Andric   // the base alignment so we can perform the computation on the offset.
1075*0fca6ea1SDimitry Andric   if (BaseAlignment.getQuantity() >= Alignment) {
1076*0fca6ea1SDimitry Andric     assert(Alignment.getBitWidth() <= 64 &&
1077*0fca6ea1SDimitry Andric            "Cannot handle > 64-bit address-space");
1078*0fca6ea1SDimitry Andric     uint64_t Alignment64 = Alignment.getZExtValue();
1079*0fca6ea1SDimitry Andric     CharUnits NewOffset =
1080*0fca6ea1SDimitry Andric         CharUnits::fromQuantity(BuiltinOp == Builtin::BI__builtin_align_down
1081*0fca6ea1SDimitry Andric                                     ? llvm::alignDown(PtrOffset, Alignment64)
1082*0fca6ea1SDimitry Andric                                     : llvm::alignTo(PtrOffset, Alignment64));
1083*0fca6ea1SDimitry Andric 
1084*0fca6ea1SDimitry Andric     S.Stk.push<Pointer>(Ptr.atIndex(NewOffset.getQuantity()));
1085*0fca6ea1SDimitry Andric     return true;
1086*0fca6ea1SDimitry Andric   }
1087*0fca6ea1SDimitry Andric 
1088*0fca6ea1SDimitry Andric   // Otherwise, we cannot constant-evaluate the result.
1089*0fca6ea1SDimitry Andric   S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_adjust) << Alignment;
1090*0fca6ea1SDimitry Andric   return false;
1091*0fca6ea1SDimitry Andric }
1092*0fca6ea1SDimitry Andric 
1093*0fca6ea1SDimitry Andric static bool interp__builtin_os_log_format_buffer_size(InterpState &S,
1094*0fca6ea1SDimitry Andric                                                       CodePtr OpPC,
1095*0fca6ea1SDimitry Andric                                                       const InterpFrame *Frame,
1096*0fca6ea1SDimitry Andric                                                       const Function *Func,
1097*0fca6ea1SDimitry Andric                                                       const CallExpr *Call) {
1098*0fca6ea1SDimitry Andric   analyze_os_log::OSLogBufferLayout Layout;
1099*0fca6ea1SDimitry Andric   analyze_os_log::computeOSLogBufferLayout(S.getCtx(), Call, Layout);
1100*0fca6ea1SDimitry Andric   pushInteger(S, Layout.size().getQuantity(), Call->getType());
1101*0fca6ea1SDimitry Andric   return true;
1102*0fca6ea1SDimitry Andric }
1103*0fca6ea1SDimitry Andric 
1104*0fca6ea1SDimitry Andric static bool interp__builtin_ptrauth_string_discriminator(
1105*0fca6ea1SDimitry Andric     InterpState &S, CodePtr OpPC, const InterpFrame *Frame,
1106*0fca6ea1SDimitry Andric     const Function *Func, const CallExpr *Call) {
1107*0fca6ea1SDimitry Andric   const auto &Ptr = S.Stk.peek<Pointer>();
1108*0fca6ea1SDimitry Andric   assert(Ptr.getFieldDesc()->isPrimitiveArray());
1109*0fca6ea1SDimitry Andric 
1110*0fca6ea1SDimitry Andric   StringRef R(&Ptr.deref<char>(), Ptr.getFieldDesc()->getNumElems() - 1);
1111*0fca6ea1SDimitry Andric   uint64_t Result = getPointerAuthStableSipHash(R);
1112*0fca6ea1SDimitry Andric   pushInteger(S, Result, Call->getType());
1113*0fca6ea1SDimitry Andric   return true;
1114*0fca6ea1SDimitry Andric }
1115*0fca6ea1SDimitry Andric 
11165f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
11175f757f3fSDimitry Andric                       const CallExpr *Call) {
1118*0fca6ea1SDimitry Andric   const InterpFrame *Frame = S.Current;
111906c3fb27SDimitry Andric   APValue Dummy;
112006c3fb27SDimitry Andric 
1121*0fca6ea1SDimitry Andric   std::optional<PrimType> ReturnT = S.getContext().classify(Call);
11225f757f3fSDimitry Andric 
112306c3fb27SDimitry Andric   switch (F->getBuiltinID()) {
112406c3fb27SDimitry Andric   case Builtin::BI__builtin_is_constant_evaluated:
1125*0fca6ea1SDimitry Andric     if (!interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call))
1126*0fca6ea1SDimitry Andric       return false;
11275f757f3fSDimitry Andric     break;
112806c3fb27SDimitry Andric   case Builtin::BI__builtin_assume:
1129*0fca6ea1SDimitry Andric   case Builtin::BI__assume:
11305f757f3fSDimitry Andric     break;
113106c3fb27SDimitry Andric   case Builtin::BI__builtin_strcmp:
1132*0fca6ea1SDimitry Andric     if (!interp__builtin_strcmp(S, OpPC, Frame, Call))
113306c3fb27SDimitry Andric       return false;
11345f757f3fSDimitry Andric     break;
11355f757f3fSDimitry Andric   case Builtin::BI__builtin_strlen:
1136*0fca6ea1SDimitry Andric     if (!interp__builtin_strlen(S, OpPC, Frame, Call))
11375f757f3fSDimitry Andric       return false;
11385f757f3fSDimitry Andric     break;
11395f757f3fSDimitry Andric   case Builtin::BI__builtin_nan:
11405f757f3fSDimitry Andric   case Builtin::BI__builtin_nanf:
11415f757f3fSDimitry Andric   case Builtin::BI__builtin_nanl:
11425f757f3fSDimitry Andric   case Builtin::BI__builtin_nanf16:
11435f757f3fSDimitry Andric   case Builtin::BI__builtin_nanf128:
11445f757f3fSDimitry Andric     if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
11455f757f3fSDimitry Andric       return false;
11465f757f3fSDimitry Andric     break;
11475f757f3fSDimitry Andric   case Builtin::BI__builtin_nans:
11485f757f3fSDimitry Andric   case Builtin::BI__builtin_nansf:
11495f757f3fSDimitry Andric   case Builtin::BI__builtin_nansl:
11505f757f3fSDimitry Andric   case Builtin::BI__builtin_nansf16:
11515f757f3fSDimitry Andric   case Builtin::BI__builtin_nansf128:
11525f757f3fSDimitry Andric     if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
11535f757f3fSDimitry Andric       return false;
11545f757f3fSDimitry Andric     break;
11555f757f3fSDimitry Andric 
11565f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_val:
11575f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_valf:
11585f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_vall:
11595f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_valf16:
11605f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_valf128:
11615f757f3fSDimitry Andric   case Builtin::BI__builtin_inf:
11625f757f3fSDimitry Andric   case Builtin::BI__builtin_inff:
11635f757f3fSDimitry Andric   case Builtin::BI__builtin_infl:
11645f757f3fSDimitry Andric   case Builtin::BI__builtin_inff16:
11655f757f3fSDimitry Andric   case Builtin::BI__builtin_inff128:
11665f757f3fSDimitry Andric     if (!interp__builtin_inf(S, OpPC, Frame, F))
11675f757f3fSDimitry Andric       return false;
11685f757f3fSDimitry Andric     break;
11695f757f3fSDimitry Andric   case Builtin::BI__builtin_copysign:
11705f757f3fSDimitry Andric   case Builtin::BI__builtin_copysignf:
11715f757f3fSDimitry Andric   case Builtin::BI__builtin_copysignl:
11725f757f3fSDimitry Andric   case Builtin::BI__builtin_copysignf128:
11735f757f3fSDimitry Andric     if (!interp__builtin_copysign(S, OpPC, Frame, F))
11745f757f3fSDimitry Andric       return false;
11755f757f3fSDimitry Andric     break;
11765f757f3fSDimitry Andric 
11775f757f3fSDimitry Andric   case Builtin::BI__builtin_fmin:
11785f757f3fSDimitry Andric   case Builtin::BI__builtin_fminf:
11795f757f3fSDimitry Andric   case Builtin::BI__builtin_fminl:
11805f757f3fSDimitry Andric   case Builtin::BI__builtin_fminf16:
11815f757f3fSDimitry Andric   case Builtin::BI__builtin_fminf128:
11825f757f3fSDimitry Andric     if (!interp__builtin_fmin(S, OpPC, Frame, F))
11835f757f3fSDimitry Andric       return false;
11845f757f3fSDimitry Andric     break;
11855f757f3fSDimitry Andric 
11865f757f3fSDimitry Andric   case Builtin::BI__builtin_fmax:
11875f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxf:
11885f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxl:
11895f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxf16:
11905f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxf128:
11915f757f3fSDimitry Andric     if (!interp__builtin_fmax(S, OpPC, Frame, F))
11925f757f3fSDimitry Andric       return false;
11935f757f3fSDimitry Andric     break;
11945f757f3fSDimitry Andric 
11955f757f3fSDimitry Andric   case Builtin::BI__builtin_isnan:
1196*0fca6ea1SDimitry Andric     if (!interp__builtin_isnan(S, OpPC, Frame, F, Call))
11975f757f3fSDimitry Andric       return false;
11985f757f3fSDimitry Andric     break;
11995f757f3fSDimitry Andric   case Builtin::BI__builtin_issignaling:
1200*0fca6ea1SDimitry Andric     if (!interp__builtin_issignaling(S, OpPC, Frame, F, Call))
12015f757f3fSDimitry Andric       return false;
12025f757f3fSDimitry Andric     break;
12035f757f3fSDimitry Andric 
12045f757f3fSDimitry Andric   case Builtin::BI__builtin_isinf:
1205*0fca6ea1SDimitry Andric     if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false, Call))
12065f757f3fSDimitry Andric       return false;
12075f757f3fSDimitry Andric     break;
12085f757f3fSDimitry Andric 
12095f757f3fSDimitry Andric   case Builtin::BI__builtin_isinf_sign:
1210*0fca6ea1SDimitry Andric     if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true, Call))
12115f757f3fSDimitry Andric       return false;
12125f757f3fSDimitry Andric     break;
12135f757f3fSDimitry Andric 
12145f757f3fSDimitry Andric   case Builtin::BI__builtin_isfinite:
1215*0fca6ea1SDimitry Andric     if (!interp__builtin_isfinite(S, OpPC, Frame, F, Call))
12165f757f3fSDimitry Andric       return false;
12175f757f3fSDimitry Andric     break;
12185f757f3fSDimitry Andric   case Builtin::BI__builtin_isnormal:
1219*0fca6ea1SDimitry Andric     if (!interp__builtin_isnormal(S, OpPC, Frame, F, Call))
12205f757f3fSDimitry Andric       return false;
12215f757f3fSDimitry Andric     break;
12225f757f3fSDimitry Andric   case Builtin::BI__builtin_issubnormal:
1223*0fca6ea1SDimitry Andric     if (!interp__builtin_issubnormal(S, OpPC, Frame, F, Call))
12245f757f3fSDimitry Andric       return false;
12255f757f3fSDimitry Andric     break;
12265f757f3fSDimitry Andric   case Builtin::BI__builtin_iszero:
1227*0fca6ea1SDimitry Andric     if (!interp__builtin_iszero(S, OpPC, Frame, F, Call))
12285f757f3fSDimitry Andric       return false;
12295f757f3fSDimitry Andric     break;
12305f757f3fSDimitry Andric   case Builtin::BI__builtin_isfpclass:
12315f757f3fSDimitry Andric     if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
12325f757f3fSDimitry Andric       return false;
12335f757f3fSDimitry Andric     break;
12345f757f3fSDimitry Andric   case Builtin::BI__builtin_fpclassify:
1235*0fca6ea1SDimitry Andric     if (!interp__builtin_fpclassify(S, OpPC, Frame, F, Call))
12365f757f3fSDimitry Andric       return false;
12375f757f3fSDimitry Andric     break;
12385f757f3fSDimitry Andric 
12395f757f3fSDimitry Andric   case Builtin::BI__builtin_fabs:
12405f757f3fSDimitry Andric   case Builtin::BI__builtin_fabsf:
12415f757f3fSDimitry Andric   case Builtin::BI__builtin_fabsl:
12425f757f3fSDimitry Andric   case Builtin::BI__builtin_fabsf128:
12435f757f3fSDimitry Andric     if (!interp__builtin_fabs(S, OpPC, Frame, F))
12445f757f3fSDimitry Andric       return false;
12455f757f3fSDimitry Andric     break;
12465f757f3fSDimitry Andric 
12475f757f3fSDimitry Andric   case Builtin::BI__builtin_popcount:
12485f757f3fSDimitry Andric   case Builtin::BI__builtin_popcountl:
12495f757f3fSDimitry Andric   case Builtin::BI__builtin_popcountll:
1250*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_popcountg:
12515f757f3fSDimitry Andric   case Builtin::BI__popcnt16: // Microsoft variants of popcount
12525f757f3fSDimitry Andric   case Builtin::BI__popcnt:
12535f757f3fSDimitry Andric   case Builtin::BI__popcnt64:
12545f757f3fSDimitry Andric     if (!interp__builtin_popcount(S, OpPC, Frame, F, Call))
12555f757f3fSDimitry Andric       return false;
12565f757f3fSDimitry Andric     break;
12575f757f3fSDimitry Andric 
12585f757f3fSDimitry Andric   case Builtin::BI__builtin_parity:
12595f757f3fSDimitry Andric   case Builtin::BI__builtin_parityl:
12605f757f3fSDimitry Andric   case Builtin::BI__builtin_parityll:
12615f757f3fSDimitry Andric     if (!interp__builtin_parity(S, OpPC, Frame, F, Call))
12625f757f3fSDimitry Andric       return false;
12635f757f3fSDimitry Andric     break;
12645f757f3fSDimitry Andric 
12655f757f3fSDimitry Andric   case Builtin::BI__builtin_clrsb:
12665f757f3fSDimitry Andric   case Builtin::BI__builtin_clrsbl:
12675f757f3fSDimitry Andric   case Builtin::BI__builtin_clrsbll:
12685f757f3fSDimitry Andric     if (!interp__builtin_clrsb(S, OpPC, Frame, F, Call))
12695f757f3fSDimitry Andric       return false;
12705f757f3fSDimitry Andric     break;
12715f757f3fSDimitry Andric 
12725f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse8:
12735f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse16:
12745f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse32:
12755f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse64:
12765f757f3fSDimitry Andric     if (!interp__builtin_bitreverse(S, OpPC, Frame, F, Call))
12775f757f3fSDimitry Andric       return false;
12785f757f3fSDimitry Andric     break;
12795f757f3fSDimitry Andric 
12805f757f3fSDimitry Andric   case Builtin::BI__builtin_classify_type:
12815f757f3fSDimitry Andric     if (!interp__builtin_classify_type(S, OpPC, Frame, F, Call))
12825f757f3fSDimitry Andric       return false;
12835f757f3fSDimitry Andric     break;
12845f757f3fSDimitry Andric 
12855f757f3fSDimitry Andric   case Builtin::BI__builtin_expect:
12865f757f3fSDimitry Andric   case Builtin::BI__builtin_expect_with_probability:
12875f757f3fSDimitry Andric     if (!interp__builtin_expect(S, OpPC, Frame, F, Call))
12885f757f3fSDimitry Andric       return false;
12895f757f3fSDimitry Andric     break;
12905f757f3fSDimitry Andric 
12915f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft8:
12925f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft16:
12935f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft32:
12945f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft64:
12955f757f3fSDimitry Andric   case Builtin::BI_rotl8: // Microsoft variants of rotate left
12965f757f3fSDimitry Andric   case Builtin::BI_rotl16:
12975f757f3fSDimitry Andric   case Builtin::BI_rotl:
12985f757f3fSDimitry Andric   case Builtin::BI_lrotl:
12995f757f3fSDimitry Andric   case Builtin::BI_rotl64:
13005f757f3fSDimitry Andric     if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/false))
13015f757f3fSDimitry Andric       return false;
13025f757f3fSDimitry Andric     break;
13035f757f3fSDimitry Andric 
13045f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright8:
13055f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright16:
13065f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright32:
13075f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright64:
13085f757f3fSDimitry Andric   case Builtin::BI_rotr8: // Microsoft variants of rotate right
13095f757f3fSDimitry Andric   case Builtin::BI_rotr16:
13105f757f3fSDimitry Andric   case Builtin::BI_rotr:
13115f757f3fSDimitry Andric   case Builtin::BI_lrotr:
13125f757f3fSDimitry Andric   case Builtin::BI_rotr64:
13135f757f3fSDimitry Andric     if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/true))
13145f757f3fSDimitry Andric       return false;
13155f757f3fSDimitry Andric     break;
13165f757f3fSDimitry Andric 
13175f757f3fSDimitry Andric   case Builtin::BI__builtin_ffs:
13185f757f3fSDimitry Andric   case Builtin::BI__builtin_ffsl:
13195f757f3fSDimitry Andric   case Builtin::BI__builtin_ffsll:
13205f757f3fSDimitry Andric     if (!interp__builtin_ffs(S, OpPC, Frame, F, Call))
13215f757f3fSDimitry Andric       return false;
13225f757f3fSDimitry Andric     break;
1323297eecfbSDimitry Andric   case Builtin::BIaddressof:
1324297eecfbSDimitry Andric   case Builtin::BI__addressof:
1325297eecfbSDimitry Andric   case Builtin::BI__builtin_addressof:
1326297eecfbSDimitry Andric     if (!interp__builtin_addressof(S, OpPC, Frame, F, Call))
1327297eecfbSDimitry Andric       return false;
1328297eecfbSDimitry Andric     break;
13295f757f3fSDimitry Andric 
1330*0fca6ea1SDimitry Andric   case Builtin::BIas_const:
1331*0fca6ea1SDimitry Andric   case Builtin::BIforward:
1332*0fca6ea1SDimitry Andric   case Builtin::BIforward_like:
1333*0fca6ea1SDimitry Andric   case Builtin::BImove:
1334*0fca6ea1SDimitry Andric   case Builtin::BImove_if_noexcept:
1335*0fca6ea1SDimitry Andric     if (!interp__builtin_move(S, OpPC, Frame, F, Call))
1336*0fca6ea1SDimitry Andric       return false;
1337*0fca6ea1SDimitry Andric     break;
1338*0fca6ea1SDimitry Andric 
1339*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_eh_return_data_regno:
1340*0fca6ea1SDimitry Andric     if (!interp__builtin_eh_return_data_regno(S, OpPC, Frame, F, Call))
1341*0fca6ea1SDimitry Andric       return false;
1342*0fca6ea1SDimitry Andric     break;
1343*0fca6ea1SDimitry Andric 
1344*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_launder:
1345*0fca6ea1SDimitry Andric     if (!noopPointer(S, OpPC, Frame, F, Call))
1346*0fca6ea1SDimitry Andric       return false;
1347*0fca6ea1SDimitry Andric     break;
1348*0fca6ea1SDimitry Andric 
1349*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_add_overflow:
1350*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_sub_overflow:
1351*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_mul_overflow:
1352*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_sadd_overflow:
1353*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_uadd_overflow:
1354*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_uaddl_overflow:
1355*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_uaddll_overflow:
1356*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_usub_overflow:
1357*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_usubl_overflow:
1358*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_usubll_overflow:
1359*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_umul_overflow:
1360*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_umull_overflow:
1361*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_umulll_overflow:
1362*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_saddl_overflow:
1363*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_saddll_overflow:
1364*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ssub_overflow:
1365*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ssubl_overflow:
1366*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ssubll_overflow:
1367*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_smul_overflow:
1368*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_smull_overflow:
1369*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_smulll_overflow:
1370*0fca6ea1SDimitry Andric     if (!interp__builtin_overflowop(S, OpPC, Frame, F, Call))
1371*0fca6ea1SDimitry Andric       return false;
1372*0fca6ea1SDimitry Andric     break;
1373*0fca6ea1SDimitry Andric 
1374*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcb:
1375*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcs:
1376*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addc:
1377*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcl:
1378*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_addcll:
1379*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcb:
1380*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcs:
1381*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subc:
1382*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcl:
1383*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_subcll:
1384*0fca6ea1SDimitry Andric     if (!interp__builtin_carryop(S, OpPC, Frame, F, Call))
1385*0fca6ea1SDimitry Andric       return false;
1386*0fca6ea1SDimitry Andric     break;
1387*0fca6ea1SDimitry Andric 
1388*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_clz:
1389*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_clzl:
1390*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_clzll:
1391*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_clzs:
1392*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_clzg:
1393*0fca6ea1SDimitry Andric   case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
1394*0fca6ea1SDimitry Andric   case Builtin::BI__lzcnt:
1395*0fca6ea1SDimitry Andric   case Builtin::BI__lzcnt64:
1396*0fca6ea1SDimitry Andric     if (!interp__builtin_clz(S, OpPC, Frame, F, Call))
1397*0fca6ea1SDimitry Andric       return false;
1398*0fca6ea1SDimitry Andric     break;
1399*0fca6ea1SDimitry Andric 
1400*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ctz:
1401*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ctzl:
1402*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ctzll:
1403*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ctzs:
1404*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ctzg:
1405*0fca6ea1SDimitry Andric     if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
1406*0fca6ea1SDimitry Andric       return false;
1407*0fca6ea1SDimitry Andric     break;
1408*0fca6ea1SDimitry Andric 
1409*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_bswap16:
1410*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_bswap32:
1411*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_bswap64:
1412*0fca6ea1SDimitry Andric     if (!interp__builtin_bswap(S, OpPC, Frame, F, Call))
1413*0fca6ea1SDimitry Andric       return false;
1414*0fca6ea1SDimitry Andric     break;
1415*0fca6ea1SDimitry Andric 
1416*0fca6ea1SDimitry Andric   case Builtin::BI__atomic_always_lock_free:
1417*0fca6ea1SDimitry Andric   case Builtin::BI__atomic_is_lock_free:
1418*0fca6ea1SDimitry Andric   case Builtin::BI__c11_atomic_is_lock_free:
1419*0fca6ea1SDimitry Andric     if (!interp__builtin_atomic_lock_free(S, OpPC, Frame, F, Call))
1420*0fca6ea1SDimitry Andric       return false;
1421*0fca6ea1SDimitry Andric     break;
1422*0fca6ea1SDimitry Andric 
1423*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_complex:
1424*0fca6ea1SDimitry Andric     if (!interp__builtin_complex(S, OpPC, Frame, F, Call))
1425*0fca6ea1SDimitry Andric       return false;
1426*0fca6ea1SDimitry Andric     break;
1427*0fca6ea1SDimitry Andric 
1428*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_is_aligned:
1429*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_align_up:
1430*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_align_down:
1431*0fca6ea1SDimitry Andric     if (!interp__builtin_is_aligned_up_down(S, OpPC, Frame, F, Call))
1432*0fca6ea1SDimitry Andric       return false;
1433*0fca6ea1SDimitry Andric     break;
1434*0fca6ea1SDimitry Andric 
1435*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_os_log_format_buffer_size:
1436*0fca6ea1SDimitry Andric     if (!interp__builtin_os_log_format_buffer_size(S, OpPC, Frame, F, Call))
1437*0fca6ea1SDimitry Andric       return false;
1438*0fca6ea1SDimitry Andric     break;
1439*0fca6ea1SDimitry Andric 
1440*0fca6ea1SDimitry Andric   case Builtin::BI__builtin_ptrauth_string_discriminator:
1441*0fca6ea1SDimitry Andric     if (!interp__builtin_ptrauth_string_discriminator(S, OpPC, Frame, F, Call))
1442*0fca6ea1SDimitry Andric       return false;
1443*0fca6ea1SDimitry Andric     break;
1444*0fca6ea1SDimitry Andric 
144506c3fb27SDimitry Andric   default:
1446*0fca6ea1SDimitry Andric     S.FFDiag(S.Current->getLocation(OpPC),
1447*0fca6ea1SDimitry Andric              diag::note_invalid_subexpr_in_const_expr)
1448*0fca6ea1SDimitry Andric         << S.Current->getRange(OpPC);
1449*0fca6ea1SDimitry Andric 
145006c3fb27SDimitry Andric     return false;
145106c3fb27SDimitry Andric   }
145206c3fb27SDimitry Andric 
14535f757f3fSDimitry Andric   return retPrimValue(S, OpPC, Dummy, ReturnT);
14545f757f3fSDimitry Andric }
14555f757f3fSDimitry Andric 
14565f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
14575f757f3fSDimitry Andric                        llvm::ArrayRef<int64_t> ArrayIndices,
14585f757f3fSDimitry Andric                        int64_t &IntResult) {
14595f757f3fSDimitry Andric   CharUnits Result;
14605f757f3fSDimitry Andric   unsigned N = E->getNumComponents();
14615f757f3fSDimitry Andric   assert(N > 0);
14625f757f3fSDimitry Andric 
14635f757f3fSDimitry Andric   unsigned ArrayIndex = 0;
14645f757f3fSDimitry Andric   QualType CurrentType = E->getTypeSourceInfo()->getType();
14655f757f3fSDimitry Andric   for (unsigned I = 0; I != N; ++I) {
14665f757f3fSDimitry Andric     const OffsetOfNode &Node = E->getComponent(I);
14675f757f3fSDimitry Andric     switch (Node.getKind()) {
14685f757f3fSDimitry Andric     case OffsetOfNode::Field: {
14695f757f3fSDimitry Andric       const FieldDecl *MemberDecl = Node.getField();
14705f757f3fSDimitry Andric       const RecordType *RT = CurrentType->getAs<RecordType>();
14715f757f3fSDimitry Andric       if (!RT)
147206c3fb27SDimitry Andric         return false;
1473*0fca6ea1SDimitry Andric       const RecordDecl *RD = RT->getDecl();
14745f757f3fSDimitry Andric       if (RD->isInvalidDecl())
14755f757f3fSDimitry Andric         return false;
14765f757f3fSDimitry Andric       const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
14775f757f3fSDimitry Andric       unsigned FieldIndex = MemberDecl->getFieldIndex();
14785f757f3fSDimitry Andric       assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type");
14795f757f3fSDimitry Andric       Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex));
14805f757f3fSDimitry Andric       CurrentType = MemberDecl->getType().getNonReferenceType();
14815f757f3fSDimitry Andric       break;
14825f757f3fSDimitry Andric     }
14835f757f3fSDimitry Andric     case OffsetOfNode::Array: {
14845f757f3fSDimitry Andric       // When generating bytecode, we put all the index expressions as Sint64 on
14855f757f3fSDimitry Andric       // the stack.
14865f757f3fSDimitry Andric       int64_t Index = ArrayIndices[ArrayIndex];
14875f757f3fSDimitry Andric       const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType);
14885f757f3fSDimitry Andric       if (!AT)
14895f757f3fSDimitry Andric         return false;
14905f757f3fSDimitry Andric       CurrentType = AT->getElementType();
14915f757f3fSDimitry Andric       CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType);
14925f757f3fSDimitry Andric       Result += Index * ElementSize;
14935f757f3fSDimitry Andric       ++ArrayIndex;
14945f757f3fSDimitry Andric       break;
14955f757f3fSDimitry Andric     }
14965f757f3fSDimitry Andric     case OffsetOfNode::Base: {
14975f757f3fSDimitry Andric       const CXXBaseSpecifier *BaseSpec = Node.getBase();
14985f757f3fSDimitry Andric       if (BaseSpec->isVirtual())
14995f757f3fSDimitry Andric         return false;
15005f757f3fSDimitry Andric 
15015f757f3fSDimitry Andric       // Find the layout of the class whose base we are looking into.
15025f757f3fSDimitry Andric       const RecordType *RT = CurrentType->getAs<RecordType>();
15035f757f3fSDimitry Andric       if (!RT)
15045f757f3fSDimitry Andric         return false;
15055f757f3fSDimitry Andric       const RecordDecl *RD = RT->getDecl();
15065f757f3fSDimitry Andric       if (RD->isInvalidDecl())
15075f757f3fSDimitry Andric         return false;
15085f757f3fSDimitry Andric       const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
15095f757f3fSDimitry Andric 
15105f757f3fSDimitry Andric       // Find the base class itself.
15115f757f3fSDimitry Andric       CurrentType = BaseSpec->getType();
15125f757f3fSDimitry Andric       const RecordType *BaseRT = CurrentType->getAs<RecordType>();
15135f757f3fSDimitry Andric       if (!BaseRT)
15145f757f3fSDimitry Andric         return false;
15155f757f3fSDimitry Andric 
15165f757f3fSDimitry Andric       // Add the offset to the base.
15175f757f3fSDimitry Andric       Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()));
15185f757f3fSDimitry Andric       break;
15195f757f3fSDimitry Andric     }
15205f757f3fSDimitry Andric     case OffsetOfNode::Identifier:
15215f757f3fSDimitry Andric       llvm_unreachable("Dependent OffsetOfExpr?");
15225f757f3fSDimitry Andric     }
15235f757f3fSDimitry Andric   }
15245f757f3fSDimitry Andric 
15255f757f3fSDimitry Andric   IntResult = Result.getQuantity();
15265f757f3fSDimitry Andric 
15275f757f3fSDimitry Andric   return true;
15285f757f3fSDimitry Andric }
15295f757f3fSDimitry Andric 
15305f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
15315f757f3fSDimitry Andric                                 const Pointer &Ptr, const APSInt &IntValue) {
15325f757f3fSDimitry Andric 
15335f757f3fSDimitry Andric   const Record *R = Ptr.getRecord();
15345f757f3fSDimitry Andric   assert(R);
15355f757f3fSDimitry Andric   assert(R->getNumFields() == 1);
15365f757f3fSDimitry Andric 
15375f757f3fSDimitry Andric   unsigned FieldOffset = R->getField(0u)->Offset;
15385f757f3fSDimitry Andric   const Pointer &FieldPtr = Ptr.atField(FieldOffset);
15395f757f3fSDimitry Andric   PrimType FieldT = *S.getContext().classify(FieldPtr.getType());
15405f757f3fSDimitry Andric 
15415f757f3fSDimitry Andric   INT_TYPE_SWITCH(FieldT,
15425f757f3fSDimitry Andric                   FieldPtr.deref<T>() = T::from(IntValue.getSExtValue()));
15435f757f3fSDimitry Andric   FieldPtr.initialize();
15445f757f3fSDimitry Andric   return true;
154506c3fb27SDimitry Andric }
154606c3fb27SDimitry Andric 
1547*0fca6ea1SDimitry Andric bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest) {
1548*0fca6ea1SDimitry Andric   assert(Src.isLive() && Dest.isLive());
1549*0fca6ea1SDimitry Andric 
1550*0fca6ea1SDimitry Andric   [[maybe_unused]] const Descriptor *SrcDesc = Src.getFieldDesc();
1551*0fca6ea1SDimitry Andric   const Descriptor *DestDesc = Dest.getFieldDesc();
1552*0fca6ea1SDimitry Andric 
1553*0fca6ea1SDimitry Andric   assert(!DestDesc->isPrimitive() && !SrcDesc->isPrimitive());
1554*0fca6ea1SDimitry Andric 
1555*0fca6ea1SDimitry Andric   if (DestDesc->isPrimitiveArray()) {
1556*0fca6ea1SDimitry Andric     assert(SrcDesc->isPrimitiveArray());
1557*0fca6ea1SDimitry Andric     assert(SrcDesc->getNumElems() == DestDesc->getNumElems());
1558*0fca6ea1SDimitry Andric     PrimType ET = DestDesc->getPrimType();
1559*0fca6ea1SDimitry Andric     for (unsigned I = 0, N = DestDesc->getNumElems(); I != N; ++I) {
1560*0fca6ea1SDimitry Andric       Pointer DestElem = Dest.atIndex(I);
1561*0fca6ea1SDimitry Andric       TYPE_SWITCH(ET, {
1562*0fca6ea1SDimitry Andric         DestElem.deref<T>() = Src.atIndex(I).deref<T>();
1563*0fca6ea1SDimitry Andric         DestElem.initialize();
1564*0fca6ea1SDimitry Andric       });
1565*0fca6ea1SDimitry Andric     }
1566*0fca6ea1SDimitry Andric     return true;
1567*0fca6ea1SDimitry Andric   }
1568*0fca6ea1SDimitry Andric 
1569*0fca6ea1SDimitry Andric   if (DestDesc->isRecord()) {
1570*0fca6ea1SDimitry Andric     assert(SrcDesc->isRecord());
1571*0fca6ea1SDimitry Andric     assert(SrcDesc->ElemRecord == DestDesc->ElemRecord);
1572*0fca6ea1SDimitry Andric     const Record *R = DestDesc->ElemRecord;
1573*0fca6ea1SDimitry Andric     for (const Record::Field &F : R->fields()) {
1574*0fca6ea1SDimitry Andric       Pointer DestField = Dest.atField(F.Offset);
1575*0fca6ea1SDimitry Andric       if (std::optional<PrimType> FT = S.Ctx.classify(F.Decl->getType())) {
1576*0fca6ea1SDimitry Andric         TYPE_SWITCH(*FT, {
1577*0fca6ea1SDimitry Andric           DestField.deref<T>() = Src.atField(F.Offset).deref<T>();
1578*0fca6ea1SDimitry Andric           DestField.initialize();
1579*0fca6ea1SDimitry Andric         });
1580*0fca6ea1SDimitry Andric       } else {
1581*0fca6ea1SDimitry Andric         return Invalid(S, OpPC);
1582*0fca6ea1SDimitry Andric       }
1583*0fca6ea1SDimitry Andric     }
1584*0fca6ea1SDimitry Andric     return true;
1585*0fca6ea1SDimitry Andric   }
1586*0fca6ea1SDimitry Andric 
1587*0fca6ea1SDimitry Andric   // FIXME: Composite types.
1588*0fca6ea1SDimitry Andric 
1589*0fca6ea1SDimitry Andric   return Invalid(S, OpPC);
1590*0fca6ea1SDimitry Andric }
1591*0fca6ea1SDimitry Andric 
159206c3fb27SDimitry Andric } // namespace interp
159306c3fb27SDimitry Andric } // namespace clang
1594