From: Daniel Berlin Date: Wed, 15 Feb 2006 22:09:45 +0000 (+0000) Subject: tree.c (init_ttree): Add STRUCT_FIELD_TAG handling. X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3c0b6c430026d7d9d20a8a72e35108b6fb769af2;p=platform%2Fupstream%2Fgcc.git tree.c (init_ttree): Add STRUCT_FIELD_TAG handling. 2006-02-15 Daniel Berlin * tree.c (init_ttree): Add STRUCT_FIELD_TAG handling. (tree_code_size): Ditto. * tree.h (struct tree_memory_tag): Remove parent_var. (struct tree_struct_field_tag): New. (SFT_OFFSET): New. (SFT_SIZE): New. (union tree_node): Add sft member. * tree-ssa-alias.c (get_tmt_for): Don't handle TYPE_READONLY specially here. (create_sft): Add size and offset argument, set SFT_OFFSET and SFT_SIZE. (create_overlap_variables_for): Update for SFT_OFFSET/SFT_SIZE. * treestruct.def: Add TS_STRUCT_FIELD_TAG. * tree-flow-inline.h (get_subvar_at): Update for SFT_OFFSET/SFT_SIZE. (var_can_have_subvars): Ditto. (overlap_subvar): Ditto. * print-tree.c (print_node): Print out interesting things for SFT's. * tree-flow.h (struct subvar): Remove offset and size members. * tree-ssa-operands.c (get_expr_operands): Update for get_indirect_ref_operands changes. (get_indirect_ref_operands): Call add_virtual_operand instead of add_stmt_operand. Only recurse on base var if requested. (access_can_touch_variable): New function. (add_stmt_operand): Split virtual operand handling into ... (add_virtual_operand): Here. Add offset, size, and for_clobber arguments. Prune alias sets. (add_call_clobber_ops): Call add_virtual_operand. From-SVN: r111120 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9b388d6..50477ba 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,35 @@ +2006-02-15 Daniel Berlin + + * tree.c (init_ttree): Add STRUCT_FIELD_TAG handling. + (tree_code_size): Ditto. + * tree.h (struct tree_memory_tag): Remove parent_var. + (struct tree_struct_field_tag): New. + (SFT_OFFSET): New. + (SFT_SIZE): New. + (union tree_node): Add sft member. + * tree-ssa-alias.c (get_tmt_for): Don't handle TYPE_READONLY + specially here. + (create_sft): Add size and offset argument, set SFT_OFFSET and + SFT_SIZE. + (create_overlap_variables_for): Update for SFT_OFFSET/SFT_SIZE. + * treestruct.def: Add TS_STRUCT_FIELD_TAG. + * tree-flow-inline.h (get_subvar_at): Update for + SFT_OFFSET/SFT_SIZE. + (var_can_have_subvars): Ditto. + (overlap_subvar): Ditto. + * print-tree.c (print_node): Print out interesting things for + SFT's. + * tree-flow.h (struct subvar): Remove offset and size members. + * tree-ssa-operands.c (get_expr_operands): Update for + get_indirect_ref_operands changes. + (get_indirect_ref_operands): Call add_virtual_operand instead of + add_stmt_operand. Only recurse on base var if requested. + (access_can_touch_variable): New function. + (add_stmt_operand): Split virtual operand handling into ... + (add_virtual_operand): Here. Add offset, size, and for_clobber + arguments. Prune alias sets. + (add_call_clobber_ops): Call add_virtual_operand. + 2006-02-15 Jakub Jelinek PR middle-end/26300 diff --git a/gcc/print-tree.c b/gcc/print-tree.c index dad7e59..02e5c7b 100644 --- a/gcc/print-tree.c +++ b/gcc/print-tree.c @@ -510,6 +510,15 @@ print_node (FILE *file, const char *prefix, tree node, int indent) && DECL_HAS_VALUE_EXPR_P (node)) print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); + if (TREE_CODE (node) == STRUCT_FIELD_TAG) + { + fprintf (file, " sft size " HOST_WIDE_INT_PRINT_DEC, + SFT_SIZE (node)); + fprintf (file, " sft offset " HOST_WIDE_INT_PRINT_DEC, + SFT_OFFSET (node)); + print_node_brief (file, "parent var", SFT_PARENT_VAR (node), + indent + 4); + } /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 1abf556..6a37b86 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -1450,7 +1450,7 @@ get_subvar_at (tree var, unsigned HOST_WIDE_INT offset) subvar_t sv; for (sv = get_subvars_for_var (var); sv; sv = sv->next) - if (sv->offset == offset) + if (SFT_OFFSET (sv->var) == offset) return sv->var; return NULL_TREE; @@ -1491,7 +1491,7 @@ var_can_have_subvars (tree v) static inline bool overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size, - subvar_t sv, bool *exact) + tree sv, bool *exact) { /* There are three possible cases of overlap. 1. We can have an exact overlap, like so: @@ -1511,17 +1511,19 @@ overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size, if (exact) *exact = false; - if (offset == sv->offset && size == sv->size) + if (offset == SFT_OFFSET (sv) && size == SFT_SIZE (sv)) { if (exact) *exact = true; return true; } - else if (offset >= sv->offset && offset < (sv->offset + sv->size)) + else if (offset >= SFT_OFFSET (sv) + && offset < (SFT_OFFSET (sv) + SFT_SIZE (sv))) { return true; } - else if (offset < sv->offset && (size > sv->offset - offset)) + else if (offset < SFT_OFFSET (sv) + && (size > SFT_OFFSET (sv) - offset)) { return true; } diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 7774c3b..864835b 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -149,12 +149,6 @@ struct subvar GTY(()) /* Fake variable. */ tree var; - /* Offset inside structure. */ - unsigned HOST_WIDE_INT offset; - - /* Size of the field. */ - unsigned HOST_WIDE_INT size; - /* Next subvar for this structure. */ subvar_t next; }; @@ -610,7 +604,7 @@ extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *, static inline bool var_can_have_subvars (tree); static inline bool overlap_subvar (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT, - subvar_t, bool *); + tree, bool *); /* Call-back function for walk_use_def_chains(). At each reaching definition, a function with this prototype is called. */ diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 75a5ae5..b262fd0 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2061,8 +2061,7 @@ get_tmt_for (tree ptr, struct alias_info *ai) { struct alias_map_d *curr = ai->pointers[i]; tree curr_tag = var_ann (curr->var)->type_mem_tag; - if (tag_set == curr->set - && TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (curr_tag))) + if (tag_set == curr->set) { tag = curr_tag; break; @@ -2099,10 +2098,6 @@ get_tmt_for (tree ptr, struct alias_info *ai) pointed-to type. */ gcc_assert (tag_set == get_alias_set (tag)); - /* If PTR's pointed-to type is read-only, then TAG's type must also - be read-only. */ - gcc_assert (TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (tag))); - return tag; } @@ -2749,11 +2744,12 @@ get_or_create_used_part_for (size_t uid) } -/* Create and return a structure sub-variable for field type FIELD of - variable VAR. */ +/* Create and return a structure sub-variable for field type FIELD at + offset OFFSET, with size SIZE, of variable VAR. */ static tree -create_sft (tree var, tree field) +create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset, + unsigned HOST_WIDE_INT size) { var_ann_t ann; tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT"); @@ -2771,7 +2767,8 @@ create_sft (tree var, tree field) ann->type_mem_tag = NULL; add_referenced_tmp_var (subvar); SFT_PARENT_VAR (subvar) = var; - + SFT_OFFSET (subvar) = offset; + SFT_SIZE (subvar) = size; return subvar; } @@ -2882,19 +2879,17 @@ create_overlap_variables_for (tree var) && currfotype == lastfotype)) continue; sv = GGC_NEW (struct subvar); - sv->offset = fo->offset; - sv->size = fosize; sv->next = *subvars; - sv->var = create_sft (var, fo->type); + sv->var = create_sft (var, fo->type, fo->offset, fosize); if (dump_file) { fprintf (dump_file, "structure field tag %s created for var %s", get_name (sv->var), get_name (var)); fprintf (dump_file, " offset " HOST_WIDE_INT_PRINT_DEC, - sv->offset); + SFT_OFFSET (sv->var)); fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC, - sv->size); + SFT_SIZE (sv->var)); fprintf (dump_file, "\n"); } diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index fbee0b9..2d0e71c 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -128,7 +128,8 @@ static unsigned operand_memory_index; static void get_expr_operands (tree, tree *, int); static void get_asm_expr_operands (tree); -static void get_indirect_ref_operands (tree, tree, int); +static void get_indirect_ref_operands (tree, tree, int, tree, HOST_WIDE_INT, + HOST_WIDE_INT, bool); static void get_tmr_operands (tree, tree, int); static void get_call_expr_operands (tree, tree); static inline void append_def (tree *); @@ -138,6 +139,9 @@ static void append_v_must_def (tree); static void add_call_clobber_ops (tree, tree); static void add_call_read_ops (tree, tree); static void add_stmt_operand (tree *, stmt_ann_t, int); +static void add_virtual_operand (tree, stmt_ann_t, int, tree, + HOST_WIDE_INT, HOST_WIDE_INT, + bool); static void build_ssa_operands (tree stmt); static def_optype_p free_defs = NULL; @@ -1123,7 +1127,8 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) case ALIGN_INDIRECT_REF: case INDIRECT_REF: - get_indirect_ref_operands (stmt, expr, flags); + get_indirect_ref_operands (stmt, expr, flags, NULL_TREE, + 0, -1, true); return; case TARGET_MEM_REF: @@ -1165,7 +1170,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) for (sv = svars; sv; sv = sv->next) { bool exact; - if (overlap_subvar (offset, maxsize, sv, &exact)) + if (overlap_subvar (offset, maxsize, sv->var, &exact)) { int subvar_flags = flags; none = false; @@ -1178,6 +1183,12 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) if (!none) flags |= opf_no_vops; } + else if (TREE_CODE (ref) == INDIRECT_REF) + { + get_indirect_ref_operands (stmt, ref, flags, expr, + offset, maxsize, false); + flags |= opf_no_vops; + } /* Even if we found subvars above we need to ensure to see immediate uses for d in s.a[d]. In case of s.a having @@ -1416,10 +1427,24 @@ get_asm_expr_operands (tree stmt) } /* A subroutine of get_expr_operands to handle INDIRECT_REF, - ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF. */ + ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF. + STMT is the statement being processed, EXPR is the INDIRECT_REF + that got us here. FLAGS is as in get_expr_operands. + FULL_REF contains the full pointer dereference expression, if we + have it, or NULL otherwise. + OFFSET and SIZE are the location of the access inside the + dereferenced pointer, if known. + RECURSE_ON_BASE should be set to true if we want to continue + calling get_expr_operands on the base pointer, and false if + something else will do it for us. + +*/ static void -get_indirect_ref_operands (tree stmt, tree expr, int flags) +get_indirect_ref_operands (tree stmt, tree expr, int flags, + tree full_ref, + HOST_WIDE_INT offset, HOST_WIDE_INT size, + bool recurse_on_base) { tree *pptr = &TREE_OPERAND (expr, 0); tree ptr = *pptr; @@ -1438,7 +1463,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags) && pi->name_mem_tag) { /* PTR has its own memory tag. Use it. */ - add_stmt_operand (&pi->name_mem_tag, s_ann, flags); + add_virtual_operand (pi->name_mem_tag, s_ann, flags, + full_ref, offset, size, false); } else { @@ -1464,8 +1490,10 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags) if (TREE_CODE (ptr) == SSA_NAME) ptr = SSA_NAME_VAR (ptr); v_ann = var_ann (ptr); + if (v_ann->type_mem_tag) - add_stmt_operand (&v_ann->type_mem_tag, s_ann, flags); + add_virtual_operand (v_ann->type_mem_tag, s_ann, flags, + full_ref, offset, size, false); } } @@ -1483,7 +1511,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags) gcc_unreachable (); /* Add a USE operand for the base pointer. */ - get_expr_operands (stmt, pptr, opf_none); + if (recurse_on_base) + get_expr_operands (stmt, pptr, opf_none); } /* A subroutine of get_expr_operands to handle TARGET_MEM_REF. */ @@ -1528,7 +1557,7 @@ get_tmr_operands (tree stmt, tree expr, int flags) for (sv = svars; sv; sv = sv->next) { bool exact; - if (overlap_subvar (offset, maxsize, sv, &exact)) + if (overlap_subvar (offset, maxsize, sv->var, &exact)) { int subvar_flags = flags; if (!exact || size != maxsize) @@ -1580,30 +1609,151 @@ get_call_expr_operands (tree stmt, tree expr) } +/* REF is a tree that contains the entire pointer dereference + expression, if available, or NULL otherwise. ALIAS is the variable + we are asking if REF can access. OFFSET and SIZE come from the + memory access expression that generated this virtual operand. + FOR_CLOBBER is true is this is adding a virtual operand for a call + clobber. */ + +static bool +access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset, + HOST_WIDE_INT size) +{ + bool offsetgtz = offset > 0; + unsigned HOST_WIDE_INT uoffset = (unsigned HOST_WIDE_INT) offset; + tree base = ref ? get_base_address (ref) : NULL; + + /* If ALIAS is an SFT, it can't be touched if the offset + and size of the access is not overlapping with the SFT offset and + size. This is only true if we are accessing through a pointer + to a type that is the same as SFT_PARENT_VAR. Otherwise, we may + be accessing through a pointer to some substruct of the + structure, and if we try to prune there, we will have the wrong + offset, and get the wrong answer. + i.e., we can't prune without more work if we have something like + struct gcc_target + { + struct asm_out + { + const char *byte_op; + struct asm_int_op + { + const char *hi; + } aligned_op; + } asm_out; + } targetm; + + foo = &targetm.asm_out.aligned_op; + return foo->hi; + + SFT.1, which represents hi, will have SFT_OFFSET=32 because in + terms of SFT_PARENT_VAR, that is where it is. + However, the access through the foo pointer will be at offset 0. + */ + if (size != -1 + && TREE_CODE (alias) == STRUCT_FIELD_TAG + && base + && TREE_TYPE (base) == TREE_TYPE (SFT_PARENT_VAR (alias)) + && !overlap_subvar (offset, size, alias, NULL)) + { +#ifdef ACCESS_DEBUGGING + fprintf (stderr, "Access to "); + print_generic_expr (stderr, ref, 0); + fprintf (stderr, " may not touch "); + print_generic_expr (stderr, alias, 0); + fprintf (stderr, " in function %s\n", get_name (current_function_decl)); +#endif + return false; + } + /* Without strict aliasing, it is impossible for a component access + through a pointer to touch a random variable, unless that + variable *is* a structure or a pointer. -/* Add *VAR_P to the appropriate operand array for INFO. FLAGS is as in - get_expr_operands. If *VAR_P is a GIMPLE register, it will be added to - the statement's real operands, otherwise it is added to virtual - operands. */ + + IE given p->c, and some random global variable b, + there is no legal way that p->c could be an access to b. + + Without strict aliasing on, we consider it legal to do something + like: + struct foos { int l; }; + int foo; + static struct foos *getfoo(void); + int main (void) + { + struct foos *f = getfoo(); + f->l = 1; + foo = 2; + if (f->l == 1) + abort(); + exit(0); + } + static struct foos *getfoo(void) + { return (struct foos *)&foo; } + + (taken from 20000623-1.c) + */ + else if (ref + && flag_strict_aliasing + && TREE_CODE (ref) != INDIRECT_REF + && !MTAG_P (alias) + && !AGGREGATE_TYPE_P (TREE_TYPE (alias)) + && !TREE_CODE (TREE_TYPE (alias)) == COMPLEX_TYPE + && !POINTER_TYPE_P (TREE_TYPE (alias))) + { +#ifdef ACCESS_DEBUGGING + fprintf (stderr, "Access to "); + print_generic_expr (stderr, ref, 0); + fprintf (stderr, " may not touch "); + print_generic_expr (stderr, alias, 0); + fprintf (stderr, " in function %s\n", get_name (current_function_decl)); +#endif + return false; + } + /* If the offset of the access is greater than the size of one of + the possible aliases, it can't be touching that alias, because it + would be past the end of the structure. */ + else if (ref + && flag_strict_aliasing + && TREE_CODE (ref) != INDIRECT_REF + && !MTAG_P (alias) + && !POINTER_TYPE_P (TREE_TYPE (alias)) + && offsetgtz + && DECL_SIZE (alias) + && TREE_CODE (DECL_SIZE (alias)) == INTEGER_CST + && uoffset > TREE_INT_CST_LOW (DECL_SIZE (alias))) + { +#ifdef ACCESS_DEBUGGING + fprintf (stderr, "Access to "); + print_generic_expr (stderr, ref, 0); + fprintf (stderr, " may not touch "); + print_generic_expr (stderr, alias, 0); + fprintf (stderr, " in function %s\n", get_name (current_function_decl)); +#endif + return false; + } + return true; +} -static void -add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags) +/* Add VAR to the virtual operands array. FLAGS is as in + get_expr_operands. FULL_REF is a tree that contains the entire + pointer dereference expression, if available, or NULL otherwise. + OFFSET and SIZE come from the memory access expression that + generated this virtual operand. FOR_CLOBBER is true is this is + adding a virtual operand for a call clobber. */ + +static void +add_virtual_operand (tree var, stmt_ann_t s_ann, int flags, + tree full_ref, HOST_WIDE_INT offset, + HOST_WIDE_INT size, bool for_clobber) { - bool is_real_op; - tree var, sym; + VEC(tree,gc) *aliases; + tree sym; var_ann_t v_ann; - - var = *var_p; - gcc_assert (SSA_VAR_P (var)); - - is_real_op = is_gimple_reg (var); - /* If this is a real operand, the operand is either ssa name or decl. - Virtual operands may only be decls. */ - gcc_assert (is_real_op || DECL_P (var)); - + sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var); v_ann = var_ann (sym); - + /* Mark statements with volatile operands. Optimizers should back off from statements having volatile operands. */ if (TREE_THIS_VOLATILE (sym) && s_ann) @@ -1623,93 +1773,146 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags) at runtime, then the program is ill formed. If the statement is not executed then all is well. At the very least, we cannot ICE. */ if ((flags & opf_non_specific) && unmodifiable_var_p (var)) - { - gcc_assert (!is_real_op); - flags &= ~(opf_is_def | opf_kill_def); - } + flags &= ~(opf_is_def | opf_kill_def); + - if (is_real_op) + /* The variable is not a GIMPLE register. Add it (or its aliases) to + virtual operands, unless the caller has specifically requested + not to add virtual operands (used when adding operands inside an + ADDR_EXPR expression). */ + if (flags & opf_no_vops) + return; + + aliases = v_ann->may_aliases; + if (aliases == NULL) { - /* The variable is a GIMPLE register. Add it to real operands. */ + /* The variable is not aliased or it is an alias tag. */ if (flags & opf_is_def) - append_def (var_p); + { + if (flags & opf_kill_def) + { + /* Only regular variables or struct fields may get a + V_MUST_DEF operand. */ + gcc_assert (!MTAG_P (var) + || TREE_CODE (var) == STRUCT_FIELD_TAG); + /* V_MUST_DEF for non-aliased, non-GIMPLE register + variable definitions. */ + append_v_must_def (var); + } + else + { + /* Add a V_MAY_DEF for call-clobbered variables and + memory tags. */ + append_v_may_def (var); + } + } else - append_use (var_p); + append_vuse (var); } else { - VEC(tree,gc) *aliases; - - /* The variable is not a GIMPLE register. Add it (or its aliases) to - virtual operands, unless the caller has specifically requested - not to add virtual operands (used when adding operands inside an - ADDR_EXPR expression). */ - if (flags & opf_no_vops) - return; + unsigned i; + tree al; + + /* The variable is aliased. Add its aliases to the virtual + operands. */ + gcc_assert (VEC_length (tree, aliases) != 0); + + if (flags & opf_is_def) + { + + bool none_added = true; - aliases = v_ann->may_aliases; + for (i = 0; VEC_iterate (tree, aliases, i, al); i++) + { + if (!access_can_touch_variable (full_ref, al, offset, size)) + continue; + + none_added = false; + append_v_may_def (al); + } - if (aliases == NULL) - { - /* The variable is not aliased or it is an alias tag. */ - if (flags & opf_is_def) + /* If the variable is also an alias tag, add a virtual + operand for it, otherwise we will miss representing + references to the members of the variable's alias set. + This fixes the bug in gcc.c-torture/execute/20020503-1.c. + + It is also necessary to add bare defs on clobbers for + TMT's, so that bare TMT uses caused by pruning all the + aliases will link up properly with calls. */ + if (v_ann->is_alias_tag || none_added + || (TREE_CODE (var) == TYPE_MEMORY_TAG && for_clobber)) { - if (flags & opf_kill_def) - { - /* Only regular variables or struct fields may get a - V_MUST_DEF operand. */ - gcc_assert (!MTAG_P (var) - || TREE_CODE (var) == STRUCT_FIELD_TAG); - /* V_MUST_DEF for non-aliased, non-GIMPLE register - variable definitions. */ - append_v_must_def (var); - } - else - { - /* Add a V_MAY_DEF for call-clobbered variables and - memory tags. */ - append_v_may_def (var); - } + /* We should never end up with adding no aliases of an + NMT, as that would imply we got the set wrong. */ + gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG)); + + append_v_may_def (var); } - else - append_vuse (var); } else { - unsigned i; - tree al; - - /* The variable is aliased. Add its aliases to the virtual - operands. */ - gcc_assert (VEC_length (tree, aliases) != 0); - - if (flags & opf_is_def) + bool none_added = true; + for (i = 0; VEC_iterate (tree, aliases, i, al); i++) { - /* If the variable is also an alias tag, add a virtual - operand for it, otherwise we will miss representing - references to the members of the variable's alias set. - This fixes the bug in gcc.c-torture/execute/20020503-1.c. */ - if (v_ann->is_alias_tag) - append_v_may_def (var); - - for (i = 0; VEC_iterate (tree, aliases, i, al); i++) - append_v_may_def (al); + if (!access_can_touch_variable (full_ref, al, offset, size)) + continue; + none_added = false; + append_vuse (al); } - else + + /* Similarly, append a virtual uses for VAR itself, when + it is an alias tag. */ + if (v_ann->is_alias_tag || none_added) { - /* Similarly, append a virtual uses for VAR itself, when - it is an alias tag. */ - if (v_ann->is_alias_tag) - append_vuse (var); + gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG)); - for (i = 0; VEC_iterate (tree, aliases, i, al); i++) - append_vuse (al); + append_vuse (var); } } } } - +/* Add *VAR_P to the appropriate operand array for INFO. FLAGS is as in + get_expr_operands. If *VAR_P is a GIMPLE register, it will be added to + the statement's real operands, otherwise it is added to virtual + operands. */ + +static void +add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags) +{ + bool is_real_op; + tree var, sym; + var_ann_t v_ann; + + var = *var_p; + gcc_assert (SSA_VAR_P (var)); + + is_real_op = is_gimple_reg (var); + /* If this is a real operand, the operand is either ssa name or decl. + Virtual operands may only be decls. */ + gcc_assert (is_real_op || DECL_P (var)); + + sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var); + v_ann = var_ann (sym); + + /* Mark statements with volatile operands. Optimizers should back + off from statements having volatile operands. */ + if (TREE_THIS_VOLATILE (sym) && s_ann) + s_ann->has_volatile_ops = true; + + if (is_real_op) + { + /* The variable is a GIMPLE register. Add it to real operands. */ + if (flags & opf_is_def) + append_def (var_p); + else + append_use (var_p); + } + else + add_virtual_operand (var, s_ann, flags, NULL_TREE, 0, -1, false); +} + /* Add the base address of REF to the set *ADDRESSES_TAKEN. If *ADDRESSES_TAKEN is NULL, a new set is created. REF may be a single variable whose address has been taken or any other valid @@ -1836,7 +2039,8 @@ add_call_clobber_ops (tree stmt, tree callee) clobber_stats.static_read_clobbers_avoided++; } else - add_stmt_operand (&var, s_ann, opf_is_def); + add_virtual_operand (var, s_ann, opf_is_def, + NULL, 0, -1, true); } } diff --git a/gcc/tree.c b/gcc/tree.c index d66e0c6..0a3d606 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -276,6 +276,8 @@ init_ttree (void) tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1; tree_contains_struct[TYPE_MEMORY_TAG][TS_MEMORY_TAG] = 1; + tree_contains_struct[STRUCT_FIELD_TAG][TS_STRUCT_FIELD_TAG] = 1; + tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1; tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS] = 1; tree_contains_struct[TYPE_DECL][TS_DECL_WITH_VIS] = 1; @@ -335,8 +337,9 @@ tree_code_size (enum tree_code code) return sizeof (struct tree_function_decl); case NAME_MEMORY_TAG: case TYPE_MEMORY_TAG: - case STRUCT_FIELD_TAG: return sizeof (struct tree_memory_tag); + case STRUCT_FIELD_TAG: + return sizeof (struct tree_struct_field_tag); default: return sizeof (struct tree_decl_non_common); } diff --git a/gcc/tree.h b/gcc/tree.h index e89389d..f0cb29d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2309,12 +2309,28 @@ struct tree_decl_minimal GTY(()) struct tree_memory_tag GTY(()) { struct tree_decl_minimal common; - tree parent_var; unsigned int is_global:1; }; #define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global) -#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->mtag.parent_var) + +struct tree_struct_field_tag GTY(()) +{ + struct tree_memory_tag common; + + /* Parent variable. */ + tree parent_var; + + /* Offset inside structure. */ + unsigned HOST_WIDE_INT offset; + + /* Size of the field. */ + unsigned HOST_WIDE_INT size; + +}; +#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.parent_var) +#define SFT_OFFSET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.offset) +#define SFT_SIZE(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.size) /* For any sort of a ..._DECL node, this points to the original (abstract) decl node which this decl is an instance of, or else it is NULL indicating @@ -3124,6 +3140,7 @@ union tree_node GTY ((ptr_alias (union lang_tree_node), struct tree_value_handle GTY ((tag ("TS_VALUE_HANDLE"))) value_handle; struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor; struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag; + struct tree_struct_field_tag GTY ((tag ("TS_STRUCT_FIELD_TAG"))) sft; struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause; }; diff --git a/gcc/treestruct.def b/gcc/treestruct.def index 3131d4b..b826be6 100644 --- a/gcc/treestruct.def +++ b/gcc/treestruct.def @@ -60,4 +60,5 @@ DEFTREESTRUCT(TS_STATEMENT_LIST, "statement list") DEFTREESTRUCT(TS_VALUE_HANDLE, "value handle") DEFTREESTRUCT(TS_CONSTRUCTOR, "constructor") DEFTREESTRUCT(TS_MEMORY_TAG, "memory tag") +DEFTREESTRUCT(TS_STRUCT_FIELD_TAG, "struct field tag") DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")