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
3 changes: 2 additions & 1 deletion clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,8 @@ elementwise to the input.
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity

The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
``__builtin_elementwise_bitreverse``, can be called in a ``constexpr`` context.
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
``__builtin_elementwise_sub_sat`` can be called in a ``constexpr`` context.

============================================== ====================================================================== =========================================
Name Operation Supported element types
Expand Down
11 changes: 5 additions & 6 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,11 @@ Non-comprehensive list of changes in this release
The flexible array member (FAM) can now be accessed immediately without causing
issues with the sanitizer because the counter is automatically set.

- ``__builtin_reduce_add`` function can now be used in constant expressions.
- ``__builtin_reduce_mul`` function can now be used in constant expressions.
- ``__builtin_reduce_and`` function can now be used in constant expressions.
- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
- ``__builtin_elementwise_bitreverse`` function can now be used in constant expressions.
- The following builtins can now be used in constant expressions: ``__builtin_reduce_add``,
``__builtin_reduce_mul``, ``__builtin_reduce_and``, ``__builtin_reduce_or``,
``__builtin_reduce_xor``, ``__builtin_elementwise_popcount``,
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
``__builtin_elementwise_sub_sat``.

New Compiler Flags
------------------
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 @@ -1450,13 +1450,13 @@ def ElementwiseFma : Builtin {

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

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

Expand Down
50 changes: 50 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11339,6 +11339,37 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
case Builtin::BI__builtin_elementwise_add_sat:
case Builtin::BI__builtin_elementwise_sub_sat: {
APValue SourceLHS, SourceRHS;
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
return false;

QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
unsigned SourceLen = SourceLHS.getVectorLength();
SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(SourceLen);

for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt();
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_elementwise_add_sat:
ResultElements.push_back(APValue(
APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : RHS.uadd_sat(RHS),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
case Builtin::BI__builtin_elementwise_sub_sat:
ResultElements.push_back(APValue(
APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : RHS.usub_sat(RHS),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
}
}

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

Expand Down Expand Up @@ -13204,6 +13235,25 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Val.rotr(Amt.urem(Val.getBitWidth())), E);
}

case Builtin::BI__builtin_elementwise_add_sat: {
APSInt LHS, RHS;
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
!EvaluateInteger(E->getArg(1), RHS, Info))
return false;

APInt Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
return Success(APSInt(Result, !LHS.isSigned()), E);
}
case Builtin::BI__builtin_elementwise_sub_sat: {
APSInt LHS, RHS;
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
!EvaluateInteger(E->getArg(1), RHS, Info))
return false;

APInt Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
return Success(APSInt(Result, !LHS.isSigned()), E);
}

case Builtin::BIstrlen:
case Builtin::BIwcslen:
// A call to strlen is not a constant expression.
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/builtins-elementwise-math.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void test_builtin_elementwise_add_sat(float f1, float f2, double d1, double d2,
// CHECK-NEXT: call i32 @llvm.sadd.sat.i32(i32 [[IAS1]], i32 [[B]])
int_as_one = __builtin_elementwise_add_sat(int_as_one, b);

// CHECK: call i32 @llvm.sadd.sat.i32(i32 1, i32 97)
// CHECK: store i64 98, ptr %i1.addr, align 8
i1 = __builtin_elementwise_add_sat(1, 'a');
}

Expand Down Expand Up @@ -165,7 +165,7 @@ void test_builtin_elementwise_sub_sat(float f1, float f2, double d1, double d2,
// CHECK-NEXT: call i32 @llvm.ssub.sat.i32(i32 [[IAS1]], i32 [[B]])
int_as_one = __builtin_elementwise_sub_sat(int_as_one, b);

// CHECK: call i32 @llvm.ssub.sat.i32(i32 1, i32 97)
// CHECK: store i64 -96, ptr %i1.addr, align 8
i1 = __builtin_elementwise_sub_sat(1, 'a');
}

Expand Down
16 changes: 16 additions & 0 deletions clang/test/Sema/constant_builtins_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,3 +822,19 @@ static_assert(__builtin_elementwise_bitreverse(0x12345678) == 0x1E6A2C48);
static_assert(__builtin_elementwise_bitreverse(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480);
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_bitreverse((vector4char){1, 2, 4, 8})) == (LITTLE_END ? 0x10204080 : 0x80402010));
static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_bitreverse((vector4short){1, 2, 4, 8})) == (LITTLE_END ? 0x1000200040008000 : 0x8000400020001000));

static_assert(__builtin_elementwise_add_sat(1, 2) == 3);
static_assert(__builtin_elementwise_add_sat(1U, 2U) == 3U);
static_assert(__builtin_elementwise_add_sat(~(1 << 31), 42) == ~(1 << 31));
static_assert(__builtin_elementwise_add_sat((1 << 31), -42) == (1 << 31));
static_assert(__builtin_elementwise_add_sat(~0U, 1U) == ~0U);
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_add_sat((vector4char){1, 2, 3, 4}, (vector4char){4, 3, 2, 1})) == (LITTLE_END ? 0x05050505 : 0x05050505));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid uniform vector results to better show each element is working.

static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_add_sat((vector4short){(short)0x8000, (short)0x8001, (short)0x8002, (short)0x8003}, (vector4short){-7, -8, -9, -10}) == (LITTLE_END ? 0x8000800080008000 : 0x8000800080008000)));

static_assert(__builtin_elementwise_sub_sat(1, 2) == -1);
static_assert(__builtin_elementwise_sub_sat(2U, 1U) == 1U);
static_assert(__builtin_elementwise_sub_sat(~(1 << 31), -42) == ~(1 << 31));
static_assert(__builtin_elementwise_sub_sat((1 << 31), 42) == (1 << 31));
static_assert(__builtin_elementwise_sub_sat(0U, 1U) == 0U);
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_sub_sat((vector4char){5, 4, 3, 2}, (vector4char){4, 3, 2, 1})) == (LITTLE_END ? 0x01010101 : 0x01010101));
static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_sub_sat((vector4short){(short)0x8000, (short)0x8001, (short)0x8002, (short)0x8003}, (vector4short){7, 8, 9, 10}) == (LITTLE_END ? 0x8000800080008000 : 0x8000800080008000)));
Loading