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]

sh-hms: simplify operands of constant addresses with MINUSes


It seems that some of the changes to introduce PIC support on sh-elf
broke sh-hms.  The replacement output_addr_const wouldn't simplify
MINUS expressions, which would cause GCC to sometimes output assembly
constants such as `s + 5 - s', for which the assembler couldn't
generate relocations, for not knowing in which segment `s' would live.

Instead of moving the simplification over to
sh.c:output_pic_addr_const(), I decided to make the generic
output_addr_const() usable for SH PIC.  Since the PIC implementation
on the SH uses a couple of unspecs within relatively complex
expressions, I had to tweak the simplification machinery to accept
those unspecs, and to add some means for output_addr_const() to
call-back into machine-specific code.

Here's the resulting patch.  No regressions on sh-elf, with and
without -fPIC, and hundreds of fixes on sh-hms.  Ok to install?

Index: gcc/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* final.c (output_addr_const) [LABEL_REF]: Simplify.
	[MINUS]: Enclose non-CONST_INTs in parentheses.
	[default]: Try OUTPUT_ADDR_CONST_EXTRA.
	* tm.texi (OUTPUT_ADDR_CONST_EXTRA): Document it.
	* varasm.c (decode_rtx_const) [CONST]: If it's not something
	PLUS or MINUS a CONST_INT, use the whole CONST with offset 0
	instead of abort()ing.
	* sh.c (output_pic_addr_const): Removed.  Fixed all callers.
	* sh.h (OUTPUT_ADDR_CONST_EXTRA): New.  Handle the UNSPECs
	formerly handled in output_pic_addr_const.
	* sh.md (sym_label2reg, symPLT_label2reg): Enclose UNSPEC
	operands of MINUS in CONSTs so that decode_rtx_const() will
	accept them.

Index: gcc/final.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/final.c,v
retrieving revision 1.147
diff -u -p -r1.147 final.c
--- gcc/final.c 2000/11/08 02:18:00 1.147
+++ gcc/final.c 2000/11/08 04:07:31
@@ -3677,10 +3677,8 @@ output_addr_const (file, x)
       break;
 
     case LABEL_REF:
-      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
-      assemble_name (file, buf);
-      break;
-
+      x = XEXP (x, 0);
+      /* Fall through.  */
     case CODE_LABEL:
       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
       assemble_name (file, buf);
@@ -3741,8 +3739,9 @@ output_addr_const (file, x)
 
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-	  && INTVAL (XEXP (x, 1)) < 0)
+      if ((GET_CODE (XEXP (x, 1)) == CONST_INT
+	   && INTVAL (XEXP (x, 1)) < 0)
+	  || GET_CODE (XEXP (x, 1)) != CONST_INT)
 	{
 	  fprintf (file, "%s", ASM_OPEN_PAREN);
 	  output_addr_const (file, XEXP (x, 1));
@@ -3758,6 +3757,12 @@ output_addr_const (file, x)
       break;
 
     default:
+#ifdef OUTPUT_ADDR_CONST_EXTRA
+      OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
+      break;
+
+    fail:
+#endif
       output_operand_lossage ("invalid expression as operand");
     }
 }
Index: gcc/tm.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tm.texi,v
retrieving revision 1.150
diff -u -p -r1.150 tm.texi
--- gcc/tm.texi 2000/11/01 00:20:34 1.150
+++ gcc/tm.texi 2000/11/08 04:07:37
@@ -5500,6 +5500,18 @@ would be identical to repeatedly calling
 a size of @code{UNITS_PER_WORD}, once for each word, you need not define
 the macro.
 
+@findex OUTPUT_ADDR_CONST_EXTRA
+@item OUTPUT_ADDR_CONST_EXTRA (@var{stream}, @var{x}, @var{fail})
+A C statement to recognize @var{rtx} patterns that
+@code{output_addr_const} can't deal with, and output assembly code to
+@var{stream} corresponding to the pattern @var{x}.  This may be used to
+allow machine-dependent @code{UNSPEC}s to appear within constants.
+
+If @code{OUTPUT_ADDR_CONST_EXTRA} fails to recognize a pattern, it must
+@code{goto fail}, so that a standard error message is printed.  If it
+prints an error message itself, by calling, for example,
+@code{output_operand_lossage}, it may just complete normally.
+
 @findex ASM_OUTPUT_BYTE
 @item ASM_OUTPUT_BYTE (@var{stream}, @var{value})
 A C statement to output to the stdio stream @var{stream} an assembler
