This tries to extend the previously posted CCP folding patch by
introducing a generic interface for non-tree-building, GIMPLE SSA
aware folding.  The low-level interface for folding regular
operations is

/* Fold the expression composed by *CODEP, TYPE and valueized operands 
*OP0P,
   *OP1P and *OP2P (as required), using the VALUEIZE callback to valueize
   SSA names that turn up during statement lookup and producing a result
   of at most KIND.  The folding result will be stored in the operands.
   GF_KIND_FAIL is returned if no folding was done.
   If GF_KIND_CONST or GF_KIND_VAL is returned the folding result is
   stored in *OP0P and is a is_gimple_min_invariant or a is_gimple_val.
   If GF_KIND_STMT is returned the folding result is stored in *CODEP,
   *OP0P, *OP1P and *OP2P (as required) and will compose a valid set of
   operands for a gimple assignment.
   If GF_KIND_COMPLEX is returned the folding result is stored in *OP0P
   and will be an arbitrarily complex tree.  */

enum gf_kind
gimple_fold (enum tree_code *codep, tree type,
             tree *op0p, tree *op1p, tree *op2p,
             tree (*valueize)(tree), enum gf_kind kind)

which would allow existing gimple-level foldings to build ontop of this
(including fold_stmt and friends and the special CCP foldings).

The current implementation is quite lame, just dispatching to fold,
but I plan to integrate it with the CCP and fold_stmt foldings before
considering to merge it (eventually producing some sort of statistics
of what the fold path catches that the gimple path does not).

The low-level interface needs to be amended by one for builtin calls
where I'm not sure if it is going to take decomposed operands
or just a gimple statement (I think we have at most 3 operands to
any builtin we can fold in some way).

This again is just a RFC (even though the patch "works" as far as
plugging into the SCCVN binary operation simplification).

Thanks,
Richard.

<ChangeLog to be inserted...>

Index: gcc/gimple-fold.h
===================================================================
*** gcc/gimple-fold.h   (revision 0)
--- gcc/gimple-fold.h   (revision 0)
***************
*** 0 ****
--- 1,39 ----
+ /* Gimple folding definitions.
+ 
+    Copyright 2011 Free Software Foundation, Inc.
+    Contributed by Richard Guenther <rguent...@suse.de>
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 3, or (at your option) any later
+ version.
+ 
+ GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #ifndef GCC_GIMPLE_FOLD_H
+ #define GCC_GIMPLE_FOLD_H
+ 
+ #include "coretypes.h"
+ 
+ enum gf_kind {
+     GF_KIND_FAIL = 0,
+     GF_KIND_CONST,
+     GF_KIND_VAL,
+     GF_KIND_STMT,
+     GF_KIND_COMPLEX
+ };
+ 
+ enum gf_kind gimple_fold (enum tree_code *, tree,
+                         tree *, tree *, tree *,
+                         tree (*)(tree), enum gf_kind);
+ 
+ #endif  /* GCC_GIMPLE_FOLD_H */
Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c   (revision 171133)
--- gcc/gimple-fold.c   (working copy)
*************** along with GCC; see the file COPYING3.
*** 30,35 ****
--- 30,36 ----
  #include "tree-pass.h"
  #include "tree-ssa-propagate.h"
  #include "target.h"
