From a916f21d3c176a23f54114a17605813a31cd5d2e Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Sat, 14 Jan 2006 14:30:33 +0000 Subject: [PATCH] re PR tree-optimization/22548 (Aliasing can not tell array members apart) 2006-01-14 Richard Guenther 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. * 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. From-SVN: r109703 --- gcc/ChangeLog | 23 +++++++ gcc/Makefile.in | 2 +- gcc/doc/invoke.texi | 4 ++ gcc/params.def | 9 ++- gcc/params.h | 2 + gcc/testsuite/ChangeLog | 15 +++++ gcc/testsuite/gcc.dg/tree-ssa/alias-10.c | 20 ++++++ gcc/testsuite/gcc.dg/tree-ssa/alias-11.c | 19 ++++++ gcc/testsuite/gcc.dg/tree-ssa/alias-12.c | 18 +++++ gcc/testsuite/gcc.dg/tree-ssa/alias-4.c | 21 ++++++ gcc/testsuite/gcc.dg/tree-ssa/alias-5.c | 23 +++++++ gcc/testsuite/gcc.dg/tree-ssa/alias-6.c | 19 ++++++ gcc/testsuite/gcc.dg/tree-ssa/alias-7.c | 17 +++++ gcc/testsuite/gcc.dg/tree-ssa/alias-8.c | 15 +++++ gcc/testsuite/gcc.dg/tree-ssa/alias-9.c | 15 +++++ gcc/tree-flow-inline.h | 8 +-- gcc/tree-ssa-alias.c | 1 + gcc/tree-ssa-operands.c | 14 ++-- gcc/tree-ssa-structalias.c | 86 +++++++++++++++++++++++- 19 files changed, 316 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-10.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-11.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-12.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-4.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-7.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-8.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-9.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 24227042462b..b9dc3c2fab0f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2006-01-14 Richard Guenther + + 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 * tree-ssa-loop-niter.c (number_of_iterations_cond): Split into several diff --git a/gcc/Makefile.in b/gcc/Makefile.in index aa3c301a536f..45152ae1f7ee 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 b428f2d8324d..032f3ad048d1 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 7690383e12b9..33fa4441cde6 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 6c9f7d6cca37..f64193982b4e 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 ffe0dc991b19..318cc53fae2b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2006-01-14 Richard Guenther + + 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 * 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 000000000000..03956100a2c2 --- /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 000000000000..cccc512cbe19 --- /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 000000000000..dbd33016032a --- /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 000000000000..e0394327d91e --- /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 000000000000..f1faae52c9c8 --- /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 000000000000..460dd11cd481 --- /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 000000000000..7ef604be293d --- /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 000000000000..7c825f965795 --- /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 000000000000..0a20e054366d --- /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 3f8e89d13619..7e36ccc0e2ad 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 667630343d2b..353e7bd4448b 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 6787dc2dc396..87a1fc6eb1de 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 e7b47fc31b2e..90bd037e3134 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; + tree exp = TREE_OPERAND (t, 0); - get_constraint_for (TREE_OPERAND (t, 0), results); + 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) {