Teach sccvn about constant vars
Richard Guenther
rguenther@suse.de
Mon Sep 6 12:52:00 GMT 2010
On Sun, 5 Sep 2010, Jan Hubicka wrote:
> Hi,
> while analyzing the remianing problems with folding in gfortran testsuite I noticed
> that there is actual bug in way fold_const_aggregate_ref handle folding of
> array refs into STRING_CST because it ignores lower bound.
> Testaces in testsuite are lucky that with ignoring lower bound we get out of
> string and thus do not fold, but this should get into real wrong code bugs
> if gfortran was not forgetting to set TREE_STATIC flags on initializers and thus
> folding happent at all.
>
> Fixed thus (by copying code from expr.c)
As said, please split out the lower-bound fix, we might want to backport
it.
More comments below.
> 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" } } */
>
> Index: tree-ssa-sccvn.c
> * 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 ...; fix handling
> of lower_bound.
> (fold_const_aggregate_ref): ... here.
> ===================================================================
> --- tree-ssa-sccvn.c (revision 163862)
> +++ tree-ssa-sccvn.c (working copy)
> @@ -1109,24 +1109,57 @@ 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);
This needs a check for is_gimple_min_invariant and an unshare_expr.
> 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))
well, also for !(TREE_STATIC (op0) || DECL_EXTERNAL (op0)), right? Thus,
> + 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 ();
Please no unreachables here, the default case should simply
return NULL_TREE.
> + break;
> +
> + case STRING_CST:
> + case CONSTRUCTOR:
> + ctor = op0;
> + break;
> +
> + default:
return NULL_TREE;
> + break;
> + }
> + gcc_assert (op->op1);
No need to assert that.
> + if (ctor)
> + return fold_const_array_ref (op->type, ctor, op->op0, op->op1);
> }
>
> return NULL_TREE;
> Index: tree-ssa-ccp.c
> ===================================================================
> --- tree-ssa-ccp.c (revision 163862)
> +++ tree-ssa-ccp.c (working copy)
> @@ -1310,6 +1310,65 @@ 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, tree low_bound)
> +{
> + 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)
> + {
> + tree index = fold_convert (sizetype, idx);
> + if (low_bound && !integer_zerop (low_bound))
> + index = size_diffop (index, fold_convert (sizetype, low_bound));
Instead of playing games with size_diffop here please reject
non-INTEGER_CST low_bound early, do the arithmetic with
double-ints and ..
> + 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 (index, TREE_STRING_LENGTH (ctor)) < 0)
.. the comparison here as well. Avoids building trees and should
speed up things as well.
Otherwise the patch looks good.
Thanks,
Richard.
> + return build_int_cst_type (type,
> + (TREE_STRING_POINTER (ctor)
> + [TREE_INT_CST_LOW (index)]));
> + 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 +1391,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 +1432,10 @@ 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),
> + array_ref_low_bound (t));
> break;
>
> case COMPONENT_REF:
>
>
--
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex
More information about the Gcc-patches
mailing list