Commit e8b7a137 by Richard Sandiford Committed by Richard Sandiford

mips.c (mips_expand_call): Use FAKE_CALL_REGNO.

gcc/
	* 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<mode>): Don't make the unspec
	depend on FAKE_CALL_REGNO.  Set FAKE_CALL_REGNO.

From-SVN: r129449
parent e34537aa
2007-10-18 Richard Sandiford <rsandifo@nildram.co.uk>
* 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<mode>): Don't make the unspec
depend on FAKE_CALL_REGNO. Set FAKE_CALL_REGNO.
2007-10-18 David Daney <ddaney@avtrex.com> 2007-10-18 David Daney <ddaney@avtrex.com>
* config/mips/linux-unwind.h (mips_fallback_frame_state): Use new * config/mips/linux-unwind.h (mips_fallback_frame_state): Use new
...@@ -308,7 +308,7 @@ static int m16_check_op (rtx, int, int, int); ...@@ -308,7 +308,7 @@ static int m16_check_op (rtx, int, int, int);
static bool mips_rtx_costs (rtx, int, int, int *); static bool mips_rtx_costs (rtx, int, int, int *);
static int mips_address_cost (rtx); static int mips_address_cost (rtx);
static void mips_emit_compare (enum rtx_code *, rtx *, rtx *, bool); 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 bool mips_function_ok_for_sibcall (tree, tree);
static void mips_block_move_straight (rtx, rtx, HOST_WIDE_INT); static void mips_block_move_straight (rtx, rtx, HOST_WIDE_INT);
static void mips_adjust_block_mem (rtx, HOST_WIDE_INT, rtx *, rtx *); static void mips_adjust_block_mem (rtx, HOST_WIDE_INT, rtx *, rtx *);
...@@ -4135,9 +4135,10 @@ mips_ok_for_lazy_binding_p (rtx x) ...@@ -4135,9 +4135,10 @@ mips_ok_for_lazy_binding_p (rtx x)
} }
/* Load function address ADDR into register DEST. SIBCALL_P is true /* 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) mips_load_call_address (rtx dest, rtx addr, int sibcall_p)
{ {
/* If we're generating PIC, and this call is to a global function, /* If we're generating PIC, and this call is to a global function,
...@@ -4157,9 +4158,13 @@ mips_load_call_address (rtx dest, rtx addr, int sibcall_p) ...@@ -4157,9 +4158,13 @@ mips_load_call_address (rtx dest, rtx addr, int sibcall_p)
emit_insn (gen_load_callsi (dest, high, lo_sum_symbol)); emit_insn (gen_load_callsi (dest, high, lo_sum_symbol));
else else
emit_insn (gen_load_calldi (dest, high, lo_sum_symbol)); emit_insn (gen_load_calldi (dest, high, lo_sum_symbol));
return true;
} }
else else
mips_emit_move (dest, addr); {
mips_emit_move (dest, addr);
return false;
}
} }
...@@ -4174,12 +4179,14 @@ void ...@@ -4174,12 +4179,14 @@ void
mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p) mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
{ {
rtx orig_addr, pattern, insn; rtx orig_addr, pattern, insn;
bool lazy_p;
orig_addr = addr; orig_addr = addr;
lazy_p = false;
if (!call_insn_operand (addr, VOIDmode)) if (!call_insn_operand (addr, VOIDmode))
{ {
addr = gen_reg_rtx (Pmode); 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 if (TARGET_MIPS16
...@@ -4210,9 +4217,15 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p) ...@@ -4210,9 +4217,15 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
insn = emit_call_insn (pattern); insn = emit_call_insn (pattern);
/* Lazy-binding stubs require $gp to be valid on entry. */ /* Lazy-binding stubs require $gp to be valid on entry. We also pretend
if (mips_ok_for_lazy_binding_p (orig_addr)) that they use FAKE_CALL_REGNO; see the load_call<mode> patterns for
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx); 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));
}
} }
...@@ -10748,7 +10761,7 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay, ...@@ -10748,7 +10761,7 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
rtx *delayed_reg, rtx lo_reg) rtx *delayed_reg, rtx lo_reg)
{ {
rtx pattern, set; rtx pattern, set;
int nops, ninsns; int nops, ninsns, hazard_set;
if (!INSN_P (insn)) if (!INSN_P (insn))
return; return;
...@@ -10797,8 +10810,15 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay, ...@@ -10797,8 +10810,15 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
break; break;
case HAZARD_DELAY: case HAZARD_DELAY:
set = single_set (insn); hazard_set = (int) get_attr_hazard_set (insn);
gcc_assert (set != 0); 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); *delayed_reg = SET_DEST (set);
break; break;
} }
......
...@@ -438,6 +438,17 @@ ...@@ -438,6 +438,17 @@
(const_string "hilo")] (const_string "hilo")]
(const_string "none"))) (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? ;; Is it a single instruction?
(define_attr "single_insn" "no,yes" (define_attr "single_insn" "no,yes"
(symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)")) (symbol_ref "get_attr_length (insn) == (TARGET_MIPS16 ? 2 : 4)"))
...@@ -5606,19 +5617,21 @@ ...@@ -5606,19 +5617,21 @@
;; we must not call it again. ;; we must not call it again.
;; ;;
;; We represent this restriction using an imaginary fixed register that ;; We represent this restriction using an imaginary fixed register that
;; acts like a GOT version number. By making the register call-clobbered, ;; is set by the GOT load and used by the call. By making this register
;; we tell the target-independent code that the address could be changed ;; call-clobbered, and by making the GOT load the only way of setting
;; by any call insn. ;; the register, we ensure that the load cannot be moved past a call.
(define_insn "load_call<mode>" (define_insn "load_call<mode>"
[(set (match_operand:P 0 "register_operand" "=d") [(set (match_operand:P 0 "register_operand" "=d")
(unspec:P [(match_operand:P 1 "register_operand" "r") (unspec:P [(match_operand:P 1 "register_operand" "r")
(match_operand:P 2 "immediate_operand" "") (match_operand:P 2 "immediate_operand" "")]
(reg:P FAKE_CALL_REGNO)] UNSPEC_LOAD_CALL))
UNSPEC_LOAD_CALL))] (set (reg:P FAKE_CALL_REGNO)
(unspec:P [(match_dup 2)] UNSPEC_LOAD_CALL))]
"TARGET_USE_GOT" "TARGET_USE_GOT"
"<load>\t%0,%R2(%1)" "<load>\t%0,%R2(%1)"
[(set_attr "type" "load") [(set_attr "type" "load")
(set_attr "mode" "<MODE>") (set_attr "mode" "<MODE>")
(set_attr "hazard_set" "0")
(set_attr "length" "4")]) (set_attr "length" "4")])
;; Sibling calls. All these patterns use jump instructions. ;; Sibling calls. All these patterns use jump instructions.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment