Skip to content

[clang] Additional FP classification functions #69041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 1, 2023
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
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,8 @@ Floating Point Support in Clang
- Add ``__builtin_exp10``, ``__builtin_exp10f``,
``__builtin_exp10f16``, ``__builtin_exp10l`` and
``__builtin_exp10f128`` builtins.
- Add ``__builtin_iszero``, ``__builtin_issignaling`` and
``__builtin_issubnormal``.

AST Matchers
------------
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ BUILTIN(__builtin_isinf, "i.", "FnctE")
BUILTIN(__builtin_isinf_sign, "i.", "FnctE")
BUILTIN(__builtin_isnan, "i.", "FnctE")
BUILTIN(__builtin_isnormal, "i.", "FnctE")
BUILTIN(__builtin_issubnormal,"i.", "FnctE")
BUILTIN(__builtin_iszero, "i.", "FnctE")
BUILTIN(__builtin_issignaling,"i.", "FnctE")
BUILTIN(__builtin_isfpclass, "i.", "nctE")

// FP signbit builtins
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12303,6 +12303,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
Success(Val.isNormal() ? 1 : 0, E);
}

case Builtin::BI__builtin_issubnormal: {
APFloat Val(0.0);
return EvaluateFloat(E->getArg(0), Val, Info) &&
Success(Val.isDenormal() ? 1 : 0, E);
}

case Builtin::BI__builtin_iszero: {
APFloat Val(0.0);
return EvaluateFloat(E->getArg(0), Val, Info) &&
Success(Val.isZero() ? 1 : 0, E);
}

case Builtin::BI__builtin_issignaling: {
APFloat Val(0.0);
return EvaluateFloat(E->getArg(0), Val, Info) &&
Success(Val.isSignaling() ? 1 : 0, E);
}

case Builtin::BI__builtin_isfpclass: {
APSInt MaskVal;
if (!EvaluateInteger(E->getArg(1), MaskVal, Info))
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class Floating final {
bool isMin() const { return F.isSmallest(); }
bool isMinusOne() const { return F.isExactlyValue(-1.0); }
bool isNan() const { return F.isNaN(); }
bool isSignaling() const { return F.isSignaling(); }
bool isInf() const { return F.isInfinity(); }
bool isFinite() const { return F.isFinite(); }
bool isNormal() const { return F.isNormal(); }
Expand Down
39 changes: 39 additions & 0 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,15 @@ static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *F) {
const Floating &Arg = S.Stk.peek<Floating>();

pushInt(S, Arg.isSignaling());
return true;
}

static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *F,
bool CheckSign) {
Expand Down Expand Up @@ -334,6 +343,24 @@ static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *F) {
const Floating &Arg = S.Stk.peek<Floating>();

pushInt(S, Arg.isDenormal());
return true;
}

static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *F) {
const Floating &Arg = S.Stk.peek<Floating>();

pushInt(S, Arg.isZero());
return true;
}

/// First parameter to __builtin_isfpclass is the floating value, the
/// second one is an integral value.
static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
Expand Down Expand Up @@ -488,6 +515,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
if (interp__builtin_isnan(S, OpPC, Frame, F))
return retInt(S, OpPC, Dummy);
break;
case Builtin::BI__builtin_issignaling:
if (interp__builtin_issignaling(S, OpPC, Frame, F))
return retInt(S, OpPC, Dummy);
break;

case Builtin::BI__builtin_isinf:
if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
Expand All @@ -507,6 +538,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
if (interp__builtin_isnormal(S, OpPC, Frame, F))
return retInt(S, OpPC, Dummy);
break;
case Builtin::BI__builtin_issubnormal:
if (interp__builtin_issubnormal(S, OpPC, Frame, F))
return retInt(S, OpPC, Dummy);
break;
case Builtin::BI__builtin_iszero:
if (interp__builtin_iszero(S, OpPC, Frame, F))
return retInt(S, OpPC, Dummy);
break;
case Builtin::BI__builtin_isfpclass:
if (interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
return retInt(S, OpPC, Dummy);
Expand Down
24 changes: 24 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3287,6 +3287,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
ConvertType(E->getType())));
}

