OSDN Git Service

PR bootstrap/13145
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Dec 2003 10:38:58 +0000 (10:38 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Dec 2003 10:38:58 +0000 (10:38 +0000)
* config/mips/mips.h (FIRST_PSEUDO_REGISTER): Adjust comment.
* config/mips/mips.c (mips_reg_names, mips_sw_reg_names): Add $fcall.
(mips_load_got): Always create a constant MEM.
(mips_expand_call): Use load_callsi and load_calldi.
* config/mips/mips.md (UNSPEC_LOAD_CALL, FAKE_CALL_REGNO): New consts.
(load_callsi, load_calldi): New patterns.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@74323 138bc75d-0d04-0410-961f-82ee72b054a4

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

index f78a834..824cb14 100644 (file)
@@ -1,3 +1,13 @@
+2003-12-05  Richard Sandiford  <rsandifo@redhat.com>
+
+       PR bootstrap/13145
+       * config/mips/mips.h (FIRST_PSEUDO_REGISTER): Adjust comment.
+       * config/mips/mips.c (mips_reg_names, mips_sw_reg_names): Add $fcall.
+       (mips_load_got): Always create a constant MEM.
+       (mips_expand_call): Use load_callsi and load_calldi.
+       * config/mips/mips.md (UNSPEC_LOAD_CALL, FAKE_CALL_REGNO): New consts.
+       (load_callsi, load_calldi): New patterns.
+
 2003-12-05  Peter Gerwinski <peter@gerwinski.de>
 
         * tree.def (PLACEHOLDER_EXPR): Clarify commentary.
index 0691941..f73b1a9 100644 (file)
@@ -569,7 +569,7 @@ char mips_reg_names[][8] =
  "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
  "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
  "hi",   "lo",   "",     "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
- "$fcc5","$fcc6","$fcc7","", "",     "",     "",     "",
+ "$fcc5","$fcc6","$fcc7","", "",     "",     "",     "$fakec",
  "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7",
  "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15",
  "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23",
@@ -598,7 +598,7 @@ char mips_sw_reg_names[][8] =
   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
   "hi",   "lo",   "",     "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
-  "$fcc5","$fcc6","$fcc7","$rap", "",     "",     "",     "",
+  "$fcc5","$fcc6","$fcc7","$rap", "",     "",     "",     "$fakec",
   "$c0r0", "$c0r1", "$c0r2", "$c0r3", "$c0r4", "$c0r5", "$c0r6", "$c0r7",
   "$c0r8", "$c0r9", "$c0r10","$c0r11","$c0r12","$c0r13","$c0r14","$c0r15",
   "$c0r16","$c0r17","$c0r18","$c0r19","$c0r20","$c0r21","$c0r22","$c0r23",
@@ -1658,14 +1658,10 @@ mips_load_got (rtx base, rtx addr, enum mips_symbol_type symbol_type)
   mem = gen_rtx_MEM (ptr_mode, gen_rtx_LO_SUM (Pmode, base, offset));
   set_mem_alias_set (mem, mips_got_alias_set);
 
-  /* GOT references can't trap.  */
+  /* GOT entries are constant and references to them can't trap.  */
+  RTX_UNCHANGING_P (mem) = 1;
   MEM_NOTRAP_P (mem) = 1;
 
-  /* If we allow a function's address to be lazily bound, its entry
-     may change after the first call.  Other entries are constant.  */
-  if (symbol_type != SYMBOL_GOTOFF_CALL)
-    RTX_UNCHANGING_P (mem) = 1;
-
   return mem;
 }
 
@@ -3193,11 +3189,19 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, int sibcall_p)
     {
       if (TARGET_EXPLICIT_RELOCS && global_got_operand (addr, VOIDmode))
        {
-         rtx high = mips_unspec_offset_high (pic_offset_table_rtx,
-                                             addr, SYMBOL_GOTOFF_CALL);
-         addr = mips_load_got (high, addr, SYMBOL_GOTOFF_CALL);
+         rtx high, lo_sum_symbol;
+
+         high = mips_unspec_offset_high (pic_offset_table_rtx,
+                                         addr, SYMBOL_GOTOFF_CALL);
+         lo_sum_symbol = mips_unspec_address (addr, SYMBOL_GOTOFF_CALL);
+         addr = gen_reg_rtx (Pmode);
+         if (Pmode == SImode)
+           emit_insn (gen_load_callsi (addr, high, lo_sum_symbol));
+         else
+           emit_insn (gen_load_calldi (addr, high, lo_sum_symbol));
        }
-      addr = force_reg (Pmode, addr);
+      else
+       addr = force_reg (Pmode, addr);
     }
 
   if (TARGET_MIPS16
index ac69384..e144d64 100644 (file)
@@ -1468,7 +1468,8 @@ extern const struct mips_cpu_info *mips_tune_info;
    - 8 condition code registers
    - 2 accumulator registers (hi and lo)
    - 32 registers each for coprocessors 0, 2 and 3
-   - 6 dummy entries that were used at various times in the past.  */
+   - FAKE_CALL_REGNO (see the comment above load_callsi for details)
+   - 5 dummy entries that were used at various times in the past.  */
 
 #define FIRST_PSEUDO_REGISTER 176
 
index 203ac2e..5b758c8 100644 (file)
    (UNSPEC_SDL                 24)
    (UNSPEC_SDR                 25)
    (UNSPEC_LOADGP              26)
+   (UNSPEC_LOAD_CALL           27)
 
-   (UNSPEC_ADDRESS_FIRST       100)])
+   (UNSPEC_ADDRESS_FIRST       100)
+
+   (FAKE_CALL_REGNO            79)])
 \f
 ;; ....................
 ;;
@@ -8331,6 +8334,42 @@ ld\t%2,%1-%S1(%2)\;daddu\t%2,%2,$31\;%*j\t%2%/"
 ;;
 ;;  ....................
 
+;; Instructions to load a call address from the GOT.  The address might
+;; point to a function or to a lazy binding stub.  In the latter case,
+;; the stub will use the dynamic linker to resolve the function, which
+;; in turn will change the GOT entry to point to the function's real
+;; address.
+;;
+;; This means that every call, even pure and constant ones, can
+;; potentially modify the GOT entry.  And once a stub has been called,
+;; 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.
+(define_insn "load_callsi"
+  [(set (match_operand:SI 0 "register_operand" "=c")
+       (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+                   (match_operand:SI 2 "immediate_operand" "")
+                   (reg:SI FAKE_CALL_REGNO)]
+                  UNSPEC_LOAD_CALL))]
+  "TARGET_ABICALLS"
+  "lw\t%0,%R2(%1)"
+  [(set_attr "type" "load")
+   (set_attr "length" "4")])
+
+(define_insn "load_calldi"
+  [(set (match_operand:DI 0 "register_operand" "=c")
+       (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+                   (match_operand:DI 2 "immediate_operand" "")
+                   (reg:DI FAKE_CALL_REGNO)]
+                  UNSPEC_LOAD_CALL))]
+  "TARGET_ABICALLS"
+  "ld\t%0,%R2(%1)"
+  [(set_attr "type" "load")
+   (set_attr "length" "4")])
+
 ;; Sibling calls.  All these patterns use jump instructions.
 
 ;; If TARGET_SIBCALLS, call_insn_operand will only accept constant