On 2020/7/7 08:18, Segher Boessenkool wrote:
> Hi!
> 
> On Sun, Jul 05, 2020 at 09:17:57PM -0500, Xionghu Luo wrote:
>> 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
> 
> Great :-)
> 
>> +;; 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))"
> 
> If the insn condition requires operands 0 and 1 to be register_operands,
> it can ask for that in the predicates, instead: not nonimmediate_operand
> and input_operand, but just gpc_reg_operand instead.  You can leave out
> the impossible alternatives as well (0, 1, 2, 3, 4, 5, 6), leaving just
> 
> (define_insn_and_split "movsf_from_si2"
>    [(set (match_operand:SF 0 "gpc_reg_operand" "=wa,?r,!r")
>       (unspec:SF
>         [(subreg:SI (ashiftrt:DI
>                       (match_operand:DI 1 "input_operand" "r,wa,r")
>                       (const_int 32))
>                     0)]
>         UNSPEC_SF_FROM_SI)))]
>    "TARGET_NO_SF_SUBREG"
>    "@
>     #
>     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);
> 
> You cannot call gen_reg_rtx too late in the pass pipeline.  What we
> usually do for such cases is put it as a match_scratch in the pattern,
> and then do code like
> 
>    if (GET_CODE (operands[2]) == SCRATCH)
>      operands[2] = gen_reg_rtx (DImode);
> 
> so that it will work both before and after reload.
> 
>    /* Avoid split {r155:SI#0=unspec[r133:DI>>0x20#0] 86;clobber scratch;} 
> from PR42745.  */
> 
> (This line is too long, btw.)
> 
>    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" "vecfloat,mffgpr,*")
>     (set_attr "isa" "p8v,p8v,*")])
> 
> I wonder what will happen if you actually do FAIL here...  There then is
> no insn alternative that can match, so we ICE?  In that case, just leave
> out the whole FAIL thing, it is useless?  You can do a gcc_assert if you
> want to check something.
> 
> Oh, and maybe you only want to handle GPRs here, not VSRs?  So just the
> "r", not the "wa" at all?  What code would it generate for vector regs?
> 
> Lots of questions, sorry!

Thanks for the nice suggestions of the initial patch contains many issues:),

For this case, %1:SF matches with "=wa"?  And how to construct cases to
match("=?r", "wa") and ("=!r", "r") combinations, please?

Removed lots of copy-paste from "movsf_from_si" and update the patch with 
your comments:


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.  This pattern also exists in PR42475 and
PR67741, etc.

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

Bootstrap and regression tested pass on Power8-LE.

gcc/ChangeLog:

2020-07-07  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-07  Xionghu Luo  <luo...@linux.ibm.com>

        PR rtl-optimization/89310
        * gcc.target/powerpc/pr89310.c: New test.
---
 gcc/config/rs6000/rs6000.md                | 40 ++++++++++++++++++++++
 gcc/testsuite/gcc.target/powerpc/pr89310.c | 17 +++++++++
 2 files changed, 57 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..d4af19375aa 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -7593,6 +7593,46 @@ (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 "gpc_reg_operand" "=wa,?r,!r")
+           (unspec:SF [
+            (subreg:SI (ashiftrt:DI
+              (match_operand:DI 1 "input_operand" "r,wa,r")
+              (const_int 32))
+             0)]
+            UNSPEC_SF_FROM_SI))
+           (clobber (match_scratch:DI 2 "=r,X,X"))]
+  "TARGET_NO_SF_SUBREG"
+  "@
+  #
+  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 op2 = operands[2];
+
+  if (GET_CODE (operands[2]) == SCRATCH)
+    op2 = gen_reg_rtx (DImode);
+
+  rtx mask = GEN_INT (HOST_WIDE_INT_M1U << 32);
+  emit_insn (gen_anddi3 (op2, op1, mask));
+  emit_insn (gen_p8_mtvsrd_sf (op0, op2));
+  emit_insn (gen_vsx_xscvspdpn_directmove (op0, op0));
+  DONE;
+}
+  [(set_attr "length" "12,*,*")
+  (set_attr "type" "vecfloat,mffgpr,*")
+  (set_attr "isa" "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

Reply via email to