Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ template <unsigned Bits, bool Signed> class Integral final {
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
APSInt toAPSInt(unsigned BitWidth) const {
return APSInt(toAPInt(BitWidth), !Signed);
}
APInt toAPInt(unsigned BitWidth) const {
if constexpr (Signed)
return APInt(Bits, static_cast<uint64_t>(V), Signed)
Expand Down
53 changes: 32 additions & 21 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1695,32 +1695,42 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
assert(Arg.getFieldDesc()->isPrimitiveArray());

unsigned ID = Func->getBuiltinID();
if (ID == Builtin::BI__builtin_reduce_add) {
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH(ElemT, {
T Sum = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Sum.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
if (T::add(Sum, Elem, BitWidth, &Sum)) {
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH(ElemT, {
T Result = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Result.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
T PrevResult = Result;

if (ID == Builtin::BI__builtin_reduce_add) {
if (T::add(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth + 1;
(void)handleOverflow(
S, OpPC,
(Sum.toAPSInt(OverflowBits) + Elem.toAPSInt(OverflowBits)));
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) +
Elem.toAPSInt(OverflowBits)));
return false;
}
} else if (ID == Builtin::BI__builtin_reduce_mul) {
if (T::mul(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth * 2;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) *
Elem.toAPSInt(OverflowBits)));
return false;
}
} else {
llvm_unreachable("Unhandled vector reduce builtin");
}
pushInteger(S, Sum, Call->getType());
});

return true;
}
}
pushInteger(S, Result, Call->getType());
});

llvm_unreachable("Unsupported vector reduce builtin");
return true;
}

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

case Builtin::BI__builtin_reduce_add:
case Builtin::BI__builtin_reduce_mul:
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
return false;
break;
Expand Down
29 changes: 29 additions & 0 deletions clang/test/AST/ByteCode/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,35 @@ namespace RecuceAdd {
#endif
}

namespace ReduceMul {
static_assert(__builtin_reduce_mul((vector4char){}) == 0);
static_assert(__builtin_reduce_mul((vector4char){1, 2, 3, 4}) == 24);
static_assert(__builtin_reduce_mul((vector4short){1, 2, 30, 40}) == 2400);
#ifndef __AVR__
static_assert(__builtin_reduce_mul((vector4int){10, 20, 300, 400}) == 24'000'000);
#endif
static_assert(__builtin_reduce_mul((vector4long){1000L, 2000L, 3000L, 4000L}) == 24'000'000'000'000L);
constexpr int reduceMulInt1 = __builtin_reduce_mul((vector4int){~(1 << (sizeof(int) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'int'}}
constexpr long long reduceMulLong1 = __builtin_reduce_mul((vector4long){~(1LL << (sizeof(long long) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'long long'}}
constexpr int reduceMulInt2 = __builtin_reduce_mul((vector4int){(1 << (sizeof(int) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'int'}}
constexpr long long reduceMulLong2 = __builtin_reduce_mul((vector4long){(1LL << (sizeof(long long) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'long long'}}
static_assert(__builtin_reduce_mul((vector4uint){~0U, 1, 1, 2}) ==
#ifdef __AVR__
0);
#else
(~0U - 1));
#endif
static_assert(__builtin_reduce_mul((vector4ulong){~0ULL, 1, 1, 2}) == ~0ULL - 1);
}

namespace BuiltinMemcpy {
constexpr int simple() {
int a = 12;
Expand Down