/* Subroutines used for code generation on the Renesas M32R cpu.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005 Free Software Foundation, Inc.
+ 2005, 2007 Free Software Foundation, Inc.
This file is part of GCC.
m32r_mode_class[i] = 1 << (int) T_MODE;
else if (GET_MODE_SIZE (i) == 32)
m32r_mode_class[i] = 1 << (int) O_MODE;
- else
+ else
m32r_mode_class[i] = 0;
break;
case MODE_FLOAT:
m32r_mode_class[i] = 1 << (int) TF_MODE;
else if (GET_MODE_SIZE (i) == 32)
m32r_mode_class[i] = 1 << (int) OF_MODE;
- else
+ else
m32r_mode_class[i] = 0;
break;
case MODE_CC:
&& CMP_INT16_P (INTVAL (y)) /* Reg equal to small const. */
&& y != const0_rtx)
{
- rtx tmp = gen_reg_rtx (SImode);
-
+ rtx tmp = gen_reg_rtx (SImode);
+
emit_insn (gen_addsi3 (tmp, x, GEN_INT (-INTVAL (y))));
x = tmp;
y = const0_rtx;
|| y == const0_rtx) /* Reg equal to zero. */
{
emit_insn (gen_cmp_eqsi_insn (x, y));
-
+
return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
}
break;
-
+
case LT:
if (register_operand (y, SImode)
|| (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
{
rtx tmp = gen_reg_rtx (SImode); /* Reg compared to reg. */
-
+
switch (code)
{
case LT:
default:
gcc_unreachable ();
}
-
+
return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
}
break;
-
+
case LTU:
if (register_operand (y, SImode)
|| (GET_CODE (y) == CONST_INT && CMP_INT16_P (INTVAL (y))))
{
rtx tmp = gen_reg_rtx (SImode); /* Reg (unsigned) compared to reg. */
-
+
switch (code)
{
case LTU:
default:
gcc_unreachable ();
}
-
+
return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
}
break;
if (compare_code == EQ
&& register_operand (y, SImode))
return gen_rtx_fmt_ee (code, CCmode, x, y);
-
+
/* Reg/zero signed comparison. */
if ((compare_code == EQ || compare_code == LT)
&& y == const0_rtx)
return gen_rtx_fmt_ee (code, CCmode, x, y);
-
+
/* Reg/smallconst equal comparison. */
if (compare_code == EQ
&& GET_CODE (y) == CONST_INT
emit_insn (gen_addsi3 (tmp, x, GEN_INT (-INTVAL (y))));
return gen_rtx_fmt_ee (code, CCmode, tmp, const0_rtx);
}
-
+
/* Reg/const equal comparison. */
if (compare_code == EQ
&& CONSTANT_P (y))
int size = M32R_MAX_PARM_REGS - first_reg_offset;
rtx regblock;
- regblock = gen_rtx_MEM (BLKmode,
- plus_constant (arg_pointer_rtx,
- FIRST_PARM_OFFSET (0)));
+ regblock = gen_frame_mem (BLKmode,
+ plus_constant (arg_pointer_rtx,
+ FIRST_PARM_OFFSET (0)));
set_mem_alias_set (regblock, get_varargs_alias_set ());
move_block_from_reg (first_reg_offset, regblock, size);
| | | |
SP+0->+-----------------------+ +-----------------------+
| reg parm save area, |
- | only created for |
- | variable argument |
- | functions |
+ | only created for |
+ | variable argument |
+ | functions |
+-----------------------+
| previous frame ptr |
- +-----------------------+
- | |
- | register save area |
- | |
+ +-----------------------+
+ | |
+ | register save area |
+ | |
+-----------------------+
- | return address |
- +-----------------------+
- | |
- | local variables |
- | |
- +-----------------------+
- | |
- | alloca allocations |
- | |
- +-----------------------+
- | |
- low | arguments on stack |
- memory | |
- SP+0->+-----------------------+
+ | return address |
+ +-----------------------+
+ | |
+ | local variables |
+ | |
+ +-----------------------+
+ | |
+ | alloca allocations |
+ | |
+ +-----------------------+
+ | |
+ low | arguments on stack |
+ memory | |
+ SP+0->+-----------------------+
Notes:
1) The "reg parm save area" does not exist for non variable argument fns.
unsigned int
m32r_compute_frame_size (int size) /* # of var. bytes allocated. */
{
- int regno;
+ unsigned int regno;
unsigned int total_size, var_size, args_size, pretend_size, extra_size;
unsigned int reg_size, frame_size;
unsigned int gmask;
\f
/* The table we use to reference PIC data. */
static rtx global_offset_table;
-
+
static void
m32r_reload_lr (rtx sp, int size)
{
rtx lr = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
if (size == 0)
- emit_insn (gen_movsi (lr, gen_rtx_MEM (Pmode, sp)));
+ emit_insn (gen_movsi (lr, gen_frame_mem (Pmode, sp)));
else if (size < 32768)
- emit_insn (gen_movsi (lr, gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode, sp,
- GEN_INT (size)))));
+ emit_insn (gen_movsi (lr, gen_frame_mem (Pmode,
+ gen_rtx_PLUS (Pmode, sp,
+ GEN_INT (size)))));
else
- {
+ {
rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
emit_insn (gen_movsi (tmp, GEN_INT (size)));
emit_insn (gen_addsi3 (tmp, tmp, sp));
- emit_insn (gen_movsi (lr, gen_rtx_MEM (Pmode, tmp)));
+ emit_insn (gen_movsi (lr, gen_frame_mem (Pmode, tmp)));
}
emit_insn (gen_rtx_USE (VOIDmode, lr));
global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
GEN_INT (TARGET_MODEL_SMALL)));
-
+
/* Need to emit this whether or not we obey regdecls,
since setjmp/longjmp can cause life info to screw up. */
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
/* Push lr for mcount (form_pc, x). */
emit_insn (gen_movsi_push (stack_pointer_rtx,
gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM)));
-
+
if (pic_reg_used)
{
m32r_load_pic_register ();
current_frame_info.extra_size);
}
\f
-/* Do any necessary cleanup after a function to restore stack, frame,
- and regs. */
+/* Output RTL to pop register REGNO from the stack. */
static void
-m32r_output_function_epilogue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+pop (int regno)
+{
+ rtx x;
+
+ x = emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, regno),
+ stack_pointer_rtx));
+ REG_NOTES (x)
+ = gen_rtx_EXPR_LIST (REG_INC, stack_pointer_rtx, 0);
+}
+
+/* Expand the m32r epilogue as a series of insns. */
+
+void
+m32r_expand_epilogue (void)
{
int regno;
int noepilogue = FALSE;
int total_size;
- enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl);
-
- /* This is only for the human reader. */
- fprintf (file, "\t%s EPILOGUE\n", ASM_COMMENT_START);
gcc_assert (current_frame_info.initialized);
total_size = current_frame_info.total_size;
/* If the last insn was a BARRIER, we don't have to write any code
because a jump (aka return) was put there. */
- if (GET_CODE (insn) == NOTE)
+ if (insn && GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
noepilogue = TRUE;
unsigned int args_size = current_frame_info.args_size;
unsigned int gmask = current_frame_info.gmask;
int can_trust_sp_p = !current_function_calls_alloca;
- const char * sp_str = reg_names[STACK_POINTER_REGNUM];
- const char * fp_str = reg_names[FRAME_POINTER_REGNUM];
+
+ if (flag_exceptions)
+ emit_insn (gen_blockage ());
/* The first thing to do is point the sp at the bottom of the register
save area. */
if (can_trust_sp_p)
{
unsigned int reg_offset = var_size + args_size;
+
if (reg_offset == 0)
; /* Nothing to do. */
- else if (reg_offset < 128)
- fprintf (file, "\taddi %s,%s%d\n",
- sp_str, IMMEDIATE_PREFIX, reg_offset);
else if (reg_offset < 32768)
- fprintf (file, "\tadd3 %s,%s,%s%d\n",
- sp_str, sp_str, IMMEDIATE_PREFIX, reg_offset);
- else if (reg_offset < (1 << 24))
- fprintf (file, "\tld24 %s,%s%d\n\tadd %s,%s\n",
- reg_names[PROLOGUE_TMP_REGNUM],
- IMMEDIATE_PREFIX, reg_offset,
- sp_str, reg_names[PROLOGUE_TMP_REGNUM]);
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (reg_offset)));
else
- fprintf (file, "\tseth %s,%s%d\n\tor3 %s,%s,%s%d\n\tadd %s,%s\n",
- reg_names[PROLOGUE_TMP_REGNUM],
- IMMEDIATE_PREFIX, reg_offset >> 16,
- reg_names[PROLOGUE_TMP_REGNUM],
- reg_names[PROLOGUE_TMP_REGNUM],
- IMMEDIATE_PREFIX, reg_offset & 0xffff,
- sp_str, reg_names[PROLOGUE_TMP_REGNUM]);
+ {
+ rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
+
+ emit_insn (gen_movsi (tmp, GEN_INT (reg_offset)));
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ tmp));
+ }
}
else if (frame_pointer_needed)
{
unsigned int reg_offset = var_size + args_size;
if (reg_offset == 0)
- fprintf (file, "\tmv %s,%s\n", sp_str, fp_str);
+ emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
else if (reg_offset < 32768)
- fprintf (file, "\tadd3 %s,%s,%s%d\n",
- sp_str, fp_str, IMMEDIATE_PREFIX, reg_offset);
- else if (reg_offset < (1 << 24))
- fprintf (file, "\tld24 %s,%s%d\n\tadd %s,%s\n",
- reg_names[PROLOGUE_TMP_REGNUM],
- IMMEDIATE_PREFIX, reg_offset,
- sp_str, reg_names[PROLOGUE_TMP_REGNUM]);
+ emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
+ GEN_INT (reg_offset)));
else
- fprintf (file, "\tseth %s,%s%d\n\tor3 %s,%s,%s%d\n\tadd %s,%s\n",
- reg_names[PROLOGUE_TMP_REGNUM],
- IMMEDIATE_PREFIX, reg_offset >> 16,
- reg_names[PROLOGUE_TMP_REGNUM],
- reg_names[PROLOGUE_TMP_REGNUM],
- IMMEDIATE_PREFIX, reg_offset & 0xffff,
- sp_str, reg_names[PROLOGUE_TMP_REGNUM]);
+ {
+ rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
+
+ emit_insn (gen_movsi (tmp, GEN_INT (reg_offset)));
+ emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ tmp));
+ }
}
else
gcc_unreachable ();
if (current_frame_info.save_lr)
- fprintf (file, "\tpop %s\n", reg_names[RETURN_ADDR_REGNUM]);
+ pop (RETURN_ADDR_REGNUM);
/* Restore any saved registers, in reverse order of course. */
gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK);
for (regno = M32R_MAX_INT_REGS - 1; regno >= 0; --regno)
{
if ((gmask & (1L << regno)) != 0)
- fprintf (file, "\tpop %s\n", reg_names[regno]);
+ pop (regno);
}
if (current_frame_info.save_fp)
- fprintf (file, "\tpop %s\n", fp_str);
+ pop (FRAME_POINTER_REGNUM);
/* Remove varargs area if present. */
if (current_frame_info.pretend_size != 0)
- fprintf (file, "\taddi %s,%s%d\n",
- sp_str, IMMEDIATE_PREFIX, current_frame_info.pretend_size);
-
- /* Emit the return instruction. */
- if (M32R_INTERRUPT_P (fn_type))
- fprintf (file, "\trte\n");
- else
- fprintf (file, "\tjmp %s\n", reg_names[RETURN_ADDR_REGNUM]);
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (current_frame_info.pretend_size)));
+
+ emit_insn (gen_blockage ());
}
+}
+
+/* Do any necessary cleanup after a function to restore stack, frame,
+ and regs. */
+static void
+m32r_output_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
/* Reset state info for each function. */
current_frame_info = zero_frame_info;
m32r_compute_function_type (NULL_TREE);
if (!reload_completed)
return FALSE;
+ if (M32R_INTERRUPT_P (m32r_compute_function_type (current_function_decl)))
+ return FALSE;
+
if (! current_frame_info.initialized)
m32r_compute_frame_size (get_frame_size ());
- return current_frame_info.total_size == 0;
+ return current_frame_info.total_size == 0;
}
\f
{
if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
return 0;
-
+
if (GET_CODE (x) == CONST
&& GET_CODE (XEXP (x, 0)) == PLUS
&& (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
|| GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
&& (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
return 0;
-
+
return 1;
}
else
output_operand_lossage ("invalid operand to %%s code");
return;
-
+
case 'p':
if (GET_CODE (x) == REG)
fprintf (file, "@%s+", reg_names [REGNO (x)]);
{
static char buffer [100];
const char * dest = reg_names [REGNO (operands [0])];
-
+
buffer [0] = 0;
-
+
/* Destination must be a register. */
gcc_assert (GET_CODE (operands [0]) == REG);
gcc_assert (conditional_move_operand (operands [2], SImode));
gcc_assert (conditional_move_operand (operands [3], SImode));
-
+
/* Check to see if the test is reversed. */
if (GET_CODE (operands [1]) == NE)
{
{
int reg_a = -1;
int reg_b = -2;
-
+
while (GET_CODE (a) == SUBREG)
a = SUBREG_REG (a);
-
+
if (GET_CODE (a) == REG)
reg_a = REGNO (a);
-
+
while (GET_CODE (b) == SUBREG)
b = SUBREG_REG (b);
-
+
if (GET_CODE (b) == REG)
reg_b = REGNO (b);
-
+
return reg_a != reg_b;
}
else
gcc_unreachable (); /* Shouldn't happen. */
extra_flags |= model << SYMBOL_FLAG_MODEL_SHIFT;
-
+
if (extra_flags)
SYMBOL_REF_FLAGS (sym) |= extra_flags;
leftover = bytes % MAX_MOVE_BYTES;
bytes -= leftover;
-
+
/* If necessary, generate a loop to handle the bulk of the copy. */
if (bytes)
{
emit_move_insn (dst_reg, new_dst_reg);
emit_move_insn (src_reg, new_src_reg);
emit_insn (gen_addsi3 (dst_reg, dst_reg, GEN_INT (4)));
-
+
if (bytes > MAX_MOVE_BYTES)
{
emit_insn (gen_cmpsi (src_reg, final_src));
}
\f
-/* Emit load/stores for a small constant word aligned block_move.
+/* Emit load/stores for a small constant word aligned block_move.
operands[0] is the memory address of the destination.
operands[1] is the memory address of the source.
HOST_WIDE_INT bytes = INTVAL (operands[2]);
int first_time;
int got_extra = 0;
-
+
gcc_assert (bytes >= 1 && bytes <= MAX_MOVE_BYTES);
-
+
/* We do not have a post-increment store available, so the first set of
stores are done without any increment, then the remaining ones can use
the pre-increment addressing mode.
-
+
Note: expand_block_move() also relies upon this behavior when building
loops to copy large blocks. */
first_time = 1;
-
+
while (bytes > 0)
{
if (bytes >= 8)
{
if (bytes > 4)
got_extra = 1;
-
+
output_asm_insn ("ld\t%5, %p1", operands);
-
+
if (got_extra)
output_asm_insn ("ld\t%6, %p1", operands);
-
+
if (first_time)
output_asm_insn ("st\t%5, @%0", operands);
else
bytes -= 4;
}
- else
+ else
{
/* Get the entire next word, even though we do not want all of it.
The saves us from doing several smaller loads, and we assume that
my_operands[1] = GEN_INT (dst_offset);
my_operands[2] = operands[0];
output_asm_insn ("sth\t%0, @(%1,%2)", my_operands);
-
+
/* If there is a byte left to store then increment the
destination address and shift the contents of the source
register down by 8 bits. We could not do the address
my_operands[1] = GEN_INT (dst_inc_amount);
output_asm_insn ("addi\t%0, #%1", my_operands);
}
-
+
/* Update the source pointer if needed. We have to do this
so that the patterns matches what we output in this
function. */
my_operands[1] = GEN_INT (src_inc_amount);
output_asm_insn ("addi\t%0, #%1", my_operands);
}
-
+
bytes = 0;
}
&& !regs_ever_live[new_reg])
return 0;
- /* We currently emit epilogues as text, not rtl, so the liveness
- of the return address register isn't visible. */
- if (current_function_is_leaf && new_reg == RETURN_ADDR_REGNUM)
- return 0;
-
return 1;
}
{
if (count != 0)
return const0_rtx;
-
+
return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNUM);
}