Skip to content

Commit fc7198b

Browse files
authored
[clang] Additional FP classification functions (#69041)
C language standard defined library functions `iszero`, `issignaling` and `issubnormal`, which did not have counterparts among clang builtin functions. This change adds new functions: __builtin_iszero __builtin_issubnormal __builtin_issignaling They provide builtin implementation for the missing standard functions. Pull request: #69041
1 parent 954af75 commit fc7198b

File tree

10 files changed

+157
-0
lines changed

10 files changed

+157
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,8 @@ Floating Point Support in Clang
809809
- Add ``__builtin_exp10``, ``__builtin_exp10f``,
810810
``__builtin_exp10f16``, ``__builtin_exp10l`` and
811811
``__builtin_exp10f128`` builtins.
812+
- Add ``__builtin_iszero``, ``__builtin_issignaling`` and
813+
``__builtin_issubnormal``.
812814

813815
AST Matchers
814816
------------

clang/include/clang/Basic/Builtins.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,9 @@ BUILTIN(__builtin_isinf, "i.", "FnctE")
494494
BUILTIN(__builtin_isinf_sign, "i.", "FnctE")
495495
BUILTIN(__builtin_isnan, "i.", "FnctE")
496496
BUILTIN(__builtin_isnormal, "i.", "FnctE")
497+
BUILTIN(__builtin_issubnormal,"i.", "FnctE")
498+
BUILTIN(__builtin_iszero, "i.", "FnctE")
499+
BUILTIN(__builtin_issignaling,"i.", "FnctE")
497500
BUILTIN(__builtin_isfpclass, "i.", "nctE")
498501

499502
// FP signbit builtins

clang/lib/AST/ExprConstant.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12398,6 +12398,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1239812398
Success(Val.isNormal() ? 1 : 0, E);
1239912399
}
1240012400

12401+
case Builtin::BI__builtin_issubnormal: {
12402+
APFloat Val(0.0);
12403+
return EvaluateFloat(E->getArg(0), Val, Info) &&
12404+
Success(Val.isDenormal() ? 1 : 0, E);
12405+
}
12406+
12407+
case Builtin::BI__builtin_iszero: {
12408+
APFloat Val(0.0);
12409+
return EvaluateFloat(E->getArg(0), Val, Info) &&
12410+
Success(Val.isZero() ? 1 : 0, E);
12411+
}
12412+
12413+
case Builtin::BI__builtin_issignaling: {
12414+
APFloat Val(0.0);
12415+
return EvaluateFloat(E->getArg(0), Val, Info) &&
12416+
Success(Val.isSignaling() ? 1 : 0, E);
12417+
}
12418+
1240112419
case Builtin::BI__builtin_isfpclass: {
1240212420
APSInt MaskVal;
1240312421
if (!EvaluateInteger(E->getArg(1), MaskVal, Info))

clang/lib/AST/Interp/Floating.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class Floating final {
9393
bool isMin() const { return F.isSmallest(); }
9494
bool isMinusOne() const { return F.isExactlyValue(-1.0); }
9595
bool isNan() const { return F.isNaN(); }
96+
bool isSignaling() const { return F.isSignaling(); }
9697
bool isInf() const { return F.isInfinity(); }
9798
bool isFinite() const { return F.isFinite(); }
9899
bool isNormal() const { return F.isNormal(); }

clang/lib/AST/Interp/InterpBuiltin.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,15 @@ static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC,
306306
return true;
307307
}
308308

309+
static bool interp__builtin_issignaling(InterpState &S, CodePtr OpPC,
310+
const InterpFrame *Frame,
311+
const Function *F) {
312+
const Floating &Arg = S.Stk.peek<Floating>();
313+
314+
pushInt(S, Arg.isSignaling());
315+
return true;
316+
}
317+
309318
static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC,
310319
const InterpFrame *Frame, const Function *F,
311320
bool CheckSign) {
@@ -337,6 +346,24 @@ static bool interp__builtin_isnormal(InterpState &S, CodePtr OpPC,
337346
return true;
338347
}
339348

349+
static bool interp__builtin_issubnormal(InterpState &S, CodePtr OpPC,
350+
const InterpFrame *Frame,
351+
const Function *F) {
352+
const Floating &Arg = S.Stk.peek<Floating>();
353+
354+
pushInt(S, Arg.isDenormal());
355+
return true;
356+
}
357+
358+
static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC,
359+
const InterpFrame *Frame,
360+
const Function *F) {
361+
const Floating &Arg = S.Stk.peek<Floating>();
362+
363+
pushInt(S, Arg.isZero());
364+
return true;
365+
}
366+
340367
/// First parameter to __builtin_isfpclass is the floating value, the
341368
/// second one is an integral value.
342369
static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC,
@@ -491,6 +518,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
491518
if (interp__builtin_isnan(S, OpPC, Frame, F))
492519
return retInt(S, OpPC, Dummy);
493520
break;
521+
case Builtin::BI__builtin_issignaling:
522+
if (interp__builtin_issignaling(S, OpPC, Frame, F))
523+
return retInt(S, OpPC, Dummy);
524+
break;
494525

