Skip to content

Commit e43d3d0

Browse files
committed
[clang] constexpr __builtin_elementwise_{max,min}
1 parent 7b904b0 commit e43d3d0

File tree

4 files changed

+120
-61
lines changed

4 files changed

+120
-61
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ Non-comprehensive list of changes in this release
126126
This feature is enabled by default but can be disabled by compiling with
127127
``-fno-sanitize-annotate-debug-info-traps``.
128128

129-
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions for integer types can
130-
now be used in constant expressions.
129+
- ``__builtin_elementwise_max`` and ``__builtin_elementwise_min`` functions can now be used in
130+
constant expressions.
131131

132132
New Compiler Flags
133133
------------------

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2339,68 +2339,88 @@ static bool interp__builtin_elementwise_maxmin(InterpState &S, CodePtr OpPC,
23392339
assert(Call->getNumArgs() == 2);
23402340

23412341
QualType Arg0Type = Call->getArg(0)->getType();
2342+
QualType Arg1Type = Call->getArg(1)->getType();
23422343

2343-
// TODO: Support floating-point types.
2344-
if (!(Arg0Type->isIntegerType() ||
2345-
(Arg0Type->isVectorType() &&
2346-
Arg0Type->castAs<VectorType>()->getElementType()->isIntegerType())))
2347-
return false;
2348-
2349-
if (!Arg0Type->isVectorType()) {
2350-
assert(!Call->getArg(1)->getType()->isVectorType());
2351-
APSInt RHS = popToAPSInt(
2352-
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
2353-
APSInt LHS = popToAPSInt(
2354-
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
2355-
APInt Result;
2344+
if (Arg0Type->isIntegerType()) {
2345+
assert(Arg1Type->isIntegerType());
2346+
APSInt RHS = popToAPSInt(S.Stk, *S.getContext().classify(Arg1Type));
2347+
APSInt LHS = popToAPSInt(S.Stk, *S.getContext().classify(Arg0Type));
2348+
APSInt Result;
23562349
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
23572350
Result = std::max(LHS, RHS);
23582351
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
23592352
Result = std::min(LHS, RHS);
23602353
} else {
23612354
llvm_unreachable("Wrong builtin ID");
23622355
}
2356+
pushInteger(S, Result, Call->getType());
2357+
return true;
2358+
}
23632359

2364-
pushInteger(S, APSInt(Result, !LHS.isSigned()), Call->getType());
2360+
if (Arg0Type->isRealFloatingType()) {
2361+
assert(Arg1Type->isRealFloatingType());
2362+
APFloat RHS = S.Stk.pop<Floating>().getAPFloat();
2363+
APFloat LHS = S.Stk.pop<Floating>().getAPFloat();
2364+
Floating Result = S.allocFloat(RHS.getSemantics());
2365+
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
2366+
Result.copy(maxnum(LHS, RHS));
2367+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
2368+
Result.copy(minnum(LHS, RHS));
2369+
} else {
2370+
llvm_unreachable("Wrong builtin ID");
2371+
}
2372+
S.Stk.push<Floating>(Result);
23652373
return true;
23662374
}
23672375

23682376
// Vector case.
2369-
assert(Call->getArg(0)->getType()->isVectorType() &&
2370-
Call->getArg(1)->getType()->isVectorType());
2371-
const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
2372-
assert(VT->getElementType() ==
2373-
Call->getArg(1)->getType()->castAs<VectorType>()->getElementType());
2374-
assert(VT->getNumElements() ==
2375-
Call->getArg(1)->getType()->castAs<VectorType>()->getNumElements());
2376-
assert(VT->getElementType()->isIntegralOrEnumerationType());
2377+
assert(Arg0Type->isVectorType() && Arg1Type->isVectorType());
2378+
2379+
const auto *VT = Arg0Type->castAs<VectorType>();
2380+
QualType ElemType = VT->getElementType();
2381+
unsigned NumElems = VT->getNumElements();
2382+
2383+
assert(ElemType == Arg1Type->castAs<VectorType>()->getElementType());
2384+
assert(NumElems == Arg1Type->castAs<VectorType>()->getNumElements());
2385+
assert(ElemType->isIntegerType() || ElemType->isRealFloatingType());
23772386

23782387
const Pointer &RHS = S.Stk.pop<Pointer>();
23792388
const Pointer &LHS = S.Stk.pop<Pointer>();
23802389
const Pointer &Dst = S.Stk.peek<Pointer>();
2381-
PrimType ElemT = *S.getContext().classify(VT->getElementType());
2382-
unsigned NumElems = VT->getNumElements();
2390+
PrimType ElemT = *S.getContext().classify(ElemType);
23832391
for (unsigned I = 0; I != NumElems; ++I) {
2384-
APSInt Elem1;
2385-
APSInt Elem2;
2386-
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
2387-
Elem1 = LHS.elem<T>(I).toAPSInt();
2388-
Elem2 = RHS.elem<T>(I).toAPSInt();
2389-
});
2392+
if (ElemType->isIntegerType()) {
2393+
APSInt LHSInt;
2394+
APSInt RHSInt;
2395+
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
2396+
LHSInt = LHS.elem<T>(I).toAPSInt();
2397+
RHSInt = RHS.elem<T>(I).toAPSInt();
2398+
});
23902399

