Skip to content

Commit 0b04c9f

Browse files
authored
Merge branch 'main' into cuf___brev
2 parents 7f91649 + 6b09e95 commit 0b04c9f

File tree

31 files changed

+1255
-403
lines changed

31 files changed

+1255
-403
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,8 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in
759759

760760
The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
761761
``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``,
762-
``__builtin_elementwise_sub_sat`` can be called in a ``constexpr`` context.
762+
``__builtin_elementwise_sub_sat``, ``__builtin_elementwise_max``,
763+
``__builtin_elementwise_min`` can be called in a ``constexpr`` context.
763764

764765
No implicit promotion of integer types takes place. The mixing of integer types
765766
of different sizes and signs is forbidden in binary and ternary builtins.

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ Non-comprehensive list of changes in this release
124124
This feature is enabled by default but can be disabled by compiling with
125125
``-fno-sanitize-annotate-debug-info-traps``.
126126

127+
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can
128+
now be used in constant expressions.
129+
127130
New Compiler Flags
128131
------------------
129132
- New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``).

clang/include/clang/Basic/Builtins.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,13 +1300,13 @@ def ElementwiseBitreverse : Builtin {
13001300

13011301
def ElementwiseMax : Builtin {
13021302
let Spellings = ["__builtin_elementwise_max"];
1303-
let Attributes = [NoThrow, Const, CustomTypeChecking];
1303+
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
13041304
let Prototype = "void(...)";
13051305
}
13061306

13071307
def ElementwiseMin : Builtin {
13081308
let Spellings = ["__builtin_elementwise_min"];
1309-
let Attributes = [NoThrow, Const, CustomTypeChecking];
1309+
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
13101310
let Prototype = "void(...)";
13111311
}
13121312

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2259,7 +2259,6 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
22592259
static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
22602260
const CallExpr *Call,
22612261
unsigned BuiltinID) {
2262-
Call->dumpColor();
22632262
assert(Call->getNumArgs() == 2);
22642263

22652264
// Single integer case.
@@ -2326,6 +2325,80 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
23262325
return true;
23272326
}
23282327

2328+
static bool interp__builtin_elementwise_maxmin(InterpState &S, CodePtr OpPC,
2329+
const CallExpr *Call,
2330+
unsigned BuiltinID) {
2331+
assert(Call->getNumArgs() == 2);
2332+
2333+
QualType Arg0Type = Call->getArg(0)->getType();
2334+
2335+
// TODO: Support floating-point types.
2336+
if (!(Arg0Type->isIntegerType() ||
2337+
(Arg0Type->isVectorType() &&
2338+
Arg0Type->castAs<VectorType>()->getElementType()->isIntegerType())))
2339+
return false;
2340+
2341+
if (!Arg0Type->isVectorType()) {
2342+
assert(!Call->getArg(1)->getType()->isVectorType());
2343+
APSInt RHS = popToAPSInt(
2344+
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
2345+
APSInt LHS = popToAPSInt(
2346+
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
2347+
APInt Result;
2348+
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
2349+
Result = std::max(LHS, RHS);
2350+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
2351+
Result = std::min(LHS, RHS);
2352+
} else {
2353+
llvm_unreachable("Wrong builtin ID");
2354+
}
2355+
2356+
pushInteger(S, APSInt(Result, !LHS.isSigned()), Call->getType());
2357+
return true;
2358+
}
2359+
2360+
// Vector case.
2361+
assert(Call->getArg(0)->getType()->isVectorType() &&
2362+
Call->getArg(1)->getType()->isVectorType());
2363+
const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
2364+
assert(VT->getElementType() ==
2365+
Call->getArg(1)->getType()->castAs<VectorType>()->getElementType());
2366+
assert(VT->getNumElements() ==
2367+
Call->getArg(1)->getType()->castAs<VectorType>()->getNumElements());
2368+
assert(VT->getElementType()->isIntegralOrEnumerationType());
2369+
2370+
const Pointer &RHS = S.Stk.pop<Pointer>();
2371+
const Pointer &LHS = S.Stk.pop<Pointer>();
2372+
const Pointer &Dst = S.Stk.peek<Pointer>();
2373+
PrimType ElemT = *S.getContext().classify(VT->getElementType());
2374+
unsigned NumElems = VT->getNumElements();
2375+
for (unsigned I = 0; I != NumElems; ++I) {
2376+
APSInt Elem1;
2377+
APSInt Elem2;
2378+
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
2379+
Elem1 = LHS.elem<T>(I).toAPSInt();
2380+
Elem2 = RHS.elem<T>(I).toAPSInt();
2381+
});
2382+
2383+
APSInt Result;
2384+
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
2385+
Result = APSInt(std::max(Elem1, Elem2),
2386+
Call->getType()->isUnsignedIntegerOrEnumerationType());
2387+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
2388+
Result = APSInt(std::min(Elem1, Elem2),
2389+
Call->getType()->isUnsignedIntegerOrEnumerationType());
2390+
} else {
2391+
llvm_unreachable("Wrong builtin ID");
2392+
}
2393+
2394+
INT_TYPE_SWITCH_NO_BOOL(ElemT,
2395+
{ Dst.elem<T>(I) = static_cast<T>(Result); });
2396+
}
2397+
Dst.initializeAllElements();
2398+
2399+
return true;
2400+
}
2401+
23292402
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
23302403
uint32_t BuiltinID) {
23312404
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -2733,6 +2806,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
27332806
case Builtin::BI__builtin_elementwise_sub_sat:
27342807
return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID);
27352808

