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:
parent
763a27ee73
commit
dbc90b6565
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 } } */
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue