https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101311
--- Comment #3 from Richard Biener <rguenth at gcc dot gnu.org> --- float func(float a) { union { float f; unsigned u; } u; u.f = a; u.u ^= 0x80000000; return u.f; } is the example w/o TBAA issue and down to the point WRT refusing negate via XOR. movd %xmm0, %eax addl $-2147483648, %eax movd %eax, %xmm0 ret The core issue (besides transforming XOR to ADD) is that *xorsi_1 does not have a xmm alternative: (insn 7 6 11 2 (parallel [ (set (subreg:SI (reg:SF 84 [ <retval> ]) 0) (xor:SI (subreg:SI (reg:SF 88) 0) (const_int -2147483647 [0xffffffff80000001]))) (clobber (reg:CC 17 flags)) ]) "t.c":6:12 529 {*xorsi_1} and this we are forced to allocate a GPR. The XOR to ADD is done via the *lea<mode>_general_4 splitters I think. Not sure if adding xmm alternatives really makes sense but STV doesn't consider the above since there are subregs involved already and it checks for REG_P instead of REG_OR_SUBREG_P. It might be a idea to specifically split the subreg case into yet another insn variant ...