diff options
Diffstat (limited to 'gcc/config/rx')
-rw-r--r-- | gcc/config/rx/constraints.md | 22 | ||||
-rw-r--r-- | gcc/config/rx/rx-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/rx/rx.c | 246 | ||||
-rw-r--r-- | gcc/config/rx/rx.h | 32 | ||||
-rw-r--r-- | gcc/config/rx/rx.md | 52 | ||||
-rw-r--r-- | gcc/config/rx/rx.opt | 6 | ||||
-rw-r--r-- | gcc/config/rx/t-rx | 4 |
7 files changed, 329 insertions, 34 deletions
diff --git a/gcc/config/rx/constraints.md b/gcc/config/rx/constraints.md index 9f7dc9ff816..7822914acbb 100644 --- a/gcc/config/rx/constraints.md +++ b/gcc/config/rx/constraints.md @@ -1,5 +1,5 @@ ;; Constraint definitions for Renesas RX. -;; 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. @@ -86,3 +86,23 @@ ) ) ) + +(define_constraint "Rpid" + "A MEM to a PID variable" + (and (match_code "mem") + (and (match_code "plus" "0") + (and (match_code "reg,subreg" "00") + (match_code "unspec" "01") + ) + ) + ) +) + +(define_constraint "Rpda" + "An address to a PID variable" + (and (match_code "plus" "") + (and (match_code "reg,subreg" "0") + (match_code "unspec" "1") + ) + ) +) diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h index 56d69316905..365bf66babd 100644 --- a/gcc/config/rx/rx-protos.h +++ b/gcc/config/rx/rx-protos.h @@ -35,6 +35,7 @@ extern bool rx_is_legitimate_constant (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 rtx rx_maybe_pidify_operand (rtx, int); extern void rx_notice_update_cc (rtx, rtx); extern void rx_split_cbranch (enum machine_mode, enum rtx_code, rtx, rtx, rtx); diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c index dcf693a6337..6ff9418c9d8 100644 --- a/gcc/config/rx/rx.c +++ b/gcc/config/rx/rx.c @@ -51,7 +51,43 @@ #include "target-def.h" #include "langhooks.h" #include "opts.h" + +static unsigned int rx_gp_base_regnum_val = INVALID_REGNUM; +static unsigned int rx_pid_base_regnum_val = INVALID_REGNUM; +static unsigned int rx_num_interrupt_regs; +static unsigned int +rx_gp_base_regnum (void) +{ + if (rx_gp_base_regnum_val == INVALID_REGNUM) + gcc_unreachable (); + return rx_gp_base_regnum_val; +} + +static unsigned int +rx_pid_base_regnum (void) +{ + if (rx_pid_base_regnum_val == INVALID_REGNUM) + gcc_unreachable (); + return rx_pid_base_regnum_val; +} + +/* Find a SYMBOL_REF in a "standard" MEM address and return its decl. */ + +static tree +rx_decl_for_addr (rtx op) +{ + if (GET_CODE (op) == MEM) + op = XEXP (op, 0); + if (GET_CODE (op) == CONST) + op = XEXP (op, 0); + while (GET_CODE (op) == PLUS) + op = XEXP (op, 0); + if (GET_CODE (op) == SYMBOL_REF) + return SYMBOL_REF_DECL (op); + return NULL_TREE; +} + static void rx_print_operand (FILE *, rtx, int); #define CC_FLAG_S (1 << 0) @@ -63,6 +99,67 @@ 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); +/* Return true if OP is a reference to an object in a PID data area. */ + +enum pid_type +{ + PID_NOT_PID = 0, /* The object is not in the PID data area. */ + PID_ENCODED, /* The object is in the PID data area. */ + PID_UNENCODED /* The object will be placed in the PID data area, but it has not been placed there yet. */ +}; + +static enum pid_type +rx_pid_data_operand (rtx op) +{ + tree op_decl; + + if (!TARGET_PID) + return PID_NOT_PID; + + if (GET_CODE (op) == PLUS + && GET_CODE (XEXP (op, 0)) == REG + && GET_CODE (XEXP (op, 1)) == CONST + && GET_CODE (XEXP (XEXP (op, 1), 0)) == UNSPEC) + return PID_ENCODED; + + op_decl = rx_decl_for_addr (op); + + if (op_decl) + { + if (TREE_READONLY (op_decl)) + return PID_UNENCODED; + } + else + { + /* Sigh, some special cases. */ + if (GET_CODE (op) == SYMBOL_REF + || GET_CODE (op) == LABEL_REF) + return PID_UNENCODED; + } + + return PID_NOT_PID; +} + +static rtx +rx_legitimize_address (rtx x, + rtx oldx ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + if (rx_pid_data_operand (x) == PID_UNENCODED) + { + rtx rv = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), x); + return rv; + } + + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 0)) == PLUS + && REG_P (XEXP (XEXP (x, 0), 0)) + && REG_P (XEXP (x, 1))) + return force_reg (SImode, x); + + return x; +} + /* Return true if OP is a reference to an object in a small data area. */ static bool @@ -93,6 +190,16 @@ rx_is_legitimate_address (enum machine_mode mode, rtx x, Post-increment Register Indirect. */ return RTX_OK_FOR_BASE (XEXP (x, 0), strict); + switch (rx_pid_data_operand (x)) + { + case PID_UNENCODED: + return false; + case PID_ENCODED: + return true; + default: + break; + } + if (GET_CODE (x) == PLUS) { rtx arg1 = XEXP (x, 0); @@ -337,15 +444,17 @@ rx_print_operand_address (FILE * file, rtx addr) { addr = XEXP (addr, 0); gcc_assert (XINT (addr, 1) == UNSPEC_CONST); - - addr = XVECEXP (addr, 0, 0); + + /* FIXME: Putting this case label here is an appalling abuse of the C language. */ + case UNSPEC: + addr = XVECEXP (addr, 0, 0); gcc_assert (CONST_INT_P (addr)); } /* Fall through. */ case LABEL_REF: case SYMBOL_REF: fprintf (file, "#"); - + /* Fall through. */ default: output_addr_const (file, addr); break; @@ -389,9 +498,11 @@ rx_assemble_integer (rtx x, unsigned int size, int is_aligned) %B Print an integer comparison name. %C Print a control register name. %F Print a condition code flag name. + %G Register used for small-data-area addressing %H Print high part of a DImode register, integer or address. %L Print low part of a DImode register, integer or address. %N Print the negation of the immediate value. + %P Register used for PID addressing %Q If the operand is a MEM, then correctly generate register indirect or register relative addressing. %R Like %Q but for zero-extending loads. */ @@ -400,6 +511,16 @@ static void rx_print_operand (FILE * file, rtx op, int letter) { bool unsigned_load = false; + bool print_hash = true; + + if (letter == 'A' + && ((GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == UNSPEC) + || GET_CODE (op) == UNSPEC)) + { + print_hash = false; + letter = 0; + } switch (letter) { @@ -538,6 +659,10 @@ rx_print_operand (FILE * file, rtx op, int letter) } break; + case 'G': + fprintf (file, "%s", reg_names [rx_gp_base_regnum ()]); + break; + case 'H': switch (GET_CODE (op)) { @@ -599,6 +724,10 @@ rx_print_operand (FILE * file, rtx op, int letter) rx_print_integer (file, - INTVAL (op)); break; + case 'P': + fprintf (file, "%s", reg_names [rx_pid_base_regnum ()]); + break; + case 'R': gcc_assert (GET_MODE_SIZE (GET_MODE (op)) < 4); unsigned_load = true; @@ -667,6 +796,24 @@ rx_print_operand (FILE * file, rtx op, int letter) /* Fall through. */ default: + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == UNSPEC) + op = XEXP (op, 0); + else if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == PLUS + && GET_CODE (XEXP (XEXP (op, 0), 0)) == UNSPEC + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT) + { + if (print_hash) + fprintf (file, "#"); + fprintf (file, "("); + rx_print_operand (file, XEXP (XEXP (op, 0), 0), 'A'); + fprintf (file, " + "); + output_addr_const (file, XEXP (XEXP (op, 0), 1)); + fprintf (file, ")"); + return; + } + switch (GET_CODE (op)) { case MULT: @@ -721,20 +868,52 @@ rx_print_operand (FILE * file, rtx op, int letter) REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_SINGLE (rv, val); - fprintf (file, TARGET_AS100_SYNTAX ? "#0%lxH" : "#0x%lx", val); + if (print_hash) + fprintf (file, "#"); + fprintf (file, TARGET_AS100_SYNTAX ? "0%lxH" : "0x%lx", val); break; } case CONST_INT: - fprintf (file, "#"); + if (print_hash) + fprintf (file, "#"); rx_print_integer (file, INTVAL (op)); break; - case SYMBOL_REF: + case UNSPEC: + switch (XINT (op, 1)) + { + case UNSPEC_PID_ADDR: + { + rtx sym, add; + + if (print_hash) + fprintf (file, "#"); + sym = XVECEXP (op, 0, 0); + add = NULL_RTX; + fprintf (file, "("); + if (GET_CODE (sym) == PLUS) + { + add = XEXP (sym, 1); + sym = XEXP (sym, 0); + } + output_addr_const (file, sym); + if (add != NULL_RTX) + { + fprintf (file, "+"); + output_addr_const (file, add); + } + fprintf (file, "-__pid_base"); + fprintf (file, ")"); + return; + } + } + /* Fall through */ + case CONST: + case SYMBOL_REF: case LABEL_REF: case CODE_LABEL: - case UNSPEC: rx_print_operand_address (file, op); break; @@ -745,6 +924,29 @@ rx_print_operand (FILE * file, rtx op, int letter) } } +/* Maybe convert an operand into its PID format. */ + +rtx +rx_maybe_pidify_operand (rtx op, int copy_to_reg) +{ + if (rx_pid_data_operand (op) == PID_UNENCODED) + { + if (GET_CODE (op) == MEM) + { + rtx a = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), XEXP (op, 0)); + op = replace_equiv_address (op, a); + } + else + { + op = gen_pid_addr (gen_rtx_REG (SImode, rx_pid_base_regnum ()), op); + } + + if (copy_to_reg) + op = copy_to_mode_reg (GET_MODE (op), op); + } + return op; +} + /* Returns an assembler template for a move instruction. */ char * @@ -784,13 +986,15 @@ rx_gen_move_template (rtx * operands, bool is_movu) gcc_unreachable (); } - if (MEM_P (src) && rx_small_data_operand (XEXP (src, 0))) - src_template = "%%gp(%A1)[r13]"; + if (MEM_P (src) && rx_pid_data_operand (XEXP (src, 0)) == PID_UNENCODED) + src_template = "(%A1-__pid_base)[%P1]"; + else if (MEM_P (src) && rx_small_data_operand (XEXP (src, 0))) + src_template = "%%gp(%A1)[%G1]"; else src_template = "%1"; if (MEM_P (dest) && rx_small_data_operand (XEXP (dest, 0))) - dst_template = "%%gp(%A0)[r13]"; + dst_template = "%%gp(%A0)[%G0]"; else dst_template = "%0"; @@ -996,8 +1200,21 @@ rx_conditional_register_usage (void) { static bool using_fixed_regs = false; + if (TARGET_PID) + { + rx_pid_base_regnum_val = GP_BASE_REGNUM - rx_num_interrupt_regs; + fixed_regs[rx_pid_base_regnum_val] = call_used_regs [rx_pid_base_regnum_val] = 1; + } + if (rx_small_data_limit > 0) - fixed_regs[GP_BASE_REGNUM] = call_used_regs [GP_BASE_REGNUM] = 1; + { + if (TARGET_PID) + rx_gp_base_regnum_val = rx_pid_base_regnum_val - 1; + else + rx_gp_base_regnum_val = GP_BASE_REGNUM - rx_num_interrupt_regs; + + fixed_regs[rx_gp_base_regnum_val] = call_used_regs [rx_gp_base_regnum_val] = 1; + } if (use_fixed_regs != using_fixed_regs) { @@ -2338,8 +2555,10 @@ rx_option_override (void) fixed_regs[13] = call_used_regs [13] = 1; /* Fall through. */ case 0: + rx_num_interrupt_regs = opt->value; break; default: + rx_num_interrupt_regs = 0; /* Error message already given because rx_handle_option returned false. */ break; @@ -2444,7 +2663,7 @@ rx_is_legitimate_constant (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) return true; case UNSPEC: - return XINT (x, 1) == UNSPEC_CONST; + return XINT (x, 1) == UNSPEC_CONST || XINT (x, 1) == UNSPEC_PID_ADDR; default: /* FIXME: Can this ever happen ? */ @@ -3031,6 +3250,9 @@ rx_adjust_insn_length (rtx insn, int current_length) #undef TARGET_LEGITIMATE_CONSTANT_P #define TARGET_LEGITIMATE_CONSTANT_P rx_is_legitimate_constant +#undef TARGET_LEGITIMIZE_ADDRESS +#define TARGET_LEGITIMIZE_ADDRESS rx_legitimize_address + 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 67e8ce1c577..10b16bda261 100644 --- a/gcc/config/rx/rx.h +++ b/gcc/config/rx/rx.h @@ -63,6 +63,13 @@ #undef ENDFILE_SPEC #define ENDFILE_SPEC "crtend.o%s crtn.o%s" +#undef CPP_SPEC +#define CPP_SPEC "\ +%{mpid:-D_RX_PID=1} \ +%{mint-register=*:-D_RX_INT_REGISTERS=%*} \ +%{msmall-data-limit*:-D_RX_SMALL_DATA} \ +" + #undef ASM_SPEC #define ASM_SPEC "\ %{mbig-endian-data:-mbig-endian-data} \ @@ -70,6 +77,8 @@ %{!m64bit-doubles:-m32bit-doubles} \ %{msmall-data-limit*:-msmall-data-limit} \ %{mrelax:-relax} \ +%{mpid} \ +%{mint-register=*} \ " #undef LIB_SPEC @@ -200,14 +209,17 @@ enum reg_class #define STRUCT_VAL_REGNUM 15 #define CC_REGNUM 16 -/* This is the register which is used to hold the address of the start - of the small data area, if that feature is being used. Note - this - register must not be call_used because otherwise library functions - that are compiled without small data support might clobber it. +/* This is the register which will probably be used to hold the address of + the start of the small data area, if -msmall-data-limit is being used, + or the address of the constant data area if -mpid is being used. If both + features are in use then two consecutive registers will be used. - FIXME: The function gcc/config/rx/rx.c:rx_gen_move_template() has a - built in copy of this register's name, rather than constructing the - name from this #define. */ + Note - these registers must not be call_used because otherwise library + functions that are compiled without -msmall-data-limit/-mpid support + might clobber them. + + Note that the actual values used depends on other options; use + rx_gp_base_regnum() and rx_pid_base_regnum() instead. */ #define GP_BASE_REGNUM 13 #define ELIMINABLE_REGS \ @@ -444,13 +456,15 @@ typedef unsigned int CUMULATIVE_ARGS; VALUE) /* This is how to output an element of a case-vector that is relative. - Note: The local label referenced by the "3b" below is emitted by + Note: The local label referenced by the "1b" below is emitted by the tablejump insn. */ #define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ fprintf (FILE, TARGET_AS100_SYNTAX \ ? "\t.LWORD L%d - ?-\n" : "\t.long .L%d - 1b\n", VALUE) +#define CASE_VECTOR_PC_RELATIVE (TARGET_PID) + #define ASM_OUTPUT_SIZE_DIRECTIVE(STREAM, NAME, SIZE) \ do \ { \ @@ -595,7 +609,7 @@ typedef unsigned int CUMULATIVE_ARGS; /* For PIC put jump tables into the text section so that the offsets that they contain are always computed between two same-section symbols. */ -#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) +#define JUMP_TABLES_IN_TEXT_SECTION (TARGET_PID || flag_pic) /* This is a version of REG_P that also returns TRUE for SUBREGs. */ #define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG) diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md index 5ce1c3976f3..708f9444ca9 100644 --- a/gcc/config/rx/rx.md +++ b/gcc/config/rx/rx.md @@ -73,6 +73,8 @@ (UNSPEC_BUILTIN_SAT 49) (UNSPEC_BUILTIN_SETPSW 50) (UNSPEC_BUILTIN_WAIT 51) + + (UNSPEC_PID_ADDR 52) ] ) @@ -330,9 +332,9 @@ (match_operand:SI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "" - { return flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0" - : "\n1:\tbra\t%0") - : "\n1:jmp\t%0"; + { return TARGET_PID ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0" + : "\n1:\tbra\t%0") + : "\n1:jmp\t%0"; } [(set_attr "timings" "33") (set_attr "length" "2")] @@ -556,8 +558,18 @@ (match_operand:register_modes 1 "general_operand"))] "" { - if (MEM_P (operand0) && MEM_P (operand1)) - operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operand1); + if (MEM_P (operands[0]) && MEM_P (operands[1])) + operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]); + operands[0] = rx_maybe_pidify_operand (operands[0], 0); + operands[1] = rx_maybe_pidify_operand (operands[1], 0); + if (GET_CODE (operands[0]) != REG + && GET_CODE (operands[1]) == PLUS) + operands[1] = copy_to_mode_reg (<register_modes:MODE>mode, operands[1]); + if (GET_CODE (operands[1]) == PLUS && GET_MODE (operands[1]) == SImode) + { + emit_insn (gen_addsi3 (operands[0], XEXP (operands[1], 0), XEXP (operands[1], 1))); + DONE; + } if (CONST_INT_P (operand1) && ! rx_is_legitimate_constant (<register_modes:MODE>mode, operand1)) FAIL; @@ -566,13 +578,13 @@ (define_insn "*mov<register_modes:mode>_internal" [(set (match_operand:register_modes - 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q") + 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q,r") (match_operand:register_modes - 1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i"))] + 1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i,RpdaRpid"))] "" { return rx_gen_move_template (operands, false); } - [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8") - (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11")] + [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8,8") + (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11,11")] ) (define_insn "extend<small_int_modes:mode>si2" @@ -830,7 +842,20 @@ [(set_attr "length" "2,3")] ) -(define_insn "addsi3" +(define_expand "addsi3" + [(parallel [(set (match_operand:SI 0 "register_operand" "") + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "rx_source_operand" ""))) + (clobber (reg:CC CC_REG))])] + "" + " + operands[0] = rx_maybe_pidify_operand (operands[0], 1); + operands[1] = rx_maybe_pidify_operand (operands[1], 1); + operands[2] = rx_maybe_pidify_operand (operands[2], 1); + " +) + +(define_insn "addsi3_internal" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r,r,r,r,r,r") (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,r,r,r,r,r,r,0") (match_operand:SI 2 "rx_source_operand" "r,Uint04,NEGint4,Sint08,Sint16,Sint24,i,0,r,Sint08,Sint16,Sint24,i,Q"))) @@ -2583,3 +2608,10 @@ "nop" [(set_attr "length" "1")] ) + +(define_expand "pid_addr" + [(plus:SI (match_operand:SI 0) + (const:SI (unspec:SI [(match_operand:SI 1)] UNSPEC_PID_ADDR)))] + "" + "" +) diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt index 4a84effdcdb..308bf0c8ada 100644 --- a/gcc/config/rx/rx.opt +++ b/gcc/config/rx/rx.opt @@ -112,3 +112,9 @@ 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. + +;--------------------------------------------------- + +mpid +Target Mask(PID) +Enables Position-Independent-Data (PID) mode. diff --git a/gcc/config/rx/t-rx b/gcc/config/rx/t-rx index 38893143981..ad667bcc5c9 100644 --- a/gcc/config/rx/t-rx +++ b/gcc/config/rx/t-rx @@ -20,8 +20,8 @@ # Enable multilibs: -MULTILIB_OPTIONS = m64bit-doubles nofpu mbig-endian-data -MULTILIB_DIRNAMES = 64-bit-double no-fpu-libs big-endian-data +MULTILIB_OPTIONS = m64bit-doubles nofpu mbig-endian-data mpid +MULTILIB_DIRNAMES = 64-bit-double no-fpu-libs big-endian-data pid MULTILIB_MATCHES = nofpu=mnofpu nofpu=mcpu?rx200 |