2809+
case Builtin::BI__builtin_elementwise_max:
2810+
case Builtin::BI__builtin_elementwise_min:
2811+
return interp__builtin_elementwise_maxmin(S, OpPC, Call, BuiltinID);
2812+
27362813
default:
27372814
S.FFDiag(S.Current->getLocation(OpPC),
27382815
diag::note_invalid_subexpr_in_const_expr)

clang/lib/AST/ExprConstant.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11688,6 +11688,41 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1168811688

1168911689
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
1169011690
}
11691+
case Builtin::BI__builtin_elementwise_max:
11692+
case Builtin::BI__builtin_elementwise_min: {
11693+
APValue SourceLHS, SourceRHS;
11694+
if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
11695+
!EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
11696+
return false;
11697+
11698+
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
11699+
11700+
if (!DestEltTy->isIntegerType())
11701+
return false;
11702+
11703+
unsigned SourceLen = SourceLHS.getVectorLength();
11704+
SmallVector<APValue, 4> ResultElements;
11705+
ResultElements.reserve(SourceLen);
11706+
11707+
for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
11708+
APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
11709+
APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt();
11710+
switch (E->getBuiltinCallee()) {
11711+
case Builtin::BI__builtin_elementwise_max:
11712+
ResultElements.push_back(
11713+
APValue(APSInt(std::max(LHS, RHS),
11714+
DestEltTy->isUnsignedIntegerOrEnumerationType())));
11715+
break;
11716+
case Builtin::BI__builtin_elementwise_min:
11717+
ResultElements.push_back(
11718+
APValue(APSInt(std::min(LHS, RHS),
11719+
DestEltTy->isUnsignedIntegerOrEnumerationType())));
11720+
break;
11721+
}
11722+
}
11723+
11724+
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
11725+
}
1169111726
}
1169211727
}
1169311728

@@ -13585,7 +13620,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1358513620
APInt Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
1358613621
return Success(APSInt(Result, !LHS.isSigned()), E);
1358713622
}
13623+
case Builtin::BI__builtin_elementwise_max: {
13624+
APSInt LHS, RHS;
13625+
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
13626+
!EvaluateInteger(E->getArg(1), RHS, Info))
13627+
return false;
13628+
13629+
APInt Result = std::max(LHS, RHS);
13630+
return Success(APSInt(Result, !LHS.isSigned()), E);
13631+
}
13632+
case Builtin::BI__builtin_elementwise_min: {
13633+
APSInt LHS, RHS;
13634+
if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
13635+
!EvaluateInteger(E->getArg(1), RHS, Info))
13636+
return false;
1358813637

