/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/Interp/InterpBuiltin.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- InterpBuiltin.cpp - Interpreter for the constexpr VM ---*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | #include "Boolean.h" |
9 | | #include "Interp.h" |
10 | | #include "PrimType.h" |
11 | | #include "clang/AST/RecordLayout.h" |
12 | | #include "clang/Basic/Builtins.h" |
13 | | #include "clang/Basic/TargetInfo.h" |
14 | | |
15 | | namespace clang { |
16 | | namespace interp { |
17 | | |
18 | | template <typename T> |
19 | 1.38k | static T getParam(const InterpFrame *Frame, unsigned Index) { |
20 | 1.38k | assert(Frame->getFunction()->getNumParams() > Index); |
21 | 1.38k | unsigned Offset = Frame->getFunction()->getParamOffset(Index); |
22 | 1.38k | return Frame->getParam<T>(Offset); |
23 | 1.38k | } InterpBuiltin.cpp:clang::interp::Pointer clang::interp::getParam<clang::interp::Pointer>(clang::interp::InterpFrame const*, unsigned int) Line | Count | Source | 19 | 859 | static T getParam(const InterpFrame *Frame, unsigned Index) { | 20 | 859 | assert(Frame->getFunction()->getNumParams() > Index); | 21 | 859 | unsigned Offset = Frame->getFunction()->getParamOffset(Index); | 22 | 859 | return Frame->getParam<T>(Offset); | 23 | 859 | } |
InterpBuiltin.cpp:clang::interp::Floating clang::interp::getParam<clang::interp::Floating>(clang::interp::InterpFrame const*, unsigned int) Line | Count | Source | 19 | 525 | static T getParam(const InterpFrame *Frame, unsigned Index) { | 20 | 525 | assert(Frame->getFunction()->getNumParams() > Index); | 21 | 525 | unsigned Offset = Frame->getFunction()->getParamOffset(Index); | 22 | 525 | return Frame->getParam<T>(Offset); | 23 | 525 | } |
|
24 | | |
25 | 1.28k | PrimType getIntPrimType(const InterpState &S) { |
26 | 1.28k | const TargetInfo &TI = S.getCtx().getTargetInfo(); |
27 | 1.28k | unsigned IntWidth = TI.getIntWidth(); |
28 | | |
29 | 1.28k | if (IntWidth == 32) |
30 | 1.04k | return PT_Sint32; |
31 | 232 | else if (IntWidth == 16) |
32 | 232 | return PT_Sint16; |
33 | 0 | llvm_unreachable("Int isn't 16 or 32 bit?"); |
34 | 0 | } |
35 | | |
36 | | /// Peek an integer value from the stack into an APSInt. |
37 | 371 | static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) { |
38 | 371 | if (Offset == 0) |
39 | 319 | Offset = align(primSize(T)); |
40 | | |
41 | 371 | APSInt R; |
42 | 371 | INT_TYPE_SWITCH(T, { |
43 | 371 | T Val = Stk.peek<T>(Offset); |
44 | 371 | R = APSInt( |
45 | 371 | APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned())); |
46 | 371 | }); |
47 | | |
48 | 371 | return R; |
49 | 371 | } |
50 | | |
51 | | /// Pushes \p Val to the stack, as a target-dependent 'int'. |
52 | 588 | static void pushInt(InterpState &S, int32_t Val) { |
53 | 588 | PrimType IntType = getIntPrimType(S); |
54 | 588 | if (IntType == PT_Sint32) |
55 | 480 | S.Stk.push<Integral<32, true>>(Integral<32, true>::from(Val)); |
56 | 108 | else if (IntType == PT_Sint16) |
57 | 108 | S.Stk.push<Integral<16, true>>(Integral<16, true>::from(Val)); |
58 | 0 | else |
59 | 0 | llvm_unreachable("Int isn't 16 or 32 bit?"); |
60 | 588 | } |
61 | | |
62 | 588 | static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) { |
63 | 588 | PrimType IntType = getIntPrimType(S); |
64 | 588 | if (IntType == PT_Sint32) |
65 | 480 | return Ret<PT_Sint32>(S, OpPC, Result); |
66 | 108 | else if (IntType == PT_Sint16) |
67 | 108 | return Ret<PT_Sint16>(S, OpPC, Result); |
68 | 0 | llvm_unreachable("Int isn't 16 or 32 bit?"); |
69 | 0 | } |
70 | | |
71 | 195 | static void pushSizeT(InterpState &S, uint64_t Val) { |
72 | 195 | const TargetInfo &TI = S.getCtx().getTargetInfo(); |
73 | 195 | unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType()); |
74 | | |
75 | 195 | switch (SizeTWidth) { |
76 | 96 | case 64: |
77 | 96 | S.Stk.push<Integral<64, false>>(Integral<64, false>::from(Val)); |
78 | 96 | break; |
79 | 66 | case 32: |
80 | 66 | S.Stk.push<Integral<32, false>>(Integral<32, false>::from(Val)); |
81 | 66 | break; |
82 | 33 | case 16: |
83 | 33 | S.Stk.push<Integral<16, false>>(Integral<16, false>::from(Val)); |
84 | 33 | break; |
85 | 0 | default: |
86 | 0 | llvm_unreachable("We don't handle this size_t size."); |
87 | 195 | } |
88 | 195 | } |
89 | | |
90 | 195 | static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) { |
91 | 195 | const TargetInfo &TI = S.getCtx().getTargetInfo(); |
92 | 195 | unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType()); |
93 | | |
94 | 195 | switch (SizeTWidth) { |
95 | 96 | case 64: |
96 | 96 | return Ret<PT_Uint64>(S, OpPC, Result); |
97 | 66 | case 32: |
98 | 66 | return Ret<PT_Uint32>(S, OpPC, Result); |
99 | 33 | case 16: |
100 | 33 | return Ret<PT_Uint16>(S, OpPC, Result); |
101 | 195 | } |
102 | | |
103 | 0 | llvm_unreachable("size_t isn't 64 or 32 bit?"); |
104 | 0 | } |
105 | | |
106 | | static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, |
107 | 185 | const InterpFrame *Frame) { |
108 | 185 | const Pointer &A = getParam<Pointer>(Frame, 0); |
109 | 185 | const Pointer &B = getParam<Pointer>(Frame, 1); |
110 | | |
111 | 185 | if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read)170 ) |
112 | 30 | return false; |
113 | | |
114 | 155 | assert(A.getFieldDesc()->isPrimitiveArray()); |
115 | 155 | assert(B.getFieldDesc()->isPrimitiveArray()); |
116 | | |
117 | 155 | unsigned IndexA = A.getIndex(); |
118 | 155 | unsigned IndexB = B.getIndex(); |
119 | 155 | int32_t Result = 0; |
120 | 1.61k | for (;; ++IndexA, ++IndexB1.46k ) { |
121 | 1.61k | const Pointer &PA = A.atIndex(IndexA); |
122 | 1.61k | const Pointer &PB = B.atIndex(IndexB); |
123 | 1.61k | if (!CheckRange(S, OpPC, PA, AK_Read) || |
124 | 1.61k | !CheckRange(S, OpPC, PB, AK_Read)1.60k ) { |
125 | 15 | return false; |
126 | 15 | } |
127 | 1.60k | uint8_t CA = PA.deref<uint8_t>(); |
128 | 1.60k | uint8_t CB = PB.deref<uint8_t>(); |
129 | | |
130 | 1.60k | if (CA > CB) { |
131 | 40 | Result = 1; |
132 | 40 | break; |
133 | 1.56k | } else if (CA < CB) { |
134 | 30 | Result = -1; |
135 | 30 | break; |
136 | 30 | } |
137 | 1.53k | if (CA == 0 || CB == 01.46k ) |
138 | 70 | break; |
139 | 1.53k | } |
140 | | |
141 | 140 | pushInt(S, Result); |
142 | 140 | return true; |
143 | 155 | } |
144 | | |
145 | | static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, |
146 | 358 | const InterpFrame *Frame) { |
147 | 358 | const Pointer &StrPtr = getParam<Pointer>(Frame, 0); |
148 | | |
149 | 358 | if (!CheckArray(S, OpPC, StrPtr)) |
150 | 0 | return false; |
151 | | |
152 | 358 | if (!CheckLive(S, OpPC, StrPtr, AK_Read)) |
153 | 0 | return false; |
154 | | |
155 | 358 | if (!CheckDummy(S, OpPC, StrPtr)) |
156 | 115 | return false; |
157 | | |
158 | 243 | assert(StrPtr.getFieldDesc()->isPrimitiveArray()); |
159 | | |
160 | 243 | size_t Len = 0; |
161 | 1.03k | for (size_t I = StrPtr.getIndex();; ++I, ++Len796 ) { |
162 | 1.03k | const Pointer &ElemPtr = StrPtr.atIndex(I); |
163 | | |
164 | 1.03k | if (!CheckRange(S, OpPC, ElemPtr, AK_Read)) |
165 | 48 | return false; |
166 | | |
167 | 991 | uint8_t Val = ElemPtr.deref<uint8_t>(); |
168 | 991 | if (Val == 0) |
169 | 195 | break; |
170 | 991 | } |
171 | | |
172 | 195 | pushSizeT(S, Len); |
173 | 195 | return true; |
174 | 243 | } |
175 | | |
176 | | static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, |
177 | | const InterpFrame *Frame, const Function *F, |
178 | 131 | bool Signaling) { |
179 | 131 | const Pointer &Arg = getParam<Pointer>(Frame, 0); |
180 | | |
181 | 131 | if (!CheckLoad(S, OpPC, Arg)) |
182 | 0 | return false; |
183 | | |
184 | 131 | assert(Arg.getFieldDesc()->isPrimitiveArray()); |
185 | | |
186 | | // Convert the given string to an integer using StringRef's API. |
187 | 131 | llvm::APInt Fill; |
188 | 131 | std::string Str; |
189 | 131 | assert(Arg.getNumElems() >= 1); |
190 | 240 | for (unsigned I = 0;; 131 ++I109 ) { |
191 | 240 | const Pointer &Elem = Arg.atIndex(I); |
192 | | |
193 | 240 | if (!CheckLoad(S, OpPC, Elem)) |
194 | 5 | return false; |
195 | | |
196 | 235 | if (Elem.deref<int8_t>() == 0) |
197 | 126 | break; |
198 | | |
199 | 109 | Str += Elem.deref<char>(); |
200 | 109 | } |
201 | | |
202 | | // Treat empty strings as if they were zero. |
203 | 126 | if (Str.empty()) |
204 | 107 | Fill = llvm::APInt(32, 0); |
205 | 19 | else if (StringRef(Str).getAsInteger(0, Fill)) |
206 | 5 | return false; |
207 | | |
208 | 121 | const llvm::fltSemantics &TargetSemantics = |
209 | 121 | S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType()); |
210 | | |
211 | 121 | Floating Result; |
212 | 121 | if (S.getCtx().getTargetInfo().isNan2008()) { |
213 | 121 | if (Signaling) |
214 | 44 | Result = Floating( |
215 | 44 | llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); |
216 | 77 | else |
217 | 77 | Result = Floating( |
218 | 77 | llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); |
219 | 121 | } else { |
220 | | // Prior to IEEE 754-2008, architectures were allowed to choose whether |
221 | | // the first bit of their significand was set for qNaN or sNaN. MIPS chose |
222 | | // a different encoding to what became a standard in 2008, and for pre- |
223 | | // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as |
224 | | // sNaN. This is now known as "legacy NaN" encoding. |
225 | 0 | if (Signaling) |
226 | 0 | Result = Floating( |
227 | 0 | llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill)); |
228 | 0 | else |
229 | 0 | Result = Floating( |
230 | 0 | llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill)); |
231 | 0 | } |
232 | | |
233 | 121 | S.Stk.push<Floating>(Result); |
234 | 121 | return true; |
235 | 126 | } |
236 | | |
237 | | static bool interp__builtin_inf(InterpState &S, CodePtr OpPC, |
238 | 102 | const InterpFrame *Frame, const Function *F) { |
239 | 102 | const llvm::fltSemantics &TargetSemantics = |
240 | 102 | S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType()); |
241 | | |
242 | 102 | S.Stk.push<Floating>(Floating::getInf(TargetSemantics)); |
243 | 102 | return true; |
244 | 102 | } |
245 | | |
246 | | static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, |
247 | | const InterpFrame *Frame, |
248 | 32 | const Function *F) { |
249 | 32 | const Floating &Arg1 = getParam<Floating>(Frame, 0); |
250 | 32 | const Floating &Arg2 = getParam<Floating>(Frame, 1); |
251 | | |
252 | 32 | APFloat Copy = Arg1.getAPFloat(); |
253 | 32 | Copy.copySign(Arg2.getAPFloat()); |
254 | 32 | S.Stk.push<Floating>(Floating(Copy)); |
255 | | |
256 | 32 | return true; |
257 | 32 | } |
258 | | |
259 | | static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, |
260 | 132 | const InterpFrame *Frame, const Function *F) { |
261 | 132 | const Floating &LHS = getParam<Floating>(Frame, 0); |
262 | 132 | const Floating &RHS = getParam<Floating>(Frame, 1); |
263 | | |
264 | 132 | Floating Result; |
265 | | |
266 | | // When comparing zeroes, return -0.0 if one of the zeroes is negative. |
267 | 132 | if (LHS.isZero() && RHS.isZero()32 && RHS.isNegative()20 ) |
268 | 10 | Result = RHS; |
269 | 122 | else if (LHS.isNan() || RHS < LHS97 ) |
270 | 49 | Result = RHS; |
271 | 73 | else |
272 | 73 | Result = LHS; |
273 | | |
274 | 132 | S.Stk.push<Floating>(Result); |
275 | 132 | return true; |
276 | 132 | } |
277 | | |
278 | | static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, |
279 | | const InterpFrame *Frame, |
280 | 96 | const Function *Func) { |
281 | 96 | const Floating &LHS = getParam<Floating>(Frame, 0); |
282 | 96 | const Floating &RHS = getParam<Floating>(Frame, 1); |
283 | | |
284 | 96 | Floating Result; |
285 | | |
286 | | // When comparing zeroes, return +0.0 if one of the zeroes is positive. |
287 | 96 | if (LHS.isZero() && RHS.isZero()32 && LHS.isNegative()20 ) |
288 | 10 | Result = RHS; |
289 | 86 | else if (LHS.isNan() || RHS > LHS70 ) |
290 | 40 | Result = RHS; |
291 | 46 | else |
292 | 46 | Result = LHS; |
293 | | |
294 | 96 | S.Stk.push<Floating>(Result); |
295 | 96 | return true; |
296 | 96 | } |
297 | | |
298 | | /// Defined as __builtin_isnan(...), to accommodate the fact that it can |
299 | | /// take a float, double, long double, etc. |
300 | | /// But for us, that's all a Floating anyway. |
301 | | static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, |
302 | 8 | const InterpFrame *Frame, const Function *F) { |
303 | 8 | const Floating &Arg = S.Stk.peek<Floating>(); |
304 | | |
305 | 8 | pushInt(S, Arg.isNan()); |
306 | 8 | return true; |
307 | 8 | } |
308 | | |
309 | | static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC, |
310 | | const InterpFrame *Frame, |
311 | 20 | const Function *F) { |
312 | 20 | const Floating &Arg = S.Stk.peek<Floating>(); |
313 | | |
314 | 20 | pushInt(S, Arg.isSignaling()); |
315 | 20 | return true; |
316 | 20 | } |
317 | | |
318 | | static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, |
319 | | const InterpFrame *Frame, const Function *F, |
320 | 10 | bool CheckSign) { |
321 | 10 | const Floating &Arg = S.Stk.peek<Floating>(); |
322 | 10 | bool IsInf = Arg.isInf(); |
323 | | |
324 | 10 | if (CheckSign) |
325 | 0 | pushInt(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0); |
326 | 10 | else |
327 | 10 | pushInt(S, Arg.isInf()); |
328 | 10 | return true; |
329 | 10 | } |
330 | | |
331 | | static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC, |
332 | | const InterpFrame *Frame, |
333 | 10 | const Function *F) { |
334 | 10 | const Floating &Arg = S.Stk.peek<Floating>(); |
335 | | |
336 | 10 | pushInt(S, Arg.isFinite()); |
337 | 10 | return true; |
338 | 10 | } |
339 | | |
340 | | static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC, |
341 | | const InterpFrame *Frame, |
342 | 10 | const Function *F) { |
343 | 10 | const Floating &Arg = S.Stk.peek<Floating>(); |
344 | | |
345 | 10 | pushInt(S, Arg.isNormal()); |
346 | 10 | return true; |
347 | 10 | } |
348 | | |
349 | | static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC, |
350 | | const InterpFrame *Frame, |
351 | 9 | const Function *F) { |
352 | 9 | const Floating &Arg = S.Stk.peek<Floating>(); |
353 | | |
354 | 9 | pushInt(S, Arg.isDenormal()); |
355 | 9 | return true; |
356 | 9 | } |
357 | | |
358 | | static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, |
359 | | const InterpFrame *Frame, |
360 | 10 | const Function *F) { |
361 | 10 | const Floating &Arg = S.Stk.peek<Floating>(); |
362 | | |
363 | 10 | pushInt(S, Arg.isZero()); |
364 | 10 | return true; |
365 | 10 | } |
366 | | |
367 | | /// First parameter to __builtin_isfpclass is the floating value, the |
368 | | /// second one is an integral value. |
369 | | static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, |
370 | | const InterpFrame *Frame, |
371 | | const Function *Func, |
372 | 194 | const CallExpr *Call) { |
373 | 194 | PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType()); |
374 | 194 | APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT); |
375 | 194 | const Floating &F = |
376 | 194 | S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float))); |
377 | | |
378 | 194 | int32_t Result = |
379 | 194 | static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue()); |
380 | 194 | pushInt(S, Result); |
381 | | |
382 | 194 | return true; |
383 | 194 | } |
384 | | |
385 | | /// Five int values followed by one floating value. |
386 | | static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, |
387 | | const InterpFrame *Frame, |
388 | 52 | const Function *Func) { |
389 | 52 | const Floating &Val = S.Stk.peek<Floating>(); |
390 | | |
391 | 52 | unsigned Index; |
392 | 52 | switch (Val.getCategory()) { |
393 | 10 | case APFloat::fcNaN: |
394 | 10 | Index = 0; |
395 | 10 | break; |
396 | 10 | case APFloat::fcInfinity: |
397 | 10 | Index = 1; |
398 | 10 | break; |
399 | 22 | case APFloat::fcNormal: |
400 | 22 | Index = Val.isDenormal() ? 313 : 29 ; |
401 | 22 | break; |
402 | 10 | case APFloat::fcZero: |
403 | 10 | Index = 4; |
404 | 10 | break; |
405 | 52 | } |
406 | | |
407 | | // The last argument is first on the stack. |
408 | 52 | assert(Index <= 4); |
409 | 52 | unsigned IntSize = primSize(getIntPrimType(S)); |
410 | 52 | unsigned Offset = |
411 | 52 | align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize)); |
412 | | |
413 | 52 | APSInt I = peekToAPSInt(S.Stk, getIntPrimType(S), Offset); |
414 | 52 | pushInt(S, I.getZExtValue()); |
415 | 52 | return true; |
416 | 52 | } |
417 | | |
418 | | // The C standard says "fabs raises no floating-point exceptions, |
419 | | // even if x is a signaling NaN. The returned value is independent of |
420 | | // the current rounding direction mode." Therefore constant folding can |
421 | | // proceed without regard to the floating point settings. |
422 | | // Reference, WG14 N2478 F.10.4.3 |
423 | | static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, |
424 | | const InterpFrame *Frame, |
425 | 5 | const Function *Func) { |
426 | 5 | const Floating &Val = getParam<Floating>(Frame, 0); |
427 | | |
428 | 5 | S.Stk.push<Floating>(Floating::abs(Val)); |
429 | 5 | return true; |
430 | 5 | } |
431 | | |
432 | | static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, |
433 | | const InterpFrame *Frame, |
434 | | const Function *Func, |
435 | 125 | const CallExpr *Call) { |
436 | 125 | PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); |
437 | 125 | APSInt Val = peekToAPSInt(S.Stk, ArgT); |
438 | 125 | pushInt(S, Val.popcount()); |
439 | 125 | return true; |
440 | 125 | } |
441 | | |
442 | | bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, |
443 | 1.50k | const CallExpr *Call) { |
444 | 1.50k | InterpFrame *Frame = S.Current; |
445 | 1.50k | APValue Dummy; |
446 | | |
447 | 1.50k | switch (F->getBuiltinID()) { |
448 | 8 | case Builtin::BI__builtin_is_constant_evaluated: |
449 | 8 | S.Stk.push<Boolean>(Boolean::from(S.inConstantContext())); |
450 | 8 | return Ret<PT_Bool>(S, OpPC, Dummy); |
451 | 8 | case Builtin::BI__builtin_assume: |
452 | 8 | return RetVoid(S, OpPC, Dummy); |
453 | 185 | case Builtin::BI__builtin_strcmp: |
454 | 185 | if (interp__builtin_strcmp(S, OpPC, Frame)) |
455 | 140 | return retInt(S, OpPC, Dummy); |
456 | 45 | break; |
457 | 358 | case Builtin::BI__builtin_strlen: |
458 | 358 | if (interp__builtin_strlen(S, OpPC, Frame)) |
459 | 195 | return retSizeT(S, OpPC, Dummy); |
460 | 163 | break; |
461 | 163 | case Builtin::BI__builtin_nan: |
462 | 82 | case Builtin::BI__builtin_nanf: |
463 | 87 | case Builtin::BI__builtin_nanl: |
464 | 87 | case Builtin::BI__builtin_nanf16: |
465 | 87 | case Builtin::BI__builtin_nanf128: |
466 | 87 | if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false)) |
467 | 77 | return Ret<PT_Float>(S, OpPC, Dummy); |
468 | 10 | break; |
469 | 34 | case Builtin::BI__builtin_nans: |
470 | 39 | case Builtin::BI__builtin_nansf: |
471 | 44 | case Builtin::BI__builtin_nansl: |
472 | 44 | case Builtin::BI__builtin_nansf16: |
473 | 44 | case Builtin::BI__builtin_nansf128: |
474 | 44 | if (interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true)) |
475 | 44 | return Ret<PT_Float>(S, OpPC, Dummy); |
476 | 0 | break; |
477 | | |
478 | 0 | case Builtin::BI__builtin_huge_val: |
479 | 0 | case Builtin::BI__builtin_huge_valf: |
480 | 0 | case Builtin::BI__builtin_huge_vall: |
481 | 0 | case Builtin::BI__builtin_huge_valf16: |
482 | 0 | case Builtin::BI__builtin_huge_valf128: |
483 | 82 | case Builtin::BI__builtin_inf: |
484 | 92 | case Builtin::BI__builtin_inff: |
485 | 102 | case Builtin::BI__builtin_infl: |
486 | 102 | case Builtin::BI__builtin_inff16: |
487 | 102 | case Builtin::BI__builtin_inff128: |
488 | 102 | if (interp__builtin_inf(S, OpPC, Frame, F)) |
489 | 102 | return Ret<PT_Float>(S, OpPC, Dummy); |
490 | 0 | break; |
491 | 32 | case Builtin::BI__builtin_copysign: |
492 | 32 | case Builtin::BI__builtin_copysignf: |
493 | 32 | case Builtin::BI__builtin_copysignl: |
494 | 32 | case Builtin::BI__builtin_copysignf128: |
495 | 32 | if (interp__builtin_copysign(S, OpPC, Frame, F)) |
496 | 32 | return Ret<PT_Float>(S, OpPC, Dummy); |
497 | 0 | break; |
498 | | |
499 | 59 | case Builtin::BI__builtin_fmin: |
500 | 82 | case Builtin::BI__builtin_fminf: |
501 | 109 | case Builtin::BI__builtin_fminl: |
502 | 132 | case Builtin::BI__builtin_fminf16: |
503 | 132 | case Builtin::BI__builtin_fminf128: |
504 | 132 | if (interp__builtin_fmin(S, OpPC, Frame, F)) |
505 | 132 | return Ret<PT_Float>(S, OpPC, Dummy); |
506 | 0 | break; |
507 | | |
508 | 23 | case Builtin::BI__builtin_fmax: |
509 | 46 | case Builtin::BI__builtin_fmaxf: |
510 | 73 | case Builtin::BI__builtin_fmaxl: |
511 | 96 | case Builtin::BI__builtin_fmaxf16: |
512 | 96 | case Builtin::BI__builtin_fmaxf128: |
513 | 96 | if (interp__builtin_fmax(S, OpPC, Frame, F)) |
514 | 96 | return Ret<PT_Float>(S, OpPC, Dummy); |
515 | 0 | break; |
516 | | |
517 | 8 | case Builtin::BI__builtin_isnan: |
518 | 8 | if (interp__builtin_isnan(S, OpPC, Frame, F)) |
519 | 8 | return retInt(S, OpPC, Dummy); |
520 | 0 | break; |
521 | 20 | case Builtin::BI__builtin_issignaling: |
522 | 20 | if (interp__builtin_issignaling(S, OpPC, Frame, F)) |
523 | 20 | return retInt(S, OpPC, Dummy); |
524 | 0 | break; |
525 | | |
526 | 10 | case Builtin::BI__builtin_isinf: |
527 | 10 | if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false)) |
528 | 10 | return retInt(S, OpPC, Dummy); |
529 | 0 | break; |
530 | | |
531 | 0 | case Builtin::BI__builtin_isinf_sign: |
532 | 0 | if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true)) |
533 | 0 | return retInt(S, OpPC, Dummy); |
534 | 0 | break; |
535 | | |
536 | 10 | case Builtin::BI__builtin_isfinite: |
537 | 10 | if (interp__builtin_isfinite(S, OpPC, Frame, F)) |
538 | 10 | return retInt(S, OpPC, Dummy); |
539 | 0 | break; |
540 | 10 | case Builtin::BI__builtin_isnormal: |
541 | 10 | if (interp__builtin_isnormal(S, OpPC, Frame, F)) |
542 | 10 | return retInt(S, OpPC, Dummy); |
543 | 0 | break; |
544 | 9 | case Builtin::BI__builtin_issubnormal: |
545 | 9 | if (interp__builtin_issubnormal(S, OpPC, Frame, F)) |
546 | 9 | return retInt(S, OpPC, Dummy); |
547 | 0 | break; |
548 | 10 | case Builtin::BI__builtin_iszero: |
549 | 10 | if (interp__builtin_iszero(S, OpPC, Frame, F)) |
550 | 10 | return retInt(S, OpPC, Dummy); |
551 | 0 | break; |
552 | 194 | case Builtin::BI__builtin_isfpclass: |
553 | 194 | if (interp__builtin_isfpclass(S, OpPC, Frame, F, Call)) |
554 | 194 | return retInt(S, OpPC, Dummy); |
555 | 0 | break; |
556 | 52 | case Builtin::BI__builtin_fpclassify: |
557 | 52 | if (interp__builtin_fpclassify(S, OpPC, Frame, F)) |
558 | 52 | return retInt(S, OpPC, Dummy); |
559 | 0 | break; |
560 | | |
561 | 5 | case Builtin::BI__builtin_fabs: |
562 | 5 | case Builtin::BI__builtin_fabsf: |
563 | 5 | case Builtin::BI__builtin_fabsl: |
564 | 5 | case Builtin::BI__builtin_fabsf128: |
565 | 5 | if (interp__builtin_fabs(S, OpPC, Frame, F)) |
566 | 5 | return Ret<PT_Float>(S, OpPC, Dummy); |
567 | 0 | break; |
568 | | |
569 | 45 | case Builtin::BI__builtin_popcount: |
570 | 85 | case Builtin::BI__builtin_popcountl: |
571 | 125 | case Builtin::BI__builtin_popcountll: |
572 | 125 | case Builtin::BI__popcnt16: // Microsoft variants of popcount |
573 | 125 | case Builtin::BI__popcnt: |
574 | 125 | case Builtin::BI__popcnt64: |
575 | 125 | if (interp__builtin_popcount(S, OpPC, Frame, F, Call)) |
576 | 125 | return retInt(S, OpPC, Dummy); |
577 | 0 | break; |
578 | | |
579 | 0 | default: |
580 | 0 | return false; |
581 | 1.50k | } |
582 | | |
583 | 218 | return false; |
584 | 1.50k | } |
585 | | |
586 | | bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, |
587 | | llvm::ArrayRef<int64_t> ArrayIndices, |
588 | 109 | int64_t &IntResult) { |
589 | 109 | CharUnits Result; |
590 | 109 | unsigned N = E->getNumComponents(); |
591 | 109 | assert(N > 0); |
592 | | |
593 | 109 | unsigned ArrayIndex = 0; |
594 | 109 | QualType CurrentType = E->getTypeSourceInfo()->getType(); |
595 | 293 | for (unsigned I = 0; I != N; ++I184 ) { |
596 | 184 | const OffsetOfNode &Node = E->getComponent(I); |
597 | 184 | switch (Node.getKind()) { |
598 | 113 | case OffsetOfNode::Field: { |
599 | 113 | const FieldDecl *MemberDecl = Node.getField(); |
600 | 113 | const RecordType *RT = CurrentType->getAs<RecordType>(); |
601 | 113 | if (!RT) |
602 | 0 | return false; |
603 | 113 | RecordDecl *RD = RT->getDecl(); |
604 | 113 | if (RD->isInvalidDecl()) |
605 | 0 | return false; |
606 | 113 | const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD); |
607 | 113 | unsigned FieldIndex = MemberDecl->getFieldIndex(); |
608 | 113 | assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type"); |
609 | 113 | Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex)); |
610 | 113 | CurrentType = MemberDecl->getType().getNonReferenceType(); |
611 | 113 | break; |
612 | 113 | } |
613 | 2 | case OffsetOfNode::Array: { |
614 | | // When generating bytecode, we put all the index expressions as Sint64 on |
615 | | // the stack. |
616 | 2 | int64_t Index = ArrayIndices[ArrayIndex]; |
617 | 2 | const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType); |
618 | 2 | if (!AT) |
619 | 0 | return false; |
620 | 2 | CurrentType = AT->getElementType(); |
621 | 2 | CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType); |
622 | 2 | Result += Index * ElementSize; |
623 | 2 | ++ArrayIndex; |
624 | 2 | break; |
625 | 2 | } |
626 | 69 | case OffsetOfNode::Base: { |
627 | 69 | const CXXBaseSpecifier *BaseSpec = Node.getBase(); |
628 | 69 | if (BaseSpec->isVirtual()) |
629 | 0 | return false; |
630 | | |
631 | | // Find the layout of the class whose base we are looking into. |
632 | 69 | const RecordType *RT = CurrentType->getAs<RecordType>(); |
633 | 69 | if (!RT) |
634 | 0 | return false; |
635 | 69 | const RecordDecl *RD = RT->getDecl(); |
636 | 69 | if (RD->isInvalidDecl()) |
637 | 0 | return false; |
638 | 69 | const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD); |
639 | | |
640 | | // Find the base class itself. |
641 | 69 | CurrentType = BaseSpec->getType(); |
642 | 69 | const RecordType *BaseRT = CurrentType->getAs<RecordType>(); |
643 | 69 | if (!BaseRT) |
644 | 0 | return false; |
645 | | |
646 | | // Add the offset to the base. |
647 | 69 | Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); |
648 | 69 | break; |
649 | 69 | } |
650 | 0 | case OffsetOfNode::Identifier: |
651 | 0 | llvm_unreachable("Dependent OffsetOfExpr?"); |
652 | 184 | } |
653 | 184 | } |
654 | | |
655 | 109 | IntResult = Result.getQuantity(); |
656 | | |
657 | 109 | return true; |
658 | 109 | } |
659 | | |
660 | | bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, |
661 | 9 | const Pointer &Ptr, const APSInt &IntValue) { |
662 | | |
663 | 9 | const Record *R = Ptr.getRecord(); |
664 | 9 | assert(R); |
665 | 9 | assert(R->getNumFields() == 1); |
666 | | |
667 | 9 | unsigned FieldOffset = R->getField(0u)->Offset; |
668 | 9 | const Pointer &FieldPtr = Ptr.atField(FieldOffset); |
669 | 9 | PrimType FieldT = *S.getContext().classify(FieldPtr.getType()); |
670 | | |
671 | 9 | INT_TYPE_SWITCH(FieldT, |
672 | 9 | FieldPtr.deref<T>() = T::from(IntValue.getSExtValue())); |
673 | 9 | FieldPtr.initialize(); |
674 | 9 | return true; |
675 | 9 | } |
676 | | |
677 | | } // namespace interp |
678 | | } // namespace clang |