This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Committed: Update RX port
- From: Nick Clifton <nickc at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 03 Nov 2009 16:22:17 +0000
- Subject: 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);
+}