PR88845 shows a problem where LRA spilled an input operand of an inline asm statement by calling our generic movsf pattern which ended up generating an insn we don't have a pattern for, so we ICE. The insn was:
(insn (set (reg:SF 125) (subreg:SF (reg:SI 124) 0))) The problem is that rs6000_emit_move_si_sf_subreg() is disabled for LRA and so wasn't able to call gen_movsf_from_si() which generates the correct pattern for moving a 32-bit value from a GPR to a FPR. The patch below fixes the issue by allowing rs6000_emit_move_si_sf_subreg() to be called during LRA as well as creating an expander so that when it is called during LRA, we can create the scratch register that is required for its associated splitter. We have to do this, since LRA has already converted all of the scratches into real registers before it does any spilling. This passed bootstrap and regtesting on powerpc64le-linux with no regressions. Ok for mainline? Peter gcc/ PR rtl-optimization/88845 * config/rs6000/rs6000.c (rs6000_emit_move_si_sf_subreg): Enable during LRA. * config/rs6000/rs6000.md (movsf_from_si): New expander; old insn and splitter renamed from this ... (movsf_from_si_internal): ... to this. gcc/testsuite/ PR rtl-optimization/88845 * gcc.target/powerpc/pr88845.c: New test. Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 269263) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -9887,7 +9887,7 @@ valid_sf_si_move (rtx dest, rtx src, mac static bool rs6000_emit_move_si_sf_subreg (rtx dest, rtx source, machine_mode mode) { - if (TARGET_DIRECT_MOVE_64BIT && !lra_in_progress && !reload_completed + if (TARGET_DIRECT_MOVE_64BIT && !reload_completed && (!SUBREG_P (dest) || !sf_subreg_operand (dest, mode)) && SUBREG_P (source) && sf_subreg_operand (source, mode)) { Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 269263) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -7353,9 +7353,31 @@ (define_insn "*mov<mode>_softfloat" ;; This function is called before reload, and it creates the temporary as ;; needed. +(define_expand "movsf_from_si" + [(parallel [(set (match_operand:SF 0 "nonimmediate_operand") + (unspec:SF [(match_operand:SI 1 "input_operand" )] + UNSPEC_SF_FROM_SI)) + (clobber (match_scratch:DI 2))])] + "TARGET_NO_SF_SUBREG + && (register_operand (operands[0], SFmode) + || register_operand (operands[1], SImode))" +{ + if (lra_in_progress + && REG_P (operands[0]) + && REG_P (operands[1])) + { + /* If LRA is generating a direct move from a GPR to a FPR, + then the splitter is going to need a scratch register. */ + rtx insn = gen_movsf_from_si_internal (operands[0], operands[1]); + XEXP (XVECEXP (insn, 0, 1), 0) = gen_reg_rtx (DImode); + emit_insn (insn); + DONE; + } +}) + ;; LWZ LFS LXSSP LXSSPX STW STFIWX ;; STXSIWX GPR->VSX VSX->GPR GPR->GPR -(define_insn_and_split "movsf_from_si" +(define_insn_and_split "movsf_from_si_internal" [(set (match_operand:SF 0 "nonimmediate_operand" "=!r, f, wb, wu, m, Z, Z, wy, ?r, !r") Index: gcc/testsuite/gcc.target/powerpc/pr88845.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr88845.c (nonexistent) +++ gcc/testsuite/gcc.target/powerpc/pr88845.c (working copy) @@ -0,0 +1,25 @@ +/* { dg-do compile { target powerpc*-*-linux* } } */ +/* { dg-skip-if "" { powerpc*-*-darwin* } } */ +/* { dg-skip-if "" { powerpc*-*-*spe* } } */ +/* { dg-require-effective-target powerpc_p8vector_ok } */ +/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */ +/* { dg-options "-mcpu=power8 -O2" } */ +/* { dg-final { scan-assembler {\mmtvsrd\M} { target { lp64 } } } } */ +/* { dg-final { scan-assembler {\mxscvspdpn\M} { target { lp64 } } } } */ + +/* Verify that we do not ICE and that we generate a direct move + for float types when compiling for 64-bit. */ + +struct a { + unsigned ui; + float f; +}; + +void +foo (void) +{ + float e; + struct a s; + e = s.f; + __asm__("" : : "d" (e)); +}