Hi,

one of the transformations performed by associate_plusminus is:

  /* Second match patterns that allow contracting a plus-minus pair
     irrespective of overflow issues.

  [...]
        (T)(P + A) - (T)P  -> (T)A

but it is actually applied only to POINTER_PLUS_EXPR and pointer types:

     /* (T)(ptr + adj) - (T)ptr -> (T)adj.  */

It turns out that this pattern arises for size computations of array slices in 
Ada, which are done in integer types; for the attached testcase, extending the 
transformation to integer types makes it possible to eliminate a call to the 
alloca builtin.

Tested on x86_64-suse-linux, OK for the mainline?


2014-05-21  Eric Botcazou  <ebotca...@adacore.com>

        * tree.h (PLUS_EXPR_CODE_P): New macro.
        (PLUS_EXPR_P): Likewise.
        (CASE_PLUS): Likewise.
        * tree-ssa-forwprop.c (associate_plusminus): Extend (T)(P+A) - (T)P
        -> (T)A transformation to integer types.


2014-05-21  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/opt37.ad[sb]: New test.


-- 
Eric Botcazou
package Opt37 is

   type T_Bit is range 0 .. 1;
   for T_Bit'Size use 1;

   type Positive is range 0 .. (2 ** 31) - 1;
   type Unsigned32 is mod 2 ** 32;

   subtype T_Bit_Count is Positive;
   subtype T_Bit_Index is T_Bit_Count range 1 .. T_Bit_Count'Last;

   type T_Bit_Array is array (T_Bit_Count range <>) of T_Bit;
   pragma Pack (T_Bit_Array);

   function Func (Bit_Array : in T_Bit_Array;
                  Bit_Index : in T_Bit_Index) return Positive;

end Opt37;
-- { dg-compile }
-- { dg-options "-O2 -gnato -fdump-tree-optimized" }

