clang 18.0.0git
InterpBuiltin.cpp
Go to the documentation of this file.
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 "../ExprConstShared.h"
9#include "Boolean.h"
10#include "Interp.h"
11#include "PrimType.h"
15
16namespace clang {
17namespace interp {
18
19template <typename T>
20static T getParam(const InterpFrame *Frame, unsigned Index) {
21 assert(Frame->getFunction()->getNumParams() > Index);
22 unsigned Offset = Frame->getFunction()->getParamOffset(Index);
23 return Frame->getParam<T>(Offset);
24}
25
27 const TargetInfo &TI = S.getCtx().getTargetInfo();
28 unsigned IntWidth = TI.getIntWidth();
29
30 if (IntWidth == 32)
31 return PT_Sint32;
32 else if (IntWidth == 16)
33 return PT_Sint16;
34 llvm_unreachable("Int isn't 16 or 32 bit?");
35}
36
37/// Peek an integer value from the stack into an APSInt.
38static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) {
39 if (Offset == 0)
40 Offset = align(primSize(T));
41
42 APSInt R;
44 T Val = Stk.peek<T>(Offset);
45 R = APSInt(
46 APInt(Val.bitWidth(), static_cast<uint64_t>(Val), T::isSigned()));
47 });
48
49 return R;
50}
51
52/// Pushes \p Val to the stack, as a target-dependent 'int'.
53static void pushInt(InterpState &S, int32_t Val) {
54 PrimType IntType = getIntPrimType(S);
55 if (IntType == PT_Sint32)
57 else if (IntType == PT_Sint16)
59 else
60 llvm_unreachable("Int isn't 16 or 32 bit?");
61}
62
63static void pushAPSInt(InterpState &S, const APSInt &Val) {
64 bool Signed = Val.isSigned();
65
66 if (Signed) {
67 switch (Val.getBitWidth()) {
68 case 64:
69 S.Stk.push<Integral<64, true>>(
70 Integral<64, true>::from(Val.getSExtValue()));
71 break;
72 case 32:
73 S.Stk.push<Integral<32, true>>(
74 Integral<32, true>::from(Val.getSExtValue()));
75 break;
76 case 16:
77 S.Stk.push<Integral<16, true>>(
78 Integral<16, true>::from(Val.getSExtValue()));
79 break;
80 case 8:
81 S.Stk.push<Integral<8, true>>(
82 Integral<8, true>::from(Val.getSExtValue()));
83 break;
84 default:
85 llvm_unreachable("Invalid integer bitwidth");
86 }
87 return;
88 }
89
90 // Unsigned.
91 switch (Val.getBitWidth()) {
92 case 64:
93 S.Stk.push<Integral<64, false>>(
94 Integral<64, false>::from(Val.getZExtValue()));
95 break;
96 case 32:
97 S.Stk.push<Integral<32, false>>(
98 Integral<32, false>::from(Val.getZExtValue()));
99 break;
100 case 16:
101 S.Stk.push<Integral<16, false>>(
102 Integral<16, false>::from(Val.getZExtValue()));
103 break;
104 case 8:
105 S.Stk.push<Integral<8, false>>(
106 Integral<8, false>::from(Val.getZExtValue()));
107 break;
108 default:
109 llvm_unreachable("Invalid integer bitwidth");
110 }
111}
112
113static void pushSizeT(InterpState &S, uint64_t Val) {
114 const TargetInfo &TI = S.getCtx().getTargetInfo();
115 unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType());
116
117 switch (SizeTWidth) {
118 case 64:
120 break;
121 case 32:
123 break;
124 case 16:
126 break;
127 default:
128 llvm_unreachable("We don't handle this size_t size.");
129 }
130}
131
133 std::optional<PrimType> &T) {
134 if (!T)
135 return RetVoid(S, OpPC, Result);
136
137#define RET_CASE(X) \
138 case X: \
139 return Ret<X>(S, OpPC, Result);
140 switch (*T) {
151 default:
152 llvm_unreachable("Unsupported return type for builtin function");
153 }
154#undef RET_CASE
155}
156
158 const InterpFrame *Frame) {
159 const Pointer &A = getParam<Pointer>(Frame, 0);
160 const Pointer &B = getParam<Pointer>(Frame, 1);
161
162 if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
163 return false;
164
165 assert(A.getFieldDesc()->isPrimitiveArray());
166 assert(B.getFieldDesc()->isPrimitiveArray());
167
168 unsigned IndexA = A.getIndex();
169 unsigned IndexB = B.getIndex();
170 int32_t Result = 0;
171 for (;; ++IndexA, ++IndexB) {
172 const Pointer &PA = A.atIndex(IndexA);
173 const Pointer &PB = B.atIndex(IndexB);
174 if (!CheckRange(S, OpPC, PA, AK_Read) ||
175 !CheckRange(S, OpPC, PB, AK_Read)) {
176 return false;
177 }
178 uint8_t CA = PA.deref<uint8_t>();
179 uint8_t CB = PB.deref<uint8_t>();
180
181 if (CA > CB) {
182 Result = 1;
183 break;
184 } else if (CA < CB) {
185 Result = -1;
186 break;
187 }
188 if (CA == 0 || CB == 0)
189 break;
190 }
191
192 pushInt(S, Result);
193 return true;
194}
195
197 const InterpFrame *Frame) {
198 const Pointer &StrPtr = getParam<Pointer>(Frame, 0);
199
200 if (!CheckArray(S, OpPC, StrPtr))
201 return false;
202
203 if (!CheckLive(S, OpPC, StrPtr, AK_Read))
204 return false;
205
206 if (!CheckDummy(S, OpPC, StrPtr))
207 return false;
208
209 assert(StrPtr.getFieldDesc()->isPrimitiveArray());
210
211 size_t Len = 0;
212 for (size_t I = StrPtr.getIndex();; ++I, ++Len) {
213 const Pointer &ElemPtr = StrPtr.atIndex(I);
214
215 if (!CheckRange(S, OpPC, ElemPtr, AK_Read))
216 return false;
217
218 uint8_t Val = ElemPtr.deref<uint8_t>();
219 if (Val == 0)
220 break;
221 }
222
223 pushSizeT(S, Len);
224 return true;
225}
226
228 const InterpFrame *Frame, const Function *F,
229 bool Signaling) {
230 const Pointer &Arg = getParam<Pointer>(Frame, 0);
231
232 if (!CheckLoad(S, OpPC, Arg))
233 return false;
234
235 assert(Arg.getFieldDesc()->isPrimitiveArray());
236
237 // Convert the given string to an integer using StringRef's API.
238 llvm::APInt Fill;
239 std::string Str;
240 assert(Arg.getNumElems() >= 1);
241 for (unsigned I = 0;; ++I) {
242 const Pointer &Elem = Arg.atIndex(I);
243
244 if (!CheckLoad(S, OpPC, Elem))
245 return false;
246
247 if (Elem.deref<int8_t>() == 0)
248 break;
249
250 Str += Elem.deref<char>();
251 }
252
253 // Treat empty strings as if they were zero.
254 if (Str.empty())
255 Fill = llvm::APInt(32, 0);
256 else if (StringRef(Str).getAsInteger(0, Fill))
257 return false;
258
259 const llvm::fltSemantics &TargetSemantics =
260 S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
261
263 if (S.getCtx().getTargetInfo().isNan2008()) {
264 if (Signaling)
266 llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
267 else
269 llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
270 } else {
271 // Prior to IEEE 754-2008, architectures were allowed to choose whether
272 // the first bit of their significand was set for qNaN or sNaN. MIPS chose
273 // a different encoding to what became a standard in 2008, and for pre-
274 // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as
275 // sNaN. This is now known as "legacy NaN" encoding.
276 if (Signaling)
278 llvm::APFloat::getQNaN(TargetSemantics, /*Negative=*/false, &Fill));
279 else
281 llvm::APFloat::getSNaN(TargetSemantics, /*Negative=*/false, &Fill));
282 }
283
284 S.Stk.push<Floating>(Result);
285 return true;
286}
287
289 const InterpFrame *Frame, const Function *F) {
290 const llvm::fltSemantics &TargetSemantics =
291 S.getCtx().getFloatTypeSemantics(F->getDecl()->getReturnType());
292
293 S.Stk.push<Floating>(Floating::getInf(TargetSemantics));
294 return true;
295}
296
298 const InterpFrame *Frame,
299 const Function *F) {
300 const Floating &Arg1 = getParam<Floating>(Frame, 0);
301 const Floating &Arg2 = getParam<Floating>(Frame, 1);
302
303 APFloat Copy = Arg1.getAPFloat();
304 Copy.copySign(Arg2.getAPFloat());
305 S.Stk.push<Floating>(Floating(Copy));
306
307 return true;
308}
309
311 const InterpFrame *Frame, const Function *F) {
312 const Floating &LHS = getParam<Floating>(Frame, 0);
313 const Floating &RHS = getParam<Floating>(Frame, 1);
314
316
317 // When comparing zeroes, return -0.0 if one of the zeroes is negative.
318 if (LHS.isZero() && RHS.isZero() && RHS.isNegative())
319 Result = RHS;
320 else if (LHS.isNan() || RHS < LHS)
321 Result = RHS;
322 else
323 Result = LHS;
324
325 S.Stk.push<Floating>(Result);
326 return true;
327}
328
330 const InterpFrame *Frame,
331 const Function *Func) {
332 const Floating &LHS = getParam<Floating>(Frame, 0);
333 const Floating &RHS = getParam<Floating>(Frame, 1);
334
336
337 // When comparing zeroes, return +0.0 if one of the zeroes is positive.
338 if (LHS.isZero() && RHS.isZero() && LHS.isNegative())
339 Result = RHS;
340 else if (LHS.isNan() || RHS > LHS)
341 Result = RHS;
342 else
343 Result = LHS;
344
345 S.Stk.push<Floating>(Result);
346 return true;
347}
348
349/// Defined as __builtin_isnan(...), to accommodate the fact that it can
350/// take a float, double, long double, etc.
351/// But for us, that's all a Floating anyway.
353 const InterpFrame *Frame, const Function *F) {
354 const Floating &Arg = S.Stk.peek<Floating>();
355
356 pushInt(S, Arg.isNan());
357 return true;
358}
359
361 const InterpFrame *Frame,
362 const Function *F) {
363 const Floating &Arg = S.Stk.peek<Floating>();
364
365 pushInt(S, Arg.isSignaling());
366 return true;
367}
368
370 const InterpFrame *Frame, const Function *F,
371 bool CheckSign) {
372 const Floating &Arg = S.Stk.peek<Floating>();
373 bool IsInf = Arg.isInf();
374
375 if (CheckSign)
376 pushInt(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0);
377 else
378 pushInt(S, Arg.isInf());
379 return true;
380}
381
383 const InterpFrame *Frame,
384 const Function *F) {
385 const Floating &Arg = S.Stk.peek<Floating>();
386
387 pushInt(S, Arg.isFinite());
388 return true;
389}
390
392 const InterpFrame *Frame,
393 const Function *F) {
394 const Floating &Arg = S.Stk.peek<Floating>();
395
396 pushInt(S, Arg.isNormal());
397 return true;
398}
399
401 const InterpFrame *Frame,
402 const Function *F) {
403 const Floating &Arg = S.Stk.peek<Floating>();
404
405 pushInt(S, Arg.isDenormal());
406 return true;
407}
408
410 const InterpFrame *Frame,
411 const Function *F) {
412 const Floating &Arg = S.Stk.peek<Floating>();
413
414 pushInt(S, Arg.isZero());
415 return true;
416}
417
418/// First parameter to __builtin_isfpclass is the floating value, the
419/// second one is an integral value.
421 const InterpFrame *Frame,
422 const Function *Func,
423 const CallExpr *Call) {
424 PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType());
425 APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT);
426 const Floating &F =
427 S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float)));
428
429 int32_t Result =
430 static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue());
431 pushInt(S, Result);
432
433 return true;
434}
435
436/// Five int values followed by one floating value.
438 const InterpFrame *Frame,
439 const Function *Func) {
440 const Floating &Val = S.Stk.peek<Floating>();
441
442 unsigned Index;
443 switch (Val.getCategory()) {
444 case APFloat::fcNaN:
445 Index = 0;
446 break;
447 case APFloat::fcInfinity:
448 Index = 1;
449 break;
450 case APFloat::fcNormal:
451 Index = Val.isDenormal() ? 3 : 2;
452 break;
453 case APFloat::fcZero:
454 Index = 4;
455 break;
456 }
457
458 // The last argument is first on the stack.
459 assert(Index <= 4);
460 unsigned IntSize = primSize(getIntPrimType(S));
461 unsigned Offset =
462 align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize));
463
464 APSInt I = peekToAPSInt(S.Stk, getIntPrimType(S), Offset);
465 pushInt(S, I.getZExtValue());
466 return true;
467}
468
469// The C standard says "fabs raises no floating-point exceptions,
470// even if x is a signaling NaN. The returned value is independent of
471// the current rounding direction mode." Therefore constant folding can
472// proceed without regard to the floating point settings.
473// Reference, WG14 N2478 F.10.4.3
475 const InterpFrame *Frame,
476 const Function *Func) {
477 const Floating &Val = getParam<Floating>(Frame, 0);
478
479 S.Stk.push<Floating>(Floating::abs(Val));
480 return true;
481}
482
484 const InterpFrame *Frame,
485 const Function *Func,
486 const CallExpr *Call) {
487 PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
488 APSInt Val = peekToAPSInt(S.Stk, ArgT);
489 pushInt(S, Val.popcount());
490 return true;
491}
492
494 const InterpFrame *Frame,
495 const Function *Func, const CallExpr *Call) {
496 PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
497 APSInt Val = peekToAPSInt(S.Stk, ArgT);
498 pushInt(S, Val.popcount() % 2);
499 return true;
500}
501
503 const InterpFrame *Frame,
504 const Function *Func, const CallExpr *Call) {
505 PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
506 APSInt Val = peekToAPSInt(S.Stk, ArgT);
507 pushInt(S, Val.getBitWidth() - Val.getSignificantBits());
508 return true;
509}
510
512 const InterpFrame *Frame,
513 const Function *Func,
514 const CallExpr *Call) {
515 PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
516 APSInt Val = peekToAPSInt(S.Stk, ArgT);
517 pushAPSInt(S, APSInt(Val.reverseBits(), /*IsUnsigned=*/true));
518 return true;
519}
520
522 const InterpFrame *Frame,
523 const Function *Func,
524 const CallExpr *Call) {
525 // This is an unevaluated call, so there are no arguments on the stack.
526 assert(Call->getNumArgs() == 1);
527 const Expr *Arg = Call->getArg(0);
528
529 GCCTypeClass ResultClass =
531 int32_t ReturnVal = static_cast<int32_t>(ResultClass);
532 pushInt(S, ReturnVal);
533 return true;
534}
535
537 const CallExpr *Call) {
538 InterpFrame *Frame = S.Current;
539 APValue Dummy;
540
541 QualType ReturnType = Call->getCallReturnType(S.getCtx());
542 std::optional<PrimType> ReturnT = S.getContext().classify(ReturnType);
543 // If classify failed, we assume void.
544 assert(ReturnT || ReturnType->isVoidType());
545
546 switch (F->getBuiltinID()) {
547 case Builtin::BI__builtin_is_constant_evaluated:
548 S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
549 break;
550 case Builtin::BI__builtin_assume:
551 break;
552 case Builtin::BI__builtin_strcmp:
553 if (!interp__builtin_strcmp(S, OpPC, Frame))
554 return false;
555 break;
556 case Builtin::BI__builtin_strlen:
557 if (!interp__builtin_strlen(S, OpPC, Frame))
558 return false;
559 break;
560 case Builtin::BI__builtin_nan:
561 case Builtin::BI__builtin_nanf:
562 case Builtin::BI__builtin_nanl:
563 case Builtin::BI__builtin_nanf16:
564 case Builtin::BI__builtin_nanf128:
565 if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/false))
566 return false;
567 break;
568 case Builtin::BI__builtin_nans:
569 case Builtin::BI__builtin_nansf:
570 case Builtin::BI__builtin_nansl:
571 case Builtin::BI__builtin_nansf16:
572 case Builtin::BI__builtin_nansf128:
573 if (!interp__builtin_nan(S, OpPC, Frame, F, /*Signaling=*/true))
574 return false;
575 break;
576
577 case Builtin::BI__builtin_huge_val:
578 case Builtin::BI__builtin_huge_valf:
579 case Builtin::BI__builtin_huge_vall:
580 case Builtin::BI__builtin_huge_valf16:
581 case Builtin::BI__builtin_huge_valf128:
582 case Builtin::BI__builtin_inf:
583 case Builtin::BI__builtin_inff:
584 case Builtin::BI__builtin_infl:
585 case Builtin::BI__builtin_inff16:
586 case Builtin::BI__builtin_inff128:
587 if (!interp__builtin_inf(S, OpPC, Frame, F))
588 return false;
589 break;
590 case Builtin::BI__builtin_copysign:
591 case Builtin::BI__builtin_copysignf:
592 case Builtin::BI__builtin_copysignl:
593 case Builtin::BI__builtin_copysignf128:
594 if (!interp__builtin_copysign(S, OpPC, Frame, F))
595 return false;
596 break;
597
598 case Builtin::BI__builtin_fmin:
599 case Builtin::BI__builtin_fminf:
600 case Builtin::BI__builtin_fminl:
601 case Builtin::BI__builtin_fminf16:
602 case Builtin::BI__builtin_fminf128:
603 if (!interp__builtin_fmin(S, OpPC, Frame, F))
604 return false;
605 break;
606
607 case Builtin::BI__builtin_fmax:
608 case Builtin::BI__builtin_fmaxf:
609 case Builtin::BI__builtin_fmaxl:
610 case Builtin::BI__builtin_fmaxf16:
611 case Builtin::BI__builtin_fmaxf128:
612 if (!interp__builtin_fmax(S, OpPC, Frame, F))
613 return false;
614 break;
615
616 case Builtin::BI__builtin_isnan:
617 if (!interp__builtin_isnan(S, OpPC, Frame, F))
618 return false;
619 break;
620 case Builtin::BI__builtin_issignaling:
621 if (!interp__builtin_issignaling(S, OpPC, Frame, F))
622 return false;
623 break;
624
625 case Builtin::BI__builtin_isinf:
626 if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
627 return false;
628 break;
629
630 case Builtin::BI__builtin_isinf_sign:
631 if (!interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/true))
632 return false;
633 break;
634
635 case Builtin::BI__builtin_isfinite:
636 if (!interp__builtin_isfinite(S, OpPC, Frame, F))
637 return false;
638 break;
639 case Builtin::BI__builtin_isnormal:
640 if (!interp__builtin_isnormal(S, OpPC, Frame, F))
641 return false;
642 break;
643 case Builtin::BI__builtin_issubnormal:
644 if (!interp__builtin_issubnormal(S, OpPC, Frame, F))
645 return false;
646 break;
647 case Builtin::BI__builtin_iszero:
648 if (!interp__builtin_iszero(S, OpPC, Frame, F))
649 return false;
650 break;
651 case Builtin::BI__builtin_isfpclass:
652 if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
653 return false;
654 break;
655 case Builtin::BI__builtin_fpclassify:
656 if (!interp__builtin_fpclassify(S, OpPC, Frame, F))
657 return false;
658 break;
659
660 case Builtin::BI__builtin_fabs:
661 case Builtin::BI__builtin_fabsf:
662 case Builtin::BI__builtin_fabsl:
663 case Builtin::BI__builtin_fabsf128:
664 if (!interp__builtin_fabs(S, OpPC, Frame, F))
665 return false;
666 break;
667
668 case Builtin::BI__builtin_popcount:
669 case Builtin::BI__builtin_popcountl:
670 case Builtin::BI__builtin_popcountll:
671 case Builtin::BI__popcnt16: // Microsoft variants of popcount
672 case Builtin::BI__popcnt:
673 case Builtin::BI__popcnt64:
674 if (!interp__builtin_popcount(S, OpPC, Frame, F, Call))
675 return false;
676 break;
677
678 case Builtin::BI__builtin_parity:
679 case Builtin::BI__builtin_parityl:
680 case Builtin::BI__builtin_parityll:
681 if (!interp__builtin_parity(S, OpPC, Frame, F, Call))
682 return false;
683 break;
684
685 case Builtin::BI__builtin_clrsb:
686 case Builtin::BI__builtin_clrsbl:
687 case Builtin::BI__builtin_clrsbll:
688 if (!interp__builtin_clrsb(S, OpPC, Frame, F, Call))
689 return false;
690 break;
691
692 case Builtin::BI__builtin_bitreverse8:
693 case Builtin::BI__builtin_bitreverse16:
694 case Builtin::BI__builtin_bitreverse32:
695 case Builtin::BI__builtin_bitreverse64:
696 if (!interp__builtin_bitreverse(S, OpPC, Frame, F, Call))
697 return false;
698 break;
699
700 case Builtin::BI__builtin_classify_type:
701 if (!interp__builtin_classify_type(S, OpPC, Frame, F, Call))
702 return false;
703 break;
704
705 default:
706 return false;
707 }
708
709 return retPrimValue(S, OpPC, Dummy, ReturnT);
710}
711
713 llvm::ArrayRef<int64_t> ArrayIndices,
714 int64_t &IntResult) {
716 unsigned N = E->getNumComponents();
717 assert(N > 0);
718
719 unsigned ArrayIndex = 0;
720 QualType CurrentType = E->getTypeSourceInfo()->getType();
721 for (unsigned I = 0; I != N; ++I) {
722 const OffsetOfNode &Node = E->getComponent(I);
723 switch (Node.getKind()) {
724 case OffsetOfNode::Field: {
725 const FieldDecl *MemberDecl = Node.getField();
726 const RecordType *RT = CurrentType->getAs<RecordType>();
727 if (!RT)
728 return false;
729 RecordDecl *RD = RT->getDecl();
730 if (RD->isInvalidDecl())
731 return false;
732 const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
733 unsigned FieldIndex = MemberDecl->getFieldIndex();
734 assert(FieldIndex < RL.getFieldCount() && "offsetof field in wrong type");
735 Result += S.getCtx().toCharUnitsFromBits(RL.getFieldOffset(FieldIndex));
736 CurrentType = MemberDecl->getType().getNonReferenceType();
737 break;
738 }
739 case OffsetOfNode::Array: {
740 // When generating bytecode, we put all the index expressions as Sint64 on
741 // the stack.
742 int64_t Index = ArrayIndices[ArrayIndex];
743 const ArrayType *AT = S.getCtx().getAsArrayType(CurrentType);
744 if (!AT)
745 return false;
746 CurrentType = AT->getElementType();
747 CharUnits ElementSize = S.getCtx().getTypeSizeInChars(CurrentType);
748 Result += Index * ElementSize;
749 ++ArrayIndex;
750 break;
751 }
752 case OffsetOfNode::Base: {
753 const CXXBaseSpecifier *BaseSpec = Node.getBase();
754 if (BaseSpec->isVirtual())
755 return false;
756
757 // Find the layout of the class whose base we are looking into.
758 const RecordType *RT = CurrentType->getAs<RecordType>();
759 if (!RT)
760 return false;
761 const RecordDecl *RD = RT->getDecl();
762 if (RD->isInvalidDecl())
763 return false;
764 const ASTRecordLayout &RL = S.getCtx().getASTRecordLayout(RD);
765
766 // Find the base class itself.
767 CurrentType = BaseSpec->getType();
768 const RecordType *BaseRT = CurrentType->getAs<RecordType>();
769 if (!BaseRT)
770 return false;
771
772 // Add the offset to the base.
773 Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()));
774 break;
775 }
777 llvm_unreachable("Dependent OffsetOfExpr?");
778 }
779 }
780
781 IntResult = Result.getQuantity();
782
783 return true;
784}
785
787 const Pointer &Ptr, const APSInt &IntValue) {
788
789 const Record *R = Ptr.getRecord();
790 assert(R);
791 assert(R->getNumFields() == 1);
792
793 unsigned FieldOffset = R->getField(0u)->Offset;
794 const Pointer &FieldPtr = Ptr.atField(FieldOffset);
795 PrimType FieldT = *S.getContext().classify(FieldPtr.getType());
796
797 INT_TYPE_SWITCH(FieldT,
798 FieldPtr.deref<T>() = T::from(IntValue.getSExtValue()));
799 FieldPtr.initialize();
800 return true;
801}
802
803} // namespace interp
804} // namespace clang
DynTypedNode Node
Defines enum values for all the target-independent builtin functions.
GCCTypeClass
Values returned by __builtin_classify_type, chosen to match the values produced by GCC's builtin.
GCCTypeClass EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts)
EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way as GCC.
#define RET_CASE(X)
#define INT_TYPE_SWITCH(Expr, B)
Definition: PrimType.h:129
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
Definition: RecordLayout.h:38
unsigned getFieldCount() const
getFieldCount - Get the number of fields in the layout.
Definition: RecordLayout.h:196
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
Definition: RecordLayout.h:200
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:249
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition: Type.h:3145
QualType getElementType() const
Definition: Type.h:3157
Represents a base class of a C++ class.
Definition: DeclCXX.h:146
bool isVirtual() const
Determines whether the base class is a virtual base class (or not).
Definition: DeclCXX.h:203
QualType getType() const
Retrieves the type of the base class.
Definition: DeclCXX.h:249
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2847
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
bool isInvalidDecl() const
Definition: DeclBase.h:592
This represents one expression.
Definition: Expr.h:110
QualType getType() const
Definition: Expr.h:142
Represents a member of a struct/union/class.
Definition: Decl.h:3015
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition: Decl.cpp:4582
QualType getReturnType() const
Definition: Decl.h:2712
OffsetOfExpr - [C99 7.17] - This represents an expression of the form offsetof(record-type,...
Definition: Expr.h:2492
const OffsetOfNode & getComponent(unsigned Idx) const
Definition: Expr.h:2539
TypeSourceInfo * getTypeSourceInfo() const
Definition: Expr.h:2532
unsigned getNumComponents() const
Definition: Expr.h:2549
Helper class for OffsetOfExpr.
Definition: Expr.h:2386
@ Array
An index into an array.
Definition: Expr.h:2391
@ Identifier
A field in a dependent type, known only by its name.
Definition: Expr.h:2395
@ Field
A field.
Definition: Expr.h:2393
@ Base
An implicit indirection through a C++ base class, when the field found is in a base class.
Definition: Expr.h:2398
A (possibly-)qualified type.
Definition: Type.h:736
QualType getNonReferenceType() const
If Type is a reference type (e.g., const int&), returns the type that the reference refers to ("const...
Definition: Type.h:6981
Represents a struct/union/class.
Definition: Decl.h:4117
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4971
RecordDecl * getDecl() const
Definition: Type.h:4981
const LangOptions & getLangOpts() const
Definition: Sema.h:1681
Exposes information about the current target.
Definition: TargetInfo.h:212
unsigned getTypeWidth(IntType T) const
Return the width (in bits) of the specified integer type enum.
Definition: TargetInfo.cpp:269
unsigned getIntWidth() const
getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for this target,...
Definition: TargetInfo.h:501
IntType getSizeType() const
Definition: TargetInfo.h:363
QualType getType() const
Return the type wrapped by this type source info.
Definition: Type.h:6763
bool isVoidType() const
Definition: Type.h:7352
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:7558
QualType getType() const
Definition: Decl.h:715
Wrapper around boolean types.
Definition: Boolean.h:25
static Boolean from(T Value)
Definition: Boolean.h:98
Pointer into the code segment.
Definition: Source.h:30
bool isInf() const
Definition: Floating.h:97
const APFloat & getAPFloat() const
Definition: Floating.h:40
llvm::FPClassTest classify() const
Definition: Floating.h:101
bool isSignaling() const
Definition: Floating.h:96
bool isNormal() const
Definition: Floating.h:99
bool isNan() const
Definition: Floating.h:95
bool isZero() const
Definition: Floating.h:91
bool isNegative() const
Definition: Floating.h:89
static Floating getInf(const llvm::fltSemantics &Sem)
Definition: Floating.h:37
bool isFinite() const
Definition: Floating.h:98
bool isDenormal() const
Definition: Floating.h:100
static Floating abs(const Floating &F)
Definition: Floating.h:159
APFloat::fltCategory getCategory() const
Definition: Floating.h:102
Base class for stack frames, shared between VM and walker.
Definition: Frame.h:25
Bytecode function.
Definition: Function.h:76
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:91
unsigned getBuiltinID() const
Definition: Function.h:178
Wrapper around numeric types.
Definition: Integral.h:50
static Integral from(ValT Value)
Definition: Integral.h:169
Frame storing local variables.
Definition: InterpFrame.h:28
Stack frame storing temporaries and parameters.
Definition: InterpStack.h:26
T & peek() const
Returns a reference to the value on the top of the stack.
Definition: InterpStack.h:68
Interpreter context.
Definition: InterpState.h:35
A pointer to a memory block, live or dead.
Definition: Pointer.h:65
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:351
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:104
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:116
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:375
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:346
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:236
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:229
void initialize() const
Initializes a field.
Definition: Pointer.cpp:183
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:289
Structure/Class descriptor.
Definition: Record.h:25
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:30
unsigned getNumFields() const
Definition: Record.h:81
Defines the clang::TargetInfo interface.
static void pushAPSInt(InterpState &S, const APSInt &Val)
llvm::APFloat APFloat
Definition: Floating.h:23
static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset=0)
Peek an integer value from the stack into an APSInt.
static bool interp__builtin_classify_type(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call)
llvm::APInt APInt
Definition: Integral.h:29
static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, llvm::ArrayRef< int64_t > ArrayIndices, int64_t &Result)
Interpret an offsetof operation.
static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F, bool Signaling)
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, const Pointer &Ptr, const APSInt &IntValue)
Sets the given integral value to the pointer, which is of a std::{weak,partial,strong}_ordering type.
static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func)
static bool interp__builtin_inf(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
static void pushInt(InterpState &S, int32_t Val)
Pushes Val to the stack, as a target-dependent 'int'.
static bool interp__builtin_clrsb(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call)
static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call)
static T getParam(const InterpFrame *Frame, unsigned Index)
PrimType getIntPrimType(const InterpState &S)
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
Definition: PrimType.h:91
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is in range.
Definition: Interp.cpp:220
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK)
Checks if a pointer is live and accessible.
Definition: Interp.cpp:177
static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result, std::optional< PrimType > &T)
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:32
static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, const InterpFrame *Frame)
static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func)
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a value can be loaded from a block.
Definition: Interp.cpp:292
bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if the array is offsetable.
Definition: Interp.cpp:169
static void pushSizeT(InterpState &S, uint64_t Val)
static bool interp__builtin_parity(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call)
size_t primSize(PrimType Type)
Returns the size of a primitive type in bytes.
Definition: PrimType.cpp:22
static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call)
Interpret a builtin function.
llvm::APSInt APSInt
Definition: Floating.h:24
static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F, bool CheckSign)
static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, const InterpFrame *Frame)
bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Checks if a pointer is a dummy pointer.
Definition: Interp.cpp:207
static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func)
Five int values followed by one floating value.
static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
Defined as __builtin_isnan(...), to accommodate the fact that it can take a float,...
static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call)
First parameter to __builtin_isfpclass is the floating value, the second one is an integral value.
static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call)
static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F)
bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.h:244
@ Result
The result type of a method or function.
@ AK_Read
Definition: State.h:27
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:184