https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71050
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Keywords| |missed-optimization Target Milestone|--- |7.0 --- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> --- On GIMPLE this is now "optimized" to refer to the upper half of the double with a BIT_FIELD_REF of the parameter d and the union is optimized away. Ideally this results in (subreg:SI (reg:DF ...) 4) or an equivalent highpart. It looks like expansion spills this to memory (in theory ok, you'd get sth equivalent to the union) but then sth messes up things badly. The GIMPLE transform doesn't factor in that the store to u->val isn't dead after it. RTL opt/target bug. Equivalent code for pre-r236066 would be unsigned int f (double d, words *u) { u->val = d; return ((unsigned int *)&d)[1]; } and compiling with -fno-strict-aliasing. With -mcpu=power8 I get f: mfvsrd 9,1 stfd 1,0(4) srdi 3,9,32 blr Expansion does a df->di move and then extracts the bits via a shift. So, as I suspected it might be neccessary to restrict the kind of "subregs" we create. The transform was designed to avoid the union for the variant typedef union { double val; struct { unsigned int w1; unsigned int w2; }; } words; unsigned int f (double d) { words u; u.val = d; return u.w2; } but even for that RTL opts cannot recover the original code it seems as the backend lies to the middle-end(?) in claiming it can do (insn 6 5 7 (set (reg:DI 158) (subreg:DI (reg/v:DF 156 [ d ]) 0)) t.c:13 -1 (nil)) but in reality it later goes through memory for this which when done at expansion time would have resulted in the same code as when being present with the union.