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]

Committed: Update RX port


Hi Guys,

  I am applying the patch below to fix several problems with the new
  RX backend to GCC, most notably the generation of correct DWARF2
  debug information.

  The patch also adds a couple of new features requested by Renesas.
  Specifically:

    * The "exception" function attribute has been renamed to
      "interrupt".  (This is consistency with the M32C target).
      Fast interrupts can now only use the "fast_interrupt" function
      attribute.

    * A new command line switch -mcpu=XXX or -patch=XXX to select the
      target RX processor.  Currently only RX610 and RX600 are
      supported.  RX600 is just a generic RX processor.  The RX610 is
      a specific implementation of the RX series and it has one
      limitation - no MVTIPL instruction.

    * A new command line switch -msave-acc-in-interrupts.  If enabled
      then interrupt functions will save the accumulator register
      during their prologue and restore it during their epilogue.

    * A new command line switch -nofpu which unilaterally disables the
      use of the RX FPU instructions, even if they would otherwise be
      used.

Cheers
  Nick

gcc/ChangeLog
2009-11-03  Nick Clifton  <nickc@redhat.com>
	    Kevin Buettner  <kevinb@redhat.com>

	* config/rx/predicates.md (rx_store_multiple_vector): Reverse
	order of expected registers.
	(rx_load_multiple_vector): Likewise.
	(rx_rtsd_vector): Likewise.
	* config/rx/rx.c (rx_cpu_type): New variable.
	(rx_print_operand): Fix bug printing 64-bit constant values.
	(rx_emit_stack_pushm): Reverse order of pushed registers.
	(gen_rx_store_vector): Likewise.
	(is_fast_interrupt_func): Only accept "fast_interrupt" as the
	attribute name.
	(is_exception_func): Rename to is_interrupt_func and only accept
	"interrupt" as the attribute name.
	(rx_get_stack_layout): Use new function name.
	(rx_func_attr_inlinable): Likewise.
	(rx_attribute_table): Remove "exception".
	(rx_expand_prologue): If necessary push the accumulator register
	in the prologue of interrupt functions.
	(rx_expand_epilogue): If necessary pop the accumulator.
	(rx_builtins): Add RX_BUILTIN_MVTIPL.
	(rx_expand_builtin_stz): Remove.
	(rx_expand_builtin_mvtipl): New function.
	(rx_init_builtins): Handle RX_BUILTIN_MVTIPL.
	(rx_expand_builtin): Likewise.
	(rx_enable_fpu): New variable.
	(rx_handle_option): Handle -fpu, -nofpu, -mcpu and -patch.
	* config/rx/rx.h (TARGET_CPU_CPP_BUILTINS): Assert machine based
	on rx_cpu_type.  Define __RX_FPU_INSNS__ if FPU insns are allowed.
	(enum rx_cpu_types): Define.
	(ASM_SPEC): Pass -m32bit-doubles on to assembler.
	(INCOMING_FRAME_SP_OFFSET): Define.
	(ARG_POINTER_CFA_OFFSET): Define.
	(FRAME_POINTER_CFA_OFFSET): Define.
	(OVERRIDE_OPTIONS): Enable fast math if RX FPU insns are enabled.
	(ALLOW_RX_FPU_INSNS): Define.
	* config/rx/rx.md: Test ALLOW_RX_FPU_INSNS instead of
	fast_math_flags_set_p.
	(UNSPEC_BUILTIN_MVTIPL): Define.
	(revl): Rename to bswapsi2.
	(bswaphi2): New pattern.
	(mvtachi): Mark as volatile because it uses a register unknown to
	GCC.
	(mvtaclo): Likewise.
	(racw): Likewise.
	(mvtc): Remove clobber of cc0.
	(mvtcp): Delete.
	(opecp): Delete.
	* config/rx/rx.opt (mieee): Remove.
	(fpu): Add.
	(nofpu): Add.
	(mcpu=): Add.
	(patch=): Add.
	(msave-acc-in-interrupts): Add.
	* config/rx/t-rx (MULTILIB_OPTIONS): Change default to 64bit
	doubles.
	(MULTILIB_DIRS): Likewise.
	(MULTILIB_MATCHES): Treat -fpu as an alias for -m32bit-doubles.
	* doc/extend.texi: Remove description of "exception" function
	attribute.
	* doc/invoke.texi: Document -fpu, -nofpu, -mcpu=, -patch= and
	-msave-acc-in-interrupts options.

gcc/testsuite/ChangeLog
2009-11-03  Nick Clifton  <nickc@redhat.com>

	* gcc.target/rx/builtins,c: Remove redundant tests.
	Add test of MVTIPL instruction.
	* gcc.target/rx/interrupts.c: Use fast_interrupt and interrupt
	function attributes.  Add -msave-acc-in-interrupts option to the
	command line.

Index: config/rx/rx.h
===================================================================
--- config/rx/rx.h	(revision 153851)
+++ config/rx/rx.h	(working copy)
@@ -24,18 +24,24 @@
     {                                           \
       builtin_define ("__RX__"); 		\
       builtin_assert ("cpu=RX"); 		\
-      builtin_assert ("machine=RX");		\
+      if (rx_cpu_type == RX610)			\
+        builtin_assert ("machine=RX610");	\
+     else					\
+        builtin_assert ("machine=RX600");	\
       						\
       if (TARGET_BIG_ENDIAN_DATA)		\
 	builtin_define ("__RX_BIG_ENDIAN__");	\
       else					\
 	builtin_define ("__RX_LITTLE_ENDIAN__");\
       						\
-      if (TARGET_64BIT_DOUBLES)			\
+      if (TARGET_32BIT_DOUBLES)			\
+	builtin_define ("__RX_32BIT_DOUBLES__");\
+      else					\
 	builtin_define ("__RX_64BIT_DOUBLES__");\
-      else					\
-	builtin_define ("__RX_32BIT_DOUBLES__");\
       						\
+      if (ALLOW_RX_FPU_INSNS)			\
+	builtin_define ("__RX_FPU_INSNS__");	\
+						\
       if (TARGET_AS100_SYNTAX)			\
 	builtin_define ("__RX_AS100_SYNTAX__"); \
       else					\
@@ -43,6 +49,17 @@
     }                                           \
   while (0)
 
