diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-03-24 11:23:29 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-03-24 11:23:29 +0000 |
commit | 1d0b727d82c306aeef33ed287bec5aa9594bc4b0 (patch) | |
tree | df3f9f4a9233142004cc074157b5b3c2abf3bcb5 /gcc/tree-ssa-ccp.c | |
parent | 9339c78bc6a05194d53a5a19ae3eb0eb58e6324a (diff) | |
download | gcc-1d0b727d82c306aeef33ed287bec5aa9594bc4b0.tar.gz |
2011-03-24 Richard Guenther <rguenther@suse.de>
PR tree-optimization/46562
* tree.c (build_invariant_address): New function.
* tree.h (build_invariant_address): Declare.
* tree-dfa.c (get_addr_base_and_unit_offset): Wrap around
a renamed function moved ...
* tree-flow-inline.h (get_addr_base_and_unit_offset_1): ... here.
Take valueization callback parameter.
* tree-flow.h (gimple_fold_stmt_to_constant): Declare.
* gimple-fold.h: New file.
* tree-ssa-ccp.c (ccp_fold): Use gimple_fold_stmt_to_constant_1.
(ccp_fold, fold_const_aggregate_ref,
fold_ctor_reference, fold_nonarray_ctor_reference,
fold_array_ctor_reference, fold_string_cst_ctor_reference,
get_base_constructor): Move ...
* gimple-fold.c: ... here.
(gimple_fold_stmt_to_constant_1): New function
split out from ccp_fold. Take a valueization callback parameter.
Valueize all operands.
(gimple_fold_stmt_to_constant): New wrapper function.
(fold_const_aggregate_ref_1): New function split out from
fold_const_aggregate_ref. Take a valueization callback parameter.
(fold_const_aggregate_ref): Wrap fold_const_aggregate_ref_1.
* tree-ssa-sccvn.c (simplify_binary_expression): Simplify
invariant POINTER_PLUS_EXPRs to invariant form.
(vn_valueize): New function.
(try_to_simplify): Simplify by using gimple_fold_stmt_to_constant.
* tree-vrp.c (vrp_valueize): New function.
(vrp_visit_assignment_or_call): Use gimple_fold_stmt_to_constant
to fold statements to constants.
* tree-ssa-pre.c (eliminate): Properly guard propagation of
function declarations.
* Makefile.in (tree-ssa-sccvn.o, tree-vrp.o, gimple-fold.o,
tree-ssa-ccp.o): Add gimple-fold.h dependencies.
* c-c++-common/pr46562-2.c: New testcase.
* c-c++-common/pr46562.c: Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171386 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-ccp.c')
-rw-r--r-- | gcc/tree-ssa-ccp.c | 608 |
1 files changed, 5 insertions, 603 deletions
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 4fc4316bb1c..059274a3513 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -132,6 +132,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "diagnostic-core.h" #include "dbgcnt.h" +#include "gimple-fold.h" /* Possible lattice values. */ @@ -167,9 +168,6 @@ static prop_value_t *const_val; static void canonicalize_float_value (prop_value_t *); static bool ccp_fold_stmt (gimple_stmt_iterator *); -static tree fold_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size); /* Dump constant propagation value VAL to file OUTF prefixed by PREFIX. */ @@ -1098,220 +1096,6 @@ ccp_fold (gimple stmt) location_t loc = gimple_location (stmt); switch (gimple_code (stmt)) { - case GIMPLE_ASSIGN: - { - enum tree_code subcode = gimple_assign_rhs_code (stmt); - - switch (get_gimple_rhs_class (subcode)) - { - case GIMPLE_SINGLE_RHS: - { - tree rhs = gimple_assign_rhs1 (stmt); - enum tree_code_class kind = TREE_CODE_CLASS (subcode); - - if (TREE_CODE (rhs) == SSA_NAME) - { - /* If the RHS is an SSA_NAME, return its known constant value, - if any. */ - return get_constant_value (rhs); - } - /* Handle propagating invariant addresses into address operations. - The folding we do here matches that in tree-ssa-forwprop.c. */ - else if (TREE_CODE (rhs) == ADDR_EXPR) - { - tree *base; - base = &TREE_OPERAND (rhs, 0); - while (handled_component_p (*base)) - base = &TREE_OPERAND (*base, 0); - if (TREE_CODE (*base) == MEM_REF - && TREE_CODE (TREE_OPERAND (*base, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (*base, 0)); - if (val - && TREE_CODE (val) == ADDR_EXPR) - { - tree ret, save = *base; - tree new_base; - new_base = fold_build2 (MEM_REF, TREE_TYPE (*base), - unshare_expr (val), - TREE_OPERAND (*base, 1)); - /* We need to return a new tree, not modify the IL - or share parts of it. So play some tricks to - avoid manually building it. */ - *base = new_base; - ret = unshare_expr (rhs); - recompute_tree_invariant_for_addr_expr (ret); - *base = save; - return ret; - } - } - } - else if (TREE_CODE (rhs) == CONSTRUCTOR - && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE - && (CONSTRUCTOR_NELTS (rhs) - == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs)))) - { - unsigned i; - tree val, list; - - list = NULL_TREE; - FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val) - { - val = valueize_op (val); - if (TREE_CODE (val) == INTEGER_CST - || TREE_CODE (val) == REAL_CST - || TREE_CODE (val) == FIXED_CST) - list = tree_cons (NULL_TREE, val, list); - else - return NULL_TREE; - } - - return build_vector (TREE_TYPE (rhs), nreverse (list)); - } - - if (kind == tcc_reference) - { - if ((TREE_CODE (rhs) == VIEW_CONVERT_EXPR - || TREE_CODE (rhs) == REALPART_EXPR - || TREE_CODE (rhs) == IMAGPART_EXPR) - && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (rhs, 0)); - if (val) - return fold_unary_loc (EXPR_LOCATION (rhs), - TREE_CODE (rhs), - TREE_TYPE (rhs), val); - } - else if (TREE_CODE (rhs) == BIT_FIELD_REF - && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (rhs, 0)); - if (val) - return fold_ternary_loc (EXPR_LOCATION (rhs), - TREE_CODE (rhs), - TREE_TYPE (rhs), val, - TREE_OPERAND (rhs, 1), - TREE_OPERAND (rhs, 2)); - } - else if (TREE_CODE (rhs) == MEM_REF - && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME) - { - tree val = get_constant_value (TREE_OPERAND (rhs, 0)); - if (val - && TREE_CODE (val) == ADDR_EXPR) - { - tree tem = fold_build2 (MEM_REF, TREE_TYPE (rhs), - unshare_expr (val), - TREE_OPERAND (rhs, 1)); - if (tem) - rhs = tem; - } - } - return fold_const_aggregate_ref (rhs); - } - else if (kind == tcc_declaration) - return get_symbol_constant_value (rhs); - return rhs; - } - - case GIMPLE_UNARY_RHS: - { - /* Handle unary operators that can appear in GIMPLE form. - Note that we know the single operand must be a constant, - so this should almost always return a simplified RHS. */ - tree lhs = gimple_assign_lhs (stmt); - tree op0 = valueize_op (gimple_assign_rhs1 (stmt)); - - /* Conversions are useless for CCP purposes if they are - value-preserving. Thus the restrictions that - useless_type_conversion_p places for pointer type conversions - do not apply here. Substitution later will only substitute to - allowed places. */ - if (CONVERT_EXPR_CODE_P (subcode) - && POINTER_TYPE_P (TREE_TYPE (lhs)) - && POINTER_TYPE_P (TREE_TYPE (op0))) - { - tree tem; - /* Try to re-construct array references on-the-fly. */ - if (!useless_type_conversion_p (TREE_TYPE (lhs), - TREE_TYPE (op0)) - && ((tem = maybe_fold_offset_to_address - (loc, - op0, integer_zero_node, TREE_TYPE (lhs))) - != NULL_TREE)) - return tem; - return op0; - } - - return - fold_unary_ignore_overflow_loc (loc, subcode, - gimple_expr_type (stmt), op0); - } - - case GIMPLE_BINARY_RHS: - { - /* Handle binary operators that can appear in GIMPLE form. */ - tree op0 = valueize_op (gimple_assign_rhs1 (stmt)); - tree op1 = valueize_op (gimple_assign_rhs2 (stmt)); - - /* Translate &x + CST into an invariant form suitable for - further propagation. */ - if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR - && TREE_CODE (op0) == ADDR_EXPR - && TREE_CODE (op1) == INTEGER_CST) - { - tree off = fold_convert (ptr_type_node, op1); - return build_fold_addr_expr - (fold_build2 (MEM_REF, - TREE_TYPE (TREE_TYPE (op0)), - unshare_expr (op0), off)); - } - - return fold_binary_loc (loc, subcode, - gimple_expr_type (stmt), op0, op1); - } - - case GIMPLE_TERNARY_RHS: - { - /* Handle ternary operators that can appear in GIMPLE form. */ - tree op0 = valueize_op (gimple_assign_rhs1 (stmt)); - tree op1 = valueize_op (gimple_assign_rhs2 (stmt)); - tree op2 = valueize_op (gimple_assign_rhs3 (stmt)); - - return fold_ternary_loc (loc, subcode, - gimple_expr_type (stmt), op0, op1, op2); - } - - default: - gcc_unreachable (); - } - } - break; - - case GIMPLE_CALL: - { - tree fn = valueize_op (gimple_call_fn (stmt)); - if (TREE_CODE (fn) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL - && DECL_BUILT_IN (TREE_OPERAND (fn, 0))) - { - tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt)); - tree call, retval; - unsigned i; - for (i = 0; i < gimple_call_num_args (stmt); ++i) - args[i] = valueize_op (gimple_call_arg (stmt, i)); - call = build_call_array_loc (loc, - gimple_call_return_type (stmt), - fn, gimple_call_num_args (stmt), args); - retval = fold_call_expr (EXPR_LOCATION (call), call, false); - if (retval) - /* fold_call_expr wraps the result inside a NOP_EXPR. */ - STRIP_NOPS (retval); - return retval; - } - return NULL_TREE; - } - case GIMPLE_COND: { /* Handle comparison operators that can appear in GIMPLE form. */ @@ -1327,395 +1111,13 @@ ccp_fold (gimple stmt) return valueize_op (gimple_switch_index (stmt)); } - default: - gcc_unreachable (); - } -} - -/* See if we can find constructor defining value of BASE. - When we know the consructor with constant offset (such as - base is array[40] and we do know constructor of array), then - BIT_OFFSET is adjusted accordingly. - - As a special case, return error_mark_node when constructor - is not explicitly available, but it is known to be zero - such as 'static const int a;'. */ -static tree -get_base_constructor (tree base, HOST_WIDE_INT *bit_offset) -{ - HOST_WIDE_INT bit_offset2, size, max_size; - if (TREE_CODE (base) == MEM_REF) - { - if (!integer_zerop (TREE_OPERAND (base, 1))) - { - if (!host_integerp (TREE_OPERAND (base, 1), 0)) - return NULL_TREE; - *bit_offset += (mem_ref_offset (base).low - * BITS_PER_UNIT); - } - - base = get_constant_value (TREE_OPERAND (base, 0)); - if (!base || TREE_CODE (base) != ADDR_EXPR) - return NULL_TREE; - base = TREE_OPERAND (base, 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. */ - switch (TREE_CODE (base)) - { - case VAR_DECL: - if (!const_value_known_p (base)) - return NULL_TREE; - - /* Fallthru. */ - case CONST_DECL: - if (!DECL_INITIAL (base) - && (TREE_STATIC (base) || DECL_EXTERNAL (base))) - return error_mark_node; - return DECL_INITIAL (base); - - case ARRAY_REF: - case COMPONENT_REF: - base = get_ref_base_and_extent (base, &bit_offset2, &size, &max_size); - if (max_size == -1 || size != max_size) - return NULL_TREE; - *bit_offset += bit_offset2; - return get_base_constructor (base, bit_offset); - - case STRING_CST: - case CONSTRUCTOR: - return base; - - default: - return NULL_TREE; - } -} - -/* CTOR is STRING_CST. Fold reference of type TYPE and size SIZE - to the memory at bit OFFSET. - - We do only simple job of folding byte accesses. */ - -static tree -fold_string_cst_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - if (INTEGRAL_TYPE_P (type) - && (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 - && size == BITS_PER_UNIT - && !(offset % BITS_PER_UNIT)) - { - offset /= BITS_PER_UNIT; - if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor)) - return build_int_cst_type (type, (TREE_STRING_POINTER (ctor) - [offset])); - /* Folding - const char a[20]="hello"; - return a[10]; - - might lead to offset greater than string length. In this case we - know value is either initialized to 0 or out of bounds. Return 0 - in both cases. */ - return build_zero_cst (type); - } - return NULL_TREE; -} - -/* CTOR is CONSTRUCTOR of an array type. Fold reference of type TYPE and size - SIZE to the memory at bit OFFSET. */ - -static tree -fold_array_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - unsigned HOST_WIDE_INT cnt; - tree cfield, cval; - double_int low_bound, elt_size; - double_int index, max_index; - double_int access_index; - tree domain_type = TYPE_DOMAIN (TREE_TYPE (ctor)); - HOST_WIDE_INT inner_offset; - - /* Compute low bound and elt size. */ - if (domain_type && TYPE_MIN_VALUE (domain_type)) - { - /* Static constructors for variably sized objects makes no sense. */ - gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST); - low_bound = tree_to_double_int (TYPE_MIN_VALUE (domain_type)); - } - else - low_bound = double_int_zero; - /* Static constructors for variably sized objects makes no sense. */ - gcc_assert (TREE_CODE(TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))) - == INTEGER_CST); - elt_size = - tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); - - - /* We can handle only constantly sized accesses that are known to not - be larger than size of array element. */ - if (!TYPE_SIZE_UNIT (type) - || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST - || double_int_cmp (elt_size, - tree_to_double_int (TYPE_SIZE_UNIT (type)), 0) < 0) - return NULL_TREE; - - /* Compute the array index we look for. */ - access_index = double_int_udiv (uhwi_to_double_int (offset / BITS_PER_UNIT), - elt_size, TRUNC_DIV_EXPR); - access_index = double_int_add (access_index, low_bound); - - /* And offset within the access. */ - inner_offset = offset % (double_int_to_uhwi (elt_size) * BITS_PER_UNIT); - - /* See if the array field is large enough to span whole access. We do not - care to fold accesses spanning multiple array indexes. */ - if (inner_offset + size > double_int_to_uhwi (elt_size) * BITS_PER_UNIT) - return NULL_TREE; - - index = double_int_sub (low_bound, double_int_one); - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) - { - /* Array constructor might explicitely set index, or specify range - or leave index NULL meaning that it is next index after previous - one. */ - if (cfield) - { - if (TREE_CODE (cfield) == INTEGER_CST) - max_index = index = tree_to_double_int (cfield); - else - { - gcc_assert (TREE_CODE (cfield) == RANGE_EXPR); - index = tree_to_double_int (TREE_OPERAND (cfield, 0)); - max_index = tree_to_double_int (TREE_OPERAND (cfield, 1)); - } - } - else - max_index = index = double_int_add (index, double_int_one); - - /* Do we have match? */ - if (double_int_cmp (access_index, index, 1) >= 0 - && double_int_cmp (access_index, max_index, 1) <= 0) - return fold_ctor_reference (type, cval, inner_offset, size); - } - /* When memory is not explicitely mentioned in constructor, - it is 0 (or out of range). */ - return build_zero_cst (type); -} - -/* CTOR is CONSTRUCTOR of an aggregate or vector. - Fold reference of type TYPE and size SIZE to the memory at bit OFFSET. */ - -static tree -fold_nonarray_ctor_reference (tree type, tree ctor, - unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - unsigned HOST_WIDE_INT cnt; - tree cfield, cval; - - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, - cval) - { - tree byte_offset = DECL_FIELD_OFFSET (cfield); - tree field_offset = DECL_FIELD_BIT_OFFSET (cfield); - tree field_size = DECL_SIZE (cfield); - double_int bitoffset; - double_int byte_offset_cst = tree_to_double_int (byte_offset); - double_int bits_per_unit_cst = uhwi_to_double_int (BITS_PER_UNIT); - double_int bitoffset_end; - - /* Variable sized objects in static constructors makes no sense, - but field_size can be NULL for flexible array members. */ - gcc_assert (TREE_CODE (field_offset) == INTEGER_CST - && TREE_CODE (byte_offset) == INTEGER_CST - && (field_size != NULL_TREE - ? TREE_CODE (field_size) == INTEGER_CST - : TREE_CODE (TREE_TYPE (cfield)) == ARRAY_TYPE)); - - /* Compute bit offset of the field. */ - bitoffset = double_int_add (tree_to_double_int (field_offset), - double_int_mul (byte_offset_cst, - bits_per_unit_cst)); - /* Compute bit offset where the field ends. */ - if (field_size != NULL_TREE) - bitoffset_end = double_int_add (bitoffset, - tree_to_double_int (field_size)); - else - bitoffset_end = double_int_zero; - - /* Is OFFSET in the range (BITOFFSET, BITOFFSET_END)? */ - if (double_int_cmp (uhwi_to_double_int (offset), bitoffset, 0) >= 0 - && (field_size == NULL_TREE - || double_int_cmp (uhwi_to_double_int (offset), - bitoffset_end, 0) < 0)) - { - double_int access_end = double_int_add (uhwi_to_double_int (offset), - uhwi_to_double_int (size)); - double_int inner_offset = double_int_sub (uhwi_to_double_int (offset), - bitoffset); - /* We do have overlap. Now see if field is large enough to - cover the access. Give up for accesses spanning multiple - fields. */ - if (double_int_cmp (access_end, bitoffset_end, 0) > 0) - return NULL_TREE; - return fold_ctor_reference (type, cval, - double_int_to_uhwi (inner_offset), size); - } - } - /* When memory is not explicitely mentioned in constructor, it is 0. */ - return build_zero_cst (type); -} - -/* CTOR is value initializing memory, fold reference of type TYPE and size SIZE - to the memory at bit OFFSET. */ - -static tree -fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset, - unsigned HOST_WIDE_INT size) -{ - tree ret; - - /* We found the field with exact match. */ - if (useless_type_conversion_p (type, TREE_TYPE (ctor)) - && !offset) - return canonicalize_constructor_val (ctor); - - /* We are at the end of walk, see if we can view convert the - result. */ - if (!AGGREGATE_TYPE_P (TREE_TYPE (ctor)) && !offset - /* VIEW_CONVERT_EXPR is defined only for matching sizes. */ - && operand_equal_p (TYPE_SIZE (type), - TYPE_SIZE (TREE_TYPE (ctor)), 0)) - { - ret = canonicalize_constructor_val (ctor); - ret = fold_unary (VIEW_CONVERT_EXPR, type, ret); - if (ret) - STRIP_NOPS (ret); - return ret; - } - if (TREE_CODE (ctor) == STRING_CST) - return fold_string_cst_ctor_reference (type, ctor, offset, size); - if (TREE_CODE (ctor) == CONSTRUCTOR) - { - - if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE) - return fold_array_ctor_reference (type, ctor, offset, size); - else - return fold_nonarray_ctor_reference (type, ctor, offset, size); - } - - 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. */ - -tree -fold_const_aggregate_ref (tree t) -{ - tree ctor, idx, base; - HOST_WIDE_INT offset, size, max_size; - tree tem; - - if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration) - return get_symbol_constant_value (t); - - tem = fold_read_from_constant_string (t); - if (tem) - return tem; - - switch (TREE_CODE (t)) - { - case ARRAY_REF: - case ARRAY_RANGE_REF: - /* Constant indexes are handled well by get_base_constructor. - Only special case variable offsets. - FIXME: This code can't handle nested references with variable indexes - (they will be handled only by iteration of ccp). Perhaps we can bring - get_ref_base_and_extent here and make it use get_constant_value. */ - if (TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME - && (idx = get_constant_value (TREE_OPERAND (t, 1))) - && host_integerp (idx, 0)) - { - tree low_bound, unit_size; - - /* If the resulting bit-offset is constant, track it. */ - if ((low_bound = array_ref_low_bound (t), - host_integerp (low_bound, 0)) - && (unit_size = array_ref_element_size (t), - host_integerp (unit_size, 1))) - { - offset = TREE_INT_CST_LOW (idx); - offset -= TREE_INT_CST_LOW (low_bound); - offset *= TREE_INT_CST_LOW (unit_size); - offset *= BITS_PER_UNIT; - - base = TREE_OPERAND (t, 0); - ctor = get_base_constructor (base, &offset); - /* Empty constructor. Always fold to 0. */ - if (ctor == error_mark_node) - return build_zero_cst (TREE_TYPE (t)); - /* Out of bound array access. Value is undefined, but don't fold. */ - if (offset < 0) - return NULL_TREE; - /* We can not determine ctor. */ - if (!ctor) - return NULL_TREE; - return fold_ctor_reference (TREE_TYPE (t), ctor, offset, - TREE_INT_CST_LOW (unit_size) - * BITS_PER_UNIT); - } - } - /* Fallthru. */ - - case COMPONENT_REF: - case BIT_FIELD_REF: - case TARGET_MEM_REF: - case MEM_REF: - base = get_ref_base_and_extent (t, &offset, &size, &max_size); - ctor = get_base_constructor (base, &offset); - - /* Empty constructor. Always fold to 0. */ - if (ctor == error_mark_node) - return build_zero_cst (TREE_TYPE (t)); - /* We do not know precise address. */ - if (max_size == -1 || max_size != size) - return NULL_TREE; - /* We can not determine ctor. */ - if (!ctor) - return NULL_TREE; - - /* Out of bound array access. Value is undefined, but don't fold. */ - if (offset < 0) - return NULL_TREE; - - return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size); - - case REALPART_EXPR: - case IMAGPART_EXPR: - { - tree c = fold_const_aggregate_ref (TREE_OPERAND (t, 0)); - if (c && TREE_CODE (c) == COMPLEX_CST) - return fold_build1_loc (EXPR_LOCATION (t), - TREE_CODE (t), TREE_TYPE (t), c); - break; - } + case GIMPLE_ASSIGN: + case GIMPLE_CALL: + return gimple_fold_stmt_to_constant_1 (stmt, valueize_op); default: - break; + gcc_unreachable (); } - - return NULL_TREE; } /* Apply the operation CODE in type TYPE to the value, mask pair |