Support TI mode and soft float on PA64
authorJohn David Anglin <danglin@gcc.gnu.org>
Fri, 5 Nov 2021 16:07:35 +0000 (16:07 +0000)
committerJohn David Anglin <danglin@gcc.gnu.org>
Fri, 5 Nov 2021 16:07:35 +0000 (16:07 +0000)
This change implements TI mode on PA64.  Various new patterns are
added to pa.md.  The libgcc build needed modification to build both
DI and TI routines.  We also need various softfp routines to
convert to and from TImode.

I added full softfp for the -msoft-float option.  At the moment,
this doesn't completely eliminate all use of the floating-point
co-processor.  For this, libgcc needs to be built with -msoft-mult.
The floating-point exception support also needs a soft option.

2021-11-05  John David Anglin  <danglin@gcc.gnu.org>

PR libgomp/96661

gcc/ChangeLog:

* config/pa/pa-modes.def: Add OImode integer type.
* config/pa/pa.c (pa_scalar_mode_supported_p): Allow TImode
for TARGET_64BIT.
* config/pa/pa.h (MIN_UNITS_PER_WORD) Define to MIN_UNITS_PER_WORD
to UNITS_PER_WORD if IN_LIBGCC2.
* config/pa/pa.md (addti3, addvti3, subti3, subvti3, negti2,
negvti2, ashlti3, shrpd_internal): New patterns.
Change some multi instruction types to multi.

libgcc/ChangeLog:

* config.host (hppa*64*-*-linux*): Revise tmake_file.
(hppa*64*-*-hpux11*): Likewise.
* config/pa/sfp-exceptions.c: New.
* config/pa/sfp-machine.h: New.
* config/pa/t-dimode: New.
* config/pa/t-softfp-sfdftf: New.

gcc/config/pa/pa-modes.def
gcc/config/pa/pa.c
gcc/config/pa/pa.h
gcc/config/pa/pa.md
libgcc/config.host
libgcc/config/pa/sfp-exceptions.c [new file with mode: 0644]
libgcc/config/pa/sfp-machine.h [new file with mode: 0644]
libgcc/config/pa/t-dimode [new file with mode: 0644]
libgcc/config/pa/t-softfp-sfdftf [new file with mode: 0644]

index 769de66..6020233 100644 (file)
@@ -30,3 +30,6 @@ FLOAT_MODE (TF, 16, mips_quad_format);
 
 /* HPPA floating comparisons produce distinct condition codes.  */
 CC_MODE (CCFP);