+enum rx_cpu_types
+{
+  RX600,
+  RX610
+};
+
+extern enum rx_cpu_types  rx_cpu_type;
+
+#undef  CC1_SPEC
+#define CC1_SPEC "%{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}}"
+
 #undef  STARTFILE_SPEC
 #define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s"
 
@@ -52,7 +69,8 @@
 #undef  ASM_SPEC
 #define ASM_SPEC "\
 %{mbig-endian-data:-mbig-endian-data} \
-%{m64bit-doubles:-m64bit-doubles} \
+%{m32bit-doubles:-m32bit-doubles} \
+%{!m32bit-doubles:-m64bit-doubles} \
 %{msmall-data-limit*:-msmall-data-limit} \
 %{mrelax:-relax} \
 "
@@ -88,16 +106,17 @@
 #define LONG_LONG_TYPE_SIZE		64
 
 #define FLOAT_TYPE_SIZE 		32
-#define DOUBLE_TYPE_SIZE 		(TARGET_64BIT_DOUBLES ? 64 : 32)
+#define DOUBLE_TYPE_SIZE 		(TARGET_32BIT_DOUBLES ? 32 : 64)
 #define LONG_DOUBLE_TYPE_SIZE		DOUBLE_TYPE_SIZE
 
-#ifdef __RX_64BIT_DOUBLES__
+#ifdef __RX_32BIT_DOUBLES__
+#define LIBGCC2_HAS_DF_MODE		0
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE   32
+#define LIBGCC2_DOUBLE_TYPE_SIZE	32
+#else
+#define LIBGCC2_HAS_DF_MODE		1
 #define LIBGCC2_LONG_DOUBLE_TYPE_SIZE   64
 #define LIBGCC2_DOUBLE_TYPE_SIZE	64
-#define LIBGCC2_HAS_DF_MODE		1
-#else
-#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE   32
-#define LIBGCC2_DOUBLE_TYPE_SIZE	32
 #endif
 
 #define DEFAULT_SIGNED_CHAR		0
@@ -591,7 +610,6 @@
 #define PRINT_OPERAND_ADDRESS(FILE, ADDR)	\
   rx_print_operand_address (FILE, ADDR)
 
-
 #define CC_NO_CARRY			0400
 #define NOTICE_UPDATE_CC(EXP, INSN)	rx_notice_update_cc (EXP, INSN)
 
@@ -614,19 +632,28 @@
 #define PREFERRED_DEBUGGING_TYPE (TARGET_AS100_SYNTAX \
 				  ? DBX_DEBUG : DWARF2_DEBUG)
 
-#undef  CC1_SPEC
-#define CC1_SPEC "%{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}}"
+#define INCOMING_FRAME_SP_OFFSET		4
+#define ARG_POINTER_CFA_OFFSET(FNDECL)		4
+#define FRAME_POINTER_CFA_OFFSET(FNDECL)	4
+
+extern int rx_enable_fpu;
 
 /* For some unknown reason LTO compression is not working, at
    least on my local system.  So set the default compression
-   level to none, for now.  */
+   level to none, for now.
+
+   For an explanation of rx_flag_no_fpu see rx_handle_option().  */
 #define OVERRIDE_OPTIONS			\
   do						\
     {						\
       if (flag_lto_compression_level == -1)	\
         flag_lto_compression_level = 0;		\
+						\
+      if (rx_enable_fpu == 1)			\
+	set_fast_math_flags (true);		\
     }						\
   while (0)
 
 /* This macro is used to decide when RX FPU instructions can be used.  */
-#define ALLOW_RX_FPU_INSNS	flag_unsafe_math_optimizations
+#define ALLOW_RX_FPU_INSNS	((rx_enable_fpu != -1) \
+				 && flag_unsafe_math_optimizations)
Index: config/rx/predicates.md
===================================================================
--- config/rx/predicates.md	(revision 153851)
+++ config/rx/predicates.md	(working copy)
@@ -117,16 +117,22 @@
   /* Check that the next element is the first push.  */
   element = XVECEXP (op, 0, 1);
   if (   ! SET_P (element)
+      || ! REG_P (SET_SRC (element))
+      || GET_MODE (SET_SRC (element)) != SImode
       || ! MEM_P (SET_DEST (element))
-      || ! REG_P (XEXP (SET_DEST (element), 0))
-      ||   REGNO (XEXP (SET_DEST (element), 0)) != SP_REG
-      || ! REG_P (SET_SRC (element)))
+      || GET_MODE (SET_DEST (element)) != SImode
+      || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
+      || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
+      ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
+      || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
+      || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
+        != GET_MODE_SIZE (SImode))
     return false;
 
   src_regno = REGNO (SET_SRC (element));
 
   /* Check that the remaining elements use SP-<disp>
-     addressing and incremental register numbers.  */
+     addressing and decreasing register numbers.  */
   for (i = 2; i < count; i++)
     {
       element = XVECEXP (op, 0, i);
@@ -134,7 +140,7 @@
       if (   ! SET_P (element)
 	  || ! REG_P (SET_SRC (element))
 	  || GET_MODE (SET_SRC (element)) != SImode
-	  || REGNO (SET_SRC (element)) != src_regno + (i - 1)
+	  || REGNO (SET_SRC (element)) != src_regno - (i - 1)
 	  || ! MEM_P (SET_DEST (element))
 	  || GET_MODE (SET_DEST (element)) != SImode
 	  || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
@@ -142,7 +148,7 @@
           ||   REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
 	  || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
 	  || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
-	     != (i - 1) * GET_MODE_SIZE (SImode))
+	     != i * GET_MODE_SIZE (SImode))
 	return false;
     }
   return true;
