summaryrefslogtreecommitdiff
path: root/gcc/config/rx
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-11 11:13:27 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-11 11:13:27 +0000
commitc41143fb1d63596ff2a0f6da741b4bae73b8be16 (patch)
treed70c0763693cfef7bc877f21e079986944261a5f /gcc/config/rx
parenteb0badc13724022c8828a55e516d0eecdc487cc3 (diff)
downloadgcc-c41143fb1d63596ff2a0f6da741b4bae73b8be16.tar.gz
2011-05-11 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 173647 using svnmerge git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@173652 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/rx')
-rw-r--r--gcc/config/rx/rx-opts.h30
-rw-r--r--gcc/config/rx/rx-protos.h21
-rw-r--r--gcc/config/rx/rx.c338
-rw-r--r--gcc/config/rx/rx.h48
-rw-r--r--gcc/config/rx/rx.md135
-rw-r--r--gcc/config/rx/rx.opt21
-rw-r--r--gcc/config/rx/t-rx4
7 files changed, 497 insertions, 100 deletions
diff --git a/gcc/config/rx/rx-opts.h b/gcc/config/rx/rx-opts.h
new file mode 100644
index 00000000000..a1d071be242
--- /dev/null
+++ b/gcc/config/rx/rx-opts.h
@@ -0,0 +1,30 @@
+/* GCC option-handling definitions for the Renesas RX processor.
+ Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef RX_OPTS_H
+#define RX_OPTS_H
+
+enum rx_cpu_types
+{
+ RX600,
+ RX610,
+ RX200
+};
+
+#endif
diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h
index a6ae416e6dc..72cb199ce30 100644
--- a/gcc/config/rx/rx-protos.h
+++ b/gcc/config/rx/rx-protos.h
@@ -21,25 +21,24 @@
#ifndef GCC_RX_PROTOS_H
#define GCC_RX_PROTOS_H
-/* A few abbreviations to make the prototypes shorter. */
-#define Mmode enum machine_mode
-#define Fargs CUMULATIVE_ARGS
-#define Rcode enum rtx_code
-
extern void rx_expand_prologue (void);
extern int rx_initial_elimination_offset (int, int);
#ifdef RTX_CODE
+extern int rx_adjust_insn_length (rtx, int);
+extern int rx_align_for_label (rtx, int);
extern void rx_emit_stack_popm (rtx *, bool);
extern void rx_emit_stack_pushm (rtx *);
extern void rx_expand_epilogue (bool);
extern char * rx_gen_move_template (rtx *, bool);
-extern bool rx_is_legitimate_constant (rtx);
-extern bool rx_is_restricted_memory_address (rtx, Mmode);
-extern void rx_notice_update_cc (rtx body, rtx insn);
-extern void rx_split_cbranch (Mmode, Rcode, rtx, rtx, rtx);
-extern Mmode rx_select_cc_mode (Rcode, rtx, rtx);
-extern bool rx_match_ccmode (rtx, Mmode);
+extern bool rx_legitimate_constant_p (enum machine_mode, rtx);
+extern bool rx_is_restricted_memory_address (rtx,
+ enum machine_mode);
+extern bool rx_match_ccmode (rtx, enum machine_mode);
+extern void rx_notice_update_cc (rtx, rtx);
+extern void rx_split_cbranch (enum machine_mode, enum rtx_code,
+ rtx, rtx, rtx);
+extern enum machine_mode rx_select_cc_mode (enum rtx_code, rtx, rtx);
#endif
#endif /* GCC_RX_PROTOS_H */
diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c
index 9356697a682..c8ff4393616 100644
--- a/gcc/config/rx/rx.c
+++ b/gcc/config/rx/rx.c
@@ -50,6 +50,7 @@
#include "target.h"
#include "target-def.h"
#include "langhooks.h"
+#include "opts.h"
static void rx_print_operand (FILE *, rtx, int);
@@ -61,8 +62,6 @@ static void rx_print_operand (FILE *, rtx, int);
static unsigned int flags_from_mode (enum machine_mode mode);
static unsigned int flags_from_code (enum rtx_code code);
-
-enum rx_cpu_types rx_cpu_type = RX600;
/* Return true if OP is a reference to an object in a small data area. */
@@ -79,13 +78,14 @@ rx_small_data_operand (rtx op)
}
static bool
-rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
+rx_is_legitimate_address (enum machine_mode mode, rtx x,
+ bool strict ATTRIBUTE_UNUSED)
{
if (RTX_OK_FOR_BASE (x, strict))
/* Register Indirect. */
return true;
- if (GET_MODE_SIZE (mode) == 4
+ if (GET_MODE_SIZE (mode) <= 4
&& (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC))
/* Pre-decrement Register Indirect or
Post-increment Register Indirect. */
@@ -116,7 +116,7 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
if (val < 0)
return false;
-
+
switch (GET_MODE_SIZE (mode))
{
default:
@@ -125,7 +125,7 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
case 1: factor = 1; break;
}
- if (val > (65535 * factor))
+ if (val >= (0x10000 * factor))
return false;
return (val % factor) == 0;
}
@@ -166,8 +166,6 @@ rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
bool
rx_is_restricted_memory_address (rtx mem, enum machine_mode mode)
{
- rtx base, index;
-
if (! rx_is_legitimate_address
(mode, mem, reload_in_progress || reload_completed))
return false;
@@ -183,11 +181,18 @@ rx_is_restricted_memory_address (rtx mem, enum machine_mode mode)
return false;
case PLUS:
- /* Only allow REG+INT addressing. */
- base = XEXP (mem, 0);
- index = XEXP (mem, 1);
+ {
+ rtx base, index;
+
+ /* Only allow REG+INT addressing. */
+ base = XEXP (mem, 0);
+ index = XEXP (mem, 1);
- return RX_REG_P (base) && CONST_INT_P (index);
+ if (! RX_REG_P (base) || ! CONST_INT_P (index))
+ return false;
+
+ return IN_RANGE (INTVAL (index), 0, (0x10000 * GET_MODE_SIZE (mode)) - 1);
+ }
case SYMBOL_REF:
/* Can happen when small data is being supported.
@@ -386,11 +391,14 @@ rx_assemble_integer (rtx x, unsigned int size, int is_aligned)
%L Print low part of a DImode register, integer or address.
%N Print the negation of the immediate value.
%Q If the operand is a MEM, then correctly generate
- register indirect or register relative addressing. */
+ register indirect or register relative addressing.
+ %R Like %Q but for zero-extending loads. */
static void
rx_print_operand (FILE * file, rtx op, int letter)
{
+ bool unsigned_load = false;
+
switch (letter)
{
case 'A':
@@ -450,6 +458,7 @@ rx_print_operand (FILE * file, rtx op, int letter)
else
{
unsigned int flags = flags_from_mode (mode);
+
switch (code)
{
case LT:
@@ -588,10 +597,15 @@ rx_print_operand (FILE * file, rtx op, int letter)
rx_print_integer (file, - INTVAL (op));
break;
+ case 'R':
+ gcc_assert (GET_MODE_SIZE (GET_MODE (op)) < 4);
+ unsigned_load = true;
+ /* Fall through. */
case 'Q':
if (MEM_P (op))
{
HOST_WIDE_INT offset;
+ rtx mem = op;
op = XEXP (op, 0);
@@ -626,22 +640,24 @@ rx_print_operand (FILE * file, rtx op, int letter)
rx_print_operand (file, op, 0);
fprintf (file, "].");
- switch (GET_MODE_SIZE (GET_MODE (op)))
+ switch (GET_MODE_SIZE (GET_MODE (mem)))
{
case 1:
- gcc_assert (offset < 65535 * 1);
- fprintf (file, "B");
+ gcc_assert (offset <= 65535 * 1);
+ fprintf (file, unsigned_load ? "UB" : "B");
break;
case 2:
gcc_assert (offset % 2 == 0);
- gcc_assert (offset < 65535 * 2);
- fprintf (file, "W");
+ gcc_assert (offset <= 65535 * 2);
+ fprintf (file, unsigned_load ? "UW" : "W");
break;
- default:
+ case 4:
gcc_assert (offset % 4 == 0);
- gcc_assert (offset < 65535 * 4);
+ gcc_assert (offset <= 65535 * 4);
fprintf (file, "L");
break;
+ default:
+ gcc_unreachable ();
}
break;
}
@@ -794,7 +810,7 @@ rx_round_up (unsigned int value, unsigned int alignment)
occupied by an argument of type TYPE and mode MODE. */
static unsigned int
-rx_function_arg_size (Mmode mode, const_tree type)
+rx_function_arg_size (enum machine_mode mode, const_tree type)
{
unsigned int num_bytes;
@@ -814,7 +830,8 @@ rx_function_arg_size (Mmode mode, const_tree type)
variable parameter list. */
static rtx
-rx_function_arg (Fargs * cum, Mmode mode, const_tree type, bool named)
+rx_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode,
+ const_tree type, bool named)
{
unsigned int next_reg;
unsigned int bytes_so_far = *cum;
@@ -851,14 +868,14 @@ rx_function_arg (Fargs * cum, Mmode mode, const_tree type, bool named)
}
static void
-rx_function_arg_advance (Fargs * cum, Mmode mode, const_tree type,
- bool named ATTRIBUTE_UNUSED)
+rx_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
*cum += rx_function_arg_size (mode, type);
}
static unsigned int
-rx_function_arg_boundary (Mmode mode ATTRIBUTE_UNUSED,
+rx_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
const_tree type ATTRIBUTE_UNUSED)
{
return 32;
@@ -1332,7 +1349,7 @@ gen_safe_add (rtx dest, rtx src, rtx val, bool is_frame_related)
insn = emit_insn (gen_addsi3 (dest, src, val));
else
{
- /* Wrap VAL in an UNSPEC so that rx_is_legitimate_constant
+ /* Wrap VAL in an UNSPEC so that rx_legitimate_constant_p
will not reject it. */
val = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, val), UNSPEC_CONST));
insn = emit_insn (gen_addsi3 (dest, src, val));
@@ -1550,7 +1567,7 @@ gen_rx_rtsd_vector (unsigned int adjust, unsigned int low, unsigned int high)
: plus_constant (stack_pointer_rtx,
i * UNITS_PER_WORD)));
- XVECEXP (vector, 0, count - 1) = gen_rtx_RETURN (VOIDmode);
+ XVECEXP (vector, 0, count - 1) = ret_rtx;
return vector;
}
@@ -2237,40 +2254,34 @@ rx_handle_func_attribute (tree * node,
/* Table of RX specific attributes. */
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 },
- { "naked", 0, 0, true, false, false, rx_handle_func_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+ /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity. */
+ { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
+ false },
+ { "interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
+ false },
+ { "naked", 0, 0, true, false, false, rx_handle_func_attribute,
+ false },
+ { NULL, 0, 0, false, false, false, NULL, false }
};
/* Extra processing for target specific command line options. */
static bool
-rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value)
+rx_handle_option (struct gcc_options *opts,
+ struct gcc_options *opts_set ATTRIBUTE_UNUSED,
+ const struct cl_decoded_option *decoded,
+ location_t loc)
{
+ size_t code = decoded->opt_index;
+ int value = decoded->value;
+
switch (code)
{
case OPT_mint_register_:
- switch (value)
- {
- case 4:
- fixed_regs[10] = call_used_regs [10] = 1;
- /* Fall through. */
- case 3:
- fixed_regs[11] = call_used_regs [11] = 1;
- /* Fall through. */
- case 2:
- fixed_regs[12] = call_used_regs [12] = 1;
- /* Fall through. */
- case 1:
- fixed_regs[13] = call_used_regs [13] = 1;
- /* Fall through. */
- case 0:
- return true;
- default:
- return false;
- }
+ /* Make sure that the -mint-register option is in range. Other
+ handling in rx_option_override. */
+ return value >= 0 && value <= 4;
break;
case OPT_mmax_constant_size_:
@@ -2278,20 +2289,13 @@ rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value)
return value >= 0 && value <= 4;
case OPT_mcpu_:
- if (strcasecmp (arg, "RX610") == 0)
- rx_cpu_type = RX610;
- else if (strcasecmp (arg, "RX200") == 0)
- {
- target_flags |= MASK_NO_USE_FPU;
- rx_cpu_type = RX200;
- }
- else if (strcasecmp (arg, "RX600") != 0)
- warning (0, "unrecognized argument '%s' to -mcpu= option", arg);
+ if ((enum rx_cpu_types) value == RX200)
+ opts->x_target_flags |= MASK_NO_USE_FPU;
break;
case OPT_fpu:
- if (rx_cpu_type == RX200)
- error ("the RX200 cpu does not have FPU hardware");
+ if (opts->x_rx_cpu_type == RX200)
+ error_at (loc, "the RX200 cpu does not have FPU hardware");
break;
default:
@@ -2331,11 +2335,56 @@ rx_override_options_after_change (void)
static void
rx_option_override (void)
{
+ unsigned int i;
+ cl_deferred_option *opt;
+ VEC(cl_deferred_option,heap) *vec
+ = (VEC(cl_deferred_option,heap) *) rx_deferred_options;
+
+ FOR_EACH_VEC_ELT (cl_deferred_option, vec, i, opt)
+ {
+ switch (opt->opt_index)
+ {
+ case OPT_mint_register_:
+ switch (opt->value)
+ {
+ case 4:
+ fixed_regs[10] = call_used_regs [10] = 1;
+ /* Fall through. */
+ case 3:
+ fixed_regs[11] = call_used_regs [11] = 1;
+ /* Fall through. */
+ case 2:
+ fixed_regs[12] = call_used_regs [12] = 1;
+ /* Fall through. */
+ case 1:
+ fixed_regs[13] = call_used_regs [13] = 1;
+ /* Fall through. */
+ case 0:
+ break;
+ default:
+ /* Error message already given because rx_handle_option
+ returned false. */
+ break;
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
/* This target defaults to strict volatile bitfields. */
if (flag_strict_volatile_bitfields < 0)
flag_strict_volatile_bitfields = 1;
rx_override_options_after_change ();
+
+ if (align_jumps == 0 && ! optimize_size)
+ align_jumps = 3;
+ if (align_loops == 0 && ! optimize_size)
+ align_loops = 3;
+ if (align_labels == 0 && ! optimize_size)
+ align_labels = 3;
}
/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
@@ -2399,7 +2448,7 @@ rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
operand on the RX. X is already known to satisfy CONSTANT_P. */
bool
-rx_is_legitimate_constant (rtx x)
+rx_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
switch (GET_CODE (x))
{
@@ -2428,8 +2477,7 @@ rx_is_legitimate_constant (rtx x)
default:
/* FIXME: Can this ever happen ? */
- abort ();
- return false;
+ gcc_unreachable ();
}
break;
@@ -2572,7 +2620,7 @@ rx_trampoline_init (rtx tramp, tree fndecl, rtx chain)
static int
rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in)
{
- return 2 + memory_move_secondary_cost (mode, regclass, in);
+ return (in ? 2 : 0) + memory_move_secondary_cost (mode, regclass, in);
}
/* Convert a CC_MODE to the set of flags that it represents. */
@@ -2726,8 +2774,161 @@ rx_match_ccmode (rtx insn, enum machine_mode cc_mode)
return true;
}
+
+int
+rx_align_for_label (rtx lab, int uses_threshold)
+{
+ /* This is a simple heuristic to guess when an alignment would not be useful
+ because the delay due to the inserted NOPs would be greater than the delay
+ due to the misaligned branch. If uses_threshold is zero then the alignment
+ is always useful. */
+ if (LABEL_NUSES (lab) < uses_threshold)
+ return 0;
+
+ return optimize_size ? 1 : 3;
+}
+
+static int
+rx_max_skip_for_label (rtx lab)
+{
+ int opsize;
+ rtx op;
+
+ if (lab == NULL_RTX)
+ return 0;
+ op = lab;
+ do
+ {
+ op = next_nonnote_nondebug_insn (op);
+ }
+ while (op && (LABEL_P (op)
+ || (INSN_P (op) && GET_CODE (PATTERN (op)) == USE)));
+ if (!op)
+ return 0;
+
+ opsize = get_attr_length (op);
+ if (opsize >= 0 && opsize < 8)
+ return opsize - 1;
+ return 0;
+}
+
+/* Compute the real length of the extending load-and-op instructions. */
+
+int
+rx_adjust_insn_length (rtx insn, int current_length)
+{
+ rtx extend, mem, offset;
+ bool zero;
+ int factor;
+
+ switch (INSN_CODE (insn))
+ {
+ default:
+ return current_length;
+
+ case CODE_FOR_plussi3_zero_extendhi:
+ case CODE_FOR_andsi3_zero_extendhi:
+ case CODE_FOR_iorsi3_zero_extendhi:
+ case CODE_FOR_xorsi3_zero_extendhi:
+ case CODE_FOR_divsi3_zero_extendhi:
+ case CODE_FOR_udivsi3_zero_extendhi:
+ case CODE_FOR_minussi3_zero_extendhi:
+ case CODE_FOR_smaxsi3_zero_extendhi:
+ case CODE_FOR_sminsi3_zero_extendhi:
+ case CODE_FOR_multsi3_zero_extendhi:
+ case CODE_FOR_comparesi3_zero_extendqi:
+ zero = true;
+ factor = 2;
+ break;
+
+ case CODE_FOR_plussi3_sign_extendhi:
+ case CODE_FOR_andsi3_sign_extendhi:
+ case CODE_FOR_iorsi3_sign_extendhi:
+ case CODE_FOR_xorsi3_sign_extendhi:
+ case CODE_FOR_divsi3_sign_extendhi:
+ case CODE_FOR_udivsi3_sign_extendhi:
+ case CODE_FOR_minussi3_sign_extendhi:
+ case CODE_FOR_smaxsi3_sign_extendhi:
+ case CODE_FOR_sminsi3_sign_extendhi:
+ case CODE_FOR_multsi3_sign_extendhi:
+ case CODE_FOR_comparesi3_zero_extendhi:
+ zero = false;
+ factor = 2;
+ break;
+
+ case CODE_FOR_plussi3_zero_extendqi:
+ case CODE_FOR_andsi3_zero_extendqi:
+ case CODE_FOR_iorsi3_zero_extendqi:
+ case CODE_FOR_xorsi3_zero_extendqi:
+ case CODE_FOR_divsi3_zero_extendqi:
+ case CODE_FOR_udivsi3_zero_extendqi:
+ case CODE_FOR_minussi3_zero_extendqi:
+ case CODE_FOR_smaxsi3_zero_extendqi:
+ case CODE_FOR_sminsi3_zero_extendqi:
+ case CODE_FOR_multsi3_zero_extendqi:
+ case CODE_FOR_comparesi3_sign_extendqi:
+ zero = true;
+ factor = 1;
+ break;
+
+ case CODE_FOR_plussi3_sign_extendqi:
+ case CODE_FOR_andsi3_sign_extendqi:
+ case CODE_FOR_iorsi3_sign_extendqi:
+ case CODE_FOR_xorsi3_sign_extendqi:
+ case CODE_FOR_divsi3_sign_extendqi:
+ case CODE_FOR_udivsi3_sign_extendqi:
+ case CODE_FOR_minussi3_sign_extendqi:
+ case CODE_FOR_smaxsi3_sign_extendqi:
+ case CODE_FOR_sminsi3_sign_extendqi:
+ case CODE_FOR_multsi3_sign_extendqi:
+ case CODE_FOR_comparesi3_sign_extendhi:
+ zero = false;
+ factor = 1;
+ break;
+ }
+
+ /* We are expecting: (SET (REG) (<OP> (REG) (<EXTEND> (MEM)))). */
+ extend = single_set (insn);
+ gcc_assert (extend != NULL_RTX);
+
+ extend = SET_SRC (extend);
+ if (GET_CODE (XEXP (extend, 0)) == ZERO_EXTEND
+ || GET_CODE (XEXP (extend, 0)) == SIGN_EXTEND)
+ extend = XEXP (extend, 0);
+ else
+ extend = XEXP (extend, 1);
+
+ gcc_assert ((zero && (GET_CODE (extend) == ZERO_EXTEND))
+ || (! zero && (GET_CODE (extend) == SIGN_EXTEND)));
+
+ mem = XEXP (extend, 0);
+ gcc_checking_assert (MEM_P (mem));
+ if (REG_P (XEXP (mem, 0)))
+ return (zero && factor == 1) ? 2 : 3;
+
+ /* We are expecting: (MEM (PLUS (REG) (CONST_INT))). */
+ gcc_checking_assert (GET_CODE (XEXP (mem, 0)) == PLUS);
+ gcc_checking_assert (REG_P (XEXP (XEXP (mem, 0), 0)));
+
+ offset = XEXP (XEXP (mem, 0), 1);
+ gcc_checking_assert (GET_CODE (offset) == CONST_INT);
+
+ if (IN_RANGE (INTVAL (offset), 0, 255 * factor))
+ return (zero && factor == 1) ? 3 : 4;
+
+ return (zero && factor == 1) ? 4 : 5;
+}
+#undef TARGET_ASM_JUMP_ALIGN_MAX_SKIP
+#define TARGET_ASM_JUMP_ALIGN_MAX_SKIP rx_max_skip_for_label
+#undef TARGET_ASM_LOOP_ALIGN_MAX_SKIP
+#define TARGET_ASM_LOOP_ALIGN_MAX_SKIP rx_max_skip_for_label
+#undef TARGET_LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
+#define TARGET_LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP rx_max_skip_for_label
+#undef TARGET_ASM_LABEL_ALIGN_MAX_SKIP
+#define TARGET_ASM_LABEL_ALIGN_MAX_SKIP rx_max_skip_for_label
+
#undef TARGET_FUNCTION_VALUE
#define TARGET_FUNCTION_VALUE rx_function_value
@@ -2860,6 +3061,9 @@ rx_match_ccmode (rtx insn, enum machine_mode cc_mode)
#undef TARGET_FLAGS_REGNUM
#define TARGET_FLAGS_REGNUM CC_REG
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P rx_legitimate_constant_p
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* #include "gt-rx.h" */
diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h
index e3966ed173d..1780867dcbf 100644
--- a/gcc/config/rx/rx.h
+++ b/gcc/config/rx/rx.h
@@ -52,15 +52,6 @@
} \
while (0)
-enum rx_cpu_types
-{
- RX600,
- RX610,
- RX200
-};
-
-extern enum rx_cpu_types rx_cpu_type;
-
#undef CC1_SPEC
#define CC1_SPEC "\
%{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}} \
@@ -153,8 +144,6 @@ extern enum rx_cpu_types rx_cpu_type;
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
-#define LEGITIMATE_CONSTANT_P(X) rx_is_legitimate_constant (X)
-
#define HAVE_PRE_DECCREMENT 1
#define HAVE_POST_INCREMENT 1
@@ -187,11 +176,6 @@ enum reg_class
{ 0x0000ffff } /* All registers. */ \
}
-#define IRA_COVER_CLASSES \
- { \
- GR_REGS, LIM_REG_CLASSES \
- }
-
#define SMALL_REGISTER_CLASSES 0
#define N_REG_CLASSES (int) LIM_REG_CLASSES
#define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \
@@ -413,6 +397,31 @@ typedef unsigned int CUMULATIVE_ARGS;
#undef USER_LABEL_PREFIX
#define USER_LABEL_PREFIX "_"
+/* Compute the alignment needed for label X in various situations.
+ If the user has specified an alignment then honour that, otherwise
+ use rx_align_for_label. */
+#define JUMP_ALIGN(x) (align_jumps ? align_jumps : rx_align_for_label (x, 0))
+#define LABEL_ALIGN(x) (align_labels ? align_labels : rx_align_for_label (x, 3))
+#define LOOP_ALIGN(x) (align_loops ? align_loops : rx_align_for_label (x, 2))
+#define LABEL_ALIGN_AFTER_BARRIER(x) rx_align_for_label (x, 0)
+
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM, LOG, MAX_SKIP) \
+ do \
+ { \
+ if ((LOG) == 0 || (MAX_SKIP) == 0) \
+ break; \
+ if (TARGET_AS100_SYNTAX) \
+ { \
+ if ((LOG) >= 2) \
+ fprintf (STREAM, "\t.ALIGN 4\t; %d alignment actually requested\n", 1 << (LOG)); \
+ else \
+ fprintf (STREAM, "\t.ALIGN 2\n"); \
+ } \
+ else \
+ fprintf (STREAM, "\t.balign %d,3,%d\n", 1 << (LOG), (MAX_SKIP)); \
+ } \
+ while (0)
+
#define ASM_OUTPUT_ALIGN(STREAM, LOG) \
do \
{ \
@@ -616,3 +625,10 @@ typedef unsigned int CUMULATIVE_ARGS;
#define REGISTER_MOVE_COST(MODE,FROM,TO) 2
#define SELECT_CC_MODE(OP,X,Y) rx_select_cc_mode(OP, X, Y)
+
+#define ADJUST_INSN_LENGTH(INSN,LENGTH) \
+ do \
+ { \
+ (LENGTH) = rx_adjust_insn_length ((INSN), (LENGTH)); \
+ } \
+ while (0)
diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md
index cd5b571dd3a..824d246cb84 100644
--- a/gcc/config/rx/rx.md
+++ b/gcc/config/rx/rx.md
@@ -556,7 +556,7 @@
if (MEM_P (operand0) && MEM_P (operand1))
operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1);
if (CONST_INT_P (operand1)
- && ! rx_is_legitimate_constant (operand1))
+ && ! rx_legitimate_constant_p (<register_modes:MODE>mode, operand1))
FAIL;
}
)
@@ -1545,6 +1545,139 @@
(set_attr "length" "3,4,5,6,7,6")]
)
+;; A set of peepholes to catch extending loads followed by arithmetic operations.
+;; We use iterators where possible to reduce the amount of typing and hence the
+;; possibilities for typos.
+
+(define_code_iterator extend_types [(zero_extend "") (sign_extend "")])
+(define_code_attr letter [(zero_extend "R") (sign_extend "Q")])
+
+(define_code_iterator memex_commutative [(plus "") (and "") (ior "") (xor "")])
+(define_code_iterator memex_noncomm [(div "") (udiv "") (minus "")])
+(define_code_iterator memex_nocc [(smax "") (smin "") (mult "")])
+
+(define_code_attr op [(plus "add") (and "and") (div "div") (udiv "divu") (smax "max") (smin "min") (mult "mul") (ior "or") (minus "sub") (xor "xor")])
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (parallel [(set (match_operand:SI 2 "register_operand")
+ (memex_commutative:SI (match_dup 0)
+ (match_dup 2)))
+ (clobber (reg:CC CC_REG))])]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(parallel [(set:SI (match_dup 2)
+ (memex_commutative:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (parallel [(set (match_operand:SI 2 "register_operand")
+ (memex_commutative:SI (match_dup 2)
+ (match_dup 0)))
+ (clobber (reg:CC CC_REG))])]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(parallel [(set:SI (match_dup 2)
+ (memex_commutative:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (parallel [(set (match_operand:SI 2 "register_operand")
+ (memex_noncomm:SI (match_dup 2)
+ (match_dup 0)))
+ (clobber (reg:CC CC_REG))])]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(parallel [(set:SI (match_dup 2)
+ (memex_noncomm:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))
+ (clobber (reg:CC CC_REG))])]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (set (match_operand:SI 2 "register_operand")
+ (memex_nocc:SI (match_dup 0)
+ (match_dup 2)))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(set:SI (match_dup 2)
+ (memex_nocc:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))]
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (set (match_operand:SI 2 "register_operand")
+ (memex_nocc:SI (match_dup 2)
+ (match_dup 0)))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(set:SI (match_dup 2)
+ (memex_nocc:SI (match_dup 2)
+ (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "<memex_commutative:code>si3_<extend_types:code><small_int_modes:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (memex_commutative:SI (match_operand:SI 1 "register_operand" "%0")
+ (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "<memex_commutative:op>\t%<extend_types:letter>2, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_insn "<memex_noncomm:code>si3_<extend_types:code><small_int_modes:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (memex_noncomm:SI (match_operand:SI 1 "register_operand" "0")
+ (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "<memex_noncomm:op>\t%<extend_types:letter>2, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_insn "<memex_nocc:code>si3_<extend_types:code><small_int_modes:mode>"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (memex_nocc:SI (match_operand:SI 1 "register_operand" "%0")
+ (extend_types:SI (match_operand:small_int_modes 2 "rx_restricted_mem_operand" "Q"))))]
+ ""
+ "<memex_nocc:op>\t%<extend_types:letter>2, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
+(define_peephole2
+ [(set (match_operand:SI 0 "register_operand")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand")))
+ (set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand")
+ (match_dup 0)))]
+ "peep2_regno_dead_p (2, REGNO (operands[0]))"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_dup 2)
+ (extend_types:SI (match_dup 1))))]
+)
+
+(define_insn "comparesi3_<extend_types:code><small_int_modes:mode>"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 0 "register_operand" "=r")
+ (extend_types:SI (match_operand:small_int_modes 1 "rx_restricted_mem_operand" "Q"))))]
+ ""
+ "cmp\t%<extend_types:letter>1, %0"
+ [(set_attr "timings" "33")
+ (set_attr "length" "5")] ;; This length is corrected in rx_adjust_insn_length
+)
+
;; Floating Point Instructions
(define_insn "addsf3"
diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt
index 35143dd0f55..4a84effdcdb 100644
--- a/gcc/config/rx/rx.opt
+++ b/gcc/config/rx/rx.opt
@@ -1,5 +1,5 @@
; Command line options for the Renesas RX port of GCC.
-; Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+; Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
; Contributed by Red Hat.
;
; This file is part of GCC.
@@ -19,6 +19,9 @@
; <http://www.gnu.org/licenses/>.
;---------------------------------------------------
+HeaderInclude
+config/rx/rx-opts.h
+
; The default is -fpu -m32bit-doubles.
m64bit-doubles
@@ -43,9 +46,21 @@ Enable the use of RX FPU instructions. This is the default.
;---------------------------------------------------
mcpu=
-Target RejectNegative Joined Var(rx_cpu_name) Report
+Target RejectNegative Joined Var(rx_cpu_type) Report ToLower Enum(rx_cpu_types) Init(RX600)
Specify the target RX cpu type.
+Enum
+Name(rx_cpu_types) Type(enum rx_cpu_types)
+
+EnumValue
+Enum(rx_cpu_types) String(rx610) Value(RX610)
+
+EnumValue
+Enum(rx_cpu_types) String(rx200) Value(RX200)
+
+EnumValue
+Enum(rx_cpu_types) String(rx600) Value(RX600)
+
;---------------------------------------------------
mbig-endian-data
@@ -89,7 +104,7 @@ Maximum size in bytes of constant values allowed as operands.
;---------------------------------------------------
mint-register=
-Target RejectNegative Joined UInteger Var(rx_interrupt_registers) Init(0)
+Target RejectNegative Joined UInteger Var(rx_deferred_options) Defer
Specifies the number of registers to reserve for interrupt handlers.
;---------------------------------------------------
diff --git a/gcc/config/rx/t-rx b/gcc/config/rx/t-rx
index 7990bcfaa47..38893143981 100644
--- a/gcc/config/rx/t-rx
+++ b/gcc/config/rx/t-rx
@@ -1,5 +1,5 @@
# Makefile fragment for building GCC for the Renesas RX target.
-# Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+# Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
# Contributed by Red Hat.
#
# This file is part of GCC.
@@ -23,7 +23,7 @@
MULTILIB_OPTIONS = m64bit-doubles nofpu mbig-endian-data
MULTILIB_DIRNAMES = 64-bit-double no-fpu-libs big-endian-data
-MULTILIB_MATCHES = nofpu=mnofpu nofpu=mcpu?rx200 nofpu=mcpu?RX200
+MULTILIB_MATCHES = nofpu=mnofpu nofpu=mcpu?rx200
MULTILIB_EXCEPTIONS =
MULTILIB_EXTRA_OPTS =