On 6 October 2011 18:54, Dr. David Alan Gilbert <david.gilb...@linaro.org> wrote: > Add ARM 64bit sync helpers for use on older ARMs. Based on 32bit > versions but with check for sufficiently new kernel version. > > gcc/ > * config/arm/linux-atomic-64bit.c: New (based on linux-atomic.c) > * config/arm/linux-atomic.c: Change comment to point to 64bit version > (SYNC_LOCK_RELEASE): Instantiate 64bit version. > * config/arm/t-linux-eabi: Pull in linux-atomic-64bit.c
OK. Ramana > > > diff --git a/gcc/config/arm/linux-atomic-64bit.c > b/gcc/config/arm/linux-atomic-64bit.c > new file mode 100644 > index 0000000..6966e66 > --- /dev/null > +++ b/gcc/config/arm/linux-atomic-64bit.c > @@ -0,0 +1,166 @@ > +/* 64bit Linux-specific atomic operations for ARM EABI. > + Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. > + Based on linux-atomic.c > + > + 64 bit additions david.gilb...@linaro.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/>. */ > + > +/* 64bit helper functions for atomic operations; the compiler will > + call these when the code is compiled for a CPU without ldrexd/strexd. > + (If the CPU had those then the compiler inlines the operation). > + > + These helpers require a kernel helper that's only present on newer > + kernels; we check for that in an init section and bail out rather > + unceremoneously. */ > + > +extern unsigned int __write (int fd, const void *buf, unsigned int count); > +extern void abort (void); > + > +/* Kernel helper for compare-and-exchange. */ > +typedef int (__kernel_cmpxchg64_t) (const long long* oldval, > + const long long* newval, > + long long *ptr); > +#define __kernel_cmpxchg64 (*(__kernel_cmpxchg64_t *) 0xffff0f60) > + > +/* Kernel helper page version number. */ > +#define __kernel_helper_version (*(unsigned int *)0xffff0ffc) > + > +/* Check that the kernel has a new enough version at load. */ > +static void __check_for_sync8_kernelhelper (void) > +{ > + if (__kernel_helper_version < 5) > + { > + const char err[] = "A newer kernel is required to run this binary. " > + "(__kernel_cmpxchg64 helper)\n"; > + /* At this point we need a way to crash with some information > + for the user - I'm not sure I can rely on much else being > + available at this point, so do the same as generic-morestack.c > + write () and abort (). */ > + __write (2 /* stderr. */, err, sizeof (err)); > + abort (); > + } > +}; > + > +static void (*__sync8_kernelhelper_inithook[]) (void) > + __attribute__ ((used, section (".init_array"))) = { > + &__check_for_sync8_kernelhelper > +}; > + > +#define HIDDEN __attribute__ ((visibility ("hidden"))) > + > +#define FETCH_AND_OP_WORD64(OP, PFX_OP, INF_OP) \ > + long long HIDDEN \ > + __sync_fetch_and_##OP##_8 (long long *ptr, long long val) \ > + { \ > + int failure; \ > + long long tmp,tmp2; \ > + \ > + do { \ > + tmp = *ptr; \ > + tmp2 = PFX_OP (tmp INF_OP val); \ > + failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr); \ > + } while (failure != 0); \ > + \ > + return tmp; \ > + } > + > +FETCH_AND_OP_WORD64 (add, , +) > +FETCH_AND_OP_WORD64 (sub, , -) > +FETCH_AND_OP_WORD64 (or, , |) > +FETCH_AND_OP_WORD64 (and, , &) > +FETCH_AND_OP_WORD64 (xor, , ^) > +FETCH_AND_OP_WORD64 (nand, ~, &) > + > +#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH > +#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH > + > +/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for > + subword-sized quantities. */ > + > +#define OP_AND_FETCH_WORD64(OP, PFX_OP, INF_OP) \ > + long long HIDDEN \ > + __sync_##OP##_and_fetch_8 (long long *ptr, long long val) \ > + { \ > + int failure; \ > + long long tmp,tmp2; \ > + \ > + do { \ > + tmp = *ptr; \ > + tmp2 = PFX_OP (tmp INF_OP val); \ > + failure = __kernel_cmpxchg64 (&tmp, &tmp2, ptr); \ > + } while (failure != 0); \ > + \ > + return tmp2; \ > + } > + > +OP_AND_FETCH_WORD64 (add, , +) > +OP_AND_FETCH_WORD64 (sub, , -) > +OP_AND_FETCH_WORD64 (or, , |) > +OP_AND_FETCH_WORD64 (and, , &) > +OP_AND_FETCH_WORD64 (xor, , ^) > +OP_AND_FETCH_WORD64 (nand, ~, &) > + > +long long HIDDEN > +__sync_val_compare_and_swap_8 (long long *ptr, long long oldval, > + long long newval) > +{ > + int failure; > + long long actual_oldval; > + > + while (1) > + { > + actual_oldval = *ptr; > + > + if (__builtin_expect (oldval != actual_oldval, 0)) > + return actual_oldval; > + > + failure = __kernel_cmpxchg64 (&actual_oldval, &newval, ptr); > + > + if (__builtin_expect (!failure, 1)) > + return oldval; > + } > +} > + > +typedef unsigned char bool; > + > +bool HIDDEN > +__sync_bool_compare_and_swap_8 (long long *ptr, long long oldval, > + long long newval) > +{ > + int failure = __kernel_cmpxchg64 (&oldval, &newval, ptr); > + return (failure == 0); > +} > + > +long long HIDDEN > +__sync_lock_test_and_set_8 (long long *ptr, long long val) > +{ > + int failure; > + long long oldval; > + > + do { > + oldval = *ptr; > + failure = __kernel_cmpxchg64 (&oldval, &val, ptr); > + } while (failure != 0); > + > + return oldval; > +} > diff --git a/gcc/config/arm/linux-atomic.c b/gcc/config/arm/linux-atomic.c > index 57065a6..80f161d 100644 > --- a/gcc/config/arm/linux-atomic.c > +++ b/gcc/config/arm/linux-atomic.c > @@ -32,8 +32,8 @@ typedef void (__kernel_dmb_t) (void); > #define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0) > > /* Note: we implement byte, short and int versions of atomic operations using > - the above kernel helpers, but there is no support for "long long" (64-bit) > - operations as yet. */ > + the above kernel helpers; see linux-atomic-64bit.c for "long long" > (64-bit) > + operations. */ > > #define HIDDEN __attribute__ ((visibility ("hidden"))) > > @@ -273,6 +273,7 @@ SUBWORD_TEST_AND_SET (unsigned char, 1) > *ptr = 0; \ > } > > +SYNC_LOCK_RELEASE (long long, 8) > SYNC_LOCK_RELEASE (int, 4) > SYNC_LOCK_RELEASE (short, 2) > SYNC_LOCK_RELEASE (char, 1) > diff --git a/gcc/config/arm/t-linux-eabi b/gcc/config/arm/t-linux-eabi > index a328a00..3814cc0 100644 > --- a/gcc/config/arm/t-linux-eabi > +++ b/gcc/config/arm/t-linux-eabi > @@ -36,3 +36,4 @@ LIB1ASMFUNCS := $(filter-out _dvmd_tls,$(LIB1ASMFUNCS)) > _dvmd_lnx _clear_cache > EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o > > LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/arm/linux-atomic.c > +LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/arm/linux-atomic-64bit.c >