diff options
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r-- | gcc/gimple-fold.c | 493 |
1 files changed, 124 insertions, 369 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index a1fc020..6af6511 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -82,7 +82,7 @@ get_symbol_constant_value (tree sym) bool may_propagate_address_into_dereference (tree addr, tree deref) { - gcc_assert (INDIRECT_REF_P (deref) + gcc_assert (TREE_CODE (deref) == MEM_REF && TREE_CODE (addr) == ADDR_EXPR); /* Don't propagate if ADDR's operand has incomplete type. */ @@ -108,15 +108,12 @@ may_propagate_address_into_dereference (tree addr, tree deref) /* A subroutine of fold_stmt. Attempts to fold *(A+O) to A[X]. - BASE is an array type. OFFSET is a byte displacement. ORIG_TYPE - is the desired result type. + BASE is an array type. OFFSET is a byte displacement. LOC is the location of the original expression. */ static tree -maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset, - tree orig_type, - bool allow_negative_idx) +maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset) { tree min_idx, idx, idx_type, elt_offset = integer_zero_node; tree array_type, elt_type, elt_size; @@ -145,8 +142,6 @@ maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset, if (TREE_CODE (array_type) != ARRAY_TYPE) return NULL_TREE; elt_type = TREE_TYPE (array_type); - if (!useless_type_conversion_p (orig_type, elt_type)) - return NULL_TREE; /* Use signed size type for intermediate computation on the index. */ idx_type = ssizetype; @@ -219,34 +214,22 @@ maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset, char *(c[4]); c[3][2]; should not be simplified into (*c)[14] or tree-vrp will - give false warnings. The same is true for - struct A { long x; char d[0]; } *a; - (char *)a - 4; - which should be not folded to &a->d[-8]. */ - if (domain_type - && TYPE_MAX_VALUE (domain_type) - && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST) + give false warnings. + This is only an issue for multi-dimensional arrays. */ + if (TREE_CODE (elt_type) == ARRAY_TYPE + && domain_type) { - tree up_bound = TYPE_MAX_VALUE (domain_type); - - if (tree_int_cst_lt (up_bound, idx) - /* Accesses after the end of arrays of size 0 (gcc - extension) and 1 are likely intentional ("struct - hack"). */ - && compare_tree_int (up_bound, 1) > 0) + if (TYPE_MAX_VALUE (domain_type) + && TREE_CODE (TYPE_MAX_VALUE (domain_type)) == INTEGER_CST + && tree_int_cst_lt (TYPE_MAX_VALUE (domain_type), idx)) return NULL_TREE; - } - if (domain_type - && TYPE_MIN_VALUE (domain_type)) - { - if (!allow_negative_idx - && TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST - && tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type))) + else if (TYPE_MIN_VALUE (domain_type) + && TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST + && tree_int_cst_lt (idx, TYPE_MIN_VALUE (domain_type))) + return NULL_TREE; + else if (compare_tree_int (idx, 0) < 0) return NULL_TREE; } - else if (!allow_negative_idx - && compare_tree_int (idx, 0) < 0) - return NULL_TREE; { tree t = build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE); @@ -256,340 +239,55 @@ maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset, } -/* Attempt to fold *(S+O) to S.X. - BASE is a record type. OFFSET is a byte displacement. ORIG_TYPE - is the desired result type. - - LOC is the location of the original expression. */ - -static tree -maybe_fold_offset_to_component_ref (location_t loc, tree record_type, - tree base, tree offset, tree orig_type) -{ - tree f, t, field_type, tail_array_field, field_offset; - tree ret; - tree new_base; - - if (TREE_CODE (record_type) != RECORD_TYPE - && TREE_CODE (record_type) != UNION_TYPE - && TREE_CODE (record_type) != QUAL_UNION_TYPE) - return NULL_TREE; - - /* Short-circuit silly cases. */ - if (useless_type_conversion_p (record_type, orig_type)) - return NULL_TREE; - - tail_array_field = NULL_TREE; - for (f = TYPE_FIELDS (record_type); f ; f = TREE_CHAIN (f)) - { - int cmp; - - if (TREE_CODE (f) != FIELD_DECL) - continue; - if (DECL_BIT_FIELD (f)) - continue; - - if (!DECL_FIELD_OFFSET (f)) - continue; - field_offset = byte_position (f); - if (TREE_CODE (field_offset) != INTEGER_CST) - continue; - - /* ??? Java creates "interesting" fields for representing base classes. - They have no name, and have no context. With no context, we get into - trouble with nonoverlapping_component_refs_p. Skip them. */ - if (!DECL_FIELD_CONTEXT (f)) - continue; - - /* The previous array field isn't at the end. */ - tail_array_field = NULL_TREE; - - /* Check to see if this offset overlaps with the field. */ - cmp = tree_int_cst_compare (field_offset, offset); - if (cmp > 0) - continue; - - field_type = TREE_TYPE (f); - - /* Here we exactly match the offset being checked. If the types match, - then we can return that field. */ - if (cmp == 0 - && useless_type_conversion_p (orig_type, field_type)) - { - t = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE); - return t; - } - - /* Don't care about offsets into the middle of scalars. */ - if (!AGGREGATE_TYPE_P (field_type)) - continue; - - /* Check for array at the end of the struct. This is often - used as for flexible array members. We should be able to - turn this into an array access anyway. */ - if (TREE_CODE (field_type) == ARRAY_TYPE) - tail_array_field = f; - - /* Check the end of the field against the offset. */ - if (!DECL_SIZE_UNIT (f) - || TREE_CODE (DECL_SIZE_UNIT (f)) != INTEGER_CST) - continue; - t = int_const_binop (MINUS_EXPR, offset, field_offset, 1); - if (!tree_int_cst_lt (t, DECL_SIZE_UNIT (f))) - continue; - - /* If we matched, then set offset to the displacement into - this field. */ - new_base = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE); - SET_EXPR_LOCATION (new_base, loc); - - /* Recurse to possibly find the match. */ - ret = maybe_fold_offset_to_array_ref (loc, new_base, t, orig_type, - f == TYPE_FIELDS (record_type)); - if (ret) - return ret; - ret = maybe_fold_offset_to_component_ref (loc, field_type, new_base, t, - orig_type); - if (ret) - return ret; - } - - if (!tail_array_field) - return NULL_TREE; - - f = tail_array_field; - field_type = TREE_TYPE (f); - offset = int_const_binop (MINUS_EXPR, offset, byte_position (f), 1); - - /* If we get here, we've got an aggregate field, and a possibly - nonzero offset into them. Recurse and hope for a valid match. */ - base = fold_build3 (COMPONENT_REF, field_type, base, f, NULL_TREE); - SET_EXPR_LOCATION (base, loc); - - t = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type, - f == TYPE_FIELDS (record_type)); - if (t) - return t; - return maybe_fold_offset_to_component_ref (loc, field_type, base, offset, - orig_type); -} - -/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type - or BASE[index] or by combination of those. - +/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE[index]. LOC is the location of original expression. - Before attempting the conversion strip off existing ADDR_EXPRs and - handled component refs. */ + Before attempting the conversion strip off existing ADDR_EXPRs. */ tree maybe_fold_offset_to_reference (location_t loc, tree base, tree offset, tree orig_type) { tree ret; - tree type; STRIP_NOPS (base); if (TREE_CODE (base) != ADDR_EXPR) return NULL_TREE; base = TREE_OPERAND (base, 0); - - /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union, - so it needs to be removed and new COMPONENT_REF constructed. - The wrong COMPONENT_REF are often constructed by folding the - (type *)&object within the expression (type *)&object+offset */ - if (handled_component_p (base)) - { - HOST_WIDE_INT sub_offset, size, maxsize; - tree newbase; - newbase = get_ref_base_and_extent (base, &sub_offset, - &size, &maxsize); - gcc_assert (newbase); - if (size == maxsize - && size != -1 - && !(sub_offset & (BITS_PER_UNIT - 1))) - { - base = newbase; - if (sub_offset) - offset = int_const_binop (PLUS_EXPR, offset, - build_int_cst (TREE_TYPE (offset), - sub_offset / BITS_PER_UNIT), 1); - } - } - if (useless_type_conversion_p (orig_type, TREE_TYPE (base)) + if (types_compatible_p (orig_type, TREE_TYPE (base)) && integer_zerop (offset)) return base; - type = TREE_TYPE (base); - ret = maybe_fold_offset_to_component_ref (loc, type, base, offset, orig_type); - if (!ret) - ret = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type, true); - - return ret; + ret = maybe_fold_offset_to_array_ref (loc, base, offset); + if (ret && types_compatible_p (orig_type, TREE_TYPE (ret))) + return ret; + return NULL_TREE; } -/* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type - or &BASE[index] or by combination of those. - - LOC is the location of the original expression. - - Before attempting the conversion strip off existing component refs. */ +/* Attempt to express (ORIG_TYPE)ADDR+OFFSET as (*ADDR)[index]. + LOC is the location of the original expression. */ tree maybe_fold_offset_to_address (location_t loc, tree addr, tree offset, tree orig_type) { - tree t; + tree base, ret; - gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr)) - && POINTER_TYPE_P (orig_type)); - - t = maybe_fold_offset_to_reference (loc, addr, offset, - TREE_TYPE (orig_type)); - if (t != NULL_TREE) - { - tree orig = addr; - tree ptr_type; - - /* For __builtin_object_size to function correctly we need to - make sure not to fold address arithmetic so that we change - reference from one array to another. This would happen for - example for - - struct X { char s1[10]; char s2[10] } s; - char *foo (void) { return &s.s2[-4]; } - - where we need to avoid generating &s.s1[6]. As the C and - C++ frontends create different initial trees - (char *) &s.s1 + -4 vs. &s.s1[-4] we have to do some - sophisticated comparisons here. Note that checking for the - condition after the fact is easier than trying to avoid doing - the folding. */ - STRIP_NOPS (orig); - if (TREE_CODE (orig) == ADDR_EXPR) - orig = TREE_OPERAND (orig, 0); - if ((TREE_CODE (orig) == ARRAY_REF - || (TREE_CODE (orig) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (orig, 1))) == ARRAY_TYPE)) - && (TREE_CODE (t) == ARRAY_REF - || TREE_CODE (t) == COMPONENT_REF) - && !operand_equal_p (TREE_CODE (orig) == ARRAY_REF - ? TREE_OPERAND (orig, 0) : orig, - TREE_CODE (t) == ARRAY_REF - ? TREE_OPERAND (t, 0) : t, 0)) - return NULL_TREE; - - ptr_type = build_pointer_type (TREE_TYPE (t)); - if (!useless_type_conversion_p (orig_type, ptr_type)) - return NULL_TREE; - return build_fold_addr_expr_with_type_loc (loc, t, ptr_type); - } - - return NULL_TREE; -} - -/* A subroutine of fold_stmt. Attempt to simplify *(BASE+OFFSET). - Return the simplified expression, or NULL if nothing could be done. */ - -static tree -maybe_fold_stmt_indirect (tree expr, tree base, tree offset) -{ - tree t; - bool volatile_p = TREE_THIS_VOLATILE (expr); - location_t loc = EXPR_LOCATION (expr); - - /* We may well have constructed a double-nested PLUS_EXPR via multiple - substitutions. Fold that down to one. Remove NON_LVALUE_EXPRs that - are sometimes added. */ - base = fold (base); - STRIP_TYPE_NOPS (base); - TREE_OPERAND (expr, 0) = base; - - /* One possibility is that the address reduces to a string constant. */ - t = fold_read_from_constant_string (expr); - if (t) - return t; - - /* Add in any offset from a POINTER_PLUS_EXPR. */ - if (TREE_CODE (base) == POINTER_PLUS_EXPR) + STRIP_NOPS (addr); + if (TREE_CODE (addr) != ADDR_EXPR) + return NULL_TREE; + base = TREE_OPERAND (addr, 0); + ret = maybe_fold_offset_to_array_ref (loc, base, offset); + if (ret) { - tree offset2; - - offset2 = TREE_OPERAND (base, 1); - if (TREE_CODE (offset2) != INTEGER_CST) + ret = build_fold_addr_expr (ret); + if (!useless_type_conversion_p (orig_type, TREE_TYPE (ret))) return NULL_TREE; - base = TREE_OPERAND (base, 0); - - offset = fold_convert (sizetype, - int_const_binop (PLUS_EXPR, offset, offset2, 1)); + SET_EXPR_LOCATION (ret, loc); } - if (TREE_CODE (base) == ADDR_EXPR) - { - tree base_addr = base; - - /* Strip the ADDR_EXPR. */ - base = TREE_OPERAND (base, 0); - - /* Fold away CONST_DECL to its value, if the type is scalar. */ - if (TREE_CODE (base) == CONST_DECL - && is_gimple_min_invariant (DECL_INITIAL (base))) - return DECL_INITIAL (base); - - /* If there is no offset involved simply return the folded base. */ - if (integer_zerop (offset)) - return base; - - /* Try folding *(&B+O) to B.X. */ - t = maybe_fold_offset_to_reference (loc, base_addr, offset, - TREE_TYPE (expr)); - if (t) - { - /* Preserve volatileness of the original expression. - We can end up with a plain decl here which is shared - and we shouldn't mess with its flags. */ - if (!SSA_VAR_P (t)) - TREE_THIS_VOLATILE (t) = volatile_p; - return t; - } - } - else - { - /* We can get here for out-of-range string constant accesses, - such as "_"[3]. Bail out of the entire substitution search - and arrange for the entire statement to be replaced by a - call to __builtin_trap. In all likelihood this will all be - constant-folded away, but in the meantime we can't leave with - something that get_expr_operands can't understand. */ - - t = base; - STRIP_NOPS (t); - if (TREE_CODE (t) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST) - { - /* FIXME: Except that this causes problems elsewhere with dead - code not being deleted, and we die in the rtl expanders - because we failed to remove some ssa_name. In the meantime, - just return zero. */ - /* FIXME2: This condition should be signaled by - fold_read_from_constant_string directly, rather than - re-checking for it here. */ - return integer_zero_node; - } - - /* Try folding *(B+O) to B->X. Still an improvement. */ - if (POINTER_TYPE_P (TREE_TYPE (base))) - { - t = maybe_fold_offset_to_reference (loc, base, offset, - TREE_TYPE (expr)); - if (t) - return t; - } - } - - /* Otherwise we had an offset that we could not simplify. */ - return NULL_TREE; + return ret; } @@ -622,18 +320,17 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1) /* Or op0 should now be A[0] and the non-constant offset defined via a multiplication by the array element size. */ if (TREE_CODE (op0) == ARRAY_REF - && integer_zerop (TREE_OPERAND (op0, 1)) - && TREE_CODE (op1) == SSA_NAME - && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (op0)), 1)) - { - gimple offset_def = SSA_NAME_DEF_STMT (op1); - if (!is_gimple_assign (offset_def)) - return NULL_TREE; - /* As we will end up creating a variable index array access in the outermost array dimension make sure there isn't a more inner array that the index could overflow to. */ - if (TREE_CODE (TREE_OPERAND (op0, 0)) == ARRAY_REF) + && TREE_CODE (TREE_OPERAND (op0, 0)) != ARRAY_REF + && integer_zerop (TREE_OPERAND (op0, 1)) + && TREE_CODE (op1) == SSA_NAME) + { + gimple offset_def = SSA_NAME_DEF_STMT (op1); + tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (op0)); + if (!host_integerp (elsz, 1) + || !is_gimple_assign (offset_def)) return NULL_TREE; /* Do not build array references of something that we can't @@ -644,15 +341,14 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1) if (gimple_assign_rhs_code (offset_def) == MULT_EXPR && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST - && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), - TYPE_SIZE_UNIT (TREE_TYPE (op0)))) + && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), elsz)) return build_fold_addr_expr (build4 (ARRAY_REF, TREE_TYPE (op0), TREE_OPERAND (op0, 0), gimple_assign_rhs1 (offset_def), TREE_OPERAND (op0, 2), TREE_OPERAND (op0, 3))); - else if (integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (op0))) + else if (integer_onep (elsz) && gimple_assign_rhs_code (offset_def) != MULT_EXPR) return build_fold_addr_expr (build4 (ARRAY_REF, TREE_TYPE (op0), @@ -661,6 +357,38 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1) TREE_OPERAND (op0, 2), TREE_OPERAND (op0, 3))); } + else if (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE + /* Dto. */ + && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) != ARRAY_TYPE + && TREE_CODE (op1) == SSA_NAME) + { + gimple offset_def = SSA_NAME_DEF_STMT (op1); + tree elsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (op0))); + if (!host_integerp (elsz, 1) + || !is_gimple_assign (offset_def)) + return NULL_TREE; + + /* Do not build array references of something that we can't + see the true number of array dimensions for. */ + if (!DECL_P (op0) + && !handled_component_p (op0)) + return NULL_TREE; + + if (gimple_assign_rhs_code (offset_def) == MULT_EXPR + && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST + && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), elsz)) + return build_fold_addr_expr + (build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)), + op0, gimple_assign_rhs1 (offset_def), + integer_zero_node, NULL_TREE)); + else if (integer_onep (elsz) + && gimple_assign_rhs_code (offset_def) != MULT_EXPR) + return build_fold_addr_expr + (build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (op0)), + op0, op1, + integer_zero_node, NULL_TREE)); + } + return NULL_TREE; } @@ -715,13 +443,12 @@ maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1) ptd_type = TREE_TYPE (TREE_TYPE (op0)); /* At which point we can try some of the same things as for indirects. */ - t = maybe_fold_offset_to_array_ref (loc, op0, op1, ptd_type, true); - if (!t) - t = maybe_fold_offset_to_component_ref (loc, TREE_TYPE (op0), op0, op1, - ptd_type); + t = maybe_fold_offset_to_array_ref (loc, op0, op1); if (t) { - t = build1 (ADDR_EXPR, res_type, t); + t = build_fold_addr_expr (t); + if (!useless_type_conversion_p (res_type, TREE_TYPE (t))) + return NULL_TREE; SET_EXPR_LOCATION (t, loc); } @@ -759,19 +486,39 @@ maybe_fold_reference (tree expr, bool is_lhs) while (handled_component_p (*t)) t = &TREE_OPERAND (*t, 0); - if (TREE_CODE (*t) == INDIRECT_REF) + /* Fold back MEM_REFs to reference trees. */ + if (TREE_CODE (*t) == MEM_REF + && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR + && integer_zerop (TREE_OPERAND (*t, 1)) + && (TREE_THIS_VOLATILE (*t) + == TREE_THIS_VOLATILE (TREE_OPERAND (TREE_OPERAND (*t, 0), 0))) + && !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*t, 1))) + && (TYPE_MAIN_VARIANT (TREE_TYPE (*t)) + == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_OPERAND (*t, 1))))) + /* We have to look out here to not drop a required conversion + from the rhs to the lhs if is_lhs, but we don't have the + rhs here to verify that. Thus require strict type + compatibility. */ + && types_compatible_p (TREE_TYPE (*t), + TREE_TYPE (TREE_OPERAND + (TREE_OPERAND (*t, 0), 0)))) { - tree tem = maybe_fold_stmt_indirect (*t, TREE_OPERAND (*t, 0), - integer_zero_node); - /* Avoid folding *"abc" = 5 into 'a' = 5. */ - if (is_lhs && tem && CONSTANT_CLASS_P (tem)) - tem = NULL_TREE; - if (!tem - && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR) - /* If we had a good reason for propagating the address here, - make sure we end up with valid gimple. See PR34989. */ - tem = TREE_OPERAND (TREE_OPERAND (*t, 0), 0); - + tree tem; + *t = TREE_OPERAND (TREE_OPERAND (*t, 0), 0); + tem = maybe_fold_reference (expr, is_lhs); + if (tem) + return tem; + return expr; + } + /* Canonicalize MEM_REFs invariant address operand. */ + else if (TREE_CODE (*t) == MEM_REF + && TREE_CODE (TREE_OPERAND (*t, 0)) == ADDR_EXPR + && !DECL_P (TREE_OPERAND (TREE_OPERAND (*t, 0), 0)) + && !CONSTANT_CLASS_P (TREE_OPERAND (TREE_OPERAND (*t, 0), 0))) + { + tree tem = fold_binary (MEM_REF, TREE_TYPE (*t), + TREE_OPERAND (*t, 0), + TREE_OPERAND (*t, 1)); if (tem) { *t = tem; @@ -863,10 +610,18 @@ fold_gimple_assign (gimple_stmt_iterator *si) else if (TREE_CODE (rhs) == ADDR_EXPR) { - tree tem = maybe_fold_reference (TREE_OPERAND (rhs, 0), true); - if (tem) + tree ref = TREE_OPERAND (rhs, 0); + tree tem = maybe_fold_reference (ref, true); + if (tem + && TREE_CODE (tem) == MEM_REF + && integer_zerop (TREE_OPERAND (tem, 1))) + result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (tem, 0)); + else if (tem) result = fold_convert (TREE_TYPE (rhs), build_fold_addr_expr_loc (loc, tem)); + else if (TREE_CODE (ref) == MEM_REF + && integer_zerop (TREE_OPERAND (ref, 1))) + result = fold_convert (TREE_TYPE (rhs), TREE_OPERAND (ref, 0)); } else if (TREE_CODE (rhs) == CONSTRUCTOR @@ -1580,7 +1335,7 @@ gimple_get_relevant_ref_binfo (tree ref, tree known_binfo) return TYPE_BINFO (TREE_TYPE (ref)); else if (known_binfo && (TREE_CODE (ref) == SSA_NAME - || TREE_CODE (ref) == INDIRECT_REF)) + || TREE_CODE (ref) == MEM_REF)) return known_binfo; else return NULL_TREE; |