Index: config/rx/constraints.md
===================================================================
--- config/rx/constraints.md	(revision 153851)
+++ config/rx/constraints.md	(working copy)
@@ -55,7 +55,7 @@
 
 ;; This constraint is used by the SUBSI3 pattern because the
 ;; RX SUB instruction can only take a 4-bit unsigned integer
-;; value.
+;; value.  Also used by the MVTIPL instruction.
 (define_constraint "Uint04"
   "@internal An unsigned 4-bit immediate value"
   (and (match_code "const_int")
Index: config/rx/rx.md
===================================================================
--- config/rx/rx.md	(revision 153851)
+++ config/rx/rx.md	(working copy)
@@ -27,8 +27,8 @@
 ;; This code iterator is used for sign- and zero- extensions.
 (define_mode_iterator small_int_modes [(HI "") (QI "")])
 
-;; We do not handle DFmode here because by default it is
-;; the same as SFmode, and if -m64bit-doubles is active
+;; We do not handle DFmode here because it is either
+;; the same as SFmode, or if -m64bit-doubles is active
 ;; then all operations on doubles have to be handled by
 ;; library functions.
 (define_mode_iterator register_modes
@@ -75,15 +75,14 @@
    (UNSPEC_BUILTIN_MVTACHI 41)
    (UNSPEC_BUILTIN_MVTACLO 42)
    (UNSPEC_BUILTIN_MVTC    43)
-   (UNSPEC_BUILTIN_MVTCP   44)
-   (UNSPEC_BUILTIN_OPEPC   45)
-   (UNSPEC_BUILTIN_RACW	   46)
-   (UNSPEC_BUILTIN_REVW    47)
-   (UNSPEC_BUILTIN_RMPA	   48)
-   (UNSPEC_BUILTIN_ROUND   49)
-   (UNSPEC_BUILTIN_SAT     50)
-   (UNSPEC_BUILTIN_SETPSW  51)
-   (UNSPEC_BUILTIN_WAIT	   52)
+   (UNSPEC_BUILTIN_MVTIPL  44)
+   (UNSPEC_BUILTIN_RACW	   45)
+   (UNSPEC_BUILTIN_REVW    46)
+   (UNSPEC_BUILTIN_RMPA	   47)
+   (UNSPEC_BUILTIN_ROUND   48)
+   (UNSPEC_BUILTIN_SAT     49)
+   (UNSPEC_BUILTIN_SETPSW  50)
+   (UNSPEC_BUILTIN_WAIT	   51)
   ]
 )
 
@@ -1002,10 +1001,8 @@
    (set_attr "timings" "11,11,11,11,11,33")
    (set_attr "length" "3,4,5,6,7,6")]
 )
-
+
 ;; Floating Point Instructions
-;; These patterns are only enabled with -ffast-math because the RX FPU
-;; cannot handle sub-normal values.
 
 (define_insn "addsf3"
   [(set (match_operand:SF          0 "register_operand"  "=r,r,r")
@@ -1298,7 +1295,6 @@
   [(set_attr "length" "3,6")
    (set_attr "timings" "22")]
 )
-
 
 ;; Block move functions.
 
@@ -1580,8 +1576,8 @@
 
 ;; Move to Accumulator (high)
 (define_insn "mvtachi"
-  [(unspec:SI [(match_operand:SI 0 "register_operand" "r")]
-	      UNSPEC_BUILTIN_MVTACHI)]
+  [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
+		       UNSPEC_BUILTIN_MVTACHI)]
   ""
   "mvtachi\t%0"
   [(set_attr "length" "3")]
@@ -1589,8 +1585,8 @@
 
 ;; Move to Accumulator (low)
 (define_insn "mvtaclo"
-  [(unspec:SI [(match_operand:SI 0 "register_operand" "r")]
-	      UNSPEC_BUILTIN_MVTACLO)]
+  [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
+		       UNSPEC_BUILTIN_MVTACLO)]
   ""
   "mvtaclo\t%0"
   [(set_attr "length" "3")]
@@ -1598,8 +1594,8 @@
 
 ;; Round Accumulator
 (define_insn "racw"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")]
-	      UNSPEC_BUILTIN_RACW)]
+  [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")]
+		       UNSPEC_BUILTIN_RACW)]
   ""
   "racw\t%0"
   [(set_attr "length" "3")]
@@ -1679,7 +1675,7 @@
 
 ;; Move from control register
 (define_insn "mvfc"
-  [(set (match_operand:SI                      0 "register_operand" "=r")
+  [(set (match_operand:SI             0 "register_operand" "=r")
 	(unspec:SI [(match_operand:SI 1 "immediate_operand" "i")]
 		   UNSPEC_BUILTIN_MVFC))]
   ""
@@ -1691,15 +1687,26 @@
 (define_insn "mvtc"
   [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i")
 	       (match_operand:SI 1 "nonmemory_operand" "r,i")]
-	      UNSPEC_BUILTIN_MVTC)
-   (clobber (cc0))]
+	      UNSPEC_BUILTIN_MVTC)]
   ""
   "mvtc\t%1, %C0"
-  [(set_attr "length" "3,7")
-   (set_attr "cc" "clobber")]  ;; Just in case the control
-                               ;; register selected is the psw.
+  [(set_attr "length" "3,7")]
+  ;; Ignore possible clobbering of the comparison flags in the
+  ;; PSW register.  This is a cc0 target so any cc0 setting
+  ;; instruction will always be paired with a cc0 user, without
+  ;; the possibility of this instruction being placed in between
+  ;; them.
 )
 
