This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add support for R_MIPS_JALR


This patch implements what we discussed on the binutils list here:

  http://sourceware.org/ml/binutils/2009-08/msg00008.html

It now uses DF to match up the indirect calls with the register loads.  This
is what I've concluded to be the best approach after the thread:

  http://www.nabble.com/Using-MEM_EXPR-inside-a-call-expression-td25185417.html

Notes:

  * After DF determines the call symbol I need to save it somewhere until
  asm-output time.  After considering many things (MEM_EXPR, REG_EXPR,
  CALL_INSN_FUNCTION_USAGE, explicit use in the parallel) I decided to extend
  the opaque args-size operand of the call expression into an optional
  call-attributes field and stick the symbol there.  So now the second op of a
  call-expr can hold an UNSPEC_CALL_ATTR or args-size as before.  As you can
  see, this allows very little change to mips.md and MIPS_CALL.

  This patch will clash with Richard's gp-restore patch (at least the
  MIPS_CALL) part but I don't see any major issues fixing the clashes.

  * I had to tweak CFG recreation in md_reorg.  We need this before splitting
  insns if the DF will be used.  See the comment in mips_reorg.

  * %call16/UNSPEC_LOAD_CALL loads don't have a corresponding REG_EQUAL of the
  symbol they load.  This is understandable as these can resolve to
  lazy-binding stubs.  Therefore I need to actually look inside these to find
  the symbol.  This is basically the inverse operation of the code
  constructing these expressions so I moved the construction code from a
  define_expand to C code.

  * I added a new option for this feature.  Its logic is quite similar
  to -mexplicit-relocs.  Here too the default is autoconf-detected based on
  binutils.  Also having the flag makes it easy to test this feature even if
  the given target does not pass the config test.

  I also disable the flag in override_options if we're not required to make
  $25 live on entry to functions in general.

  * The autoconf test to detect support for .reloc ,R_MIPS_JALR is actually a
  testcase for both of the bugs I fixed in binutils recently.  Analogously I
  require binutils 2.20.

  * I've set up the dependencies for the new flag in mips.exp.

  * Two generic tests needed updating because now the function name can appear
  twice for each call in the assembly.  In loop-1.c I need to change the xfail
  selector to target so I guess that needs approval from Janis.  I will submit
  that separately as well.

  * A minor thing regarding the DF code, maybe we should turn:

	  use = df_find_use (def_insn, regno_reg_rtx[REGNO (src)]);
	  if (!use)
	    return NULL_RTX;
	  defs = DF_REF_CHAIN (use);

    into a little helper.  I use this twice and the r10k_insert_cache_barriers
    code also uses it.  Thoughts?

Bootstrapped and regtested on mips64octeon-linux-gnu.  5486 JALRs are
converted to BALs in cc1 with the patch.

OK to install if there are no surprises after the merge and retest with the
gp-restore check-in?

Adam


	* 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.
	* 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 -mexplicit-relocs
	and -mno-plt.
	* 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
	scan-assmebler-not.
	* gcc.dg/tree-ssa/loop-1.c: Change generic scan-assembler-times
	selector from xfail to target.  Add MIPS-specific
	scan-assembler-times.

Index: gcc/config/mips/mips.opt
===================================================================
--- gcc.orig/config/mips/mips.opt	2009-09-11 15:12:17.000000000 -0700
+++ gcc/config/mips/mips.opt	2009-09-11 15:32:59.000000000 -0700
@@ -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 turn PIC (indirect) 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
Index: gcc/config/mips/mips.c
===================================================================
--- gcc.orig/config/mips/mips.c	2009-09-11 15:32:53.000000000 -0700
+++ gcc/config/mips/mips.c	2009-09-14 12:34:04.000000000 -0700
@@ -2490,6 +2490,20 @@ mips_unspec_address (rtx address, enum m
   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.
@@ -2581,6 +2595,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.  */
 
@@ -2600,9 +2636,7 @@ mips_got_load (rtx temp, rtx addr, enum 
   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)
@@ -5865,7 +5899,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:
 
@@ -6063,7 +6097,7 @@ mips16_build_call_stub (rtx retval, rtx 
 	     $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.  */
@@ -6955,20 +6989,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.  */
 
@@ -12654,6 +12674,15 @@ mips16_rewrite_pool_refs (rtx *x, void *
   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
@@ -12666,7 +12695,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))
@@ -13002,14 +13034,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);
 