case Builtin::BI__builtin_issignaling: {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
Value *V = EmitScalarExpr(E->getArg(0));
return RValue::get(
Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcSNan),
ConvertType(E->getType())));
}

case Builtin::BI__builtin_isinf: {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
Value *V = EmitScalarExpr(E->getArg(0));
Expand Down Expand Up @@ -3321,6 +3329,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
ConvertType(E->getType())));
}

case Builtin::BI__builtin_issubnormal: {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
Value *V = EmitScalarExpr(E->getArg(0));
return RValue::get(
Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcSubnormal),
ConvertType(E->getType())));
}

case Builtin::BI__builtin_iszero: {
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
Value *V = EmitScalarExpr(E->getArg(0));
return RValue::get(
Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcZero),
ConvertType(E->getType())));
}

case Builtin::BI__builtin_isfpclass: {
Expr::EvalResult Result;
if (!E->getArg(1)->EvaluateAsInt(Result, CGM.getContext()))
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2227,7 +2227,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_isinf:
case Builtin::BI__builtin_isinf_sign:
case Builtin::BI__builtin_isnan:
case Builtin::BI__builtin_issignaling:
case Builtin::BI__builtin_isnormal:
case Builtin::BI__builtin_issubnormal:
case Builtin::BI__builtin_iszero:
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
case Builtin::BI__builtin_signbitl:
Expand Down
13 changes: 13 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ namespace nan {
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{read of dereferenced one-past-the-end pointer}} \
// expected-note {{in call to}}
static_assert(!__builtin_issignaling(__builtin_nan("")), "");
static_assert(__builtin_issignaling(__builtin_nans("")), "");
}

