fortran: Expand ieee_arithmetic module's ieee_class inline [PR106579]

Message ID YvodhlCSHsa4iZhf@tucnak
State New
Headers
Series fortran: Expand ieee_arithmetic module's ieee_class inline [PR106579] |

Commit Message

Jakub Jelinek Aug. 15, 2022, 10:18 a.m. UTC
  Hi!

The following patch expands IEEE_CLASS inline in the FE, using the
__builtin_fpclassify, __builtin_signbit and the new __builtin_issignaling
builtins.

Bootstrapped/regtested on x86_64-linux, i686-linux, powerpc64le-linux
and powerpc64-linux, ok for trunk?

2022-08-15  Jakub Jelinek  <jakub@redhat.com>

	PR fortran/106579
gcc/fortran/
	* f95-lang.cc (gfc_init_builtin_functions): Initialize
	BUILT_IN_FPCLASSIFY.
	* libgfortran.h (IEEE_OTHER_VALUE, IEEE_SIGNALING_NAN,
	IEEE_QUIET_NAN, IEEE_NEGATIVE_INF, IEEE_NEGATIVE_NORMAL,
	IEEE_NEGATIVE_DENORMAL, IEEE_NEGATIVE_SUBNORMAL,
	IEEE_NEGATIVE_ZERO, IEEE_POSITIVE_ZERO, IEEE_POSITIVE_DENORMAL,
	IEEE_POSITIVE_SUBNORMAL, IEEE_POSITIVE_NORMAL, IEEE_POSITIVE_INF):
	New enum.
	* trans-intrinsic.cc (conv_intrinsic_ieee_class): New function.
	(gfc_conv_ieee_arithmetic_function): Handle ieee_class.
libgfortran/
	* ieee/ieee_helper.c (IEEE_OTHER_VALUE, IEEE_SIGNALING_NAN,
	IEEE_QUIET_NAN, IEEE_NEGATIVE_INF, IEEE_NEGATIVE_NORMAL,
	IEEE_NEGATIVE_DENORMAL, IEEE_NEGATIVE_SUBNORMAL,
	IEEE_NEGATIVE_ZERO, IEEE_POSITIVE_ZERO, IEEE_POSITIVE_DENORMAL,
	IEEE_POSITIVE_SUBNORMAL, IEEE_POSITIVE_NORMAL, IEEE_POSITIVE_INF):
	Move to gcc/fortran/libgfortran.h.


	Jakub
  

Comments

FX Coudert Aug. 15, 2022, 7:47 p.m. UTC | #1
Question to the Fortran maintainers:

Do you know if the standard allows IEEE_CLASS and IEEE_VALUE to be used as procedure pointers? I think not, because they do not follow (in F2008) the standard constraint C729 / R740.

If so, we need to keep these functions implementations in libgfortran for now (for ABI compatibility) but can remove them at the next breakage. Is one planned? Where is this tracked, is it still at https://gcc.gnu.org/wiki/LibgfortranAbiCleanup or do we have another place (e.g. in bugzilla)?

Thanks,
FX
  
Jakub Jelinek Aug. 15, 2022, 8:11 p.m. UTC | #2
On Mon, Aug 15, 2022 at 09:47:45PM +0200, FX wrote:
> Question to the Fortran maintainers:
> 
> Do you know if the standard allows IEEE_CLASS and IEEE_VALUE to be used as procedure pointers? I think not, because they do not follow (in F2008) the standard constraint C729 / R740.
> 
> If so, we need to keep these functions implementations in libgfortran for now (for ABI compatibility) but can remove them at the next breakage. Is one planned? Where is this tracked, is it still at https://gcc.gnu.org/wiki/LibgfortranAbiCleanup or do we have another place (e.g. in bugzilla)?

Both are elemental generic procedures, and we have
Procedure pointer %qs at %L shall not be elemental
and
Interface %qs at %L may not be generic
errors for these 2 cases (trying to create procedure
pointer to elemental and trying to create procedure
pointer to generic procedure).

	Jakub
  

Patch

--- gcc/fortran/f95-lang.cc.jj	2022-08-12 17:06:33.906598328 +0200
+++ gcc/fortran/f95-lang.cc	2022-08-12 18:39:47.727073699 +0200
@@ -1017,8 +1017,9 @@  gfc_init_builtin_functions (void)
 		      "__builtin_issignaling", ATTR_CONST_NOTHROW_LEAF_LIST);
   gfc_define_builtin ("__builtin_signbit", ftype, BUILT_IN_SIGNBIT,
 		      "__builtin_signbit", ATTR_CONST_NOTHROW_LEAF_LIST);