13638+
APInt Result = std::min(LHS, RHS);
13639+
return Success(APSInt(Result, !LHS.isSigned()), E);
13640+
}
1358913641
case Builtin::BIstrlen:
1359013642
case Builtin::BIwcslen:
1359113643
// A call to strlen is not a constant expression.

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ void test_builtin_elementwise_max(float f1, float f2, double d1, double d2,
418418
// CHECK-NEXT: call i32 @llvm.smax.i32(i32 [[IAS1]], i32 [[B]])
419419
int_as_one = __builtin_elementwise_max(int_as_one, b);
420420

421-
// CHECK: call i32 @llvm.smax.i32(i32 1, i32 97)
421+
// CHECK: store i64 97, ptr [[I1:%.+]], align 8
422422
i1 = __builtin_elementwise_max(1, 'a');
423423
}
424424

@@ -508,6 +508,9 @@ void test_builtin_elementwise_min(float f1, float f2, double d1, double d2,
508508
// CHECK-NEXT: [[B:%.+]] = load i32, ptr @b, align 4
509509
// CHECK-NEXT: call i32 @llvm.smin.i32(i32 [[IAS1]], i32 [[B]])
510510
int_as_one = __builtin_elementwise_min(int_as_one, b);
511+
512+
// CHECK: store i64 2, ptr [[I1:%.+]], align 8
513+
i1 = __builtin_elementwise_min(2, 'b');
511514
}
512515

513516
void test_builtin_elementwise_bitreverse(si8 vi1, si8 vi2,

clang/test/Interpreter/bad_percent_command.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// UNSUPPORTED: system-aix
12
// RUN: cat %s | clang-repl 2>&1 | FileCheck %s
23
%foobar
34
// CHECK: Invalid % command "%foobar", use "%help" to list commands

clang/test/Interpreter/dynamic-library-bad-args.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// UNSUPPORTED: system-aix
12
// RUN: cat %s | clang-repl 2>&1 | FileCheck %s
23
%lib
34
// CHECK: %lib expects 1 argument: the path to a dynamic library

clang/test/Interpreter/help.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// UNSUPPORTED: system-aix
12
// RUN: cat %s | clang-repl | FileCheck %s
23
%help
34
// CHECK: %help list clang-repl %commands

clang/test/Sema/constant-builtins-vector.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,3 +860,19 @@ static_assert(__builtin_elementwise_sub_sat(0U, 1U) == 0U);
860860
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_sub_sat((vector4char){5, 4, 3, 2}, (vector4char){1, 1, 1, 1})) == (LITTLE_END ? 0x01020304 : 0x04030201));
861861
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_sub_sat((vector4uchar){5, 4, 3, 2}, (vector4uchar){1, 1, 1, 1})) == (LITTLE_END ? 0x01020304U : 0x04030201U));
862862
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)));
863+
864+
static_assert(__builtin_elementwise_max(1, 2) == 2);
865+
static_assert(__builtin_elementwise_max(-1, 1) == 1);
866+
static_assert(__builtin_elementwise_max(1U, 2U) == 2U);
867+
static_assert(__builtin_elementwise_max(~0U, 0U) == ~0U);
868+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_max((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFF03FE04 : 0x04FE03FF ));
869+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_max((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x04030304U);
870+
static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_max((vector4short){1, -2, 3, -4}, (vector4short){4, -3, 2, -1})) == (LITTLE_END ? 0xFFFF0003FFFE0004 : 0x0004FFFE0003FFFF));
871+
872+
static_assert(__builtin_elementwise_min(1, 2) == 1);
873+
static_assert(__builtin_elementwise_min(-1, 1) == -1);
874+
static_assert(__builtin_elementwise_min(1U, 2U) == 1U);
875+
static_assert(__builtin_elementwise_min(~0U, 0U) == 0U);
876+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFC02FD01 : 0x01FD02FC));
877+
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x01020201U);
878+
static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_min((vector4short){1, -2, 3, -4}, (vector4short){4, -3, 2, -1})) == (LITTLE_END ? 0xFFFC0002FFFD0001 : 0x0001FFFD0002FFFC));

0 commit comments

Comments
 (0)