PR92488 shows we do not generate hardware conversion instructions when converting from _Decimal128 to _Decimal32. There is no one instruction that does the conversion, so we currently call the __dpd_trunctdsd2 function to do the conversion for us. This is slow. Paul Murphy described a short sequence of dfp hardware instructions that would do the conversion correctly. The patch below implements that idea.
The convert-fp-128.c test case uses dg-require-effective-target dfp, so its !dfp usages are basically disabling those tests completely. What we really want is to know whether the compiler is generating hardware instructions or calling the libcalls. For that, we need to test hard_dfp. This patch bootstrapped and regtested with no regressions on powerpc64le-linux. Segher, you pre-approved the pattern, but I thought I'd have you double check the test case changes and new test case. Still ok for trunk? Peter gcc/ PR target/92488 * config/rs6000/dfp.md (trunctdsd2): New define_insn. gcc/testsuite/ PR target/92488 * gcc.target/powerpc/convert-fp-128.c (bl, drsp, drdpq): Update counts. (__dpd_trunctdsd2): Make conditional on !hard_dfp. (__dpd_extendsddd2, __dpd_extendsdtd2, __dpd_truncddsd2, __dpd_extendddtd2, __dpd_trunctddd2): Use !hard_dfp. * gcc.target/powerpc/pr92488.c: New test. diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md index e91d6f581ed..50bfad6beb7 100644 --- a/gcc/config/rs6000/dfp.md +++ b/gcc/config/rs6000/dfp.md @@ -155,6 +155,16 @@ [(set_attr "type" "dfp") (set_attr "length" "8")]) +(define_insn "trunctdsd2" + [(set (match_operand:SD 0 "gpc_reg_operand" "=d") + (float_truncate:SD (match_operand:TD 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:TD 2 "=&d")) + (clobber (match_scratch:DF 3 "=&d"))] + "TARGET_DFP" + "mffs %3\;mtfsfi 7,7,1\;drdpq %2,%1\;mtfsf 0xff,%3,1,0\;drsp %0,%2" + [(set_attr "type" "dfp") + (set_attr "length" "20")]) + (define_insn "add<mode>3" [(set (match_operand:DDTD 0 "gpc_reg_operand" "=d") (plus:DDTD (match_operand:DDTD 1 "gpc_reg_operand" "%d") diff --git a/gcc/testsuite/gcc.target/powerpc/convert-fp-128.c b/gcc/testsuite/gcc.target/powerpc/convert-fp-128.c index 67896d92c86..5b0ef3b0d49 100644 --- a/gcc/testsuite/gcc.target/powerpc/convert-fp-128.c +++ b/gcc/testsuite/gcc.target/powerpc/convert-fp-128.c @@ -34,7 +34,7 @@ conv2 /* { dg-final { scan-assembler-times {\mbl\M} 24 { target { ! hard_dfp } } } } */ /* { dg-final { scan-assembler-times {\mbl\M} 19 { target { hard_dfp && { ! ppc_float128 } } } } } */ -/* { dg-final { scan-assembler-times {\mbl\M} 31 { target { hard_dfp && { ppc_float128 && { ! ppc_float128_insns } } } } } } */ +/* { dg-final { scan-assembler-times {\mbl\M} 30 { target { hard_dfp && { ppc_float128 && { ! ppc_float128_insns } } } } } } */ /* { dg-final { scan-assembler-times {\mbl\M} 27 { target { hard_dfp && { ppc_float128 && { ppc_float128_insns } } } } } } */ @@ -60,20 +60,20 @@ conv2 /* { dg-final { scan-assembler-times {\mbl __dpd_extendsddf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_extendsdtf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_extendsdkf\M} 1 { target { ppc_float128 } } } } */ -/* { dg-final { scan-assembler-times {\mbl __dpd_extendsddd2\M} 1 { target { ! dfp } } } } */ -/* { dg-final { scan-assembler-times {\mbl __dpd_extendsdtd2\M} 1 { target { ! dfp } } } } */ +/* { dg-final { scan-assembler-times {\mbl __dpd_extendsddd2\M} 1 { target { ! hard_dfp } } } } */ +/* { dg-final { scan-assembler-times {\mbl __dpd_extendsdtd2\M} 1 { target { ! hard_dfp } } } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_truncddsf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_truncdddf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_extendddtf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_extendddkf\M} 1 { target { ppc_float128 } } } } */ -/* { dg-final { scan-assembler-times {\mbl __dpd_truncddsd2\M} 1 { target { ! dfp } } } } */ -/* { dg-final { scan-assembler-times {\mbl __dpd_extendddtd2\M} 1 { target { ! dfp } } } } */ +/* { dg-final { scan-assembler-times {\mbl __dpd_truncddsd2\M} 1 { target { ! hard_dfp } } } } */ +/* { dg-final { scan-assembler-times {\mbl __dpd_extendddtd2\M} 1 { target { ! hard_dfp } } } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_trunctdsf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_trunctddf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_trunctdtf\M} 1 } } */ /* { dg-final { scan-assembler-times {\mbl __dpd_trunctdkf\M} 1 { target { ppc_float128 } } } } */ -/* { dg-final { scan-assembler-times {\mbl __dpd_trunctdsd2\M} 1 } } */ -/* { dg-final { scan-assembler-times {\mbl __dpd_trunctddd2\M} 1 { target { ! dfp } } } } */ +/* { dg-final { scan-assembler-times {\mbl __dpd_trunctdsd2\M} 1 { target { ! hard_dfp } } } } */ +/* { dg-final { scan-assembler-times {\mbl __dpd_trunctddd2\M} 1 { target { ! hard_dfp } } } } */ /* { dg-final { scan-assembler-times {\mfrsp|xsrsp\M} 2 { target { ! ppc_float128_insns } } } } */ @@ -88,8 +88,8 @@ conv2 /* { dg-final { scan-assembler-times {\mxxlor|xscpsgndp\M} 3 { target { ppc_float128_insns } } } } */ -/* { dg-final { scan-assembler-times {\mdrsp\M} 1 { target { hard_dfp } } } } */ -/* { dg-final { scan-assembler-times {\mdrdpq\M} 1 { target { hard_dfp } } } } */ +/* { dg-final { scan-assembler-times {\mdrsp\M} 2 { target { hard_dfp } } } } */ +/* { dg-final { scan-assembler-times {\mdrdpq\M} 2 { target { hard_dfp } } } } */ /* { dg-final { scan-assembler-times {\mdctdp\M} 2 { target { hard_dfp } } } } */ /* { dg-final { scan-assembler-times {\mdctqpq\M} 2 { target { hard_dfp } } } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/pr92488.c b/gcc/testsuite/gcc.target/powerpc/pr92488.c new file mode 100644 index 00000000000..3ca575531ca --- /dev/null +++ b/gcc/testsuite/gcc.target/powerpc/pr92488.c @@ -0,0 +1,43 @@ +/* { dg-do run } */ +/* { dg-require-effective-target dfprt } */ +/* { dg-options "-O2" } */ + +#include <stdio.h> +#include <stdlib.h> + +/* Runnable test case for testing _Decimal128 to _Decimal32 rounding. + The value below when rounded to _Decimal64 would result in the value + 1.2345675e+00, which if it were rounded to _Decimal32 would result in + the value 1.234568e+00. However, the correct value when rounding from + _Decimal128 directly to _Decimal32 is 1.234567e+00. */ + +_Decimal128 td = 1.23456749999999999999e+00dl; +_Decimal32 sd_expected = 1.234567e+00df; + +_Decimal32 __attribute__((noinline)) +td2sd (_Decimal128 td) +{ + return td; +} + +int +main (void) +{ + _Decimal32 sd = td2sd (td); + if (sd != sd_expected) + { + union { + _Decimal32 sd; + unsigned int i; + } u; + + printf ("cast to _Decimal32 failed:\n"); + u.sd = sd; + printf (" actual = 0x%x\n", u.i); + u.sd = sd_expected; + printf (" expected = 0x%x\n", u.i); + abort (); + } + + return 0; +}