The following patch fixes a bug in the rs6000 DFP handling of some _Decimal128
patterns, namely the unary patterns neg, abs and nabs.  These patterns use
the legacy binary floating point instructions fneg, fabs and fnabs to
twiddle the signbit.  However, these instructions only operate on the first
register in the even/odd register pair, so for destiniation and source
operands that do not overlap, the destination's odd register will be left
uninitialized.  This patch fixes that.

I also noticed there is no current way for the ABS and NABS patterns to be
generated, so I created some generic builtins so they can be.  I have also
created testcases to verify we generate correct code.

This bootstrapped and regtested with no regressions.  Is this ok for trunk?

David, since this is a bad code generation bug, is it ok to backport just
the *negtd2_fpr portion of the patch to the open release branches?

Peter


gcc/
        * builtins.def (BUILT_IN_FABSD32): New DFP ABS builtin.
        (BUILT_IN_FABSD64): Likewise.
        (BUILT_IN_FABSD128): Likewise.
        * builtins.c (expand_builtin): Add support for new DFP ABS builtins.
        (fold_builtin_1): Likewise.
        * config/rs6000/dfp.md (*negtd2_fpr): Handle non-overlapping destination
        and source operands.
        (*abstd2_fpr): Likewise.
        (*nabstd2_fpr): Likewise.

gcc/testsuite/
        * gcc.target/powerpc/dfp-dd-2.c: New test.
        * gcc.target/powerpc/dfp-td-2.c: Likewise.

