X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-ssa-ccp.c;h=30a0e14b6fcf48675c8d8024e9423111230574d6;hb=acf5dbc0b7780759d8291a43195df00b4d88c28e;hp=734147794a6b4baa3f0f82829c8f6cc7b79921f9;hpb=32766954718495854f4b31b5f6c84802532db4b7;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 734147794a6..30a0e14b6fc 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -131,7 +131,6 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "target.h" #include "diagnostic-core.h" -#include "toplev.h" #include "dbgcnt.h" @@ -168,6 +167,9 @@ 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. */ @@ -315,7 +317,14 @@ get_value (tree var) static inline tree get_constant_value (tree var) { - prop_value_t *val = get_value (var); + prop_value_t *val; + if (TREE_CODE (var) != SSA_NAME) + { + if (is_gimple_min_invariant (var)) + return var; + return NULL_TREE; + } + val = get_value (var); if (val && val->lattice_val == CONSTANT && (TREE_CODE (val->value) != INTEGER_CST @@ -1308,169 +1317,374 @@ ccp_fold (gimple stmt) } } -/* 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. */ +/* 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. -tree -fold_const_aggregate_ref (tree t) + 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) { - tree base, ctor, idx, field; - unsigned HOST_WIDE_INT cnt; - tree cfield, cval; - tree tem; - - if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration) - return get_symbol_constant_value (t); + 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); + } - tem = fold_read_from_constant_string (t); - if (tem) - return tem; + base = get_constant_value (TREE_OPERAND (base, 0)); + if (!base || TREE_CODE (base) != ADDR_EXPR) + return NULL_TREE; + base = TREE_OPERAND (base, 0); + } - switch (TREE_CODE (t)) + /* 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: - /* 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: - /* ??? We could handle this case. */ - if (!integer_zerop (TREE_OPERAND (base, 1))) - return NULL_TREE; - base = get_base_address (base); - if (!base - || TREE_CODE (base) != VAR_DECL) - return NULL_TREE; + 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); - /* Fallthru. */ - case VAR_DECL: - if (!TREE_READONLY (base) - || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE - || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) - && !varpool_get_node (base)->const_value_known)) - return NULL_TREE; + case STRING_CST: + case CONSTRUCTOR: + return base; - ctor = DECL_INITIAL (base); - break; + default: + return NULL_TREE; + } +} - case ARRAY_REF: - case COMPONENT_REF: - ctor = fold_const_aggregate_ref (base); - break; +/* CTOR is STRING_CST. Fold reference of type TYPE and size SIZE + to the memory at bit OFFSET. - case STRING_CST: - case CONSTRUCTOR: - ctor = base; - break; + We do only simple job of folding byte accesses. */ - default: - return NULL_TREE; - } +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; +} - if (ctor == NULL_TREE - || (TREE_CODE (ctor) != CONSTRUCTOR - && TREE_CODE (ctor) != STRING_CST) - || !TREE_STATIC (ctor)) - 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); - /* 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)) + /* 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) { - case SSA_NAME: - if ((tem = get_constant_value (idx)) - && TREE_CODE (tem) == INTEGER_CST) - idx = tem; + if (TREE_CODE (cfield) == INTEGER_CST) + max_index = index = tree_to_double_int (cfield); else - return NULL_TREE; - break; + { + 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); - case INTEGER_CST: - break; + /* 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); +} - default: - return NULL_TREE; - } +/* CTOR is CONSTRUCTOR of an aggregate or vector. + Fold reference of type TYPE and size SIZE to the memory at bit OFFSET. */ - /* Fold read from constant string. */ - if (TREE_CODE (ctor) == STRING_CST - && TREE_CODE (idx) == INTEGER_CST) - { - tree low_bound = array_ref_low_bound (t); - double_int low_bound_cst; - double_int index_cst; - double_int length_cst; - bool signed_p = TYPE_UNSIGNED (TREE_TYPE (idx)); +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; - if (TREE_CODE (low_bound) != INTEGER_CST) + /* 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; - low_bound_cst = tree_to_double_int (low_bound); - index_cst = tree_to_double_int (idx); - length_cst = uhwi_to_double_int (TREE_STRING_LENGTH (ctor)); - index_cst = double_int_sub (index_cst, low_bound_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 - && double_int_cmp (index_cst, length_cst, signed_p) < 0) - return build_int_cst_type (TREE_TYPE (t), - (TREE_STRING_POINTER (ctor) - [double_int_to_uhwi (index_cst)])); - 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); +} - /* 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); - break; +/* CTOR is value initializing memory, fold reference of type TYPE and size SIZE + to the memory at bit OFFSET. */ - case COMPONENT_REF: - /* 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 VAR_DECL: - if (!TREE_READONLY (base) - || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE - || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) - && !varpool_get_node (base)->const_value_known)) - return NULL_TREE; +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) + { - ctor = DECL_INITIAL (base); - break; + 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); + } - case ARRAY_REF: - case COMPONENT_REF: - ctor = fold_const_aggregate_ref (base); - break; + return NULL_TREE; +} - default: - 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 (ctor == NULL_TREE - || TREE_CODE (ctor) != CONSTRUCTOR - || !TREE_STATIC (ctor)) + /* 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; - field = TREE_OPERAND (t, 1); + /* Out of bound array access. Value is undefined, but don't fold. */ + if (offset < 0) + return NULL_TREE; - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) - if (cfield == field - /* FIXME: Handle bit-fields. */ - && ! DECL_BIT_FIELD (cfield)) - return canonicalize_constructor_val (cval); - break; + return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size); case REALPART_EXPR: case IMAGPART_EXPR: @@ -1482,99 +1696,6 @@ fold_const_aggregate_ref (tree t) break; } - case MEM_REF: - /* Get the base object we are accessing. */ - base = TREE_OPERAND (t, 0); - if (TREE_CODE (base) == SSA_NAME - && (tem = get_constant_value (base))) - base = tem; - if (TREE_CODE (base) != ADDR_EXPR) - return NULL_TREE; - base = TREE_OPERAND (base, 0); - switch (TREE_CODE (base)) - { - case VAR_DECL: - if (DECL_P (base) - && !AGGREGATE_TYPE_P (TREE_TYPE (base)) - && integer_zerop (TREE_OPERAND (t, 1))) - { - tree res = get_symbol_constant_value (base); - if (res - && !useless_type_conversion_p - (TREE_TYPE (t), TREE_TYPE (res))) - res = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (t), res); - return res; - } - - if (!TREE_READONLY (base) - || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE - || ((TREE_STATIC (base) || DECL_EXTERNAL (base)) - && !varpool_get_node (base)->const_value_known)) - return NULL_TREE; - - ctor = DECL_INITIAL (base); - break; - - case STRING_CST: - case CONSTRUCTOR: - ctor = base; - break; - - default: - return NULL_TREE; - } - - if (ctor == NULL_TREE - || (TREE_CODE (ctor) != CONSTRUCTOR - && TREE_CODE (ctor) != STRING_CST) - || !TREE_STATIC (ctor)) - return NULL_TREE; - - /* Get the byte offset. */ - idx = TREE_OPERAND (t, 1); - - /* 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; - } - - /* ??? Implement byte-offset indexing into a non-array CONSTRUCTOR. */ - if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE - && (TYPE_MODE (TREE_TYPE (t)) - == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) - && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t))) != 0 - && integer_zerop - (int_const_binop - (TRUNC_MOD_EXPR, idx, - size_int (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t)))), 0))) - { - idx = int_const_binop (TRUNC_DIV_EXPR, idx, - size_int (GET_MODE_SIZE - (TYPE_MODE (TREE_TYPE (t)))), 0); - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) - if (tree_int_cst_equal (cfield, idx)) - { - cval = canonicalize_constructor_val (cval); - if (useless_type_conversion_p (TREE_TYPE (t), TREE_TYPE (cval))) - return cval; - else if (CONSTANT_CLASS_P (cval)) - return fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (t), cval); - else - return NULL_TREE; - } - } - break; - default: break; } @@ -2148,6 +2269,7 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi) tree lhs = gimple_call_lhs (stmt); tree val; tree argt; + tree callee; bool changed = false; unsigned i; @@ -2188,6 +2310,25 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi) } } + callee = gimple_call_fn (stmt); + if (TREE_CODE (callee) == OBJ_TYPE_REF + && TREE_CODE (OBJ_TYPE_REF_EXPR (callee)) == SSA_NAME) + { + tree expr = OBJ_TYPE_REF_EXPR (callee); + OBJ_TYPE_REF_EXPR (callee) = valueize_op (expr); + if (TREE_CODE (OBJ_TYPE_REF_EXPR (callee)) == ADDR_EXPR) + { + tree t; + t = gimple_fold_obj_type_ref (callee, NULL_TREE); + if (t) + { + gimple_call_set_fn (stmt, t); + changed = true; + } + } + OBJ_TYPE_REF_EXPR (callee) = expr; + } + return changed; }