+
+/* Mode used for signed overflow checking of TImode.  */
+INT_MODE (OI, 32);
index 21b812e..f22d25a 100644 (file)
@@ -6550,18 +6550,16 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
 
 /* True if MODE is valid for the target.  By "valid", we mean able to
    be manipulated in non-trivial ways.  In particular, this means all
-   the arithmetic is supported.
-
-   Currently, TImode is not valid as the HP 64-bit runtime documentation
-   doesn't document the alignment and calling conventions for this type. 
-   Thus, we return false when PRECISION is 2 * BITS_PER_WORD and
-   2 * BITS_PER_WORD isn't equal LONG_LONG_TYPE_SIZE.  */
+   the arithmetic is supported.  */
 
 static bool
 pa_scalar_mode_supported_p (scalar_mode mode)
 {
   int precision = GET_MODE_PRECISION (mode);
 
+  if (TARGET_64BIT && mode == TImode)
+    return true;
+
   switch (GET_MODE_CLASS (mode))
     {
     case MODE_PARTIAL_INT:
index 0fe3fd6..96815ec 100644 (file)
@@ -258,11 +258,17 @@ typedef struct GTY(()) machine_function
    is UNITS_PER_WORD.  Otherwise, it is the constant value that is the
    smallest value that UNITS_PER_WORD can have at run-time.
 
-   FIXME: This needs to be 4 when TARGET_64BIT is true to suppress the
-   building of various TImode routines in libgcc.  The HP runtime
-   specification doesn't provide the alignment requirements and calling
-   conventions for TImode variables.  */
-#define MIN_UNITS_PER_WORD 4
+   This needs to be 8 when TARGET_64BIT is true to allow building various
+   TImode routines in libgcc.  However, we also need the DImode DIVMOD
+   routines because they are not currently implemented in pa.md.
+   
+   The HP runtime specification doesn't provide the alignment requirements
+   and calling conventions for TImode variables.  */
+#ifdef IN_LIBGCC2
+#define MIN_UNITS_PER_WORD      UNITS_PER_WORD
+#else
+#define MIN_UNITS_PER_WORD      4
+#endif
 
 /* The widest floating point format supported by the hardware.  Note that
    setting this influences some Ada floating point type sizes, currently
index ea6da45..f124c30 100644 (file)
   [(set_attr "type" "binary,binary")
    (set_attr "length" "4,4")])
 
+(define_insn "addti3"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+       (plus:TI (match_operand:TI 1 "register_operand" "r")
+                (match_operand:TI 2 "register_operand" "r")))]
+  "TARGET_64BIT"
+  "*
+{
+  operands[3] = gen_lowpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_lowpart (DImode, operands[2]);
+  operands[0] = gen_highpart (DImode, operands[0]);
+  operands[1] = gen_highpart (DImode, operands[1]);
+  operands[2] = gen_highpart (DImode, operands[2]);
+  return \"add %4,%5,%3\;add,dc %1,%2,%0\";
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")])
+
+(define_insn "addvti3"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+       (plus:TI (match_operand:TI 1 "register_operand" "r")
+                (match_operand:TI 2 "register_operand" "r")))
+   (trap_if (ne (plus:OI (sign_extend:OI (match_dup 1))
+                        (sign_extend:OI (match_dup 2)))
+               (sign_extend:OI (plus:TI (match_dup 1)
+                                        (match_dup 2))))
+           (const_int 0))]
+  "TARGET_64BIT"
+  "*
+{
+  operands[3] = gen_lowpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_lowpart (DImode, operands[2]);
+  operands[0] = gen_highpart (DImode, operands[0]);
+  operands[1] = gen_highpart (DImode, operands[1]);
+  operands[2] = gen_highpart (DImode, operands[2]);
+  return \"add %4,%5,%3\;add,dc,tsv %1,%2,%0\";
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")])
+
+(define_insn "subti3"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+       (minus:TI (match_operand:TI 1 "register_operand" "r")
+                 (match_operand:TI 2 "register_operand" "r")))]
+  "TARGET_64BIT"
+  "*
+{
+  operands[3] = gen_lowpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_lowpart (DImode, operands[2]);
+  operands[0] = gen_highpart (DImode, operands[0]);
+  operands[1] = gen_highpart (DImode, operands[1]);
+  operands[2] = gen_highpart (DImode, operands[2]);
+  return \"sub %4,%5,%3\;sub,db %1,%2,%0\";
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")])
+
+(define_insn "subvti3"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+       (minus:TI (match_operand:TI 1 "register_operand" "r")
+                 (match_operand:TI 2 "register_operand" "r")))
+   (trap_if (ne (minus:OI (sign_extend:OI (match_dup 1))
+                         (sign_extend:OI (match_dup 2)))
+               (sign_extend:OI (minus:TI (match_dup 1)
+                                         (match_dup 2))))
+           (const_int 0))]
+  "TARGET_64BIT"
+  "*
+{
+  operands[3] = gen_lowpart (DImode, operands[0]);
+  operands[4] = gen_lowpart (DImode, operands[1]);
+  operands[5] = gen_lowpart (DImode, operands[2]);
+  operands[0] = gen_highpart (DImode, operands[0]);
+  operands[1] = gen_highpart (DImode, operands[1]);
+  operands[2] = gen_highpart (DImode, operands[2]);
+  return \"sub %4,%5,%3\;sub,db,tsv %1,%2,%0\";
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")])
+
 ;; Trap instructions.
 
 (define_insn "trap"
        (neg:DI (match_operand:DI 1 "register_operand" "r")))]
   "!TARGET_64BIT"
   "sub %%r0,%R1,%R0\;{subb|sub,b} %%r0,%1,%0"
-  [(set_attr "type" "unary")
+  [(set_attr "type" "multi")
    (set_attr "length" "8")])
 
 (define_insn ""
   [(set_attr "type" "unary")
    (set_attr "length" "4")])
 
+(define_insn "negti2"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+       (neg:TI (match_operand:TI 1 "register_operand" "r")))]
+  "TARGET_64BIT"
+  "*
+{
+  operands[2] = gen_lowpart (DImode, operands[0]);
+  operands[3] = gen_lowpart (DImode, operands[1]);
+  operands[0] = gen_highpart (DImode, operands[0]);
+  operands[1] = gen_highpart (DImode, operands[1]);
+  return \"sub %%r0,%3,%2\;sub,db %%r0,%1,%0\";
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")])
+
 (define_expand "negvdi2"
   [(parallel [(set (match_operand:DI 0 "register_operand" "")
                   (neg:DI (match_operand:DI 1 "register_operand" "")))
            (const_int 0))]
   "!TARGET_64BIT"
   "sub %%r0,%R1,%R0\;{subbo|sub,b,tsv} %%r0,%1,%0"
-  [(set_attr "type" "unary")
+  [(set_attr "type" "multi")
    (set_attr "length" "8")])
 
 (define_insn ""
   [(set_attr "type" "unary")
    (set_attr "length" "4")])
 
+(define_insn "negvti2"
+  [(set (match_operand:TI 0 "register_operand" "=r")
+       (neg:TI (match_operand:TI 1 "register_operand" "r")))
+   (trap_if (ne (neg:OI (sign_extend:OI (match_dup 1)))
+               (sign_extend:OI (neg:TI (match_dup 1))))
+           (const_int 0))]
+  "TARGET_64BIT"
+  "*
+{
+  operands[2] = gen_lowpart (DImode, operands[0]);
+  operands[3] = gen_lowpart (DImode, operands[1]);
+  operands[0] = gen_highpart (DImode, operands[0]);
+  operands[1] = gen_highpart (DImode, operands[1]);
+  return \"sub %%r0,%3,%2\;sub,db,tsv %%r0,%1,%0\";
+}"
+  [(set_attr "type" "multi")
+   (set_attr "length" "8")])
+
 (define_insn "negsi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (neg:SI (match_operand:SI 1 "register_operand" "r")))]
   operands[1] = force_reg (DImode, operands[1]);
 }")
 
+(define_expand "ashlti3"
+  [(set (match_operand:TI 0 "register_operand" "")
+       (ashift:TI (match_operand:TI 1 "lhs_lshift_operand" "")
+                  (match_operand:TI 2 "arith32_operand" "")))]
+  "TARGET_64BIT"
+{
+  if (REG_P (operands[0]) && GET_CODE (operands[2]) == CONST_INT)
+    {
+      unsigned HOST_WIDE_INT shift = UINTVAL (operands[2]);
+      rtx dst = operands[0];
+      rtx src = force_reg (TImode, operands[1]);
+      if (shift >= 1 && shift <= 63)
+       {
+         emit_insn (gen_shrpd_internal (gen_highpart (DImode, dst),
+                                        gen_lowpart (DImode, src),
+                                        GEN_INT (64-shift),
+                                        gen_highpart (DImode, src),
+                                        GEN_INT (shift)));
+         emit_insn (gen_ashldi3 (gen_lowpart (DImode, dst),
+                                 gen_lowpart (DImode, src),
+                                 GEN_INT (shift)));
+         DONE;
+       }
+      else if (shift >= 64 && shift <= 127)
+       {
+         emit_insn (gen_ashldi3 (gen_highpart (DImode, dst),
+                                 gen_lowpart (DImode, src),
+                                 GEN_INT (shift - 64)));
+         emit_move_insn (gen_lowpart (DImode, dst), GEN_INT (0));
+         DONE;
+       }
+    }
+  /* Fallback to using optabs.c's expand_doubleword_shift.  */
+  FAIL;
+})
+
 (define_insn ""
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (match_operand:DI 1 "register_operand" "r")
                     (match_operand:SI 4 "const_int_operand"))))]
   "")
 
