diff options
Diffstat (limited to 'gcc/config/m68hc11/m68hc11.c')
-rw-r--r-- | gcc/config/m68hc11/m68hc11.c | 282 |
1 files changed, 197 insertions, 85 deletions
diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index ac16b527a97..093d8ed0a14 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -1,5 +1,5 @@ /* Subroutines for code generation on Motorola 68HC11 and 68HC12. - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Contributed by Stephane Carrez (stcarrez@nerim.fr) This file is part of GNU CC. @@ -64,9 +64,10 @@ static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode, int)); static int register_indirect_p PARAMS((rtx, enum machine_mode, int)); static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx)); -static int m68hc11_autoinc_compatible_p PARAMS ((rtx, rtx)); static int must_parenthesize PARAMS ((rtx)); static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int)); +static int autoinc_mode PARAMS ((rtx)); +static int m68hc11_make_autoinc_notes PARAMS ((rtx*, void*)); static int m68hc11_auto_inc_p PARAMS ((rtx)); static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *)); const struct attribute_spec m68hc11_attribute_table[]; @@ -79,8 +80,6 @@ static void m68hc11_asm_out_constructor PARAMS ((rtx, int)); static void m68hc11_asm_out_destructor PARAMS ((rtx, int)); static void m68hc11_encode_section_info PARAMS((tree, int)); -rtx m68hc11_soft_tmp_reg; - /* Must be set to 1 to produce debug messages. */ int debug_m6811 = 0; @@ -89,11 +88,12 @@ extern FILE *asm_out_file; rtx ix_reg; rtx iy_reg; rtx d_reg; -rtx da_reg; -rtx stack_push_word; -rtx stack_pop_word; +rtx m68hc11_soft_tmp_reg; +static GTY(()) rtx stack_push_word; +static GTY(()) rtx stack_pop_word; +static GTY(()) rtx z_reg; +static GTY(()) rtx z_reg_qi; static int regs_inited = 0; -rtx z_reg; /* Set to 1 by expand_prologue() when the function is an interrupt handler. */ int current_function_interrupt; @@ -284,7 +284,7 @@ m68hc11_override_options () m68hc11_sp_correction = 0; m68hc11_tmp_regs_class = TMP_REGS; target_flags &= ~MASK_M6811; - target_flags |= MASK_NO_DIRECT_MODE | MASK_MIN_MAX; + target_flags |= MASK_NO_DIRECT_MODE; if (m68hc11_soft_reg_count == 0) m68hc11_soft_reg_count = "0"; @@ -335,7 +335,6 @@ create_regs_rtx () ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM); iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM); d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM); - da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM); m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM); stack_push_word = gen_rtx (MEM, HImode, @@ -385,6 +384,23 @@ hard_regno_mode_ok (regno, mode) } } +int +m68hc11_hard_regno_rename_ok (reg1, reg2) + int reg1, reg2; +{ + /* Don't accept renaming to Z register. We will replace it to + X,Y or D during machine reorg pass. */ + if (reg2 == HARD_Z_REGNUM) + return 0; + + /* Don't accept renaming D,X to Y register as the code will be bigger. */ + if (TARGET_M6811 && reg2 == HARD_Y_REGNUM + && (D_REGNO_P (reg1) || X_REGNO_P (reg1))) + return 0; + + return 1; +} + enum reg_class preferred_reload_class (operand, class) rtx operand; @@ -1131,6 +1147,16 @@ m68hc11_non_shift_operator (op, mode) || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS; } +/* Return true if op is a shift operator. */ +int +m68hc11_shift_operator (op, mode) + register rtx op; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT + || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT + || GET_CODE (op) == ASHIFTRT; +} int m68hc11_unary_operator (op, mode) @@ -1196,9 +1222,16 @@ const struct attribute_spec m68hc11_attribute_table[] = /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, + { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, + { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute }, { NULL, 0, 0, false, false, false, NULL } }; +/* Keep track of the symbol which has a `trap' attribute and which uses + the `swi' calling convention. Since there is only one trap, we only + record one such symbol. If there are several, a warning is reported. */ +static rtx trap_handler_symbol = 0; + /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL; arguments as in struct attribute_spec.handler. */ static tree @@ -1210,6 +1243,7 @@ m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs) bool *no_add_attrs; { if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE && TREE_CODE (*node) != FIELD_DECL && TREE_CODE (*node) != TYPE_DECL) { @@ -1232,16 +1266,56 @@ m68hc11_encode_section_info (decl, first) { tree func_attr; int trap_handler; + int is_far = 0; rtx rtl; - + if (TREE_CODE (decl) != FUNCTION_DECL) return; rtl = DECL_RTL (decl); func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + + + if (lookup_attribute ("far", func_attr) != NULL_TREE) + is_far = 1; + else if (lookup_attribute ("near", func_attr) == NULL_TREE) + is_far = TARGET_LONG_CALLS != 0; + trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; - SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler; + if (trap_handler && is_far) + { + warning ("`trap' and `far' attributes are not compatible, ignoring `far'"); + trap_handler = 0; + } + if (trap_handler) + { + if (trap_handler_symbol != 0) + warning ("`trap' attribute is already used"); + else + trap_handler_symbol = XEXP (rtl, 0); + } + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far; +} + +int +m68hc11_is_far_symbol (sym) + rtx sym; +{ + if (GET_CODE (sym) == MEM) + sym = XEXP (sym, 0); + + return SYMBOL_REF_FLAG (sym); +} + +int +m68hc11_is_trap_symbol (sym) + rtx sym; +{ + if (GET_CODE (sym) == MEM) + sym = XEXP (sym, 0); + + return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym); } @@ -1281,6 +1355,14 @@ m68hc11_initial_elimination_offset (from, to) /* For a trap handler, we must take into account the registers which are pushed on the stack during the trap (except the PC). */ func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)); + + if (lookup_attribute ("far", func_attr) != 0) + current_function_far = 1; + else if (lookup_attribute ("near", func_attr) != 0) + current_function_far = 0; + else + current_function_far = TARGET_LONG_CALLS != 0; + trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; if (trap_handler && from == ARG_POINTER_REGNUM) size = 7; @@ -1452,51 +1534,6 @@ m68hc11_function_arg (cum, mode, type, named) return NULL_RTX; } -rtx -m68hc11_va_arg (valist, type) - tree valist; - tree type; -{ - tree addr_tree, t; - HOST_WIDE_INT align; - HOST_WIDE_INT rounded_size; - rtx addr; - int pad_direction; - - /* Compute the rounded size of the type. */ - align = PARM_BOUNDARY / BITS_PER_UNIT; - rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align); - - /* Get AP. */ - addr_tree = valist; - pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type); - - if (pad_direction == downward) - { - /* Small args are padded downward. */ - - HOST_WIDE_INT adj; - adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT; - if (rounded_size > align) - adj = rounded_size; - - addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree, - build_int_2 (rounded_size - adj, 0)); - } - - addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL); - addr = copy_to_reg (addr); - - /* Compute new value for AP. */ - t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, - build (PLUS_EXPR, TREE_TYPE (valist), valist, - build_int_2 (rounded_size, 0))); - TREE_SIDE_EFFECTS (t) = 1; - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); - - return addr; -} - /* If defined, a C expression which determines whether, and in which direction, to pad out an argument with extra space. The value should be of type `enum direction': either `upward' to pad above the argument, @@ -1620,6 +1657,12 @@ expand_prologue () current_function_interrupt = lookup_attribute ("interrupt", func_attr) != NULL_TREE; current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE; + if (lookup_attribute ("far", func_attr) != NULL_TREE) + current_function_far = 1; + else if (lookup_attribute ("near", func_attr) != NULL_TREE) + current_function_far = 0; + else + current_function_far = TARGET_LONG_CALLS != 0; /* Get the scratch register to build the frame and push registers. If the first argument is a 32-bit quantity, the D+X registers @@ -1654,7 +1697,7 @@ expand_prologue () emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size))); } - else if (size > 8) + else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) { rtx insn; @@ -1742,7 +1785,7 @@ expand_epilogue () emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size))); } - else if (size > 8) + else if ((!optimize_size && size > 8) || (optimize_size && size > 10)) { rtx insn; @@ -2163,6 +2206,10 @@ print_operand (file, op, letter) asm_print_register (file, REGNO (op)); fprintf (file, "+1"); } + else if (letter == 'b' && D_REG_P (op)) + { + asm_print_register (file, HARD_B_REGNUM); + } else { asm_print_register (file, REGNO (op)); @@ -3214,6 +3261,16 @@ m68hc11_gen_movhi (insn, operands) { if (SP_REG_P (operands[0])) output_asm_insn ("lds\t%1", operands); + else if (!D_REG_P (operands[0]) + && GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1) + && find_reg_note (insn, REG_WAS_0, 0)) + { + if (INTVAL (operands[1]) == 1) + output_asm_insn ("in%0", operands); + else + output_asm_insn ("de%0", operands); + } else output_asm_insn ("ld%0\t%1", operands); } @@ -3379,11 +3436,17 @@ m68hc11_gen_movhi (insn, operands) output_asm_insn ("xgdx", operands); CC_STATUS_INIT; } - else + else if (!optimize_size) { output_asm_insn ("sty\t%t1", operands); output_asm_insn ("ldx\t%t1", operands); } + else + { + CC_STATUS_INIT; + output_asm_insn ("pshy", operands); + output_asm_insn ("pulx", operands); + } } else if (SP_REG_P (operands[1])) { @@ -3391,6 +3454,15 @@ m68hc11_gen_movhi (insn, operands) cc_status = cc_prev_status; output_asm_insn ("tsx", operands); } + else if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1) + && find_reg_note (insn, REG_WAS_0, 0)) + { + if (INTVAL (operands[1]) == 1) + output_asm_insn ("in%0", operands); + else + output_asm_insn ("de%0", operands); + } else { output_asm_insn ("ldx\t%1", operands); @@ -3421,11 +3493,17 @@ m68hc11_gen_movhi (insn, operands) output_asm_insn ("xgdy", operands); CC_STATUS_INIT; } - else + else if (!optimize_size) { output_asm_insn ("stx\t%t1", operands); output_asm_insn ("ldy\t%t1", operands); } + else + { + CC_STATUS_INIT; + output_asm_insn ("pshx", operands); + output_asm_insn ("puly", operands); + } } else if (SP_REG_P (operands[1])) { @@ -3433,7 +3511,16 @@ m68hc11_gen_movhi (insn, operands) cc_status = cc_prev_status; output_asm_insn ("tsy", operands); } - else + else if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1) + && find_reg_note (insn, REG_WAS_0, 0)) + { + if (INTVAL (operands[1]) == 1) + output_asm_insn ("in%0", operands); + else + output_asm_insn ("de%0", operands); + } + else { output_asm_insn ("ldy\t%1", operands); } @@ -3673,6 +3760,15 @@ m68hc11_gen_movqi (insn, operands) output_asm_insn ("ldab\t%T0", operands); } } + else if (GET_CODE (operands[1]) == CONST_INT + && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1) + && find_reg_note (insn, REG_WAS_0, 0)) + { + if (INTVAL (operands[1]) == 1) + output_asm_insn ("inc%b0", operands); + else + output_asm_insn ("dec%b0", operands); + } else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1]) && !DA_REG_P (operands[1])) { @@ -3881,15 +3977,15 @@ m68hc11_gen_rotate (code, insn, operands) if (val > 0) { - /* Set the carry to bit-15, but don't change D yet. */ - if (GET_MODE (operands[0]) != QImode) - { - output_asm_insn ("asra", operands); - output_asm_insn ("rola", operands); - } - while (--val >= 0) { + /* Set the carry to bit-15, but don't change D yet. */ + if (GET_MODE (operands[0]) != QImode) + { + output_asm_insn ("asra", operands); + output_asm_insn ("rola", operands); + } + /* Rotate B first to move the carry to bit-0. */ if (D_REG_P (operands[0])) output_asm_insn ("rolb", operands); @@ -3900,14 +3996,12 @@ m68hc11_gen_rotate (code, insn, operands) } else { - /* Set the carry to bit-8 of D. */ - if (val != 0 && GET_MODE (operands[0]) != QImode) - { - output_asm_insn ("tap", operands); - } - while (++val <= 0) { + /* Set the carry to bit-8 of D. */ + if (GET_MODE (operands[0]) != QImode) + output_asm_insn ("tap", operands); + /* Rotate B first to move the carry to bit-7. */ if (D_REG_P (operands[0])) output_asm_insn ("rorb", operands); @@ -4103,8 +4197,6 @@ struct replace_info int z_loaded_with_sp; }; -rtx z_reg_qi; - static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *)); static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *)); static void m68hc11_z_replacement PARAMS ((rtx)); @@ -4204,7 +4296,7 @@ m68hc11_check_z_replacement (insn, info) info->need_save_z = 0; info->found_call = 1; info->regno = SOFT_Z_REGNUM; - info->last = insn; + info->last = NEXT_INSN (insn); } return 0; } @@ -4338,7 +4430,13 @@ m68hc11_check_z_replacement (insn, info) info->z_died = 1; info->need_save_z = 0; } - else + else if (TARGET_M6812 && side_effects_p (src)) + { + info->last = 0; + info->must_restore_reg = 0; + return 0; + } + else { info->save_before_last = 1; } @@ -4415,7 +4513,13 @@ m68hc11_check_z_replacement (insn, info) info->z_died = 1; info->need_save_z = 0; } - else + else if (TARGET_M6812 && side_effects_p (src)) + { + info->last = 0; + info->must_restore_reg = 0; + return 0; + } + else { info->save_before_last = 1; } @@ -5058,6 +5162,12 @@ m68hc11_reorg (first) int split_done = 0; rtx insn; + compute_bb_for_insn (); + + /* ??? update_life_info_in_dirty_blocks fails to terminate during + non-optimizing bootstrap. + + update_life_info (NULL, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES); */ z_replacement_completed = 0; z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM); @@ -5073,9 +5183,6 @@ m68hc11_reorg (first) z_replacement_completed = 1; m68hc11_reassign_regs (first); - if (optimize) - compute_bb_for_insn (); - /* After some splitting, there are some oportunities for CSE pass. This happens quite often when 32-bit or above patterns are split. */ if (optimize > 0 && split_done) @@ -5174,7 +5281,7 @@ m68hc11_memory_move_cost (mode, class, in) else { if (GET_MODE_SIZE (mode) <= 2) - return COSTS_N_INSNS (2); + return COSTS_N_INSNS (3); else return COSTS_N_INSNS (4); } @@ -5506,7 +5613,10 @@ m68hc11_asm_file_start (out, main_file) const char *main_file; { fprintf (out, ";;;-----------------------------------------\n"); - fprintf (out, ";;; Start MC68HC11 gcc assembly output\n"); + fprintf (out, ";;; Start %s gcc assembly output\n", + TARGET_M6811 + ? "MC68HC11" + : TARGET_M68S12 ? "MC68HCS12" : "MC68HC12"); fprintf (out, ";;; gcc compiler %s\n", version_string); print_options (out); fprintf (out, ";;;-----------------------------------------\n"); @@ -5536,3 +5646,5 @@ m68hc11_asm_out_destructor (symbol, priority) default_dtor_section_asm_out_destructor (symbol, priority); fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n"); } + +#include "gt-m68hc11.h" |