#undef TARGET_HELP
#define TARGET_HELP avr_help
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
static void
return length;
}
+/* Implement INCOMING_RETURN_ADDR_RTX. */
+
+rtx
+avr_incoming_return_addr_rtx (void)
+{
+ /* The return address is at the top of the stack. Note that the push
+ was via post-decrement, which means the actual address is off by one. */
+ return gen_frame_mem (HImode, plus_constant (stack_pointer_rtx, 1));
+}
+
+/* Helper for expand_prologue. Emit a push of a byte register. */
+
+static void
+emit_push_byte (unsigned regno, bool frame_related_p)
+{
+ rtx mem, reg, insn;
+
+ mem = gen_rtx_POST_DEC (HImode, stack_pointer_rtx);
+ mem = gen_frame_mem (QImode, mem);
+ reg = gen_rtx_REG (QImode, regno);
+
+ insn = emit_insn (gen_rtx_SET (VOIDmode, mem, reg));
+ if (frame_related_p)
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ cfun->machine->stack_usage++;
+}
+
+
/* Output function prologue. */
void
HARD_REG_SET set;
int minimize;
HOST_WIDE_INT size = get_frame_size();
- /* Define templates for push instructions. */
- rtx pushbyte = gen_rtx_MEM (QImode,
- gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
- rtx pushword = gen_rtx_MEM (HImode,
- gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
rtx insn;
/* Init cfun->machine. */
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
{
+ /* Enable interrupts. */
if (cfun->machine->is_interrupt)
- {
- /* Enable interrupts. */
- insn = emit_insn (gen_enable_interrupt ());
- RTX_FRAME_RELATED_P (insn) = 1;
- }
+ emit_insn (gen_enable_interrupt ());
/* Push zero reg. */
- insn = emit_move_insn (pushbyte, zero_reg_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- cfun->machine->stack_usage++;
+ emit_push_byte (ZERO_REGNO, true);
/* Push tmp reg. */
- insn = emit_move_insn (pushbyte, tmp_reg_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- cfun->machine->stack_usage++;
+ emit_push_byte (TMP_REGNO, true);
/* Push SREG. */
- insn = emit_move_insn (tmp_reg_rtx,
- gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
- RTX_FRAME_RELATED_P (insn) = 1;
- insn = emit_move_insn (pushbyte, tmp_reg_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- cfun->machine->stack_usage++;
+ /* ??? There's no dwarf2 column reserved for SREG. */
+ emit_move_insn (tmp_reg_rtx, gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
+ emit_push_byte (TMP_REGNO, false);
/* Push RAMPZ. */
- if(AVR_HAVE_RAMPZ
- && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+ /* ??? There's no dwarf2 column reserved for RAMPZ. */
+ if (AVR_HAVE_RAMPZ
+ && TEST_HARD_REG_BIT (set, REG_Z)
+ && TEST_HARD_REG_BIT (set, REG_Z + 1))
{
- insn = emit_move_insn (tmp_reg_rtx,
- gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
- RTX_FRAME_RELATED_P (insn) = 1;
- insn = emit_move_insn (pushbyte, tmp_reg_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- cfun->machine->stack_usage++;
+ emit_move_insn (tmp_reg_rtx,
+ gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
+ emit_push_byte (TMP_REGNO, false);
}
/* Clear zero reg. */
- insn = emit_move_insn (zero_reg_rtx, const0_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
+ emit_move_insn (zero_reg_rtx, const0_rtx);
/* Prevent any attempt to delete the setting of ZERO_REG! */
emit_use (zero_reg_rtx);
|| (AVR_2_BYTE_PC && live_seq > 6)
|| live_seq > 7))
{
- insn = emit_move_insn (gen_rtx_REG (HImode, REG_X),
- gen_int_mode (size, HImode));
- RTX_FRAME_RELATED_P (insn) = 1;
+ int first_reg, reg, offset;
+
+ emit_move_insn (gen_rtx_REG (HImode, REG_X),
+ gen_int_mode (size, HImode));
- insn =
- emit_insn (gen_call_prologue_saves (gen_int_mode (live_seq, HImode),
- gen_int_mode (size + live_seq, HImode)));
+ insn = emit_insn (gen_call_prologue_saves
+ (gen_int_mode (live_seq, HImode),
+ gen_int_mode (size + live_seq, HImode)));
RTX_FRAME_RELATED_P (insn) = 1;
+
+ /* Describe the effect of the unspec_volatile call to prologue_saves.
+ Note that this formulation assumes that add_reg_note pushes the
+ notes to the front. Thus we build them in the reverse order of
+ how we want dwarf2out to process them. */
+
+ /* The function does always set frame_pointer_rtx, but whether that
+ is going to be permanent in the function is frame_pointer_needed. */
+ add_reg_note (insn, REG_CFA_ADJUST_CFA,
+ gen_rtx_SET (VOIDmode,
+ (frame_pointer_needed
+ ? frame_pointer_rtx : stack_pointer_rtx),
+ plus_constant (stack_pointer_rtx,
+ -(size + live_seq))));
+
+ /* Note that live_seq always contains r28+r29, but the other
+ registers to be saved are all below 18. */
+ first_reg = 18 - (live_seq - 2);
+
+ for (reg = 29, offset = -live_seq + 1;
+ reg >= first_reg;
+ reg = (reg == 28 ? 17 : reg - 1), ++offset)
+ {
+ rtx m, r;
+
+ m = gen_rtx_MEM (QImode, plus_constant (stack_pointer_rtx, offset));
+ r = gen_rtx_REG (QImode, reg);
+ add_reg_note (insn, REG_CFA_OFFSET, gen_rtx_SET (VOIDmode, m, r));
+ }
+
cfun->machine->stack_usage += size + live_seq;
}
else
{
int reg;
for (reg = 0; reg < 32; ++reg)
- {
- if (TEST_HARD_REG_BIT (set, reg))
- {
- /* Emit push of register to save. */
- insn=emit_move_insn (pushbyte, gen_rtx_REG (QImode, reg));
- RTX_FRAME_RELATED_P (insn) = 1;
- cfun->machine->stack_usage++;
- }
- }
+ if (TEST_HARD_REG_BIT (set, reg))
+ emit_push_byte (reg, true);
+
if (frame_pointer_needed)
{
if (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))
{
- /* Push frame pointer. */
- insn = emit_move_insn (pushword, frame_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
- cfun->machine->stack_usage += 2;
+ /* Push frame pointer. Always be consistent about the
+ ordering of pushes -- epilogue_restores expects the
+ register pair to be pushed low byte first. */
+ emit_push_byte (REG_Y, true);
+ emit_push_byte (REG_Y + 1, true);
}
if (!size)
is selected. */
rtx myfp;
rtx fp_plus_insns;
- rtx sp_plus_insns = NULL_RTX;
if (AVR_HAVE_8BIT_SP)
{
- /* The high byte (r29) doesn't change - prefer 'subi' (1 cycle)
- over 'sbiw' (2 cycles, same size). */
- myfp = gen_rtx_REG (QImode, REGNO (frame_pointer_rtx));
+ /* The high byte (r29) doesn't change. Prefer 'subi'
+ (1 cycle) over 'sbiw' (2 cycles, same size). */
+ myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM);
}
else
{
/* Method 1-Adjust frame pointer. */
start_sequence ();
- insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
+ /* Normally the dwarf2out frame-related-expr interpreter does
+ not expect to have the CFA change once the frame pointer is
+ set up. Thus we avoid marking the move insn below and
+ instead indicate that the entire operation is complete after
+ the frame pointer subtraction is done. */
- insn =
- emit_move_insn (myfp,
- gen_rtx_PLUS (GET_MODE(myfp), myfp,
- gen_int_mode (-size,
- GET_MODE(myfp))));
- RTX_FRAME_RELATED_P (insn) = 1;
+ emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
- /* Copy to stack pointer. */
+ insn = emit_move_insn (myfp, plus_constant (myfp, -size));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ add_reg_note (insn, REG_CFA_ADJUST_CFA,
+ gen_rtx_SET (VOIDmode, frame_pointer_rtx,
+ plus_constant (stack_pointer_rtx,
+ -size)));
+
+ /* Copy to stack pointer. Note that since we've already
+ changed the CFA to the frame pointer this operation
+ need not be annotated at all. */
if (AVR_HAVE_8BIT_SP)
{
- insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
+ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
}
else if (TARGET_NO_INTERRUPTS
|| cfun->machine->is_signal
|| cfun->machine->is_OS_main)
{
- insn =
- emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx,
- frame_pointer_rtx));
- RTX_FRAME_RELATED_P (insn) = 1;
+ emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx,
+ frame_pointer_rtx));
}
else if (cfun->machine->is_interrupt)
{
- insn = emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx,
- frame_pointer_rtx));
- RTX_FRAME_RELATED_P (insn) = 1;
+ emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx,
+ frame_pointer_rtx));
}
else
{
- insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- RTX_FRAME_RELATED_P (insn) = 1;
+ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
}
fp_plus_insns = get_insns ();
/* Method 2-Adjust Stack pointer. */
if (size <= 6)
{
+ rtx sp_plus_insns;
+
start_sequence ();
- insn =
- emit_move_insn (stack_pointer_rtx,
- gen_rtx_PLUS (HImode,
- stack_pointer_rtx,
- gen_int_mode (-size,
- HImode)));
+ insn = plus_constant (stack_pointer_rtx, -size);
+ insn = emit_move_insn (stack_pointer_rtx, insn);
RTX_FRAME_RELATED_P (insn) = 1;
- insn =
- emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
sp_plus_insns = get_insns ();
end_sequence ();
- }
- /* Use shortest method. */
- if (size <= 6 && (get_sequence_length (sp_plus_insns)
- < get_sequence_length (fp_plus_insns)))
- emit_insn (sp_plus_insns);
- else
+ /* Use shortest method. */
+ if (get_sequence_length (sp_plus_insns)
+ < get_sequence_length (fp_plus_insns))
+ emit_insn (sp_plus_insns);
+ else
+ emit_insn (fp_plus_insns);
+ }
+ else
emit_insn (fp_plus_insns);
+
cfun->machine->stack_usage += size;
}
}
return 0;
}
+/* Helper for expand_epilogue. Emit a pop of a byte register. */
+
+static void
+emit_pop_byte (unsigned regno)
+{
+ rtx mem, reg;
+
+ mem = gen_rtx_PRE_INC (HImode, stack_pointer_rtx);
+ mem = gen_frame_mem (QImode, mem);
+ reg = gen_rtx_REG (QImode, regno);
+
+ emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
+}
+
/* Output RTL epilogue. */
void
/* Try two methods to adjust stack and select shortest. */
rtx myfp;
rtx fp_plus_insns;
- rtx sp_plus_insns = NULL_RTX;
-
+
if (AVR_HAVE_8BIT_SP)
{
/* The high byte (r29) doesn't change - prefer 'subi'
(1 cycle) over 'sbiw' (2 cycles, same size). */
- myfp = gen_rtx_REG (QImode, REGNO (frame_pointer_rtx));
+ myfp = gen_rtx_REG (QImode, FRAME_POINTER_REGNUM);
}
else
{
/* Method 1-Adjust frame pointer. */
start_sequence ();
- emit_move_insn (myfp,
- gen_rtx_PLUS (GET_MODE (myfp), myfp,
- gen_int_mode (size,
- GET_MODE(myfp))));
+ emit_move_insn (myfp, plus_constant (myfp, size));
/* Copy to stack pointer. */
if (AVR_HAVE_8BIT_SP)
/* Method 2-Adjust Stack pointer. */
if (size <= 5)
{
+ rtx sp_plus_insns;
+
start_sequence ();
emit_move_insn (stack_pointer_rtx,
- gen_rtx_PLUS (HImode, stack_pointer_rtx,
- gen_int_mode (size,
- HImode)));
+ plus_constant (stack_pointer_rtx, size));
sp_plus_insns = get_insns ();
end_sequence ();
- }
- /* Use shortest method. */
- if (size <= 5 && (get_sequence_length (sp_plus_insns)
- < get_sequence_length (fp_plus_insns)))
- emit_insn (sp_plus_insns);
- else
+ /* Use shortest method. */
+ if (get_sequence_length (sp_plus_insns)
+ < get_sequence_length (fp_plus_insns))
+ emit_insn (sp_plus_insns);
+ else
+ emit_insn (fp_plus_insns);
+ }
+ else
emit_insn (fp_plus_insns);
}
if (!(cfun->machine->is_OS_task || cfun->machine->is_OS_main))
{
- /* Restore previous frame_pointer. */
- emit_insn (gen_pophi (frame_pointer_rtx));
+ /* Restore previous frame_pointer. See expand_prologue for
+ rationale for not using pophi. */
+ emit_pop_byte (REG_Y + 1);
+ emit_pop_byte (REG_Y);
}
}
+
/* Restore used registers. */
for (reg = 31; reg >= 0; --reg)
- {
- if (TEST_HARD_REG_BIT (set, reg))
- emit_insn (gen_popqi (gen_rtx_REG (QImode, reg)));
- }
+ if (TEST_HARD_REG_BIT (set, reg))
+ emit_pop_byte (reg);
+
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
{
/* Restore RAMPZ using tmp reg as scratch. */
- if(AVR_HAVE_RAMPZ
- && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+ if (AVR_HAVE_RAMPZ
+ && TEST_HARD_REG_BIT (set, REG_Z)
+ && TEST_HARD_REG_BIT (set, REG_Z + 1))
{
- emit_insn (gen_popqi (tmp_reg_rtx));
- emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(RAMPZ_ADDR)),
+ emit_pop_byte (TMP_REGNO);
+ emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)),
tmp_reg_rtx);
}
/* Restore SREG using tmp reg as scratch. */
- emit_insn (gen_popqi (tmp_reg_rtx));
+ emit_pop_byte (TMP_REGNO);
- emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)),
+ emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)),
tmp_reg_rtx);
/* Restore tmp REG. */
- emit_insn (gen_popqi (tmp_reg_rtx));
+ emit_pop_byte (TMP_REGNO);
/* Restore zero REG. */
- emit_insn (gen_popqi (zero_reg_rtx));
+ emit_pop_byte (ZERO_REGNO);
}
emit_jump_insn (gen_return ());