From: Ian Bolton Date: Mon, 18 Jun 2012 18:06:54 +0000 (+0000) Subject: As a result of the previous changes, epilogue_insns pattern can only be generated... X-Git-Tag: upstream/12.2.0~75695 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c59e1214f746c120caf4849daeffc11681f9d660;p=platform%2Fupstream%2Fgcc.git As a result of the previous changes, epilogue_insns pattern can only be generated in Thumb1. 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. gcc/ 2012-06-18 Ian Bolton Sameera Deshpande Greta Yorsh * 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. Co-Authored-By: Greta Yorsh Co-Authored-By: Sameera Deshpande From-SVN: r188745 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cc72e97..97659f8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,16 @@ Sameera Deshpande Greta Yorsh + * 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. + +2012-06-18 Ian Bolton + Sameera Deshpande + Greta Yorsh + * config/arm/arm-protos.h (thumb2_expand_return): New declaration. * config/arm/arm.c (thumb2_expand_return): New function. * config/arm/arm.md (return): Update condition and code. diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 5a9940e..76e1abd 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 3f5b500..627b436 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -13659,86 +13659,6 @@ fp_const_from_val (REAL_VALUE_TYPE *r) return "0"; } -/* 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 @@ -15833,451 +15753,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 eb99488..f4ced7b 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -10619,11 +10619,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