Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 4 additions & 2 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -875,12 +875,14 @@ of different sizes and signs is forbidden in binary and ternary builtins.
for the comparison.
T __builtin_elementwise_fshl(T x, T y, T z) perform a funnel shift left. Concatenate x and y (x is the most integer types
significant bits of the wide value), the combined value is shifted
left by z, and the most significant bits are extracted to produce
left by z (modulo the bit width of the original arguments),
and the most significant bits are extracted to produce
a result that is the same size as the original arguments.

T __builtin_elementwise_fshr(T x, T y, T z) perform a funnel shift right. Concatenate x and y (x is the most integer types
significant bits of the wide value), the combined value is shifted
right by z, and the least significant bits are extracted to produce
right by z (modulo the bit width of the original arguments),
and the least significant bits are extracted to produce
a result that is the same size as the original arguments.
T __builtin_elementwise_ctlz(T x[, T y]) return the number of leading 0 bits in the first argument. If integer types
the first argument is 0 and an optional second argument is provided,
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1528,13 +1528,13 @@ def ElementwiseSubSat : Builtin {

def ElementwiseFshl : Builtin {
let Spellings = ["__builtin_elementwise_fshl"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

def ElementwiseFshr : Builtin {
let Spellings = ["__builtin_elementwise_fshr"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

Expand Down
80 changes: 80 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2817,6 +2817,82 @@ static bool interp__builtin_select(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_elementwise_fsh(InterpState &S, CodePtr OpPC,
const CallExpr *Call,
unsigned BuiltinID) {
assert(Call->getNumArgs() == 3);

const QualType &Arg1Type = Call->getArg(0)->getType();
const QualType &Arg2Type = Call->getArg(1)->getType();
const QualType &Arg3Type = Call->getArg(2)->getType();

// Non-vector integer types.
if (!Arg1Type->isVectorType()) {
assert(!Arg2Type->isVectorType());
assert(!Arg3Type->isVectorType());
const APSInt &Shift = popToAPSInt(
S.Stk, *S.getContext().classify(Call->getArg(2)->getType()));
const APSInt &Lo = popToAPSInt(
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
const APSInt &Hi = popToAPSInt(
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
APSInt Result;
if (BuiltinID == Builtin::BI__builtin_elementwise_fshl) {
Result = APSInt(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned());
} else if (BuiltinID == Builtin::BI__builtin_elementwise_fshr) {
Result = APSInt(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned());
} else {
llvm_unreachable("Wrong builtin ID");
}
pushInteger(S, Result, Call->getType());
return true;
}

// Vector type.
assert(Arg1Type->isVectorType() && Arg2Type->isVectorType() &&
Arg3Type->isVectorType());

const VectorType *VecT = Arg1Type->castAs<VectorType>();
const PrimType &ElemT = *S.getContext().classify(VecT->getElementType());
unsigned NumElems = VecT->getNumElements();

assert(VecT->getElementType() ==
Arg2Type->castAs<VectorType>()->getElementType() &&
VecT->getElementType() ==
Arg3Type->castAs<VectorType>()->getElementType());
assert(NumElems == Arg2Type->castAs<VectorType>()->getNumElements() &&
NumElems == Arg3Type->castAs<VectorType>()->getNumElements());
assert(VecT->getElementType()->isIntegralOrEnumerationType());

const Pointer &VecShift = S.Stk.pop<Pointer>();
const Pointer &VecLo = S.Stk.pop<Pointer>();
const Pointer &VecHi = S.Stk.pop<Pointer>();
const Pointer &Dst = S.Stk.peek<Pointer>();
for (unsigned I = 0; I != NumElems; ++I) {
APSInt Hi;
APSInt Lo;
APSInt Shift;
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
Hi = VecHi.elem<T>(I).toAPSInt();
Lo = VecLo.elem<T>(I).toAPSInt();
Shift = VecShift.elem<T>(I).toAPSInt();
});
APSInt Result;
if (BuiltinID == Builtin::BI__builtin_elementwise_fshl) {
Result = APSInt(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned());
} else if (BuiltinID == Builtin::BI__builtin_elementwise_fshr) {
Result = APSInt(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned());
} else {
llvm_unreachable("Wrong builtin ID");
}
INT_TYPE_SWITCH_NO_BOOL(ElemT,
{ Dst.elem<T>(I) = static_cast<T>(Result); });
}
Dst.initializeAllElements();

return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
Expand Down Expand Up @@ -3279,6 +3355,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case X86::BI__builtin_ia32_selectpd_512:
return interp__builtin_select(S, OpPC, Call);

case Builtin::BI__builtin_elementwise_fshl:
case Builtin::BI__builtin_elementwise_fshr:
return interp__builtin_elementwise_fsh(S, OpPC, Call, BuiltinID);

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
55 changes: 55 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11941,6 +11941,42 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}

case Builtin::BI__builtin_elementwise_fshl:
case Builtin::BI__builtin_elementwise_fshr: {
APValue SourceHi, SourceLo, SourceShift;
if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) ||
!EvaluateAsRValue(Info, E->getArg(1), SourceLo) ||
!EvaluateAsRValue(Info, E->getArg(2), SourceShift))
return false;

const QualType &DestEltTy =
E->getType()->castAs<VectorType>()->getElementType();

if (!DestEltTy->isIntegerType())
return false;

unsigned SourceLen = SourceHi.getVectorLength();
SmallVector<APValue> ResultElements;
ResultElements.reserve(SourceLen);
for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
const APSInt &Hi = SourceHi.getVectorElt(EltNum).getInt();
const APSInt &Lo = SourceLo.getVectorElt(EltNum).getInt();
const APSInt &Shift = SourceShift.getVectorElt(EltNum).getInt();
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_elementwise_fshl:
ResultElements.push_back(APValue(
APSInt(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned())));
break;
case Builtin::BI__builtin_elementwise_fshr:
ResultElements.push_back(APValue(
APSInt(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned())));
break;
}
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
}
}

Expand Down Expand Up @@ -13879,6 +13915,25 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
APInt Result = std::min(LHS, RHS);
return Success(APSInt(Result, !LHS.isSigned()), E);
}
case Builtin::BI__builtin_elementwise_fshl:
case Builtin::BI__builtin_elementwise_fshr: {
APSInt Hi, Lo, Shift;
if (!EvaluateInteger(E->getArg(0), Hi, Info) ||
!EvaluateInteger(E->getArg(1), Lo, Info) ||
!EvaluateInteger(E->getArg(2), Shift, Info))
return false;

switch (BuiltinOp) {
case Builtin::BI__builtin_elementwise_fshl: {
APSInt Result(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned());
return Success(Result, E);
}
case Builtin::BI__builtin_elementwise_fshr: {
APSInt Result(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned());
return Success(Result, E);
}
}
}
case Builtin::BIstrlen:
case Builtin::BIwcslen:
// A call to strlen is not a constant expression.
Expand Down
48 changes: 48 additions & 0 deletions clang/test/Sema/constant-builtins-vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -961,3 +961,51 @@ static_assert(fmaDouble1[3] == 26.0);
constexpr float fmaArray[] = {2.0f, 2.0f, 2.0f, 2.0f};
constexpr float fmaResult = __builtin_elementwise_fma(fmaArray[1], fmaArray[2], fmaArray[3]);
static_assert(fmaResult == 6.0f, "");

static_assert(__builtin_elementwise_fshl((unsigned char)255, (unsigned char)0, (unsigned char)8) == (unsigned char)255);
static_assert(__builtin_elementwise_fshl((char)127, (char)0, (char)8) == (char)127);
static_assert(__builtin_elementwise_fshl((unsigned char)0, (unsigned char)255, (unsigned char)8) == (unsigned char)0);
static_assert(__builtin_elementwise_fshl((char)0, (char)127, (char)8) == (char)0);
static_assert(__builtin_elementwise_fshr((unsigned char)255, (unsigned char)0, (unsigned char)8) == (unsigned char)0);
static_assert(__builtin_elementwise_fshr((char)127, (char)0, (char)8) == (char)0);
static_assert(__builtin_elementwise_fshr((unsigned char)0, (unsigned char)255, (unsigned char)8) == (unsigned char)255);
static_assert(__builtin_elementwise_fshr((char)0, (char)127, (char)8) == (char)127);
static_assert(__builtin_elementwise_fshl((unsigned int)4294967295, (unsigned int)0, (unsigned int)32) == (unsigned int)4294967295);
static_assert(__builtin_elementwise_fshl((int)2147483647, (int)0, (int)32) == (int)2147483647);
static_assert(__builtin_elementwise_fshl((unsigned int)0, (unsigned int)4294967295, (unsigned int)32) == (unsigned int)0);
static_assert(__builtin_elementwise_fshl((int)0, (int)2147483647, (int)32) == (int)0);
static_assert(__builtin_elementwise_fshr((unsigned int)4294967295, (unsigned int)0, (unsigned int)32) == (unsigned int)0);
static_assert(__builtin_elementwise_fshr((int)2147483647, (int)0, (int)32) == (int)0);
static_assert(__builtin_elementwise_fshr((unsigned int)0, (unsigned int)4294967295, (unsigned int)32) == (unsigned int)4294967295);
static_assert(__builtin_elementwise_fshr((int)0, (int)2147483647, (int)32) == (int)2147483647);
static_assert(__builtin_elementwise_fshl((unsigned long long)18446744073709551615ULL, (unsigned long long)0, (unsigned long long)64) == (unsigned long long)18446744073709551615ULL);
static_assert(__builtin_elementwise_fshl((long long)9223372036854775807, (long long)0, (long long)64) == (long long)9223372036854775807);
static_assert(__builtin_elementwise_fshl((unsigned long long)0, (unsigned long long)18446744073709551615ULL, (unsigned long long)64) == (unsigned long long)0);
static_assert(__builtin_elementwise_fshl((long long)0, (long long)9223372036854775807, (long long)64) == (long long)0);
static_assert(__builtin_elementwise_fshr((unsigned long long)18446744073709551615ULL, (unsigned long long)0, (unsigned long long)64) == (unsigned long long)0);
static_assert(__builtin_elementwise_fshr((long long)9223372036854775807, (long long)0, (long long)64) == (long long)0);
static_assert(__builtin_elementwise_fshr((unsigned long long)0, (unsigned long long)18446744073709551615ULL, (unsigned long long)64) == (unsigned long long)18446744073709551615ULL);
static_assert(__builtin_elementwise_fshr((long long)0, (long long)9223372036854775807, (long long)64) == (long long)9223372036854775807);
static_assert(__builtin_elementwise_fshl((short) 1, (short) 2, (short) 3) == (short)8);
static_assert(__builtin_elementwise_fshl((short) 2, (short) 1, (short) 3) == (short)16);
static_assert(__builtin_elementwise_fshl(1, 2 , 2) == 4);
static_assert(__builtin_elementwise_fshl(2L, 1L , 2L) == 8L);
static_assert(__builtin_elementwise_fshr((unsigned char)1, (unsigned char)2, (unsigned char)3) == (unsigned char)32);
constexpr vector4uchar v4s_fshl_var =
__builtin_elementwise_fshl((vector4uchar){255, 15, 0, 2},
(vector4uchar){0, 15, 255, 1},
(vector4uchar){15, 11, 8, 3});
static_assert(v4s_fshl_var[0] == 128);
static_assert(v4s_fshl_var[1] == 120);
static_assert(v4s_fshl_var[2] == 0);
static_assert(v4s_fshl_var[3] == 16);
constexpr vector4uchar v4s_fshr_var =
__builtin_elementwise_fshr((vector4uchar){255, 15, 0, 1},
(vector4uchar){0, 15, 255, 2},
(vector4uchar){15, 11, 8, 3});
static_assert(v4s_fshr_var[0] == 254);
static_assert(v4s_fshr_var[1] == 225);
static_assert(v4s_fshr_var[2] == 255);
static_assert(v4s_fshr_var[3] == 32);
static_assert(__builtin_elementwise_fshl(v4s_fshl_var[0], v4s_fshl_var[1], v4s_fshl_var[2]) == 128);
static_assert(__builtin_elementwise_fshr(v4s_fshr_var[0], v4s_fshr_var[1], v4s_fshr_var[2]) == 253);