https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87691
--- Comment #8 from rguenther at suse dot de <rguenther at suse dot de> --- On Tue, 23 Oct 2018, jozef.l at mittosystems dot com wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87691 > > --- Comment #7 from Jozef Lawrynowicz <jozef.l at mittosystems dot com> --- > (In reply to Richard Biener from comment #6) > > > > I think it's better to, at this place, simply allow MODE_INT or > > MODE_PARTIAL_INT > > for unions. Allowing MODE_INT is what we'd fall back to anyways and you > > want to allow MODE_PARTIAL_INT which is already allowed for RECORD_TYPEs. > > > > What I'm not sure is if the target is happy about, say, > > > > union U { float f; __int20 i; }; > > > > float foo() > > { > > union U u; > > u.i = 10; > > return u.f; > > } > > > > iff we were to put u into a MODE_PARTIAL_INT register are targets to be > > expected to be able to extract a MODE_FLOAT from it or are we going > > to spill here anyways? > > I tweaked the above source a little: > > float foo(union U u) > { > u.i = u.i + 10; > return u.f; > } > > For this, GCC fills u.i then spills after modifying it. I therefore assume in > general that if u.f is alive then modifications to u.i will always be spilled > after. > > > How is TYPE_SIZE / GET_MODE_BITSIZE of this union anyways? The loop > > in stor-layout checks TYPE_SIZE vs. DECL_SIZE - is DECL_SIZE always > > matching GET_MODE_BITSIZE? > > It actually depends on the order of the fields in the union, which is not > good. > Since __int20 and float have the same BITSIZE, the mode of the last field in > the union will be used for the mode of the union. So for the above code with > my > current patch, the union TYPE_MODE is PSImode. This causes wrong code to be > generated, as the function foo starts by only pushing the __int20 value of the > union onto the stack, rather than the full 32-bits. > > I had the following additional patch which didn't seem to affect the > testresults, but fixes this issue so is clearly beneficial: > > diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c > index 6449f16..3bb0bbc 100644 > --- a/gcc/stor-layout.c > +++ b/gcc/stor-layout.c > @@ -1834,7 +1834,13 @@ compute_record_mode (tree type) > /* If this field is the whole struct, remember its mode so > that, say, we can put a double in a class into a DF > register instead of forcing it to live in the stack. */ > - if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field))) > + if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)) > + /* Partial int types (e.g. __int20) may have TYPE_SIZE equal to > + wider types (e.g. int32), despite precision being less. Ensure > + that the TYPE_MODE of the struct does not get set to the partial > + int mode if there is a wider type also in the struct. */ > + && known_gt (GET_MODE_PRECISION (DECL_MODE (field)), > + GET_MODE_PRECISION (mode))) > mode = DECL_MODE (field); > > /* With some targets, it is sub-optimal to access an aligned > > This fixes the above issue, so the union TYPE_MODE is always SFmode, > regardless > of the ordering of the fields. That makes sense.