diff options
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/arm/arm.c | 126 |
1 files changed, 104 insertions, 22 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 6cf226e..826bbac 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -50,6 +50,7 @@ #include "tm_p.h" #include "target.h" #include "target-def.h" +#include "debug.h" /* Forward definitions of types. */ typedef struct minipool_node Mnode; @@ -85,7 +86,7 @@ static struct machine_function *arm_init_machine_status (void); static int number_of_first_bit_set (int); static void replace_symbols_in_block (tree, rtx, rtx); static void thumb_exit (FILE *, int, rtx); -static void thumb_pushpop (FILE *, int, int); +static void thumb_pushpop (FILE *, int, int, int *, int); static rtx is_jump_table (rtx); static HOST_WIDE_INT get_jump_table_size (rtx); static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT); @@ -11562,7 +11563,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs) } /* Pop as many registers as we can. */ - thumb_pushpop (f, regs_available_for_popping, FALSE); + thumb_pushpop (f, regs_available_for_popping, FALSE, NULL, + regs_available_for_popping); /* Process the registers we popped. */ if (reg_containing_return_addr == -1) @@ -11643,7 +11645,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs) int popped_into; int move_to; - thumb_pushpop (f, regs_available_for_popping, FALSE); + thumb_pushpop (f, regs_available_for_popping, FALSE, NULL, + regs_available_for_popping); /* We have popped either FP or SP. Move whichever one it is into the correct register. */ @@ -11663,7 +11666,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs) { int popped_into; - thumb_pushpop (f, regs_available_for_popping, FALSE); + thumb_pushpop (f, regs_available_for_popping, FALSE, NULL, + regs_available_for_popping); popped_into = number_of_first_bit_set (regs_available_for_popping); @@ -11693,12 +11697,20 @@ thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs) asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr); } -/* Emit code to push or pop registers to or from the stack. */ +/* Emit code to push or pop registers to or from the stack. F is the + assembly file. MASK is the registers to push or pop. PUSH is + non-zero if we should push, and zero if we should pop. For debugging + output, if pushing, adjust CFA_OFFSET by the amount of space added + to the stack. REAL_REGS should have the same number of bits set as + MASK, and will be used instead (in the same order) to describe which + registers were saved - this is used to mark the save slots when we + push high registers after moving them to low registers. */ static void -thumb_pushpop (FILE *f, int mask, int push) +thumb_pushpop (FILE *f, int mask, int push, int *cfa_offset, int real_regs) { int regno; int lo_mask = mask & 0xFF; + int pushed_words = 0; if (lo_mask == 0 && !push && (mask & (1 << 15))) { @@ -11719,6 +11731,8 @@ thumb_pushpop (FILE *f, int mask, int push) if ((lo_mask & ~1) != 0) fprintf (f, ", "); + + pushed_words++; } } @@ -11729,6 +11743,8 @@ thumb_pushpop (FILE *f, int mask, int push) fprintf (f, ", "); asm_fprintf (f, "%r", LR_REGNUM); + + pushed_words++; } else if (!push && (mask & (1 << PC_REGNUM))) { @@ -11753,6 +11769,23 @@ thumb_pushpop (FILE *f, int mask, int push) } fprintf (f, "}\n"); + + if (push && pushed_words && dwarf2out_do_frame ()) + { + char *l = dwarf2out_cfi_label (); + int pushed_mask = real_regs; + + *cfa_offset += pushed_words * 4; + dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset); + + pushed_words = 0; + pushed_mask = real_regs; + for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1) + { + if (pushed_mask & 1) + dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset); + } + } } void @@ -11951,7 +11984,7 @@ thumb_unexpanded_epilogue (void) mask &= (2 << regno) - 1; /* A noop if regno == 8 */ /* Pop the values into the low register(s). */ - thumb_pushpop (asm_out_file, mask, 0); + thumb_pushpop (asm_out_file, mask, 0, NULL, mask); /* Move the value(s) into the high registers. */ for (regno = 0; regno <= LAST_LO_REGNUM; regno++) @@ -11993,7 +12026,8 @@ thumb_unexpanded_epilogue (void) structure was created which includes an adjusted stack pointer, so just pop everything. */ if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL, + live_regs_mask); if (eh_ofs) thumb_exit (asm_out_file, 2, eh_ofs); @@ -12013,11 +12047,13 @@ thumb_unexpanded_epilogue (void) live_regs_mask &= ~(1 << PC_REGNUM); if (live_regs_mask) - thumb_pushpop (asm_out_file, live_regs_mask, FALSE); + thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL, + live_regs_mask); if (had_to_push_lr) /* Get the return address into a temporary register. */ - thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0); + thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL, + 1 << LAST_ARG_REGNUM); /* Remove the argument registers that were pushed onto the stack. */ asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n", @@ -12163,6 +12199,8 @@ thumb_get_frame_size (void) void thumb_expand_prologue (void) { + rtx insn, dwarf; + HOST_WIDE_INT amount = (thumb_get_frame_size () + current_function_outgoing_args_size); unsigned long func_type; @@ -12180,15 +12218,21 @@ thumb_expand_prologue (void) } if (frame_pointer_needed) - emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx)); + { + insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx)); + RTX_FRAME_RELATED_P (insn) = 1; + } if (amount) { amount = ROUND_UP_WORD (amount); if (amount < 512) - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (- amount))); + { + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- amount))); + RTX_FRAME_RELATED_P (insn) = 1; + } else { int regno; @@ -12228,8 +12272,16 @@ thumb_expand_prologue (void) /* Decrement the stack. */ emit_insn (gen_movsi (reg, GEN_INT (- amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - reg)); + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, reg)); + RTX_FRAME_RELATED_P (insn) = 1; + dwarf = gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + GEN_INT (- amount))); + RTX_FRAME_RELATED_P (dwarf) = 1; + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, + REG_NOTES (insn)); /* Restore the low register's original value. */ emit_insn (gen_movsi (reg, spare)); @@ -12245,8 +12297,17 @@ thumb_expand_prologue (void) reg = gen_rtx (REG, SImode, regno); emit_insn (gen_movsi (reg, GEN_INT (- amount))); - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - reg)); + + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, reg)); + RTX_FRAME_RELATED_P (insn) = 1; + dwarf = gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + GEN_INT (- amount))); + RTX_FRAME_RELATED_P (dwarf) = 1; + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, + REG_NOTES (insn)); } } } @@ -12307,6 +12368,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) { int live_regs_mask = 0; int high_regs_pushed = 0; + int cfa_offset = 0; int regno; if (IS_NAKED (arm_current_func_type ())) @@ -12369,6 +12431,16 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, SP_REGNUM, current_function_pretend_args_size); + + /* We don't need to record the stores for unwinding (would it + help the debugger any if we did?), but record the change in + the stack pointer. */ + if (dwarf2out_do_frame ()) + { + char *l = dwarf2out_cfi_label (); + cfa_offset = cfa_offset + current_function_pretend_args_size; + dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset); + } } for (regno = 0; regno <= LAST_LO_REGNUM; regno++) @@ -12424,9 +12496,16 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) asm_fprintf (f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n", SP_REGNUM, SP_REGNUM); - + + if (dwarf2out_do_frame ()) + { + char *l = dwarf2out_cfi_label (); + cfa_offset = cfa_offset + 16; + dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset); + } + if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); + thumb_pushpop (f, live_regs_mask, 1, &cfa_offset, live_regs_mask); for (offset = 0, wr = 1 << 15; wr != 0; wr >>= 1) if (wr & live_regs_mask) @@ -12470,7 +12549,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ARM_HARD_FRAME_POINTER_REGNUM, work_register); } else if (live_regs_mask) - thumb_pushpop (f, live_regs_mask, 1); + thumb_pushpop (f, live_regs_mask, 1, &cfa_offset, live_regs_mask); for (regno = 8; regno < 13; regno++) if (THUMB_REG_PUSHED_P (regno)) @@ -12498,6 +12577,8 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) while (high_regs_pushed > 0) { + int real_regs_mask = 0; + for (regno = LAST_LO_REGNUM; regno >= 0; regno--) { if (mask & (1 << regno)) @@ -12505,6 +12586,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg); high_regs_pushed--; + real_regs_mask |= (1 << next_hi_reg); if (high_regs_pushed) { @@ -12520,8 +12602,8 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) } } } - - thumb_pushpop (f, mask, 1); + + thumb_pushpop (f, mask, 1, &cfa_offset, real_regs_mask); } if (pushable_regs == 0 |