diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -3489,6 +3489,68 @@ Floating point builtins --------------------------------------- +``__builtin_isfpclass`` +----------------------- + +``__builtin_isfpclass`` is used to test if the specified floating-point value +falls into one of the specified floating-point classes. + +**Syntax**: + +.. code-block:: c++ + + int __builtin_isfpclass(fp_type expr, int mask) + +``fp_type`` is a floating-point type supported by the target. ``mask`` is an +integer constant expression, where each bit represents floating-point class to +test. The function returns boolean value. + +**Example of use**: + +.. code-block:: c++ + + if (__builtin_isfpclass(x, 448)) { + // `x` is positive finite value + ... + } + +**Description**: + +The ``__builtin_isfpclass()`` builtin is a generalization of functions ``isnan``, +``isinf``, ``isfinite`` and some others defined by the C standard. It tests if +the floating-point value, specified by the first argument, falls into any of data +classes, specified by the second argument. The later is a bitmask, in which each +data class is represented by a bit using the encoding: + +========== =================== ====================== +Mask value Data class Macro +========== =================== ====================== +0x0001 Signaling NaN __FPCLASS_SNAN +0x0002 Quiet NaN __FPCLASS_QNAN +0x0004 Negative infinity __FPCLASS_NEGINF +0x0008 Negative normal __FPCLASS_NEGNORMAL +0x0010 Negative subnormal __FPCLASS_NEGSUBNORMAL +0x0020 Negative zero __FPCLASS_NEGZERO +0x0040 Positive zero __FPCLASS_POSZERO +0x0080 Positive subnormal __FPCLASS_POSSUBNORMAL +0x0100 Positive normal __FPCLASS_POSNORMAL +0x0200 Positive infinity __FPCLASS_POSINF + +For convenience preprocessor defines macros for these values. The function +returns 1 if ``expr`` falls into one of the specified data classes, 0 otherwise. + +In the example above the mask value 448 (0x1C0) contains the bits selecting +positive zero, positive subnormal and positive normal classes. +``__builtin_isfpclass(x, 448)`` would return true only if ``x`` if of any of +these data classes. Using suitable mask value, the function can implement any of +the standard classification functions, for example, ``__builtin_isfpclass(x, 3)`` +is identical to ``isnan``,``__builtin_isfpclass(x, 504)`` - to ``isfinite`` +and so on. + +This function never raises floating-point exceptions and does not canonicalize +its input. The floating-point argument is not promoted, its data class is +determined based on its representation in its actual semantic type. + ``__builtin_canonicalize`` -------------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -226,6 +226,8 @@ This fixes (`#58951 `_). - Clang now supports the `NO_COLOR `_ environment variable as a way to disable color diagnostics. +- Clang now supports ``__builtin_isfpclass``, which checks if the specified + floating-point value falls into any of the specified data classes. New Compiler Flags ------------------ diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -488,6 +488,7 @@ BUILTIN(__builtin_isinf_sign, "i.", "FnctE") BUILTIN(__builtin_isnan, "i.", "FnctE") BUILTIN(__builtin_isnormal, "i.", "FnctE") +BUILTIN(__builtin_isfpclass, "i.", "nctE") // FP signbit builtins BUILTIN(__builtin_signbit, "i.", "Fnct") diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12155,6 +12155,16 @@ Success(Val.isNormal() ? 1 : 0, E); } + case Builtin::BI__builtin_isfpclass: { + APSInt MaskVal; + if (!EvaluateInteger(E->getArg(1), MaskVal, Info)) + return false; + unsigned Test = static_cast(MaskVal.getZExtValue()); + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success((Val.classify() & Test) ? 1 : 0, E); + } + case Builtin::BI__builtin_parity: case Builtin::BI__builtin_parityl: case Builtin::BI__builtin_parityll: { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3131,6 +3131,17 @@ return RValue::get(V); } + case Builtin::BI__builtin_isfpclass: { + Expr::EvalResult Result; + if (!E->getArg(1)->EvaluateAsInt(Result, CGM.getContext())) + break; + uint64_t Test = Result.Val.getInt().getLimitedValue(); + CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E); + Value *V = EmitScalarExpr(E->getArg(0)); + return RValue::get(Builder.CreateZExt(Builder.createIsFPClass(V, Test), + ConvertType(E->getType()))); + } + case Builtin::BI__builtin_nondeterministic_value: { llvm::Type *Ty = ConvertType(E->getArg(0)->getType()); diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -795,6 +795,18 @@ Builder.defineMacro("__OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES", "3"); Builder.defineMacro("__OPENCL_MEMORY_SCOPE_SUB_GROUP", "4"); + // Define macros for floating-point data classes, used in __builtin_isfpclass. + Builder.defineMacro("__FPCLASS_SNAN", "0x0001"); + Builder.defineMacro("__FPCLASS_QNAN", "0x0002"); + Builder.defineMacro("__FPCLASS_NEGINF", "0x0004"); + Builder.defineMacro("__FPCLASS_NEGNORMAL", "0x0008"); + Builder.defineMacro("__FPCLASS_NEGSUBNORMAL", "0x0010"); + Builder.defineMacro("__FPCLASS_NEGZERO", "0x0020"); + Builder.defineMacro("__FPCLASS_POSZERO", "0x0040"); + Builder.defineMacro("__FPCLASS_POSSUBNORMAL", "0x0080"); + Builder.defineMacro("__FPCLASS_POSNORMAL", "0x0100"); + Builder.defineMacro("__FPCLASS_POSINF", "0x0200"); + // Support for #pragma redefine_extname (Sun compatibility) Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1"); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2170,6 +2170,10 @@ if (SemaBuiltinFPClassification(TheCall, 6)) return ExprError(); break; + case Builtin::BI__builtin_isfpclass: + if (SemaBuiltinFPClassification(TheCall, 2)) + return ExprError(); + break; case Builtin::BI__builtin_isfinite: case Builtin::BI__builtin_isinf: case Builtin::BI__builtin_isinf_sign: @@ -7688,9 +7692,12 @@ if (checkArgCount(*this, TheCall, NumArgs)) return true; - // __builtin_fpclassify is the only case where NumArgs != 1, so we can count - // on all preceding parameters just being int. Try all of those. - for (unsigned i = 0; i < NumArgs - 1; ++i) { + // Find out position of floating-point argument. + unsigned FPArgNo = (NumArgs == 2) ? 0 : NumArgs - 1; + + // We can count on all parameters preceding the floating-point just being int. + // Try all of those. + for (unsigned i = 0; i < FPArgNo; ++i) { Expr *Arg = TheCall->getArg(i); if (Arg->isTypeDependent()) @@ -7703,7 +7710,7 @@ TheCall->setArg(i, Res.get()); } - Expr *OrigArg = TheCall->getArg(NumArgs-1); + Expr *OrigArg = TheCall->getArg(FPArgNo); if (OrigArg->isTypeDependent()) return false; @@ -7715,7 +7722,7 @@ OrigArg = UsualUnaryConversions(OrigArg).get(); else OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get(); - TheCall->setArg(NumArgs - 1, OrigArg); + TheCall->setArg(FPArgNo, OrigArg); // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) @@ -7723,6 +7730,12 @@ diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); + // __builtin_isfpclass has integer parameter that specify test mask. It is + // passed in (...), so it should be analyzed completely here. + if (NumArgs == 2) + if (SemaBuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) + return true; + return false; } diff --git a/clang/test/CodeGen/builtins.c b/clang/test/CodeGen/builtins.c --- a/clang/test/CodeGen/builtins.c +++ b/clang/test/CodeGen/builtins.c @@ -63,6 +63,7 @@ P(isinf, (1.)); P(isinf_sign, (1.)); P(isnan, (1.)); + P(isfpclass, (1., 1)); // Bitwise & Numeric Functions diff --git a/clang/test/CodeGen/isfpclass.c b/clang/test/CodeGen/isfpclass.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/isfpclass.c @@ -0,0 +1,86 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 2 +// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +avx512fp16 -S -O1 -emit-llvm %s -o - | FileCheck %s + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_finite +// CHECK-SAME: (float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.is.fpclass.f32(float [[X]], i32 504) +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_finite(float x) { + return __builtin_isfpclass(x, 504 /*Finite*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_finite_strict +// CHECK-SAME: (float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.is.fpclass.f32(float [[X]], i32 504) #[[ATTR4:[0-9]+]] +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_finite_strict(float x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(x, 504 /*Finite*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_nan_f32 +// CHECK-SAME: (float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = fcmp uno float [[X]], 0.000000e+00 +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_nan_f32(float x) { + return __builtin_isfpclass(x, 3 /*NaN*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_nan_f32_strict +// CHECK-SAME: (float noundef [[X:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.is.fpclass.f32(float [[X]], i32 3) #[[ATTR4]] +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_nan_f32_strict(float x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(x, 3 /*NaN*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_snan_f64 +// CHECK-SAME: (double noundef [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.is.fpclass.f64(double [[X]], i32 1) +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_snan_f64(double x) { + return __builtin_isfpclass(x, 1 /*SNaN*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_snan_f64_strict +// CHECK-SAME: (double noundef [[X:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.is.fpclass.f64(double [[X]], i32 1) #[[ATTR4]] +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_snan_f64_strict(double x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(x, 1 /*NaN*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_zero_f16 +// CHECK-SAME: (half noundef [[X:%.*]]) local_unnamed_addr #[[ATTR3]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = fcmp oeq half [[X]], 0xH0000 +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_zero_f16(_Float16 x) { + return __builtin_isfpclass(x, 96 /*Zero*/); +} + +// CHECK-LABEL: define dso_local i1 @check_isfpclass_zero_f16_strict +// CHECK-SAME: (half noundef [[X:%.*]]) local_unnamed_addr #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.is.fpclass.f16(half [[X]], i32 96) #[[ATTR4]] +// CHECK-NEXT: ret i1 [[TMP0]] +// +_Bool check_isfpclass_zero_f16_strict(_Float16 x) { +#pragma STDC FENV_ACCESS ON + return __builtin_isfpclass(x, 96 /*Zero*/); +} diff --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c --- a/clang/test/Preprocessor/init-aarch64.c +++ b/clang/test/Preprocessor/init-aarch64.c @@ -104,6 +104,16 @@ // AARCH64-NEXT: #define __FLT_MIN_EXP__ (-125) // AARCH64-NEXT: #define __FLT_MIN__ 1.17549435e-38F // AARCH64-NEXT: #define __FLT_RADIX__ 2 +// AARCH64-NEXT: #define __FPCLASS_NEGINF 0x0004 +// AARCH64-NEXT: #define __FPCLASS_NEGNORMAL 0x0008 +// AARCH64-NEXT: #define __FPCLASS_NEGSUBNORMAL 0x0010 +// AARCH64-NEXT: #define __FPCLASS_NEGZERO 0x0020 +// AARCH64-NEXT: #define __FPCLASS_POSINF 0x0200 +// AARCH64-NEXT: #define __FPCLASS_POSNORMAL 0x0100 +// AARCH64-NEXT: #define __FPCLASS_POSSUBNORMAL 0x0080 +// AARCH64-NEXT: #define __FPCLASS_POSZERO 0x0040 +// AARCH64-NEXT: #define __FPCLASS_QNAN 0x0002 +// AARCH64-NEXT: #define __FPCLASS_SNAN 0x0001 // AARCH64-NEXT: #define __FP_FAST_FMA 1 // AARCH64-NEXT: #define __FP_FAST_FMAF 1 // AARCH64-NEXT: #define __GCC_ASM_FLAG_OUTPUTS__ 1 diff --git a/clang/test/Preprocessor/init.c b/clang/test/Preprocessor/init.c --- a/clang/test/Preprocessor/init.c +++ b/clang/test/Preprocessor/init.c @@ -1605,6 +1605,16 @@ // WEBASSEMBLY-NEXT:#define __FLT_MIN_EXP__ (-125) // WEBASSEMBLY-NEXT:#define __FLT_MIN__ 1.17549435e-38F // WEBASSEMBLY-NEXT:#define __FLT_RADIX__ 2 +// WEBASSEMBLY-NEXT:#define __FPCLASS_NEGINF 0x0004 +// WEBASSEMBLY-NEXT:#define __FPCLASS_NEGNORMAL 0x0008 +// WEBASSEMBLY-NEXT:#define __FPCLASS_NEGSUBNORMAL 0x0010 +// WEBASSEMBLY-NEXT:#define __FPCLASS_NEGZERO 0x0020 +// WEBASSEMBLY-NEXT:#define __FPCLASS_POSINF 0x0200 +// WEBASSEMBLY-NEXT:#define __FPCLASS_POSNORMAL 0x0100 +// WEBASSEMBLY-NEXT:#define __FPCLASS_POSSUBNORMAL 0x0080 +// WEBASSEMBLY-NEXT:#define __FPCLASS_POSZERO 0x0040 +// WEBASSEMBLY-NEXT:#define __FPCLASS_QNAN 0x0002 +// WEBASSEMBLY-NEXT:#define __FPCLASS_SNAN 0x0001 // WEBASSEMBLY-NEXT:#define __GCC_ATOMIC_BOOL_LOCK_FREE 2 // WEBASSEMBLY-NEXT:#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2 // WEBASSEMBLY-NEXT:#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2 diff --git a/clang/test/Sema/builtins.c b/clang/test/Sema/builtins.c --- a/clang/test/Sema/builtins.c +++ b/clang/test/Sema/builtins.c @@ -378,3 +378,14 @@ } _Complex double builtin_complex_static_init = __builtin_complex(1.0, 2.0); + +int test_is_fpclass(float x, int mask) { + int x1 = __builtin_isfpclass(x, 1024); // expected-error {{argument value 1024 is outside the valid range [0, 1023]}} + int x2 = __builtin_isfpclass(3, 3); // expected-error{{floating point classification requires argument of floating point type (passed in 'int')}} + int x3 = __builtin_isfpclass(x, 3, x); // expected-error{{too many arguments to function call, expected 2, have 3}} + int x4 = __builtin_isfpclass(x); // expected-error{{too few arguments to function call, expected 2, have 1}} + int x5 = __builtin_isfpclass(x, mask); // expected-error{{argument to '__builtin_isfpclass' must be a constant integer}} + int x6 = __builtin_isfpclass(x, -1); // expected-error{{argument value -1 is outside the valid range [0, 1023]}} + float _Complex c = x; + int x7 = __builtin_isfpclass(c, 3); // expected-error{{floating point classification requires argument of floating point type (passed in '_Complex float')}} +} diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -124,6 +124,47 @@ char isnormal_nan [!__builtin_isnormal(__builtin_nan("")) ? 1 : -1]; char isnormal_snan [!__builtin_isnormal(__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 +char isfpclass_inf_pos_3[!__builtin_isfpclass(__builtin_inf(), 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_pos_0 [__builtin_isfpclass(1.0, 0x0100) ? 1 : -1]; // fcPosNormal +char isfpclass_pos_1 [!__builtin_isfpclass(1.0f, 0x0008) ? 1 : -1]; // fcNegNormal +char isfpclass_pos_2 [__builtin_isfpclass(1.0L, 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_pos_3 [!__builtin_isfpclass(1.0, 0x0003) ? 1 : -1]; // fcSNan|fcQNan +char isfpclass_pdenorm_0[__builtin_isfpclass(1.0e-40f, 0x0080) ? 1 : -1]; // fcPosSubnormal +char isfpclass_pdenorm_1[__builtin_isfpclass(1.0e-310, 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_pdenorm_2[!__builtin_isfpclass(1.0e-40f, 0x003C) ? 1 : -1]; // fcNegative +char isfpclass_pdenorm_3[!__builtin_isfpclass(1.0e-310, 0x0207) ? 1 : -1]; // ~fcFinite +char isfpclass_pzero_0 [__builtin_isfpclass(0.0f, 0x0060) ? 1 : -1]; // fcZero +char isfpclass_pzero_1 [__builtin_isfpclass(0.0, 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_pzero_2 [!__builtin_isfpclass(0.0L, 0x0020) ? 1 : -1]; // fcNegZero +char isfpclass_pzero_3 [!__builtin_isfpclass(0.0, 0x0003) ? 1 : -1]; // fcNan +char isfpclass_nzero_0 [__builtin_isfpclass(-0.0f, 0x0060) ? 1 : -1]; // fcZero +char isfpclass_nzero_1 [__builtin_isfpclass(-0.0, 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_nzero_2 [!__builtin_isfpclass(-0.0L, 0x0040) ? 1 : -1]; // fcPosZero +char isfpclass_nzero_3 [!__builtin_isfpclass(-0.0, 0x0003) ? 1 : -1]; // fcNan +char isfpclass_ndenorm_0[__builtin_isfpclass(-1.0e-40f, 0x0010) ? 1 : -1]; // fcNegSubnormal +char isfpclass_ndenorm_1[__builtin_isfpclass(-1.0e-310, 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_ndenorm_2[!__builtin_isfpclass(-1.0e-40f, 0x03C0) ? 1 : -1]; // fcPositive +char isfpclass_ndenorm_3[!__builtin_isfpclass(-1.0e-310, 0x0207) ? 1 : -1]; // ~fcFinite +char isfpclass_neg_0 [__builtin_isfpclass(-1.0, 0x0008) ? 1 : -1]; // fcNegNormal +char isfpclass_neg_1 [!__builtin_isfpclass(-1.0f, 0x00100) ? 1 : -1]; // fcPosNormal +char isfpclass_neg_2 [__builtin_isfpclass(-1.0L, 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_neg_3 [!__builtin_isfpclass(-1.0, 0x0003) ? 1 : -1]; // fcSNan|fcQNan +char isfpclass_inf_neg_0[__builtin_isfpclass(-__builtin_inf(), 0x0004) ? 1 : -1]; // fcNegInf +char isfpclass_inf_neg_1[!__builtin_isfpclass(-__builtin_inff(), 0x0200) ? 1 : -1]; // fcPosInf +char isfpclass_inf_neg_2[__builtin_isfpclass(-__builtin_infl(), 0x0207) ? 1 : -1]; // ~fcFinite +char isfpclass_inf_neg_3[!__builtin_isfpclass(-__builtin_inf(), 0x03C0) ? 1 : -1]; // fcPositive +char isfpclass_qnan_0 [__builtin_isfpclass(__builtin_nan(""), 0x0002) ? 1 : -1]; // fcQNan +char isfpclass_qnan_1 [!__builtin_isfpclass(__builtin_nanf(""), 0x0001) ? 1 : -1]; // fcSNan +char isfpclass_qnan_2 [__builtin_isfpclass(__builtin_nanl(""), 0x0207) ? 1 : -1]; // ~fcFinite +char isfpclass_qnan_3 [!__builtin_isfpclass(__builtin_nan(""), 0x01F8) ? 1 : -1]; // fcFinite +char isfpclass_snan_0 [__builtin_isfpclass(__builtin_nansf(""), 0x0001) ? 1 : -1]; // fcSNan +char isfpclass_snan_1 [!__builtin_isfpclass(__builtin_nans(""), 0x0002) ? 1 : -1]; // fcQNan +char isfpclass_snan_2 [__builtin_isfpclass(__builtin_nansl(""), 0x0207) ? 1 : -1]; // ~fcFinite +char isfpclass_snan_3 [!__builtin_isfpclass(__builtin_nans(""), 0x01F8) ? 1 : -1]; // fcFinite + //double g19 = __builtin_powi(2.0, 4); //float g20 = __builtin_powif(2.0f, 4); //long double g21 = __builtin_powil(2.0L, 4); diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -2528,6 +2528,8 @@ unsigned Index, unsigned FieldIndex, MDNode *DbgInfo); + Value *createIsFPClass(Value *FPNum, unsigned Test); + private: /// Helper function that creates an assume intrinsic call that /// represents an alignment assumption on the provided pointer \p PtrValue diff --git a/llvm/lib/IR/IRBuilder.cpp b/llvm/lib/IR/IRBuilder.cpp --- a/llvm/lib/IR/IRBuilder.cpp +++ b/llvm/lib/IR/IRBuilder.cpp @@ -1383,6 +1383,14 @@ return Fn; } +Value *IRBuilderBase::createIsFPClass(Value *FPNum, unsigned Test) { + ConstantInt *TestV = getInt32(Test); + Module *M = BB->getParent()->getParent(); + Function *FnIsFPClass = + Intrinsic::getDeclaration(M, Intrinsic::is_fpclass, {FPNum->getType()}); + return CreateCall(FnIsFPClass, {FPNum, TestV}); +} + CallInst *IRBuilderBase::CreateAlignmentAssumptionHelper(const DataLayout &DL, Value *PtrValue, Value *AlignValue,