2391-
APSInt Result;
2392-
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
2393-
Result = APSInt(std::max(Elem1, Elem2),
2394-
Call->getType()->isUnsignedIntegerOrEnumerationType());
2395-
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
2396-
Result = APSInt(std::min(Elem1, Elem2),
2397-
Call->getType()->isUnsignedIntegerOrEnumerationType());
2400+
APSInt Result;
2401+
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
2402+
Result = std::max(LHSInt, RHSInt);
2403+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
2404+
Result = std::min(LHSInt, RHSInt);
2405+
} else {
2406+
llvm_unreachable("Wrong builtin ID");
2407+
}
2408+
2409+
INT_TYPE_SWITCH_NO_BOOL(ElemT,
2410+
{ Dst.elem<T>(I) = static_cast<T>(Result); });
23982411
} else {
2399-
llvm_unreachable("Wrong builtin ID");
2412+
APFloat RHSFloat = RHS.elem<Floating>(I).getAPFloat();
2413+
APFloat LHSFloat = LHS.elem<Floating>(I).getAPFloat();
2414+
Floating Result = S.allocFloat(RHSFloat.getSemantics());
2415+
if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
2416+
Result.copy(maxnum(LHSFloat, RHSFloat));
2417+
} else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
2418+
Result.copy(minnum(LHSFloat, RHSFloat));
2419+
} else {
2420+
llvm_unreachable("Wrong builtin ID");
2421+
}
2422+
Dst.elem<Floating>(I) = Result;
24002423
}
2401-
2402-
INT_TYPE_SWITCH_NO_BOOL(ElemT,
2403-
{ Dst.elem<T>(I) = static_cast<T>(Result); });
24042424
}
24052425
Dst.initializeAllElements();
24062426

clang/lib/AST/ExprConstant.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11697,28 +11697,42 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1169711697

1169811698
QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
1169911699

11700-
if (!DestEltTy->isIntegerType())
11701-
return false;
11702-
1170311700
unsigned SourceLen = SourceLHS.getVectorLength();
1170411701
SmallVector<APValue, 4> ResultElements;
1170511702
ResultElements.reserve(SourceLen);
1170611703

1170711704
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;
11705+
APValue LHS = SourceLHS.getVectorElt(EltNum);
11706+
APValue RHS = SourceRHS.getVectorElt(EltNum);
11707+
APValue ResultElt;
11708+
if (DestEltTy->isIntegerType()) {
11709+
APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
11710+
APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt();
11711+
switch (E->getBuiltinCallee()) {
11712+
case Builtin::BI__builtin_elementwise_max:
11713+
ResultElt =
11714+
APValue(APSInt(std::max(LHS, RHS),
11715+
DestEltTy->isUnsignedIntegerOrEnumerationType()));
11716+
break;
11717+
case Builtin::BI__builtin_elementwise_min:
11718+
ResultElt =
11719+
APValue(APSInt(std::min(LHS, RHS),
11720+
DestEltTy->isUnsignedIntegerOrEnumerationType()));
11721+
break;
11722+
}
11723+
} else if (DestEltTy->isRealFloatingType()) {
11724+
APFloat LHS = SourceLHS.getVectorElt(EltNum).getFloat();
11725+
APFloat RHS = SourceRHS.getVectorElt(EltNum).getFloat();
11726+
switch (E->getBuiltinCallee()) {
11727+
case Builtin::BI__builtin_elementwise_max:
11728+
ResultElt = APValue(maxnum(LHS, RHS));
11729+
break;
11730+
case Builtin::BI__builtin_elementwise_min:
11731+
ResultElt = APValue(minnum(LHS, RHS));
11732+
break;
11733+
}
1172111734
}
11735+
ResultElements.push_back(std::move(ResultElt));
1172211736
}
1172311737

