[PATCH] add insn implementing signbit to middle end and s390

Gellerich gelleric@tuxmaker.boeblingen.de.ibm.com
Tue Apr 3 13:35:00 GMT 2007


Here is the reworked version.

Concerning documentation: I would provide a description for the
"Standard Pattern Names..." section in a separate patch. However, I
saw that a quite similar pattern named isinf is not mentioned
there. Is this pattern intentionally omitted, or should I add a
description for that one, too?

Regards, Wolfgang

---
Dr. Wolfgang Gellerich
IBM Deutschland Entwicklung GmbH
Schönaicher Strasse 220
71032 Böblingen, Germany
Tel. +49 / 7031 / 162598
gellerich@de.ibm.com

=======================

IBM Deutschland Entwicklung GmbH
Vorsitzender des Aufsichtsrats: Johann Weihen 
Geschäftsführung: Herbert Kircher 
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294






----------------------------------------------------------------------------------

Changelog:

2007-04-02  Wolfgang Gellerich  <gellerich@de.ibm.com>

	* optabs.h: Added declaration for signbit_optab.  
	* optabs.c: (init_optabs): Added initialization for signbit_optab.
	* genoptinit.c (optabs): Added entry for signbit insns.  
	* builtins.c (expand_builtin_signbit): Added code to use a signbit insn,
	  if available.  
	* config/s390/s390.h (S390_TDC_POSITIVE_ZERO):New constant.  
	  (S390_TDC_NEGATIVE_ZERO): New constant.
	  (S390_TDC_POSITIVE_NORMALIZED_NUMBER): New constant.
	  (S390_TDC_NEGATIVE_NORMALIZED_NUMBER): New constant.
	  (S390_TDC_POSITIVE_DENORMALIZED_NUMBER): New constant.
	  (S390_TDC_NEGATIVE_DENORMALIZED_NUMBER): New constant.
	  (S390_TDC_POSITIVE_INFINITY): New constant.
	  (S390_TDC_NEGATIVE_INFINITY): New constant.
	  (S390_TDC_POSITIVE_QUIET_NAN): New constant.
	  (S390_TDC_NEGATIVE_QUIET_NAN): New constant.
	  (S390_TDC_POSITIVE_SIGNALING_NAN): New constant.
	  (S390_TDC_NEGATIVE_SIGNALING_NAN): New constant.
	  (S390_TDC_SIGNBIT_SET): New constant.  
	* config/s390/s390.c (s390_canonicalize_comparison): Renamed
	  UNSPEC_CMPINT to UNSPEC_CCU_TO_INT, added a CCU-like
	  optimization for UNSPEC_CCZ_TO_INT.
	* config/s390/s390.md (signbit_<mode>): New expander.  
	  (TDC_insn_<mode>): New insn.  (*ccz_to_int): New insn.
	  (UNSPEC_CMPINT): Renamed to UNSPEC_CCU_TO_INT.
	  (UNSPEC_CCU_TO_INT): New constant, replaces UNSPEC_CMPINT.
	  (UNSPEC_CCZ_TO_INT): New constant.

----------------------------------------------------------------------------------




Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(Revision 123425)
+++ gcc/optabs.c	(Arbeitskopie)
@@ -5584,6 +5584,7 @@
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
       movmem_optab[i] = CODE_FOR_nothing;
+      signbit_optab[i] = CODE_FOR_nothing;
       cmpstr_optab[i] = CODE_FOR_nothing;
       cmpstrn_optab[i] = CODE_FOR_nothing;
       cmpmem_optab[i] = CODE_FOR_nothing;
Index: gcc/optabs.h
===================================================================
--- gcc/optabs.h	(Revision 123425)
+++ gcc/optabs.h	(Arbeitskopie)
@@ -513,6 +513,9 @@
 /* This array records the insn_code of insns to perform block moves.  */
 extern enum insn_code movmem_optab[NUM_MACHINE_MODES];
 
+/* This array records the insn_code of insns to implement the signbit function.  */
+extern enum insn_code signbit_optab[NUM_MACHINE_MODES];
+
 /* This array records the insn_code of insns to perform block sets.  */
 extern enum insn_code setmem_optab[NUM_MACHINE_MODES];
 
Index: gcc/genopinit.c
===================================================================
--- gcc/genopinit.c	(Revision 123425)
+++ gcc/genopinit.c	(Arbeitskopie)
@@ -172,6 +172,7 @@
   "push_optab->handlers[$A].insn_code = CODE_FOR_$(push$a1$)",
   "reload_in_optab[$A] = CODE_FOR_$(reload_in$a$)",
   "reload_out_optab[$A] = CODE_FOR_$(reload_out$a$)",