+  gfc_define_builtin ("__builtin_fpclassify", ftype, BUILT_IN_FPCLASSIFY,
+		      "__builtin_fpclassify", ATTR_CONST_NOTHROW_LEAF_LIST);
 
-  ftype = build_function_type (integer_type_node, NULL_TREE);
   gfc_define_builtin ("__builtin_isless", ftype, BUILT_IN_ISLESS,
 		      "__builtin_isless", ATTR_CONST_NOTHROW_LEAF_LIST);
   gfc_define_builtin ("__builtin_islessequal", ftype, BUILT_IN_ISLESSEQUAL,
--- gcc/fortran/libgfortran.h.jj	2022-05-31 11:33:51.550250610 +0200
+++ gcc/fortran/libgfortran.h	2022-08-12 17:22:33.210947170 +0200
@@ -187,3 +187,23 @@  typedef enum
   BT_ASSUMED, BT_UNION, BT_BOZ
 }
 bt;
+
+/* Enumeration of the possible floating-point types. These values
+   correspond to the hidden arguments of the IEEE_CLASS_TYPE
+   derived-type of IEEE_ARITHMETIC.  */
+
+enum {
+  IEEE_OTHER_VALUE = 0,
+  IEEE_SIGNALING_NAN,
+  IEEE_QUIET_NAN,
+  IEEE_NEGATIVE_INF,
+  IEEE_NEGATIVE_NORMAL,
+  IEEE_NEGATIVE_DENORMAL,
+  IEEE_NEGATIVE_SUBNORMAL = IEEE_NEGATIVE_DENORMAL,
+  IEEE_NEGATIVE_ZERO,
+  IEEE_POSITIVE_ZERO,
+  IEEE_POSITIVE_DENORMAL,
+  IEEE_POSITIVE_SUBNORMAL = IEEE_POSITIVE_DENORMAL,
+  IEEE_POSITIVE_NORMAL,
+  IEEE_POSITIVE_INF
+};
--- gcc/fortran/trans-intrinsic.cc.jj	2022-06-28 13:14:45.322799333 +0200
+++ gcc/fortran/trans-intrinsic.cc	2022-08-12 18:51:28.095927643 +0200
@@ -10013,6 +10013,78 @@  conv_intrinsic_ieee_copy_sign (gfc_se *
 }
 
 
