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