+  "signbit_optab[$A] = CODE_FOR_$(signbit_$F$a$)",
   "movmem_optab[$A] = CODE_FOR_$(movmem$a$)",
   "cmpstr_optab[$A] = CODE_FOR_$(cmpstr$a$)",
   "cmpstrn_optab[$A] = CODE_FOR_$(cmpstrn$a$)",
Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c	(Revision 123425)
+++ gcc/builtins.c	(Arbeitskopie)
@@ -230,6 +230,11 @@
 			  int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t));
 static tree do_mpfr_sincos (tree, tree, tree);
 
+/* This array records the insn_code of insns to imlement the signbit
+   function. */
+enum insn_code signbit_optab[NUM_MACHINE_MODES];
+
+
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
    its "internal" name, which normally contains the prefix "__builtin".  */
@@ -5553,11 +5558,15 @@
   return tramp;
 }
 
-/* Expand a call to the built-in signbit, signbitf or signbitl function.
-   Return NULL_RTX if a normal call should be emitted rather than expanding
-   the function in-line.  EXP is the expression that is a call to the builtin
-   function; if convenient, the result should be placed in TARGET.  */
 
+/* Expand a call to the built-in signbit, signbitf or signbitl function.  The
+   function first checks whether the back end provides an insn to implement
+   signbit for the respective mode. If not, it checks whether the floating
+   point format of the value is such that the sign bit can be extracted. If
+   that is not the case, the function returns NULL_RTX to indicate that a
+   normal call should be emitted rather than expanding the function in-line.
+   EXP is the expression that is a call to the builtin function; if
+   convenient, the result should be placed in TARGET.  */
 static rtx
 expand_builtin_signbit (tree exp, rtx target)
 {
@@ -5566,6 +5575,7 @@
   HOST_WIDE_INT hi, lo;
   tree arg;
   int word, bitpos;
+  enum insn_code signbit_insn_code;
   rtx temp;
 
   if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
@@ -5576,6 +5586,28 @@
   rmode = TYPE_MODE (TREE_TYPE (exp));
   fmt = REAL_MODE_FORMAT (fmode);
 
+  /* Expand the argument yielding a RTX expression. */
+  temp = expand_normal (arg);
+
+  /* Check if the back end provides an insn that handles signbit for the
+     argument's mode. */
+  signbit_insn_code = signbit_optab [(int) fmode];
+  if (signbit_insn_code != CODE_FOR_nothing)
+    {
+      rtx result = gen_reg_rtx (SImode);
+      rtx signbit_insn;
+
+      if (!insn_data[(int) signbit_insn_code].operand[1].predicate (temp, fmode))
+	temp = force_reg (fmode, temp);
+
+      signbit_insn = GEN_FCN (signbit_insn_code) (temp, result);
+      if (signbit_insn == NULL_RTX)
+        gcc_unreachable ();
+      emit_insn (signbit_insn);
+
+      return result;
+    }
+
   /* For floating point formats without a sign bit, implement signbit
      as "ARG < 0.0".  */
   bitpos = fmt->signbit_ro;
@@ -5590,7 +5622,6 @@
     return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   }
 
-  temp = expand_normal (arg);
   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
       imode = int_mode_for_mode (fmode);
@@ -5649,7 +5680,6 @@
       temp = expand_binop (rmode, and_optab, temp, const1_rtx,
 			   NULL_RTX, 1, OPTAB_LIB_WIDEN);
     }
-
   return temp;
 }
 
Index: gcc/config/s390/s390.c
===================================================================
--- gcc/config/s390/s390.c	(Revision 123426)
+++ gcc/config/s390/s390.c	(Arbeitskopie)
@@ -700,9 +700,9 @@
     }
 
 
-  /* Remove redundant UNSPEC_CMPINT conversions if possible.  */
+  /* Remove redundant UNSPEC_CCU_TO_INT conversions if possible.  */
   if (GET_CODE (*op0) == UNSPEC
-      && XINT (*op0, 1) == UNSPEC_CMPINT
+      && XINT (*op0, 1) == UNSPEC_CCU_TO_INT
       && XVECLEN (*op0, 0) == 1
       && GET_MODE (XVECEXP (*op0, 0, 0)) == CCUmode
       && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
@@ -728,6 +728,32 @@
 	}
     }
 
