From 822ba114ef720cf4b734cdf4f224cfdf42df29a5 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Mon, 22 Oct 2007 20:09:07 +0000 Subject: [PATCH] backport: mips.c (mips_expand_call): Use FAKE_CALL_REGNO. gcc/ Backport from mainline: 2007-10-18 Richard Sandiford * config/mips/mips.c (mips_expand_call): Use FAKE_CALL_REGNO. (mips_avoid_hazard): Allow multiple sets for HAZARD_DELAY, and pick the first. * config/mips/mips.md (load_call): Don't make the unspec depend on FAKE_CALL_REGNO. Set FAKE_CALL_REGNO. From-SVN: r129558 --- gcc/ChangeLog | 12 ++++++++++++ gcc/config/mips/mips.c | 42 ++++++++++++++++++++++++++++++----------- gcc/config/mips/mips.md | 25 ++++++++++++++++++------ 3 files changed, 62 insertions(+), 17 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 38279fe60f9c..deaab711885f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2007-10-22 Richard Sandiford + + Backport from mainline: + + 2007-10-18 Richard Sandiford + + * config/mips/mips.c (mips_expand_call): Use FAKE_CALL_REGNO. + (mips_avoid_hazard): Allow multiple sets for HAZARD_DELAY, + and pick the first. + * config/mips/mips.md (load_call): Don't make the unspec + depend on FAKE_CALL_REGNO. Set FAKE_CALL_REGNO. + 2007-10-20 Jakub Jelinek * config/rs6000/linux-unwind.h (ppc_fallback_frame_state): Point diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 19b732182dba..c1f6a4d2a012 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -289,7 +289,7 @@ static int m16_check_op (rtx, int, int, int); static bool mips_rtx_costs (rtx, int, int, int *); static int mips_address_cost (rtx); static void mips_emit_compare (enum rtx_code *, rtx *, rtx *, bool); -static void mips_load_call_address (rtx, rtx, int); +static bool mips_load_call_address (rtx, rtx, int); static bool mips_function_ok_for_sibcall (tree, tree); static void mips_block_move_straight (rtx, rtx, HOST_WIDE_INT); static void mips_adjust_block_mem (rtx, HOST_WIDE_INT, rtx *, rtx *); @@ -3371,9 +3371,10 @@ mips_gen_conditional_trap (rtx *operands) } /* Load function address ADDR into register DEST. SIBCALL_P is true - if the address is needed for a sibling call. */ + if the address is needed for a sibling call. Return true if we + used an explicit lazy-binding sequence. */ -static void +static bool mips_load_call_address (rtx dest, rtx addr, int sibcall_p) { /* If we're generating PIC, and this call is to a global function, @@ -3393,9 +3394,13 @@ mips_load_call_address (rtx dest, rtx addr, int sibcall_p) emit_insn (gen_load_callsi (dest, high, lo_sum_symbol)); else emit_insn (gen_load_calldi (dest, high, lo_sum_symbol)); + return true; } else - emit_move_insn (dest, addr); + { + emit_move_insn (dest, addr); + return false; + } } @@ -3410,12 +3415,14 @@ void mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p) { rtx orig_addr, pattern, insn; + bool lazy_p; orig_addr = addr; + lazy_p = false; if (!call_insn_operand (addr, VOIDmode)) { addr = gen_reg_rtx (Pmode); - mips_load_call_address (addr, orig_addr, sibcall_p); + lazy_p = mips_load_call_address (addr, orig_addr, sibcall_p); } if (TARGET_MIPS16 @@ -3446,9 +3453,15 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p) insn = emit_call_insn (pattern); - /* Lazy-binding stubs require $gp to be valid on entry. */ - if (global_got_operand (orig_addr, VOIDmode)) - use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); + /* Lazy-binding stubs require $gp to be valid on entry. We also pretend + that they use FAKE_CALL_REGNO; see the load_call patterns for + details. */ + if (lazy_p) + { + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), + gen_rtx_REG (Pmode, FAKE_CALL_REGNO)); + } } @@ -8973,7 +8986,7 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay, rtx *delayed_reg, rtx lo_reg) { rtx pattern, set; - int nops, ninsns; + int nops, ninsns, hazard_set; if (!INSN_P (insn)) return; @@ -9022,8 +9035,15 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay, break; case HAZARD_DELAY: - set = single_set (insn); - gcc_assert (set != 0); + hazard_set = (int) get_attr_hazard_set (insn); + if (hazard_set == 0) + set = single_set (insn); + else + { + gcc_assert (GET_CODE (PATTERN (insn)) == PARALLEL); + set = XVECEXP (PATTERN (insn), 0, hazard_set - 1); + } + gcc_assert (set && GET_CODE (set) == SET); *delayed_reg = SET_DEST (set); break; } diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 87a36c6be3f1..ccb75cbf3127 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -370,6 +370,17 @@ (const_string "hilo")] (const_string "none"))) +;; Indicates which SET in an instruction pattern induces a hazard. +;; Only meaningful when "hazard" is not "none". SINGLE means that +;; the pattern has only one set while the other values are indexes +;; into a PARALLEL vector. +;; +;; Hazardous instructions with multiple sets should generally put the +;; hazardous set first. The only purpose of this attribute is to force +;; each multi-set pattern to explicitly assert that this condition holds. +(define_attr "hazard_set" "single,0" + (const_string "single")) + ;; Is it a single instruction? (define_attr "single_insn" "no,yes" (symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)")) @@ -5045,19 +5056,21 @@ ;; we must not call it again. ;; ;; We represent this restriction using an imaginary fixed register that -;; acts like a GOT version number. By making the register call-clobbered, -;; we tell the target-independent code that the address could be changed -;; by any call insn. +;; is set by the GOT load and used by the call. By making this register +;; call-clobbered, and by making the GOT load the only way of setting +;; the register, we ensure that the load cannot be moved past a call. (define_insn "load_call" [(set (match_operand:P 0 "register_operand" "=c") (unspec:P [(match_operand:P 1 "register_operand" "r") - (match_operand:P 2 "immediate_operand" "") - (reg:P FAKE_CALL_REGNO)] - UNSPEC_LOAD_CALL))] + (match_operand:P 2 "immediate_operand" "")] + UNSPEC_LOAD_CALL)) + (set (reg:P FAKE_CALL_REGNO) + (unspec:P [(match_dup 2)] UNSPEC_LOAD_CALL))] "TARGET_ABICALLS" "\t%0,%R2(%1)" [(set_attr "type" "load") (set_attr "mode" "") + (set_attr "hazard_set" "0") (set_attr "length" "4")]) ;; Sibling calls. All these patterns use jump instructions. -- 2.47.2