+(define_expand "shrpd_internal"
+  [(set (match_operand:DI 0 "register_operand")
+       (ior:DI
+         (lshiftrt:DI (match_operand:DI 1 "register_operand")
+                      (match_operand:DI 2 "const_int_operand"))
+         (ashift:DI (match_operand:DI 3 "register_operand")
+                    (match_operand:DI 4 "const_int_operand"))))]
+  "TARGET_64BIT")
+
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=r")
        (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r")
index 85de83d..168535b 100644 (file)
@@ -619,7 +619,8 @@ h8300-*-linux*)
        tm_file="$tm_file h8300/h8300-lib.h"
        ;;
 hppa*64*-*-linux*)
-       tmake_file="$tmake_file pa/t-linux64"
+       tmake_file="$tmake_file pa/t-linux64 pa/t-dimode"
+       tmake_file="$tmake_file pa/t-softfp-sfdftf t-softfp"
        extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
        ;;
 hppa*-*-linux*)
@@ -645,7 +646,8 @@ hppa[12]*-*-hpux10*)
        md_unwind_header=pa/hpux-unwind.h
        ;;
 hppa*64*-*-hpux11*)
-       tmake_file="$tmake_file pa/t-hpux pa/t-pa64 pa/t-stublib t-libgcc-pic t-slibgcc"
+       tmake_file="$tmake_file pa/t-hpux pa/t-pa64 pa/t-dimode"
+       tmake_file="$tmake_file pa/t-stublib t-libgcc-pic t-slibgcc"
        # Set the libgcc version number
        if test x$ac_cv_sjlj_exceptions = xyes; then
            tmake_file="$tmake_file pa/t-slibgcc-sjlj-ver"
