This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][RFC] Add gimple_fold


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 <rguenther@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;
  }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]