aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/config/rs6000/rs6000.md25
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr108338.c21
2 files changed, 37 insertions, 9 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 8e7edfc..96084c1 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -8309,13 +8309,26 @@
{
rtx op0 = operands[0];
rtx op1 = operands[1];
- rtx op2 = operands[2];
- rtx op1_di = gen_rtx_REG (DImode, REGNO (op1));
- /* Move SF value to upper 32-bits for xscvspdpn. */
- emit_insn (gen_ashldi3 (op2, op1_di, GEN_INT (32)));
- emit_insn (gen_p8_mtvsrd_sf (op0, op2));
- emit_insn (gen_vsx_xscvspdpn_directmove (op0, op0));
+ /* Move lowpart 32-bits from register for SFmode. */
+ if (TARGET_P9_VECTOR)
+ {
+ /* Using mtvsrws;xscvspdpn. */
+ rtx op0_v = gen_rtx_REG (V4SImode, REGNO (op0));
+ emit_insn (gen_vsx_splat_v4si (op0_v, op1));
+ emit_insn (gen_vsx_xscvspdpn_directmove (op0, op0));
+ }
+ else
+ {
+ rtx op2 = operands[2];
+ rtx op1_di = gen_rtx_REG (DImode, REGNO (op1));
+
+ /* Using sldi;mtvsrd;xscvspdpn. */
+ emit_insn (gen_ashldi3 (op2, op1_di, GEN_INT (32)));
+ emit_insn (gen_p8_mtvsrd_sf (op0, op2));
+ emit_insn (gen_vsx_xscvspdpn_directmove (op0, op0));
+ }
+
DONE;
}
[(set_attr "length"
diff --git a/gcc/testsuite/gcc.target/powerpc/pr108338.c b/gcc/testsuite/gcc.target/powerpc/pr108338.c
index bd83c0b..5f2f628 100644
--- a/gcc/testsuite/gcc.target/powerpc/pr108338.c
+++ b/gcc/testsuite/gcc.target/powerpc/pr108338.c
@@ -3,9 +3,12 @@
/* { dg-options "-O2 -save-temps" } */
/* Under lp64, parameter 'v' is in DI regs, then bitcast sub DI to SF. */
-/* { dg-final { scan-assembler-times {\mxscvspdpn\M} 1 { target { lp64 && has_arch_pwr8 } } } } */
-/* { dg-final { scan-assembler-times {\mmtvsrd\M} 1 { target { lp64 && has_arch_pwr8 } } } } */
+/* { 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 && { ! has_arch_pwr9 } } } } } } */
+/* { dg-final { scan-assembler-times {\mmtvsrd\M} 1 { target { lp64 && has_arch_pwr9 } } } } */
+/* { dg-final { scan-assembler-times {\mmtvsrws\M} 1 { target { lp64 && has_arch_pwr9 } } } } */
/* { 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 && { ! has_arch_pwr9 } } } } } } */
struct di_sf_sf
{
@@ -22,16 +25,28 @@ sf_from_high32bit_di (struct di_sf_sf v)
#endif
}
+float __attribute__ ((noipa))
+sf_from_low32bit_di (struct di_sf_sf v)
+{
+#ifdef __LITTLE_ENDIAN__
+ return v.f1;
+#else
+ return v.f2;
+#endif
+}
+
int main()
{
struct di_sf_sf v;
v.f1 = v.f2 = 0.0f;
#ifdef __LITTLE_ENDIAN__
+ v.f1 = 1.0f;
v.f2 = 2.0f;
#else
v.f1 = 2.0f;
+ v.f2 = 1.0f;
#endif
- if (sf_from_high32bit_di (v) != 2.0f)
+ if (sf_from_high32bit_di (v) != 2.0f || sf_from_low32bit_di (v) != 1.0f)
__builtin_abort ();
return 0;
}