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