Index: gcc/builtins.c
===================================================================
--- gcc/builtins.c      (revision 201779)
+++ gcc/builtins.c      (working copy)
@@ -5865,6 +5865,9 @@ expand_builtin (tree exp, rtx target, rt
   switch (fcode)
     {
     CASE_FLT_FN (BUILT_IN_FABS):
+    case BUILT_IN_FABSD32:
+    case BUILT_IN_FABSD64:
+    case BUILT_IN_FABSD128:
       target = expand_builtin_fabs (exp, target, subtarget);
       if (target)
        return target;
@@ -10314,6 +10317,9 @@ fold_builtin_1 (location_t loc, tree fnd
       return fold_builtin_strlen (loc, type, arg0);

     CASE_FLT_FN (BUILT_IN_FABS):
+    case BUILT_IN_FABSD32:
+    case BUILT_IN_FABSD64:
+    case BUILT_IN_FABSD128:
       return fold_builtin_fabs (loc, arg0, type);

     case BUILT_IN_ABS:
Index: gcc/builtins.def
===================================================================
--- gcc/builtins.def    (revision 201779)
+++ gcc/builtins.def    (working copy)
@@ -257,6 +257,9 @@ DEF_C99_BUILTIN        (BUILT_IN_EXPM1L,
 DEF_LIB_BUILTIN        (BUILT_IN_FABS, "fabs", BT_FN_DOUBLE_DOUBLE, 
ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_FABSF, "fabsf", BT_FN_FLOAT_FLOAT, 
ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_FABSL, "fabsl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_FABSD32, "fabsd32", BT_FN_DFLOAT32_DFLOAT32, 
ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_FABSD64, "fabsd64", BT_FN_DFLOAT64_DFLOAT64, 
ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_GCC_BUILTIN        (BUILT_IN_FABSD128, "fabsd128", 
BT_FN_DFLOAT128_DFLOAT128, ATTR_CONST_NOTHROW_LEAF_LIST)
 DEF_C99_BUILTIN        (BUILT_IN_FDIM, "fdim", BT_FN_DOUBLE_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_FDIMF, "fdimf", BT_FN_FLOAT_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_BUILTIN        (BUILT_IN_FDIML, "fdiml", 
BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
Index: gcc/config/rs6000/dfp.md
===================================================================
--- gcc/config/rs6000/dfp.md    (revision 201779)
+++ gcc/config/rs6000/dfp.md    (working copy)
@@ -135,8 +135,15 @@ (define_insn "*negtd2_fpr"
   [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
        (neg:TD (match_operand:TD 1 "gpc_reg_operand" "d")))]
   "TARGET_HARD_FLOAT && TARGET_FPRS"
-  "fneg %0,%1"
-  [(set_attr "type" "fp")])
+  "*
+{
+  if (REGNO (operands[0]) == REGNO (operands[1]))
+    return \"fneg %0,%1\";
+  else
+    return \"fneg %0,%1\;fmr %L0,%L1\";
+}"
+  [(set_attr "type" "fp")
+   (set_attr "length" "8")])

 (define_expand "abstd2"
   [(set (match_operand:TD 0 "gpc_reg_operand" "")
@@ -148,15 +155,29 @@ (define_insn "*abstd2_fpr"
   [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
        (abs:TD (match_operand:TD 1 "gpc_reg_operand" "d")))]
   "TARGET_HARD_FLOAT && TARGET_FPRS"
-  "fabs %0,%1"
-  [(set_attr "type" "fp")])
+  "*
+{
+  if (REGNO (operands[0]) == REGNO (operands[1]))
+    return \"fabs %0,%1\";
+  else
+    return \"fabs %0,%1\;fmr %L0,%L1\";
+}"
+  [(set_attr "type" "fp")
+   (set_attr "length" "8")])

 (define_insn "*nabstd2_fpr"
   [(set (match_operand:TD 0 "gpc_reg_operand" "=d")
        (neg:TD (abs:TD (match_operand:TD 1 "gpc_reg_operand" "d"))))]
   "TARGET_HARD_FLOAT && TARGET_FPRS"
-  "fnabs %0,%1"
-  [(set_attr "type" "fp")])
+  "*
+{
+  if (REGNO (operands[0]) == REGNO (operands[1]))
+    return \"fnabs %0,%1\";
+  else
+    return \"fnabs %0,%1\;fmr %L0,%L1\";
+}"
+  [(set_attr "type" "fp")
+   (set_attr "length" "8")])

 ;; Hardware support for decimal floating point operations.

Index: gcc/testsuite/gcc.target/powerpc/dfp-dd-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/dfp-dd-2.c (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/dfp-dd-2.c (revision 0)
@@ -0,0 +1,26 @@
+/* Test generation of DFP instructions for POWER6.  */
+/* { dg-do compile { target { powerpc*-*-linux* && powerpc_fprs } } } */
+/* { dg-options "-std=gnu99 -O1 -mcpu=power6" } */
+
+/* { dg-final { scan-assembler-times "fneg" 1 } } */
+/* { dg-final { scan-assembler-times "fabs" 1 } } */
+/* { dg-final { scan-assembler-times "fnabs" 1 } } */
+/* { dg-final { scan-assembler-times "fmr" 0 } } */
+
+_Decimal64
+func1 (_Decimal64 a, _Decimal64 b)
+{
+  return -b;
+}
+
+_Decimal64
+func2 (_Decimal64 a, _Decimal64 b)
+{
+  return __builtin_fabsd64 (b);
+}
+
+_Decimal64
+func3 (_Decimal64 a, _Decimal64 b)
+{
+  return - __builtin_fabsd64 (b);
+}
Index: gcc/testsuite/gcc.target/powerpc/dfp-td-2.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/dfp-td-2.c (revision 0)
+++ gcc/testsuite/gcc.target/powerpc/dfp-td-2.c (revision 0)
@@ -0,0 +1,26 @@
+/* Test generation of DFP instructions for POWER6.  */
+/* { dg-do compile { target { powerpc*-*-linux* && powerpc_fprs } } } */
+/* { dg-options "-std=gnu99 -O1 -mcpu=power6" } */
+
+/* { dg-final { scan-assembler-times "fneg" 1 } } */
+/* { dg-final { scan-assembler-times "fabs" 1 } } */
+/* { dg-final { scan-assembler-times "fnabs" 1 } } */
+/* { dg-final { scan-assembler-times "fmr" 3 } } */
+
+_Decimal128
+func1 (_Decimal128 a, _Decimal128 b)
+{
+  return -b;
+}
+
+_Decimal128
+func2 (_Decimal128 a, _Decimal128 b)
+{
+  return __builtin_fabsd128 (b);
+}
+
+_Decimal128
+func3 (_Decimal128 a, _Decimal128 b)
+{
+  return - __builtin_fabsd128 (b);
+}


Reply via email to