Skip to content

Commit f145ff3

Browse files
authored
[clang] constexpr built-in elementwise add_sat/sub_sat functions. (#119082)
Part of #51787. This patch adds constexpr support for the built-in elementwise add_sat and sub_sat functions.
1 parent f91a5fe commit f145ff3

File tree

6 files changed

+77
-11
lines changed

6 files changed

+77
-11
lines changed

clang/docs/LanguageExtensions.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,8 @@ elementwise to the input.
648648
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity
649649

650650
The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
651-
``__builtin_elementwise_bitreverse``, can be called in a ``constexpr`` context.
651+
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
652+
``__builtin_elementwise_sub_sat`` can be called in a ``constexpr`` context.
652653

653654
============================================== ====================================================================== =========================================
654655
Name Operation Supported element types

clang/docs/ReleaseNotes.rst

+5-6
Original file line numberDiff line numberDiff line change
@@ -408,12 +408,11 @@ Non-comprehensive list of changes in this release
408408
The flexible array member (FAM) can now be accessed immediately without causing
409409
issues with the sanitizer because the counter is automatically set.
410410

411-
- ``__builtin_reduce_add`` function can now be used in constant expressions.
412-
- ``__builtin_reduce_mul`` function can now be used in constant expressions.
413-
- ``__builtin_reduce_and`` function can now be used in constant expressions.
414-
- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
415-
- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
416-
- ``__builtin_elementwise_bitreverse`` function can now be used in constant expressions.
411+
- The following builtins can now be used in constant expressions: ``__builtin_reduce_add``,
412+
``__builtin_reduce_mul``, ``__builtin_reduce_and``, ``__builtin_reduce_or``,
413+
``__builtin_reduce_xor``, ``__builtin_elementwise_popcount``,
414+
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
415+
``__builtin_elementwise_sub_sat``.
417416

418417
New Compiler Flags
419418
------------------

clang/include/clang/Basic/Builtins.td

+2-2
Original file line numberDiff line numberDiff line change
@@ -1450,13 +1450,13 @@ def ElementwiseFma : Builtin {
14501450

14511451
def ElementwiseAddSat : Builtin {
14521452
let Spellings = ["__builtin_elementwise_add_sat"];
1453-
let Attributes = [NoThrow, Const, CustomTypeChecking];
1453+
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
14541454
let Prototype = "void(...)";
14551455
}
14561456

14571457
def ElementwiseSubSat : Builtin {
14581458
let Spellings = ["__builtin_elementwise_sub_sat"];
1459-
let Attributes = [NoThrow, Const, CustomTypeChecking];
1459+
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
14601460
let Prototype = "void(...)";
14611461
}
14621462

clang/lib/AST/ExprConstant.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -11339,6 +11339,37 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1133911339

1134011340
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
1134111341
}
11342+
case Builtin::BI__builtin_elementwise_add_sat:
11343+
case Builtin::BI__builtin_elementwise_sub_sat: {
11344+
APValue SourceLHS, SourceRHS;
11345+
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
11346+
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
11347+
return false;
11348+
11349+
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
11350+
unsigned SourceLen = SourceLHS.getVectorLength();
11351+
SmallVector<APValue, 4> ResultElements;
11352+
ResultElements.reserve(SourceLen);
11353+
11354+
for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
11355+
APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
11356+
APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt();
11357+
switch (E->getBuiltinCallee()) {
11358+
case Builtin::BI__builtin_elementwise_add_sat:
11359+
ResultElements.push_back(APValue(
11360+
APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : RHS.uadd_sat(RHS),
11361+
DestEltTy->isUnsignedIntegerOrEnumerationType())));
11362+
break;
11363+
case Builtin::BI__builtin_elementwise_sub_sat:
11364+
ResultElements.push_back(APValue(
11365+
APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : RHS.usub_sat(RHS),
11366+
DestEltTy->isUnsignedIntegerOrEnumerationType())));
11367+
break;
11368+
}
11369+
}
11370+
11371+
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
11372+
}
1134211373
}
1134311374
}
1134411375

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

13238+
case Builtin::BI__builtin_elementwise_add_sat: {
13239+
APSInt LHS, RHS;
13240+
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
13241+
!EvaluateInteger(E->getArg(1), RHS, Info))
13242+
return false;
13243+
13244+
APInt Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
13245+
return Success(APSInt(Result, !LHS.isSigned()), E);
13246+
}
13247+
case Builtin::BI__builtin_elementwise_sub_sat: {
13248+
APSInt LHS, RHS;
13249+
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
13250+
!EvaluateInteger(E->getArg(1), RHS, Info))
13251+
return false;
13252+
13253+
APInt Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
13254+
return Success(APSInt(Result, !LHS.isSigned()), E);
13255+
}
13256+
1320713257
case Builtin::BIstrlen:
1320813258
case Builtin::BIwcslen:
1320913259
// A call to strlen is not a constant expression.

clang/test/CodeGen/builtins-elementwise-math.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void test_builtin_elementwise_add_sat(float f1, float f2, double d1, double d2,
112112
// CHECK-NEXT: call i32 @llvm.sadd.sat.i32(i32 [[IAS1]], i32 [[B]])
113113
int_as_one = __builtin_elementwise_add_sat(int_as_one, b);
114114

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

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

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

clang/test/Sema/constant_builtins_vector.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -822,3 +822,19 @@ static_assert(__builtin_elementwise_bitreverse(0x12345678) == 0x1E6A2C48);
822822
static_assert(__builtin_elementwise_bitreverse(0x0123456789ABCDEFULL) == 0xF7B3D591E6A2C480);
823823
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_bitreverse((vector4char){1, 2, 4, 8})) == (LITTLE_END ? 0x10204080 : 0x80402010));
824824
static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_bitreverse((vector4short){1, 2, 4, 8})) == (LITTLE_END ? 0x1000200040008000 : 0x8000400020001000));
825+
826+
static_assert(__builtin_elementwise_add_sat(1, 2) == 3);
827+
static_assert(__builtin_elementwise_add_sat(1U, 2U) == 3U);
828+
static_assert(__builtin_elementwise_add_sat(~(1 << 31), 42) == ~(1 << 31));
829+
static_assert(__builtin_elementwise_add_sat((1 << 31), -42) == (1 << 31));
830+
static_assert(__builtin_elementwise_add_sat(~0U, 1U) == ~0U);
831+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_add_sat((vector4char){1, 2, 3, 4}, (vector4char){1, 2, 3, 4})) == (LITTLE_END ? 0x08060402 : 0x02040608));
832+
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)));
833+
834+
static_assert(__builtin_elementwise_sub_sat(1, 2) == -1);
835+
static_assert(__builtin_elementwise_sub_sat(2U, 1U) == 1U);
836+
static_assert(__builtin_elementwise_sub_sat(~(1 << 31), -42) == ~(1 << 31));
837+
static_assert(__builtin_elementwise_sub_sat((1 << 31), 42) == (1 << 31));
838+
static_assert(__builtin_elementwise_sub_sat(0U, 1U) == 0U);
839+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_sub_sat((vector4char){5, 4, 3, 2}, (vector4char){1, 1, 1, 1})) == (LITTLE_END ? 0x01020304 : 0x04030201));
840+
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)));

0 commit comments

Comments
 (0)