+;; Move to interrupt priority level
+(define_insn "mvtipl"
+  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "Uint04")]
+	      UNSPEC_BUILTIN_MVTIPL)]
+  ""
+  "mvtipl\t%0"
+  [(set_attr "length" "3")]
+)
+
 ;;---------- Interrupts ------------------------
 
 ;; Break
@@ -1748,27 +1755,6 @@
   [(set_attr "length" "5")]
 )
 
-;; Move to co-processor register
-(define_insn "mvtcp"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i")
-	       (match_operand:SI 1 "nonmemory_operand" "i,r")
-	       (match_operand:SI 2 "immediate_operand" "i,i")]
-	      UNSPEC_BUILTIN_MVTCP)]
-  ""
-  "; mvtcp\t%0, %1, %2"
-  [(set_attr "length" "7,5")]
-)
-
-;; Co-processor operation
-(define_insn "opecp"
-  [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")
-	       (match_operand:SI 1 "immediate_operand" "i")]
-	      UNSPEC_BUILTIN_OPEPC)]
-  ""
-  "; opecp\t%0, %1"
-  [(set_attr "length" "5")]
-)
-
 ;;---------- Misc ------------------------
 
 ;; Required by cfglayout.c...
Index: config/rx/rx.c
===================================================================
--- config/rx/rx.c	(revision 153851)
+++ config/rx/rx.c	(working copy)
@@ -51,6 +51,8 @@
 #include "target-def.h"
 #include "langhooks.h"
 
+enum rx_cpu_types  rx_cpu_type = RX600;
+
 /* Return true if OP is a reference to an object in a small data area.  */
 
 static bool
@@ -249,7 +251,6 @@
     }
 }
 
-
 /* A C compound statement to output to stdio stream FILE the
    assembler syntax for an instruction operand that is a memory
    reference whose address is ADDR.  */
@@ -445,8 +446,13 @@
 	fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 0 : 1)]);
       else if (CONST_INT_P (op))
 	{
+	  HOST_WIDE_INT v = INTVAL (op);
+
 	  fprintf (file, "#");
-	  rx_print_integer (file, INTVAL (op) >> 32);
+	  /* Trickery to avoid problems with shifting 32 bits at a time.  */
+	  v = v >> 16;
+	  v = v >> 16;	  
+	  rx_print_integer (file, v);
 	}
       else
 	{
@@ -840,22 +846,20 @@
   return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
 }
 
-/* Returns true if the provided function has
-   the "[fast_]interrupt" attribute.  */
+/* Returns true if the provided function has the "fast_interrupt" attribute.  */
 
 static inline bool
 is_fast_interrupt_func (const_tree decl)
 {
-  return has_func_attr (decl, "interrupt")
-    || has_func_attr (decl, "fast_interrupt") ;
+  return has_func_attr (decl, "fast_interrupt");
 }
 
-/* Returns true if the provided function has the "exception" attribute.  */
+/* Returns true if the provided function has the "interrupt" attribute.  */
 
 static inline bool
-is_exception_func (const_tree decl)
+is_interrupt_func (const_tree decl)
 {
-  return has_func_attr (decl, "exception");
+  return has_func_attr (decl, "interrupt");
 }
 
 /* Returns true if the provided function has the "naked" attribute.  */
@@ -945,8 +949,8 @@
 {
   /* Remember the last target of rx_set_current_function.  */
   static tree rx_previous_fndecl;
-  bool prev_was_interrupt;
-  bool current_is_interrupt;
+  bool prev_was_fast_interrupt;
+  bool current_is_fast_interrupt;
 
   /* Only change the context if the function changes.  This hook is called
      several times in the course of compiling a function, and we don't want
@@ -954,18 +958,19 @@
   if (fndecl == rx_previous_fndecl)
     return;
 
-  prev_was_interrupt
+  prev_was_fast_interrupt
     = rx_previous_fndecl
     ? is_fast_interrupt_func (rx_previous_fndecl) : false;
-  current_is_interrupt
+
+  current_is_fast_interrupt
     = fndecl ? is_fast_interrupt_func (fndecl) : false;
       
-  if (prev_was_interrupt != current_is_interrupt)
+  if (prev_was_fast_interrupt != current_is_fast_interrupt)
     {
-      use_fixed_regs = current_is_interrupt;
+      use_fixed_regs = current_is_fast_interrupt;
       target_reinit ();
     }
-      
+
   rx_previous_fndecl = fndecl;
 }
 
@@ -1057,8 +1062,8 @@
       if (df_regs_ever_live_p (reg)
 	  && (! call_used_regs[reg]
 	      /* Even call clobbered registered must
-		 be pushed inside exception handlers.  */
-	      || is_exception_func (NULL_TREE)))
+		 be pushed inside interrupt handlers.  */
+	      || is_interrupt_func (NULL_TREE)))
 	{
 	  if (low == 0)
 	    low = reg;
@@ -1142,9 +1147,8 @@
   gcc_assert (REG_P (first_push));
 
   asm_fprintf (asm_out_file, "\tpushm\t%s-%s\n",
-	       reg_names [REGNO (first_push)],
-	       reg_names [REGNO (first_push) + last_reg]);
-  
+	       reg_names [REGNO (first_push) - last_reg],
+	       reg_names [REGNO (first_push)]);
 }
 
 /* Generate a PARALLEL that will pass the rx_store_multiple_vector predicate.  */
@@ -1167,14 +1171,30 @@
     XVECEXP (vector, 0, i + 1) =
       gen_rtx_SET (SImode,
 		   gen_rtx_MEM (SImode,
-				i == 0 ? stack_pointer_rtx
-				: gen_rtx_MINUS (SImode, stack_pointer_rtx,
-						 GEN_INT (i * UNITS_PER_WORD))),
-		   gen_rtx_REG (SImode, low + i));
-
+				gen_rtx_MINUS (SImode, stack_pointer_rtx,
+					       GEN_INT ((i + 1) * UNITS_PER_WORD))),
+		   gen_rtx_REG (SImode, high - i));
   return vector;
 }
 
