As a result of the previous changes, epilogue_insns pattern can only be
generated in Thumb1. After removing other cases in define_insn for
epilogue_insns, the function arm_output_epilogue becomes dead code and can
be eliminated, along with all its helper functions.
ChangeLog:
gcc
2012-05-31 Ian Bolton <ian.bol...@arm.com>
Sameera Deshpande <sameera.deshpa...@arm.com>
Greta Yorsh <greta.yo...@arm.com>
* config/arm/arm-protos.h (arm_output_epilogue): Remove.
* config/arm/arm.c (print_multi_reg): Remove.
(vfp_output_fldmd): Likewise.
(arm_output_epilogue): Likewise.
* config/arm/arm.md (epilogue_insns): Update condition and code.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 34de513..b97773b 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -28,7 +28,6 @@ extern int use_return_insn (int, rtx);
extern enum reg_class arm_regno_class (int);
extern void arm_load_pic_register (unsigned long);
extern int arm_volatile_func (void);
-extern const char *arm_output_epilogue (rtx);
extern void arm_expand_prologue (void);
extern void arm_expand_epilogue (bool);
extern void thumb2_expand_return (void);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 903517d..712e38f 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -13886,86 +13886,6 @@ fp_const_from_val (REAL_VALUE_TYPE *r)
gcc_unreachable ();
}
-/* Output the operands of a LDM/STM instruction to STREAM.
- MASK is the ARM register set mask of which only bits 0-15 are important.
- REG is the base register, either the frame pointer or the stack pointer,
- INSTR is the possibly suffixed load or store instruction.
- RFE is nonzero if the instruction should also copy spsr to cpsr. */
-
-static void
-print_multi_reg (FILE *stream, const char *instr, unsigned reg,
- unsigned long mask, int rfe)
-{
- unsigned i;
- bool not_first = FALSE;
-
- gcc_assert (!rfe || (mask & (1 << PC_REGNUM)));
- fputc ('\t', stream);
- asm_fprintf (stream, instr, reg);
- fputc ('{', stream);
-
- for (i = 0; i <= LAST_ARM_REGNUM; i++)
- if (mask & (1 << i))
- {
- if (not_first)
- fprintf (stream, ", ");
-
- asm_fprintf (stream, "%r", i);
- not_first = TRUE;
- }
-
- if (rfe)
- fprintf (stream, "}^\n");
- else
- fprintf (stream, "}\n");
-}
-
-
-/* Output a FLDMD instruction to STREAM.
- BASE if the register containing the address.
- REG and COUNT specify the register range.
- Extra registers may be added to avoid hardware bugs.
-
- We output FLDMD even for ARMv5 VFP implementations. Although
- FLDMD is technically not supported until ARMv6, it is believed
- that all VFP implementations support its use in this context. */
-
-static void
-vfp_output_fldmd (FILE * stream, unsigned int base, int reg, int count)
-{
- int i;
-
- /* Workaround ARM10 VFPr1 bug. */
- if (count == 2 && !arm_arch6)
- {
- if (reg == 15)
- reg--;
- count++;
- }
-
- /* FLDMD may not load more than 16 doubleword registers at a time. Split the
- load into multiple parts if we have to handle more than 16 registers. */
- if (count > 16)
- {
- vfp_output_fldmd (stream, base, reg, 16);
- vfp_output_fldmd (stream, base, reg + 16, count - 16);
- return;
- }
-
- fputc ('\t', stream);
- asm_fprintf (stream, "fldmfdd\t%r!, {", base);
-
- for (i = reg; i < reg + count; i++)
- {
- if (i > reg)
- fputs (", ", stream);
- asm_fprintf (stream, "d%d", i);
- }
- fputs ("}\n", stream);
-
-}
-
-
/* OPERANDS[0] is the entire list of insns that constitute pop,
OPERANDS[1] is the base register, RETURN_PC is true iff return insn
is in the list, UPDATE is true iff the list contains explicit
@@ -16061,451 +15981,6 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT
frame_size)
}
-const char *
-arm_output_epilogue (rtx sibling)
-{
- int reg;
- unsigned long saved_regs_mask;
- unsigned long func_type;
- /* Floats_offset is the offset from the "virtual" frame. In an APCS
- frame that is $fp + 4 for a non-variadic function. */
- int floats_offset = 0;
- rtx operands[3];
- FILE * f = asm_out_file;
- unsigned int lrm_count = 0;
- int really_return = (sibling == NULL);
- int start_reg;
- arm_stack_offsets *offsets;
-
- /* If we have already generated the return instruction
- then it is futile to generate anything else. */
- if (use_return_insn (FALSE, sibling) &&
- (cfun->machine->return_used_this_function != 0))
- return "";
-
- func_type = arm_current_func_type ();
-
- if (IS_NAKED (func_type))
- /* Naked functions don't have epilogues. */
- return "";
-
- if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
- {
- rtx op;
-
- /* A volatile function should never return. Call abort. */
- op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
- assemble_external_libcall (op);
- output_asm_insn ("bl\t%a0", &op);
-
- return "";
- }
-
- /* If we are throwing an exception, then we really must be doing a
- return, so we can't tail-call. */
- gcc_assert (!crtl->calls_eh_return || really_return);
-
- offsets = arm_get_frame_offsets ();
- saved_regs_mask = offsets->saved_regs_mask;
-
- if (TARGET_IWMMXT)
- lrm_count = bit_count (saved_regs_mask);
-
- floats_offset = offsets->saved_args;
- /* Compute how far away the floats will be. */
- for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
- if (saved_regs_mask & (1 << reg))
- floats_offset += 4;
-
- if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
- {
- /* This variable is for the Virtual Frame Pointer, not VFP regs. */
- int vfp_offset = offsets->frame;
-
- if (TARGET_FPA_EMU2)
- {
- for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
- if (df_regs_ever_live_p (reg) && !call_used_regs[reg])
- {
- floats_offset += 12;
- asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
- reg, FP_REGNUM, floats_offset - vfp_offset);
- }
- }
- else
- {
- start_reg = LAST_FPA_REGNUM;
-
- for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
- {
- if (df_regs_ever_live_p (reg) && !call_used_regs[reg])
- {
- floats_offset += 12;
-
- /* We can't unstack more than four registers at once. */
- if (start_reg - reg == 3)
- {
- asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
- reg, FP_REGNUM, floats_offset - vfp_offset);
- start_reg = reg - 1;
- }
- }
- else
- {
- if (reg != start_reg)
- asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
- reg + 1, start_reg - reg,
- FP_REGNUM, floats_offset - vfp_offset);
- start_reg = reg - 1;
- }
- }
-
- /* Just in case the last register checked also needs unstacking. */
- if (reg != start_reg)
- asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
- reg + 1, start_reg - reg,
- FP_REGNUM, floats_offset - vfp_offset);
- }
-
- if (TARGET_HARD_FLOAT && TARGET_VFP)
- {
- int saved_size;
-
- /* The fldmd insns do not have base+offset addressing
- modes, so we use IP to hold the address. */
- saved_size = arm_get_vfp_saved_size ();
-
- if (saved_size > 0)
- {
- floats_offset += saved_size;
- asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
- FP_REGNUM, floats_offset - vfp_offset);
- }
- start_reg = FIRST_VFP_REGNUM;
- for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
- {
- if ((!df_regs_ever_live_p (reg) || call_used_regs[reg])
- && (!df_regs_ever_live_p (reg + 1) || call_used_regs[reg +
1]))
- {
- if (start_reg != reg)
- vfp_output_fldmd (f, IP_REGNUM,
- (start_reg - FIRST_VFP_REGNUM) / 2,
- (reg - start_reg) / 2);
- start_reg = reg + 2;
- }
- }
- if (start_reg != reg)
- vfp_output_fldmd (f, IP_REGNUM,
- (start_reg - FIRST_VFP_REGNUM) / 2,
- (reg - start_reg) / 2);
- }
-
- if (TARGET_IWMMXT)
- {
- /* The frame pointer is guaranteed to be non-double-word aligned.
- This is because it is set to (old_stack_pointer - 4) and the
- old_stack_pointer was double word aligned. Thus the offset to
- the iWMMXt registers to be loaded must also be non-double-word
- sized, so that the resultant address *is* double-word aligned.
- We can ignore floats_offset since that was already included in
- the live_regs_mask. */
- lrm_count += (lrm_count % 2 ? 2 : 1);
-
- for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
- if (df_regs_ever_live_p (reg) && !call_used_regs[reg])
- {
- asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
- reg, FP_REGNUM, lrm_count * 4);
- lrm_count += 2;
- }
- }
-
- /* saved_regs_mask should contain the IP, which at the time of stack
- frame generation actually contains the old stack pointer. So a
- quick way to unwind the stack is just pop the IP register directly
- into the stack pointer. */
- gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
- saved_regs_mask &= ~ (1 << IP_REGNUM);
- saved_regs_mask |= (1 << SP_REGNUM);
-
- /* There are two registers left in saved_regs_mask - LR and PC. We
- only need to restore the LR register (the return address), but to
- save time we can load it directly into the PC, unless we need a
- special function exit sequence, or we are not really returning. */
- if (really_return
- && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
- && !crtl->calls_eh_return)
- /* Delete the LR from the register mask, so that the LR on
- the stack is loaded into the PC in the register mask. */
- saved_regs_mask &= ~ (1 << LR_REGNUM);
- else
- saved_regs_mask &= ~ (1 << PC_REGNUM);
-
- /* We must use SP as the base register, because SP is one of the
- registers being restored. If an interrupt or page fault
- happens in the ldm instruction, the SP might or might not
- have been restored. That would be bad, as then SP will no
- longer indicate the safe area of stack, and we can get stack
- corruption. Using SP as the base register means that it will
- be reset correctly to the original value, should an interrupt
- occur. If the stack pointer already points at the right
- place, then omit the subtraction. */
- if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
- || cfun->calls_alloca)
- asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
- 4 * bit_count (saved_regs_mask));
- print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask, 0);
-
- if (IS_INTERRUPT (func_type))
- /* Interrupt handlers will have pushed the
- IP onto the stack, so restore it now. */
- print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, 1 << IP_REGNUM, 0);
- }
- else
- {
- /* This branch is executed for ARM mode (non-apcs frames) and
- Thumb-2 mode. Frame layout is essentially the same for those
- cases, except that in ARM mode frame pointer points to the
- first saved register, while in Thumb-2 mode the frame pointer points
- to the last saved register.
-
- It is possible to make frame pointer point to last saved
- register in both cases, and remove some conditionals below.
- That means that fp setup in prologue would be just "mov fp, sp"
- and sp restore in epilogue would be just "mov sp, fp", whereas
- now we have to use add/sub in those cases. However, the value
- of that would be marginal, as both mov and add/sub are 32-bit
- in ARM mode, and it would require extra conditionals
- in arm_expand_prologue to distinguish ARM-apcs-frame case
- (where frame pointer is required to point at first register)
- and ARM-non-apcs-frame. Therefore, such change is postponed
- until real need arise. */
- unsigned HOST_WIDE_INT amount;
- int rfe;
- /* Restore stack pointer if necessary. */
- if (TARGET_ARM && frame_pointer_needed)
- {
- operands[0] = stack_pointer_rtx;
- operands[1] = hard_frame_pointer_rtx;
-
- operands[2] = GEN_INT (offsets->frame - offsets->saved_regs);
- output_add_immediate (operands);
- }
- else
- {
- if (frame_pointer_needed)
- {
- /* For Thumb-2 restore sp from the frame pointer.
- Operand restrictions mean we have to incrememnt FP, then copy
- to SP. */
- amount = offsets->locals_base - offsets->saved_regs;
- operands[0] = hard_frame_pointer_rtx;
- }
- else
- {
- unsigned long count;
- operands[0] = stack_pointer_rtx;
- amount = offsets->outgoing_args - offsets->saved_regs;
- /* pop call clobbered registers if it avoids a
- separate stack adjustment. */
- count = offsets->saved_regs - offsets->saved_args;
- if (optimize_size
- && count != 0
- && !crtl->calls_eh_return
- && bit_count(saved_regs_mask) * 4 == count
- && !IS_INTERRUPT (func_type)
- && !IS_STACKALIGN (func_type)
- && !crtl->tail_call_emit)
- {
- unsigned long mask;
- /* Preserve return values, of any size. */
- mask = (1 << ((arm_size_return_regs() + 3) / 4)) - 1;
- mask ^= 0xf;
- mask &= ~saved_regs_mask;
- reg = 0;
- while (bit_count (mask) * 4 > amount)
- {
- while ((mask & (1 << reg)) == 0)
- reg++;
- mask &= ~(1 << reg);
- }
- if (bit_count (mask) * 4 == amount) {
- amount = 0;
- saved_regs_mask |= mask;
- }
- }
- }
-
- if (amount)
- {
- operands[1] = operands[0];
- operands[2] = GEN_INT (amount);
- output_add_immediate (operands);
- }
- if (frame_pointer_needed)
- asm_fprintf (f, "\tmov\t%r, %r\n",
- SP_REGNUM, HARD_FRAME_POINTER_REGNUM);
- }
-
- if (TARGET_FPA_EMU2)
- {
- for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
- if (df_regs_ever_live_p (reg) && !call_used_regs[reg])
- asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
- reg, SP_REGNUM);
- }
- else
- {
- start_reg = FIRST_FPA_REGNUM;
-
- for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
- {
- if (df_regs_ever_live_p (reg) && !call_used_regs[reg])
- {
- if (reg - start_reg == 3)
- {
- asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
- start_reg, SP_REGNUM);
- start_reg = reg + 1;
- }
- }
- else
- {
- if (reg != start_reg)
- asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
- start_reg, reg - start_reg,
- SP_REGNUM);
-
- start_reg = reg + 1;
- }
- }
-
- /* Just in case the last register checked also needs unstacking. */
- if (reg != start_reg)
- asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
- start_reg, reg - start_reg, SP_REGNUM);
- }
-
- if (TARGET_HARD_FLOAT && TARGET_VFP)
- {
- int end_reg = LAST_VFP_REGNUM + 1;
-
- /* Scan the registers in reverse order. We need to match
- any groupings made in the prologue and generate matching
- pop operations. */
- for (reg = LAST_VFP_REGNUM - 1; reg >= FIRST_VFP_REGNUM; reg -= 2)
- {
- if ((!df_regs_ever_live_p (reg) || call_used_regs[reg])
- && (!df_regs_ever_live_p (reg + 1)
- || call_used_regs[reg + 1]))
- {
- if (end_reg > reg + 2)
- vfp_output_fldmd (f, SP_REGNUM,
- (reg + 2 - FIRST_VFP_REGNUM) / 2,
- (end_reg - (reg + 2)) / 2);
- end_reg = reg;
- }
- }
- if (end_reg > reg + 2)
- vfp_output_fldmd (f, SP_REGNUM, 0,
- (end_reg - (reg + 2)) / 2);
- }
-
- if (TARGET_IWMMXT)
- for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
- if (df_regs_ever_live_p (reg) && !call_used_regs[reg])
- asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
-
- /* If we can, restore the LR into the PC. */
- if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
- && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
- && !IS_STACKALIGN (func_type)
- && really_return
- && crtl->args.pretend_args_size == 0
- && saved_regs_mask & (1 << LR_REGNUM)
- && !crtl->calls_eh_return)
- {
- saved_regs_mask &= ~ (1 << LR_REGNUM);
- saved_regs_mask |= (1 << PC_REGNUM);
- rfe = IS_INTERRUPT (func_type);
- }
- else
- rfe = 0;
-
- /* Load the registers off the stack. If we only have one register
- to load use the LDR instruction - it is faster. For Thumb-2
- always use pop and the assembler will pick the best instruction.*/
- if (TARGET_ARM && saved_regs_mask == (1 << LR_REGNUM)
- && !IS_INTERRUPT(func_type))
- {
- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
- }
- else if (saved_regs_mask)
- {
- if (saved_regs_mask & (1 << SP_REGNUM))
- /* Note - write back to the stack register is not enabled
- (i.e. "ldmfd sp!..."). We know that the stack pointer is
- in the list of registers and if we add writeback the
- instruction becomes UNPREDICTABLE. */
- print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask,
- rfe);
- else if (TARGET_ARM)
- print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, saved_regs_mask,
- rfe);
- else
- print_multi_reg (f, "pop\t", SP_REGNUM, saved_regs_mask, 0);
- }
-
- if (crtl->args.pretend_args_size)
- {
- /* Unwind the pre-pushed regs. */
- operands[0] = operands[1] = stack_pointer_rtx;
- operands[2] = GEN_INT (crtl->args.pretend_args_size);
- output_add_immediate (operands);
- }
- }
-
- /* We may have already restored PC directly from the stack. */
- if (!really_return || saved_regs_mask & (1 << PC_REGNUM))
- return "";
-
- /* Stack adjustment for exception handler. */
- if (crtl->calls_eh_return)
- asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
- ARM_EH_STACKADJ_REGNUM);
-
- /* Generate the return instruction. */
- switch ((int) ARM_FUNC_TYPE (func_type))
- {
- case ARM_FT_ISR:
- case ARM_FT_FIQ:
- asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
- break;
-
- case ARM_FT_EXCEPTION:
- asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
- break;
-
- case ARM_FT_INTERWORKED:
- asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
- break;
-
- default:
- if (IS_STACKALIGN (func_type))
- {
- /* See comment in arm_expand_prologue. */
- asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, 0);
- }
- if (arm_arch5 || arm_arch4t)
- asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
- else
- asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
- break;
- }
-
- return "";
-}
-
static void
arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 40abfde..1cddedd 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -10748,11 +10748,8 @@
(define_insn "*epilogue_insns"
[(unspec_volatile [(return)] VUNSPEC_EPILOGUE)]
- "TARGET_EITHER"
+ "TARGET_THUMB1"
"*
- if (TARGET_32BIT)
- return arm_output_epilogue (NULL);
- else /* TARGET_THUMB1 */
return thumb1_unexpanded_epilogue ();
"
; Length is absolute worst case