This is the mail archive of the gcc@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]

[gsoc 2014] moving fold-const patterns to gimple


Hi, I am an undergraduate student at University of Pune, India, and would
like to work on moving folding patterns from fold-const.c to gimple.

If I understand correctly, constant folding is done on GENERIC (by
routines in fold-const.c), and then GENERIC is lowered to GIMPLE. The
purpose of this project,
is to have constant folding to be performed on GIMPLE instead (in
gimple-fold.c?)

I have a few elementary questions to ask:

a) A contrived example:
Consider a C expression, a = ~0 (assume a is int)
In GENERIC, this would roughly be represented as:
modify_expr<var_decl "a", <bit_not_expr<integer_cst 0>>>
this gets folded to:
modify_expr<var_decl "a", integer_cst -1>
and the corresponding gimple tuple generated is (-fdump-tree-gimple-raw):
gimple_assign <integer_cst, x, -1, NULL, NULL>

So, instead of folding performed on GENERIC, it should be
done on GIMPLE.
So a tuple like the following should be generated by gimplification:
<bit_not_expr, a, 0, NULL, NULL>
and folded to (by call to fold_stmt):
<integer_cst, a, -1, NUL, NULL>
Is this the expected behavior ?

I have attached a rough/incomplete patch (only stage1 compiled cc1), that
does the following foldings on bit_not_expr:
a) ~ INTEGER_CST => folded
b) ~~x => x
c) ~(-x) => x - 1
(For the moment, I put case BIT_NOT_EXPR: return NULL_TREE
in fold_unary_loc to avoid folding in GENERIC on bit_not_expr)

Is the patch going in the correct direction ? Or have I completely missed
the point here ? I would be grateful to receive suggestions, and start working
on a fair patch.

On the following test-case:
int main()
{
  int a, b, c;
  a = ~~~~b;
  c = ~-a;
  return 0;
}

The following GIMPLE is generated:
main ()
gimple_bind <
  int D.1748;
  int D.1749;
  int D.1750;
  int D.1751;
  int D.1752;
  int a;
  int b;
  int c;

  gimple_assign <var_decl, D.1749, b, NULL, NULL>
  gimple_assign <var_decl, a, D.1749, NULL, NULL>
  gimple_assign <plus_expr, c, a, -1, NULL>
  gimple_assign <integer_cst, D.1752, 0, NULL, NULL>
  gimple_return <D.1752>
>

The patch generates two tuples for a = ~~~~b,
where only one is needed, and extra temporaries, which
are not removed after the folding. How should I go about
removing that (should I worry about that since subsequent passes,
shall remove those ?)

b) Some front-ends, C, for example, requires constant folding in certain places,
like case statement. If constant folding is completely moved off to gimple,
how shall this be handled ? Shall we gimplify the expression immediately if
it's required to be evaluated ?

Thanks and Regards,
Prathamesh
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 208111)
+++ gcc/fold-const.c	(working copy)
@@ -8313,6 +8313,7 @@ fold_unary_loc (location_t loc, enum tre
       return NULL_TREE;
 
     case BIT_NOT_EXPR:
+      return NULL_TREE;
       if (TREE_CODE (arg0) == INTEGER_CST)
         return fold_not_const (arg0, type);
       else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 208111)
+++ gcc/gimple-fold.c	(working copy)
@@ -352,6 +352,68 @@ maybe_fold_reference (tree expr, bool is
   return NULL_TREE;
 }
 
+static tree
+fold_not_const (const_tree arg0, tree type)
+{
+  double_int val;
+
+  gcc_assert (TREE_CODE (arg0) == INTEGER_CST);
+
+  val = ~tree_to_double_int (arg0);
+  return force_fit_type_double (type, val, 0, TREE_OVERFLOW (arg0));
+}
+
+static tree
+fold_gimple_bit_not_expr (gimple_stmt_iterator *si)
+{
+  gimple stmt = gsi_stmt (*si);
+  tree rhs = gimple_assign_rhs1 (stmt);
+  tree result = NULL_TREE; 
+  enum tree_code code = TREE_CODE (rhs);
+  tree type = gimple_expr_type (stmt);
+  gimple_stmt_iterator temp_iter;
+
+  if (code == INTEGER_CST)
+    return fold_not_const (rhs, type); 
+  
+  temp_iter = *si;
+  gsi_prev (&temp_iter);
+  gimple prev = gsi_stmt (temp_iter);
+  
+  if (prev)
+    {
+      if (gimple_code (prev) != GIMPLE_ASSIGN)
+	return NULL_TREE;
+
+      switch (gimple_assign_rhs_code (prev))
+	{
+	  case BIT_NOT_EXPR:  // x = ~~y => x = y
+	    if (gimple_assign_lhs (prev) == rhs)
+	      {
+		result = gimple_assign_rhs1 (prev);
+		gsi_remove (&temp_iter, true);
+		return result;
+	      }
+	    return NULL_TREE;
+	
+	  case NEGATE_EXPR:  // x = ~-y => x = y - 1
+	    if (INTEGRAL_TYPE_P (type))
+	      {
+		result = fold_build2 (MINUS_EXPR, type, 
+				      fold_convert (type, gimple_assign_rhs1 (prev)),
+				      build_int_cst (type, 1));
+		gsi_remove (&temp_iter, true);
+		return result;
+	      }
+	    return NULL_TREE;
+
+	  default:
+	    return NULL_TREE;
+	}
+    }
+  
+  return NULL_TREE; 
+}
 
 /* Attempt to fold an assignment statement pointed-to by SI.  Returns a
    replacement rhs for the statement or NULL_TREE if no simplification
@@ -458,8 +520,10 @@ fold_gimple_assign (gimple_stmt_iterator
     case GIMPLE_UNARY_RHS:
       {
 	tree rhs = gimple_assign_rhs1 (stmt);
-
-	result = fold_unary_loc (loc, subcode, gimple_expr_type (stmt), rhs);
+	if (subcode == BIT_NOT_EXPR)
+	  result = fold_gimple_bit_not_expr (si);
+	else
+	  result = fold_unary_loc (loc, subcode, gimple_expr_type (stmt), rhs);
 	if (result)
 	  {
 	    /* If the operation was a conversion do _not_ mark a

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