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]

Committed, CRIS: Minor rewrite of PIC support.


Now uses UNSPEC wrapping the PIC constants, and "real" RTL for the rest,
where previously e.g. a symbol_ref for a global object symbol was kept
as-was in PIC and only emitted in asm as [R0+symbol:GOT]; not modelling the
GOT memory access or the R0 ("PIC offset table" register) dependency.

Exposing memory accesses and register usage is in preparation for CRISv32
support, but was observed to shave a few k's in size from libstdc++.so as
well.  *In general* it *should* yield better code, but I haven't asserted
that in any tests and I certainly observed *some* code regressions
inspecting libstdc++.so.  Usual suspects in such cases (besides incomplete
target costs) are bb-reorder and register allocation.

Tested cross to cris-axis-linux-gnu cris-sim/\{-mno-gotplt,\}\{-fpic,-fPIC\}
and regtested plain as well.  (All with -static, so no actual DSO's were
used.)  There was one kind-of-regression for which I add PR 22382; "FAIL:
gfortran.fortran-torture/execute/common.f90 execution, -O2".  That test
fails *without -fpic and friends* on all above -O0 baseline cross from
x86_64-unknown-linux-gnu (FC4t3) with "Thu Jun 30 14:21:26 UTC 2005" and
passes with "Fri Jul 8 06:17:12 UTC 2005" on i686-pc-linux-gnu (FC2), and
passes for the latter with -fpic too.  Might be a 64-bit thing lurking
somewhere.  Some compilation failures appearing on baseline with -fpic were
fixed (see case 'd' comment below).  A GAS bug (gas/1049) was observed with
this patch, fixed as well.

I also took the opportunity to remove the "last" warning from cris.c, see
below.

	Rewrite PIC support to more closely model actual instructions.
	* config/cris/cris-protos.h (cris_gotless_symbol, cris_got_symbol)
	(cris_symbol): Remove prototypes for removed functions.
	(cris_pic_symbol_type_of, cris_valid_pic_const)
	(cris_expand_pic_call_address): Prototypes for new functions.
	* config/cris/cris/cris.c (cris_pic_sympart_only): Remove unused
	variable.
	(cris_print_operand) <case 'v', 'P'>: Remove cases for unused
	modifiers.
	<case ':'>: Add case for new punctuation character.
	<case 'd'>: Temporarily set flag_pic = 2 instead of incorrectly
	emitting (extra) PIC modifier.
	<case UNSPEC>: Do not assert for PLT.
	(cris_initial_frame_pointer_offset, cris_simple_epilogue)
	(cris_expand_prologue, cris_expand_epilogue): Check
	for pic_offset_table_rtx usage instead of taking
	current_function_uses_pic_offset_table as the final word.
	(cris_rtx_costs, cris_address_cost, cris_side_effect_mode_ok):
	Remove flag_pic difference.
	(cris_valid_pic_const, cris_pic_symbol_type_of): New functions,
	the moral equivalents of...
	(cris_symbol, cris_gotless_symbol, cris_got_symbol): Remove
	functions.
	(cris_legitimate_pic_operand): Just call cris_valid_pic_const.
	(cris_handle_option): Mark ARG as unused.
	(cris_expand_pic_call_address): New worker function for "call",
	"call_value".
	(cris_asm_output_symbol_ref, cris_asm_output_label_ref): Do not
	output PIC constructs here.
	(cris_output_addr_const_extra): Changes for emitting PIC modifiers
	as symbol-specific modifers, not whole or part of operands.
	* config/cris/cris/cris.h (EXTRA_CONSTRAINT): Remove 'U' case.
	(EXTRA_CONSTRAINT_S): Changed semantics: allow only CONST-wrapped
	constants and flag_pic.
	(CONSTANT_INDEX_P): Adjust for new functions.
	(enum cris_pic_symbol_type): New helper type.
	(PRINT_OPERAND_PUNCT_VALID_P): Add ':'.
	* config/cris/cris/cris.md (CRIS_UNSPEC_GOTREL)
	(CRIS_UNSPEC_GOTREAD, CRIS_UNSPEC_PLTGOTREAD): New
	define_constants.
	("movsi"): Emit actual instructions for GOT and relative access.
	("*movsi_got_load"): New pattern to set up the register holding
	the GOT pointer.
	("*movsi_internal"): Operand 1 is not a plain general_operand.
	Adjust FIXME for 'S'.
	<output for 'S' alternative>: Sanity-check UNSPEC types for PIC.
	Use "movs" for -fpic cases.
	("addsi3"): Add alternative for 'S'; use adds.w when possible.
	("uminsi3","*expanded_call_value"): Remove 'S' alternative.
	("call", "call_value"): Just call cris_expand_pic_call_address for
	PIC addresses.
	("*expanded_call_no_gotplt", "*expanded_call_value_no_gotplt"):
	Remove special pattern.
	("*expanded_call_side", "*expanded_call_value_side"): New
	patterns.
	(gotplt-to-plt, gotplt-to-plt-side-call)
	(gotplt-to-plt-side-call-value, gotplt-to-plt-side): New
	peephole2:s.
	* config/cris/cris/predicates.md
	("cris_general_operand_or_gotless_symbol"): Remove unused
	predicate.
	("cris_general_operand_or_symbol"): Adjust for new functions.

Index: cris-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris-protos.h,v
retrieving revision 1.20
diff -p -u -r1.20 cris-protos.h
--- cris-protos.h	25 Jun 2005 01:21:01 -0000	1.20
+++ cris-protos.h	7 Jul 2005 11:42:44 -0000
@@ -38,9 +38,8 @@ extern int cris_side_effect_mode_ok (enu
 extern rtx cris_return_addr_rtx (int, rtx);
 extern rtx cris_split_movdx (rtx *);
 extern int cris_legitimate_pic_operand (rtx);
-extern int cris_gotless_symbol (rtx);
-extern int cris_got_symbol (rtx);
-extern int cris_symbol (rtx);
+extern enum cris_pic_symbol_type cris_pic_symbol_type_of (rtx);
+extern bool cris_valid_pic_const (rtx);
 extern bool cris_store_multiple_op_p (rtx);
 extern bool cris_movem_load_rest_p (rtx, int);
 extern void cris_asm_output_symbol_ref (FILE *, rtx);
@@ -48,6 +47,7 @@ extern bool cris_output_addr_const_extra
 extern int cris_cfun_uses_pic_table (void);
 extern rtx cris_gen_movem_load (rtx, rtx, int);
 extern rtx cris_emit_movem_store (rtx, rtx, int, bool);
+extern void cris_expand_pic_call_address (rtx *);
 #endif /* RTX_CODE */
 extern void cris_asm_output_label_ref (FILE *, char *);
 extern void cris_target_asm_named_section (const char *, unsigned int, tree);
Index: cris.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.c,v
retrieving revision 1.78
diff -p -u -r1.78 cris.c
--- cris.c	25 Jun 2005 01:21:01 -0000	1.78
+++ cris.c	7 Jul 2005 11:42:46 -0000
@@ -82,12 +82,6 @@ struct machine_function GTY(())
    pattern.  */
 static char cris_output_insn_is_bound = 0;
 
-/* This one suppresses printing out the "rPIC+" in
-   "rPIC+sym:GOTOFF+offset" when doing PIC.  For a PLT symbol, it
-   suppresses outputting it as [rPIC+sym:GOTPLT] and outputs similarly
-   just the "sym:GOTOFF" part.  */
-static int cris_pic_sympart_only = 0;
-
 /* In code for output macros, this is how we know whether e.g. constant
    goes in code or in a static initializer.  */
 static int in_code = 0;
@@ -681,15 +675,6 @@ cris_print_operand (FILE *file, rtx x, i
       fprintf (file, "%s", cris_op_str (operand));
       return;
 
-    case 'v':
-      /* Print the operand without the PIC register.  */
-      if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x))
-	LOSE_AND_RETURN ("invalid operand for 'v' modifier", x);
-      cris_pic_sympart_only++;
-      cris_output_addr_const (file, x);
-      cris_pic_sympart_only--;
-      return;
-
     case 'o':
       {
 	/* A movem modifier working on a parallel; output the register
@@ -746,14 +731,6 @@ cris_print_operand (FILE *file, rtx x, i
       }
       return;
 
-    case 'P':
-      /* Print the PIC register.  Applied to a GOT-less PIC symbol for
-         sanity.  */
-      if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x))
-	LOSE_AND_RETURN ("invalid operand for 'P' modifier", x);
-      fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-      return;
-
     case 'p':
       /* Adjust a power of two to its log2.  */
       if (GET_CODE (x) != CONST_INT || exact_log2 (INTVAL (x)) < 0 )
