Patchwork Teach sccvn about constant vars

login
register
mail settings
Submitter Jan Hubicka
Date Sept. 4, 2010, 9:13 p.m.
Message ID <20100904211313.GE31380@kam.mff.cuni.cz>
Download mbox | patch
Permalink /patch/63807/
State New
Headers show

Comments

Jan Hubicka - Sept. 4, 2010, 9:13 p.m.
Hi,
this patch adds folding of constant vars accesses into
fully_constant_vn_reference_p.  I tested that both main code paths (vars alone
and array refs) are tripped during bootstrap, the testcase bellow shows
fragment where we otherwise fail to fold until cfgexpand time.

It is my first attempt to add something into tree-ssa-sccvn, so I am not quite
sure I got everything right.  We should probably also fold component ref though
producing a testcase might be tricky (because in array ref one can arrange
the offset to be known only at VN time, but I am not sure I can think of component
ref testcase)

Bootstrapped/regtested x86_64-linux, seems sane?

Honza

/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
enum
{
  ERROR_OK, ERROR_UNKNOWN, 
  ERROR_NUM
};
enum
{ __LC_CTYPE = 0, __LC_NUMERIC = 1, __LC_TIME = 2, __LC_COLLATE =
    3, __LC_MONETARY = 4, __LC_MESSAGES = 5, __LC_ALL = 6, __LC_PAPER =
    10, __LC_MEASUREMENT = 11, __LC_IDENTIFICATION = 12 };
static const char *const _messages[] = {
  "no error", "unknown error", "Internal error: unknown reason",
};
elf_errmsg (int err)
{
  if (err < 0 || err >= ERROR_NUM || _messages[err] == ((void *) 0))
    {
      err = ERROR_UNKNOWN;
    }
  return _messages[err];
}

/* We should fold _messages[1].  */
/* { dg-final { scan-tree-dump "unknown error" "optimized"} } */
/* { dg-final { cleanup-tree-dump "optimized" } } */

	* gimple.h (fold_const_array_ref): Declare.
	* tree-ssa-sccvn.c (fully_constant_vn_reference_p): Fold initialized
	readonly static vars and array references into them.
	* tree-ssa-ccp.c (fold_const_array_ref): Break out from ...
	(fold_const_aggregate_ref): ... here.

Patch

Index: gimple.h
===================================================================
--- gimple.h	(revision 163862)
+++ gimple.h	(working copy)
@@ -4870,6 +4870,7 @@  extern void dump_gimple_statistics (void
 /* In gimple-fold.c.  */
 void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 tree gimple_fold_builtin (gimple);
+tree fold_const_array_ref (tree, tree, tree);
 bool fold_stmt (gimple_stmt_iterator *);
 bool fold_stmt_inplace (gimple);
 tree maybe_fold_offset_to_address (location_t, tree, tree, tree);
Index: tree-ssa-sccvn.c
===================================================================
--- tree-ssa-sccvn.c	(revision 163862)
+++ tree-ssa-sccvn.c	(working copy)
@@ -1109,24 +1109,56 @@  fully_constant_vn_reference_p (vn_refere
 	    return folded;
 	}
     }
-
-  /* Simplify reads from constant strings.  */
+  else if (op->opcode == VAR_DECL
+	   || op->opcode == CONST_DECL)
+    return get_symbol_constant_value (op->op0);
   else if (op->opcode == ARRAY_REF
-	   && TREE_CODE (op->op0) == INTEGER_CST
-	   && integer_zerop (op->op1)
 	   && VEC_length (vn_reference_op_s, operands) == 2)
     {
       vn_reference_op_t arg0;
+      tree ctor = NULL_TREE;
+      tree op0;
+
       arg0 = VEC_index (vn_reference_op_s, operands, 1);
-      if (arg0->opcode == STRING_CST
-	  && (TYPE_MODE (op->type)
-	      == TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0))))
-	  && GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT
-	  && GET_MODE_SIZE (TYPE_MODE (op->type)) == 1
-	  && compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0)
-	return build_int_cst_type (op->type,
-				   (TREE_STRING_POINTER (arg0->op0)
-				    [TREE_INT_CST_LOW (op->op0)]));
+      op0 = arg0->op0;
+
+      switch (arg0->opcode)
+	{
+	case MEM_REF:
+	  /* ???  We could handle this case.  */
+	  if (!integer_zerop (TREE_OPERAND (op0, 1)))
+	    return NULL_TREE;
+	  op0 = get_base_address (op0);
+	  if (!op0
+	      || TREE_CODE (op0) != VAR_DECL)
+	    return NULL_TREE;
+
+	  /* Fallthru.  */
+	case VAR_DECL:
+	  if (!TREE_READONLY (op0)
+	      || TREE_CODE (TREE_TYPE (op0)) != ARRAY_TYPE
+	      || ((TREE_STATIC (op0) || DECL_EXTERNAL (op0))
+		  && !varpool_get_node (op0)->const_value_known))
+	    return NULL_TREE;
+
+	  ctor = DECL_INITIAL (op0);
+	  break;
+
+	case ARRAY_REF:
+	case COMPONENT_REF:
+	  gcc_unreachable ();
+	  break;
+
+	case STRING_CST:
+	case CONSTRUCTOR:
+	  ctor = op0;
+	  break;
+
+	default:
+	  break;
+	}
+      if (ctor)
+        return fold_const_array_ref (op->type, ctor, op->op0);
     }
 
   return NULL_TREE;