+/* Mark INSN as being frame related.  If it is a PARALLEL
+   then mark each element as being frame related as well.  */
+
+static void
+mark_frame_related (rtx insn)
+{
+  RTX_FRAME_RELATED_P (insn) = 1;
+  insn = PATTERN (insn);
+
+  if (GET_CODE (insn) == PARALLEL)
+    {
+      unsigned int i;
+
+      for (i = 0; i < XVECLEN (insn, 0); i++)
+	RTX_FRAME_RELATED_P (XVECEXP (insn, 0, i)) = 1;
+    }
+}
+
 void
 rx_expand_prologue (void)
 {
@@ -1183,6 +1203,7 @@
   unsigned int mask;
   unsigned int low;
   unsigned int high;
+  unsigned int reg;
   rtx insn;
 
   /* Naked functions use their own, programmer provided prologues.  */
@@ -1196,14 +1217,12 @@
   /* If we use any of the callee-saved registers, save them now.  */
   if (mask)
     {
-      unsigned int reg;
-
       /* Push registers in reverse order.  */
       for (reg = FIRST_PSEUDO_REGISTER; reg --;)
 	if (mask & (1 << reg))
 	  {
 	    insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, reg)));
-	    RTX_FRAME_RELATED_P (insn) = 1;
+	    mark_frame_related (insn);
 	  }
     }
   else if (low)
@@ -1214,9 +1233,59 @@
 	insn = emit_insn (gen_stack_pushm (GEN_INT (((high - low) + 1)
 						    * UNITS_PER_WORD),
 					   gen_rx_store_vector (low, high)));
-      RTX_FRAME_RELATED_P (insn) = 1;
+      mark_frame_related (insn);
     }
 
+  if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER)
+    {
+      unsigned int acc_high, acc_low;
+
+      /* Interrupt handlers have to preserve the accumulator
+	 register if so requested by the user.  Use the first
+         two pushed register as intermediaries.  */
+      if (mask)
+	{
+	  acc_low = acc_high = 0;
+
+	  for (reg = 1; reg < FIRST_PSEUDO_REGISTER; reg ++)
+	    if (mask & (1 << reg))
+	      {
+		if (acc_low == 0)
+		  acc_low = reg;
+		else
+		  {
+		    acc_high = reg;
+		    break;
+		  }
+	      }
+	    
+	  /* We have assumed that there are at least two registers pushed... */
+	  gcc_assert (acc_high != 0);
+
+	  /* Note - the bottom 16 bits of the accumulator are inaccessible.
+	     We just assume that they are zero.  */
+	  emit_insn (gen_mvfacmi (gen_rtx_REG (SImode, acc_low)));
+	  emit_insn (gen_mvfachi (gen_rtx_REG (SImode, acc_high)));
+	  emit_insn (gen_stack_push (gen_rtx_REG (SImode, acc_low)));
+	  emit_insn (gen_stack_push (gen_rtx_REG (SImode, acc_high)));
+	}
+      else
+	{
+	  acc_low = low;
+	  acc_high = low + 1;
+
+	  /* We have assumed that there are at least two registers pushed... */
+	  gcc_assert (acc_high <= high);
+
+	  emit_insn (gen_mvfacmi (gen_rtx_REG (SImode, acc_low)));
+	  emit_insn (gen_mvfachi (gen_rtx_REG (SImode, acc_high)));
+	  emit_insn (gen_stack_pushm (GEN_INT (2 * UNITS_PER_WORD),
+				      gen_rx_store_vector (acc_low, acc_high)));
+	}
+
+      frame_size += 2 * UNITS_PER_WORD;
+    }
+
   /* If needed, set up the frame pointer.  */
   if (frame_pointer_needed)
     {
@@ -1270,8 +1339,8 @@
   if (is_fast_interrupt_func (NULL_TREE))
     asm_fprintf (file, "\t; Note: Fast Interrupt Handler\n");
 
-  if (is_exception_func (NULL_TREE))
-    asm_fprintf (file, "\t; Note: Exception Handler\n");
+  if (is_interrupt_func (NULL_TREE))
+    asm_fprintf (file, "\t; Note: Interrupt Handler\n");
 
   if (is_naked_func (NULL_TREE))
     asm_fprintf (file, "\t; Note: Naked Function\n");
@@ -1382,6 +1451,7 @@
   unsigned int stack_size;
   unsigned int register_mask;
   unsigned int regs_size;
+  unsigned int reg;
   unsigned HOST_WIDE_INT total_size;
 
   if (is_naked_func (NULL_TREE))
@@ -1407,14 +1477,14 @@
        their caller.  Instead they branch to their sibling and allow their
        return instruction to return to this function's parent.
 
-     - Fast interrupt and exception handling functions have to use special
+     - Fast and normal interrupt handling functions have to use special
        return instructions.
 
      - Functions where we have pushed a fragmented set of registers into the
        call-save area must have the same set of registers popped.  */
   if (is_sibcall
       || is_fast_interrupt_func (NULL_TREE)
-      || is_exception_func (NULL_TREE)
+      || is_interrupt_func (NULL_TREE)
       || register_mask)
     {
       /* Cannot use the special instructions - deconstruct by hand.  */
@@ -1422,10 +1492,47 @@
 	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 			       GEN_INT (total_size)));
 
