gcc-patches@gcc.gnu.org
[Top] [All Lists]

[patch] Miscelaneous ivopts improvements (1 of 3)

Subject: [patch] Miscelaneous ivopts improvements 1 of 3
From: Zdenek Dvorak
Date: Sun, 30 Jan 2005 19:21:45 +0100
Hello,

in http://gcc.gnu.org/ml/gcc-patches/2004-12/msg01381.html I posted
several patches.  I am resending those of them that I believe to be
suitable for 4.0, together with reasons for this.

The first one is the patch to extend strip_offset and to use it
in selection of iv candidates.  The fact that we are unable to
strip constant offsets from array addresses causes us to create
too many ivs, and is responsible for several regressions in
specfp (especially on fortran testcases).

The improved strip_offset and selection of ivs also helps PR19701.

Bootstrapped & regtested on i686.

Zdenek

        * tree-ssa-loop-ivopts.c (strip_offset): Handle addresses.
        (add_address_candidates): Use strip_offset.
        (difference_cost): Reflect strip_offset change.

Index: tree-ssa-loop-ivopts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-ssa-loop-ivopts.c,v
retrieving revision 2.35
diff -c -3 -p -r2.35 tree-ssa-loop-ivopts.c
*** tree-ssa-loop-ivopts.c      7 Dec 2004 21:23:04 -0000       2.35
--- tree-ssa-loop-ivopts.c      15 Dec 2004 01:01:15 -0000
*************** find_interesting_uses (struct ivopts_dat
*** 1628,1633 ****
--- 1628,1746 ----
    free (body);
  }
  
+ /* Strips constant offsets from EXPR and stores them to OFFSET.  If 
INSIDE_ADDR
+    is true, assume we are inside an address.  If MAY_STRIP_NOPS is true,
+    also strip nops if useful.  */
+ 
+ static tree
+ strip_offset (tree expr, bool inside_addr, bool may_strip_nops,
+             unsigned HOST_WIDE_INT *offset)
+ {
+   tree op0 = NULL_TREE, op1 = NULL_TREE, step;
+   enum tree_code code;
+   tree type;
+   unsigned HOST_WIDE_INT off0, off1, st;
+ 
+   if (may_strip_nops)
+     STRIP_NOPS (expr);
+ 
+   type = TREE_TYPE (expr);
+   code = TREE_CODE (expr);
+   *offset = 0;
+ 
+   switch (code)
+     {
+     case INTEGER_CST:
+       if (!cst_and_fits_in_hwi (expr))
+       return expr;
+ 
+       *offset = int_cst_value (expr);
+       return build_int_cst_type (type, 0);
+ 
+     case PLUS_EXPR:
+     case MINUS_EXPR:
+       op0 = TREE_OPERAND (expr, 0);
+       op1 = TREE_OPERAND (expr, 1);
+ 
+       op0 = strip_offset (op0, false, may_strip_nops, &off0);
+       op1 = strip_offset (op1, false, may_strip_nops, &off1);
+ 
+       *offset = (code == PLUS_EXPR ? off0 + off1 : off0 - off1);
+       if (op0 != TREE_OPERAND (expr, 0)
+         || op1 != TREE_OPERAND (expr, 1))
+       {
+         if (zero_p (op1))
+           expr = op0;
+         else if (zero_p (op0))
+           {
+             if (code == PLUS_EXPR)
+               expr = op1;
+             else
+               expr = build1 (NEGATE_EXPR, type, op1);
+           }
+         else
+           expr = build2 (code, type, op0, op1);
+       }
+       return expr;
+ 
+     case ARRAY_REF:
+       if (!inside_addr)
+       return expr;
+ 
+       step = array_ref_element_size (expr);
+       if (!cst_and_fits_in_hwi (step))
+       goto unary;
+ 
+       st = int_cst_value (step);
+       op1 = TREE_OPERAND (expr, 1);
+       op1 = strip_offset (op1, false, may_strip_nops, &off1);
+       *offset = off1 * st;
+       goto unary;
+ 
+     case COMPONENT_REF:
+       if (!inside_addr)
+       return expr;
+       goto unary;
+ 
+     case ADDR_EXPR:
+       inside_addr = true;
+       goto unary;
+ 
+     case NOP_EXPR:
+     case CONVERT_EXPR:
+     case NON_LVALUE_EXPR:
+       if (may_strip_nops)
+       return expr;
+ 
+       /* If we cannot strip nops, traverse into them.  */
+       op0 = expr;
+       STRIP_NOPS (op0);
+       if (op0 == expr)
+       return expr;
+ 
+       inside_addr = false;
+       goto unary;
+ 
+     default:
+       return expr;
+     }
+ 
+ unary:
+       op0 = TREE_OPERAND (expr, 0);
+       op0 = strip_offset (op0, inside_addr, may_strip_nops, &off0);
+       *offset += off0;
+ 
+       if (op0 != TREE_OPERAND (expr, 0)
+         || (op1 && op1 != TREE_OPERAND (expr, 1)))
+       {
+         expr = copy_node (expr);
+         TREE_OPERAND (expr, 0) = op0;
+         if (op1)
+           TREE_OPERAND (expr, 1) = op1;
+       }
+       return expr;
+ }
+ 
  /* Adds a candidate BASE + STEP * i.  Important field is set to IMPORTANT and
     position to POS.  If USE is not NULL, the candidate is set as related to
     it.  If both BASE and STEP are NULL, we add a pseudocandidate for the
*************** static void
*** 1831,1837 ****
  add_address_candidates (struct ivopts_data *data,
                        struct iv *iv, struct iv_use *use)
  {
!   tree base, abase, tmp, *act;
  
    /* First, the trivial choices.  */
    add_iv_value_candidates (data, iv, use);
