-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[Clang][bytecode] interp__builtin_elementwise_int_binop - use APSInt callback instead of repeated switch statement #155891
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…llback 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
@llvm/pr-subscribers-clang Author: Simon Pilgrim (RKSimon) ChangesUsers 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 Full diff: https://github.com/llvm/llvm-project/pull/155891.diff 1 Files Affected:
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:
|
Does this also work with the immediate shifts from #155542? |
Unlikely - it's really just for elementwise patterns. But as a followup we could tweak the implementation so a scalar RHS is repeatedly used in the Fn call for every LHS element? |
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