X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=blobdiff_plain;f=gcc%2Fconfig%2Fm68hc11%2Fm68hc11.c;h=4fba4a39a1ceb09ed78e231fff7203bc1be49f8a;hb=6fed43773c9b0ce596dca5686f37ac3fc0fa11c0;hp=87cc7c40e38ebb2bfaed2a63da85177c7f542004;hpb=27b11d56b743098deb193d510b337ba22dc52e5c;p=msp430-gcc.git diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index 87cc7c40..4fba4a39 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -1,23 +1,23 @@ /* 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, 2004, 2005, 2006, 2007, 2008 + Free Software Foundation, Inc. Contributed by Stephane Carrez (stcarrez@nerim.fr) -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify +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 2, or (at your option) +the Free Software Foundation; either version 3, or (at your option) any later version. -GNU CC is distributed in the hope that it will be useful, +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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. +along with GCC; see the file COPYING3. If not see +. Note: A first 68HC11 port was made by Otto Lind (otto@coactive.com) @@ -35,6 +35,8 @@ Note: #include #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" #include "tree.h" #include "tm_p.h" @@ -48,6 +50,7 @@ Note: #include "flags.h" #include "recog.h" #include "expr.h" +#include "libfuncs.h" #include "toplev.h" #include "basic-block.h" #include "function.h" @@ -55,30 +58,37 @@ Note: #include "reload.h" #include "target.h" #include "target-def.h" - -static void print_options PARAMS ((FILE *)); -static void emit_move_after_reload PARAMS ((rtx, rtx, rtx)); -static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *)); -static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *)); -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 must_parenthesize PARAMS ((rtx)); -static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int)); -static int m68hc11_auto_inc_p PARAMS ((rtx)); -static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *)); +#include "df.h" + +static void emit_move_after_reload (rtx, rtx, rtx); +static rtx simplify_logical (enum machine_mode, int, rtx, rtx *); +static void m68hc11_emit_logical (enum machine_mode, int, rtx *); +static void m68hc11_reorg (void); +static int go_if_legitimate_address_internal (rtx, enum machine_mode, int); +static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx); +static int must_parenthesize (rtx); +static int m68hc11_address_cost (rtx, bool); +static int m68hc11_shift_cost (enum machine_mode, rtx, int); +static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code); +static bool m68hc11_rtx_costs (rtx, int, int, int *, bool); +static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *); const struct attribute_spec m68hc11_attribute_table[]; -void create_regs_rtx PARAMS ((void)); -static void m68hc11_add_gc_roots PARAMS ((void)); - -static void asm_print_register PARAMS ((FILE *, int)); -static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT)); -static void m68hc11_asm_out_constructor PARAMS ((rtx, int)); -static void m68hc11_asm_out_destructor PARAMS ((rtx, int)); - -rtx m68hc11_soft_tmp_reg; +void create_regs_rtx (void); + +static void asm_print_register (FILE *, int); +static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT); +static void m68hc11_asm_out_constructor (rtx, int); +static void m68hc11_asm_out_destructor (rtx, int); +static void m68hc11_file_start (void); +static void m68hc11_encode_section_info (tree, rtx, int); +static const char *m68hc11_strip_name_encoding (const char* str); +static unsigned int m68hc11_section_type_flags (tree, const char*, int); +static int autoinc_mode (rtx); +static int m68hc11_make_autoinc_notes (rtx *, void *); +static void m68hc11_init_libfuncs (void); +static rtx m68hc11_struct_value_rtx (tree, int); +static bool m68hc11_return_in_memory (const_tree, const_tree); /* Must be set to 1 to produce debug messages. */ int debug_m6811 = 0; @@ -88,11 +98,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; -static rtx z_reg; /* Set to 1 by expand_prologue() when the function is an interrupt handler. */ int current_function_interrupt; @@ -100,6 +111,10 @@ int current_function_interrupt; /* Set to 1 by expand_prologue() when the function is a trap handler. */ int current_function_trap; +/* Set to 1 when the current function is placed in 68HC12 banked + memory and must return with rtc. */ +int current_function_far; + /* Min offset that is valid for the indirect addressing mode. */ HOST_WIDE_INT m68hc11_min_offset = 0; @@ -124,6 +139,9 @@ unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER]; This is 1 for 68HC11 and 0 for 68HC12. */ int m68hc11_sp_correction; +int m68hc11_addr_mode; +int m68hc11_mov_addr_mode; + /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */ rtx m68hc11_compare_op0; rtx m68hc11_compare_op1; @@ -200,14 +218,6 @@ static const struct processor_costs m6812_cost = { /* divSI */ COSTS_N_INSNS (100) }; - -/* Machine specific options */ - -const char *m68hc11_regparm_string; -const char *m68hc11_reg_alloc_order; -const char *m68hc11_soft_reg_count; - -static int nb_soft_regs; /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE @@ -219,13 +229,46 @@ static int nb_soft_regs; #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START m68hc11_file_start +#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE +#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true + +#undef TARGET_DEFAULT_TARGET_FLAGS +#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT + +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info + +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS m68hc11_rtx_costs +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST m68hc11_address_cost + +#undef TARGET_MACHINE_DEPENDENT_REORG +#define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg + +#undef TARGET_INIT_LIBFUNCS +#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory +#undef TARGET_CALLEE_COPIES +#define TARGET_CALLEE_COPIES hook_callee_copies_named + +#undef TARGET_STRIP_NAME_ENCODING +#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding + struct gcc_target targetm = TARGET_INITIALIZER; int -m68hc11_override_options () +m68hc11_override_options (void) { - m68hc11_add_gc_roots (); - memset (m68hc11_reg_valid_for_index, 0, sizeof (m68hc11_reg_valid_for_index)); memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base)); @@ -233,21 +276,20 @@ m68hc11_override_options () /* Compilation with -fpic generates a wrong code. */ if (flag_pic) { - warning ("-f%s ignored for 68HC11/68HC12 (not supported)", + warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)", (flag_pic > 1) ? "PIC" : "pic"); flag_pic = 0; } + /* Do not enable -fweb because it breaks the 32-bit shift patterns + by breaking the match_dup of those patterns. The shift patterns + will no longer be recognized after that. */ + flag_web = 0; + /* Configure for a 68hc11 processor. */ if (TARGET_M6811) { - /* If gcc was built for a 68hc12, invalidate that because - a -m68hc11 option was specified on the command line. */ - if (TARGET_DEFAULT != MASK_M6811) - target_flags &= ~TARGET_DEFAULT; - - if (!TARGET_M6812) - target_flags &= ~TARGET_AUTO_INC_DEC; + target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX); m68hc11_cost = &m6811_cost; m68hc11_min_offset = 0; m68hc11_max_offset = 256; @@ -258,8 +300,10 @@ m68hc11_override_options () m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1; m68hc11_sp_correction = 1; m68hc11_tmp_regs_class = D_REGS; - if (m68hc11_soft_reg_count == 0 && !TARGET_M6812) - m68hc11_soft_reg_count = "4"; + m68hc11_addr_mode = ADDR_OFFSET; + m68hc11_mov_addr_mode = 0; + if (m68hc11_soft_reg_count < 0) + m68hc11_soft_reg_count = 4; } /* Configure for a 68hc12 processor. */ @@ -277,43 +321,30 @@ m68hc11_override_options () m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1; m68hc11_sp_correction = 0; m68hc11_tmp_regs_class = TMP_REGS; - target_flags &= ~MASK_M6811; + m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST + | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); + m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST + | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0); target_flags |= MASK_NO_DIRECT_MODE; - if (m68hc11_soft_reg_count == 0) - m68hc11_soft_reg_count = "0"; - } - return 0; -} + if (m68hc11_soft_reg_count < 0) + m68hc11_soft_reg_count = 0; - -int -m68hc11_optimization_options (level, size) - int level ATTRIBUTE_UNUSED; - int size; -{ - /* When optimizing for size, do not reorder basic blocks because - it duplicates some insns for speed and this results in larder code. - This reordering can still be enabled but explicitly. */ - if (size) - { - flag_reorder_blocks = 0; + if (TARGET_LONG_CALLS) + current_function_far = 1; } return 0; } + void -m68hc11_conditional_register_usage () +m68hc11_conditional_register_usage (void) { int i; - int cnt = atoi (m68hc11_soft_reg_count); - if (cnt < 0) - cnt = 0; - if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST) - cnt = SOFT_REG_LAST - SOFT_REG_FIRST; + if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST) + m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST; - nb_soft_regs = cnt; - for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++) + for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++) { fixed_regs[i] = 1; call_used_regs[i] = 1; @@ -331,48 +362,44 @@ m68hc11_conditional_register_usage () /* Reload and register operations. */ -static const char *const reg_class_names[] = REG_CLASS_NAMES; - void -create_regs_rtx () +create_regs_rtx (void) { /* regs_inited = 1; */ - 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, - gen_rtx (PRE_DEC, HImode, - gen_rtx (REG, HImode, HARD_SP_REGNUM))); - stack_pop_word = gen_rtx (MEM, HImode, - gen_rtx (POST_INC, HImode, - gen_rtx (REG, HImode, HARD_SP_REGNUM))); + 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); + m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM); + + stack_push_word = gen_rtx_MEM (HImode, + gen_rtx_PRE_DEC (HImode, + gen_rtx_REG (HImode, HARD_SP_REGNUM))); + stack_pop_word = gen_rtx_MEM (HImode, + gen_rtx_POST_INC (HImode, + gen_rtx_REG (HImode, HARD_SP_REGNUM))); } /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. - - 8 bit values are stored anywhere (except the SP register). - - 16 bit values can be stored in any register whose mode is 16 - - 32 bit values can be stored in D, X registers or in a soft register + - 8-bit values are stored anywhere (except the SP register). + - 16-bit values can be stored in any register whose mode is 16 + - 32-bit values can be stored in D, X registers or in a soft register (except the last one because we need 2 soft registers) - Values whose size is > 32 bit are not stored in real hard registers. They may be stored in soft registers if there are enough of them. */ int -hard_regno_mode_ok (regno, mode) - int regno; - enum machine_mode mode; +hard_regno_mode_ok (int regno, enum machine_mode mode) { switch (GET_MODE_SIZE (mode)) { case 8: - return S_REGNO_P (regno) && nb_soft_regs >= 4; + return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4; case 4: - return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2); + return (X_REGNO_P (regno) + || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2)); case 2: return G_REGNO_P (regno); @@ -391,10 +418,24 @@ hard_regno_mode_ok (regno, mode) } } +int +m68hc11_hard_regno_rename_ok (int reg1, int 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; - enum reg_class class; +preferred_reload_class (rtx operand, enum reg_class rclass) { enum machine_mode mode; @@ -402,97 +443,97 @@ preferred_reload_class (operand, class) if (debug_m6811) { - printf ("Preferred reload: (class=%s): ", reg_class_names[class]); + printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]); } - if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand)) + if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand)) return m68hc11_base_reg_class; - if (class >= S_REGS && (GET_CODE (operand) == MEM + if (rclass >= S_REGS && (GET_CODE (operand) == MEM || GET_CODE (operand) == CONST_INT)) { /* S_REGS class must not be used. The movhi template does not work to move a memory to a soft register. Restrict to a hard reg. */ - switch (class) + switch (rclass) { default: case G_REGS: case D_OR_A_OR_S_REGS: - class = A_OR_D_REGS; + rclass = A_OR_D_REGS; break; case A_OR_S_REGS: - class = A_REGS; + rclass = A_REGS; break; case D_OR_SP_OR_S_REGS: - class = D_OR_SP_REGS; + rclass = D_OR_SP_REGS; break; case D_OR_Y_OR_S_REGS: - class = D_OR_Y_REGS; + rclass = D_OR_Y_REGS; break; case D_OR_X_OR_S_REGS: - class = D_OR_X_REGS; + rclass = D_OR_X_REGS; break; case SP_OR_S_REGS: - class = SP_REGS; + rclass = SP_REGS; break; case Y_OR_S_REGS: - class = Y_REGS; + rclass = Y_REGS; break; case X_OR_S_REGS: - class = X_REGS; + rclass = X_REGS; break; case D_OR_S_REGS: - class = D_REGS; + rclass = D_REGS; } } - else if (class == Y_REGS && GET_CODE (operand) == MEM) + else if (rclass == Y_REGS && GET_CODE (operand) == MEM) { - class = Y_REGS; + rclass = Y_REGS; } - else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4) + else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4) { - class = D_OR_X_REGS; + rclass = D_OR_X_REGS; } - else if (class >= S_REGS && S_REG_P (operand)) + else if (rclass >= S_REGS && S_REG_P (operand)) { - switch (class) + switch (rclass) { default: case G_REGS: case D_OR_A_OR_S_REGS: - class = A_OR_D_REGS; + rclass = A_OR_D_REGS; break; case A_OR_S_REGS: - class = A_REGS; + rclass = A_REGS; break; case D_OR_SP_OR_S_REGS: - class = D_OR_SP_REGS; + rclass = D_OR_SP_REGS; break; case D_OR_Y_OR_S_REGS: - class = D_OR_Y_REGS; + rclass = D_OR_Y_REGS; break; case D_OR_X_OR_S_REGS: - class = D_OR_X_REGS; + rclass = D_OR_X_REGS; break; case SP_OR_S_REGS: - class = SP_REGS; + rclass = SP_REGS; break; case Y_OR_S_REGS: - class = Y_REGS; + rclass = Y_REGS; break; case X_OR_S_REGS: - class = X_REGS; + rclass = X_REGS; break; case D_OR_S_REGS: - class = D_REGS; + rclass = D_REGS; } } - else if (class >= S_REGS) + else if (rclass >= S_REGS) { if (debug_m6811) { - printf ("Class = %s for: ", reg_class_names[class]); + printf ("Class = %s for: ", reg_class_names[rclass]); fflush (stdout); debug_rtx (operand); } @@ -500,33 +541,37 @@ preferred_reload_class (operand, class) if (debug_m6811) { - printf (" => class=%s\n", reg_class_names[class]); + printf (" => class=%s\n", reg_class_names[rclass]); fflush (stdout); debug_rtx (operand); } - return class; + return rclass; } /* Return 1 if the operand is a valid indexed addressing mode. For 68hc11: n,r with n in [0..255] and r in A_REGS class For 68hc12: n,r no constraint on the constant, r in A_REGS class. */ -static int -register_indirect_p (operand, mode, strict) - rtx operand; - enum machine_mode mode; - int strict; +int +m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode) { rtx base, offset; switch (GET_CODE (operand)) { + case MEM: + if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2) + return m68hc11_valid_addressing_p (XEXP (operand, 0), mode, + addr_mode & (ADDR_STRICT | ADDR_OFFSET)); + return 0; + case POST_INC: case PRE_INC: case POST_DEC: case PRE_DEC: - if (TARGET_M6812 && TARGET_AUTO_INC_DEC) - return register_indirect_p (XEXP (operand, 0), mode, strict); + if (addr_mode & ADDR_INCDEC) + return m68hc11_valid_addressing_p (XEXP (operand, 0), mode, + addr_mode & ADDR_STRICT); return 0; case PLUS: @@ -538,36 +583,57 @@ register_indirect_p (operand, mode, strict) if (GET_CODE (offset) == MEM) return 0; + /* Indexed addressing mode with 2 registers. */ + if (GET_CODE (base) == REG && GET_CODE (offset) == REG) + { + if (!(addr_mode & ADDR_INDEXED)) + return 0; + + addr_mode &= ADDR_STRICT; + if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode) + && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode)) + return 1; + + if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode) + && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode)) + return 1; + + return 0; + } + + if (!(addr_mode & ADDR_OFFSET)) + return 0; + if (GET_CODE (base) == REG) { - if (!VALID_CONSTANT_OFFSET_P (offset, mode)) + if (!VALID_CONSTANT_OFFSET_P (offset, mode)) return 0; - if (strict == 0) + if (!(addr_mode & ADDR_STRICT)) return 1; - return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict); + return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1); } + if (GET_CODE (offset) == REG) { if (!VALID_CONSTANT_OFFSET_P (base, mode)) return 0; - if (strict == 0) + if (!(addr_mode & ADDR_STRICT)) return 1; - return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict); + return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1); } return 0; case REG: - return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict); + return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT); case CONST_INT: - if (TARGET_M6811) - return 0; - - return VALID_CONSTANT_OFFSET_P (operand, mode); + if (addr_mode & ADDR_CONST) + return VALID_CONSTANT_OFFSET_P (operand, mode); + return 0; default: return 0; @@ -577,11 +643,10 @@ register_indirect_p (operand, mode, strict) /* Returns 1 if the operand fits in a 68HC11 indirect mode or in a 68HC12 1-byte index addressing mode. */ int -m68hc11_small_indexed_indirect_p (operand, mode) - rtx operand; - enum machine_mode mode; +m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode) { rtx base, offset; + int addr_mode; if (GET_CODE (operand) == REG && reload_in_progress && REGNO (operand) >= FIRST_PSEUDO_REGISTER @@ -601,7 +666,8 @@ m68hc11_small_indexed_indirect_p (operand, mode) if (PUSH_POP_ADDRESS_P (operand)) return 1; - if (!register_indirect_p (operand, mode, reload_completed)) + addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0); + if (!m68hc11_valid_addressing_p (operand, mode, addr_mode)) return 0; if (TARGET_M6812 && GET_CODE (operand) == PLUS @@ -640,25 +706,32 @@ m68hc11_small_indexed_indirect_p (operand, mode) } int -m68hc11_register_indirect_p (operand, mode) - rtx operand; - enum machine_mode mode; +m68hc11_register_indirect_p (rtx operand, enum machine_mode mode) { + int addr_mode; + + if (GET_CODE (operand) == REG && reload_in_progress + && REGNO (operand) >= FIRST_PSEUDO_REGISTER + && reg_equiv_memory_loc[REGNO (operand)]) + { + operand = reg_equiv_memory_loc[REGNO (operand)]; + operand = eliminate_regs (operand, 0, NULL_RTX); + } if (GET_CODE (operand) != MEM) return 0; operand = XEXP (operand, 0); - return register_indirect_p (operand, mode, - (reload_completed | reload_in_progress)); + addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); + return m68hc11_valid_addressing_p (operand, mode, addr_mode); } static int -go_if_legitimate_address_internal (operand, mode, strict) - rtx operand; - enum machine_mode mode; - int strict; +go_if_legitimate_address_internal (rtx operand, enum machine_mode mode, + int strict) { - if (CONSTANT_ADDRESS_P (operand)) + int addr_mode; + + if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812) { /* Reject the global variables if they are too wide. This forces a load of their address in a register and generates smaller code. */ @@ -667,7 +740,8 @@ go_if_legitimate_address_internal (operand, mode, strict) return 1; } - if (register_indirect_p (operand, mode, strict)) + addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0); + if (m68hc11_valid_addressing_p (operand, mode, addr_mode)) { return 1; } @@ -683,10 +757,8 @@ go_if_legitimate_address_internal (operand, mode, strict) } int -m68hc11_go_if_legitimate_address (operand, mode, strict) - rtx operand; - enum machine_mode mode; - int strict; +m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode, + int strict) { int result; @@ -718,18 +790,16 @@ m68hc11_go_if_legitimate_address (operand, mode, strict) } int -m68hc11_legitimize_address (operand, old_operand, mode) - rtx *operand ATTRIBUTE_UNUSED; - rtx old_operand ATTRIBUTE_UNUSED; - enum machine_mode mode ATTRIBUTE_UNUSED; +m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED, + rtx old_operand ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) { return 0; } int -m68hc11_reload_operands (operands) - rtx operands[]; +m68hc11_reload_operands (rtx operands[]) { enum machine_mode mode; @@ -752,9 +822,9 @@ m68hc11_reload_operands (operands) } /* If the offset is out of range, we have to compute the address - with a separate add instruction. We try to do with with an 8-bit + with a separate add instruction. We try to do this with an 8-bit add on the A register. This is possible only if the lowest part - of the offset (ie, big_offset % 256) is a valid constant offset + of the offset (i.e., big_offset % 256) is a valid constant offset with respect to the mode. If it's not, we have to generate a 16-bit add on the D register. From: @@ -802,19 +872,19 @@ m68hc11_reload_operands (operands) offset = GEN_INT (vl); if (!VALID_CONSTANT_OFFSET_P (offset, mode)) { - emit_insn (gen_rtx (SET, VOIDmode, reg, - gen_rtx (PLUS, HImode, reg, big_offset))); + emit_insn (gen_rtx_SET (VOIDmode, reg, + gen_rtx_PLUS (HImode, reg, big_offset))); offset = const0_rtx; } else { - emit_insn (gen_rtx (SET, VOIDmode, reg, - gen_rtx (PLUS, HImode, reg, + emit_insn (gen_rtx_SET (VOIDmode, reg, + gen_rtx_PLUS (HImode, reg, GEN_INT (vh << 8)))); } emit_move_insn (operands[0], - gen_rtx (MEM, GET_MODE (operands[1]), - gen_rtx (PLUS, Pmode, reg, offset))); + gen_rtx_MEM (GET_MODE (operands[1]), + gen_rtx_PLUS (Pmode, reg, offset))); return 1; } } @@ -824,13 +894,9 @@ m68hc11_reload_operands (operands) } void -m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands) - const char *name; - enum rtx_code code; - enum machine_mode dmode; - enum machine_mode smode; - int noperands; - rtx *operands; +m68hc11_emit_libcall (const char *name, enum rtx_code code, + enum machine_mode dmode, enum machine_mode smode, + int noperands, rtx *operands) { rtx ret; rtx insns; @@ -844,7 +910,7 @@ m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands) case 2: ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST, dmode, 1, operands[1], smode); - equiv = gen_rtx (code, dmode, operands[1]); + equiv = gen_rtx_fmt_e (code, dmode, operands[1]); break; case 3: @@ -852,11 +918,11 @@ m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands) LCT_CONST, dmode, 2, operands[1], smode, operands[2], smode); - equiv = gen_rtx (code, dmode, operands[1], operands[2]); + equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]); break; default: - abort (); + gcc_unreachable (); } insns = get_insns (); @@ -867,9 +933,8 @@ m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands) /* Returns true if X is a PRE/POST increment decrement (same as auto_inc_p() in rtlanal.c but do not take into account the stack). */ -static int -m68hc11_auto_inc_p (x) - rtx x; +int +m68hc11_auto_inc_p (rtx x) { return GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC @@ -880,9 +945,7 @@ m68hc11_auto_inc_p (x) /* Predicates for machine description. */ int -memory_reload_operand (operand, mode) - rtx operand; - enum machine_mode mode ATTRIBUTE_UNUSED; +memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED) { return GET_CODE (operand) == MEM && GET_CODE (XEXP (operand, 0)) == PLUS @@ -893,74 +956,7 @@ memory_reload_operand (operand, mode) } int -tst_operand (operand, mode) - rtx operand; - enum machine_mode mode; -{ - if (GET_CODE (operand) == MEM && reload_completed == 0) - { - rtx addr = XEXP (operand, 0); - if (m68hc11_auto_inc_p (addr)) - return 0; - } - return nonimmediate_operand (operand, mode); -} - -int -cmp_operand (operand, mode) - rtx operand; - enum machine_mode mode; -{ - if (GET_CODE (operand) == MEM) - { - rtx addr = XEXP (operand, 0); - if (m68hc11_auto_inc_p (addr)) - return 0; - } - return general_operand (operand, mode); -} - -int -non_push_operand (operand, mode) - rtx operand; - enum machine_mode mode; -{ - if (general_operand (operand, mode) == 0) - return 0; - - if (push_operand (operand, mode) == 1) - return 0; - return 1; -} - -int -reg_or_some_mem_operand (operand, mode) - rtx operand; - enum machine_mode mode; -{ - if (GET_CODE (operand) == MEM) - { - rtx op = XEXP (operand, 0); - - if (symbolic_memory_operand (op, mode)) - return 1; - - if (IS_STACK_PUSH (operand)) - return 1; - - if (m68hc11_register_indirect_p (operand, mode)) - return 1; - - return 0; - } - - return register_operand (operand, mode); -} - -int -m68hc11_symbolic_p (operand, mode) - rtx operand; - enum machine_mode mode; +m68hc11_symbolic_p (rtx operand, enum machine_mode mode) { if (GET_CODE (operand) == MEM) { @@ -973,79 +969,31 @@ m68hc11_symbolic_p (operand, mode) } int -m68hc11_indirect_p (operand, mode) - rtx operand; - enum machine_mode mode; +m68hc11_indirect_p (rtx operand, enum machine_mode mode) { - if (GET_CODE (operand) == MEM) + if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode) { rtx op = XEXP (operand, 0); + int addr_mode; + + if (m68hc11_page0_symbol_p (op)) + return 1; if (symbolic_memory_operand (op, mode)) - return 0; + return TARGET_M6812; if (reload_in_progress) return 1; operand = XEXP (operand, 0); - return register_indirect_p (operand, mode, reload_completed); + addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); + return m68hc11_valid_addressing_p (operand, mode, addr_mode); } return 0; } int -stack_register_operand (operand, mode) - rtx operand; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - return SP_REG_P (operand); -} - -int -d_register_operand (operand, mode) - rtx operand; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - if (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); - - return GET_CODE (operand) == REG - && (REGNO (operand) >= FIRST_PSEUDO_REGISTER - || REGNO (operand) == HARD_D_REGNUM - || (mode == QImode && REGNO (operand) == HARD_B_REGNUM)); -} - -int -hard_addr_reg_operand (operand, mode) - rtx operand; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - if (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); - - return GET_CODE (operand) == REG - && (REGNO (operand) == HARD_X_REGNUM - || REGNO (operand) == HARD_Y_REGNUM - || REGNO (operand) == HARD_Z_REGNUM); -} - -int -hard_reg_operand (operand, mode) - rtx operand; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - if (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); - - return GET_CODE (operand) == REG - && (REGNO (operand) >= FIRST_PSEUDO_REGISTER - || H_REGNO_P (REGNO (operand))); -} - -int -memory_indexed_operand (operand, mode) - rtx operand; - enum machine_mode mode ATTRIBUTE_UNUSED; +memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED) { if (GET_CODE (operand) != MEM) return 0; @@ -1064,8 +1012,7 @@ memory_indexed_operand (operand, mode) } int -push_pop_operand_p (operand) - rtx operand; +push_pop_operand_p (rtx operand) { if (GET_CODE (operand) != MEM) { @@ -1079,9 +1026,7 @@ push_pop_operand_p (operand) reference and a constant. */ int -symbolic_memory_operand (op, mode) - register rtx op; - enum machine_mode mode; +symbolic_memory_operand (rtx op, enum machine_mode mode) { switch (GET_CODE (op)) { @@ -1107,45 +1052,6 @@ symbolic_memory_operand (op, mode) return 0; } } - -int -m68hc11_logical_operator (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR; -} - -int -m68hc11_arith_operator (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR - || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS - || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT - || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE - || GET_CODE (op) == ROTATERT; -} - -int -m68hc11_non_shift_operator (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR - || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS; -} - - -int -m68hc11_unary_operator (op, mode) - register rtx op; - enum machine_mode mode ATTRIBUTE_UNUSED; -{ - return GET_CODE (op) == NEG || GET_CODE (op) == NOT - || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND; -} /* Emit the code to build the trampoline used to call a nested function. @@ -1157,10 +1063,7 @@ m68hc11_unary_operator (op, mode) */ void -m68hc11_initialize_trampoline (tramp, fnaddr, cxt) - rtx tramp; - rtx fnaddr; - rtx cxt; +m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt) { const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM]; @@ -1197,89 +1100,195 @@ m68hc11_initialize_trampoline (tramp, fnaddr, cxt) /* Declaration of types. */ +/* Handle an "tiny_data" attribute; arguments as in + struct attribute_spec.handler. */ +static tree +m68hc11_handle_page0_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + tree decl = *node; + + if (TREE_STATIC (decl) || DECL_EXTERNAL (decl)) + { + DECL_SECTION_NAME (decl) = build_string (6, ".page0"); + } + else + { + warning (OPT_Wattributes, "%qs attribute ignored", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + 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 }, + { "page0", 0, 0, false, false, false, m68hc11_handle_page0_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 -m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs) - tree *node; - tree name; - tree args ATTRIBUTE_UNUSED; - int flags ATTRIBUTE_UNUSED; - bool *no_add_attrs; +m68hc11_handle_fntype_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + 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) { - warning ("`%s' attribute only applies to functions", + warning (OPT_Wattributes, "%qs attribute only applies to functions", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE; } +/* Undo the effects of the above. */ -/* Define this macro if references to a symbol must be treated - differently depending on something about the variable or function - named by the symbol (such as what section it is in). +static const char * +m68hc11_strip_name_encoding (const char *str) +{ + return str + (*str == '*' || *str == '@' || *str == '&'); +} - For the 68HC11, we want to recognize trap handlers so that we - handle calls to traps in a special manner (by issuing the trap). - This information is stored in SYMBOL_REF_FLAG. */ -void -m68hc11_encode_section_info (decl) - tree decl; +static void +m68hc11_encode_label (tree decl) +{ + const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0); + int len = strlen (str); + char *newstr = XALLOCAVEC (char, len + 2); + + newstr[0] = '@'; + strcpy (&newstr[1], str); + + XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1); +} + +/* Return 1 if this is a symbol in page0 */ +int +m68hc11_page0_symbol_p (rtx x) +{ + switch (GET_CODE (x)) + { + case SYMBOL_REF: + return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@'; + + case CONST: + return m68hc11_page0_symbol_p (XEXP (x, 0)); + + case PLUS: + if (!m68hc11_page0_symbol_p (XEXP (x, 0))) + return 0; + + return GET_CODE (XEXP (x, 1)) == CONST_INT + && INTVAL (XEXP (x, 1)) < 256 + && INTVAL (XEXP (x, 1)) >= 0; + + default: + return 0; + } +} + +/* We want to recognize trap handlers so that we handle calls to traps + in a special manner (by issuing the trap). This information is stored + in SYMBOL_REF_FLAG. */ + +static void +m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) { tree func_attr; int trap_handler; - rtx rtl; + int is_far = 0; + + if (TREE_CODE (decl) == VAR_DECL) + { + if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0) + m68hc11_encode_label (decl); + return; + } 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 (OPT_Wattributes, "% and % attributes are " + "not compatible, ignoring %"); + trap_handler = 0; + } + if (trap_handler) + { + if (trap_handler_symbol != 0) + warning (OPT_Wattributes, "% attribute is already used"); + else + trap_handler_symbol = XEXP (rtl, 0); + } + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far; } - -/* Argument support functions. */ +static unsigned int +m68hc11_section_type_flags (tree decl, const char *name, int reloc) +{ + unsigned int flags = default_section_type_flags (decl, name, reloc); + + if (strncmp (name, ".eeprom", 7) == 0) + { + flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE; + } + + return flags; +} + +int +m68hc11_is_far_symbol (rtx sym) +{ + if (GET_CODE (sym) == MEM) + sym = XEXP (sym, 0); -/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro. - Arrays are passed by references and other types by value. + return SYMBOL_REF_FLAG (sym); +} - SCz: I tried to pass DImode by reference but it seems that this - does not work very well. */ int -m68hc11_function_arg_pass_by_reference (cum, mode, type, named) - const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; - enum machine_mode mode ATTRIBUTE_UNUSED; - tree type; - int named ATTRIBUTE_UNUSED; +m68hc11_is_trap_symbol (rtx sym) { - return ((type && TREE_CODE (type) == ARRAY_TYPE) - /* Consider complex values as aggregates, so care for TCmode. */ - /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */ - /*|| (type && AGGREGATE_TYPE_P (type))) */ ); + if (GET_CODE (sym) == MEM) + sym = XEXP (sym, 0); + + return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym); } + +/* Argument support functions. */ /* Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */ int -m68hc11_initial_elimination_offset (from, to) - int from; - int to; +m68hc11_initial_elimination_offset (int from, int to) { int trap_handler; tree func_attr; @@ -1289,9 +1298,26 @@ 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)); + current_function_interrupt = lookup_attribute ("interrupt", + func_attr) != NULL_TREE; trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE; + + 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 + && !current_function_interrupt + && !trap_handler); + if (trap_handler && from == ARG_POINTER_REGNUM) size = 7; + + /* For a function using 'call/rtc' we must take into account the + page register which is pushed in the call. */ + else if (current_function_far && from == ARG_POINTER_REGNUM) + size = 1; else size = 0; @@ -1310,7 +1336,7 @@ m68hc11_initial_elimination_offset (from, to) /* Push any 2 byte pseudo hard registers that we need to save. */ for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++) { - if (regs_ever_live[regno] && !call_used_regs[regno]) + if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) { size += 2; } @@ -1333,10 +1359,7 @@ m68hc11_initial_elimination_offset (from, to) For a library call, FNTYPE is 0. */ void -m68hc11_init_cumulative_args (cum, fntype, libname) - CUMULATIVE_ARGS *cum; - tree fntype; - rtx libname; +m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname) { tree ret_type; @@ -1377,7 +1400,7 @@ m68hc11_init_cumulative_args (cum, fntype, libname) ret_type = TREE_TYPE (fntype); - if (ret_type && aggregate_value_p (ret_type)) + if (ret_type && aggregate_value_p (ret_type, fntype)) { cum->words = 1; cum->nregs = 1; @@ -1389,11 +1412,8 @@ m68hc11_init_cumulative_args (cum, fntype, libname) (TYPE is null for libcalls where that information may not be available.) */ void -m68hc11_function_arg_advance (cum, mode, type, named) - CUMULATIVE_ARGS *cum; - enum machine_mode mode; - tree type; - int named ATTRIBUTE_UNUSED; +m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type, int named ATTRIBUTE_UNUSED) { if (mode != BLKmode) { @@ -1430,11 +1450,8 @@ m68hc11_function_arg_advance (cum, mode, type, named) (otherwise it is an extra parameter matching an ellipsis). */ struct rtx_def * -m68hc11_function_arg (cum, mode, type, named) - const CUMULATIVE_ARGS *cum; - enum machine_mode mode; - tree type ATTRIBUTE_UNUSED; - int named ATTRIBUTE_UNUSED; +m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) { if (cum->words != 0) { @@ -1444,85 +1461,17 @@ m68hc11_function_arg (cum, mode, type, named) if (mode != BLKmode) { if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE) - return gen_rtx (REG, mode, HARD_X_REGNUM); + return gen_rtx_REG (mode, HARD_X_REGNUM); if (GET_MODE_SIZE (mode) > HARD_REG_SIZE) { return NULL_RTX; } - return gen_rtx (REG, mode, HARD_D_REGNUM); + return gen_rtx_REG (mode, HARD_D_REGNUM); } return NULL_RTX; } -/* The "standard" implementation of va_start: just assign `nextarg' to - the variable. */ -void -m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg) - int stdarg_p ATTRIBUTE_UNUSED; - tree valist; - rtx nextarg; -{ - tree t; - - /* SCz: the default implementation in builtins.c adjust the - nextarg using UNITS_PER_WORD. This works only with -mshort - and fails when integers are 32-bit. Here is the correct way. */ - if (!stdarg_p) - nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8); - - t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, - make_tree (ptr_type_node, nextarg)); - TREE_SIDE_EFFECTS (t) = 1; - - expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); -} - -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, @@ -1530,21 +1479,13 @@ m68hc11_va_arg (valist, type) Structures are stored left shifted in their argument slot. */ int -m68hc11_function_arg_padding (mode, type) - enum machine_mode mode; - tree type; +m68hc11_function_arg_padding (enum machine_mode mode, const_tree type) { if (type != 0 && AGGREGATE_TYPE_P (type)) return upward; - /* This is the default definition. */ - return (!BYTES_BIG_ENDIAN - ? upward - : ((mode == BLKmode - ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST - && int_size_in_bytes (type) < - (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) < - PARM_BOUNDARY) ? downward : upward)); + /* Fall back to the default. */ + return DEFAULT_FUNCTION_ARG_PADDING (mode, type); } @@ -1553,8 +1494,7 @@ m68hc11_function_arg_padding (mode, type) /* Emit a move after the reload pass has completed. This is used to emit the prologue and epilogue. */ static void -emit_move_after_reload (to, from, scratch) - rtx to, from, scratch; +emit_move_after_reload (rtx to, rtx from, rtx scratch) { rtx insn; @@ -1596,7 +1536,7 @@ emit_move_after_reload (to, from, scratch) } int -m68hc11_total_frame_size () +m68hc11_total_frame_size (void) { int size; int regno; @@ -1610,16 +1550,15 @@ m68hc11_total_frame_size () size += HARD_REG_SIZE; for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) - if (regs_ever_live[regno] && !call_used_regs[regno]) + if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) size += HARD_REG_SIZE; return size; } static void -m68hc11_output_function_epilogue (out, size) - FILE *out ATTRIBUTE_UNUSED; - HOST_WIDE_INT size ATTRIBUTE_UNUSED; +m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED, + HOST_WIDE_INT size ATTRIBUTE_UNUSED) { /* We catch the function epilogue generation to have a chance to clear the z_replacement_completed flag. */ @@ -1627,15 +1566,14 @@ m68hc11_output_function_epilogue (out, size) } void -expand_prologue () +expand_prologue (void) { tree func_attr; int size; int regno; rtx scratch; - if (reload_completed != 1) - abort (); + gcc_assert (reload_completed == 1); size = get_frame_size (); @@ -1646,16 +1584,28 @@ 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 + && !current_function_interrupt + && !current_function_trap); /* Get the scratch register to build the frame and push registers. If the first argument is a 32-bit quantity, the D+X registers are used. Use Y to compute the frame. Otherwise, X is cheaper. For 68HC12, this scratch register is not used. */ - if (current_function_args_info.nregs == 2) + if (crtl->args.info.nregs == 2) scratch = iy_reg; else scratch = ix_reg; + /* Save current stack frame. */ + if (frame_pointer_needed) + emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch); + /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy. Other soft registers in page0 need not to be saved because they will be restored by C functions. For a trap handler, we don't @@ -1664,23 +1614,19 @@ expand_prologue () { emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch); emit_move_after_reload (stack_push_word, - gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch); + gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch); emit_move_after_reload (stack_push_word, - gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM), + gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), scratch); } - /* Save current stack frame. */ - if (frame_pointer_needed) - emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch); - /* Allocate local variables. */ if (TARGET_M6812 && (size > 4 || size == 3)) { 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; @@ -1705,7 +1651,7 @@ expand_prologue () if (size & 1) emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (-1))); + stack_pointer_rtx, constm1_rtx)); } /* Create the frame pointer. */ @@ -1716,38 +1662,37 @@ expand_prologue () /* Push any 2 byte pseudo hard registers that we need to save. */ for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++) { - if (regs_ever_live[regno] && !call_used_regs[regno]) + if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) { emit_move_after_reload (stack_push_word, - gen_rtx (REG, HImode, regno), scratch); + gen_rtx_REG (HImode, regno), scratch); } } } void -expand_epilogue () +expand_epilogue (void) { int size; register int regno; int return_size; rtx scratch; - if (reload_completed != 1) - abort (); + gcc_assert (reload_completed == 1); size = get_frame_size (); /* If we are returning a value in two registers, we have to preserve the X register and use the Y register to restore the stack and the saved registers. Otherwise, use X because it's faster (and smaller). */ - if (current_function_return_rtx == 0) + if (crtl->return_rtx == 0) return_size = 0; - else if (GET_CODE (current_function_return_rtx) == MEM) + else if (GET_CODE (crtl->return_rtx) == MEM) return_size = HARD_REG_SIZE; else - return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx)); + return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx)); - if (return_size > HARD_REG_SIZE) + if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE) scratch = iy_reg; else scratch = ix_reg; @@ -1755,9 +1700,9 @@ expand_epilogue () /* Pop any 2 byte pseudo hard registers that we saved. */ for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--) { - if (regs_ever_live[regno] && !call_used_regs[regno]) + if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) { - emit_move_after_reload (gen_rtx (REG, HImode, regno), + emit_move_after_reload (gen_rtx_REG (HImode, regno), stack_pop_word, scratch); } } @@ -1768,7 +1713,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; @@ -1791,23 +1736,23 @@ expand_epilogue () emit_move_after_reload (scratch, stack_pop_word, scratch); if (size & 1) emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (1))); + stack_pointer_rtx, const1_rtx)); } - /* Restore previous frame pointer. */ - if (frame_pointer_needed) - emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch); - /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */ if (current_function_interrupt) { - emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM), + emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM), stack_pop_word, scratch); - emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM), + emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM), stack_pop_word, scratch); emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch); } + /* Restore previous frame pointer. */ + if (frame_pointer_needed) + emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch); + /* If the trap handler returns some value, copy the value in D, X onto the stack so that the rti will pop the return value correctly. */ @@ -1820,12 +1765,12 @@ expand_epilogue () emit_move_after_reload (scratch, stack_pointer_rtx, 0); addr_reg = scratch; } - emit_move_after_reload (gen_rtx (MEM, HImode, - gen_rtx (PLUS, HImode, addr_reg, - GEN_INT (1))), d_reg, 0); + emit_move_after_reload (gen_rtx_MEM (HImode, + gen_rtx_PLUS (HImode, addr_reg, + const1_rtx)), d_reg, 0); if (return_size > HARD_REG_SIZE) - emit_move_after_reload (gen_rtx (MEM, HImode, - gen_rtx (PLUS, HImode, addr_reg, + emit_move_after_reload (gen_rtx_MEM (HImode, + gen_rtx_PLUS (HImode, addr_reg, GEN_INT (3))), ix_reg, 0); } @@ -1838,16 +1783,14 @@ expand_epilogue () fixed to work for constants and 68HC11 specific registers. */ rtx -m68hc11_gen_lowpart (mode, x) - enum machine_mode mode; - rtx x; +m68hc11_gen_lowpart (enum machine_mode mode, rtx x) { /* We assume that the low part of an auto-inc mode is the same with the mode changed and that the caller split the larger mode in the correct order. */ if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) { - return gen_rtx (MEM, mode, XEXP (x, 0)); + return gen_rtx_MEM (mode, XEXP (x, 0)); } /* Note that a CONST_DOUBLE rtx could represent either an integer or a @@ -1877,32 +1820,39 @@ m68hc11_gen_lowpart (mode, x) if (mode == SImode) return GEN_INT (l[0]); - return GEN_INT (trunc_int_for_mode (l[0], HImode)); + return gen_int_mode (l[0], HImode); } else { l[0] = CONST_DOUBLE_LOW (x); } - if (mode == SImode) - return GEN_INT (l[0]); - else if (mode == HImode && GET_MODE (x) == SFmode) - return GEN_INT (trunc_int_for_mode (l[0], HImode)); - else - abort (); + switch (mode) + { + case SImode: + return GEN_INT (l[0]); + case HImode: + gcc_assert (GET_MODE (x) == SFmode); + return gen_int_mode (l[0], HImode); + default: + gcc_unreachable (); + } } if (mode == QImode && D_REG_P (x)) - return gen_rtx (REG, mode, HARD_B_REGNUM); + return gen_rtx_REG (mode, HARD_B_REGNUM); /* gen_lowpart crashes when it is called with a SUBREG. */ if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0) { - if (mode == SImode) - return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4); - else if (mode == HImode) - return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2); - else - abort (); + switch (mode) + { + case SImode: + return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4); + case HImode: + return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2); + default: + gcc_unreachable (); + } } x = gen_lowpart (mode, x); @@ -1915,16 +1865,14 @@ m68hc11_gen_lowpart (mode, x) } rtx -m68hc11_gen_highpart (mode, x) - enum machine_mode mode; - rtx x; +m68hc11_gen_highpart (enum machine_mode mode, rtx x) { /* We assume that the high part of an auto-inc mode is the same with the mode changed and that the caller split the larger mode in the correct order. */ if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0))) { - return gen_rtx (MEM, mode, XEXP (x, 0)); + return gen_rtx_MEM (mode, XEXP (x, 0)); } /* Note that a CONST_DOUBLE rtx could represent either an integer or a @@ -1954,19 +1902,23 @@ m68hc11_gen_highpart (mode, x) if (mode == SImode) return GEN_INT (l[1]); - return GEN_INT (trunc_int_for_mode ((l[1] >> 16), HImode)); + return gen_int_mode ((l[1] >> 16), HImode); } else { l[1] = CONST_DOUBLE_HIGH (x); } - if (mode == SImode) - return GEN_INT (l[1]); - else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) - return GEN_INT (trunc_int_for_mode ((l[0] >> 16), HImode)); - else - abort (); + switch (mode) + { + case SImode: + return GEN_INT (l[1]); + case HImode: + gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT); + return gen_int_mode ((l[0] >> 16), HImode); + default: + gcc_unreachable (); + } } if (GET_CODE (x) == CONST_INT) { @@ -1974,15 +1926,19 @@ m68hc11_gen_highpart (mode, x) if (mode == QImode) { - return GEN_INT (trunc_int_for_mode (val >> 8, QImode)); + return gen_int_mode (val >> 8, QImode); } else if (mode == HImode) { - return GEN_INT (trunc_int_for_mode (val >> 16, HImode)); + return gen_int_mode (val >> 16, HImode); } + else if (mode == SImode) + { + return gen_int_mode (val >> 32, SImode); + } } if (mode == QImode && D_REG_P (x)) - return gen_rtx (REG, mode, HARD_A_REGNUM); + return gen_rtx_REG (mode, HARD_A_REGNUM); /* There is no way in GCC to represent the upper part of a word register. To obtain the 8-bit upper part of a soft register, we change the @@ -1995,26 +1951,22 @@ m68hc11_gen_highpart (mode, x) /* Avoid the '*' for direct addressing mode when this addressing mode is disabled. */ pos = TARGET_NO_DIRECT_MODE ? 1 : 0; - return gen_rtx (MEM, QImode, - gen_rtx (SYMBOL_REF, Pmode, + return gen_rtx_MEM (QImode, + gen_rtx_SYMBOL_REF (Pmode, ®_names[REGNO (x)][pos])); } /* gen_highpart crashes when it is called with a SUBREG. */ - if (GET_CODE (x) == SUBREG) - { - return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1)); - } - if (GET_CODE (x) == REG) + switch (GET_CODE (x)) { + case SUBREG: + return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1)); + case REG: if (REGNO (x) < FIRST_PSEUDO_REGISTER) - return gen_rtx (REG, mode, REGNO (x)); + return gen_rtx_REG (mode, REGNO (x)); else return gen_rtx_SUBREG (mode, x, 0); - } - - if (GET_CODE (x) == MEM) - { + case MEM: x = change_address (x, mode, 0); /* Return a different rtx to avoid to share it in several insns @@ -2023,8 +1975,10 @@ m68hc11_gen_highpart (mode, x) if (GET_CODE (x) == MEM) x = copy_rtx (x); return x; + + default: + gcc_unreachable (); } - abort (); } @@ -2036,20 +1990,18 @@ m68hc11_gen_highpart (mode, x) of code when we know that some register dies or can be clobbered. */ int -dead_register_here (x, reg) - rtx x; - rtx reg; +dead_register_here (rtx x, rtx reg) { rtx x_reg; rtx p; if (D_REG_P (reg)) - x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM); + x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM); else x_reg = 0; for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p)) - if (GET_RTX_CLASS (GET_CODE (p)) == 'i') + if (INSN_P (p)) { rtx body; @@ -2116,16 +2068,14 @@ dead_register_here (x, reg) /* Print the name of register 'regno' in the assembly file. */ static void -asm_print_register (file, regno) - FILE *file; - int regno; +asm_print_register (FILE *file, int regno) { const char *name = reg_names[regno]; if (TARGET_NO_DIRECT_MODE && name[0] == '*') name++; - asm_fprintf (file, "%s", name); + fprintf (file, "%s", name); } /* A C compound statement to output to stdio stream STREAM the @@ -2161,10 +2111,7 @@ asm_print_register (file, regno) ignored. */ void -print_operand (file, op, letter) - FILE *file; - rtx op; - int letter; +print_operand (FILE *file, rtx op, int letter) { if (letter == 't') { @@ -2174,12 +2121,12 @@ print_operand (file, op, letter) else if (letter == 'T') { asm_print_register (file, SOFT_TMP_REGNUM); - asm_fprintf (file, "+1"); + fprintf (file, "+1"); return; } else if (letter == '#') { - asm_fprintf (file, "%0I"); + asm_fprintf (file, "%I"); } if (GET_CODE (op) == REG) @@ -2187,7 +2134,11 @@ print_operand (file, op, letter) if (letter == 'b' && S_REG_P (op)) { asm_print_register (file, REGNO (op)); - asm_fprintf (file, "+1"); + fprintf (file, "+1"); + } + else if (letter == 'b' && D_REG_P (op)) + { + asm_print_register (file, HARD_B_REGNUM); } else { @@ -2199,12 +2150,12 @@ print_operand (file, op, letter) if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h')) { if (letter == 'b') - asm_fprintf (file, "%0I%%lo("); + asm_fprintf (file, "%I%%lo("); else - asm_fprintf (file, "%0I%%hi("); + asm_fprintf (file, "%I%%hi("); output_addr_const (file, op); - asm_fprintf (file, ")"); + fprintf (file, ")"); return; } @@ -2228,48 +2179,42 @@ print_operand (file, op, letter) switch (GET_CODE (base)) { case PRE_DEC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op))); + asm_print_register (file, REGNO (XEXP (base, 0))); break; case POST_DEC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - asm_fprintf (file, "-"); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); + asm_print_register (file, REGNO (XEXP (base, 0))); + fprintf (file, "-"); break; case POST_INC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - asm_fprintf (file, "+"); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op))); + asm_print_register (file, REGNO (XEXP (base, 0))); + fprintf (file, "+"); break; case PRE_INC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op))); - asm_print_register (file, REGNO (XEXP (base, 0))); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op))); + asm_print_register (file, REGNO (XEXP (base, 0))); break; + case MEM: + gcc_assert (TARGET_M6812); + fprintf (file, "["); + print_operand_address (file, XEXP (base, 0)); + fprintf (file, "]"); + break; + default: + if (m68hc11_page0_symbol_p (base)) + fprintf (file, "*"); + output_address (base); break; } @@ -2283,14 +2228,12 @@ print_operand (file, op, letter) REAL_VALUE_TO_TARGET_SINGLE (r, l); asm_fprintf (file, "%I0x%lx", l); } - else if (GET_CODE (op) == CONST_DOUBLE - && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode)) + else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode) { - REAL_VALUE_TYPE r; char dstr[30]; - REAL_VALUE_FROM_CONST_DOUBLE (r, op); - REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr); + real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op), + sizeof (dstr), 0, 1); asm_fprintf (file, "%I0r%s", dstr); } else @@ -2298,25 +2241,24 @@ print_operand (file, op, letter) int need_parenthesize = 0; if (letter != 'i') - asm_fprintf (file, "%0I"); + asm_fprintf (file, "%I"); else need_parenthesize = must_parenthesize (op); if (need_parenthesize) - asm_fprintf (file, "("); + fprintf (file, "("); output_addr_const (file, op); if (need_parenthesize) - asm_fprintf (file, ")"); + fprintf (file, ")"); } } /* Returns true if the operand 'op' must be printed with parenthesis - arround it. This must be done only if there is a symbol whose name + around it. This must be done only if there is a symbol whose name is a processor register. */ static int -must_parenthesize (op) - rtx op; +must_parenthesize (rtx op) { const char *name; @@ -2362,9 +2304,7 @@ must_parenthesize (op) reference whose address is ADDR. ADDR is an RTL expression. */ void -print_operand_address (file, addr) - FILE *file; - rtx addr; +print_operand_address (FILE *file, rtx addr) { rtx base; rtx offset; @@ -2373,10 +2313,9 @@ print_operand_address (file, addr) switch (GET_CODE (addr)) { case REG: - if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr)) - abort (); + gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr)); - asm_fprintf (file, "0,"); + fprintf (file, "0,"); asm_print_register (file, REGNO (addr)); break; @@ -2385,55 +2324,39 @@ print_operand_address (file, addr) switch (GET_CODE (base)) { case PRE_DEC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr))); + asm_print_register (file, REGNO (XEXP (base, 0))); break; case POST_DEC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - asm_fprintf (file, "-"); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); + asm_print_register (file, REGNO (XEXP (base, 0))); + fprintf (file, "-"); break; case POST_INC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - asm_fprintf (file, "+"); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr))); + asm_print_register (file, REGNO (XEXP (base, 0))); + fprintf (file, "+"); break; case PRE_INC: - if (TARGET_M6812) - { - asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr))); - asm_print_register (file, REGNO (XEXP (base, 0))); - } - else - abort (); + gcc_assert (TARGET_M6812); + fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr))); + asm_print_register (file, REGNO (XEXP (base, 0))); break; default: need_parenthesis = must_parenthesize (base); if (need_parenthesis) - asm_fprintf (file, "("); + fprintf (file, "("); output_addr_const (file, base); if (need_parenthesis) - asm_fprintf (file, ")"); + fprintf (file, ")"); break; } break; @@ -2446,66 +2369,60 @@ print_operand_address (file, addr) base = XEXP (addr, 1); offset = XEXP (addr, 0); } - if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset))) + if (CONSTANT_ADDRESS_P (base)) { need_parenthesis = must_parenthesize (addr); + gcc_assert (CONSTANT_ADDRESS_P (offset)); if (need_parenthesis) - asm_fprintf (file, "("); + fprintf (file, "("); output_addr_const (file, base); - asm_fprintf (file, "+"); + fprintf (file, "+"); output_addr_const (file, offset); if (need_parenthesis) - asm_fprintf (file, ")"); + fprintf (file, ")"); } - else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base)) + else { + gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base)); if (REG_P (offset)) { - if (TARGET_M6812) - { - asm_print_register (file, REGNO (offset)); - asm_fprintf (file, ","); - asm_print_register (file, REGNO (base)); - } - else - abort (); + gcc_assert (TARGET_M6812); + asm_print_register (file, REGNO (offset)); + fprintf (file, ","); + asm_print_register (file, REGNO (base)); } else { need_parenthesis = must_parenthesize (offset); if (need_parenthesis) - asm_fprintf (file, "("); + fprintf (file, "("); output_addr_const (file, offset); if (need_parenthesis) - asm_fprintf (file, ")"); - asm_fprintf (file, ","); + fprintf (file, ")"); + fprintf (file, ","); asm_print_register (file, REGNO (base)); } } - else - { - abort (); - } break; default: if (GET_CODE (addr) == CONST_INT && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000) { - asm_fprintf (file, "%d", INTVAL (addr)); + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr)); } else { need_parenthesis = must_parenthesize (addr); if (need_parenthesis) - asm_fprintf (file, "("); + fprintf (file, "("); output_addr_const (file, addr); if (need_parenthesis) - asm_fprintf (file, ")"); + fprintf (file, ")"); } break; } @@ -2515,28 +2432,21 @@ print_operand_address (file, addr) /* Splitting of some instructions. */ static rtx -m68hc11_expand_compare (code, op0, op1) - enum rtx_code code; - rtx op0, op1; +m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1) { rtx ret = 0; - if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT) - abort (); - else - { - emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, - gen_rtx_COMPARE (VOIDmode, op0, op1))); - ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx); - } + gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT); + emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx, + gen_rtx_COMPARE (VOIDmode, op0, op1))); + ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx); return ret; } rtx -m68hc11_expand_compare_and_branch (code, op0, op1, label) - enum rtx_code code; - rtx op0, op1, label; +m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1, + rtx label) { rtx tmp; @@ -2649,15 +2559,15 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label) break; case EQ: - code1 = NIL; + code1 = UNKNOWN; code2 = NE; break; case NE: - code2 = NIL; + code2 = UNKNOWN; break; default: - abort (); + gcc_unreachable (); } /* @@ -2667,20 +2577,20 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label) * if (lo(a) < lo(b)) goto true; * false: */ - if (code1 != NIL) + if (code1 != UNKNOWN) m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label); - if (code2 != NIL) + if (code2 != UNKNOWN) m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2); m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label); - if (code2 != NIL) + if (code2 != UNKNOWN) emit_label (label2); return 0; } default: - abort (); + gcc_unreachable (); } return 0; } @@ -2688,8 +2598,7 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label) /* Return the increment/decrement mode of a MEM if it is such. Return CONST if it is anything else. */ static int -autoinc_mode (x) - rtx x; +autoinc_mode (rtx x) { if (GET_CODE (x) != MEM) return CONST; @@ -2705,9 +2614,7 @@ autoinc_mode (x) } static int -m68hc11_make_autoinc_notes (x, data) - rtx *x; - void *data; +m68hc11_make_autoinc_notes (rtx *x, void *data) { rtx insn; @@ -2731,8 +2638,7 @@ m68hc11_make_autoinc_notes (x, data) The scratch register 'scratch' is used as a temporary to load store intermediate values. It must be a hard register. */ void -m68hc11_split_move (to, from, scratch) - rtx to, from, scratch; +m68hc11_split_move (rtx to, rtx from, rtx scratch) { rtx low_to, low_from; rtx high_to, high_from; @@ -2848,7 +2754,7 @@ m68hc11_split_move (to, from, scratch) if (TARGET_M6812 && IS_STACK_PUSH (to) - && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from)) + && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from)) { if (mode == SImode) { @@ -2866,15 +2772,7 @@ m68hc11_split_move (to, from, scratch) high_to = m68hc11_gen_highpart (mode, to); low_from = m68hc11_gen_lowpart (mode, from); - if (mode == SImode && GET_CODE (from) == CONST_INT) - { - if (INTVAL (from) >= 0) - high_from = const0_rtx; - else - high_from = constm1_rtx; - } - else - high_from = m68hc11_gen_highpart (mode, from); + high_from = m68hc11_gen_highpart (mode, from); if (offset) { @@ -2938,11 +2836,7 @@ m68hc11_split_move (to, from, scratch) } static rtx -simplify_logical (mode, code, operand, result) - enum machine_mode mode; - int code; - rtx operand; - rtx *result; +simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result) { int val; int mask; @@ -2982,10 +2876,7 @@ simplify_logical (mode, code, operand, result) } static void -m68hc11_emit_logical (mode, code, operands) - enum machine_mode mode; - int code; - rtx *operands; +m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands) { rtx result; int need_copy; @@ -3016,18 +2907,19 @@ m68hc11_emit_logical (mode, code, operands) if (!H_REG_P (operands[0]) && operands[3]) { emit_move_insn (operands[3], operands[1]); - emit_insn (gen_rtx (SET, mode, - operands[3], - gen_rtx (code, mode, - operands[3], operands[2]))); + emit_insn (gen_rtx_SET (mode, + operands[3], + gen_rtx_fmt_ee (code, mode, + operands[3], operands[2]))); insn = emit_move_insn (operands[0], operands[3]); } else { - insn = emit_insn (gen_rtx (SET, mode, - operands[0], - gen_rtx (code, mode, - operands[0], operands[2]))); + insn = emit_insn (gen_rtx_SET (mode, + operands[0], + gen_rtx_fmt_ee (code, mode, + operands[0], + operands[2]))); } } @@ -3054,10 +2946,7 @@ m68hc11_emit_logical (mode, code, operands) } void -m68hc11_split_logical (mode, code, operands) - enum machine_mode mode; - int code; - rtx *operands; +m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands) { rtx low[4]; rtx high[4]; @@ -3067,26 +2956,8 @@ m68hc11_split_logical (mode, code, operands) low[2] = m68hc11_gen_lowpart (mode, operands[2]); high[0] = m68hc11_gen_highpart (mode, operands[0]); - - if (mode == SImode && GET_CODE (operands[1]) == CONST_INT) - { - if (INTVAL (operands[1]) >= 0) - high[1] = const0_rtx; - else - high[1] = constm1_rtx; - } - else - high[1] = m68hc11_gen_highpart (mode, operands[1]); - - if (mode == SImode && GET_CODE (operands[2]) == CONST_INT) - { - if (INTVAL (operands[2]) >= 0) - high[2] = const0_rtx; - else - high[2] = constm1_rtx; - } - else - high[2] = m68hc11_gen_highpart (mode, operands[2]); + high[1] = m68hc11_gen_highpart (mode, operands[1]); + high[2] = m68hc11_gen_highpart (mode, operands[2]); low[3] = operands[3]; high[3] = operands[3]; @@ -3105,9 +2976,7 @@ m68hc11_split_logical (mode, code, operands) /* Code generation. */ void -m68hc11_output_swap (insn, operands) - rtx insn ATTRIBUTE_UNUSED; - rtx operands[]; +m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[]) { /* We have to be careful with the cc_status. An address register swap is generated for some comparison. The comparison is made with D @@ -3123,10 +2992,10 @@ m68hc11_output_swap (insn, operands) { cc_status = cc_prev_status; if (D_REG_P (cc_status.value1)) - cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1), + cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), HARD_X_REGNUM); else - cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1), + cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), HARD_D_REGNUM); } else @@ -3142,10 +3011,10 @@ m68hc11_output_swap (insn, operands) { cc_status = cc_prev_status; if (D_REG_P (cc_status.value1)) - cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1), + cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), HARD_Y_REGNUM); else - cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1), + cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1), HARD_D_REGNUM); } else @@ -3159,9 +3028,7 @@ m68hc11_output_swap (insn, operands) This is used to decide whether a move that set flags should be used instead. */ int -next_insn_test_reg (insn, reg) - rtx insn; - rtx reg; +next_insn_test_reg (rtx insn, rtx reg) { rtx body; @@ -3182,9 +3049,7 @@ next_insn_test_reg (insn, reg) /* Generate the code to move a 16-bit operand into another one. */ void -m68hc11_gen_movhi (insn, operands) - rtx insn; - rtx *operands; +m68hc11_gen_movhi (rtx insn, rtx *operands) { int reg; @@ -3199,10 +3064,13 @@ m68hc11_gen_movhi (insn, operands) if (TARGET_M6812) { - if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1])) + rtx from = operands[1]; + rtx to = operands[0]; + + if (IS_STACK_PUSH (to) && H_REG_P (from)) { cc_status = cc_prev_status; - switch (REGNO (operands[1])) + switch (REGNO (from)) { case HARD_X_REGNUM: case HARD_Y_REGNUM: @@ -3210,17 +3078,17 @@ m68hc11_gen_movhi (insn, operands) output_asm_insn ("psh%1", operands); break; case HARD_SP_REGNUM: - output_asm_insn ("sts\t-2,sp", operands); + output_asm_insn ("sts\t2,-sp", operands); break; default: - abort (); + gcc_unreachable (); } return; } - if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0])) + if (IS_STACK_POP (from) && H_REG_P (to)) { cc_status = cc_prev_status; - switch (REGNO (operands[0])) + switch (REGNO (to)) { case HARD_X_REGNUM: case HARD_Y_REGNUM: @@ -3228,7 +3096,7 @@ m68hc11_gen_movhi (insn, operands) output_asm_insn ("pul%0", operands); break; default: - abort (); + gcc_unreachable (); } return; } @@ -3251,11 +3119,52 @@ m68hc11_gen_movhi (insn, operands) else output_asm_insn ("st%1\t%0", operands); } + + /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw + instruction. We have to use a scratch register as temporary location. + Trying to use a specific pattern or constrain failed. */ + else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM) + { + rtx ops[4]; + + ops[0] = to; + ops[2] = from; + ops[3] = 0; + if (dead_register_here (insn, d_reg)) + ops[1] = d_reg; + else if (dead_register_here (insn, ix_reg)) + ops[1] = ix_reg; + else if (dead_register_here (insn, iy_reg)) + ops[1] = iy_reg; + else + { + ops[1] = d_reg; + ops[3] = d_reg; + output_asm_insn ("psh%3", ops); + } + + ops[0] = to; + ops[2] = from; + output_asm_insn ("ld%1\t%2", ops); + output_asm_insn ("st%1\t%0", ops); + if (ops[3]) + output_asm_insn ("pul%3", ops); + } + + /* Use movw for non-null constants or when we are clearing + a volatile memory reference. However, this is possible + only if the memory reference has a small offset or is an + absolute address. */ + else if (GET_CODE (from) == CONST_INT + && INTVAL (from) == 0 + && (MEM_VOLATILE_P (to) == 0 + || m68hc11_small_indexed_indirect_p (to, HImode) == 0)) + { + output_asm_insn ("clr\t%h0", operands); + output_asm_insn ("clr\t%b0", operands); + } else { - rtx from = operands[1]; - rtx to = operands[0]; - if ((m68hc11_register_indirect_p (from, GET_MODE (from)) && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from))) || (m68hc11_register_indirect_p (to, GET_MODE (to)) @@ -3272,6 +3181,7 @@ m68hc11_gen_movhi (insn, operands) ops[0] = to; ops[1] = operands[2]; m68hc11_gen_movhi (insn, ops); + return; } else { @@ -3279,19 +3189,11 @@ m68hc11_gen_movhi (insn, operands) fatal_insn ("move insn not handled", insn); } } - else - { - if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0) - { - output_asm_insn ("clr\t%h0", operands); - output_asm_insn ("clr\t%b0", operands); - } - else - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("movw\t%1,%0", operands); - } - } + else + { + m68hc11_notice_keep_cc (operands[0]); + output_asm_insn ("movw\t%1,%0", operands); + } } return; } @@ -3310,7 +3212,7 @@ m68hc11_gen_movhi (insn, operands) output_asm_insn ("pulb", operands); break; default: - abort (); + gcc_unreachable (); } return; } @@ -3406,11 +3308,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])) { @@ -3448,11 +3356,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])) { @@ -3460,7 +3374,7 @@ m68hc11_gen_movhi (insn, operands) cc_status = cc_prev_status; output_asm_insn ("tsy", operands); } - else + else { output_asm_insn ("ldy\t%1", operands); } @@ -3522,7 +3436,7 @@ m68hc11_gen_movhi (insn, operands) output_asm_insn ("psha", operands); break; default: - abort (); + gcc_unreachable (); } return; } @@ -3586,9 +3500,7 @@ m68hc11_gen_movhi (insn, operands) } void -m68hc11_gen_movqi (insn, operands) - rtx insn; - rtx *operands; +m68hc11_gen_movqi (rtx insn, rtx *operands) { /* Move a register or memory to the same location. This is possible because such insn can appear @@ -3609,8 +3521,10 @@ m68hc11_gen_movqi (insn, operands) } else if (H_REG_P (operands[0])) { - if (Q_REG_P (operands[0])) - output_asm_insn ("lda%0\t%b1", operands); + if (IS_STACK_POP (operands[1])) + output_asm_insn ("pul%b0", operands); + else if (Q_REG_P (operands[0])) + output_asm_insn ("lda%0\t%b1", operands); else if (D_REG_P (operands[0])) output_asm_insn ("ldab\t%b1", operands); else @@ -3868,10 +3782,7 @@ m68hc11_gen_movqi (insn, operands) The source and destination must be D or A and the shift must be a constant. */ void -m68hc11_gen_rotate (code, insn, operands) - enum rtx_code code; - rtx insn; - rtx operands[]; +m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[]) { int val; @@ -3908,15 +3819,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); @@ -3927,14 +3838,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); @@ -3952,9 +3861,7 @@ m68hc11_gen_rotate (code, insn, operands) Do not alter them if the instruction would not alter the cc's. */ void -m68hc11_notice_update_cc (exp, insn) - rtx exp; - rtx insn ATTRIBUTE_UNUSED; +m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED) { /* recognize SET insn's. */ if (GET_CODE (exp) == SET) @@ -4048,14 +3955,19 @@ m68hc11_notice_update_cc (exp, insn) && cc_status.value2 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) cc_status.value2 = 0; + + else if (cc_status.value1 && side_effects_p (cc_status.value1)) + cc_status.value1 = 0; + + else if (cc_status.value2 && side_effects_p (cc_status.value2)) + cc_status.value2 = 0; } /* The current instruction does not affect the flags but changes the register 'reg'. See if the previous flags can be kept for the next instruction to avoid a comparison. */ void -m68hc11_notice_keep_cc (reg) - rtx reg; +m68hc11_notice_keep_cc (rtx reg) { if (reg == 0 || cc_prev_status.value1 == 0 @@ -4130,12 +4042,10 @@ struct replace_info int z_loaded_with_sp; }; -static 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)); -static void m68hc11_reassign_regs PARAMS ((rtx)); +static int m68hc11_check_z_replacement (rtx, struct replace_info *); +static void m68hc11_find_z_replacement (rtx, struct replace_info *); +static void m68hc11_z_replacement (rtx); +static void m68hc11_reassign_regs (rtx); int z_replacement_completed = 0; @@ -4145,9 +4055,7 @@ int z_replacement_completed = 0; continue replacement in next insns. */ static int -m68hc11_check_z_replacement (insn, info) - rtx insn; - struct replace_info *info; +m68hc11_check_z_replacement (rtx insn, struct replace_info *info) { int this_insn_uses_ix; int this_insn_uses_iy; @@ -4220,8 +4128,10 @@ m68hc11_check_z_replacement (insn, info) { if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM) || (GET_CODE (src) == COMPARE && - (rtx_equal_p (XEXP (src, 0), z_reg) - || rtx_equal_p (XEXP (src, 1), z_reg)))) + ((rtx_equal_p (XEXP (src, 0), z_reg) + && H_REG_P (XEXP (src, 1))) + || (rtx_equal_p (XEXP (src, 1), z_reg) + && H_REG_P (XEXP (src, 0)))))) { if (insn == info->first) { @@ -4231,7 +4141,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; } @@ -4337,9 +4247,7 @@ m68hc11_check_z_replacement (insn, info) info->must_restore_reg = 0; info->found_call = 1; info->can_use_d = 0; - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; + SET_INSN_DELETED (insn); info->last = NEXT_INSN (insn); return 0; } @@ -4365,7 +4273,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; } @@ -4414,9 +4328,7 @@ m68hc11_check_z_replacement (insn, info) info->must_restore_reg = 0; info->found_call = 1; info->can_use_d = 0; - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; + SET_INSN_DELETED (insn); info->last = NEXT_INSN (insn); return 0; } @@ -4442,7 +4354,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; } @@ -4698,9 +4616,7 @@ m68hc11_check_z_replacement (insn, info) } static void -m68hc11_find_z_replacement (insn, info) - rtx insn; - struct replace_info *info; +m68hc11_find_z_replacement (rtx insn, struct replace_info *info) { int reg; @@ -4775,7 +4691,7 @@ m68hc11_find_z_replacement (insn, info) if (info->regno >= 0) { reg = info->regno; - info->replace_reg = gen_rtx (REG, HImode, reg); + info->replace_reg = gen_rtx_REG (HImode, reg); } else if (info->can_use_d) { @@ -4807,12 +4723,11 @@ m68hc11_find_z_replacement (insn, info) /* The insn uses the Z register. Find a replacement register for it (either X or Y) and replace it in the insn and the next ones until the flow changes or the replacement register is used. Instructions - are emited before and after the Z-block to preserve the value of + are emitted before and after the Z-block to preserve the value of Z and of the replacement register. */ static void -m68hc11_z_replacement (insn) - rtx insn; +m68hc11_z_replacement (rtx insn) { rtx replace_reg_qi; rtx replace_reg; @@ -4828,26 +4743,26 @@ m68hc11_z_replacement (insn) if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src))) { - XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM); + XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM); return; } else if (Z_REG_P (src) && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx)) { - XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM); + XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM); return; } else if (D_REG_P (dst) && m68hc11_arith_operator (src, GET_MODE (src)) && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1))) { - XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM); + XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM); return; } else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT && INTVAL (src) == 0) { - XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM); + XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM); /* Force it to be re-recognized. */ INSN_CODE (insn) = -1; return; @@ -4865,19 +4780,19 @@ m68hc11_z_replacement (insn) rtx dst; if (info.must_push_reg && 0) - dst = gen_rtx (MEM, HImode, - gen_rtx (PRE_DEC, HImode, - gen_rtx (REG, HImode, HARD_SP_REGNUM))); + dst = gen_rtx_MEM (HImode, + gen_rtx_PRE_DEC (HImode, + gen_rtx_REG (HImode, HARD_SP_REGNUM))); else - dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM); + dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM); emit_insn_before (gen_movhi (dst, - gen_rtx (REG, HImode, info.regno)), insn); + gen_rtx_REG (HImode, info.regno)), insn); } if (info.must_load_z && !info.must_push_reg) { - emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno), - gen_rtx (REG, HImode, SOFT_Z_REGNUM)), + emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno), + gen_rtx_REG (HImode, SOFT_Z_REGNUM)), insn); } @@ -4900,6 +4815,7 @@ m68hc11_z_replacement (insn) body = PATTERN (insn); if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL + || GET_CODE (body) == ASM_OPERANDS || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) { rtx note; @@ -4936,7 +4852,7 @@ m68hc11_z_replacement (insn) if (reg_mentioned_p (z_reg, insn)) { if (replace_reg_qi == NULL_RTX) - replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg)); + replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg)); validate_replace_rtx (z_reg_qi, replace_reg_qi, insn); } @@ -4968,8 +4884,8 @@ m68hc11_z_replacement (insn) if (info.save_before_last) save_pos_insn = PREV_INSN (save_pos_insn); - emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM), - gen_rtx (REG, HImode, info.regno)), + emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM), + gen_rtx_REG (HImode, info.regno)), save_pos_insn); } @@ -4978,12 +4894,12 @@ m68hc11_z_replacement (insn) rtx new_body, body; body = PATTERN (info.last); - new_body = gen_rtx (PARALLEL, VOIDmode, + new_body = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (3, body, - gen_rtx (USE, VOIDmode, + gen_rtx_USE (VOIDmode, replace_reg), - gen_rtx (USE, VOIDmode, - gen_rtx (REG, HImode, + gen_rtx_USE (VOIDmode, + gen_rtx_REG (HImode, SOFT_Z_REGNUM)))); PATTERN (info.last) = new_body; @@ -5003,13 +4919,13 @@ m68hc11_z_replacement (insn) rtx dst; if (info.must_push_reg && 0) - dst = gen_rtx (MEM, HImode, - gen_rtx (POST_INC, HImode, - gen_rtx (REG, HImode, HARD_SP_REGNUM))); + dst = gen_rtx_MEM (HImode, + gen_rtx_POST_INC (HImode, + gen_rtx_REG (HImode, HARD_SP_REGNUM))); else - dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM); + dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM); - emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno), + emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno), dst), insn); } @@ -5021,15 +4937,14 @@ m68hc11_z_replacement (insn) on the instruction. */ static void -m68hc11_reassign_regs (first) - rtx first; +m68hc11_reassign_regs (rtx first) { rtx insn; - ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM); - iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM); - z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM); - z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM); + ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM); + iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM); + z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM); + z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM); /* Scan all insns to replace Z by X or Y preserving the old value of X/Y and restoring it afterward. */ @@ -5042,7 +4957,7 @@ m68hc11_reassign_regs (first) || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER) continue; - if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + if (!INSN_P (insn)) continue; body = PATTERN (insn); @@ -5077,21 +4992,29 @@ m68hc11_reassign_regs (first) } -void -m68hc11_reorg (first) - rtx first; +/* Machine-dependent reorg pass. + Specific optimizations are defined here: + - this pass changes the Z register into either X or Y + (it preserves X/Y previous values in a memory slot in page0). + + When this pass is finished, the global variable + 'z_replacement_completed' is set to 2. */ + +static void +m68hc11_reorg (void) { int split_done = 0; - rtx insn; + rtx first; z_replacement_completed = 0; - z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM); + z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM); + first = get_insns (); /* Some RTX are shared at this point. This breaks the Z register replacement, unshare everything. */ unshare_all_rtl_again (first); - /* Force a split of all splitable insn. This is necessary for the + /* Force a split of all splittable insn. This is necessary for the Z register replacement mechanism because we end up with basic insns. */ split_all_insns_noflow (); split_done = 1; @@ -5099,11 +5022,13 @@ m68hc11_reorg (first) z_replacement_completed = 1; m68hc11_reassign_regs (first); - /* After some splitting, there are some oportunities for CSE pass. + if (optimize) + compute_bb_for_insn (); + + /* After some splitting, there are some opportunities for CSE pass. This happens quite often when 32-bit or above patterns are split. */ if (optimize > 0 && split_done) { - find_basic_blocks (first, max_reg_num (), 0); reload_cse_regs (first); } @@ -5111,30 +5036,9 @@ m68hc11_reorg (first) description to use the best assembly directives. */ if (optimize) { - /* Before recomputing the REG_DEAD notes, remove all of them. - This is necessary because the reload_cse_regs() pass can - have replaced some (MEM) with a register. In that case, - the REG_DEAD that could exist for that register may become - wrong. */ - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - if (INSN_P (insn)) - { - rtx *pnote; - - pnote = ®_NOTES (insn); - while (*pnote != 0) - { - if (REG_NOTE_KIND (*pnote) == REG_DEAD) - *pnote = XEXP (*pnote, 1); - else - pnote = &XEXP (*pnote, 1); - } - } - } - - find_basic_blocks (first, max_reg_num (), 0); - life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES); + df_note_add_problem (); + df_analyze (); + df_remove_problem (df_note); } z_replacement_completed = 2; @@ -5162,7 +5066,7 @@ m68hc11_reorg (first) if (INSN_DELETED_P (insn)) continue; - if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + if (!INSN_P (insn)) continue; /* Remove the (set (R) (R)) insns generated by some splits. */ @@ -5170,26 +5074,33 @@ m68hc11_reorg (first) if (GET_CODE (body) == SET && rtx_equal_p (SET_SRC (body), SET_DEST (body))) { - PUT_CODE (insn, NOTE); - NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; - NOTE_SOURCE_FILE (insn) = 0; + SET_INSN_DELETED (insn); continue; } } } } + +/* Override memcpy */ + +static void +m68hc11_init_libfuncs (void) +{ + memcpy_libfunc = init_one_libfunc ("__memcpy"); + memcmp_libfunc = init_one_libfunc ("__memcmp"); + memset_libfunc = init_one_libfunc ("__memset"); +} + /* Cost functions. */ /* Cost of moving memory. */ int -m68hc11_memory_move_cost (mode, class, in) - enum machine_mode mode; - enum reg_class class; - int in ATTRIBUTE_UNUSED; +m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass, + int in ATTRIBUTE_UNUSED) { - if (class <= H_REGS && class > NO_REGS) + if (rclass <= H_REGS && rclass > NO_REGS) { if (GET_MODE_SIZE (mode) <= 2) return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress); @@ -5199,7 +5110,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); } @@ -5211,10 +5122,8 @@ m68hc11_memory_move_cost (mode, class, in) have a move cost of 2. Setting a higher cost will force reload to check the constraints. */ int -m68hc11_register_move_cost (mode, from, to) - enum machine_mode mode; - enum reg_class from; - enum reg_class to; +m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from, + enum reg_class to) { /* All costs are symmetric, so reduce cases by putting the lower number class as the destination. */ @@ -5235,9 +5144,8 @@ m68hc11_register_move_cost (mode, from, to) /* Provide the costs of an addressing mode that contains ADDR. If ADDR is not a valid address, its cost is irrelevant. */ -int -m68hc11_address_cost (addr) - rtx addr; +static int +m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED) { int cost = 4; @@ -5318,14 +5226,11 @@ m68hc11_address_cost (addr) } static int -m68hc11_shift_cost (mode, x, shift) - enum machine_mode mode; - rtx x; - int shift; +m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift) { int total; - total = rtx_cost (x, SET); + total = rtx_cost (x, SET, !optimize_size); if (mode == QImode) total += m68hc11_cost->shiftQI_const[shift % 8]; else if (mode == HImode) @@ -5349,11 +5254,9 @@ m68hc11_shift_cost (mode, x, shift) return total; } -int -m68hc11_rtx_costs (x, code, outer_code) - rtx x; - enum rtx_code code; - enum rtx_code outer_code ATTRIBUTE_UNUSED; +static int +m68hc11_rtx_costs_1 (rtx x, enum rtx_code code, + enum rtx_code outer_code ATTRIBUTE_UNUSED) { enum machine_mode mode = GET_MODE (x); int extra_cost = 0; @@ -5371,14 +5274,14 @@ m68hc11_rtx_costs (x, code, outer_code) return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1))); } - total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code); + total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); total += m68hc11_cost->shift_var; return total; case AND: case XOR: case IOR: - total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code); + total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); total += m68hc11_cost->logical; /* Logical instructions are byte instructions only. */ @@ -5387,7 +5290,7 @@ m68hc11_rtx_costs (x, code, outer_code) case MINUS: case PLUS: - total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code); + total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); total += m68hc11_cost->add; if (GET_MODE_SIZE (mode) > 2) { @@ -5398,7 +5301,7 @@ m68hc11_rtx_costs (x, code, outer_code) case UDIV: case DIV: case MOD: - total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code); + total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size); switch (mode) { case QImode: @@ -5421,18 +5324,19 @@ m68hc11_rtx_costs (x, code, outer_code) if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND) return m68hc11_cost->multQI - + rtx_cost (XEXP (XEXP (x, 0), 0), code) - + rtx_cost (XEXP (XEXP (x, 1), 0), code); + + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size) + + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size); /* emul instruction produces 32-bit result for 68HC12. */ if (TARGET_M6812 && mode == SImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND) return m68hc11_cost->multHI - + rtx_cost (XEXP (XEXP (x, 0), 0), code) - + rtx_cost (XEXP (XEXP (x, 1), 0), code); + + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size) + + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size); - total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code); + total = rtx_cost (XEXP (x, 0), code, !optimize_size) + + rtx_cost (XEXP (x, 1), code, !optimize_size); switch (mode) { case QImode: @@ -5459,7 +5363,7 @@ m68hc11_rtx_costs (x, code, outer_code) case COMPARE: case ABS: case ZERO_EXTEND: - total = extra_cost + rtx_cost (XEXP (x, 0), code); + total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size); if (mode == QImode) { return total + COSTS_N_INSNS (1); @@ -5484,89 +5388,112 @@ m68hc11_rtx_costs (x, code, outer_code) return COSTS_N_INSNS (4); } } - -/* print_options - called at the start of the code generation for a - module. */ - -extern char *asm_file_name; - -#include -#include - -static void -print_options (out) - FILE *out; +static bool +m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total, + bool speed ATTRIBUTE_UNUSED) { - const char *a_time; - long c_time; - int i; - extern int save_argc; - extern char **save_argv; - - fprintf (out, ";;; Command:\t"); - for (i = 0; i < save_argc; i++) - { - fprintf (out, "%s", save_argv[i]); - if (i + 1 < save_argc) - fprintf (out, " "); - } - fprintf (out, "\n"); - c_time = time (0); - a_time = ctime (&c_time); - fprintf (out, ";;; Compiled:\t%s", a_time); -#ifdef __GNUC__ -#ifndef __VERSION__ -#define __VERSION__ "[unknown]" -#endif - fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__); -#else - fprintf (out, ";;; (META)compiled by CC.\n"); -#endif -} + switch (code) + { + /* Constants are cheap. Moving them in registers must be avoided + because most instructions do not handle two register operands. */ + case CONST_INT: + case CONST: + case LABEL_REF: + case SYMBOL_REF: + case CONST_DOUBLE: + /* Logical and arithmetic operations with a constant operand are + better because they are not supported with two registers. */ + /* 'clr' is slow */ + if (outer_code == SET && x == const0_rtx) + /* After reload, the reload_cse pass checks the cost to change + a SET into a PLUS. Make const0 cheap then. */ + *total = 1 - reload_completed; + else + *total = 0; + return true; + + case ROTATE: + case ROTATERT: + case ASHIFT: + case LSHIFTRT: + case ASHIFTRT: + case MINUS: + case PLUS: + case AND: + case XOR: + case IOR: + case UDIV: + case DIV: + case MOD: + case MULT: + case NEG: + case SIGN_EXTEND: + case NOT: + case COMPARE: + case ZERO_EXTEND: + case IF_THEN_ELSE: + *total = m68hc11_rtx_costs_1 (x, code, outer_code); + return true; -void -m68hc11_asm_file_start (out, main_file) - FILE *out; - const char *main_file; -{ - fprintf (out, ";;;-----------------------------------------\n"); - fprintf (out, ";;; Start MC68HC11 gcc assembly output\n"); - fprintf (out, ";;; gcc compiler %s\n", version_string); - print_options (out); - fprintf (out, ";;;-----------------------------------------\n"); - output_file_directive (out, main_file); + default: + return false; + } } + +/* Worker function for TARGET_ASM_FILE_START. */ static void -m68hc11_add_gc_roots () +m68hc11_file_start (void) { - ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1); - ggc_add_rtx_root (&ix_reg, 1); - ggc_add_rtx_root (&iy_reg, 1); - ggc_add_rtx_root (&d_reg, 1); - ggc_add_rtx_root (&da_reg, 1); - ggc_add_rtx_root (&z_reg, 1); - ggc_add_rtx_root (&z_reg_qi, 1); - ggc_add_rtx_root (&stack_push_word, 1); - ggc_add_rtx_root (&stack_pop_word, 1); + default_file_start (); + + fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong"); } + +/* Worker function for TARGET_ASM_CONSTRUCTOR. */ + static void -m68hc11_asm_out_constructor (symbol, priority) - rtx symbol; - int priority; +m68hc11_asm_out_constructor (rtx symbol, int priority) { default_ctor_section_asm_out_constructor (symbol, priority); fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n"); } +/* Worker function for TARGET_ASM_DESTRUCTOR. */ + static void -m68hc11_asm_out_destructor (symbol, priority) - rtx symbol; - int priority; +m68hc11_asm_out_destructor (rtx symbol, int priority) { default_dtor_section_asm_out_destructor (symbol, priority); fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n"); } + +/* Worker function for TARGET_STRUCT_VALUE_RTX. */ + +static rtx +m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (Pmode, HARD_D_REGNUM); +} + +/* Return true if type TYPE should be returned in memory. + Blocks and data types largers than 4 bytes cannot be returned + in the register (D + X = 4). */ + +static bool +m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + if (TYPE_MODE (type) == BLKmode) + { + HOST_WIDE_INT size = int_size_in_bytes (type); + return (size == -1 || size > 4); + } + else + return GET_MODE_SIZE (TYPE_MODE (type)) > 4; +} + +#include "gt-m68hc11.h"