diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 24227042462bfd702f024a04487c8be291f3be26..b9dc3c2fab0f689cf757da49fe3843814b725286 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2006-01-14 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/22548 + PR tree-optimization/22555 + PR tree-optimization/22501 + * Makefile.in (tree-ssa-structalias.o): Depend on $(PARAMS_H). + * params.def (salias-max-array-elements): New parameter. + * params.h (SALIAS_MAX_ARRAY_ELEMENTS): Define. + * doc/invoke.texi (salias-max-array-elements): Document. + * tree-flow-inline.h (var_can_have_subvars): We also handle + arrays now. + * tree-ssa-alias.c (find_used_portions): Handle ARRAY_REF like + COMPONENT_REF. + * tree-ssa-structalias.c (params.h): Include. + (push_fields_onto_fieldstack): Handle ARRAY_TYPE. + (find_func_aliases): Handle multiple constraints from ARRAY_REF. + (get_constraint_for): For ADDR_EXPR operating on something + containing an ARRAY_REF, add all subvars to the solution. + (handle_ptr_arith): Handle ARRAY_TYPE like RECORD_TYPE types. + * tree-ssa-operands.c (parse_ssa_operands): Handle ARRAY_REF + for creating MUST_DEFs. + (get_expr_operands): Treat ARRAY_REF like COMPONENT_REF wrt subvars. + 2006-01-14 Zdenek Dvorak <dvorakz@suse.cz> * tree-ssa-loop-niter.c (number_of_iterations_cond): Split into several diff --git a/gcc/Makefile.in b/gcc/Makefile.in index aa3c301a536fde00cb6e7042d6419d2fb8c33008..45152ae1f7eeefeb093dae1ffdd05fc37365a212 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1792,7 +1792,7 @@ stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ tree-ssa-structalias.o: tree-ssa-structalias.c tree-ssa-structalias.h \ $(SYSTEM_H) $(CONFIG_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \ $(TM_H) coretypes.h cgraph.h tree-pass.h $(TIMEVAR_H) \ - gt-tree-ssa-structalias.h + gt-tree-ssa-structalias.h $(PARAMS_H) tree-ssa.o : tree-ssa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) output.h $(DIAGNOSTIC_H) \ toplev.h function.h $(TIMEVAR_H) $(TM_H) coretypes.h \ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index b428f2d8324dd4df993d7889bb4bf1d40b3c7994..032f3ad048d1a50c6a180f9e1b02f09ccda8bef5 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5744,6 +5744,10 @@ The maximum number of fields in a variable without direct structure accesses for which structure aliasing will consider trying to track each field. The default is 5 +@item salias-max-array-elements +The maximum number of elements an array can have and its elements +still be tracked individually by structure aliasing. The default is 4 + @item sra-max-structure-size The maximum structure size, in bytes, at which the scalar replacement of aggregates (SRA) optimization will perform block copies. The diff --git a/gcc/params.def b/gcc/params.def index 7690383e12b96a405dcd4852087dce40ce8711ae..33fa4441cde6c2d0a7850e63e54c22da442c1b6c 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -47,7 +47,14 @@ DEFPARAM (PARAM_SALIAS_MAX_IMPLICIT_FIELDS, "salias-max-implicit-fields", "The maximum number of fields in a structure variable without direct structure accesses that GCC will attempt to track separately", 5, 0, 0) - + +/* The maximum number of array elements structure aliasing will decompose + an array for. The default is 4. */ +DEFPARAM (PARAM_SALIAS_MAX_ARRAY_ELEMENTS, + "salias-max-array-elements", + "The maximum number of elements in an array for wich we track its elements separately", + 4, 0, 0) + /* The maximum structure size at which the scalar replacement of aggregates (SRA) pass will perform block copies. The default value, 0, implies that GCC will select the most appropriate size diff --git a/gcc/params.h b/gcc/params.h index 6c9f7d6cca3724101ae677b663a1a46149d46bd5..f64193982b4e0578e80f239d09f001c5ff7d74b7 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -91,6 +91,8 @@ typedef enum compiler_param /* Macros for the various parameters. */ #define SALIAS_MAX_IMPLICIT_FIELDS \ PARAM_VALUE (PARAM_SALIAS_MAX_IMPLICIT_FIELDS) +#define SALIAS_MAX_ARRAY_ELEMENTS \ + PARAM_VALUE (PARAM_SALIAS_MAX_ARRAY_ELEMENTS) #define SRA_MAX_STRUCTURE_SIZE \ PARAM_VALUE (PARAM_SRA_MAX_STRUCTURE_SIZE) #define SRA_MAX_STRUCTURE_COUNT \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ffe0dc991b1960843962a998f3d3f6f8f0a035dc..318cc53fae2b741fc223dd8b05f4ba182a7a0b13 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2006-01-14 Richard Guenther <rguenther@suse.de> + + PR tree-optimization/22548 + PR tree-optimization/22555 + PR tree-optimization/22501 + * gcc.dg/tree-ssa/alias-4.c: New testcase. + * gcc.dg/tree-ssa/alias-5.c: Likewise. + * gcc.dg/tree-ssa/alias-6.c: Likewise. + * gcc.dg/tree-ssa/alias-7.c: Likewise. + * gcc.dg/tree-ssa/alias-8.c: Likewise. + * gcc.dg/tree-ssa/alias-9.c: Likewise. + * gcc.dg/tree-ssa/alias-10.c: Likewise. + * gcc.dg/tree-ssa/alias-11.c: Likewise. + * gcc.dg/tree-ssa/alias-12.c: Likewise. + 2005-01-14 Zdenek Dvorak <dvorakz@suse.cz> * gcc.dg/tree-ssa/pr19210-1.c: Update outcome. Add new test loop. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-10.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-10.c new file mode 100644 index 0000000000000000000000000000000000000000..03956100a2c20f5fddecfa33d1dc6471cbf0276e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-10.c @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct { + int i; + int x[2]; + int j; +} a; + +int foo(int i) +{ + a.i = 1; + a.j = 2; + a.x[i] = 0; + return a.i + a.j; +} + +/* { dg-final { scan-tree-dump "return 3;" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-11.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-11.c new file mode 100644 index 0000000000000000000000000000000000000000..cccc512cbe19a83afbd51a44589ab7fb05be1e2e --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-11.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct param { int *a; }; +void foo(struct param *p); +int bar(void) +{ + int a[32]; + struct param p; + a[0] = 1; + a[1] = 1; + p.a = &a[0]; + foo(&p); + return a[0] + *p.a; +} + +/* { dg-final { scan-tree-dump "return \\*p\\.a \\\+ a.0.;" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-12.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-12.c new file mode 100644 index 0000000000000000000000000000000000000000..dbd33016032ac54a58d8e292a6ea327e3eb8240c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-12.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-alias1-vops" } */ + +struct { + int i; + int x[128]; + int j; +} a; + +int foo(int i) +{ + a.x[i] = 0; + return a.x[i]; +} + +/* { dg-final { scan-tree-dump "V_MAY_DEF" "alias1" } } */ +/* { dg-final { cleanup-tree-dump "alias1" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-4.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-4.c new file mode 100644 index 0000000000000000000000000000000000000000..e0394327d91e92fcb6b1a9489d57129c76bb6f74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-4.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct { + int i; + struct { + int x[2]; + } b; +} a; + +int foo(void) +{ + a.i = 1; + a.b.x[0] = 0; + a.b.x[1] = 1; + return a.i + a.b.x[0]; +} + +/* { dg-final { scan-tree-dump "return 1;" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-5.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-5.c new file mode 100644 index 0000000000000000000000000000000000000000..f1faae52c9c8e69896cae5d3a0598f1a5a52b0e4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-5.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct { + int i; + struct { + struct { + int i; + } x[2]; + } b; +} a; + +int foo(void) +{ + a.i = 1; + a.b.x[0].i = 0; + a.b.x[1].i = 1; + return a.i + a.b.x[0].i; +} + +/* { dg-final { scan-tree-dump "return 1;" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-6.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-6.c new file mode 100644 index 0000000000000000000000000000000000000000..460dd11cd481c7dd438d2d6dfe967c4aa15c8f3b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-6.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +struct param { int *a; }; +void foo(struct param *p); +int bar(void) +{ + int a[2]; + struct param p; + a[0] = 1; + a[1] = 1; + p.a = &a[0]; + foo(&p); + return a[0] + *p.a; +} + +/* { dg-final { scan-tree-dump "return \\*p\\.a \\\+ a.0.;" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-7.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-7.c new file mode 100644 index 0000000000000000000000000000000000000000..7ef604be293d907a976a5c3ae1e21ba27b7d7169 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-7.c @@ -0,0 +1,17 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +void abort(void); +int main() +{ + int a[2]; + int *p = a; + int i; + a[0] = 1; + a[1] = 2; + for (i=0; i<2; ++i) + if (p[i] != i+1) + abort(); + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-8.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-8.c new file mode 100644 index 0000000000000000000000000000000000000000..7c825f9657952db00bc38c54334c84436b147713 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-8.c @@ -0,0 +1,15 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +void abort(void); +int main() +{ + int a[2]; + int i = 1; + a[0] = 1; + a[1] = 2; + if (*(a + i) != 2) + abort(); + return 0; +} + diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-9.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-9.c new file mode 100644 index 0000000000000000000000000000000000000000..0a20e054366dea551e2e255c422a02be550d4d41 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-9.c @@ -0,0 +1,15 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +void abort(void); +int main() +{ + int a[32]; + int i = 1; + a[0] = 1; + a[1] = 2; + if (*(a + i) != 2) + abort(); + return 0; +} + diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index 3f8e89d136199b9139b23aeb08c06025b9ffb195..7e36ccc0e2ad3e0a420225817de4408a9fb80106 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -1489,8 +1489,7 @@ get_subvar_at (tree var, unsigned HOST_WIDE_INT offset) } /* Return true if V is a tree that we can have subvars for. - Normally, this is any aggregate type, however, due to implementation - limitations ATM, we exclude array types as well. Also complex + Normally, this is any aggregate type. Also complex types which are not gimple registers can have subvars. */ static inline bool @@ -1500,9 +1499,8 @@ var_can_have_subvars (tree v) if (!DECL_P (v) || MTAG_P (v)) return false; - /* Aggregates besides arrays can have subvars. */ - if (AGGREGATE_TYPE_P (TREE_TYPE (v)) - && TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE) + /* Aggregates can have subvars. */ + if (AGGREGATE_TYPE_P (TREE_TYPE (v))) return true; /* Complex types variables which are not also a gimple register can diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 667630343d2b76a5f16a6289bf007b2a32216320..353e7bd4448b62274bdcfdfe1d0ab2cc3370de45 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2698,6 +2698,7 @@ find_used_portions (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) case REALPART_EXPR: case IMAGPART_EXPR: case COMPONENT_REF: + case ARRAY_REF: { HOST_WIDE_INT bitsize; HOST_WIDE_INT bitmaxsize; diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 6787dc2dc39648de2111bd610f31c3107971d927..87a1fc6eb1de7d758ac6152a03b327f13abb2c8a 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -732,8 +732,7 @@ parse_ssa_operands (tree stmt) if (TREE_CODE (lhs) == VIEW_CONVERT_EXPR) lhs = TREE_OPERAND (lhs, 0); - if (TREE_CODE (lhs) != ARRAY_REF - && TREE_CODE (lhs) != ARRAY_RANGE_REF + if (TREE_CODE (lhs) != ARRAY_RANGE_REF && TREE_CODE (lhs) != BIT_FIELD_REF) lhs_flags |= opf_kill_def; @@ -1101,7 +1100,6 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) get_tmr_operands (stmt, expr, flags); return; - case ARRAY_REF: case ARRAY_RANGE_REF: /* Treat array references as references to the virtual variable representing the array. The virtual variable for an ARRAY_REF @@ -1115,6 +1113,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) get_expr_operands (stmt, &TREE_OPERAND (expr, 3), opf_none); return; + case ARRAY_REF: case COMPONENT_REF: case REALPART_EXPR: case IMAGPART_EXPR: @@ -1162,6 +1161,12 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) s_ann->has_volatile_ops = true; get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none); } + else if (code == ARRAY_REF) + { + get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none); + get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none); + get_expr_operands (stmt, &TREE_OPERAND (expr, 3), opf_none); + } return; } case WITH_SIZE_EXPR: @@ -1192,8 +1197,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags) op = TREE_OPERAND (expr, 0); if (TREE_CODE (op) == WITH_SIZE_EXPR) op = TREE_OPERAND (expr, 0); - if (TREE_CODE (op) == ARRAY_REF - || TREE_CODE (op) == ARRAY_RANGE_REF + if (TREE_CODE (op) == ARRAY_RANGE_REF || TREE_CODE (op) == REALPART_EXPR || TREE_CODE (op) == IMAGPART_EXPR) subflags = opf_is_def; diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index e7b47fc31b2e58bd1e56957299a49f8ebe556884..90bd037e313488e1028abd3871f7b62b2992fe3a 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -48,6 +48,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #include "timevar.h" #include "alloc-pool.h" #include "splay-tree.h" +#include "params.h" #include "tree-ssa-structalias.h" #include "cgraph.h" @@ -2493,8 +2494,30 @@ get_constraint_for (tree t, VEC (ce_s, heap) **results) { struct constraint_expr *c; unsigned int i; - - get_constraint_for (TREE_OPERAND (t, 0), results); + tree exp = TREE_OPERAND (t, 0); + + get_constraint_for (exp, results); + /* Make sure we capture constraints to all elements + of an array. */ + if ((handled_component_p (exp) + && ref_contains_array_ref (exp)) + || TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) + { + struct constraint_expr *origrhs; + varinfo_t origvar; + struct constraint_expr tmp; + + gcc_assert (VEC_length (ce_s, *results) == 1); + origrhs = VEC_last (ce_s, *results); + tmp = *origrhs; + VEC_pop (ce_s, *results); + origvar = get_varinfo (origrhs->var); + for (; origvar; origvar = origvar->next) + { + tmp.var = origvar->id; + VEC_safe_push (ce_s, heap, *results, &tmp); + } + } for (i = 0; VEC_iterate (ce_s, *results, i, c); i++) { if (c->type == DEREF) @@ -3151,7 +3174,6 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr) get_constraint_for (op0, &temp); if (POINTER_TYPE_P (TREE_TYPE (op0)) - && TREE_CODE (TREE_TYPE (TREE_TYPE (op0))) == RECORD_TYPE && TREE_CODE (op1) == INTEGER_CST) { rhsoffset = TREE_INT_CST_LOW (op1) * BITS_PER_UNIT; @@ -3378,7 +3400,8 @@ find_func_aliases (tree origt) get_constraint_for (rhsop, &rhsc); if (TREE_CODE (strippedrhs) == ADDR_EXPR - && AGGREGATE_TYPE_P (TREE_TYPE (rhstype))) + && AGGREGATE_TYPE_P (TREE_TYPE (rhstype)) + && VEC_length (ce_s, rhsc) == 1) { struct constraint_expr *origrhs; varinfo_t origvar; @@ -3568,6 +3591,63 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack, return 2; } + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree sz = TYPE_SIZE (type); + tree elsz = TYPE_SIZE (TREE_TYPE (type)); + HOST_WIDE_INT nr; + int i; + + if (! sz + || ! host_integerp (sz, 1) + || TREE_INT_CST_LOW (sz) == 0 + || ! elsz + || ! host_integerp (elsz, 1) + || TREE_INT_CST_LOW (elsz) == 0) + return 0; + + nr = TREE_INT_CST_LOW (sz) / TREE_INT_CST_LOW (elsz); + if (nr > SALIAS_MAX_ARRAY_ELEMENTS) + return 0; + + for (i = 0; i < nr; ++i) + { + bool push = false; + int pushed = 0; + + if (has_union + && (TREE_CODE (TREE_TYPE (type)) == QUAL_UNION_TYPE + || TREE_CODE (TREE_TYPE (type)) == UNION_TYPE)) + *has_union = true; + + if (!AGGREGATE_TYPE_P (TREE_TYPE (type))) /* var_can_have_subvars */ + push = true; + else if (!(pushed = push_fields_onto_fieldstack + (TREE_TYPE (type), fieldstack, + offset + i * TREE_INT_CST_LOW (elsz), has_union))) + /* Empty structures may have actual size, like in C++. So + see if we didn't push any subfields and the size is + nonzero, push the field onto the stack */ + push = true; + + if (push) + { + fieldoff_s *pair; + + pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL); + pair->type = TREE_TYPE (type); + pair->size = elsz; + pair->decl = NULL_TREE; + pair->offset = offset + i * TREE_INT_CST_LOW (elsz); + count++; + } + else + count += pushed; + } + + return count; + } + for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL) {