re PR target/34981 (Lazily-bound function called twice)

gcc/
	PR target/34981
	* config/mips/mips-protos.h (mips_expand_call): Return an rtx.
	* config/mips/mips.h (FIRST_PSEUDO_REGISTER): Rename FAKE_CALL_REGNO
	to GOT_VERSION_REGNUM.
	(CALL_REALLY_USED_REGISTERS): Set the GOT_VERSION_REGNUM entry to 0.
	(EPILOGUE_USES): Include GOT_VERSION_REGNUM if TARGET_USE_GOT.
	* config/mips/mips.c (mips_emit_call_insn): New function.
	(mips_call_tls_get_addr): Call mips_expand_call directly.
	(mips16_copy_fpr_return_value): Use mips_emit_call_insn rather than
	emit_call_insn.
	(mips16_build_call_stub): Likewise.  Return the call insn or null.
	(mips_expand_call): Update the call to mips16_build_call_stub
	accordingly and a remove redundant condition.  Assert that MIPS16
	stubs do not use lazy binding.  Use mips_emit_call_insn and return
	the call insn.
	(mips_extra_live_on_entry): Include GOT_VERSION_REGNUM if
	TARGET_USE_GOT.
	(mips_hard_regno_mode_ok_p): Allow SImode for GOT_VERSION_REGNUM.
	(mips_avoid_hazard): Remove hazard_set handling.
	* config/mips/mips.md (UNSPEC_EH_RECEIVER): Rename to...
	(UNSPEC_RESTORE_GP): ...this.
	(UNSPEC_SET_GOT_VERSION, UNSPEC_UPDATE_GOT_VERSION): New constants.
	(FAKE_CALL_REGNO): Rename to...
	(GOT_VERSION_REGNUM): ...this.
	(type): Add "ghost" value.  Add an associated insn reservation.
	(hazard_set): Remove.
	(exception_receiver): Rename to...
	(restore_gp): ...this and update the unspec identifier accordingly.
	(exception_receiver, nonlocal_got_receiver): New expanders.
	(load_call<mode>): Use GOT_VERSION_REGNUM.  Don't set
	FAKE_CALL_REGNO.  Remove hazard_set attribute.
	(set_got_version, update_got_version): New patterns.

gcc/testsuite/
	PR target/34981
	* gcc.target/mips/lazy-binding-1.c: New test.
	* gcc.target/mips/mips.exp (setup_mips_tests): Set
	mips_forced_no_abicalls and mips_forced_no_shared.
	(dg-mips-options): Avoid using -mabicalls with an implicit -mabi=eabi.
	Avoid using small data with -mabicalls.  Don't make -G0 force
	-mn-abicalls.  Skip -mabicalls and -mshared tests if the multilib
	forces the opposite option.

From-SVN: r131860
This commit is contained in:
Richard Sandiford 2008-01-26 10:22:14 +00:00 committed by Richard Sandiford
parent 763a27ee73
commit dbc90b6565
8 changed files with 270 additions and 77 deletions

View File

@ -1,3 +1,38 @@
2008-01-26 Richard Sandiford <rsandifo@nildram.co.uk>
PR target/34981
* config/mips/mips-protos.h (mips_expand_call): Return an rtx.
* config/mips/mips.h (FIRST_PSEUDO_REGISTER): Rename FAKE_CALL_REGNO
to GOT_VERSION_REGNUM.
(CALL_REALLY_USED_REGISTERS): Set the GOT_VERSION_REGNUM entry to 0.
(EPILOGUE_USES): Include GOT_VERSION_REGNUM if TARGET_USE_GOT.
* config/mips/mips.c (mips_emit_call_insn): New function.
(mips_call_tls_get_addr): Call mips_expand_call directly.
(mips16_copy_fpr_return_value): Use mips_emit_call_insn rather than
emit_call_insn.
(mips16_build_call_stub): Likewise. Return the call insn or null.
(mips_expand_call): Update the call to mips16_build_call_stub
accordingly and a remove redundant condition. Assert that MIPS16
stubs do not use lazy binding. Use mips_emit_call_insn and return
the call insn.
(mips_extra_live_on_entry): Include GOT_VERSION_REGNUM if
TARGET_USE_GOT.
(mips_hard_regno_mode_ok_p): Allow SImode for GOT_VERSION_REGNUM.
(mips_avoid_hazard): Remove hazard_set handling.
* config/mips/mips.md (UNSPEC_EH_RECEIVER): Rename to...
(UNSPEC_RESTORE_GP): ...this.
(UNSPEC_SET_GOT_VERSION, UNSPEC_UPDATE_GOT_VERSION): New constants.
(FAKE_CALL_REGNO): Rename to...
(GOT_VERSION_REGNUM): ...this.
(type): Add "ghost" value. Add an associated insn reservation.
(hazard_set): Remove.
(exception_receiver): Rename to...
(restore_gp): ...this and update the unspec identifier accordingly.
(exception_receiver, nonlocal_got_receiver): New expanders.
(load_call<mode>): Use GOT_VERSION_REGNUM. Don't set
FAKE_CALL_REGNO. Remove hazard_set attribute.
(set_got_version, update_got_version): New patterns.
2008-01-26 Danny Smith <dannysmith@users.sourceforge.net>
PR target/34970

