/* Subroutines for code generation on Motorola 68HC11 and 68HC12.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009, 2010 Free Software Foundation, Inc.
Contributed by Stephane Carrez (stcarrez@nerim.fr)
This file is part of GCC.
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.
GCC is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; 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 "expr.h"
#include "tm_p.h"
#include "regs.h"
#include "hard-reg-set.h"
-#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "recog.h"
#include "expr.h"
#include "libfuncs.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "basic-block.h"
#include "function.h"
#include "ggc.h"
#include "reload.h"
#include "target.h"
#include "target-def.h"
+#include "df.h"
+static void m68hc11_option_override (void);
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_emit_logical (enum machine_mode, enum rtx_code, rtx *);
static void m68hc11_reorg (void);
-static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);
-static int register_indirect_p (rtx, enum machine_mode, int);
+static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
+static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
static int must_parenthesize (rtx);
-static int m68hc11_address_cost (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 *);
-static int m68hc11_auto_inc_p (rtx);
+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[];
+static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
+static bool m68hc11_class_likely_spilled_p (reg_class_t);
void create_regs_rtx (void);
static void asm_print_register (FILE *, int);
+static void m68hc11_print_operand (FILE *, rtx, int);
+static void m68hc11_print_operand_address (FILE *, rtx);
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 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 (tree, tree);
+static bool m68hc11_return_in_memory (const_tree, const_tree);
+static bool m68hc11_can_eliminate (const int, const int);
+static void m68hc11_conditional_register_usage (void);
+static void m68hc11_trampoline_init (rtx, tree, rtx);
+
+static rtx m68hc11_function_arg (CUMULATIVE_ARGS*, enum machine_mode,
+ const_tree, bool);
+static void m68hc11_function_arg_advance (CUMULATIVE_ARGS*, enum machine_mode,
+ const_tree, bool);
/* Must be set to 1 to produce debug messages. */
int debug_m6811 = 0;
This is 1 for 68HC11 and 0 for 68HC12. */
int m68hc11_sp_correction;
-#define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */
-#define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */
-#define ADDR_INDEXED 0x04 /* D-reg index */
-#define ADDR_OFFSET 0x08
-#define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */
-#define ADDR_CONST 0x20 /* Accept const and symbol_ref */
-
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;
\f
const struct processor_costs *m68hc11_cost;
/* divSI */
COSTS_N_INSNS (100)
};
+\f
+/* M68HC11 specific attributes. */
-/* 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;
+static const struct attribute_spec m68hc11_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity } */
+ { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
+ false },
+ { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
+ false },
+ { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
+ false },
+ { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
+ false },
+ { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute,
+ false },
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
\f
/* Initialize the GCC target structure. */
#undef TARGET_ATTRIBUTE_TABLE
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND m68hc11_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
+
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
#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_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG m68hc11_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE m68hc11_function_arg_advance
+
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
#undef TARGET_RETURN_IN_MEMORY
#undef TARGET_STRIP_NAME_ENCODING
#define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE m68hc11_conditional_register_usage
+
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P m68hc11_class_likely_spilled_p
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE m68hc11_option_override
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
-int
-m68hc11_override_options (void)
+static void
+m68hc11_option_override (void)
{
memset (m68hc11_reg_valid_for_index, 0,
sizeof (m68hc11_reg_valid_for_index));
/* 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;
}
/* 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_MIN_MAX);
+ target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
m68hc11_cost = &m6811_cost;
m68hc11_min_offset = 0;
m68hc11_max_offset = 256;
m68hc11_tmp_regs_class = D_REGS;
m68hc11_addr_mode = ADDR_OFFSET;
m68hc11_mov_addr_mode = 0;
- if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
- m68hc11_soft_reg_count = "4";
+ if (m68hc11_soft_reg_count < 0)
+ m68hc11_soft_reg_count = 4;
}
/* Configure for a 68hc12 processor. */
| (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_M6811;
target_flags |= MASK_NO_DIRECT_MODE;
- if (m68hc11_soft_reg_count == 0)
- m68hc11_soft_reg_count = "0";
+ if (m68hc11_soft_reg_count < 0)
+ m68hc11_soft_reg_count = 0;
if (TARGET_LONG_CALLS)
current_function_far = 1;
}
- return 0;
}
-void
+/* The soft-registers are disabled or enabled according to the
+ -msoft-reg-count=<n> option. */
+
+static void
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;
}
/* 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
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);
}
enum reg_class
-preferred_reload_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;
+}
+
+/* Implement TARGET_CLASS_LIKELY_SPILLED_P. */
+
+static bool
+m68hc11_class_likely_spilled_p (reg_class_t rclass)
+{
+ switch (rclass)
+ {
+ case D_REGS:
+ case X_REGS:
+ case Y_REGS:
+ case A_REGS:
+ case SP_REGS:
+ case D_OR_X_REGS:
+ case D_OR_Y_REGS:
+ case X_OR_SP_REGS:
+ case Y_OR_SP_REGS:
+ case D_OR_SP_REGS:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
}
/* 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 (rtx operand, enum machine_mode mode, int addr_mode)
+int
+m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
{
rtx base, offset;
{
case MEM:
if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
- return register_indirect_p (XEXP (operand, 0), mode,
- addr_mode & (ADDR_STRICT | ADDR_OFFSET));
+ return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
+ addr_mode & (ADDR_STRICT | ADDR_OFFSET));
return 0;
case POST_INC:
case POST_DEC:
case PRE_DEC:
if (addr_mode & ADDR_INCDEC)
- return register_indirect_p (XEXP (operand, 0), mode,
- addr_mode & ADDR_STRICT);
+ return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
+ addr_mode & ADDR_STRICT);
return 0;
case PLUS:
&& reg_equiv_memory_loc[REGNO (operand)])
{
operand = reg_equiv_memory_loc[REGNO (operand)];
- operand = eliminate_regs (operand, 0, NULL_RTX);
+ operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
}
if (GET_CODE (operand) != MEM)
return 1;
addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
- if (!register_indirect_p (operand, mode, addr_mode))
+ if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
return 0;
if (TARGET_M6812 && GET_CODE (operand) == PLUS
&& reg_equiv_memory_loc[REGNO (operand)])
{
operand = reg_equiv_memory_loc[REGNO (operand)];
- operand = eliminate_regs (operand, 0, NULL_RTX);
+ operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
}
if (GET_CODE (operand) != MEM)
return 0;
operand = XEXP (operand, 0);
addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
- return register_indirect_p (operand, mode, addr_mode);
+ return m68hc11_valid_addressing_p (operand, mode, addr_mode);
}
-static int
-go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
- int strict)
+static bool
+m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
+ bool strict)
{
int addr_mode;
return 1;
}
addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
- if (register_indirect_p (operand, mode, addr_mode))
+ if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
{
return 1;
}
return 0;
}
-int
-m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
- int strict)
+bool
+m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
+ bool strict)
{
int result;
debug_rtx (operand);
}
- result = go_if_legitimate_address_internal (operand, mode, strict);
+ result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
if (debug_m6811)
{
return result;
}
-int
-m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
- rtx old_operand ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
int
m68hc11_reload_operands (rtx 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 (i.e., big_offset % 256) is a valid constant offset
with respect to the mode. If it's not, we have to generate a
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
+int
m68hc11_auto_inc_p (rtx x)
{
return GET_CODE (x) == PRE_DEC
&& GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
}
-int
-tst_operand (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 (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 (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
-splitable_operand (rtx operand, enum machine_mode mode)
-{
- if (general_operand (operand, mode) == 0)
- return 0;
-
- if (push_operand (operand, mode) == 1)
- return 0;
-
- /* Reject a (MEM (MEM X)) because the patterns that use non_push_operand
- need to split such addresses to access the low and high part but it
- is not possible to express a valid address for the low part. */
- if (mode != QImode && GET_CODE (operand) == MEM
- && GET_CODE (XEXP (operand, 0)) == MEM)
- return 0;
- return 1;
-}
-
-int
-reg_or_some_mem_operand (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 (rtx operand, enum machine_mode mode)
{
operand = XEXP (operand, 0);
addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
- return register_indirect_p (operand, mode, addr_mode);
+ return m68hc11_valid_addressing_p (operand, mode, addr_mode);
}
return 0;
}
-int
-stack_register_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return SP_REG_P (operand);
-}
-
-int
-d_register_operand (rtx operand, enum machine_mode mode)
-{
- if (GET_MODE (operand) != mode && mode != VOIDmode)
- return 0;
-
- 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 (rtx operand, enum machine_mode mode)
-{
- if (GET_MODE (operand) != mode && mode != VOIDmode)
- return 0;
-
- 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 (rtx operand, enum machine_mode mode)
-{
- if (GET_MODE (operand) != mode && mode != VOIDmode)
- return 0;
-
- 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 (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return 0;
}
}
-
-int
-m68hc11_eq_compare_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return GET_CODE (op) == EQ || GET_CODE (op) == NE;
-}
-
-int
-m68hc11_logical_operator (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 (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 (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;
-}
-
-/* Return true if op is a shift operator. */
-int
-m68hc11_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
- || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
- || GET_CODE (op) == ASHIFTRT;
-}
-
-int
-m68hc11_unary_operator (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.
jmp FNADDR
*/
-void
-m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
+static void
+m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
{
const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx mem;
/* Skip the '*'. */
if (*static_chain_reg == '*')
static_chain_reg++;
if (TARGET_M6811)
{
- emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
- emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
- emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
- GEN_INT (0x18df));
- emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
+ mem = adjust_address (m_tramp, HImode, 0);
+ emit_move_insn (mem, GEN_INT (0x18ce));
+ mem = adjust_address (m_tramp, HImode, 2);
+ emit_move_insn (mem, cxt);
+ mem = adjust_address (m_tramp, HImode, 4);
+ emit_move_insn (mem, GEN_INT (0x18df));
+ mem = adjust_address (m_tramp, QImode, 6);
+ emit_move_insn (mem,
gen_rtx_CONST (QImode,
gen_rtx_SYMBOL_REF (Pmode,
static_chain_reg)));
- emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
- GEN_INT (0x7e));
- emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
+ mem = adjust_address (m_tramp, QImode, 7);
+ emit_move_insn (mem, GEN_INT (0x7e));
+ mem = adjust_address (m_tramp, HImode, 8);
+ emit_move_insn (mem, fnaddr);
}
else
{
- emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
- emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
- emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
+ mem = adjust_address (m_tramp, HImode, 0);
+ emit_move_insn (mem, GEN_INT (0x1803));
+ mem = adjust_address (m_tramp, HImode, 2);
+ emit_move_insn (mem, cxt);
+ mem = adjust_address (m_tramp, HImode, 4);
+ emit_move_insn (mem,
gen_rtx_CONST (HImode,
gen_rtx_SYMBOL_REF (Pmode,
static_chain_reg)));
- emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
- GEN_INT (0x06));
- emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
+ mem = adjust_address (m_tramp, QImode, 6);
+ emit_move_insn (mem, GEN_INT (0x06));
+ mem = adjust_address (m_tramp, HImode, 7);
+ emit_move_insn (mem, fnaddr);
}
}
\f
}
else
{
- warning ("%qs attribute ignored", IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute ignored",
+ 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. */
&& TREE_CODE (*node) != FIELD_DECL
&& TREE_CODE (*node) != TYPE_DECL)
{
- warning ("%qs attribute only applies to functions",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
*no_add_attrs = true;
}
{
const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
int len = strlen (str);
- char *newstr = alloca (len + 2);
+ char *newstr = XALLOCAVEC (char, len + 2);
newstr[0] = '@';
strcpy (&newstr[1], str);
trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
if (trap_handler && is_far)
{
- warning ("%<trap%> and %<far%> attributes are not compatible, ignoring %<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 ("%<trap%> attribute is already used");
+ warning (OPT_Wattributes, "%<trap%> attribute is already used");
else
trap_handler_symbol = XEXP (rtl, 0);
}
/* Argument support functions. */
+/* Given FROM and TO register numbers, say whether this elimination is
+ allowed. Frame pointer elimination is automatically handled.
+
+ All other eliminations are valid. */
+
+bool
+m68hc11_can_eliminate (const int from, const int to)
+{
+ return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
+ ? ! frame_pointer_needed
+ : true);
+}
+
/* Define the offset between two registers, one to be eliminated, and the
other its replacement, at the start of a routine. */
int
/* 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;
}
of mode MODE and data type TYPE.
(TYPE is null for libcalls where that information may not be available.) */
-void
+static void
m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
- tree type, int named ATTRIBUTE_UNUSED)
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
if (mode != BLKmode)
{
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis). */
-struct rtx_def *
-m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
- tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
+static rtx
+m68hc11_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named ATTRIBUTE_UNUSED)
{
if (cum->words != 0)
{
`downward' to pad below, or `none' to inhibit padding.
Structures are stored left shifted in their argument slot. */
-int
-m68hc11_function_arg_padding (enum machine_mode mode, tree type)
+enum direction
+m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
{
if (type != 0 && AGGREGATE_TYPE_P (type))
return upward;
/* Put a REG_INC note to tell the flow analysis that the instruction
is necessary. */
if (IS_STACK_PUSH (to))
- {
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
- XEXP (XEXP (to, 0), 0),
- REG_NOTES (insn));
- }
+ add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
else if (IS_STACK_POP (from))
- {
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
- XEXP (XEXP (from, 0), 0),
- REG_NOTES (insn));
- }
+ add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
/* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
to think that sp == _.frame and later replace a x = sp with x = _.frame.
The problem is that we are lying to gcc and use `txs' for x = sp
(which is not really true because txs is really x = sp + 1). */
else if (TARGET_M6811 && SP_REG_P (from))
- {
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
- from,
- REG_NOTES (insn));
- }
+ add_reg_note (insn, REG_INC, from);
}
int
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;
int regno;
rtx scratch;
- if (reload_completed != 1)
- abort ();
+ gcc_assert (reload_completed == 1);
size = get_frame_size ();
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;
/* 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);
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 && return_size <= 2 * HARD_REG_SIZE)
scratch = iy_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),
stack_pop_word, scratch);
{
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_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))
/* 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);
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_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)
{
{
return gen_int_mode (val >> 16, HImode);
}
+ else if (mode == SImode)
+ {
+ return gen_int_mode ((val >> 16) >> 16, SImode);
+ }
}
if (mode == QImode && D_REG_P (x))
return gen_rtx_REG (mode, HARD_A_REGNUM);
}
/* 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));
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
'T' generate the low-part temporary scratch register. The operand is
ignored. */
-void
-print_operand (FILE *file, rtx op, int letter)
+static void
+m68hc11_print_operand (FILE *file, rtx op, int letter)
{
if (letter == 't')
{
switch (GET_CODE (base))
{
case PRE_DEC:
- if (TARGET_M6812)
- {
- 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)
- {
- fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
- asm_print_register (file, REGNO (XEXP (base, 0)));
- 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)
- {
- fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
- asm_print_register (file, REGNO (XEXP (base, 0)));
- 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)
- {
- 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:
- if (TARGET_M6812)
- {
- fprintf (file, "[");
- print_operand_address (file, XEXP (base, 0));
- fprintf (file, "]");
- }
- else
- abort ();
+ gcc_assert (TARGET_M6812);
+ fprintf (file, "[");
+ m68hc11_print_operand_address (file, XEXP (base, 0));
+ fprintf (file, "]");
break;
default:
assembler syntax for an instruction operand that is a memory
reference whose address is ADDR. ADDR is an RTL expression. */
-void
-print_operand_address (FILE *file, rtx addr)
+static void
+m68hc11_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));
fprintf (file, "0,");
asm_print_register (file, REGNO (addr));
switch (GET_CODE (base))
{
case PRE_DEC:
- if (TARGET_M6812)
- {
- 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)
- {
- fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
- asm_print_register (file, REGNO (XEXP (base, 0)));
- 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)
- {
- fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
- asm_print_register (file, REGNO (XEXP (base, 0)));
- 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)
- {
- 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:
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)
fprintf (file, "(");
if (need_parenthesis)
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));
- 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
{
asm_print_register (file, REGNO (base));
}
}
- else
- {
- abort ();
- }
break;
default:
{
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_fmt_ee (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;
}
break;
default:
- abort ();
+ gcc_unreachable ();
}
/*
}
default:
- abort ();
+ gcc_unreachable ();
}
return 0;
}
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 void
-m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
+m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
{
rtx result;
int need_copy;
}
else if (operands[1] != 0 && operands[2] != 0)
{
- rtx insn;
-
if (!H_REG_P (operands[0]) && operands[3])
{
emit_move_insn (operands[3], operands[1]);
operands[3],
gen_rtx_fmt_ee (code, mode,
operands[3], operands[2])));
- insn = emit_move_insn (operands[0], operands[3]);
+ emit_move_insn (operands[0], operands[3]);
}
else
{
- insn = emit_insn (gen_rtx_SET (mode,
- operands[0],
- gen_rtx_fmt_ee (code, mode,
- operands[0],
- operands[2])));
+ emit_insn (gen_rtx_SET (mode, operands[0],
+ gen_rtx_fmt_ee (code, mode,
+ operands[0], operands[2])));
}
}
}
void
-m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
+m68hc11_split_logical (enum machine_mode mode, enum rtx_code 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];
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 ("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 ("psha", operands);
break;
default:
- abort ();
+ gcc_unreachable ();
}
return;
}
}
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
{
cc_status.flags = 0;
cc_status.value1 = XEXP (exp, 0);
- cc_status.value2 = XEXP (exp, 1);
+ if (GET_CODE (XEXP (exp, 1)) == COMPARE
+ && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
+ cc_status.value2 = XEXP (XEXP (exp, 1), 0);
+ else
+ cc_status.value2 = XEXP (exp, 1);
}
else
{
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->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;
}
}
if (GET_CODE (body) == CLOBBER)
{
+ rtx dst = XEXP (body, 0);
+
+ this_insn_uses_ix = reg_mentioned_p (ix_reg, dst);
+ this_insn_uses_iy = reg_mentioned_p (iy_reg, dst);
/* IX and IY are used at the same time, we have to restore
the value of the scratch register before this insn. */
m68hc11_reorg (void)
{
int split_done = 0;
- rtx insn, first;
+ rtx first;
z_replacement_completed = 0;
z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
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;
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);
- }
- }
- }
-
- life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
+ df_note_add_problem ();
+ df_analyze ();
+ df_remove_problem (df_note);
}
z_replacement_completed = 2;
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;
}
}
/* Cost of moving memory. */
int
-m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
+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);
If ADDR is not a valid address, its cost is irrelevant. */
static int
-m68hc11_address_cost (rtx addr)
+m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
{
int cost = 4;
{
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 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);
+ case ZERO_EXTRACT:
+ total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
if (mode == QImode)
{
return total + COSTS_N_INSNS (1);
}
static bool
-m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
+m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
+ bool speed ATTRIBUTE_UNUSED)
{
+ enum rtx_code code = (enum rtx_code) codearg;
+ enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
+
switch (code)
{
/* Constants are cheap. Moving them in registers must be avoided
*total = 0;
return true;
+ case ZERO_EXTRACT:
+ if (outer_code != COMPARE)
+ return false;
+
case ROTATE:
case ROTATERT:
case ASHIFT:
in the register (D + X = 4). */
static bool
-m68hc11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
{
if (TYPE_MODE (type) == BLKmode)
{