+      if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER)
+	{
+	  unsigned int acc_low, acc_high;
+
+	  /* Reverse the saving of the accumulator register onto the stack.
+	     Note we must adjust the saved "low" accumulator value as it
+	     is really the middle 32-bits of the accumulator.  */
+	  if (register_mask)
+	    {
+	      acc_low = acc_high = 0;
+	      for (reg = 1; reg < FIRST_PSEUDO_REGISTER; reg ++)
+		if (register_mask & (1 << reg))
+		  {
+		    if (acc_low == 0)
+		      acc_low = reg;
+		    else
+		      {
+			acc_high = reg;
+			break;
+		      }
+		  }
+	      emit_insn (gen_stack_pop (gen_rtx_REG (SImode, acc_high)));
+	      emit_insn (gen_stack_pop (gen_rtx_REG (SImode, acc_low)));
+	    }
+	  else
+	    {
+	      acc_low = low;
+	      acc_high = low + 1;
+	      emit_insn (gen_stack_popm (GEN_INT (2 * UNITS_PER_WORD),
+					 gen_rx_popm_vector (acc_low, acc_high)));
+	    }
+
+	  emit_insn (gen_ashlsi3 (gen_rtx_REG (SImode, acc_low),
+				  gen_rtx_REG (SImode, acc_low),
+				  GEN_INT (16)));
+	  emit_insn (gen_mvtaclo (gen_rtx_REG (SImode, acc_low)));
+	  emit_insn (gen_mvtachi (gen_rtx_REG (SImode, acc_high)));
+	}
+
       if (register_mask)
 	{
-	  unsigned int reg;
-
 	  for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++)
 	    if (register_mask & (1 << reg))
 	      emit_insn (gen_stack_pop (gen_rtx_REG (SImode, reg)));
@@ -1441,7 +1548,7 @@
 
       if (is_fast_interrupt_func (NULL_TREE))
 	emit_jump_insn (gen_fast_interrupt_return ());
-      else if (is_exception_func (NULL_TREE))
+      else if (is_interrupt_func (NULL_TREE))
 	emit_jump_insn (gen_exception_return ());
       else if (! is_sibcall)
 	emit_jump_insn (gen_simple_return ());
@@ -1670,6 +1777,7 @@
   RX_BUILTIN_MVTACHI,
   RX_BUILTIN_MVTACLO,
   RX_BUILTIN_MVTC,
+  RX_BUILTIN_MVTIPL,
   RX_BUILTIN_RACW,
   RX_BUILTIN_REVW,
   RX_BUILTIN_RMPA,
@@ -1725,6 +1833,7 @@
   ADD_RX_BUILTIN1 (RMPA,    "rmpa",    void,  void);
   ADD_RX_BUILTIN1 (MVFC,    "mvfc",    intSI, integer);
   ADD_RX_BUILTIN2 (MVTC,    "mvtc",    void,  integer, integer);
+  ADD_RX_BUILTIN1 (MVTIPL,  "mvtipl",  void,  integer);
   ADD_RX_BUILTIN1 (RACW,    "racw",    void,  integer);
   ADD_RX_BUILTIN1 (ROUND,   "round",   intSI, float);
   ADD_RX_BUILTIN1 (REVW,    "revw",    intSI, intSI);
@@ -1733,20 +1842,6 @@
 }
 
 static rtx
-rx_expand_builtin_stz (rtx arg, rtx target, rtx (* gen_func)(rtx, rtx))
-{
-  if (! CONST_INT_P (arg))
-    return NULL_RTX;
-
-  if (target == NULL_RTX || ! REG_P (target))
-    target = gen_reg_rtx (SImode);
-
-  emit_insn (gen_func (target, arg));
-
-  return target;
-}
-
-static rtx
 rx_expand_void_builtin_1_arg (rtx arg, rtx (* gen_func)(rtx), bool reg)
 {
   if (reg && ! REG_P (arg))
@@ -1791,6 +1886,21 @@
 }
 
 static rtx
+rx_expand_builtin_mvtipl (rtx arg)
+{
+  /* The RX610 does not support the MVTIPL instruction.  */
+  if (rx_cpu_type == RX610)
+    return NULL_RTX;
+
+  if (! CONST_INT_P (arg) || ! IN_RANGE (arg, 0, (1 << 4) - 1))
+    return NULL_RTX;
+
+  emit_insn (gen_mvtipl (arg));
+
+  return NULL_RTX;
+}
+
+static rtx
 rx_expand_builtin_mac (tree exp, rtx (* gen_func)(rtx, rtx))
 {
   rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
@@ -1887,6 +1997,7 @@
     case RX_BUILTIN_RMPA:    emit_insn (gen_rmpa ()); return NULL_RTX;
     case RX_BUILTIN_MVFC:    return rx_expand_builtin_mvfc (arg, target);
     case RX_BUILTIN_MVTC:    return rx_expand_builtin_mvtc (exp);
+    case RX_BUILTIN_MVTIPL:  return rx_expand_builtin_mvtipl (op);
     case RX_BUILTIN_RACW:    return rx_expand_void_builtin_1_arg
 	(op, gen_racw, false);
     case RX_BUILTIN_ROUND:   return rx_expand_builtin_round (op, target);
@@ -1945,7 +2056,7 @@
   rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */false);
 }
 
-/* Check "interrupt", "exception" and "naked" attributes.  */
+/* Check "fast_interrupt", "interrupt" and "naked" attributes.  */
 
 static tree
 rx_handle_func_attribute (tree * node,
@@ -1975,9 +2086,8 @@
 const struct attribute_spec rx_attribute_table[] =
 {
   /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler.  */
+  { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute },
   { "interrupt",      0, 0, true, false, false, rx_handle_func_attribute },
-  { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute },
-  { "exception",      0, 0, true, false, false, rx_handle_func_attribute },
   { "naked",          0, 0, true, false, false, rx_handle_func_attribute },
   { NULL,             0, 0, false, false, false, NULL }
 };
@@ -1993,7 +2103,7 @@
 rx_func_attr_inlinable (const_tree decl)
 {
   return ! is_fast_interrupt_func (decl)
-    &&   ! is_exception_func (decl)
+    &&   ! is_interrupt_func (decl)
     &&   ! is_naked_func (decl);  
 }
 
@@ -2115,6 +2225,20 @@
 		        ( 1 << (rx_max_constant_size * 8)));
 }
 
