From 1c494086b2649039d4e6efe1cc44e635ddbdad0a Mon Sep 17 00:00:00 2001 From: rearnsha Date: Sat, 6 May 2000 18:13:35 +0000 Subject: [PATCH] Use new tail-calling mechanism on ARM. * arm.md (sibcall, sibcall_value): New expands. (sibcall_insn, sibcall_value_insn, sibcall_epilogue): New insns. (tailcalling peepholes): Delete. (push_multi): Simplify. * arm.c (lr_save_eliminated): Delete definition. (pattern_really_clobbers_lr, function_really_clobbers_lr): Delete. (output_return_instruction): Remove checks on lr_save_eliminated. (output_arm_prologue): Remove old tail-calling code. (arm_output_epilogue): New parameter, really_return. All callers changed. Handle tail-calling epilogues. * arm.h (lr_save_eliminated): Delete declaration. (frame_pointer_needed): Delete declaration. * arm-protos.h (arm_output_epilogue): Adjust prototype. * arm.md (is_thumb): Examine symbol thumb_code, not expression TARGET_ARM. * arm.c (thumb_code): Define it. (arm_override_options): Set it. * arm.h (thumb_code): Declare it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33731 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 23 ++++ gcc/config/arm/arm-protos.h | 2 +- gcc/config/arm/arm.c | 253 +++++++++----------------------------------- gcc/config/arm/arm.h | 6 +- gcc/config/arm/arm.md | 198 +++++++++++++++------------------- 5 files changed, 166 insertions(+), 316 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6e05a3fd861..be9337f39ad 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,28 @@ 2000-05-06 Richard Earnshaw (reanrsha@arm.com) + Use new tail-calling mechanism on ARM. + * arm.md (sibcall, sibcall_value): New expands. + (sibcall_insn, sibcall_value_insn, sibcall_epilogue): New insns. + (tailcalling peepholes): Delete. + (push_multi): Simplify. + * arm.c (lr_save_eliminated): Delete definition. + (pattern_really_clobbers_lr, function_really_clobbers_lr): Delete. + (output_return_instruction): Remove checks on lr_save_eliminated. + (output_arm_prologue): Remove old tail-calling code. + (arm_output_epilogue): New parameter, really_return. All callers + changed. Handle tail-calling epilogues. + * arm.h (lr_save_eliminated): Delete declaration. + (frame_pointer_needed): Delete declaration. + * arm-protos.h (arm_output_epilogue): Adjust prototype. + + * arm.md (is_thumb): Examine symbol thumb_code, not expression + TARGET_ARM. + * arm.c (thumb_code): Define it. + (arm_override_options): Set it. + * arm.h (thumb_code): Declare it. + +2000-05-06 Richard Earnshaw (reanrsha@arm.com) + * arm-protos.h (arm_dllexport_name_p, arm_dllimport_name_p): Constify. 2000-05-06 Richard Earnshaw (reanrsha@arm.com) diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 9c4d942b52c..8a3cb5b3001 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -27,7 +27,7 @@ extern int arm_process_pragma PARAMS ((int (*)(void), void (*) (int), char *)); extern void arm_finalize_pic PARAMS ((void)); extern int arm_volatile_func PARAMS ((void)); -extern char * arm_output_epilogue PARAMS ((void)); +extern char * arm_output_epilogue PARAMS ((int)); extern void output_func_epilogue PARAMS ((int)); extern void arm_expand_prologue PARAMS ((void)); /* Used in arm.md, but defined in output.c. */ diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index ba5b38cb17d..206224d6a0a 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -64,13 +64,11 @@ static int eliminate_lr2ip PARAMS ((rtx *)); static rtx emit_multi_reg_push PARAMS ((int)); static rtx emit_sfm PARAMS ((int, int)); static char * fp_const_from_val PARAMS ((REAL_VALUE_TYPE *)); -static int function_really_clobbers_lr PARAMS ((rtx)); static arm_cc get_arm_condition_code PARAMS ((rtx)); static void init_fpa_table PARAMS ((void)); static Hint int_log2 PARAMS ((Hint)); static rtx is_jump_table PARAMS ((rtx)); static char * output_multi_immediate PARAMS ((rtx *, char *, char *, int, Hint)); -static int pattern_really_clobbers_lr PARAMS ((rtx)); static void print_multi_reg PARAMS ((FILE *, char *, int, int, int)); static Mmode select_dominance_cc_mode PARAMS ((rtx, rtx, Hint)); static char * shift_op PARAMS ((rtx, Hint *)); @@ -171,6 +169,9 @@ int arm_is_strong = 0; /* Nonzero if this chip is a an ARM6 or an ARM7. */ int arm_is_6_or_7 = 0; +/* Nonzero if generating Thumb instructions. */ +int thumb_code = 0; + /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we must report the mode of the memory reference from PRINT_OPERAND to PRINT_OPERAND_ADDRESS. */ @@ -183,10 +184,6 @@ int current_function_anonymous_args; const char * arm_pic_register_string = NULL; int arm_pic_register = 9; -/* Set to one if we think that lr is only saved because of subroutine calls, - but all of these can be `put after' return insns. */ -int lr_save_eliminated; - /* Set to 1 when a return insn is output, this means that the epilogue is not needed. */ int return_used_this_function; @@ -569,6 +566,7 @@ arm_override_options () arm_ld_sched = (tune_flags & FL_LDSCHED) != 0; arm_is_strong = (tune_flags & FL_STRONG) != 0; + thumb_code = (TARGET_ARM == 0); arm_is_6_or_7 = (((tune_flags & (FL_MODE26 | FL_MODE32)) && !(tune_flags & FL_ARCH4))) != 0; @@ -6449,151 +6447,6 @@ output_ascii_pseudo_op (stream, p, len) } -/* Try to determine whether a pattern really clobbers the link register. - This information is useful when peepholing, so that lr need not be pushed - if we combine a call followed by a return. - NOTE: This code does not check for side-effect expressions in a SET_SRC: - such a check should not be needed because these only update an existing - value within a register; the register must still be set elsewhere within - the function. */ -static int -pattern_really_clobbers_lr (x) - rtx x; -{ - int i; - - switch (GET_CODE (x)) - { - case SET: - switch (GET_CODE (SET_DEST (x))) - { - case REG: - return REGNO (SET_DEST (x)) == LR_REGNUM; - - case SUBREG: - if (GET_CODE (XEXP (SET_DEST (x), 0)) == REG) - return REGNO (XEXP (SET_DEST (x), 0)) == LR_REGNUM; - - if (GET_CODE (XEXP (SET_DEST (x), 0)) == MEM) - return 0; - abort (); - - default: - return 0; - } - - case PARALLEL: - for (i = 0; i < XVECLEN (x, 0); i++) - if (pattern_really_clobbers_lr (XVECEXP (x, 0, i))) - return 1; - return 0; - - case CLOBBER: - switch (GET_CODE (XEXP (x, 0))) - { - case REG: - return REGNO (XEXP (x, 0)) == LR_REGNUM; - - case SUBREG: - if (GET_CODE (XEXP (XEXP (x, 0), 0)) == REG) - return REGNO (XEXP (XEXP (x, 0), 0)) == LR_REGNUM; - abort (); - - default: - return 0; - } - - case UNSPEC: - return 1; - - default: - return 0; - } -} - -static int -function_really_clobbers_lr (first) - rtx first; -{ - rtx insn, next; - - for (insn = first; insn; insn = next_nonnote_insn (insn)) - { - switch (GET_CODE (insn)) - { - case BARRIER: - case NOTE: - case CODE_LABEL: - case JUMP_INSN: /* Jump insns only change the PC (and conds) */ - break; - - case INSN: - if (pattern_really_clobbers_lr (PATTERN (insn))) - return 1; - break; - - case CALL_INSN: - /* Don't yet know how to handle those calls that are not to a - SYMBOL_REF. */ - if (GET_CODE (PATTERN (insn)) != PARALLEL) - abort (); - - switch (GET_CODE (XVECEXP (PATTERN (insn), 0, 0))) - { - case CALL: - if (GET_CODE (XEXP (XEXP (XVECEXP (PATTERN (insn), 0, 0), 0), 0)) - != SYMBOL_REF) - return 1; - break; - - case SET: - if (GET_CODE (XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (insn), - 0, 0)), 0), 0)) - != SYMBOL_REF) - return 1; - break; - - default: /* Don't recognize it, be safe. */ - return 1; - } - - /* A call can be made (by peepholing) not to clobber lr iff it is - followed by a return. There may, however, be a use insn iff - we are returning the result of the call. - If we run off the end of the insn chain, then that means the - call was at the end of the function. Unfortunately we don't - have a return insn for the peephole to recognize, so we - must reject this. (Can this be fixed by adding our own insn?) */ - if ((next = next_nonnote_insn (insn)) == NULL) - return 1; - - /* No need to worry about lr if the call never returns. */ - if (GET_CODE (next) == BARRIER) - break; - - if (GET_CODE (next) == INSN - && GET_CODE (PATTERN (next)) == USE - && (GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) - && (GET_CODE (XEXP (PATTERN (next), 0)) == REG) - && (REGNO (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))) - == REGNO (XEXP (PATTERN (next), 0)))) - if ((next = next_nonnote_insn (next)) == NULL) - return 1; - - if (GET_CODE (next) == JUMP_INSN - && GET_CODE (PATTERN (next)) == RETURN) - break; - return 1; - - default: - abort (); - } - } - - /* We have reached the end of the chain so lr was _not_ clobbered. */ - return 0; -} - char * output_return_instruction (operand, really_return, reverse) rtx operand; @@ -6646,7 +6499,7 @@ output_return_instruction (operand, really_return, reverse) && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) live_regs++; - if (live_regs || (regs_ever_live[LR_REGNUM] && ! lr_save_eliminated)) + if (live_regs || regs_ever_live[LR_REGNUM]) live_regs++; if (frame_pointer_needed) @@ -6656,21 +6509,17 @@ output_return_instruction (operand, really_return, reverse) load a single register. On other architectures, the cost is the same. */ if (live_regs == 1 && regs_ever_live[LR_REGNUM] - && ! lr_save_eliminated - /* FIXME: We ought to handle the case TARGET_APCS_32 is true, - really_return is true, and only the PC needs restoring. */ && ! really_return) output_asm_insn (reverse ? "ldr%?%D0\t%|lr, [%|sp], #4" : "ldr%?%d0\t%|lr, [%|sp], #4", &operand); else if (live_regs == 1 && regs_ever_live[LR_REGNUM] - && ! lr_save_eliminated && TARGET_APCS_32) output_asm_insn (reverse ? "ldr%?%D0\t%|pc, [%|sp], #4" : "ldr%?%d0\t%|pc, [%|sp], #4", &operand); else if (live_regs) { - if (lr_save_eliminated || ! regs_ever_live[LR_REGNUM]) + if (! regs_ever_live[LR_REGNUM]) live_regs++; if (frame_pointer_needed) @@ -6835,7 +6684,6 @@ output_arm_prologue (f, frame_size) return; return_used_this_function = 0; - lr_save_eliminated = 0; asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n", current_function_args_size, @@ -6868,26 +6716,15 @@ output_arm_prologue (f, frame_size) live_regs_mask |= 0xD800; else if (regs_ever_live[LR_REGNUM]) { - if (! current_function_args_size - && ! function_really_clobbers_lr (get_insns ())) - lr_save_eliminated = 1; - else - live_regs_mask |= 1 << LR_REGNUM; - } - - if (live_regs_mask) - { - /* If a di mode load/store multiple is used, and the base register - is r3, then r4 can become an ever live register without lr - doing so, in this case we need to push lr as well, or we - will fail to get a proper return. */ live_regs_mask |= 1 << LR_REGNUM; - lr_save_eliminated = 0; - } - if (lr_save_eliminated) - asm_fprintf (f,"\t%@ I don't think this function clobbers lr\n"); + if (live_regs_mask) + /* If a di mode load/store multiple is used, and the base register + is r3, then r4 can become an ever live register without lr + doing so, in this case we need to push lr as well, or we + will fail to get a proper return. */ + live_regs_mask |= 1 << LR_REGNUM; #ifdef AOF_ASSEMBLER if (flag_pic) @@ -6896,7 +6733,8 @@ output_arm_prologue (f, frame_size) } char * -arm_output_epilogue () +arm_output_epilogue (really_return) + int really_return; { int reg; int live_regs_mask = 0; @@ -6920,6 +6758,11 @@ arm_output_epilogue () R1; otherwise, it's in LR. */ return_regnum = eh_ofs ? 2 : LR_REGNUM; + /* If we are throwing an exception, then we really must be doing a return, + so we can't tail-call. */ + if (eh_ofs && ! really_return) + abort(); + /* A volatile function should never return. Call abort. */ if (TARGET_ABORT_NORETURN && volatile_func) { @@ -7010,17 +6853,22 @@ arm_output_epilogue () if (eh_ofs) asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, REGNO (eh_ofs)); - asm_fprintf (f, "\tbx\t%r\n", return_regnum); + if (really_return) + asm_fprintf (f, "\tbx\t%r\n", return_regnum); } - else if (eh_ofs) + else if (eh_ofs || ! really_return) { live_regs_mask |= 0x6800; print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE); - asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, - REGNO (eh_ofs)); - /* Even in 26-bit mode we do a mov (rather than a movs) because - we don't have the PSR bits set in the address. */ - asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); + if (eh_ofs) + { + asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, + REGNO (eh_ofs)); + /* Even in 26-bit mode we do a mov (rather than a movs) + because we don't have the PSR bits set in the + address. */ + asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); + } } else { @@ -7083,8 +6931,7 @@ arm_output_epilogue () { if (TARGET_INTERWORK) { - if (! lr_save_eliminated) - live_regs_mask |= 1 << LR_REGNUM; + live_regs_mask |= 1 << LR_REGNUM; /* Handle LR on its own. */ if (live_regs_mask == (1 << LR_REGNUM)) @@ -7104,12 +6951,9 @@ arm_output_epilogue () asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, REGNO (eh_ofs)); - asm_fprintf (f, "\tbx\t%r\n", return_regnum); + if (really_return) + asm_fprintf (f, "\tbx\t%r\n", return_regnum); } - else if (lr_save_eliminated) - asm_fprintf (f, - TARGET_APCS_32 ? "\tmov\t%r, %r\n" : "\tmovs\t%r, %r\n", - PC_REGNUM, LR_REGNUM); else if (eh_ofs) { if (live_regs_mask == 0) @@ -7123,8 +6967,13 @@ arm_output_epilogue () /* Jump to the target; even in 26-bit mode. */ asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); } - else if (TARGET_APCS_32 && live_regs_mask == 0) + else if (TARGET_APCS_32 && live_regs_mask == 0 && ! really_return) + asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM); + else if (TARGET_APCS_32 && live_regs_mask == 0 && really_return) asm_fprintf (f, "\tldr\t%r, [%r], #4\n", PC_REGNUM, SP_REGNUM); + else if (! really_return) + print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, + live_regs_mask | (1 << LR_REGNUM), FALSE); else print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask | (1 << PC_REGNUM), @@ -7135,8 +6984,7 @@ arm_output_epilogue () if (live_regs_mask || regs_ever_live[LR_REGNUM]) { /* Restore the integer regs, and the return address into lr. */ - if (! lr_save_eliminated) - live_regs_mask |= 1 << LR_REGNUM; + live_regs_mask |= 1 << LR_REGNUM; if (live_regs_mask == (1 << LR_REGNUM)) { @@ -7163,14 +7011,17 @@ arm_output_epilogue () if (eh_ofs) asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM, REGNO (eh_ofs)); - - /* And finally, go home. */ - if (TARGET_INTERWORK) - asm_fprintf (f, "\tbx\t%r\n", return_regnum); - else if (TARGET_APCS_32 || eh_ofs) - asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); - else - asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, return_regnum); + + if (really_return) + { + /* And finally, go home. */ + if (TARGET_INTERWORK) + asm_fprintf (f, "\tbx\t%r\n", return_regnum); + else if (TARGET_APCS_32 || eh_ofs) + asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum); + else + asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, return_regnum); + } } } diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 0bbf627d92d..d4c553f6b1e 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -66,9 +66,6 @@ extern char * arm_condition_codes[]; extern int arm_target_label; extern int arm_ccfsm_state; extern struct rtx_def * arm_target_insn; -extern int lr_save_eliminated; -/* This is needed by the tail-calling peepholes */ -extern int frame_pointer_needed; /* Run-time compilation parameters selecting different hardware subsets. */ extern int target_flags; /* The floating point instruction architecture, can be 2 or 3 */ @@ -540,6 +537,9 @@ extern int arm_arch5; /* Nonzero if this chip can benefit from load scheduling. */ extern int arm_ld_sched; +/* Nonzero if generating thumb code. */ +extern int thumb_code; + /* Nonzero if this chip is a StrongARM. */ extern int arm_is_strong; diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 67e053b4418..69e7c9bddb1 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -40,7 +40,7 @@ ;; Attributes -(define_attr "is_thumb" "no,yes" (const (symbol_ref "TARGET_ARM"))) +(define_attr "is_thumb" "no,yes" (const (symbol_ref "thumb_code"))) ; PROG_MODE attribute is used to determine whether condition codes are ; clobbered by a call insn: they are if in prog32 mode. This is controlled @@ -6024,7 +6024,8 @@ (match_operand:SI 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI 14))] - "TARGET_THUMB && operands[2] == const0_rtx && (GET_CODE (operands[0]) == SYMBOL_REF)" + "TARGET_THUMB + && operands[2] == const0_rtx && (GET_CODE (operands[0]) == SYMBOL_REF)" "bl\\t%a0" [(set_attr "length" "4") (set_attr "type" "call")] @@ -6036,12 +6037,79 @@ (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI 14))] - "TARGET_THUMB && operands[3] == const0_rtx && (GET_CODE (operands[1]) == SYMBOL_REF)" + "TARGET_THUMB + && operands[3] == const0_rtx && (GET_CODE (operands[1]) == SYMBOL_REF)" "bl\\t%a1" [(set_attr "length" "4") (set_attr "type" "call")] ) +;; We may also be able to do sibcalls for Thumb, but it's much harder... +(define_expand "sibcall" + [(parallel [(call (match_operand 0 "memory_operand" "") + (match_operand 1 "general_operand" "")) + (use (match_operand 2 "" ""))])] + "TARGET_ARM" + " + { + if (operands[2] == NULL_RTX) + operands[2] = const0_rtx; + + /* If we need to emit a long-call, we can't do it as a sibling call, + so fail over to a normal call. */ + if (arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0)) + { + emit_call_insn (gen_call (operands[0], operands[1], operands[2])); + DONE; + } + }" +) + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "register_operand" "") + (call (match_operand 1 "memory_operand" "") + (match_operand 2 "general_operand" ""))) + (use (match_operand 3 "" ""))])] + "TARGET_ARM" + " + { + if (operands[3] == NULL_RTX) + operands[3] = const0_rtx; + + /* If we need to emit a long-call, we can't do it as a sibling call, + so fail over to a normal call. */ + if (arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) + { + emit_call_insn (gen_call_value (operands[0], operands[1], operands[2], + operands[3])); + DONE; + } + }" +) + +(define_insn "*sibcall_insn" + [(call (mem:SI (match_operand:SI 0 "" "X")) + (match_operand 1 "" "")) + (use (match_operand 2 "" ""))] + "TARGET_ARM && GET_CODE (operands[0]) == SYMBOL_REF" + "* + return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\"; + " + [(set_attr "type" "call")] +) + +(define_insn "*sibcall_value_insn" + [(set (match_operand 0 "s_register_operand" "=rf") + (call (mem:SI (match_operand:SI 1 "" "X")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" ""))] + "TARGET_ARM && GET_CODE (operands[1]) == SYMBOL_REF" + "* + return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\"; + " + [(set_attr "type" "call")] +) + ;; Often the return insn will be the same as loading from memory, so set attr (define_insn "return" [(return)] @@ -7791,103 +7859,6 @@ return emit_stm_seq (operands, 2); ") -;; A call followed by return can be replaced by restoring the regs and -;; jumping to the subroutine, provided we aren't passing the address of -;; any of our local variables. If we call alloca then this is unsafe -;; since restoring the frame frees the memory, which is not what we want. -;; Sometimes the return might have been targeted by the final prescan: -;; if so then emit a proper return insn as well. -;; Unfortunately, if the frame pointer is required, we don't know if the -;; current function has any implicit stack pointer adjustments that will -;; be restored by the return: we can't therefore do a tail call. -;; Another unfortunate that we can't handle is if current_function_args_size -;; is non-zero: in this case elimination of the argument pointer assumed -;; that lr was pushed onto the stack, so eliminating upsets the offset -;; calculations. - -(define_peephole - [(parallel [(call (mem:SI (match_operand:SI 0 "" "X")) - (match_operand:SI 1 "general_operand" "g")) - (use (match_operand 2 "" "")) - (clobber (reg:SI 14))]) - (return)] - "TARGET_ARM - && (GET_CODE (operands[0]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) - && !get_frame_size () && !current_function_calls_alloca - && !frame_pointer_needed && !current_function_args_size)" - "* -{ - if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) - { - arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); - output_return_instruction (NULL, TRUE, FALSE); - arm_ccfsm_state = 0; - arm_target_insn = NULL; - } - - output_return_instruction (NULL, FALSE, FALSE); - return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\"; -}" -[(set_attr "type" "call") - (set_attr "length" "8")]) - -(define_peephole - [(parallel [(set (match_operand 0 "s_register_operand" "=rf") - (call (mem:SI (match_operand:SI 1 "" "X")) - (match_operand:SI 2 "general_operand" "g"))) - (use (match_operand 3 "" "")) - (clobber (reg:SI 14))]) - (return)] - "TARGET_ARM && (GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) - && !get_frame_size () && !current_function_calls_alloca - && !frame_pointer_needed && !current_function_args_size)" - "* -{ - if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) - { - arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); - output_return_instruction (NULL, TRUE, FALSE); - arm_ccfsm_state = 0; - arm_target_insn = NULL; - } - - output_return_instruction (NULL, FALSE, FALSE); - return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\"; -}" -[(set_attr "type" "call") - (set_attr "length" "8")]) - -;; As above but when this function is not void, we must be returning the -;; result of the called subroutine. - -(define_peephole - [(parallel [(set (match_operand 0 "s_register_operand" "=rf") - (call (mem:SI (match_operand:SI 1 "" "X")) - (match_operand:SI 2 "general_operand" "g"))) - (use (match_operand 3 "" "")) - (clobber (reg:SI 14))]) - (use (match_dup 0)) - (return)] - "TARGET_ARM - && (GET_CODE (operands[1]) == SYMBOL_REF && USE_RETURN_INSN (FALSE) - && !get_frame_size () && !current_function_calls_alloca - && !frame_pointer_needed && !current_function_args_size)" - "* -{ - if (arm_ccfsm_state && arm_target_insn && INSN_DELETED_P (arm_target_insn)) - { - arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc); - output_return_instruction (NULL, TRUE, FALSE); - arm_ccfsm_state = 0; - arm_target_insn = NULL; - } - - output_return_instruction (NULL, FALSE, FALSE); - return \"b%?\\t%a1\"; -}" -[(set_attr "type" "call") - (set_attr "length" "8")]) - (define_split [(set (match_operand:SI 0 "s_register_operand" "") (and:SI (ge:SI (match_operand:SI 1 "s_register_operand" "") @@ -7952,12 +7923,26 @@ " ) +(define_insn "sibcall_epilogue" + [(unspec_volatile [(const_int 0)] 1)] + "TARGET_ARM" + "* + output_asm_insn (\"%@ Sibcall epilogue\", operands); + if (USE_RETURN_INSN (FALSE)) + return output_return_instruction (NULL, FALSE, FALSE); + return arm_output_epilogue (FALSE); + " +;; Length is absolute worst case + [(set_attr "length" "44") + (set_attr "type" "block")] +) + (define_insn "*epilogue_insns" [(unspec_volatile [(return)] 1)] "TARGET_EITHER" "* if (TARGET_ARM) - return arm_output_epilogue (); + return arm_output_epilogue (TRUE); else /* TARGET_THUMB */ return thumb_unexpanded_epilogue (); " @@ -8094,26 +8079,17 @@ "TARGET_ARM" "* { - extern int lr_save_eliminated; int num_saves = XVECLEN (operands[2], 0); - if (lr_save_eliminated) - { - if (num_saves > 1) - abort (); - } /* For the StrongARM at least it is faster to use STR to store only a single register. */ - else if (num_saves == 1) + if (num_saves == 1) output_asm_insn (\"str\\t%1, [%m0, #-4]!\", operands); else { int i; char pattern[100]; - if (lr_save_eliminated) - abort (); - strcpy (pattern, \"stmfd\\t%m0!, {%1\"); for (i = 1; i < num_saves; i++) -- 2.11.4.GIT