#include <stdio.h>
#include "config.h"
#include "system.h"
#include "rtl.h"
#include "tree.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 "insn-attr.h"
#include "flags.h"
#include "recog.h"
#include "expr.h"
#include "toplev.h"
#include "basic-block.h"
#include "function.h"
#include "ggc.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 autoinc_mode PARAMS ((rtx));
static int m68hc11_make_autoinc_notes PARAMS ((rtx*, void*));
static int m68hc11_auto_inc_p PARAMS ((rtx));
static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
const struct attribute_spec m68hc11_attribute_table[];
void create_regs_rtx 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));
static void m68hc11_encode_section_info PARAMS((tree, int));
int debug_m6811 = 0;
extern FILE *asm_out_file;
rtx ix_reg;
rtx iy_reg;
rtx d_reg;
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;
int current_function_interrupt;
int current_function_trap;
int current_function_far;
HOST_WIDE_INT m68hc11_min_offset = 0;
HOST_WIDE_INT m68hc11_max_offset = 256;
enum reg_class m68hc11_base_reg_class = A_REGS;
enum reg_class m68hc11_index_reg_class = NO_REGS;
enum reg_class m68hc11_tmp_regs_class = NO_REGS;
unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
int m68hc11_sp_correction;
rtx m68hc11_compare_op0;
rtx m68hc11_compare_op1;
const struct processor_costs *m68hc11_cost;
static const struct processor_costs m6811_cost = {
COSTS_N_INSNS (2),
COSTS_N_INSNS (2),
COSTS_N_INSNS (20),
{ COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
{ COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
COSTS_N_INSNS (4), COSTS_N_INSNS (2),
COSTS_N_INSNS (2), COSTS_N_INSNS (4),
COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
},
COSTS_N_INSNS (20),
COSTS_N_INSNS (20 * 4),
COSTS_N_INSNS (20 * 16),
COSTS_N_INSNS (20),
COSTS_N_INSNS (80),
COSTS_N_INSNS (100)
};
static const struct processor_costs m6812_cost = {
COSTS_N_INSNS (2),
COSTS_N_INSNS (2),
COSTS_N_INSNS (20),
{ COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
{ COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
COSTS_N_INSNS (4), COSTS_N_INSNS (2),
COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
COSTS_N_INSNS (6), COSTS_N_INSNS (4)
},
COSTS_N_INSNS (3),
COSTS_N_INSNS (3),
COSTS_N_INSNS (3 * 4),
COSTS_N_INSNS (12),
COSTS_N_INSNS (12),
COSTS_N_INSNS (100)
};
const char *m68hc11_regparm_string;
const char *m68hc11_reg_alloc_order;
const char *m68hc11_soft_reg_count;
static int nb_soft_regs;
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
struct gcc_target targetm = TARGET_INITIALIZER;
int
m68hc11_override_options ()
{
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));
if (flag_pic)
{
warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
(flag_pic > 1) ? "PIC" : "pic");
flag_pic = 0;
}
if (TARGET_M6811)
{
if (TARGET_DEFAULT != MASK_M6811)
target_flags &= ~TARGET_DEFAULT;
if (!TARGET_M6812)
target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
m68hc11_cost = &m6811_cost;
m68hc11_min_offset = 0;
m68hc11_max_offset = 256;
m68hc11_index_reg_class = NO_REGS;
m68hc11_base_reg_class = A_REGS;
m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
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";
}
if (TARGET_M6812)
{
m68hc11_cost = &m6812_cost;
m68hc11_min_offset = -65536;
m68hc11_max_offset = 65536;
m68hc11_index_reg_class = D_REGS;
m68hc11_base_reg_class = A_OR_SP_REGS;
m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
m68hc11_sp_correction = 0;
m68hc11_tmp_regs_class = TMP_REGS;
target_flags &= ~MASK_M6811;
target_flags |= MASK_NO_DIRECT_MODE;
if (m68hc11_soft_reg_count == 0)
m68hc11_soft_reg_count = "0";
if (TARGET_LONG_CALLS)
current_function_far = 1;
}
return 0;
}
void
m68hc11_conditional_register_usage ()
{
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;
nb_soft_regs = cnt;
for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
{
fixed_regs[i] = 1;
call_used_regs[i] = 1;
}
if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
{
fixed_regs[HARD_Z_REGNUM] = 1;
}
}
static const char *const reg_class_names[] = REG_CLASS_NAMES;
void
create_regs_rtx ()
{
ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
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)));
}
int
hard_regno_mode_ok (regno, mode)
int regno;
enum machine_mode mode;
{
switch (GET_MODE_SIZE (mode))
{
case 8:
return S_REGNO_P (regno) && nb_soft_regs >= 4;
case 4:
return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
case 2:
return G_REGNO_P (regno);
case 1:
return G_REGNO_P (regno) && !SP_REGNO_P (regno);
default:
return 0;
}
}
enum reg_class
preferred_reload_class (operand, class)
rtx operand;
enum reg_class class;
{
enum machine_mode mode;
mode = GET_MODE (operand);
if (debug_m6811)
{
printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
}
if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
return m68hc11_base_reg_class;
if (class >= S_REGS && (GET_CODE (operand) == MEM
|| GET_CODE (operand) == CONST_INT))
{
switch (class)
{
default:
case G_REGS:
case D_OR_A_OR_S_REGS:
class = A_OR_D_REGS;
break;
case A_OR_S_REGS:
class = A_REGS;
break;
case D_OR_SP_OR_S_REGS:
class = D_OR_SP_REGS;
break;
case D_OR_Y_OR_S_REGS:
class = D_OR_Y_REGS;
break;
case D_OR_X_OR_S_REGS:
class = D_OR_X_REGS;
break;
case SP_OR_S_REGS:
class = SP_REGS;
break;
case Y_OR_S_REGS:
class = Y_REGS;
break;
case X_OR_S_REGS:
class = X_REGS;
break;
case D_OR_S_REGS:
class = D_REGS;
}
}
else if (class == Y_REGS && GET_CODE (operand) == MEM)
{
class = Y_REGS;
}
else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
{
class = D_OR_X_REGS;
}
else if (class >= S_REGS && S_REG_P (operand))
{
switch (class)
{
default:
case G_REGS:
case D_OR_A_OR_S_REGS:
class = A_OR_D_REGS;
break;
case A_OR_S_REGS:
class = A_REGS;
break;
case D_OR_SP_OR_S_REGS:
class = D_OR_SP_REGS;
break;
case D_OR_Y_OR_S_REGS:
class = D_OR_Y_REGS;
break;
case D_OR_X_OR_S_REGS:
class = D_OR_X_REGS;
break;
case SP_OR_S_REGS:
class = SP_REGS;
break;
case Y_OR_S_REGS:
class = Y_REGS;
break;
case X_OR_S_REGS:
class = X_REGS;
break;
case D_OR_S_REGS:
class = D_REGS;
}
}
else if (class >= S_REGS)
{
if (debug_m6811)
{
printf ("Class = %s for: ", reg_class_names[class]);
fflush (stdout);
debug_rtx (operand);
}
}
if (debug_m6811)
{
printf (" => class=%s\n", reg_class_names[class]);
fflush (stdout);
debug_rtx (operand);
}
return class;
}
static int
register_indirect_p (operand, mode, strict)
rtx operand;
enum machine_mode mode;
int strict;
{
rtx base, offset;
switch (GET_CODE (operand))
{
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);
return 0;
case PLUS:
base = XEXP (operand, 0);
if (GET_CODE (base) == MEM)
return 0;
offset = XEXP (operand, 1);
if (GET_CODE (offset) == MEM)
return 0;
if (GET_CODE (base) == REG)
{
if (!VALID_CONSTANT_OFFSET_P (offset, mode))
return 0;
if (strict == 0)
return 1;
return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
}
if (GET_CODE (offset) == REG)
{
if (!VALID_CONSTANT_OFFSET_P (base, mode))
return 0;
if (strict == 0)
return 1;
return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
}
return 0;
case REG:
return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
case CONST_INT:
if (TARGET_M6811)
return 0;
return VALID_CONSTANT_OFFSET_P (operand, mode);
default:
return 0;
}
}
int
m68hc11_small_indexed_indirect_p (operand, mode)
rtx operand;
enum machine_mode mode;
{
rtx base, offset;
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);
if (CONSTANT_ADDRESS_P (operand))
return 1;
if (PUSH_POP_ADDRESS_P (operand))
return 1;
if (!register_indirect_p (operand, mode, reload_completed))
return 0;
if (TARGET_M6812 && GET_CODE (operand) == PLUS
&& (reload_completed | reload_in_progress))
{
base = XEXP (operand, 0);
offset = XEXP (operand, 1);
if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
return 0;
if (GET_CODE (base) == CONST_INT)
offset = base;
switch (GET_MODE_SIZE (mode))
{
case 8:
if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
return 0;
break;
case 4:
if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
return 0;
break;
default:
if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
return 0;
break;
}
}
return 1;
}
int
m68hc11_register_indirect_p (operand, mode)
rtx operand;
enum machine_mode mode;
{
if (GET_CODE (operand) != MEM)
return 0;
operand = XEXP (operand, 0);
return register_indirect_p (operand, mode,
(reload_completed | reload_in_progress));
}
static int
go_if_legitimate_address_internal (operand, mode, strict)
rtx operand;
enum machine_mode mode;
int strict;
{
if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
{
if (GET_MODE_SIZE (mode) == 8)
return 0;
return 1;
}
if (register_indirect_p (operand, mode, strict))
{
return 1;
}
if (PUSH_POP_ADDRESS_P (operand))
{
return 1;
}
if (symbolic_memory_operand (operand, mode))
{
return 1;
}
return 0;
}
int
m68hc11_go_if_legitimate_address (operand, mode, strict)
rtx operand;
enum machine_mode mode;
int strict;
{
int result;
if (debug_m6811)
{
printf ("Checking: ");
fflush (stdout);
debug_rtx (operand);
}
result = go_if_legitimate_address_internal (operand, mode, strict);
if (debug_m6811)
{
printf (" -> %s\n", result == 0 ? "NO" : "YES");
}
if (result == 0)
{
if (debug_m6811)
{
printf ("go_if_legitimate%s, ret 0: %d:",
(strict ? "_strict" : ""), mode);
fflush (stdout);
debug_rtx (operand);
}
}
return result;
}
int
m68hc11_legitimize_address (operand, old_operand, mode)
rtx *operand ATTRIBUTE_UNUSED;
rtx old_operand ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return 0;
}
int
m68hc11_reload_operands (operands)
rtx operands[];
{
enum machine_mode mode;
if (regs_inited == 0)
create_regs_rtx ();
mode = GET_MODE (operands[1]);
if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
{
rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
rtx base = XEXP (XEXP (operands[1], 0), 0);
if (GET_CODE (base) != REG)
{
rtx tmp = base;
base = big_offset;
big_offset = tmp;
}
if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
{
int vh, vl;
rtx reg = operands[0];
rtx offset;
int val = INTVAL (big_offset);
if (!rtx_equal_p (base, operands[0]))
{
emit_move_insn (reg, base);
}
if (val > 0)
{
vh = val >> 8;
vl = val & 0x0FF;
}
else
{
vh = (val >> 8) & 0x0FF;
vl = val & 0x0FF;
}
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)));
offset = const0_rtx;
}
else
{
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)));
return 1;
}
}
return 0;
}
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;
{
rtx ret;
rtx insns;
rtx libcall;
rtx equiv;
start_sequence ();
libcall = gen_rtx_SYMBOL_REF (Pmode, name);
switch (noperands)
{
case 2:
ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
dmode, 1, operands[1], smode);
equiv = gen_rtx (code, dmode, operands[1]);
break;
case 3:
ret = emit_library_call_value (libcall, NULL_RTX,
LCT_CONST, dmode, 2,
operands[1], smode, operands[2],
smode);
equiv = gen_rtx (code, dmode, operands[1], operands[2]);
break;
default:
abort ();
}
insns = get_insns ();
end_sequence ();
emit_libcall_block (insns, operands[0], ret, equiv);
}
static int
m68hc11_auto_inc_p (x)
rtx x;
{
return GET_CODE (x) == PRE_DEC
|| GET_CODE (x) == POST_INC
|| GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
}
int
memory_reload_operand (operand, mode)
rtx operand;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (operand) == MEM
&& GET_CODE (XEXP (operand, 0)) == PLUS
&& ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
&& GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
|| (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
&& GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
}
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;
{
if (GET_CODE (operand) == MEM)
{
rtx op = XEXP (operand, 0);
if (symbolic_memory_operand (op, mode))
return 1;
}
return 0;
}
int
m68hc11_indirect_p (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 0;
if (reload_in_progress)
return 1;
operand = XEXP (operand, 0);
return register_indirect_p (operand, mode, reload_completed);
}
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;
{
if (GET_CODE (operand) != MEM)
return 0;
operand = XEXP (operand, 0);
if (GET_CODE (operand) == PLUS)
{
if (GET_CODE (XEXP (operand, 0)) == REG)
operand = XEXP (operand, 0);
else if (GET_CODE (XEXP (operand, 1)) == REG)
operand = XEXP (operand, 1);
}
return GET_CODE (operand) == REG
&& (REGNO (operand) >= FIRST_PSEUDO_REGISTER
|| A_REGNO_P (REGNO (operand)));
}
int
push_pop_operand_p (operand)
rtx operand;
{
if (GET_CODE (operand) != MEM)
{
return 0;
}
operand = XEXP (operand, 0);
return PUSH_POP_ADDRESS_P (operand);
}
int
symbolic_memory_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
case CONST_DOUBLE:
return GET_MODE (op) == mode;
case PLUS:
return symbolic_memory_operand (XEXP (op, 0), mode)
&& symbolic_memory_operand (XEXP (op, 1), mode);
default:
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_shift_operator (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
|| GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
|| GET_CODE (op) == ASHIFTRT;
}
int
m68hc11_unary_operator (op, mode)
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;
}
void
m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
rtx tramp;
rtx fnaddr;
rtx cxt;
{
const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
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)),
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);
}
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)),
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);
}
}
const struct attribute_spec m68hc11_attribute_table[] =
{
{ "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
{ "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
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;
{
if (TREE_CODE (*node) != FUNCTION_TYPE
&& TREE_CODE (*node) != FIELD_DECL
&& TREE_CODE (*node) != TYPE_DECL)
{
warning ("`%s' attribute only applies to functions",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
return NULL_TREE;
}
static void
m68hc11_encode_section_info (decl, first)
tree decl;
int first ATTRIBUTE_UNUSED;
{
tree func_attr;
int trap_handler;
rtx rtl;
if (TREE_CODE (decl) != FUNCTION_DECL)
return;
rtl = DECL_RTL (decl);
func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
}
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;
{
return ((type && TREE_CODE (type) == ARRAY_TYPE)
);
}
int
m68hc11_initial_elimination_offset (from, to)
int from;
int to;
{
int trap_handler;
tree func_attr;
int size;
int regno;
func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
if (trap_handler && from == ARG_POINTER_REGNUM)
size = 7;
else if (current_function_far && from == ARG_POINTER_REGNUM)
size = 1;
else
size = 0;
if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
{
return get_frame_size () + 2 + m68hc11_sp_correction + size;
}
if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
{
return m68hc11_sp_correction;
}
for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
{
if (regs_ever_live[regno] && !call_used_regs[regno])
{
size += 2;
}
}
if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
{
return get_frame_size () + size;
}
if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
{
return size;
}
return 0;
}
void
m68hc11_init_cumulative_args (cum, fntype, libname)
CUMULATIVE_ARGS *cum;
tree fntype;
rtx libname;
{
tree ret_type;
z_replacement_completed = 0;
cum->words = 0;
cum->nregs = 0;
if (fntype == 0)
{
const char *name;
size_t len;
if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
return;
name = XSTR (libname, 0);
len = strlen (name);
if (len > 3
&& ((name[len - 2] == 'd'
&& (name[len - 1] == 'f' || name[len - 1] == 'i'))
|| (name[len - 3] == 'd'
&& (name[len - 2] == 'i' || name[len - 2] == 'f'))))
{
cum->words = 1;
cum->nregs = 1;
}
return;
}
ret_type = TREE_TYPE (fntype);
if (ret_type && aggregate_value_p (ret_type))
{
cum->words = 1;
cum->nregs = 1;
}
}
void
m68hc11_function_arg_advance (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named ATTRIBUTE_UNUSED;
{
if (mode != BLKmode)
{
if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
{
cum->nregs = 2;
cum->words = GET_MODE_SIZE (mode);
}
else
{
cum->words += GET_MODE_SIZE (mode);
if (cum->words <= HARD_REG_SIZE)
cum->nregs = 1;
}
}
else
{
cum->words += int_size_in_bytes (type);
}
return;
}
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;
{
if (cum->words != 0)
{
return NULL_RTX;
}
if (mode != BLKmode)
{
if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
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 NULL_RTX;
}
rtx
m68hc11_va_arg (valist, type)
tree valist;
tree type;
{
tree addr_tree, t;
HOST_WIDE_INT align;
HOST_WIDE_INT rounded_size;
rtx addr;
int pad_direction;
align = PARM_BOUNDARY / BITS_PER_UNIT;
rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
addr_tree = valist;
pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
if (pad_direction == 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);
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;
}
int
m68hc11_function_arg_padding (mode, type)
enum machine_mode mode;
tree type;
{
if (type != 0 && AGGREGATE_TYPE_P (type))
return upward;
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));
}
static void
emit_move_after_reload (to, from, scratch)
rtx to, from, scratch;
{
rtx insn;
if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
{
insn = emit_move_insn (to, from);
}
else
{
emit_move_insn (scratch, from);
insn = emit_move_insn (to, scratch);
}
if (IS_STACK_PUSH (to))
{
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
XEXP (XEXP (to, 0), 0),
REG_NOTES (insn));
}
else if (IS_STACK_POP (from))
{
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
XEXP (XEXP (from, 0), 0),
REG_NOTES (insn));
}
else if (TARGET_M6811 && SP_REG_P (from))
{
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
from,
REG_NOTES (insn));
}
}
int
m68hc11_total_frame_size ()
{
int size;
int regno;
size = get_frame_size ();
if (current_function_interrupt)
{
size += 3 * HARD_REG_SIZE;
}
if (frame_pointer_needed)
size += HARD_REG_SIZE;
for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
if (regs_ever_live[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;
{
z_replacement_completed = 0;
}
void
expand_prologue ()
{
tree func_attr;
int size;
int regno;
rtx scratch;
if (reload_completed != 1)
abort ();
size = get_frame_size ();
create_regs_rtx ();
func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
current_function_interrupt = lookup_attribute ("interrupt",
func_attr) != NULL_TREE;
current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
if (current_function_args_info.nregs == 2)
scratch = iy_reg;
else
scratch = ix_reg;
if (current_function_interrupt)
{
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);
emit_move_after_reload (stack_push_word,
gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
scratch);
}
if (frame_pointer_needed)
emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
if (TARGET_M6812 && (size > 4 || size == 3))
{
emit_insn (gen_addhi3 (stack_pointer_rtx,
stack_pointer_rtx, GEN_INT (-size)));
}
else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
{
rtx insn;
insn = gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2,
gen_rtx_SET (VOIDmode,
stack_pointer_rtx,
gen_rtx_PLUS (HImode,
stack_pointer_rtx,
GEN_INT (-size))),
gen_rtx_CLOBBER (VOIDmode, scratch)));
emit_insn (insn);
}
else
{
int i;
for (i = 2; i <= size; i += 2)
emit_move_after_reload (stack_push_word, ix_reg, 0);
if (size & 1)
emit_insn (gen_addhi3 (stack_pointer_rtx,
stack_pointer_rtx, GEN_INT (-1)));
}
if (frame_pointer_needed)
emit_move_after_reload (hard_frame_pointer_rtx,
stack_pointer_rtx, scratch);
for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
{
if (regs_ever_live[regno] && !call_used_regs[regno])
{
emit_move_after_reload (stack_push_word,
gen_rtx (REG, HImode, regno), scratch);
}
}
}
void
expand_epilogue ()
{
int size;
register int regno;
int return_size;
rtx scratch;
if (reload_completed != 1)
abort ();
size = get_frame_size ();
if (current_function_return_rtx == 0)
return_size = 0;
else if (GET_CODE (current_function_return_rtx) == MEM)
return_size = HARD_REG_SIZE;
else
return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
if (return_size > HARD_REG_SIZE)
scratch = iy_reg;
else
scratch = ix_reg;
for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
{
if (regs_ever_live[regno] && !call_used_regs[regno])
{
emit_move_after_reload (gen_rtx (REG, HImode, regno),
stack_pop_word, scratch);
}
}
if (TARGET_M6812 && (size > 4 || size == 3))
{
emit_insn (gen_addhi3 (stack_pointer_rtx,
stack_pointer_rtx, GEN_INT (size)));
}
else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
{
rtx insn;
insn = gen_rtx_PARALLEL
(VOIDmode,
gen_rtvec (2,
gen_rtx_SET (VOIDmode,
stack_pointer_rtx,
gen_rtx_PLUS (HImode,
stack_pointer_rtx,
GEN_INT (size))),
gen_rtx_CLOBBER (VOIDmode, scratch)));
emit_insn (insn);
}
else
{
int i;
for (i = 2; i <= size; i += 2)
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)));
}
if (frame_pointer_needed)
emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
if (current_function_interrupt)
{
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),
stack_pop_word, scratch);
emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
}
else if (current_function_trap && return_size != 0)
{
rtx addr_reg = stack_pointer_rtx;
if (!TARGET_M6812)
{
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);
if (return_size > HARD_REG_SIZE)
emit_move_after_reload (gen_rtx (MEM, HImode,
gen_rtx (PLUS, HImode, addr_reg,
GEN_INT (3))), ix_reg, 0);
}
emit_jump_insn (gen_return ());
}
rtx
m68hc11_gen_lowpart (mode, x)
enum machine_mode mode;
rtx x;
{
if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
{
return gen_rtx (MEM, mode, XEXP (x, 0));
}
if (GET_CODE (x) == CONST_DOUBLE)
{
long l[2];
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
REAL_VALUE_TYPE r;
if (GET_MODE (x) == SFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
}
else
{
rtx first, second;
split_double (x, &first, &second);
return second;
}
if (mode == SImode)
return GEN_INT (l[0]);
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_mode (l[0], HImode);
else
abort ();
}
if (mode == QImode && D_REG_P (x))
return gen_rtx (REG, mode, HARD_B_REGNUM);
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 ();
}
x = gen_lowpart (mode, x);
if (GET_CODE (x) == MEM)
x = copy_rtx (x);
return x;
}
rtx
m68hc11_gen_highpart (mode, x)
enum machine_mode mode;
rtx x;
{
if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
{
return gen_rtx (MEM, mode, XEXP (x, 0));
}
if (GET_CODE (x) == CONST_DOUBLE)
{
long l[2];
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
REAL_VALUE_TYPE r;
if (GET_MODE (x) == SFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
}
else
{
rtx first, second;
split_double (x, &first, &second);
return first;
}
if (mode == SImode)
return GEN_INT (l[1]);
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_mode ((l[0] >> 16), HImode);
else
abort ();
}
if (GET_CODE (x) == CONST_INT)
{
HOST_WIDE_INT val = INTVAL (x);
if (mode == QImode)
{
return gen_int_mode (val >> 8, QImode);
}
else if (mode == HImode)
{
return gen_int_mode (val >> 16, HImode);
}
}
if (mode == QImode && D_REG_P (x))
return gen_rtx (REG, mode, HARD_A_REGNUM);
if (mode == QImode && S_REG_P (x))
{
int pos;
pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
return gen_rtx (MEM, QImode,
gen_rtx (SYMBOL_REF, Pmode,
®_names[REGNO (x)][pos]));
}
if (GET_CODE (x) == SUBREG)
{
return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
}
if (GET_CODE (x) == 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)
{
x = change_address (x, mode, 0);
if (GET_CODE (x) == MEM)
x = copy_rtx (x);
return x;
}
abort ();
}
int
dead_register_here (x, reg)
rtx x;
rtx reg;
{
rtx x_reg;
rtx p;
if (D_REG_P (reg))
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')
{
rtx body;
body = PATTERN (p);
if (GET_CODE (body) == CALL_INSN)
break;
if (GET_CODE (body) == JUMP_INSN)
break;
if (GET_CODE (body) == SET)
{
rtx dst = XEXP (body, 0);
if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
break;
if (x_reg && rtx_equal_p (dst, x_reg))
break;
if (find_regno_note (p, REG_DEAD, REGNO (reg)))
return 1;
}
else if (reg_mentioned_p (reg, p)
|| (x_reg && reg_mentioned_p (x_reg, p)))
break;
}
for (p = x ; p; p = NEXT_INSN (p))
{
rtx body;
if (GET_CODE (p) == CODE_LABEL
|| GET_CODE (p) == JUMP_INSN
|| GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
break;
if (GET_CODE (p) != INSN)
continue;
body = PATTERN (p);
if (GET_CODE (body) == SET)
{
rtx src = XEXP (body, 1);
rtx dst = XEXP (body, 0);
if (GET_CODE (dst) == REG
&& REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
return 1;
}
if (reg_mentioned_p (reg, p)
|| (x_reg != 0 && GET_MODE (p) == SImode
&& reg_mentioned_p (x_reg, p)))
break;
}
return p == 0 ? 1 : 0;
}
static void
asm_print_register (file, regno)
FILE *file;
int regno;
{
const char *name = reg_names[regno];
if (TARGET_NO_DIRECT_MODE && name[0] == '*')
name++;
fprintf (file, "%s", name);
}
void
print_operand (file, op, letter)
FILE *file;
rtx op;
int letter;
{
if (letter == 't')
{
asm_print_register (file, SOFT_TMP_REGNUM);
return;
}
else if (letter == 'T')
{
asm_print_register (file, SOFT_TMP_REGNUM);
fprintf (file, "+1");
return;
}
else if (letter == '#')
{
asm_fprintf (file, "%0I");
}
if (GET_CODE (op) == REG)
{
if (letter == 'b' && S_REG_P (op))
{
asm_print_register (file, REGNO (op));
fprintf (file, "+1");
}
else
{
asm_print_register (file, REGNO (op));
}
return;
}
if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
{
if (letter == 'b')
asm_fprintf (file, "%0I%%lo(");
else
asm_fprintf (file, "%0I%%hi(");
output_addr_const (file, op);
fprintf (file, ")");
return;
}
if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
{
if (letter == 'b')
{
op = m68hc11_gen_lowpart (QImode, op);
}
else if (letter == 'h')
{
op = m68hc11_gen_highpart (QImode, op);
}
}
if (GET_CODE (op) == MEM)
{
rtx base = XEXP (op, 0);
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 ();
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 ();
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 ();
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 ();
break;
default:
output_address (base);
break;
}
}
else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
{
REAL_VALUE_TYPE r;
long l;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
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))
{
char dstr[30];
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");
else
need_parenthesize = must_parenthesize (op);
if (need_parenthesize)
fprintf (file, "(");
output_addr_const (file, op);
if (need_parenthesize)
fprintf (file, ")");
}
}
static int
must_parenthesize (op)
rtx op;
{
const char *name;
switch (GET_CODE (op))
{
case SYMBOL_REF:
name = XSTR (op, 0);
return (strcasecmp (name, "a") == 0
|| strcasecmp (name, "b") == 0
|| strcasecmp (name, "d") == 0
|| strcasecmp (name, "x") == 0
|| strcasecmp (name, "y") == 0
|| strcasecmp (name, "ix") == 0
|| strcasecmp (name, "iy") == 0
|| strcasecmp (name, "pc") == 0
|| strcasecmp (name, "sp") == 0
|| strcasecmp (name, "ccr") == 0) ? 1 : 0;
case PLUS:
case MINUS:
return must_parenthesize (XEXP (op, 0))
|| must_parenthesize (XEXP (op, 1));
case MEM:
case CONST:
case ZERO_EXTEND:
case SIGN_EXTEND:
return must_parenthesize (XEXP (op, 0));
case CONST_DOUBLE:
case CONST_INT:
case LABEL_REF:
case CODE_LABEL:
default:
return 0;
}
}
void
print_operand_address (file, addr)
FILE *file;
rtx addr;
{
rtx base;
rtx offset;
int need_parenthesis = 0;
switch (GET_CODE (addr))
{
case REG:
if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
abort ();
fprintf (file, "0,");
asm_print_register (file, REGNO (addr));
break;
case MEM:
base = XEXP (addr, 0);
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 ();
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 ();
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 ();
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 ();
break;
default:
need_parenthesis = must_parenthesize (base);
if (need_parenthesis)
fprintf (file, "(");
output_addr_const (file, base);
if (need_parenthesis)
fprintf (file, ")");
break;
}
break;
case PLUS:
base = XEXP (addr, 0);
offset = XEXP (addr, 1);
if (!G_REG_P (base) && G_REG_P (offset))
{
base = XEXP (addr, 1);
offset = XEXP (addr, 0);
}
if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
{
need_parenthesis = must_parenthesize (addr);
if (need_parenthesis)
fprintf (file, "(");
output_addr_const (file, base);
fprintf (file, "+");
output_addr_const (file, offset);
if (need_parenthesis)
fprintf (file, ")");
}
else if (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 ();
}
else
{
need_parenthesis = must_parenthesize (offset);
if (need_parenthesis)
fprintf (file, "(");
output_addr_const (file, offset);
if (need_parenthesis)
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)
{
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
}
else
{
need_parenthesis = must_parenthesize (addr);
if (need_parenthesis)
fprintf (file, "(");
output_addr_const (file, addr);
if (need_parenthesis)
fprintf (file, ")");
}
break;
}
}
static rtx
m68hc11_expand_compare (code, op0, op1)
enum rtx_code code;
rtx op0, 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);
}
return ret;
}
rtx
m68hc11_expand_compare_and_branch (code, op0, op1, label)
enum rtx_code code;
rtx op0, op1, label;
{
rtx tmp;
switch (GET_MODE (op0))
{
case QImode:
case HImode:
tmp = m68hc11_expand_compare (code, op0, op1);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx);
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
return 0;
#if 0
case SFmode:
case DFmode:
{
rtvec vec;
int use_fcomi;
code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
&m68hc11_compare_op1);
tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
m68hc11_compare_op0, m68hc11_compare_op1);
tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx);
tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
use_fcomi = ix86_use_fcomi_compare (code);
vec = rtvec_alloc (3 + !use_fcomi);
RTVEC_ELT (vec, 0) = tmp;
RTVEC_ELT (vec, 1)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
RTVEC_ELT (vec, 2)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
if (!use_fcomi)
RTVEC_ELT (vec, 3)
= gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
return;
}
#endif
case SImode:
{
rtx lo[2], hi[2], label2;
enum rtx_code code1, code2, code3;
if (CONSTANT_P (op0) && !CONSTANT_P (op1))
{
tmp = op0;
op0 = op1;
op1 = tmp;
code = swap_condition (code);
}
lo[0] = m68hc11_gen_lowpart (HImode, op0);
lo[1] = m68hc11_gen_lowpart (HImode, op1);
hi[0] = m68hc11_gen_highpart (HImode, op0);
hi[1] = m68hc11_gen_highpart (HImode, op1);
if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
&& (code == LT || code == LTU))
{
return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
label);
}
label2 = gen_label_rtx ();
code1 = code;
code2 = swap_condition (code);
code3 = unsigned_condition (code);
switch (code)
{
case LT:
case GT:
case LTU:
case GTU:
break;
case LE:
code1 = LT;
code2 = GT;
break;
case GE:
code1 = GT;
code2 = LT;
break;
case LEU:
code1 = LTU;
code2 = GTU;
break;
case GEU:
code1 = GTU;
code2 = LTU;
break;
case EQ:
code1 = NIL;
code2 = NE;
break;
case NE:
code2 = NIL;
break;
default:
abort ();
}
if (code1 != NIL)
m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
if (code2 != NIL)
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)
emit_label (label2);
return 0;
}
default:
abort ();
}
return 0;
}
static int
autoinc_mode (x)
rtx x;
{
if (GET_CODE (x) != MEM)
return CONST;
x = XEXP (x, 0);
if (GET_CODE (x) == PRE_INC
|| GET_CODE (x) == PRE_DEC
|| GET_CODE (x) == POST_INC
|| GET_CODE (x) == POST_DEC)
return GET_CODE (x);
return CONST;
}
static int
m68hc11_make_autoinc_notes (x, data)
rtx *x;
void *data;
{
rtx insn;
switch (GET_CODE (*x))
{
case PRE_DEC:
case PRE_INC:
case POST_DEC:
case POST_INC:
insn = (rtx) data;
REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
REG_NOTES (insn));
return -1;
default:
return 0;
}
}
void
m68hc11_split_move (to, from, scratch)
rtx to, from, scratch;
{
rtx low_to, low_from;
rtx high_to, high_from;
rtx insn;
enum machine_mode mode;
int offset = 0;
int autoinc_from = autoinc_mode (from);
int autoinc_to = autoinc_mode (to);
mode = GET_MODE (to);
if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
{
rtx reg;
int code;
if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
{
code = GET_CODE (XEXP (from, 0));
reg = XEXP (XEXP (from, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (from));
if (code == POST_DEC)
offset = -offset;
if (code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
if (code == POST_DEC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
{
code = GET_CODE (XEXP (to, 0));
reg = XEXP (XEXP (to, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (to));
if (code == POST_DEC)
offset = -offset;
if (code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
if (code == POST_DEC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
if ((autoinc_to != autoinc_from
&& autoinc_to != CONST && autoinc_from != CONST)
|| (autoinc_to != CONST
&& reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
&& !IS_STACK_PUSH (to)))
{
code = GET_CODE (XEXP (to, 0));
reg = XEXP (XEXP (to, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (to));
if (code == PRE_DEC || code == POST_DEC)
offset = -offset;
if (code == PRE_DEC || code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
if (code == POST_DEC || code == POST_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
if (autoinc_from != CONST
&& reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
&& !IS_STACK_PUSH (to))
{
code = GET_CODE (XEXP (from, 0));
reg = XEXP (XEXP (from, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (from));
if (code == PRE_DEC || code == POST_DEC)
offset = -offset;
if (code == PRE_DEC || code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
if (code == POST_DEC || code == POST_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
}
if (GET_MODE_SIZE (mode) == 8)
mode = SImode;
else if (GET_MODE_SIZE (mode) == 4)
mode = HImode;
else
mode = QImode;
if (TARGET_M6812
&& IS_STACK_PUSH (to)
&& reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
{
if (mode == SImode)
{
offset = 4;
}
else if (mode == HImode)
{
offset = 2;
}
else
offset = 0;
}
low_to = m68hc11_gen_lowpart (mode, to);
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);
if (offset)
{
high_from = adjust_address (high_from, mode, offset);
low_from = high_from;
}
if (TARGET_M6812
&& GET_MODE_SIZE (mode) >= 2
&& autoinc_from != autoinc_to
&& (autoinc_from == POST_INC || autoinc_to == POST_INC))
{
rtx swap;
swap = low_to;
low_to = high_to;
high_to = swap;
swap = low_from;
low_from = high_from;
high_from = swap;
}
if (mode == SImode)
{
m68hc11_split_move (low_to, low_from, scratch);
m68hc11_split_move (high_to, high_from, scratch);
}
else if (H_REG_P (to) || H_REG_P (from)
|| (low_from == const0_rtx
&& high_from == const0_rtx
&& ! push_operand (to, GET_MODE (to))
&& ! H_REG_P (scratch))
|| (TARGET_M6812
&& (!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))
|| m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
{
insn = emit_move_insn (low_to, low_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
insn = emit_move_insn (high_to, high_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
}
else
{
insn = emit_move_insn (scratch, low_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
insn = emit_move_insn (low_to, scratch);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
insn = emit_move_insn (scratch, high_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
insn = emit_move_insn (high_to, scratch);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
}
}
static rtx
simplify_logical (mode, code, operand, result)
enum machine_mode mode;
int code;
rtx operand;
rtx *result;
{
int val;
int mask;
*result = 0;
if (GET_CODE (operand) != CONST_INT)
return operand;
if (mode == HImode)
mask = 0x0ffff;
else
mask = 0x0ff;
val = INTVAL (operand);
switch (code)
{
case IOR:
if ((val & mask) == 0)
return 0;
if ((val & mask) == mask)
*result = constm1_rtx;
break;
case AND:
if ((val & mask) == 0)
*result = const0_rtx;
if ((val & mask) == mask)
return 0;
break;
case XOR:
if ((val & mask) == 0)
return 0;
break;
}
return operand;
}
static void
m68hc11_emit_logical (mode, code, operands)
enum machine_mode mode;
int code;
rtx *operands;
{
rtx result;
int need_copy;
need_copy = (rtx_equal_p (operands[0], operands[1])
|| rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
operands[1] = simplify_logical (mode, code, operands[1], &result);
operands[2] = simplify_logical (mode, code, operands[2], &result);
if (result && GET_CODE (result) == CONST_INT)
{
if (!H_REG_P (operands[0]) && operands[3]
&& (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
{
emit_move_insn (operands[3], result);
emit_move_insn (operands[0], operands[3]);
}
else
{
emit_move_insn (operands[0], result);
}
}
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]);
emit_insn (gen_rtx (SET, mode,
operands[3],
gen_rtx (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])));
}
}
else if (need_copy)
{
rtx src;
if (GET_CODE (operands[1]) == CONST_INT)
src = operands[2];
else
src = operands[1];
if (!H_REG_P (operands[0]) && !H_REG_P (src))
{
emit_move_insn (operands[3], src);
emit_move_insn (operands[0], operands[3]);
}
else
{
emit_move_insn (operands[0], src);
}
}
}
void
m68hc11_split_logical (mode, code, operands)
enum machine_mode mode;
int code;
rtx *operands;
{
rtx low[4];
rtx high[4];
low[0] = m68hc11_gen_lowpart (mode, operands[0]);
low[1] = m68hc11_gen_lowpart (mode, operands[1]);
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]);
low[3] = operands[3];
high[3] = operands[3];
if (mode == SImode)
{
m68hc11_split_logical (HImode, code, low);
m68hc11_split_logical (HImode, code, high);
return;
}
m68hc11_emit_logical (mode, code, low);
m68hc11_emit_logical (mode, code, high);
}
void
m68hc11_output_swap (insn, operands)
rtx insn ATTRIBUTE_UNUSED;
rtx operands[];
{
if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
{
if (cc_prev_status.value1 != 0
&& (D_REG_P (cc_prev_status.value1)
|| X_REG_P (cc_prev_status.value1)))
{
cc_status = cc_prev_status;
if (D_REG_P (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),
HARD_D_REGNUM);
}
else
CC_STATUS_INIT;
output_asm_insn ("xgdx", operands);
}
else
{
if (cc_prev_status.value1 != 0
&& (D_REG_P (cc_prev_status.value1)
|| Y_REG_P (cc_prev_status.value1)))
{
cc_status = cc_prev_status;
if (D_REG_P (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),
HARD_D_REGNUM);
}
else
CC_STATUS_INIT;
output_asm_insn ("xgdy", operands);
}
}
int
next_insn_test_reg (insn, reg)
rtx insn;
rtx reg;
{
rtx body;
insn = next_nonnote_insn (insn);
if (GET_CODE (insn) != INSN)
return 0;
body = PATTERN (insn);
if (sets_cc0_p (body) != 1)
return 0;
if (rtx_equal_p (XEXP (body, 1), reg) == 0)
return 0;
return 1;
}
void
m68hc11_gen_movhi (insn, operands)
rtx insn;
rtx *operands;
{
int reg;
if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
{
cc_status = cc_prev_status;
return;
}
if (TARGET_M6812)
{
if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
{
cc_status = cc_prev_status;
switch (REGNO (operands[1]))
{
case HARD_X_REGNUM:
case HARD_Y_REGNUM:
case HARD_D_REGNUM:
output_asm_insn ("psh%1", operands);
break;
case HARD_SP_REGNUM:
output_asm_insn ("sts\t-2,sp", operands);
break;
default:
abort ();
}
return;
}
if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
{
cc_status = cc_prev_status;
switch (REGNO (operands[0]))
{
case HARD_X_REGNUM:
case HARD_Y_REGNUM:
case HARD_D_REGNUM:
output_asm_insn ("pul%0", operands);
break;
default:
abort ();
}
return;
}
if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
{
m68hc11_notice_keep_cc (operands[0]);
output_asm_insn ("tfr\t%1,%0", operands);
}
else if (H_REG_P (operands[0]))
{
if (SP_REG_P (operands[0]))
output_asm_insn ("lds\t%1", operands);
else
output_asm_insn ("ld%0\t%1", operands);
}
else if (H_REG_P (operands[1]))
{
if (SP_REG_P (operands[1]))
output_asm_insn ("sts\t%0", operands);
else
output_asm_insn ("st%1\t%0", 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))
&& !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
{
rtx ops[3];
if (operands[2])
{
ops[0] = operands[2];
ops[1] = from;
ops[2] = 0;
m68hc11_gen_movhi (insn, ops);
ops[0] = to;
ops[1] = operands[2];
m68hc11_gen_movhi (insn, ops);
}
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);
}
}
}
return;
}
if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
{
cc_status = cc_prev_status;
switch (REGNO (operands[0]))
{
case HARD_X_REGNUM:
case HARD_Y_REGNUM:
output_asm_insn ("pul%0", operands);
break;
case HARD_D_REGNUM:
output_asm_insn ("pula", operands);
output_asm_insn ("pulb", operands);
break;
default:
abort ();
}
return;
}
if (H_REG_P (operands[0]))
{
switch (REGNO (operands[0]))
{
case HARD_D_REGNUM:
if (X_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else if (next_insn_test_reg (insn, operands[0]))
{
output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
}
else
{
m68hc11_notice_keep_cc (operands[0]);
output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
}
}
else if (Y_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else
{
output_asm_insn ("sty\t%t1", operands);
output_asm_insn ("ldd\t%t1", operands);
}
}
else if (SP_REG_P (operands[1]))
{
CC_STATUS_INIT;
if (ix_reg == 0)
create_regs_rtx ();
if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
output_asm_insn ("xgdx", operands);
output_asm_insn ("tsx", operands);
output_asm_insn ("xgdx", operands);
}
else if (IS_STACK_POP (operands[1]))
{
output_asm_insn ("pula\n\tpulb", operands);
}
else if (GET_CODE (operands[1]) == CONST_INT
&& INTVAL (operands[1]) == 0)
{
output_asm_insn ("clra\n\tclrb", operands);
}
else
{
output_asm_insn ("ldd\t%1", operands);
}
break;
case HARD_X_REGNUM:
if (D_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else if (next_insn_test_reg (insn, operands[0]))
{
output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
}
else
{
m68hc11_notice_keep_cc (operands[0]);
output_asm_insn ("pshb", operands);
output_asm_insn ("psha", operands);
output_asm_insn ("pulx", operands);
}
}
else if (Y_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
&& dead_register_here (insn, d_reg))
{
output_asm_insn ("xgdy", operands);
output_asm_insn ("xgdx", operands);
CC_STATUS_INIT;
}
else
{
output_asm_insn ("sty\t%t1", operands);
output_asm_insn ("ldx\t%t1", operands);
}
}
else if (SP_REG_P (operands[1]))
{
cc_status = cc_prev_status;
output_asm_insn ("tsx", operands);
}
else
{
output_asm_insn ("ldx\t%1", operands);
}
break;
case HARD_Y_REGNUM:
if (D_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else
{
output_asm_insn ("std\t%t1", operands);
output_asm_insn ("ldy\t%t1", operands);
}
}
else if (X_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
&& dead_register_here (insn, d_reg))
{
output_asm_insn ("xgdx", operands);
output_asm_insn ("xgdy", operands);
CC_STATUS_INIT;
}
else
{
output_asm_insn ("stx\t%t1", operands);
output_asm_insn ("ldy\t%t1", operands);
}
}
else if (SP_REG_P (operands[1]))
{
cc_status = cc_prev_status;
output_asm_insn ("tsy", operands);
}
else
{
output_asm_insn ("ldy\t%1", operands);
}
break;
case HARD_SP_REGNUM:
if (D_REG_P (operands[1]))
{
m68hc11_notice_keep_cc (operands[0]);
output_asm_insn ("xgdx", operands);
output_asm_insn ("txs", operands);
output_asm_insn ("xgdx", operands);
}
else if (X_REG_P (operands[1]))
{
cc_status = cc_prev_status;
output_asm_insn ("txs", operands);
}
else if (Y_REG_P (operands[1]))
{
cc_status = cc_prev_status;
output_asm_insn ("tys", operands);
}
else
{
CC_STATUS_INIT;
output_asm_insn ("lds\t%1", operands);
output_asm_insn ("des", operands);
}
break;
default:
fatal_insn ("invalid register in the move instruction", insn);
break;
}
return;
}
if (SP_REG_P (operands[1]) && REG_P (operands[0])
&& REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
{
output_asm_insn ("sts\t%0", operands);
return;
}
if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
{
cc_status = cc_prev_status;
switch (REGNO (operands[1]))
{
case HARD_X_REGNUM:
case HARD_Y_REGNUM:
output_asm_insn ("psh%1", operands);
break;
case HARD_D_REGNUM:
output_asm_insn ("pshb", operands);
output_asm_insn ("psha", operands);
break;
default:
abort ();
}
return;
}
if (!H_REG_P (operands[1]))
{
fatal_insn ("invalid operand in the instruction", insn);
}
reg = REGNO (operands[1]);
switch (reg)
{
case HARD_D_REGNUM:
output_asm_insn ("std\t%0", operands);
break;
case HARD_X_REGNUM:
output_asm_insn ("stx\t%0", operands);
break;
case HARD_Y_REGNUM:
output_asm_insn ("sty\t%0", operands);
break;
case HARD_SP_REGNUM:
if (ix_reg == 0)
create_regs_rtx ();
if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
{
output_asm_insn ("pshx", operands);
output_asm_insn ("tsx", operands);
output_asm_insn ("inx", operands);
output_asm_insn ("inx", operands);
output_asm_insn ("stx\t%0", operands);
output_asm_insn ("pulx", operands);
}
else if (reg_mentioned_p (ix_reg, operands[0]))
{
output_asm_insn ("sty\t%t0", operands);
output_asm_insn ("tsy", operands);
output_asm_insn ("sty\t%0", operands);
output_asm_insn ("ldy\t%t0", operands);
}
else
{
output_asm_insn ("stx\t%t0", operands);
output_asm_insn ("tsx", operands);
output_asm_insn ("stx\t%0", operands);
output_asm_insn ("ldx\t%t0", operands);
}
CC_STATUS_INIT;
break;
default:
fatal_insn ("invalid register in the move instruction", insn);
break;
}
}
void
m68hc11_gen_movqi (insn, operands)
rtx insn;
rtx *operands;
{
if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
{
cc_status = cc_prev_status;
return;
}
if (TARGET_M6812)
{
if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
{
m68hc11_notice_keep_cc (operands[0]);
output_asm_insn ("tfr\t%1,%0", operands);
}
else if (H_REG_P (operands[0]))
{
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
goto m6811_move;
}
else if (H_REG_P (operands[1]))
{
if (Q_REG_P (operands[1]))
output_asm_insn ("sta%1\t%b0", operands);
else if (D_REG_P (operands[1]))
output_asm_insn ("stab\t%b0", operands);
else
goto m6811_move;
}
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))
&& !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
{
rtx ops[3];
if (operands[2])
{
ops[0] = operands[2];
ops[1] = from;
ops[2] = 0;
m68hc11_gen_movqi (insn, ops);
ops[0] = to;
ops[1] = operands[2];
m68hc11_gen_movqi (insn, ops);
}
else
{
fatal_insn ("move insn not handled", insn);
}
}
else
{
if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
{
output_asm_insn ("clr\t%b0", operands);
}
else
{
m68hc11_notice_keep_cc (operands[0]);
output_asm_insn ("movb\t%b1,%b0", operands);
}
}
}
return;
}
m6811_move:
if (H_REG_P (operands[0]))
{
switch (REGNO (operands[0]))
{
case HARD_B_REGNUM:
case HARD_D_REGNUM:
if (X_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else
{
output_asm_insn ("stx\t%t1", operands);
output_asm_insn ("ldab\t%T0", operands);
}
}
else if (Y_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else
{
output_asm_insn ("sty\t%t1", operands);
output_asm_insn ("ldab\t%T0", operands);
}
}
else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
&& !DA_REG_P (operands[1]))
{
output_asm_insn ("ldab\t%b1", operands);
}
else if (DA_REG_P (operands[1]))
{
output_asm_insn ("tab", operands);
}
else
{
cc_status = cc_prev_status;
return;
}
break;
case HARD_A_REGNUM:
if (X_REG_P (operands[1]))
{
output_asm_insn ("stx\t%t1", operands);
output_asm_insn ("ldaa\t%T0", operands);
}
else if (Y_REG_P (operands[1]))
{
output_asm_insn ("sty\t%t1", operands);
output_asm_insn ("ldaa\t%T0", operands);
}
else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
&& !DA_REG_P (operands[1]))
{
output_asm_insn ("ldaa\t%b1", operands);
}
else if (!DA_REG_P (operands[1]))
{
output_asm_insn ("tba", operands);
}
else
{
cc_status = cc_prev_status;
}
break;
case HARD_X_REGNUM:
if (D_REG_P (operands[1]))
{
if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
{
m68hc11_output_swap (insn, operands);
}
else
{
output_asm_insn ("stab\t%T1", operands);
output_asm_insn ("ldx\t%t1", operands);
}
CC_STATUS_INIT;
}
else if (Y_REG_P (operands[1]))
{
output_asm_insn ("sty\t%t0", operands);
output_asm_insn ("ldx\t%t0", operands);
}
else if (GET_CODE (operands[1]) == CONST_INT)
{
output_asm_insn ("ldx\t%1", operands);
}
else if (dead_register_here (insn, d_reg))
{
output_asm_insn ("ldab\t%b1", operands);
output_asm_insn ("xgdx", operands);
}
else if (!reg_mentioned_p (operands[0], operands[1]))
{
output_asm_insn ("xgdx", operands);
output_asm_insn ("ldab\t%b1", operands);
output_asm_insn ("xgdx", operands);
}
else
{
output_asm_insn ("pshb", operands);
output_asm_insn ("ldab\t%b1", operands);
output_asm_insn ("stab\t%T1", operands);
output_asm_insn ("ldx\t%t1", operands);
output_asm_insn ("pulb", operands);
CC_STATUS_INIT;
}
break;
case HARD_Y_REGNUM:
if (D_REG_P (operands[1]))
{
output_asm_insn ("stab\t%T1", operands);
output_asm_insn ("ldy\t%t1", operands);
CC_STATUS_INIT;
}
else if (X_REG_P (operands[1]))
{
output_asm_insn ("stx\t%t1", operands);
output_asm_insn ("ldy\t%t1", operands);
CC_STATUS_INIT;
}
else if (GET_CODE (operands[1]) == CONST_INT)
{
output_asm_insn ("ldy\t%1", operands);
}
else if (dead_register_here (insn, d_reg))
{
output_asm_insn ("ldab\t%b1", operands);
output_asm_insn ("xgdy", operands);
}
else if (!reg_mentioned_p (operands[0], operands[1]))
{
output_asm_insn ("xgdy", operands);
output_asm_insn ("ldab\t%b1", operands);
output_asm_insn ("xgdy", operands);
}
else
{
output_asm_insn ("pshb", operands);
output_asm_insn ("ldab\t%b1", operands);
output_asm_insn ("stab\t%T1", operands);
output_asm_insn ("ldy\t%t1", operands);
output_asm_insn ("pulb", operands);
CC_STATUS_INIT;
}
break;
default:
fatal_insn ("invalid register in the instruction", insn);
break;
}
}
else if (H_REG_P (operands[1]))
{
switch (REGNO (operands[1]))
{
case HARD_D_REGNUM:
case HARD_B_REGNUM:
output_asm_insn ("stab\t%b0", operands);
break;
case HARD_A_REGNUM:
output_asm_insn ("staa\t%b0", operands);
break;
case HARD_X_REGNUM:
output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
break;
case HARD_Y_REGNUM:
output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
break;
default:
fatal_insn ("invalid register in the move instruction", insn);
break;
}
return;
}
else
{
fatal_insn ("operand 1 must be a hard register", insn);
}
}
void
m68hc11_gen_rotate (code, insn, operands)
enum rtx_code code;
rtx insn;
rtx operands[];
{
int val;
if (GET_CODE (operands[2]) != CONST_INT
|| (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
fatal_insn ("invalid rotate insn", insn);
val = INTVAL (operands[2]);
if (code == ROTATERT)
val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
if (GET_MODE (operands[0]) != QImode)
CC_STATUS_INIT;
if (val >= 5 && val <= 11)
{
if (TARGET_M6812)
output_asm_insn ("exg\ta,b", operands);
else
{
output_asm_insn ("psha", operands);
output_asm_insn ("tba", operands);
output_asm_insn ("pulb", operands);
}
val -= 8;
}
else if (val >= 12)
{
val = val - 16;
}
if (val > 0)
{
if (GET_MODE (operands[0]) != QImode)
{
output_asm_insn ("asra", operands);
output_asm_insn ("rola", operands);
}
while (--val >= 0)
{
if (D_REG_P (operands[0]))
output_asm_insn ("rolb", operands);
if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
output_asm_insn ("rola", operands);
}
}
else
{
if (val != 0 && GET_MODE (operands[0]) != QImode)
{
output_asm_insn ("tap", operands);
}
while (++val <= 0)
{
if (D_REG_P (operands[0]))
output_asm_insn ("rorb", operands);
if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
output_asm_insn ("rora", operands);
}
}
}
void
m68hc11_notice_update_cc (exp, insn)
rtx exp;
rtx insn ATTRIBUTE_UNUSED;
{
if (GET_CODE (exp) == SET)
{
if (SET_DEST (exp) == pc_rtx)
;
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
}
else if (SET_DEST (exp) == cc0_rtx)
{
cc_status.flags = 0;
cc_status.value1 = XEXP (exp, 0);
cc_status.value2 = XEXP (exp, 1);
}
else
{
cc_status.flags = 0;
cc_status.value1 = XEXP (exp, 0);
cc_status.value2 = XEXP (exp, 1);
}
}
else
{
CC_STATUS_INIT;
}
if (cc_status.value2 != 0)
switch (GET_CODE (cc_status.value2))
{
case IOR:
case XOR:
case AND:
break;
case NOT:
if (GET_MODE (cc_status.value2) != QImode)
CC_STATUS_INIT;
break;
case PLUS:
case MINUS:
case MULT:
case DIV:
case UDIV:
case MOD:
case UMOD:
case NEG:
if (GET_MODE (cc_status.value2) != VOIDmode)
cc_status.flags |= CC_NO_OVERFLOW;
break;
case ASHIFT:
case ROTATE:
case ROTATERT:
if (GET_MODE (cc_status.value2) != VOIDmode)
cc_status.flags |= CC_NO_OVERFLOW;
break;
case MEM:
case SYMBOL_REF:
case REG:
case CONST_INT:
cc_status.flags |= CC_NO_OVERFLOW;
break;
default:
break;
}
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
}
void
m68hc11_notice_keep_cc (reg)
rtx reg;
{
if (reg == 0
|| cc_prev_status.value1 == 0
|| rtx_equal_p (reg, cc_prev_status.value1)
|| (cc_prev_status.value2
&& reg_mentioned_p (reg, cc_prev_status.value2)))
CC_STATUS_INIT;
else
cc_status = cc_prev_status;
}
struct replace_info
{
rtx first;
rtx replace_reg;
int need_save_z;
int must_load_z;
int must_save_reg;
int must_restore_reg;
rtx last;
int regno;
int x_used;
int y_used;
int can_use_d;
int found_call;
int z_died;
int z_set_count;
rtx z_value;
int must_push_reg;
int save_before_last;
int z_loaded_with_sp;
};
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));
int z_replacement_completed = 0;
static int
m68hc11_check_z_replacement (insn, info)
rtx insn;
struct replace_info *info;
{
int this_insn_uses_ix;
int this_insn_uses_iy;
int this_insn_uses_z;
int this_insn_uses_z_in_dst;
int this_insn_uses_d;
rtx body;
int z_dies_here;
if (GET_CODE (insn) == CALL_INSN)
{
body = PATTERN (insn);
info->can_use_d = 0;
if (reg_mentioned_p (z_reg, body))
{
insn = NEXT_INSN (insn);
info->x_used = 1;
info->y_used = 0;
info->found_call = 1;
info->must_restore_reg = 0;
info->last = NEXT_INSN (insn);
}
info->need_save_z = 0;
return 0;
}
if (GET_CODE (insn) == CODE_LABEL
|| GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
return 0;
if (GET_CODE (insn) == JUMP_INSN)
{
if (reg_mentioned_p (z_reg, insn) == 0)
return 0;
info->can_use_d = 0;
info->must_save_reg = 0;
info->must_restore_reg = 0;
info->need_save_z = 0;
info->last = NEXT_INSN (insn);
return 0;
}
if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
{
return 1;
}
z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
body = PATTERN (insn);
if (GET_CODE (body) == SET)
{
rtx src = XEXP (body, 1);
rtx dst = XEXP (body, 0);
if (dst == cc0_rtx)
{
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))))
{
if (insn == info->first)
{
info->must_load_z = 0;
info->must_save_reg = 0;
info->must_restore_reg = 0;
info->need_save_z = 0;
info->found_call = 1;
info->regno = SOFT_Z_REGNUM;
info->last = insn;
}
return 0;
}
if (reg_mentioned_p (z_reg, src) == 0)
{
info->can_use_d = 0;
return 0;
}
if (insn != info->first)
return 0;
info->must_push_reg = 1;
info->last = insn;
}
if (Z_REG_P (dst))
{
if (!reg_mentioned_p (z_reg, src))
{
if (insn != info->first)
{
return 0;
}
info->must_load_z = 0;
}
info->z_set_count++;
info->z_value = src;
if (SP_REG_P (src))
info->z_loaded_with_sp = 1;
}
else if (reg_mentioned_p (z_reg, dst))
info->can_use_d = 0;
this_insn_uses_d = reg_mentioned_p (d_reg, src)
| reg_mentioned_p (d_reg, dst);
this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
| reg_mentioned_p (ix_reg, dst);
this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
| reg_mentioned_p (iy_reg, dst);
this_insn_uses_z = reg_mentioned_p (z_reg, src);
if (this_insn_uses_z && !Z_REG_P (src)
&& !(m68hc11_arith_operator (src, GET_MODE (src))
&& Z_REG_P (XEXP (src, 0))
&& !reg_mentioned_p (z_reg, XEXP (src, 1))
&& insn == info->first
&& dead_register_here (insn, d_reg)))
info->can_use_d = 0;
this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
if (TARGET_M6812 && !z_dies_here
&& ((this_insn_uses_z && side_effects_p (src))
|| (this_insn_uses_z_in_dst && side_effects_p (dst))))
{
info->need_save_z = 1;
info->z_set_count++;
}
this_insn_uses_z |= this_insn_uses_z_in_dst;
if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
{
fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
}
if (this_insn_uses_d)
info->can_use_d = 0;
if (this_insn_uses_ix && this_insn_uses_iy)
{
return 0;
}
if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
info->can_use_d = 0;
if (info->x_used == 0 && this_insn_uses_ix)
{
if (info->y_used)
{
if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
{
if (z_dies_here)
{
info->need_save_z = 0;
info->z_died = 1;
}
info->must_save_reg = 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;
info->last = NEXT_INSN (insn);
return 0;
}
if (X_REG_P (dst)
&& (rtx_equal_p (src, z_reg)
|| (z_dies_here && !reg_mentioned_p (ix_reg, src))))
{
if (z_dies_here)
{
info->need_save_z = 0;
info->z_died = 1;
}
info->last = NEXT_INSN (insn);
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
&& !reg_mentioned_p (ix_reg, src))
{
if (z_dies_here)
{
info->z_died = 1;
info->need_save_z = 0;
}
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->last = NEXT_INSN (insn);
}
else if (info->can_use_d)
{
info->last = NEXT_INSN (insn);
info->x_used = 1;
}
return 0;
}
info->x_used = 1;
if (z_dies_here && !reg_mentioned_p (ix_reg, src)
&& GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
{
info->need_save_z = 0;
info->z_died = 1;
info->last = NEXT_INSN (insn);
info->regno = HARD_X_REGNUM;
info->must_save_reg = 0;
info->must_restore_reg = 0;
return 0;
}
if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
{
info->regno = HARD_X_REGNUM;
info->must_restore_reg = 0;
info->must_save_reg = 0;
return 0;
}
}
if (info->y_used == 0 && this_insn_uses_iy)
{
if (info->x_used)
{
if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
{
if (z_dies_here)
{
info->need_save_z = 0;
info->z_died = 1;
}
info->must_save_reg = 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;
info->last = NEXT_INSN (insn);
return 0;
}
if (Y_REG_P (dst)
&& (rtx_equal_p (src, z_reg)
|| (z_dies_here && !reg_mentioned_p (iy_reg, src))))
{
if (z_dies_here)
{
info->z_died = 1;
info->need_save_z = 0;
}
info->last = NEXT_INSN (insn);
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
&& !reg_mentioned_p (iy_reg, src))
{
if (z_dies_here)
{
info->z_died = 1;
info->need_save_z = 0;
}
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->last = NEXT_INSN (insn);
}
else if (info->can_use_d)
{
info->last = NEXT_INSN (insn);
info->y_used = 1;
}
return 0;
}
info->y_used = 1;
if (z_dies_here && !reg_mentioned_p (iy_reg, src)
&& GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
{
info->need_save_z = 0;
info->z_died = 1;
info->last = NEXT_INSN (insn);
info->regno = HARD_Y_REGNUM;
info->must_save_reg = 0;
info->must_restore_reg = 0;
return 0;
}
if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
{
info->regno = HARD_Y_REGNUM;
info->must_restore_reg = 0;
info->must_save_reg = 0;
return 0;
}
}
if (z_dies_here)
{
info->need_save_z = 0;
info->z_died = 1;
if (info->last == 0)
info->last = NEXT_INSN (insn);
return 0;
}
return info->last != NULL_RTX ? 0 : 1;
}
if (GET_CODE (body) == PARALLEL)
{
int i;
char ix_clobber = 0;
char iy_clobber = 0;
char z_clobber = 0;
this_insn_uses_iy = 0;
this_insn_uses_ix = 0;
this_insn_uses_z = 0;
for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
{
rtx x;
int uses_ix, uses_iy, uses_z;
x = XVECEXP (body, 0, i);
if (info->can_use_d && reg_mentioned_p (d_reg, x))
info->can_use_d = 0;
uses_ix = reg_mentioned_p (ix_reg, x);
uses_iy = reg_mentioned_p (iy_reg, x);
uses_z = reg_mentioned_p (z_reg, x);
if (GET_CODE (x) == CLOBBER)
{
ix_clobber |= uses_ix;
iy_clobber |= uses_iy;
z_clobber |= uses_z;
}
else
{
this_insn_uses_ix |= uses_ix;
this_insn_uses_iy |= uses_iy;
this_insn_uses_z |= uses_z;
}
if (uses_z && GET_CODE (x) == SET)
{
rtx dst = XEXP (x, 0);
if (Z_REG_P (dst))
info->z_set_count++;
}
if (TARGET_M6812 && uses_z && side_effects_p (x))
info->need_save_z = 1;
if (z_clobber)
info->need_save_z = 0;
}
if (debug_m6811)
{
printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
this_insn_uses_ix, this_insn_uses_iy,
this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
debug_rtx (insn);
}
if (this_insn_uses_z)
info->can_use_d = 0;
if (z_clobber && info->first != insn)
{
info->need_save_z = 0;
info->last = insn;
return 0;
}
if (z_clobber && info->x_used == 0 && info->y_used == 0)
{
if (this_insn_uses_z == 0 && insn == info->first)
{
info->must_load_z = 0;
}
if (dead_register_here (insn, d_reg))
{
info->regno = HARD_D_REGNUM;
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
else if (dead_register_here (insn, ix_reg))
{
info->regno = HARD_X_REGNUM;
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
else if (dead_register_here (insn, iy_reg))
{
info->regno = HARD_Y_REGNUM;
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
if (info->regno >= 0)
{
info->last = NEXT_INSN (insn);
return 0;
}
if (this_insn_uses_ix == 0)
{
info->regno = HARD_X_REGNUM;
info->must_save_reg = 1;
info->must_restore_reg = 1;
}
else if (this_insn_uses_iy == 0)
{
info->regno = HARD_Y_REGNUM;
info->must_save_reg = 1;
info->must_restore_reg = 1;
}
else
{
info->regno = HARD_D_REGNUM;
info->must_save_reg = 1;
info->must_restore_reg = 1;
}
info->last = NEXT_INSN (insn);
return 0;
}
if (((info->x_used || this_insn_uses_ix) && iy_clobber)
|| ((info->y_used || this_insn_uses_iy) && ix_clobber))
{
if (this_insn_uses_z)
{
if (info->y_used == 0 && iy_clobber)
{
info->regno = HARD_Y_REGNUM;
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
if (info->first != insn
&& ((info->y_used && ix_clobber)
|| (info->x_used && iy_clobber)))
info->last = insn;
else
info->last = NEXT_INSN (insn);
info->save_before_last = 1;
}
return 0;
}
if (this_insn_uses_ix && this_insn_uses_iy)
{
if (this_insn_uses_z)
{
fatal_insn ("cannot do z-register replacement", insn);
}
return 0;
}
if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
{
if (info->y_used)
{
return 0;
}
info->x_used = 1;
if (iy_clobber || z_clobber)
{
info->last = NEXT_INSN (insn);
info->save_before_last = 1;
return 0;
}
}
if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
{
if (info->x_used)
{
return 0;
}
info->y_used = 1;
if (ix_clobber || z_clobber)
{
info->last = NEXT_INSN (insn);
info->save_before_last = 1;
return 0;
}
}
if (z_dies_here)
{
info->z_died = 1;
info->need_save_z = 0;
}
return 1;
}
if (GET_CODE (body) == CLOBBER)
{
if (this_insn_uses_ix && this_insn_uses_iy)
{
return 0;
}
if (info->x_used == 0 && this_insn_uses_ix)
{
if (info->y_used)
{
return 0;
}
info->x_used = 1;
}
if (info->y_used == 0 && this_insn_uses_iy)
{
if (info->x_used)
{
return 0;
}
info->y_used = 1;
}
return 1;
}
return 1;
}
static void
m68hc11_find_z_replacement (insn, info)
rtx insn;
struct replace_info *info;
{
int reg;
info->replace_reg = NULL_RTX;
info->must_load_z = 1;
info->need_save_z = 1;
info->must_save_reg = 1;
info->must_restore_reg = 1;
info->first = insn;
info->x_used = 0;
info->y_used = 0;
info->can_use_d = TARGET_M6811 ? 1 : 0;
info->found_call = 0;
info->z_died = 0;
info->last = 0;
info->regno = -1;
info->z_set_count = 0;
info->z_value = NULL_RTX;
info->must_push_reg = 0;
info->save_before_last = 0;
info->z_loaded_with_sp = 0;
for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
{
if (m68hc11_check_z_replacement (insn, info) == 0)
break;
}
if (info->z_set_count == 1)
{
rtx p = info->first;
rtx v = 0;
if (info->x_used)
{
v = find_last_value (iy_reg, &p, insn, 1);
}
else if (info->y_used)
{
v = find_last_value (ix_reg, &p, insn, 1);
}
if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
{
if (info->x_used)
info->regno = HARD_Y_REGNUM;
else
info->regno = HARD_X_REGNUM;
info->must_load_z = 0;
info->must_save_reg = 0;
info->must_restore_reg = 0;
info->found_call = 1;
}
}
if (info->z_set_count == 0)
info->need_save_z = 0;
if (insn == 0)
info->need_save_z = 0;
if (info->last == 0)
info->last = insn;
if (info->regno >= 0)
{
reg = info->regno;
info->replace_reg = gen_rtx (REG, HImode, reg);
}
else if (info->can_use_d)
{
reg = HARD_D_REGNUM;
info->replace_reg = d_reg;
}
else if (info->x_used)
{
reg = HARD_Y_REGNUM;
info->replace_reg = iy_reg;
}
else
{
reg = HARD_X_REGNUM;
info->replace_reg = ix_reg;
}
info->regno = reg;
if (info->must_save_reg && info->must_restore_reg)
{
if (insn && dead_register_here (insn, info->replace_reg))
{
info->must_save_reg = 0;
info->must_restore_reg = 0;
}
}
}
static void
m68hc11_z_replacement (insn)
rtx insn;
{
rtx replace_reg_qi;
rtx replace_reg;
struct replace_info info;
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
{
rtx body = PATTERN (insn);
rtx src = XEXP (body, 1);
rtx dst = XEXP (body, 0);
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);
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);
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);
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);
INSN_CODE (insn) = -1;
return;
}
}
m68hc11_find_z_replacement (insn, &info);
replace_reg = info.replace_reg;
replace_reg_qi = NULL_RTX;
if (info.must_save_reg && !info.must_push_reg)
{
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)));
else
dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
emit_insn_before (gen_movhi (dst,
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)),
insn);
}
for (; insn && insn != info.last; insn = NEXT_INSN (insn))
{
rtx body;
if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
break;
if (GET_CODE (insn) != INSN
&& GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
continue;
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 (debug_m6811 && reg_mentioned_p (replace_reg, body))
{
printf ("Reg mentioned here...:\n");
fflush (stdout);
debug_rtx (insn);
}
if (info.must_push_reg
&& info.z_loaded_with_sp && GET_CODE (body) == SET)
{
rtx src, dst;
src = SET_SRC (body);
dst = SET_DEST (body);
if (SP_REG_P (src) && Z_REG_P (dst))
emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
}
if (!validate_replace_rtx (z_reg, replace_reg, insn))
{
INSN_CODE (insn) = -1;
if (!validate_replace_rtx (z_reg, replace_reg, insn))
fatal_insn ("cannot do z-register replacement", insn);
}
if (reg_mentioned_p (z_reg, insn))
{
if (replace_reg_qi == NULL_RTX)
replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
}
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_INC
&& GET_CODE (XEXP (note, 0)) == REG
&& REGNO (XEXP (note, 0)) == REGNO (z_reg))
{
XEXP (note, 0) = replace_reg;
}
}
}
if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
break;
}
if (insn && info.need_save_z && !info.must_push_reg)
{
rtx save_pos_insn = 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)),
save_pos_insn);
}
if (info.must_push_reg && info.last)
{
rtx new_body, body;
body = PATTERN (info.last);
new_body = gen_rtx (PARALLEL, VOIDmode,
gen_rtvec (3, body,
gen_rtx (USE, VOIDmode,
replace_reg),
gen_rtx (USE, VOIDmode,
gen_rtx (REG, HImode,
SOFT_Z_REGNUM))));
PATTERN (info.last) = new_body;
INSN_CODE (insn) = -1;
if (!validate_replace_rtx (z_reg, replace_reg, info.last))
{
fatal_insn ("invalid Z register replacement for insn", insn);
}
insn = NEXT_INSN (info.last);
}
if (insn && info.must_restore_reg && !info.must_push_reg)
{
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)));
else
dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
dst), insn);
}
}
static void
m68hc11_reassign_regs (first)
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);
for (insn = first; insn; insn = NEXT_INSN (insn))
{
rtx body;
if (GET_CODE (insn) == CODE_LABEL
|| GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
continue;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
body = PATTERN (insn);
if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
continue;
if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
|| GET_CODE (body) == ASM_OPERANDS
|| GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
continue;
if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
|| GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
{
if (reg_mentioned_p (z_reg, body))
{
m68hc11_z_replacement (insn);
}
}
else
{
printf ("insn not handled by Z replacement:\n");
fflush (stdout);
debug_rtx (insn);
}
}
}
void
m68hc11_reorg (first)
rtx first;
{
int split_done = 0;
rtx insn;
compute_bb_for_insn ();
z_replacement_completed = 0;
z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
unshare_all_rtl_again (first);
split_all_insns_noflow ();
split_done = 1;
z_replacement_completed = 1;
m68hc11_reassign_regs (first);
if (optimize > 0 && split_done)
{
reload_cse_regs (first);
}
if (optimize)
{
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 (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
}
z_replacement_completed = 2;
if (optimize > 0)
split_all_insns_noflow ();
{
rtx insn;
for (insn = first; insn; insn = NEXT_INSN (insn))
{
rtx body;
if (INSN_DELETED_P (insn))
continue;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
body = PATTERN (insn);
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;
continue;
}
}
}
}
int
m68hc11_memory_move_cost (mode, class, in)
enum machine_mode mode;
enum reg_class class;
int in ATTRIBUTE_UNUSED;
{
if (class <= H_REGS && class > NO_REGS)
{
if (GET_MODE_SIZE (mode) <= 2)
return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
else
return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
}
else
{
if (GET_MODE_SIZE (mode) <= 2)
return COSTS_N_INSNS (3);
else
return COSTS_N_INSNS (4);
}
}
int
m68hc11_register_move_cost (mode, from, to)
enum machine_mode mode;
enum reg_class from;
enum reg_class to;
{
if (from < to)
{
enum reg_class tmp = to;
to = from, from = tmp;
}
if (to >= S_REGS)
return m68hc11_memory_move_cost (mode, S_REGS, 0);
else if (from <= S_REGS)
return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
else
return COSTS_N_INSNS (2);
}
int
m68hc11_address_cost (addr)
rtx addr;
{
int cost = 4;
switch (GET_CODE (addr))
{
case REG:
if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
cost = 0;
else
cost = 1;
break;
case SYMBOL_REF:
cost = 8;
break;
case LABEL_REF:
case CONST:
cost = 0;
break;
case PLUS:
{
register rtx plus0 = XEXP (addr, 0);
register rtx plus1 = XEXP (addr, 1);
if (GET_CODE (plus0) != REG)
break;
switch (GET_CODE (plus1))
{
case CONST_INT:
if (INTVAL (plus1) >= 2 * m68hc11_max_offset
|| INTVAL (plus1) < m68hc11_min_offset)
cost = 3;
else if (INTVAL (plus1) >= m68hc11_max_offset)
cost = 2;
else
cost = 1;
if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
cost += 0;
else
cost += 1;
break;
case SYMBOL_REF:
cost = 8;
break;
case CONST:
case LABEL_REF:
cost = 0;
break;
default:
break;
}
break;
}
case PRE_DEC:
case PRE_INC:
if (SP_REG_P (XEXP (addr, 0)))
cost = 1;
break;
default:
break;
}
if (debug_m6811)
{
printf ("Address cost: %d for :", cost);
fflush (stdout);
debug_rtx (addr);
}
return cost;
}
static int
m68hc11_shift_cost (mode, x, shift)
enum machine_mode mode;
rtx x;
int shift;
{
int total;
total = rtx_cost (x, SET);
if (mode == QImode)
total += m68hc11_cost->shiftQI_const[shift % 8];
else if (mode == HImode)
total += m68hc11_cost->shiftHI_const[shift % 16];
else if (shift == 8 || shift == 16 || shift == 32)
total += m68hc11_cost->shiftHI_const[8];
else if (shift != 0 && shift != 16 && shift != 32)
{
total += m68hc11_cost->shiftHI_const[1] * shift;
}
if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
total *= GET_MODE_SIZE (mode) / 2;
if (optimize_size && (shift % 8) != 0)
total *= 2;
return total;
}
int
m68hc11_rtx_costs (x, code, outer_code)
rtx x;
enum rtx_code code;
enum rtx_code outer_code ATTRIBUTE_UNUSED;
{
enum machine_mode mode = GET_MODE (x);
int extra_cost = 0;
int total;
switch (code)
{
case ROTATE:
case ROTATERT:
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
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 += 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 += m68hc11_cost->logical;
total *= GET_MODE_SIZE (mode);
return total;
case MINUS:
case PLUS:
total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
total += m68hc11_cost->add;
if (GET_MODE_SIZE (mode) > 2)
{
total *= GET_MODE_SIZE (mode) / 2;
}
return total;
case UDIV:
case DIV:
case MOD:
total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
switch (mode)
{
case QImode:
total += m68hc11_cost->divQI;
break;
case HImode:
total += m68hc11_cost->divHI;
break;
case SImode:
default:
total += m68hc11_cost->divSI;
break;
}
return total;
case MULT:
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);
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);
total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
switch (mode)
{
case QImode:
total += m68hc11_cost->multQI;
break;
case HImode:
total += m68hc11_cost->multHI;
break;
case SImode:
default:
total += m68hc11_cost->multSI;
break;
}
return total;
case NEG:
case SIGN_EXTEND:
extra_cost = COSTS_N_INSNS (2);
case NOT:
case COMPARE:
case ABS:
case ZERO_EXTEND:
total = extra_cost + rtx_cost (XEXP (x, 0), code);
if (mode == QImode)
{
return total + COSTS_N_INSNS (1);
}
if (mode == HImode)
{
return total + COSTS_N_INSNS (2);
}
if (mode == SImode)
{
return total + COSTS_N_INSNS (4);
}
return total + COSTS_N_INSNS (8);
case IF_THEN_ELSE:
if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
return COSTS_N_INSNS (1);
return COSTS_N_INSNS (1);
default:
return COSTS_N_INSNS (4);
}
}
extern char *asm_file_name;
#include <time.h>
#include <sys/types.h>
static void
print_options (out)
FILE *out;
{
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
}
void
m68hc11_asm_file_start (out, main_file)
FILE *out;
const char *main_file;
{
fprintf (out, ";;;-----------------------------------------\n");
fprintf (out, ";;; Start %s gcc assembly output\n",
TARGET_M6811
? "MC68HC11"
: TARGET_M68S12 ? "MC68HCS12" : "MC68HC12");
fprintf (out, ";;; gcc compiler %s\n", version_string);
print_options (out);
fprintf (out, ";;;-----------------------------------------\n");
output_file_directive (out, main_file);
if (TARGET_SHORT)
fprintf (out, "\t.mode mshort\n");
else
fprintf (out, "\t.mode mlong\n");
}
static void
m68hc11_asm_out_constructor (symbol, priority)
rtx symbol;
int priority;
{
default_ctor_section_asm_out_constructor (symbol, priority);
fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
}
static void
m68hc11_asm_out_destructor (symbol, priority)
rtx symbol;
int priority;
{
default_dtor_section_asm_out_destructor (symbol, priority);
fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
}
#include "gt-m68hc11.h"