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 0fe3fd6796b..96815ec69cb 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -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
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
+ * .
+ */
+
+
+#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
+. */
+
+#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