--- 1944,1951 ----
  add_address_candidates (struct ivopts_data *data,
                        struct iv *iv, struct iv_use *use)
  {
!   tree base, abase;
!   unsigned HOST_WIDE_INT offset;
  
    /* First, the trivial choices.  */
    add_iv_value_candidates (data, iv, use);
*************** add_address_candidates (struct ivopts_da
*** 1860,1885 ****
  
    /* Third, try removing the constant offset.  */
    abase = iv->base;
!   while (TREE_CODE (abase) == PLUS_EXPR
!        && TREE_CODE (TREE_OPERAND (abase, 1)) != INTEGER_CST)
!     abase = TREE_OPERAND (abase, 0);
!   /* We found the offset, so make the copy of the non-shared part and
!      remove it.  */
!   if (TREE_CODE (abase) == PLUS_EXPR)
!     {
!       tmp = iv->base;
!       act = &base;
! 
!       for (tmp = iv->base; tmp != abase; tmp = TREE_OPERAND (tmp, 0))
!       {
!         *act = build2 (PLUS_EXPR, TREE_TYPE (tmp),
!                        NULL_TREE, TREE_OPERAND (tmp, 1));
!         act = &TREE_OPERAND (*act, 0);
!       }
!       *act = TREE_OPERAND (tmp, 0);
! 
!       add_candidate (data, base, iv->step, false, use);
!     }
  }
  
  /* Possibly adds pseudocandidate for replacing the final value of USE by
--- 1974,1982 ----
  
    /* Third, try removing the constant offset.  */
    abase = iv->base;
!   base = strip_offset (abase, false, false, &offset);
!   if (offset)
!     add_candidate (data, base, iv->step, false, use);
  }
  
  /* Possibly adds pseudocandidate for replacing the final value of USE by
*************** get_computation (struct loop *loop, stru
*** 2350,2402 ****
    return get_computation_at (loop, use, cand, use->stmt);
  }
  
- /* Strips constant offsets from EXPR and adds them to OFFSET.  */
- 
- static void
- strip_offset (tree *expr, unsigned HOST_WIDE_INT *offset)
- {
-   tree op0, op1;
-   enum tree_code code;
-   
-   while (1)
-     {
-       if (cst_and_fits_in_hwi (*expr))
-       {
-         *offset += int_cst_value (*expr);
-         *expr = integer_zero_node;
-         return;
-       }
- 
-       code = TREE_CODE (*expr);
-      
-       if (code != PLUS_EXPR && code != MINUS_EXPR)
-       return;
- 
-       op0 = TREE_OPERAND (*expr, 0);
-       op1 = TREE_OPERAND (*expr, 1);
- 
-       if (cst_and_fits_in_hwi (op1))
-       {
-         if (code == PLUS_EXPR)
-           *offset += int_cst_value (op1);
-         else
-           *offset -= int_cst_value (op1);
- 
-         *expr = op0;
-         continue;
-       }
- 
-       if (code != PLUS_EXPR)
-       return;
- 
-       if (!cst_and_fits_in_hwi (op0))
-       return;
- 
-       *offset += int_cst_value (op0);
-       *expr = op1;
-     }
- }
- 
  /* Returns cost of addition in MODE.  */
  
  static unsigned
--- 2443,2448 ----
*************** difference_cost (struct ivopts_data *dat
*** 2898,2908 ****
  {
    unsigned cost;
    enum machine_mode mode = TYPE_MODE (TREE_TYPE (e1));
  
!   strip_offset (&e1, offset);
!   *offset = -*offset;
!   strip_offset (&e2, offset);
!   *offset = -*offset;
  
    if (TREE_CODE (e1) == ADDR_EXPR)
      return ptr_difference_cost (data, e1, e2, symbol_present, var_present, 
offset,
--- 2950,2960 ----
  {
    unsigned cost;
    enum machine_mode mode = TYPE_MODE (TREE_TYPE (e1));
+   unsigned HOST_WIDE_INT off1, off2;
  
!   e1 = strip_offset (e1, false, true, &off1);
!   e2 = strip_offset (e2, false, true, &off2);
!   *offset += off1 - off2;
  
    if (TREE_CODE (e1) == ADDR_EXPR)
      return ptr_difference_cost (data, e1, e2, symbol_present, var_present, 
offset,

<Prev in Thread] Current Thread [Next in Thread>
  • [patch] Miscelaneous ivopts improvements (1 of 3), Zdenek Dvorak <=