Skip to content

Commit d72d84c

Browse files
authored
[clang][bytecode] Implement missing elementwise builtins (#147892)
1 parent b57df56 commit d72d84c

File tree

2 files changed

+107
-5
lines changed

2 files changed

+107
-5
lines changed

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 103 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/Basic/TargetBuiltins.h"
1919
#include "clang/Basic/TargetInfo.h"
2020
#include "llvm/ADT/StringExtras.h"
21+
#include "llvm/Support/ErrorHandling.h"
2122
#include "llvm/Support/SipHash.h"
2223

2324
namespace clang {
@@ -1673,6 +1674,12 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
16731674
(void)T::bitOr(Result, Elem, BitWidth, &Result);
16741675
} else if (ID == Builtin::BI__builtin_reduce_xor) {
16751676
(void)T::bitXor(Result, Elem, BitWidth, &Result);
1677+
} else if (ID == Builtin::BI__builtin_reduce_min) {
1678+
if (Elem < Result)
1679+
Result = Elem;
1680+
} else if (ID == Builtin::BI__builtin_reduce_max) {
1681+
if (Elem > Result)
1682+
Result = Elem;
16761683
} else {
16771684
llvm_unreachable("Unhandled vector reduce builtin");
16781685
}
@@ -1686,12 +1693,18 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
16861693
/// Can be called with an integer or vector as the first and only parameter.
16871694
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
16881695
const InterpFrame *Frame,
1689-
const CallExpr *Call) {
1696+
const CallExpr *Call,
1697+
unsigned BuiltinID) {
16901698
assert(Call->getNumArgs() == 1);
16911699
if (Call->getArg(0)->getType()->isIntegerType()) {
16921700
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
16931701
APSInt Val = popToAPSInt(S.Stk, ArgT);
1694-
pushInteger(S, Val.popcount(), Call->getType());
1702+
1703+
if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
1704+
pushInteger(S, Val.popcount(), Call->getType());
1705+
} else {
1706+
pushInteger(S, Val.reverseBits(), Call->getType());
1707+
}
16951708
return true;
16961709
}
16971710
// Otherwise, the argument must be a vector.
@@ -1710,8 +1723,13 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
17101723
// FIXME: Reading from uninitialized vector elements?
17111724
for (unsigned I = 0; I != NumElems; ++I) {
17121725
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
1713-
Dst.atIndex(I).deref<T>() =
1714-
T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
1726+
if (BuiltinID == Builtin::BI__builtin_elementwise_popcount) {
1727+
Dst.atIndex(I).deref<T>() =
1728+
T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
1729+
} else {
1730+
Dst.atIndex(I).deref<T>() = T::from(
1731+
Arg.atIndex(I).deref<T>().toAPSInt().reverseBits().getZExtValue());
1732+
}
17151733
Dst.atIndex(I).initialize();
17161734
});
17171735
}
@@ -2234,6 +2252,78 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
22342252
return true;
22352253
}
22362254

