]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
S/390: Fix rounding for _Decimal128 to _Decimal32 conversion
authorkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 11 Mar 2016 07:47:47 +0000 (07:47 +0000)
committerkrebbel <krebbel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 11 Mar 2016 07:47:47 +0000 (07:47 +0000)
We do not have a direct conversion instruction from 128 bit DFP to 32
bit DFP so this needs to be done in two steps.  The first needs to be
done with the "prepare for shorter precision rounding mode" in order
to produce a correct result.

gcc/ChangeLog:

2016-03-11  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>

* config/s390/s390.md ("trunctddd2"): Turn former define_insn into
define_expand.
("*trunctddd2"): New pattern definition.
("trunctdsd2"): Set prep_for_short_prec rounding mode for the
TD->DD truncation.

gcc/testsuite/ChangeLog:

2016-03-11  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>

* gcc.target/s390/dfp-1.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@234134 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/s390/s390.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/s390/dfp-1.c [new file with mode: 0644]

index 0cfc1e2eadd5e274c505dcf2bf51ff0c4538c69a..6e85072e916b321506512f2ece39504ac31b0ea5 100644 (file)
@@ -1,3 +1,11 @@
+2016-03-11  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>
+
+       * config/s390/s390.md ("trunctddd2"): Turn former define_insn into
+       define_expand.
+       ("*trunctddd2"): New pattern definition.
+       ("trunctdsd2"): Set prep_for_short_prec rounding mode for the
+       TD->DD truncation.
+
 2016-03-11  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>
 
        * config/s390/s390.md (BFP_RND_*, DFP_RND_*): Add new constant
index 185a3f8511ba715ebe24aeeb5e3f408eff8a3fb7..5a9f1c8a6066d0211b904e6937f72c0bfa182590 100644 (file)
 ; trunctddd2 and truncddsd2 instruction pattern(s).
 ;
 
-(define_insn "trunctddd2"
+
+(define_expand "trunctddd2"
+  [(parallel
+    [(set (match_operand:DD 0 "register_operand" "")
+         (float_truncate:DD (match_operand:TD 1 "register_operand" "")))
+     (unspec:DI [(const_int DFP_RND_CURRENT)] UNSPEC_ROUND)
+     (clobber (scratch:TD))])]
+  "TARGET_HARD_DFP")
+
+(define_insn "*trunctddd2"
   [(set (match_operand:DD 0 "register_operand" "=f")
        (float_truncate:DD (match_operand:TD 1 "register_operand" "f")))
-   (clobber (match_scratch:TD 2 "=f"))]
+   (unspec:DI [(match_operand:DI 2 "const_mask_operand" "I")] UNSPEC_ROUND)
+   (clobber (match_scratch:TD 3 "=f"))]
   "TARGET_HARD_DFP"
-  "ldxtr\t%2,0,%1,0\;ldr\t%0,%2"
+  "ldxtr\t%3,%2,%1,0\;ldr\t%0,%3"
   [(set_attr "length"  "6")
    (set_attr "type"    "ftruncdd")])
 
   [(parallel
     [(set (match_dup 3)
          (float_truncate:DD (match_operand:TD 1 "register_operand" "")))
+     (unspec:DI [(const_int DFP_RND_PREP_FOR_SHORT_PREC)] UNSPEC_ROUND)
      (clobber (match_scratch:TD 2 ""))])
    (set (match_operand:SD 0 "register_operand" "")
        (float_truncate:SD (match_dup 3)))]
index be04568f5ddda5fdade8c3377ad41263c7ab858f..254b6bccff37d2c658ebad8757d0fe66c584f8dd 100644 (file)
@@ -1,3 +1,7 @@
+2016-03-11  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>
+
+       * gcc.target/s390/dfp-1.c: New test.
+
 2016-03-10  Nick Clifton  <nickc@redhat.com>
 
        PR target/70044
diff --git a/gcc/testsuite/gcc.target/s390/dfp-1.c b/gcc/testsuite/gcc.target/s390/dfp-1.c
new file mode 100644 (file)
index 0000000..109d9fb
--- /dev/null
@@ -0,0 +1,23 @@
+/* We do not have a direct conversion instruction from 128 bit DFP to
+   32 bit DFP so this needs to be done in two steps.  The first needs
+   to be done with the "prepare for shorter precision rounding mode"
+   in order to produce a correct result.  Otherwise the 8th digit of
+   the number will change from 4 to 5 in the first rounding step which
+   then will turn the last digit of the 32 bit DFP number (the 3) into
+   a 4.  Although with direct rounding it would stay a 3.  */
+
+/* { dg-do run } */
+/* { dg-options "-O3 -march=z10 -mzarch" } */
+
+_Decimal32 __attribute__((noinline))
+foo (_Decimal128 a)
+{
+  return (_Decimal32)a;
+}
+
+int
+main ()
+{
+    if (foo (1.23456349999999999DL) != 1.234563DF)
+    __builtin_abort ();
+}