From: Uros Bizjak <ubizjak@gmail.com>
To: Jakub Jelinek <jakub@redhat.com>
Cc: Richard Biener <rguenther@suse.de>,
"Joseph S. Myers" <joseph@codesourcery.com>,
Jeff Law <jeffreyalaw@gmail.com>,
gcc-patches@gcc.gnu.org, FX <fxcoudert@gmail.com>
Subject: Re: [PATCH] Implement __builtin_issignaling
Date: Mon, 15 Aug 2022 22:52:44 +0200 [thread overview]
Message-ID: <CAFULd4ayJChMHa2AG1C=zK-D5EkRS=AQbim1nNBhJFe5BfmOdQ@mail.gmail.com> (raw)
In-Reply-To: <Yvob8gMilv36WN4T@tucnak>
On Mon, Aug 15, 2022 at 12:12 PM Jakub Jelinek via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> Hi!
>
> The following patch implements a new builtin, __builtin_issignaling,
> which can be used to implement the ISO/IEC TS 18661-1 issignaling
> macro.
>
> It is implemented as type-generic function, so there is just one
> builtin, not many with various suffixes.
> This patch doesn't address PR56831 nor PR58416, but I think compared to
> using glibc issignaling macro could make some cases better (as
> the builtin is expanded always inline and for SFmode/DFmode just
> reinterprets a memory or pseudo register as SImode/DImode, so could
> avoid some raising of exception + turning sNaN into qNaN before the
> builtin can analyze it).
>
> For floading point modes that do not have NaNs it will return 0,
> otherwise I've tried to implement this for all the other supported
> real formats.
> It handles both the MIPS/PA floats where a sNaN has the mantissa
> MSB set and the rest where a sNaN has it cleared, with the exception
> of format which are known never to be in the MIPS/PA form.
> The MIPS/PA floats are handled using a test like
> (x & mask) == mask,
> the other usually as
> ((x ^ bit) & mask) > val
> where bit, mask and val are some constants.
> IBM double double is done by doing DFmode test on the most significant
> half, and Intel/Motorola extended (12 or 16 bytes) and IEEE quad are
> handled by extracting 32-bit/16-bit words or 64-bit parts from the
> value and testing those.
> On x86, XFmode is handled by a special optab so that even pseudo numbers
> are considered signaling, like in glibc and like the i386 specific testcase
> tests.
>
> Bootstrapped/regtested on x86_64-linux, i686-linux, powerpc64le-linux and
> powerpc64-linux (the last tested with -m32/-m64), ok for trunk?
>
> 2022-08-15 Jakub Jelinek <jakub@redhat.com>
>
> gcc/
> * builtins.def (BUILT_IN_ISSIGNALING): New built-in.
> * builtins.cc (expand_builtin_issignaling): New function.
> (expand_builtin_signbit): Don't overwrite target.
> (expand_builtin): Handle BUILT_IN_ISSIGNALING.
> (fold_builtin_classify): Likewise.
> (fold_builtin_1): Likewise.
> * optabs.def (issignaling_optab): New.
> * fold-const-call.cc (fold_const_call_ss): Handle
> BUILT_IN_ISSIGNALING.
> * config/i386/i386.md (issignalingxf2): New expander.
> * doc/extend.texi (__builtin_issignaling): Document.
> * doc/md.texi (issignaling<mode>2): Likewise.
> gcc/c-family/
> * c-common.cc (check_builtin_function_arguments): Handle
> BUILT_IN_ISSIGNALING.
> gcc/c/
> * c-typeck.cc (convert_arguments): Handle BUILT_IN_ISSIGNALING.
> gcc/fortran/
> * f95-lang.cc (gfc_init_builtin_functions): Initialize
> BUILT_IN_ISSIGNALING.
> gcc/testsuite/
> * gcc.dg/torture/builtin-issignaling-1.c: New test.
> * gcc.dg/torture/builtin-issignaling-2.c: New test.
> * gcc.target/i386/builtin-issignaling-1.c: New test.
OK for x86 part.
Thanks,
Uros.
>
> --- gcc/builtins.def.jj 2022-01-11 23:11:21.548301986 +0100
> +++ gcc/builtins.def 2022-08-11 12:15:14.200908656 +0200
> @@ -908,6 +908,7 @@ DEF_GCC_BUILTIN (BUILT_IN_ISLESS,
> DEF_GCC_BUILTIN (BUILT_IN_ISLESSEQUAL, "islessequal", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
> DEF_GCC_BUILTIN (BUILT_IN_ISLESSGREATER, "islessgreater", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
> DEF_GCC_BUILTIN (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
> +DEF_GCC_BUILTIN (BUILT_IN_ISSIGNALING, "issignaling", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
> DEF_LIB_BUILTIN (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
> DEF_C99_BUILTIN (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
> DEF_GCC_BUILTIN (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LIST)
> --- gcc/builtins.cc.jj 2022-07-26 10:32:23.250277352 +0200
> +++ gcc/builtins.cc 2022-08-12 17:13:06.158423558 +0200
> @@ -123,6 +123,7 @@ static rtx expand_builtin_fegetround (tr
> static rtx expand_builtin_feclear_feraise_except (tree, rtx, machine_mode,
> optab);
> static rtx expand_builtin_cexpi (tree, rtx);
> +static rtx expand_builtin_issignaling (tree, rtx);
> static rtx expand_builtin_int_roundingfn (tree, rtx);
> static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
> static rtx expand_builtin_next_arg (void);
> @@ -2747,6 +2748,294 @@ build_call_nofold_loc (location_t loc, t
> return fn;
> }
>
> +/* Expand the __builtin_issignaling builtin. This needs to handle
> + all floating point formats that do support NaNs (for those that
> + don't it just sets target to 0). */
> +
> +static rtx
> +expand_builtin_issignaling (tree exp, rtx target)
> +{
> + if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
> + return NULL_RTX;
> +
> + tree arg = CALL_EXPR_ARG (exp, 0);
> + scalar_float_mode fmode = SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (arg));
> + const struct real_format *fmt = REAL_MODE_FORMAT (fmode);
> +
> + /* Expand the argument yielding a RTX expression. */
> + rtx temp = expand_normal (arg);
> +
> + /* If mode doesn't support NaN, always return 0. */
> + if (!HONOR_NANS (fmode))
> + {
> + emit_move_insn (target, const0_rtx);
> + return target;
> + }
> +
> + /* Check if the back end provides an insn that handles issignaling for the
> + argument's mode. */
> + enum insn_code icode = optab_handler (issignaling_optab, fmode);
> + if (icode != CODE_FOR_nothing)
> + {
> + rtx_insn *last = get_last_insn ();
> + rtx this_target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
> + if (maybe_emit_unop_insn (icode, this_target, temp, UNKNOWN))
> + return this_target;
> + delete_insns_since (last);
> + }
> +
> + if (DECIMAL_FLOAT_MODE_P (fmode))
> + {
> + scalar_int_mode imode;
> + rtx hi;
> + switch (fmt->ieee_bits)
> + {
> + case 32:
> + case 64:
> + imode = int_mode_for_mode (fmode).require ();
> + temp = gen_lowpart (imode, temp);
> + break;
> + case 128:
> + imode = int_mode_for_size (64, 1).require ();
> + hi = NULL_RTX;
> + /* For decimal128, TImode support isn't always there and even when
> + it is, working on the DImode high part is usually better. */
> + if (!MEM_P (temp))
> + {
> + if (rtx t = simplify_gen_subreg (imode, temp, fmode,
> + subreg_highpart_offset (imode,
> + fmode)))
> + hi = t;
> + else
> + {
> + scalar_int_mode imode2;
> + if (int_mode_for_mode (fmode).exists (&imode2))
> + {
> + rtx temp2 = gen_lowpart (imode2, temp);
> + poly_uint64 off = subreg_highpart_offset (imode, imode2);
> + if (rtx t = simplify_gen_subreg (imode, temp2,
> + imode2, off))
> + hi = t;
> + }
> + }
> + if (!hi)
> + {
> + rtx mem = assign_stack_temp (fmode, GET_MODE_SIZE (fmode));
> + emit_move_insn (mem, temp);
> + temp = mem;
> + }
> + }
> + if (!hi)
> + {
> + poly_int64 offset
> + = subreg_highpart_offset (imode, GET_MODE (temp));
> + hi = adjust_address (temp, imode, offset);
> + }
> + temp = hi;
> + break;
> + default:
> + gcc_unreachable ();
> + }
> + /* In all of decimal{32,64,128}, there is MSB sign bit and sNaN
> + have 6 bits below it all set. */
> + rtx val
> + = GEN_INT (HOST_WIDE_INT_C (0x3f) << (GET_MODE_BITSIZE (imode) - 7));
> + temp = expand_binop (imode, and_optab, temp, val,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (target, EQ, temp, val, imode, 1, 1);
> + return temp;
> + }
> +
> + /* Only PDP11 has these defined differently but doesn't support NaNs. */
> + gcc_assert (FLOAT_WORDS_BIG_ENDIAN == WORDS_BIG_ENDIAN);
> + gcc_assert (fmt->signbit_ro > 0 && fmt->b == 2);
> + gcc_assert (MODE_COMPOSITE_P (fmode)
> + || (fmt->pnan == fmt->p
> + && fmt->signbit_ro == fmt->signbit_rw));
> +
> + switch (fmt->p)
> + {
> + case 106: /* IBM double double */
> + /* For IBM double double, recurse on the most significant double. */
> + gcc_assert (MODE_COMPOSITE_P (fmode));
> + temp = convert_modes (DFmode, fmode, temp, 0);
> + fmode = DFmode;
> + fmt = REAL_MODE_FORMAT (DFmode);
> + /* FALLTHRU */
> + case 8: /* bfloat */
> + case 11: /* IEEE half */
> + case 24: /* IEEE single */
> + case 53: /* IEEE double or Intel extended with rounding to double */
> + if (fmt->p == 53 && fmt->signbit_ro == 79)
> + goto extended;
> + {
> + scalar_int_mode imode = int_mode_for_mode (fmode).require ();
> + temp = gen_lowpart (imode, temp);
> + rtx val = GEN_INT ((HOST_WIDE_INT_M1U << (fmt->p - 2))
> + & ~(HOST_WIDE_INT_M1U << fmt->signbit_ro));
> + if (fmt->qnan_msb_set)
> + {
> + rtx mask = GEN_INT (~(HOST_WIDE_INT_M1U << fmt->signbit_ro));
> + rtx bit = GEN_INT (HOST_WIDE_INT_1U << (fmt->p - 2));
> + /* For non-MIPS/PA IEEE single/double/half or bfloat, expand to:
> + ((temp ^ bit) & mask) > val. */
> + temp = expand_binop (imode, xor_optab, temp, bit,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = expand_binop (imode, and_optab, temp, mask,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (target, GTU, temp, val, imode,
> + 1, 1);
> + }
> + else
> + {
> + /* For MIPS/PA IEEE single/double, expand to:
> + (temp & val) == val. */
> + temp = expand_binop (imode, and_optab, temp, val,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (target, EQ, temp, val, imode,
> + 1, 1);
> + }
> + }
> + break;
> + case 113: /* IEEE quad */
> + {
> + rtx hi = NULL_RTX, lo = NULL_RTX;
> + scalar_int_mode imode = int_mode_for_size (64, 1).require ();
> + /* For IEEE quad, TImode support isn't always there and even when
> + it is, working on DImode parts is usually better. */
> + if (!MEM_P (temp))
> + {
> + hi = simplify_gen_subreg (imode, temp, fmode,
> + subreg_highpart_offset (imode, fmode));
> + lo = simplify_gen_subreg (imode, temp, fmode,
> + subreg_lowpart_offset (imode, fmode));
> + if (!hi || !lo)
> + {
> + scalar_int_mode imode2;
> + if (int_mode_for_mode (fmode).exists (&imode2))
> + {
> + rtx temp2 = gen_lowpart (imode2, temp);
> + hi = simplify_gen_subreg (imode, temp2, imode2,
> + subreg_highpart_offset (imode,
> + imode2));
> + lo = simplify_gen_subreg (imode, temp2, imode2,
> + subreg_lowpart_offset (imode,
> + imode2));
> + }
> + }
> + if (!hi || !lo)
> + {
> + rtx mem = assign_stack_temp (fmode, GET_MODE_SIZE (fmode));
> + emit_move_insn (mem, temp);
> + temp = mem;
> + }
> + }
> + if (!hi || !lo)
> + {
> + poly_int64 offset
> + = subreg_highpart_offset (imode, GET_MODE (temp));
> + hi = adjust_address (temp, imode, offset);
> + offset = subreg_lowpart_offset (imode, GET_MODE (temp));
> + lo = adjust_address (temp, imode, offset);
> + }
> + rtx val = GEN_INT ((HOST_WIDE_INT_M1U << (fmt->p - 2 - 64))
> + & ~(HOST_WIDE_INT_M1U << (fmt->signbit_ro - 64)));
> + if (fmt->qnan_msb_set)
> + {
> + rtx mask = GEN_INT (~(HOST_WIDE_INT_M1U << (fmt->signbit_ro
> + - 64)));
> + rtx bit = GEN_INT (HOST_WIDE_INT_1U << (fmt->p - 2 - 64));
> + /* For non-MIPS/PA IEEE quad, expand to:
> + (((hi ^ bit) | ((lo | -lo) >> 63)) & mask) > val. */
> + rtx nlo = expand_unop (imode, neg_optab, lo, NULL_RTX, 0);
> + lo = expand_binop (imode, ior_optab, lo, nlo,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + lo = expand_shift (RSHIFT_EXPR, imode, lo, 63, NULL_RTX, 1);
> + temp = expand_binop (imode, xor_optab, hi, bit,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = expand_binop (imode, ior_optab, temp, lo,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = expand_binop (imode, and_optab, temp, mask,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (target, GTU, temp, val, imode,
> + 1, 1);
> + }
> + else
> + {
> + /* For MIPS/PA IEEE quad, expand to:
> + (hi & val) == val. */
> + temp = expand_binop (imode, and_optab, hi, val,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (target, EQ, temp, val, imode,
> + 1, 1);
> + }
> + }
> + break;
> + case 64: /* Intel or Motorola extended */
> + extended:
> + {
> + rtx ex, hi, lo;
> + scalar_int_mode imode = int_mode_for_size (32, 1).require ();
> + scalar_int_mode iemode = int_mode_for_size (16, 1).require ();
> + if (!MEM_P (temp))
> + {
> + rtx mem = assign_stack_temp (fmode, GET_MODE_SIZE (fmode));
> + emit_move_insn (mem, temp);
> + temp = mem;
> + }
> + if (fmt->signbit_ro == 95)
> + {
> + /* Motorola, always big endian, with 16-bit gap in between
> + 16-bit sign+exponent and 64-bit mantissa. */
> + ex = adjust_address (temp, iemode, 0);
> + hi = adjust_address (temp, imode, 4);
> + lo = adjust_address (temp, imode, 8);
> + }
> + else if (!WORDS_BIG_ENDIAN)
> + {
> + /* Intel little endian, 64-bit mantissa followed by 16-bit
> + sign+exponent and then either 16 or 48 bits of gap. */
> + ex = adjust_address (temp, iemode, 8);
> + hi = adjust_address (temp, imode, 4);
> + lo = adjust_address (temp, imode, 0);
> + }
> + else
> + {
> + /* Big endian Itanium. */
> + ex = adjust_address (temp, iemode, 0);
> + hi = adjust_address (temp, imode, 2);
> + lo = adjust_address (temp, imode, 6);
> + }
> + rtx val = GEN_INT (HOST_WIDE_INT_M1U << 30);
> + gcc_assert (fmt->qnan_msb_set);
> + rtx mask = GEN_INT (0x7fff);
> + rtx bit = GEN_INT (HOST_WIDE_INT_1U << 30);
> + /* For Intel/Motorola extended format, expand to:
> + (ex & mask) == mask && ((hi ^ bit) | ((lo | -lo) >> 31)) > val. */
> + rtx nlo = expand_unop (imode, neg_optab, lo, NULL_RTX, 0);
> + lo = expand_binop (imode, ior_optab, lo, nlo,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + lo = expand_shift (RSHIFT_EXPR, imode, lo, 31, NULL_RTX, 1);
> + temp = expand_binop (imode, xor_optab, hi, bit,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = expand_binop (imode, ior_optab, temp, lo,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (target, GTU, temp, val, imode, 1, 1);
> + ex = expand_binop (iemode, and_optab, ex, mask,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + ex = emit_store_flag_force (gen_reg_rtx (GET_MODE (temp)), EQ,
> + ex, mask, iemode, 1, 1);
> + temp = expand_binop (GET_MODE (temp), and_optab, temp, ex,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + }
> + break;
> + default:
> + gcc_unreachable ();
> + }
> +
> + return temp;
> +}
> +
> /* Expand a call to one of the builtin rounding functions gcc defines
> as an extension (lfloor and lceil). As these are gcc extensions we
> do not need to worry about setting errno to EDOM.
> @@ -5508,9 +5797,9 @@ expand_builtin_signbit (tree exp, rtx ta
> if (icode != CODE_FOR_nothing)
> {
> rtx_insn *last = get_last_insn ();
> - target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
> - if (maybe_emit_unop_insn (icode, target, temp, UNKNOWN))
> - return target;
> + rtx this_target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
> + if (maybe_emit_unop_insn (icode, this_target, temp, UNKNOWN))
> + return this_target;
> delete_insns_since (last);
> }
>
> @@ -7120,6 +7409,12 @@ expand_builtin (tree exp, rtx target, rt
> return target;
> break;
>
> + case BUILT_IN_ISSIGNALING:
> + target = expand_builtin_issignaling (exp, target);
> + if (target)
> + return target;
> + break;
> +
> CASE_FLT_FN (BUILT_IN_ICEIL):
> CASE_FLT_FN (BUILT_IN_LCEIL):
> CASE_FLT_FN (BUILT_IN_LLCEIL):
> @@ -8963,6 +9258,11 @@ fold_builtin_classify (location_t loc, t
> arg = builtin_save_expr (arg);
> return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg);
>
> + case BUILT_IN_ISSIGNALING:
> + if (!tree_expr_maybe_nan_p (arg))
> + return omit_one_operand_loc (loc, type, integer_zero_node, arg);
> + return NULL_TREE;
> +
> default:
> gcc_unreachable ();
> }
> @@ -9399,6 +9699,9 @@ fold_builtin_1 (location_t loc, tree exp
> case BUILT_IN_ISNAND128:
> return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISNAN);
>
> + case BUILT_IN_ISSIGNALING:
> + return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISSIGNALING);
> +
> case BUILT_IN_FREE:
> if (integer_zerop (arg0))
> return build_empty_stmt (loc);
> --- gcc/optabs.def.jj 2022-02-04 14:36:55.424599447 +0100
> +++ gcc/optabs.def 2022-08-11 13:06:09.888416939 +0200
> @@ -313,6 +313,7 @@ OPTAB_D (fmod_optab, "fmod$a3")
> OPTAB_D (hypot_optab, "hypot$a3")
> OPTAB_D (ilogb_optab, "ilogb$a2")
> OPTAB_D (isinf_optab, "isinf$a2")
> +OPTAB_D (issignaling_optab, "issignaling$a2")
> OPTAB_D (ldexp_optab, "ldexp$a3")
> OPTAB_D (log10_optab, "log10$a2")
> OPTAB_D (log1p_optab, "log1p$a2")
> --- gcc/fold-const-call.cc.jj 2022-01-18 11:58:59.510983085 +0100
> +++ gcc/fold-const-call.cc 2022-08-11 12:31:07.294918860 +0200
> @@ -952,6 +952,10 @@ fold_const_call_ss (wide_int *result, co
> *result = wi::shwi (real_isfinite (arg) ? 1 : 0, precision);
> return true;
>
> + case CFN_BUILT_IN_ISSIGNALING:
> + *result = wi::shwi (real_issignaling_nan (arg) ? 1 : 0, precision);
> + return true;
> +
> CASE_CFN_ISINF:
> case CFN_BUILT_IN_ISINFD32:
> case CFN_BUILT_IN_ISINFD64:
> --- gcc/config/i386/i386.md.jj 2022-08-10 09:06:51.463232943 +0200
> +++ gcc/config/i386/i386.md 2022-08-12 11:56:14.763951760 +0200
> @@ -24720,6 +24720,58 @@ (define_expand "spaceshipxf3"
> DONE;
> })
>
> +;; Defined because the generic expand_builtin_issignaling for XFmode
> +;; only tests for sNaNs, but i387 treats also pseudo numbers as always
> +;; signaling.
> +(define_expand "issignalingxf2"
> + [(match_operand:SI 0 "register_operand")
> + (match_operand:XF 1 "general_operand")]
> + ""
> +{
> + rtx temp = operands[1];
> + if (!MEM_P (temp))
> + {
> + rtx mem = assign_stack_temp (XFmode, GET_MODE_SIZE (XFmode));
> + emit_move_insn (mem, temp);
> + temp = mem;
> + }
> + rtx ex = adjust_address (temp, HImode, 8);
> + rtx hi = adjust_address (temp, SImode, 4);
> + rtx lo = adjust_address (temp, SImode, 0);
> + rtx val = GEN_INT (HOST_WIDE_INT_M1U << 30);
> + rtx mask = GEN_INT (0x7fff);
> + rtx bit = GEN_INT (HOST_WIDE_INT_1U << 30);
> + /* Expand to:
> + ((ex & mask) && (int) hi >= 0)
> + || ((ex & mask) == mask && ((hi ^ bit) | ((lo | -lo) >> 31)) > val). */
> + rtx nlo = expand_unop (SImode, neg_optab, lo, NULL_RTX, 0);
> + lo = expand_binop (SImode, ior_optab, lo, nlo,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + lo = expand_shift (RSHIFT_EXPR, SImode, lo, 31, NULL_RTX, 1);
> + temp = expand_binop (SImode, xor_optab, hi, bit,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = expand_binop (SImode, ior_optab, temp, lo,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = emit_store_flag_force (gen_reg_rtx (SImode), GTU, temp, val,
> + SImode, 1, 1);
> + ex = expand_binop (HImode, and_optab, ex, mask,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + rtx temp2 = emit_store_flag_force (gen_reg_rtx (SImode), NE,
> + ex, const0_rtx, SImode, 1, 1);
> + ex = emit_store_flag_force (gen_reg_rtx (SImode), EQ,
> + ex, mask, HImode, 1, 1);
> + temp = expand_binop (SImode, and_optab, temp, ex,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + rtx temp3 = emit_store_flag_force (gen_reg_rtx (SImode), GE,
> + hi, const0_rtx, SImode, 0, 1);
> + temp2 = expand_binop (SImode, and_optab, temp2, temp3,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + temp = expand_binop (SImode, ior_optab, temp, temp2,
> + NULL_RTX, 1, OPTAB_LIB_WIDEN);
> + emit_move_insn (operands[0], temp);
> + DONE;
> +})
> +
> (include "mmx.md")
> (include "sse.md")
> (include "sync.md")
> --- gcc/doc/extend.texi.jj 2022-07-26 10:32:23.642272293 +0200
> +++ gcc/doc/extend.texi 2022-08-11 21:57:06.727147454 +0200
> @@ -13001,6 +13001,7 @@ is called and the @var{flag} argument pa
> @findex __builtin_isless
> @findex __builtin_islessequal
> @findex __builtin_islessgreater
> +@findex __builtin_issignaling
> @findex __builtin_isunordered
> @findex __builtin_object_size
> @findex __builtin_powi
> @@ -14489,6 +14490,14 @@ Similar to @code{__builtin_nans}, except
> @code{_Float@var{n}x}.
> @end deftypefn
>
> +@deftypefn {Built-in Function} int __builtin_issignaling (...)
> +Return non-zero if the argument is a signaling NaN and zero otherwise.
> +Note while the parameter list is an
> +ellipsis, this function only accepts exactly one floating-point
> +argument. GCC treats this parameter as type-generic, which means it
> +does not do default promotion from float to double.
> +@end deftypefn
> +
> @deftypefn {Built-in Function} int __builtin_ffs (int x)
> Returns one plus the index of the least significant 1-bit of @var{x}, or
> if @var{x} is zero, returns zero.
> --- gcc/doc/md.texi.jj 2022-06-27 11:18:02.610059335 +0200
> +++ gcc/doc/md.texi 2022-08-11 22:00:11.470708501 +0200
> @@ -6184,6 +6184,10 @@ floating-point mode.
>
> This pattern is not allowed to @code{FAIL}.
>
> +@cindex @code{issignaling@var{m}2} instruction pattern
> +@item @samp{issignaling@var{m}2}
> +Set operand 0 to 1 if operand 1 is a signaling NaN and to 0 otherwise.
> +
> @cindex @code{cadd90@var{m}3} instruction pattern
> @item @samp{cadd90@var{m}3}
> Perform vector add and subtract on even/odd number pairs. The operation being
> --- gcc/c-family/c-common.cc.jj 2022-08-10 09:06:51.214236184 +0200
> +++ gcc/c-family/c-common.cc 2022-08-11 12:19:06.471714333 +0200
> @@ -6294,6 +6294,7 @@ check_builtin_function_arguments (locati
> case BUILT_IN_ISINF_SIGN:
> case BUILT_IN_ISNAN:
> case BUILT_IN_ISNORMAL:
> + case BUILT_IN_ISSIGNALING:
> case BUILT_IN_SIGNBIT:
> if (builtin_function_validate_nargs (loc, fndecl, nargs, 1))
> {
> --- gcc/c/c-typeck.cc.jj 2022-08-10 09:06:51.331234661 +0200
> +++ gcc/c/c-typeck.cc 2022-08-11 12:16:20.586995677 +0200
> @@ -3546,6 +3546,7 @@ convert_arguments (location_t loc, vec<l
> case BUILT_IN_ISINF_SIGN:
> case BUILT_IN_ISNAN:
> case BUILT_IN_ISNORMAL:
> + case BUILT_IN_ISSIGNALING:
> case BUILT_IN_FPCLASSIFY:
> type_generic_remove_excess_precision = true;
> break;
> --- gcc/fortran/f95-lang.cc.jj 2022-06-03 11:20:13.207071074 +0200
> +++ gcc/fortran/f95-lang.cc 2022-08-11 12:20:57.243190944 +0200
> @@ -1013,6 +1013,8 @@ gfc_init_builtin_functions (void)
> "__builtin_isnan", ATTR_CONST_NOTHROW_LEAF_LIST);
> gfc_define_builtin ("__builtin_isnormal", ftype, BUILT_IN_ISNORMAL,
> "__builtin_isnormal", ATTR_CONST_NOTHROW_LEAF_LIST);
> + gfc_define_builtin ("__builtin_issignaling", ftype, BUILT_IN_ISSIGNALING,
> + "__builtin_issignaling", ATTR_CONST_NOTHROW_LEAF_LIST);
> gfc_define_builtin ("__builtin_signbit", ftype, BUILT_IN_SIGNBIT,
> "__builtin_signbit", ATTR_CONST_NOTHROW_LEAF_LIST);
>
> --- gcc/testsuite/gcc.dg/torture/builtin-issignaling-1.c.jj 2022-08-11 21:20:48.790870018 +0200
> +++ gcc/testsuite/gcc.dg/torture/builtin-issignaling-1.c 2022-08-12 12:11:34.800702002 +0200
> @@ -0,0 +1,95 @@
> +/* { dg-do run } */
> +/* { dg-add-options ieee } */
> +/* { dg-additional-options "-fsignaling-nans" } */
> +/* Workaround for PR57484 on ia32: */
> +/* { dg-additional-options "-msse2 -mfpmath=sse" { target { ia32 && sse2_runtime } } } */
> +
> +int
> +f1 (void)
> +{
> + return __builtin_issignaling (__builtin_nansf (""));
> +}
> +
> +int
> +f2 (void)
> +{
> + return __builtin_issignaling (__builtin_nan (""));
> +}
> +
> +int
> +f3 (void)
> +{
> + return __builtin_issignaling (0.0L);
> +}
> +
> +int
> +f4 (float x)
> +{
> + return __builtin_issignaling (x);
> +}
> +
> +int
> +f5 (double x)
> +{
> + return __builtin_issignaling (x);
> +}
> +
> +int
> +f6 (long double x)
> +{
> + return __builtin_issignaling (x);
> +}
> +
> +#ifdef __SIZEOF_FLOAT128__
> +int
> +f7 (_Float128 x)
> +{
> + return __builtin_issignaling (x);
> +}
> +#endif
> +
> +float x;
> +double y;
> +long double z;
> +#ifdef __SIZEOF_FLOAT128__
> +_Float128 w;
> +#endif
> +
> +int
> +main ()
> +{
> + if (!f1 () || f2 () || f3 ())
> + __builtin_abort ();
> + asm volatile ("" : : : "memory");
> + if (f4 (x) || !f4 (__builtin_nansf ("0x123")) || f4 (42.0f) || f4 (__builtin_nanf ("0x234"))
> + || f4 (__builtin_inff ()) || f4 (-__builtin_inff ()) || f4 (-42.0f) || f4 (-0.0f) || f4 (0.0f))
> + __builtin_abort ();
> + x = __builtin_nansf ("");
> + asm volatile ("" : : : "memory");
> + if (!f4 (x))
> + __builtin_abort ();
> + if (f5 (y) || !f5 (__builtin_nans ("0x123")) || f5 (42.0) || f5 (__builtin_nan ("0x234"))
> + || f5 (__builtin_inf ()) || f5 (-__builtin_inf ()) || f5 (-42.0) || f5 (-0.0) || f5 (0.0))
> + __builtin_abort ();
> + y = __builtin_nans ("");
> + asm volatile ("" : : : "memory");
> + if (!f5 (y))
> + __builtin_abort ();
> + if (f6 (z) || !f6 (__builtin_nansl ("0x123")) || f6 (42.0L) || f6 (__builtin_nanl ("0x234"))
> + || f6 (__builtin_infl ()) || f6 (-__builtin_infl ()) || f6 (-42.0L) || f6 (-0.0L) || f6 (0.0L))
> + __builtin_abort ();
> + z = __builtin_nansl ("");
> + asm volatile ("" : : : "memory");
> + if (!f6 (z))
> + __builtin_abort ();
> +#ifdef __SIZEOF_FLOAT128__
> + if (f7 (w) || !f7 (__builtin_nansf128 ("0x123")) || f7 (42.0Q) || f7 (__builtin_nanf128 ("0x234"))
> + || f7 (__builtin_inff128 ()) || f7 (-__builtin_inff128 ()) || f7 (-42.0Q) || f7 (-0.0Q) || f7 (0.0Q))
> + __builtin_abort ();
> + w = __builtin_nansf128 ("");
> + asm volatile ("" : : : "memory");
> + if (!f7 (w))
> + __builtin_abort ();
> +#endif
> + return 0;
> +}
> --- gcc/testsuite/gcc.dg/torture/builtin-issignaling-2.c.jj 2022-08-11 21:21:34.673265283 +0200
> +++ gcc/testsuite/gcc.dg/torture/builtin-issignaling-2.c 2022-08-12 12:13:10.349427951 +0200
> @@ -0,0 +1,73 @@
> +/* { dg-do run } */
> +/* { dg-require-effective-target dfp } */
> +/* { dg-additional-options "-fsignaling-nans" } */
> +
> +int
> +f1 (void)
> +{
> + return __builtin_issignaling (__builtin_nansd32 (""));
> +}
> +
> +int
> +f2 (void)
> +{
> + return __builtin_issignaling (__builtin_nand64 (""));
> +}
> +
> +int
> +f3 (void)
> +{
> + return __builtin_issignaling (0.0DD);
> +}
> +
> +int
> +f4 (_Decimal32 x)
> +{
> + return __builtin_issignaling (x);
> +}
> +
> +int
> +f5 (_Decimal64 x)
> +{
> + return __builtin_issignaling (x);
> +}
> +
> +int
> +f6 (_Decimal128 x)
> +{
> + return __builtin_issignaling (x);
> +}
> +
> +_Decimal32 x;
> +_Decimal64 y;
> +_Decimal128 z;
> +
> +int
> +main ()
> +{
> + if (!f1 () || f2 () || f3 ())
> + __builtin_abort ();
> + asm volatile ("" : : : "memory");
> + if (f4 (x) || !f4 (__builtin_nansd32 ("0x123")) || f4 (42.0DF) || f4 (__builtin_nand32 ("0x234"))
> + || f4 (__builtin_infd32 ()) || f4 (-__builtin_infd32 ()) || f4 (-42.0DF) || f4 (-0.0DF) || f4 (0.0DF))
> + __builtin_abort ();
> + x = __builtin_nansd32 ("");
> + asm volatile ("" : : : "memory");
> + if (!f4 (x))
> + __builtin_abort ();
> + if (f5 (y) || !f5 (__builtin_nansd64 ("0x123")) || f5 (42.0DD) || f5 (__builtin_nand64 ("0x234"))
> + || f5 (__builtin_infd64 ()) || f5 (-__builtin_infd64 ()) || f5 (-42.0DD) || f5 (-0.0DD) || f5 (0.0DD))
> + __builtin_abort ();
> + y = __builtin_nansd64 ("");
> + asm volatile ("" : : : "memory");
> + if (!f5 (y))
> + __builtin_abort ();
> + if (f6 (z) || !f6 (__builtin_nansd128 ("0x123")) || f6 (42.0DL) || f6 (__builtin_nand128 ("0x234"))
> + || f6 (__builtin_infd128 ()) || f6 (-__builtin_infd128 ()) || f6 (-42.0DL) || f6 (-0.0DL) || f6 (0.0DL))
> + __builtin_abort ();
> + z = __builtin_nansd128 ("");
> + asm volatile ("" : : : "memory");
> + if (!f6 (z))
> + __builtin_abort ();
> + return 0;
> +}
> --- gcc/testsuite/gcc.target/i386/builtin-issignaling-1.c.jj 2022-08-12 12:19:19.723502685 +0200
> +++ gcc/testsuite/gcc.target/i386/builtin-issignaling-1.c 2022-08-12 12:40:51.499218604 +0200
> @@ -0,0 +1,80 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -fsignaling-nans" } */
> +
> +#if __LDBL_MANT_DIG__ == 64
> +union U { struct { unsigned long long m; unsigned short e; } p; long double l; };
> +union U zero = { { 0, 0 } };
> +union U mzero = { { 0, 0x8000 } };
> +union U denorm = { { 42, 0 } };
> +union U mdenorm = { { 42, 0x8000 } };
> +union U pseudodenorm = { { 0x8000000000000000ULL, 0 } };
> +union U mpseudodenorm = { { 0x8000000000000000ULL, 0x8000 } };
> +union U pseudodenorm1 = { { 0x8000000000000042ULL, 0 } };
> +union U mpseudodenorm1 = { { 0x8000000000000042ULL, 0x8000 } };
> +union U pseudoinf = { { 0, 0x7fff } };
> +union U mpseudoinf = { { 0, 0xffff } };
> +union U pseudonan = { { 42, 0x7fff } };
> +union U mpseudonan = { { 42, 0xffff } };
> +union U pseudonan1 = { { 0x4000000000000000ULL, 0x7fff } };
> +union U mpseudonan1 = { { 0x4000000000000000ULL, 0xffff } };
> +union U pseudonan2 = { { 0x4000000000000042ULL, 0x7fff } };
> +union U mpseudonan2 = { { 0x4000000000000042ULL, 0xffff } };
> +union U inf = { { 0x8000000000000000ULL, 0x7fff } };
> +union U minf = { { 0x8000000000000000ULL, 0xffff } };
> +union U snan = { { 0x8000000000000042ULL, 0x7fff } };
> +union U msnan = { { 0x8000000000000042ULL, 0xffff } };
> +union U indefinite = { { 0xc000000000000000ULL, 0x7fff } };
> +union U mindefinite = { { 0xc000000000000000ULL, 0xffff } };
> +union U qnan = { { 0xc000000000000042ULL, 0x7fff } };
> +union U mqnan = { { 0xc000000000000042ULL, 0xffff } };
> +union U unnormal = { { 0, 0x42 } };
> +union U munnormal = { { 0, 0x8042 } };
> +union U unnormal1 = { { 42, 0x42 } };
> +union U munnormal1 = { { 42, 0x8042 } };
> +union U normal = { { 0x8000000000000000ULL, 0x42 } };
> +union U mnormal = { { 0x8000000000000000ULL, 0x8042 } };
> +union U normal1 = { { 0x8000000000000042ULL, 0x42 } };
> +union U mnormal1 = { { 0x8000000000000042ULL, 0x8042 } };
> +#endif
> +
> +int
> +main ()
> +{
> +#if __LDBL_MANT_DIG__ == 64
> + asm volatile ("" : : : "memory");
> + if (__builtin_issignaling (zero.l)
> + || __builtin_issignaling (mzero.l)
> + || __builtin_issignaling (denorm.l)
> + || __builtin_issignaling (mdenorm.l)
> + || __builtin_issignaling (pseudodenorm.l)
> + || __builtin_issignaling (mpseudodenorm.l)
> + || __builtin_issignaling (pseudodenorm1.l)
> + || __builtin_issignaling (mpseudodenorm1.l)
> + || !__builtin_issignaling (pseudoinf.l)
> + || !__builtin_issignaling (mpseudoinf.l)
> + || !__builtin_issignaling (pseudonan.l)
> + || !__builtin_issignaling (mpseudonan.l)
> + || !__builtin_issignaling (pseudonan1.l)
> + || !__builtin_issignaling (mpseudonan1.l)
> + || !__builtin_issignaling (pseudonan2.l)
> + || !__builtin_issignaling (mpseudonan2.l)
> + || __builtin_issignaling (inf.l)
> + || __builtin_issignaling (minf.l)
> + || !__builtin_issignaling (snan.l)
> + || !__builtin_issignaling (msnan.l)
> + || __builtin_issignaling (indefinite.l)
> + || __builtin_issignaling (mindefinite.l)
> + || __builtin_issignaling (qnan.l)
> + || __builtin_issignaling (mqnan.l)
> + || !__builtin_issignaling (unnormal.l)
> + || !__builtin_issignaling (munnormal.l)
> + || !__builtin_issignaling (unnormal1.l)
> + || !__builtin_issignaling (munnormal1.l)
> + || __builtin_issignaling (normal.l)
> + || __builtin_issignaling (mnormal.l)
> + || __builtin_issignaling (normal1.l)
> + || __builtin_issignaling (mnormal1.l))
> + __builtin_abort ();
> +#endif
> + return 0;
> +}
>
> Jakub
>
next prev parent reply other threads:[~2022-08-15 20:52 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-08-15 10:12 Jakub Jelinek
2022-08-15 11:24 ` Richard Biener
2022-08-15 11:47 ` Jakub Jelinek
2022-08-15 12:04 ` Andreas Schwab
2022-08-15 12:07 ` Richard Biener
2022-08-15 13:06 ` Jakub Jelinek
2022-08-16 11:33 ` Jakub Jelinek
2022-08-16 11:41 ` Richard Biener
2022-08-16 11:57 ` Jakub Jelinek
2022-08-16 12:04 ` Richard Biener
2022-08-23 7:58 ` Patch ping (Re: [PATCH] Implement __builtin_issignaling) Jakub Jelinek
2022-08-23 18:23 ` Joseph Myers
2022-08-23 19:21 ` [PATCH] v2: Implement __builtin_issignaling Jakub Jelinek
2022-08-15 16:14 ` [PATCH] " FX
2022-08-15 16:23 ` Jakub Jelinek
2022-08-15 20:52 ` Uros Bizjak [this message]
2022-08-25 19:23 ` Michael Meissner
2022-08-25 19:56 ` Jakub Jelinek
2022-08-26 17:25 ` Michael Meissner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAFULd4ayJChMHa2AG1C=zK-D5EkRS=AQbim1nNBhJFe5BfmOdQ@mail.gmail.com' \
--to=ubizjak@gmail.com \
--cc=fxcoudert@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=jeffreyalaw@gmail.com \
--cc=joseph@codesourcery.com \
--cc=rguenther@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).