[clang] [Clang][bytecode] interp__builtin_elementwise_int_binop - use APSInt callback instead of repeated switch statement (PR #155891)
Simon Pilgrim via cfe-commits
cfe-commits at lists.llvm.org
Fri Aug 29 04:25:16 PDT 2025
https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/155891
>From 5e7ef5c215f5e7250f885c8d9e78f08c2c1e679f Mon Sep 17 00:00:00 2001
From: Simon Pilgrim <llvm-dev at redking.me.uk>
Date: Thu, 28 Aug 2025 18:26:20 +0100
Subject: [PATCH] [Clang][Interp] interp__builtin_elementwise_int_binop - use
APSInt callback instead of repeated switch statement
Users of interp__builtin_elementwise_int_binop are going to be very well defined, we can use a simple callback mechanism (including existing llvm::APIntOps static methods) to perform the evaluation and avoid a repeated switch statement.
Hopefully this will help keep interp__builtin_elementwise_int_binop clean as we add more uses
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 116 +++++++++--------------
1 file changed, 46 insertions(+), 70 deletions(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 765c692991645..eba0b25997699 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2548,9 +2548,9 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
return true;
}
-static bool interp__builtin_elementwise_int_binop(InterpState &S, CodePtr OpPC,
- const CallExpr *Call,
- unsigned BuiltinID) {
+static bool interp__builtin_elementwise_int_binop(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned BuiltinID,
+ llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) {
assert(Call->getNumArgs() == 2);
// Single integer case.
@@ -2560,15 +2560,7 @@ static bool interp__builtin_elementwise_int_binop(InterpState &S, CodePtr OpPC,
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
APSInt LHS = popToAPSInt(
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
- APInt Result;
- if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
- Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
- } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
- Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
- } else {
- llvm_unreachable("Wrong builtin ID");
- }
-
+ APInt Result = Fn(LHS, RHS);
pushInteger(S, APSInt(std::move(Result), !LHS.isSigned()), Call->getType());
return true;
}
@@ -2587,8 +2579,6 @@ static bool interp__builtin_elementwise_int_binop(InterpState &S, CodePtr OpPC,
const Pointer &LHS = S.Stk.pop<Pointer>();
const Pointer &Dst = S.Stk.peek<Pointer>();
PrimType ElemT = *S.getContext().classify(VT->getElementType());
- bool DestUnsigned =
- VT->getElementType()->isUnsignedIntegerOrEnumerationType();
unsigned NumElems = VT->getNumElements();
for (unsigned I = 0; I != NumElems; ++I) {
APSInt Elem1;
@@ -2598,61 +2588,9 @@ static bool interp__builtin_elementwise_int_binop(InterpState &S, CodePtr OpPC,
Elem2 = RHS.elem<T>(I).toAPSInt();
});
- APSInt Result;
- switch (BuiltinID) {
- case Builtin::BI__builtin_elementwise_add_sat:
- Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2)
- : Elem1.uadd_sat(Elem2),
- Call->getType()->isUnsignedIntegerOrEnumerationType());
- break;
- case Builtin::BI__builtin_elementwise_sub_sat:
- Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2)
- : Elem1.usub_sat(Elem2),
- Call->getType()->isUnsignedIntegerOrEnumerationType());
- break;
- case clang::X86::BI__builtin_ia32_pmulhuw128:
- case clang::X86::BI__builtin_ia32_pmulhuw256:
- case clang::X86::BI__builtin_ia32_pmulhuw512:
- Result = APSInt(llvm::APIntOps::mulhu(Elem1, Elem2),
- /*isUnsigned=*/true);
- break;
- case clang::X86::BI__builtin_ia32_pmulhw128:
- case clang::X86::BI__builtin_ia32_pmulhw256:
- case clang::X86::BI__builtin_ia32_pmulhw512:
- Result = APSInt(llvm::APIntOps::mulhs(Elem1, Elem2),
- /*isUnsigned=*/false);
- break;
- case clang::X86::BI__builtin_ia32_psllv2di:
- case clang::X86::BI__builtin_ia32_psllv4di:
- case clang::X86::BI__builtin_ia32_psllv4si:
- case clang::X86::BI__builtin_ia32_psllv8si:
- if (Elem2.uge(Elem2.getBitWidth())) {
- Result = APSInt(APInt::getZero(Elem2.getBitWidth()), DestUnsigned);
- break;
- }
- Result = APSInt(Elem1.shl(Elem2.getZExtValue()), DestUnsigned);
- break;
- case clang::X86::BI__builtin_ia32_psrav4si:
- case clang::X86::BI__builtin_ia32_psrav8si:
- if (Elem2.uge(Elem2.getBitWidth())) {
- Result = APSInt(Elem1.ashr(Elem2.getBitWidth() - 1), DestUnsigned);
- break;
- }
- Result = APSInt(Elem1.ashr(Elem2.getZExtValue()), DestUnsigned);
- break;
- case clang::X86::BI__builtin_ia32_psrlv2di:
- case clang::X86::BI__builtin_ia32_psrlv4di:
- case clang::X86::BI__builtin_ia32_psrlv4si:
- case clang::X86::BI__builtin_ia32_psrlv8si:
- if (Elem2.uge(Elem2.getBitWidth())) {
- Result = APSInt(APInt::getZero(Elem2.getBitWidth()), DestUnsigned);
- break;
- }
- Result = APSInt(Elem1.lshr(Elem2.getZExtValue()), DestUnsigned);
- break;
- default:
- llvm_unreachable("Wrong builtin ID");
- }
+ APSInt Result =
+ APSInt(Fn(Elem1, Elem2),
+ Call->getType()->isUnsignedIntegerOrEnumerationType());
INT_TYPE_SWITCH_NO_BOOL(ElemT,
{ Dst.elem<T>(I) = static_cast<T>(Result); });
@@ -3289,24 +3227,62 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_is_within_lifetime(S, OpPC, Call);
case Builtin::BI__builtin_elementwise_add_sat:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
+ });
+
case Builtin::BI__builtin_elementwise_sub_sat:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
+ });
+
case clang::X86::BI__builtin_ia32_pmulhuw128:
case clang::X86::BI__builtin_ia32_pmulhuw256:
case clang::X86::BI__builtin_ia32_pmulhuw512:
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call, BuiltinID,
+ llvm::APIntOps::mulhu);
+
case clang::X86::BI__builtin_ia32_pmulhw128:
case clang::X86::BI__builtin_ia32_pmulhw256:
case clang::X86::BI__builtin_ia32_pmulhw512:
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call, BuiltinID,
+ llvm::APIntOps::mulhs);
+
case clang::X86::BI__builtin_ia32_psllv2di:
case clang::X86::BI__builtin_ia32_psllv4di:
case clang::X86::BI__builtin_ia32_psllv4si:
case clang::X86::BI__builtin_ia32_psllv8si:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(RHS.getBitWidth())) {
+ return APInt::getZero(RHS.getBitWidth());
+ }
+ return LHS.shl(RHS.getZExtValue());
+ });
+
case clang::X86::BI__builtin_ia32_psrav4si:
case clang::X86::BI__builtin_ia32_psrav8si:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(RHS.getBitWidth())) {
+ return LHS.ashr(RHS.getBitWidth() - 1);
+ }
+ return LHS.ashr(RHS.getZExtValue());
+ });
+
case clang::X86::BI__builtin_ia32_psrlv2di:
case clang::X86::BI__builtin_ia32_psrlv4di:
case clang::X86::BI__builtin_ia32_psrlv4si:
case clang::X86::BI__builtin_ia32_psrlv8si:
- return interp__builtin_elementwise_int_binop(S, OpPC, Call, BuiltinID);
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(RHS.getBitWidth())) {
+ return APInt::getZero(RHS.getBitWidth());
+ }
+ return LHS.lshr(RHS.getZExtValue());
+ });
case Builtin::BI__builtin_elementwise_max:
case Builtin::BI__builtin_elementwise_min:
More information about the cfe-commits
mailing list