@@ -824,6 +801,13 @@ cris_print_operand (FILE *file, rtx x, i
 	       : ".p2alignw 5,0x050f,2\n\t", file);
       return;
 
+    case ':':
+      /* The PIC register.  */
+      if (! flag_pic)
+	internal_error ("invalid use of ':' modifier");
+      fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+      return;
+
     case 'H':
       /* Print high (most significant) part of something.  */
       switch (GET_CODE (operand))
@@ -934,11 +918,16 @@ cris_print_operand (FILE *file, rtx x, i
       return;
 
     case 'd':
-      /* If this is a GOT symbol, print it as :GOT regardless of -fpic.  */
-      if (flag_pic && CONSTANT_P (operand) && cris_got_symbol (operand))
+      /* If this is a GOT symbol, force it to be emitted as :GOT and
+	 :GOTPLT regardless of -fpic (i.e. not as :GOT16, :GOTPLT16).
+	 Avoid making this too much of a special case.  */
+      if (flag_pic == 1 && CONSTANT_P (operand))
 	{
+	  int flag_pic_save = flag_pic;
+
+	  flag_pic = 2;
 	  cris_output_addr_const (file, operand);
-	  fprintf (file, ":GOT");
+	  flag_pic = flag_pic_save;
 	  return;
 	}
       break;
@@ -1009,9 +998,7 @@ cris_print_operand (FILE *file, rtx x, i
       return;
 
     case UNSPEC:
-      ASSERT_PLT_UNSPEC (operand);
       /* Fall through.  */
-
     case CONST:
       cris_output_addr_const (file, operand);
       return;
@@ -1147,7 +1134,16 @@ cris_initial_frame_pointer_offset (void)
 
   /* Initial offset is 0 if we don't have a frame pointer.  */
   int offs = 0;
-  bool got_really_used = current_function_uses_pic_offset_table;
+  bool got_really_used = false;
+
+  if (current_function_uses_pic_offset_table)
+    {
+      push_topmost_sequence ();
+      got_really_used
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (),
+			      NULL_RTX);
+      pop_topmost_sequence ();
+    }
 
   /* And 4 for each register pushed.  */
   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
@@ -1479,7 +1475,7 @@ cris_simple_epilogue (void)
 {
   unsigned int regno;
   unsigned int reglimit = STACK_POINTER_REGNUM;
-  bool got_really_used = current_function_uses_pic_offset_table;
+  bool got_really_used = false;
 
   if (! reload_completed
       || frame_pointer_needed
@@ -1494,6 +1490,14 @@ cris_simple_epilogue (void)
       || !TARGET_PROLOGUE_EPILOGUE)
     return false;
 
+  if (current_function_uses_pic_offset_table)
+    {
+      push_topmost_sequence ();
+      got_really_used
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL_RTX);
+      pop_topmost_sequence ();
+    }
+
   /* No simple epilogue if there are saved registers.  */
   for (regno = 0; regno < reglimit; regno++)
     if (cris_reg_saved_in_regsave_area (regno, got_really_used))
@@ -1555,18 +1559,7 @@ cris_rtx_costs (rtx x, int code, int out
 
     case CONST:
     case SYMBOL_REF:
-      /* For PIC, we need a prefix (if it isn't already there),
-	 and the PIC register.  For a global PIC symbol, we also
-	 need a read of the GOT.  */
-      if (flag_pic)
-	{
-	  if (cris_got_symbol (x))
-	    *total = 2 + 4 + 6;
-	  else
-	    *total = 2 + 6;
-	}
-      else
-	*total = 6;
+      *total = 6;
       return true;
 
     case CONST_DOUBLE:
@@ -1651,12 +1644,9 @@ cris_address_cost (rtx x)
     return (2 + 4) / 2;
 
   /* Assume (2 + 4) / 2 for a single constant; a dword, since it needs
-     an extra DIP prefix and 4 bytes of constant in most cases.
-     For PIC and a symbol with a GOT entry, we double the cost since we
-     add a [rPIC+...] offset.  A GOT-less symbol uses a BDAP prefix
-     equivalent to the DIP prefix for non-PIC, hence the same cost.  */
+     an extra DIP prefix and 4 bytes of constant in most cases.  */
   if (CONSTANT_P (x))
-    return flag_pic && cris_got_symbol (x) ? 2 * (2 + 4) / 2 : (2 + 4) / 2;
+    return (2 + 4) / 2;
 
   /* Handle BIAP and BDAP prefixes.  */
   if (GET_CODE (x) == PLUS)
@@ -1783,10 +1773,9 @@ cris_side_effect_mode_ok (enum rtx_code 
 	  && (INTVAL (val_rtx) <= 63 && INTVAL (val_rtx) >= -63))
 	return 0;
 
-      /* Check allowed cases, like [r(+)?].[bwd] and const.
-	 A symbol is not allowed with PIC.  */
+      /* Check allowed cases, like [r(+)?].[bwd] and const.  */
       if (CONSTANT_P (val_rtx))
-	return flag_pic == 0 || cris_symbol (val_rtx) == 0;
+	return 1;
 
       if (GET_CODE (val_rtx) == MEM
 	  && BASE_OR_AUTOINCR_P (XEXP (val_rtx, 0)))
@@ -1855,162 +1844,104 @@ cris_target_asm_named_section (const cha
     default_elf_asm_named_section (name, flags, decl);
 }
 
-/* The LEGITIMATE_PIC_OPERAND_P worker.  */
+/* Return TRUE iff X is a CONST valid for e.g. indexing.  */
 
-int
-cris_legitimate_pic_operand (rtx x)
+bool
+cris_valid_pic_const (rtx x)
 {
-  /* The PIC representation of a symbol with a GOT entry will be (for
-     example; relocations differ):
-      sym => [rPIC+sym:GOT]
-     and for a GOT-less symbol it will be (for example, relocation differ):
-      sym => rPIC+sym:GOTOFF
-     so only a symbol with a GOT is by itself a valid operand, and it
-     can't be a sum of a symbol and an offset.  */
-  return ! cris_symbol (x) || cris_got_symbol (x);
-}
-
-/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
-   CONSTANT_P.  */
+  gcc_assert (flag_pic);
 
-int
-cris_symbol (rtx x)
-{
   switch (GET_CODE (x))
     {
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
-
-    case UNSPEC:
-      if (XINT (x, 1) == CRIS_UNSPEC_GOT || XINT (x, 1) != CRIS_UNSPEC_PLT)
-	return 0;
-      /* A PLT reference.  */
-      ASSERT_PLT_UNSPEC (x);
-      return 1;
-
-    case CONST:
-      return cris_symbol (XEXP (x, 0));
-
-    case PLUS:
-    case MINUS:
-      return cris_symbol (XEXP (x, 0)) || cris_symbol (XEXP (x, 1));
-
     case CONST_INT:
     case CONST_DOUBLE:
-      return 0;
-
+      return true;
     default:
-      fatal_insn ("unrecognized supposed constant", x);
+      ;
     }
 
-  return 1;
+  if (GET_CODE (x) != CONST)
+    return false;
+
+  x = XEXP (x, 0);
+
+  /* Handle (const (plus (unspec .. UNSPEC_GOTREL) (const_int ...))).  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == UNSPEC
+      && XINT (XEXP (x, 0), 1) == CRIS_UNSPEC_GOTREL
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    x = XEXP (x, 0);
+
+  if (GET_CODE (x) == UNSPEC)
+    switch (XINT (x, 1))
+      {
+      case CRIS_UNSPEC_PLT:
+      case CRIS_UNSPEC_PLTGOTREAD:
+      case CRIS_UNSPEC_GOTREAD:
+      case CRIS_UNSPEC_GOTREL:
+	return true;
+      default:
+	gcc_unreachable ();
+      }
+
+  return cris_pic_symbol_type_of (x) == cris_no_symbol;
 }
 
-/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
-   CONSTANT_P, and the symbol does not need a GOT entry.  Also set
-   current_function_uses_pic_offset_table if we're generating PIC and ever
-   see something that would need one.  */
+/* Helper function to find the right PIC-type symbol to generate,
+   given the original (non-PIC) representation.  */
 
-int
-cris_gotless_symbol (rtx x)
+enum cris_pic_symbol_type
+cris_pic_symbol_type_of (rtx x)
 {
-  CRIS_ASSERT (flag_pic);
-
   switch (GET_CODE (x))
     {
-    case UNSPEC:
-      if (XINT (x, 1) == CRIS_UNSPEC_GOT)
-	return 1;
-      if (XINT (x, 1) != CRIS_UNSPEC_PLT)
-	return 0;
-      ASSERT_PLT_UNSPEC (x);
-      return 1;
-
     case SYMBOL_REF:
-      if (cfun != NULL)
-	current_function_uses_pic_offset_table = 1;
-      return SYMBOL_REF_LOCAL_P (x);
+      return SYMBOL_REF_LOCAL_P (x)
+	? cris_gotrel_symbol : cris_got_symbol;
 
     case LABEL_REF:
-      /* We don't set current_function_uses_pic_offset_table for
-	 LABEL_REF:s in here, since they are almost always originating
-	 from some branch.  The only time it does not come from a label is
-	 when GCC does something like __builtin_setjmp.  Then we get the
-	 LABEL_REF from the movsi expander, so we mark it there as a
-	 special case.  */
-      return 1;
+      return cris_gotrel_symbol;
 
     case CONST:
-      return cris_gotless_symbol (XEXP (x, 0));
+      return cris_pic_symbol_type_of (XEXP (x, 0));
 
     case PLUS:
     case MINUS:
       {
-	int x0 = cris_gotless_symbol (XEXP (x, 0)) != 0;
-	int x1 = cris_gotless_symbol (XEXP (x, 1)) != 0;
+	enum cris_pic_symbol_type t1 = cris_pic_symbol_type_of (XEXP (x, 0));
+	enum cris_pic_symbol_type t2 = cris_pic_symbol_type_of (XEXP (x, 1));
+
+	gcc_assert (t1 == cris_no_symbol || t2 == cris_no_symbol);
+
+	if (t1 == cris_got_symbol || t1 == cris_got_symbol)
+	  return cris_got_symbol_needing_fixup;
 
-	/* One and only one of them must be a local symbol.  Neither must
-	   be some other, more general kind of symbol.  */
-	return
-	  (x0 ^ x1)
-	  && ! (x0 == 0 && cris_symbol (XEXP (x, 0)))
-	  && ! (x1 == 0 && cris_symbol (XEXP (x, 1)));
+	return t1 != cris_no_symbol ? t1 : t2;
       }
 
     case CONST_INT:
     case CONST_DOUBLE:
-      return 0;
+      return cris_no_symbol;
+
+    case UNSPEC:
+      /* Likely an offsettability-test attempting to add a constant to
+	 a GOTREAD symbol, which can't be handled.  */
+      return cris_invalid_pic_symbol;
 
     default:
       fatal_insn ("unrecognized supposed constant", x);
     }
 
-  return 1;
+  gcc_unreachable ();
 }
 
-/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
-   CONSTANT_P, and the symbol needs a GOT entry.  */
+/* The LEGITIMATE_PIC_OPERAND_P worker.  */
 
 int
-cris_got_symbol (rtx x)
+cris_legitimate_pic_operand (rtx x)
 {
-  CRIS_ASSERT (flag_pic);
-
-  switch (GET_CODE (x))
-    {
-    case UNSPEC:
-      if (XINT (x, 1) == CRIS_UNSPEC_GOT)
-	return 0;
-      ASSERT_PLT_UNSPEC (x);
-      return 0;
-
-    case SYMBOL_REF:
-      if (cfun != NULL)
-	current_function_uses_pic_offset_table = 1;
-      return ! SYMBOL_REF_LOCAL_P (x);
-
-    case CONST:
-      return cris_got_symbol (XEXP (x, 0));
-
-    case LABEL_REF:
-      /* A LABEL_REF is never visible as a symbol outside the local
-         function.  */
-    case PLUS:
-    case MINUS:
-      /* Nope, can't access the GOT for "symbol + offset".  */
-      return 0;
-
-    case CONST_INT:
-    case CONST_DOUBLE:
-      return 0;
-
-    default:
-      fatal_insn ("unrecognized supposed constant in cris_global_pic_symbol",
-		  x);
-    }
-
-  return 1;
+  /* Symbols are not valid PIC operands as-is; just constants.  */
+  return cris_valid_pic_const (x);
 }
 
 /* TARGET_HANDLE_OPTION worker.  We just store the values into local
@@ -2018,7 +1949,8 @@ cris_got_symbol (rtx x)
    cris_override_options.  */
 
 static bool
-cris_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+cris_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
+		    int value ATTRIBUTE_UNUSED)
 {
   switch (code)
     {
@@ -2435,7 +2367,7 @@ cris_expand_prologue (void)
   int framesize = 0;
   rtx mem, insn;
   int return_address_on_stack = cris_return_address_on_stack ();
-  int got_really_used = current_function_uses_pic_offset_table;
+  int got_really_used = false;
   int n_movem_regs = 0;
   int pretend = current_function_pretend_args_size;
 
@@ -2445,6 +2377,17 @@ cris_expand_prologue (void)
 
   CRIS_ASSERT (size >= 0);
 
+  if (current_function_uses_pic_offset_table)
+    {
+      /* A reference may have been optimized out (like the abort () in
+	 fde_split in unwind-dw2-fde.c, at least 3.2.1) so check that
+	 it's still used.  */
+      push_topmost_sequence ();
+      got_really_used
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL_RTX);
+      pop_topmost_sequence ();
+    }
+
   /* Align the size to what's best for the CPU model.  */
   if (TARGET_STACK_ALIGN)
     size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
@@ -2707,12 +2650,23 @@ cris_expand_epilogue (void)
   /* A reference may have been optimized out
      (like the abort () in fde_split in unwind-dw2-fde.c, at least 3.2.1)
      so check that it's still used.  */
-  int got_really_used = current_function_uses_pic_offset_table;
+  int got_really_used = false;
   int n_movem_regs = 0;
 
   if (!TARGET_PROLOGUE_EPILOGUE)
     return;
 
+  if (current_function_uses_pic_offset_table)
+    {
+      /* A reference may have been optimized out (like the abort () in
+	 fde_split in unwind-dw2-fde.c, at least 3.2.1) so check that
+	 it's still used.  */
+      push_topmost_sequence ();
+      got_really_used
+	= reg_used_between_p (pic_offset_table_rtx, get_insns (), NULL_RTX);
+      pop_topmost_sequence ();
+    }
+
   /* Align byte count of stack frame.  */
   if (TARGET_STACK_ALIGN)
     size = TARGET_ALIGN_BY_32 ? (size + 3) & ~3 : (size + 1) & ~1;
@@ -3053,6 +3007,93 @@ cris_emit_movem_store (rtx dest, rtx nre
   return insn;
 }
 
+/* Worker function for expanding the address for PIC function calls.  */
+
+void
+cris_expand_pic_call_address (rtx *opp)
+{
+  rtx op = *opp;
+
+  gcc_assert (MEM_P (op));
+  op = XEXP (op, 0);
+
+  /* It might be that code can be generated that jumps to 0 (or to a
+     specific address).  Don't die on that.  (There is a
+     testcase.)  */
+  if (CONSTANT_ADDRESS_P (op) && GET_CODE (op) != CONST_INT)
+    {
+      enum cris_pic_symbol_type t = cris_pic_symbol_type_of (op);
+
+      CRIS_ASSERT (!no_new_pseudos);
+
+      /* For local symbols (non-PLT), just get the plain symbol
+	 reference into a register.  For symbols that can be PLT, make
+	 them PLT.  */
+      if (t == cris_gotrel_symbol)
+	op = force_reg (Pmode, op);
+      else if (t == cris_got_symbol)
+	{
+	  if (TARGET_AVOID_GOTPLT)
+	    {
+	      /* Change a "jsr sym" into (allocate register rM, rO)
+		 "move.d (const (unspec [sym] CRIS_UNSPEC_PLT)),rM"
+		 "add.d rPIC,rM,rO", "jsr rO".  */
+	      rtx tem, rm, ro;
+	      gcc_assert (! no_new_pseudos);
+	      current_function_uses_pic_offset_table = 1;
+	      tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), CRIS_UNSPEC_PLT);
+	      rm = gen_reg_rtx (Pmode);
+	      emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+	      ro = gen_reg_rtx (Pmode);
+	      if (expand_binop (Pmode, add_optab, rm,
+				pic_offset_table_rtx,
+				ro, 0, OPTAB_LIB_WIDEN) != ro)
+		internal_error ("expand_binop failed in movsi got");
+	      op = ro;
+	    }
+	  else
+	    {
+	      /* Change a "jsr sym" into (allocate register rM, rO)
+		 "move.d (const (unspec [sym] CRIS_UNSPEC_PLTGOT)),rM"
+		 "add.d rPIC,rM,rO" "jsr [rO]" with the memory access
+		 marked as not trapping and not aliasing.  No "move.d
+		 [rO],rP" as that would invite to re-use of a value
+		 that should not be reused.  FIXME: Need a peephole2
+		 for cases when this is cse:d from the call, to change
+		 back to just get the PLT entry address, so we don't
+		 resolve the same symbol over and over (the memory
+		 access of the PLTGOT isn't constant).  */
+	      rtx tem, mem, rm, ro;
+
+	      gcc_assert (! no_new_pseudos);
+	      current_function_uses_pic_offset_table = 1;
+	      tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op),
+				    CRIS_UNSPEC_PLTGOTREAD);
+	      rm = gen_reg_rtx (Pmode);
+	      emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+	      ro = gen_reg_rtx (Pmode);
+	      if (expand_binop (Pmode, add_optab, rm,
+				pic_offset_table_rtx,
+				ro, 0, OPTAB_LIB_WIDEN) != ro)
+		internal_error ("expand_binop failed in movsi got");
+	      mem = gen_rtx_MEM (Pmode, ro);
+
+	      /* This MEM doesn't alias anything.  Whether it aliases
+		 other same symbols is unimportant.  */
+	      set_mem_alias_set (mem, new_alias_set ());
+	      MEM_NOTRAP_P (mem) = 1;
+	      op = mem;
+	    }
+	}
+      else
+	/* Can't possibly get a GOT-needing-fixup for a function-call,
+	   right?  */
+	fatal_insn ("Unidentifiable call op", op);
+
+      *opp = replace_equiv_address (*opp, op);
+    }
+}
+
 /* Use from within code, from e.g. PRINT_OPERAND and
    PRINT_OPERAND_ADDRESS.  Macros used in output_addr_const need to emit
    different things depending on whether code operand or constant is
@@ -3071,38 +3112,18 @@ cris_output_addr_const (FILE *file, rtx 
 void
 cris_asm_output_symbol_ref (FILE *file, rtx x)
 {
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
   if (flag_pic && in_code > 0)
     {
-      const char *origstr = XSTR (x, 0);
-      const char *str;
-
-      str = (* targetm.strip_name_encoding) (origstr);
-
-      if (cris_gotless_symbol (x))
-	{
-	  if (! cris_pic_sympart_only)
-	    fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-	  assemble_name (file, str);
-	  fprintf (file, ":GOTOFF");
-	}
-      else if (cris_got_symbol (x))
-	{
-	  CRIS_ASSERT (!cris_pic_sympart_only);
-
-	  fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-	  assemble_name (file, XSTR (x, 0));
-
-	  if (flag_pic == 1)
-	    fprintf (file, ":GOT16]");
-	  else
-	    fprintf (file, ":GOT]");
-	}
-      else
-	LOSE_AND_RETURN ("unexpected PIC symbol", x);
-
-      /* Sanity check.  */
-      if (! current_function_uses_pic_offset_table)
-	output_operand_lossage ("PIC register isn't set up");
+     const char *origstr = XSTR (x, 0);
+     const char *str;
+     str = (* targetm.strip_name_encoding) (origstr);
+     assemble_name (file, str);
+
+     /* Sanity check.  */
+     if (! current_function_uses_pic_offset_table)
+       output_operand_lossage ("PIC register isn't set up");
     }
   else
     assemble_name (file, XSTR (x, 0));
