Handle XOR in canonicalize_condition

Richard Sandiford rdsandiford@googlemail.com
Thu Jan 23 19:35:00 GMT 2014


This patch fixes gcc.dg/unroll_1.c for MIPS16.  There were two problems,
one in the testcase itself and one in the rtl code.

The testcase problem was that gcc.dg/unroll_1.c forces loop2_unroll to
be run via -fenable-rtl-loop2_unroll but it doesn't explicitly force the
associated init pass (loop2) to be run as well.  This only happens because
-fmove-loop-invariants is usually the default for -O2.  It isn't the default
on MIPS16 though, so neither loop2 nor loop2_unroll were being run.  The
patch adds an explicit -fenable-rtl-loop2 to get around this.

The other problem is related to the way that MIPS16 tests for equality.
Conditional branches test register $24, and the only instructions that
set $24 are MOVE and CMP(I), which is actually an XOR rather than a
subtraction.  So branches for equality typically look like:

       (set (reg:SI cond) (xor:SI (reg:SI X) (const_int Y)))
       (set (pc)
            (if_then_else (eq (reg:SI cond) (const_int 0))
                          (label_ref ...)
                          (pc)))

get_condition didn't recognise this form and so loop-iv.c couldn't
figure out the number of iterations.

I fixed that by handling (eq (xor ...) (const_int 0)) and
(ne (xor ...) (const_int 0)) in canonicalize_condition, in a similar
way to (compare ...).

The existing (compare ...) conditions both test:

	     ((GET_MODE_CLASS (mode) == MODE_CC)
	       != (GET_MODE_CLASS (inner_mode) == MODE_CC))
	      && mode != VOIDmode
	      && inner_mode != VOIDmode)

with the comment:

	  /* ??? We may not combine comparisons done in a CCmode with
	     comparisons not done in a CCmode.  This is to aid targets
	     like Alpha that have an IEEE compliant EQ instruction, and
	     a non-IEEE compliant BEQ instruction.  The use of CCmode is
	     actually artificial, simply to prevent the combination, but
	     should not affect other platforms.

	     However, we must allow VOIDmode comparisons to match either
	     CCmode or non-CCmode comparison, because some ports have
	     modeless comparisons inside branch patterns.

	     ??? This mode check should perhaps look more like the mode check
	     in simplify_comparison in combine.  */

The IEEE thing obviously isn't a worry for XOR, but it still seemed more
consistent to handle all cases in the same way.  I therefore split the
condition out into a separate test.

Tested on mips64-linux-gnu.  OK to install?

Thanks,
Richard


gcc/
	* rtlanal.c (canonicalize_condition): Split out duplicated mode check.
	Handle XOR.

gcc/testsuite/
	* gcc.dg/unroll_1.c: Add -fenable-rtl-loop2.

Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	2014-01-23 19:12:05.089232340 +0000
+++ gcc/rtlanal.c	2014-01-23 19:12:15.168333561 +0000
@@ -5051,23 +5051,24 @@ canonicalize_condition (rtx insn, rtx co
 
 	     ??? This mode check should perhaps look more like the mode check
 	     in simplify_comparison in combine.  */
-
-	  if ((GET_CODE (SET_SRC (set)) == COMPARE
-	       || (((code == NE
-		     || (code == LT
-			 && val_signbit_known_set_p (inner_mode,
-						     STORE_FLAG_VALUE))
+	  if (((GET_MODE_CLASS (mode) == MODE_CC)
+	       != (GET_MODE_CLASS (inner_mode) == MODE_CC))
+	      && mode != VOIDmode
+	      && inner_mode != VOIDmode)
+	    break;
+	  if (GET_CODE (SET_SRC (set)) == COMPARE
+	      || (((code == NE
+		    || (code == LT
+			&& val_signbit_known_set_p (inner_mode,
+						    STORE_FLAG_VALUE))
 #ifdef FLOAT_STORE_FLAG_VALUE
-		     || (code == LT
-			 && SCALAR_FLOAT_MODE_P (inner_mode)
-			 && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
-			     REAL_VALUE_NEGATIVE (fsfv)))
+		    || (code == LT
+			&& SCALAR_FLOAT_MODE_P (inner_mode)
+			&& (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode),
+			    REAL_VALUE_NEGATIVE (fsfv)))
 #endif
-		     ))
-		   && COMPARISON_P (SET_SRC (set))))
-	      && (((GET_MODE_CLASS (mode) == MODE_CC)
-		   == (GET_MODE_CLASS (inner_mode) == MODE_CC))
-		  || mode == VOIDmode || inner_mode == VOIDmode))
+		    ))
+		  && COMPARISON_P (SET_SRC (set))))
 	    x = SET_SRC (set);
 	  else if (((code == EQ
 		     || (code == GE
@@ -5080,15 +5081,18 @@ canonicalize_condition (rtx insn, rtx co
 			     REAL_VALUE_NEGATIVE (fsfv)))
 #endif
 		     ))
-		   && COMPARISON_P (SET_SRC (set))
-		   && (((GET_MODE_CLASS (mode) == MODE_CC)
-			== (GET_MODE_CLASS (inner_mode) == MODE_CC))
-		       || mode == VOIDmode || inner_mode == VOIDmode))
-
+		   && COMPARISON_P (SET_SRC (set)))
 	    {
 	      reverse_code = 1;
 	      x = SET_SRC (set);
 	    }
+	  else if ((code == EQ || code == NE)
+		   && GET_CODE (SET_SRC (set)) == XOR)
+	    /* (eq (xor X Y) (const_int 0)) -> (eq X Y)
+	       (ne (xor X Y) (const_int 0)) -> (ne X Y)
+
+	       This is the form used by MIPS16, for example.  */
+	    x = SET_SRC (set);
 	  else
 	    break;
 	}
Index: gcc/testsuite/gcc.dg/unroll_1.c
===================================================================
--- gcc/testsuite/gcc.dg/unroll_1.c	2014-01-23 19:12:05.089232340 +0000
+++ gcc/testsuite/gcc.dg/unroll_1.c	2014-01-23 19:12:15.185333731 +0000
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-rtl-loop2_unroll=stderr -fno-peel-loops -fno-tree-vrp -fdisable-tree-cunroll -fdisable-tree-cunrolli -fenable-rtl-loop2_unroll" } */
+/* { dg-options "-O2 -fdump-rtl-loop2_unroll=stderr -fno-peel-loops -fno-tree-vrp -fdisable-tree-cunroll -fdisable-tree-cunrolli -fenable-rtl-loop2 -fenable-rtl-loop2_unroll" } */
 
 unsigned a[100], b[100];
 inline void bar()



More information about the Gcc-patches mailing list