Hi,

Currently, we have the pattern "movsf_from_si2" which was trying
to support moving high part DI to SF.

The pattern looks like: XX:SF=bitcast:SF(subreg(YY:DI>>32),0)
It only accepts the "ashiftrt" for ">>", but "lshiftrt" is also ok.
And the offset of "subreg" is hard code 0, which only works for LE.

"movsf_from_si2" is updated to cover BE for "subreg", and cover
the logical shift for ":DI>>32".

Pass bootstrap and regression on ppc64{,le}.
Is this ok for trunk?

BR,
Jeff (Jiufu Guo)

        PR target/108338

gcc/ChangeLog:

        * config/rs6000/predicates.md (lowpart_subreg_operator): New
        define_predicate.
        * config/rs6000/rs6000.md (any_rshift): New code_iterator.
        (movsf_from_si2): Rename to ...
        (movsf_from_si2_<code>): ... this.

gcc/testsuite/ChangeLog:

        * gcc.target/powerpc/pr108338.c: New test.

---
 gcc/config/rs6000/predicates.md             |  5 +++
 gcc/config/rs6000/rs6000.md                 | 11 +++---
 gcc/testsuite/gcc.target/powerpc/pr108338.c | 40 +++++++++++++++++++++
 3 files changed, 51 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/pr108338.c

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 
3552d908e9d149a30993e3e6568466de537336be..e25b3b4864f681d47e9d5c2eb88bcde0aea6d17b
 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -2098,3 +2098,8 @@ (define_predicate "macho_pic_address"
   else
     return false;
 })
+
+(define_predicate "lowpart_subreg_operator"
+  (and (match_code "subreg")
+       (match_test "subreg_lowpart_offset (mode, GET_MODE (SUBREG_REG (op)))
+                   == SUBREG_BYTE (op)")))
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 
1a9a7b1a47918f39fc91038607f21a8ba9a2e740..8c92cbf976de915136ad5dba24e69a363d21438d
 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -8299,18 +8299,19 @@ (define_insn_and_split "movsf_from_si"
            "*,          *,         p9v,       p8v,       *,         *,
             p8v,        p8v,       p8v,       *")])
 
+(define_code_iterator any_rshift [ashiftrt lshiftrt])
+
 ;; 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"
+(define_insn_and_split "movsf_from_si2_<code>"
   [(set (match_operand:SF 0 "gpc_reg_operand" "=wa")
            (unspec:SF
-            [(subreg:SI
-              (ashiftrt:DI
+            [(match_operator:SI 3 "lowpart_subreg_operator"
+              [(any_rshift:DI
                (match_operand:DI 1 "input_operand" "r")
-               (const_int 32))
-              0)]
+               (const_int 32))])]
             UNSPEC_SF_FROM_SI))
   (clobber (match_scratch:DI 2 "=r"))]
   "TARGET_NO_SF_SUBREG"
diff --git a/gcc/testsuite/gcc.target/powerpc/pr108338.c 
b/gcc/testsuite/gcc.target/powerpc/pr108338.c
new file mode 100644
index 
0000000000000000000000000000000000000000..6db65595343c2407fc32f68f5f52a1f7196c371d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr108338.c
@@ -0,0 +1,40 @@
+// { dg-do run }
+// { dg-options "-O2 -save-temps" }
+
+float __attribute__ ((noipa)) sf_from_di_off0 (long long l)
+{
+  char buff[16];
+  *(long long*)buff = l;
+  float f = *(float*)(buff);
+  return f;    
+}
+
+float  __attribute__ ((noipa)) sf_from_di_off4 (long long l)
+{
+  char buff[16];
+  *(long long*)buff = l;
+  float f = *(float*)(buff + 4);
+  return f; 
+}
+
+/* Under lp64, parameter 'l' is in one DI reg, then bitcast sub DI to SF. */
+/* { dg-final { scan-assembler-times {\mxscvspdpn\M} 2 { target { lp64 && 
has_arch_pwr8 } } } } */
+/* { dg-final { scan-assembler-times {\mmtvsrd\M} 2 { target { lp64 && 
has_arch_pwr8 } } } } */
+/* { dg-final { scan-assembler-times {\mrldicr\M} 1 { target { lp64 && 
has_arch_pwr8 } } } } */
+/* { dg-final { scan-assembler-times {\msldi\M} 1 { target { lp64 && 
has_arch_pwr8 } } } } */
+
+union di_sf_sf
+{
+  struct {float f1; float f2;};
+  long long l;
+};
+
+int main()
+{
+  union di_sf_sf v;
+  v.f1 = 1.0f;
+  v.f2 = 2.0f;
+  if (sf_from_di_off0 (v.l) != 1.0f || sf_from_di_off4 (v.l) != 2.0f )
+    __builtin_abort ();
+  return 0;
+}
-- 
2.25.1

Reply via email to