Mercurial > hg > CbC > CbC_gcc
diff gcc/config/m32c/m32c.c @ 67:f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Mar 2011 17:18:12 +0900 |
parents | b7f97abdc517 |
children | 04ced10e8804 |
line wrap: on
line diff
--- a/gcc/config/m32c/m32c.c Tue May 25 18:58:51 2010 +0900 +++ b/gcc/config/m32c/m32c.c Tue Mar 22 17:18:12 2011 +0900 @@ -1,5 +1,5 @@ /* Target Code for R8C/M16C/M32C - Copyright (C) 2005, 2006, 2007, 2008, 2009 + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Red Hat. @@ -34,7 +34,7 @@ #include "flags.h" #include "recog.h" #include "reload.h" -#include "toplev.h" +#include "diagnostic-core.h" #include "obstack.h" #include "tree.h" #include "expr.h" @@ -72,9 +72,14 @@ static struct machine_function *m32c_init_machine_status (void); static void m32c_insert_attributes (tree, tree *); static bool m32c_legitimate_address_p (enum machine_mode, rtx, bool); +static bool m32c_addr_space_legitimate_address_p (enum machine_mode, rtx, bool, addr_space_t); +static rtx m32c_function_arg (CUMULATIVE_ARGS *, enum machine_mode, + const_tree, bool); static bool m32c_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, const_tree, bool); -static bool m32c_promote_prototypes (const_tree); +static void m32c_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, + const_tree, bool); +static unsigned int m32c_function_arg_boundary (enum machine_mode, const_tree); static int m32c_pushm_popm (Push_Pop_Type); static bool m32c_strict_argument_naming (CUMULATIVE_ARGS *); static rtx m32c_struct_value_rtx (tree, int); @@ -83,7 +88,8 @@ static rtx m32c_function_value (const_tree, const_tree, bool); static rtx m32c_libcall_value (enum machine_mode, const_rtx); -int current_function_special_page_vector (rtx); +/* Returns true if an address is specified, else false. */ +static bool m32c_get_pragma_address (const char *varname, unsigned *addr); #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) @@ -116,6 +122,18 @@ #define IS_CR_REGNO(regno) ((regno) >= SB_REGNO && (regno) <= PC_REGNO) #define IS_CR_REG(rtx) (GET_CODE (rtx) == REG && IS_CR_REGNO (REGNO (rtx))) +static int +far_addr_space_p (rtx x) +{ + if (GET_CODE (x) != MEM) + return 0; +#if DEBUG0 + fprintf(stderr, "\033[35mfar_addr_space: "); debug_rtx(x); + fprintf(stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR); +#endif + return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR; +} + /* We do most RTX matching by converting the RTX into a string, and using string compares. This vastly simplifies the logic in many of the functions in this file. @@ -158,6 +176,16 @@ case CONST: encode_pattern_1 (XEXP (x, 0)); break; + case SIGN_EXTEND: + *patternp++ = '^'; + *patternp++ = 'S'; + encode_pattern_1 (XEXP (x, 0)); + break; + case ZERO_EXTEND: + *patternp++ = '^'; + *patternp++ = 'Z'; + encode_pattern_1 (XEXP (x, 0)); + break; case PLUS: *patternp++ = '+'; encode_pattern_1 (XEXP (x, 0)); @@ -336,47 +364,33 @@ return best; } -/* Returns TRUE If there are any registers that exist in both register - classes. */ -static int -classes_intersect (int class1, int class2) -{ - return class_contents[class1][0] & class_contents[class2][0]; -} - /* Used by m32c_register_move_cost to determine if a move is impossibly expensive. */ -static int -class_can_hold_mode (int rclass, enum machine_mode mode) +static bool +class_can_hold_mode (reg_class_t rclass, enum machine_mode mode) { /* Cache the results: 0=untested 1=no 2=yes */ static char results[LIM_REG_CLASSES][MAX_MACHINE_MODE]; - if (results[rclass][mode] == 0) + + if (results[(int) rclass][mode] == 0) { - int r, n, i; + int r; results[rclass][mode] = 1; for (r = 0; r < FIRST_PSEUDO_REGISTER; r++) - if (class_contents[rclass][0] & (1 << r) + if (in_hard_reg_set_p (reg_class_contents[(int) rclass], mode, r) && HARD_REGNO_MODE_OK (r, mode)) { - int ok = 1; - n = HARD_REGNO_NREGS (r, mode); - for (i = 1; i < n; i++) - if (!(class_contents[rclass][0] & (1 << (r + i)))) - ok = 0; - if (ok) - { - results[rclass][mode] = 2; - break; - } + results[rclass][mode] = 2; + break; } } + #if DEBUG0 fprintf (stderr, "class %s can hold %s? %s\n", - class_names[rclass], mode_name[mode], + class_names[(int) rclass], mode_name[mode], (results[rclass][mode] == 2) ? "yes" : "no"); #endif - return results[rclass][mode] == 2; + return results[(int) rclass][mode] == 2; } /* Run-time Target Specification. */ @@ -412,11 +426,15 @@ return TRUE; } -/* Implements OVERRIDE_OPTIONS. We limit memregs to 0..16, and - provide a default. */ -void -m32c_override_options (void) +/* Implements TARGET_OPTION_OVERRIDE. */ + +#undef TARGET_OPTION_OVERRIDE +#define TARGET_OPTION_OVERRIDE m32c_option_override + +static void +m32c_option_override (void) { + /* We limit memregs to 0..16, and provide a default. */ if (target_memregs_set) { if (target_memregs < 0 || target_memregs > 16) @@ -427,6 +445,30 @@ if (TARGET_A24) flag_ivopts = 0; + + /* This target defaults to strict volatile bitfields. */ + if (flag_strict_volatile_bitfields < 0) + flag_strict_volatile_bitfields = 1; + + /* r8c/m16c have no 16-bit indirect call, so thunks are involved. + This is always worse than an absolute call. */ + if (TARGET_A16) + flag_no_function_cse = 1; + + /* This wants to put insns between compares and their jumps. */ + /* FIXME: The right solution is to properly trace the flags register + values, but that is too much work for stage 4. */ + flag_combine_stack_adjustments = 0; +} + +#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE +#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE m32c_override_options_after_change + +static void +m32c_override_options_after_change (void) +{ + if (TARGET_A16) + flag_no_function_cse = 1; } /* Defining data structures for per-function information */ @@ -435,11 +477,7 @@ static struct machine_function * m32c_init_machine_status (void) { - struct machine_function *machine; - machine = - (machine_function *) ggc_alloc_cleared (sizeof (machine_function)); - - return machine; + return ggc_alloc_cleared_machine_function (); } /* Implements INIT_EXPANDERS. We just set up to call the above @@ -489,10 +527,12 @@ { 1, 1, 0, 0, 0 }, /* mem7 */ }; -/* Implements CONDITIONAL_REGISTER_USAGE. We adjust the number of - available memregs, and select which registers need to be preserved +/* Implements TARGET_CONDITIONAL_REGISTER_USAGE. We adjust the number + of available memregs, and select which registers need to be preserved across calls based on the chip family. */ +#undef TARGET_CONDITIONAL_REGISTER_USAGE +#define TARGET_CONDITIONAL_REGISTER_USAGE m32c_conditional_register_usage void m32c_conditional_register_usage (void) { @@ -540,7 +580,7 @@ return nregs_table[regno].qi_regs; if (GET_MODE_SIZE (mode) <= 2) return nregs_table[regno].hi_regs; - if (regno == A0_REGNO && mode == PSImode && TARGET_A16) + if (regno == A0_REGNO && mode == SImode && TARGET_A16) return 2; if ((GET_MODE_SIZE (mode) <= 3 || mode == PSImode) && TARGET_A24) return nregs_table[regno].pi_regs; @@ -587,7 +627,7 @@ /* Register Classes */ /* Implements REGNO_REG_CLASS. */ -enum machine_mode +enum reg_class m32c_regno_reg_class (int regno) { switch (regno) @@ -601,8 +641,9 @@ case R3_REGNO: return R3_REGS; case A0_REGNO: + return A0_REGS; case A1_REGNO: - return A_REGS; + return A1_REGS; case SB_REGNO: return SB_REGS; case FB_REGNO: @@ -732,7 +773,7 @@ if (rclass == NO_REGS) rclass = GET_MODE (x) == QImode ? HL_REGS : R03_REGS; - if (classes_intersect (rclass, CR_REGS)) + if (reg_classes_intersect_p (rclass, CR_REGS)) { switch (GET_MODE (x)) { @@ -818,21 +859,26 @@ if (mode == QImode && GET_CODE (x) == MEM && (cc & ~class_contents[R23_REGS][0]) == 0) return QI_REGS; - if (classes_intersect (rclass, CR_REGS) + if (reg_classes_intersect_p (rclass, CR_REGS) && GET_CODE (x) == REG && REGNO (x) >= SB_REGNO && REGNO (x) <= SP_REGNO) return TARGET_A16 ? HI_REGS : A_REGS; return NO_REGS; } -/* Implements CLASS_LIKELY_SPILLED_P. A_REGS is needed for address +/* Implements TARGET_CLASS_LIKELY_SPILLED_P. A_REGS is needed for address reloads. */ -int -m32c_class_likely_spilled_p (int regclass) + +#undef TARGET_CLASS_LIKELY_SPILLED_P +#define TARGET_CLASS_LIKELY_SPILLED_P m32c_class_likely_spilled_p + +static bool +m32c_class_likely_spilled_p (reg_class_t regclass) { if (regclass == A_REGS) - return 1; - return reg_class_size[regclass] == 1; + return true; + + return (reg_class_size[(int) regclass] == 1); } /* Implements CLASS_MAX_NREGS. We calculate this according to its @@ -975,6 +1021,8 @@ return 0; } +#define A0_OR_PSEUDO(x) (IS_REG(x, A0_REGNO) || REGNO (x) >= FIRST_PSEUDO_REGISTER) + /* Implements EXTRA_CONSTRAINT_STR (see next function too). 'S' is for memory constraints, plus "Rpa" for PARALLEL rtx's we use for call return values. */ @@ -982,6 +1030,29 @@ m32c_extra_constraint_p2 (rtx value, char c ATTRIBUTE_UNUSED, const char *str) { encode_pattern (value); + + if (far_addr_space_p (value)) + { + if (memcmp (str, "SF", 2) == 0) + { + return ( (RTX_IS ("mr") + && A0_OR_PSEUDO (patternr[1]) + && GET_MODE (patternr[1]) == SImode) + || (RTX_IS ("m+^Sri") + && A0_OR_PSEUDO (patternr[4]) + && GET_MODE (patternr[4]) == HImode) + || (RTX_IS ("m+^Srs") + && A0_OR_PSEUDO (patternr[4]) + && GET_MODE (patternr[4]) == HImode) + || (RTX_IS ("m+^S+ris") + && A0_OR_PSEUDO (patternr[5]) + && GET_MODE (patternr[5]) == HImode) + || RTX_IS ("ms") + ); + } + return 0; + } + if (memcmp (str, "Sd", 2) == 0) { /* This is the common "src/dest" address */ @@ -1049,6 +1120,10 @@ { return r1h_operand (value, QImode); } + else if (memcmp (str, "SF", 2) == 0) + { + return 0; + } gcc_assert (str[0] != 'S'); @@ -1381,8 +1456,7 @@ pushm = F (emit_insn (gen_pushm (GEN_INT (reg_mask)))); - REG_NOTES (pushm) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, note, - REG_NOTES (pushm)); + add_reg_note (pushm, REG_FRAME_RELATED_EXPR, note); } if (cfun->machine->is_interrupt) @@ -1449,7 +1523,7 @@ /* Implements PUSH_ROUNDING. The R8C and M16C have byte stacks, the M32C has word stacks. */ -int +unsigned int m32c_push_rounding (int n) { if (TARGET_R8C || TARGET_M16C) @@ -1459,10 +1533,11 @@ /* Passing Arguments in Registers */ -/* Implements FUNCTION_ARG. Arguments are passed partly in registers, - partly on stack. If our function returns a struct, a pointer to a - buffer for it is at the top of the stack (last thing pushed). The - first few real arguments may be in registers as follows: +/* Implements TARGET_FUNCTION_ARG. Arguments are passed partly in + registers, partly on stack. If our function returns a struct, a + pointer to a buffer for it is at the top of the stack (last thing + pushed). The first few real arguments may be in registers as + follows: R8C/M16C: arg1 in r1 if it's QI or HI (else it's pushed on stack) arg2 in r2 if it's HI (else pushed on stack) @@ -1475,9 +1550,11 @@ Note that when arg1 doesn't fit in r1, arg2 may still be passed in r2 if it fits. */ -rtx +#undef TARGET_FUNCTION_ARG +#define TARGET_FUNCTION_ARG m32c_function_arg +static rtx m32c_function_arg (CUMULATIVE_ARGS * ca, - enum machine_mode mode, tree type, int named) + enum machine_mode mode, const_tree type, bool named) { /* Can return a reg, parallel, or 0 for stack */ rtx rv = NULL_RTX; @@ -1550,15 +1627,17 @@ ca->parm_num = 1; } -/* Implements FUNCTION_ARG_ADVANCE. force_mem is set for functions - returning structures, so we always reset that. Otherwise, we only - need to know the sequence number of the argument to know what to do - with it. */ -void +/* Implements TARGET_FUNCTION_ARG_ADVANCE. force_mem is set for + functions returning structures, so we always reset that. Otherwise, + we only need to know the sequence number of the argument to know what + to do with it. */ +#undef TARGET_FUNCTION_ARG_ADVANCE +#define TARGET_FUNCTION_ARG_ADVANCE m32c_function_arg_advance +static void m32c_function_arg_advance (CUMULATIVE_ARGS * ca, enum machine_mode mode ATTRIBUTE_UNUSED, - tree type ATTRIBUTE_UNUSED, - int named ATTRIBUTE_UNUSED) + const_tree type ATTRIBUTE_UNUSED, + bool named ATTRIBUTE_UNUSED) { if (ca->force_mem) ca->force_mem = 0; @@ -1566,6 +1645,16 @@ ca->parm_num++; } +/* Implements TARGET_FUNCTION_ARG_BOUNDARY. */ +#undef TARGET_FUNCTION_ARG_BOUNDARY +#define TARGET_FUNCTION_ARG_BOUNDARY m32c_function_arg_boundary +static unsigned int +m32c_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED) +{ + return (TARGET_A16 ? 8 : 16); +} + /* Implements FUNCTION_ARG_REGNO_P. */ int m32c_function_arg_regno_p (int r) @@ -1671,9 +1760,12 @@ return m32c_libcall_value (mode, NULL_RTX); } -/* Implements FUNCTION_VALUE_REGNO_P. */ - -bool +/* Implements TARGET_FUNCTION_VALUE_REGNO_P. */ + +#undef TARGET_FUNCTION_VALUE_REGNO_P +#define TARGET_FUNCTION_VALUE_REGNO_P m32c_function_value_regno_p + +static bool m32c_function_value_regno_p (const unsigned int regno) { return (regno == R0_REGNO || regno == MEM0_REGNO); @@ -1790,9 +1882,9 @@ the right modes are found. */ if (TARGET_A24) { - optab_handler (cstore_optab, QImode)->insn_code = CODE_FOR_cstoreqi4_24; - optab_handler (cstore_optab, HImode)->insn_code = CODE_FOR_cstorehi4_24; - optab_handler (cstore_optab, PSImode)->insn_code = CODE_FOR_cstorepsi4_24; + set_optab_handler (cstore_optab, QImode, CODE_FOR_cstoreqi4_24); + set_optab_handler (cstore_optab, HImode, CODE_FOR_cstorehi4_24); + set_optab_handler (cstore_optab, PSImode, CODE_FOR_cstorepsi4_24); } } @@ -1811,6 +1903,11 @@ if (CONSTANT_P (x)) return 1; + if (TARGET_A16 && GET_MODE (x) != HImode && GET_MODE (x) != SImode) + return 0; + if (TARGET_A24 && GET_MODE (x) != PSImode) + return 0; + /* Wide references to memory will be split after reload, so we must ensure that all parts of such splits remain legitimate addresses. */ @@ -1845,11 +1942,13 @@ to please the assembler. */ switch (REGNO (patternr[0])) { - case A0_REGNO: case A1_REGNO: case SB_REGNO: case FB_REGNO: case SP_REGNO: + if (TARGET_A16 && GET_MODE (x) == SImode) + return 0; + case A0_REGNO: return 1; default: @@ -1858,6 +1957,10 @@ return 0; } } + + if (TARGET_A16 && GET_MODE (x) == SImode) + return 0; + if (RTX_IS ("+ri")) { /* This is more interesting, because different base registers @@ -2039,7 +2142,7 @@ type = RELOAD_FOR_OTHER_ADDRESS; push_reload (sum, NULL_RTX, &XEXP (*x, 0), NULL, A_REGS, Pmode, VOIDmode, 0, 0, opnum, - type); + (enum reload_type) type); return 1; } @@ -2055,7 +2158,7 @@ type = RELOAD_FOR_OTHER_ADDRESS; push_reload (XEXP (*x, 0), NULL_RTX, &XEXP (*x, 0), NULL, A_REGS, Pmode, VOIDmode, 0, 0, opnum, - type); + (enum reload_type) type); return 1; } @@ -2071,6 +2174,204 @@ } +/* Return the appropriate mode for a named address pointer. */ +#undef TARGET_ADDR_SPACE_POINTER_MODE +#define TARGET_ADDR_SPACE_POINTER_MODE m32c_addr_space_pointer_mode +static enum machine_mode +m32c_addr_space_pointer_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return TARGET_A24 ? PSImode : HImode; + case ADDR_SPACE_FAR: + return SImode; + default: + gcc_unreachable (); + } +} + +/* Return the appropriate mode for a named address address. */ +#undef TARGET_ADDR_SPACE_ADDRESS_MODE +#define TARGET_ADDR_SPACE_ADDRESS_MODE m32c_addr_space_address_mode +static enum machine_mode +m32c_addr_space_address_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return TARGET_A24 ? PSImode : HImode; + case ADDR_SPACE_FAR: + return SImode; + default: + gcc_unreachable (); + } +} + +/* Like m32c_legitimate_address_p, except with named addresses. */ +#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ + m32c_addr_space_legitimate_address_p +static bool +m32c_addr_space_legitimate_address_p (enum machine_mode mode, rtx x, + bool strict, addr_space_t as) +{ + if (as == ADDR_SPACE_FAR) + { + if (TARGET_A24) + return 0; + encode_pattern (x); + if (RTX_IS ("r")) + { + if (GET_MODE (x) != SImode) + return 0; + switch (REGNO (patternr[0])) + { + case A0_REGNO: + return 1; + + default: + if (IS_PSEUDO (patternr[0], strict)) + return 1; + return 0; + } + } + if (RTX_IS ("+^Sri")) + { + int rn = REGNO (patternr[3]); + HOST_WIDE_INT offs = INTVAL (patternr[4]); + if (GET_MODE (patternr[3]) != HImode) + return 0; + switch (rn) + { + case A0_REGNO: + return (offs >= 0 && offs <= 0xfffff); + + default: + if (IS_PSEUDO (patternr[3], strict)) + return 1; + return 0; + } + } + if (RTX_IS ("+^Srs")) + { + int rn = REGNO (patternr[3]); + if (GET_MODE (patternr[3]) != HImode) + return 0; + switch (rn) + { + case A0_REGNO: + return 1; + + default: + if (IS_PSEUDO (patternr[3], strict)) + return 1; + return 0; + } + } + if (RTX_IS ("+^S+ris")) + { + int rn = REGNO (patternr[4]); + if (GET_MODE (patternr[4]) != HImode) + return 0; + switch (rn) + { + case A0_REGNO: + return 1; + + default: + if (IS_PSEUDO (patternr[4], strict)) + return 1; + return 0; + } + } + if (RTX_IS ("s")) + { + return 1; + } + return 0; + } + + else if (as != ADDR_SPACE_GENERIC) + gcc_unreachable (); + + return m32c_legitimate_address_p (mode, x, strict); +} + +/* Like m32c_legitimate_address, except with named address support. */ +#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS +#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS m32c_addr_space_legitimize_address +static rtx +m32c_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode, + addr_space_t as) +{ + if (as != ADDR_SPACE_GENERIC) + { +#if DEBUG0 + fprintf (stderr, "\033[36mm32c_addr_space_legitimize_address for mode %s\033[0m\n", mode_name[mode]); + debug_rtx (x); + fprintf (stderr, "\n"); +#endif + + if (GET_CODE (x) != REG) + { + x = force_reg (SImode, x); + } + return x; + } + + return m32c_legitimize_address (x, oldx, mode); +} + +/* Determine if one named address space is a subset of another. */ +#undef TARGET_ADDR_SPACE_SUBSET_P +#define TARGET_ADDR_SPACE_SUBSET_P m32c_addr_space_subset_p +static bool +m32c_addr_space_subset_p (addr_space_t subset, addr_space_t superset) +{ + gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR); + gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR); + + if (subset == superset) + return true; + + else + return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR); +} + +#undef TARGET_ADDR_SPACE_CONVERT +#define TARGET_ADDR_SPACE_CONVERT m32c_addr_space_convert +/* Convert from one address space to another. */ +static rtx +m32c_addr_space_convert (rtx op, tree from_type, tree to_type) +{ + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); + rtx result; + + gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR); + gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR); + + if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR) + { + /* This is unpredictable, as we're truncating off usable address + bits. */ + + result = gen_reg_rtx (HImode); + emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0)); + return result; + } + else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC) + { + /* This always works. */ + result = gen_reg_rtx (SImode); + emit_insn (gen_zero_extendhisi2 (result, op)); + return result; + } + else + gcc_unreachable (); +} + /* Condition Code Status */ #undef TARGET_FIXED_CONDITION_CODE_REGS @@ -2085,19 +2386,29 @@ /* Describing Relative Costs of Operations */ -/* Implements REGISTER_MOVE_COST. We make impossible moves +/* Implements TARGET_REGISTER_MOVE_COST. We make impossible moves prohibitively expensive, like trying to put QIs in r2/r3 (there are no opcodes to do that). We also discourage use of mem* registers since they're really memory. */ -int -m32c_register_move_cost (enum machine_mode mode, int from, int to) + +#undef TARGET_REGISTER_MOVE_COST +#define TARGET_REGISTER_MOVE_COST m32c_register_move_cost + +static int +m32c_register_move_cost (enum machine_mode mode, reg_class_t from, + reg_class_t to) { int cost = COSTS_N_INSNS (3); - int cc = class_contents[from][0] | class_contents[to][0]; - /* FIXME: pick real values, but not 2 for now. */ - if (mode == QImode && (cc & class_contents[R23_REGS][0])) + HARD_REG_SET cc; + +/* FIXME: pick real values, but not 2 for now. */ + COPY_HARD_REG_SET (cc, reg_class_contents[(int) from]); + IOR_HARD_REG_SET (cc, reg_class_contents[(int) to]); + + if (mode == QImode + && hard_reg_set_intersect_p (cc, reg_class_contents[R23_REGS])) { - if (!(cc & ~class_contents[R23_REGS][0])) + if (hard_reg_set_subset_p (cc, reg_class_contents[R23_REGS])) cost = COSTS_N_INSNS (1000); else cost = COSTS_N_INSNS (80); @@ -2106,30 +2417,35 @@ if (!class_can_hold_mode (from, mode) || !class_can_hold_mode (to, mode)) cost = COSTS_N_INSNS (1000); - if (classes_intersect (from, CR_REGS)) + if (reg_classes_intersect_p (from, CR_REGS)) cost += COSTS_N_INSNS (5); - if (classes_intersect (to, CR_REGS)) + if (reg_classes_intersect_p (to, CR_REGS)) cost += COSTS_N_INSNS (5); if (from == MEM_REGS || to == MEM_REGS) cost += COSTS_N_INSNS (50); - else if (classes_intersect (from, MEM_REGS) - || classes_intersect (to, MEM_REGS)) + else if (reg_classes_intersect_p (from, MEM_REGS) + || reg_classes_intersect_p (to, MEM_REGS)) cost += COSTS_N_INSNS (10); #if DEBUG0 fprintf (stderr, "register_move_cost %s from %s to %s = %d\n", - mode_name[mode], class_names[from], class_names[to], cost); + mode_name[mode], class_names[(int) from], class_names[(int) to], + cost); #endif return cost; } -/* Implements MEMORY_MOVE_COST. */ -int +/* Implements TARGET_MEMORY_MOVE_COST. */ + +#undef TARGET_MEMORY_MOVE_COST +#define TARGET_MEMORY_MOVE_COST m32c_memory_move_cost + +static int m32c_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, - int reg_class ATTRIBUTE_UNUSED, - int in ATTRIBUTE_UNUSED) + reg_class_t rclass ATTRIBUTE_UNUSED, + bool in ATTRIBUTE_UNUSED) { /* FIXME: pick real values. */ return COSTS_N_INSNS (10); @@ -2309,6 +2625,12 @@ { 0, "mr", "z[1]" }, { 0, "m+ri", "3[2]" }, { 0, "m+rs", "3[2]" }, + { 0, "m+^Zrs", "5[4]" }, + { 0, "m+^Zri", "5[4]" }, + { 0, "m+^Z+ris", "7+6[5]" }, + { 0, "m+^Srs", "5[4]" }, + { 0, "m+^Sri", "5[4]" }, + { 0, "m+^S+ris", "7+6[5]" }, { 0, "m+r+si", "4+5[2]" }, { 0, "ms", "1" }, { 0, "mi", "1" }, @@ -2933,7 +3255,108 @@ m32c_insert_attributes (tree node ATTRIBUTE_UNUSED, tree * attr_ptr ATTRIBUTE_UNUSED) { - /* Nothing to do here. */ + unsigned addr; + /* See if we need to make #pragma address variables volatile. */ + + if (TREE_CODE (node) == VAR_DECL) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (node)); + if (m32c_get_pragma_address (name, &addr)) + { + TREE_THIS_VOLATILE (node) = true; + } + } +} + + +struct GTY(()) pragma_entry { + const char *varname; + unsigned address; +}; +typedef struct pragma_entry pragma_entry; + +/* Hash table of pragma info. */ +static GTY((param_is (pragma_entry))) htab_t pragma_htab; + +static int +pragma_entry_eq (const void *p1, const void *p2) +{ + const pragma_entry *old = (const pragma_entry *) p1; + const char *new_name = (const char *) p2; + + return strcmp (old->varname, new_name) == 0; +} + +static hashval_t +pragma_entry_hash (const void *p) +{ + const pragma_entry *old = (const pragma_entry *) p; + return htab_hash_string (old->varname); +} + +void +m32c_note_pragma_address (const char *varname, unsigned address) +{ + pragma_entry **slot; + + if (!pragma_htab) + pragma_htab = htab_create_ggc (31, pragma_entry_hash, + pragma_entry_eq, NULL); + + slot = (pragma_entry **) + htab_find_slot_with_hash (pragma_htab, varname, + htab_hash_string (varname), INSERT); + + if (!*slot) + { + *slot = ggc_alloc_pragma_entry (); + (*slot)->varname = ggc_strdup (varname); + } + (*slot)->address = address; +} + +static bool +m32c_get_pragma_address (const char *varname, unsigned *address) +{ + pragma_entry **slot; + + if (!pragma_htab) + return false; + + slot = (pragma_entry **) + htab_find_slot_with_hash (pragma_htab, varname, + htab_hash_string (varname), NO_INSERT); + if (slot && *slot) + { + *address = (*slot)->address; + return true; + } + return false; +} + +void +m32c_output_aligned_common (FILE *stream, tree decl ATTRIBUTE_UNUSED, + const char *name, + int size, int align, int global) +{ + unsigned address; + + if (m32c_get_pragma_address (name, &address)) + { + /* We never output these as global. */ + assemble_name (stream, name); + fprintf (stream, " = 0x%04x\n", address); + return; + } + if (!global) + { + fprintf (stream, "\t.local\t"); + assemble_name (stream, name); + fprintf (stream, "\n"); + } + fprintf (stream, "\t.comm\t"); + assemble_name (stream, name); + fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT); } /* Predicates */ @@ -2964,7 +3387,7 @@ }; /* Returns TRUE if OP is a subreg of a hard reg which we don't - support. */ + support. We also bail on MEMs with illegal addresses. */ bool m32c_illegal_subreg_p (rtx op) { @@ -2972,6 +3395,12 @@ unsigned int i; int src_mode, dest_mode; + if (GET_CODE (op) == MEM + && ! m32c_legitimate_address_p (Pmode, XEXP (op, 0), false)) + { + return true; + } + if (GET_CODE (op) != SUBREG) return false; @@ -3185,7 +3614,19 @@ return gen_rtx_MEM (outer, XEXP (XEXP (x, 0), 0)); if (GET_CODE (x) != REG) - return simplify_gen_subreg (outer, x, inner, byte); + { + rtx r = simplify_gen_subreg (outer, x, inner, byte); + if (GET_CODE (r) == SUBREG + && GET_CODE (x) == MEM + && MEM_VOLATILE_P (x)) + { + /* Volatile MEMs don't get simplified, but we need them to + be. We are little endian, so the subreg byte is the + offset. */ + r = adjust_address_nv (x, outer, byte); + } + return r; + } r = REGNO (x); if (r >= FIRST_PSEUDO_REGISTER || r == AP_REGNO) @@ -3233,6 +3674,11 @@ int m32c_prepare_move (rtx * operands, enum machine_mode mode) { + if (far_addr_space_p (operands[0]) + && CONSTANT_P (operands[1])) + { + operands[1] = force_reg (GET_MODE (operands[0]), operands[1]); + } if (TARGET_A16 && mode == PSImode) return m32c_split_move (operands, mode, 1); if ((GET_CODE (operands[0]) == MEM) @@ -3338,6 +3784,11 @@ if (m32c_extra_constraint_p (operands[0], 'S', "Ss")) split_all = 3; + if (TARGET_A16 + && (far_addr_space_p (operands[0]) + || far_addr_space_p (operands[1]))) + split_all |= 1; + /* We don't need to split these. */ if (TARGET_A24 && split_all != 3 @@ -3686,13 +4137,12 @@ undefined to skip one of the comparisons. */ rtx count; - rtx label, lref, insn, tempvar; + rtx label, insn, tempvar; emit_move_insn (operands[0], operands[1]); count = temp; label = gen_label_rtx (); - lref = gen_rtx_LABEL_REF (VOIDmode, label); LABEL_NUSES (label) ++; tempvar = gen_reg_rtx (mode); @@ -3759,7 +4209,6 @@ m32c_expand_movcc (rtx *operands) { rtx rel = operands[1]; - rtx cmp; if (GET_CODE (rel) != EQ && GET_CODE (rel) != NE) return 1; @@ -3822,7 +4271,7 @@ if (GET_MODE (op0) == HImode && INTVAL (operands[2]) >= 8 - && GET_MODE (op0) == MEM) + && GET_CODE (op0) == MEM) { /* We are little endian. */ rtx new_mem = gen_rtx_MEM (QImode, plus_constant (XEXP (op0, 0), 1)); @@ -4164,14 +4613,13 @@ int flags_needed; int pflags; rtx prev, pp, next; - rtx op0, op1, op2; + rtx op0, op1; #if DEBUG_CMP int prev_icode, i; #endif op0 = operands[0]; op1 = operands[1]; - op2 = operands[2]; #if DEBUG_CMP fprintf(stderr, "\n\033[32mm32c_compare_redundant\033[0m\n");