+/* Generate code for IEEE_CLASS.  */
+
+static void
+conv_intrinsic_ieee_class (gfc_se *se, gfc_expr *expr)
+{
+  tree arg, c, t1, t2, t3, t4;
+
+  /* Convert arg, evaluate it only once.  */
+  conv_ieee_function_args (se, expr, &arg, 1);
+  arg = gfc_evaluate_now (arg, &se->pre);
+
+  c = build_call_expr_loc (input_location,
+			   builtin_decl_explicit (BUILT_IN_FPCLASSIFY), 6,
+			   build_int_cst (integer_type_node, IEEE_QUIET_NAN),
+			   build_int_cst (integer_type_node,
+					  IEEE_POSITIVE_INF),
+			   build_int_cst (integer_type_node,
+					  IEEE_POSITIVE_NORMAL),
+			   build_int_cst (integer_type_node,
+					  IEEE_POSITIVE_DENORMAL),
+			   build_int_cst (integer_type_node,
+					  IEEE_POSITIVE_ZERO),
+			   arg);
+  c = gfc_evaluate_now (c, &se->pre);
+  t1 = fold_build2_loc (input_location, EQ_EXPR, logical_type_node,
+			c, build_int_cst (integer_type_node,
+					  IEEE_QUIET_NAN));
+  t2 = build_call_expr_loc (input_location,
+			    builtin_decl_explicit (BUILT_IN_ISSIGNALING), 1,
+			    arg);
+  t2 = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
+			t2, build_zero_cst (TREE_TYPE (t2)));
+  t1 = fold_build2_loc (input_location, TRUTH_AND_EXPR,
+			logical_type_node, t1, t2);
+  t3 = fold_build2_loc (input_location, GE_EXPR, logical_type_node,
+			c, build_int_cst (integer_type_node,
+					  IEEE_POSITIVE_ZERO));
+  t4 = build_call_expr_loc (input_location,
+			    builtin_decl_explicit (BUILT_IN_SIGNBIT), 1,
+			    arg);
+  t4 = fold_build2_loc (input_location, NE_EXPR, logical_type_node,
+			t4, build_zero_cst (TREE_TYPE (t4)));
+  t3 = fold_build2_loc (input_location, TRUTH_AND_EXPR,
+			logical_type_node, t3, t4);
+  int s = IEEE_NEGATIVE_ZERO + IEEE_POSITIVE_ZERO;
+  gcc_assert (IEEE_NEGATIVE_INF == s - IEEE_POSITIVE_INF);
+  gcc_assert (IEEE_NEGATIVE_NORMAL == s - IEEE_POSITIVE_NORMAL);
+  gcc_assert (IEEE_NEGATIVE_DENORMAL == s - IEEE_POSITIVE_DENORMAL);
+  gcc_assert (IEEE_NEGATIVE_SUBNORMAL == s - IEEE_POSITIVE_SUBNORMAL);
+  gcc_assert (IEEE_NEGATIVE_ZERO == s - IEEE_POSITIVE_ZERO);
+  t4 = fold_build2_loc (input_location, MINUS_EXPR, TREE_TYPE (c),
+			build_int_cst (TREE_TYPE (c), s), c);
+  t3 = fold_build3_loc (input_location, COND_EXPR, TREE_TYPE (c),
+			t3, t4, c);
+  t1 = fold_build3_loc (input_location, COND_EXPR, TREE_TYPE (c), t1,
+			build_int_cst (TREE_TYPE (c), IEEE_SIGNALING_NAN),
+			t3);
+  tree type = gfc_typenode_for_spec (&expr->ts);
+  gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+  tree field = NULL_TREE;
+  for (tree f = TYPE_FIELDS (type); f != NULL_TREE; f = DECL_CHAIN (f))
+    if (TREE_CODE (f) == FIELD_DECL)
+      {
+	gcc_assert (field == NULL_TREE);
+	field = f;
+      }
+  gcc_assert (field);
+  t1 = fold_convert (TREE_TYPE (field), t1);
+  se->expr = build_constructor_single (type, field, t1);
+}
+
+
 /* Generate code for an intrinsic function from the IEEE_ARITHMETIC
    module.  */
 
@@ -10043,6 +10115,8 @@  gfc_conv_ieee_arithmetic_function (gfc_s
     conv_intrinsic_ieee_logb_rint (se, expr, BUILT_IN_LOGB);
   else if (startswith (name, "_gfortran_ieee_rint"))
     conv_intrinsic_ieee_logb_rint (se, expr, BUILT_IN_RINT);
+  else if (startswith (name, "ieee_class_") && ISDIGIT (name[11]))
+    conv_intrinsic_ieee_class (se, expr);
   else
     /* It is not among the functions we translate directly.  We return
        false, so a library function call is emitted.  */
--- libgfortran/ieee/ieee_helper.c.jj	2022-08-12 13:39:50.285337026 +0200
+++ libgfortran/ieee/ieee_helper.c	2022-08-12 17:22:00.923372705 +0200
@@ -51,26 +51,6 @@  extern int ieee_class_helper_16 (GFC_REA
 internal_proto(ieee_class_helper_16);
 #endif
 
-/* Enumeration of the possible floating-point types. These values
-   correspond to the hidden arguments of the IEEE_CLASS_TYPE
-   derived-type of IEEE_ARITHMETIC.  */
-
-enum {
-  IEEE_OTHER_VALUE = 0,
-  IEEE_SIGNALING_NAN,
-  IEEE_QUIET_NAN,
-  IEEE_NEGATIVE_INF,
-  IEEE_NEGATIVE_NORMAL,
-  IEEE_NEGATIVE_DENORMAL,
-  IEEE_NEGATIVE_SUBNORMAL = IEEE_NEGATIVE_DENORMAL,
-  IEEE_NEGATIVE_ZERO,
-  IEEE_POSITIVE_ZERO,
-  IEEE_POSITIVE_DENORMAL,
-  IEEE_POSITIVE_SUBNORMAL = IEEE_POSITIVE_DENORMAL,
-  IEEE_POSITIVE_NORMAL,
-  IEEE_POSITIVE_INF
-};
-
 
 #define CLASSMACRO(TYPE) \
   int ieee_class_helper_ ## TYPE (GFC_REAL_ ## TYPE *value) \