mips.c (mips_expand_call): Use FAKE_CALL_REGNO.
authorRichard Sandiford <rsandifo@nildram.co.uk>
Thu, 18 Oct 2007 17:03:59 +0000 (17:03 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Thu, 18 Oct 2007 17:03:59 +0000 (17:03 +0000)
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

gcc/ChangeLog
gcc/config/mips/mips.c
gcc/config/mips/mips.md

index 125ae45..956f467 100644 (file)
@@ -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
index f9d559c..befb1fe 100644 (file)
@@ -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;
       }
index f4b90eb..53726e8 100644 (file)
         (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)"))
 ;; 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.