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

Wolfgang Gellerich gellerich@de.ibm.com
Fri Mar 30 09:36:00 GMT 2007


Some platforms like s390 and spu provide instructions that implement the
math.h:signbit function. Using this instruction is faster and shorter than
making a lib call, or using the optimization currently performend by
builtins.c:expand_builtin_signbit. The signbit instruction also has the
advantage that it avoids the local variable currently introduced by
expand_builtin_signbit.

This patch enhances the middle end with an interface via optabs so that back
ends can provide insns named signbit_<FLOAT MODE> if they like, and it also
contains an appropriate implementation for s390. For s390, I also introduced a
CCZ to INTEGER conversion and renamed the CMPINT UNSPEC to CCU_TO_INT.

Verification: the patched compiler bootstraps and does not introduce new
reg.test failures on s390 (which now has signbit insns) and on i686 (without
signbit insn). I also checked the generated assembler code manually for some
example programs using signbit on s390.

Here is a suggestion for the Changelog:

2007-03-29  Wolfgang Gellerich  <gellerich@de.ibm.com>

	* optabs.h: added declaration for signbit_optab.
	* optabs.c (init_optabs): added initialization for
          signbit_optab.
	* genoptinit.c: added handling of signbit insns.
	* builtins.c (expand_builtin_signbit): Added code to use a
          signbit insn, if available.
	* s390.h.c: Added named constants for bit masks controllong the test
	  data class instruction
	* s390.c (s390_canonicalize_comparison): renamed CMPINT to CCU_TO_INT,
	  added a CCU-like optimization for CCU_TO_INT 
 	* s390.md: added insns signbit_<mode>, TDC_insn_<mode>, 
	  ccz_to_int, renamed UNSPEC_CMPINT to UNSPEC_CCU_TO_INT, added 
          UNSPEC_CCZ_TO_INT


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



Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(Revision 123324)
+++ 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 123324)
+++ 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 123324)
+++ 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 123324)
+++ gcc/builtins.c	(Arbeitskopie)
@@ -230,6 +230,10 @@
 			  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 +5557,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 +5574,9 @@
   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 +5587,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 +5623,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);
@@ -5653,6 +5685,7 @@
   return temp;
 }
 
+
 /* Expand fork or exec calls.  TARGET is the desired target of the
    call.  EXP is the call. FN is the
    identificator of the actual function.  IGNORE is nonzero if the
Index: gcc/config/s390/s390.c
===================================================================
--- gcc/config/s390/s390.c	(Revision 123324)
+++ 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 123324)
+++ 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_quite_NaN           (1 << 3)
+#define s390_TDC_negative_quite_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_quite_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 123324)
+++ 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,56 @@
   [(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))
+   (parallel
+    [ (set (match_operand:SI 1 "register_operand" "=d")
+        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CCZ_TO_INT))
+      (clobber (reg:CC CC_REGNUM))])
+  ]
+  "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"
+)
+
+
+(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))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "#"
+  "reload_completed"
+  [(set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 28)))])
+
+
+;
 ; setmemM instruction pattern(s).
 ;
 
@@ -2564,7 +2618,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 +2631,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 +2651,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 +2665,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