495526
case Builtin::BI__builtin_isinf:
496527
if (interp__builtin_isinf(S, OpPC, Frame, F, /*Sign=*/false))
@@ -510,6 +541,14 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
510541
if (interp__builtin_isnormal(S, OpPC, Frame, F))
511542
return retInt(S, OpPC, Dummy);
512543
break;
544+
case Builtin::BI__builtin_issubnormal:
545+
if (interp__builtin_issubnormal(S, OpPC, Frame, F))
546+
return retInt(S, OpPC, Dummy);
547+
break;
548+
case Builtin::BI__builtin_iszero:
549+
if (interp__builtin_iszero(S, OpPC, Frame, F))
550+
return retInt(S, OpPC, Dummy);
551+
break;
513552
case Builtin::BI__builtin_isfpclass:
514553
if (interp__builtin_isfpclass(S, OpPC, Frame, F, Call))
515554
return retInt(S, OpPC, Dummy);

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,6 +3356,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
33563356
ConvertType(E->getType())));
33573357
}
33583358

3359+
case Builtin::BI__builtin_issignaling: {
3360+
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
3361+
Value *V = EmitScalarExpr(E->getArg(0));
3362+
return RValue::get(
3363+
Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcSNan),
3364+
ConvertType(E->getType())));
3365+
}
3366+
33593367
case Builtin::BI__builtin_isinf: {
33603368
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
33613369
Value *V = EmitScalarExpr(E->getArg(0));
@@ -3390,6 +3398,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
33903398
ConvertType(E->getType())));
33913399
}
33923400