@@ -3115,12 +3136,8 @@ cris_asm_output_label_ref (FILE *file, c
 {
   if (flag_pic && in_code > 0)
     {
-      if (! cris_pic_sympart_only)
-	fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
       assemble_name (file, buf);
 
-      fprintf (file, ":GOTOFF");
-
       /* Sanity check.  */
       if (! current_function_uses_pic_offset_table)
 	internal_error ("emitting PIC operand, but PIC register isn't set up");
@@ -3132,34 +3149,44 @@ cris_asm_output_label_ref (FILE *file, c
 /* Worker function for OUTPUT_ADDR_CONST_EXTRA.  */
 
 bool
-cris_output_addr_const_extra (FILE *file, rtx x)
+cris_output_addr_const_extra (FILE *file, rtx xconst)
 {
-  switch (GET_CODE (x))
+  switch (GET_CODE (xconst))
     {
-      const char *origstr;
-      const char *str;
+      rtx x;
 
     case UNSPEC:
-      ASSERT_PLT_UNSPEC (x);
-      x = XVECEXP (x, 0, 0);
-      origstr = XSTR (x, 0);
-      str = (* targetm.strip_name_encoding) (origstr);
-      if (cris_pic_sympart_only)
+      x = XVECEXP (xconst, 0, 0);
+      CRIS_ASSERT (GET_CODE (x) == SYMBOL_REF
+		   || GET_CODE (x) == LABEL_REF
+		   || GET_CODE (x) == CONST);
+      output_addr_const (file, x);
+      switch (XINT (xconst, 1))
 	{
-	  assemble_name (file, str);
+	case CRIS_UNSPEC_PLT:
 	  fprintf (file, ":PLTG");
-	}
-      else
-	{
-	  CRIS_ASSERT (!TARGET_AVOID_GOTPLT);
+	  break;
 
-	  fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
-	  assemble_name (file, XSTR (x, 0));
+	case CRIS_UNSPEC_GOTREL:
+	  fprintf (file, ":GOTOFF");
+	  break;
 
+	case CRIS_UNSPEC_GOTREAD:
 	  if (flag_pic == 1)
-	    fprintf (file, ":GOTPLT16]");
+	    fprintf (file, ":GOT16");
 	  else
-	    fprintf (file, ":GOTPLT]");
+	    fprintf (file, ":GOT");
+	  break;
+
+	case CRIS_UNSPEC_PLTGOTREAD:
+	  if (flag_pic == 1)
+	    fprintf (file, CRIS_GOTPLT_SUFFIX "16");
+	  else
+	    fprintf (file, CRIS_GOTPLT_SUFFIX);
+	  break;
+
+	default:
+	  gcc_unreachable ();
 	}
       return true;
 
Index: cris.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.h,v
retrieving revision 1.97
diff -p -u -r1.97 cris.h
--- cris.h	26 Jun 2005 05:18:28 -0000	1.97
+++ cris.h	7 Jul 2005 11:42:47 -0000
@@ -615,8 +615,6 @@ enum reg_class 
   (C) == 'S' ? EXTRA_CONSTRAINT_S (X) :		\
   /* A three-address addressing-mode?  */	\
   (C) == 'T' ? EXTRA_CONSTRAINT_T (X) :		\
-  /* A global PIC symbol?  */			\
-  (C) == 'U' ? EXTRA_CONSTRAINT_U (X) :		\
   0)
 
 #define EXTRA_MEMORY_CONSTRAINT(X, STR) ((X) == 'Q')
@@ -666,16 +664,9 @@ enum reg_class 
 		  && BIAP_INDEX_P (XEXP (XEXP (X, 0), 0))))))		\
  )
 