Index: tree-ssa-ccp.c
===================================================================
--- tree-ssa-ccp.c	(revision 163862)
+++ tree-ssa-ccp.c	(working copy)
@@ -1310,6 +1310,62 @@  ccp_fold (gimple stmt)
     }
 }
 
+/* Fold array reference of TYPE into a variable with known value CTOR
+   with known index IDX.  */
+tree
+fold_const_array_ref (tree type, tree ctor, tree idx)
+{
+  unsigned HOST_WIDE_INT cnt;
+  tree cfield, cval;
+  tree tem;
+
+  if (ctor == NULL_TREE
+      || (TREE_CODE (ctor) != CONSTRUCTOR
+	  && TREE_CODE (ctor) != STRING_CST)
+      || !TREE_STATIC (ctor))
+    return NULL_TREE;
+
+  /* Get the index.  If we have an SSA_NAME, try to resolve it
+     with the current lattice value for the SSA_NAME.  */
+  switch (TREE_CODE (idx))
+    {
+    case SSA_NAME:
+      if ((tem = get_constant_value (idx))
+	  && TREE_CODE (tem) == INTEGER_CST)
+	idx = tem;
+      else
+	return NULL_TREE;
+      break;
+
+    case INTEGER_CST:
+      break;
+
+    default:
+      return NULL_TREE;
+    }
+
+  /* Fold read from constant string.  */
+  if (TREE_CODE (ctor) == STRING_CST)
+    {
+      if ((TYPE_MODE (type)
+	   == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
+	  && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
+	      == MODE_INT)
+	  && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
+	  && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0)
+	return build_int_cst_type (type,
+				   (TREE_STRING_POINTER (ctor)
+				    [TREE_INT_CST_LOW (idx)]));
+      return NULL_TREE;
+    }
+
+  /* Whoo-hoo!  I'll fold ya baby.  Yeah!  */
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
+    if (tree_int_cst_equal (cfield, idx))
+     return canonicalize_constructor_val (cval);
+  return NULL_TREE;
+}
+
 /* Return the tree representing the element referenced by T if T is an
    ARRAY_REF or COMPONENT_REF into constant aggregates.  Return
    NULL_TREE otherwise.  */
@@ -1332,11 +1388,11 @@  fold_const_aggregate_ref (tree t)
   switch (TREE_CODE (t))
     {
     case ARRAY_REF:
+      base = TREE_OPERAND (t, 0);
       /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
 	 DECL_INITIAL.  If BASE is a nested reference into another
 	 ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
 	 the inner reference.  */
-      base = TREE_OPERAND (t, 0);
       switch (TREE_CODE (base))
 	{
 	case MEM_REF:
@@ -1373,51 +1429,9 @@  fold_const_aggregate_ref (tree t)
 	  return NULL_TREE;
 	}
 
-      if (ctor == NULL_TREE
-	  || (TREE_CODE (ctor) != CONSTRUCTOR
-	      && TREE_CODE (ctor) != STRING_CST)
-	  || !TREE_STATIC (ctor))
-	return NULL_TREE;
-
-      /* Get the index.  If we have an SSA_NAME, try to resolve it
-	 with the current lattice value for the SSA_NAME.  */
-      idx = TREE_OPERAND (t, 1);
-      switch (TREE_CODE (idx))
-	{
-	case SSA_NAME:
-	  if ((tem = get_constant_value (idx))
-	      && TREE_CODE (tem) == INTEGER_CST)
-	    idx = tem;
-	  else
-	    return NULL_TREE;
-	  break;
-
-	case INTEGER_CST:
-	  break;
-
-	default:
-	  return NULL_TREE;
-	}
-
-      /* Fold read from constant string.  */
-      if (TREE_CODE (ctor) == STRING_CST)
-	{
-	  if ((TYPE_MODE (TREE_TYPE (t))
-	       == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-	      && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-	          == MODE_INT)
-	      && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
-	      && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0)
-	    return build_int_cst_type (TREE_TYPE (t),
-				       (TREE_STRING_POINTER (ctor)
-					[TREE_INT_CST_LOW (idx)]));
-	  return NULL_TREE;
-	}
-
-      /* Whoo-hoo!  I'll fold ya baby.  Yeah!  */
-      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
-	if (tree_int_cst_equal (cfield, idx))
-	  return canonicalize_constructor_val (cval);
+      return fold_const_array_ref (TREE_TYPE (t),
+				   ctor,
+				   TREE_OPERAND (t, 1));
       break;
 
     case COMPONENT_REF: