diff options
author | Timm Baeder <tbaeder@redhat.com> | 2025-06-05 07:36:25 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-06-05 07:36:25 +0200 |
commit | c7a93efa50c777c4d0618a41f0c178edddc88db6 (patch) | |
tree | d6a574ad8e8e7c16e6b6cb30671940d60a638866 /clang/lib/AST/ByteCode/InterpBuiltin.cpp | |
parent | a56442529cbd340ae9e2e73b236a3267906f93dd (diff) | |
download | llvm-c7a93efa50c777c4d0618a41f0c178edddc88db6.zip llvm-c7a93efa50c777c4d0618a41f0c178edddc88db6.tar.gz llvm-c7a93efa50c777c4d0618a41f0c178edddc88db6.tar.bz2 |
[clang][bytecode] Pop builtin args from the stack while evaluating (#142832)
Instead of just peek()ing the values when evaluating the builtins and
later classify()ing all the call args once again to remove them, just do
it while evaluating. This saves quite a bit of code.
Diffstat (limited to 'clang/lib/AST/ByteCode/InterpBuiltin.cpp')
-rw-r--r-- | clang/lib/AST/ByteCode/InterpBuiltin.cpp | 718 |
1 files changed, 259 insertions, 459 deletions
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 89c626d..a7c3683 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -41,25 +41,12 @@ static bool isNoopBuiltin(unsigned ID) { return false; } -static unsigned callArgSize(const InterpState &S, const CallExpr *C) { - unsigned O = 0; - - for (const Expr *E : C->arguments()) { - O += align(primSize(*S.getContext().classify(E))); - } - - return O; +static void discard(InterpStack &Stk, PrimType T) { + TYPE_SWITCH(T, { Stk.discard<T>(); }); } -/// Peek an integer value from the stack into an APSInt. -static APSInt peekToAPSInt(InterpStack &Stk, PrimType T, size_t Offset = 0) { - if (Offset == 0) - Offset = align(primSize(T)); - - APSInt R; - INT_TYPE_SWITCH(T, R = Stk.peek<T>(Offset).toAPSInt()); - - return R; +static APSInt popToAPSInt(InterpStack &Stk, PrimType T) { + INT_TYPE_SWITCH(T, return Stk.pop<T>().toAPSInt()); } /// Pushes \p Val on the stack as the type given by \p QT. @@ -94,68 +81,12 @@ static void pushInteger(InterpState &S, T Val, QualType QT) { QT); } -static void assignInteger(Pointer &Dest, PrimType ValueT, const APSInt &Value) { +static void assignInteger(const Pointer &Dest, PrimType ValueT, + const APSInt &Value) { INT_TYPE_SWITCH_NO_BOOL( ValueT, { Dest.deref<T>() = T::from(static_cast<T>(Value)); }); } -template <PrimType Name, class V = typename PrimConv<Name>::T> -static bool retBI(InterpState &S, const CallExpr *Call, unsigned BuiltinID) { - // The return value of the function is already on the stack. - // Remove it, get rid of all the arguments and add it back. - const V &Val = S.Stk.pop<V>(); - if (!Context::isUnevaluatedBuiltin(BuiltinID)) { - for (int32_t I = Call->getNumArgs() - 1; I >= 0; --I) { - const Expr *A = Call->getArg(I); - PrimType Ty = S.getContext().classify(A).value_or(PT_Ptr); - TYPE_SWITCH(Ty, S.Stk.discard<T>()); - } - } - S.Stk.push<V>(Val); - return true; -} - -static bool retPrimValue(InterpState &S, CodePtr OpPC, - std::optional<PrimType> &T, const CallExpr *Call, - unsigned BuiltinID) { - if (isNoopBuiltin(BuiltinID)) - return true; - - if (!T) { - if (!Context::isUnevaluatedBuiltin(BuiltinID)) { - for (int32_t I = Call->getNumArgs() - 1; I >= 0; --I) { - const Expr *A = Call->getArg(I); - PrimType Ty = S.getContext().classify(A).value_or(PT_Ptr); - TYPE_SWITCH(Ty, S.Stk.discard<T>()); - } - } - - return true; - } - -#define RET_CASE(X) \ - case X: \ - return retBI<X>(S, Call, BuiltinID); - switch (*T) { - RET_CASE(PT_Ptr); - RET_CASE(PT_Float); - RET_CASE(PT_Bool); - RET_CASE(PT_Sint8); - RET_CASE(PT_Uint8); - RET_CASE(PT_Sint16); - RET_CASE(PT_Uint16); - RET_CASE(PT_Sint32); - RET_CASE(PT_Uint32); - RET_CASE(PT_Sint64); - RET_CASE(PT_Uint64); - RET_CASE(PT_IntAP); - RET_CASE(PT_IntAPS); - default: - llvm_unreachable("Unsupported return type for builtin function"); - } -#undef RET_CASE -} - static QualType getElemType(const Pointer &P) { const Descriptor *Desc = P.getFieldDesc(); QualType T = Desc->getType(); @@ -214,27 +145,30 @@ static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC, return true; } +// __builtin_assume(int) +static bool interp__builtin_assume(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + assert(Call->getNumArgs() == 1); + discard(S.Stk, *S.getContext().classify(Call->getArg(0))); + return true; +} + static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned ID) { - unsigned LimitSize = - Call->getNumArgs() == 2 - ? 0 - : align(primSize(*S.getContext().classify(Call->getArg(2)))); - const Pointer &A = - S.Stk.peek<Pointer>(align(primSize(PT_Ptr)) * 2 + LimitSize); - const Pointer &B = S.Stk.peek<Pointer>(align(primSize(PT_Ptr)) + LimitSize); - - if (ID == Builtin::BIstrcmp || ID == Builtin::BIstrncmp || - ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp) - diagnoseNonConstexprBuiltin(S, OpPC, ID); - uint64_t Limit = ~static_cast<uint64_t>(0); if (ID == Builtin::BIstrncmp || ID == Builtin::BI__builtin_strncmp || ID == Builtin::BIwcsncmp || ID == Builtin::BI__builtin_wcsncmp) - Limit = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2))) + Limit = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2))) .getZExtValue(); + const Pointer &B = S.Stk.pop<Pointer>(); + const Pointer &A = S.Stk.pop<Pointer>(); + if (ID == Builtin::BIstrcmp || ID == Builtin::BIstrncmp || + ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp) + diagnoseNonConstexprBuiltin(S, OpPC, ID); + if (Limit == 0) { pushInteger(S, 0, Call->getType()); return true; @@ -305,7 +239,7 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned ID) { - const Pointer &StrPtr = S.Stk.peek<Pointer>(); + const Pointer &StrPtr = S.Stk.pop<Pointer>(); if (ID == Builtin::BIstrlen || ID == Builtin::BIwcslen) diagnoseNonConstexprBuiltin(S, OpPC, ID); @@ -360,7 +294,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, bool Signaling) { - const Pointer &Arg = S.Stk.peek<Pointer>(); + const Pointer &Arg = S.Stk.pop<Pointer>(); if (!CheckLoad(S, OpPC, Arg)) return false; @@ -432,8 +366,8 @@ static bool interp__builtin_inf(InterpState &S, CodePtr OpPC, static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { - const Floating &Arg1 = S.Stk.peek<Floating>(align(primSize(PT_Float)) * 2); - const Floating &Arg2 = S.Stk.peek<Floating>(); + const Floating &Arg2 = S.Stk.pop<Floating>(); + const Floating &Arg1 = S.Stk.pop<Floating>(); APFloat Copy = Arg1.getAPFloat(); Copy.copySign(Arg2.getAPFloat()); @@ -444,8 +378,8 @@ static bool interp__builtin_copysign(InterpState &S, CodePtr OpPC, static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, bool IsNumBuiltin) { - const Floating &LHS = S.Stk.peek<Floating>(align(primSize(PT_Float)) * 2); - const Floating &RHS = S.Stk.peek<Floating>(); + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); if (IsNumBuiltin) S.Stk.push<Floating>(llvm::minimumnum(LHS.getAPFloat(), RHS.getAPFloat())); @@ -456,8 +390,8 @@ static bool interp__builtin_fmin(InterpState &S, CodePtr OpPC, static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, bool IsNumBuiltin) { - const Floating &LHS = S.Stk.peek<Floating>(align(primSize(PT_Float)) * 2); - const Floating &RHS = S.Stk.peek<Floating>(); + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); if (IsNumBuiltin) S.Stk.push<Floating>(llvm::maximumnum(LHS.getAPFloat(), RHS.getAPFloat())); @@ -472,7 +406,7 @@ static bool interp__builtin_fmax(InterpState &S, CodePtr OpPC, static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isNan(), Call->getType()); return true; @@ -481,7 +415,7 @@ static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isSignaling(), Call->getType()); return true; @@ -490,7 +424,7 @@ static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC, static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, bool CheckSign, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); bool IsInf = Arg.isInf(); if (CheckSign) @@ -503,7 +437,7 @@ static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC, static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isFinite(), Call->getType()); return true; @@ -512,7 +446,7 @@ static bool interp__builtin_isfinite(InterpState &S, CodePtr OpPC, static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isNormal(), Call->getType()); return true; @@ -521,7 +455,7 @@ static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC, static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isDenormal(), Call->getType()); return true; @@ -530,7 +464,7 @@ static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC, static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isZero(), Call->getType()); return true; @@ -539,7 +473,7 @@ static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, static bool interp__builtin_signbit(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg = S.Stk.peek<Floating>(); + const Floating &Arg = S.Stk.pop<Floating>(); pushInteger(S, Arg.isNegative(), Call->getType()); return true; @@ -547,8 +481,8 @@ static bool interp__builtin_signbit(InterpState &S, CodePtr OpPC, static bool interp_floating_comparison(InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned ID) { - const Floating &RHS = S.Stk.peek<Floating>(); - const Floating &LHS = S.Stk.peek<Floating>(align(2u * primSize(PT_Float))); + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); pushInteger( S, @@ -584,9 +518,8 @@ static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType FPClassArgT = *S.getContext().classify(Call->getArg(1)->getType()); - APSInt FPClassArg = peekToAPSInt(S.Stk, FPClassArgT); - const Floating &F = - S.Stk.peek<Floating>(align(primSize(FPClassArgT) + primSize(PT_Float))); + APSInt FPClassArg = popToAPSInt(S.Stk, FPClassArgT); + const Floating &F = S.Stk.pop<Floating>(); int32_t Result = static_cast<int32_t>((F.classify() & FPClassArg).getZExtValue()); @@ -596,10 +529,16 @@ static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, } /// Five int values followed by one floating value. +/// __builtin_fpclassify(int, int, int, int, int, float) static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Val = S.Stk.peek<Floating>(); + const Floating &Val = S.Stk.pop<Floating>(); + + PrimType IntT = *S.getContext().classify(Call->getArg(0)); + APSInt Values[5]; + for (unsigned I = 0; I != 5; ++I) + Values[4 - I] = popToAPSInt(S.Stk, IntT); unsigned Index; switch (Val.getCategory()) { @@ -619,13 +558,8 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, // The last argument is first on the stack. assert(Index <= 4); - PrimType IntT = *S.getContext().classify(Call->getArg(0)); - unsigned IntSize = primSize(IntT); - unsigned Offset = - align(primSize(PT_Float)) + ((1 + (4 - Index)) * align(IntSize)); - APSInt I = peekToAPSInt(S.Stk, IntT, Offset); - pushInteger(S, I, Call->getType()); + pushInteger(S, Values[Index], Call->getType()); return true; } @@ -636,7 +570,7 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, // Reference, WG14 N2478 F.10.4.3 static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { - const Floating &Val = S.Stk.peek<Floating>(); + const Floating &Val = S.Stk.pop<Floating>(); S.Stk.push<Floating>(Floating::abs(Val)); return true; @@ -646,7 +580,7 @@ static bool interp__builtin_abs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = peekToAPSInt(S.Stk, ArgT); + APSInt Val = popToAPSInt(S.Stk, ArgT); if (Val == APSInt(APInt::getSignedMinValue(Val.getBitWidth()), /*IsUnsigned=*/false)) return false; @@ -660,7 +594,7 @@ static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = peekToAPSInt(S.Stk, ArgT); + APSInt Val = popToAPSInt(S.Stk, ArgT); pushInteger(S, Val.popcount(), Call->getType()); return true; } @@ -669,7 +603,7 @@ static bool interp__builtin_parity(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = peekToAPSInt(S.Stk, ArgT); + APSInt Val = popToAPSInt(S.Stk, ArgT); pushInteger(S, Val.popcount() % 2, Call->getType()); return true; } @@ -678,7 +612,7 @@ static bool interp__builtin_clrsb(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = peekToAPSInt(S.Stk, ArgT); + APSInt Val = popToAPSInt(S.Stk, ArgT); pushInteger(S, Val.getBitWidth() - Val.getSignificantBits(), Call->getType()); return true; } @@ -687,7 +621,7 @@ static bool interp__builtin_bitreverse(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = peekToAPSInt(S.Stk, ArgT); + APSInt Val = popToAPSInt(S.Stk, ArgT); pushInteger(S, Val.reverseBits(), Call->getType()); return true; } @@ -717,11 +651,11 @@ static bool interp__builtin_expect(InterpState &S, CodePtr OpPC, assert(NumArgs == 2 || NumArgs == 3); PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - unsigned Offset = align(ArgT) * 2; if (NumArgs == 3) - Offset += align(primSize(PT_Float)); + S.Stk.discard<Floating>(); + discard(S.Stk, ArgT); - APSInt Val = peekToAPSInt(S.Stk, ArgT, Offset); + APSInt Val = popToAPSInt(S.Stk, ArgT); pushInteger(S, Val, Call->getType()); return true; } @@ -733,9 +667,8 @@ static bool interp__builtin_rotate(InterpState &S, CodePtr OpPC, PrimType AmountT = *S.getContext().classify(Call->getArg(1)->getType()); PrimType ValueT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Amount = peekToAPSInt(S.Stk, AmountT); - APSInt Value = peekToAPSInt( - S.Stk, ValueT, align(primSize(AmountT)) + align(primSize(ValueT))); + APSInt Amount = popToAPSInt(S.Stk, AmountT); + APSInt Value = popToAPSInt(S.Stk, ValueT); APSInt Result; if (Right) @@ -753,7 +686,7 @@ static bool interp__builtin_ffs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Value = peekToAPSInt(S.Stk, ArgT); + APSInt Value = popToAPSInt(S.Stk, ArgT); uint64_t N = Value.countr_zero(); pushInteger(S, N == Value.getBitWidth() ? 0 : N + 1, Call->getType()); @@ -782,7 +715,7 @@ static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Arg = peekToAPSInt(S.Stk, ArgT); + APSInt Arg = popToAPSInt(S.Stk, ArgT); int Result = S.getASTContext().getTargetInfo().getEHDataRegisterNumber( Arg.getZExtValue()); @@ -794,17 +727,14 @@ static bool interp__builtin_eh_return_data_regno(InterpState &S, CodePtr OpPC, static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned BuiltinOp) { - Pointer &ResultPtr = S.Stk.peek<Pointer>(); + const Pointer &ResultPtr = S.Stk.pop<Pointer>(); if (ResultPtr.isDummy()) return false; PrimType RHST = *S.getContext().classify(Call->getArg(1)->getType()); PrimType LHST = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt RHS = peekToAPSInt(S.Stk, RHST, - align(primSize(PT_Ptr)) + align(primSize(RHST))); - APSInt LHS = peekToAPSInt(S.Stk, LHST, - align(primSize(PT_Ptr)) + align(primSize(RHST)) + - align(primSize(LHST))); + APSInt RHS = popToAPSInt(S.Stk, RHST); + APSInt LHS = popToAPSInt(S.Stk, LHST); QualType ResultType = Call->getArg(2)->getType()->getPointeeType(); PrimType ResultT = *S.getContext().classify(ResultType); bool Overflow; @@ -887,7 +817,7 @@ static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC, Result = Temp; } - // Write Result to ResultPtr and put Overflow on the stacl. + // Write Result to ResultPtr and put Overflow on the stack. assignInteger(ResultPtr, ResultT, Result); ResultPtr.initialize(); assert(Call->getDirectCallee()->getReturnType()->isBooleanType()); @@ -899,18 +829,13 @@ static bool interp__builtin_overflowop(InterpState &S, CodePtr OpPC, static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned BuiltinOp) { + const Pointer &CarryOutPtr = S.Stk.pop<Pointer>(); PrimType LHST = *S.getContext().classify(Call->getArg(0)->getType()); PrimType RHST = *S.getContext().classify(Call->getArg(1)->getType()); - PrimType CarryT = *S.getContext().classify(Call->getArg(2)->getType()); - APSInt RHS = peekToAPSInt(S.Stk, RHST, - align(primSize(PT_Ptr)) + align(primSize(CarryT)) + - align(primSize(RHST))); - APSInt LHS = - peekToAPSInt(S.Stk, LHST, - align(primSize(PT_Ptr)) + align(primSize(RHST)) + - align(primSize(CarryT)) + align(primSize(LHST))); - APSInt CarryIn = peekToAPSInt( - S.Stk, LHST, align(primSize(PT_Ptr)) + align(primSize(CarryT))); + APSInt CarryIn = popToAPSInt(S.Stk, LHST); + APSInt RHS = popToAPSInt(S.Stk, RHST); + APSInt LHS = popToAPSInt(S.Stk, LHST); + APSInt CarryOut; APSInt Result; @@ -944,7 +869,6 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, // this is consistent. CarryOut = (uint64_t)(FirstOverflowed | SecondOverflowed); - Pointer &CarryOutPtr = S.Stk.peek<Pointer>(); QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType(); PrimType CarryOutT = *S.getContext().classify(CarryOutType); assignInteger(CarryOutPtr, CarryOutT, CarryOut); @@ -958,9 +882,14 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned BuiltinOp) { - unsigned CallSize = callArgSize(S, Call); + + std::optional<APSInt> Fallback; + if (BuiltinOp == Builtin::BI__builtin_clzg && Call->getNumArgs() == 2) { + PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); + Fallback = popToAPSInt(S.Stk, FallbackT); + } PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize); + const APSInt &Val = popToAPSInt(S.Stk, ValT); // When the argument is 0, the result of GCC builtins is undefined, whereas // for Microsoft intrinsics, the result is the bit-width of the argument. @@ -969,11 +898,8 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, BuiltinOp != Builtin::BI__lzcnt64; if (Val == 0) { - if (BuiltinOp == Builtin::BI__builtin_clzg && Call->getNumArgs() == 2) { - // We have a fallback parameter. - PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); - const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT); - pushInteger(S, Fallback, Call->getType()); + if (Fallback) { + pushInteger(S, *Fallback, Call->getType()); return true; } @@ -988,16 +914,17 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned BuiltinID) { - unsigned CallSize = callArgSize(S, Call); + std::optional<APSInt> Fallback; + if (BuiltinID == Builtin::BI__builtin_ctzg && Call->getNumArgs() == 2) { + PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); + Fallback = popToAPSInt(S.Stk, FallbackT); + } PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize); + const APSInt &Val = popToAPSInt(S.Stk, ValT); if (Val == 0) { - if (BuiltinID == Builtin::BI__builtin_ctzg && Call->getNumArgs() == 2) { - // We have a fallback parameter. - PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); - const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT); - pushInteger(S, Fallback, Call->getType()); + if (Fallback) { + pushInteger(S, *Fallback, Call->getType()); return true; } return false; @@ -1012,7 +939,7 @@ static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC, const CallExpr *Call) { PrimType ReturnT = *S.getContext().classify(Call->getType()); PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT); + const APSInt &Val = popToAPSInt(S.Stk, ValT); assert(Val.getActiveBits() <= 64); INT_TYPE_SWITCH(ReturnT, @@ -1022,22 +949,19 @@ static bool interp__builtin_bswap(InterpState &S, CodePtr OpPC, /// bool __atomic_always_lock_free(size_t, void const volatile*) /// bool __atomic_is_lock_free(size_t, void const volatile*) -/// bool __c11_atomic_is_lock_free(size_t) static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned BuiltinOp) { - PrimType ValT = *S.getContext().classify(Call->getArg(0)); - unsigned SizeValOffset = 0; - if (BuiltinOp != Builtin::BI__c11_atomic_is_lock_free) - SizeValOffset = align(primSize(ValT)) + align(primSize(PT_Ptr)); - const APSInt &SizeVal = peekToAPSInt(S.Stk, ValT, SizeValOffset); - auto returnBool = [&S](bool Value) -> bool { S.Stk.push<Boolean>(Value); return true; }; + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + const Pointer &Ptr = S.Stk.pop<Pointer>(); + const APSInt &SizeVal = popToAPSInt(S.Stk, ValT); + // For __atomic_is_lock_free(sizeof(_Atomic(T))), if the size is a power // of two less than or equal to the maximum inline atomic width, we know it // is lock-free. If the size isn't a power of two, or greater than the @@ -1057,13 +981,11 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC, // OK, we will inline appropriately-aligned operations of this size, // and _Atomic(T) is appropriately-aligned. - if (BuiltinOp == Builtin::BI__c11_atomic_is_lock_free || - Size == CharUnits::One()) + if (Size == CharUnits::One()) return returnBool(true); // Same for null pointers. assert(BuiltinOp != Builtin::BI__c11_atomic_is_lock_free); - const Pointer &Ptr = S.Stk.peek<Pointer>(); if (Ptr.isZero()) return returnBool(true); @@ -1099,14 +1021,38 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC, return false; } +/// bool __c11_atomic_is_lock_free(size_t) +static bool interp__builtin_c11_atomic_is_lock_free(InterpState &S, + CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + PrimType ValT = *S.getContext().classify(Call->getArg(0)); + const APSInt &SizeVal = popToAPSInt(S.Stk, ValT); + + auto returnBool = [&S](bool Value) -> bool { + S.Stk.push<Boolean>(Value); + return true; + }; + + CharUnits Size = CharUnits::fromQuantity(SizeVal.getZExtValue()); + if (Size.isPowerOfTwo()) { + // Check against inlining width. + unsigned InlineWidthBits = + S.getASTContext().getTargetInfo().getMaxAtomicInlineWidth(); + if (Size <= S.getASTContext().toCharUnitsFromBits(InlineWidthBits)) + return returnBool(true); + } + + return false; // returnBool(false); +} + /// __builtin_complex(Float A, float B); static bool interp__builtin_complex(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg2 = S.Stk.peek<Floating>(); - const Floating &Arg1 = S.Stk.peek<Floating>(align(primSize(PT_Float)) * 2); - Pointer &Result = S.Stk.peek<Pointer>(align(primSize(PT_Float)) * 2 + - align(primSize(PT_Ptr))); + const Floating &Arg2 = S.Stk.pop<Floating>(); + const Floating &Arg1 = S.Stk.pop<Floating>(); + Pointer &Result = S.Stk.peek<Pointer>(); Result.atIndex(0).deref<Floating>() = Arg1; Result.atIndex(0).initialize(); @@ -1126,10 +1072,8 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned BuiltinOp) { - unsigned CallSize = callArgSize(S, Call); - PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1)); - const APSInt &Alignment = peekToAPSInt(S.Stk, AlignmentT); + const APSInt &Alignment = popToAPSInt(S.Stk, AlignmentT); if (Alignment < 0 || !Alignment.isPowerOf2()) { S.FFDiag(Call, diag::note_constexpr_invalid_alignment) << Alignment; @@ -1148,7 +1092,7 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC, PrimType FirstArgT = *S.Ctx.classify(Call->getArg(0)); if (isIntegralType(FirstArgT)) { - const APSInt &Src = peekToAPSInt(S.Stk, FirstArgT, CallSize); + const APSInt &Src = popToAPSInt(S.Stk, FirstArgT); APSInt Align = Alignment.extOrTrunc(Src.getBitWidth()); if (BuiltinOp == Builtin::BI__builtin_align_up) { APSInt AlignedVal = @@ -1165,7 +1109,7 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC, } assert(FirstArgT == PT_Ptr); - const Pointer &Ptr = S.Stk.peek<Pointer>(CallSize); + const Pointer &Ptr = S.Stk.pop<Pointer>(); unsigned PtrOffset = Ptr.getByteOffset(); PtrOffset = Ptr.getIndex(); @@ -1233,25 +1177,12 @@ static bool interp__builtin_assume_aligned(InterpState &S, CodePtr OpPC, const CallExpr *Call) { assert(Call->getNumArgs() == 2 || Call->getNumArgs() == 3); - // Might be called with function pointers in C. - std::optional<PrimType> PtrT = S.Ctx.classify(Call->getArg(0)); - if (PtrT != PT_Ptr) - return false; - - unsigned ArgSize = callArgSize(S, Call); - const Pointer &Ptr = S.Stk.peek<Pointer>(ArgSize); std::optional<APSInt> ExtraOffset; - APSInt Alignment; - if (Call->getNumArgs() == 2) { - Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1))); - } else { - PrimType AlignmentT = *S.Ctx.classify(Call->getArg(1)); - PrimType ExtraOffsetT = *S.Ctx.classify(Call->getArg(2)); - Alignment = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1)), - align(primSize(AlignmentT)) + - align(primSize(ExtraOffsetT))); - ExtraOffset = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(2))); - } + if (Call->getNumArgs() == 3) + ExtraOffset = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(2))); + + APSInt Alignment = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(1))); + const Pointer &Ptr = S.Stk.pop<Pointer>(); CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue()); @@ -1300,9 +1231,8 @@ static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC, PrimType ValT = *S.Ctx.classify(Call->getArg(0)); PrimType IndexT = *S.Ctx.classify(Call->getArg(1)); - APSInt Val = peekToAPSInt(S.Stk, ValT, - align(primSize(ValT)) + align(primSize(IndexT))); - APSInt Index = peekToAPSInt(S.Stk, IndexT); + APSInt Index = popToAPSInt(S.Stk, IndexT); + APSInt Val = popToAPSInt(S.Stk, ValT); unsigned BitWidth = Val.getBitWidth(); uint64_t Shift = Index.extractBitsAsZExtValue(8, 0); @@ -1333,9 +1263,8 @@ static bool interp__builtin_ia32_bzhi(InterpState &S, CodePtr OpPC, PrimType ValT = *S.Ctx.classify(Call->getArg(0)); PrimType IndexT = *S.Ctx.classify(Call->getArg(1)); - APSInt Val = peekToAPSInt(S.Stk, ValT, - align(primSize(ValT)) + align(primSize(IndexT))); - APSInt Idx = peekToAPSInt(S.Stk, IndexT); + APSInt Idx = popToAPSInt(S.Stk, IndexT); + APSInt Val = popToAPSInt(S.Stk, ValT); unsigned BitWidth = Val.getBitWidth(); uint64_t Index = Idx.extractBitsAsZExtValue(8, 0); @@ -1355,7 +1284,7 @@ static bool interp__builtin_ia32_lzcnt(InterpState &S, CodePtr OpPC, !Call->getArg(0)->getType()->isIntegerType()) return false; - APSInt Val = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0))); + APSInt Val = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0))); pushInteger(S, Val.countLeadingZeros(), CallType); return true; } @@ -1368,7 +1297,7 @@ static bool interp__builtin_ia32_tzcnt(InterpState &S, CodePtr OpPC, !Call->getArg(0)->getType()->isIntegerType()) return false; - APSInt Val = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0))); + APSInt Val = popToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0))); pushInteger(S, Val.countTrailingZeros(), CallType); return true; } @@ -1383,9 +1312,8 @@ static bool interp__builtin_ia32_pdep(InterpState &S, CodePtr OpPC, PrimType ValT = *S.Ctx.classify(Call->getArg(0)); PrimType MaskT = *S.Ctx.classify(Call->getArg(1)); - APSInt Val = - peekToAPSInt(S.Stk, ValT, align(primSize(ValT)) + align(primSize(MaskT))); - APSInt Mask = peekToAPSInt(S.Stk, MaskT); + APSInt Mask = popToAPSInt(S.Stk, MaskT); + APSInt Val = popToAPSInt(S.Stk, ValT); unsigned BitWidth = Val.getBitWidth(); APInt Result = APInt::getZero(BitWidth); @@ -1407,9 +1335,8 @@ static bool interp__builtin_ia32_pext(InterpState &S, CodePtr OpPC, PrimType ValT = *S.Ctx.classify(Call->getArg(0)); PrimType MaskT = *S.Ctx.classify(Call->getArg(1)); - APSInt Val = - peekToAPSInt(S.Stk, ValT, align(primSize(ValT)) + align(primSize(MaskT))); - APSInt Mask = peekToAPSInt(S.Stk, MaskT); + APSInt Mask = popToAPSInt(S.Stk, MaskT); + APSInt Val = popToAPSInt(S.Stk, ValT); unsigned BitWidth = Val.getBitWidth(); APInt Result = APInt::getZero(BitWidth); @@ -1432,17 +1359,14 @@ static bool interp__builtin_ia32_addcarry_subborrow(InterpState &S, !Call->getArg(2)->getType()->isIntegerType()) return false; + const Pointer &CarryOutPtr = S.Stk.pop<Pointer>(); + PrimType CarryInT = *S.getContext().classify(Call->getArg(0)); PrimType LHST = *S.getContext().classify(Call->getArg(1)); PrimType RHST = *S.getContext().classify(Call->getArg(2)); - unsigned PtrSize = align(primSize(PT_Ptr)); - APSInt CarryIn = - peekToAPSInt(S.Stk, CarryInT, - PtrSize + align(primSize(RHST)) + align(primSize(LHST)) + - align(primSize(CarryInT))); - APSInt LHS = peekToAPSInt( - S.Stk, LHST, PtrSize + align(primSize(RHST)) + align(primSize(LHST))); - APSInt RHS = peekToAPSInt(S.Stk, RHST, PtrSize + align(primSize(RHST))); + APSInt RHS = popToAPSInt(S.Stk, RHST); + APSInt LHS = popToAPSInt(S.Stk, LHST); + APSInt CarryIn = popToAPSInt(S.Stk, CarryInT); bool IsAdd = BuiltinOp == clang::X86::BI__builtin_ia32_addcarryx_u32 || BuiltinOp == clang::X86::BI__builtin_ia32_addcarryx_u64; @@ -1457,7 +1381,6 @@ static bool interp__builtin_ia32_addcarry_subborrow(InterpState &S, APSInt CarryOut = APSInt(ExResult.extractBits(1, BitWidth), /*IsUnsigned=*/true); - Pointer &CarryOutPtr = S.Stk.peek<Pointer>(); QualType CarryOutType = Call->getArg(3)->getType()->getPointeeType(); PrimType CarryOutT = *S.getContext().classify(CarryOutType); assignInteger(CarryOutPtr, CarryOutT, APSInt(Result, true)); @@ -1481,7 +1404,7 @@ static bool interp__builtin_ptrauth_string_discriminator(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const auto &Ptr = S.Stk.peek<Pointer>(); + const auto &Ptr = S.Stk.pop<Pointer>(); assert(Ptr.getFieldDesc()->isPrimitiveArray()); // This should be created for a StringLiteral, so should alway shold at least @@ -1500,6 +1423,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, // Walk up the call stack to find the appropriate caller and get the // element type from it. auto [NewCall, ElemType] = S.getStdAllocatorCaller("allocate"); + APSInt Bytes = popToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0))); if (ElemType.isNull()) { S.FFDiag(Call, S.getLangOpts().CPlusPlus20 @@ -1515,7 +1439,6 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC, return false; } - APSInt Bytes = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(0))); CharUnits ElemSize = S.getASTContext().getTypeSizeInChars(ElemType); assert(!ElemSize.isZero()); // Divide the number of bytes by sizeof(ElemType), so we get the number of @@ -1597,17 +1520,20 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC, const Expr *Source = nullptr; const Block *BlockToDelete = nullptr; - if (S.checkingPotentialConstantExpression()) + if (S.checkingPotentialConstantExpression()) { + S.Stk.discard<Pointer>(); return false; + } // This is permitted only within a call to std::allocator<T>::deallocate. if (!S.getStdAllocatorCaller("deallocate")) { S.FFDiag(Call); + S.Stk.discard<Pointer>(); return true; } { - const Pointer &Ptr = S.Stk.peek<Pointer>(); + const Pointer &Ptr = S.Stk.pop<Pointer>(); if (Ptr.isZero()) { S.CCEDiag(Call, diag::note_constexpr_deallocate_null); @@ -1646,14 +1572,14 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC, static bool interp__builtin_arithmetic_fence(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { - const Floating &Arg0 = S.Stk.peek<Floating>(); + const Floating &Arg0 = S.Stk.pop<Floating>(); S.Stk.push<Floating>(Arg0); return true; } static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned ID) { - const Pointer &Arg = S.Stk.peek<Pointer>(); + const Pointer &Arg = S.Stk.pop<Pointer>(); assert(Arg.getFieldDesc()->isPrimitiveArray()); QualType ElemType = Arg.getFieldDesc()->getElemQualType(); @@ -1708,15 +1634,15 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC, assert(Call->getNumArgs() == 1); if (Call->getArg(0)->getType()->isIntegerType()) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); - APSInt Val = peekToAPSInt(S.Stk, ArgT); + APSInt Val = popToAPSInt(S.Stk, ArgT); pushInteger(S, Val.popcount(), Call->getType()); return true; } // Otherwise, the argument must be a vector. assert(Call->getArg(0)->getType()->isVectorType()); - const Pointer &Arg = S.Stk.peek<Pointer>(); + const Pointer &Arg = S.Stk.pop<Pointer>(); assert(Arg.getFieldDesc()->isPrimitiveArray()); - const Pointer &Dst = S.Stk.peek<Pointer>(primSize(PT_Ptr) * 2); + const Pointer &Dst = S.Stk.peek<Pointer>(); assert(Dst.getFieldDesc()->isPrimitiveArray()); assert(Arg.getFieldDesc()->getNumElems() == Dst.getFieldDesc()->getNumElems()); @@ -1743,11 +1669,9 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC, assert(Call->getNumArgs() == 3); const ASTContext &ASTCtx = S.getASTContext(); PrimType SizeT = *S.getContext().classify(Call->getArg(2)); - Pointer DestPtr = S.Stk.peek<Pointer>(align(primSize(SizeT)) + - (align(primSize(PT_Ptr)) * 2)); - const Pointer SrcPtr = S.Stk.peek<Pointer>(align(primSize(SizeT)) + - (align(primSize(PT_Ptr)) * 1)); - APSInt Size = peekToAPSInt(S.Stk, SizeT); + APSInt Size = popToAPSInt(S.Stk, SizeT); + const Pointer SrcPtr = S.Stk.pop<Pointer>(); + const Pointer DestPtr = S.Stk.pop<Pointer>(); assert(!Size.isSigned() && "memcpy and friends take an unsigned size"); @@ -1902,11 +1826,9 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned ID) { assert(Call->getNumArgs() == 3); PrimType SizeT = *S.getContext().classify(Call->getArg(2)); - const APSInt &Size = peekToAPSInt(S.Stk, SizeT); - const Pointer &PtrA = S.Stk.peek<Pointer>(align(primSize(SizeT)) + - (align(primSize(PT_Ptr)) * 2)); - const Pointer &PtrB = S.Stk.peek<Pointer>(align(primSize(SizeT)) + - (align(primSize(PT_Ptr)) * 1)); + const APSInt &Size = popToAPSInt(S.Stk, SizeT); + const Pointer &PtrB = S.Stk.pop<Pointer>(); + const Pointer &PtrA = S.Stk.pop<Pointer>(); if (ID == Builtin::BImemcmp || ID == Builtin::BIbcmp || ID == Builtin::BIwmemcmp) @@ -2008,27 +1930,22 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, return false; } +// __builtin_memchr(ptr, int, int) +// __builtin_strchr(ptr, int) static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned ID) { if (ID == Builtin::BImemchr || ID == Builtin::BIwcschr || ID == Builtin::BIstrchr || ID == Builtin::BIwmemchr) diagnoseNonConstexprBuiltin(S, OpPC, ID); - unsigned ArgOffset = 0; - APSInt Desired; std::optional<APSInt> MaxLength; PrimType DesiredT = *S.getContext().classify(Call->getArg(1)); if (Call->getNumArgs() == 3) { PrimType MaxT = *S.getContext().classify(Call->getArg(2)); - MaxLength = peekToAPSInt(S.Stk, MaxT); - - ArgOffset += align(primSize(MaxT)) + align(primSize(DesiredT)); - Desired = peekToAPSInt(S.Stk, DesiredT, ArgOffset); - } else { - Desired = peekToAPSInt(S.Stk, DesiredT); - ArgOffset += align(primSize(DesiredT)); + MaxLength = popToAPSInt(S.Stk, MaxT); } - const Pointer &Ptr = S.Stk.peek<Pointer>(ArgOffset + align(primSize(PT_Ptr))); + APSInt Desired = popToAPSInt(S.Stk, DesiredT); + const Pointer &Ptr = S.Stk.pop<Pointer>(); if (MaxLength && MaxLength->isZero()) { S.Stk.push<Pointer>(); @@ -2182,12 +2099,11 @@ static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType KindT = *S.getContext().classify(Call->getArg(1)); - [[maybe_unused]] unsigned Kind = peekToAPSInt(S.Stk, KindT).getZExtValue(); + [[maybe_unused]] unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue(); assert(Kind <= 3 && "unexpected kind"); - const Pointer &Ptr = - S.Stk.peek<Pointer>(align(primSize(KindT)) + align(primSize(PT_Ptr))); + const Pointer &Ptr = S.Stk.pop<Pointer>(); if (Ptr.isZero()) return false; @@ -2212,7 +2128,7 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC, if (!S.inConstantContext()) return false; - const Pointer &Ptr = S.Stk.peek<Pointer>(); + const Pointer &Ptr = S.Stk.pop<Pointer>(); auto Error = [&](int Diag) { bool CalledFromStd = false; @@ -2256,17 +2172,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return Invalid(S, OpPC); const InterpFrame *Frame = S.Current; - - std::optional<PrimType> ReturnT = S.getContext().classify(Call); - switch (BuiltinID) { case Builtin::BI__builtin_is_constant_evaluated: - if (!interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call); + case Builtin::BI__builtin_assume: case Builtin::BI__assume: - break; + return interp__builtin_assume(S, OpPC, Frame, Call); + case Builtin::BI__builtin_strcmp: case Builtin::BIstrcmp: case Builtin::BI__builtin_strncmp: @@ -2275,32 +2188,27 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BIwcsncmp: case Builtin::BI__builtin_wcscmp: case Builtin::BIwcscmp: - if (!interp__builtin_strcmp(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_strcmp(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_strlen: case Builtin::BIstrlen: case Builtin::BI__builtin_wcslen: case Builtin::BIwcslen: - if (!interp__builtin_strlen(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_strlen(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: case Builtin::BI__builtin_nanf16: case Builtin::BI__builtin_nanf128: - if (!interp__builtin_nan(S, OpPC, Frame, Call, /*Signaling=*/false)) - return false; - break; + return interp__builtin_nan(S, OpPC, Frame, Call, /*Signaling=*/false); + case Builtin::BI__builtin_nans: case Builtin::BI__builtin_nansf: case Builtin::BI__builtin_nansl: case Builtin::BI__builtin_nansf16: case Builtin::BI__builtin_nansf128: - if (!interp__builtin_nan(S, OpPC, Frame, Call, /*Signaling=*/true)) - return false; - break; + return interp__builtin_nan(S, OpPC, Frame, Call, /*Signaling=*/true); case Builtin::BI__builtin_huge_val: case Builtin::BI__builtin_huge_valf: @@ -2312,126 +2220,95 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_infl: case Builtin::BI__builtin_inff16: case Builtin::BI__builtin_inff128: - if (!interp__builtin_inf(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_inf(S, OpPC, Frame, Call); + case Builtin::BI__builtin_copysign: case Builtin::BI__builtin_copysignf: case Builtin::BI__builtin_copysignl: case Builtin::BI__builtin_copysignf128: - if (!interp__builtin_copysign(S, OpPC, Frame)) - return false; - break; + return interp__builtin_copysign(S, OpPC, Frame); case Builtin::BI__builtin_fmin: case Builtin::BI__builtin_fminf: case Builtin::BI__builtin_fminl: case Builtin::BI__builtin_fminf16: case Builtin::BI__builtin_fminf128: - if (!interp__builtin_fmin(S, OpPC, Frame, /*IsNumBuiltin=*/false)) - return false; - break; + return interp__builtin_fmin(S, OpPC, Frame, /*IsNumBuiltin=*/false); case Builtin::BI__builtin_fminimum_num: case Builtin::BI__builtin_fminimum_numf: case Builtin::BI__builtin_fminimum_numl: case Builtin::BI__builtin_fminimum_numf16: case Builtin::BI__builtin_fminimum_numf128: - if (!interp__builtin_fmin(S, OpPC, Frame, /*IsNumBuiltin=*/true)) - return false; - break; + return interp__builtin_fmin(S, OpPC, Frame, /*IsNumBuiltin=*/true); case Builtin::BI__builtin_fmax: case Builtin::BI__builtin_fmaxf: case Builtin::BI__builtin_fmaxl: case Builtin::BI__builtin_fmaxf16: case Builtin::BI__builtin_fmaxf128: - if (!interp__builtin_fmax(S, OpPC, Frame, /*IsNumBuiltin=*/false)) - return false; - break; + return interp__builtin_fmax(S, OpPC, Frame, /*IsNumBuiltin=*/false); case Builtin::BI__builtin_fmaximum_num: case Builtin::BI__builtin_fmaximum_numf: case Builtin::BI__builtin_fmaximum_numl: case Builtin::BI__builtin_fmaximum_numf16: case Builtin::BI__builtin_fmaximum_numf128: - if (!interp__builtin_fmax(S, OpPC, Frame, /*IsNumBuiltin=*/true)) - return false; - break; + return interp__builtin_fmax(S, OpPC, Frame, /*IsNumBuiltin=*/true); case Builtin::BI__builtin_isnan: - if (!interp__builtin_isnan(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_isnan(S, OpPC, Frame, Call); + case Builtin::BI__builtin_issignaling: - if (!interp__builtin_issignaling(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_issignaling(S, OpPC, Frame, Call); case Builtin::BI__builtin_isinf: - if (!interp__builtin_isinf(S, OpPC, Frame, /*Sign=*/false, Call)) - return false; - break; + return interp__builtin_isinf(S, OpPC, Frame, /*Sign=*/false, Call); case Builtin::BI__builtin_isinf_sign: - if (!interp__builtin_isinf(S, OpPC, Frame, /*Sign=*/true, Call)) - return false; - break; + return interp__builtin_isinf(S, OpPC, Frame, /*Sign=*/true, Call); case Builtin::BI__builtin_isfinite: - if (!interp__builtin_isfinite(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_isfinite(S, OpPC, Frame, Call); + case Builtin::BI__builtin_isnormal: - if (!interp__builtin_isnormal(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_isnormal(S, OpPC, Frame, Call); + case Builtin::BI__builtin_issubnormal: - if (!interp__builtin_issubnormal(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_issubnormal(S, OpPC, Frame, Call); + case Builtin::BI__builtin_iszero: - if (!interp__builtin_iszero(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_iszero(S, OpPC, Frame, Call); + case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: - if (!interp__builtin_signbit(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_signbit(S, OpPC, Frame, Call); + case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: case Builtin::BI__builtin_islessequal: case Builtin::BI__builtin_islessgreater: case Builtin::BI__builtin_isunordered: - if (!interp_floating_comparison(S, OpPC, Call, BuiltinID)) - return false; - break; + return interp_floating_comparison(S, OpPC, Call, BuiltinID); + case Builtin::BI__builtin_isfpclass: - if (!interp__builtin_isfpclass(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_isfpclass(S, OpPC, Frame, Call); + case Builtin::BI__builtin_fpclassify: - if (!interp__builtin_fpclassify(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_fpclassify(S, OpPC, Frame, Call); case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: case Builtin::BI__builtin_fabsf128: - if (!interp__builtin_fabs(S, OpPC, Frame)) - return false; - break; + return interp__builtin_fabs(S, OpPC, Frame); case Builtin::BI__builtin_abs: case Builtin::BI__builtin_labs: case Builtin::BI__builtin_llabs: - if (!interp__builtin_abs(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_abs(S, OpPC, Frame, Call); case Builtin::BI__builtin_popcount: case Builtin::BI__builtin_popcountl: @@ -2440,42 +2317,30 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__popcnt16: // Microsoft variants of popcount case Builtin::BI__popcnt: case Builtin::BI__popcnt64: - if (!interp__builtin_popcount(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_popcount(S, OpPC, Frame, Call); case Builtin::BI__builtin_parity: case Builtin::BI__builtin_parityl: case Builtin::BI__builtin_parityll: - if (!interp__builtin_parity(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_parity(S, OpPC, Frame, Call); case Builtin::BI__builtin_clrsb: case Builtin::BI__builtin_clrsbl: case Builtin::BI__builtin_clrsbll: - if (!interp__builtin_clrsb(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_clrsb(S, OpPC, Frame, Call); case Builtin::BI__builtin_bitreverse8: case Builtin::BI__builtin_bitreverse16: case Builtin::BI__builtin_bitreverse32: case Builtin::BI__builtin_bitreverse64: - if (!interp__builtin_bitreverse(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_bitreverse(S, OpPC, Frame, Call); case Builtin::BI__builtin_classify_type: - if (!interp__builtin_classify_type(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_classify_type(S, OpPC, Frame, Call); case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: - if (!interp__builtin_expect(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_expect(S, OpPC, Frame, Call); case Builtin::BI__builtin_rotateleft8: case Builtin::BI__builtin_rotateleft16: @@ -2486,9 +2351,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI_rotl: case Builtin::BI_lrotl: case Builtin::BI_rotl64: - if (!interp__builtin_rotate(S, OpPC, Frame, Call, /*Right=*/false)) - return false; - break; + return interp__builtin_rotate(S, OpPC, Frame, Call, /*Right=*/false); case Builtin::BI__builtin_rotateright8: case Builtin::BI__builtin_rotateright16: @@ -2499,23 +2362,18 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI_rotr: case Builtin::BI_lrotr: case Builtin::BI_rotr64: - if (!interp__builtin_rotate(S, OpPC, Frame, Call, /*Right=*/true)) - return false; - break; + return interp__builtin_rotate(S, OpPC, Frame, Call, /*Right=*/true); case Builtin::BI__builtin_ffs: case Builtin::BI__builtin_ffsl: case Builtin::BI__builtin_ffsll: - if (!interp__builtin_ffs(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ffs(S, OpPC, Frame, Call); + case Builtin::BIaddressof: case Builtin::BI__addressof: case Builtin::BI__builtin_addressof: assert(isNoopBuiltin(BuiltinID)); - if (!interp__builtin_addressof(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_addressof(S, OpPC, Frame, Call); case Builtin::BIas_const: case Builtin::BIforward: @@ -2523,18 +2381,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BImove: case Builtin::BImove_if_noexcept: assert(isNoopBuiltin(BuiltinID)); - if (!interp__builtin_move(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_move(S, OpPC, Frame, Call); case Builtin::BI__builtin_eh_return_data_regno: - if (!interp__builtin_eh_return_data_regno(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_eh_return_data_regno(S, OpPC, Frame, Call); case Builtin::BI__builtin_launder: assert(isNoopBuiltin(BuiltinID)); - break; + return true; case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: @@ -2557,9 +2411,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_smul_overflow: case Builtin::BI__builtin_smull_overflow: case Builtin::BI__builtin_smulll_overflow: - if (!interp__builtin_overflowop(S, OpPC, Call, BuiltinID)) - return false; - break; + return interp__builtin_overflowop(S, OpPC, Call, BuiltinID); case Builtin::BI__builtin_addcb: case Builtin::BI__builtin_addcs: @@ -2571,9 +2423,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_subc: case Builtin::BI__builtin_subcl: case Builtin::BI__builtin_subcll: - if (!interp__builtin_carryop(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_carryop(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_clz: case Builtin::BI__builtin_clzl: @@ -2583,141 +2433,101 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes case Builtin::BI__lzcnt: case Builtin::BI__lzcnt64: - if (!interp__builtin_clz(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_clz(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctzg: - if (!interp__builtin_ctz(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_ctz(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: - if (!interp__builtin_bswap(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_bswap(S, OpPC, Frame, Call); case Builtin::BI__atomic_always_lock_free: case Builtin::BI__atomic_is_lock_free: + return interp__builtin_atomic_lock_free(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__c11_atomic_is_lock_free: - if (!interp__builtin_atomic_lock_free(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_c11_atomic_is_lock_free(S, OpPC, Frame, Call); case Builtin::BI__builtin_complex: - if (!interp__builtin_complex(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_complex(S, OpPC, Frame, Call); case Builtin::BI__builtin_is_aligned: case Builtin::BI__builtin_align_up: case Builtin::BI__builtin_align_down: - if (!interp__builtin_is_aligned_up_down(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_is_aligned_up_down(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_assume_aligned: - if (!interp__builtin_assume_aligned(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_assume_aligned(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_bextr_u32: case clang::X86::BI__builtin_ia32_bextr_u64: case clang::X86::BI__builtin_ia32_bextri_u32: case clang::X86::BI__builtin_ia32_bextri_u64: - if (!interp__builtin_ia32_bextr(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ia32_bextr(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_bzhi_si: case clang::X86::BI__builtin_ia32_bzhi_di: - if (!interp__builtin_ia32_bzhi(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ia32_bzhi(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_lzcnt_u16: case clang::X86::BI__builtin_ia32_lzcnt_u32: case clang::X86::BI__builtin_ia32_lzcnt_u64: - if (!interp__builtin_ia32_lzcnt(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ia32_lzcnt(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_tzcnt_u16: case clang::X86::BI__builtin_ia32_tzcnt_u32: case clang::X86::BI__builtin_ia32_tzcnt_u64: - if (!interp__builtin_ia32_tzcnt(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ia32_tzcnt(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_pdep_si: case clang::X86::BI__builtin_ia32_pdep_di: - if (!interp__builtin_ia32_pdep(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ia32_pdep(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_pext_si: case clang::X86::BI__builtin_ia32_pext_di: - if (!interp__builtin_ia32_pext(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ia32_pext(S, OpPC, Frame, Call); case clang::X86::BI__builtin_ia32_addcarryx_u32: case clang::X86::BI__builtin_ia32_addcarryx_u64: case clang::X86::BI__builtin_ia32_subborrow_u32: case clang::X86::BI__builtin_ia32_subborrow_u64: - if (!interp__builtin_ia32_addcarry_subborrow(S, OpPC, Frame, Call, - BuiltinID)) - return false; - break; + return interp__builtin_ia32_addcarry_subborrow(S, OpPC, Frame, Call, + BuiltinID); case Builtin::BI__builtin_os_log_format_buffer_size: - if (!interp__builtin_os_log_format_buffer_size(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_os_log_format_buffer_size(S, OpPC, Frame, Call); case Builtin::BI__builtin_ptrauth_string_discriminator: - if (!interp__builtin_ptrauth_string_discriminator(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_ptrauth_string_discriminator(S, OpPC, Frame, Call); case Builtin::BI__noop: pushInteger(S, 0, Call->getType()); - break; + return true; case Builtin::BI__builtin_operator_new: - if (!interp__builtin_operator_new(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_operator_new(S, OpPC, Frame, Call); case Builtin::BI__builtin_operator_delete: - if (!interp__builtin_operator_delete(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_operator_delete(S, OpPC, Frame, Call); case Builtin::BI__arithmetic_fence: - if (!interp__builtin_arithmetic_fence(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_arithmetic_fence(S, OpPC, Frame, Call); case Builtin::BI__builtin_reduce_add: case Builtin::BI__builtin_reduce_mul: case Builtin::BI__builtin_reduce_and: case Builtin::BI__builtin_reduce_or: case Builtin::BI__builtin_reduce_xor: - if (!interp__builtin_vector_reduce(S, OpPC, Call, BuiltinID)) - return false; - break; + return interp__builtin_vector_reduce(S, OpPC, Call, BuiltinID); case Builtin::BI__builtin_elementwise_popcount: - if (!interp__builtin_elementwise_popcount(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call); case Builtin::BI__builtin_memcpy: case Builtin::BImemcpy: @@ -2727,9 +2537,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BImemmove: case Builtin::BI__builtin_wmemmove: case Builtin::BIwmemmove: - if (!interp__builtin_memcpy(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_memcpy(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_memcmp: case Builtin::BImemcmp: @@ -2737,9 +2545,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BIbcmp: case Builtin::BI__builtin_wmemcmp: case Builtin::BIwmemcmp: - if (!interp__builtin_memcmp(S, OpPC, Frame, Call, BuiltinID)) - return false; - break; + return interp__builtin_memcmp(S, OpPC, Frame, Call, BuiltinID); case Builtin::BImemchr: case Builtin::BI__builtin_memchr: @@ -2750,20 +2556,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BIwcschr: case Builtin::BI__builtin_wcschr: case Builtin::BI__builtin_char_memchr: - if (!interp__builtin_memchr(S, OpPC, Call, BuiltinID)) - return false; - break; + return interp__builtin_memchr(S, OpPC, Call, BuiltinID); case Builtin::BI__builtin_object_size: case Builtin::BI__builtin_dynamic_object_size: - if (!interp__builtin_object_size(S, OpPC, Frame, Call)) - return false; - break; + return interp__builtin_object_size(S, OpPC, Frame, Call); case Builtin::BI__builtin_is_within_lifetime: - if (!interp__builtin_is_within_lifetime(S, OpPC, Call)) - return false; - break; + return interp__builtin_is_within_lifetime(S, OpPC, Call); default: S.FFDiag(S.Current->getLocation(OpPC), @@ -2773,7 +2573,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return false; } - return retPrimValue(S, OpPC, ReturnT, Call, BuiltinID); + llvm_unreachable("Unhandled builtin ID"); } bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, |