+
+  /* Remove redundant UNSPEC_CCZ_TO_INT conversions if possible.  */
+  if (GET_CODE (*op0) == UNSPEC
+      && XINT (*op0, 1) == UNSPEC_CCZ_TO_INT
+      && XVECLEN (*op0, 0) == 1
+      && GET_MODE (XVECEXP (*op0, 0, 0)) == CCZmode
+      && GET_CODE (XVECEXP (*op0, 0, 0)) == REG
+      && REGNO (XVECEXP (*op0, 0, 0)) == CC_REGNUM
+      && *op1 == const0_rtx)
+    {
+      enum rtx_code new_code = UNKNOWN;
+      switch (*code)
+	{
+	  case EQ: new_code = EQ;  break;
+	  case NE: new_code = NE;  break;
+	  default: break;
+	}
+
+      if (new_code != UNKNOWN)
+	{
+	  *op0 = XVECEXP (*op0, 0, 0);
+	  *code = new_code;
+	}
+    }
+
+
   /* Simplify cascaded EQ, NE with const0_rtx.  */
   if ((*code == NE || *code == EQ)
       && (GET_CODE (*op0) == EQ || GET_CODE (*op0) == NE)
@@ -753,6 +779,8 @@
     }
 }
 
+
+
 /* Emit a compare instruction suitable to implement the comparison
    OP0 CODE OP1.  Return the correct condition RTL to be placed in
    the IF_THEN_ELSE of the conditional branch testing the result.  */
Index: gcc/config/s390/s390.h
===================================================================
--- gcc/config/s390/s390.h	(Revision 123426)
+++ gcc/config/s390/s390.h	(Arbeitskopie)
@@ -146,7 +146,27 @@
 /* Frame pointer is not used for debugging.  */
 #define CAN_DEBUG_WITHOUT_FP
 
+/* Constants needed to control the TEST DATA CLASS (TDC) instruction. */
+#define S390_TDC_POSITIVE_ZERO                (1 << 11)
+#define S390_TDC_NEGATIVE_ZERO                (1 << 10)
+#define S390_TDC_POSITIVE_NORMALIZED_NUMBER   (1 << 9)
+#define S390_TDC_NEGATIVE_NORMALIZED_NUMBER   (1 << 8)
+#define S390_TDC_POSITIVE_DENORMALIZED_NUMBER (1 << 7)
+#define S390_TDC_NEGATIVE_DENORMALIZED_NUMBER (1 << 6)
+#define S390_TDC_POSITIVE_INFINITY            (1 << 5)
+#define S390_TDC_NEGATIVE_INFINITY            (1 << 4)
+#define S390_TDC_POSITIVE_QUIET_NAN           (1 << 3)
+#define S390_TDC_NEGATIVE_QUIET_NAN           (1 << 2)
+#define S390_TDC_POSITIVE_SIGNALING_NAN       (1 << 1)
+#define S390_TDC_NEGATIVE_SIGNALING_NAN       (1 << 0)
 
+#define S390_TDC_SIGNBIT_SET (S390_TDC_NEGATIVE_ZERO \
+                          | S390_TDC_NEGATIVE_NORMALIZED_NUMBER \
+                          | S390_TDC_NEGATIVE_DENORMALIZED_NUMBER\
+                          | S390_TDC_NEGATIVE_INFINITY \
+                          | S390_TDC_NEGATIVE_QUIET_NAN \
+			  | S390_TDC_NEGATIVE_SIGNALING_NAN )
+
 /* In libgcc2, determine target settings as compile-time constants.  */
 #ifdef IN_LIBGCC2
 #undef TARGET_64BIT
Index: gcc/config/s390/s390.md
===================================================================
--- gcc/config/s390/s390.md	(Revision 123426)
+++ gcc/config/s390/s390.md	(Arbeitskopie)
@@ -59,7 +59,8 @@
 (define_constants
   [; Miscellaneous
    (UNSPEC_ROUND		1)
-   (UNSPEC_CMPINT		2)
+   (UNSPEC_CCU_TO_INT		2)
+   (UNSPEC_CCZ_TO_INT		3)
    (UNSPEC_ICM			10)
 
    ; GOT/PLT and lt-relative accesses
@@ -97,11 +98,15 @@
    ; Stack Smashing Protector
    (UNSPEC_SP_SET 		700)
    (UNSPEC_SP_TEST		701)
-
+   
    ; Copy sign instructions
    (UNSPEC_COPYSIGN             800)
+
+   ; Test Data Class (TDC)
+   (UNSPEC_TDC_INSN		900)
  ])
 
