[PATCH] Fix -mv8plus (was Re: c/838: sparc-solaris2.7 extra testsuite failures when RTL checking)

Jakub Jelinek jakub@redhat.com
Thu Nov 23 02:53:00 GMT 2000


On Wed, Nov 22, 2000 at 07:22:37PM +0000, Graham Stott wrote:
> It looks to me to be a bug in the sparc.md file here's the offending pattern.
> 
> ;; V8plus wide multiply.
> ;; XXX
> (define_insn "muldi3_v8plus"
>   [(set (match_operand:DI 0 "register_operand" "=r,h")
>         (mult:DI (match_operand:DI 1 "arith_double_operand" "%r,0")
>                  (match_operand:DI 2 "arith_double_operand" "rHI,rHI")))
>    (clobber (match_scratch:SI 3 "=&h,X"))
>    (clobber (match_scratch:SI 4 "=&h,X"))]
>   "TARGET_V8PLUS"
>   "*
> {
>   if (sparc_check_64 (operands[1], insn) <= 0)
>     output_asm_insn (\"srl\\t%L1, 0, %L1\", operands);
>   if (which_alternative == 1)
>     output_asm_insn (\"sllx\\t%H1, 32, %H1\", operands);
>   if (sparc_check_64 (operands[2], insn) <= 0)
>     output_asm_insn (\"srl\\t%L2, 0, %L2\", operands);
>   if (which_alternative == 1)
>     return \"or\\t%L1, %H1, %H1\\n\\tsllx\\t%H2, 32, %L1\\n\\tor\\t%L2, %L1, %L1\\n\\tmulx\\t%H1, %L1, %L0\;srlx\\t%L0, 32, %H0\";
>   else
>     return \"sllx\\t%H1, 32, %3\\n\\tsllx\\t%H2, 32, %4\\n\\tor\\t%L1, %3, %3\\n\\tor\\t%L2, %4, %4\\n\\tmulx\\t%3, %4, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0\";
> }"
>   [(set_attr "length" "9,8")])
> 
> The relevant values are
> 
> 	operand 0 (reg:DI 24 %i0)
> 	operand 1 (reg:DI 24 %i0)
> 	operand 2 (const_int -1 [0xffffffff])

The following patch should fix it.
I've removed the H constraint, because non SMALL_INT constants would have to
be special cased in the pattern anyway, they are rare and reload will do the
work for us. I had to special case the CONST_INT case though.

While looking into it, I've noticed sparc_check_64 does pretty bogus things
(like it should be checking the DImode pair and SImode low part of it, not
die on first mentioned overlap if high part of register pair is assigned
later than the first pair, also, e.g. AND could return 1 if it was SImode
andn or second argument had not all upper bits guaranteed to be 0).

BTW: Long term, I think we should allocate additional 16 call-clobbered
registers which would not be used in normal register allocation and split
the V8PLUS patterns after reload into some parallels like:

(insn 25 23 29 (parallel[
	    (set (reg:SI 3 %g3)
		 (const_int 0)
	    (set (reg:DI 102 %dg3)
		 (ashift:DI (reg:SI 24 %i0)
			    (const_int 32 [0x20])))
	] ) 302 {*ashldi3_v8plus_insn} (nil)
    (nil))			# sllx %i0, 32, %g3

(insn 17 32 35 (parallel[
	    (set (reg:SI 8 %o0)
                (mult:SI (reg:SI 8 %o0)
                    (reg:SI 9 %o1)))
            (set (reg:DI 112 %do0)
                (mult:DI (reg:DI 112 %do0)
                    (reg:DI 114 %do1)))
        ] ) 192 {muldi3_v8plus_insn} (nil)
    (nil))			# mulx %o0, %o1, %o0

The advantage of this would be that we could schedule them, put them into
delay slots, whatever. The %d[og][0-7] registers would not be used in the
actual output, they would be the same as %[og][0-7] but including the high
32 bits.
What do you think?

2000-11-23  Jakub Jelinek  <jakub@redhat.com>

	* config/sparc/sparc.md (muldi3_v8plus): Remove H constraint.
	Handle CONST_INT as second argument.
	* config/sparc/sparc.c (set_extends): Remove first argument.
	Properly handle AND, CONST_INT and CONST_DOUBLE, handle IOR, XOR and
	MOV.
	(sparc_check_64): Abort if first argument is not REG.
	If it is DImode REG, look at the lower register of the register
	pair.

	* config/sparc/sparc.c (load_pic_register, restore_regs,
	output_return, sparc_v8plus_shift, sparc_function_profiler,
	sparc_function_block_profiler, sparc_block_profiler): Fix output
	formatting.

	* gcc.dg/ultrasp3.c: New test.

--- gcc/config/sparc/sparc.md.jj	Wed Nov 22 21:41:13 2000
+++ gcc/config/sparc/sparc.md	Wed Nov 22 23:17:15 2000
@@ -6088,7 +6088,7 @@
 (define_insn "muldi3_v8plus"
   [(set (match_operand:DI 0 "register_operand" "=r,h")
 	(mult:DI (match_operand:DI 1 "arith_double_operand" "%r,0")
-		 (match_operand:DI 2 "arith_double_operand" "rHI,rHI")))
+		 (match_operand:DI 2 "arith_double_operand" "rI,rI")))
    (clobber (match_scratch:SI 3 "=&h,X"))
    (clobber (match_scratch:SI 4 "=&h,X"))]
   "TARGET_V8PLUS"
@@ -6098,6 +6098,13 @@
     output_asm_insn (\"srl\\t%L1, 0, %L1\", operands);
   if (which_alternative == 1)
     output_asm_insn (\"sllx\\t%H1, 32, %H1\", operands);
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if (which_alternative == 1)
+	return \"or\\t%L1, %H1, %H1\\n\\tmulx\\t%H1, %2, %L0\;srlx\\t%L0, 32, %H0\";
+      else
+	return \"sllx\\t%H1, 32, %3\\n\\tor\\t%L1, %3, %3\\n\\tmulx\\t%3, %2, %3\\n\\tsrlx\\t%3, 32, %H0\\n\\tmov\\t%3, %L0\";
+    }
   if (sparc_check_64 (operands[2], insn) <= 0)
     output_asm_insn (\"srl\\t%L2, 0, %L2\", operands);
   if (which_alternative == 1)
--- gcc/config/sparc/sparc.c.jj	Wed Nov 22 23:18:44 2000
+++ gcc/config/sparc/sparc.c	Thu Nov 23 10:47:13 2000
@@ -153,7 +153,7 @@ static rtx *ultra_find_type PARAMS ((int
 static void ultra_build_types_avail PARAMS ((rtx *, int));
 static void ultra_flush_pipeline PARAMS ((void));
 static void ultra_rescan_pipeline_state PARAMS ((rtx *, int));
-static int set_extends PARAMS ((rtx, rtx));
+static int set_extends PARAMS ((rtx));
 static void output_restore_regs PARAMS ((FILE *, int));
 
 /* Option handling.  */
@@ -2852,7 +2852,7 @@ load_pic_register ()
       if (align > 0)
 	ASM_OUTPUT_ALIGN (asm_out_file, align);
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0);
-      fputs ("\tretl\n\tadd %o7,%l7,%l7\n", asm_out_file);
+      fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
     }
 
   /* Initialize every time through, since we can't easily
@@ -3253,11 +3253,11 @@ restore_regs (file, low, high, base, off
 		       base, offset + 4 * n_regs, reg_names[i]),
 	      n_regs += 2;
 	    else
-	      fprintf (file, "\tld\t[%s+%d],%s\n",
+	      fprintf (file, "\tld\t[%s+%d], %s\n",
 		       base, offset + 4 * n_regs, reg_names[i]),
 	      n_regs += 2;
 	  else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
-	    fprintf (file, "\tld\t[%s+%d],%s\n",
+	    fprintf (file, "\tld\t[%s+%d], %s\n",
 		     base, offset + 4 * n_regs + 4, reg_names[i+1]),
 	    n_regs += 2;
 	}
@@ -5417,9 +5417,9 @@ output_return (operands)
       else
 	{
 	  if ((actual_fsize & 0x3ff) != 0)
-	    return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+	    return "sethi\t%%hi(%a0), %%g1\n\tor\t%%g1, %%lo(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
 	  else
-	    return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+	    return "sethi\t%%hi(%a0), %%g1\n\tretl\n\tadd\t%%sp, %%g1, %%sp";
 	}
     }
   else if (TARGET_V9)
@@ -7978,8 +7978,8 @@ sparc_issue_rate ()
 }
 
 static int
-set_extends(x, insn)
-     rtx x, insn;
+set_extends (insn)
+     rtx insn;
 {
   register rtx pat = PATTERN (insn);
 
@@ -8003,27 +8003,40 @@ set_extends(x, insn)
       return 1;
     case AND:
       {
+	rtx op0 = XEXP (SET_SRC (pat), 0);
 	rtx op1 = XEXP (SET_SRC (pat), 1);
 	if (GET_CODE (op1) == CONST_INT)
 	  return INTVAL (op1) >= 0;
-	if (GET_CODE (XEXP (SET_SRC (pat), 0)) == REG
-	    && sparc_check_64 (XEXP (SET_SRC (pat), 0), insn) == 1)
-	  return 1;
-	if (GET_CODE (op1) == REG
-	    && sparc_check_64 ((op1), insn) == 1)
+	if (GET_CODE (op0) != REG)
+	  return 0;
+	if (sparc_check_64 (op0, insn) == 1)
 	  return 1;
+	return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
+      }
+    case IOR:
+    case XOR:
+      {
+	rtx op0 = XEXP (SET_SRC (pat), 0);
+	rtx op1 = XEXP (SET_SRC (pat), 1);
+	if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
+	  return 0;
+	if (GET_CODE (op1) == CONST_INT)
+	  return INTVAL (op1) >= 0;
+	return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
       }
     case ASHIFT:
     case LSHIFTRT:
       return GET_MODE (SET_SRC (pat)) == SImode;
       /* Positive integers leave the high bits zero. */
     case CONST_DOUBLE:
-      return ! (CONST_DOUBLE_LOW (x) & 0x80000000);
+      return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
     case CONST_INT:
-      return ! (INTVAL (x) & 0x80000000);
+      return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
     case ASHIFTRT:
     case SIGN_EXTEND:
       return - (GET_MODE (SET_SRC (pat)) == SImode);
+    case REG:
+      return sparc_check_64 (SET_SRC (pat), insn);
     default:
       return 0;
     }
@@ -8145,10 +8158,16 @@ sparc_check_64 (x, insn)
      the single set and return the correct value or fail to recognize
      it and return 0.  */
   int set_once = 0;
+  rtx y = x;
+
+  if (GET_CODE (x) != REG)
+    abort ();
+
+  if (GET_MODE (x) == DImode)
+    y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
 
-  if (GET_CODE (x) == REG
-      && flag_expensive_optimizations
-      && REG_N_SETS (REGNO (x)) == 1)
+  if (flag_expensive_optimizations
+      && REG_N_SETS (REGNO (y)) == 1)
     set_once = 1;
 
   if (insn == 0)
@@ -8178,8 +8197,10 @@ sparc_check_64 (x, insn)
 	    if (GET_CODE (pat) != SET)
 	      return 0;
 	    if (rtx_equal_p (x, SET_DEST (pat)))
-	      return set_extends (x, insn);
-	    if (reg_overlap_mentioned_p (SET_DEST (pat), x))
+	      return set_extends (insn);
+	    if (y && rtx_equal_p (y, SET_DEST (pat)))
+	      return set_extends (insn);
+	    if (reg_overlap_mentioned_p (SET_DEST (pat), y))
 	      return 0;
 	  }
 	}
@@ -8199,21 +8220,21 @@ sparc_v8plus_shift (operands, insn, opco
     operands[3] = operands[0];
   if (GET_CODE (operands[1]) == CONST_INT)
     {
-      output_asm_insn ("mov %1,%3", operands);
+      output_asm_insn ("mov\t%1, %3", operands);
     }
   else
     {
-      output_asm_insn ("sllx %H1,32,%3", operands);
+      output_asm_insn ("sllx\t%H1, 32, %3", operands);
       if (sparc_check_64 (operands[1], insn) <= 0)
-	output_asm_insn ("srl %L1,0,%L1", operands);
-      output_asm_insn ("or %L1,%3,%3", operands);
+	output_asm_insn ("srl\t%L1, 0, %L1", operands);
+      output_asm_insn ("or\t%L1, %3, %3", operands);
     }
 
   strcpy(asm_code, opcode);
   if (which_alternative != 2)
-    return strcat (asm_code, " %0,%2,%L0\n\tsrlx %L0,32,%H0");
+    return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
   else
-    return strcat (asm_code, " %3,%2,%3\n\tsrlx %3,32,%H0\n\tmov %3,%L0");
+    return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
 }
 
 
@@ -8250,22 +8271,22 @@ sparc_function_profiler (file, labelno)
   ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
 
   if (! TARGET_ARCH64)
-    fputs ("\tst\t%g2,[%fp-4]\n", file);
+    fputs ("\tst\t%g2, [%fp-4]\n", file);
 
   fputs ("\tsethi\t%hi(", file);
   assemble_name (file, buf);
-  fputs ("),%o0\n", file);
+  fputs ("), %o0\n", file);
 
   fputs ("\tcall\t", file);
   assemble_name (file, MCOUNT_FUNCTION);
   putc ('\n', file);
 
-  fputs ("\t or\t%o0,%lo(", file);
+  fputs ("\t or\t%o0, %lo(", file);
   assemble_name (file, buf);
-  fputs ("),%o0\n", file);
+  fputs ("), %o0\n", file);
 
   if (! TARGET_ARCH64)
-    fputs ("\tld\t[%fp-4],%g2\n", file);
+    fputs ("\tld\t[%fp-4], %g2\n", file);
 }
 
 
@@ -8337,17 +8358,17 @@ sparc_function_block_profiler(file, bloc
     {
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
   
-      fprintf (file, "\tsethi\t%%hi(%d),%%o1\n", block_or_label);
+      fprintf (file, "\tsethi\t%%hi(%d), %%o1\n", block_or_label);
 
-      fputs ("\tor\t%o0,%lo(", file);
+      fputs ("\tor\t%o0, %lo(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
   
       fprintf (file, "\tcall\t%s__bb_init_trace_func\n", user_label_prefix);
 
-      fprintf (file, "\t or\t%%o1,%%lo(%d),%%o1\n", block_or_label);
+      fprintf (file, "\t or\t%%o1, %%lo(%d), %%o1\n", block_or_label);
     }
   else if (profile_block_flag != 0)
     {
@@ -8356,11 +8377,11 @@ sparc_function_block_profiler(file, bloc
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
       
       fputs ("\tld\t[%lo(", file);
       assemble_name (file, LPBX);
-      fputs (")+%o0],%o1\n", file);
+      fputs (")+%o0], %o1\n", file);
 
       fputs ("\ttst\t%o1\n", file);
 
@@ -8377,9 +8398,9 @@ sparc_function_block_profiler(file, bloc
 	  putc ('\n', file);
 	}
 
-      fputs ("\t or\t%o0,%lo(", file);
+      fputs ("\t or\t%o0, %lo(", file);
       assemble_name (file, LPBX);
-      fputs ("),%o0\n", file);
+      fputs ("), %o0\n", file);
 
       fprintf (file, "\tcall\t%s__bb_init_func\n\t nop\n", user_label_prefix);
 
@@ -8464,27 +8485,27 @@ sparc_block_profiler(file, blockno)
     {
       ASM_GENERATE_INTERNAL_LABEL (LPBX, "LPBX", 0);
 
-      fprintf (file, "\tsethi\t%%hi(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tsethi\t%%hi(%d),%%g%d\n", blockno, bbreg);
-      fprintf (file, "\tor\t%%g1,%%lo(%s__bb),%%g1\n", user_label_prefix);
-      fprintf (file, "\tor\t%%g%d,%%lo(%d),%%g%d\n", bbreg, blockno, bbreg);
+      fprintf (file, "\tsethi\t%%hi(%s__bb), %%g1\n", user_label_prefix);
+      fprintf (file, "\tsethi\t%%hi(%d), %%g%d\n", blockno, bbreg);
+      fprintf (file, "\tor\t%%g1, %%lo(%s__bb), %%g1\n", user_label_prefix);
+      fprintf (file, "\tor\t%%g%d, %%lo(%d), %%g%d\n", bbreg, blockno, bbreg);
 
-      fprintf (file, "\tst\t%%g%d,[%%g1]\n", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1]\n", bbreg);
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "),%%g%d\n", bbreg);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fputs ("\tor\t%o2,%lo(", file);
+      fputs ("\tor\t%o2, %lo(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "),%%g%d\n", bbreg);
+      fprintf (file, "), %%g%d\n", bbreg);
   
-      fprintf (file, "\tst\t%%g%d,[%%g1+4]\n", bbreg);
-      fprintf (file, "\tmov\t%%o7,%%g%d\n", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1 + 4]\n", bbreg);
+      fprintf (file, "\tmov\t%%o7, %%g%d\n", bbreg);
 
       fprintf (file, "\tcall\t%s__bb_trace_func\n\t nop\n", user_label_prefix);
 
-      fprintf (file, "\tmov\t%%g%d,%%o7\n", bbreg);
+      fprintf (file, "\tmov\t%%g%d, %%o7\n", bbreg);
     }
   else if (profile_block_flag != 0)
     {
@@ -8492,18 +8513,18 @@ sparc_block_profiler(file, blockno)
 
       fputs ("\tsethi\t%hi(", file);
       assemble_name (file, LPBX);
-      fprintf (file, "+%d),%%g1\n", blockno*4);
+      fprintf (file, "+%d), %%g1\n", blockno*4);
 
       fputs ("\tld\t[%g1+%lo(", file);
       assemble_name (file, LPBX);
       if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
-	fprintf (file, ")+%d],%%g%d\n", blockno*4, bbreg);
+	fprintf (file, ")+%d], %%g%d\n", blockno*4, bbreg);
       else
-	fprintf (file, "+%d)],%%g%d\n", blockno*4, bbreg);
+	fprintf (file, "+%d)], %%g%d\n", blockno*4, bbreg);
 
-      fprintf (file, "\tadd\t%%g%d,1,%%g%d\n", bbreg, bbreg);
+      fprintf (file, "\tadd\t%%g%d, 1, %%g%d\n", bbreg, bbreg);
 
-      fprintf (file, "\tst\t%%g%d,[%%g1+%%lo(", bbreg);
+      fprintf (file, "\tst\t%%g%d, [%%g1+%%lo(", bbreg);
       assemble_name (file, LPBX);
       if (TARGET_ARCH64 && USE_AS_OFFSETABLE_LO10)
 	fprintf (file, ")+%d]\n", blockno*4);
--- gcc/testsuite/gcc.dg/ultrasp3.c.jj	Thu Nov 23 11:27:31 2000
+++ gcc/testsuite/gcc.dg/ultrasp3.c	Thu Nov 23 11:27:04 2000
@@ -0,0 +1,36 @@
+/* { dg-options "" } */
+/* { dg-options -mcpu=ultrasparc -mv8plus { target sparc-*-* } } */
+
+unsigned long long foo (unsigned long long x)
+{
+  return 0x73500000735LL * x;
+}
+
+unsigned long long a, b;
+unsigned long p;
+
+unsigned long long bar (void)  
+{
+  unsigned long long c = a | b;
+  return 0x73500000735LL * c;
+}
+
+unsigned long long baz (void)
+{
+  unsigned long long c = (p + 345) & -2;
+  return c * a;
+}
+
+main ()
+{
+  if (foo (0x56789LL) != 0x26f32e5d26f32e5dLL)
+    abort ();
+  a = 0x8000000080000000LL;
+  b = 0x0000000180000001LL;
+  if (bar () != 0x120480000735LL)
+    abort ();
+  p = 0xffffffff;
+  if (baz () != 0xac00000000LL)
+    abort ();
+  exit (0);
+}

	Jakub


More information about the Gcc-patches mailing list