+ #include "gimple-fold.h"
  
  /* Return true when DECL can be referenced from current unit.
     We can get declarations that are not possible to reference for
*************** maybe_fold_or_comparisons (enum tree_cod
*** 2665,2667 ****
--- 2666,2914 ----
    else
      return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
  }
+ 
+ 
+ static tree
+ build_valueized_tree_from_def (tree name, tree (*valueize)(tree))
+ {
+   gimple def_stmt = SSA_NAME_DEF_STMT (name);
+   tree op0, op1, op2;
+ 
+   if (!is_gimple_assign (def_stmt)
+       || gimple_vuse (def_stmt))
+     return name;
+ 
+   switch (gimple_assign_rhs_class (def_stmt))
+     {
+     case GIMPLE_SINGLE_RHS:
+       return gimple_assign_rhs1 (def_stmt);
+ 
+     case GIMPLE_TERNARY_RHS:
+       op2 = gimple_assign_rhs3 (def_stmt);
+       if (TREE_CODE (op2) == SSA_NAME
+         && valueize)
+       op2 = (*valueize) (op2);
+ 
+     case GIMPLE_BINARY_RHS:
+       op1 = gimple_assign_rhs2 (def_stmt);
+       if (TREE_CODE (op1) == SSA_NAME
+         && valueize)
+       op1 = (*valueize) (op1);
+ 
+     case GIMPLE_UNARY_RHS:
+       op0 = gimple_assign_rhs1 (def_stmt);
+       if (TREE_CODE (op0) == SSA_NAME
+         && valueize)
+       op0 = (*valueize) (op0);
+       break;
+ 
+     default:;
+     }
+ 
+   switch (gimple_assign_rhs_class (def_stmt))
+     {
+     case GIMPLE_UNARY_RHS:
+       return fold_build1 (gimple_assign_rhs_code (def_stmt),
+                         TREE_TYPE (name), op0);
+     case GIMPLE_BINARY_RHS:
+       return fold_build2 (gimple_assign_rhs_code (def_stmt),
+                         TREE_TYPE (name), op0, op1);
+     case GIMPLE_TERNARY_RHS:
+       return fold_build3 (gimple_assign_rhs_code (def_stmt),
+                         TREE_TYPE (name), op0, op1, op2);
+     default:;
+     }
+ 
+   return name;
+ }
+ 
+ static enum gf_kind
+ const_or_val (tree res, enum gf_kind kind)
+ {
+   if (res
+       && kind >= GF_KIND_CONST
+       && is_gimple_min_invariant (res))
+     return GF_KIND_CONST;
+   if (res
+       && kind >= GF_KIND_VAL
+       && is_gimple_val (res))
+     return GF_KIND_VAL;
+   return GF_KIND_FAIL;
+ }
+ 
+ /* Fold the expression composed by *CODEP, TYPE and valueized operands *OP0P,
+    *OP1P and *OP2P (as required), using the VALUEIZE callback to valueize
+    SSA names that turn up during statement lookup and producing a result
+    of at most KIND.  The folding result will be stored in the operands.
+    GF_KIND_FAIL is returned if no folding was done.
+    If GF_KIND_CONST or GF_KIND_VAL is returned the folding result is
+    stored in *OP0P and is a is_gimple_min_invariant or a is_gimple_val.
+    If GF_KIND_STMT is returned the folding result is stored in *CODEP,
+    *OP0P, *OP1P and *OP2P (as required) and will compose a valid set of
+    operands for a gimple assignment.
+    If GF_KIND_COMPLEX is returned the folding result is stored in *OP0P
+    and will be an arbitrarily complex tree.  */
+ 
+ enum gf_kind
+ gimple_fold (enum tree_code *codep, tree type,
+            tree *op0p, tree *op1p, tree *op2p,
+            tree (*valueize)(tree), enum gf_kind kind)
+ {
+   enum tree_code code = *codep;
+   tree op0 = *op0p;
+   tree op1 = *op1p;
+   tree op2 = *op2p;
+   tree alt_op0, alt_op1, res;
+   enum gf_kind res_kind;
+ 
+   switch (code)
+     {
+     case COMPLEX_EXPR:
+       if (TREE_CODE (op0) == SSA_NAME
+         && TREE_CODE (op1) == SSA_NAME)
+       {
+         gimple def_stmt0 = SSA_NAME_DEF_STMT (op0);
+         gimple def_stmt1 = SSA_NAME_DEF_STMT (op1);
+         if (gimple_assign_single_p (def_stmt0)
+             && !gimple_vuse (def_stmt0)
+             && gimple_assign_single_p (def_stmt1)
+             && !gimple_vuse (def_stmt1)
+             && gimple_assign_rhs_code (def_stmt0) == REALPART_EXPR
+             && gimple_assign_rhs_code (def_stmt1) == IMAGPART_EXPR)
+           {
+             tree dop0 = TREE_OPERAND (gimple_assign_rhs1 (def_stmt0), 0);
+             tree dop1 = TREE_OPERAND (gimple_assign_rhs1 (def_stmt1), 0);
+             if (TREE_CODE (dop0) == SSA_NAME)
+               dop0 = (*valueize) (dop0);
+             if (TREE_CODE (dop1) == SSA_NAME)
+               dop1 = (*valueize) (dop1);
+             if (operand_equal_p (dop0, dop1, 0))
+               {
+                 *op0p = dop0;
+                 return (TREE_CODE (dop0) == COMPLEX_CST
+                         ? GF_KIND_CONST : GF_KIND_VAL);
+               }
+           }
+       }
+     default:;
+     }
+ 
+   /* Now fall back to building trees and using fold.  */
+   /* ???  This code should obviously go completely and be replaced by
+      gimple aware, non-tree building variants.  It can be used to
+      identify commonly missed opportunities.  */
+ 
+   switch (get_gimple_rhs_class (code))
+     {
+     case GIMPLE_SINGLE_RHS:
+       if ((code == VIEW_CONVERT_EXPR
+          || code == REALPART_EXPR
+          || code == IMAGPART_EXPR)
+         && TREE_CODE (TREE_OPERAND (op0, 0)) == SSA_NAME)
+       {
+         op0 = TREE_OPERAND (op0, 0);
+         if (valueize)
+           op0 = (*valueize) (op0);
+         goto handle_unary;
+       }
+       else if (code == BIT_FIELD_REF
+              && TREE_CODE (TREE_OPERAND (op0, 0)) == SSA_NAME)
+       {
+         op0 = TREE_OPERAND (op0, 0);
+         if (valueize)
+           op0 = (*valueize) (op0);
+         goto handle_ternary;
+       }
+       return GF_KIND_FAIL;
+ 
+ handle_unary:
+     case GIMPLE_UNARY_RHS:
+       res = fold_unary (code, type, op0);
+       if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+       {
+         *op0p = res;
+         return res_kind;
+       }
+       alt_op0 = op0;
+       if (TREE_CODE (op0) == SSA_NAME)
+       alt_op0 = build_valueized_tree_from_def (op0, valueize);
+       if (alt_op0 != op0)
+       {
+         res = fold_unary (code, type, alt_op0);
+         if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+           {
+             *op0p = res;
+             return res_kind;
+           }
+       }
+       return GF_KIND_FAIL;
+ 
+     case GIMPLE_BINARY_RHS:
+       res = fold_binary (code, type, op0, op1);
+       if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+       {
+         *op0p = res;
+         return res_kind;
+       }
+       alt_op0 = op0;
+       if (TREE_CODE (op0) == SSA_NAME)
+       alt_op0 = build_valueized_tree_from_def (op0, valueize);
+       if (alt_op0 != op0)
+       {
+         res = fold_binary (code, type, alt_op0, op1);
+         if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+           {
+             *op0p = res;
+             return res_kind;
+           }
+       }
+       alt_op1 = op1;
+       if (TREE_CODE (op1) == SSA_NAME)
+       alt_op1 = build_valueized_tree_from_def (op1, valueize);
+       if (alt_op1 != op1)
+       {
+         res = fold_binary (code, type, op0, alt_op1);
+         if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+           {
+             *op0p = res;
+             return res_kind;
+           }
+       }
+       if (alt_op0 != op0
+         && alt_op1 != op1)
+       {
+         res = fold_binary (code, type, alt_op0, alt_op1);
+         if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+           {
+             *op0p = res;
+             return res_kind;
+           }
+       }
+       return GF_KIND_FAIL;
+ 
+ handle_ternary:
+     case GIMPLE_TERNARY_RHS:
+       res = fold_ternary (code, type, op0, op1, op2);
+       if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+       {
+         *op0p = res;
+         return res_kind;
+       }
+       alt_op0 = op0;
+       if (TREE_CODE (op0) == SSA_NAME)
+       alt_op0 = build_valueized_tree_from_def (op0, valueize);
+       if (alt_op0 != op0)
+       {
+         res = fold_ternary (code, type, alt_op0, op1, op2);
+         if ((res_kind = const_or_val (res, kind)) != GF_KIND_FAIL)
+           {
+             *op0p = res;
+             return res_kind;
+           }
+       }
+       return GF_KIND_FAIL;
+ 
+     default:
+       return GF_KIND_FAIL;
+     }
+ }
Index: gcc/tree-ssa-sccvn.c
===================================================================
*** gcc/tree-ssa-sccvn.c        (revision 171133)
--- gcc/tree-ssa-sccvn.c        (working copy)
*************** along with GCC; see the file COPYING3.
*** 44,49 ****
--- 44,50 ----
  #include "params.h"
  #include "tree-ssa-propagate.h"
  #include "tree-ssa-sccvn.h"
