summaryrefslogtreecommitdiff
path: root/gcc/config/rx
diff options
context:
space:
mode:
authornickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>2009-11-03 16:25:29 +0000
committernickc <nickc@138bc75d-0d04-0410-961f-82ee72b054a4>2009-11-03 16:25:29 +0000
commit67e66e16928468050d4593ada24a16013fe3ca20 (patch)
treee2ed6b0428b652d000e627bca0a843d199164895 /gcc/config/rx
parent98f767b793f057165c877f91c46fe0bfd4ee7124 (diff)
downloadgcc-67e66e16928468050d4593ada24a16013fe3ca20.tar.gz
* 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.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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@153853 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rx')
-rw-r--r--gcc/config/rx/constraints.md2
-rw-r--r--gcc/config/rx/predicates.md18
-rw-r--r--gcc/config/rx/rx.c268
-rw-r--r--gcc/config/rx/rx.h59
-rw-r--r--gcc/config/rx/rx.md82
-rw-r--r--gcc/config/rx/rx.opt34
-rw-r--r--gcc/config/rx/t-rx6
7 files changed, 333 insertions, 136 deletions
diff --git a/gcc/config/rx/constraints.md b/gcc/config/rx/constraints.md
index f15b586afb5..52bf7df3621 100644
--- a/gcc/config/rx/constraints.md
+++ b/gcc/config/rx/constraints.md
@@ -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")
diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md
index 75cf8ebaed8..d7a363ebb88 100644
--- a/gcc/config/rx/predicates.md
+++ b/gcc/config/rx/predicates.md
@@ -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;
diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c
index cf2b098e83c..885f52581de 100644
--- a/gcc/config/rx/rx.c
+++ b/gcc/config/rx/rx.c
@@ -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 @@ rx_is_mode_dependent_addr (rtx addr)
}
}
-
/* 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 @@ rx_print_operand (FILE * file, rtx op, int letter)
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 @@ has_func_attr (const_tree decl, const char * func_attr)
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 @@ rx_set_current_function (tree fndecl)
{
/* 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 @@ rx_set_current_function (tree fndecl)
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 @@ rx_get_stack_layout (unsigned int * lowest,
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 @@ rx_emit_stack_pushm (rtx * operands)
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 @@ gen_rx_store_vector (unsigned int low, unsigned int high)
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 @@ rx_expand_prologue (void)
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 @@ rx_expand_prologue (void)
/* 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,7 +1233,57 @@ rx_expand_prologue (void)
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. */
@@ -1270,8 +1339,8 @@ rx_output_function_prologue (FILE * file,
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 @@ rx_expand_epilogue (bool is_sibcall)
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 @@ rx_expand_epilogue (bool is_sibcall)
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 @@ rx_expand_epilogue (bool is_sibcall)
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (total_size)));
- if (register_mask)
+ if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER)
{
- unsigned int reg;
+ 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)
+ {
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 @@ rx_expand_epilogue (bool is_sibcall)
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 @@ enum rx_builtin
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 @@ rx_init_builtins (void)
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 @@ rx_init_builtins (void)
}
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 @@ rx_expand_builtin_mvfc (tree t_arg, rtx target)
}
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 @@ rx_expand_builtin (tree exp,
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_destructor (rtx symbol, int priority)
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 @@ rx_handle_func_attribute (tree * node,
const struct attribute_spec rx_attribute_table[] =
{
/* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler. */
- { "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 },
+ { "interrupt", 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 @@ static bool
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 @@ rx_is_legitimate_constant (rtx x)
( 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 @@ rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value)
{
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 @@ rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value)
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
diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h
index a01e194910b..bb7cf7f1e3e 100644
--- a/gcc/config/rx/rx.h
+++ b/gcc/config/rx/rx.h
@@ -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) \
- builtin_define ("__RX_64BIT_DOUBLES__");\
- else \
+ if (TARGET_32BIT_DOUBLES) \
builtin_define ("__RX_32BIT_DOUBLES__");\
+ else \
+ builtin_define ("__RX_64BIT_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__
-#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
-#define LIBGCC2_DOUBLE_TYPE_SIZE 64
-#define LIBGCC2_HAS_DF_MODE 1
-#else
+#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
#endif
#define DEFAULT_SIGNED_CHAR 0
@@ -591,7 +610,6 @@ typedef unsigned int CUMULATIVE_ARGS;
#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 @@ extern int rx_float_compare_mode;
#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)
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index 165da4f41a1..360f6235558 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -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,13 +1687,24 @@
(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 ------------------------
@@ -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...
diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt
index 83e75bfba76..768d565b478 100644
--- a/gcc/config/rx/rx.opt
+++ b/gcc/config/rx/rx.opt
@@ -19,13 +19,31 @@
; <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.
;---------------------------------------------------
@@ -72,3 +90,9 @@ Maximum size in bytes of constant values allowed as operands.
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.
diff --git a/gcc/config/rx/t-rx b/gcc/config/rx/t-rx
index 39cda72af57..eb1ca48d3a3 100644
--- a/gcc/config/rx/t-rx
+++ b/gcc/config/rx/t-rx
@@ -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 =