namespace fmin {
Expand All @@ -153,6 +155,17 @@ namespace inf {

static_assert(__builtin_isnormal(1.0), "");
static_assert(!__builtin_isnormal(__builtin_inf()), "");

#ifndef __AVR__
static_assert(__builtin_issubnormal(0x1p-1070), "");
#endif
static_assert(!__builtin_issubnormal(__builtin_inf()), "");

static_assert(__builtin_iszero(0.0), "");
static_assert(!__builtin_iszero(__builtin_inf()), "");

static_assert(__builtin_issignaling(__builtin_nans("")), "");
static_assert(!__builtin_issignaling(__builtin_inf()), "");
}

namespace isfpclass {
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CodeGen/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ int main(void) {
P(isinf_sign, (1.));
P(isnan, (1.));
P(isfinite, (1.));
P(iszero, (1.));
P(issubnormal, (1.));
P(issignaling, (1.));
P(isfpclass, (1., 1));

// Bitwise & Numeric Functions
Expand Down Expand Up @@ -270,6 +273,18 @@ void test_float_builtins(__fp16 *H, float F, double D, long double LD) {
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 264)
// CHECK: zext i1 [[TMP]] to i32

res = __builtin_issubnormal(F);
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
// CHECK: zext i1 [[TMP]] to i32

res = __builtin_iszero(F);
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
// CHECK: zext i1 [[TMP]] to i32

res = __builtin_issignaling(F);
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1)
// CHECK: zext i1 [[TMP]] to i32

res = __builtin_flt_rounds();
// CHECK: call i32 @llvm.get.rounding(
}
Expand Down
39 changes: 39 additions & 0 deletions clang/test/Sema/constant-builtins-2.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,45 @@ char isnormal_inf_neg[!__builtin_isnormal(-__builtin_inf()) ? 1 : -1];
char isnormal_nan [!__builtin_isnormal(__builtin_nan("")) ? 1 : -1];
char isnormal_snan [!__builtin_isnormal(__builtin_nans("")) ? 1 : -1];

char iszero_inf_pos[!__builtin_iszero(__builtin_inf()) ? 1 : -1];
char iszero_pos [!__builtin_iszero(1.0) ? 1 : -1];
char iszero_normf [!__builtin_iszero(1e-37f) ? 1 : -1];
char iszero_denormf[!__builtin_iszero(1e-38f) ? 1 : -1];
char iszero_norm [!__builtin_iszero(1e-307) ? 1 : -1];
char iszero_denorm [!__builtin_iszero(1e-308) ? 1 : -1];
char iszero_zero [__builtin_iszero(0.0) ? 1 : -1];
char iszero_negzero[__builtin_iszero(-0.0) ? 1 : -1];
char iszero_neg [!__builtin_iszero(-1.0) ? 1 : -1];
char iszero_inf_neg[!__builtin_iszero(-__builtin_inf()) ? 1 : -1];
char iszero_nan [!__builtin_iszero(__builtin_nan("")) ? 1 : -1];
char iszero_snan [!__builtin_iszero(__builtin_nans("")) ? 1 : -1];

char issubnormal_inf_pos[!__builtin_issubnormal(__builtin_inf()) ? 1 : -1];
char issubnormal_pos [!__builtin_issubnormal(1.0) ? 1 : -1];
char issubnormal_normf [!__builtin_issubnormal(1e-37f) ? 1 : -1];
char issubnormal_denormf[__builtin_issubnormal(1e-38f) ? 1 : -1];
char issubnormal_norm [!__builtin_issubnormal(1e-307) ? 1 : -1];
char issubnormal_denorm [__builtin_issubnormal(1e-308) ? 1 : -1];
char issubnormal_zero [!__builtin_issubnormal(0.0) ? 1 : -1];
char issubnormal_negzero[!__builtin_issubnormal(-0.0) ? 1 : -1];
char issubnormal_neg [!__builtin_issubnormal(-1.0) ? 1 : -1];
char issubnormal_inf_neg[!__builtin_issubnormal(-__builtin_inf()) ? 1 : -1];
char issubnormal_nan [!__builtin_issubnormal(__builtin_nan("")) ? 1 : -1];
char issubnormal_snan [!__builtin_issubnormal(__builtin_nans("")) ? 1 : -1];

char issignaling_inf_pos[!__builtin_issignaling(__builtin_inf()) ? 1 : -1];
char issignaling_pos [!__builtin_issignaling(1.0) ? 1 : -1];
char issignaling_normf [!__builtin_issignaling(1e-37f) ? 1 : -1];
char issignaling_denormf[!__builtin_issignaling(1e-38f) ? 1 : -1];
char issignaling_norm [!__builtin_issignaling(1e-307) ? 1 : -1];
char issignaling_denorm [!__builtin_issignaling(1e-308) ? 1 : -1];
char issignaling_zero [!__builtin_issignaling(0.0) ? 1 : -1];
char issignaling_negzero[!__builtin_issignaling(-0.0) ? 1 : -1];
char issignaling_neg [!__builtin_issignaling(-1.0) ? 1 : -1];
char issignaling_inf_neg[!__builtin_issignaling(-__builtin_inf()) ? 1 : -1];
char issignaling_nan [!__builtin_issignaling(__builtin_nan("")) ? 1 : -1];
char issignaling_snan [__builtin_issignaling(__builtin_nans("")) ? 1 : -1];

char isfpclass_inf_pos_0[__builtin_isfpclass(__builtin_inf(), 0x0200) ? 1 : -1]; // fcPosInf
char isfpclass_inf_pos_1[!__builtin_isfpclass(__builtin_inff(), 0x0004) ? 1 : -1]; // fcNegInf
char isfpclass_inf_pos_2[__builtin_isfpclass(__builtin_infl(), 0x0207) ? 1 : -1]; // fcSNan|fcQNan|fcNegInf|fcPosInf
Expand Down