For extracting high part element from DImode register like: {%1:SF=unspec[r122:DI>>0x20#0] 86;clobber scratch;}
split it before reload with "and mask" to avoid generating shift right 32 bit then shift left 32 bit. srdi 3,3,32 sldi 9,3,32 mtvsrd 1,9 xscvspdpn 1,1 => rldicr 3,3,0,31 mtvsrd 1,3 xscvspdpn 1,1 gcc/ChangeLog: 2020-07-03 Xionghu Luo <luo...@linux.ibm.com> PR rtl-optimization/89310 * config/rs6000/rs6000.md (movsf_from_si2): New define_insn_and_split. gcc/testsuite/ChangeLog: 2020-07-03 Xionghu Luo <luo...@linux.ibm.com> PR rtl-optimization/89310 * gcc.target/powerpc/pr89310.c: New test. --- gcc/config/rs6000/rs6000.md | 63 ++++++++++++++++++++++ gcc/testsuite/gcc.target/powerpc/pr89310.c | 17 ++++++ 2 files changed, 80 insertions(+) create mode 100644 gcc/testsuite/gcc.target/powerpc/pr89310.c diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 4fcd6a94022..8d51de07594 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -7593,6 +7593,69 @@ (define_insn_and_split "movsf_from_si" "*, *, p9v, p8v, *, *, p8v, p8v, p8v, *")]) +;; For extracting high part element from DImode register like: +;; {%1:SF=unspec[r122:DI>>0x20#0] 86;clobber scratch;} +;; split it before reload with "and mask" to avoid generating shift right +;; 32 bit then shift left 32 bit. +(define_insn_and_split "movsf_from_si2" + [(set (match_operand:SF 0 "nonimmediate_operand" + "=!r, f, v, wa, m, Z, + Z, wa, ?r, !r") + (unspec:SF [ + (subreg:SI (ashiftrt:DI + (match_operand:DI 1 "input_operand" + "m, m, wY, Z, r, f, + wa, r, wa, r") + (const_int 32)) 0)] + UNSPEC_SF_FROM_SI)) + (clobber (match_scratch:DI 2 + "=X, X, X, X, X, X, + X, r, X, X"))] + "TARGET_NO_SF_SUBREG + && (register_operand (operands[0], SFmode) + && register_operand (operands[1], DImode))" + "@ + lwz%U1%X1 %0,%1 + lfs%U1%X1 %0,%1 + lxssp %0,%1 + lxsspx %x0,%y1 + stw%U0%X0 %1,%0 + stfiwx %1,%y0 + stxsiwx %x1,%y0 + # + mfvsrwz %0,%x1 + mr %0,%1" + + "&& !reload_completed + && vsx_reg_sfsubreg_ok (operands[0], SFmode)" + [(const_int 0)] +{ + rtx op0 = operands[0]; + rtx op1 = operands[1]; + rtx tmp = gen_reg_rtx (DImode); + + /* Avoid split {r155:SI#0=unspec[r133:DI>>0x20#0] 86;clobber scratch;} from PR42745. */ + if (!SUBREG_P (operands[0])) + { + rtx mask = GEN_INT (HOST_WIDE_INT_M1U << 32); + emit_insn (gen_anddi3 (tmp, op1, mask)); + emit_insn (gen_p8_mtvsrd_sf (op0, tmp)); + emit_insn (gen_vsx_xscvspdpn_directmove (op0, op0)); + DONE; + } + else + FAIL; +} + [(set_attr "length" + "*, *, *, *, *, *, + *, 12, *, *") + (set_attr "type" + "load, fpload, fpload, fpload, store, fpstore, + fpstore, vecfloat, mffgpr, *") + (set_attr "isa" + "*, *, p9v, p8v, *, *, + p8v, p8v, p8v, *")]) + ;; Move 64-bit binary/decimal floating point (define_expand "mov<mode>" diff --git a/gcc/testsuite/gcc.target/powerpc/pr89310.c b/gcc/testsuite/gcc.target/powerpc/pr89310.c new file mode 100644 index 00000000000..15e78509246 --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr89310.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct s { + int i; + float f; +}; + +float +foo (struct s arg) +{ + return arg.f; +} + +/* { dg-final { scan-assembler-not {\msrdi\M} } } */ +/* { dg-final { scan-assembler-not {\msldi\M} } } */ +/* { dg-final { scan-assembler-times {\mrldicr\M} 1 } } */ -- 2.21.0.777.g83232e3864