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
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 @@ -1540,13 +1540,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
63 changes: 63 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2829,6 +2829,65 @@ 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);

QualType Arg0Type = Call->getArg(0)->getType();
QualType Arg1Type = Call->getArg(1)->getType();
QualType Arg2Type = Call->getArg(2)->getType();

// Non-vector integer types.
if (!Arg0Type->isVectorType()) {
const APSInt &Shift =
popToAPSInt(S.Stk, *S.getContext().classify(Arg2Type));
const APSInt &Lo = popToAPSInt(S.Stk, *S.getContext().classify(Arg1Type));
const APSInt &Hi = popToAPSInt(S.Stk, *S.getContext().classify(Arg0Type));
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.
const auto *VecT = Arg0Type->castAs<VectorType>();
const PrimType &ElemT = *S.getContext().classify(VecT->getElementType());
unsigned NumElems = VecT->getNumElements();

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 @@ -3393,6 +3452,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
53 changes: 53 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12105,6 +12105,40 @@ 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;

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 @@ -14058,6 +14092,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);