@@ -13088,10 +13112,183 @@ 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;
+
+  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))
+	{
+	  df_ref use;
+	  struct df_link *defs;
+
+	  use = df_find_use (def_insn, regno_reg_rtx[REGNO (src)]);
+	  if (!use)
+	    return NULL_RTX;
+	  defs = DF_REF_CHAIN (use);
+	  if (defs && defs->next == NULL)
+	    return mips_pic_call_symbol_from_set (defs->ref, 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);
 
-  free_bb_for_insn ();
+  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);
+      /* Don't check for PIC_FUNCTION_ADDR_REGNUM here.  MIPS16 calls through
+	 one of the MIPS16 regs.  */
+      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.  */
@@ -13765,14 +13962,42 @@ mips_reorg_process_insns (void)
   htab_delete (htab);
 }
 
+/* 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 ();
@@ -14564,6 +14789,10 @@ mips_override_options (void)
       target_flags &= ~MASK_SYNCI;
     }
 
+  /* Only optimize PIC indirect calls if they are actually required.  */
+  if (!TARGET_USE_PIC_FN_ADDR_REG)
+    target_flags &= ~MASK_RELAX_PIC_CALLS;
+
   /* Save base state of options.  */
   mips_base_target_flags = target_flags;
   mips_base_schedule_insns = flag_schedule_insns;
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc.orig/config/mips/mips-protos.h	2009-09-11 15:12:17.000000000 -0700
+++ gcc/config/mips/mips-protos.h	2009-09-11 15:32:59.000000000 -0700
@@ -230,6 +230,7 @@ extern void mips_expand_conditional_trap
 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);
Index: gcc/config/mips/mips.h
===================================================================
--- gcc.orig/config/mips/mips.h	2009-09-11 15:12:17.000000000 -0700
+++ gcc/config/mips/mips.h	2009-09-12 23:41:35.000000000 -0700
@@ -2667,24 +2667,31 @@ #define MIPS_BRANCH(OPCODE, OPERANDS) \
   "%*" OPCODE "%?\t" OPERANDS "%/"
 
 /* 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 "%/"				\
+   ? "%*" 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 "%/"				\
    : TARGET_ABICALLS_PIC2					\
    ? (".option\tpic0\n\t"					\
-      "%*" INSN "\t%" #OPNO "%/\n\t"				\
+      "%*" INSN "\t%" #TARGET_OPNO "%/\n\t"			\
       ".option\tpic2")						\
-   : "%*" INSN "\t%" #OPNO "%/")
+   : "%*" INSN "\t%" #TARGET_OPNO "%/")
 
 /* Control the assembler format that we output.  */
 
