diff options
author | jamborm <jamborm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-08-07 00:51:34 +0000 |
---|---|---|
committer | jamborm <jamborm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-08-07 00:51:34 +0000 |
commit | 547f1802a096a0b092de758d34cafd5c6d026857 (patch) | |
tree | e32de0fb2f6c7763918d428281ac22fa32a5626e /gcc | |
parent | 673dad3fa772c6f11fce17e1493e21ab365ac5fe (diff) | |
download | gcc-547f1802a096a0b092de758d34cafd5c6d026857.tar.gz |
2009-08-07 Martin Jambor <mjambor@suse.cz>
* ipa-prop.c (count_formal_params_1): New function.
(ipa_get_vector_of_formal_parms): New function.
(get_vector_of_formal_parm_types): New function.
(ipa_modify_formal_parameters): New function.
(ipa_modify_call_arguments): New function.
(index_in_adjustments_multiple_times_p): New function.
(ipa_combine_adjustments): New function.
(ipa_dump_param_adjustments): New function.
* ipa-prop.h (struct ipa_parm_adjustment): New type.
(ipa_get_vector_of_formal_parms): Declare.
(ipa_modify_formal_parameters): Declare.
(ipa_modify_call_arguments): Declare.
(ipa_combine_adjustments): Declare.
(ipa_dump_param_adjustments): Declare.
(build_ref_for_offset): Declare.
* Makefile.in (tree-sra.o): Add ipa-prop.h to dependencies.
* tree-sra.c: Include ipa-prop.c.
(build_ref_for_offset): Make public.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@150551 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/Makefile.in | 4 | ||||
-rw-r--r-- | gcc/ipa-prop.c | 474 | ||||
-rw-r--r-- | gcc/ipa-prop.h | 71 | ||||
-rw-r--r-- | gcc/tree-sra.c | 3 |
5 files changed, 562 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 879b9d1e34f..75129f68720 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2009-08-07 Martin Jambor <mjambor@suse.cz> + + * ipa-prop.c (count_formal_params_1): New function. + (ipa_get_vector_of_formal_parms): New function. + (get_vector_of_formal_parm_types): New function. + (ipa_modify_formal_parameters): New function. + (ipa_modify_call_arguments): New function. + (index_in_adjustments_multiple_times_p): New function. + (ipa_combine_adjustments): New function. + (ipa_dump_param_adjustments): New function. + * ipa-prop.h (struct ipa_parm_adjustment): New type. + (ipa_get_vector_of_formal_parms): Declare. + (ipa_modify_formal_parameters): Declare. + (ipa_modify_call_arguments): Declare. + (ipa_combine_adjustments): Declare. + (ipa_dump_param_adjustments): Declare. + (build_ref_for_offset): Declare. + * Makefile.in (tree-sra.o): Add ipa-prop.h to dependencies. + * tree-sra.c: Include ipa-prop.c. + (build_ref_for_offset): Make public. + 2009-08-06 Thomas Schwinge <tschwinge@gnu.org> * gcc/doc/extend.texi (__builtin_extract_return_address) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 4df47353b49..dd52a037cb5 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2887,8 +2887,8 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \ $(TREE_DUMP_H) $(BASIC_BLOCK_H) $(TREE_PASS_H) langhooks.h \ tree-ssa-propagate.h value-prof.h $(FLAGS_H) $(TARGET_H) $(TOPLEV_H) tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) coretypes.h alloc-pool.h \ - $(TM_H) $(TREE_H) $(GIMPLE_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) statistics.h \ - $(TREE_DUMP_H) $(TIMEVAR_H) $(PARAMS_H) $(TARGET_H) $(FLAGS_H) + $(TM_H) $(TREE_H) $(GIMPLE_H) $(TREE_FLOW_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \ + statistics.h $(TREE_DUMP_H) $(TIMEVAR_H) $(PARAMS_H) $(TARGET_H) $(FLAGS_H) tree-switch-conversion.o : tree-switch-conversion.c $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \ $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(GIMPLE_H) \ diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 8308aa36f8f..fcc4f70435c 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -142,6 +142,20 @@ ipa_populate_param_decls (struct cgraph_node *node, } } +/* Return how many formal parameters FNDECL has. */ + +static inline int +count_formal_params_1 (tree fndecl) +{ + tree parm; + int count = 0; + + for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm)) + count++; + + return count; +} + /* Count number of formal parameters in NOTE. Store the result to the appropriate field of INFO. */ @@ -149,16 +163,9 @@ static void ipa_count_formal_params (struct cgraph_node *node, struct ipa_node_params *info) { - tree fndecl; - tree fnargs; - tree parm; int param_num; - fndecl = node->decl; - fnargs = DECL_ARGUMENTS (fndecl); - param_num = 0; - for (parm = fnargs; parm; parm = TREE_CHAIN (parm)) - param_num++; + param_num = count_formal_params_1 (node->decl); ipa_set_param_count (info, param_num); } @@ -1303,3 +1310,454 @@ ipa_print_all_params (FILE * f) for (node = cgraph_nodes; node; node = node->next) ipa_print_node_params (f, node); } + +/* Return a heap allocated vector containing formal parameters of FNDECL. */ + +VEC(tree, heap) * +ipa_get_vector_of_formal_parms (tree fndecl) +{ + VEC(tree, heap) *args; + int count; + tree parm; + + count = count_formal_params_1 (fndecl); + args = VEC_alloc (tree, heap, count); + for (parm = DECL_ARGUMENTS (fndecl); parm; parm = TREE_CHAIN (parm)) + VEC_quick_push (tree, args, parm); + + return args; +} + +/* Return a heap allocated vector containing types of formal parameters of + function type FNTYPE. */ + +static inline VEC(tree, heap) * +get_vector_of_formal_parm_types (tree fntype) +{ + VEC(tree, heap) *types; + int count = 0; + tree t; + + for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) + count++; + + types = VEC_alloc (tree, heap, count); + for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t)) + VEC_quick_push (tree, types, TREE_VALUE (t)); + + return types; +} + +/* Modify the function declaration FNDECL and its type according to the plan in + ADJUSTMENTS. It also sets base fields of individual adjustments structures + to reflect the actual parameters being modified which are determined by the + base_index field. */ + +void +ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments, + const char *synth_parm_prefix) +{ + VEC(tree, heap) *oparms, *otypes; + tree orig_type, new_type = NULL; + tree old_arg_types, t, new_arg_types = NULL; + tree parm, *link = &DECL_ARGUMENTS (fndecl); + int i, len = VEC_length (ipa_parm_adjustment_t, adjustments); + tree new_reversed = NULL; + bool care_for_types, last_parm_void; + + if (!synth_parm_prefix) + synth_parm_prefix = "SYNTH"; + + oparms = ipa_get_vector_of_formal_parms (fndecl); + orig_type = TREE_TYPE (fndecl); + old_arg_types = TYPE_ARG_TYPES (orig_type); + + /* The following test is an ugly hack, some functions simply don't have any + arguments in their type. This is probably a bug but well... */ + care_for_types = (old_arg_types != NULL_TREE); + if (care_for_types) + { + last_parm_void = (TREE_VALUE (tree_last (old_arg_types)) + == void_type_node); + otypes = get_vector_of_formal_parm_types (orig_type); + if (last_parm_void) + gcc_assert (VEC_length (tree, oparms) + 1 == VEC_length (tree, otypes)); + else + gcc_assert (VEC_length (tree, oparms) == VEC_length (tree, otypes)); + } + else + { + last_parm_void = false; + otypes = NULL; + } + + for (i = 0; i < len; i++) + { + struct ipa_parm_adjustment *adj; + gcc_assert (link); + + adj = VEC_index (ipa_parm_adjustment_t, adjustments, i); + parm = VEC_index (tree, oparms, adj->base_index); + adj->base = parm; + + if (adj->copy_param) + { + if (care_for_types) + new_arg_types = tree_cons (NULL_TREE, VEC_index (tree, otypes, + adj->base_index), + new_arg_types); + *link = parm; + link = &TREE_CHAIN (parm); + } + else if (!adj->remove_param) + { + tree new_parm; + tree ptype; + + if (adj->by_ref) + ptype = build_pointer_type (adj->type); + else + ptype = adj->type; + + if (care_for_types) + new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types); + + new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE, + ptype); + DECL_NAME (new_parm) = create_tmp_var_name (synth_parm_prefix); + + DECL_ARTIFICIAL (new_parm) = 1; + DECL_ARG_TYPE (new_parm) = ptype; + DECL_CONTEXT (new_parm) = fndecl; + TREE_USED (new_parm) = 1; + DECL_IGNORED_P (new_parm) = 1; + layout_decl (new_parm, 0); + + add_referenced_var (new_parm); + mark_sym_for_renaming (new_parm); + adj->base = parm; + adj->reduction = new_parm; + + *link = new_parm; + + link = &TREE_CHAIN (new_parm); + } + } + + *link = NULL_TREE; + + if (care_for_types) + { + new_reversed = nreverse (new_arg_types); + if (last_parm_void) + { + if (new_reversed) + TREE_CHAIN (new_arg_types) = void_list_node; + else + new_reversed = void_list_node; + } + } + + /* Use copy_node to preserve as much as possible from original type + (debug info, attribute lists etc.) + Exception is METHOD_TYPEs must have THIS argument. + When we are asked to remove it, we need to build new FUNCTION_TYPE + instead. */ + if (TREE_CODE (orig_type) != METHOD_TYPE + || (VEC_index (ipa_parm_adjustment_t, adjustments, 0)->copy_param + && VEC_index (ipa_parm_adjustment_t, adjustments, 0)->base_index == 0)) + { + new_type = copy_node (orig_type); + TYPE_ARG_TYPES (new_type) = new_reversed; + } + else + { + new_type + = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type), + new_reversed)); + TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type); + DECL_VINDEX (fndecl) = NULL_TREE; + } + + /* This is a new type, not a copy of an old type. Need to reassociate + variants. We can handle everything except the main variant lazily. */ + t = TYPE_MAIN_VARIANT (orig_type); + if (orig_type != t) + { + TYPE_MAIN_VARIANT (new_type) = t; + TYPE_NEXT_VARIANT (new_type) = TYPE_NEXT_VARIANT (t); + TYPE_NEXT_VARIANT (t) = new_type; + } + else + { + TYPE_MAIN_VARIANT (new_type) = new_type; + TYPE_NEXT_VARIANT (new_type) = NULL; + } + + TREE_TYPE (fndecl) = new_type; + if (otypes) + VEC_free (tree, heap, otypes); + VEC_free (tree, heap, oparms); +} + +/* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS. + If this is a directly recursive call, CS must be NULL. Otherwise it must + contain the corresponding call graph edge. */ + +void +ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt, + ipa_parm_adjustment_vec adjustments) +{ + VEC(tree, heap) *vargs; + gimple new_stmt; + gimple_stmt_iterator gsi; + tree callee_decl; + int i, len; + + len = VEC_length (ipa_parm_adjustment_t, adjustments); + vargs = VEC_alloc (tree, heap, len); + + gsi = gsi_for_stmt (stmt); + for (i = 0; i < len; i++) + { + struct ipa_parm_adjustment *adj; + + adj = VEC_index (ipa_parm_adjustment_t, adjustments, i); + + if (adj->copy_param) + { + tree arg = gimple_call_arg (stmt, adj->base_index); + + VEC_quick_push (tree, vargs, arg); + } + else if (!adj->remove_param) + { + tree expr, orig_expr; + bool allow_ptr, repl_found; + + orig_expr = expr = gimple_call_arg (stmt, adj->base_index); + if (TREE_CODE (expr) == ADDR_EXPR) + { + allow_ptr = false; + expr = TREE_OPERAND (expr, 0); + } + else + allow_ptr = true; + + repl_found = build_ref_for_offset (&expr, TREE_TYPE (expr), + adj->offset, adj->type, + allow_ptr); + if (repl_found) + { + if (adj->by_ref) + expr = build_fold_addr_expr (expr); + } + else + { + tree ptrtype = build_pointer_type (adj->type); + expr = orig_expr; + if (!POINTER_TYPE_P (TREE_TYPE (expr))) + expr = build_fold_addr_expr (expr); + if (!useless_type_conversion_p (ptrtype, TREE_TYPE (expr))) + expr = fold_convert (ptrtype, expr); + expr = fold_build2 (POINTER_PLUS_EXPR, ptrtype, expr, + build_int_cst (size_type_node, + adj->offset / BITS_PER_UNIT)); + if (!adj->by_ref) + expr = fold_build1 (INDIRECT_REF, adj->type, expr); + } + expr = force_gimple_operand_gsi (&gsi, expr, + adj->by_ref + || is_gimple_reg_type (adj->type), + NULL, true, GSI_SAME_STMT); + VEC_quick_push (tree, vargs, expr); + } + } + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "replacing stmt:"); + print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, 0); + } + + callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl; + new_stmt = gimple_build_call_vec (callee_decl, vargs); + VEC_free (tree, heap, vargs); + if (gimple_call_lhs (stmt)) + gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt)); + + gimple_set_block (new_stmt, gimple_block (stmt)); + if (gimple_has_location (stmt)) + gimple_set_location (new_stmt, gimple_location (stmt)); + gimple_call_copy_flags (new_stmt, stmt); + gimple_call_set_chain (new_stmt, gimple_call_chain (stmt)); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "with stmt:"); + print_gimple_stmt (dump_file, new_stmt, 0, 0); + fprintf (dump_file, "\n"); + } + gsi_replace (&gsi, new_stmt, true); + if (cs) + cgraph_set_call_stmt (cs, new_stmt); + update_ssa (TODO_update_ssa); + free_dominance_info (CDI_DOMINATORS); +} + +/* Return true iff BASE_INDEX is in ADJUSTMENTS more than once. */ + +static bool +index_in_adjustments_multiple_times_p (int base_index, + ipa_parm_adjustment_vec adjustments) +{ + int i, len = VEC_length (ipa_parm_adjustment_t, adjustments); + bool one = false; + + for (i = 0; i < len; i++) + { + struct ipa_parm_adjustment *adj; + adj = VEC_index (ipa_parm_adjustment_t, adjustments, i); + + if (adj->base_index == base_index) + { + if (one) + return true; + else + one = true; + } + } + return false; +} + + +/* Return adjustments that should have the same effect on function parameters + and call arguments as if they were first changed according to adjustments in + INNER and then by adjustments in OUTER. */ + +ipa_parm_adjustment_vec +ipa_combine_adjustments (ipa_parm_adjustment_vec inner, + ipa_parm_adjustment_vec outer) +{ + int i, outlen = VEC_length (ipa_parm_adjustment_t, outer); + int inlen = VEC_length (ipa_parm_adjustment_t, inner); + int removals = 0; + ipa_parm_adjustment_vec adjustments, tmp; + + tmp = VEC_alloc (ipa_parm_adjustment_t, heap, inlen); + for (i = 0; i < inlen; i++) + { + struct ipa_parm_adjustment *n; + n = VEC_index (ipa_parm_adjustment_t, inner, i); + + if (n->remove_param) + removals++; + else + VEC_quick_push (ipa_parm_adjustment_t, tmp, n); + } + + adjustments = VEC_alloc (ipa_parm_adjustment_t, heap, outlen + removals); + for (i = 0; i < outlen; i++) + { + struct ipa_parm_adjustment *r; + struct ipa_parm_adjustment *out = VEC_index (ipa_parm_adjustment_t, + outer, i); + struct ipa_parm_adjustment *in = VEC_index (ipa_parm_adjustment_t, tmp, + out->base_index); + + gcc_assert (!in->remove_param); + if (out->remove_param) + { + if (!index_in_adjustments_multiple_times_p (in->base_index, tmp)) + { + r = VEC_quick_push (ipa_parm_adjustment_t, adjustments, NULL); + memset (r, 0, sizeof (*r)); + r->remove_param = true; + } + continue; + } + + r = VEC_quick_push (ipa_parm_adjustment_t, adjustments, NULL); + memset (r, 0, sizeof (*r)); + r->base_index = in->base_index; + r->type = out->type; + + /* FIXME: Create nonlocal value too. */ + + if (in->copy_param && out->copy_param) + r->copy_param = true; + else if (in->copy_param) + r->offset = out->offset; + else if (out->copy_param) + r->offset = in->offset; + else + r->offset = in->offset + out->offset; + } + + for (i = 0; i < inlen; i++) + { + struct ipa_parm_adjustment *n = VEC_index (ipa_parm_adjustment_t, + inner, i); + + if (n->remove_param) + VEC_quick_push (ipa_parm_adjustment_t, adjustments, n); + } + + VEC_free (ipa_parm_adjustment_t, heap, tmp); + return adjustments; +} + +/* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human + friendly way, assuming they are meant to be applied to FNDECL. */ + +void +ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments, + tree fndecl) +{ + int i, len = VEC_length (ipa_parm_adjustment_t, adjustments); + bool first = true; + VEC(tree, heap) *parms = ipa_get_vector_of_formal_parms (fndecl); + + fprintf (file, "IPA param adjustments: "); + for (i = 0; i < len; i++) + { + struct ipa_parm_adjustment *adj; + adj = VEC_index (ipa_parm_adjustment_t, adjustments, i); + + if (!first) + fprintf (file, " "); + else + first = false; + + fprintf (file, "%i. base_index: %i - ", i, adj->base_index); + print_generic_expr (file, VEC_index (tree, parms, adj->base_index), 0); + if (adj->base) + { + fprintf (file, ", base: "); + print_generic_expr (file, adj->base, 0); + } + if (adj->reduction) + { + fprintf (file, ", reduction: "); + print_generic_expr (file, adj->reduction, 0); + } + if (adj->new_ssa_base) + { + fprintf (file, ", new_ssa_base: "); + print_generic_expr (file, adj->new_ssa_base, 0); + } + + if (adj->copy_param) + fprintf (file, ", copy_param"); + else if (adj->remove_param) + fprintf (file, ", remove_param"); + else + fprintf (file, ", offset %li", (long) adj->offset); + if (adj->by_ref) + fprintf (file, ", by_ref"); + print_node_brief (file, ", type: ", adj->type, 0); + fprintf (file, "\n"); + } + VEC_free (tree, heap, parms); +} + diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index fafadaca247..4794f691fba 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -403,4 +403,75 @@ void ipa_print_all_params (FILE *); void ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node); void ipa_print_all_jump_functions (FILE * f); +/* Structure to describe transformations of formal parameters and actual + arguments. Each instance describes one new parameter and they are meant to + be stored in a vector. Additionally, most users will probably want to store + adjustments about parameters that are being removed altogether so that SSA + names belonging to them can be replaced by SSA names of an artificial + variable. */ +struct ipa_parm_adjustment +{ + /* The original PARM_DECL itself, helpful for processing of the body of the + function itself. Intended for traversing function bodies. + ipa_modify_formal_parameters, ipa_modify_call_arguments and + ipa_combine_adjustments ignore this and use base_index. + ipa_modify_formal_parameters actually sets this. */ + tree base; + + /* Type of the new parameter. However, if by_ref is true, the real type will + be a pointer to this type. */ + tree type; + + /* The new declaration when creating/replacing a parameter. Created by + ipa_modify_formal_parameters, useful for functions modifying the body + accordingly. */ + tree reduction; + + /* New declaration of a substitute variable that we may use to replace all + non-default-def ssa names when a parm decl is going away. */ + tree new_ssa_base; + + /* If non-NULL and the original parameter is to be removed (copy_param below + is NULL), this is going to be its nonlocalized vars value. */ + tree nonlocal_value; + + /* Offset into the original parameter (for the cases when the new parameter + is a component of an original one). */ + HOST_WIDE_INT offset; + + /* Zero based index of the original parameter this one is based on. (ATM + there is no way to insert a new parameter out of the blue because there is + no need but if it arises the code can be easily exteded to do so.) */ + int base_index; + + /* This new parameter is an unmodified parameter at index base_index. */ + unsigned copy_param : 1; + + /* This adjustment describes a parameter that is about to be removed + completely. Most users will probably need to book keep those so that they + don't leave behinfd any non default def ssa names belonging to them. */ + unsigned remove_param : 1; + + /* The parameter is to be passed by reference. */ + unsigned by_ref : 1; +}; + +typedef struct ipa_parm_adjustment ipa_parm_adjustment_t; +DEF_VEC_O (ipa_parm_adjustment_t); +DEF_VEC_ALLOC_O (ipa_parm_adjustment_t, heap); + +typedef VEC (ipa_parm_adjustment_t, heap) *ipa_parm_adjustment_vec; + +VEC(tree, heap) *ipa_get_vector_of_formal_parms (tree fndecl); +void ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec, + const char *); +void ipa_modify_call_arguments (struct cgraph_edge *, gimple, + ipa_parm_adjustment_vec); +ipa_parm_adjustment_vec ipa_combine_adjustments (ipa_parm_adjustment_vec, + ipa_parm_adjustment_vec); +void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree); + +/* From tree-sra.c: */ +bool build_ref_for_offset (tree *, tree, HOST_WIDE_INT, tree, bool); + #endif /* IPA_PROP_H */ diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index a7bb017b476..33be0f6aaca 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see #include "tree.h" #include "gimple.h" #include "tree-flow.h" +#include "ipa-prop.h" #include "diagnostic.h" #include "statistics.h" #include "tree-dump.h" @@ -1119,7 +1120,7 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, minor rewrite of fold_stmt. */ -static bool +bool build_ref_for_offset (tree *expr, tree type, HOST_WIDE_INT offset, tree exp_type, bool allow_ptr) { |