View File

@ -209,7 +209,7 @@ extern void mips_expand_vcondv2sf (rtx, rtx, rtx, enum rtx_code, rtx, rtx);
extern void mips_expand_conditional_move (rtx *);
extern void mips_expand_conditional_trap (enum rtx_code);
#endif
extern void mips_expand_call (rtx, rtx, rtx, rtx, bool);
extern rtx mips_expand_call (rtx, rtx, rtx, rtx, bool);
extern void mips_expand_fcc_reload (rtx, rtx, rtx);
extern void mips_set_return_address (rtx, rtx);
extern bool mips_expand_block_move (rtx, rtx, rtx);

View File

@ -2135,6 +2135,31 @@ mips_force_temporary (rtx dest, rtx value)
return dest;
}
}
/* Emit a call sequence with call pattern PATTERN and return the call
instruction itself (which is not necessarily the last instruction
emitted). LAZY_P is true if the call address is lazily-bound. */
static rtx
mips_emit_call_insn (rtx pattern, bool lazy_p)
{
rtx insn;
insn = emit_call_insn (pattern);
/* Lazy-binding stubs require $gp to be valid on entry. */
if (lazy_p)
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
if (TARGET_USE_GOT)
{
/* See the comment above load_call<mode> for details. */
use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
gen_rtx_REG (Pmode, GOT_VERSION_REGNUM));
emit_insn (gen_update_got_version ());
}
return insn;
}
/* Return a pseudo register that contains the value of $gp throughout
the current function. Such registers are needed by MIPS16 functions,
@ -2309,7 +2334,7 @@ static GTY(()) rtx mips_tls_symbol;
static rtx
mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
{
rtx insn, loc, tga, a0;
rtx insn, loc, a0;
a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
@ -2322,8 +2347,7 @@ mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
emit_insn (gen_rtx_SET (Pmode, a0,
gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, loc)));
tga = gen_const_mem (Pmode, mips_tls_symbol);
insn = emit_call_insn (gen_call_value (v0, tga, const0_rtx, const0_rtx));
insn = mips_expand_call (v0, mips_tls_symbol, const0_rtx, const0_rtx, false);
CONST_OR_PURE_CALL_P (insn) = 1;
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
insn = get_insns ();
@ -5198,7 +5222,7 @@ mips16_copy_fpr_return_value (void)
fn = gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (id));
arg = gen_rtx_REG (return_mode, GP_RETURN);
call = gen_call_value_internal (arg, fn, const0_rtx);
insn = emit_call_insn (call);
insn = mips_emit_call_insn (call, false);
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg);
}
@ -5208,7 +5232,8 @@ mips16_copy_fpr_return_value (void)
arguments and FP_CODE is the code built by mips_function_arg;
see the comment above CUMULATIVE_ARGS for details.
Return true if a stub was needed, and emit the call if so.
If a stub was needed, emit the call and return the call insn itself.
Return null otherwise.
A stub is needed for calls to functions that, in normal mode,
receive arguments in FPRs or return values in FPRs. The stub
@ -5221,7 +5246,7 @@ mips16_copy_fpr_return_value (void)
to be to a non-MIPS16 function, the linker automatically redirects
the JAL to the stub, otherwise the JAL continues to call FN directly. */
static bool
static rtx
mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
{
const char *fnname;
@ -5232,7 +5257,7 @@ mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
/* We don't need to do anything if we aren't in MIPS16 mode, or if
we were invoked with the -msoft-float option. */
if (!TARGET_MIPS16 || TARGET_SOFT_FLOAT_ABI)
return false;
return NULL_RTX;
/* Figure out whether the value might come back in a floating-point
register. */
@ -5242,13 +5267,13 @@ mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
arguments and the value will not be returned in a floating-point
register. */
if (fp_code == 0 && !fp_ret_p)
return false;
return NULL_RTX;
/* We don't need to do anything if this is a call to a special
MIPS16 support function. */
if (GET_CODE (fn) == SYMBOL_REF
&& strncmp (XSTR (fn, 0), "__mips16_", 9) == 0)
return false;
return NULL_RTX;
/* This code will only work for o32 and o64 abis. The other ABI's
require more sophisticated support. */
@ -5281,7 +5306,7 @@ mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
insn = gen_call_internal (stub_fn, args_size);
else
insn = gen_call_value_internal (retval, stub_fn, args_size);
insn = emit_call_insn (insn);
insn = mips_emit_call_insn (insn, false);
/* Tell GCC that this call does indeed use the value of $2. */
CALL_INSN_FUNCTION_USAGE (insn) =
@ -5301,7 +5326,7 @@ mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
gen_rtx_REG (word_mode, 18)),
CALL_INSN_FUNCTION_USAGE (insn));
return true;
return insn;
}
/* We know the function we are going to call. If we have already
@ -5468,7 +5493,7 @@ mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
insn = gen_call_internal_direct (fn, args_size);
else
insn = gen_call_value_internal_direct (retval, fn, args_size);
insn = emit_call_insn (insn);
insn = mips_emit_call_insn (insn, false);
/* If we are calling a stub which handles a floating-point return
value, we need to arrange to save $18 in the prologue. We do this
@ -5480,7 +5505,7 @@ mips16_build_call_stub (rtx retval, rtx fn, rtx args_size, int fp_code)
gen_rtx_USE (VOIDmode, gen_rtx_REG (word_mode, 18)),
CALL_INSN_FUNCTION_USAGE (insn));
return true;
return insn;
}
/* Return true if calls to X can use R_MIPS_CALL* relocations. */
@ -5531,9 +5556,11 @@ mips_load_call_address (rtx dest, rtx addr, bool sibcall_p)
ADDR is the address of the function, ARGS_SIZE is the size of the
arguments and AUX is the value passed to us by mips_function_arg.
SIBCALL_P is true if we are expanding a sibling call, false if we're
expanding a normal call. */
expanding a normal call.
void
Return the call itself. */
rtx
mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, bool sibcall_p)
{
rtx orig_addr, pattern, insn;
@ -5547,13 +5574,12 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, bool sibcall_p)
lazy_p = mips_load_call_address (addr, orig_addr, sibcall_p);
}
if (TARGET_MIPS16
&& TARGET_HARD_FLOAT_ABI
&& mips16_build_call_stub (result, addr, args_size,
aux == 0 ? 0 : (int) GET_MODE (aux)))
insn = mips16_build_call_stub (result, addr, args_size,
aux == 0 ? 0 : (int) GET_MODE (aux));
if (insn)
{
gcc_assert (!sibcall_p);
return;
gcc_assert (!sibcall_p && !lazy_p);
return insn;
}
if (result == 0)
@ -5582,17 +5608,7 @@ mips_expand_call (rtx result, rtx addr, rtx args_size, rtx aux, bool sibcall_p)
: gen_call_value_internal (result, addr, args_size));
}
insn = emit_call_insn (pattern);
/* 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));
}
return mips_emit_call_insn (pattern, lazy_p);
}
/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
@ -7977,14 +7993,21 @@ mips_initial_elimination_offset (int from, int to)
return offset;
}
/* Implement TARGET_EXTRA_LIVE_ON_ENTRY. Some code models use the incoming
value of PIC_FUNCTION_ADDR_REGNUM to set up the global pointer. */
/* Implement TARGET_EXTRA_LIVE_ON_ENTRY. */
static void
mips_extra_live_on_entry (bitmap regs)
{
if (TARGET_USE_GOT && !TARGET_ABSOLUTE_ABICALLS)
bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
if (TARGET_USE_GOT)
{
/* PIC_FUNCTION_ADDR_REGNUM is live if we need it to set up
the global pointer. */
if (!TARGET_ABSOLUTE_ABICALLS)
bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
/* See the comment above load_call<mode> for details. */
bitmap_set_bit (regs, GOT_VERSION_REGNUM);
}
}
/* Implement RETURN_ADDR_RTX. We do not support moving back to a
@ -8720,6 +8743,9 @@ mips_hard_regno_mode_ok_p (unsigned int regno, enum machine_mode mode)
if (ALL_COP_REG_P (regno))
return class == MODE_INT && size <= UNITS_PER_WORD;
if (regno == GOT_VERSION_REGNUM)
return mode == SImode;
return false;
}
@ -11360,7 +11386,7 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
rtx *delayed_reg, rtx lo_reg)
{
rtx pattern, set;
int nops, ninsns, hazard_set;
int nops, ninsns;
pattern = PATTERN (insn);
@ -11406,15 +11432,8 @@ mips_avoid_hazard (rtx after, rtx insn, int *hilo_delay,
break;
case HAZARD_DELAY:
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);
set = single_set (insn);
gcc_assert (set);
*delayed_reg = SET_DEST (set);
break;
}

View File

@ -1372,7 +1372,7 @@ enum mips_code_readable_setting {
- 3 fake registers:
- ARG_POINTER_REGNUM
- FRAME_POINTER_REGNUM
- FAKE_CALL_REGNO (see the comment above load_callsi for details)
- GOT_VERSION_REGNUM (see the comment above load_call<mode> for details)
- 3 dummy entries that were used at various times in the past.
- 6 DSP accumulator registers (3 hi-lo pairs) for MIPS DSP ASE
- 6 DSP control registers */
@ -1452,7 +1452,7 @@ enum mips_code_readable_setting {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
/* Others. */ \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, \
/* COP0 registers */ \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
@ -2089,8 +2089,12 @@ typedef struct mips_args {
/* Say that the epilogue uses the return address register. Note that
in the case of sibcalls, the values "used by the epilogue" are
considered live at the start of the called function. */
#define EPILOGUE_USES(REGNO) ((REGNO) == 31)
considered live at the start of the called function.
If using a GOT, say that the epilogue also uses GOT_VERSION_REGNUM.
See the comment above load_call<mode> for details. */
#define EPILOGUE_USES(REGNO) \
((REGNO) == 31 || (TARGET_USE_GOT && (REGNO) == GOT_VERSION_REGNUM))
/* Treat LOC as a byte offset from the stack pointer and round it up
to the next fully-aligned offset. */

View File

@ -30,7 +30,7 @@
(UNSPEC_GET_FNADDR 3)
(UNSPEC_BLOCKAGE 4)
(UNSPEC_CPRESTORE 5)
(UNSPEC_EH_RECEIVER 6)
(UNSPEC_RESTORE_GP 6)
(UNSPEC_EH_RETURN 7)
(UNSPEC_CONSTTABLE_INT 8)
(UNSPEC_CONSTTABLE_FLOAT 9)
@ -58,10 +58,12 @@
(UNSPEC_SYNC_NEW_OP 39)
(UNSPEC_SYNC_EXCHANGE 40)
(UNSPEC_MEMORY_BARRIER 41)
(UNSPEC_SET_GOT_VERSION 42)
(UNSPEC_UPDATE_GOT_VERSION 43)
(UNSPEC_ADDRESS_FIRST 100)
(FAKE_CALL_REGNO 79)
(GOT_VERSION_REGNUM 79)
;; For MIPS Paired-Singled Floating Point Instructions.
@ -290,8 +292,9 @@
;; frsqrt2 floating point reciprocal square root step2
;; multi multiword sequence (or user asm statements)
;; nop no operation
;; ghost an instruction that produces no real code
(define_attr "type"
"unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,prefetch,prefetchx,condmove,mfc,mtc,mthilo,mfhilo,const,arith,logical,shift,slt,signext,clz,trap,imul,imul3,imadd,idiv,move,fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,frsqrt1,frsqrt2,multi,nop"
"unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,prefetch,prefetchx,condmove,mfc,mtc,mthilo,mfhilo,const,arith,logical,shift,slt,signext,clz,trap,imul,imul3,imadd,idiv,move,fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,frsqrt,frsqrt1,frsqrt2,multi,nop,ghost"
(cond [(eq_attr "jal" "!unset") (const_string "call")
(eq_attr "got" "load") (const_string "load")]
(const_string "unknown")))
@ -438,17 +441,6 @@
(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)"))
@ -703,6 +695,12 @@
(define_cpu_unit "alu" "alu")
(define_cpu_unit "imuldiv" "imuldiv")
;; Ghost instructions produce no real code and introduce no hazards.
;; They exist purely to express an effect on dataflow.
(define_insn_reservation "ghost" 0
(eq_attr "type" "ghost")
"nothing")
(include "4k.md")
(include "5k.md")
(include "20kc.md")
@ -5598,9 +5596,33 @@
DONE;
})
(define_insn_and_split "exception_receiver"
(define_expand "exception_receiver"
[(const_int 0)]
"TARGET_USE_GOT"
{
/* See the comment above load_call<mode> for details. */
emit_insn (gen_set_got_version ());
/* If we have a call-clobbered $gp, restore it from its save slot. */
if (HAVE_restore_gp)
emit_insn (gen_restore_gp ());
DONE;
})
(define_expand "nonlocal_goto_receiver"
[(const_int 0)]
"TARGET_USE_GOT"
{
/* See the comment above load_call<mode> for details. */
emit_insn (gen_set_got_version ());
DONE;
})
;; Restore $gp from its .cprestore stack slot. The instruction remains
;; volatile until all uses of $28 are exposed.
(define_insn_and_split "restore_gp"
[(set (reg:SI 28)
(unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))]
(unspec_volatile:SI [(const_int 0)] UNSPEC_RESTORE_GP))]
"TARGET_CALL_CLOBBERED_GP"
"#"
"&& reload_completed"
@ -5629,24 +5651,66 @@
;; 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
;; 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.
;; We represent this restriction using an imaginary, fixed, call-saved
;; register called GOT_VERSION_REGNUM. The idea is to make the register
;; live throughout the function and to change its value after every
;; potential call site. This stops any rtx value that uses the register
;; from being computed before an earlier call. To do this, we:
;;
;; - Ensure that the register is live on entry to the function,
;; so that it is never thought to be used uninitalized.
;;
;; - Ensure that the register is live on exit from the function,
;; so that it is live throughout.
;;
;; - Make each call (lazily-bound or not) use the current value
;; of GOT_VERSION_REGNUM, so that updates of the register are
;; not moved across call boundaries.
;;
;; - Add "ghost" definitions of the register to the beginning of
;; blocks reached by EH and ABNORMAL_CALL edges, because those
;; edges may involve calls that normal paths don't. (E.g. the
;; unwinding code that handles a non-call exception may change
;; lazily-bound GOT entries.) We do this by making the
;; exception_receiver and nonlocal_goto_receiver expanders emit
;; a set_got_version instruction.
;;
;; - After each call (lazily-bound or not), use a "ghost"
;; update_got_version instruction to change the register's value.
;; This instruction mimics the _possible_ effect of the dynamic
;; resolver during the call and it remains live even if the call
;; itself becomes dead.
;;
;; - Leave GOT_VERSION_REGNUM out of all register classes.
;; The register is therefore not a valid register_operand
;; and cannot be moved to or from other registers.
(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" "")]
UNSPEC_LOAD_CALL))
(set (reg:P FAKE_CALL_REGNO)
(unspec:P [(match_dup 2)] UNSPEC_LOAD_CALL))]
(match_operand:P 2 "immediate_operand" "")
(reg:SI GOT_VERSION_REGNUM)] 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")])
(define_insn "set_got_version"
[(set (reg:SI GOT_VERSION_REGNUM)
(unspec_volatile:SI [(const_int 0)] UNSPEC_SET_GOT_VERSION))]
"TARGET_USE_GOT"
""
[(set_attr "length" "0")
(set_attr "type" "ghost")])
(define_insn "update_got_version"
[(set (reg:SI GOT_VERSION_REGNUM)
(unspec:SI [(reg:SI GOT_VERSION_REGNUM)] UNSPEC_UPDATE_GOT_VERSION))]
"TARGET_USE_GOT"
""
[(set_attr "length" "0")
(set_attr "type" "ghost")])
;; Sibling calls. All these patterns use jump instructions.
;; If TARGET_SIBCALLS, call_insn_operand will only accept constant

