xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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