-/* We're kind of out of constraints, so we use "S" for both gotless
-   symbols and the GOT-address load.  Both must go in a general register
-   only: for pre-V32, arithmetic is done on the destination.  */
+/* PIC-constructs for symbols.  */
 #define EXTRA_CONSTRAINT_S(X)						\
- (flag_pic								\
-  && ((CONSTANT_P (X) && cris_gotless_symbol (X))			\
-      || (GET_CODE (X) == UNSPEC && XINT ((X), 1) == CRIS_UNSPEC_GOT)))
-
-#define EXTRA_CONSTRAINT_U(X) \
- (flag_pic && CONSTANT_P (X) && cris_got_symbol (X))
+ (flag_pic && GET_CODE (X) == CONST && cris_valid_pic_const (X))
 
 
 /* Node: Frame Layout */
@@ -937,7 +928,7 @@ struct cum_args {int regs;};
 /* No symbol can be used as an index (or more correct, as a base) together
    with a register with PIC; the PIC register must be there.  */
 #define CONSTANT_INDEX_P(X) \
- (CONSTANT_P (X) && !(flag_pic && cris_symbol (X)))
+ (CONSTANT_P (X) && (!flag_pic || cris_valid_pic_const (X)))
 
 /* True if X is a valid base register.  */
 #define BASE_P(X) \