View File

@ -1,3 +1,14 @@
2008-01-26 Richard Sandiford <rsandifo@nildram.co.uk>
PR target/34981
* gcc.target/mips/lazy-binding-1.c: New test.
* gcc.target/mips/mips.exp (setup_mips_tests): Set
mips_forced_no_abicalls and mips_forced_no_shared.
(dg-mips-options): Avoid using -mabicalls with an implicit -mabi=eabi.
Avoid using small data with -mabicalls. Don't make -G0 force
-mn-abicalls. Skip -mabicalls and -mshared tests if the multilib
forces the opposite option.
2008-01-26 Danny Smith <dannysmith@users.sourceforge.net>
PR target/34970

View File

@ -0,0 +1,20 @@
/* { dg-mips-options "-mabicalls -mshared -mexplicit-relocs -O2 -fno-delayed-branch" } */
void bar (void);
void
foo (int n)
{
while (n--)
{
bar ();
bar ();
}
}
/* There should be exactly five uses of $25: one to set up $gp, two to
load the address of bar (), and two to call it. */
/* { dg-final { scan-assembler-times "\tl.\t\\\$25,%call16\\\(bar\\\)" 2 } } */
/* { dg-final { scan-assembler-times "\tjalr\t\\\$25" 2 } } */
/* { dg-final { scan-assembler "(\\\$28,|\t.cpload\t)\\\$25" } } */
/* { dg-final { scan-assembler-times "\\\$25" 5 } } */