+/* This is a tri-state variable.  The default value of 0 means that the user
+   has specified neither -mfpu nor -mnofpu on the command line.  In this case
+   the selection of RX FPU instructions is entirely based upon the size of
+   the floating point object and whether unsafe math optimizations were
+   enabled.  If 32-bit doubles have been enabled then both floats and doubles
+   can make use of FPU instructions, otherwise only floats may do so.
+
+   If the value is 1 then the user has specified -mfpu and the FPU
+   instructions should be used.  Unsafe math optimizations will automatically
+   be enabled and doubles set to 32-bits.  If the value is -1 then -mnofpu
+   has been specified and FPU instructions will not be used, even if unsafe
+   math optimizations have been enabled.  */
+int rx_enable_fpu = 0;
+
 /* Extra processing for target specific command line options.  */
 
 static bool
@@ -2122,6 +2246,27 @@
 {
   switch (code)
     {
+      /* -mfpu enables the use of RX FPU instructions.  This implies the use
+	 of 32-bit doubles and also the enabling of fast math optimizations.
+	 (Since the RX FPU instructions are not IEEE compliant).  The -mnofpu
+	 option disables the use of RX FPU instructions, but does not make
+	 place any constraints on the size of doubles or the use of fast math
+	 optimizations.
+
+	 The selection of 32-bit vs 64-bit doubles is handled by the setting
+	 of the 32BIT_DOUBLES mask in the rx.opt file.  Enabling fast math
+	 optimizations is performed in OVERRIDE_OPTIONS since if it was done
+	 here it could be overridden by a -fno-fast-math option specified
+	 *earlier* on the command line.  (Target specific options are
+	 processed before generic ones).  */
+    case OPT_fpu:
+      rx_enable_fpu = 1;
+      break;
+
+    case OPT_nofpu:
+      rx_enable_fpu = -1;
+      break;
+
     case OPT_mint_register_:
       switch (value)
 	{
@@ -2145,12 +2290,21 @@
       break;
 
     case OPT_mmax_constant_size_:
-      /* Make sure that the the -mmax-constant_size option is in range.  */
+      /* Make sure that the -mmax-constant_size option is in range.  */
       return IN_RANGE (value, 0, 4);
 
+    case OPT_mcpu_:
+    case OPT_patch_:
+      if (strcasecmp (arg, "RX610") == 0)
+	rx_cpu_type = RX610;
+      /* FIXME: Should we check for non-RX cpu names here ?  */
+      break;
+      
     default:
-      return true;
+      break;
     }
+
+  return true;
 }
 
 static int
Index: config/rx/rx.opt
===================================================================
--- config/rx/rx.opt	(revision 153851)
+++ config/rx/rx.opt	(working copy)
@@ -19,16 +19,34 @@
 ; <http://www.gnu.org/licenses/>.
 ;---------------------------------------------------
 
+m32bit-doubles
+Target RejectNegative Mask(32BIT_DOUBLES)
+Stores doubles in 32 bits.
+
 m64bit-doubles
-Target RejectNegative Mask(64BIT_DOUBLES)
-Store doubles in 64 bits.
+Target RejectNegative InverseMask(32BIT_DOUBLES)
+Store doubles in 64 bits.  This is the default.
 
-m32bit-doubles
-Target RejectNegative InverseMask(64BIT_DOUBLES)
-Stores doubles in 32 bits.  This is the default.
+fpu
+Target RejectNegative Mask(32BIT_DOUBLES) MaskExists
+Enable the use of RX FPU instructions.
 
+nofpu
+Target RejectNegative InverseMask(32BIT_DOUBLES) MaskExists
+Disable the use of RX FPU instructions.
+
 ;---------------------------------------------------
 
+mcpu=
+Target RejectNegative Joined Var(rx_cpu_name)
+Specify the target RX cpu type.
+
+patch=
+Target RejectNegative Joined Var(rx_cpu_name)
+Alias for -mcpu.
+
+;---------------------------------------------------
+
 mbig-endian-data
 Target RejectNegative Mask(BIG_ENDIAN_DATA)
 Data is stored in big-endian format.
@@ -72,3 +90,9 @@
 mint-register=
 Target RejectNegative Joined UInteger Var(rx_interrupt_registers) Init(0)
 Specifies the number of registers to reserve for interrupt handlers.
+
+;---------------------------------------------------
+
+msave-acc-in-interrupts
+Target Mask(SAVE_ACC_REGISTER)
+Specifies whether interrupt functions should save and restore the accumulator register.
Index: config/rx/t-rx
===================================================================
--- config/rx/t-rx	(revision 153851)
+++ config/rx/t-rx	(working copy)
@@ -20,9 +20,9 @@
 
 # Enable multilibs:
 
-MULTILIB_OPTIONS    = m64bit-doubles mbig-endian-data
-MULTILIB_DIRNAMES   = 64fp           big-endian-data
-MULTILIB_MATCHES    = m64bit-doubles=mieee
+MULTILIB_OPTIONS    = m32bit-doubles mbig-endian-data
+MULTILIB_DIRNAMES   = 32fp           big-endian-data
+MULTILIB_MATCHES    = m32bit-doubles=fpu
 MULTILIB_EXCEPTIONS =
 MULTILIB_EXTRA_OPTS = 
 
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 153851)
+++ doc/extend.texi	(working copy)
@@ -2270,13 +2270,6 @@
 You must use GAS and GLD from GNU binutils version 2.7 or later for
 this attribute to work correctly.
 