@@ -653,6 +655,7 @@ hppa*64*-*-hpux11*)
            tmake_file="$tmake_file pa/t-slibgcc-dwarf-ver"
        fi
        tmake_file="$tmake_file pa/t-slibgcc-hpux t-slibgcc-hpux"
+       tmake_file="$tmake_file pa/t-softfp-sfdftf t-softfp"
        tm_file="$tm_file pa/pa64-hpux-lib.h"
        extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o \
                     libgcc_stub.a"
diff --git a/libgcc/config/pa/sfp-exceptions.c b/libgcc/config/pa/sfp-exceptions.c
new file mode 100644 (file)
index 0000000..4dadaf4
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 1997-2021 Free Software Foundation, Inc.
+ *
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * Under Section 7 of GPL version 3, you are granted additional
+ * permissions described in the GCC Runtime Library Exception, version
+ * 3.1, as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License and
+ * a copy of the GCC Runtime Library Exception along with this program;
+ * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "sfp-machine.h"
+
+#define HUGE_VAL (__builtin_huge_val ())
+
+/* Please see section 10,
+   page 10-5 "Delayed Trapping" in the PA-RISC 2.0 Architecture manual */
+
+void
+__sfp_handle_exceptions (int _fex)
+{
+  /* Raise exceptions represented by _FEX.  But we must raise only one
+     signal at a time.  It is important that if the overflow/underflow
+     exception and the divide by zero exception are given at the same
+     time, the overflow/underflow exception follows the divide by zero
+     exception.  */
+
+  /* We do these bits in assembly to be certain GCC doesn't optimize
+     away something important, and so we can force delayed traps to
+     occur. */
+
+  /* We use "fldd 0(%%sr0,%%sp),%0" to flush the delayed exception */
+
+  /* First: Invalid exception.  */
+  if (_fex & FP_EX_INVALID)
+    {
+      /* One example of an invalid operation is 0 * Infinity.  */
+      double d = HUGE_VAL;
+      __asm__ __volatile__ (
+               "       fcpy,dbl %%fr0,%%fr22\n"
+               "       fmpy,dbl %0,%%fr22,%0\n"
+               "       fldd 0(%%sr0,%%sp),%0"
+               : "+f" (d) : : "%fr22" );
+    }
+
+  /* Second: Division by zero.  */
+  if (_fex & FP_EX_DIVZERO)
+    {
+      double d = 1.0;
+      __asm__ __volatile__ (
+               "       fcpy,dbl %%fr0,%%fr22\n"
+               "       fdiv,dbl %0,%%fr22,%0\n"
+               "       fldd 0(%%sr0,%%sp),%0"
+               : "+f" (d) : : "%fr22" );
+    }
+
+  /* Third: Overflow.  */
+  if (_fex & FP_EX_OVERFLOW)
+    {
+      double d = __DBL_MAX__;
+      __asm__ __volatile__ (
+               "       fadd,dbl %0,%0,%0\n"
+               "       fldd 0(%%sr0,%%sp),%0"
+               : "+f" (d) );
+    }
+
+  /* Fourth: Underflow.  */
+  if (_fex & FP_EX_UNDERFLOW)
+    {
+      double d = __DBL_MIN__;
+      double e = 3.0;
+      __asm__ __volatile__ (
+               "       fdiv,dbl %0,%1,%0\n"
+               "       fldd 0(%%sr0,%%sp),%0"
+               : "+f" (d) : "f" (e) );
+    }
+
+  /* Fifth: Inexact */
+  if (_fex & FP_EX_INEXACT)
+    {
+      double d = 3.14159265358979323846;
+      double e = 69.69;
+      __asm__ __volatile__ (
+               "       fdiv,dbl %0,%1,%%fr22\n"
+               "       fcnvfxt,dbl,sgl %%fr22,%%fr22L\n"
+               "       fldd 0(%%sr0,%%sp),%%fr22"
+               : : "f" (d), "f" (e) : "%fr22" );
+    }
+}
diff --git a/libgcc/config/pa/sfp-machine.h b/libgcc/config/pa/sfp-machine.h
new file mode 100644 (file)
index 0000000..661b1cf
--- /dev/null
@@ -0,0 +1,155 @@
+/* softfp machine description for PA-RISC.
+   Copyright (C) 2009-2021 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#ifdef __LP64__
+#define _FP_W_TYPE_SIZE                64
+#define _FP_W_TYPE             unsigned long
+#define _FP_WS_TYPE            signed long
+#define _FP_I_TYPE             long
+
+typedef int TItype __attribute__ ((mode (TI)));
+typedef unsigned int UTItype __attribute__ ((mode (TI)));
+#define TI_BITS (__CHAR_BIT__ * (int) sizeof (TItype))
+
+#define _FP_MUL_MEAT_S(R,X,Y)                          \
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)                          \
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)                          \
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)  _FP_DIV_MEAT_1_udiv_norm(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)  _FP_DIV_MEAT_1_udiv_norm(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)  _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S          (_FP_QNANBIT_S - 1)
+#define _FP_NANFRAC_D          (_FP_QNANBIT_D - 1)
+#define _FP_NANFRAC_Q          (_FP_QNANBIT_Q - 1), -1
+#else
+#define _FP_W_TYPE_SIZE                32
+#define _FP_W_TYPE             unsigned int
+#define _FP_WS_TYPE            signed int
+#define _FP_I_TYPE             int
+
+#define _FP_MUL_MEAT_S(R,X,Y)                          \
+  _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)                          \
+  _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)                          \
+  _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y)  _FP_DIV_MEAT_1_udiv_norm(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)  _FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)  _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S          (_FP_QNANBIT_S - 1)
+#define _FP_NANFRAC_D          (_FP_QNANBIT_D - 1), -1
+#define _FP_NANFRAC_Q          (_FP_QNANBIT_Q - 1), -1, -1, -1
+#endif
+
+/* The type of the result of a floating point comparison.  This must
+   match __libgcc_cmp_return__ in GCC for the target.  */
+typedef int __gcc_CMPtype __attribute__ ((mode (__libgcc_cmp_return__)));
+#define CMPtype __gcc_CMPtype
+
+#define _FP_NANSIGN_S          0
+#define _FP_NANSIGN_D          0
+#define _FP_NANSIGN_Q          0
+
+#define _FP_KEEPNANFRACP       1
+#define _FP_QNANNEGATEDP       1
+
+/* Comment from glibc: */
+/* From my experiments it seems X is chosen unless one of the
+   NaNs is sNaN,  in which case the result is NANSIGN/NANFRAC.  */
+# define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)                    \
+  do {                                                         \
+    if ((_FP_FRAC_HIGH_RAW_##fs(X) |                           \
+        _FP_FRAC_HIGH_RAW_##fs(Y)) & _FP_QNANBIT_##fs)         \
+      {                                                                \
+       R##_s = _FP_NANSIGN_##fs;                               \
+       _FP_FRAC_SET_##wc(R,_FP_NANFRAC_##fs);                  \
+      }                                                                \
+    else                                                       \
+      {                                                                \
+       R##_s = X##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,X);                                \
+      }                                                                \
+    R##_c = FP_CLS_NAN;                                                \
+  } while (0)
+
+#define FP_RND_NEAREST         (0 << 9)
+#define FP_RND_ZERO            (1 << 9)
+#define FP_RND_PINF            (2 << 9)
+#define FP_RND_MINF            (3 << 9)
+#define FP_RND_MASK            (3 << 9)
+
+#define FP_EX_INEXACT          0x01
+#define FP_EX_UNDERFLOW                0x02
+#define FP_EX_OVERFLOW         0x04
+#define FP_EX_DIVZERO          0x08
+#define FP_EX_INVALID          0x10
+#define FP_EX_ALL              0x1F
+#define FP_EX_SHIFT            27
+
+#define _FP_TININESS_AFTER_ROUNDING 1
+
+#define _FP_DECL_EX \
+  unsigned int _fcsr __attribute__ ((unused)) = FP_RND_NEAREST
+
+/* Get floating-point status.  */
+#define _FPU_GETCW(cw)                                         \
+({                                                             \
+  union { unsigned long long __fpreg;                          \
+         unsigned int __halfreg[2]; } __fullfp;                \
+  /* Get the current status word. */                           \
+  __asm__ ("fstd %%fr0,0(%1)\n\t"                              \
+          "fldd 0(%1),%%fr0\n\t"                               \
+           : "=m" (__fullfp.__fpreg)                           \
+           : "r" (&__fullfp.__fpreg)                           \
+           : "%r0");                                           \
+  cw = __fullfp.__halfreg[0];                                  \
+})
+
+#define FP_INIT_ROUNDMODE _FPU_GETCW(_fcsr)
+#define FP_ROUNDMODE (_fcsr & FP_RND_MASK)
+#define FP_TRAPPING_EXCEPTIONS (_fcsr & FP_EX_ALL)
+
+void __sfp_handle_exceptions (int);
+
+#define FP_HANDLE_EXCEPTIONS                           \
+  do {                                                 \
+    if (__builtin_expect (_fex, 0))                    \
+      __sfp_handle_exceptions (_fex);                  \
+  } while (0)
+
+#define        __LITTLE_ENDIAN 1234
+#define        __BIG_ENDIAN    4321
+
+#define __BYTE_ORDER __BIG_ENDIAN
+
+/* Define ALIASNAME as a strong alias for NAME.  */
+# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+# define _strong_alias(name, aliasname) \
+  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
diff --git a/libgcc/config/pa/t-dimode b/libgcc/config/pa/t-dimode
new file mode 100644 (file)
index 0000000..1344e93
--- /dev/null
@@ -0,0 +1,33 @@
+# Extra DImode libgcc2 functions to build.
+lib2difuncs = _muldi3 _negdi2 _lshrdi _ashldi3 _ashrdi3 _cmpdi2 _ucmpdi2
+
+# Build lib2difuncs.
+lib2difuncs-o = $(patsubst %,%_di$(objext),$(lib2difuncs))
+$(lib2difuncs-o): %_di$(objext): $(srcdir)/libgcc2.c
+       $(gcc_compile) -DLIBGCC2_UNITS_PER_WORD=4 -DL$* -c $< $(vis_hide)
+libgcc-objects += $(lib2difuncs-o)
+
+ifeq ($(enable_shared),yes)
+lib2difuncs-s-o = $(patsubst %,%_di_s$(objext),$(lib2difuncs))
+$(lib2difuncs-s-o): %_di_s$(objext): $(srcdir)/libgcc2.c
+       $(gcc_s_compile) -DLIBGCC2_UNITS_PER_WORD=4 -DL$* -c $<
+libgcc-s-objects += $(lib2difuncs-s-o)
+endif
+
+# Extra DImode divmod functions to build.
+lib2didivmodfuncs = _divdi3 _moddi3 _udivdi3 _umoddi3
+
+# Build lib2didivmodfuncs.
+lib2didivmod-o = $(patsubst %,%_di$(objext),$(lib2didivmodfuncs))
+$(lib2didivmod-o): %_di$(objext): $(srcdir)/libgcc2.c
+       $(gcc_compile) -DLIBGCC2_UNITS_PER_WORD=4 -DL$* -c $< \
+         $(LIB2_DIVMOD_EXCEPTION_FLAGS) $(vis_hide)
+libgcc-objects += $(lib2didivmod-o)
+
+ifeq ($(enable_shared),yes)
+lib2didivmod-s-o = $(patsubst %,%_di_s$(objext),$(lib2didivmodfuncs))
+$(lib2didivmod-s-o): %_di_s$(objext): $(srcdir)/libgcc2.c
+       $(gcc_s_compile) -DLIBGCC2_UNITS_PER_WORD=4 -DL$* -c $< \
+         $(LIB2_DIVMOD_EXCEPTION_FLAGS)
+libgcc-s-objects += $(lib2didivmod-s-o)
+endif
diff --git a/libgcc/config/pa/t-softfp-sfdftf b/libgcc/config/pa/t-softfp-sfdftf
new file mode 100644 (file)
index 0000000..51ff051
--- /dev/null
@@ -0,0 +1,8 @@
+# Soft float configuration for PA64
+LIB2ADD += $(srcdir)/config/pa/sfp-exceptions.c
+
+softfp_float_modes := sf df tf
+softfp_int_modes := si di ti
+softfp_extensions := sfdf sftf dftf
+softfp_truncations := dfsf tfsf tfdf
+softfp_exclude_libgcc2 := n