"$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",
"$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",
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;
}
{
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
(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
;; ....................
;;
;;
;; ....................
+;; 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