diff mbox series

[committed] hppa: Support TI mode and soft float on PA64

Message ID d0c97011-5a20-f62e-d216-a815be930581@bell.net
State New
Headers show
Series [committed] hppa: Support TI mode and soft float on PA64 | expand

Commit Message

John David Anglin Nov. 5, 2021, 5:16 p.m. UTC
Without TImode support on hppa64, it is necessary to disable building libgomp with fortran.

Previously, we didn't support TImode because we need both DImode and TImode divmod routines
from libgcc.  The standard build only builds one of the two.  This is nominally determined
by MIN_UNITS_PER_WORD.  I created a makefile fragment to build the needed DImode routines.

Since the alignment requirements for TImode are not defined, I just assumed the standard
alignment and calling convention for a structure containing a pair of 64-bit words.

I also added softfp support based on early mips float format and hppa glibc exception support.

Tested on hppa64-hp-hpux11.11 and hppa64-unknown-linux-gnu.

Committed on trunk and gcc-11.

Dave
---
Support TI mode and soft float on PA64

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.
diff mbox series

Patch

diff --git a/gcc/config/pa/pa-modes.def b/gcc/config/pa/pa-modes.def
index 769de66f6b6..6020233c171 100644
--- a/gcc/config/pa/pa-modes.def
+++ b/gcc/config/pa/pa-modes.def
@@ -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);
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 21b812e9be7..f22d25a4066 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -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:
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index 7a313d617b0..96815ec69cb 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -255,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
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index ea6da457fcb..f124c301b7a 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -5357,6 +5357,88 @@ 
    [(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"
@@ -5897,7 +5979,7 @@ 
  	(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 ""
@@ -5908,6 +5990,21 @@ 
    [(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" "")))
@@ -5925,7 +6022,7 @@ 
  	    (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 ""
@@ -5939,6 +6036,24 @@ 
    [(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")))]
@@ -6566,6 +6681,42 @@ 
    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")
@@ -6944,6 +7095,15 @@ 
  		     (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")
diff --git a/libgcc/config.host b/libgcc/config.host
index 85de83da766..168535b1780 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -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
index 00000000000..4dadaf43d17
--- /dev/null
+++ b/libgcc/config/pa/sfp-exceptions.c
@@ -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
index 00000000000..661b1cf2cf4
--- /dev/null
+++ b/libgcc/config/pa/sfp-machine.h
@@ -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
index 00000000000..1344e937644
--- /dev/null
+++ b/libgcc/config/pa/t-dimode
@@ -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
index 00000000000..51ff051ede2
--- /dev/null
+++ b/libgcc/config/pa/t-softfp-sfdftf
@@ -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