@@ -984,10 +975,7 @@ struct cum_args {int regs;};
    rtx x1, x2;							\
    if (SIMPLE_ADDRESS_P (X))					\
      goto ADDR;							\
-   if (CONSTANT_P (X)						\
-       && (! flag_pic						\
-	   || cris_gotless_symbol (X)				\
-	   || ! cris_symbol (X)))				\
+   if (CONSTANT_INDEX_P (X))					\
      goto ADDR;							\
    /* Indexed?  */						\
    if (GET_CODE (X) == PLUS)					\
@@ -1131,6 +1119,17 @@ struct cum_args {int regs;};
 
 /* Node: PIC */
 
+/* Helper type.  */
+
+enum cris_pic_symbol_type
+  {
+    cris_no_symbol = 0,
+    cris_got_symbol = 1,
+    cris_gotrel_symbol = 2,
+    cris_got_symbol_needing_fixup = 3,
+    cris_invalid_pic_symbol = 4
+  };
+
 #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? CRIS_GOT_REGNUM : INVALID_REGNUM)
 
 #define LEGITIMATE_PIC_OPERAND_P(X) cris_legitimate_pic_operand (X)
@@ -1257,7 +1256,7 @@ struct cum_args {int regs;};
 
 /* For delay-slot handling.  */
 #define PRINT_OPERAND_PUNCT_VALID_P(CODE)	\
- ((CODE) == '#' || (CODE) == '!')
+ ((CODE) == '#' || (CODE) == '!' || (CODE) == ':')
 
 #define PRINT_OPERAND_ADDRESS(FILE, ADDR)	\
    cris_print_operand_address (FILE, ADDR)
Index: cris.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/cris.md,v
retrieving revision 1.36
diff -p -u -r1.36 cris.md
--- cris.md	25 Jun 2005 01:21:01 -0000	1.36
+++ cris.md	7 Jul 2005 11:42:49 -0000
@@ -60,11 +60,17 @@
 ;;   the mode is VOIDmode.  Always wrapped in CONST.
 ;; 1 Stack frame deallocation barrier.
 ;; 2 The address of the global offset table as a source operand.
+;; 3 The address of a global-offset-table-relative symbol + offset.
+;; 4 The offset within GOT of a symbol.
+;; 5 The offset within GOT of a symbol that has a PLT.
 