1172411738
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
@@ -15917,7 +15931,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
1591715931
case Builtin::BI__builtin_fmaxf:
1591815932
case Builtin::BI__builtin_fmaxl:
1591915933
case Builtin::BI__builtin_fmaxf16:
15920-
case Builtin::BI__builtin_fmaxf128: {
15934+
case Builtin::BI__builtin_fmaxf128:
15935+
case Builtin::BI__builtin_elementwise_max: {
1592115936
APFloat RHS(0.);
1592215937
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
1592315938
!EvaluateFloat(E->getArg(1), RHS, Info))
@@ -15930,7 +15945,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
1593015945
case Builtin::BI__builtin_fminf:
1593115946
case Builtin::BI__builtin_fminl:
1593215947
case Builtin::BI__builtin_fminf16:
15933-
case Builtin::BI__builtin_fminf128: {
15948+
case Builtin::BI__builtin_fminf128:
15949+
case Builtin::BI__builtin_elementwise_min: {
1593415950
APFloat RHS(0.);
1593515951
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
1593615952
!EvaluateFloat(E->getArg(1), RHS, Info))

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,8 @@ static_assert(__builtin_elementwise_max(1, 2) == 2);
865865
static_assert(__builtin_elementwise_max(-1, 1) == 1);
866866
static_assert(__builtin_elementwise_max(1U, 2U) == 2U);
867867
static_assert(__builtin_elementwise_max(~0U, 0U) == ~0U);
868+
static_assert(__builtin_fabs(__builtin_elementwise_max(1.0f, 2.0f) - 2.0f) < 1e-6);
869+
static_assert(__builtin_fabs(__builtin_elementwise_max(-1.0f, 1.0f) - 1.0f) < 1e-6);
868870
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_max((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFF03FE04 : 0x04FE03FF ));
869871
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_max((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x04030304U);
870872
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));
@@ -873,6 +875,27 @@ static_assert(__builtin_elementwise_min(1, 2) == 1);
873875
static_assert(__builtin_elementwise_min(-1, 1) == -1);
874876
static_assert(__builtin_elementwise_min(1U, 2U) == 1U);
875877
static_assert(__builtin_elementwise_min(~0U, 0U) == 0U);
878+
static_assert(__builtin_fabs(__builtin_elementwise_min(1.0f, 2.0f) - 1.0f) < 1e-6);
879+
static_assert(__builtin_fabs(__builtin_elementwise_min(-1.0f, 1.0f) - (-1.0f)) < 1e-6);
876880
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFC02FD01 : 0x01FD02FC));
877881
static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x01020201U);
878882
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));
883+
884+
#define CHECK_VECTOR4_FLOAT_EQ(v1, v2) \
885+
static_assert(__builtin_fabs((v1)[0] - (v2)[0]) < 1e-6 && \
886+
__builtin_fabs((v1)[1] - (v2)[1]) < 1e-6 && \
887+
__builtin_fabs((v1)[2] - (v2)[2]) < 1e-6 && \
888+
__builtin_fabs((v1)[3] - (v2)[3]) < 1e-6);
889+
CHECK_VECTOR4_FLOAT_EQ(
890+
(__builtin_elementwise_max((vector4float){1.0f, -2.0f, 3.0f, -4.0f}, (vector4float){4.0f, -3.0f, 2.0f, -1.0f})),
891+
((vector4float){4.0f, -2.0f, 3.0f, -1.0f}))
892+
CHECK_VECTOR4_FLOAT_EQ(
893+
(__builtin_elementwise_max((vector4double){1.0f, -2.0f, 3.0f, -4.0f}, (vector4double){4.0f, -3.0f, 2.0f, -1.0f})),
894+
((vector4double){4.0f, -2.0f, 3.0f, -1.0f}))
895+
CHECK_VECTOR4_FLOAT_EQ(
896+
(__builtin_elementwise_min((vector4float){1.0f, -2.0f, 3.0f, -4.0f}, (vector4float){4.0f, -3.0f, 2.0f, -1.0f})),
897+
((vector4float){1.0f, -3.0f, 2.0f, -4.0f}))
898+
CHECK_VECTOR4_FLOAT_EQ(
899+
(__builtin_elementwise_max((vector4double){1.0f, -2.0f, 3.0f, -4.0f}, (vector4double){4.0f, -3.0f, 2.0f, -1.0f})),
900+
((vector4double){4.0f, -2.0f, 3.0f, -1.0f}))
901+
#undef CHECK_VECTOR4_FLOAT_EQ

0 commit comments

Comments
 (0)