public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Biener <rguenther@suse.de>
To: Jakub Jelinek <jakub@redhat.com>
Cc: "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 11:24:14 +0000 (UTC)	[thread overview]
Message-ID: <nycvar.YFH.7.77.849.2208151114140.13569@jbgna.fhfr.qr> (raw)
In-Reply-To: <Yvob8gMilv36WN4T@tucnak>

On Mon, 15 Aug 2022, Jakub Jelinek 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?

Unlike the issignalling macro from glibc the builtin will return
false for sNaN arguments when -fno-signalling-nans is used (similar
to isinf, isnan, etc.).  I think this deserves mentioning in the
documentation (and I have my reservations about this long-time
behavior of FP classification builtins we have).

Generally it looks OK - what does it do to size optimized code?

glibc 2.31 seems to silently accept

#include <tgmath.h>

int foo(_Complex double x)
{
  return issignaling (x);
}

for vector double we get

t.c:5:23: error: incompatible type for argument 1 of ‘__issignalingf’
    5 |   return issignaling (x);
      |                       ^
      |                       |
      |                       v2df {aka __vector(2) double}
/usr/include/bits/mathcalls-helper-functions.h:42:1: note: expected 
‘float’ but argument is of type ‘v2df’ {aka ‘__vector(2) double’}
   42 | __MATHDECL_1 (int, __issignaling,, (_Mdouble_ __value))
      | ^

as far as I can see your __builtin silently accepts all arguments
without diagnostics and eventually dispatches to 'issignaling'
which isn't in glibc which instead seems to have __issignaling?

Richard.

> 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.
> 
> --- 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
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg,
Germany; GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman;
HRB 36809 (AG Nuernberg)

  reply	other threads:[~2022-08-15 11:24 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 [this message]
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
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=nycvar.YFH.7.77.849.2208151114140.13569@jbgna.fhfr.qr \
    --to=rguenther@suse.de \
    --cc=fxcoudert@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=jeffreyalaw@gmail.com \
    --cc=joseph@codesourcery.com \
    /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).