-(define_constants
+(define_constants ; FIXME: reorder sanely.
   [(CRIS_UNSPEC_PLT 0)
    (CRIS_UNSPEC_FRAME_DEALLOC 1)
-   (CRIS_UNSPEC_GOT 2)])
+   (CRIS_UNSPEC_GOT 2)
+   (CRIS_UNSPEC_GOTREL 3)
+   (CRIS_UNSPEC_GOTREAD 4)
+   (CRIS_UNSPEC_PLTGOTREAD 5)])
 
 ;; Register numbers.
 (define_constants
@@ -768,64 +774,114 @@
      FIXME: Do we *have* to recognize anything that would normally be a
      valid symbol?  Can we exclude global PIC addresses with an added
      offset?  */
-  if (flag_pic
-      && CONSTANT_ADDRESS_P (operands[1])
-      && cris_symbol (operands[1]))
-    {
-      /* We must have a register as destination for what we're about to
-	 do, and for the patterns we generate.  */
-      if (! REG_S_P (operands[0]))
-	{
-	  CRIS_ASSERT (!no_new_pseudos);
-	  operands[1] = force_reg (SImode, operands[1]);
-	}
-      else
-	{
-	  /* Mark a needed PIC setup for a LABEL_REF:s coming in here:
-	     they are so rare not-being-branch-targets that we don't mark
-	     a function as needing PIC setup just because we have
-	     inspected LABEL_REF:s as operands.  It is only in
-	     __builtin_setjmp and such that we can get a LABEL_REF
-	     assigned to a register.  */
-	  if (GET_CODE (operands[1]) == LABEL_REF)
+    if (flag_pic
+	&& CONSTANT_ADDRESS_P (operands[1])
+	&& !cris_valid_pic_const (operands[1]))
+      {
+	enum cris_pic_symbol_type t = cris_pic_symbol_type_of (operands[1]);
+
+	gcc_assert (t != cris_no_symbol);
+
+	if (! REG_S_P (operands[0]))
+	  {
+	    /* We must have a register as destination for what we're about to
+	       do, and for the patterns we generate.  */
+	    CRIS_ASSERT (!no_new_pseudos);
+	    operands[1] = force_reg (SImode, operands[1]);
+	  }
+	else
+	  {
+	    /* FIXME: add a REG_EQUAL (or is it REG_EQUIV) note to the
+	       destination register for the symbol.  It might not be
+	       worth it.  Measure.  */
 	    current_function_uses_pic_offset_table = 1;
-
-	  /* We don't have to do anything for global PIC operands; they
-	     look just like ``[rPIC+sym]''.  */
-	  if (! cris_got_symbol (operands[1])
-	      /* We don't do anything for local PIC operands; we match
-		 that with a special alternative.  */
-	      && ! cris_gotless_symbol (operands[1]))
-	    {
-	      /* We get here when we have to change something that would
-		 be recognizable if it wasn't PIC.  A ``sym'' is ok for
-		 PIC symbols both with and without a GOT entry.  And ``sym
-		 + offset'' is ok for local symbols, so the only thing it
-		 could be, is a global symbol with an offset.  Check and
-		 abort if not.  */
-	      rtx sym = get_related_value (operands[1]);
-	      HOST_WIDE_INT offs = get_integer_term (operands[1]);
-
-	      CRIS_ASSERT (sym != NULL_RTX && offs != 0);
-
-	      emit_move_insn (operands[0], sym);
-	      if (expand_binop (SImode, add_optab, operands[0],
-				GEN_INT (offs), operands[0], 0,
-				OPTAB_LIB_WIDEN) != operands[0])
-	        internal_error ("expand_binop failed in movsi");
-	      DONE;
-	    }
-	}
-    }
-})
+	    if (t == cris_gotrel_symbol)
+	      {
+		/* Change a "move.d sym(+offs),rN" into (allocate register rM)
+		   "move.d (const (plus (unspec [sym]
+		    CRIS_UNSPEC_GOTREL) offs)),rM" "add.d rPIC,rM,rN"  */
+		rtx tem, rm, rn = operands[0];
+		rtx sym = GET_CODE (operands[1]) != CONST
+		  ? operands[1] : get_related_value (operands[1]);
+		HOST_WIDE_INT offs = get_integer_term (operands[1]);
+
+		gcc_assert (! no_new_pseudos);
+		tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym),
+				      CRIS_UNSPEC_GOTREL);
+		if (offs != 0)
+		  tem = plus_constant (tem, offs);
+		rm = gen_reg_rtx (Pmode);
+		emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+	        if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
+				  rn, 0, OPTAB_LIB_WIDEN) != rn)
+		  internal_error ("expand_binop failed in movsi gotrel");
+		DONE;
+	      }
+	    else if (t == cris_got_symbol)
+	      {
+		/* Change a "move.d sym,rN" into (allocate register rM, rO)
+		   "move.d (const (unspec [sym] CRIS_UNSPEC_GOTREAD)),rM"
+		   "add.d rPIC,rM,rO", "move.d [rO],rN" with
+		   the memory access marked as read-only.  */
+		rtx tem, mem, rm, ro, rn = operands[0];
+		gcc_assert (! no_new_pseudos);
+		tem = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, operands[1]),
+				      CRIS_UNSPEC_GOTREAD);
+		rm = gen_reg_rtx (Pmode);
+		emit_move_insn (rm, gen_rtx_CONST (Pmode, tem));
+		ro = gen_reg_rtx (Pmode);
+	        if (expand_binop (Pmode, add_optab, rm, pic_offset_table_rtx,
+				  ro, 0, OPTAB_LIB_WIDEN) != ro)
+		  internal_error ("expand_binop failed in movsi got");
+		mem = gen_rtx_MEM (Pmode, ro);
+
+		/* This MEM doesn't alias anything.  Whether it
+		   aliases other same symbols is unimportant.  */
+		set_mem_alias_set (mem, new_alias_set ());
+		MEM_NOTRAP_P (mem) = 1;
+		MEM_READONLY_P (mem) = 1;
+		emit_move_insn (rn, mem);
+		DONE;
+	      }
+	    else
+	      {
+		/* We get here when we have to change something that would
+		   be recognizable if it wasn't PIC.  A ``sym'' is ok for
+		   PIC symbols both with and without a GOT entry.  And ``sym
+		   + offset'' is ok for local symbols, so the only thing it
+		   could be, is a global symbol with an offset.  Check and
+		   abort if not.  */
+		rtx reg = gen_reg_rtx (Pmode);
+		rtx sym = get_related_value (operands[1]);
+		HOST_WIDE_INT offs = get_integer_term (operands[1]);
+
+		gcc_assert (! no_new_pseudos
+			    && t == cris_got_symbol_needing_fixup
+			    && sym != NULL_RTX && offs != 0);
+
+		emit_move_insn (reg, sym);
+		if (expand_binop (SImode, add_optab, reg,
+				  GEN_INT (offs), operands[0], 0,
+				  OPTAB_LIB_WIDEN) != operands[0])
+		  internal_error ("expand_binop failed in movsi got+offs");
+		DONE;
+	      }
+	  }
+      }
+})
+
+(define_insn "*movsi_got_load"
+  [(set (reg:SI CRIS_GOT_REGNUM) (unspec:SI [(const_int 0)] CRIS_UNSPEC_GOT))]
+  "flag_pic"
+  "move.d $pc,%:\;sub.d .:GOTOFF,%:"
+  [(set_attr "cc" "clobber")])
 
 (define_insn "*movsi_internal"
   [(set
     (match_operand:SI 0 "nonimmediate_operand" "=r,r, r,Q>,r,Q>,g,r,r, r,g,rQ>,x,  m,x")
-    (match_operand:SI 1
-    ;; FIXME: We want to put S last, but apparently g matches S.
-    ;; It's a bug: an S is not a general_operand and shouldn't match g.
-     "cris_general_operand_or_gotless_symbol"   "r,Q>,M,M, I,r, M,n,!S,g,r,x,  rQ>,x,gi"))]
+    ;; Note that we prefer not to use the S alternative (if for some reason
+    ;; it competes with others), but g matches S.
+    (match_operand:SI 1 "general_operand"	"r,Q>,M,M, I,r, M,n,!S,g,r,x,  rQ>,x,gi"))]
   ""
 {
   /* Better to have c-switch here; it is worth it to optimize the size of
@@ -872,32 +928,32 @@
       return "move.d %1,%0";
 
     case 8:
-      /* FIXME: Try and split this into pieces GCC makes better code of,
-	 than this multi-insn pattern.  Synopsis: wrap the GOT-relative
-	 symbol into an unspec, and when PIC, recognize the unspec
-	 everywhere a symbol is normally recognized.  (The PIC register
-	 should be recognized by GCC as pic_offset_table_rtx when needed
-	 and similar for PC.)  Each component can then be optimized with
-	 the rest of the code; it should be possible to have a constant
-	 term added on an unspec.  Don't forget to add a REG_EQUAL (or
-	 is it REG_EQUIV) note to the destination.  It might not be
-	 worth it.  Measure.
-
-	 Note that the 'v' modifier makes PLT references be output as
-	 sym:PLT rather than [rPIC+sym:GOTPLT].  */
-      if (GET_CODE (operands[1]) == UNSPEC
-	  && XINT (operands[1], 1) == CRIS_UNSPEC_GOT)
-	{
-	  /* We clobber cc0 rather than set it to GOT.  Should not
-             matter, though.  */
-	  CC_STATUS_INIT;
-	  CRIS_ASSERT (REGNO (operands[0]) == PIC_OFFSET_TABLE_REGNUM);
-
-	  return "move.d $pc,%0\;sub.d .:GOTOFF,%0";
-	}
-
-      return "move.d %v1,%0\;add.d %P1,%0";
-
+      {
+	rtx tem = operands[1];
+	gcc_assert (GET_CODE (tem) == CONST);
+	tem = XEXP (tem, 0);
+	if (GET_CODE (tem) == PLUS
+	    && GET_CODE (XEXP (tem, 0)) == UNSPEC
+	    && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
+	    && GET_CODE (XEXP (tem, 1)) == CONST_INT)
+	  tem = XEXP (tem, 0);
+	gcc_assert (GET_CODE (tem) == UNSPEC);
+	switch (XINT (tem, 1))
+	  {
+	  case CRIS_UNSPEC_GOTREAD:
+	  case CRIS_UNSPEC_PLTGOTREAD:
+	    /* Using sign-extend mostly to be consistent with the
+	       indexed addressing mode.  */
+	    if (flag_pic == 1)
+	      return "movs.w %1,%0";
+	  case CRIS_UNSPEC_GOTREL:
+	  case CRIS_UNSPEC_PLT:
+	    return "move.d %1,%0";
+
+	  default:
+	    gcc_unreachable ();
+	  }
+      }
     default:
       return "BOGUS: %1 to %0";
     }
@@ -1346,10 +1402,10 @@
    add.d %M2,%M1,%M0\;ax\;add.d %H2,%H1,%H0")
 
 (define_insn "addsi3"
-  [(set (match_operand:SI 0 "register_operand"  "=r,r, r,r,r,r,r,  r")
+  [(set (match_operand:SI 0 "register_operand"  "=r,r, r,r,r,r, r,r,  r")
 	(plus:SI
-	 (match_operand:SI 1 "register_operand" "%0,0, 0,0,0,0,r,  r")
-	 (match_operand:SI 2 "general_operand"   "r,Q>,J,N,n,g,!To,0")))]
+	 (match_operand:SI 1 "register_operand" "%0,0, 0,0,0,0, 0,r,  r")
+	 (match_operand:SI 2 "general_operand"   "r,Q>,J,N,n,!S,g,!To,0")))]
 
 ;; The last constraint is due to that after reload, the '%' is not
 ;; honored, and canonicalization doesn't care about keeping the same
@@ -1385,17 +1441,44 @@
 	    return "subu.w %n2,%0";
 	}
       return "add.d %2,%0";
-    case 6:
-      return "add.d %2,%1,%0";
     case 5:
