Skip to content

Commit 246528c

Browse files
authored
[clang][bytecode] Unify elementwise integer builtins using callback pattern (#169957)
This patch refactors the handling of elementwise integer unary operations to use a unified callback-based approach, eliminating code duplication. Changes: - Extended interp__builtin_elementwise_int_unaryop to handle vector types - Replaced BI__builtin_elementwise_popcount with callback invocation - Replaced BI__builtin_elementwise_bitreverse with callback invocation - Removed interp__builtin_elementwise_popcount function The new approach uses a lambda function to specify the operation (popcount or reverseBits), which is applied uniformly to both scalar and vector operands. This reduces code duplication and makes it easier to add similar builtins in the future. Fixes #169657
1 parent 8462cff commit 246528c

File tree

1 file changed

+30
-50
lines changed

1 file changed

+30
-50
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,51 +1626,6 @@ static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC,
16261626
return true;
16271627
}
16281628

1629-
/// Can be called with an integer or vector as the first and only parameter.
1630-
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
1631-
const InterpFrame *Frame,
1632-
const CallExpr *Call,
1633-
unsigned BuiltinID) {
1634-
assert(Call->getNumArgs() == 1);
1635-
if (Call->getArg(0)->getType()->isIntegerType()) {
1636-
APSInt Val = popToAPSInt(S, Call->getArg(0));
1637-
1638-
if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
1639-
pushInteger(S, Val.popcount(), Call->getType());
1640-
} else {
1641-
pushInteger(S, Val.reverseBits(), Call->getType());
1642-
}
1643-
return true;
1644-
}
1645-
// Otherwise, the argument must be a vector.
1646-
assert(Call->getArg(0)->getType()->isVectorType());
1647-
const Pointer &Arg = S.Stk.pop<Pointer>();
1648-
assert(Arg.getFieldDesc()->isPrimitiveArray());
1649-
const Pointer &Dst = S.Stk.peek<Pointer>();
1650-
assert(Dst.getFieldDesc()->isPrimitiveArray());
1651-
assert(Arg.getFieldDesc()->getNumElems() ==
1652-
Dst.getFieldDesc()->getNumElems());
1653-
1654-
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
1655-
PrimType ElemT = *S.getContext().classify(ElemType);
1656-
unsigned NumElems = Arg.getNumElems();
1657-
1658-
// FIXME: Reading from uninitialized vector elements?
1659-
for (unsigned I = 0; I != NumElems; ++I) {
1660-
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
1661-
if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
1662-
Dst.elem<T>(I) = T::from(Arg.elem<T>(I).toAPSInt().popcount());
1663-
} else {
1664-
Dst.elem<T>(I) =
1665-
T::from(Arg.elem<T>(I).toAPSInt().reverseBits().getZExtValue());
1666-
}
1667-
});
1668-
}
1669-
Dst.initializeAllElements();
1670-
1671-
return true;
1672-
}
1673-
16741629
/// Can be called with an integer or vector as the first and only parameter.
16751630
static bool interp__builtin_elementwise_countzeroes(InterpState &S,
16761631
CodePtr OpPC,
@@ -2407,18 +2362,39 @@ static bool interp__builtin_elementwise_int_unaryop(
24072362
InterpState &S, CodePtr OpPC, const CallExpr *Call,
24082363
llvm::function_ref<APInt(const APSInt &)> Fn) {
24092364
assert(Call->getNumArgs() == 1);
2410-
assert(Call->getType()->isIntegerType());
24112365

24122366
// Single integer case.
24132367
if (!Call->getArg(0)->getType()->isVectorType()) {
2368+
assert(Call->getType()->isIntegerType());
24142369
APSInt Src = popToAPSInt(S, Call->getArg(0));
24152370
APInt Result = Fn(Src);
24162371
pushInteger(S, APSInt(std::move(Result), !Src.isSigned()), Call->getType());
24172372
return true;
24182373
}
24192374

2420-
// TODO: Add vector integer handling.
2421-
return false;
2375+
// Vector case.
2376+
const Pointer &Arg = S.Stk.pop<Pointer>();
2377+
assert(Arg.getFieldDesc()->isPrimitiveArray());
2378+
const Pointer &Dst = S.Stk.peek<Pointer>();
2379+
assert(Dst.getFieldDesc()->isPrimitiveArray());
2380+
assert(Arg.getFieldDesc()->getNumElems() ==
2381+
Dst.getFieldDesc()->getNumElems());
2382+
2383+
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
2384+
PrimType ElemT = *S.getContext().classify(ElemType);
2385+
unsigned NumElems = Arg.getNumElems();
2386+
bool DestUnsigned = Call->getType()->isUnsignedIntegerOrEnumerationType();
2387+
2388+
for (unsigned I = 0; I != NumElems; ++I) {
2389+
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
2390+
APSInt Src = Arg.elem<T>(I).toAPSInt();
2391+
APInt Result = Fn(Src);
2392+
Dst.elem<T>(I) = static_cast<T>(APSInt(std::move(Result), DestUnsigned));
2393+
});
2394+
}
2395+
Dst.initializeAllElements();
2396+
2397+
return true;
24222398
}
24232399

24242400
static bool interp__builtin_elementwise_int_binop(
@@ -4212,9 +4188,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
42124188
return interp__builtin_vector_reduce(S, OpPC, Call, BuiltinID);
42134189

42144190
case Builtin::BI__builtin_elementwise_popcount:
4191+
return interp__builtin_elementwise_int_unaryop(
4192+
S, OpPC, Call, [](const APSInt &Src) {
4193+
return APInt(Src.getBitWidth(), Src.popcount());
4194+
});
42154195
case Builtin::BI__builtin_elementwise_bitreverse:
4216-
return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call,
4217-
BuiltinID);
4196+
return interp__builtin_elementwise_int_unaryop(
4197+
S, OpPC, Call, [](const APSInt &Src) { return Src.reverseBits(); });
42184198

42194199
case Builtin::BI__builtin_elementwise_abs:
42204200
return interp__builtin_elementwise_abs(S, OpPC, Frame, Call, BuiltinID);

0 commit comments

Comments
 (0)