Skip to content

Commit c1dcf75

Browse files
authored
[clang][bytecode] Implement __builtin_reduce_mul (#118287)
1 parent 16ec534 commit c1dcf75

File tree

3 files changed

+64
-22
lines changed

3 files changed

+64
-22
lines changed

clang/lib/AST/ByteCode/Integral.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ template <unsigned Bits, bool Signed> class Integral final {
123123
APSInt toAPSInt() const {
124124
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
125125
}
126-
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
126+
APSInt toAPSInt(unsigned BitWidth) const {
127+
return APSInt(toAPInt(BitWidth), !Signed);
128+
}
127129
APInt toAPInt(unsigned BitWidth) const {
128130
if constexpr (Signed)
129131
return APInt(Bits, static_cast<uint64_t>(V), Signed)

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,32 +1695,42 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
16951695
assert(Arg.getFieldDesc()->isPrimitiveArray());
16961696

16971697
unsigned ID = Func->getBuiltinID();
1698-
if (ID == Builtin::BI__builtin_reduce_add) {
1699-
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
1700-
assert(Call->getType() == ElemType);
1701-
PrimType ElemT = *S.getContext().classify(ElemType);
1702-
unsigned NumElems = Arg.getNumElems();
1703-
1704-
INT_TYPE_SWITCH(ElemT, {
1705-
T Sum = Arg.atIndex(0).deref<T>();
1706-
unsigned BitWidth = Sum.bitWidth();
1707-
for (unsigned I = 1; I != NumElems; ++I) {
1708-
T Elem = Arg.atIndex(I).deref<T>();
1709-
if (T::add(Sum, Elem, BitWidth, &Sum)) {
1698+
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
1699+
assert(Call->getType() == ElemType);
1700+
PrimType ElemT = *S.getContext().classify(ElemType);
1701+
unsigned NumElems = Arg.getNumElems();
1702+
1703+
INT_TYPE_SWITCH(ElemT, {
1704+
T Result = Arg.atIndex(0).deref<T>();
1705+
unsigned BitWidth = Result.bitWidth();
1706+
for (unsigned I = 1; I != NumElems; ++I) {
1707+
T Elem = Arg.atIndex(I).deref<T>();
1708+
T PrevResult = Result;
1709+
1710+
if (ID == Builtin::BI__builtin_reduce_add) {
1711+
if (T::add(Result, Elem, BitWidth, &Result)) {
17101712
unsigned OverflowBits = BitWidth + 1;
1711-
(void)handleOverflow(
1712-
S, OpPC,
1713-
(Sum.toAPSInt(OverflowBits) + Elem.toAPSInt(OverflowBits)));
1713+
(void)handleOverflow(S, OpPC,
1714+
(PrevResult.toAPSInt(OverflowBits) +
1715+
Elem.toAPSInt(OverflowBits)));
17141716
return false;
17151717
}
1718+
} else if (ID == Builtin::BI__builtin_reduce_mul) {
1719+
if (T::mul(Result, Elem, BitWidth, &Result)) {
1720+
unsigned OverflowBits = BitWidth * 2;
1721+
(void)handleOverflow(S, OpPC,
1722+
(PrevResult.toAPSInt(OverflowBits) *
1723+
Elem.toAPSInt(OverflowBits)));
1724+
return false;
1725+
}
1726+
} else {
1727+
llvm_unreachable("Unhandled vector reduce builtin");
17161728
}
1717-
pushInteger(S, Sum, Call->getType());
1718-
});
1719-
1720-
return true;
1721-
}
1729+
}
1730+
pushInteger(S, Result, Call->getType());
1731+
});
17221732

1723-
llvm_unreachable("Unsupported vector reduce builtin");
1733+
return true;
17241734
}
17251735

17261736
static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
@@ -2195,6 +2205,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
21952205
break;
21962206

21972207
case Builtin::BI__builtin_reduce_add:
2208+
case Builtin::BI__builtin_reduce_mul:
21982209
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
21992210
return false;
22002211
break;

clang/test/AST/ByteCode/builtin-functions.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,35 @@ namespace RecuceAdd {
10351035
#endif
10361036
}
10371037

1038+
namespace ReduceMul {
1039+
static_assert(__builtin_reduce_mul((vector4char){}) == 0);
1040+
static_assert(__builtin_reduce_mul((vector4char){1, 2, 3, 4}) == 24);
1041+
static_assert(__builtin_reduce_mul((vector4short){1, 2, 30, 40}) == 2400);
1042+
#ifndef __AVR__
1043+
static_assert(__builtin_reduce_mul((vector4int){10, 20, 300, 400}) == 24'000'000);
1044+
#endif
1045+
static_assert(__builtin_reduce_mul((vector4long){1000L, 2000L, 3000L, 4000L}) == 24'000'000'000'000L);
1046+
constexpr int reduceMulInt1 = __builtin_reduce_mul((vector4int){~(1 << (sizeof(int) * 8 - 1)), 1, 1, 2});
1047+
// both-error@-1 {{must be initialized by a constant expression}} \
1048+
// both-note@-1 {{outside the range of representable values of type 'int'}}
1049+
constexpr long long reduceMulLong1 = __builtin_reduce_mul((vector4long){~(1LL << (sizeof(long long) * 8 - 1)), 1, 1, 2});
1050+
// both-error@-1 {{must be initialized by a constant expression}} \
1051+
// both-note@-1 {{outside the range of representable values of type 'long long'}}
1052+
constexpr int reduceMulInt2 = __builtin_reduce_mul((vector4int){(1 << (sizeof(int) * 8 - 1)), 1, 1, 2});
1053+
// both-error@-1 {{must be initialized by a constant expression}} \
1054+
// both-note@-1 {{outside the range of representable values of type 'int'}}
1055+
constexpr long long reduceMulLong2 = __builtin_reduce_mul((vector4long){(1LL << (sizeof(long long) * 8 - 1)), 1, 1, 2});
1056+
// both-error@-1 {{must be initialized by a constant expression}} \
1057+
// both-note@-1 {{outside the range of representable values of type 'long long'}}
1058+
static_assert(__builtin_reduce_mul((vector4uint){~0U, 1, 1, 2}) ==
1059+
#ifdef __AVR__
1060+
0);
1061+
#else
1062+
(~0U - 1));
1063+
#endif
1064+
static_assert(__builtin_reduce_mul((vector4ulong){~0ULL, 1, 1, 2}) == ~0ULL - 1);
1065+
}
1066+
10381067
namespace BuiltinMemcpy {
10391068
constexpr int simple() {
10401069
int a = 12;

0 commit comments

Comments
 (0)