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