package body Opt37 is

   function To_Unchecked (Bits : T_Bit_Array) return Unsigned32 is
      Value : Unsigned32 := 0;
   begin
      for I in Bits'Range loop
         Value := Value * 2 + Unsigned32 (Bits(I));
      end loop;
      return Value;
   end;

   function To_Scalar (Bits : T_Bit_Array) return Positive is
      Tmp   : Unsigned32;
      Value : Positive;
   begin
      Tmp := To_Unchecked (Bits);
      if Tmp in 0 .. Unsigned32 (Positive'last) then
         Value := Positive (Tmp);
      else
         Value := -Positive (Unsigned32'last - Tmp);
         if Value > Positive'first then
            Value := Value - 1;
         else
            raise Program_Error;
         end if;
      end if;
      return Value;
   end;

   function Func (Bit_Array : T_Bit_Array;
                  Bit_Index : T_Bit_Index) return Positive is
   begin
      return To_Scalar (Bit_Array (Bit_Index .. Bit_Index + 1));
   end;

end Opt37;

-- { dg-final { scan-tree-dump-not "alloca" "optimized" } }
-- { dg-final { cleanup-tree-dump "optimized" } }
Index: tree-ssa-forwprop.c
===================================================================
--- tree-ssa-forwprop.c	(revision 210676)
+++ tree-ssa-forwprop.c	(working copy)
@@ -2642,49 +2642,46 @@ associate_plusminus (gimple_stmt_iterato
 		  gimple_set_modified (stmt, true);
 		}
 	    }
-	  else if (CONVERT_EXPR_CODE_P (def_code) && code == MINUS_EXPR
+	  else if (code == MINUS_EXPR
+		   && CONVERT_EXPR_CODE_P (def_code)
+		   && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
 		   && TREE_CODE (rhs2) == SSA_NAME)
 	    {
-	      /* (T)(ptr + adj) - (T)ptr -> (T)adj.  */
+	      /* (T)(P + A) - (T)P -> (T)A.  */
 	      gimple def_stmt2 = SSA_NAME_DEF_STMT (rhs2);
-	      if (TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
-		  && is_gimple_assign (def_stmt2)
+	      if (is_gimple_assign (def_stmt2)
 		  && can_propagate_from (def_stmt2)
 		  && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2))
 		  && TREE_CODE (gimple_assign_rhs1 (def_stmt2)) == SSA_NAME)
 		{
-		  /* Now we have (T)A - (T)ptr.  */
-		  tree ptr = gimple_assign_rhs1 (def_stmt2);
+		  /* Now we have (T)X - (T)P.  */
+		  tree p = gimple_assign_rhs1 (def_stmt2);
 		  def_stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def_stmt));
 		  if (is_gimple_assign (def_stmt2)
-		      && gimple_assign_rhs_code (def_stmt2) == POINTER_PLUS_EXPR
-		      && gimple_assign_rhs1 (def_stmt2) == ptr)
+		      && can_propagate_from (def_stmt2)
+		      && PLUS_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt2))
+		      && gimple_assign_rhs1 (def_stmt2) == p)
 		    {
-		      /* And finally (T)(ptr + X) - (T)ptr.  */
-		      tree adj = gimple_assign_rhs2 (def_stmt2);
-		      /* If the conversion of the pointer adjustment to the
-		         final type requires a sign- or zero-extension we
-			 have to punt - it is not defined which one is
-			 correct.  */
-		      if (TYPE_PRECISION (TREE_TYPE (rhs1))
-			  <= TYPE_PRECISION (TREE_TYPE (adj))
-			  || (TREE_CODE (adj) == INTEGER_CST
-			      && tree_int_cst_sign_bit (adj) == 0))
+		      /* And finally (T)(P + A) - (T)P.  */
+		      tree a = gimple_assign_rhs2 (def_stmt2);
+		      /* For pointer types, if the conversion of A to the final
+			 type requires a sign- or zero-extension, then we have
+			 to punt - it is not defined which one is correct.  */
+		      if (!POINTER_TYPE_P (TREE_TYPE (rhs1))
+			  || TYPE_PRECISION (TREE_TYPE (rhs1))
+			     <= TYPE_PRECISION (TREE_TYPE (a))
+			  || (TREE_CODE (a) == INTEGER_CST
+			      && tree_int_cst_sign_bit (a) == 0))
 			{
 			  if (useless_type_conversion_p (TREE_TYPE (rhs1),
-							 TREE_TYPE (adj)))
-			    {
-			      code = TREE_CODE (adj);
-			      rhs1 = adj;
-			    }
+							 TREE_TYPE (a)))
+			    code = TREE_CODE (a);
 			  else
-			    {
-			      code = NOP_EXPR;
-			      rhs1 = adj;
-			    }
+			    code = NOP_EXPR;
+			  rhs1 = a;
 			  rhs2 = NULL_TREE;
 			  gimple_assign_set_rhs_with_ops (gsi, code, rhs1,
-							  NULL_TREE);
+							  rhs2);
 			  gcc_assert (gsi_stmt (*gsi) == stmt);
 			  gimple_set_modified (stmt, true);
 			}
Index: tree.h
===================================================================
--- tree.h	(revision 210676)
+++ tree.h	(working copy)
@@ -439,6 +439,19 @@ extern void omp_clause_range_check_faile
   case NOP_EXPR:						\
   case CONVERT_EXPR
 
+/* Tests if CODE is a plus expr (PLUS_EXPR or POINTER_PLUS_EXPR).  */
+#define PLUS_EXPR_CODE_P(CODE)				\
+  ((CODE) == PLUS_EXPR || (CODE) == POINTER_PLUS_EXPR)
+
+/* Similarly, but accept an expressions instead of a tree code.  */
+#define PLUS_EXPR_P(EXP)	PLUS_EXPR_CODE_P (TREE_CODE (EXP))
+
+/* Generate case for PLUS_EXPR, POINTER_PLUS_EXPR.  */
+
+#define CASE_PLUS						\
+  case PLUS_EXPR:						\
+  case POINTER_PLUS_EXPR
+
 /* Given an expression as a tree, strip any conversion that generates
    no instruction.  Accepts both tree and const_tree arguments since
    we are not modifying the tree itself.  */

Reply via email to