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