[clang] [clang][bytecode] Pop builtin args from the stack while evaluating (PR #142832)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 4 11:35:43 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
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.
---
Patch is 62.36 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/142832.diff
1 Files Affected:
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+258-458)
``````````diff
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 89c626dd3cee8..9a3cf4f8a3309 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;
@@ -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,
- ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/142832
More information about the cfe-commits
mailing list