Index: gcc/varasm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/varasm.c,v
retrieving revision 1.137
diff -u -p -r1.137 varasm.c
--- gcc/varasm.c 2000/11/03 18:55:53 1.137
+++ gcc/varasm.c 2000/11/08 04:07:39
@@ -3386,22 +3386,21 @@ decode_rtx_const (mode, x, value)
 
     case CONST:
       x = XEXP (x, 0);
-      if (GET_CODE (x) == PLUS)
+      if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
 	{
 	  value->un.addr.base = XEXP (x, 0);
-	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
-	    abort ();
 	  value->un.addr.offset = INTVAL (XEXP (x, 1));
 	}
-      else if (GET_CODE (x) == MINUS)
+      else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
 	{
 	  value->un.addr.base = XEXP (x, 0);
-	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
-	    abort ();
 	  value->un.addr.offset = - INTVAL (XEXP (x, 1));
 	}
       else
-	abort ();
+	{
+	  value->un.addr.base = x;
+	  value->un.addr.offset = 0;
+	}
       break;
 
     default:
Index: gcc/config/sh/sh.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sh/sh.c,v
retrieving revision 1.69
diff -u -p -r1.69 sh.c
--- gcc/config/sh/sh.c 2000/10/31 15:34:27 1.69
+++ gcc/config/sh/sh.c 2000/11/08 04:07:41
@@ -202,7 +202,7 @@ print_operand_address (stream, x)
       break;
 
     default:
-      output_pic_addr_const (stream, x);
+      output_addr_const (stream, x);
       break;
     }
 }
@@ -5350,120 +5350,4 @@ legitimize_pic_address (orig, mode, reg)
       return reg;
     }
   return orig;
-}
-
-/* Like output_addr_const(), but recognize PIC unspecs and special
-   expressions.  */
-void
-output_pic_addr_const (file, x)
-     FILE *file;
-     rtx x;
-{
-  char buf[256];
-
-  switch (GET_CODE (x))
-    {
-    case PC:
-      if (flag_pic)
-	putc ('.', file);
-      else
-	abort ();
-      break;
-
-    case SYMBOL_REF:
-      assemble_name (file, XSTR (x, 0));
-      break;
-
-    case LABEL_REF:
-      x = XEXP (x, 0);
-      /* FALLTHRU */
-    case CODE_LABEL:
-      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
-      assemble_name (asm_out_file, buf);
-      break;
-
-    case CONST:
-      output_pic_addr_const (file, XEXP (x, 0));
-      break;
-
-    case CONST_INT:
-      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
-      break;
-
-    case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
-	{
-	  /* We can use %d if the number is <32 bits and positive.  */
-	  if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
-	    fprintf (file, "0x%lx%08lx",
-		     (unsigned long) CONST_DOUBLE_HIGH (x),
-		     (unsigned long) CONST_DOUBLE_LOW (x));
-	  else
-	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
-	}
-      else
-	/* We can't handle floating point constants;
-	   PRINT_OPERAND must handle them.  */
-	output_operand_lossage ("floating constant misused");
-      break;
-
-    case PLUS:
-      /* Some assemblers need integer constants to appear first.  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
-	{
-	  output_pic_addr_const (file, XEXP (x, 0));
-	  fprintf (file, "+");
-	  output_pic_addr_const (file, XEXP (x, 1));
-	}
-      else if (GET_CODE (XEXP (x, 1)) == CONST_INT
-	       || GET_CODE (XEXP (x, 0)) == PC)
-	{
-	  output_pic_addr_const (file, XEXP (x, 1));
-	  fprintf (file, "+");
-	  output_pic_addr_const (file, XEXP (x, 0));
-	}
-      else
-	abort ();
-      break;
-
-    case MINUS:
-      output_pic_addr_const (file, XEXP (x, 0));
-      fprintf (file, "-");
-      if (GET_CODE (XEXP (x, 1)) == CONST)
-	{
-	  putc ('(', file);
-	  output_pic_addr_const (file, XEXP (x, 1));
-	  putc (')', file);
-	}
-      else
-	output_pic_addr_const (file, XEXP (x, 1));
-      break;
-
-    case UNSPEC:
-      if ((XVECLEN (x, 0)) > 3)
- 	abort ();
-      output_pic_addr_const (file, XVECEXP (x, 0, 0));
-      switch (XINT (x, 1))
- 	{
-	case 6:
-	  /* GLOBAL_OFFSET_TABLE or local symbols, no suffix.  */
-	  break;
- 	case 7:
- 	  fputs ("@GOT", file);
- 	  break;
-	case 8:
-	  fputs ("@GOTOFF", file);
-	  break;
-        case 9:
-	  fputs ("@PLT", file);
-	  break;
- 	default:
- 	  output_operand_lossage ("invalid UNSPEC as operand");
- 	  break;
- 	}
-      break;
-
-    default:
-      output_operand_lossage ("invalid expression as operand");
-    }
 }
