diff options
-rw-r--r-- | gcc/ChangeLog | 50 | ||||
-rw-r--r-- | gcc/config/mips/mips-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/mips/mips.c | 286 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 21 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 35 | ||||
-rw-r--r-- | gcc/config/mips/mips.opt | 4 | ||||
-rwxr-xr-x | gcc/configure | 38 | ||||
-rw-r--r-- | gcc/configure.ac | 36 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 17 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr27095.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/loop-1.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/mips/call-1.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/mips/call-2.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/mips/call-3.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/mips/mips.exp | 6 |
16 files changed, 515 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index bc78ee3..656df2a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 91fa729..abcc2d4 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -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); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 2b0df8f..2f0c56d 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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; + + if (!CALL_P (insn)) + return NULL_RTX; - free_bb_for_insn (); + 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; diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index eda7447..71b9b1b 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -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. */ diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 4e1e785..19f3ffc 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -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. diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt index 9038125..8462e46 100644 --- a/gcc/config/mips/mips.opt +++ b/gcc/config/mips/mips.opt @@ -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 diff --git a/gcc/configure b/gcc/configure index 2e9385e..2369ba7 100755 --- a/gcc/configure +++ b/gcc/configure @@ -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 diff --git a/gcc/configure.ac b/gcc/configure.ac index ca6e3c2..d1eed72 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ad8e51c..5a547e2 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 301dfbb..c2841f6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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: diff --git a/gcc/testsuite/gcc.dg/pr27095.c b/gcc/testsuite/gcc.dg/pr27095.c index d274f4e..8e72771 100644 --- a/gcc/testsuite/gcc.dg/pr27095.c +++ b/gcc/testsuite/gcc.dg/pr27095.c @@ -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 *); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c index a3d409e..a843048 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-1.c @@ -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; diff --git a/gcc/testsuite/gcc.target/mips/call-1.c b/gcc/testsuite/gcc.target/mips/call-1.c new file mode 100644 index 0000000..7dceefa --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-1.c @@ -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 (); +} diff --git a/gcc/testsuite/gcc.target/mips/call-2.c b/gcc/testsuite/gcc.target/mips/call-2.c new file mode 100644 index 0000000..8e74991 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-2.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/mips/call-3.c b/gcc/testsuite/gcc.target/mips/call-3.c new file mode 100644 index 0000000..b552b61 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/call-3.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp index a7a6bd5..aef473f 100644 --- a/gcc/testsuite/gcc.target/mips/mips.exp +++ b/gcc/testsuite/gcc.target/mips/mips.exp @@ -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" |