-@item exception
-@cindex exception handler functions on the RX processor
-Use this attribute on the RX to indicate that the specified function
-is an exception handler.  The compiler will generate function entry and
-exit sequences suitable for use in an exception handler when this
-attribute is present.
-
 @item exception_handler
 @cindex exception handler functions on the Blackfin processor
 Use this attribute on the Blackfin to indicate that the specified function
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 153851)
+++ doc/invoke.texi	(working copy)
@@ -784,14 +784,16 @@
 -msdata=@var{opt}  -mvxworks  -G @var{num}  -pthread}
 
 @emph{RX Options}
-@gccoptlist{-m64bit-doubles  -m32bit-doubles  -mieee  -mno-ieee@gol
+@gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
+-mcpu= -patch=@gol
 -mbig-endian-data -mlittle-endian-data @gol
 -msmall-data @gol
 -msim  -mno-sim@gol
 -mas100-syntax -mno-as100-syntax@gol
 -mrelax@gol
 -mmax-constant-size=@gol
--mint-register=}
+-mint-register=@gol
+-msave-acc-in-interrupts}
 
 @emph{S/390 and zSeries Options}
 @gccoptlist{-mtune=@var{cpu-type}  -march=@var{cpu-type} @gol
@@ -15408,16 +15410,37 @@
 @table @gcctabopt
 @item -m64bit-doubles
 @itemx -m32bit-doubles
+@itemx -fpu
+@itemx -nofpu
 @opindex m64bit-doubles
 @opindex m32bit-doubles
+@opindex fpu
+@opindex nofpu
 Make the @code{double} data type be 64-bits (@option{-m64bit-doubles})
 or 32-bits (@option{-m32bit-doubles}) in size.  The default is
-@option{-m32bit-doubles}.  @emph{Note} the RX's hardware floating
+@option{-m64bit-doubles}.  @emph{Note} the RX's hardware floating
 point instructions are only used for 32-bit floating point values, and
 then only if @option{-ffast-math} has been specified on the command
 line.  This is because the RX FPU instructions do not properly support
 denormal (or sub-normal) values.
 
+The options @option{-fpu} and @option{-nofpu} have been provided at
+the request of Rensas for compatibility with their toolchain.  The
+@option{-mfpu} option enables the use of RX FPU instructions by
+selecting 32-bit doubles and enabling unsafe math optimizations.  The
+@option{-mnofpu} option disables the use of RX FPU instructions, even
+if @option{-m32bit-doubles} is active and unsafe math optimizations
+have been enabled.
+
+@item -mcpu=@var{name}
+@itemx -patch=@var{name}
+@opindex -mcpu
+@opindex -patch
+Selects the type of RX CPU to be targeted.  Currently on two types are
+supported, the generic @var{RX600} and the specific @var{RX610}.  The
+only difference between them is that the @var{RX610} does not support
+the @code{MVTIPL} instruction.
+
 @item -mbig-endian-data
 @itemx -mlittle-endian-data
 @opindex mbig-endian-data
@@ -15493,6 +15516,15 @@
 @code{r12}.  A value of 3 reserves @code{r13}, @code{r12} and
 @code{r11}, and a value of 4 reserves @code{r13} through @code{r10}.
 A value of 0, the default, does not reserve any registers.
+
+@item -msave-acc-in-interrupts
+@opindex msave-acc-in-interrupts
+Specifies that interrupt handler functions should preserve the
+accumulator register.  This is only necessary if normal code might use
+the accumulator register, for example because it performs 64-bit
+multiplications.  The default is to ignore the accumulator as this
+makes the interrupt handlers faster.
+
 @end table
 
 @emph{Note:} The generic GCC command line @option{-ffixed-@var{reg}}
Index: testsuite/gcc.target/rx/interrupts.c
===================================================================
--- testsuite/gcc.target/rx/interrupts.c	(revision 153851)
+++ testsuite/gcc.target/rx/interrupts.c	(working copy)
@@ -1,10 +1,10 @@
 /* { dg-do compile } */
-/* { dg-options "-mint-register=3" } */
+/* { dg-options "-mint-register=3 -msave-acc-in-interrupts" } */
 
 /* Verify that the RX specific function attributes work.  */
 
+void fast_interrupt (void) __attribute__((__fast_interrupt__));
 void interrupt (void) __attribute__((__interrupt__));
-void exception (void) __attribute__((__exception__));
 int naked (int) __attribute__((__naked__));
 
 int flag = 0;
@@ -13,16 +13,16 @@
    by the -fixed-xxx gcc command line option.  Returns via RTFI.  */
 
 void
-interrupt (void)
+fast_interrupt (void)
 {
   flag = 1;
 }
 
-/* Exception handler.  Must preserve any register it uses, even
+/* Interrupt handler.  Must preserve any register it uses, even
    call clobbered ones.  Returns via RTE.  */
 
 void
-exception (void)
+interrupt (void)
 {
   switch (flag)
     {
Index: testsuite/gcc.target/rx/builtins.c
===================================================================
--- testsuite/gcc.target/rx/builtins.c	(revision 153851)
+++ testsuite/gcc.target/rx/builtins.c	(working copy)
@@ -17,7 +17,6 @@
    to correctly set the psw flags.  */
 
 int saturate_add         (int, int)      __attribute__((__noinline__));
-int subtract_with_borrow (int, int, int) __attribute__((__noinline__));
 int exchange             (int, int)      __attribute__((__noinline__));
 
 int
@@ -33,6 +32,13 @@
   return __builtin_rx_sat (arg1);
 }
 
+int
+exchange (int arg1, int arg2)
+{
+  arg1 = __builtin_rx_xchg (arg2);
+  return arg1;
+}
+
 long
 multiply_and_accumulate (long arg1, long arg2, long arg3)
 {
@@ -157,3 +163,9 @@
 {
   __builtin_rx_rmpa ();
 }
+
+void
+set_interrupts (void)
+{
+  __builtin_mvtipl (3);
+}


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