/* 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
+<http://www.gnu.org/licenses/>.
Note:
A first 68HC11 port was made by Otto Lind (otto@coactive.com)
#include <stdio.h>
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
#include "recog.h"
#include "expr.h"
+#include "libfuncs.h"
#include "toplev.h"
#include "basic-block.h"
#include "function.h"
#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;
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;
/* 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;
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;
/* 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;
\f
/* Initialize the GCC target structure. */
#undef TARGET_ATTRIBUTE_TABLE
#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;
\f
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));
/* 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;
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. */
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;
/* 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);
}
}
+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;
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);
}
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:
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;
/* 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
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
}
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. */
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;
}
}
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;
}
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;
}
/* 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:
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;
}
}
}
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;
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:
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 ();
/* 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
/* 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
}
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)
{
}
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;
}
int
-push_pop_operand_p (operand)
- rtx operand;
+push_pop_operand_p (rtx operand)
{
if (GET_CODE (operand) != MEM)
{
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))
{
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;
-}
\f
/* Emit the code to build the trampoline used to call a nested function.
*/
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];
\f
/* 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, "%<trap%> and %<far%> attributes are "
+ "not compatible, ignoring %<far%>");
+ trap_handler = 0;
+ }
+ if (trap_handler)
+ {
+ if (trap_handler_symbol != 0)
+ warning (OPT_Wattributes, "%<trap%> attribute is already used");
+ else
+ trap_handler_symbol = XEXP (rtl, 0);
+ }
+ SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
}
-\f
-/* 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);
}
+\f
+/* 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;
/* 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;
/* 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;
}
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;
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;
(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)
{
(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)
{
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,
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);
}
\f
/* 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;
}
int
-m68hc11_total_frame_size ()
+m68hc11_total_frame_size (void)
{
int size;
int regno;
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. */
}
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 ();
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
{
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;
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. */
/* 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;
/* 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);
}
}
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;
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. */
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);
}
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
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);
}
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
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)
{
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
/* 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
if (GET_CODE (x) == MEM)
x = copy_rtx (x);
return x;
+
+ default:
+ gcc_unreachable ();
}
- abort ();
}
\f
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;
/* 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
ignored. */
void
-print_operand (file, op, letter)
- FILE *file;
- rtx op;
- int letter;
+print_operand (FILE *file, rtx op, int letter)
{
if (letter == 't')
{
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)
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
{
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;
}
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;
}
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
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;
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;
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;
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;
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;
}
/* 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;
break;
case EQ:
- code1 = NIL;
+ code1 = UNKNOWN;
code2 = NE;
break;
case NE:
- code2 = NIL;
+ code2 = UNKNOWN;
break;
default:
- abort ();
+ gcc_unreachable ();
}
/*
* 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;
}
/* 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;
}
static int
-m68hc11_make_autoinc_notes (x, data)
- rtx *x;
- void *data;
+m68hc11_make_autoinc_notes (rtx *x, void *data)
{
rtx insn;
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;
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)
{
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)
{
}
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;
}
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;
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])));
}
}
}
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];
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];
/* 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
{
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
{
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
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;
/* 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;
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:
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:
output_asm_insn ("pul%0", operands);
break;
default:
- abort ();
+ gcc_unreachable ();
}
return;
}
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))
ops[0] = to;
ops[1] = operands[2];
m68hc11_gen_movhi (insn, ops);
+ return;
}
else
{
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;
}
output_asm_insn ("pulb", operands);
break;
default:
- abort ();
+ gcc_unreachable ();
}
return;
}
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]))
{
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]))
{
cc_status = cc_prev_status;
output_asm_insn ("tsy", operands);
}
- else
+ else
{
output_asm_insn ("ldy\t%1", operands);
}
output_asm_insn ("psha", operands);
break;
default:
- abort ();
+ gcc_unreachable ();
}
return;
}
}
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
}
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
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;
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);
}
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);
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)
&& 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
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;
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;
{
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)
{
info->need_save_z = 0;
info->found_call = 1;
info->regno = SOFT_Z_REGNUM;
- info->last = insn;
+ info->last = NEXT_INSN (insn);
}
return 0;
}
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;
}
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;
}
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;
}
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;
}
}
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;
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)
{
/* 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;
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;
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);
}
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;
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);
}
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);
}
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;
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);
}
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. */
|| 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);
}
-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;
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);
}
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;
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. */
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;
}
}
}
}
+\f
+/* 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");
+}
+
\f
/* 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);
else
{
if (GET_MODE_SIZE (mode) <= 2)
- return COSTS_N_INSNS (2);
+ return COSTS_N_INSNS (3);
else
return COSTS_N_INSNS (4);
}
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. */
/* 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;
}
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)
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;
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. */
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)
{
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:
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:
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);
return COSTS_N_INSNS (4);
}
}
-\f
-/* print_options - called at the start of the code generation for a
- module. */
-
-extern char *asm_file_name;
-
-#include <time.h>
-#include <sys/types.h>
-
-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;
+ }
}
+\f
+/* 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"