+ #include "gimple-fold.h"
  
  /* This algorithm is based on the SCC algorithm presented by Keith
     Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
*************** valueize_expr (tree expr)
*** 2745,2796 ****
  static tree
  simplify_binary_expression (gimple stmt)
  {
-   tree result = NULL_TREE;
    tree op0 = gimple_assign_rhs1 (stmt);
    tree op1 = gimple_assign_rhs2 (stmt);
  
!   /* This will not catch every single case we could combine, but will
!      catch those with constants.  The goal here is to simultaneously
!      combine constants between expressions, but avoid infinite
!      expansion of expressions during simplification.  */
!   if (TREE_CODE (op0) == SSA_NAME)
!     {
!       if (VN_INFO (op0)->has_constants
!         || TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison)
!       op0 = valueize_expr (vn_get_expr_for (op0));
!       else if (SSA_VAL (op0) != VN_TOP && SSA_VAL (op0) != op0)
!       op0 = SSA_VAL (op0);
!     }
! 
!   if (TREE_CODE (op1) == SSA_NAME)
!     {
!       if (VN_INFO (op1)->has_constants)
!       op1 = valueize_expr (vn_get_expr_for (op1));
!       else if (SSA_VAL (op1) != VN_TOP && SSA_VAL (op1) != op1)
!       op1 = SSA_VAL (op1);
!     }
! 
!   /* Avoid folding if nothing changed.  */
!   if (op0 == gimple_assign_rhs1 (stmt)
!       && op1 == gimple_assign_rhs2 (stmt))
!     return NULL_TREE;
! 
!   fold_defer_overflow_warnings ();
! 
!   result = fold_binary (gimple_assign_rhs_code (stmt),
!                       gimple_expr_type (stmt), op0, op1);
!   if (result)
!     STRIP_USELESS_TYPE_CONVERSION (result);
! 
!   fold_undefer_overflow_warnings (result && valid_gimple_rhs_p (result),
!                                 stmt, 0);
! 
!   /* Make sure result is not a complex expression consisting
!      of operators of operators (IE (a + b) + (a + c))
!      Otherwise, we will end up with unbounded expressions if
!      fold does anything at all.  */
!   if (result && valid_gimple_rhs_p (result))
!     return result;
  
    return NULL_TREE;
  }
--- 2746,2767 ----
  static tree
  simplify_binary_expression (gimple stmt)
  {
    tree op0 = gimple_assign_rhs1 (stmt);
    tree op1 = gimple_assign_rhs2 (stmt);
+   enum tree_code code = gimple_assign_rhs_code (stmt);
+   tree dummy;
  
!   if (TREE_CODE (op0) == SSA_NAME
!       && SSA_VAL (op0) != VN_TOP)
!     op0 = SSA_VAL (op0);
! 
!   if (TREE_CODE (op1) == SSA_NAME
!       && SSA_VAL (op1) != VN_TOP)
!     op1 = SSA_VAL (op1);
! 
!   if (gimple_fold (&code, TREE_TYPE (gimple_assign_lhs (stmt)),
!                  &op0, &op1, &dummy, NULL, GF_KIND_VAL) != GF_KIND_FAIL)
!     return op0;
  
    return NULL_TREE;
  }

Reply via email to