On Thu, 5 Sep 2019, Jakub Jelinek wrote: > Hi! > > The following testcase ICEs on most targets. The problem is that > initialize_argument_information properly considers the type of the first > field in this case for how the aggregate should be passed, but then > load_register_parameters uses the type of the aggregate unmodified in > the computation of e.g. how many registers to use. So, if as in the > testcase the first field needs at most one word, but the whole union > needs say 16 words, we use 15 hard registers after the one chosen, > which can include say special flags register, frame, floating point regs, > whatever, including running into virtual registers or pseudo registers. > > Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for > trunk?
OK. Thanks, Richard. > 2019-09-05 Jakub Jelinek <ja...@redhat.com> > > PR middle-end/91001 > PR middle-end/91105 > PR middle-end/91106 > * calls.c (load_register_parameters): For TYPE_TRANSPARENT_AGGR > types, use type of their first field instead of type of > args[i].tree_value. > > * gcc.c-torture/compile/pr91001.c: New test. > > --- gcc/calls.c.jj 2019-08-27 12:27:06.000000000 +0200 > +++ gcc/calls.c 2019-09-04 13:34:10.764020515 +0200 > @@ -2771,6 +2771,11 @@ load_register_parameters (struct arg_dat > poly_int64 size = 0; > HOST_WIDE_INT const_size = 0; > rtx_insn *before_arg = get_last_insn (); > + tree type = TREE_TYPE (args[i].tree_value); > + if ((TREE_CODE (type) == UNION_TYPE > + || TREE_CODE (type) == RECORD_TYPE) > + && TYPE_TRANSPARENT_AGGR (type)) > + type = TREE_TYPE (first_field (type)); > /* Set non-negative if we must move a word at a time, even if > just one word (e.g, partial == 4 && mode == DFmode). Set > to -1 if we just use a normal move insn. This value can be > @@ -2783,11 +2788,11 @@ load_register_parameters (struct arg_dat > gcc_assert (partial % UNITS_PER_WORD == 0); > nregs = partial / UNITS_PER_WORD; > } > - else if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode) > + else if (TYPE_MODE (type) == BLKmode) > { > /* Variable-sized parameters should be described by a > PARALLEL instead. */ > - const_size = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); > + const_size = int_size_in_bytes (type); > gcc_assert (const_size >= 0); > nregs = (const_size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; > size = const_size; > @@ -2914,8 +2919,7 @@ load_register_parameters (struct arg_dat > if (GET_CODE (reg) == PARALLEL) > use_group_regs (call_fusage, reg); > else if (nregs == -1) > - use_reg_mode (call_fusage, reg, > - TYPE_MODE (TREE_TYPE (args[i].tree_value))); > + use_reg_mode (call_fusage, reg, TYPE_MODE (type)); > else if (nregs > 0) > use_regs (call_fusage, REGNO (reg), nregs); > } > --- gcc/testsuite/gcc.c-torture/compile/pr91001.c.jj 2019-09-04 > 13:48:25.428062724 +0200 > +++ gcc/testsuite/gcc.c-torture/compile/pr91001.c 2019-09-04 > 13:47:55.849511169 +0200 > @@ -0,0 +1,31 @@ > +/* PR middle-end/91001 */ > +/* PR middle-end/91105 */ > +/* PR middle-end/91106 */ > + > +struct __attribute__((packed)) S { short b; char c; }; > +struct T { short b, c, d; }; > +struct __attribute__((packed)) R { int b; char c; }; > +union __attribute__((aligned(128), transparent_union)) U { struct S c; } u; > +union __attribute__((aligned(32), transparent_union)) V { struct T c; } v; > +union __attribute__((aligned(32), transparent_union)) W { struct R c; } w; > +void foo (union U); > +void bar (union V); > +void baz (union W); > + > +void > +qux (void) > +{ > + foo (u); > +} > + > +void > +quux (void) > +{ > + bar (v); > +} > + > +void > +corge (void) > +{ > + baz (w); > +} > > Jakub > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imendörffer; HRB 247165 (AG München)