Index: gcc/config/sh/sh.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sh/sh.h,v
retrieving revision 1.81
diff -u -p -r1.81 sh.h
--- gcc/config/sh/sh.h 2000/11/02 23:29:13 1.81
+++ gcc/config/sh/sh.h 2000/11/08 04:07:42
@@ -2069,12 +2069,12 @@ do { char dstr[30];					\
 
 #define ASM_OUTPUT_INT(STREAM, EXP)		\
   (fprintf ((STREAM), "\t.long\t"),      	\
-   output_pic_addr_const ((STREAM), (EXP)),  	\
+   output_addr_const ((STREAM), (EXP)),  	\
    fputc ('\n', (STREAM)))
 
 #define ASM_OUTPUT_SHORT(STREAM, EXP)	\
   (fprintf ((STREAM), "\t.short\t"),	\
-   output_pic_addr_const ((STREAM), (EXP)),	\
+   output_addr_const ((STREAM), (EXP)),	\
    fputc ('\n', (STREAM)))
 
 #define ASM_OUTPUT_CHAR(STREAM, EXP)		\
@@ -2154,6 +2154,37 @@ do { char dstr[30];					\
 #define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
   ((CHAR) == '.' || (CHAR) == '#' || (CHAR) == '@' || (CHAR) == ','	\
    || (CHAR) == '$')
+
+/* Recognize machine-specific patterns that may appear within
+   constants.  Used for PIC-specific UNSPECs.  */
+#define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \
+  do									\
+    if (flag_pic && GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1)	\
+      {									\
+	output_addr_const ((STREAM), XVECEXP ((X), 0, 0));		\
+	switch (XINT ((X), 1))						\
+	  {								\
+	  case 6:							\
+	    /* GLOBAL_OFFSET_TABLE or local symbols, no suffix.  */	\
+	    break;							\
+	  case 7:							\
+	    fputs ("@GOT", (STREAM));					\
+	    break;							\
+	  case 8:							\
+	    fputs ("@GOTOFF", (STREAM));				\
+	    break;							\
+	  case 9:							\
+	    fputs ("@PLT", (STREAM));					\
+	    break;							\
+	  default:							\
+	    goto FAIL;							\
+	  }								\
+	break;								\
+      }									\
+    else								\
+      goto FAIL;							\
+  while (0)
+
 
 extern struct rtx_def *sh_compare_op0;
 extern struct rtx_def *sh_compare_op1;
Index: gcc/config/sh/sh.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/sh/sh.md,v
retrieving revision 1.54
diff -u -p -r1.54 sh.md
--- gcc/config/sh/sh.md 2000/10/31 15:34:27 1.54
+++ gcc/config/sh/sh.md 2000/11/08 04:07:43
@@ -3485,7 +3485,7 @@
 (define_expand "sym_label2reg"
   [(set (match_operand:SI 0 "" "")
 	(const (minus:SI
-		(unspec [(match_operand:SI 1 "" "")] 6)
+		(const (unspec [(match_operand:SI 1 "" "")] 6))
 		(const (plus:SI
 			(unspec [(label_ref (match_operand:SI 2 "" ""))] 6)
 			(const_int 2))))))]
@@ -3517,12 +3517,11 @@
 (define_expand "symPLT_label2reg"
   [(set (match_operand:SI 0 "" "")
 	(const (minus:SI
-		(plus:SI (pc)
-			 (unspec [(match_operand:SI 1 "" "")] 9))
-		(const
-		 (plus:SI
-		  (unspec [(label_ref (match_operand:SI 2 "" ""))] 6)
-		  (const_int 2))))))
+		(const (plus:SI (unspec [(match_operand:SI 1 "" "")] 9)
+				(pc)))
+		(const (plus:SI
+			(unspec [(label_ref (match_operand:SI 2 "" ""))] 6)
+			(const_int 2))))))
    (use (match_dup 3))]
   ;; Even though the PIC register is not really used by the call
   ;; sequence in which this is expanded, the PLT code assumes the PIC

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer                  aoliva@{cygnus.com, redhat.com}
CS PhD student at IC-Unicamp        oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist    *Please* write to mailing lists, not to me

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