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 //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric #include "../ExprConstShared.h" 906c3fb27SDimitry Andric #include "Boolean.h" 1006c3fb27SDimitry Andric #include "Interp.h" 1106c3fb27SDimitry Andric #include "PrimType.h" 12*5f757f3fSDimitry Andric #include "clang/AST/RecordLayout.h" 1306c3fb27SDimitry Andric #include "clang/Basic/Builtins.h" 14*5f757f3fSDimitry Andric #include "clang/Basic/TargetInfo.h" 1506c3fb27SDimitry Andric 1606c3fb27SDimitry Andric namespace clang { 1706c3fb27SDimitry Andric namespace interp { 1806c3fb27SDimitry Andric 19*5f757f3fSDimitry Andric template <typename T> 20*5f757f3fSDimitry Andric static T getParam(const InterpFrame *Frame, unsigned Index) { 21*5f757f3fSDimitry Andric assert(Frame->getFunction()->getNumParams() > Index); 2206c3fb27SDimitry Andric unsigned Offset = Frame->getFunction()->getParamOffset(Index); 2306c3fb27SDimitry Andric return Frame->getParam<T>(Offset); 2406c3fb27SDimitry Andric } 2506c3fb27SDimitry Andric 26*5f757f3fSDimitry Andric PrimType getIntPrimType(const InterpState &S) { 27*5f757f3fSDimitry Andric const TargetInfo &TI = S.getCtx().getTargetInfo(); 28*5f757f3fSDimitry Andric unsigned IntWidth = TI.getIntWidth(); 29*5f757f3fSDimitry Andric 30*5f757f3fSDimitry Andric if (IntWidth == 32) 31*5f757f3fSDimitry Andric return PT_Sint32; 32*5f757f3fSDimitry Andric else if (IntWidth == 16) 33*5f757f3fSDimitry Andric return PT_Sint16; 34*5f757f3fSDimitry Andric llvm_unreachable("Int isn't 16 or 32 bit?"); 35*5f757f3fSDimitry Andric } 36*5f757f3fSDimitry Andric 37*5f757f3fSDimitry Andric PrimType getLongPrimType(const InterpState &S) { 38*5f757f3fSDimitry Andric const TargetInfo &TI = S.getCtx().getTargetInfo(); 39*5f757f3fSDimitry Andric unsigned LongWidth = TI.getLongWidth(); 40*5f757f3fSDimitry Andric 41*5f757f3fSDimitry Andric if (LongWidth == 64) 42*5f757f3fSDimitry Andric return PT_Sint64; 43*5f757f3fSDimitry Andric else if (LongWidth == 32) 44*5f757f3fSDimitry Andric return PT_Sint32; 45*5f757f3fSDimitry Andric else if (LongWidth == 16) 46*5f757f3fSDimitry Andric return PT_Sint16; 47*5f757f3fSDimitry Andric llvm_unreachable("long isn't 16, 32 or 64 bit?"); 48*5f757f3fSDimitry Andric } 49*5f757f3fSDimitry Andric 50*5f757f3fSDimitry Andric /// Peek an integer value from the stack into an APSInt. 51*5f757f3fSDimitry Andric static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) { 52*5f757f3fSDimitry Andric if (Offset == 0) 53*5f757f3fSDimitry Andric Offset = align(primSize(T)); 54*5f757f3fSDimitry Andric 55*5f757f3fSDimitry Andric APSInt R; 56*5f757f3fSDimitry Andric INT_TYPE_SWITCH(T, { 57*5f757f3fSDimitry Andric T Val = Stk.peek<T>(Offset); 58*5f757f3fSDimitry Andric R = APSInt( 59*5f757f3fSDimitry Andric APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned())); 60*5f757f3fSDimitry Andric }); 61*5f757f3fSDimitry Andric 62*5f757f3fSDimitry Andric return R; 63*5f757f3fSDimitry Andric } 64*5f757f3fSDimitry Andric 65*5f757f3fSDimitry Andric /// Pushes \p Val to the stack, as a target-dependent 'int'. 66*5f757f3fSDimitry Andric static void pushInt(InterpState &S, int32_t Val) { 67*5f757f3fSDimitry Andric PrimType IntType = getIntPrimType(S); 68*5f757f3fSDimitry Andric if (IntType == PT_Sint32) 69*5f757f3fSDimitry Andric S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val)); 70*5f757f3fSDimitry Andric else if (IntType == PT_Sint16) 71*5f757f3fSDimitry Andric S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val)); 72*5f757f3fSDimitry Andric else 73*5f757f3fSDimitry Andric llvm_unreachable("Int isn't 16 or 32 bit?"); 74*5f757f3fSDimitry Andric } 75*5f757f3fSDimitry Andric 76*5f757f3fSDimitry Andric static void pushAPSInt(InterpState &S, const APSInt &Val) { 77*5f757f3fSDimitry Andric bool Signed = Val.isSigned(); 78*5f757f3fSDimitry Andric 79*5f757f3fSDimitry Andric if (Signed) { 80*5f757f3fSDimitry Andric switch (Val.getBitWidth()) { 81*5f757f3fSDimitry Andric case 64: 82*5f757f3fSDimitry Andric S.Stk.push<Integral<64, true>>( 83*5f757f3fSDimitry Andric Integral<64, true>::from(Val.getSExtValue())); 84*5f757f3fSDimitry Andric break; 85*5f757f3fSDimitry Andric case 32: 86*5f757f3fSDimitry Andric S.Stk.push<Integral<32, true>>( 87*5f757f3fSDimitry Andric Integral<32, true>::from(Val.getSExtValue())); 88*5f757f3fSDimitry Andric break; 89*5f757f3fSDimitry Andric case 16: 90*5f757f3fSDimitry Andric S.Stk.push<Integral<16, true>>( 91*5f757f3fSDimitry Andric Integral<16, true>::from(Val.getSExtValue())); 92*5f757f3fSDimitry Andric break; 93*5f757f3fSDimitry Andric case 8: 94*5f757f3fSDimitry Andric S.Stk.push<Integral<8, true>>( 95*5f757f3fSDimitry Andric Integral<8, true>::from(Val.getSExtValue())); 96*5f757f3fSDimitry Andric break; 97*5f757f3fSDimitry Andric default: 98*5f757f3fSDimitry Andric llvm_unreachable("Invalid integer bitwidth"); 99*5f757f3fSDimitry Andric } 100*5f757f3fSDimitry Andric return; 101*5f757f3fSDimitry Andric } 102*5f757f3fSDimitry Andric 103*5f757f3fSDimitry Andric // Unsigned. 104*5f757f3fSDimitry Andric switch (Val.getBitWidth()) { 105*5f757f3fSDimitry Andric case 64: 106*5f757f3fSDimitry Andric S.Stk.push<Integral<64, false>>( 107*5f757f3fSDimitry Andric Integral<64, false>::from(Val.getZExtValue())); 108*5f757f3fSDimitry Andric break; 109*5f757f3fSDimitry Andric case 32: 110*5f757f3fSDimitry Andric S.Stk.push<Integral<32, false>>( 111*5f757f3fSDimitry Andric Integral<32, false>::from(Val.getZExtValue())); 112*5f757f3fSDimitry Andric break; 113*5f757f3fSDimitry Andric case 16: 114*5f757f3fSDimitry Andric S.Stk.push<Integral<16, false>>( 115*5f757f3fSDimitry Andric Integral<16, false>::from(Val.getZExtValue())); 116*5f757f3fSDimitry Andric break; 117*5f757f3fSDimitry Andric case 8: 118*5f757f3fSDimitry Andric S.Stk.push<Integral<8, false>>( 119*5f757f3fSDimitry Andric Integral<8, false>::from(Val.getZExtValue())); 120*5f757f3fSDimitry Andric break; 121*5f757f3fSDimitry Andric default: 122*5f757f3fSDimitry Andric llvm_unreachable("Invalid integer bitwidth"); 123*5f757f3fSDimitry Andric } 124*5f757f3fSDimitry Andric } 125*5f757f3fSDimitry Andric 126*5f757f3fSDimitry Andric /// Pushes \p Val to the stack, as a target-dependent 'long'. 127*5f757f3fSDimitry Andric static void pushLong(InterpState &S, int64_t Val) { 128*5f757f3fSDimitry Andric PrimType LongType = getLongPrimType(S); 129*5f757f3fSDimitry Andric if (LongType == PT_Sint64) 130*5f757f3fSDimitry Andric S.Stk.push<Integral<64, true>>(Integral<64, true>::from(Val)); 131*5f757f3fSDimitry Andric else if (LongType == PT_Sint32) 132*5f757f3fSDimitry Andric S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val)); 133*5f757f3fSDimitry Andric else if (LongType == PT_Sint16) 134*5f757f3fSDimitry Andric S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val)); 135*5f757f3fSDimitry Andric else 136*5f757f3fSDimitry Andric llvm_unreachable("Long isn't 16, 32 or 64 bit?"); 137*5f757f3fSDimitry Andric } 138*5f757f3fSDimitry Andric 139*5f757f3fSDimitry Andric static void pushSizeT(InterpState &S, uint64_t Val) { 140*5f757f3fSDimitry Andric const TargetInfo &TI = S.getCtx().getTargetInfo(); 141*5f757f3fSDimitry Andric unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType()); 142*5f757f3fSDimitry Andric 143*5f757f3fSDimitry Andric switch (SizeTWidth) { 144*5f757f3fSDimitry Andric case 64: 145*5f757f3fSDimitry Andric S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Val)); 146*5f757f3fSDimitry Andric break; 147*5f757f3fSDimitry Andric case 32: 148*5f757f3fSDimitry Andric S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Val)); 149*5f757f3fSDimitry Andric break; 150*5f757f3fSDimitry Andric case 16: 151*5f757f3fSDimitry Andric S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Val)); 152*5f757f3fSDimitry Andric break; 153*5f757f3fSDimitry Andric default: 154*5f757f3fSDimitry Andric llvm_unreachable("We don't handle this size_t size."); 155*5f757f3fSDimitry Andric } 156*5f757f3fSDimitry Andric } 157*5f757f3fSDimitry Andric 158*5f757f3fSDimitry Andric static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result, 159*5f757f3fSDimitry Andric std::optional<PrimType> &T) { 160*5f757f3fSDimitry Andric if (!T) 161*5f757f3fSDimitry Andric return RetVoid(S, OpPC, Result); 162*5f757f3fSDimitry Andric 163*5f757f3fSDimitry Andric #define RET_CASE(X) \ 164*5f757f3fSDimitry Andric case X: \ 165*5f757f3fSDimitry Andric return Ret<X>(S, OpPC, Result); 166*5f757f3fSDimitry Andric switch (*T) { 167*5f757f3fSDimitry Andric RET_CASE(PT_Float); 168*5f757f3fSDimitry Andric RET_CASE(PT_Bool); 169*5f757f3fSDimitry Andric RET_CASE(PT_Sint8); 170*5f757f3fSDimitry Andric RET_CASE(PT_Uint8); 171*5f757f3fSDimitry Andric RET_CASE(PT_Sint16); 172*5f757f3fSDimitry Andric RET_CASE(PT_Uint16); 173*5f757f3fSDimitry Andric RET_CASE(PT_Sint32); 174*5f757f3fSDimitry Andric RET_CASE(PT_Uint32); 175*5f757f3fSDimitry Andric RET_CASE(PT_Sint64); 176*5f757f3fSDimitry Andric RET_CASE(PT_Uint64); 177*5f757f3fSDimitry Andric default: 178*5f757f3fSDimitry Andric llvm_unreachable("Unsupported return type for builtin function"); 179*5f757f3fSDimitry Andric } 180*5f757f3fSDimitry Andric #undef RET_CASE 181*5f757f3fSDimitry Andric } 182*5f757f3fSDimitry Andric 18306c3fb27SDimitry Andric static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, 184*5f757f3fSDimitry Andric const InterpFrame *Frame) { 18506c3fb27SDimitry Andric const Pointer &A = getParam<Pointer>(Frame, 0); 18606c3fb27SDimitry Andric const Pointer &B = getParam<Pointer>(Frame, 1); 18706c3fb27SDimitry Andric 18806c3fb27SDimitry Andric if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read)) 18906c3fb27SDimitry Andric return false; 19006c3fb27SDimitry Andric 19106c3fb27SDimitry Andric assert(A.getFieldDesc()->isPrimitiveArray()); 19206c3fb27SDimitry Andric assert(B.getFieldDesc()->isPrimitiveArray()); 19306c3fb27SDimitry Andric 19406c3fb27SDimitry Andric unsigned IndexA = A.getIndex(); 19506c3fb27SDimitry Andric unsigned IndexB = B.getIndex(); 19606c3fb27SDimitry Andric int32_t Result = 0; 19706c3fb27SDimitry Andric for (;; ++IndexA, ++IndexB) { 19806c3fb27SDimitry Andric const Pointer &PA = A.atIndex(IndexA); 19906c3fb27SDimitry Andric const Pointer &PB = B.atIndex(IndexB); 20006c3fb27SDimitry Andric if (!CheckRange(S, OpPC, PA, AK_Read) || 20106c3fb27SDimitry Andric !CheckRange(S, OpPC, PB, AK_Read)) { 20206c3fb27SDimitry Andric return false; 20306c3fb27SDimitry Andric } 20406c3fb27SDimitry Andric uint8_t CA = PA.deref<uint8_t>(); 20506c3fb27SDimitry Andric uint8_t CB = PB.deref<uint8_t>(); 20606c3fb27SDimitry Andric 20706c3fb27SDimitry Andric if (CA > CB) { 20806c3fb27SDimitry Andric Result = 1; 20906c3fb27SDimitry Andric break; 21006c3fb27SDimitry Andric } else if (CA < CB) { 21106c3fb27SDimitry Andric Result = -1; 21206c3fb27SDimitry Andric break; 21306c3fb27SDimitry Andric } 21406c3fb27SDimitry Andric if (CA == 0 || CB == 0) 21506c3fb27SDimitry Andric break; 21606c3fb27SDimitry Andric } 21706c3fb27SDimitry Andric 218*5f757f3fSDimitry Andric pushInt(S, Result); 21906c3fb27SDimitry Andric return true; 22006c3fb27SDimitry Andric } 22106c3fb27SDimitry Andric 222*5f757f3fSDimitry Andric static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, 223*5f757f3fSDimitry Andric const InterpFrame *Frame) { 224*5f757f3fSDimitry Andric const Pointer &StrPtr = getParam<Pointer>(Frame, 0); 225*5f757f3fSDimitry Andric 226*5f757f3fSDimitry Andric if (!CheckArray(S, OpPC, StrPtr)) 227*5f757f3fSDimitry Andric return false; 228*5f757f3fSDimitry Andric 229*5f757f3fSDimitry Andric if (!CheckLive(S, OpPC, StrPtr, AK_Read)) 230*5f757f3fSDimitry Andric return false; 231*5f757f3fSDimitry Andric 232*5f757f3fSDimitry Andric if (!CheckDummy(S, OpPC, StrPtr)) 233*5f757f3fSDimitry Andric return false; 234*5f757f3fSDimitry Andric 235*5f757f3fSDimitry Andric assert(StrPtr.getFieldDesc()->isPrimitiveArray()); 236*5f757f3fSDimitry Andric 237*5f757f3fSDimitry Andric size_t Len = 0; 238*5f757f3fSDimitry Andric for (size_t I = StrPtr.getIndex();; ++I, ++Len) { 239*5f757f3fSDimitry Andric const Pointer &ElemPtr = StrPtr.atIndex(I); 240*5f757f3fSDimitry Andric 241*5f757f3fSDimitry Andric if (!CheckRange(S, OpPC, ElemPtr, AK_Read)) 242*5f757f3fSDimitry Andric return false; 243*5f757f3fSDimitry Andric 244*5f757f3fSDimitry Andric uint8_t Val = ElemPtr.deref<uint8_t>(); 245*5f757f3fSDimitry Andric if (Val == 0) 246*5f757f3fSDimitry Andric break; 247*5f757f3fSDimitry Andric } 248*5f757f3fSDimitry Andric 249*5f757f3fSDimitry Andric pushSizeT(S, Len); 250*5f757f3fSDimitry Andric return true; 251*5f757f3fSDimitry Andric } 252*5f757f3fSDimitry Andric 253*5f757f3fSDimitry Andric static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, 254*5f757f3fSDimitry Andric const InterpFrame *Frame, const Function *F, 255*5f757f3fSDimitry Andric bool Signaling) { 256*5f757f3fSDimitry Andric const Pointer &Arg = getParam<Pointer>(Frame, 0); 257*5f757f3fSDimitry Andric 258*5f757f3fSDimitry Andric if (!CheckLoad(S, OpPC, Arg)) 259*5f757f3fSDimitry Andric return false; 260*5f757f3fSDimitry Andric 261*5f757f3fSDimitry Andric assert(Arg.getFieldDesc()->isPrimitiveArray()); 262*5f757f3fSDimitry Andric 263*5f757f3fSDimitry Andric // Convert the given string to an integer using StringRef's API. 264*5f757f3fSDimitry Andric llvm::APInt Fill; 265*5f757f3fSDimitry Andric std::string Str; 266*5f757f3fSDimitry Andric assert(Arg.getNumElems() >= 1); 267*5f757f3fSDimitry Andric for (unsigned I = 0;; ++I) { 268*5f757f3fSDimitry Andric const Pointer &Elem = Arg.atIndex(I); 269*5f757f3fSDimitry Andric 270*5f757f3fSDimitry Andric if (!CheckLoad(S, OpPC, Elem)) 271*5f757f3fSDimitry Andric return false; 272*5f757f3fSDimitry Andric 273*5f757f3fSDimitry Andric if (Elem.deref<int8_t>() == 0) 274*5f757f3fSDimitry Andric break; 275*5f757f3fSDimitry Andric 276*5f757f3fSDimitry Andric Str += Elem.deref<char>(); 277*5f757f3fSDimitry Andric } 278*5f757f3fSDimitry Andric 279*5f757f3fSDimitry Andric // Treat empty strings as if they were zero. 280*5f757f3fSDimitry Andric if (Str.empty()) 281*5f757f3fSDimitry Andric Fill = llvm::APInt(32, 0); 282*5f757f3fSDimitry Andric else if (StringRef(Str).getAsInteger(0, Fill)) 283*5f757f3fSDimitry Andric return false; 284*5f757f3fSDimitry Andric 285*5f757f3fSDimitry Andric const llvm::fltSemantics &TargetSemantics = 286*5f757f3fSDimitry Andric S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType()); 287*5f757f3fSDimitry Andric 288*5f757f3fSDimitry Andric Floating Result; 289*5f757f3fSDimitry Andric if (S.getCtx().getTargetInfo().isNan2008()) { 290*5f757f3fSDimitry Andric if (Signaling) 291*5f757f3fSDimitry Andric Result = Floating( 292*5f757f3fSDimitry Andric llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); 293*5f757f3fSDimitry Andric else 294*5f757f3fSDimitry Andric Result = Floating( 295*5f757f3fSDimitry Andric llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); 296*5f757f3fSDimitry Andric } else { 297*5f757f3fSDimitry Andric // Prior to IEEE 754-2008, architectures were allowed to choose whether 298*5f757f3fSDimitry Andric // the first bit of their significand was set for qNaN or sNaN. MIPS chose 299*5f757f3fSDimitry Andric // a different encoding to what became a standard in 2008, and for pre- 300*5f757f3fSDimitry Andric // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as 301*5f757f3fSDimitry Andric // sNaN. This is now known as "legacy NaN" encoding. 302*5f757f3fSDimitry Andric if (Signaling) 303*5f757f3fSDimitry Andric Result = Floating( 304*5f757f3fSDimitry Andric llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); 305*5f757f3fSDimitry Andric else 306*5f757f3fSDimitry Andric Result = Floating( 307*5f757f3fSDimitry Andric llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); 308*5f757f3fSDimitry Andric } 309*5f757f3fSDimitry Andric 310*5f757f3fSDimitry Andric S.Stk.push<Floating>(Result); 311*5f757f3fSDimitry Andric return true; 312*5f757f3fSDimitry Andric } 313*5f757f3fSDimitry Andric 314*5f757f3fSDimitry Andric static bool interp__builtin_inf(InterpState &S, CodePtr OpPC, 315*5f757f3fSDimitry Andric const InterpFrame *Frame, const Function *F) { 316*5f757f3fSDimitry Andric const llvm::fltSemantics &TargetSemantics = 317*5f757f3fSDimitry Andric S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType()); 318*5f757f3fSDimitry Andric 319*5f757f3fSDimitry Andric S.Stk.push<Floating>(Floating::getInf(TargetSemantics)); 320*5f757f3fSDimitry Andric return true; 321*5f757f3fSDimitry Andric } 322*5f757f3fSDimitry Andric 323*5f757f3fSDimitry Andric static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, 324*5f757f3fSDimitry Andric const InterpFrame *Frame, 325*5f757f3fSDimitry Andric const Function *F) { 326*5f757f3fSDimitry Andric const Floating &Arg1 = getParam<Floating>(Frame, 0); 327*5f757f3fSDimitry Andric const Floating &Arg2 = getParam<Floating>(Frame, 1); 328*5f757f3fSDimitry Andric 329*5f757f3fSDimitry Andric APFloat Copy = Arg1.getAPFloat(); 330*5f757f3fSDimitry Andric Copy.copySign(Arg2.getAPFloat()); 331*5f757f3fSDimitry Andric S.Stk.push<Floating>(Floating(Copy)); 332*5f757f3fSDimitry Andric 333*5f757f3fSDimitry Andric return true; 334*5f757f3fSDimitry Andric } 335*5f757f3fSDimitry Andric 336*5f757f3fSDimitry Andric static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, 337*5f757f3fSDimitry Andric const InterpFrame *Frame, const Function *F) { 338*5f757f3fSDimitry Andric const Floating &LHS = getParam<Floating>(Frame, 0); 339*5f757f3fSDimitry Andric const Floating &RHS = getParam<Floating>(Frame, 1); 340*5f757f3fSDimitry Andric 341*5f757f3fSDimitry Andric Floating Result; 342*5f757f3fSDimitry Andric 343*5f757f3fSDimitry Andric // When comparing zeroes, return -0.0 if one of the zeroes is negative. 344*5f757f3fSDimitry Andric if (LHS.isZero() && RHS.isZero() && RHS.isNegative()) 345*5f757f3fSDimitry Andric Result = RHS; 346*5f757f3fSDimitry Andric else if (LHS.isNan() || RHS < LHS) 347*5f757f3fSDimitry Andric Result = RHS; 348*5f757f3fSDimitry Andric else 349*5f757f3fSDimitry Andric Result = LHS; 350*5f757f3fSDimitry Andric 351*5f757f3fSDimitry Andric S.Stk.push<Floating>(Result); 352*5f757f3fSDimitry Andric return true; 353*5f757f3fSDimitry Andric } 354*5f757f3fSDimitry Andric 355*5f757f3fSDimitry Andric static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, 356*5f757f3fSDimitry Andric const InterpFrame *Frame, 357*5f757f3fSDimitry Andric const Function *Func) { 358*5f757f3fSDimitry Andric const Floating &LHS = getParam<Floating>(Frame, 0); 359*5f757f3fSDimitry Andric const Floating &RHS = getParam<Floating>(Frame, 1); 360*5f757f3fSDimitry Andric 361*5f757f3fSDimitry Andric Floating Result; 362*5f757f3fSDimitry Andric 363*5f757f3fSDimitry Andric // When comparing zeroes, return +0.0 if one of the zeroes is positive. 364*5f757f3fSDimitry Andric if (LHS.isZero() && RHS.isZero() && LHS.isNegative()) 365*5f757f3fSDimitry Andric Result = RHS; 366*5f757f3fSDimitry Andric else if (LHS.isNan() || RHS > LHS) 367*5f757f3fSDimitry Andric Result = RHS; 368*5f757f3fSDimitry Andric else 369*5f757f3fSDimitry Andric Result = LHS; 370*5f757f3fSDimitry Andric 371*5f757f3fSDimitry Andric S.Stk.push<Floating>(Result); 372*5f757f3fSDimitry Andric return true; 373*5f757f3fSDimitry Andric } 374*5f757f3fSDimitry Andric 375*5f757f3fSDimitry Andric /// Defined as __builtin_isnan(...), to accommodate the fact that it can 376*5f757f3fSDimitry Andric /// take a float, double, long double, etc. 377*5f757f3fSDimitry Andric /// But for us, that's all a Floating anyway. 378*5f757f3fSDimitry Andric static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, 379*5f757f3fSDimitry Andric const InterpFrame *Frame, const Function *F) { 380*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 381*5f757f3fSDimitry Andric 382*5f757f3fSDimitry Andric pushInt(S, Arg.isNan()); 383*5f757f3fSDimitry Andric return true; 384*5f757f3fSDimitry Andric } 385*5f757f3fSDimitry Andric 386*5f757f3fSDimitry Andric static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC, 387*5f757f3fSDimitry Andric const InterpFrame *Frame, 388*5f757f3fSDimitry Andric const Function *F) { 389*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 390*5f757f3fSDimitry Andric 391*5f757f3fSDimitry Andric pushInt(S, Arg.isSignaling()); 392*5f757f3fSDimitry Andric return true; 393*5f757f3fSDimitry Andric } 394*5f757f3fSDimitry Andric 395*5f757f3fSDimitry Andric static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, 396*5f757f3fSDimitry Andric const InterpFrame *Frame, const Function *F, 397*5f757f3fSDimitry Andric bool CheckSign) { 398*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 399*5f757f3fSDimitry Andric bool IsInf = Arg.isInf(); 400*5f757f3fSDimitry Andric 401*5f757f3fSDimitry Andric if (CheckSign) 402*5f757f3fSDimitry Andric pushInt(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0); 403*5f757f3fSDimitry Andric else 404*5f757f3fSDimitry Andric pushInt(S, Arg.isInf()); 405*5f757f3fSDimitry Andric return true; 406*5f757f3fSDimitry Andric } 407*5f757f3fSDimitry Andric 408*5f757f3fSDimitry Andric static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC, 409*5f757f3fSDimitry Andric const InterpFrame *Frame, 410*5f757f3fSDimitry Andric const Function *F) { 411*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 412*5f757f3fSDimitry Andric 413*5f757f3fSDimitry Andric pushInt(S, Arg.isFinite()); 414*5f757f3fSDimitry Andric return true; 415*5f757f3fSDimitry Andric } 416*5f757f3fSDimitry Andric 417*5f757f3fSDimitry Andric static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC, 418*5f757f3fSDimitry Andric const InterpFrame *Frame, 419*5f757f3fSDimitry Andric const Function *F) { 420*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 421*5f757f3fSDimitry Andric 422*5f757f3fSDimitry Andric pushInt(S, Arg.isNormal()); 423*5f757f3fSDimitry Andric return true; 424*5f757f3fSDimitry Andric } 425*5f757f3fSDimitry Andric 426*5f757f3fSDimitry Andric static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC, 427*5f757f3fSDimitry Andric const InterpFrame *Frame, 428*5f757f3fSDimitry Andric const Function *F) { 429*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 430*5f757f3fSDimitry Andric 431*5f757f3fSDimitry Andric pushInt(S, Arg.isDenormal()); 432*5f757f3fSDimitry Andric return true; 433*5f757f3fSDimitry Andric } 434*5f757f3fSDimitry Andric 435*5f757f3fSDimitry Andric static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, 436*5f757f3fSDimitry Andric const InterpFrame *Frame, 437*5f757f3fSDimitry Andric const Function *F) { 438*5f757f3fSDimitry Andric const Floating &Arg = S.Stk.peek<Floating>(); 439*5f757f3fSDimitry Andric 440*5f757f3fSDimitry Andric pushInt(S, Arg.isZero()); 441*5f757f3fSDimitry Andric return true; 442*5f757f3fSDimitry Andric } 443*5f757f3fSDimitry Andric 444*5f757f3fSDimitry Andric /// First parameter to __builtin_isfpclass is the floating value, the 445*5f757f3fSDimitry Andric /// second one is an integral value. 446*5f757f3fSDimitry Andric static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, 447*5f757f3fSDimitry Andric const InterpFrame *Frame, 448*5f757f3fSDimitry Andric const Function *Func, 449*5f757f3fSDimitry Andric const CallExpr *Call) { 450*5f757f3fSDimitry Andric PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType()); 451*5f757f3fSDimitry Andric APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT); 452*5f757f3fSDimitry Andric const Floating &F = 453*5f757f3fSDimitry Andric S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float))); 454*5f757f3fSDimitry Andric 455*5f757f3fSDimitry Andric int32_t Result = 456*5f757f3fSDimitry Andric static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue()); 457*5f757f3fSDimitry Andric pushInt(S, Result); 458*5f757f3fSDimitry Andric 459*5f757f3fSDimitry Andric return true; 460*5f757f3fSDimitry Andric } 461*5f757f3fSDimitry Andric 462*5f757f3fSDimitry Andric /// Five int values followed by one floating value. 463*5f757f3fSDimitry Andric static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, 464*5f757f3fSDimitry Andric const InterpFrame *Frame, 465*5f757f3fSDimitry Andric const Function *Func) { 466*5f757f3fSDimitry Andric const Floating &Val = S.Stk.peek<Floating>(); 467*5f757f3fSDimitry Andric 468*5f757f3fSDimitry Andric unsigned Index; 469*5f757f3fSDimitry Andric switch (Val.getCategory()) { 470*5f757f3fSDimitry Andric case APFloat::fcNaN: 471*5f757f3fSDimitry Andric Index = 0; 472*5f757f3fSDimitry Andric break; 473*5f757f3fSDimitry Andric case APFloat::fcInfinity: 474*5f757f3fSDimitry Andric Index = 1; 475*5f757f3fSDimitry Andric break; 476*5f757f3fSDimitry Andric case APFloat::fcNormal: 477*5f757f3fSDimitry Andric Index = Val.isDenormal() ? 3 : 2; 478*5f757f3fSDimitry Andric break; 479*5f757f3fSDimitry Andric case APFloat::fcZero: 480*5f757f3fSDimitry Andric Index = 4; 481*5f757f3fSDimitry Andric break; 482*5f757f3fSDimitry Andric } 483*5f757f3fSDimitry Andric 484*5f757f3fSDimitry Andric // The last argument is first on the stack. 485*5f757f3fSDimitry Andric assert(Index <= 4); 486*5f757f3fSDimitry Andric unsigned IntSize = primSize(getIntPrimType(S)); 487*5f757f3fSDimitry Andric unsigned Offset = 488*5f757f3fSDimitry Andric align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize)); 489*5f757f3fSDimitry Andric 490*5f757f3fSDimitry Andric APSInt I = peekToAPSInt(S.Stk, getIntPrimType(S), Offset); 491*5f757f3fSDimitry Andric pushInt(S, I.getZExtValue()); 492*5f757f3fSDimitry Andric return true; 493*5f757f3fSDimitry Andric } 494*5f757f3fSDimitry Andric 495*5f757f3fSDimitry Andric // The C standard says "fabs raises no floating-point exceptions, 496*5f757f3fSDimitry Andric // even if x is a signaling NaN. The returned value is independent of 497*5f757f3fSDimitry Andric // the current rounding direction mode." Therefore constant folding can 498*5f757f3fSDimitry Andric // proceed without regard to the floating point settings. 499*5f757f3fSDimitry Andric // Reference, WG14 N2478 F.10.4.3 500*5f757f3fSDimitry Andric static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, 501*5f757f3fSDimitry Andric const InterpFrame *Frame, 502*5f757f3fSDimitry Andric const Function *Func) { 503*5f757f3fSDimitry Andric const Floating &Val = getParam<Floating>(Frame, 0); 504*5f757f3fSDimitry Andric 505*5f757f3fSDimitry Andric S.Stk.push<Floating>(Floating::abs(Val)); 506*5f757f3fSDimitry Andric return true; 507*5f757f3fSDimitry Andric } 508*5f757f3fSDimitry Andric 509*5f757f3fSDimitry Andric static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, 510*5f757f3fSDimitry Andric const InterpFrame *Frame, 511*5f757f3fSDimitry Andric const Function *Func, 512*5f757f3fSDimitry Andric const CallExpr *Call) { 513*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 514*5f757f3fSDimitry Andric APSInt Val = peekToAPSInt(S.Stk, ArgT); 515*5f757f3fSDimitry Andric pushInt(S, Val.popcount()); 516*5f757f3fSDimitry Andric return true; 517*5f757f3fSDimitry Andric } 518*5f757f3fSDimitry Andric 519*5f757f3fSDimitry Andric static bool interp__builtin_parity(InterpState &S, CodePtr OpPC, 520*5f757f3fSDimitry Andric const InterpFrame *Frame, 521*5f757f3fSDimitry Andric const Function *Func, const CallExpr *Call) { 522*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 523*5f757f3fSDimitry Andric APSInt Val = peekToAPSInt(S.Stk, ArgT); 524*5f757f3fSDimitry Andric pushInt(S, Val.popcount() % 2); 525*5f757f3fSDimitry Andric return true; 526*5f757f3fSDimitry Andric } 527*5f757f3fSDimitry Andric 528*5f757f3fSDimitry Andric static bool interp__builtin_clrsb(InterpState &S, CodePtr OpPC, 529*5f757f3fSDimitry Andric const InterpFrame *Frame, 530*5f757f3fSDimitry Andric const Function *Func, const CallExpr *Call) { 531*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 532*5f757f3fSDimitry Andric APSInt Val = peekToAPSInt(S.Stk, ArgT); 533*5f757f3fSDimitry Andric pushInt(S, Val.getBitWidth() - Val.getSignificantBits()); 534*5f757f3fSDimitry Andric return true; 535*5f757f3fSDimitry Andric } 536*5f757f3fSDimitry Andric 537*5f757f3fSDimitry Andric static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC, 538*5f757f3fSDimitry Andric const InterpFrame *Frame, 539*5f757f3fSDimitry Andric const Function *Func, 540*5f757f3fSDimitry Andric const CallExpr *Call) { 541*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 542*5f757f3fSDimitry Andric APSInt Val = peekToAPSInt(S.Stk, ArgT); 543*5f757f3fSDimitry Andric pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigned=*/true)); 544*5f757f3fSDimitry Andric return true; 545*5f757f3fSDimitry Andric } 546*5f757f3fSDimitry Andric 547*5f757f3fSDimitry Andric static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC, 548*5f757f3fSDimitry Andric const InterpFrame *Frame, 549*5f757f3fSDimitry Andric const Function *Func, 550*5f757f3fSDimitry Andric const CallExpr *Call) { 551*5f757f3fSDimitry Andric // This is an unevaluated call, so there are no arguments on the stack. 552*5f757f3fSDimitry Andric assert(Call->getNumArgs() == 1); 553*5f757f3fSDimitry Andric const Expr *Arg = Call->getArg(0); 554*5f757f3fSDimitry Andric 555*5f757f3fSDimitry Andric GCCTypeClass ResultClass = 556*5f757f3fSDimitry Andric EvaluateBuiltinClassifyType(Arg->getType(), S.getLangOpts()); 557*5f757f3fSDimitry Andric int32_t ReturnVal = static_cast<int32_t>(ResultClass); 558*5f757f3fSDimitry Andric pushInt(S, ReturnVal); 559*5f757f3fSDimitry Andric return true; 560*5f757f3fSDimitry Andric } 561*5f757f3fSDimitry Andric 562*5f757f3fSDimitry Andric // __builtin_expect(long, long) 563*5f757f3fSDimitry Andric // __builtin_expect_with_probability(long, long, double) 564*5f757f3fSDimitry Andric static bool interp__builtin_expect(InterpState &S, CodePtr OpPC, 565*5f757f3fSDimitry Andric const InterpFrame *Frame, 566*5f757f3fSDimitry Andric const Function *Func, const CallExpr *Call) { 567*5f757f3fSDimitry Andric // The return value is simply the value of the first parameter. 568*5f757f3fSDimitry Andric // We ignore the probability. 569*5f757f3fSDimitry Andric unsigned NumArgs = Call->getNumArgs(); 570*5f757f3fSDimitry Andric assert(NumArgs == 2 || NumArgs == 3); 571*5f757f3fSDimitry Andric 572*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 573*5f757f3fSDimitry Andric unsigned Offset = align(primSize(getLongPrimType(S))) * 2; 574*5f757f3fSDimitry Andric if (NumArgs == 3) 575*5f757f3fSDimitry Andric Offset += align(primSize(PT_Float)); 576*5f757f3fSDimitry Andric 577*5f757f3fSDimitry Andric APSInt Val = peekToAPSInt(S.Stk, ArgT, Offset); 578*5f757f3fSDimitry Andric pushLong(S, Val.getSExtValue()); 579*5f757f3fSDimitry Andric return true; 580*5f757f3fSDimitry Andric } 581*5f757f3fSDimitry Andric 582*5f757f3fSDimitry Andric /// rotateleft(value, amount) 583*5f757f3fSDimitry Andric static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC, 584*5f757f3fSDimitry Andric const InterpFrame *Frame, 585*5f757f3fSDimitry Andric const Function *Func, const CallExpr *Call, 586*5f757f3fSDimitry Andric bool Right) { 587*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 588*5f757f3fSDimitry Andric assert(ArgT == *S.getContext().classify(Call->getArg(1)->getType())); 589*5f757f3fSDimitry Andric 590*5f757f3fSDimitry Andric APSInt Amount = peekToAPSInt(S.Stk, ArgT); 591*5f757f3fSDimitry Andric APSInt Value = peekToAPSInt(S.Stk, ArgT, align(primSize(ArgT)) * 2); 592*5f757f3fSDimitry Andric 593*5f757f3fSDimitry Andric APSInt Result; 594*5f757f3fSDimitry Andric if (Right) 595*5f757f3fSDimitry Andric Result = APSInt(Value.rotr(Amount.urem(Value.getBitWidth())), 596*5f757f3fSDimitry Andric /*IsUnsigned=*/true); 597*5f757f3fSDimitry Andric else // Left. 598*5f757f3fSDimitry Andric Result = APSInt(Value.rotl(Amount.urem(Value.getBitWidth())), 599*5f757f3fSDimitry Andric /*IsUnsigned=*/true); 600*5f757f3fSDimitry Andric 601*5f757f3fSDimitry Andric pushAPSInt(S, Result); 602*5f757f3fSDimitry Andric return true; 603*5f757f3fSDimitry Andric } 604*5f757f3fSDimitry Andric 605*5f757f3fSDimitry Andric static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC, 606*5f757f3fSDimitry Andric const InterpFrame *Frame, const Function *Func, 607*5f757f3fSDimitry Andric const CallExpr *Call) { 608*5f757f3fSDimitry Andric PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); 609*5f757f3fSDimitry Andric APSInt Value = peekToAPSInt(S.Stk, ArgT); 610*5f757f3fSDimitry Andric 611*5f757f3fSDimitry Andric uint64_t N = Value.countr_zero(); 612*5f757f3fSDimitry Andric pushInt(S, N == Value.getBitWidth() ? 0 : N + 1); 613*5f757f3fSDimitry Andric return true; 614*5f757f3fSDimitry Andric } 615*5f757f3fSDimitry Andric 616*5f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, 617*5f757f3fSDimitry Andric const CallExpr *Call) { 61806c3fb27SDimitry Andric InterpFrame *Frame = S.Current; 61906c3fb27SDimitry Andric APValue Dummy; 62006c3fb27SDimitry Andric 621*5f757f3fSDimitry Andric QualType ReturnType = Call->getCallReturnType(S.getCtx()); 622*5f757f3fSDimitry Andric std::optional<PrimType> ReturnT = S.getContext().classify(ReturnType); 623*5f757f3fSDimitry Andric // If classify failed, we assume void. 624*5f757f3fSDimitry Andric assert(ReturnT || ReturnType->isVoidType()); 625*5f757f3fSDimitry Andric 62606c3fb27SDimitry Andric switch (F->getBuiltinID()) { 62706c3fb27SDimitry Andric case Builtin::BI__builtin_is_constant_evaluated: 62806c3fb27SDimitry Andric S.Stk.push<Boolean>(Boolean::from(S.inConstantContext())); 629*5f757f3fSDimitry Andric break; 63006c3fb27SDimitry Andric case Builtin::BI__builtin_assume: 631*5f757f3fSDimitry Andric break; 63206c3fb27SDimitry Andric case Builtin::BI__builtin_strcmp: 633*5f757f3fSDimitry Andric if (!interp__builtin_strcmp(S, OpPC, Frame)) 63406c3fb27SDimitry Andric return false; 635*5f757f3fSDimitry Andric break; 636*5f757f3fSDimitry Andric case Builtin::BI__builtin_strlen: 637*5f757f3fSDimitry Andric if (!interp__builtin_strlen(S, OpPC, Frame)) 638*5f757f3fSDimitry Andric return false; 639*5f757f3fSDimitry Andric break; 640*5f757f3fSDimitry Andric case Builtin::BI__builtin_nan: 641*5f757f3fSDimitry Andric case Builtin::BI__builtin_nanf: 642*5f757f3fSDimitry Andric case Builtin::BI__builtin_nanl: 643*5f757f3fSDimitry Andric case Builtin::BI__builtin_nanf16: 644*5f757f3fSDimitry Andric case Builtin::BI__builtin_nanf128: 645*5f757f3fSDimitry Andric if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false)) 646*5f757f3fSDimitry Andric return false; 647*5f757f3fSDimitry Andric break; 648*5f757f3fSDimitry Andric case Builtin::BI__builtin_nans: 649*5f757f3fSDimitry Andric case Builtin::BI__builtin_nansf: 650*5f757f3fSDimitry Andric case Builtin::BI__builtin_nansl: 651*5f757f3fSDimitry Andric case Builtin::BI__builtin_nansf16: 652*5f757f3fSDimitry Andric case Builtin::BI__builtin_nansf128: 653*5f757f3fSDimitry Andric if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true)) 654*5f757f3fSDimitry Andric return false; 655*5f757f3fSDimitry Andric break; 656*5f757f3fSDimitry Andric 657*5f757f3fSDimitry Andric case Builtin::BI__builtin_huge_val: 658*5f757f3fSDimitry Andric case Builtin::BI__builtin_huge_valf: 659*5f757f3fSDimitry Andric case Builtin::BI__builtin_huge_vall: 660*5f757f3fSDimitry Andric case Builtin::BI__builtin_huge_valf16: 661*5f757f3fSDimitry Andric case Builtin::BI__builtin_huge_valf128: 662*5f757f3fSDimitry Andric case Builtin::BI__builtin_inf: 663*5f757f3fSDimitry Andric case Builtin::BI__builtin_inff: 664*5f757f3fSDimitry Andric case Builtin::BI__builtin_infl: 665*5f757f3fSDimitry Andric case Builtin::BI__builtin_inff16: 666*5f757f3fSDimitry Andric case Builtin::BI__builtin_inff128: 667*5f757f3fSDimitry Andric if (!interp__builtin_inf(S, OpPC, Frame, F)) 668*5f757f3fSDimitry Andric return false; 669*5f757f3fSDimitry Andric break; 670*5f757f3fSDimitry Andric case Builtin::BI__builtin_copysign: 671*5f757f3fSDimitry Andric case Builtin::BI__builtin_copysignf: 672*5f757f3fSDimitry Andric case Builtin::BI__builtin_copysignl: 673*5f757f3fSDimitry Andric case Builtin::BI__builtin_copysignf128: 674*5f757f3fSDimitry Andric if (!interp__builtin_copysign(S, OpPC, Frame, F)) 675*5f757f3fSDimitry Andric return false; 676*5f757f3fSDimitry Andric break; 677*5f757f3fSDimitry Andric 678*5f757f3fSDimitry Andric case Builtin::BI__builtin_fmin: 679*5f757f3fSDimitry Andric case Builtin::BI__builtin_fminf: 680*5f757f3fSDimitry Andric case Builtin::BI__builtin_fminl: 681*5f757f3fSDimitry Andric case Builtin::BI__builtin_fminf16: 682*5f757f3fSDimitry Andric case Builtin::BI__builtin_fminf128: 683*5f757f3fSDimitry Andric if (!interp__builtin_fmin(S, OpPC, Frame, F)) 684*5f757f3fSDimitry Andric return false; 685*5f757f3fSDimitry Andric break; 686*5f757f3fSDimitry Andric 687*5f757f3fSDimitry Andric case Builtin::BI__builtin_fmax: 688*5f757f3fSDimitry Andric case Builtin::BI__builtin_fmaxf: 689*5f757f3fSDimitry Andric case Builtin::BI__builtin_fmaxl: 690*5f757f3fSDimitry Andric case Builtin::BI__builtin_fmaxf16: 691*5f757f3fSDimitry Andric case Builtin::BI__builtin_fmaxf128: 692*5f757f3fSDimitry Andric if (!interp__builtin_fmax(S, OpPC, Frame, F)) 693*5f757f3fSDimitry Andric return false; 694*5f757f3fSDimitry Andric break; 695*5f757f3fSDimitry Andric 696*5f757f3fSDimitry Andric case Builtin::BI__builtin_isnan: 697*5f757f3fSDimitry Andric if (!interp__builtin_isnan(S, OpPC, Frame, F)) 698*5f757f3fSDimitry Andric return false; 699*5f757f3fSDimitry Andric break; 700*5f757f3fSDimitry Andric case Builtin::BI__builtin_issignaling: 701*5f757f3fSDimitry Andric if (!interp__builtin_issignaling(S, OpPC, Frame, F)) 702*5f757f3fSDimitry Andric return false; 703*5f757f3fSDimitry Andric break; 704*5f757f3fSDimitry Andric 705*5f757f3fSDimitry Andric case Builtin::BI__builtin_isinf: 706*5f757f3fSDimitry Andric if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false)) 707*5f757f3fSDimitry Andric return false; 708*5f757f3fSDimitry Andric break; 709*5f757f3fSDimitry Andric 710*5f757f3fSDimitry Andric case Builtin::BI__builtin_isinf_sign: 711*5f757f3fSDimitry Andric if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true)) 712*5f757f3fSDimitry Andric return false; 713*5f757f3fSDimitry Andric break; 714*5f757f3fSDimitry Andric 715*5f757f3fSDimitry Andric case Builtin::BI__builtin_isfinite: 716*5f757f3fSDimitry Andric if (!interp__builtin_isfinite(S, OpPC, Frame, F)) 717*5f757f3fSDimitry Andric return false; 718*5f757f3fSDimitry Andric break; 719*5f757f3fSDimitry Andric case Builtin::BI__builtin_isnormal: 720*5f757f3fSDimitry Andric if (!interp__builtin_isnormal(S, OpPC, Frame, F)) 721*5f757f3fSDimitry Andric return false; 722*5f757f3fSDimitry Andric break; 723*5f757f3fSDimitry Andric case Builtin::BI__builtin_issubnormal: 724*5f757f3fSDimitry Andric if (!interp__builtin_issubnormal(S, OpPC, Frame, F)) 725*5f757f3fSDimitry Andric return false; 726*5f757f3fSDimitry Andric break; 727*5f757f3fSDimitry Andric case Builtin::BI__builtin_iszero: 728*5f757f3fSDimitry Andric if (!interp__builtin_iszero(S, OpPC, Frame, F)) 729*5f757f3fSDimitry Andric return false; 730*5f757f3fSDimitry Andric break; 731*5f757f3fSDimitry Andric case Builtin::BI__builtin_isfpclass: 732*5f757f3fSDimitry Andric if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call)) 733*5f757f3fSDimitry Andric return false; 734*5f757f3fSDimitry Andric break; 735*5f757f3fSDimitry Andric case Builtin::BI__builtin_fpclassify: 736*5f757f3fSDimitry Andric if (!interp__builtin_fpclassify(S, OpPC, Frame, F)) 737*5f757f3fSDimitry Andric return false; 738*5f757f3fSDimitry Andric break; 739*5f757f3fSDimitry Andric 740*5f757f3fSDimitry Andric case Builtin::BI__builtin_fabs: 741*5f757f3fSDimitry Andric case Builtin::BI__builtin_fabsf: 742*5f757f3fSDimitry Andric case Builtin::BI__builtin_fabsl: 743*5f757f3fSDimitry Andric case Builtin::BI__builtin_fabsf128: 744*5f757f3fSDimitry Andric if (!interp__builtin_fabs(S, OpPC, Frame, F)) 745*5f757f3fSDimitry Andric return false; 746*5f757f3fSDimitry Andric break; 747*5f757f3fSDimitry Andric 748*5f757f3fSDimitry Andric case Builtin::BI__builtin_popcount: 749*5f757f3fSDimitry Andric case Builtin::BI__builtin_popcountl: 750*5f757f3fSDimitry Andric case Builtin::BI__builtin_popcountll: 751*5f757f3fSDimitry Andric case Builtin::BI__popcnt16: // Microsoft variants of popcount 752*5f757f3fSDimitry Andric case Builtin::BI__popcnt: 753*5f757f3fSDimitry Andric case Builtin::BI__popcnt64: 754*5f757f3fSDimitry Andric if (!interp__builtin_popcount(S, OpPC, Frame, F, Call)) 755*5f757f3fSDimitry Andric return false; 756*5f757f3fSDimitry Andric break; 757*5f757f3fSDimitry Andric 758*5f757f3fSDimitry Andric case Builtin::BI__builtin_parity: 759*5f757f3fSDimitry Andric case Builtin::BI__builtin_parityl: 760*5f757f3fSDimitry Andric case Builtin::BI__builtin_parityll: 761*5f757f3fSDimitry Andric if (!interp__builtin_parity(S, OpPC, Frame, F, Call)) 762*5f757f3fSDimitry Andric return false; 763*5f757f3fSDimitry Andric break; 764*5f757f3fSDimitry Andric 765*5f757f3fSDimitry Andric case Builtin::BI__builtin_clrsb: 766*5f757f3fSDimitry Andric case Builtin::BI__builtin_clrsbl: 767*5f757f3fSDimitry Andric case Builtin::BI__builtin_clrsbll: 768*5f757f3fSDimitry Andric if (!interp__builtin_clrsb(S, OpPC, Frame, F, Call)) 769*5f757f3fSDimitry Andric return false; 770*5f757f3fSDimitry Andric break; 771*5f757f3fSDimitry Andric 772*5f757f3fSDimitry Andric case Builtin::BI__builtin_bitreverse8: 773*5f757f3fSDimitry Andric case Builtin::BI__builtin_bitreverse16: 774*5f757f3fSDimitry Andric case Builtin::BI__builtin_bitreverse32: 775*5f757f3fSDimitry Andric case Builtin::BI__builtin_bitreverse64: 776*5f757f3fSDimitry Andric if (!interp__builtin_bitreverse(S, OpPC, Frame, F, Call)) 777*5f757f3fSDimitry Andric return false; 778*5f757f3fSDimitry Andric break; 779*5f757f3fSDimitry Andric 780*5f757f3fSDimitry Andric case Builtin::BI__builtin_classify_type: 781*5f757f3fSDimitry Andric if (!interp__builtin_classify_type(S, OpPC, Frame, F, Call)) 782*5f757f3fSDimitry Andric return false; 783*5f757f3fSDimitry Andric break; 784*5f757f3fSDimitry Andric 785*5f757f3fSDimitry Andric case Builtin::BI__builtin_expect: 786*5f757f3fSDimitry Andric case Builtin::BI__builtin_expect_with_probability: 787*5f757f3fSDimitry Andric if (!interp__builtin_expect(S, OpPC, Frame, F, Call)) 788*5f757f3fSDimitry Andric return false; 789*5f757f3fSDimitry Andric break; 790*5f757f3fSDimitry Andric 791*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateleft8: 792*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateleft16: 793*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateleft32: 794*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateleft64: 795*5f757f3fSDimitry Andric case Builtin::BI_rotl8: // Microsoft variants of rotate left 796*5f757f3fSDimitry Andric case Builtin::BI_rotl16: 797*5f757f3fSDimitry Andric case Builtin::BI_rotl: 798*5f757f3fSDimitry Andric case Builtin::BI_lrotl: 799*5f757f3fSDimitry Andric case Builtin::BI_rotl64: 800*5f757f3fSDimitry Andric if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/false)) 801*5f757f3fSDimitry Andric return false; 802*5f757f3fSDimitry Andric break; 803*5f757f3fSDimitry Andric 804*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateright8: 805*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateright16: 806*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateright32: 807*5f757f3fSDimitry Andric case Builtin::BI__builtin_rotateright64: 808*5f757f3fSDimitry Andric case Builtin::BI_rotr8: // Microsoft variants of rotate right 809*5f757f3fSDimitry Andric case Builtin::BI_rotr16: 810*5f757f3fSDimitry Andric case Builtin::BI_rotr: 811*5f757f3fSDimitry Andric case Builtin::BI_lrotr: 812*5f757f3fSDimitry Andric case Builtin::BI_rotr64: 813*5f757f3fSDimitry Andric if (!interp__builtin_rotate(S, OpPC, Frame, F, Call, /*Right=*/true)) 814*5f757f3fSDimitry Andric return false; 815*5f757f3fSDimitry Andric break; 816*5f757f3fSDimitry Andric 817*5f757f3fSDimitry Andric case Builtin::BI__builtin_ffs: 818*5f757f3fSDimitry Andric case Builtin::BI__builtin_ffsl: 819*5f757f3fSDimitry Andric case Builtin::BI__builtin_ffsll: 820*5f757f3fSDimitry Andric if (!interp__builtin_ffs(S, OpPC, Frame, F, Call)) 821*5f757f3fSDimitry Andric return false; 822*5f757f3fSDimitry Andric break; 823*5f757f3fSDimitry Andric 82406c3fb27SDimitry Andric default: 82506c3fb27SDimitry Andric return false; 82606c3fb27SDimitry Andric } 82706c3fb27SDimitry Andric 828*5f757f3fSDimitry Andric return retPrimValue(S, OpPC, Dummy, ReturnT); 829*5f757f3fSDimitry Andric } 830*5f757f3fSDimitry Andric 831*5f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, 832*5f757f3fSDimitry Andric llvm::ArrayRef<int64_t> ArrayIndices, 833*5f757f3fSDimitry Andric int64_t &IntResult) { 834*5f757f3fSDimitry Andric CharUnits Result; 835*5f757f3fSDimitry Andric unsigned N = E->getNumComponents(); 836*5f757f3fSDimitry Andric assert(N > 0); 837*5f757f3fSDimitry Andric 838*5f757f3fSDimitry Andric unsigned ArrayIndex = 0; 839*5f757f3fSDimitry Andric QualType CurrentType = E->getTypeSourceInfo()->getType(); 840*5f757f3fSDimitry Andric for (unsigned I = 0; I != N; ++I) { 841*5f757f3fSDimitry Andric const OffsetOfNode &Node = E->getComponent(I); 842*5f757f3fSDimitry Andric switch (Node.getKind()) { 843*5f757f3fSDimitry Andric case OffsetOfNode::Field: { 844*5f757f3fSDimitry Andric const FieldDecl *MemberDecl = Node.getField(); 845*5f757f3fSDimitry Andric const RecordType *RT = CurrentType->getAs<RecordType>(); 846*5f757f3fSDimitry Andric if (!RT) 84706c3fb27SDimitry Andric return false; 848*5f757f3fSDimitry Andric RecordDecl *RD = RT->getDecl(); 849*5f757f3fSDimitry Andric if (RD->isInvalidDecl()) 850*5f757f3fSDimitry Andric return false; 851*5f757f3fSDimitry Andric const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD); 852*5f757f3fSDimitry Andric unsigned FieldIndex = MemberDecl->getFieldIndex(); 853*5f757f3fSDimitry Andric assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type"); 854*5f757f3fSDimitry Andric Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex)); 855*5f757f3fSDimitry Andric CurrentType = MemberDecl->getType().getNonReferenceType(); 856*5f757f3fSDimitry Andric break; 857*5f757f3fSDimitry Andric } 858*5f757f3fSDimitry Andric case OffsetOfNode::Array: { 859*5f757f3fSDimitry Andric // When generating bytecode, we put all the index expressions as Sint64 on 860*5f757f3fSDimitry Andric // the stack. 861*5f757f3fSDimitry Andric int64_t Index = ArrayIndices[ArrayIndex]; 862*5f757f3fSDimitry Andric const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType); 863*5f757f3fSDimitry Andric if (!AT) 864*5f757f3fSDimitry Andric return false; 865*5f757f3fSDimitry Andric CurrentType = AT->getElementType(); 866*5f757f3fSDimitry Andric CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType); 867*5f757f3fSDimitry Andric Result += Index * ElementSize; 868*5f757f3fSDimitry Andric ++ArrayIndex; 869*5f757f3fSDimitry Andric break; 870*5f757f3fSDimitry Andric } 871*5f757f3fSDimitry Andric case OffsetOfNode::Base: { 872*5f757f3fSDimitry Andric const CXXBaseSpecifier *BaseSpec = Node.getBase(); 873*5f757f3fSDimitry Andric if (BaseSpec->isVirtual()) 874*5f757f3fSDimitry Andric return false; 875*5f757f3fSDimitry Andric 876*5f757f3fSDimitry Andric // Find the layout of the class whose base we are looking into. 877*5f757f3fSDimitry Andric const RecordType *RT = CurrentType->getAs<RecordType>(); 878*5f757f3fSDimitry Andric if (!RT) 879*5f757f3fSDimitry Andric return false; 880*5f757f3fSDimitry Andric const RecordDecl *RD = RT->getDecl(); 881*5f757f3fSDimitry Andric if (RD->isInvalidDecl()) 882*5f757f3fSDimitry Andric return false; 883*5f757f3fSDimitry Andric const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD); 884*5f757f3fSDimitry Andric 885*5f757f3fSDimitry Andric // Find the base class itself. 886*5f757f3fSDimitry Andric CurrentType = BaseSpec->getType(); 887*5f757f3fSDimitry Andric const RecordType *BaseRT = CurrentType->getAs<RecordType>(); 888*5f757f3fSDimitry Andric if (!BaseRT) 889*5f757f3fSDimitry Andric return false; 890*5f757f3fSDimitry Andric 891*5f757f3fSDimitry Andric // Add the offset to the base. 892*5f757f3fSDimitry Andric Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); 893*5f757f3fSDimitry Andric break; 894*5f757f3fSDimitry Andric } 895*5f757f3fSDimitry Andric case OffsetOfNode::Identifier: 896*5f757f3fSDimitry Andric llvm_unreachable("Dependent OffsetOfExpr?"); 897*5f757f3fSDimitry Andric } 898*5f757f3fSDimitry Andric } 899*5f757f3fSDimitry Andric 900*5f757f3fSDimitry Andric IntResult = Result.getQuantity(); 901*5f757f3fSDimitry Andric 902*5f757f3fSDimitry Andric return true; 903*5f757f3fSDimitry Andric } 904*5f757f3fSDimitry Andric 905*5f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, 906*5f757f3fSDimitry Andric const Pointer &Ptr, const APSInt &IntValue) { 907*5f757f3fSDimitry Andric 908*5f757f3fSDimitry Andric const Record *R = Ptr.getRecord(); 909*5f757f3fSDimitry Andric assert(R); 910*5f757f3fSDimitry Andric assert(R->getNumFields() == 1); 911*5f757f3fSDimitry Andric 912*5f757f3fSDimitry Andric unsigned FieldOffset = R->getField(0u)->Offset; 913*5f757f3fSDimitry Andric const Pointer &FieldPtr = Ptr.atField(FieldOffset); 914*5f757f3fSDimitry Andric PrimType FieldT = *S.getContext().classify(FieldPtr.getType()); 915*5f757f3fSDimitry Andric 916*5f757f3fSDimitry Andric INT_TYPE_SWITCH(FieldT, 917*5f757f3fSDimitry Andric FieldPtr.deref<T>() = T::from(IntValue.getSExtValue())); 918*5f757f3fSDimitry Andric FieldPtr.initialize(); 919*5f757f3fSDimitry Andric return true; 92006c3fb27SDimitry Andric } 92106c3fb27SDimitry Andric 92206c3fb27SDimitry Andric } // namespace interp 92306c3fb27SDimitry Andric } // namespace clang 924