aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/m68hc11/m68hc11.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/m68hc11/m68hc11.c')
-rw-r--r--gcc/config/m68hc11/m68hc11.c282
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"