Index: gcc/config/mips/mips.md
===================================================================
--- gcc.orig/config/mips/mips.md	2009-09-11 15:12:17.000000000 -0700
+++ gcc/config/mips/mips.md	2009-09-11 15:32:59.000000000 -0700
@@ -73,6 +73,9 @@ (define_constants
    (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)
 
@@ -5890,12 +5893,6 @@ (define_insn_and_split "restore_gp"
 ;;	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")
@@ -5949,7 +5946,7 @@ (define_insn "sibcall_internal"
   [(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"
@@ -5969,7 +5966,7 @@ (define_insn "sibcall_value_internal"
         (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"
@@ -5980,7 +5977,7 @@ (define_insn "sibcall_value_multiple_int
 	(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"
@@ -6037,7 +6034,7 @@ (define_insn_and_split "call_internal"
 	 (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)]
 {
@@ -6052,7 +6049,7 @@ (define_insn "call_split"
    (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
@@ -6065,7 +6062,7 @@ (define_insn_and_split "call_internal_di
    (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)]
 {
@@ -6082,7 +6079,7 @@ (define_insn "call_direct_split"
    (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"
@@ -6104,7 +6101,7 @@ (define_insn_and_split "call_value_inter
               (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)]
 {
@@ -6122,7 +6119,7 @@ (define_insn "call_value_split"
    (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.
@@ -6133,7 +6130,7 @@ (define_insn_and_split "call_value_inter
    (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)]
 {
@@ -6152,7 +6149,7 @@ (define_insn "call_value_direct_split"
    (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.
@@ -6165,7 +6162,7 @@ (define_insn_and_split "call_value_multi
 	      (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)]
 {
@@ -6186,7 +6183,7 @@ (define_insn "call_value_multiple_split"
    (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.
Index: gcc/configure.ac
===================================================================
--- gcc.orig/configure.ac	2009-09-11 15:12:17.000000000 -0700
+++ gcc/configure.ac	2009-09-11 15:32:59.000000000 -0700
@@ -3277,6 +3277,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
 
Index: gcc/doc/invoke.texi
===================================================================
--- gcc.orig/doc/invoke.texi	2009-09-11 15:12:17.000000000 -0700
+++ gcc/doc/invoke.texi	2009-09-11 15:32:59.000000000 -0700
@@ -701,7 +701,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
@@ -13816,6 +13817,20 @@ When compiling code for single processor
 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 desination 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
Index: gcc/testsuite/gcc.target/mips/mips.exp
===================================================================
--- gcc.orig/testsuite/gcc.target/mips/mips.exp	2009-09-11 15:12:17.000000000 -0700
+++ gcc/testsuite/gcc.target/mips/mips.exp	2009-09-14 11:50:55.000000000 -0700
@@ -235,6 +235,7 @@ foreach option {
     smartmips
     sym32
     synci
+    relax-pic-calls
 } {
     lappend mips_option_groups $option "-m(no-|)$option"
 }
@@ -746,6 +747,8 @@ proc mips-dg-finish {} {
 #            |                           |
 #         -mno-sym32                  -msym32
 #            |                           |
+#         -mrelax-pic-calls           -mno-relax-pic-calls
+#            |                           |
 #         -fpic                       -fno-pic
 #            |                           |
 #         -mshared                    -mno-shared
@@ -806,6 +809,8 @@ 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" "-mexplicit-relocs"
+    mips_option_dependency options "-mrelax-pic-calls" "-mno-plt"
     mips_option_dependency options "-fpic" "-mshared"
     mips_option_dependency options "-mshared" "-mno-plt"
     mips_option_dependency options "-mno-plt" "addressing=unknown"
Index: gcc/testsuite/gcc.target/mips/call-1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.target/mips/call-1.c	2009-09-12 14:45:10.000000000 -0700
@@ -0,0 +1,32 @@
+/* { dg-options "-O2 -mrelax-pic-calls -mabicalls -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 ();
+
+f (int *p)
+{
+  *p = normal ();
+  normal2 ();
+  staticfunc ();
+  return 1;
+}
+
+int tail ();
+
+NOMIPS16 h ()
+{
+  return tail ();
+}
+
+void tail2 ();
+
+NOMIPS16 void g ()
+{
+  tail2 ();
+}
Index: gcc/testsuite/gcc.target/mips/call-2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.target/mips/call-2.c	2009-09-14 11:51:50.000000000 -0700
@@ -0,0 +1,16 @@
+/* See through some simple data-flow.  */
+/* { dg-options "-O2 -mrelax-pic-calls -mabicalls" } */
+/* { dg-final { scan-assembler-times "\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalr\t" 3 } } */
+
+f (int i)
+{
+  while (i--)
+    g ();
+}
+
+ff ()
+{
+  g ();
+  g ();
+  return 1;
+}
Index: gcc/testsuite/gcc.target/mips/call-3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gcc/testsuite/gcc.target/mips/call-3.c	2009-09-14 12:22:51.000000000 -0700
@@ -0,0 +1,10 @@
+/* { dg-options "-O2 -mrelax-pic-calls -mabicalls -mno-shared" } */
+/* { dg-final { scan-assembler "\.reloc\t1f,R_MIPS_JALR,g\n1:\tjalr\t" } } */
+
+__attribute__ ((visibility ("hidden"))) void g ();
+
+f ()
+{
+  g ();
+  return 1;
+}
Index: gcc/testsuite/gcc.dg/pr27095.c
===================================================================
--- gcc.orig/testsuite/gcc.dg/pr27095.c	2009-09-11 15:12:17.000000000 -0700
+++ gcc/testsuite/gcc.dg/pr27095.c	2009-09-11 15:32:59.000000000 -0700
@@ -11,7 +11,7 @@ main (int argc, char **argv)
   memset (x, argc, strlen (x));
   return 0;
 }
-/* { dg-final { scan-assembler-not "(?n)strlen\(.*\n\)+.*strlen" { target { ! { powerpc*-*-darwin* hppa*-*-hpux* ia64-*-hpux* alpha*-*-* spu-*-* } } } } } */
+/* { dg-final { scan-assembler-not "(?n)strlen\(.*\n\)+.*strlen" { target { ! { powerpc*-*-darwin* hppa*-*-hpux* ia64-*-hpux* alpha*-*-* spu-*-* mips*-*-* } } } } } */
 /* hppa*-*-hpux* has an IMPORT statement for strlen (plus the branch). */
 /* *-*-darwin* has something similar. */
 /* { dg-final { scan-assembler-not "(?n)strlen\(.*\n\)+.*strlen\(.*\n\)+.*strlen" { target hppa*-*-hpux* } } } */
@@ -22,3 +22,5 @@ main (int argc, char **argv)
 /* { dg-final { scan-assembler-not "(?n)jsr .*,strlen\(.*\n\)+.*jsr .*,strlen" { target alpha*-*-* } } } */
 /* spu-*-* has a branch hint and the call.  */
 /* { dg-final { scan-assembler-not "(?n)brsl.*,strlen\(.*\n\)+.*brsl.*,strlen" { target spu-*-* } } } */
+/* mips*-*-* can also have a branch hint (R_MIPS_JALR) and the call.  */
+/* { dg-final { scan-assembler-not "(?n)jal\tstrlen\(.*\n\)+.*jal\tstrlen" { target mips*-*-* } } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/loop-1.c
===================================================================
--- gcc.orig/testsuite/gcc.dg/tree-ssa/loop-1.c	2009-09-11 15:12:17.000000000 -0700
+++ gcc/testsuite/gcc.dg/tree-ssa/loop-1.c	2009-09-11 15:32:59.000000000 -0700
@@ -38,11 +38,13 @@ void xxx(void)
    relaxation.  */
 /* CRIS keeps the address in a register.  */
 /* m68k sometimes puts the address in a register, depending on CPU and PIC.  */
+/* mips can have a branch hint (R_MIPS_JALR) and the call.  */
 
-/* { dg-final { scan-assembler-times "foo" 5 { xfail hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* } } } */
+/* { dg-final { scan-assembler-times "foo" 5 { target { ! { hppa*-*-* ia64*-*-* sh*-*-* cris-*-* crisv32-*-* fido-*-* m68k-*-* i?86-*-mingw* i?86-*-cygwin* mips*-*-* } } } } } */
 /* { dg-final { scan-assembler-times "foo,%r" 5 { target hppa*-*-* } } } */
 /* { dg-final { scan-assembler-times "= foo"  5 { target ia64*-*-* } } } */
 /* { dg-final { scan-assembler-times "call\[ \t\]*_foo" 5 { target i?86-*-mingw* i?86-*-cygwin* } } } */
 /* { dg-final { scan-assembler-times "jsr|bsrf|blink\ttr?,r18"  5 { target sh*-*-* } } } */
 /* { dg-final { scan-assembler-times "Jsr \\\$r" 5 { target cris-*-* } } } */
 /* { dg-final { scan-assembler-times "\[jb\]sr" 5 { target fido-*-* m68k-*-* } } } */
+/* { dg-final { scan-assembler-times "\tjalr?\t" 5 { target mips*-*-* } } } */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]