1 //===--- InterpBuiltin.cpp - Interpreter for the constexpr VM ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
11 #include "clang/AST/RecordLayout.h"
12 #include "clang/Basic/Builtins.h"
13 #include "clang/Basic/TargetInfo.h"
19 static T
getParam(const InterpFrame
*Frame
, unsigned Index
) {
20 assert(Frame
->getFunction()->getNumParams() > Index
);
21 unsigned Offset
= Frame
->getFunction()->getParamOffset(Index
);
22 return Frame
->getParam
<T
>(Offset
);
25 PrimType
getIntPrimType(const InterpState
&S
) {
26 const TargetInfo
&TI
= S
.getCtx().getTargetInfo();
27 unsigned IntWidth
= TI
.getIntWidth();
31 else if (IntWidth
== 16)
33 llvm_unreachable("Int isn't 16 or 32 bit?");
36 /// Peek an integer value from the stack into an APSInt.
37 static APSInt
peekToAPSInt(InterpStack
&Stk
, PrimType T
, size_t Offset
= 0) {
39 Offset
= align(primSize(T
));
43 T Val
= Stk
.peek
<T
>(Offset
);
45 APInt(Val
.bitWidth(), static_cast<uint64_t>(Val
), T::isSigned()));
51 /// Pushes \p Val to the stack, as a target-dependent 'int'.
52 static void pushInt(InterpState
&S
, int32_t Val
) {
53 PrimType IntType
= getIntPrimType(S
);
54 if (IntType
== PT_Sint32
)
55 S
.Stk
.push
<Integral
<32, true>>(Integral
<32, true>::from(Val
));
56 else if (IntType
== PT_Sint16
)
57 S
.Stk
.push
<Integral
<16, true>>(Integral
<16, true>::from(Val
));
59 llvm_unreachable("Int isn't 16 or 32 bit?");
62 static bool retInt(InterpState
&S
, CodePtr OpPC
, APValue
&Result
) {
63 PrimType IntType
= getIntPrimType(S
);
64 if (IntType
== PT_Sint32
)
65 return Ret
<PT_Sint32
>(S
, OpPC
, Result
);
66 else if (IntType
== PT_Sint16
)
67 return Ret
<PT_Sint16
>(S
, OpPC
, Result
);
68 llvm_unreachable("Int isn't 16 or 32 bit?");
71 static void pushSizeT(InterpState
&S
, uint64_t Val
) {
72 const TargetInfo
&TI
= S
.getCtx().getTargetInfo();
73 unsigned SizeTWidth
= TI
.getTypeWidth(TI
.getSizeType());
77 S
.Stk
.push
<Integral
<64, false>>(Integral
<64, false>::from(Val
));
80 S
.Stk
.push
<Integral
<32, false>>(Integral
<32, false>::from(Val
));
83 S
.Stk
.push
<Integral
<16, false>>(Integral
<16, false>::from(Val
));
86 llvm_unreachable("We don't handle this size_t size.");
90 static bool retSizeT(InterpState
&S
, CodePtr OpPC
, APValue
&Result
) {
91 const TargetInfo
&TI
= S
.getCtx().getTargetInfo();
92 unsigned SizeTWidth
= TI
.getTypeWidth(TI
.getSizeType());
96 return Ret
<PT_Uint64
>(S
, OpPC
, Result
);
98 return Ret
<PT_Uint32
>(S
, OpPC
, Result
);
100 return Ret
<PT_Uint16
>(S
, OpPC
, Result
);
103 llvm_unreachable("size_t isn't 64 or 32 bit?");
106 static bool interp__builtin_strcmp(InterpState
&S
, CodePtr OpPC
,
107 const InterpFrame
*Frame
) {
108 const Pointer
&A
= getParam
<Pointer
>(Frame
, 0);
109 const Pointer
&B
= getParam
<Pointer
>(Frame
, 1);
111 if (!CheckLive(S
, OpPC
, A
, AK_Read
) || !CheckLive(S
, OpPC
, B
, AK_Read
))
114 assert(A
.getFieldDesc()->isPrimitiveArray());
115 assert(B
.getFieldDesc()->isPrimitiveArray());
117 unsigned IndexA
= A
.getIndex();
118 unsigned IndexB
= B
.getIndex();
120 for (;; ++IndexA
, ++IndexB
) {
121 const Pointer
&PA
= A
.atIndex(IndexA
);
122 const Pointer
&PB
= B
.atIndex(IndexB
);
123 if (!CheckRange(S
, OpPC
, PA
, AK_Read
) ||
124 !CheckRange(S
, OpPC
, PB
, AK_Read
)) {
127 uint8_t CA
= PA
.deref
<uint8_t>();
128 uint8_t CB
= PB
.deref
<uint8_t>();
133 } else if (CA
< CB
) {
137 if (CA
== 0 || CB
== 0)
145 static bool interp__builtin_strlen(InterpState
&S
, CodePtr OpPC
,
146 const InterpFrame
*Frame
) {
147 const Pointer
&StrPtr
= getParam
<Pointer
>(Frame
, 0);
149 if (!CheckArray(S
, OpPC
, StrPtr
))
152 if (!CheckLive(S
, OpPC
, StrPtr
, AK_Read
))
155 if (!CheckDummy(S
, OpPC
, StrPtr
))
158 assert(StrPtr
.getFieldDesc()->isPrimitiveArray());
161 for (size_t I
= StrPtr
.getIndex();; ++I
, ++Len
) {
162 const Pointer
&ElemPtr
= StrPtr
.atIndex(I
);
164 if (!CheckRange(S
, OpPC
, ElemPtr
, AK_Read
))
167 uint8_t Val
= ElemPtr
.deref
<uint8_t>();
176 static bool interp__builtin_nan(InterpState
&S
, CodePtr OpPC
,
177 const InterpFrame
*Frame
, const Function
*F
,
179 const Pointer
&Arg
= getParam
<Pointer
>(Frame
, 0);
181 if (!CheckLoad(S
, OpPC
, Arg
))
184 assert(Arg
.getFieldDesc()->isPrimitiveArray());
186 // Convert the given string to an integer using StringRef's API.
189 assert(Arg
.getNumElems() >= 1);
190 for (unsigned I
= 0;; ++I
) {
191 const Pointer
&Elem
= Arg
.atIndex(I
);
193 if (!CheckLoad(S
, OpPC
, Elem
))
196 if (Elem
.deref
<int8_t>() == 0)
199 Str
+= Elem
.deref
<char>();
202 // Treat empty strings as if they were zero.
204 Fill
= llvm::APInt(32, 0);
205 else if (StringRef(Str
).getAsInteger(0, Fill
))
208 const llvm::fltSemantics
&TargetSemantics
=
209 S
.getCtx().getFloatTypeSemantics(F
->getDecl()->getReturnType());
212 if (S
.getCtx().getTargetInfo().isNan2008()) {
215 llvm::APFloat::getSNaN(TargetSemantics
, /*Negative=*/false, &Fill
));
218 llvm::APFloat::getQNaN(TargetSemantics
, /*Negative=*/false, &Fill
));
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.
227 llvm::APFloat::getQNaN(TargetSemantics
, /*Negative=*/false, &Fill
));
230 llvm::APFloat::getSNaN(TargetSemantics
, /*Negative=*/false, &Fill
));
233 S
.Stk
.push
<Floating
>(Result
);
237 static bool interp__builtin_inf(InterpState
&S
, CodePtr OpPC
,
238 const InterpFrame
*Frame
, const Function
*F
) {
239 const llvm::fltSemantics
&TargetSemantics
=
240 S
.getCtx().getFloatTypeSemantics(F
->getDecl()->getReturnType());
242 S
.Stk
.push
<Floating
>(Floating::getInf(TargetSemantics
));
246 static bool interp__builtin_copysign(InterpState
&S
, CodePtr OpPC
,
247 const InterpFrame
*Frame
,
249 const Floating
&Arg1
= getParam
<Floating
>(Frame
, 0);
250 const Floating
&Arg2
= getParam
<Floating
>(Frame
, 1);
252 APFloat Copy
= Arg1
.getAPFloat();
253 Copy
.copySign(Arg2
.getAPFloat());
254 S
.Stk
.push
<Floating
>(Floating(Copy
));
259 static bool interp__builtin_fmin(InterpState
&S
, CodePtr OpPC
,
260 const InterpFrame
*Frame
, const Function
*F
) {
261 const Floating
&LHS
= getParam
<Floating
>(Frame
, 0);
262 const Floating
&RHS
= getParam
<Floating
>(Frame
, 1);
266 // When comparing zeroes, return -0.0 if one of the zeroes is negative.
267 if (LHS
.isZero() && RHS
.isZero() && RHS
.isNegative())
269 else if (LHS
.isNan() || RHS
< LHS
)
274 S
.Stk
.push
<Floating
>(Result
);
278 static bool interp__builtin_fmax(InterpState
&S
, CodePtr OpPC
,
279 const InterpFrame
*Frame
,
280 const Function
*Func
) {
281 const Floating
&LHS
= getParam
<Floating
>(Frame
, 0);
282 const Floating
&RHS
= getParam
<Floating
>(Frame
, 1);
286 // When comparing zeroes, return +0.0 if one of the zeroes is positive.
287 if (LHS
.isZero() && RHS
.isZero() && LHS
.isNegative())
289 else if (LHS
.isNan() || RHS
> LHS
)
294 S
.Stk
.push
<Floating
>(Result
);
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 const InterpFrame
*Frame
, const Function
*F
) {
303 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
305 pushInt(S
, Arg
.isNan());
309 static bool interp__builtin_issignaling(InterpState
&S
, CodePtr OpPC
,
310 const InterpFrame
*Frame
,
312 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
314 pushInt(S
, Arg
.isSignaling());
318 static bool interp__builtin_isinf(InterpState
&S
, CodePtr OpPC
,
319 const InterpFrame
*Frame
, const Function
*F
,
321 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
322 bool IsInf
= Arg
.isInf();
325 pushInt(S
, IsInf
? (Arg
.isNegative() ? -1 : 1) : 0);
327 pushInt(S
, Arg
.isInf());
331 static bool interp__builtin_isfinite(InterpState
&S
, CodePtr OpPC
,
332 const InterpFrame
*Frame
,
334 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
336 pushInt(S
, Arg
.isFinite());
340 static bool interp__builtin_isnormal(InterpState
&S
, CodePtr OpPC
,
341 const InterpFrame
*Frame
,
343 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
345 pushInt(S
, Arg
.isNormal());
349 static bool interp__builtin_issubnormal(InterpState
&S
, CodePtr OpPC
,
350 const InterpFrame
*Frame
,
352 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
354 pushInt(S
, Arg
.isDenormal());
358 static bool interp__builtin_iszero(InterpState
&S
, CodePtr OpPC
,
359 const InterpFrame
*Frame
,
361 const Floating
&Arg
= S
.Stk
.peek
<Floating
>();
363 pushInt(S
, Arg
.isZero());
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 const CallExpr
*Call
) {
373 PrimType FPClassArgT
= *S
.getContext().classify(Call
->getArg(1)->getType());
374 APSInt FPClassArg
= peekToAPSInt(S
.Stk
, FPClassArgT
);
376 S
.Stk
.peek
<Floating
>(align(primSize(FPClassArgT
) + primSize(PT_Float
)));
379 static_cast<int32_t>((F
.classify() & FPClassArg
).getZExtValue());
385 /// Five int values followed by one floating value.
386 static bool interp__builtin_fpclassify(InterpState
&S
, CodePtr OpPC
,
387 const InterpFrame
*Frame
,
388 const Function
*Func
) {
389 const Floating
&Val
= S
.Stk
.peek
<Floating
>();
392 switch (Val
.getCategory()) {
396 case APFloat::fcInfinity
:
399 case APFloat::fcNormal
:
400 Index
= Val
.isDenormal() ? 3 : 2;
402 case APFloat::fcZero
:
407 // The last argument is first on the stack.
409 unsigned IntSize
= primSize(getIntPrimType(S
));
411 align(primSize(PT_Float
)) + ((1 + (4 - Index
)) * align(IntSize
));
413 APSInt I
= peekToAPSInt(S
.Stk
, getIntPrimType(S
), Offset
);
414 pushInt(S
, I
.getZExtValue());
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 const Function
*Func
) {
426 const Floating
&Val
= getParam
<Floating
>(Frame
, 0);
428 S
.Stk
.push
<Floating
>(Floating::abs(Val
));
432 static bool interp__builtin_popcount(InterpState
&S
, CodePtr OpPC
,
433 const InterpFrame
*Frame
,
434 const Function
*Func
,
435 const CallExpr
*Call
) {
436 PrimType ArgT
= *S
.getContext().classify(Call
->getArg(0)->getType());
437 APSInt Val
= peekToAPSInt(S
.Stk
, ArgT
);
438 pushInt(S
, Val
.popcount());
442 bool InterpretBuiltin(InterpState
&S
, CodePtr OpPC
, const Function
*F
,
443 const CallExpr
*Call
) {
444 InterpFrame
*Frame
= S
.Current
;
447 switch (F
->getBuiltinID()) {
448 case Builtin::BI__builtin_is_constant_evaluated
:
449 S
.Stk
.push
<Boolean
>(Boolean::from(S
.inConstantContext()));
450 return Ret
<PT_Bool
>(S
, OpPC
, Dummy
);
451 case Builtin::BI__builtin_assume
:
452 return RetVoid(S
, OpPC
, Dummy
);
453 case Builtin::BI__builtin_strcmp
:
454 if (interp__builtin_strcmp(S
, OpPC
, Frame
))
455 return retInt(S
, OpPC
, Dummy
);
457 case Builtin::BI__builtin_strlen
:
458 if (interp__builtin_strlen(S
, OpPC
, Frame
))
459 return retSizeT(S
, OpPC
, Dummy
);
461 case Builtin::BI__builtin_nan
:
462 case Builtin::BI__builtin_nanf
:
463 case Builtin::BI__builtin_nanl
:
464 case Builtin::BI__builtin_nanf16
:
465 case Builtin::BI__builtin_nanf128
:
466 if (interp__builtin_nan(S
, OpPC
, Frame
, F
, /*Signaling=*/false))
467 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
469 case Builtin::BI__builtin_nans
:
470 case Builtin::BI__builtin_nansf
:
471 case Builtin::BI__builtin_nansl
:
472 case Builtin::BI__builtin_nansf16
:
473 case Builtin::BI__builtin_nansf128
:
474 if (interp__builtin_nan(S
, OpPC
, Frame
, F
, /*Signaling=*/true))
475 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
478 case Builtin::BI__builtin_huge_val
:
479 case Builtin::BI__builtin_huge_valf
:
480 case Builtin::BI__builtin_huge_vall
:
481 case Builtin::BI__builtin_huge_valf16
:
482 case Builtin::BI__builtin_huge_valf128
:
483 case Builtin::BI__builtin_inf
:
484 case Builtin::BI__builtin_inff
:
485 case Builtin::BI__builtin_infl
:
486 case Builtin::BI__builtin_inff16
:
487 case Builtin::BI__builtin_inff128
:
488 if (interp__builtin_inf(S
, OpPC
, Frame
, F
))
489 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
491 case Builtin::BI__builtin_copysign
:
492 case Builtin::BI__builtin_copysignf
:
493 case Builtin::BI__builtin_copysignl
:
494 case Builtin::BI__builtin_copysignf128
:
495 if (interp__builtin_copysign(S
, OpPC
, Frame
, F
))
496 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
499 case Builtin::BI__builtin_fmin
:
500 case Builtin::BI__builtin_fminf
:
501 case Builtin::BI__builtin_fminl
:
502 case Builtin::BI__builtin_fminf16
:
503 case Builtin::BI__builtin_fminf128
:
504 if (interp__builtin_fmin(S
, OpPC
, Frame
, F
))
505 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
508 case Builtin::BI__builtin_fmax
:
509 case Builtin::BI__builtin_fmaxf
:
510 case Builtin::BI__builtin_fmaxl
:
511 case Builtin::BI__builtin_fmaxf16
:
512 case Builtin::BI__builtin_fmaxf128
:
513 if (interp__builtin_fmax(S
, OpPC
, Frame
, F
))
514 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
517 case Builtin::BI__builtin_isnan
:
518 if (interp__builtin_isnan(S
, OpPC
, Frame
, F
))
519 return retInt(S
, OpPC
, Dummy
);
521 case Builtin::BI__builtin_issignaling
:
522 if (interp__builtin_issignaling(S
, OpPC
, Frame
, F
))
523 return retInt(S
, OpPC
, Dummy
);
526 case Builtin::BI__builtin_isinf
:
527 if (interp__builtin_isinf(S
, OpPC
, Frame
, F
, /*Sign=*/false))
528 return retInt(S
, OpPC
, Dummy
);
531 case Builtin::BI__builtin_isinf_sign
:
532 if (interp__builtin_isinf(S
, OpPC
, Frame
, F
, /*Sign=*/true))
533 return retInt(S
, OpPC
, Dummy
);
536 case Builtin::BI__builtin_isfinite
:
537 if (interp__builtin_isfinite(S
, OpPC
, Frame
, F
))
538 return retInt(S
, OpPC
, Dummy
);
540 case Builtin::BI__builtin_isnormal
:
541 if (interp__builtin_isnormal(S
, OpPC
, Frame
, F
))
542 return retInt(S
, OpPC
, Dummy
);
544 case Builtin::BI__builtin_issubnormal
:
545 if (interp__builtin_issubnormal(S
, OpPC
, Frame
, F
))
546 return retInt(S
, OpPC
, Dummy
);
548 case Builtin::BI__builtin_iszero
:
549 if (interp__builtin_iszero(S
, OpPC
, Frame
, F
))
550 return retInt(S
, OpPC
, Dummy
);
552 case Builtin::BI__builtin_isfpclass
:
553 if (interp__builtin_isfpclass(S
, OpPC
, Frame
, F
, Call
))
554 return retInt(S
, OpPC
, Dummy
);
556 case Builtin::BI__builtin_fpclassify
:
557 if (interp__builtin_fpclassify(S
, OpPC
, Frame
, F
))
558 return retInt(S
, OpPC
, Dummy
);
561 case Builtin::BI__builtin_fabs
:
562 case Builtin::BI__builtin_fabsf
:
563 case Builtin::BI__builtin_fabsl
:
564 case Builtin::BI__builtin_fabsf128
:
565 if (interp__builtin_fabs(S
, OpPC
, Frame
, F
))
566 return Ret
<PT_Float
>(S
, OpPC
, Dummy
);
569 case Builtin::BI__builtin_popcount
:
570 case Builtin::BI__builtin_popcountl
:
571 case Builtin::BI__builtin_popcountll
:
572 case Builtin::BI__popcnt16
: // Microsoft variants of popcount
573 case Builtin::BI__popcnt
:
574 case Builtin::BI__popcnt64
:
575 if (interp__builtin_popcount(S
, OpPC
, Frame
, F
, Call
))
576 return retInt(S
, OpPC
, Dummy
);
586 bool InterpretOffsetOf(InterpState
&S
, CodePtr OpPC
, const OffsetOfExpr
*E
,
587 llvm::ArrayRef
<int64_t> ArrayIndices
,
588 int64_t &IntResult
) {
590 unsigned N
= E
->getNumComponents();
593 unsigned ArrayIndex
= 0;
594 QualType CurrentType
= E
->getTypeSourceInfo()->getType();
595 for (unsigned I
= 0; I
!= N
; ++I
) {
596 const OffsetOfNode
&Node
= E
->getComponent(I
);
597 switch (Node
.getKind()) {
598 case OffsetOfNode::Field
: {
599 const FieldDecl
*MemberDecl
= Node
.getField();
600 const RecordType
*RT
= CurrentType
->getAs
<RecordType
>();
603 RecordDecl
*RD
= RT
->getDecl();
604 if (RD
->isInvalidDecl())
606 const ASTRecordLayout
&RL
= S
.getCtx().getASTRecordLayout(RD
);
607 unsigned FieldIndex
= MemberDecl
->getFieldIndex();
608 assert(FieldIndex
< RL
.getFieldCount() && "offsetof field in wrong type");
609 Result
+= S
.getCtx().toCharUnitsFromBits(RL
.getFieldOffset(FieldIndex
));
610 CurrentType
= MemberDecl
->getType().getNonReferenceType();
613 case OffsetOfNode::Array
: {
614 // When generating bytecode, we put all the index expressions as Sint64 on
616 int64_t Index
= ArrayIndices
[ArrayIndex
];
617 const ArrayType
*AT
= S
.getCtx().getAsArrayType(CurrentType
);
620 CurrentType
= AT
->getElementType();
621 CharUnits ElementSize
= S
.getCtx().getTypeSizeInChars(CurrentType
);
622 Result
+= Index
* ElementSize
;
626 case OffsetOfNode::Base
: {
627 const CXXBaseSpecifier
*BaseSpec
= Node
.getBase();
628 if (BaseSpec
->isVirtual())
631 // Find the layout of the class whose base we are looking into.
632 const RecordType
*RT
= CurrentType
->getAs
<RecordType
>();
635 const RecordDecl
*RD
= RT
->getDecl();
636 if (RD
->isInvalidDecl())
638 const ASTRecordLayout
&RL
= S
.getCtx().getASTRecordLayout(RD
);
640 // Find the base class itself.
641 CurrentType
= BaseSpec
->getType();
642 const RecordType
*BaseRT
= CurrentType
->getAs
<RecordType
>();
646 // Add the offset to the base.
647 Result
+= RL
.getBaseClassOffset(cast
<CXXRecordDecl
>(BaseRT
->getDecl()));
650 case OffsetOfNode::Identifier
:
651 llvm_unreachable("Dependent OffsetOfExpr?");
655 IntResult
= Result
.getQuantity();
660 bool SetThreeWayComparisonField(InterpState
&S
, CodePtr OpPC
,
661 const Pointer
&Ptr
, const APSInt
&IntValue
) {
663 const Record
*R
= Ptr
.getRecord();
665 assert(R
->getNumFields() == 1);
667 unsigned FieldOffset
= R
->getField(0u)->Offset
;
668 const Pointer
&FieldPtr
= Ptr
.atField(FieldOffset
);
669 PrimType FieldT
= *S
.getContext().classify(FieldPtr
.getType());
671 INT_TYPE_SWITCH(FieldT
,
672 FieldPtr
.deref
<T
>() = T::from(IntValue
.getSExtValue()));
673 FieldPtr
.initialize();
677 } // namespace interp