xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp (revision 297eecfb02bb25902531dbb5c3b9a88caf8adf29)
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"
125f757f3fSDimitry Andric #include "clang/AST/RecordLayout.h"
1306c3fb27SDimitry Andric #include "clang/Basic/Builtins.h"
145f757f3fSDimitry Andric #include "clang/Basic/TargetInfo.h"
1506c3fb27SDimitry Andric 
1606c3fb27SDimitry Andric namespace clang {
1706c3fb27SDimitry Andric namespace interp {
1806c3fb27SDimitry Andric 
195f757f3fSDimitry Andric template <typename T>
205f757f3fSDimitry Andric static T getParam(const InterpFrame *Frame, unsigned Index) {
215f757f3fSDimitry Andric   assert(Frame->getFunction()->getNumParams() > Index);
2206c3fb27SDimitry Andric   unsigned Offset = Frame->getFunction()->getParamOffset(Index);
2306c3fb27SDimitry Andric   return Frame->getParam<T>(Offset);
2406c3fb27SDimitry Andric }
2506c3fb27SDimitry Andric 
265f757f3fSDimitry Andric PrimType getIntPrimType(const InterpState &S) {
275f757f3fSDimitry Andric   const TargetInfo &TI = S.getCtx().getTargetInfo();
285f757f3fSDimitry Andric   unsigned IntWidth = TI.getIntWidth();
295f757f3fSDimitry Andric 
305f757f3fSDimitry Andric   if (IntWidth == 32)
315f757f3fSDimitry Andric     return PT_Sint32;
325f757f3fSDimitry Andric   else if (IntWidth == 16)
335f757f3fSDimitry Andric     return PT_Sint16;
345f757f3fSDimitry Andric   llvm_unreachable("Int isn't 16 or 32 bit?");
355f757f3fSDimitry Andric }
365f757f3fSDimitry Andric 
375f757f3fSDimitry Andric PrimType getLongPrimType(const InterpState &S) {
385f757f3fSDimitry Andric   const TargetInfo &TI = S.getCtx().getTargetInfo();
395f757f3fSDimitry Andric   unsigned LongWidth = TI.getLongWidth();
405f757f3fSDimitry Andric 
415f757f3fSDimitry Andric   if (LongWidth == 64)
425f757f3fSDimitry Andric     return PT_Sint64;
435f757f3fSDimitry Andric   else if (LongWidth == 32)
445f757f3fSDimitry Andric     return PT_Sint32;
455f757f3fSDimitry Andric   else if (LongWidth == 16)
465f757f3fSDimitry Andric     return PT_Sint16;
475f757f3fSDimitry Andric   llvm_unreachable("long isn't 16, 32 or 64 bit?");
485f757f3fSDimitry Andric }
495f757f3fSDimitry Andric 
505f757f3fSDimitry Andric /// Peek an integer value from the stack into an APSInt.
515f757f3fSDimitry Andric static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
525f757f3fSDimitry Andric   if (Offset == 0)
535f757f3fSDimitry Andric     Offset = align(primSize(T));
545f757f3fSDimitry Andric 
555f757f3fSDimitry Andric   APSInt R;
565f757f3fSDimitry Andric   INT_TYPE_SWITCH(T, {
575f757f3fSDimitry Andric     T Val = Stk.peek<T>(Offset);
585f757f3fSDimitry Andric     R = APSInt(
595f757f3fSDimitry Andric         APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned()));
605f757f3fSDimitry Andric   });
615f757f3fSDimitry Andric 
625f757f3fSDimitry Andric   return R;
635f757f3fSDimitry Andric }
645f757f3fSDimitry Andric 
655f757f3fSDimitry Andric /// Pushes \p Val to the stack, as a target-dependent 'int'.
665f757f3fSDimitry Andric static void pushInt(InterpState &S, int32_t Val) {
675f757f3fSDimitry Andric   PrimType IntType = getIntPrimType(S);
685f757f3fSDimitry Andric   if (IntType == PT_Sint32)
695f757f3fSDimitry Andric     S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val));
705f757f3fSDimitry Andric   else if (IntType == PT_Sint16)
715f757f3fSDimitry Andric     S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val));
725f757f3fSDimitry Andric   else
735f757f3fSDimitry Andric     llvm_unreachable("Int isn't 16 or 32 bit?");
745f757f3fSDimitry Andric }
755f757f3fSDimitry Andric 
765f757f3fSDimitry Andric static void pushAPSInt(InterpState &S, const APSInt &Val) {
775f757f3fSDimitry Andric   bool Signed = Val.isSigned();
785f757f3fSDimitry Andric 
795f757f3fSDimitry Andric   if (Signed) {
805f757f3fSDimitry Andric     switch (Val.getBitWidth()) {
815f757f3fSDimitry Andric     case 64:
825f757f3fSDimitry Andric       S.Stk.push<Integral<64, true>>(
835f757f3fSDimitry Andric           Integral<64, true>::from(Val.getSExtValue()));
845f757f3fSDimitry Andric       break;
855f757f3fSDimitry Andric     case 32:
865f757f3fSDimitry Andric       S.Stk.push<Integral<32, true>>(
875f757f3fSDimitry Andric           Integral<32, true>::from(Val.getSExtValue()));
885f757f3fSDimitry Andric       break;
895f757f3fSDimitry Andric     case 16:
905f757f3fSDimitry Andric       S.Stk.push<Integral<16, true>>(
915f757f3fSDimitry Andric           Integral<16, true>::from(Val.getSExtValue()));
925f757f3fSDimitry Andric       break;
935f757f3fSDimitry Andric     case 8:
945f757f3fSDimitry Andric       S.Stk.push<Integral<8, true>>(
955f757f3fSDimitry Andric           Integral<8, true>::from(Val.getSExtValue()));
965f757f3fSDimitry Andric       break;
975f757f3fSDimitry Andric     default:
985f757f3fSDimitry Andric       llvm_unreachable("Invalid integer bitwidth");
995f757f3fSDimitry Andric     }
1005f757f3fSDimitry Andric     return;
1015f757f3fSDimitry Andric   }
1025f757f3fSDimitry Andric 
1035f757f3fSDimitry Andric   // Unsigned.
1045f757f3fSDimitry Andric   switch (Val.getBitWidth()) {
1055f757f3fSDimitry Andric   case 64:
1065f757f3fSDimitry Andric     S.Stk.push<Integral<64, false>>(
1075f757f3fSDimitry Andric         Integral<64, false>::from(Val.getZExtValue()));
1085f757f3fSDimitry Andric     break;
1095f757f3fSDimitry Andric   case 32:
1105f757f3fSDimitry Andric     S.Stk.push<Integral<32, false>>(
1115f757f3fSDimitry Andric         Integral<32, false>::from(Val.getZExtValue()));
1125f757f3fSDimitry Andric     break;
1135f757f3fSDimitry Andric   case 16:
1145f757f3fSDimitry Andric     S.Stk.push<Integral<16, false>>(
1155f757f3fSDimitry Andric         Integral<16, false>::from(Val.getZExtValue()));
1165f757f3fSDimitry Andric     break;
1175f757f3fSDimitry Andric   case 8:
1185f757f3fSDimitry Andric     S.Stk.push<Integral<8, false>>(
1195f757f3fSDimitry Andric         Integral<8, false>::from(Val.getZExtValue()));
1205f757f3fSDimitry Andric     break;
1215f757f3fSDimitry Andric   default:
1225f757f3fSDimitry Andric     llvm_unreachable("Invalid integer bitwidth");
1235f757f3fSDimitry Andric   }
1245f757f3fSDimitry Andric }
1255f757f3fSDimitry Andric 
1265f757f3fSDimitry Andric /// Pushes \p Val to the stack, as a target-dependent 'long'.
1275f757f3fSDimitry Andric static void pushLong(InterpState &S, int64_t Val) {
1285f757f3fSDimitry Andric   PrimType LongType = getLongPrimType(S);
1295f757f3fSDimitry Andric   if (LongType == PT_Sint64)
1305f757f3fSDimitry Andric     S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Val));
1315f757f3fSDimitry Andric   else if (LongType == PT_Sint32)
1325f757f3fSDimitry Andric     S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val));
1335f757f3fSDimitry Andric   else if (LongType == PT_Sint16)
1345f757f3fSDimitry Andric     S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val));
1355f757f3fSDimitry Andric   else
1365f757f3fSDimitry Andric     llvm_unreachable("Long isn't 16, 32 or 64 bit?");
1375f757f3fSDimitry Andric }
1385f757f3fSDimitry Andric 
1395f757f3fSDimitry Andric static void pushSizeT(InterpState &S, uint64_t Val) {
1405f757f3fSDimitry Andric   const TargetInfo &TI = S.getCtx().getTargetInfo();
1415f757f3fSDimitry Andric   unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
1425f757f3fSDimitry Andric 
1435f757f3fSDimitry Andric   switch (SizeTWidth) {
1445f757f3fSDimitry Andric   case 64:
1455f757f3fSDimitry Andric     S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Val));
1465f757f3fSDimitry Andric     break;
1475f757f3fSDimitry Andric   case 32:
1485f757f3fSDimitry Andric     S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Val));
1495f757f3fSDimitry Andric     break;
1505f757f3fSDimitry Andric   case 16:
1515f757f3fSDimitry Andric     S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Val));
1525f757f3fSDimitry Andric     break;
1535f757f3fSDimitry Andric   default:
1545f757f3fSDimitry Andric     llvm_unreachable("We don't handle this size_t size.");
1555f757f3fSDimitry Andric   }
1565f757f3fSDimitry Andric }
1575f757f3fSDimitry Andric 
1585f757f3fSDimitry Andric static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
1595f757f3fSDimitry Andric                          std::optional<PrimType> &T) {
1605f757f3fSDimitry Andric   if (!T)
1615f757f3fSDimitry Andric     return RetVoid(S, OpPC, Result);
1625f757f3fSDimitry Andric 
1635f757f3fSDimitry Andric #define RET_CASE(X)                                                            \
1645f757f3fSDimitry Andric   case X:                                                                      \
1655f757f3fSDimitry Andric     return Ret<X>(S, OpPC, Result);
1665f757f3fSDimitry Andric   switch (*T) {
167*297eecfbSDimitry Andric     RET_CASE(PT_Ptr);
168*297eecfbSDimitry Andric     RET_CASE(PT_FnPtr);
1695f757f3fSDimitry Andric     RET_CASE(PT_Float);
1705f757f3fSDimitry Andric     RET_CASE(PT_Bool);
1715f757f3fSDimitry Andric     RET_CASE(PT_Sint8);
1725f757f3fSDimitry Andric     RET_CASE(PT_Uint8);
1735f757f3fSDimitry Andric     RET_CASE(PT_Sint16);
1745f757f3fSDimitry Andric     RET_CASE(PT_Uint16);
1755f757f3fSDimitry Andric     RET_CASE(PT_Sint32);
1765f757f3fSDimitry Andric     RET_CASE(PT_Uint32);
1775f757f3fSDimitry Andric     RET_CASE(PT_Sint64);
1785f757f3fSDimitry Andric     RET_CASE(PT_Uint64);
1795f757f3fSDimitry Andric   default:
1805f757f3fSDimitry Andric     llvm_unreachable("Unsupported return type for builtin function");
1815f757f3fSDimitry Andric   }
1825f757f3fSDimitry Andric #undef RET_CASE
1835f757f3fSDimitry Andric }
1845f757f3fSDimitry Andric 
18506c3fb27SDimitry Andric static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
1865f757f3fSDimitry Andric                                    const InterpFrame *Frame) {
18706c3fb27SDimitry Andric   const Pointer &A = getParam<Pointer>(Frame, 0);
18806c3fb27SDimitry Andric   const Pointer &B = getParam<Pointer>(Frame, 1);
18906c3fb27SDimitry Andric 
19006c3fb27SDimitry Andric   if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
19106c3fb27SDimitry Andric     return false;
19206c3fb27SDimitry Andric 
19306c3fb27SDimitry Andric   assert(A.getFieldDesc()->isPrimitiveArray());
19406c3fb27SDimitry Andric   assert(B.getFieldDesc()->isPrimitiveArray());
19506c3fb27SDimitry Andric 
19606c3fb27SDimitry Andric   unsigned IndexA = A.getIndex();
19706c3fb27SDimitry Andric   unsigned IndexB = B.getIndex();
19806c3fb27SDimitry Andric   int32_t Result = 0;
19906c3fb27SDimitry Andric   for (;; ++IndexA, ++IndexB) {
20006c3fb27SDimitry Andric     const Pointer &PA = A.atIndex(IndexA);
20106c3fb27SDimitry Andric     const Pointer &PB = B.atIndex(IndexB);
20206c3fb27SDimitry Andric     if (!CheckRange(S, OpPC, PA, AK_Read) ||
20306c3fb27SDimitry Andric         !CheckRange(S, OpPC, PB, AK_Read)) {
20406c3fb27SDimitry Andric       return false;
20506c3fb27SDimitry Andric     }
20606c3fb27SDimitry Andric     uint8_t CA = PA.deref<uint8_t>();
20706c3fb27SDimitry Andric     uint8_t CB = PB.deref<uint8_t>();
20806c3fb27SDimitry Andric 
20906c3fb27SDimitry Andric     if (CA > CB) {
21006c3fb27SDimitry Andric       Result = 1;
21106c3fb27SDimitry Andric       break;
21206c3fb27SDimitry Andric     } else if (CA < CB) {
21306c3fb27SDimitry Andric       Result = -1;
21406c3fb27SDimitry Andric       break;
21506c3fb27SDimitry Andric     }
21606c3fb27SDimitry Andric     if (CA == 0 || CB == 0)
21706c3fb27SDimitry Andric       break;
21806c3fb27SDimitry Andric   }
21906c3fb27SDimitry Andric 
2205f757f3fSDimitry Andric   pushInt(S, Result);
22106c3fb27SDimitry Andric   return true;
22206c3fb27SDimitry Andric }
22306c3fb27SDimitry Andric 
2245f757f3fSDimitry Andric static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
2255f757f3fSDimitry Andric                                    const InterpFrame *Frame) {
2265f757f3fSDimitry Andric   const Pointer &StrPtr = getParam<Pointer>(Frame, 0);
2275f757f3fSDimitry Andric 
2285f757f3fSDimitry Andric   if (!CheckArray(S, OpPC, StrPtr))
2295f757f3fSDimitry Andric     return false;
2305f757f3fSDimitry Andric 
2315f757f3fSDimitry Andric   if (!CheckLive(S, OpPC, StrPtr, AK_Read))
2325f757f3fSDimitry Andric     return false;
2335f757f3fSDimitry Andric 
2345f757f3fSDimitry Andric   if (!CheckDummy(S, OpPC, StrPtr))
2355f757f3fSDimitry Andric     return false;
2365f757f3fSDimitry Andric 
2375f757f3fSDimitry Andric   assert(StrPtr.getFieldDesc()->isPrimitiveArray());
2385f757f3fSDimitry Andric 
2395f757f3fSDimitry Andric   size_t Len = 0;
2405f757f3fSDimitry Andric   for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
2415f757f3fSDimitry Andric     const Pointer &ElemPtr = StrPtr.atIndex(I);
2425f757f3fSDimitry Andric 
2435f757f3fSDimitry Andric     if (!CheckRange(S, OpPC, ElemPtr, AK_Read))
2445f757f3fSDimitry Andric       return false;
2455f757f3fSDimitry Andric 
2465f757f3fSDimitry Andric     uint8_t Val = ElemPtr.deref<uint8_t>();
2475f757f3fSDimitry Andric     if (Val == 0)
2485f757f3fSDimitry Andric       break;
2495f757f3fSDimitry Andric   }
2505f757f3fSDimitry Andric 
2515f757f3fSDimitry Andric   pushSizeT(S, Len);
2525f757f3fSDimitry Andric   return true;
2535f757f3fSDimitry Andric }
2545f757f3fSDimitry Andric 
2555f757f3fSDimitry Andric static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
2565f757f3fSDimitry Andric                                 const InterpFrame *Frame, const Function *F,
2575f757f3fSDimitry Andric                                 bool Signaling) {
2585f757f3fSDimitry Andric   const Pointer &Arg = getParam<Pointer>(Frame, 0);
2595f757f3fSDimitry Andric 
2605f757f3fSDimitry Andric   if (!CheckLoad(S, OpPC, Arg))
2615f757f3fSDimitry Andric     return false;
2625f757f3fSDimitry Andric 
2635f757f3fSDimitry Andric   assert(Arg.getFieldDesc()->isPrimitiveArray());
2645f757f3fSDimitry Andric 
2655f757f3fSDimitry Andric   // Convert the given string to an integer using StringRef's API.
2665f757f3fSDimitry Andric   llvm::APInt Fill;
2675f757f3fSDimitry Andric   std::string Str;
2685f757f3fSDimitry Andric   assert(Arg.getNumElems() >= 1);
2695f757f3fSDimitry Andric   for (unsigned I = 0;; ++I) {
2705f757f3fSDimitry Andric     const Pointer &Elem = Arg.atIndex(I);
2715f757f3fSDimitry Andric 
2725f757f3fSDimitry Andric     if (!CheckLoad(S, OpPC, Elem))
2735f757f3fSDimitry Andric       return false;
2745f757f3fSDimitry Andric 
2755f757f3fSDimitry Andric     if (Elem.deref<int8_t>() == 0)
2765f757f3fSDimitry Andric       break;
2775f757f3fSDimitry Andric 
2785f757f3fSDimitry Andric     Str += Elem.deref<char>();
2795f757f3fSDimitry Andric   }
2805f757f3fSDimitry Andric 
2815f757f3fSDimitry Andric   // Treat empty strings as if they were zero.
2825f757f3fSDimitry Andric   if (Str.empty())
2835f757f3fSDimitry Andric     Fill = llvm::APInt(32, 0);
2845f757f3fSDimitry Andric   else if (StringRef(Str).getAsInteger(0, Fill))
2855f757f3fSDimitry Andric     return false;
2865f757f3fSDimitry Andric 
2875f757f3fSDimitry Andric   const llvm::fltSemantics &TargetSemantics =
2885f757f3fSDimitry Andric       S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
2895f757f3fSDimitry Andric 
2905f757f3fSDimitry Andric   Floating Result;
2915f757f3fSDimitry Andric   if (S.getCtx().getTargetInfo().isNan2008()) {
2925f757f3fSDimitry Andric     if (Signaling)
2935f757f3fSDimitry Andric       Result = Floating(
2945f757f3fSDimitry Andric           llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
2955f757f3fSDimitry Andric     else
2965f757f3fSDimitry Andric       Result = Floating(
2975f757f3fSDimitry Andric           llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
2985f757f3fSDimitry Andric   } else {
2995f757f3fSDimitry Andric     // Prior to IEEE 754-2008, architectures were allowed to choose whether
3005f757f3fSDimitry Andric     // the first bit of their significand was set for qNaN or sNaN. MIPS chose
3015f757f3fSDimitry Andric     // a different encoding to what became a standard in 2008, and for pre-
3025f757f3fSDimitry Andric     // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
3035f757f3fSDimitry Andric     // sNaN. This is now known as "legacy NaN" encoding.
3045f757f3fSDimitry Andric     if (Signaling)
3055f757f3fSDimitry Andric       Result = Floating(
3065f757f3fSDimitry Andric           llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
3075f757f3fSDimitry Andric     else
3085f757f3fSDimitry Andric       Result = Floating(
3095f757f3fSDimitry Andric           llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
3105f757f3fSDimitry Andric   }
3115f757f3fSDimitry Andric 
3125f757f3fSDimitry Andric   S.Stk.push<Floating>(Result);
3135f757f3fSDimitry Andric   return true;
3145f757f3fSDimitry Andric }
3155f757f3fSDimitry Andric 
3165f757f3fSDimitry Andric static bool interp__builtin_inf(InterpState &S, CodePtr OpPC,
3175f757f3fSDimitry Andric                                 const InterpFrame *Frame, const Function *F) {
3185f757f3fSDimitry Andric   const llvm::fltSemantics &TargetSemantics =
3195f757f3fSDimitry Andric       S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
3205f757f3fSDimitry Andric 
3215f757f3fSDimitry Andric   S.Stk.push<Floating>(Floating::getInf(TargetSemantics));
3225f757f3fSDimitry Andric   return true;
3235f757f3fSDimitry Andric }
3245f757f3fSDimitry Andric 
3255f757f3fSDimitry Andric static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC,
3265f757f3fSDimitry Andric                                      const InterpFrame *Frame,
3275f757f3fSDimitry Andric                                      const Function *F) {
3285f757f3fSDimitry Andric   const Floating &Arg1 = getParam<Floating>(Frame, 0);
3295f757f3fSDimitry Andric   const Floating &Arg2 = getParam<Floating>(Frame, 1);
3305f757f3fSDimitry Andric 
3315f757f3fSDimitry Andric   APFloat Copy = Arg1.getAPFloat();
3325f757f3fSDimitry Andric   Copy.copySign(Arg2.getAPFloat());
3335f757f3fSDimitry Andric   S.Stk.push<Floating>(Floating(Copy));
3345f757f3fSDimitry Andric 
3355f757f3fSDimitry Andric   return true;
3365f757f3fSDimitry Andric }
3375f757f3fSDimitry Andric 
3385f757f3fSDimitry Andric static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC,
3395f757f3fSDimitry Andric                                  const InterpFrame *Frame, const Function *F) {
3405f757f3fSDimitry Andric   const Floating &LHS = getParam<Floating>(Frame, 0);
3415f757f3fSDimitry Andric   const Floating &RHS = getParam<Floating>(Frame, 1);
3425f757f3fSDimitry Andric 
3435f757f3fSDimitry Andric   Floating Result;
3445f757f3fSDimitry Andric 
3455f757f3fSDimitry Andric   // When comparing zeroes, return -0.0 if one of the zeroes is negative.
3465f757f3fSDimitry Andric   if (LHS.isZero() && RHS.isZero() && RHS.isNegative())
3475f757f3fSDimitry Andric     Result = RHS;
3485f757f3fSDimitry Andric   else if (LHS.isNan() || RHS < LHS)
3495f757f3fSDimitry Andric     Result = RHS;
3505f757f3fSDimitry Andric   else
3515f757f3fSDimitry Andric     Result = LHS;
3525f757f3fSDimitry Andric 
3535f757f3fSDimitry Andric   S.Stk.push<Floating>(Result);
3545f757f3fSDimitry Andric   return true;
3555f757f3fSDimitry Andric }
3565f757f3fSDimitry Andric 
3575f757f3fSDimitry Andric static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC,
3585f757f3fSDimitry Andric                                  const InterpFrame *Frame,
3595f757f3fSDimitry Andric                                  const Function *Func) {
3605f757f3fSDimitry Andric   const Floating &LHS = getParam<Floating>(Frame, 0);
3615f757f3fSDimitry Andric   const Floating &RHS = getParam<Floating>(Frame, 1);
3625f757f3fSDimitry Andric 
3635f757f3fSDimitry Andric   Floating Result;
3645f757f3fSDimitry Andric 
3655f757f3fSDimitry Andric   // When comparing zeroes, return +0.0 if one of the zeroes is positive.
3665f757f3fSDimitry Andric   if (LHS.isZero() && RHS.isZero() && LHS.isNegative())
3675f757f3fSDimitry Andric     Result = RHS;
3685f757f3fSDimitry Andric   else if (LHS.isNan() || RHS > LHS)
3695f757f3fSDimitry Andric     Result = RHS;
3705f757f3fSDimitry Andric   else
3715f757f3fSDimitry Andric     Result = LHS;
3725f757f3fSDimitry Andric 
3735f757f3fSDimitry Andric   S.Stk.push<Floating>(Result);
3745f757f3fSDimitry Andric   return true;
3755f757f3fSDimitry Andric }
3765f757f3fSDimitry Andric 
3775f757f3fSDimitry Andric /// Defined as __builtin_isnan(...), to accommodate the fact that it can
3785f757f3fSDimitry Andric /// take a float, double, long double, etc.
3795f757f3fSDimitry Andric /// But for us, that's all a Floating anyway.
3805f757f3fSDimitry Andric static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
3815f757f3fSDimitry Andric                                   const InterpFrame *Frame, const Function *F) {
3825f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
3835f757f3fSDimitry Andric 
3845f757f3fSDimitry Andric   pushInt(S, Arg.isNan());
3855f757f3fSDimitry Andric   return true;
3865f757f3fSDimitry Andric }
3875f757f3fSDimitry Andric 
3885f757f3fSDimitry Andric static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC,
3895f757f3fSDimitry Andric                                         const InterpFrame *Frame,
3905f757f3fSDimitry Andric                                         const Function *F) {
3915f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
3925f757f3fSDimitry Andric 
3935f757f3fSDimitry Andric   pushInt(S, Arg.isSignaling());
3945f757f3fSDimitry Andric   return true;
3955f757f3fSDimitry Andric }
3965f757f3fSDimitry Andric 
3975f757f3fSDimitry Andric static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC,
3985f757f3fSDimitry Andric                                   const InterpFrame *Frame, const Function *F,
3995f757f3fSDimitry Andric                                   bool CheckSign) {
4005f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4015f757f3fSDimitry Andric   bool IsInf = Arg.isInf();
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric   if (CheckSign)
4045f757f3fSDimitry Andric     pushInt(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0);
4055f757f3fSDimitry Andric   else
4065f757f3fSDimitry Andric     pushInt(S, Arg.isInf());
4075f757f3fSDimitry Andric   return true;
4085f757f3fSDimitry Andric }
4095f757f3fSDimitry Andric 
4105f757f3fSDimitry Andric static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC,
4115f757f3fSDimitry Andric                                      const InterpFrame *Frame,
4125f757f3fSDimitry Andric                                      const Function *F) {
4135f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4145f757f3fSDimitry Andric 
4155f757f3fSDimitry Andric   pushInt(S, Arg.isFinite());
4165f757f3fSDimitry Andric   return true;
4175f757f3fSDimitry Andric }
4185f757f3fSDimitry Andric 
4195f757f3fSDimitry Andric static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC,
4205f757f3fSDimitry Andric                                      const InterpFrame *Frame,
4215f757f3fSDimitry Andric                                      const Function *F) {
4225f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4235f757f3fSDimitry Andric 
4245f757f3fSDimitry Andric   pushInt(S, Arg.isNormal());
4255f757f3fSDimitry Andric   return true;
4265f757f3fSDimitry Andric }
4275f757f3fSDimitry Andric 
4285f757f3fSDimitry Andric static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC,
4295f757f3fSDimitry Andric                                         const InterpFrame *Frame,
4305f757f3fSDimitry Andric                                         const Function *F) {
4315f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4325f757f3fSDimitry Andric 
4335f757f3fSDimitry Andric   pushInt(S, Arg.isDenormal());
4345f757f3fSDimitry Andric   return true;
4355f757f3fSDimitry Andric }
4365f757f3fSDimitry Andric 
4375f757f3fSDimitry Andric static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
4385f757f3fSDimitry Andric                                    const InterpFrame *Frame,
4395f757f3fSDimitry Andric                                    const Function *F) {
4405f757f3fSDimitry Andric   const Floating &Arg = S.Stk.peek<Floating>();
4415f757f3fSDimitry Andric 
4425f757f3fSDimitry Andric   pushInt(S, Arg.isZero());
4435f757f3fSDimitry Andric   return true;
4445f757f3fSDimitry Andric }
4455f757f3fSDimitry Andric 
4465f757f3fSDimitry Andric /// First parameter to __builtin_isfpclass is the floating value, the
4475f757f3fSDimitry Andric /// second one is an integral value.
4485f757f3fSDimitry Andric static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
4495f757f3fSDimitry Andric                                       const InterpFrame *Frame,
4505f757f3fSDimitry Andric                                       const Function *Func,
4515f757f3fSDimitry Andric                                       const CallExpr *Call) {
4525f757f3fSDimitry Andric   PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType());
4535f757f3fSDimitry Andric   APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT);
4545f757f3fSDimitry Andric   const Floating &F =
4555f757f3fSDimitry Andric       S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float)));
4565f757f3fSDimitry Andric 
4575f757f3fSDimitry Andric   int32_t Result =
4585f757f3fSDimitry Andric       static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue());
4595f757f3fSDimitry Andric   pushInt(S, Result);
4605f757f3fSDimitry Andric 
4615f757f3fSDimitry Andric   return true;
4625f757f3fSDimitry Andric }
4635f757f3fSDimitry Andric 
4645f757f3fSDimitry Andric /// Five int values followed by one floating value.
4655f757f3fSDimitry Andric static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC,
4665f757f3fSDimitry Andric                                        const InterpFrame *Frame,
4675f757f3fSDimitry Andric                                        const Function *Func) {
4685f757f3fSDimitry Andric   const Floating &Val = S.Stk.peek<Floating>();
4695f757f3fSDimitry Andric 
4705f757f3fSDimitry Andric   unsigned Index;
4715f757f3fSDimitry Andric   switch (Val.getCategory()) {
4725f757f3fSDimitry Andric   case APFloat::fcNaN:
4735f757f3fSDimitry Andric     Index = 0;
4745f757f3fSDimitry Andric     break;
4755f757f3fSDimitry Andric   case APFloat::fcInfinity:
4765f757f3fSDimitry Andric     Index = 1;
4775f757f3fSDimitry Andric     break;
4785f757f3fSDimitry Andric   case APFloat::fcNormal:
4795f757f3fSDimitry Andric     Index = Val.isDenormal() ? 3 : 2;
4805f757f3fSDimitry Andric     break;
4815f757f3fSDimitry Andric   case APFloat::fcZero:
4825f757f3fSDimitry Andric     Index = 4;
4835f757f3fSDimitry Andric     break;
4845f757f3fSDimitry Andric   }
4855f757f3fSDimitry Andric 
4865f757f3fSDimitry Andric   // The last argument is first on the stack.
4875f757f3fSDimitry Andric   assert(Index <= 4);
4885f757f3fSDimitry Andric   unsigned IntSize = primSize(getIntPrimType(S));
4895f757f3fSDimitry Andric   unsigned Offset =
4905f757f3fSDimitry Andric       align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize));
4915f757f3fSDimitry Andric 
4925f757f3fSDimitry Andric   APSInt I = peekToAPSInt(S.Stk, getIntPrimType(S), Offset);
4935f757f3fSDimitry Andric   pushInt(S, I.getZExtValue());
4945f757f3fSDimitry Andric   return true;
4955f757f3fSDimitry Andric }
4965f757f3fSDimitry Andric 
4975f757f3fSDimitry Andric // The C standard says "fabs raises no floating-point exceptions,
4985f757f3fSDimitry Andric // even if x is a signaling NaN. The returned value is independent of
4995f757f3fSDimitry Andric // the current rounding direction mode."  Therefore constant folding can
5005f757f3fSDimitry Andric // proceed without regard to the floating point settings.
5015f757f3fSDimitry Andric // Reference, WG14 N2478 F.10.4.3
5025f757f3fSDimitry Andric static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
5035f757f3fSDimitry Andric                                  const InterpFrame *Frame,
5045f757f3fSDimitry Andric                                  const Function *Func) {
5055f757f3fSDimitry Andric   const Floating &Val = getParam<Floating>(Frame, 0);
5065f757f3fSDimitry Andric 
5075f757f3fSDimitry Andric   S.Stk.push<Floating>(Floating::abs(Val));
5085f757f3fSDimitry Andric   return true;
5095f757f3fSDimitry Andric }
5105f757f3fSDimitry Andric 
5115f757f3fSDimitry Andric static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
5125f757f3fSDimitry Andric                                      const InterpFrame *Frame,
5135f757f3fSDimitry Andric                                      const Function *Func,
5145f757f3fSDimitry Andric                                      const CallExpr *Call) {
5155f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5165f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
5175f757f3fSDimitry Andric   pushInt(S, Val.popcount());
5185f757f3fSDimitry Andric   return true;
5195f757f3fSDimitry Andric }
5205f757f3fSDimitry Andric 
5215f757f3fSDimitry Andric static bool interp__builtin_parity(InterpState &S, CodePtr OpPC,
5225f757f3fSDimitry Andric                                    const InterpFrame *Frame,
5235f757f3fSDimitry Andric                                    const Function *Func, const CallExpr *Call) {
5245f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5255f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
5265f757f3fSDimitry Andric   pushInt(S, Val.popcount() % 2);
5275f757f3fSDimitry Andric   return true;
5285f757f3fSDimitry Andric }
5295f757f3fSDimitry Andric 
5305f757f3fSDimitry Andric static bool interp__builtin_clrsb(InterpState &S, CodePtr OpPC,
5315f757f3fSDimitry Andric                                   const InterpFrame *Frame,
5325f757f3fSDimitry Andric                                   const Function *Func, const CallExpr *Call) {
5335f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5345f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
5355f757f3fSDimitry Andric   pushInt(S, Val.getBitWidth() - Val.getSignificantBits());
5365f757f3fSDimitry Andric   return true;
5375f757f3fSDimitry Andric }
5385f757f3fSDimitry Andric 
5395f757f3fSDimitry Andric static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC,
5405f757f3fSDimitry Andric                                        const InterpFrame *Frame,
5415f757f3fSDimitry Andric                                        const Function *Func,
5425f757f3fSDimitry Andric                                        const CallExpr *Call) {
5435f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5445f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT);
5455f757f3fSDimitry Andric   pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigned=*/true));
5465f757f3fSDimitry Andric   return true;
5475f757f3fSDimitry Andric }
5485f757f3fSDimitry Andric 
5495f757f3fSDimitry Andric static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC,
5505f757f3fSDimitry Andric                                           const InterpFrame *Frame,
5515f757f3fSDimitry Andric                                           const Function *Func,
5525f757f3fSDimitry Andric                                           const CallExpr *Call) {
5535f757f3fSDimitry Andric   // This is an unevaluated call, so there are no arguments on the stack.
5545f757f3fSDimitry Andric   assert(Call->getNumArgs() == 1);
5555f757f3fSDimitry Andric   const Expr *Arg = Call->getArg(0);
5565f757f3fSDimitry Andric 
5575f757f3fSDimitry Andric   GCCTypeClass ResultClass =
5585f757f3fSDimitry Andric       EvaluateBuiltinClassifyType(Arg->getType(), S.getLangOpts());
5595f757f3fSDimitry Andric   int32_t ReturnVal = static_cast<int32_t>(ResultClass);
5605f757f3fSDimitry Andric   pushInt(S, ReturnVal);
5615f757f3fSDimitry Andric   return true;
5625f757f3fSDimitry Andric }
5635f757f3fSDimitry Andric 
5645f757f3fSDimitry Andric // __builtin_expect(long, long)
5655f757f3fSDimitry Andric // __builtin_expect_with_probability(long, long, double)
5665f757f3fSDimitry Andric static bool interp__builtin_expect(InterpState &S, CodePtr OpPC,
5675f757f3fSDimitry Andric                                    const InterpFrame *Frame,
5685f757f3fSDimitry Andric                                    const Function *Func, const CallExpr *Call) {
5695f757f3fSDimitry Andric   // The return value is simply the value of the first parameter.
5705f757f3fSDimitry Andric   // We ignore the probability.
5715f757f3fSDimitry Andric   unsigned NumArgs = Call->getNumArgs();
5725f757f3fSDimitry Andric   assert(NumArgs == 2 || NumArgs == 3);
5735f757f3fSDimitry Andric 
5745f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5755f757f3fSDimitry Andric   unsigned Offset = align(primSize(getLongPrimType(S))) * 2;
5765f757f3fSDimitry Andric   if (NumArgs == 3)
5775f757f3fSDimitry Andric     Offset += align(primSize(PT_Float));
5785f757f3fSDimitry Andric 
5795f757f3fSDimitry Andric   APSInt Val = peekToAPSInt(S.Stk, ArgT, Offset);
5805f757f3fSDimitry Andric   pushLong(S, Val.getSExtValue());
5815f757f3fSDimitry Andric   return true;
5825f757f3fSDimitry Andric }
5835f757f3fSDimitry Andric 
5845f757f3fSDimitry Andric /// rotateleft(value, amount)
5855f757f3fSDimitry Andric static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC,
5865f757f3fSDimitry Andric                                    const InterpFrame *Frame,
5875f757f3fSDimitry Andric                                    const Function *Func, const CallExpr *Call,
5885f757f3fSDimitry Andric                                    bool Right) {
5895f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
5905f757f3fSDimitry Andric   assert(ArgT == *S.getContext().classify(Call->getArg(1)->getType()));
5915f757f3fSDimitry Andric 
5925f757f3fSDimitry Andric   APSInt Amount = peekToAPSInt(S.Stk, ArgT);
5935f757f3fSDimitry Andric   APSInt Value = peekToAPSInt(S.Stk, ArgT, align(primSize(ArgT)) * 2);
5945f757f3fSDimitry Andric 
5955f757f3fSDimitry Andric   APSInt Result;
5965f757f3fSDimitry Andric   if (Right)
5975f757f3fSDimitry Andric     Result = APSInt(Value.rotr(Amount.urem(Value.getBitWidth())),
5985f757f3fSDimitry Andric                     /*IsUnsigned=*/true);
5995f757f3fSDimitry Andric   else // Left.
6005f757f3fSDimitry Andric     Result = APSInt(Value.rotl(Amount.urem(Value.getBitWidth())),
6015f757f3fSDimitry Andric                     /*IsUnsigned=*/true);
6025f757f3fSDimitry Andric 
6035f757f3fSDimitry Andric   pushAPSInt(S, Result);
6045f757f3fSDimitry Andric   return true;
6055f757f3fSDimitry Andric }
6065f757f3fSDimitry Andric 
6075f757f3fSDimitry Andric static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC,
6085f757f3fSDimitry Andric                                 const InterpFrame *Frame, const Function *Func,
6095f757f3fSDimitry Andric                                 const CallExpr *Call) {
6105f757f3fSDimitry Andric   PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
6115f757f3fSDimitry Andric   APSInt Value = peekToAPSInt(S.Stk, ArgT);
6125f757f3fSDimitry Andric 
6135f757f3fSDimitry Andric   uint64_t N = Value.countr_zero();
6145f757f3fSDimitry Andric   pushInt(S, N == Value.getBitWidth() ? 0 : N + 1);
6155f757f3fSDimitry Andric   return true;
6165f757f3fSDimitry Andric }
6175f757f3fSDimitry Andric 
618*297eecfbSDimitry Andric static bool interp__builtin_addressof(InterpState &S, CodePtr OpPC,
619*297eecfbSDimitry Andric                                       const InterpFrame *Frame,
620*297eecfbSDimitry Andric                                       const Function *Func,
621*297eecfbSDimitry Andric                                       const CallExpr *Call) {
622*297eecfbSDimitry Andric   PrimType PtrT =
623*297eecfbSDimitry Andric       S.getContext().classify(Call->getArg(0)->getType()).value_or(PT_Ptr);
624*297eecfbSDimitry Andric 
625*297eecfbSDimitry Andric   if (PtrT == PT_FnPtr) {
626*297eecfbSDimitry Andric     const FunctionPointer &Arg = S.Stk.peek<FunctionPointer>();
627*297eecfbSDimitry Andric     S.Stk.push<FunctionPointer>(Arg);
628*297eecfbSDimitry Andric   } else if (PtrT == PT_Ptr) {
629*297eecfbSDimitry Andric     const Pointer &Arg = S.Stk.peek<Pointer>();
630*297eecfbSDimitry Andric     S.Stk.push<Pointer>(Arg);
631*297eecfbSDimitry Andric   } else {
632*297eecfbSDimitry Andric     assert(false && "Unsupported pointer type passed to __builtin_addressof()");
633*297eecfbSDimitry Andric   }
634*297eecfbSDimitry Andric   return true;
635*297eecfbSDimitry Andric }
636*297eecfbSDimitry Andric 
6375f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
6385f757f3fSDimitry Andric                       const CallExpr *Call) {
63906c3fb27SDimitry Andric   InterpFrame *Frame = S.Current;
64006c3fb27SDimitry Andric   APValue Dummy;
64106c3fb27SDimitry Andric 
642*297eecfbSDimitry Andric   std::optional<PrimType> ReturnT = S.getContext().classify(Call->getType());
643*297eecfbSDimitry Andric 
6445f757f3fSDimitry Andric   // If classify failed, we assume void.
645*297eecfbSDimitry Andric   assert(ReturnT || Call->getType()->isVoidType());
6465f757f3fSDimitry Andric 
64706c3fb27SDimitry Andric   switch (F->getBuiltinID()) {
64806c3fb27SDimitry Andric   case Builtin::BI__builtin_is_constant_evaluated:
64906c3fb27SDimitry Andric     S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
6505f757f3fSDimitry Andric     break;
65106c3fb27SDimitry Andric   case Builtin::BI__builtin_assume:
6525f757f3fSDimitry Andric     break;
65306c3fb27SDimitry Andric   case Builtin::BI__builtin_strcmp:
6545f757f3fSDimitry Andric     if (!interp__builtin_strcmp(S, OpPC, Frame))
65506c3fb27SDimitry Andric       return false;
6565f757f3fSDimitry Andric     break;
6575f757f3fSDimitry Andric   case Builtin::BI__builtin_strlen:
6585f757f3fSDimitry Andric     if (!interp__builtin_strlen(S, OpPC, Frame))
6595f757f3fSDimitry Andric       return false;
6605f757f3fSDimitry Andric     break;
6615f757f3fSDimitry Andric   case Builtin::BI__builtin_nan:
6625f757f3fSDimitry Andric   case Builtin::BI__builtin_nanf:
6635f757f3fSDimitry Andric   case Builtin::BI__builtin_nanl:
6645f757f3fSDimitry Andric   case Builtin::BI__builtin_nanf16:
6655f757f3fSDimitry Andric   case Builtin::BI__builtin_nanf128:
6665f757f3fSDimitry Andric     if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
6675f757f3fSDimitry Andric       return false;
6685f757f3fSDimitry Andric     break;
6695f757f3fSDimitry Andric   case Builtin::BI__builtin_nans:
6705f757f3fSDimitry Andric   case Builtin::BI__builtin_nansf:
6715f757f3fSDimitry Andric   case Builtin::BI__builtin_nansl:
6725f757f3fSDimitry Andric   case Builtin::BI__builtin_nansf16:
6735f757f3fSDimitry Andric   case Builtin::BI__builtin_nansf128:
6745f757f3fSDimitry Andric     if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
6755f757f3fSDimitry Andric       return false;
6765f757f3fSDimitry Andric     break;
6775f757f3fSDimitry Andric 
6785f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_val:
6795f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_valf:
6805f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_vall:
6815f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_valf16:
6825f757f3fSDimitry Andric   case Builtin::BI__builtin_huge_valf128:
6835f757f3fSDimitry Andric   case Builtin::BI__builtin_inf:
6845f757f3fSDimitry Andric   case Builtin::BI__builtin_inff:
6855f757f3fSDimitry Andric   case Builtin::BI__builtin_infl:
6865f757f3fSDimitry Andric   case Builtin::BI__builtin_inff16:
6875f757f3fSDimitry Andric   case Builtin::BI__builtin_inff128:
6885f757f3fSDimitry Andric     if (!interp__builtin_inf(S, OpPC, Frame, F))
6895f757f3fSDimitry Andric       return false;
6905f757f3fSDimitry Andric     break;
6915f757f3fSDimitry Andric   case Builtin::BI__builtin_copysign:
6925f757f3fSDimitry Andric   case Builtin::BI__builtin_copysignf:
6935f757f3fSDimitry Andric   case Builtin::BI__builtin_copysignl:
6945f757f3fSDimitry Andric   case Builtin::BI__builtin_copysignf128:
6955f757f3fSDimitry Andric     if (!interp__builtin_copysign(S, OpPC, Frame, F))
6965f757f3fSDimitry Andric       return false;
6975f757f3fSDimitry Andric     break;
6985f757f3fSDimitry Andric 
6995f757f3fSDimitry Andric   case Builtin::BI__builtin_fmin:
7005f757f3fSDimitry Andric   case Builtin::BI__builtin_fminf:
7015f757f3fSDimitry Andric   case Builtin::BI__builtin_fminl:
7025f757f3fSDimitry Andric   case Builtin::BI__builtin_fminf16:
7035f757f3fSDimitry Andric   case Builtin::BI__builtin_fminf128:
7045f757f3fSDimitry Andric     if (!interp__builtin_fmin(S, OpPC, Frame, F))
7055f757f3fSDimitry Andric       return false;
7065f757f3fSDimitry Andric     break;
7075f757f3fSDimitry Andric 
7085f757f3fSDimitry Andric   case Builtin::BI__builtin_fmax:
7095f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxf:
7105f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxl:
7115f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxf16:
7125f757f3fSDimitry Andric   case Builtin::BI__builtin_fmaxf128:
7135f757f3fSDimitry Andric     if (!interp__builtin_fmax(S, OpPC, Frame, F))
7145f757f3fSDimitry Andric       return false;
7155f757f3fSDimitry Andric     break;
7165f757f3fSDimitry Andric 
7175f757f3fSDimitry Andric   case Builtin::BI__builtin_isnan:
7185f757f3fSDimitry Andric     if (!interp__builtin_isnan(S, OpPC, Frame, F))
7195f757f3fSDimitry Andric       return false;
7205f757f3fSDimitry Andric     break;
7215f757f3fSDimitry Andric   case Builtin::BI__builtin_issignaling:
7225f757f3fSDimitry Andric     if (!interp__builtin_issignaling(S, OpPC, Frame, F))
7235f757f3fSDimitry Andric       return false;
7245f757f3fSDimitry Andric     break;
7255f757f3fSDimitry Andric 
7265f757f3fSDimitry Andric   case Builtin::BI__builtin_isinf:
7275f757f3fSDimitry Andric     if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
7285f757f3fSDimitry Andric       return false;
7295f757f3fSDimitry Andric     break;
7305f757f3fSDimitry Andric 
7315f757f3fSDimitry Andric   case Builtin::BI__builtin_isinf_sign:
7325f757f3fSDimitry Andric     if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true))
7335f757f3fSDimitry Andric       return false;
7345f757f3fSDimitry Andric     break;
7355f757f3fSDimitry Andric 
7365f757f3fSDimitry Andric   case Builtin::BI__builtin_isfinite:
7375f757f3fSDimitry Andric     if (!interp__builtin_isfinite(S, OpPC, Frame, F))
7385f757f3fSDimitry Andric       return false;
7395f757f3fSDimitry Andric     break;
7405f757f3fSDimitry Andric   case Builtin::BI__builtin_isnormal:
7415f757f3fSDimitry Andric     if (!interp__builtin_isnormal(S, OpPC, Frame, F))
7425f757f3fSDimitry Andric       return false;
7435f757f3fSDimitry Andric     break;
7445f757f3fSDimitry Andric   case Builtin::BI__builtin_issubnormal:
7455f757f3fSDimitry Andric     if (!interp__builtin_issubnormal(S, OpPC, Frame, F))
7465f757f3fSDimitry Andric       return false;
7475f757f3fSDimitry Andric     break;
7485f757f3fSDimitry Andric   case Builtin::BI__builtin_iszero:
7495f757f3fSDimitry Andric     if (!interp__builtin_iszero(S, OpPC, Frame, F))
7505f757f3fSDimitry Andric       return false;
7515f757f3fSDimitry Andric     break;
7525f757f3fSDimitry Andric   case Builtin::BI__builtin_isfpclass:
7535f757f3fSDimitry Andric     if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
7545f757f3fSDimitry Andric       return false;
7555f757f3fSDimitry Andric     break;
7565f757f3fSDimitry Andric   case Builtin::BI__builtin_fpclassify:
7575f757f3fSDimitry Andric     if (!interp__builtin_fpclassify(S, OpPC, Frame, F))
7585f757f3fSDimitry Andric       return false;
7595f757f3fSDimitry Andric     break;
7605f757f3fSDimitry Andric 
7615f757f3fSDimitry Andric   case Builtin::BI__builtin_fabs:
7625f757f3fSDimitry Andric   case Builtin::BI__builtin_fabsf:
7635f757f3fSDimitry Andric   case Builtin::BI__builtin_fabsl:
7645f757f3fSDimitry Andric   case Builtin::BI__builtin_fabsf128:
7655f757f3fSDimitry Andric     if (!interp__builtin_fabs(S, OpPC, Frame, F))
7665f757f3fSDimitry Andric       return false;
7675f757f3fSDimitry Andric     break;
7685f757f3fSDimitry Andric 
7695f757f3fSDimitry Andric   case Builtin::BI__builtin_popcount:
7705f757f3fSDimitry Andric   case Builtin::BI__builtin_popcountl:
7715f757f3fSDimitry Andric   case Builtin::BI__builtin_popcountll:
7725f757f3fSDimitry Andric   case Builtin::BI__popcnt16: // Microsoft variants of popcount
7735f757f3fSDimitry Andric   case Builtin::BI__popcnt:
7745f757f3fSDimitry Andric   case Builtin::BI__popcnt64:
7755f757f3fSDimitry Andric     if (!interp__builtin_popcount(S, OpPC, Frame, F, Call))
7765f757f3fSDimitry Andric       return false;
7775f757f3fSDimitry Andric     break;
7785f757f3fSDimitry Andric 
7795f757f3fSDimitry Andric   case Builtin::BI__builtin_parity:
7805f757f3fSDimitry Andric   case Builtin::BI__builtin_parityl:
7815f757f3fSDimitry Andric   case Builtin::BI__builtin_parityll:
7825f757f3fSDimitry Andric     if (!interp__builtin_parity(S, OpPC, Frame, F, Call))
7835f757f3fSDimitry Andric       return false;
7845f757f3fSDimitry Andric     break;
7855f757f3fSDimitry Andric 
7865f757f3fSDimitry Andric   case Builtin::BI__builtin_clrsb:
7875f757f3fSDimitry Andric   case Builtin::BI__builtin_clrsbl:
7885f757f3fSDimitry Andric   case Builtin::BI__builtin_clrsbll:
7895f757f3fSDimitry Andric     if (!interp__builtin_clrsb(S, OpPC, Frame, F, Call))
7905f757f3fSDimitry Andric       return false;
7915f757f3fSDimitry Andric     break;
7925f757f3fSDimitry Andric 
7935f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse8:
7945f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse16:
7955f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse32:
7965f757f3fSDimitry Andric   case Builtin::BI__builtin_bitreverse64:
7975f757f3fSDimitry Andric     if (!interp__builtin_bitreverse(S, OpPC, Frame, F, Call))
7985f757f3fSDimitry Andric       return false;
7995f757f3fSDimitry Andric     break;
8005f757f3fSDimitry Andric 
8015f757f3fSDimitry Andric   case Builtin::BI__builtin_classify_type:
8025f757f3fSDimitry Andric     if (!interp__builtin_classify_type(S, OpPC, Frame, F, Call))
8035f757f3fSDimitry Andric       return false;
8045f757f3fSDimitry Andric     break;
8055f757f3fSDimitry Andric 
8065f757f3fSDimitry Andric   case Builtin::BI__builtin_expect:
8075f757f3fSDimitry Andric   case Builtin::BI__builtin_expect_with_probability:
8085f757f3fSDimitry Andric     if (!interp__builtin_expect(S, OpPC, Frame, F, Call))
8095f757f3fSDimitry Andric       return false;
8105f757f3fSDimitry Andric     break;
8115f757f3fSDimitry Andric 
8125f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft8:
8135f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft16:
8145f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft32:
8155f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateleft64:
8165f757f3fSDimitry Andric   case Builtin::BI_rotl8: // Microsoft variants of rotate left
8175f757f3fSDimitry Andric   case Builtin::BI_rotl16:
8185f757f3fSDimitry Andric   case Builtin::BI_rotl:
8195f757f3fSDimitry Andric   case Builtin::BI_lrotl:
8205f757f3fSDimitry Andric   case Builtin::BI_rotl64:
8215f757f3fSDimitry Andric     if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/false))
8225f757f3fSDimitry Andric       return false;
8235f757f3fSDimitry Andric     break;
8245f757f3fSDimitry Andric 
8255f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright8:
8265f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright16:
8275f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright32:
8285f757f3fSDimitry Andric   case Builtin::BI__builtin_rotateright64:
8295f757f3fSDimitry Andric   case Builtin::BI_rotr8: // Microsoft variants of rotate right
8305f757f3fSDimitry Andric   case Builtin::BI_rotr16:
8315f757f3fSDimitry Andric   case Builtin::BI_rotr:
8325f757f3fSDimitry Andric   case Builtin::BI_lrotr:
8335f757f3fSDimitry Andric   case Builtin::BI_rotr64:
8345f757f3fSDimitry Andric     if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/true))
8355f757f3fSDimitry Andric       return false;
8365f757f3fSDimitry Andric     break;
8375f757f3fSDimitry Andric 
8385f757f3fSDimitry Andric   case Builtin::BI__builtin_ffs:
8395f757f3fSDimitry Andric   case Builtin::BI__builtin_ffsl:
8405f757f3fSDimitry Andric   case Builtin::BI__builtin_ffsll:
8415f757f3fSDimitry Andric     if (!interp__builtin_ffs(S, OpPC, Frame, F, Call))
8425f757f3fSDimitry Andric       return false;
8435f757f3fSDimitry Andric     break;
844*297eecfbSDimitry Andric   case Builtin::BIaddressof:
845*297eecfbSDimitry Andric   case Builtin::BI__addressof:
846*297eecfbSDimitry Andric   case Builtin::BI__builtin_addressof:
847*297eecfbSDimitry Andric     if (!interp__builtin_addressof(S, OpPC, Frame, F, Call))
848*297eecfbSDimitry Andric       return false;
849*297eecfbSDimitry Andric     break;
8505f757f3fSDimitry Andric 
85106c3fb27SDimitry Andric   default:
85206c3fb27SDimitry Andric     return false;
85306c3fb27SDimitry Andric   }
85406c3fb27SDimitry Andric 
8555f757f3fSDimitry Andric   return retPrimValue(S, OpPC, Dummy, ReturnT);
8565f757f3fSDimitry Andric }
8575f757f3fSDimitry Andric 
8585f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
8595f757f3fSDimitry Andric                        llvm::ArrayRef<int64_t> ArrayIndices,
8605f757f3fSDimitry Andric                        int64_t &IntResult) {
8615f757f3fSDimitry Andric   CharUnits Result;
8625f757f3fSDimitry Andric   unsigned N = E->getNumComponents();
8635f757f3fSDimitry Andric   assert(N > 0);
8645f757f3fSDimitry Andric 
8655f757f3fSDimitry Andric   unsigned ArrayIndex = 0;
8665f757f3fSDimitry Andric   QualType CurrentType = E->getTypeSourceInfo()->getType();
8675f757f3fSDimitry Andric   for (unsigned I = 0; I != N; ++I) {
8685f757f3fSDimitry Andric     const OffsetOfNode &Node = E->getComponent(I);
8695f757f3fSDimitry Andric     switch (Node.getKind()) {
8705f757f3fSDimitry Andric     case OffsetOfNode::Field: {
8715f757f3fSDimitry Andric       const FieldDecl *MemberDecl = Node.getField();
8725f757f3fSDimitry Andric       const RecordType *RT = CurrentType->getAs<RecordType>();
8735f757f3fSDimitry Andric       if (!RT)
87406c3fb27SDimitry Andric         return false;
8755f757f3fSDimitry Andric       RecordDecl *RD = RT->getDecl();
8765f757f3fSDimitry Andric       if (RD->isInvalidDecl())
8775f757f3fSDimitry Andric         return false;
8785f757f3fSDimitry Andric       const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
8795f757f3fSDimitry Andric       unsigned FieldIndex = MemberDecl->getFieldIndex();
8805f757f3fSDimitry Andric       assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type");
8815f757f3fSDimitry Andric       Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex));
8825f757f3fSDimitry Andric       CurrentType = MemberDecl->getType().getNonReferenceType();
8835f757f3fSDimitry Andric       break;
8845f757f3fSDimitry Andric     }
8855f757f3fSDimitry Andric     case OffsetOfNode::Array: {
8865f757f3fSDimitry Andric       // When generating bytecode, we put all the index expressions as Sint64 on
8875f757f3fSDimitry Andric       // the stack.
8885f757f3fSDimitry Andric       int64_t Index = ArrayIndices[ArrayIndex];
8895f757f3fSDimitry Andric       const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType);
8905f757f3fSDimitry Andric       if (!AT)
8915f757f3fSDimitry Andric         return false;
8925f757f3fSDimitry Andric       CurrentType = AT->getElementType();
8935f757f3fSDimitry Andric       CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType);
8945f757f3fSDimitry Andric       Result += Index * ElementSize;
8955f757f3fSDimitry Andric       ++ArrayIndex;
8965f757f3fSDimitry Andric       break;
8975f757f3fSDimitry Andric     }
8985f757f3fSDimitry Andric     case OffsetOfNode::Base: {
8995f757f3fSDimitry Andric       const CXXBaseSpecifier *BaseSpec = Node.getBase();
9005f757f3fSDimitry Andric       if (BaseSpec->isVirtual())
9015f757f3fSDimitry Andric         return false;
9025f757f3fSDimitry Andric 
9035f757f3fSDimitry Andric       // Find the layout of the class whose base we are looking into.
9045f757f3fSDimitry Andric       const RecordType *RT = CurrentType->getAs<RecordType>();
9055f757f3fSDimitry Andric       if (!RT)
9065f757f3fSDimitry Andric         return false;
9075f757f3fSDimitry Andric       const RecordDecl *RD = RT->getDecl();
9085f757f3fSDimitry Andric       if (RD->isInvalidDecl())
9095f757f3fSDimitry Andric         return false;
9105f757f3fSDimitry Andric       const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
9115f757f3fSDimitry Andric 
9125f757f3fSDimitry Andric       // Find the base class itself.
9135f757f3fSDimitry Andric       CurrentType = BaseSpec->getType();
9145f757f3fSDimitry Andric       const RecordType *BaseRT = CurrentType->getAs<RecordType>();
9155f757f3fSDimitry Andric       if (!BaseRT)
9165f757f3fSDimitry Andric         return false;
9175f757f3fSDimitry Andric 
9185f757f3fSDimitry Andric       // Add the offset to the base.
9195f757f3fSDimitry Andric       Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()));
9205f757f3fSDimitry Andric       break;
9215f757f3fSDimitry Andric     }
9225f757f3fSDimitry Andric     case OffsetOfNode::Identifier:
9235f757f3fSDimitry Andric       llvm_unreachable("Dependent OffsetOfExpr?");
9245f757f3fSDimitry Andric     }
9255f757f3fSDimitry Andric   }
9265f757f3fSDimitry Andric 
9275f757f3fSDimitry Andric   IntResult = Result.getQuantity();
9285f757f3fSDimitry Andric 
9295f757f3fSDimitry Andric   return true;
9305f757f3fSDimitry Andric }
9315f757f3fSDimitry Andric 
9325f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
9335f757f3fSDimitry Andric                                 const Pointer &Ptr, const APSInt &IntValue) {
9345f757f3fSDimitry Andric 
9355f757f3fSDimitry Andric   const Record *R = Ptr.getRecord();
9365f757f3fSDimitry Andric   assert(R);
9375f757f3fSDimitry Andric   assert(R->getNumFields() == 1);
9385f757f3fSDimitry Andric 
9395f757f3fSDimitry Andric   unsigned FieldOffset = R->getField(0u)->Offset;
9405f757f3fSDimitry Andric   const Pointer &FieldPtr = Ptr.atField(FieldOffset);
9415f757f3fSDimitry Andric   PrimType FieldT = *S.getContext().classify(FieldPtr.getType());
9425f757f3fSDimitry Andric 
9435f757f3fSDimitry Andric   INT_TYPE_SWITCH(FieldT,
9445f757f3fSDimitry Andric                   FieldPtr.deref<T>() = T::from(IntValue.getSExtValue()));
9455f757f3fSDimitry Andric   FieldPtr.initialize();
9465f757f3fSDimitry Andric   return true;
94706c3fb27SDimitry Andric }
94806c3fb27SDimitry Andric 
94906c3fb27SDimitry Andric } // namespace interp
95006c3fb27SDimitry Andric } // namespace clang
951