This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

stfiwx for rs6000


This patch adds minimal support for the 'stfiwx' instruction to the
rs6000 backend.  I say 'minimal' because even though it is used, the
benefit of it is only that 4 bytes are saved on the stack per
temporary, rather than what you'd really like, which is that it will
store directory into a variable in memory if that's more efficient.  I
couldn't work out how to make it store into user memory, after trying
several possibilities; combine won't do it, and when I tried to just say
that "this instruction requires a memory operand", reload would fail.

But, 4 bytes is 4 bytes.  In fact, sometimes it's hundreds of bytes if
there are many temporaries.

Bootstrapped & tested on powerpc-darwin8.

-- 
- Geoffrey Keating <geoffk@apple.com>

===File ~/patches/rs6000-stfiwx-2.patch=====================
2005-03-24  Geoffrey Keating  <geoffk@apple.com>

	* config/rs6000/rs6000.md (UNSPEC constants): Add UNSPEC_STFIWX.
	(fix_truncdfsi2): Allow registers or memory as destination.
	When TARGET_PPC_GFXOPT, generate simplified pattern.
	(fix_truncdfsi2_internal): Use define_insn_and_split.
	(fix_truncdfsi2_internal_gfxopt): New.
	(fctiwz): Don't confuse register allocation by giving it no choices.
	(stfiwx): New.
	* config/rs6000/rs6000.h (EXTRA_CONSTRAINT): Add 'Z'.
	(EXTRA_MEMORY_CONSTRAINT): Likewise.
	* config/rs6000/rs6000.c (indexed_or_indirect_operand): New. 
	* config/rs6000/rs6000-protos.h (indexed_or_indirect_operand): New.

Index: testsuite/ChangeLog
2005-03-25  Geoffrey Keating  <geoffk@apple.com>

	* gcc.dg/ppc-stfiwx.c: New.

Index: config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.96
diff -u -p -u -p -r1.96 rs6000-protos.h
--- config/rs6000/rs6000-protos.h	14 Mar 2005 07:24:24 -0000	1.96
+++ config/rs6000/rs6000-protos.h	25 Mar 2005 19:44:38 -0000
@@ -49,6 +49,7 @@ extern bool rs6000_legitimate_offset_add
 extern rtx rs6000_got_register (rtx);
 extern rtx find_addr_reg (rtx);
 extern int word_offset_memref_operand (rtx, enum machine_mode);
+extern int indexed_or_indirect_operand (rtx, enum machine_mode);
 extern rtx gen_easy_vector_constant_add_self (rtx);
 extern const char *output_vec_const_move (rtx *);
 extern void build_mask64_2_operands (rtx, rtx *);
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.796
diff -u -p -u -p -r1.796 rs6000.c
--- config/rs6000/rs6000.c	20 Mar 2005 23:25:14 -0000	1.796
+++ config/rs6000/rs6000.c	25 Mar 2005 19:44:38 -0000
@@ -2297,6 +2297,25 @@ word_offset_memref_operand (rtx op, enum
   return (off % 4) == 0;
 }
 
+/* Return true if the operand is an indirect or indexed memory operand.  */
+
+int
+indexed_or_indirect_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx addr;
+  if (!memory_operand (op, mode))
+    return 0;
+
+  addr = XEXP (op, 0);
+  if (GET_CODE (addr) == REG)
+    return 1;
+  if (GET_CODE (addr) == PLUS
+      && GET_CODE (XEXP (addr, 0)) == REG
+      && GET_CODE (XEXP (addr, 1)) == REG)
+    return 1;
+  return 0;
+}
+
 /* Return true if either operand is a general purpose register.  */
 
 bool
Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.357
diff -u -p -u -p -r1.357 rs6000.h
--- config/rs6000/rs6000.h	14 Mar 2005 07:24:29 -0000	1.357
+++ config/rs6000/rs6000.h	25 Mar 2005 19:44:40 -0000
@@ -1357,6 +1357,7 @@ enum reg_class
    'U' is for V.4 small data references.
    'W' is a vector constant that can be easily generated (no mem refs).
    'Y' is a indexed or word-aligned displacement memory operand.
+   'Z' is an indexed or indirect memory operand.
    't' is for AND masks that can be performed by two rldic{l,r} insns.  */
 
 #define EXTRA_CONSTRAINT(OP, C)						\
@@ -1372,6 +1373,7 @@ enum reg_class
 		   && !mask64_operand (OP, DImode))			\
    : (C) == 'W' ? (easy_vector_constant (OP, GET_MODE (OP)))		\
    : (C) == 'Y' ? (word_offset_memref_operand (OP, GET_MODE (OP)))      \
+   : (C) == 'Z' ? (indexed_or_indirect_operand (OP, GET_MODE (OP)))	\
    : 0)
 
 /* Define which constraints are memory constraints.  Tell reload
@@ -1379,7 +1381,7 @@ enum reg_class
    memory address into a base register if required.  */
 
 #define EXTRA_MEMORY_CONSTRAINT(C, STR)				\
