From 764678d17d7e22a3b5d087b3f3e1d9a518df9a22 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Sun, 2 May 2004 04:57:47 +0000 Subject: [PATCH] frv-protos.h (frv_expand_epilogue, [...]): Add bool argument. * config/frv/frv-protos.h (frv_expand_epilogue, frv_expand_fdpic_call): Add bool argument. * config/frv/frv.c (frv_function_ok_for_sibcall): New. (TARGET_FUNCTION_OK_FOR_SIBCALL): Define to it. (frv_expand_epilogue): Use new argument to decide whether to emit return instruction or copy the return address to LR. (frv_expand_fdpic_call): Inline PLT entry when emitting direct sibcalls. (sibcall_operand): New. * config/frv/frv.h (PREDICATE_CODES): call_operand doesn't match PLUS nor LABEL_REF. Add sibcall_operand. * config/frv/frv.md (call, call_value): Pass false to frv_expand_fdpic_call. (call_fdpicdi, call_value_fdpicdi): Insert %i0 in calll. (sibcall, sibcall_internal, sibcall_fdpicdi, sibcall_value, sibcall_value_internal, sibcall_value_fdpicdi): New. (return_unsigned_true, return_unsigned_false): New. (epilogue): Adjust call to frv_expand_epilogue. (sibcall_epilogue): New. From-SVN: r81405 --- gcc/ChangeLog | 20 +++++ gcc/config/frv/frv-protos.h | 4 +- gcc/config/frv/frv.c | 61 ++++++++++++--- gcc/config/frv/frv.h | 6 +- gcc/config/frv/frv.md | 145 ++++++++++++++++++++++++++++++++++-- 5 files changed, 217 insertions(+), 19 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c2373755047..fb929086eed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,25 @@ 2004-05-02 Alexandre Oliva + * config/frv/frv-protos.h (frv_expand_epilogue, + frv_expand_fdpic_call): Add bool argument. + * config/frv/frv.c (frv_function_ok_for_sibcall): New. + (TARGET_FUNCTION_OK_FOR_SIBCALL): Define to it. + (frv_expand_epilogue): Use new argument to decide whether to emit + return instruction or copy the return address to LR. + (frv_expand_fdpic_call): Inline PLT entry when emitting direct + sibcalls. + (sibcall_operand): New. + * config/frv/frv.h (PREDICATE_CODES): call_operand doesn't match + PLUS nor LABEL_REF. Add sibcall_operand. + * config/frv/frv.md (call, call_value): Pass false to + frv_expand_fdpic_call. + (call_fdpicdi, call_value_fdpicdi): Insert %i0 in calll. + (sibcall, sibcall_internal, sibcall_fdpicdi, sibcall_value, + sibcall_value_internal, sibcall_value_fdpicdi): New. + (return_unsigned_true, return_unsigned_false): New. + (epilogue): Adjust call to frv_expand_epilogue. + (sibcall_epilogue): New. + * config/frv/frv.h (ASM_SPEC): Pass -mno-fdpic as -mnopic. (CPP_SPEC, CPP_SIMPLE_SPEC): Undefine __FRV_ACC__ and __FRV_FPR__ before redefining them. diff --git a/gcc/config/frv/frv-protos.h b/gcc/config/frv/frv-protos.h index 642635090d0..3a0e386d25d 100644 --- a/gcc/config/frv/frv-protos.h +++ b/gcc/config/frv/frv-protos.h @@ -53,7 +53,7 @@ extern frv_cpu_t frv_cpu_type; /* value of -mcpu= */ /* Define functions defined in frv.c */ extern void frv_expand_prologue (void); -extern void frv_expand_epilogue (int); +extern void frv_expand_epilogue (bool); extern void frv_override_options (void); extern void frv_optimization_options (int, int); extern void frv_conditional_register_usage (void); @@ -225,7 +225,7 @@ extern int even_acc_operand (rtx, enum machine_mode); extern int quad_acc_operand (rtx, enum machine_mode); extern int accg_operand (rtx, enum machine_mode); extern rtx frv_matching_accg_for_acc (rtx); -extern void frv_expand_fdpic_call (rtx *, int); +extern void frv_expand_fdpic_call (rtx *, bool, bool); extern rtx frv_gen_GPsym2reg (rtx, rtx); #endif diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c index d5808bfa7ac..92e0dd213fa 100644 --- a/gcc/config/frv/frv.c +++ b/gcc/config/frv/frv.c @@ -285,6 +285,7 @@ static bool frv_cannot_force_const_mem (rtx); static const char *unspec_got_name (int); static void frv_output_const_unspec (FILE *, const struct frv_unspec *); +static bool frv_function_ok_for_sibcall (tree, tree); static rtx frv_struct_value_rtx (tree, int); /* Initialize the GCC target structure. */ @@ -319,6 +320,8 @@ static rtx frv_struct_value_rtx (tree, int); #undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE #define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE frv_use_dfa_pipeline_interface +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL frv_function_ok_for_sibcall #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM frv_cannot_force_const_mem @@ -332,6 +335,16 @@ static rtx frv_struct_value_rtx (tree, int); struct gcc_target targetm = TARGET_INITIALIZER; +/* Any function call that satisfies the machine-independent + requirements is eligible on FR-V. */ + +static bool +frv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, + tree exp ATTRIBUTE_UNUSED) +{ + return true; +} + /* Return true if SYMBOL is a small data symbol and relocation RELOC can be used to access it directly in a load or store. */ @@ -1749,7 +1762,7 @@ frv_function_epilogue (FILE *file ATTRIBUTE_UNUSED, slots for arguments passed to the current function. */ void -frv_expand_epilogue (int sibcall_p) +frv_expand_epilogue (bool emit_return) { frv_stack_t *info = frv_stack_info (); rtx fp = frame_pointer_rtx; @@ -1769,9 +1782,7 @@ frv_expand_epilogue (int sibcall_p) /* Set RETURN_ADDR to the address we should return to. Set it to NULL if no return instruction should be emitted. */ - if (sibcall_p) - return_addr = 0; - else if (info->save_p[LR_REGNO]) + if (info->save_p[LR_REGNO]) { int lr_offset; rtx mem; @@ -1814,8 +1825,20 @@ frv_expand_epilogue (int sibcall_p) if (current_function_calls_eh_return) emit_insn (gen_stack_adjust (sp, sp, EH_RETURN_STACKADJ_RTX)); - if (return_addr) + if (emit_return) emit_jump_insn (gen_epilogue_return (return_addr)); + else + { + rtx lr = return_addr; + + if (REGNO (return_addr) != LR_REGNO) + { + lr = gen_rtx_REG (Pmode, LR_REGNO); + emit_move_insn (lr, return_addr); + } + + emit_insn (gen_rtx_USE (VOIDmode, lr)); + } } @@ -3529,7 +3552,7 @@ frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p) } void -frv_expand_fdpic_call (rtx *operands, int ret_value) +frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall) { rtx lr = gen_rtx_REG (Pmode, LR_REGNO); rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REG); @@ -3565,8 +3588,9 @@ frv_expand_fdpic_call (rtx *operands, int ret_value) all external functions, so one would have to also mark function declarations available in the same module with non-default visibility, which is advantageous in itself. */ - if (GET_CODE (addr) == SYMBOL_REF && !SYMBOL_REF_LOCAL_P (addr) - && TARGET_INLINE_PLT) + if (GET_CODE (addr) == SYMBOL_REF + && ((!SYMBOL_REF_LOCAL_P (addr) && TARGET_INLINE_PLT) + || sibcall)) { rtx x, dest; dest = gen_reg_rtx (SImode); @@ -3598,7 +3622,11 @@ frv_expand_fdpic_call (rtx *operands, int ret_value) picreg = gen_reg_rtx (DImode); emit_insn (gen_movdi_ldd (picreg, addr)); - if (ret_value) + if (sibcall && ret_value) + c = gen_sibcall_value_fdpicdi (rvrtx, picreg, const0_rtx); + else if (sibcall) + c = gen_sibcall_fdpicdi (picreg, const0_rtx); + else if (ret_value) c = gen_call_value_fdpicdi (rvrtx, picreg, const0_rtx, lr); else c = gen_call_fdpicdi (picreg, const0_rtx, lr); @@ -4766,6 +4794,21 @@ call_operand (rtx op, enum machine_mode mode) return gpr_or_int12_operand (op, mode); } +/* Return true if operand is a memory reference suitable for a sibcall. */ + +int +sibcall_operand (rtx op, enum machine_mode mode) +{ + if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT) + return FALSE; + + /* Note this doesn't allow reg+reg or reg+imm12 addressing (which should + never occur anyway), but prevents reload from not handling the case + properly of a call through a pointer on a function that calls + vfork/setjmp, etc. due to the need to flush all of the registers to stack. */ + return gpr_or_int12_operand (op, mode); +} + /* Return true if operator is a kind of relational operator. */ int diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h index 438fbfef488..e6baec07973 100644 --- a/gcc/config/frv/frv.h +++ b/gcc/config/frv/frv.h @@ -3111,8 +3111,10 @@ do { \ { "odd_fpr_operand", { REG, SUBREG }}, \ { "dbl_memory_one_insn_operand", { MEM }}, \ { "dbl_memory_two_insn_operand", { MEM }}, \ - { "call_operand", { REG, SUBREG, PLUS, CONST_INT, \ - SYMBOL_REF, LABEL_REF, CONST }}, \ + { "call_operand", { REG, SUBREG, CONST_INT, \ + CONST, SYMBOL_REF }}, \ + { "sibcall_operand", { REG, SUBREG, CONST_INT, \ + CONST }}, \ { "upper_int16_operand", { CONST_INT }}, \ { "uint16_operand", { CONST_INT }}, \ { "relational_operator", { EQ, NE, LE, LT, GE, GT, \ diff --git a/gcc/config/frv/frv.md b/gcc/config/frv/frv.md index 20170bd4123..36b6d8e7afc 100644 --- a/gcc/config/frv/frv.md +++ b/gcc/config/frv/frv.md @@ -5260,7 +5260,7 @@ operands[2] = const0_rtx; if (TARGET_FDPIC) - frv_expand_fdpic_call (operands, 0); + frv_expand_fdpic_call (operands, false, false); else emit_call_insn (gen_call_internal (addr, operands[1], operands[2], lr)); @@ -5308,7 +5308,7 @@ (match_operand 1 "" "")) (clobber (match_operand:SI 2 "lr_operand" "=l"))] "TARGET_FDPIC" - "calll %M0" + "call%i0l %M0" [(set_attr "length" "4") (set_attr "type" "jumpl")]) @@ -5325,6 +5325,65 @@ [(set_attr "length" "4") (set_attr "type" "call,jumpl")]) +(define_expand "sibcall" + [(use (match_operand:QI 0 "" "")) + (use (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" ""))] + "" + " +{ + rtx addr; + + if (GET_CODE (operands[0]) != MEM) + abort (); + + addr = XEXP (operands[0], 0); + if (! sibcall_operand (addr, Pmode)) + addr = force_reg (Pmode, addr); + + if (! operands[2]) + operands[2] = const0_rtx; + + if (TARGET_FDPIC) + frv_expand_fdpic_call (operands, false, true); + else + emit_call_insn (gen_sibcall_internal (addr, operands[1], operands[2])); + + DONE; +}") + +;; It might seem that these sibcall patterns are missing references to +;; LR, but they're not necessary because sibcall_epilogue will make +;; sure LR is restored, and having LR here will set +;; regs_ever_used[REG_LR], forcing it to be saved on the stack, and +;; then restored in sibcalls and regular return code paths, even if +;; the function becomes a leaf function after tail-call elimination. + +;; We must not use a call-saved register here. `W' limits ourselves +;; to gr14 or gr15, but since we're almost running out of constraint +;; letters, and most other call-clobbered registers are often used for +;; argument-passing, this will do. +(define_insn "sibcall_internal" + [(call (mem:QI (match_operand:SI 0 "sibcall_operand" "WNOP")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (return)] + "! TARGET_FDPIC" + "jmp%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "sibcall_fdpicdi" + [(call (mem:QI (match_operand:DI 0 "fdpic_fptr_operand" "W")) + (match_operand 1 "" "")) + (return)] + "TARGET_FDPIC" + "jmp%i0l %M0" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + + ;; Subroutine call instruction returning a value. Operand 0 is the hard ;; register in which the value is returned. There are three more operands, the ;; same as the three operands of the `call' instruction (but with numbers @@ -5355,7 +5414,7 @@ operands[3] = const0_rtx; if (TARGET_FDPIC) - frv_expand_fdpic_call (operands, 1); + frv_expand_fdpic_call (operands, true, false); else emit_call_insn (gen_call_value_internal (operands[0], addr, operands[2], operands[3], lr)); @@ -5382,7 +5441,7 @@ (match_operand 2 "" ""))) (clobber (match_operand:SI 3 "lr_operand" "=l"))] "TARGET_FDPIC" - "calll %M1" + "call%i1l %M1" [(set_attr "length" "4") (set_attr "type" "jumpl")]) @@ -5400,6 +5459,56 @@ [(set_attr "length" "4") (set_attr "type" "call,jumpl")]) +(define_expand "sibcall_value" + [(use (match_operand 0 "" "")) + (use (match_operand:QI 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (use (match_operand 4 "" ""))] + "" + " +{ + rtx addr; + + if (GET_CODE (operands[1]) != MEM) + abort (); + + addr = XEXP (operands[1], 0); + if (! sibcall_operand (addr, Pmode)) + addr = force_reg (Pmode, addr); + + if (! operands[3]) + operands[3] = const0_rtx; + + if (TARGET_FDPIC) + frv_expand_fdpic_call (operands, true, true); + else + emit_call_insn (gen_sibcall_value_internal (operands[0], addr, operands[2], + operands[3])); + DONE; +}") + +(define_insn "sibcall_value_internal" + [(set (match_operand 0 "register_operand" "=d") + (call (mem:QI (match_operand:SI 1 "sibcall_operand" "WNOP")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (return)] + "! TARGET_FDPIC" + "jmp%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + +(define_insn "sibcall_value_fdpicdi" + [(set (match_operand 0 "register_operand" "=d") + (call (mem:QI (match_operand:DI 1 "fdpic_fptr_operand" "W")) + (match_operand 2 "" ""))) + (return)] + "TARGET_FDPIC" + "jmp%i1l %M1" + [(set_attr "length" "4") + (set_attr "type" "jumpl")]) + ;; return instruction generated instead of jmp to epilog (define_expand "return" [(parallel [(return) @@ -5430,6 +5539,30 @@ [(set_attr "length" "4") (set_attr "type" "jump,jumpl")]) +(define_insn "*return_unsigned_true" + [(set (pc) + (if_then_else (match_operator:CC_UNS 0 "unsigned_relational_operator" + [(match_operand 1 "icc_operand" "t") + (const_int 0)]) + (return) + (pc)))] + "direct_return_p ()" + "b%c0lr %1,%#" + [(set_attr "length" "4") + (set_attr "type" "jump")]) + +(define_insn "*return_unsigned_false" + [(set (pc) + (if_then_else (match_operator:CC_UNS 0 "unsigned_relational_operator" + [(match_operand 1 "icc_operand" "t") + (const_int 0)]) + (pc) + (return)))] + "direct_return_p ()" + "b%C0lr %1,%#" + [(set_attr "length" "4") + (set_attr "type" "jump")]) + ;; A version of addsi3 for deallocating stack space at the end of the ;; epilogue. The addition is done in parallel with an (unspec_volatile), ;; which represents the clobbering of the deallocated space. @@ -5634,7 +5767,7 @@ "" " { - frv_expand_epilogue (FALSE); + frv_expand_epilogue (true); DONE; }") @@ -5650,7 +5783,7 @@ "" " { - frv_expand_epilogue (TRUE); + frv_expand_epilogue (false); DONE; }") -- 2.30.2