+      {
+	rtx tem = operands[2];
+	gcc_assert (GET_CODE (tem) == CONST);
+	tem = XEXP (tem, 0);
+	if (GET_CODE (tem) == PLUS
+	    && GET_CODE (XEXP (tem, 0)) == UNSPEC
+	    && XINT (XEXP (tem, 0), 1) == CRIS_UNSPEC_GOTREL
+	    && GET_CODE (XEXP (tem, 1)) == CONST_INT)
+	  tem = XEXP (tem, 0);
+	gcc_assert (GET_CODE (tem) == UNSPEC);
+	switch (XINT (tem, 1))
+	  {
+	  case CRIS_UNSPEC_GOTREAD:
+	  case CRIS_UNSPEC_PLTGOTREAD:
+	    /* Using sign-extend mostly to be consistent with the
+	       indexed addressing mode.  */
+	    if (flag_pic == 1)
+	      return "adds.w %2,%0";
+	    /* Fall through.  */
+	  case CRIS_UNSPEC_PLT:
+	  case CRIS_UNSPEC_GOTREL:
+	    return "add.d %2,%0";
+	  default:
+	    gcc_unreachable ();
+	  }
+      }
+    case 6:
       return "add.d %2,%0";
     case 7:
+      return "add.d %2,%1,%0";
+    case 8:
       return "add.d %1,%0";
     default:
       return "BOGUS addsi %2+%1 to %0";
     }
 }
- [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,yes")])
+ [(set_attr "slottable" "yes,yes,yes,yes,no,no,no,no,yes")])
 
 (define_insn "addhi3"
   [(set (match_operand:HI 0 "register_operand"		"=r,r, r,r,r,r")
@@ -2550,7 +2633,7 @@
 (define_insn "uminsi3"
   [(set (match_operand:SI 0 "register_operand"		 "=r,r, r,r")
 	(umin:SI  (match_operand:SI 1 "register_operand" "%0,0, 0,r")
-		  (match_operand:SI 2 "general_operand"   "r,Q>,g,!STo")))]
+		  (match_operand:SI 2 "general_operand"   "r,Q>,g,!To")))]
   ""
 {
   if (GET_CODE (operands[2]) == CONST_INT)
@@ -2761,39 +2844,9 @@
 	      (clobber (reg:SI CRIS_SRP_REGNUM))])]
   ""
 {
-  rtx op0;
-
   gcc_assert (GET_CODE (operands[0]) == MEM);
-
   if (flag_pic)
-    {
-      op0 = XEXP (operands[0], 0);
-
-      /* It might be that code can be generated that jumps to 0 (or to a
-	 specific address).  Don't die on that.  (There is a testcase.)  */
-      if (CONSTANT_ADDRESS_P (op0) && GET_CODE (op0) != CONST_INT)
-	{
-	  CRIS_ASSERT (!no_new_pseudos);
-
-	  /* For local symbols (non-PLT), get the plain symbol reference
-	     into a register.  For symbols that can be PLT, make them PLT.  */
-	  if (cris_gotless_symbol (op0) || GET_CODE (op0) != SYMBOL_REF)
-	    op0 = force_reg (Pmode, op0);
-	  else if (cris_symbol (op0))
-	    /* FIXME: Would hanging a REG_EQUIV/EQUAL on that register
-	       for the symbol cause bad recombinatorial effects?  */
-	    op0 = force_reg (Pmode,
-			     gen_rtx_CONST
-			     (Pmode,
-			      gen_rtx_UNSPEC (VOIDmode,
-					      gen_rtvec (1, op0),
-					      CRIS_UNSPEC_PLT)));
-	  else
-	    internal_error ("Unidentifiable op0");
-
-	  operands[0] = replace_equiv_address (operands[0], op0);
-	}
-    }
+    cris_expand_pic_call_address (&operands[0]);
 })
 
 ;; Accept *anything* as operand 1.  Accept operands for operand 0 in
