mips.opt (mrelax-pic-calls): New option.
* config/mips/mips.opt (mrelax-pic-calls): New option. * config/mips/mips.c (mips_strip_unspec_address): Move it up in the file. (mips_unspec_call): Change "unspec_call" expander into this. (mips_strip_unspec_call): New function. (mips_got_load): Call mips_unspec_call instead of gen_unspec_call<mode>. (mips16_build_call_stub): Fix comment for fp_code. Adjust call to MIPS_CALL. (mips_cfg_in_reorg): New function. (mips16_lay_out_constants): Use it to decide whether to call CFG-aware insn splitting. (r10k_insert_cache_barriers): Move CFG set-up code from here to mips_reorg. Move DF set-up code from here ... (mips_df_reorg): ... to here. Call r10k_insert_cache_barriers from here. (mips_reorg): Call mips_df_reorg instead of r10k_insert_cache_barriers. Move CFG set-up code here from r10k_insert_cache_barriers. (mips_call_expr_from_insn): New function. (mips_pic_call_symbol_from_set): Likewise. (mips_find_pic_call_symbol): Likewise. (mips_annotate_pic_call_expr): Likewise. (mips_get_pic_call_symbol): Likewise. (mips_annotate_pic_calls): Likewise. (mips_override_options): Disable -mrelax-pic-calls unless PIC calls are used. (mips_set_mips16_mode): Disable -mrelax-pic-calls for MIPS16. * config/mips/mips-protos.h (mips_get_pic_call_symbol): Declare it. * config/mips/mips.h (MIPS_CALL): Use it to print the .reloc directive. * config/mips/mips.md (UNSPEC_CALL_ATTR): New unspec. (unspec_call<mode>): Remove it. (sibcall_internal, sibcall_value_internal, sibcall_value_multiple_internal, call_internal, call_split, call_value_internal, call_value_split, call_value_multiple_internal, call_value_multiple_split): Pass SIZE_OPNO to MIPS_CALL. (call_internal_direct, call_direct_split, call_value_internal_direct, call_value_direct_split): Pass -1 as SIZE_OPNO to MIPS_CALL. * configure.ac <mips*-*-*>: Add test for .reloc R_MIPS_JALR. * configure: Regenerate. * doc/invoke.texi (Option Summary): Add -mrelax-pic-calls and -mno-relax-pic-calls. (MIPS Options): Document -mrelax-pic-calls and -mno-relax-pic-calls. testsuite/ * gcc.target/mips/mips.exp: Add relax-pic-calls under -mfoo/-mno-foo options. (mips-dg-options): Make -mrelax-pic-calls imply -mno-plt, -mabicalls and -mexplicit-relocs. * gcc.target/mips/call-1.c: New test. * gcc.target/mips/call-2.c: New test. * gcc.target/mips/call-3.c: New test. * gcc.target/mips/lazy-binding-1.c: Add MIPS-specific dg-options. * gcc.dg/tree-ssa/loop-1.c: Likewise. From-SVN: r151890
This commit is contained in:
parent
4172245c93
commit
b53da24424
|
@ -1,3 +1,53 @@
|
|||
2009-09-19 Adam Nemet <anemet@caviumnetworks.com>
|
||||
|
||||
* config/mips/mips.opt (mrelax-pic-calls): New option.
|
||||
* config/mips/mips.c (mips_strip_unspec_address): Move it up in
|
||||
the file.
|
||||
(mips_unspec_call): Change "unspec_call" expander into this.
|
||||
(mips_strip_unspec_call): New function.
|
||||
(mips_got_load): Call mips_unspec_call instead of
|
||||
gen_unspec_call<mode>.
|
||||
(mips16_build_call_stub): Fix comment for fp_code. Adjust call to
|
||||
MIPS_CALL.
|
||||
(mips_cfg_in_reorg): New function.
|
||||
(mips16_lay_out_constants): Use it to decide whether to call
|
||||
CFG-aware insn splitting.
|
||||
(r10k_insert_cache_barriers): Move CFG set-up code from here to
|
||||
mips_reorg. Move DF set-up code from here ...
|
||||
(mips_df_reorg): ... to here. Call r10k_insert_cache_barriers
|
||||
from here.
|
||||
(mips_reorg): Call mips_df_reorg instead of
|
||||
r10k_insert_cache_barriers. Move CFG set-up code here from
|
||||
r10k_insert_cache_barriers.
|
||||
(mips_call_expr_from_insn): New function.
|
||||
(mips_pic_call_symbol_from_set): Likewise.
|
||||
(mips_find_pic_call_symbol): Likewise.
|
||||
(mips_annotate_pic_call_expr): Likewise.
|
||||
(mips_get_pic_call_symbol): Likewise.
|
||||
(mips_annotate_pic_calls): Likewise.
|
||||
(mips_override_options): Disable -mrelax-pic-calls unless PIC
|
||||
calls are used.
|
||||
(mips_set_mips16_mode): Disable -mrelax-pic-calls for MIPS16.
|
||||
* config/mips/mips-protos.h (mips_get_pic_call_symbol): Declare it.
|
||||
* config/mips/mips.h (MIPS_CALL): Use it to print the .reloc
|
||||
directive.
|
||||
* config/mips/mips.md (UNSPEC_CALL_ATTR): New unspec.
|
||||
(unspec_call<mode>): Remove it.
|
||||
(sibcall_internal, sibcall_value_internal,
|
||||
sibcall_value_multiple_internal, call_internal, call_split,
|
||||
call_value_internal, call_value_split,
|
||||
call_value_multiple_internal, call_value_multiple_split): Pass
|
||||
SIZE_OPNO to MIPS_CALL.
|
||||
(call_internal_direct, call_direct_split,
|
||||
call_value_internal_direct, call_value_direct_split): Pass -1 as
|
||||
SIZE_OPNO to MIPS_CALL.
|
||||
* configure.ac <mips*-*-*>: Add test for .reloc R_MIPS_JALR.
|
||||
* configure: Regenerate.
|
||||
* doc/invoke.texi (Option Summary): Add -mrelax-pic-calls
|
||||
and -mno-relax-pic-calls.
|
||||
(MIPS Options): Document -mrelax-pic-calls
|
||||
and -mno-relax-pic-calls.
|
||||
|
||||
2009-09-19 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
|
||||
PR bootstrap/35619
|
||||
|
|
|
@ -233,6 +233,7 @@ extern void mips_expand_conditional_trap (rtx);
|
|||
extern bool mips_use_pic_fn_addr_reg_p (const_rtx);
|
||||
extern rtx mips_expand_call (enum mips_call_type, rtx, rtx, rtx, rtx, bool);
|
||||
extern void mips_split_call (rtx, rtx);
|
||||
extern bool mips_get_pic_call_symbol (rtx *, int);
|
||||
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);
|
||||
|
|
|
@ -1125,6 +1125,8 @@ static const struct mips_rtx_cost_data mips_rtx_cost_data[PROCESSOR_MAX] = {
|
|||
}
|
||||
};
|
||||
|
||||
static rtx mips_find_pic_call_symbol (rtx, rtx);
|
||||
|
||||
/* This hash table keeps track of implicit "mips16" and "nomips16" attributes
|
||||
for -mflip_mips16. It maps decl names onto a boolean mode setting. */
|
||||
struct GTY (()) mflip_mips16_entry {
|
||||
|
@ -2509,6 +2511,20 @@ mips_unspec_address (rtx address, enum mips_symbol_type symbol_type)
|
|||
return mips_unspec_address_offset (base, offset, symbol_type);
|
||||
}
|
||||
|
||||
/* If OP is an UNSPEC address, return the address to which it refers,
|
||||
otherwise return OP itself. */
|
||||
|
||||
static rtx
|
||||
mips_strip_unspec_address (rtx op)
|
||||
{
|
||||
rtx base, offset;
|
||||
|
||||
split_const (op, &base, &offset);
|
||||
if (UNSPEC_ADDRESS_P (base))
|
||||
op = plus_constant (UNSPEC_ADDRESS (base), INTVAL (offset));
|
||||
return op;
|
||||
}
|
||||
|
||||
/* If mips_unspec_address (ADDR, SYMBOL_TYPE) is a 32-bit value, add the
|
||||
high part to BASE and return the result. Just return BASE otherwise.
|
||||
TEMP is as for mips_force_temporary.
|
||||
|
@ -2600,6 +2616,28 @@ mips_pic_base_register (rtx temp)
|
|||
return temp;
|
||||
}
|
||||
|
||||
/* Return the RHS of a load_call<mode> insn. */
|
||||
|
||||
static rtx
|
||||
mips_unspec_call (rtx reg, rtx symbol)
|
||||
{
|
||||
rtvec vec;
|
||||
|
||||
vec = gen_rtvec (3, reg, symbol, gen_rtx_REG (SImode, GOT_VERSION_REGNUM));
|
||||
return gen_rtx_UNSPEC (Pmode, vec, UNSPEC_LOAD_CALL);
|
||||
}
|
||||
|
||||
/* If SRC is the RHS of a load_call<mode> insn, return the underlying symbol
|
||||
reference. Return NULL_RTX otherwise. */
|
||||
|
||||
static rtx
|
||||
mips_strip_unspec_call (rtx src)
|
||||
{
|
||||
if (GET_CODE (src) == UNSPEC && XINT (src, 1) == UNSPEC_LOAD_CALL)
|
||||
return mips_strip_unspec_address (XVECEXP (src, 0, 1));
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Create and return a GOT reference of type TYPE for address ADDR.
|
||||
TEMP, if nonnull, is a scratch Pmode base register. */
|
||||
|
||||
|
@ -2619,9 +2657,7 @@ mips_got_load (rtx temp, rtx addr, enum mips_symbol_type type)
|
|||
lo_sum_symbol = mips_unspec_address (addr, type);
|
||||
|
||||
if (type == SYMBOL_GOTOFF_CALL)
|
||||
return (Pmode == SImode
|
||||
? gen_unspec_callsi (high, lo_sum_symbol)
|
||||
: gen_unspec_calldi (high, lo_sum_symbol));
|
||||
return mips_unspec_call (high, lo_sum_symbol);
|
||||
else
|
||||
return (Pmode == SImode
|
||||
? gen_unspec_gotsi (high, lo_sum_symbol)
|
||||
|
@ -6010,7 +6046,7 @@ mips16_copy_fpr_return_value (void)
|
|||
RETVAL is the location of the return value, or null if this is
|
||||
a "call" rather than a "call_value". ARGS_SIZE is the size of the
|
||||
arguments and FP_CODE is the code built by mips_function_arg;
|
||||
see the comment above CUMULATIVE_ARGS for details.
|
||||
see the comment before the fp_code field in CUMULATIVE_ARGS for details.
|
||||
|
||||
There are three alternatives:
|
||||
|
||||
|
@ -6208,7 +6244,7 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, rtx args_size, int fp_code)
|
|||
$18 is usually a call-saved register. */
|
||||
fprintf (asm_out_file, "\tmove\t%s,%s\n",
|
||||
reg_names[GP_REG_FIRST + 18], reg_names[GP_REG_FIRST + 31]);
|
||||
output_asm_insn (MIPS_CALL ("jal", &fn, 0), &fn);
|
||||
output_asm_insn (MIPS_CALL ("jal", &fn, 0, -1), &fn);
|
||||
|
||||
/* Move the result from floating-point registers to
|
||||
general registers. */
|
||||
|
@ -7094,20 +7130,6 @@ mips_init_relocs (void)
|
|||
mips_lo_relocs[SYMBOL_HALF] = "%half(";
|
||||
}
|
||||
|
||||
/* If OP is an UNSPEC address, return the address to which it refers,
|
||||
otherwise return OP itself. */
|
||||
|
||||
static rtx
|
||||
mips_strip_unspec_address (rtx op)
|
||||
{
|
||||
rtx base, offset;
|
||||
|
||||
split_const (op, &base, &offset);
|
||||
if (UNSPEC_ADDRESS_P (base))
|
||||
op = plus_constant (UNSPEC_ADDRESS (base), INTVAL (offset));
|
||||
return op;
|
||||
}
|
||||
|
||||
/* Print symbolic operand OP, which is part of a HIGH or LO_SUM
|
||||
in context CONTEXT. RELOCS is the array of relocations to use. */
|
||||
|
||||
|
@ -13435,6 +13457,15 @@ mips16_rewrite_pool_refs (rtx *x, void *data)
|
|||
return GET_CODE (*x) == CONST ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Return whether CFG is used in mips_reorg. */
|
||||
|
||||
static bool
|
||||
mips_cfg_in_reorg (void)
|
||||
{
|
||||
return (mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE
|
||||
|| TARGET_RELAX_PIC_CALLS);
|
||||
}
|
||||
|
||||
/* Build MIPS16 constant pools. */
|
||||
|
||||
static void
|
||||
|
@ -13447,7 +13478,10 @@ mips16_lay_out_constants (void)
|
|||
if (!TARGET_MIPS16_PCREL_LOADS)
|
||||
return;
|
||||
|
||||
split_all_insns_noflow ();
|
||||
if (mips_cfg_in_reorg ())
|
||||
split_all_insns ();
|
||||
else
|
||||
split_all_insns_noflow ();
|
||||
barrier = 0;
|
||||
memset (&pool, 0, sizeof (pool));
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
|
@ -13783,14 +13817,6 @@ r10k_insert_cache_barriers (void)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Restore the BLOCK_FOR_INSN pointers, which are needed by DF. */
|
||||
compute_bb_for_insn ();
|
||||
|
||||
/* Create def-use chains. */
|
||||
df_set_flags (DF_EQ_NOTES);
|
||||
df_chain_add_problem (DF_UD_CHAIN);
|
||||
df_analyze ();
|
||||
|
||||
/* Calculate dominators. */
|
||||
calculate_dominance_info (CDI_DOMINATORS);
|
||||
|
||||
|
@ -13869,10 +13895,171 @@ r10k_insert_cache_barriers (void)
|
|||
sbitmap_free (protected_bbs);
|
||||
|
||||
free_dominance_info (CDI_DOMINATORS);
|
||||
}
|
||||
|
||||
/* If INSN is a call, return the underlying CALL expr. Return NULL_RTX
|
||||
otherwise. */
|
||||
|
||||
df_finish_pass (false);
|
||||
static rtx
|
||||
mips_call_expr_from_insn (rtx insn)
|
||||
{
|
||||
rtx x;
|
||||
|
||||
free_bb_for_insn ();
|
||||
if (!CALL_P (insn))
|
||||
return NULL_RTX;
|
||||
|
||||
x = PATTERN (insn);
|
||||
if (GET_CODE (x) == PARALLEL)
|
||||
x = XVECEXP (x, 0, 0);
|
||||
if (GET_CODE (x) == SET)
|
||||
x = XEXP (x, 1);
|
||||
|
||||
gcc_assert (GET_CODE (x) == CALL);
|
||||
return x;
|
||||
}
|
||||
|
||||
/* REG is set in DEF. See if the definition is one of the ways we load a
|
||||
register with a symbol address for a mips_use_pic_fn_addr_reg_p call. If
|
||||
it is return the symbol reference of the function, otherwise return
|
||||
NULL_RTX. */
|
||||
|
||||
static rtx
|
||||
mips_pic_call_symbol_from_set (df_ref def, rtx reg)
|
||||
{
|
||||
rtx def_insn, set;
|
||||
|
||||
if (DF_REF_IS_ARTIFICIAL (def))
|
||||
return NULL_RTX;
|
||||
|
||||
def_insn = DF_REF_INSN (def);
|
||||
set = single_set (def_insn);
|
||||
if (set && rtx_equal_p (SET_DEST (set), reg))
|
||||
{
|
||||
rtx note, src, symbol;
|
||||
|
||||
/* First, look at REG_EQUAL/EQUIV notes. */
|
||||
note = find_reg_equal_equiv_note (def_insn);
|
||||
if (note && GET_CODE (XEXP (note, 0)) == SYMBOL_REF)
|
||||
return XEXP (note, 0);
|
||||
|
||||
/* For %call16 references we don't have REG_EQUAL. */
|
||||
src = SET_SRC (set);
|
||||
symbol = mips_strip_unspec_call (src);
|
||||
if (symbol)
|
||||
{
|
||||
gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/* Follow simple register copies. */
|
||||
if (REG_P (src))
|
||||
return mips_find_pic_call_symbol (def_insn, src);
|
||||
}
|
||||
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Find the definition of the use of REG in INSN. See if the definition is
|
||||
one of the ways we load a register with a symbol address for a
|
||||
mips_use_pic_fn_addr_reg_p call. If it is return the symbol reference of
|
||||
the function, otherwise return NULL_RTX. */
|
||||
|
||||
static rtx
|
||||
mips_find_pic_call_symbol (rtx insn, rtx reg)
|
||||
{
|
||||
df_ref use;
|
||||
struct df_link *defs;
|
||||
rtx symbol;
|
||||
|
||||
use = df_find_use (insn, regno_reg_rtx[REGNO (reg)]);
|
||||
if (!use)
|
||||
return NULL_RTX;
|
||||
defs = DF_REF_CHAIN (use);
|
||||
if (!defs)
|
||||
return NULL_RTX;
|
||||
symbol = mips_pic_call_symbol_from_set (defs->ref, reg);
|
||||
if (!symbol)
|
||||
return NULL_RTX;
|
||||
|
||||
/* If we have more than one definition, they need to be identical. */
|
||||
for (defs = defs->next; defs; defs = defs->next)
|
||||
{
|
||||
rtx other;
|
||||
|
||||
other = mips_pic_call_symbol_from_set (defs->ref, reg);
|
||||
if (!rtx_equal_p (symbol, other))
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/* Replace the args_size operand of the call expression CALL with the
|
||||
call-attribute UNSPEC and fill in SYMBOL as the function symbol. */
|
||||
|
||||
static void
|
||||
mips_annotate_pic_call_expr (rtx call, rtx symbol)
|
||||
{
|
||||
rtx args_size;
|
||||
|
||||
args_size = XEXP (call, 1);
|
||||
XEXP (call, 1) = gen_rtx_UNSPEC (GET_MODE (args_size),
|
||||
gen_rtvec (2, args_size, symbol),
|
||||
UNSPEC_CALL_ATTR);
|
||||
}
|
||||
|
||||
/* OPERANDS[ARGS_SIZE_OPNO] is the arg_size operand of a CALL expression. See
|
||||
if instead of the arg_size argument it contains the call attributes. If
|
||||
yes return true along with setting OPERANDS[ARGS_SIZE_OPNO] to the function
|
||||
symbol from the call attributes. Also return false if ARGS_SIZE_OPNO is
|
||||
-1. */
|
||||
|
||||
bool
|
||||
mips_get_pic_call_symbol (rtx *operands, int args_size_opno)
|
||||
{
|
||||
rtx args_size, symbol;
|
||||
|
||||
if (!TARGET_RELAX_PIC_CALLS || args_size_opno == -1)
|
||||
return false;
|
||||
|
||||
args_size = operands[args_size_opno];
|
||||
if (GET_CODE (args_size) != UNSPEC)
|
||||
return false;
|
||||
gcc_assert (XINT (args_size, 1) == UNSPEC_CALL_ATTR);
|
||||
|
||||
symbol = XVECEXP (args_size, 0, 1);
|
||||
gcc_assert (GET_CODE (symbol) == SYMBOL_REF);
|
||||
|
||||
operands[args_size_opno] = symbol;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Use DF to annotate PIC indirect calls with the function symbol they
|
||||
dispatch to. */
|
||||
|
||||
static void
|
||||
mips_annotate_pic_calls (void)
|
||||
{
|
||||
basic_block bb;
|
||||
rtx insn;
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
FOR_BB_INSNS (bb, insn)
|
||||
{
|
||||
rtx call, reg, symbol;
|
||||
|
||||
call = mips_call_expr_from_insn (insn);
|
||||
if (!call)
|
||||
continue;
|
||||
gcc_assert (MEM_P (XEXP (call, 0)));
|
||||
reg = XEXP (XEXP (call, 0), 0);
|
||||
if (!REG_P (reg))
|
||||
continue;
|
||||
|
||||
symbol = mips_find_pic_call_symbol (insn, reg);
|
||||
if (symbol)
|
||||
mips_annotate_pic_call_expr (call, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/* A temporary variable used by for_each_rtx callbacks, etc. */
|
||||
|
@ -14586,14 +14773,42 @@ mips_expand_ghost_gp_insns (void)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Subroutine of mips_reorg to manage passes that require DF. */
|
||||
|
||||
static void
|
||||
mips_df_reorg (void)
|
||||
{
|
||||
/* Create def-use chains. */
|
||||
df_set_flags (DF_EQ_NOTES);
|
||||
df_chain_add_problem (DF_UD_CHAIN);
|
||||
df_analyze ();
|
||||
|
||||
if (TARGET_RELAX_PIC_CALLS)
|
||||
mips_annotate_pic_calls ();
|
||||
|
||||
if (mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE)
|
||||
r10k_insert_cache_barriers ();
|
||||
|
||||
df_finish_pass (false);
|
||||
}
|
||||
|
||||
/* Implement TARGET_MACHINE_DEPENDENT_REORG. */
|
||||
|
||||
static void
|
||||
mips_reorg (void)
|
||||
{
|
||||
/* Restore the BLOCK_FOR_INSN pointers, which are needed by DF. Also during
|
||||
insn splitting in mips16_lay_out_constants, DF insn info is only kept up
|
||||
to date if the CFG is available. */
|
||||
if (mips_cfg_in_reorg ())
|
||||
compute_bb_for_insn ();
|
||||
mips16_lay_out_constants ();
|
||||
if (mips_r10k_cache_barrier != R10K_CACHE_BARRIER_NONE)
|
||||
r10k_insert_cache_barriers ();
|
||||
if (mips_cfg_in_reorg ())
|
||||
{
|
||||
mips_df_reorg ();
|
||||
free_bb_for_insn ();
|
||||
}
|
||||
|
||||
if (optimize > 0 && flag_delayed_branch)
|
||||
dbr_schedule (get_insns ());
|
||||
mips_reorg_process_insns ();
|
||||
|
@ -14798,6 +15013,9 @@ mips_set_mips16_mode (int mips16_p)
|
|||
|
||||
targetm.const_anchor = 0;
|
||||
|
||||
/* MIPS16 has no BAL instruction. */
|
||||
target_flags &= ~MASK_RELAX_PIC_CALLS;
|
||||
|
||||
if (flag_pic && !TARGET_OLDABI)
|
||||
sorry ("MIPS16 PIC for ABIs other than o32 and o64");
|
||||
|
||||
|
@ -15389,6 +15607,10 @@ mips_override_options (void)
|
|||
target_flags &= ~MASK_SYNCI;
|
||||
}
|
||||
|
||||
/* Only optimize PIC indirect calls if they are actually required. */
|
||||
if (!TARGET_USE_GOT || !TARGET_EXPLICIT_RELOCS)
|
||||
target_flags &= ~MASK_RELAX_PIC_CALLS;
|
||||
|
||||
/* Save base state of options. */
|
||||
mips_base_target_flags = target_flags;
|
||||
mips_base_schedule_insns = flag_schedule_insns;
|
||||
|
|
|
@ -2686,20 +2686,27 @@ typedef struct mips_args {
|
|||
: INSN)
|
||||
|
||||
/* Return the asm template for a call. INSN is the instruction's mnemonic
|
||||
("j" or "jal"), OPERANDS are its operands, and OPNO is the operand number
|
||||
of the target.
|
||||
("j" or "jal"), OPERANDS are its operands, TARGET_OPNO is the operand
|
||||
number of the target. SIZE_OPNO is the operand number of the argument size
|
||||
operand that can optionally hold the call attributes. If SIZE_OPNO is not
|
||||
-1 and the call is indirect, use the function symbol from the call
|
||||
attributes to attach a R_MIPS_JALR relocation to the call.
|
||||
|
||||
When generating GOT code without explicit relocation operators,
|
||||
all calls should use assembly macros. Otherwise, all indirect
|
||||
calls should use "jr" or "jalr"; we will arrange to restore $gp
|
||||
afterwards if necessary. Finally, we can only generate direct
|
||||
calls for -mabicalls by temporarily switching to non-PIC mode. */
|
||||
#define MIPS_CALL(INSN, OPERANDS, OPNO) \
|
||||
#define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO) \
|
||||
(TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS \
|
||||
? "%*" INSN "\t%" #OPNO "%/" \
|
||||
: REG_P (OPERANDS[OPNO]) \
|
||||
? "%*" INSN "r\t%" #OPNO "%/" \
|
||||
: MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
|
||||
? "%*" INSN "\t%" #TARGET_OPNO "%/" \
|
||||
: (REG_P (OPERANDS[TARGET_OPNO]) \
|
||||
&& mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)) \
|
||||
? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n" \
|
||||
"1:\t" INSN "r\t%" #TARGET_OPNO "%/") \
|
||||
: REG_P (OPERANDS[TARGET_OPNO]) \
|
||||
? "%*" INSN "r\t%" #TARGET_OPNO "%/" \
|
||||
: MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
|
||||
|
||||
/* Control the assembler format that we output. */
|
||||
|
||||
|
|
|
@ -75,6 +75,9 @@
|
|||
(UNSPEC_EHB 52)
|
||||
(UNSPEC_RDPGPR 53)
|
||||
(UNSPEC_COP0 54)
|
||||
;; Used in a call expression in place of args_size. It's present for PIC
|
||||
;; indirect calls where it contains args_size and the function symbol.
|
||||
(UNSPEC_CALL_ATTR 55)
|
||||
|
||||
(UNSPEC_ADDRESS_FIRST 100)
|
||||
|
||||
|
@ -5981,12 +5984,6 @@
|
|||
;; The register is therefore not a valid register_operand
|
||||
;; and cannot be moved to or from other registers.
|
||||
|
||||
;; Convenience expander that generates the rhs of a load_call<mode> insn.
|
||||
(define_expand "unspec_call<mode>"
|
||||
[(unspec:P [(match_operand:P 0)
|
||||
(match_operand:P 1)
|
||||
(reg:SI GOT_VERSION_REGNUM)] UNSPEC_LOAD_CALL)])
|
||||
|
||||
(define_insn "load_call<mode>"
|
||||
[(set (match_operand:P 0 "register_operand" "=d")
|
||||
(unspec:P [(match_operand:P 1 "register_operand" "d")
|
||||
|
@ -6040,7 +6037,7 @@
|
|||
[(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
|
||||
(match_operand 1 "" ""))]
|
||||
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
||||
{ return MIPS_CALL ("j", operands, 0); }
|
||||
{ return MIPS_CALL ("j", operands, 0, 1); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
(define_expand "sibcall_value"
|
||||
|
@ -6060,7 +6057,7 @@
|
|||
(call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
|
||||
(match_operand 2 "" "")))]
|
||||
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
||||
{ return MIPS_CALL ("j", operands, 1); }
|
||||
{ return MIPS_CALL ("j", operands, 1, 2); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
(define_insn "sibcall_value_multiple_internal"
|
||||
|
@ -6071,7 +6068,7 @@
|
|||
(call (mem:SI (match_dup 1))
|
||||
(match_dup 2)))]
|
||||
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
|
||||
{ return MIPS_CALL ("j", operands, 1); }
|
||||
{ return MIPS_CALL ("j", operands, 1, 2); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
(define_expand "call"
|
||||
|
@ -6128,7 +6125,7 @@
|
|||
(match_operand 1 "" ""))
|
||||
(clobber (reg:SI 31))]
|
||||
""
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0); }
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, 1); }
|
||||
"reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
||||
[(const_int 0)]
|
||||
{
|
||||
|
@ -6143,7 +6140,7 @@
|
|||
(clobber (reg:SI 31))
|
||||
(clobber (reg:SI 28))]
|
||||
"TARGET_SPLIT_CALLS"
|
||||
{ return MIPS_CALL ("jal", operands, 0); }
|
||||
{ return MIPS_CALL ("jal", operands, 0, 1); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
;; A pattern for calls that must be made directly. It is used for
|
||||
|
@ -6156,7 +6153,7 @@
|
|||
(const_int 1)
|
||||
(clobber (reg:SI 31))]
|
||||
""
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0); }
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 0, -1); }
|
||||
"reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
|
||||
[(const_int 0)]
|
||||
{
|
||||
|
@ -6173,7 +6170,7 @@
|
|||
(clobber (reg:SI 31))
|
||||
(clobber (reg:SI 28))]
|
||||
"TARGET_SPLIT_CALLS"
|
||||
{ return MIPS_CALL ("jal", operands, 0); }
|
||||
{ return MIPS_CALL ("jal", operands, 0, -1); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
(define_expand "call_value"
|
||||
|
@ -6195,7 +6192,7 @@
|
|||
(match_operand 2 "" "")))
|
||||
(clobber (reg:SI 31))]
|
||||
""
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); }
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
||||
"reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
||||
[(const_int 0)]
|
||||
{
|
||||
|
@ -6213,7 +6210,7 @@
|
|||
(clobber (reg:SI 31))
|
||||
(clobber (reg:SI 28))]
|
||||
"TARGET_SPLIT_CALLS"
|
||||
{ return MIPS_CALL ("jal", operands, 1); }
|
||||
{ return MIPS_CALL ("jal", operands, 1, 2); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
;; See call_internal_direct.
|
||||
|
@ -6224,7 +6221,7 @@
|
|||
(const_int 1)
|
||||
(clobber (reg:SI 31))]
|
||||
""
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); }
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, -1); }
|
||||
"reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
|
||||
[(const_int 0)]
|
||||
{
|
||||
|
@ -6243,7 +6240,7 @@
|
|||
(clobber (reg:SI 31))
|
||||
(clobber (reg:SI 28))]
|
||||
"TARGET_SPLIT_CALLS"
|
||||
{ return MIPS_CALL ("jal", operands, 1); }
|
||||
{ return MIPS_CALL ("jal", operands, 1, -1); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
;; See comment for call_internal.
|
||||
|
@ -6256,7 +6253,7 @@
|
|||
(match_dup 2)))
|
||||
(clobber (reg:SI 31))]
|
||||
""
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1); }
|
||||
{ return TARGET_SPLIT_CALLS ? "#" : MIPS_CALL ("jal", operands, 1, 2); }
|
||||
"reload_completed && TARGET_SPLIT_CALLS && (operands[4] = insn)"
|
||||
[(const_int 0)]
|
||||
{
|
||||
|
@ -6277,7 +6274,7 @@
|
|||
(clobber (reg:SI 31))
|
||||
(clobber (reg:SI 28))]
|
||||
"TARGET_SPLIT_CALLS"
|
||||
{ return MIPS_CALL ("jal", operands, 1); }
|
||||
{ return MIPS_CALL ("jal", operands, 1, 2); }
|
||||
[(set_attr "type" "call")])
|
||||
|
||||
;; Call subroutine returning any type.
|
||||
|
|
|
@ -244,6 +244,10 @@ mr10k-cache-barrier=
|
|||
Target Joined RejectNegative
|
||||
-mr10k-cache-barrier=SETTING Specify when r10k cache barriers should be inserted
|
||||
|
||||
mrelax-pic-calls
|
||||
Target Report Mask(RELAX_PIC_CALLS)
|
||||
Try to allow the linker to turn PIC calls into direct calls
|
||||
|
||||
mshared
|
||||
Target Report Var(TARGET_SHARED) Init(1)
|
||||
When generating -mabicalls code, make the code suitable for use in shared libraries
|
||||
|
|
|
@ -23687,6 +23687,44 @@ if test $gcc_cv_as_mips_dtprelword = yes; then
|
|||
$as_echo "#define HAVE_AS_DTPRELWORD 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler and linker for explicit JALR relocation" >&5
|
||||
$as_echo_n "checking assembler and linker for explicit JALR relocation... " >&6; }
|
||||
gcc_cv_as_ld_jalr_reloc=no
|
||||
if test $gcc_cv_as_mips_explicit_relocs = yes; then
|
||||
if test $in_tree_ld = yes ; then
|
||||
if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 20 -o "$gcc_cv_gld_major_version" -gt 2 \
|
||||
&& test $in_tree_ld_is_elf = yes; then
|
||||
gcc_cv_as_ld_jalr_reloc=yes
|
||||
fi
|
||||
elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_objdump != x; then
|
||||
echo ' .ent x' > conftest.s
|
||||
echo 'x: ld $2,%got_disp(y)($3)' >> conftest.s
|
||||
echo ' ld $25,%call16(y)($28)' >> conftest.s
|
||||
echo ' .reloc 1f,R_MIPS_JALR,y' >> conftest.s
|
||||
echo '1: jalr $25' >> conftest.s
|
||||
echo ' .reloc 1f,R_MIPS_JALR,x' >> conftest.s
|
||||
echo '1: jalr $25' >> conftest.s
|
||||
echo ' .end x' >> conftest.s
|
||||
if $gcc_cv_as -o conftest.o conftest.s >/dev/null 2>&5 \
|
||||
&& $gcc_cv_ld -shared -o conftest.so conftest.o >/dev/null 2>&5; then
|
||||
if $gcc_cv_objdump -d conftest.so | grep -q jalr \
|
||||
&& $gcc_cv_objdump -d conftest.so | grep -q "bal.*<x>"; then
|
||||
gcc_cv_as_ld_jalr_reloc=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest.*
|
||||
fi
|
||||
fi
|
||||
if test $gcc_cv_as_ld_jalr_reloc = yes; then
|
||||
if test x$target_cpu_default = x; then
|
||||
target_cpu_default=MASK_RELAX_PIC_CALLS
|
||||
else
|
||||
target_cpu_default="($target_cpu_default)|MASK_RELAX_PIC_CALLS"
|
||||
fi
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_ld_jalr_reloc" >&5
|
||||
$as_echo "$gcc_cv_as_ld_jalr_reloc" >&6; }
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
|
@ -3279,6 +3279,42 @@ x:
|
|||
.dtprelword x+0x8000],,
|
||||
[AC_DEFINE(HAVE_AS_DTPRELWORD, 1,
|
||||
[Define if your assembler supports .dtprelword.])])
|
||||
|
||||
AC_MSG_CHECKING(assembler and linker for explicit JALR relocation)
|
||||
gcc_cv_as_ld_jalr_reloc=no
|
||||
if test $gcc_cv_as_mips_explicit_relocs = yes; then
|
||||
if test $in_tree_ld = yes ; then
|
||||
if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 20 -o "$gcc_cv_gld_major_version" -gt 2 \
|
||||
&& test $in_tree_ld_is_elf = yes; then
|
||||
gcc_cv_as_ld_jalr_reloc=yes
|
||||
fi
|
||||
elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_objdump != x; then
|
||||
echo ' .ent x' > conftest.s
|
||||
echo 'x: ld $2,%got_disp(y)($3)' >> conftest.s
|
||||
echo ' ld $25,%call16(y)($28)' >> conftest.s
|
||||
echo ' .reloc 1f,R_MIPS_JALR,y' >> conftest.s
|
||||
echo '1: jalr $25' >> conftest.s
|
||||
echo ' .reloc 1f,R_MIPS_JALR,x' >> conftest.s
|
||||
echo '1: jalr $25' >> conftest.s
|
||||
echo ' .end x' >> conftest.s
|
||||
if $gcc_cv_as -o conftest.o conftest.s >/dev/null 2>&AS_MESSAGE_LOG_FD \
|
||||
&& $gcc_cv_ld -shared -o conftest.so conftest.o >/dev/null 2>&AS_MESSAGE_LOG_FD; then
|
||||
if $gcc_cv_objdump -d conftest.so | grep -q jalr \
|
||||
&& $gcc_cv_objdump -d conftest.so | grep -q "bal.*<x>"; then
|
||||
gcc_cv_as_ld_jalr_reloc=yes
|
||||
fi
|
||||
fi
|
||||
rm -f conftest.*
|
||||
fi
|
||||
fi
|
||||
if test $gcc_cv_as_ld_jalr_reloc = yes; then
|
||||
if test x$target_cpu_default = x; then
|
||||
target_cpu_default=MASK_RELAX_PIC_CALLS
|
||||
else
|
||||
target_cpu_default="($target_cpu_default)|MASK_RELAX_PIC_CALLS"
|
||||
fi
|
||||
fi
|
||||
AC_MSG_RESULT($gcc_cv_as_ld_jalr_reloc)
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
|
@ -705,7 +705,8 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-mflush-func=@var{func} -mno-flush-func @gol
|
||||
-mbranch-cost=@var{num} -mbranch-likely -mno-branch-likely @gol
|
||||
-mfp-exceptions -mno-fp-exceptions @gol
|
||||
-mvr4130-align -mno-vr4130-align -msynci -mno-synci}
|
||||
-mvr4130-align -mno-vr4130-align -msynci -mno-synci @gol
|
||||
-mrelax-pic-calls -mno-relax-pic-calls}
|
||||
|
||||
@emph{MMIX Options}
|
||||
@gccoptlist{-mlibfuncs -mno-libfuncs -mepsilon -mno-epsilon -mabi=gnu @gol
|
||||
|
@ -13906,6 +13907,20 @@ When compiling code for single processor systems, it is generally safe
|
|||
to use @code{synci}. However, on many multi-core (SMP) systems, it
|
||||
will not invalidate the instruction caches on all cores and may lead
|
||||
to undefined behavior.
|
||||
|
||||
@item -mrelax-pic-calls
|
||||
@itemx -mno-relax-pic-calls
|
||||
@opindex mrelax-pic-calls
|
||||
Try to turn PIC calls that are normally dispatched via register
|
||||
@code{$25} into direct calls. This is only possible if the linker can
|
||||
resolve the destination at link-time and if the destination is within
|
||||
range for a direct call.
|
||||
|
||||
@option{-mrelax-pic-calls} is the default if GCC was configured to use
|
||||
an assembler and a linker that supports the @code{.reloc} assembly
|
||||
directive and @code{-mexplicit-relocs} is in effect. With
|
||||
@code{-mno-explicit-relocs}, this optimization can be performed by the
|
||||
assembler and the linker alone without help from the compiler.
|
||||
@end table
|
||||
|
||||
@node MMIX Options
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
2009-09-19 Adam Nemet <anemet@caviumnetworks.com>
|
||||
|
||||
* gcc.target/mips/mips.exp: Add relax-pic-calls
|
||||
under -mfoo/-mno-foo options.
|
||||
(mips-dg-options): Make -mrelax-pic-calls imply -mno-plt, -mabicalls
|
||||
and -mexplicit-relocs.
|
||||
* gcc.target/mips/call-1.c: New test.
|
||||
* gcc.target/mips/call-2.c: New test.
|
||||
* gcc.target/mips/call-3.c: New test.
|
||||
* gcc.target/mips/lazy-binding-1.c: Add MIPS-specific dg-options.
|
||||
* gcc.dg/tree-ssa/loop-1.c: Likewise.
|
||||
|
||||
2009-09-19 Chris Demetriou <cgd@google.com>
|
||||
|
||||
PR preprocessor/28435:
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
/* On MIPS, disable generating hints (R_MIPS_JALR) for PIC calls. In addition
|
||||
to the load from the GOT this also contains the name of the funtion so for
|
||||
each call the function name would appear twice. */
|
||||
/* { dg-options "-O2 -mno-relax-pic-calls" { target mips*-*-* } } */
|
||||
|
||||
extern void *memset (void *, int, __SIZE_TYPE__);
|
||||
extern __SIZE_TYPE__ strlen (const char *);
|
||||
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
of PIC mode. */
|
||||
/* { dg-options "-O1 -ftree-loop-ivcanon -funroll-loops -fdump-tree-ivcanon-details -fdump-tree-cunroll-details -fdump-tree-optimized -static" { target *-*-darwin* } } */
|
||||
|
||||
/* On MIPS, disable generating hints (R_MIPS_JALR) for PIC calls. In addition
|
||||
to the load from the GOT this also contains the name of the funtion so for
|
||||
each call the function name would appear twice. */
|
||||
/* { dg-options "-O1 -ftree-loop-ivcanon -funroll-loops -fdump-tree-ivcanon-details -fdump-tree-cunroll-details -fdump-tree-optimized -mno-relax-pic-calls" { target mips*-*-* } } */
|
||||
|
||||
void xxx(void)
|
||||
{
|
||||
int x = 45;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* { dg-options "-O2 -mrelax-pic-calls -mshared" } */
|
||||
/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal\n1:\tjalr\t" } } */
|
||||
/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,normal2\n1:\tjalr\t" } } */
|
||||
/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,staticfunc\n1:\tjalr\t" } } */
|
||||
/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail\n1:\tjr\t" } } */
|
||||
/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,tail2\n1:\tjr\t" } } */
|
||||
|
||||
__attribute__ ((noinline)) static void staticfunc () { asm (""); }
|
||||
int normal ();
|
||||
void normal2 ();
|
||||
|
||||
NOMIPS16 f (int *p)
|
||||
{
|
||||
*p = normal ();
|
||||
normal2 ();
|
||||
staticfunc ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tail ();
|
||||
|
||||
NOMIPS16 h ()
|
||||
{
|
||||
return tail ();
|
||||
}
|
||||
|
||||
void tail2 ();
|
||||
|
||||
NOMIPS16 void g ()
|
||||
{
|
||||
tail2 ();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/* See through some simple data-flow. */
|
||||
/* { dg-options "-O2 -mrelax-pic-calls" } */
|
||||
/* { dg-final { scan-assembler-times "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalr\t" 3 } } */
|
||||
|
||||
NOMIPS16 f (int i)
|
||||
{
|
||||
while (i--)
|
||||
g ();
|
||||
}
|
||||
|
||||
NOMIPS16 ff ()
|
||||
{
|
||||
g ();
|
||||
g ();
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/* { dg-options "-O2 -mrelax-pic-calls -mno-shared" } */
|
||||
/* { dg-final { scan-assembler "\\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalr\t" } } */
|
||||
|
||||
__attribute__ ((visibility ("hidden"))) void g ();
|
||||
|
||||
NOMIPS16 f ()
|
||||
{
|
||||
g ();
|
||||
return 1;
|
||||
}
|
|
@ -262,6 +262,7 @@ foreach option {
|
|||
smartmips
|
||||
sym32
|
||||
synci
|
||||
relax-pic-calls
|
||||
} {
|
||||
lappend mips_option_groups $option "-m(no-|)$option"
|
||||
}
|
||||
|
@ -773,6 +774,8 @@ proc mips-dg-finish {} {
|
|||
# | |
|
||||
# -mno-sym32 -msym32
|
||||
# | |
|
||||
# -mrelax-pic-calls -mno-relax-pic-calls
|
||||
# | |
|
||||
# -fpic -fno-pic
|
||||
# | |
|
||||
# -mshared -mno-shared
|
||||
|
@ -833,6 +836,9 @@ proc mips-dg-options { args } {
|
|||
mips_option_dependency options "-mips3d" "-mpaired-single"
|
||||
mips_option_dependency options "-mpaired-single" "-mfp64"
|
||||
mips_option_dependency options "-mfp64" "-mhard-float"
|
||||
mips_option_dependency options "-mrelax-pic-calls" "-mno-plt"
|
||||
mips_option_dependency options "-mrelax-pic-calls" "-mabicalls"
|
||||
mips_option_dependency options "-mrelax-pic-calls" "-mexplicit-relocs"
|
||||
mips_option_dependency options "-fpic" "-mshared"
|
||||
mips_option_dependency options "-mshared" "-mno-plt"
|
||||
mips_option_dependency options "-mno-plt" "addressing=unknown"
|
||||
|
|
Loading…
Reference in New Issue