aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@nildram.co.uk>2007-10-18 17:03:59 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2007-10-18 17:03:59 +0000
commite8b7a1372c940ebd8e6db448efeb6386d4c1c206 (patch)
tree629ac7ece722e175279e37850a6234c784b3968a /gcc
parente34537aa38200164919385f3b6cdf460790ed9d6 (diff)
downloadgcc-e8b7a1372c940ebd8e6db448efeb6386d4c1c206.zip
gcc-e8b7a1372c940ebd8e6db448efeb6386d4c1c206.tar.gz
gcc-e8b7a1372c940ebd8e6db448efeb6386d4c1c206.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/mips/mips.c42
-rw-r--r--gcc/config/mips/mips.md25
3 files changed, 58 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 125ae45..956f467 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+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>
* config/mips/linux-unwind.h (mips_fallback_frame_state): Use new
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index f9d559c..befb1fe4 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -308,7 +308,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 *);
@@ -4135,9 +4135,10 @@ mips_ok_for_lazy_binding_p (rtx x)
}
/* 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,
@@ -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));
else
emit_insn (gen_load_calldi (dest, high, lo_sum_symbol));
+ return true;
}
else
- mips_emit_move (dest, addr);
+ {
+ mips_emit_move (dest, addr);
+ return false;
+ }
}
@@ -4174,12 +4179,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
@@ -4210,9 +4217,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 (mips_ok_for_lazy_binding_p (orig_addr))
- 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<mode> 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));
+ }
}
@@ -10748,7 +10761,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;
@@ -10797,8 +10810,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 f4b90eb..53726e8 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -438,6 +438,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)"))
@@ -5606,19 +5617,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<mode>"
[(set (match_operand:P 0 "register_operand" "=d")
(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_USE_GOT"
"<load>\t%0,%R2(%1)"
[(set_attr "type" "load")
(set_attr "mode" "<MODE>")
+ (set_attr "hazard_set" "0")
(set_attr "length" "4")])
;; Sibling calls. All these patterns use jump instructions.