aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorJohn David Anglin <danglin@gcc.gnu.org>2023-01-13 19:22:49 +0000
committerJohn David Anglin <danglin@gcc.gnu.org>2023-01-13 19:24:15 +0000
commitcf467fb93b7b92330ddcb9c8fe7c93df45ce8e40 (patch)
tree821c49d285046168caf441f057bb2ab1e499b87c /libgcc
parent733a1b777f16cd397b43a242d9c31761f66d3da8 (diff)
downloadgcc-cf467fb93b7b92330ddcb9c8fe7c93df45ce8e40.zip
gcc-cf467fb93b7b92330ddcb9c8fe7c93df45ce8e40.tar.gz
gcc-cf467fb93b7b92330ddcb9c8fe7c93df45ce8e40.tar.bz2
Fix support for atomic loads and stores on hppa.
This change updates the atomic libcall support to fix the following issues: 1) A internal compiler error with -fno-sync-libcalls. 2) When sync libcalls are disabled, we don't generate libcalls for libatomic. 3) There is no sync libcall support for targets other than linux. As a result, non-atomic stores are silently emitted for types smaller or equal to the word size. There are now a few atomic libcalls in the libgcc code, so we need sync support on all targets. 2023-01-13 John David Anglin <danglin@gcc.gnu.org> gcc/ChangeLog: * config/pa/pa-linux.h (TARGET_SYNC_LIBCALL): Delete define. * config/pa/pa.cc (pa_init_libfuncs): Use MAX_SYNC_LIBFUNC_SIZE define. * config/pa/pa.h (TARGET_SYNC_LIBCALLS): Use flag_sync_libcalls. (MAX_SYNC_LIBFUNC_SIZE): Define. (TARGET_CPU_CPP_BUILTINS): Define __SOFTFP__ when soft float is enabled. * config/pa/pa.md (atomic_storeqi): Emit __atomic_exchange_1 libcall when sync libcalls are disabled. (atomic_storehi, atomic_storesi, atomic_storedi): Likewise. (atomic_loaddi): Emit __atomic_load_8 libcall when sync libcalls are disabled on 32-bit target. * config/pa/pa.opt (matomic-libcalls): New option. * doc/invoke.texi (HPPA Options): Update. libgcc/ChangeLog: * config.host (hppa*64*-*-linux*): Adjust tmake_file to use pa/t-pa64-linux. (hppa*64*-*-hpux11*): Adjust tmake_file to use pa/t-pa64-hpux instead of pa/t-hpux and pa/t-pa64. * config/pa/linux-atomic.c: Define u32 type. (ATOMIC_LOAD): Define new macro to implement atomic_load_1, atomic_load_2, atomic_load_4 and atomic_load_8. Update sync defines to use atomic_load calls for type. (SYNC_LOCK_LOAD_2): New macro to implement __sync_lock_load_8. * config/pa/sync-libfuncs.c: New file. * config/pa/t-netbsd (LIB2ADD_ST): Define. * config/pa/t-openbsd (LIB2ADD_ST): Define. * config/pa/t-pa64-hpux: New file. * config/pa/t-pa64-linux: New file.
Diffstat (limited to 'libgcc')
-rw-r--r--libgcc/config.host4
-rw-r--r--libgcc/config/pa/linux-atomic.c79
-rw-r--r--libgcc/config/pa/sync-libfuncs.c324
-rw-r--r--libgcc/config/pa/t-netbsd1
-rw-r--r--libgcc/config/pa/t-openbsd1
-rw-r--r--libgcc/config/pa/t-pa64-hpux4
-rw-r--r--libgcc/config/pa/t-pa64-linux8
7 files changed, 402 insertions, 19 deletions
diff --git a/libgcc/config.host b/libgcc/config.host
index d208765..3e2c910 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -633,7 +633,7 @@ h8300-*-linux*)
tm_file="$tm_file h8300/h8300-lib.h"
;;
hppa*64*-*-linux*)
- tmake_file="$tmake_file pa/t-linux64 pa/t-dimode"
+ tmake_file="$tmake_file pa/t-pa64-linux 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"
;;
@@ -649,7 +649,7 @@ hppa*-*-linux*)
md_unwind_header=pa/linux-unwind.h
;;
hppa*64*-*-hpux11*)
- tmake_file="$tmake_file pa/t-hpux pa/t-pa64 pa/t-dimode"
+ tmake_file="$tmake_file pa/t-pa64-hpux 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
diff --git a/libgcc/config/pa/linux-atomic.c b/libgcc/config/pa/linux-atomic.c
index 10d7f42..1978e68 100644
--- a/libgcc/config/pa/linux-atomic.c
+++ b/libgcc/config/pa/linux-atomic.c
@@ -32,6 +32,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
typedef unsigned char u8;
typedef short unsigned int u16;
+typedef unsigned int u32;
#ifdef __LP64__
typedef long unsigned int u64;
#else
@@ -115,6 +116,36 @@ __kernel_cmpxchg2 (volatile void *mem, const void *oldval, const void *newval,
#define MASK_1 0xffu
#define MASK_2 0xffffu
+/* Load value with an atomic processor load if possible. */
+#define ATOMIC_LOAD(TYPE, WIDTH) \
+ static inline TYPE \
+ atomic_load_##WIDTH (volatile void *ptr) \
+ { \
+ return *(volatile TYPE *)ptr; \
+ }
+
+#if defined(__LP64__) || defined(__SOFTFP__)
+ATOMIC_LOAD (u64, 8)
+#else
+static inline u64
+atomic_load_8 (volatile void *ptr)
+{
+ u64 result;
+ double tmp;
+
+ asm volatile ("{fldds|fldd} 0(%2),%1\n\t"
+ "{fstds|fstd} %1,-16(%%sp)\n\t"
+ "{ldws|ldw} -16(%%sp),%0\n\t"
+ "{ldws|ldw} -12(%%sp),%R0"
+ : "=r" (result), "=f" (tmp) : "r" (ptr): "memory");
+ return result;
+}
+#endif
+
+ATOMIC_LOAD (u32, 4)
+ATOMIC_LOAD (u16, 2)
+ATOMIC_LOAD (u8, 1)
+
#define FETCH_AND_OP_2(OP, PFX_OP, INF_OP, TYPE, WIDTH, INDEX) \
TYPE HIDDEN \
__sync_fetch_and_##OP##_##WIDTH (volatile void *ptr, TYPE val) \
@@ -123,7 +154,7 @@ __kernel_cmpxchg2 (volatile void *mem, const void *oldval, const void *newval,
long failure; \
\
do { \
- tmp = __atomic_load_n ((volatile TYPE *)ptr, __ATOMIC_RELAXED); \
+ tmp = atomic_load_##WIDTH ((volatile TYPE *)ptr); \
newval = PFX_OP (tmp INF_OP val); \
failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX); \
} while (failure != 0); \
@@ -160,7 +191,7 @@ FETCH_AND_OP_2 (nand, ~, &, u8, 1, 0)
long failure; \
\
do { \
- tmp = __atomic_load_n ((volatile TYPE *)ptr, __ATOMIC_RELAXED); \
+ tmp = atomic_load_##WIDTH ((volatile TYPE *)ptr); \
newval = PFX_OP (tmp INF_OP val); \
failure = __kernel_cmpxchg2 (ptr, &tmp, &newval, INDEX); \
} while (failure != 0); \
@@ -197,8 +228,7 @@ OP_AND_FETCH_2 (nand, ~, &, u8, 1, 0)
long failure; \
\
do { \
- tmp = __atomic_load_n ((volatile unsigned int *)ptr, \
- __ATOMIC_RELAXED); \
+ tmp = atomic_load_4 ((volatile unsigned int *)ptr); \
failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val)); \
} while (failure != 0); \
\
@@ -220,8 +250,7 @@ FETCH_AND_OP_WORD (nand, ~, &)
long failure; \
\
do { \
- tmp = __atomic_load_n ((volatile unsigned int *)ptr, \
- __ATOMIC_RELAXED); \
+ tmp = atomic_load_4 ((volatile unsigned int *)ptr); \
failure = __kernel_cmpxchg (ptr, tmp, PFX_OP (tmp INF_OP val)); \
} while (failure != 0); \
\
@@ -247,8 +276,7 @@ typedef unsigned char bool;
\
while (1) \
{ \
- actual_oldval = __atomic_load_n ((volatile TYPE *)ptr, \
- __ATOMIC_RELAXED); \
+ actual_oldval = atomic_load_##WIDTH ((volatile TYPE *)ptr); \
\
if (__builtin_expect (oldval != actual_oldval, 0)) \
return actual_oldval; \
@@ -281,8 +309,7 @@ __sync_val_compare_and_swap_4 (volatile void *ptr, unsigned int oldval,
while (1)
{
- actual_oldval = __atomic_load_n ((volatile unsigned int *)ptr,
- __ATOMIC_RELAXED);
+ actual_oldval = atomic_load_4 ((volatile unsigned int *)ptr);
if (__builtin_expect (oldval != actual_oldval, 0))
return actual_oldval;
@@ -310,8 +337,7 @@ TYPE HIDDEN \
long failure; \
\
do { \
- oldval = __atomic_load_n ((volatile TYPE *)ptr, \
- __ATOMIC_RELAXED); \
+ oldval = atomic_load_##WIDTH ((volatile TYPE *)ptr); \
failure = __kernel_cmpxchg2 (ptr, &oldval, &val, INDEX); \
} while (failure != 0); \
\
@@ -322,14 +348,14 @@ SYNC_LOCK_TEST_AND_SET_2 (u64, 8, 3)
SYNC_LOCK_TEST_AND_SET_2 (u16, 2, 1)
SYNC_LOCK_TEST_AND_SET_2 (u8, 1, 0)
-unsigned int HIDDEN
+u32 HIDDEN
__sync_lock_test_and_set_4 (volatile void *ptr, unsigned int val)
{
long failure;
unsigned int oldval;
do {
- oldval = __atomic_load_n ((volatile unsigned int *)ptr, __ATOMIC_RELAXED);
+ oldval = atomic_load_4 ((volatile unsigned int *)ptr);
failure = __kernel_cmpxchg (ptr, oldval, val);
} while (failure != 0);
@@ -344,8 +370,7 @@ __sync_lock_test_and_set_4 (volatile void *ptr, unsigned int val)
long failure; \
\
do { \
- oldval = __atomic_load_n ((volatile TYPE *)ptr, \
- __ATOMIC_RELAXED); \
+ oldval = atomic_load_##WIDTH ((volatile TYPE *)ptr); \
failure = __kernel_cmpxchg2 (ptr, &oldval, &val, INDEX); \
} while (failure != 0); \
}
@@ -361,7 +386,27 @@ __sync_lock_release_4 (volatile void *ptr)
unsigned int oldval;
do {
- oldval = __atomic_load_n ((volatile unsigned int *)ptr, __ATOMIC_RELAXED);
+ oldval = atomic_load_4 ((volatile unsigned int *)ptr);
failure = __kernel_cmpxchg (ptr, oldval, 0);
} while (failure != 0);
}
+
+#ifndef __LP64__
+#define SYNC_LOCK_LOAD_2(TYPE, WIDTH, INDEX) \
+ TYPE __sync_lock_load_##WIDTH (volatile void *) HIDDEN; \
+ TYPE \
+ __sync_lock_load_##WIDTH (volatile void *ptr) \
+ { \
+ TYPE oldval; \
+ long failure; \
+ \
+ do { \
+ oldval = atomic_load_##WIDTH ((volatile TYPE *)ptr); \
+ failure = __kernel_cmpxchg2 (ptr, &oldval, &oldval, INDEX); \
+ } while (failure != 0); \
+ \
+ return oldval; \
+ }
+
+SYNC_LOCK_LOAD_2 (u64, 8, 3)
+#endif
diff --git a/libgcc/config/pa/sync-libfuncs.c b/libgcc/config/pa/sync-libfuncs.c
new file mode 100644
index 0000000..c70be0f
--- /dev/null
+++ b/libgcc/config/pa/sync-libfuncs.c
@@ -0,0 +1,324 @@
+/* PA-RISC sync libfunc support.
+ Copyright (C) 2008-2023 Free Software Foundation, Inc.
+ Based on code contributed by CodeSourcery for ARM EABI Linux.
+ Modifications for PA Linux by Helge Deller <deller@gmx.de>
+ Revised for general use by John David Anglin <danglin@gcc.gnu.org>
+
+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/>. */
+
+typedef unsigned char u8;
+typedef short unsigned int u16;
+typedef unsigned int u32;
+#ifdef __LP64__
+typedef long unsigned int u64;
+#else
+typedef long long unsigned int u64;
+#endif
+
+/* PA-RISC 2.0 supports out-of-order execution for loads and stores.
+ Thus, we need to synchonize memory accesses. For more info, see:
+ "Advanced Performance Features of the 64-bit PA-8000" by Doug Hunt. */
+
+typedef volatile int __attribute__((aligned (16))) ldcw_t;
+static ldcw_t __atomicity_lock = 1;
+
+/* We want default visibility for the sync routines. */
+#undef VISIBILITY
+#if defined(__hpux__) && !defined(__LP64__)
+#define VISIBILITY
+#else
+#define VISIBILITY __attribute__ ((visibility ("default")))
+#endif
+
+/* Perform ldcw operation in cache when possible. The ldcw instruction
+ is a full barrier. */
+#ifndef _PA_LDCW_INSN
+# ifdef _PA_RISC2_0
+# define _PA_LDCW_INSN "ldcw,co"
+# else
+# define _PA_LDCW_INSN "ldcw"
+# endif
+#endif
+
+static inline void
+__sync_spin_lock (void)
+{
+ ldcw_t *lock = &__atomicity_lock;
+ int tmp;
+
+ __asm__ __volatile__ (_PA_LDCW_INSN " 0(%1),%0\n\t"
+ "cmpib,<>,n 0,%0,.+20\n\t"
+ "ldw,ma 0(%1),%0\n\t"
+ "cmpib,<> 0,%0,.-12\n\t"
+ "nop\n\t"
+ "b,n .-12"
+ : "=&r" (tmp)
+ : "r" (lock)
+ : "memory");
+}
+
+static inline void
+__sync_spin_unlock (void)
+{
+ ldcw_t *lock = &__atomicity_lock;
+ int tmp = 1;
+
+ /* Use ordered store for release. */
+ __asm__ __volatile__ ("stw,ma %1,0(%0)"
+ : : "r" (lock), "r" (tmp) : "memory");
+}
+
+/* Load value with an atomic processor load if possible. */
+#define ATOMIC_LOAD(TYPE, WIDTH) \
+ static inline TYPE \
+ atomic_load_##WIDTH (volatile void *ptr) \
+ { \
+ return *(volatile TYPE *)ptr; \
+ }
+
+#if defined(__LP64__) || defined(__SOFTFP__)
+ATOMIC_LOAD (u64, 8)
+#else
+static inline u64
+atomic_load_8 (volatile void *ptr)
+{
+ u64 result;
+ double tmp;
+
+ asm volatile ("{fldds|fldd} 0(%2),%1\n\t"
+ "{fstds|fstd} %1,-16(%%sp)\n\t"
+ "{ldws|ldw} -16(%%sp),%0\n\t"
+ "{ldws|ldw} -12(%%sp),%R0"
+ : "=r" (result), "=f" (tmp) : "r" (ptr): "memory");
+ return result;
+}
+#endif
+
+ATOMIC_LOAD (u32, 4)
+ATOMIC_LOAD (u16, 2)
+ATOMIC_LOAD (u8, 1)
+
+/* Store value with an atomic processor store if possible. */
+#define ATOMIC_STORE(TYPE, WIDTH) \
+ static inline void \
+ atomic_store_##WIDTH (volatile void *ptr, TYPE value) \
+ { \
+ *(volatile TYPE *)ptr = value; \
+ }
+
+#if defined(__LP64__) || defined(__SOFTFP__)
+ATOMIC_STORE (u64, 8)
+#else
+static inline void
+atomic_store_8 (volatile void *ptr, u64 value)
+{
+ double tmp;
+
+ asm volatile ("stws|stw} %2,-16(%%sp)\n\t"
+ "{stws|stw} %R2,-12(%%sp)\n\t"
+ "{fldds|fldd} -16(%%sp),%1\n\t"
+ "{fstds|fstd} %1,0(%0)"
+ : "=m" (ptr), "=&f" (tmp) : "r" (value): "memory");
+}
+#endif
+
+ATOMIC_STORE (u32, 4)
+ATOMIC_STORE (u16, 2)
+ATOMIC_STORE (u8, 1)
+
+#define FETCH_AND_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH) \
+ TYPE VISIBILITY \
+ __sync_fetch_and_##OP##_##WIDTH (volatile void *ptr, TYPE val) \
+ { \
+ TYPE tmp, newval; \
+ \
+ __sync_spin_lock(); \
+ tmp = atomic_load_##WIDTH (ptr); \
+ newval = PFX_OP (tmp INF_OP val); \
+ atomic_store_##WIDTH (ptr, newval); \
+ __sync_spin_unlock(); \
+ \
+ return tmp; \
+ }
+
+FETCH_AND_OP (add, , +, u64, 8)
+FETCH_AND_OP (sub, , -, u64, 8)
+FETCH_AND_OP (or, , |, u64, 8)
+FETCH_AND_OP (and, , &, u64, 8)
+FETCH_AND_OP (xor, , ^, u64, 8)
+FETCH_AND_OP (nand, ~, &, u64, 8)
+
+FETCH_AND_OP (add, , +, u32, 4)
+FETCH_AND_OP (sub, , -, u32, 4)
+FETCH_AND_OP (or, , |, u32, 4)
+FETCH_AND_OP (and, , &, u32, 4)
+FETCH_AND_OP (xor, , ^, u32, 4)
+FETCH_AND_OP (nand, ~, &, u32, 4)
+
+FETCH_AND_OP (add, , +, u16, 2)
+FETCH_AND_OP (sub, , -, u16, 2)
+FETCH_AND_OP (or, , |, u16, 2)
+FETCH_AND_OP (and, , &, u16, 2)
+FETCH_AND_OP (xor, , ^, u16, 2)
+FETCH_AND_OP (nand, ~, &, u16, 2)
+
+FETCH_AND_OP (add, , +, u8, 1)
+FETCH_AND_OP (sub, , -, u8, 1)
+FETCH_AND_OP (or, , |, u8, 1)
+FETCH_AND_OP (and, , &, u8, 1)
+FETCH_AND_OP (xor, , ^, u8, 1)
+FETCH_AND_OP (nand, ~, &, u8, 1)
+
+#define OP_AND_FETCH(OP, PFX_OP, INF_OP, TYPE, WIDTH) \
+ TYPE VISIBILITY \
+ __sync_##OP##_and_fetch_##WIDTH (volatile void *ptr, TYPE val) \
+ { \
+ TYPE tmp, newval; \
+ \
+ __sync_spin_lock(); \
+ tmp = atomic_load_##WIDTH (ptr); \
+ newval = PFX_OP (tmp INF_OP val); \
+ atomic_store_##WIDTH (ptr, newval); \
+ __sync_spin_unlock(); \
+ \
+ return newval; \
+ }
+
+OP_AND_FETCH (add, , +, u64, 8)
+OP_AND_FETCH (sub, , -, u64, 8)
+OP_AND_FETCH (or, , |, u64, 8)
+OP_AND_FETCH (and, , &, u64, 8)
+OP_AND_FETCH (xor, , ^, u64, 8)
+OP_AND_FETCH (nand, ~, &, u64, 8)
+
+OP_AND_FETCH (add, , +, u32, 4)
+OP_AND_FETCH (sub, , -, u32, 4)
+OP_AND_FETCH (or, , |, u32, 4)
+OP_AND_FETCH (and, , &, u32, 4)
+OP_AND_FETCH (xor, , ^, u32, 4)
+OP_AND_FETCH (nand, ~, &, u32, 4)
+
+OP_AND_FETCH (add, , +, u16, 2)
+OP_AND_FETCH (sub, , -, u16, 2)
+OP_AND_FETCH (or, , |, u16, 2)
+OP_AND_FETCH (and, , &, u16, 2)
+OP_AND_FETCH (xor, , ^, u16, 2)
+OP_AND_FETCH (nand, ~, &, u16, 2)
+
+OP_AND_FETCH (add, , +, u8, 1)
+OP_AND_FETCH (sub, , -, u8, 1)
+OP_AND_FETCH (or, , |, u8, 1)
+OP_AND_FETCH (and, , &, u8, 1)
+OP_AND_FETCH (xor, , ^, u8, 1)
+OP_AND_FETCH (nand, ~, &, u8, 1)
+
+#define COMPARE_AND_SWAP(TYPE, WIDTH) \
+ TYPE VISIBILITY \
+ __sync_val_compare_and_swap_##WIDTH (volatile void *ptr, TYPE oldval, \
+ TYPE newval) \
+ { \
+ TYPE actual_oldval; \
+ \
+ __sync_spin_lock(); \
+ actual_oldval = atomic_load_##WIDTH (ptr); \
+ if (actual_oldval == oldval) \
+ atomic_store_##WIDTH (ptr, newval); \
+ __sync_spin_unlock(); \
+ \
+ return actual_oldval; \
+ } \
+ \
+ _Bool VISIBILITY \
+ __sync_bool_compare_and_swap_##WIDTH (volatile void *ptr, \
+ TYPE oldval, TYPE newval) \
+ { \
+ TYPE actual_oldval; \
+ _Bool result; \
+ \
+ __sync_spin_lock(); \
+ actual_oldval = atomic_load_##WIDTH (ptr); \
+ result = (actual_oldval == oldval); \
+ if (result) \
+ atomic_store_##WIDTH (ptr, newval); \
+ __sync_spin_unlock(); \
+ \
+ return result; \
+ }
+
+COMPARE_AND_SWAP (u64, 8)
+COMPARE_AND_SWAP (u32, 4)
+COMPARE_AND_SWAP (u16, 2)
+COMPARE_AND_SWAP (u8, 1)
+
+#define SYNC_LOCK_TEST_AND_SET(TYPE, WIDTH) \
+TYPE VISIBILITY \
+ __sync_lock_test_and_set_##WIDTH (volatile void *ptr, TYPE val) \
+ { \
+ TYPE oldval; \
+ \
+ __sync_spin_lock(); \
+ oldval = atomic_load_##WIDTH (ptr); \
+ atomic_store_##WIDTH (ptr, val); \
+ __sync_spin_unlock(); \
+ \
+ return oldval; \
+ }
+
+SYNC_LOCK_TEST_AND_SET (u64, 8)
+SYNC_LOCK_TEST_AND_SET (u32, 4)
+SYNC_LOCK_TEST_AND_SET (u16, 2)
+SYNC_LOCK_TEST_AND_SET (u8, 1)
+
+#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \
+ void VISIBILITY \
+ __sync_lock_release_##WIDTH (volatile void *ptr) \
+ { \
+ TYPE val = 0; \
+ \
+ __sync_spin_lock(); \
+ atomic_store_##WIDTH (ptr, val); \
+ __sync_spin_unlock(); \
+ }
+
+SYNC_LOCK_RELEASE (u64, 8)
+SYNC_LOCK_RELEASE (u32, 4)
+SYNC_LOCK_RELEASE (u16, 2)
+SYNC_LOCK_RELEASE (u8, 1)
+
+#define SYNC_LOCK_LOAD(TYPE, WIDTH) \
+TYPE VISIBILITY __sync_lock_load_##WIDTH (volatile void *); \
+TYPE VISIBILITY \
+ __sync_lock_load_##WIDTH (volatile void *ptr) \
+ { \
+ TYPE oldval; \
+ \
+ __sync_spin_lock(); \
+ oldval = atomic_load_##WIDTH (ptr); \
+ __sync_spin_unlock(); \
+ \
+ return oldval; \
+ }
+
+SYNC_LOCK_LOAD (u64, 8)
+SYNC_LOCK_LOAD (u32, 4)
+SYNC_LOCK_LOAD (u16, 2)
+SYNC_LOCK_LOAD (u8, 1)
diff --git a/libgcc/config/pa/t-netbsd b/libgcc/config/pa/t-netbsd
index 8b99068..1394394 100644
--- a/libgcc/config/pa/t-netbsd
+++ b/libgcc/config/pa/t-netbsd
@@ -7,3 +7,4 @@ LIB1ASMFUNCS = _divI _divU _remI _remU _div_const _mulI _dyncall
HOST_LIBGCC2_CFLAGS += -DELF=1 -DLINUX=1
LIB2ADD = $(srcdir)/config/pa/fptr.c
+LIB2ADD_ST = $(srcdir)/config/pa/sync-libfuncs.c
diff --git a/libgcc/config/pa/t-openbsd b/libgcc/config/pa/t-openbsd
index 8b99068..1394394 100644
--- a/libgcc/config/pa/t-openbsd
+++ b/libgcc/config/pa/t-openbsd
@@ -7,3 +7,4 @@ LIB1ASMFUNCS = _divI _divU _remI _remU _div_const _mulI _dyncall
HOST_LIBGCC2_CFLAGS += -DELF=1 -DLINUX=1
LIB2ADD = $(srcdir)/config/pa/fptr.c
+LIB2ADD_ST = $(srcdir)/config/pa/sync-libfuncs.c
diff --git a/libgcc/config/pa/t-pa64-hpux b/libgcc/config/pa/t-pa64-hpux
new file mode 100644
index 0000000..55194e8
--- /dev/null
+++ b/libgcc/config/pa/t-pa64-hpux
@@ -0,0 +1,4 @@
+LIB2ADD = $(srcdir)/config/pa/quadlib.c
+LIB2ADD_ST = $(srcdir)/config/pa/sync-libfuncs.c
+
+HOST_LIBGCC2_CFLAGS += -frandom-seed=fixed-seed -Dpa64=1 -DELF=1 -mlong-calls
diff --git a/libgcc/config/pa/t-pa64-linux b/libgcc/config/pa/t-pa64-linux
new file mode 100644
index 0000000..026b48b
--- /dev/null
+++ b/libgcc/config/pa/t-pa64-linux
@@ -0,0 +1,8 @@
+# Plug millicode routines into libgcc.a We want these on both native and
+# cross compiles.
+LIB1ASMSRC = pa/milli64.S
+LIB1ASMFUNCS = _divI _divU _remI _remU _div_const _mulI
+
+HOST_LIBGCC2_CFLAGS += -Dpa64=1 -DELF=1 -DLINUX=1
+
+LIB2ADD_ST = $(srcdir)/config/pa/linux-atomic.c