public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [PATCH] add insn implementing signbit to middle end and s390
@ 2007-04-03 13:35 Gellerich
  2007-04-03 13:50 ` Richard Guenther
  2007-04-03 14:02 ` Paolo Bonzini
  0 siblings, 2 replies; 21+ messages in thread
From: Gellerich @ 2007-04-03 13:35 UTC (permalink / raw)
  To: gcc-patches, gellerich

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 14525 bytes --]


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"


^ permalink raw reply	[flat|nested] 21+ messages in thread
* Re: [PATCH] add insn implementing signbit to middle end and s390
@ 2007-04-03 14:18 Uros Bizjak
  2007-04-11 12:58 ` gellerich
  0 siblings, 1 reply; 21+ messages in thread
From: Uros Bizjak @ 2007-04-03 14:18 UTC (permalink / raw)
  To: GCC Patches; +Cc: Gellerich

Hello!

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

I forgot to add documentation...

Regadring your patch: It looks to me you are somehow reinventing
expand_builtin_interclass_mathfn() functionality. The patch for isinf
(please look at my ChangeLog entry from 2007-01-31) added
infrastructure that handles builtins with FP mode arguments and SImode
outputs using generic optab handling.

Perhaps you could enhance expand_builtin_interclass_mathfn() to
fallback to generic signbit handling (expand_builtin_signbit) in case
named pattern is not available?

BTW: You could implement isinf() just by adding appropriate named
pattern to s390.md. Please look at "isinf<mode>2" expander in
config/i386/i386.md

> +(define_expand "signbit_<mode>"

I belive that correct name for the named pattern is "signbit<mode>2"
as it has two operands. Underscore is usually not needed.

Uros.

^ permalink raw reply	[flat|nested] 21+ messages in thread
* [PATCH] add insn implementing signbit to middle end and s390
@ 2007-03-30  9:36 Wolfgang Gellerich
  2007-03-30 14:49 ` Ulrich Weigand
  2007-03-30 17:24 ` Richard Henderson
  0 siblings, 2 replies; 21+ messages in thread
From: Wolfgang Gellerich @ 2007-03-30  9:36 UTC (permalink / raw)
  To: gcc-patches

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 14396 bytes --]


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"



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2007-07-06 15:58 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-03 13:35 [PATCH] add insn implementing signbit to middle end and s390 Gellerich
2007-04-03 13:50 ` Richard Guenther
2007-04-11  7:46   ` gellerich
2007-04-11  7:46   ` gellerich
2007-04-11  7:46   ` gellerich
2007-04-11  8:54   ` gellerich
2007-04-03 14:02 ` Paolo Bonzini
2007-04-11 10:17   ` gellerich
  -- strict thread matches above, loose matches on Subject: below --
2007-04-03 14:18 Uros Bizjak
2007-04-11 12:58 ` gellerich
2007-04-12  6:59   ` Uros Bizjak
2007-04-30 15:05     ` Wolfgang Gellerich
2007-03-30  9:36 Wolfgang Gellerich
2007-03-30 14:49 ` Ulrich Weigand
2007-03-30 17:24 ` Richard Henderson
2007-04-02  7:57   ` Wolfgang Gellerich
2007-04-30 17:02     ` Wolfgang Gellerich
2007-06-11  9:25       ` Richard Guenther
2007-07-06 15:02         ` Wolfgang Gellerich
2007-07-06 15:37         ` Wolfgang Gellerich
2007-07-06 16:22           ` Richard Guenther

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