+
 ;;
 ;; UNSPEC_VOLATILE usage
 ;;
@@ -2090,7 +2095,7 @@
      (use (reg:SI 0))])
    (parallel
     [(set (match_operand:SI 0 "register_operand" "=d")
-	  (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_CMPINT))
+	  (unspec:SI [(reg:CCU CC_REGNUM)] UNSPEC_CCU_TO_INT))
      (clobber (reg:CC CC_REGNUM))])]
   ""
 {
@@ -2288,7 +2293,50 @@
   [(set_attr "length" "8")
    (set_attr "type" "vs")])
 
+
+
 ;
+; Test data class.
+;
+
+(define_expand "signbit_<mode>"
+  [(set (reg:CCZ CC_REGNUM)
+        (unspec:CCZ [(match_operand:BFP 0 "register_operand" "f") 
+                     (match_dup 2)] 
+                     UNSPEC_TDC_INSN))
+   (set (match_operand:SI 1 "register_operand" "=d")
+        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))]
+  "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+{
+  operands[2] = GEN_INT (S390_TDC_SIGNBIT_SET);
+})
+
+
+; This insn is used to generate all variants of the Test Data Class
+; instruction.  The insn's first operand is the register to be tested
+; and the second one is the bit mask specifying the required test(s).
+;
+(define_insn "*TDC_insn_<mode>"
+  [(set (reg:CCZ CC_REGNUM)
+        (unspec:CCZ [(match_operand:BFP 0 "register_operand" "f") 
+                     (match_operand:SI 1 "const_int_operand")] UNSPEC_TDC_INSN))]
+  "TARGET_HARD_FLOAT && TARGET_IEEE_FLOAT"
+  "tc<xde>b\t%0,%1"
+   [(set_attr "op_type" "RXE")
+    (set_attr "type"  "fsimp<mode>")])
+
+
+(define_insn_and_split "*ccz_to_int"
+  [(set (match_operand:SI 0 "register_operand" "=d")
+        (unspec:SI [(match_operand:CCZ 1 "register_operand" "0")]
+                   UNSPEC_CCZ_TO_INT))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))])
+
+
+;
 ; setmemM instruction pattern(s).
 ;
 
@@ -2564,7 +2612,7 @@
 (define_insn_and_split "cmpint"
   [(set (match_operand:SI 0 "register_operand" "=d")
         (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
-                   UNSPEC_CMPINT))
+                   UNSPEC_CCU_TO_INT))
    (clobber (reg:CC CC_REGNUM))]
   ""
   "#"
@@ -2577,10 +2625,10 @@
 (define_insn_and_split "*cmpint_cc"
   [(set (reg CC_REGNUM)
         (compare (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
-                            UNSPEC_CMPINT)
+                            UNSPEC_CCU_TO_INT)
                  (const_int 0)))
    (set (match_operand:SI 0 "register_operand" "=d")
-        (unspec:SI [(match_dup 1)] UNSPEC_CMPINT))]
+        (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT))]
   "s390_match_ccmode (insn, CCSmode)"
   "#"
   "&& reload_completed"
@@ -2597,7 +2645,7 @@
 (define_insn_and_split "*cmpint_sign"
   [(set (match_operand:DI 0 "register_operand" "=d")
         (sign_extend:DI (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
-                                   UNSPEC_CMPINT)))
+                                   UNSPEC_CCU_TO_INT)))
    (clobber (reg:CC CC_REGNUM))]
   "TARGET_64BIT"
   "#"
@@ -2611,11 +2659,11 @@
   [(set (reg CC_REGNUM)
         (compare (ashiftrt:DI (ashift:DI (subreg:DI 
                    (unspec:SI [(match_operand:CCU 1 "register_operand" "0")]
-                              UNSPEC_CMPINT) 0)
+                              UNSPEC_CCU_TO_INT) 0)
                    (const_int 32)) (const_int 32))
                  (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=d")
-        (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_CMPINT)))]
+        (sign_extend:DI (unspec:SI [(match_dup 1)] UNSPEC_CCU_TO_INT)))]
   "s390_match_ccmode (insn, CCSmode) && TARGET_64BIT"
   "#"
   "&& reload_completed"




More information about the Gcc-patches mailing list