3401+
case Builtin::BI__builtin_issubnormal: {
3402+
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
3403+
Value *V = EmitScalarExpr(E->getArg(0));
3404+
return RValue::get(
3405+
Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcSubnormal),
3406+
ConvertType(E->getType())));
3407+
}
3408+
3409+
case Builtin::BI__builtin_iszero: {
3410+
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
3411+
Value *V = EmitScalarExpr(E->getArg(0));
3412+
return RValue::get(
3413+
Builder.CreateZExt(Builder.createIsFPClass(V, FPClassTest::fcZero),
3414+
ConvertType(E->getType())));
3415+
}
3416+
33933417
case Builtin::BI__builtin_isfpclass: {
33943418
Expr::EvalResult Result;
33953419
if (!E->getArg(1)->EvaluateAsInt(Result, CGM.getContext()))

clang/lib/Sema/SemaChecking.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,7 +2255,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
22552255
case Builtin::BI__builtin_isinf:
22562256
case Builtin::BI__builtin_isinf_sign:
22572257
case Builtin::BI__builtin_isnan:
2258+
case Builtin::BI__builtin_issignaling:
22582259
case Builtin::BI__builtin_isnormal:
2260+
case Builtin::BI__builtin_issubnormal:
2261+
case Builtin::BI__builtin_iszero:
22592262
case Builtin::BI__builtin_signbit:
22602263
case Builtin::BI__builtin_signbitf:
22612264
case Builtin::BI__builtin_signbitl:

clang/test/AST/Interp/builtin-functions.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ namespace nan {
130130
// expected-error {{must be initialized by a constant expression}} \
131131
// expected-note {{read of dereferenced one-past-the-end pointer}} \
132132
// expected-note {{in call to}}
133+
static_assert(!__builtin_issignaling(__builtin_nan("")), "");
134+
static_assert(__builtin_issignaling(__builtin_nans("")), "");
133135
}
134136

135137
namespace fmin {
@@ -153,6 +155,17 @@ namespace inf {
153155

154156
static_assert(__builtin_isnormal(1.0), "");
155157
static_assert(!__builtin_isnormal(__builtin_inf()), "");
158+
159+
#ifndef __AVR__
160+
static_assert(__builtin_issubnormal(0x1p-1070), "");
161+
#endif
162+
static_assert(!__builtin_issubnormal(__builtin_inf()), "");
163+
164+
static_assert(__builtin_iszero(0.0), "");
165+
static_assert(!__builtin_iszero(__builtin_inf()), "");
166+
167+
static_assert(__builtin_issignaling(__builtin_nans("")), "");
168+
static_assert(!__builtin_issignaling(__builtin_inf()), "");
156169
}
157170

158171
namespace isfpclass {

clang/test/CodeGen/builtins.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ int main(void) {
6464
P(isinf_sign, (1.));
6565
P(isnan, (1.));
6666
P(isfinite, (1.));
67+
P(iszero, (1.));
68+
P(issubnormal, (1.));
69+
P(issignaling, (1.));
6770
P(isfpclass, (1., 1));
6871

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

276+
res = __builtin_issubnormal(F);
277+
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 144)
278+
// CHECK: zext i1 [[TMP]] to i32
279+
280+
res = __builtin_iszero(F);
281+
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 96)
282+
// CHECK: zext i1 [[TMP]] to i32
283+
284+
res = __builtin_issignaling(F);
285+
// CHECK: [[TMP:%.*]] = call i1 @llvm.is.fpclass.f32(float {{.*}}, i32 1)
286+
// CHECK: zext i1 [[TMP]] to i32
287+
273288
res = __builtin_flt_rounds();
274289
// CHECK: call i32 @llvm.get.rounding(
275290
}

clang/test/Sema/constant-builtins-2.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,45 @@ char isnormal_inf_neg[!__builtin_isnormal(-__builtin_inf()) ? 1 : -1];
124124
char isnormal_nan [!__builtin_isnormal(__builtin_nan("")) ? 1 : -1];
125125
char isnormal_snan [!__builtin_isnormal(__builtin_nans("")) ? 1 : -1];
126126

127+
char iszero_inf_pos[!__builtin_iszero(__builtin_inf()) ? 1 : -1];
128+
char iszero_pos [!__builtin_iszero(1.0) ? 1 : -1];
129+
char iszero_normf [!__builtin_iszero(1e-37f) ? 1 : -1];
130+
char iszero_denormf[!__builtin_iszero(1e-38f) ? 1 : -1];
131+
char iszero_norm [!__builtin_iszero(1e-307) ? 1 : -1];
132+
char iszero_denorm [!__builtin_iszero(1e-308) ? 1 : -1];
133+
char iszero_zero [__builtin_iszero(0.0) ? 1 : -1];
134+
char iszero_negzero[__builtin_iszero(-0.0) ? 1 : -1];
135+
char iszero_neg [!__builtin_iszero(-1.0) ? 1 : -1];
136+
char iszero_inf_neg[!__builtin_iszero(-__builtin_inf()) ? 1 : -1];
137+
char iszero_nan [!__builtin_iszero(__builtin_nan("")) ? 1 : -1];
138+
char iszero_snan [!__builtin_iszero(__builtin_nans("")) ? 1 : -1];
139+
140+
char issubnormal_inf_pos[!__builtin_issubnormal(__builtin_inf()) ? 1 : -1];
141+
char issubnormal_pos [!__builtin_issubnormal(1.0) ? 1 : -1];
142+
char issubnormal_normf [!__builtin_issubnormal(1e-37f) ? 1 : -1];
143+
char issubnormal_denormf[__builtin_issubnormal(1e-38f) ? 1 : -1];
144+
char issubnormal_norm [!__builtin_issubnormal(1e-307) ? 1 : -1];
145+
char issubnormal_denorm [__builtin_issubnormal(1e-308) ? 1 : -1];
146+
char issubnormal_zero [!__builtin_issubnormal(0.0) ? 1 : -1];
147+
char issubnormal_negzero[!__builtin_issubnormal(-0.0) ? 1 : -1];
148+
char issubnormal_neg [!__builtin_issubnormal(-1.0) ? 1 : -1];
149+
char issubnormal_inf_neg[!__builtin_issubnormal(-__builtin_inf()) ? 1 : -1];
150+
char issubnormal_nan [!__builtin_issubnormal(__builtin_nan("")) ? 1 : -1];
151+
char issubnormal_snan [!__builtin_issubnormal(__builtin_nans("")) ? 1 : -1];
152+
153+
char issignaling_inf_pos[!__builtin_issignaling(__builtin_inf()) ? 1 : -1];
154+
char issignaling_pos [!__builtin_issignaling(1.0) ? 1 : -1];
155+
char issignaling_normf [!__builtin_issignaling(1e-37f) ? 1 : -1];
156+
char issignaling_denormf[!__builtin_issignaling(1e-38f) ? 1 : -1];
157+
char issignaling_norm [!__builtin_issignaling(1e-307) ? 1 : -1];
158+
char issignaling_denorm [!__builtin_issignaling(1e-308) ? 1 : -1];
159+
char issignaling_zero [!__builtin_issignaling(0.0) ? 1 : -1];
160+
char issignaling_negzero[!__builtin_issignaling(-0.0) ? 1 : -1];
161+
char issignaling_neg [!__builtin_issignaling(-1.0) ? 1 : -1];
162+
char issignaling_inf_neg[!__builtin_issignaling(-__builtin_inf()) ? 1 : -1];
163+
char issignaling_nan [!__builtin_issignaling(__builtin_nan("")) ? 1 : -1];
164+
char issignaling_snan [__builtin_issignaling(__builtin_nans("")) ? 1 : -1];
165+
127166
char isfpclass_inf_pos_0[__builtin_isfpclass(__builtin_inf(), 0x0200) ? 1 : -1]; // fcPosInf
128167
char isfpclass_inf_pos_1[!__builtin_isfpclass(__builtin_inff(), 0x0004) ? 1 : -1]; // fcNegInf
129168
char isfpclass_inf_pos_2[__builtin_isfpclass(__builtin_infl(), 0x0207) ? 1 : -1]; // fcSNan|fcQNan|fcNegInf|fcPosInf

0 commit comments

Comments
 (0)