2255+
static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
2256+
const CallExpr *Call,
2257+
unsigned BuiltinID) {
2258+
Call->dumpColor();
2259+
assert(Call->getNumArgs() == 2);
2260+
2261+
// Single integer case.
2262+
if (!Call->getArg(0)->getType()->isVectorType()) {
2263+
assert(!Call->getArg(1)->getType()->isVectorType());
2264+
APSInt RHS = popToAPSInt(
2265+
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
2266+
APSInt LHS = popToAPSInt(
2267+
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
2268+
APInt Result;
2269+
if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
2270+
Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
2271+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
2272+
Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
2273+
} else {
2274+
llvm_unreachable("Wrong builtin ID");
2275+
}
2276+
2277+
pushInteger(S, APSInt(Result, !LHS.isSigned()), Call->getType());
2278+
return true;
2279+
}
2280+
2281+
// Vector case.
2282+
assert(Call->getArg(0)->getType()->isVectorType() &&
2283+
Call->getArg(1)->getType()->isVectorType());
2284+
const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
2285+
assert(VT->getElementType() ==
2286+
Call->getArg(1)->getType()->castAs<VectorType>()->getElementType());
2287+
assert(VT->getNumElements() ==
2288+
Call->getArg(1)->getType()->castAs<VectorType>()->getNumElements());
2289+
assert(VT->getElementType()->isIntegralOrEnumerationType());
2290+
2291+
const Pointer &RHS = S.Stk.pop<Pointer>();
2292+
const Pointer &LHS = S.Stk.pop<Pointer>();
2293+
const Pointer &Dst = S.Stk.peek<Pointer>();
2294+
PrimType ElemT = *S.getContext().classify(VT->getElementType());
2295+
unsigned NumElems = VT->getNumElements();
2296+
for (unsigned I = 0; I != NumElems; ++I) {
2297+
APSInt Elem1;
2298+
APSInt Elem2;
2299+
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
2300+
Elem1 = LHS.atIndex(I).deref<T>().toAPSInt();
2301+
Elem2 = RHS.atIndex(I).deref<T>().toAPSInt();
2302+
});
2303+
2304+
APSInt Result;
2305+
if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
2306+
Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2)
2307+
: Elem1.uadd_sat(Elem2),
2308+
Call->getType()->isUnsignedIntegerOrEnumerationType());
2309+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
2310+
Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2)
2311+
: Elem1.usub_sat(Elem2),
2312+
Call->getType()->isUnsignedIntegerOrEnumerationType());
2313+
} else {
2314+
llvm_unreachable("Wrong builtin ID");
2315+
}
2316+
2317+
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
2318+
const Pointer &E = Dst.atIndex(I);
2319+
E.deref<T>() = static_cast<T>(Result);
2320+
E.initialize();
2321+
});
2322+
}
2323+
2324+
return true;
2325+
}
2326+
22372327
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
22382328
uint32_t BuiltinID) {
22392329
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -2592,10 +2682,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
25922682
case Builtin::BI__builtin_reduce_and:
25932683
case Builtin::BI__builtin_reduce_or:
25942684
case Builtin::BI__builtin_reduce_xor:
2685+
case Builtin::BI__builtin_reduce_min:
2686+
case Builtin::BI__builtin_reduce_max:
25952687
return interp__builtin_vector_reduce(S, OpPC, Call, BuiltinID);
25962688

25972689
case Builtin::BI__builtin_elementwise_popcount:
2598-
return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call);
2690+
case Builtin::BI__builtin_elementwise_bitreverse:
2691+
return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call,
2692+
BuiltinID);
25992693

26002694
case Builtin::BI__builtin_memcpy:
26012695
case Builtin::BImemcpy:
@@ -2633,6 +2727,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
26332727
case Builtin::BI__builtin_is_within_lifetime:
26342728
return interp__builtin_is_within_lifetime(S, OpPC, Call);
26352729

2730+
case Builtin::BI__builtin_elementwise_add_sat:
2731+
case Builtin::BI__builtin_elementwise_sub_sat:
2732+
return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID);
2733+
26362734
default:
26372735
S.FFDiag(S.Current->getLocation(OpPC),
26382736
diag::note_invalid_subexpr_in_const_expr)

clang/test/Sema/constant_builtins_vector.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -Wno-bit-int-extension -triple ppc64-unknown-linux %s
33
// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -Wno-bit-int-extension -triple ppc64le-unknown-linux %s
44

5+
// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -Wno-bit-int-extension %s -fexperimental-new-constant-interpreter
6+
// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -Wno-bit-int-extension -triple ppc64-unknown-linux %s -fexperimental-new-constant-interpreter
7+
// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -Wno-bit-int-extension -triple ppc64le-unknown-linux %s -fexperimental-new-constant-interpreter
8+
59
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
610
#define LITTLE_END 1
711
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__

0 commit comments

Comments
 (0)