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]

Fix powerpc-linux gcc.dg/20020103-1.c


This is a fix for "FAIL: gcc.dg/20020103-1.c scan-assembler-not LC"
on powerpc-linux, which has been failing since gcc-3.1.

The reason for the failure is that gcc is generating unspec patterns
early, for example these two:

(insn 11 9 12 1 (set (reg/f:SI 118)
        (unspec:SI [
                (symbol_ref:SI ("ext") [flags 0x44] <var_decl 0x400aaf00 ext>)
                (reg:SI 30 30)
            ] 8)) -1 (nil)
    (expr_list:REG_EQUAL (symbol_ref:SI ("ext") [flags 0x44] <var_decl 0x400aaf00 ext>)
        (nil)))

(insn 24 22 25 1 (set (reg:SI 124)
        (unspec:SI [
                (symbol_ref:SI ("ext") [flags 0x44] <var_decl 0x400aaf00 ext>)
                (reg:SI 30 30)
            ] 8)) -1 (nil)
    (expr_list:REG_EQUAL (symbol_ref:SI ("ext") [flags 0x44] <var_decl 0x400aaf00 ext>)
        (nil)))

with the second insn (and a reg move) being CSE'd to

(insn 27 22 28 0 (set (reg:SI 3 3)
        (reg/f:SI 118)) 258 {*movsi_internal1} (nil)
    (expr_list:REG_EQUAL (symbol_ref:SI ("ext") [flags 0x44] <var_decl 0x400aaf00 ext>)
        (nil)))

Due to register pressure, reg 118 never gets a hard reg, so reload
replaces reg 118 in insn 27 with the symbol_ref in the reg_equal note.
Reload of course doesn't know anything about the unspec GOT pattern,
so instead of recreating something like the old insn 24, you get a
load of "ext" address from memory, with the address of this constant
being put in the GOT.  That's bad because it's an unnecessary
indirection, and also unnecessarily increases GOT size.  In terms of
assembly, we get

	.LC0:
	        .long   ext
[snip]
	        lwz 9,.LC0@got(30)
	        lwz 3,0(9)

instead of simply

	        lwz 3,ext@got(30)

Rather than trying to teach reload how to recreate insn 24, I figured
a better fix would be to delay creating the unspec GOT patterns until
after reload.  Using unspec_movsi_got early does help towards a
couple of goals:
a) It marks the pic register used, via rs6000_got_register.
b) It stops certain transformations from being considered.  For
   example, an earlier version of this patch didn't remove CONST
   from got_operand, and I found that (set (reg) (symbol_ref)),
   (set (reg) (plus (reg) (const_int))) was being combined back to
   (set (reg) (const (plus (symbol_ref) (const_int)))).  This we
   don't want.  (sym+offset)@got doesn't do what you might expect.

Unfortunately, we can't use the pic register for other purposes even
if it is marked unused;  reload might force a constant to mem, which
requires use of the pic register.  So (a) isn't particularly
important.  I did see an approx 1% increase in -fpic -O2 compilation
of insn-attrtab.c after this patch, so (b) might be significant, but
I'm not sure what I can do about that..  One thing that might help
is reducing the number of constraints used in movsi_internal1.  I'm
reasonably confident that 'U' and 'R' can be combined, and perhaps 'Z'
too.  Moving the ABI_V4 cases to new movsi_internal* patterns might
help as well.

	* config/rs6000/rs6000.c (got_operand): Delete.
	(got_no_const_operand): Rename to got_operand.
	(input_operand): Allow get_operand type operands.
	(rs6000_emit_move): Simplify code handling small data.  Leave
	got_operand moves as simple sets rather than converting to
	movsi_got.  Split offsets for got syms and labels.
	* config/rs6000/rs6000.h (EXTRA_CONSTRAINT): Handle 'Z'.
	(PREDICATE_CODES): Remove got_no_const_operand.
	* config/rs6000/rs6000.md (movsi_got): Delete.
	(movsi_got_internal, and splitter): Use got_operand in place of
	got_no_const_operand.
	(movsi_internal1): Handle 'Z' constraint.  Add define_split.

Bootstrapped and regression tested powerpc-linux.  OK for mainline?

diff -urp -xCVS -x'*~' -x'.#*' gcc-virgin/gcc/config/rs6000/rs6000.c gcc-current/gcc/config/rs6000/rs6000.c
--- gcc-virgin/gcc/config/rs6000/rs6000.c	2004-10-23 07:34:46.000000000 +0930
+++ gcc-current/gcc/config/rs6000/rs6000.c	2004-10-28 22:29:01.804792448 +0930
@@ -2044,21 +2044,11 @@ reg_or_logical_cint_operand (rtx op, enu
     return gpc_reg_operand (op, mode);
 }
 
-/* Return 1 if the operand is an operand that can be loaded via the GOT.  */
-
-int
-got_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == SYMBOL_REF
-	  || GET_CODE (op) == CONST
-	  || GET_CODE (op) == LABEL_REF);
-}
-
 /* Return 1 if the operand is a simple references that can be loaded via
    the GOT (labels involving addition aren't allowed).  */
 
 int