-  ((C) == 'Q' || (C) == 'Y')
+  ((C) == 'Q' || (C) == 'Y' || (C) == 'Z')
 
 /* Given an rtx X being reloaded into a reg required to be
    in class CLASS, return the class of reg to actually use.
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.355
diff -u -p -u -p -r1.355 rs6000.md
--- config/rs6000/rs6000.md	16 Mar 2005 18:29:26 -0000	1.355
+++ config/rs6000/rs6000.md	25 Mar 2005 19:44:40 -0000
@@ -51,6 +51,7 @@
    (UNSPEC_TLSTLS		29)
    (UNSPEC_FIX_TRUNC_TF		30)	; fadd, rounding towards zero
    (UNSPEC_MV_CR_GT		31)	; move_from_CR_eq_bit
+   (UNSPEC_STFIWX		32)
   ])
 
 ;;
@@ -5272,7 +5273,7 @@
 }")
 
 (define_expand "fix_truncdfsi2"
-  [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+  [(parallel [(set (match_operand:SI 0 "reg_or_mem_operand" "")
 		   (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
 	      (clobber (match_dup 2))
 	      (clobber (match_dup 3))])]
@@ -5286,28 +5287,29 @@
      DONE;
     }
   operands[2] = gen_reg_rtx (DImode);
+  if (TARGET_PPC_GFXOPT)
+    {
+      rtx orig_dest = operands[0];
+      if (GET_CODE (orig_dest) != MEM)
+	operands[0] = assign_stack_temp (SImode, GET_MODE_SIZE (SImode), 0);
+      emit_insn (gen_fix_truncdfsi2_internal_gfxopt (operands[0], operands[1],
+						     operands[2]));
+      if (operands[0] != orig_dest)
+	emit_move_insn (orig_dest, operands[0]);
+      DONE;
+    }
   operands[3] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0);
 }")
 
-(define_insn "*fix_truncdfsi2_internal"
+(define_insn_and_split "*fix_truncdfsi2_internal"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
 	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
    (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))
    (clobber (match_operand:DI 3 "memory_operand" "=o"))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
   "#"
-  [(set_attr "length" "16")])
-
-(define_split
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
-   (clobber (match_operand:DI 3 "offsettable_mem_operand" ""))]
-  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))
-   (clobber (match_operand:DI 2 "gpc_reg_operand" ""))
-   (clobber (match_operand:DI 3 "offsettable_mem_operand" ""))]
+  "&& 1"
+  [(pc)]
   "
 {
   rtx lowword;
@@ -5321,20 +5323,47 @@
   emit_move_insn (operands[3], operands[2]);
   emit_move_insn (operands[0], gen_rtx_MEM (SImode, lowword));
   DONE;
-}")
+}"
+  [(set_attr "length" "16")])
+
+(define_insn_and_split "fix_truncdfsi2_internal_gfxopt"
+  [(set (match_operand:SI 0 "memory_operand" "=Z")
+	(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f")))
+   (clobber (match_operand:DI 2 "gpc_reg_operand" "=f"))]
+  "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS
+   && TARGET_PPC_GFXOPT"
+  "#"
+  "&& 1"
+  [(pc)]
+  "
+{
+  emit_insn (gen_fctiwz (operands[2], operands[1]));
+  emit_insn (gen_stfiwx (operands[0], operands[2]));
+  DONE;
+}"
+  [(set_attr "length" "16")])
 
 ; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
 ; rather than (set (subreg:SI (reg)) (fix:SI ...))
 ; because the first makes it clear that operand 0 is not live
 ; before the instruction.
 (define_insn "fctiwz"
-  [(set (match_operand:DI 0 "gpc_reg_operand" "=*f")
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
 	(unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))]
 		   UNSPEC_FCTIWZ))]
   "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
   "{fcirz|fctiwz} %0,%1"
   [(set_attr "type" "fp")])
 
+; An UNSPEC is used so we don't have to support SImode in FP registers.
+(define_insn "stfiwx"
+  [(set (match_operand:SI 0 "memory_operand" "=Z")
+	(unspec:SI [(match_operand:DI 1 "gpc_reg_operand" "f")]
+		   UNSPEC_STFIWX))]
+  "TARGET_PPC_GFXOPT"
+  "stfiwx %1,%y0"
+  [(set_attr "type" "fpstore")])
+
 (define_expand "floatsisf2"
   [(set (match_operand:SF 0 "gpc_reg_operand" "")
         (float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
Index: testsuite/gcc.dg/ppc-stfiwx.c
===================================================================
RCS file: testsuite/gcc.dg/ppc-stfiwx.c
diff -N testsuite/gcc.dg/ppc-stfiwx.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gcc.dg/ppc-stfiwx.c	25 Mar 2005 19:44:43 -0000
@@ -0,0 +1,8 @@
+/* { dg-do compile { target powerpc*-*-* } } */
+/* { dg-options "-mpowerpc-gfxopt" } */
+/* { dg-final { scan-assembler "stfiwx" } } */
+
+int foo (double x)
+{
+  return x;
+}
============================================================


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]