diff mbox

Combiner fixes

Message ID 4C572CA0.3040802@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt Aug. 2, 2010, 8:37 p.m. UTC
While testing a different ARM patch, I found that I was getting some
code changes that I couldn't explain.  It turned out to be a bug in the
combiner: a CONST_INT is created without using trunc_int_for_mode,
missing a sign extension, and it ends up not matching const_int_operand
for that reason.

While I was there, I also added some extra canonicalization that helps
on ARM (and produces the optimization I was previously only seeing by
accident).  According to the documentation,

   * In combinations of `neg', `mult', `plus', and `minus', the `neg'
     operations (if any) will be moved inside the operations as far as
     possible.  For instance, `(neg (mult A B))' is canonicalized as
     `(mult (neg A) B)', but `(plus (mult (neg A) B) C)' is
     canonicalized as `(minus A (mult B C))'.

It doesn't say so explicitly, but I take this to mean we can and should
change both

(set (reg/v:SI 137 [ q ])
     (plus:SI (mult:SI (neg:SI (reg/v:SI 135 [ y ])) (const_int 2))
              (reg/v:SI 137 [ q ])))

and

(set (reg/v:SI 137 [ q ])
     (plus:SI (mult:SI (reg/v:SI 135 [ y ]) (const_int -2))
              (reg/v:SI 137 [ q ])))

into

(set (reg/v:SI 137 [ q ])
     (minus:SI (reg/v:SI 137 [ q ])
        (mult:SI (reg/v:SI 135 [ y ]) (const_int 2))))

The latter is recognized by the ARM backend.  IMO the canonicalization
of a shift into a mult is supposed to produce multiplications by powers
of two, and those are all positive values.

On ARM, this helps as follow:
-       rsb     r3, r0, r0, lsl #30
-       add     r6, r6, r3, lsl #2
+       sub     r6, r6, r0, lsl #2

I've also added code to transform (mult (neg (...)) (const)) into
multiplication by the negated constant.

Bootstrapped and tested on i686-linux.  There are some ARM-specific bits
in here, since we forgot to mask off unwanted bits in a HOST_WIDE_INT in
some places.  ARM tests are in progress.   Ok?


Bernd
* simplify-rtx.c (simplify_binary_operation_1): Change a multiply of a
	negated value and a constant into a multiply by the negated constant.
	* combine.c (make_compound_operation): Use trunc_int_for_mode when
	generating a MULT with constant.  Canonicalize PLUS involving MULT.
	* config/arm/constraints.md (M): Examine only 32 bits of a
	HOST_WIDE_INT.
	* config/arm/predicates.md (power_of_two_operand): Likewise.

Comments

Paolo Bonzini Aug. 3, 2010, 7:24 a.m. UTC | #1
On 08/02/2010 10:37 PM, Bernd Schmidt wrote:
> +      if (GET_CODE (op0) == NEG && CONST_INT_P (trueop1))
> +	return simplify_gen_binary (MULT, mode, XEXP (op0, 0),
> +				    simplify_gen_unary (NEG, mode, op1, mode));

Why not go one step further and try it on all operands:

   if (GET_CODE (op0) == NEG)
     {
       rtx temp = simplify_unary (NEG, mode, op1, mode);
       if (temp)
         return simplify_gen_binary (MULT, mode, XEXP (op0, 0), temp);
     }
   if (GET_CODE (op1) == NEG)
     {
       rtx temp = simplify_unary (NEG, mode, op0, mode);
       if (temp)
         return simplify_gen_binary (MULT, mode, temp, XEXP (op1, 0));
     }

Paolo
Richard Henderson Aug. 3, 2010, 4:05 p.m. UTC | #2
> 	* config/arm/constraints.md (M): Examine only 32 bits of a
> 	HOST_WIDE_INT.
> 	* config/arm/predicates.md (power_of_two_operand): Likewise.

Is this left over from before you fixed the GEN_INT to
be trunc_int_for_mode?  This doesn't seem right...


r~
Bernd Schmidt Aug. 3, 2010, 4:09 p.m. UTC | #3
On 08/03/2010 06:05 PM, Richard Henderson wrote:
>> 	* config/arm/constraints.md (M): Examine only 32 bits of a
>> 	HOST_WIDE_INT.
>> 	* config/arm/predicates.md (power_of_two_operand): Likewise.
> 
> Is this left over from before you fixed the GEN_INT to
> be trunc_int_for_mode?  This doesn't seem right...

Why not?  The problem is (1 << 31), which is a power of two, but
negative in SImode and fails the test if sizeof HOST_WIDE_INT > 32.
It's actually needed _after_ fixing the GEN_INT.


Bernd
Richard Henderson Aug. 3, 2010, 4:26 p.m. UTC | #4
On 08/03/2010 09:09 AM, Bernd Schmidt wrote:
> On 08/03/2010 06:05 PM, Richard Henderson wrote:
>>> 	* config/arm/constraints.md (M): Examine only 32 bits of a
>>> 	HOST_WIDE_INT.
>>> 	* config/arm/predicates.md (power_of_two_operand): Likewise.
>>
>> Is this left over from before you fixed the GEN_INT to
>> be trunc_int_for_mode?  This doesn't seem right...
> 
> Why not?  The problem is (1 << 31), which is a power of two, but
> negative in SImode and fails the test if sizeof HOST_WIDE_INT > 32.
> It's actually needed _after_ fixing the GEN_INT.

Ah, ok.


r~
diff mbox

Patch

Index: config/arm/constraints.md
===================================================================
--- config/arm/constraints.md	(revision 162821)
+++ config/arm/constraints.md	(working copy)
@@ -121,7 +121,7 @@  (define_constraint "M"
  "In Thumb-1 state a constant that is a multiple of 4 in the range 0-1020."
  (and (match_code "const_int")
       (match_test "TARGET_32BIT ? ((ival >= 0 && ival <= 32)
-				 || ((ival & (ival - 1)) == 0))
+				 || (((ival & (ival - 1)) & 0xFFFFFFFF) == 0))
 		   : ival >= 0 && ival <= 1020 && (ival & 3) == 0")))
 
 (define_constraint "N"
Index: config/arm/predicates.md
===================================================================
--- config/arm/predicates.md	(revision 162821)
+++ config/arm/predicates.md	(working copy)
@@ -289,7 +289,7 @@  (define_special_predicate "arm_reg_or_ex
 (define_predicate "power_of_two_operand"
   (match_code "const_int")
 {
-  HOST_WIDE_INT value = INTVAL (op);
+  unsigned HOST_WIDE_INT value = INTVAL (op) & 0xffffffff;
 
   return value != 0 && (value & (value - 1)) == 0;
 })
Index: simplify-rtx.c
===================================================================
--- simplify-rtx.c	(revision 162821)
+++ simplify-rtx.c	(working copy)
@@ -2109,6 +2109,10 @@  simplify_binary_operation_1 (enum rtx_co
       if (trueop1 == constm1_rtx)
 	return simplify_gen_unary (NEG, mode, op0, mode);
 
+      if (GET_CODE (op0) == NEG && CONST_INT_P (trueop1))
+	return simplify_gen_binary (MULT, mode, XEXP (op0, 0),
+				    simplify_gen_unary (NEG, mode, op1, mode));
+      
       /* Maybe simplify x * 0 to 0.  The reduction is not valid if
 	 x is NaN, since x * 0 is then also NaN.  Nor is it valid
 	 when the mode has signed zeros, since multiplying a negative
Index: combine.c
===================================================================
--- combine.c	(revision 162821)
+++ combine.c	(working copy)
@@ -7110,10 +7110,46 @@  make_compound_operation (rtx x, enum rtx
 	  && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
 	  && INTVAL (XEXP (x, 1)) >= 0)
 	{
+	  HOST_WIDE_INT count = INTVAL (XEXP (x, 1));
+	  HOST_WIDE_INT multval = (HOST_WIDE_INT) 1 << count;
+
 	  new_rtx = make_compound_operation (XEXP (x, 0), next_code);
-	  new_rtx = gen_rtx_MULT (mode, new_rtx,
-			      GEN_INT ((HOST_WIDE_INT) 1
-				       << INTVAL (XEXP (x, 1))));
+	  if (GET_CODE (new_rtx) == NEG)
+	    {
+	      new_rtx = XEXP (new_rtx, 0);
+	      multval = -multval;
+	    }
+	  multval = trunc_int_for_mode (multval, mode);
+	  new_rtx = gen_rtx_MULT (mode, new_rtx, GEN_INT (multval));
+	}
+      break;
+
+    case PLUS:
+      lhs = XEXP (x, 0);
+      rhs = XEXP (x, 1);
+      lhs = make_compound_operation (lhs, MEM);
+      rhs = make_compound_operation (rhs, MEM);
+      if (GET_CODE (lhs) == MULT && GET_CODE (XEXP (lhs, 0)) == NEG
+	  && SCALAR_INT_MODE_P (mode))
+	{
+	  tem = simplify_gen_binary (MULT, mode, XEXP (XEXP (lhs, 0), 0),
+				     XEXP (lhs, 1));
+	  new_rtx = simplify_gen_binary (MINUS, mode, rhs, tem);
+	}
+      else if (GET_CODE (lhs) == MULT
+	       && (CONST_INT_P (XEXP (lhs, 1)) && INTVAL (XEXP (lhs, 1)) < 0))
+	{
+	  tem = simplify_gen_binary (MULT, mode, XEXP (lhs, 0),
+				     simplify_gen_unary (NEG, mode,
+							 XEXP (lhs, 1),
+							 mode));
+	  new_rtx = simplify_gen_binary (MINUS, mode, rhs, tem);
+	}
+      else
+	{
+	  SUBST (XEXP (x, 0), lhs);
+	  SUBST (XEXP (x, 1), rhs);
+	  goto maybe_swap;
 	}
       break;
 
@@ -7345,6 +7381,7 @@  make_compound_operation (rtx x, enum rtx
 	  SUBST (XVECEXP (x, i, j), new_rtx);
 	}
 
+ maybe_swap:
   /* If this is a commutative operation, the changes to the operands
      may have made it noncanonical.  */
   if (COMMUTATIVE_ARITH_P (x)