View File

@ -44,6 +44,10 @@ load_lib gcc-dg.exp
# $mips_forced_be true if the command line uses -EB or -meb
# $mips_forced_le true if the command line uses -EL or -mel
# $mips_forced_gp true if the command line forces a particular GP mode
# $mips_forced_no_abicalls
# true if the command line contains -mno-abicalls
# $mips_forced_no_shared
# true if the command line contains -mno-shared
# $mips_forced_no_er true if the command line contains -mno-explicit-relocs
proc setup_mips_tests {} {
global mips_isa
@ -61,6 +65,8 @@ proc setup_mips_tests {} {
global mips_forced_be
global mips_forced_le
global mips_forced_gp
global mips_forced_no_abicalls
global mips_forced_no_shared
global mips_forced_no_er
global mips_forced_regs
@ -123,6 +129,8 @@ proc setup_mips_tests {} {
set mips_forced_be [regexp -- {-(EB|meb)[[:>:]]} $compiler_flags]
set mips_forced_le [regexp -- {-(EL|mel)[[:>:]]} $compiler_flags]
set mips_forced_gp [regexp -- {-(G|m(|no-)((extern|local)-sdata|gpopt)|mabicalls|mrtp)} $compiler_flags]
set mips_forced_no_abicalls [regexp -- {-mno-abicalls} $compiler_flags]
set mips_forced_no_shared [regexp -- {-mno-shared} $compiler_flags]
set mips_forced_no_er [regexp -- {-mno-explicit-relocs} $compiler_flags]
if {$mips_forced_regs && $mips_gp == 32 && $mips_fp == 64} {
@ -178,6 +186,11 @@ proc setup_mips_tests {} {
# the multilib flags already contain such an option, or specify
# something that might be incompatible with them.
#
# -mabicalls
# -mshared
# Select the form of SVR4 PIC. Skip the test if the multilib flags
# conflict with the required setting.
#
# -mexplicit-relocs
# Select explicit relocations. Skip the test if the multilib flags
# force -mno-explicit-relocs.
@ -204,6 +217,8 @@ proc dg-mips-options {args} {
global mips_forced_be
global mips_forced_le
global mips_forced_gp
global mips_forced_no_abicalls
global mips_forced_no_shared
global mips_forced_no_er
set flags [lindex $args 1]
@ -281,6 +296,21 @@ proc dg-mips-options {args} {
}
}
foreach flag $flags {
if {[string match -mabicalls $flag]} {
# EABI has no SVR4-style PIC mode, so try to force another ABI.
if {$mips_abi == "eabi" && [lsearch $flags "-mabi=*"] < 0} {
if {$mips_new_gp == 32} {
append flags " -mabi=32"
} else {
append flags " -mabi=n32"
}
}
# Turn off small data, if on by default.
append flags " -G0"
}
}
# Handle the other options.
foreach flag $flags {
if {[regexp -- {^-mabi=(.*)} $flag dummy abi]} {
@ -313,10 +343,20 @@ proc dg-mips-options {args} {
set matches 0
}
} elseif {[regexp -- {^-(G|m(|no-)((extern|local)-sdata|gpopt))} $flag]} {
append flags " -mno-abicalls"
if {$flag != "-G0"} {
append flags " -mno-abicalls"
}
if {$mips_forced_gp} {
set matches 0
}
} elseif {[regexp -- {^-mabicalls$} $flag]} {
if {$mips_forced_no_abicalls} {
set matches 0
}
} elseif {[regexp -- {^-mshared$} $flag]} {
if {$mips_forced_no_shared} {
set matches 0
}
} elseif {[regexp -- {^-mexplicit-relocs$} $flag]} {
if {$mips_forced_no_er} {
set matches 0