diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-11 11:13:27 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-05-11 11:13:27 +0000 |
commit | c41143fb1d63596ff2a0f6da741b4bae73b8be16 (patch) | |
tree | d70c0763693cfef7bc877f21e079986944261a5f /gcc/config/rx | |
parent | eb0badc13724022c8828a55e516d0eecdc487cc3 (diff) | |
download | gcc-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.h | 30 | ||||
-rw-r--r-- | gcc/config/rx/rx-protos.h | 21 | ||||
-rw-r--r-- | gcc/config/rx/rx.c | 338 | ||||
-rw-r--r-- | gcc/config/rx/rx.h | 48 | ||||
-rw-r--r-- | gcc/config/rx/rx.md | 135 | ||||
-rw-r--r-- | gcc/config/rx/rx.opt | 21 | ||||
-rw-r--r-- | gcc/config/rx/t-rx | 4 |
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 = |