-got_no_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+got_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF);
 }
@@ -2986,6 +2976,11 @@ input_operand (rtx op, enum machine_mode
       && small_data_operand (op, Pmode))
     return 1;
 
+  if (DEFAULT_ABI == ABI_V4 && flag_pic == 1
+      && mode == SImode
+      && got_operand (op, mode))
+    return 1;
+
   return 0;
 }
 
@@ -4373,27 +4368,45 @@ rs6000_emit_move (rtx dest, rtx source, 
       break;
 
     case SImode:
-    case DImode:
       /* Use default pattern for address of ELF small data */
-      if (TARGET_ELF
-	  && mode == Pmode
-	  && DEFAULT_ABI == ABI_V4
+      if (DEFAULT_ABI == ABI_V4
 	  && (GET_CODE (operands[1]) == SYMBOL_REF
 	      || GET_CODE (operands[1]) == CONST)
 	  && small_data_operand (operands[1], mode))
-	{
-	  emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
-	  return;
-	}
+	goto emit_set;
 
-      if (DEFAULT_ABI == ABI_V4
-	  && mode == Pmode && mode == SImode
-	  && flag_pic == 1 && got_operand (operands[1], mode))
-	{
-	  emit_insn (gen_movsi_got (operands[0], operands[1]));
-	  return;
+      /* Similarly for symbols and labels we load via the GOT.  */
+      if (DEFAULT_ABI == ABI_V4 && flag_pic == 1
+	  && got_operand (operands[1], mode))
+	goto emit_set;
+
+      /* Split offsets from any symbols or labels loaded via the GOT.  */
+      if (DEFAULT_ABI == ABI_V4 && flag_pic == 1
+	  && GET_CODE (operands[1]) == CONST)
+	{
+	  /* (sym+offset)@got isn't what we want as that means
+	     sym@got + offset, ie. an offset from an address in
+	     the got.  */
+	  rtx offset = const0_rtx;
+	  operands[1] = eliminate_constant_term (XEXP (operands[1], 0),
+						 &offset);
+	  if (!got_operand (operands[1], mode))
+	    abort ();
+
+	  if (INTVAL (offset) != 0)
+	    {
+	      rtx tmp = operands[0];
+	      if (!no_new_pseudos)
+		tmp = gen_reg_rtx (SImode);
+	      emit_insn (gen_rtx_SET (VOIDmode, tmp, operands[1]));
+	      emit_insn (gen_addsi3 (operands[0], tmp, offset));
+	      return;
+	    }
+	  goto emit_set;
 	}
+      /* Fall thru */
 
+    case DImode:
       if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
 	  && TARGET_NO_TOC
 	  && ! flag_pic
diff -urp -xCVS -x'*~' -x'.#*' gcc-virgin/gcc/config/rs6000/rs6000.h gcc-current/gcc/config/rs6000/rs6000.h
--- gcc-virgin/gcc/config/rs6000/rs6000.h	2004-10-23 07:34:46.000000000 +0930
+++ gcc-current/gcc/config/rs6000/rs6000.h	2004-10-28 22:17:39.964016414 +0930
@@ -1347,6 +1347,7 @@ enum reg_class
    'U' is for V.4 small data references.
    'W' is a vector constant that can be easily generated (no mem refs).
    'Y' is a indexed or word-aligned displacement memory operand.
+   'Z' is for V.4 got entries.
    't' is for AND masks that can be performed by two rldic{l,r} insns.  */
 
 #define EXTRA_CONSTRAINT(OP, C)						\
@@ -1356,12 +1357,14 @@ enum reg_class
    : (C) == 'T' ? mask_operand (OP, SImode)				\
    : (C) == 'U' ? (DEFAULT_ABI == ABI_V4				\
 		   && small_data_operand (OP, GET_MODE (OP)))		\
+   : (C) == 'W' ? (easy_vector_constant (OP, GET_MODE (OP)))		\
+   : (C) == 'Y' ? (word_offset_memref_operand (OP, GET_MODE (OP)))	\
+   : (C) == 'Z' ? (DEFAULT_ABI == ABI_V4 && flag_pic == 1		\
+		   && got_operand (OP, GET_MODE (OP)))			\
    : (C) == 't' ? (mask64_2_operand (OP, DImode)			\
 		   && (fixed_regs[CR0_REGNO]				\
 		       || !logical_operand (OP, DImode))		\
 		   && !mask64_operand (OP, DImode))			\
-   : (C) == 'W' ? (easy_vector_constant (OP, GET_MODE (OP)))		\
-   : (C) == 'Y' ? (word_offset_memref_operand (OP, GET_MODE (OP)))      \
    : 0)
 
 /* Define which constraints are memory constraints.  Tell reload
@@ -2553,7 +2551,6 @@ extern char rs6000_reg_names[][8];	/* re
   {"reg_or_sub_cint64_operand", {SUBREG, REG, CONST_INT}},		   \
   {"reg_or_logical_cint_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
   {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},			   \
-  {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}},			   \
   {"easy_fp_constant", {CONST_DOUBLE}},					   \
   {"easy_vector_constant", {CONST_VECTOR}},				   \
   {"easy_vector_constant_add_self", {CONST_VECTOR}},			   \
diff -urp -xCVS -x'*~' -x'.#*' gcc-virgin/gcc/config/rs6000/rs6000.md gcc-current/gcc/config/rs6000/rs6000.md
--- gcc-virgin/gcc/config/rs6000/rs6000.md	2004-10-23 07:34:46.000000000 +0930
+++ gcc-current/gcc/config/rs6000/rs6000.md	2004-10-28 22:17:40.841878478 +0930
@@ -7677,37 +7678,9 @@
     {cal %0,%a2@l(%1)|la %0,lo16(%2)(%1)}
     {cal %0,%a2@l(%1)|addic %0,%1,lo16(%2)}")
 
-;; Set up a register with a value from the GOT table
-
-(define_expand "movsi_got"
-  [(set (match_operand:SI 0 "gpc_reg_operand" "")
-	(unspec:SI [(match_operand:SI 1 "got_operand" "")
-		    (match_dup 2)] UNSPEC_MOVSI_GOT))]
-  "DEFAULT_ABI == ABI_V4 && flag_pic == 1"
-  "
-{
-  if (GET_CODE (operands[1]) == CONST)
-    {
-      rtx offset = const0_rtx;
-      HOST_WIDE_INT value;
-
-      operands[1] = eliminate_constant_term (XEXP (operands[1], 0), &offset);
-      value = INTVAL (offset);
-      if (value != 0)
-	{
-	  rtx tmp = (no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode));
-	  emit_insn (gen_movsi_got (tmp, operands[1]));
-	  emit_insn (gen_addsi3 (operands[0], tmp, offset));
-	  DONE;
-	}
-    }
-
-  operands[2] = rs6000_got_register (operands[1]);
-}")
-
 (define_insn "*movsi_got_internal"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
-	(unspec:SI [(match_operand:SI 1 "got_no_const_operand" "")
+	(unspec:SI [(match_operand:SI 1 "got_operand" "")
 		    (match_operand:SI 2 "gpc_reg_operand" "b")]
 		   UNSPEC_MOVSI_GOT))]
   "DEFAULT_ABI == ABI_V4 && flag_pic == 1"
@@ -7718,7 +7691,7 @@
 ;; didn't get allocated to a hard register.
 (define_split
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
-	(unspec:SI [(match_operand:SI 1 "got_no_const_operand" "")
+	(unspec:SI [(match_operand:SI 1 "got_operand" "")
 		    (match_operand:SI 2 "memory_operand" "")]
 		   UNSPEC_MOVSI_GOT))]
   "DEFAULT_ABI == ABI_V4
@@ -7831,13 +7804,14 @@
    (set_attr "length" "4")])
 
 (define_insn "*movsi_internal1"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
-	(match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
+	(match_operand:SI 1 "input_operand" "r,U,Z,m,r,I,L,n,R,*h,r,r,r,0"))]
   "gpc_reg_operand (operands[0], SImode)
    || gpc_reg_operand (operands[1], SImode)"
   "@
    mr %0,%1
    {cal|la} %0,%a1
+   #
    {l%U1%X1|lwz%U1%X1} %0,%1
    {st%U0%X0|stw%U0%X0} %1,%0
    {lil|li} %0,%1
@@ -7849,8 +7823,8 @@
    mt%0 %1
    mt%0 %1
    {cror 0,0,0|nop}"
-  [(set_attr "type" "*,*,load,store,*,*,*,*,mfjmpr,*,mtjmpr,*,*")
-   (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4,4")])
+  [(set_attr "type" "*,*,*,load,store,*,*,*,*,mfjmpr,*,mtjmpr,*,*")
+   (set_attr "length" "4,4,4,4,4,4,4,8,4,4,4,4,4,4")])
 
 ;; Split a load of a large constant into the appropriate two-insn
 ;; sequence.
@@ -7874,6 +7848,22 @@
     FAIL;
 }")
 
+;; Convert symbol refs and label refs to got references.
+
+(define_split
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+	(match_operand:SI 1 "got_operand" ""))]
+  "DEFAULT_ABI == ABI_V4 && flag_pic == 1
+   && reload_completed"
+  [(set (match_dup 0)
+	(unspec:SI [(match_dup 1)
+		    (match_dup 2)]
+		   UNSPEC_MOVSI_GOT))]
+  "
+{
+  operands[2] = rs6000_got_register (operands[1]);
+}")
+
 (define_insn "*movsi_internal2"
   [(set (match_operand:CC 2 "cc_reg_operand" "=y,x,?y")
 	(compare:CC (match_operand:SI 1 "gpc_reg_operand" "0,r,r")

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


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