@@ -2801,22 +2854,30 @@
 
 (define_insn "*expanded_call"
   [(call (mem:QI (match_operand:SI
-		  0 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
-	 (match_operand 1 "" ""))
-   (clobber (reg:SI CRIS_SRP_REGNUM))]
-  "! TARGET_AVOID_GOTPLT"
-  "jsr %0")
-
-;; Same as above, since can't afford wasting a constraint letter to mean
-;; "S unless TARGET_AVOID_GOTPLT".
-(define_insn "*expanded_call_no_gotplt"
-  [(call (mem:QI (match_operand:SI
 		  0 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
 	 (match_operand 1 "" ""))
    (clobber (reg:SI CRIS_SRP_REGNUM))]
-  "TARGET_AVOID_GOTPLT"
+  ""
   "jsr %0")
 
+;; Parallel when calculating and reusing address of indirect pointer
+;; with simple offset.  (Makes most sense with PIC.)  It looks a bit
+;; wrong not to have the clobber last, but that's the way combine
+;; generates it (except it doesn' look into the *inner* mem, so this
+;; just matches a peephole2).  FIXME: investigate that.
+(define_insn "*expanded_call_side"
+  [(call (mem:QI
+	  (mem:SI
+	   (plus:SI (match_operand:SI 0 "cris_bdap_operand" "%r,  r,r")
+		    (match_operand:SI 1 "cris_bdap_operand" "r>Rn,r,>Rn"))))
+	 (match_operand 2 "" ""))
+   (clobber (reg:SI CRIS_SRP_REGNUM))
+   (set (match_operand:SI 3 "register_operand" "=*0,r,r")
+	(plus:SI (match_dup 0)
+		 (match_dup 1)))]
+  "! TARGET_AVOID_GOTPLT"
+  "jsr [%3=%0%S1]")
+
 (define_expand "call_value"
   [(parallel [(set (match_operand 0 "" "")
 		   (call (match_operand:QI 1 "cris_mem_call_operand" "")
@@ -2824,37 +2885,9 @@
 	      (clobber (reg:SI CRIS_SRP_REGNUM))])]
   ""
 {
-  rtx op1;
-
   gcc_assert (GET_CODE (operands[1]) == MEM);
-
   if (flag_pic)
-    {
-      op1 = XEXP (operands[1], 0);
-
-      /* It might be that code can be generated that jumps to 0 (or to a
-	 specific address).  Don't die on that.  (There is a testcase.)  */
-      if (CONSTANT_ADDRESS_P (op1) && GET_CODE (op1) != CONST_INT)
-	{
-	  CRIS_ASSERT (!no_new_pseudos);
-
-	  if (cris_gotless_symbol (op1))
-	    op1 = force_reg (Pmode, op1);
-	  else if (cris_symbol (op1))
-	    /* FIXME: Would hanging a REG_EQUIV/EQUAL on that register
-	       for the symbol cause bad recombinatorial effects?  */
-	    op1 = force_reg (Pmode,
-			     gen_rtx_CONST
-			     (Pmode,
-			      gen_rtx_UNSPEC (VOIDmode,
-					      gen_rtvec (1, op1),
-					      CRIS_UNSPEC_PLT)));
-	  else
-	    internal_error ("Unidentifiable op0");
-
-	  operands[1] = replace_equiv_address (operands[1], op1);
-	}
-    }
+    cris_expand_pic_call_address (&operands[1]);
 })
 
 ;; Accept *anything* as operand 2.  The validity other than "general" of
@@ -2864,25 +2897,30 @@
 ;; than requiring getting rPIC + sym:PLT into a register.
 
 (define_insn "*expanded_call_value"
-  [(set (match_operand 0 "nonimmediate_operand" "=g,g,g,g")
+  [(set (match_operand 0 "nonimmediate_operand" "=g,g,g")
 	(call (mem:QI (match_operand:SI
-		       1 "cris_general_operand_or_plt_symbol" "r,Q>,g,S"))
+		       1 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
 	      (match_operand 2 "" "")))
    (clobber (reg:SI CRIS_SRP_REGNUM))]
-  "! TARGET_AVOID_GOTPLT"
+  ""
   "Jsr %1"
   [(set_attr "cc" "clobber")])
 
-;; Same as above, since can't afford wasting a constraint letter to mean
-;; "S unless TARGET_AVOID_GOTPLT".
-(define_insn "*expanded_call_value_no_gotplt"
+;; See similar call special-case.
+(define_insn "*expanded_call_value_side"
   [(set (match_operand 0 "nonimmediate_operand" "=g,g,g")
-	(call (mem:QI (match_operand:SI
-		       1 "cris_general_operand_or_plt_symbol" "r,Q>,g"))
-	      (match_operand 2 "" "")))
-   (clobber (reg:SI CRIS_SRP_REGNUM))]
-  "TARGET_AVOID_GOTPLT"
-  "Jsr %1"
+	(call
+	 (mem:QI
+	  (mem:SI
+	   (plus:SI (match_operand:SI 1 "cris_bdap_operand" "%r,  r,r")
+		    (match_operand:SI 2 "cris_bdap_operand" "r>Rn,r,>Rn"))))
+	      (match_operand 3 "" "")))
+   (clobber (reg:SI CRIS_SRP_REGNUM))
+   (set (match_operand:SI 4 "register_operand" "=*1,r,r")
+	(plus:SI (match_dup 1)
+		 (match_dup 2)))]
+  "! TARGET_AVOID_GOTPLT"
+  "Jsr [%4=%1%S2]"
   [(set_attr "cc" "clobber")])
 
 ;; Used in debugging.  No use for the direct pattern; unfilled
@@ -3960,6 +3998,126 @@
 						amode == SImode
 						? QImode : amode)));
 })
+
+;; Try and avoid GOTPLT reads escaping a call: transform them into
+;; PLT.  Curiously (but thankfully), peepholes for instructions
+;; *without side-effects* that just feed a call (or call_value) are
+;; not matched neither in a build or test-suite, so those patterns are
+;; omitted.
+
+;; A "normal" move where we don't check the consumer.
+
+(define_peephole2 ; gotplt-to-plt
+  [(set
+    (match_operand:SI 0 "register_operand" "")
+    (match_operator:SI
+     1 "cris_mem_op"
+     [(plus:SI
+       (reg:SI CRIS_GOT_REGNUM)
+       (const:SI
+	(unspec:SI [(match_operand:SI 2 "cris_general_operand_or_symbol" "")]
+		   CRIS_UNSPEC_PLTGOTREAD)))]))]
+  "flag_pic
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && REGNO_REG_CLASS (REGNO (operands[0])) == REGNO_REG_CLASS (0)"
+  [(set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT)))
+   (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
+  "")
+
+;; And one set with a side-effect getting the PLTGOT offset.
+;; First call and call_value variants.
+
+(define_peephole2 ; gotplt-to-plt-side-call
+  [(parallel
+    [(set
+      (match_operand:SI 0 "register_operand" "")
+      (match_operator:SI
+       1 "cris_mem_op"
+       [(plus:SI
+	 (reg:SI CRIS_GOT_REGNUM)
+	 (const:SI
+	  (unspec:SI [(match_operand:SI
+		       2 "cris_general_operand_or_symbol" "")]
+		     CRIS_UNSPEC_PLTGOTREAD)))]))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (plus:SI (reg:SI CRIS_GOT_REGNUM)
+		   (const:SI
+		    (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])
+  (parallel [(call (mem:QI (match_dup 0))
+		    (match_operand 4 "" ""))
+	      (clobber (reg:SI CRIS_SRP_REGNUM))])]
+  "flag_pic
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && peep2_reg_dead_p (2, operands[0])"
+  [(parallel [(call (mem:QI (match_dup 1))
+		    (match_dup 4))
+	      (clobber (reg:SI CRIS_SRP_REGNUM))
+	      (set (match_dup 3)
+		   (plus:SI (reg:SI CRIS_GOT_REGNUM)
+			    (const:SI
+			     (unspec:SI [(match_dup 2)]
+					CRIS_UNSPEC_PLTGOTREAD))))])]
+  "")
+
+(define_peephole2 ; gotplt-to-plt-side-call-value
+  [(parallel
+    [(set
+      (match_operand:SI 0 "register_operand" "")
+      (match_operator:SI
+       1 "cris_mem_op"
+       [(plus:SI
+	 (reg:SI CRIS_GOT_REGNUM)
+	 (const:SI
+	  (unspec:SI [(match_operand:SI
+		       2 "cris_general_operand_or_symbol" "")]
+		     CRIS_UNSPEC_PLTGOTREAD)))]))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (plus:SI (reg:SI CRIS_GOT_REGNUM)
+		   (const:SI
+		    (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])
+   (parallel [(set (match_operand 5 "" "")
+		   (call (mem:QI (match_dup 0))
+			 (match_operand 4 "" "")))
+	      (clobber (reg:SI CRIS_SRP_REGNUM))])]
+  "flag_pic
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && peep2_reg_dead_p (2, operands[0])"
+  [(parallel [(set (match_dup 5)
+		   (call (mem:QI (match_dup 1))
+			 (match_dup 4)))
+	      (clobber (reg:SI CRIS_SRP_REGNUM))
+	      (set (match_dup 3)
+		   (plus:SI (reg:SI CRIS_GOT_REGNUM)
+			    (const:SI
+			     (unspec:SI [(match_dup 2)]
+					CRIS_UNSPEC_PLTGOTREAD))))])]
+  "")
+
+(define_peephole2 ; gotplt-to-plt-side
+  [(parallel
+    [(set
+      (match_operand:SI 0 "register_operand" "")
+      (match_operator:SI
+       1 "cris_mem_op"
+       [(plus:SI
+	 (reg:SI CRIS_GOT_REGNUM)
+	 (const:SI
+	  (unspec:SI [(match_operand:SI
+		       2 "cris_general_operand_or_symbol" "")]
+		     CRIS_UNSPEC_PLTGOTREAD)))]))
+     (set (match_operand:SI 3 "register_operand" "")
+	  (plus:SI (reg:SI CRIS_GOT_REGNUM)
+		   (const:SI
+		    (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD))))])]
+  "flag_pic
+   && cris_valid_pic_const (XEXP (XEXP (operands[1], 0), 1))
+   && REGNO_REG_CLASS (REGNO (operands[0])) == REGNO_REG_CLASS (0)"
+  [(set (match_dup 3)
+	(const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLTGOTREAD)))
+   (set (match_dup 3) (plus:SI (match_dup 3) (reg:SI CRIS_GOT_REGNUM)))
+   (set (match_dup 0) (const:SI (unspec:SI [(match_dup 2)] CRIS_UNSPEC_PLT)))
+   (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI CRIS_GOT_REGNUM)))]
+  "")
 
 ;; Local variables:
 ;; mode:emacs-lisp
Index: predicates.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/cris/predicates.md,v
retrieving revision 1.2
diff -p -u -r1.2 predicates.md
--- predicates.md	25 Jun 2005 01:21:01 -0000	1.2
+++ predicates.md	7 Jul 2005 11:42:49 -0000
@@ -63,8 +63,8 @@
 
 (define_predicate "cris_bdap_const_operand"
   (and (match_code "label_ref, symbol_ref, const_int, const_double, const")
-       (not (and (match_test "flag_pic")
-		 (match_test "cris_symbol (op)")))))
+       (ior (not (match_test "flag_pic"))
+	    (match_test "cris_valid_pic_const (op)"))))
 
 (define_predicate "cris_simple_address_operand"
   (ior (match_operand:SI 0 "register_operand")
@@ -127,16 +127,6 @@
   (ior (match_operand 0 "cris_bdap_operand")
        (match_operand 0 "cris_biap_mult_operand")))
 
-;; Since a PIC symbol without a GOT entry is not a general_operand, we
-;; have to have a predicate that matches it.  We use this in the expanded
-;; "movsi" anonymous pattern.
-;; FIXME: Can s/special_// when PR 20413 is fixed.
-
-(define_special_predicate "cris_general_operand_or_gotless_symbol"
-  (ior (match_operand 0 "general_operand")
-       (and (match_code "const, symbol_ref, label_ref, unspec")
-	    (match_test "cris_gotless_symbol (op)"))))
-
 ;; Since with -fPIC, not all symbols are valid PIC symbols or indeed
 ;; general_operands, we have to have a predicate that matches it for the
 ;; "movsi" expander.
@@ -145,7 +135,8 @@
 (define_special_predicate "cris_general_operand_or_symbol"
   (ior (match_operand 0 "general_operand")
        (and (match_code "const, symbol_ref, label_ref")
-	    (match_test "cris_symbol (op)"))))
+       	    ; The following test is actually just an assertion.
+	    (match_test "cris_pic_symbol_type_of (op) != cris_no_symbol"))))
 
 ;; Since a PLT symbol is not a general_operand, we have to have a
 ;; predicate that matches it when we need it.  We use this in the expanded

brgds, H-P


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