===================================================================
@@ -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);
===================================================================
@@ -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;
===================================================================
@@ -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:
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.