Commit 48310492 by Richard Henderson Committed by Richard Henderson

Add libatomic as a target library.

From-SVN: r187018
parent e8053cf5
2012-05-01 Richard Henderson <rth@redhat.com>
* Makefile.def (libatomic): New target_module.
* configure.ac (target_libraries): Add libatomic.
(noconfigdirs): Check if libatomic is supported.
* Makefile.in, configure: Rebuild.
2012-05-01 Greta Yorsh <Greta.Yorsh@arm.com>
* MAINTAINERS (Write After Approval): Add myself.
......
......@@ -140,6 +140,7 @@ target_modules = { module= rda; };
target_modules = { module= libada; };
target_modules = { module= libgomp; bootstrap= true; lib_path=.libs; };
target_modules = { module= libitm; lib_path=.libs; };
target_modules = { module= libatomic; lib_path=.libs; };
// These are (some of) the make targets to be done in each subdirectory.
// Not all; these are the ones which don't have special options.
......
......@@ -2688,6 +2688,7 @@ target_libraries="target-libgcc \
target-libgloss \
target-newlib \
target-libgomp \
target-libatomic \
target-libitm \
target-libstdc++-v3 \
target-libmudflap \
......@@ -3064,6 +3065,25 @@ if test x$enable_libgomp = x ; then
esac
fi
# Disable libatomic on unsupported systems.
if test -d ${srcdir}/libatomic; then
if test x$enable_libatomic = x; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libatomic support" >&5
$as_echo_n "checking for libatomic support... " >&6; }
if (srcdir=${srcdir}/libatomic; \
. ${srcdir}/configure.tgt; \
test -n "$UNSUPPORTED")
then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
noconfigdirs="$noconfigdirs target-libatomic"
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
fi
fi
# Disable libitm on unsupported systems.
if test -d ${srcdir}/libitm; then
if test x$enable_libitm = x; then
......
......@@ -154,6 +154,7 @@ target_libraries="target-libgcc \
target-libgloss \
target-newlib \
target-libgomp \
target-libatomic \
target-libitm \
target-libstdc++-v3 \
target-libmudflap \
......@@ -493,6 +494,22 @@ if test x$enable_libgomp = x ; then
esac
fi
# Disable libatomic on unsupported systems.
if test -d ${srcdir}/libatomic; then
if test x$enable_libatomic = x; then
AC_MSG_CHECKING([for libatomic support])
if (srcdir=${srcdir}/libatomic; \
. ${srcdir}/configure.tgt; \
test -n "$UNSUPPORTED")
then
AC_MSG_RESULT([no])
noconfigdirs="$noconfigdirs target-libatomic"
else
AC_MSG_RESULT([yes])
fi
fi
fi
# Disable libitm on unsupported systems.
if test -d ${srcdir}/libitm; then
if test x$enable_libitm = x; then
......
2012-05-01 Richard Henderson <rth@redhat.com>
* gcc_update: Add libatomic generated files.
2012-04-23 Manuel López-Ibáñez <manu@gcc.gnu.org>
* compare_tests: Append '/' to make 'find' traverse
......
......@@ -144,6 +144,11 @@ libitm/Makefile.in: libitm/Makefile.am libitm/aclocal.m4
libitm/testsuite/Makefile.in: libitm/testsuite/Makefile.am libitm/aclocal.m4
libitm/configure: libitm/configure.ac libitm/aclocal.m4
libitm/config.h.in: libitm/configure.ac libitm/aclocal.m4
libatomic/aclocal.m4: libatomic/configure.ac libatomic/acinclude.m4
libatomic/Makefile.in: libatomic/Makefile.am libatomic/aclocal.m4
libatomic/testsuite/Makefile.in: libatomic/testsuite/Makefile.am libatomic/aclocal.m4
libatomic/configure: libatomic/configure.ac libatomic/aclocal.m4
libatomic/auto-config.h.in: libatomic/configure.ac libatomic/aclocal.m4
# Top level
Makefile.in: Makefile.tpl Makefile.def
configure: configure.ac config/acx.m4
......
autom4te.cache
auto-config.h.in~
2012-05-01 Richard Henderson <rth@redhat.com>
* Initial commit.
## Copyright (C) 2012 Free Software Foundation, Inc.
## Contributed by Richard Henderson <rth@redhat.com>.
##
## This file is part of the GNU Atomic Library (libatomic).
##
## Libatomic 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 of the License, or
## (at your option) any later version.
##
## Libatomic 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/>.
ACLOCAL_AMFLAGS = -I .. -I ../config
SUBDIRS = testsuite
## May be used by toolexeclibdir.
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
config_path= @config_path@
search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) \
$(top_srcdir) $(top_builddir)
vpath % $(strip $(search_path))
DEFAULT_INCLUDES = $(addprefix -I, $(search_path))
AM_CFLAGS = $(XCFLAGS)
AM_CCASFLAGS = $(XCFLAGS)
AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS)
toolexeclib_LTLIBRARIES = libatomic.la
if LIBAT_BUILD_VERSIONED_SHLIB
if LIBAT_BUILD_VERSIONED_SHLIB_GNU
libatomic_version_script = -Wl,--version-script,$(top_srcdir)/libatomic.map
libatomic_version_dep = $(top_srcdir)/libatomic.map
endif
if LIBAT_BUILD_VERSIONED_SHLIB_SUN
libatomic_version_script = -Wl,-M,libatomic.map-sun
libatomic_version_dep = libatomic.map-sun
libatomic.map-sun : $(top_srcdir)/libatomic.map \
$(top_srcdir)/../contrib/make_sunver.pl \
$(libatomic_la_OBJECTS) $(libatomic_la_LIBADD)
perl $(top_srcdir)/../contrib/make_sunver.pl \
$(top_srcdir)/libatomic.map \
$(libatomic_la_OBJECTS:%.lo=.libs/%.o) \
`echo $(libatomic_la_LIBADD) | \
sed 's,/\([^/.]*\)\.la,/.libs/\1.a,g'` \
> $@ || (rm -f $@ ; exit 1)
endif
else
libatomic_version_script =
libatomic_version_dep =
endif
libatomic_version_info = -version-info $(libtool_VERSION)
libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script)
libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c
SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
SIZES = @SIZES@
EXTRA_libatomic_la_SOURCES = $(addsuffix _n.c,$(SIZEOBJS))
libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) $(libatomic_version_dep)
## And now our custom target patterns that allow us not to have tons of
## extra source files hanging about. Unfortunately, the complex relation
## between source and object filenames doesn't allow us to add an explicit
## dependency here. Fortunately that doesn't matter since auto-generated
## dependencies do the job just as well:
-include $(wildcard $(DEPDIR)/*.Ppo)
## Naming pattern: base_n_i_.lo
##
## N size of data
## I IFUNC alternative, index beginning at 1.
##
## The trailing _ in the output object file name is required to differentiate
## these objects from those which should be compiled normally. We can only
## have one stem in the implicit rule.
empty =
space = $(empty) $(empty)
PAT_SPLIT = $(subst _,$(space),$(*F))
PAT_BASE = $(word 1,$(PAT_SPLIT))
PAT_N = $(word 2,$(PAT_SPLIT))
PAT_S = $(word 3,$(PAT_SPLIT))
IFUNC_DEF = -DIFUNC_ALT=$(PAT_S)
IFUNC_OPT = $(word $(PAT_S),$(IFUNC_OPTIONS))
M_DEPS = -MT $@ -MD -MP -MF $(DEPDIR)/$(@F).Ppo
M_SIZE = -DN=$(PAT_N)
M_IFUNC = $(if $(PAT_S),$(IFUNC_DEF) $(IFUNC_OPT))
M_FILE = $(PAT_BASE)_n.c
# The lack of explicit dependency on the source file means that VPATH cannot
# work properly. Instead, perform this operation by hand. First, collect a
# list of all .c files in the search path.
all_c_files := $(foreach dir,$(search_path),$(wildcard $(dir)/*.c))
# Then sort through them to find the one we want, and select the first.
M_SRC = $(firstword $(filter %/$(M_FILE), $(all_c_files)))
%_.lo: Makefile
$(LTCOMPILE) $(M_DEPS) $(M_SIZE) $(M_IFUNC) -c -o $@ $(M_SRC)
## Include all of the sizes in the "normal" set of compilation flags.
libatomic_la_LIBADD = $(foreach s,$(SIZES),$(addsuffix _$(s)_.lo,$(SIZEOBJS)))
## On a target-specific basis, include alternates to be selected by IFUNC.
if HAVE_IFUNC
if ARCH_ARM_LINUX
IFUNC_OPTIONS = -march=armv7-a -DHAVE_KERNEL64
libatomic_la_LIBADD += $(foreach s,$(SIZES),$(addsuffix _$(s)_1_.lo,$(SIZEOBJS)))
libatomic_la_LIBADD += $(addsuffix _8_2_.lo,$(SIZEOBJS))
endif
if ARCH_I386
IFUNC_OPTIONS = -march=i586
libatomic_la_LIBADD += $(addsuffix _8_1_.lo,$(SIZEOBJS))
endif
if ARCH_X86_64
IFUNC_OPTIONS = -mcx16
libatomic_la_LIBADD += $(addsuffix _16_1_.lo,$(SIZEOBJS))
endif
endif
/* auto-config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
#undef AC_APPLE_UNIVERSAL_BUILD
/* Have __atomic_compare_exchange for 1 byte integers. */
#undef HAVE_ATOMIC_CAS_1
/* Have __atomic_compare_exchange for 16 byte integers. */
#undef HAVE_ATOMIC_CAS_16
/* Have __atomic_compare_exchange for 2 byte integers. */
#undef HAVE_ATOMIC_CAS_2
/* Have __atomic_compare_exchange for 4 byte integers. */
#undef HAVE_ATOMIC_CAS_4
/* Have __atomic_compare_exchange for 8 byte integers. */
#undef HAVE_ATOMIC_CAS_8
/* Have __atomic_exchange for 1 byte integers. */
#undef HAVE_ATOMIC_EXCHANGE_1
/* Have __atomic_exchange for 16 byte integers. */
#undef HAVE_ATOMIC_EXCHANGE_16
/* Have __atomic_exchange for 2 byte integers. */
#undef HAVE_ATOMIC_EXCHANGE_2
/* Have __atomic_exchange for 4 byte integers. */
#undef HAVE_ATOMIC_EXCHANGE_4
/* Have __atomic_exchange for 8 byte integers. */
#undef HAVE_ATOMIC_EXCHANGE_8
/* Have __atomic_fetch_add for 1 byte integers. */
#undef HAVE_ATOMIC_FETCH_ADD_1
/* Have __atomic_fetch_add for 16 byte integers. */
#undef HAVE_ATOMIC_FETCH_ADD_16
/* Have __atomic_fetch_add for 2 byte integers. */
#undef HAVE_ATOMIC_FETCH_ADD_2
/* Have __atomic_fetch_add for 4 byte integers. */
#undef HAVE_ATOMIC_FETCH_ADD_4
/* Have __atomic_fetch_add for 8 byte integers. */
#undef HAVE_ATOMIC_FETCH_ADD_8
/* Have __atomic_fetch_op for all op for 1 byte integers. */
#undef HAVE_ATOMIC_FETCH_OP_1
/* Have __atomic_fetch_op for all op for 16 byte integers. */
#undef HAVE_ATOMIC_FETCH_OP_16
/* Have __atomic_fetch_op for all op for 2 byte integers. */
#undef HAVE_ATOMIC_FETCH_OP_2
/* Have __atomic_fetch_op for all op for 4 byte integers. */
#undef HAVE_ATOMIC_FETCH_OP_4
/* Have __atomic_fetch_op for all op for 8 byte integers. */
#undef HAVE_ATOMIC_FETCH_OP_8
/* Have __atomic_load/store for 1 byte integers. */
#undef HAVE_ATOMIC_LDST_1
/* Have __atomic_load/store for 16 byte integers. */
#undef HAVE_ATOMIC_LDST_16
/* Have __atomic_load/store for 2 byte integers. */
#undef HAVE_ATOMIC_LDST_2
/* Have __atomic_load/store for 4 byte integers. */
#undef HAVE_ATOMIC_LDST_4
/* Have __atomic_load/store for 8 byte integers. */
#undef HAVE_ATOMIC_LDST_8
/* Have __atomic_test_and_set for 1 byte integers. */
#undef HAVE_ATOMIC_TAS_1
/* Have __atomic_test_and_set for 16 byte integers. */
#undef HAVE_ATOMIC_TAS_16
/* Have __atomic_test_and_set for 2 byte integers. */
#undef HAVE_ATOMIC_TAS_2
/* Have __atomic_test_and_set for 4 byte integers. */
#undef HAVE_ATOMIC_TAS_4
/* Have __atomic_test_and_set for 8 byte integers. */
#undef HAVE_ATOMIC_TAS_8
/* Define to 1 if the target supports __attribute__((alias(...))). */
#undef HAVE_ATTRIBUTE_ALIAS
/* Define to 1 if the target supports __attribute__((dllexport)). */
#undef HAVE_ATTRIBUTE_DLLEXPORT
/* Define to 1 if the target supports __attribute__((visibility(...))). */
#undef HAVE_ATTRIBUTE_VISIBILITY
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if the target supports __attribute__((ifunc(...))). */
#undef HAVE_IFUNC
/* Have support for 1 byte integers. */
#undef HAVE_INT1
/* Have support for 16 byte integers. */
#undef HAVE_INT16
/* Have support for 2 byte integers. */
#undef HAVE_INT2
/* Have support for 4 byte integers. */
#undef HAVE_INT4
/* Have support for 8 byte integers. */
#undef HAVE_INT8
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if GNU symbol versioning is used for libatomic. */
#undef LIBAT_GNU_SYMBOL_VERSIONING
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `char', as computed by sizeof. */
#undef SIZEOF_CHAR
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* The size of `void *', as computed by sizeof. */
#undef SIZEOF_VOID_P
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if you can safely include both <string.h> and <strings.h>. */
#undef STRING_WITH_STRINGS
/* Version number of package */
#undef VERSION
/* The word size in bytes of the machine. */
#undef WORDSIZE
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
# undef WORDS_BIGENDIAN
# endif
#endif
#define MAYBE_HAVE_ATOMIC_LDST_1 HAVE_ATOMIC_LDST_1
#define MAYBE_HAVE_ATOMIC_TAS_16 HAVE_ATOMIC_TAS_16
#define MAYBE_HAVE_ATOMIC_EXCHANGE_1 HAVE_ATOMIC_EXCHANGE_1
#define MAYBE_HAVE_ATOMIC_EXCHANGE_2 HAVE_ATOMIC_EXCHANGE_2
#define MAYBE_HAVE_ATOMIC_EXCHANGE_4 HAVE_ATOMIC_EXCHANGE_4
#define MAYBE_HAVE_ATOMIC_EXCHANGE_8 HAVE_ATOMIC_EXCHANGE_8
#define MAYBE_HAVE_ATOMIC_EXCHANGE_16 HAVE_ATOMIC_EXCHANGE_16
#define MAYBE_HAVE_ATOMIC_CAS_1 HAVE_ATOMIC_CAS_1
#define MAYBE_HAVE_ATOMIC_CAS_2 HAVE_ATOMIC_CAS_2
#define MAYBE_HAVE_ATOMIC_CAS_4 HAVE_ATOMIC_CAS_4
#define MAYBE_HAVE_ATOMIC_CAS_8 HAVE_ATOMIC_CAS_8
#define MAYBE_HAVE_ATOMIC_LDST_2 HAVE_ATOMIC_LDST_2
#define MAYBE_HAVE_ATOMIC_CAS_16 HAVE_ATOMIC_CAS_16
#define MAYBE_HAVE_ATOMIC_FETCH_ADD_1 HAVE_ATOMIC_FETCH_ADD_1
#define MAYBE_HAVE_ATOMIC_FETCH_ADD_2 HAVE_ATOMIC_FETCH_ADD_2
#define MAYBE_HAVE_ATOMIC_FETCH_ADD_4 HAVE_ATOMIC_FETCH_ADD_4
#define MAYBE_HAVE_ATOMIC_FETCH_ADD_8 HAVE_ATOMIC_FETCH_ADD_8
#define MAYBE_HAVE_ATOMIC_FETCH_ADD_16 HAVE_ATOMIC_FETCH_ADD_16
#define MAYBE_HAVE_ATOMIC_FETCH_OP_1 HAVE_ATOMIC_FETCH_OP_1
#define MAYBE_HAVE_ATOMIC_FETCH_OP_2 HAVE_ATOMIC_FETCH_OP_2
#define MAYBE_HAVE_ATOMIC_FETCH_OP_4 HAVE_ATOMIC_FETCH_OP_4
#define MAYBE_HAVE_ATOMIC_FETCH_OP_8 HAVE_ATOMIC_FETCH_OP_8
#define MAYBE_HAVE_ATOMIC_LDST_4 HAVE_ATOMIC_LDST_4
#define MAYBE_HAVE_ATOMIC_FETCH_OP_16 HAVE_ATOMIC_FETCH_OP_16
#ifndef WORDS_BIGENDIAN
#define WORDS_BIGENDIAN 0
#endif
#define MAYBE_HAVE_ATOMIC_LDST_8 HAVE_ATOMIC_LDST_8
#define MAYBE_HAVE_ATOMIC_LDST_16 HAVE_ATOMIC_LDST_16
#define MAYBE_HAVE_ATOMIC_TAS_1 HAVE_ATOMIC_TAS_1
#define MAYBE_HAVE_ATOMIC_TAS_2 HAVE_ATOMIC_TAS_2
#define MAYBE_HAVE_ATOMIC_TAS_4 HAVE_ATOMIC_TAS_4
#define MAYBE_HAVE_ATOMIC_TAS_8 HAVE_ATOMIC_TAS_8
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we support the builtin, just use it. */
#if !DONE && defined(atomic_compare_exchange_n)
bool
SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
int smodel, int fmodel UNUSED)
{
if (maybe_specialcase_relaxed(smodel))
return atomic_compare_exchange_n (mptr, eptr, newval, false,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
return atomic_compare_exchange_n (mptr, eptr, newval, false,
__ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
else
return atomic_compare_exchange_n (mptr, eptr, newval, false,
__ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
}
#define DONE 1
#endif /* HAVE_ATOMIC_CAS */
/* If this type is not larger than word-sized, fall back to a word-sized
compare-and-swap loop, possibly assisted by the OS. */
#if !DONE && N <= WORDSIZE && defined(atomic_compare_exchange_w)
bool
SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
int smodel, int fmodel UNUSED)
{
UWORD mask, shift, weval, woldval, wnewval, t, *wptr;
bool ret = false;
pre_barrier (smodel);
if (N < WORDSIZE)
{
wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ SIZE(INVERT_MASK);
mask = SIZE(MASK) << shift;
}
else
{
wptr = (UWORD *)mptr;
shift = 0;
mask = -1;
}
weval = *eptr << shift;
wnewval = (UWORD)newval << shift;
woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
do
{
if ((woldval & mask) != weval)
goto failure;
t = (woldval & ~mask) | wnewval;
}
while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
ret = true;
failure:
*eptr = woldval >> shift;
post_barrier (smodel);
return ret;
}
#define DONE 1
#endif /* HAVE_ATOMIC_CAS && N <= WORDSIZE */
/* Otherwise, fall back to some sort of protection mechanism. */
#if !DONE
bool
SIZE(libat_compare_exchange) (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
int smodel, int fmodel UNUSED)
{
UTYPE oldval;
UWORD magic;
bool ret = false;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
oldval = *mptr;
if (oldval == *eptr)
{
*mptr = newval;
ret = true;
}
*eptr = oldval;
protect_end (mptr, magic);
post_seq_barrier (smodel);
return ret;
}
#endif
EXPORT_ALIAS (SIZE(compare_exchange));
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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/>. */
#if defined(__ARM_ARCH_2__)
# define __ARM_ARCH__ 2
#endif
#if defined(__ARM_ARCH_3__)
# define __ARM_ARCH__ 3
#endif
#if defined(__ARM_ARCH_3M__) || defined(__ARM_ARCH_4__) \
|| defined(__ARM_ARCH_4T__)
/* We use __ARM_ARCH__ set to 4 here, but in reality it's any processor with
long multiply instructions. That includes v3M. */
# define __ARM_ARCH__ 4
#endif
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__)
# define __ARM_ARCH__ 5
#endif
#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|| defined(__ARM_ARCH_6M__)
# define __ARM_ARCH__ 6
#endif
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7EM__)
# define __ARM_ARCH__ 7
#endif
#ifndef __ARM_ARCH__
#error Unable to determine architecture.
#endif
#if __ARM_ARCH__ >= 7 || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__)
# define HAVE_STREX 1
# define HAVE_STREXBHD 1
#elif __ARM_ARCH__ == 6
# define HAVE_STREX 1
#endif
#if __ARM_ARCH__ >= 7
# define HAVE_DMB 1
#elif __ARM_ARCH__ == 6
# define HAVE_DMB_MCR 1
#endif
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 <libatomic_i.h>
#include <arm-config.h>
/* When using STREX to implement sub-word exchange, we can do much better
than the compiler by using the APSR.GE and APSR.C flags. */
#if !DONE && HAVE_STREX && !HAVE_STREXBH && N == 2
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel)
{
UWORD t1, t2;
UTYPE oldval;
__atomic_thread_fence (__ATOMIC_SEQ_CST);
/* In the N=2 case, there are only two cases for MPTR: mptr % 4 == {0,2}.
Rather than computing a variable shift for this, we can store the one
bit of misalignment in the carry flag, and use conditional constant
shifts instead. This saves a register. */
#ifdef __ARMEB__
# define HI "cc" /* iff value is in high half */
# define LO "cs" /* iff value is in low half */
#else
# define HI "cs"
# define LO "cc"
#endif
asm volatile (
"lsrs %[t2],%[ptr],#2\n" /* carry = mptr & 2 */
" bic %[ptr],%[ptr],#3\n" /* align mptr */
" itt "HI"\n"
" lsl"HI" %[t1],%[t1],#16\n" /* shift mask into place */
" lsl"HI" %[new],%[new],#16\n" /* shift newval into place */
" uadd16 %[t1],%[t1],%[t1]\n" /* copy mask into APSR.GE */
"0: ldrex %[t2],[%[ptr]]\n"
" ite "LO"\n"
" uxth"LO" %[old],%[t2]\n" /* return old value */
" uxth"HI" %[old],%[t2], ror #16\n"
" sel %[t1],%[new],%[t2]\n" /* merge newval */
" strex %[t2],%[t1],[%[ptr]]\n"
" tst %[t2],%[t2]\n" /* dont clobber carry */
" bne 0b"
: [old] "=&r"(oldval), [t1] "=&r"(t1), [t2] "=&r"(t2),
[ptr] "+r"(mptr), [new] "+r"(newval)
: "1"(0xffff)
: "memory");
__atomic_thread_fence (__ATOMIC_SEQ_CST);
return oldval;
}
#define DONE 1
#endif /* !HAVE_STREXBH && N == 2 */
#if !DONE && HAVE_STREX && !HAVE_STREXBH && N == 1
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel)
{
UWORD *wptr, woldval, wnewval, shift, mask, t1, t2;
__atomic_thread_fence (__ATOMIC_SEQ_CST);
wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ INVERT_MASK_1;
mask = MASK_1 << shift;
wnewval = newval << shift;
asm volatile (
"uadd8 %[t1],%[t1],%[t1]\n" /* move mask to APSR.GE */
"0: ldrex %[old],[%[wptr]]\n"
" sel %[t1],%[new],%[old]\n" /* merge newval */
" strex %[t2],%[t1],[%[wptr]]\n"
" cmp %[t2],#0\n"
" bne 0b"
: [old] "=&r"(woldval), [t1] "=&r"(t1), [t2] "=&r"(t2)
: [new] "r"(wnewval), [wptr] "r"(wptr), "1"(mask)
: "memory");
__atomic_thread_fence (__ATOMIC_SEQ_CST);
return woldval >> shift;
}
#define DONE 1
#endif /* !HAVE_STREXBH && N == 1 */
#include "../../exch_n.c"
/* Avoiding the DMB (or kernel helper) can be a good thing. */
#define WANT_SPECIALCASE_RELAXED
#include_next <host-config.h>
/* Avoiding the synchronizations are a good thing. */
#define WANT_SPECIALCASE_RELAXED
#define WANT_SPECIALCASE_ACQREL
#include_next <host-config.h>
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 <config/arm/arm-config.h>
/* Kernel helper for 32-bit compare-and-exchange. */
typedef int (__kernel_cmpxchg_t) (UWORD oldval, UWORD newval, UWORD *ptr);
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *) 0xffff0fc0)
/* Kernel helper for 64-bit compare-and-exchange. */
typedef int (__kernel_cmpxchg64_t) (const U_8 * oldval, const U_8 * newval,
U_8 *ptr);
#define __kernel_cmpxchg64 (*(__kernel_cmpxchg64_t *) 0xffff0f60)
/* Kernel helper for memory barrier. */
typedef void (__kernel_dmb_t) (void);
#define __kernel_dmb (*(__kernel_dmb_t *) 0xffff0fa0)
/* Kernel helper page version number. */
#define __kernel_helper_version (*(unsigned int *)0xffff0ffc)
#ifndef HAVE_STREX
static inline bool
atomic_compare_exchange_w (UWORD *mptr, UWORD *eptr, UWORD newval,
bool weak_p UNUSED, int sm UNUSED, int fm UNUSED)
{
bool ret = true;
UWORD oldval;
oldval = *eptr;
if (__builtin_expect (__kernel_cmpxchg (oldval, newval, mptr) != 0, 0))
{
oldval = *mptr;
ret = false;
}
*eptr = oldval;
return ret;
}
# define atomic_compare_exchange_w atomic_compare_exchange_w
# if N == WORDSIZE
# define atomic_compare_exchange_n atomic_compare_exchange_w
# endif
#endif /* HAVE_STREX */
#if !defined(HAVE_STREXBHD) && defined(HAVE_KERNEL64) && N == 8
static inline bool
atomic_compare_exchange_n (UTYPE *mptr, UTYPE *eptr, UTYPE newval,
bool weak_p UNUSED, int sm UNUSED, int fm UNUSED)
{
if (__kernel_cmpxchg64 (eptr, &newval, mptr) == 0)
return true;
else
{
*eptr = *mptr;
return false;
}
}
#define atomic_compare_exchange_n atomic_compare_exchange_n
#endif
#if !defined(HAVE_DMB) && !defined(HAVE_DMB_MCR)
static inline void
pre_barrier(int model UNUSED)
{
__kernel_dmb ();
}
static inline void
post_barrier(int model UNUSED)
{
__kernel_dmb ();
}
# define pre_post_barrier 1
#endif /* !HAVE_DMB */
#if HAVE_IFUNC
extern bool libat_have_strexbhd HIDDEN;
# define IFUNC_COND_1 libat_have_strexbhd
# define IFUNC_COND_2 (__kernel_helper_version >= 5)
/* Alternative 1 is -march=armv7-a -- we have everything native. */
# if IFUNC_ALT == 1
# undef HAVE_ATOMIC_CAS_1
# undef HAVE_ATOMIC_CAS_2
# undef HAVE_ATOMIC_CAS_4
# undef HAVE_ATOMIC_CAS_8
# undef HAVE_ATOMIC_EXCHANGE_1
# undef HAVE_ATOMIC_EXCHANGE_2
# undef HAVE_ATOMIC_EXCHANGE_4
# undef HAVE_ATOMIC_EXCHANGE_8
# undef HAVE_ATOMIC_LDST_1
# undef HAVE_ATOMIC_LDST_2
# undef HAVE_ATOMIC_LDST_4
# undef HAVE_ATOMIC_LDST_8
# undef HAVE_ATOMIC_FETCH_OP_1
# undef HAVE_ATOMIC_FETCH_OP_2
# undef HAVE_ATOMIC_FETCH_OP_4
# undef HAVE_ATOMIC_FETCH_OP_8
# undef HAVE_ATOMIC_TAS_1
# undef HAVE_ATOMIC_TAS_2
# undef HAVE_ATOMIC_TAS_4
# undef HAVE_ATOMIC_TAS_8
# define HAVE_ATOMIC_CAS_1 1
# define HAVE_ATOMIC_CAS_2 1
# define HAVE_ATOMIC_CAS_4 1
# define HAVE_ATOMIC_CAS_8 1
# define HAVE_ATOMIC_EXCHANGE_1 1
# define HAVE_ATOMIC_EXCHANGE_2 1
# define HAVE_ATOMIC_EXCHANGE_4 1
# define HAVE_ATOMIC_EXCHANGE_8 1
# define HAVE_ATOMIC_LDST_1 1
# define HAVE_ATOMIC_LDST_2 1
# define HAVE_ATOMIC_LDST_4 1
# define HAVE_ATOMIC_LDST_8 1
# define HAVE_ATOMIC_FETCH_OP_1 1
# define HAVE_ATOMIC_FETCH_OP_2 1
# define HAVE_ATOMIC_FETCH_OP_4 1
# define HAVE_ATOMIC_FETCH_OP_8 1
# define HAVE_ATOMIC_TAS_1 1
# define HAVE_ATOMIC_TAS_2 1
# define HAVE_ATOMIC_TAS_4 1
# define HAVE_ATOMIC_TAS_8 1
# endif /* IFUNC_ALT == 1 */
# undef MAYBE_HAVE_ATOMIC_CAS_1
# define MAYBE_HAVE_ATOMIC_CAS_1 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_EXCHANGE_1
# define MAYBE_HAVE_ATOMIC_EXCHANGE_1 MAYBE_HAVE_ATOMIC_CAS_1
# undef MAYBE_HAVE_ATOMIC_LDST_1
# define MAYBE_HAVE_ATOMIC_LDST_1 MAYBE_HAVE_ATOMIC_CAS_1
# undef MAYBE_HAVE_ATOMIC_CAS_2
# define MAYBE_HAVE_ATOMIC_CAS_2 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_EXCHANGE_2
# define MAYBE_HAVE_ATOMIC_EXCHANGE_2 MAYBE_HAVE_ATOMIC_CAS_2
# undef MAYBE_HAVE_ATOMIC_LDST_2
# define MAYBE_HAVE_ATOMIC_LDST_2 MAYBE_HAVE_ATOMIC_CAS_2
# undef MAYBE_HAVE_ATOMIC_CAS_4
# define MAYBE_HAVE_ATOMIC_CAS_4 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_EXCHANGE_4
# define MAYBE_HAVE_ATOMIC_EXCHANGE_4 MAYBE_HAVE_ATOMIC_CAS_4
# undef MAYBE_HAVE_ATOMIC_LDST_4
# define MAYBE_HAVE_ATOMIC_LDST_4 MAYBE_HAVE_ATOMIC_CAS_4
# undef MAYBE_HAVE_ATOMIC_CAS_8
# define MAYBE_HAVE_ATOMIC_CAS_8 (IFUNC_COND_1 | IFUNC_COND_2)
# undef MAYBE_HAVE_ATOMIC_EXCHANGE_8
# define MAYBE_HAVE_ATOMIC_EXCHANGE_8 MAYBE_HAVE_ATOMIC_CAS_8
# undef MAYBE_HAVE_ATOMIC_LDST_8
# define MAYBE_HAVE_ATOMIC_LDST_8 MAYBE_HAVE_ATOMIC_CAS_8
# define IFUNC_NCOND(N) (N == 8 ? 2 : 1)
#endif /* HAVE_IFUNC */
#include_next <host-config.h>
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
#if HAVE_IFUNC
bool libat_have_strexbhd;
static void __attribute__((constructor))
init_cpu_revision (void)
{
}
#endif /* HAVE_IFUNC */
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we use the builtin we'll get __sync_synchronize, not __kernel_dmb. */
#if !DONE && N <= WORDSIZE && !defined(HAVE_DMB) && !defined(HAVE_DMB_MCR)
UTYPE
SIZE(libat_load) (UTYPE *mptr, int smodel)
{
UTYPE ret;
if (maybe_specialcase_relaxed(smodel))
ret = *mptr;
else
{
__kernel_dmb ();
ret = *mptr;
__kernel_dmb ();
}
return ret;
}
#define DONE 1
#endif /* !HAVE_DMB */
#include "../../../load_n.c"
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we use the builtin we'll get __sync_synchronize, not __kernel_dmb. */
#if !DONE && N <= WORDSIZE && !defined(HAVE_DMB) && !defined(HAVE_DMB_MCR)
void
SIZE(libat_store) (UTYPE *mptr, UTYPE val, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
*mptr = val;
else
{
__kernel_dmb ();
*mptr = val;
__kernel_dmb ();
}
}
#define DONE 1
#endif /* !HAVE_DMB */
#include "../../../store_n.c"
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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/>. */
/* Included after all more target-specific host-config.h. */
#ifndef protect_start_end
# ifdef HAVE_ATTRIBUTE_VISIBILITY
# pragma GCC visibility push(hidden)
# endif
void libat_lock_1 (void *ptr);
void libat_unlock_1 (void *ptr);
static inline UWORD
protect_start (void *ptr)
{
libat_lock_1 (ptr);
return 0;
}
static inline void
protect_end (void *ptr, UWORD dummy UNUSED)
{
libat_unlock_1 (ptr);
}
# define protect_start_end 1
# ifdef HAVE_ATTRIBUTE_VISIBILITY
# pragma GCC visibility pop
# endif
#endif /* protect_start_end */
#include_next <host-config.h>
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
#include <pthread.h>
/* The target page size. Must be no larger than the runtime page size,
lest locking fail with virtual address aliasing (i.e. a page mmaped
at two locations). */
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
/* The target cacheline size. This is an optimization; the padding that
should be applied to the locks to keep them from interfering. */
#ifndef CACHLINE_SIZE
#define CACHLINE_SIZE 64
#endif
/* The granularity at which locks are applied. Almost certainly the
cachline size is the right thing to use here. */
#ifndef WATCH_SIZE
#define WATCH_SIZE CACHLINE_SIZE
#endif
struct lock
{
pthread_mutex_t mutex;
char pad[sizeof(pthread_mutex_t) < CACHLINE_SIZE
? CACHLINE_SIZE - sizeof(pthread_mutex_t)
: 0];
};
#define NLOCKS (PAGE_SIZE / WATCH_SIZE)
static struct lock locks[NLOCKS] = {
[0 ... NLOCKS-1].mutex = PTHREAD_MUTEX_INITIALIZER
};
static inline uintptr_t
addr_hash (void *ptr)
{
return ((uintptr_t)ptr / WATCH_SIZE) % NLOCKS;
}
void
libat_lock_1 (void *ptr)
{
pthread_mutex_lock (&locks[addr_hash (ptr)].mutex);
}
void
libat_unlock_1 (void *ptr)
{
pthread_mutex_unlock (&locks[addr_hash (ptr)].mutex);
}
void
libat_lock_n (void *ptr, size_t n)
{
uintptr_t h = addr_hash (ptr);
size_t i = 0;
/* Don't lock more than all the locks we have. */
if (n > PAGE_SIZE)
n = PAGE_SIZE;
do
{
pthread_mutex_lock (&locks[h].mutex);
if (++h == NLOCKS)
h = 0;
i += WATCH_SIZE;
}
while (i < n);
}
void
libat_unlock_n (void *ptr, size_t n)
{
uintptr_t h = addr_hash (ptr);
size_t i = 0;
if (n > PAGE_SIZE)
n = PAGE_SIZE;
do
{
pthread_mutex_unlock (&locks[h].mutex);
if (++h == NLOCKS)
h = 0;
i += WATCH_SIZE;
}
while (i < n);
}
/* Avoiding the synchronizations are a good thing. */
#define WANT_SPECIALCASE_RELAXED
#define WANT_SPECIALCASE_ACQREL
/* Glibc, at least, uses lwsync (aka acq_rel) in its pthread mutex
implementation. If the user is asking for seq_cst (aka hwsync),
this is insufficient. */
static inline void __attribute__((always_inline, artificial))
pre_seq_barrier(int model)
{
if (model == __ATOMIC_SEQ_CST)
__atomic_thread_fence (__ATOMIC_SEQ_CST);
}
static inline void __attribute__((always_inline, artificial))
post_seq_barrier(int model)
{
pre_seq_barrier(model);
}
#define pre_post_seq_barrier 1
#include_next <host-config.h>
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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/>. */
#if HAVE_IFUNC
#include <cpuid.h>
extern unsigned int libat_feat1_ecx HIDDEN;
extern unsigned int libat_feat1_edx HIDDEN;
#ifdef __x86_64__
# define IFUNC_COND_1 (libat_feat1_ecx & bit_CMPXCHG16B)
#else
# define IFUNC_COND_1 (libat_feat1_edx & bit_CMPXCHG8B)
#endif
#ifdef __x86_64__
# define IFUNC_NCOND(N) (N == 16)
#else
# define IFUNC_NCOND(N) (N == 8)
#endif
#ifdef __x86_64__
# undef MAYBE_HAVE_ATOMIC_CAS_16
# define MAYBE_HAVE_ATOMIC_CAS_16 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_EXCHANGE_16
# define MAYBE_HAVE_ATOMIC_EXCHANGE_16 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_LDST_16
# define MAYBE_HAVE_ATOMIC_LDST_16 IFUNC_COND_1
# if IFUNC_ALT == 1
# undef HAVE_ATOMIC_CAS_16
# define HAVE_ATOMIC_CAS_16 1
# endif
#else
# undef MAYBE_HAVE_ATOMIC_CAS_8
# define MAYBE_HAVE_ATOMIC_CAS_8 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_EXCHANGE_8
# define MAYBE_HAVE_ATOMIC_EXCHANGE_8 IFUNC_COND_1
# undef MAYBE_HAVE_ATOMIC_LDST_8
# define MAYBE_HAVE_ATOMIC_LDST_8 IFUNC_COND_1
# if IFUNC_ALT == 1
# undef HAVE_ATOMIC_CAS_8
# define HAVE_ATOMIC_CAS_8 1
# endif
#endif
#endif /* HAVE_IFUNC */
#include_next <host-config.h>
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
#if HAVE_IFUNC
unsigned int libat_feat1_ecx, libat_feat1_edx;
static void __attribute__((constructor))
init_cpuid (void)
{
unsigned int eax, ebx;
__get_cpuid (1, &eax, &ebx, &libat_feat1_ecx, &libat_feat1_edx);
}
#endif /* HAVE_IFUNC */
This source diff could not be displayed because it is too large. You can view the blob instead.
# Process this file with autoreconf to produce a configure script.
# Copyright (C) 2012 Free Software Foundation, Inc.
#
# This file is part of the GNU Atomic Library (libatomic).
#
# Libatomic 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 of the License, or
# (at your option) any later version.
#
# Libatomic 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/>.
AC_PREREQ(2.59)
AC_INIT([GNU Atomic Library], 1.0,,[libatomic])
AC_CONFIG_HEADER(auto-config.h)
# -------
# Options
# -------
AC_MSG_CHECKING([for --enable-version-specific-runtime-libs])
LIBAT_ENABLE(version-specific-runtime-libs, no, ,
[Specify that runtime libraries should be installed in a compiler-specific directory],
permit yes|no)
AC_MSG_RESULT($enable_version_specific_runtime_libs)
# We would like our source tree to be readonly. However when releases or
# pre-releases are generated, the flex/bison generated files as well as the
# various formats of manuals need to be included along with the rest of the
# sources. Therefore we have --enable-generated-files-in-srcdir to do
# just that.
AC_MSG_CHECKING([for --enable-generated-files-in-srcdir])
LIBAT_ENABLE(generated-files-in-srcdir, no, ,
[put copies of generated files in source dir intended for creating source
tarballs for users without texinfo bison or flex.],
permit yes|no)
AC_MSG_RESULT($enable_generated_files_in_srcdir)
AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes)
# -------
# Gets build, host, target, *_vendor, *_cpu, *_os, etc.
#
# You will slowly go insane if you do not grok the following fact: when
# building this library, the top-level /target/ becomes the library's /host/.
#
# configure then causes --target to default to --host, exactly like any
# other package using autoconf. Therefore, 'target' and 'host' will
# always be the same. This makes sense both for native and cross compilers
# just think about it for a little while. :-)
#
# Also, if this library is being configured as part of a cross compiler, the
# top-level configure script will pass the "real" host as $with_cross_host.
#
# Do not delete or change the following two lines. For why, see
# http://gcc.gnu.org/ml/libstdc++/2003-07/msg00451.html
AC_CANONICAL_SYSTEM
target_alias=${target_alias-$host_alias}
# Sets up automake. Must come after AC_CANONICAL_SYSTEM. Each of the
# following is magically included in AUTOMAKE_OPTIONS in each Makefile.am.
# 1.9.0: minimum required version
# no-define: PACKAGE and VERSION will not be #define'd in config.h (a bunch
# of other PACKAGE_* variables will, however, and there's nothing
# we can do about that; they come from AC_INIT).
# foreign: we don't follow the normal rules for GNU packages (no COPYING
# file in the top srcdir, etc, etc), so stop complaining.
# -Wall: turns on all automake warnings...
# -Wno-portability: ...except this one, since GNU make is required.
# -Wno-override: ... and this one, since we do want this in testsuite.
AM_INIT_AUTOMAKE([1.9.0 foreign -Wall -Wno-portability -Wno-override])
AM_ENABLE_MULTILIB(, ..)
# Calculate toolexeclibdir
# Also toolexecdir, though it's only used in toolexeclibdir
case ${enable_version_specific_runtime_libs} in
yes)
# Need the gcc compiler version to know where to install libraries
# and header files if --enable-version-specific-runtime-libs option
# is selected.
toolexecdir='$(libdir)/gcc/$(target_alias)'
toolexeclibdir='$(toolexecdir)/$(gcc_version)$(MULTISUBDIR)'
;;
no)
if test -n "$with_cross_host" &&
test x"$with_cross_host" != x"no"; then
# Install a library built with a cross compiler in tooldir, not libdir.
toolexecdir='$(exec_prefix)/$(target_alias)'
toolexeclibdir='$(toolexecdir)/lib'
else
toolexecdir='$(libdir)/gcc-lib/$(target_alias)'
toolexeclibdir='$(libdir)'
fi
multi_os_directory=`$CC -print-multi-os-directory`
case $multi_os_directory in
.) ;; # Avoid trailing /.
*) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;;
esac
;;
esac
AC_SUBST(toolexecdir)
AC_SUBST(toolexeclibdir)
# Check the compiler.
# The same as in boehm-gc and libstdc++. Have to borrow it from there.
# We must force CC to /not/ be precious variables; otherwise
# the wrong, non-multilib-adjusted value will be used in multilibs.
# As a side effect, we have to subst CFLAGS ourselves.
m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS])
m4_define([_AC_ARG_VAR_PRECIOUS],[])
AC_PROG_CC
AM_PROG_AS
m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS])
AC_SUBST(CFLAGS)
# In order to override CFLAGS_FOR_TARGET, all of our special flags go
# in XCFLAGS. But we need them in CFLAGS during configury. So put them
# in both places for now and restore CFLAGS at the end of config.
save_CFLAGS="$CFLAGS"
# Find other programs we need.
AC_CHECK_TOOL(AR, ar)
AC_CHECK_TOOL(NM, nm)
AC_CHECK_TOOL(RANLIB, ranlib, ranlib-not-found-in-path-error)
AC_PATH_PROG(PERL, perl, perl-not-found-in-path-error)
AC_PROG_INSTALL
# Configure libtool
AM_PROG_LIBTOOL
AC_SUBST(enable_shared)
AC_SUBST(enable_static)
# For libtool versioning info, format is CURRENT:REVISION:AGE
libtool_VERSION=1:0:0
AC_SUBST(libtool_VERSION)
# Get target configury.
. ${srcdir}/configure.tgt
if test -n "$UNSUPPORTED"; then
AC_MSG_ERROR([Configuration ${target} is unsupported.])
fi
# Disable fallbacks to __sync routines from libgcc. Otherwise we'll
# make silly decisions about what the cpu can do.
CFLAGS="$save_CFLAGS -fno-sync-libcalls $XCFLAGS"
# Check header files.
AC_STDC_HEADERS
ACX_HEADER_STRING
GCC_HEADER_STDINT(gstdint.h)
# Check for common type sizes
LIBAT_FORALL_MODES([LIBAT_HAVE_INT_MODE])
# Check for compiler builtins of atomic operations.
LIBAT_TEST_ATOMIC_INIT
LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_LOADSTORE])
LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_TAS])
LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_EXCHANGE])
LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_CAS])
LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_FETCH_ADD])
LIBAT_FORALL_MODES([LIBAT_HAVE_ATOMIC_FETCH_OP])
AC_C_BIGENDIAN
# I don't like the default behaviour of WORDS_BIGENDIAN undefined for LE.
AH_BOTTOM(
[#ifndef WORDS_BIGENDIAN
#define WORDS_BIGENDIAN 0
#endif])
LIBAT_WORDSIZE
# Check to see if -pthread or -lpthread is needed. Prefer the former.
# In case the pthread.h system header is not found, this test will fail.
case " $config_path " in
*" posix "*)
XPCFLAGS=""
CFLAGS="$CFLAGS -pthread"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <pthread.h>
void *g(void *d) { return NULL; }],
[pthread_t t; pthread_create(&t,NULL,g,NULL);])],
[XPCFLAGS=" -pthread"],
[CFLAGS="$save_CFLAGS $XCFLAGS" LIBS="-lpthread $LIBS"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[#include <pthread.h>
void *g(void *d) { return NULL; }],
[pthread_t t; pthread_create(&t,NULL,g,NULL);])],
[],
[AC_MSG_ERROR([Pthreads are required to build libatomic])])])
CFLAGS="$save_CFLAGS $XCFLAGS"
;;
esac
# See what sort of export controls are available.
LIBAT_CHECK_ATTRIBUTE_VISIBILITY
LIBAT_CHECK_ATTRIBUTE_DLLEXPORT
LIBAT_CHECK_ATTRIBUTE_ALIAS
if test x$try_ifunc = xyes; then
LIBAT_CHECK_IFUNC
fi
# Check linker support.
LIBAT_ENABLE_SYMVERS
# Cleanup and exit.
CFLAGS="$save_CFLAGS"
AC_CACHE_SAVE
# Add -Wall -Werror if we are using GCC.
if test "x$GCC" = "xyes"; then
XCFLAGS="$XCFLAGS -Wall -Werror"
fi
XCFLAGS="$XCFLAGS $XPCFLAGS"
AC_SUBST(config_path)
AC_SUBST(XCFLAGS)
AC_SUBST(XLDFLAGS)
AC_SUBST(LIBS)
AC_SUBST(SIZES)
AM_CONDITIONAL(HAVE_IFUNC, test x$libat_cv_have_ifunc = xyes)
AM_CONDITIONAL(ARCH_ARM_LINUX,
[expr "$config_path" : ".* linux/arm .*" > /dev/null])
AM_CONDITIONAL(ARCH_I386,
[test "$ARCH" = x86 && test x$libat_cv_wordsize = x4])
AM_CONDITIONAL(ARCH_X86_64,
[test "$ARCH" = x86 && test x$libat_cv_wordsize = x8])
if test ${multilib} = yes; then
multilib_arg="--enable-multilib"
else
multilib_arg=
fi
AC_CONFIG_FILES(Makefile testsuite/Makefile)
AC_OUTPUT
# -*- shell-script -*-
# Copyright (C) 2012 Free Software Foundation, Inc.
# Contributed by Richard Henderson <rth@redhat.com>.
#
# This file is part of the GNU Atomic Library (libatomic).
#
# Libatomic 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 of the License, or
# (at your option) any later version.
#
# Libatomic 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/>.
# Map the target cpu to an ARCH sub-directory. At the same time,
# work out any special compilation flags as necessary.
case "${target_cpu}" in
alpha*) ARCH=alpha ;;
rs6000 | powerpc*) ARCH=powerpc ;;
sh*) ARCH=sh ;;
arm*)
ARCH=arm
# ??? Detect when -march=armv7 is already enabled.
try_ifunc=yes
;;
sparc)
case " ${CC} ${CFLAGS} " in
*" -m64 "*)
;;
*)
if test -z "$with_cpu"; then
XCFLAGS="${XCFLAGS} -mcpu=v9"
fi
esac
ARCH=sparc
;;
sparc64|sparcv9)
case " ${CC} ${CFLAGS} " in
*" -m32 "*)
XCFLAGS="${XCFLAGS} -mcpu=v9"
;;
esac
ARCH=sparc
;;
i[3456]86)
case " ${CC} ${CFLAGS} " in
*" -m64 "*)
;;
*)
if test -z "$with_arch"; then
XCFLAGS="${XCFLAGS} -march=i486 -mtune=${target_cpu}"
XCFLAGS="${XCFLAGS} -fomit-frame-pointer"
fi
esac
ARCH=x86
# ??? Detect when -march=i686 is already enabled.
try_ifunc=yes
;;
x86_64)
case " ${CC} ${CFLAGS} " in
*" -m32 "*)
XCFLAGS="${XCFLAGS} -march=i486 -mtune=generic"
XCFLAGS="${XCFLAGS} -fomit-frame-pointer"
;;
*)
;;
esac
ARCH=x86
# ??? Detect when -mcx16 is already enabled.
try_ifunc=yes
;;
*) ARCH="${target_cpu}" ;;
esac
# The cpu configury is always most relevant.
if test -d ${srcdir}/config/$ARCH ; then
config_path="$ARCH"
fi
# Other system configury
case "${target}" in
arm*-*-linux*)
# OS support for atomic primitives.
config_path="${config_path} linux/arm posix"
;;
*-*-linux* | *-*-gnu* | *-*-k*bsd*-gnu \
| *-*-netbsd* | *-*-freebsd* | *-*-openbsd* \
| *-*-solaris2* | *-*-sysv4* | *-*-irix6* | *-*-osf* | *-*-hpux11* \
| *-*-darwin* | *-*-aix*)
# POSIX system. The OS is supported.
config_path="${config_path} posix"
;;
*-*-elf*)
# ??? No target OS. We could be targeting bare-metal kernel-mode,
# or user-mode for some custom OS. If the target supports TAS,
# we can build our own spinlocks, given there are no signals.
# If the target supports disabling interrupts, we can work in
# kernel-mode, given the system is not multi-processor.
UNSUPPORTED=1
;;
*)
# Who are you?
UNSUPPORTED=1
;;
esac
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we support the builtin, just use it. */
#if !DONE && SIZE(HAVE_ATOMIC_EXCHANGE)
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
return __atomic_exchange_n (mptr, newval, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
return __atomic_exchange_n (mptr, newval, __ATOMIC_ACQ_REL);
else
return __atomic_exchange_n (mptr, newval, __ATOMIC_SEQ_CST);
}
#define DONE 1
#endif /* HAVE_ATOMIC_EXCHANGE */
#if !DONE && defined(atomic_compare_exchange_n)
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel)
{
UTYPE oldval;
pre_barrier (smodel);
oldval = *mptr;
while (!atomic_compare_exchange_n (mptr, &oldval, newval, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED))
continue;
post_barrier (smodel);
return oldval;
}
#define DONE 1
#endif /* atomic_compare_exchange_n */
/* If this type is smaller than word-sized, fall back to a word-sized
compare-and-swap loop. */
#if !DONE && N <= WORDSIZE && defined(atomic_compare_exchange_w)
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel)
{
UWORD mask, shift, woldval, wnewval, t, *wptr;
pre_barrier (smodel);
if (N < WORDSIZE)
{
wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ SIZE(INVERT_MASK);
mask = SIZE(MASK) << shift;
}
else
{
wptr = (UWORD *)mptr;
shift = 0;
mask = -1;
}
wnewval = (UWORD)newval << shift;
woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
do
{
t = (woldval & ~mask) | wnewval;
}
while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
post_barrier (smodel);
return woldval >> shift;
}
#define DONE 1
#endif /* HAVE_ATOMIC_CAS && N < WORDSIZE */
/* Otherwise, fall back to some sort of protection mechanism. */
#if !DONE
UTYPE
SIZE(libat_exchange) (UTYPE *mptr, UTYPE newval, int smodel UNUSED)
{
UTYPE oldval;
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
oldval = *mptr;
*mptr = newval;
protect_end (mptr, magic);
post_seq_barrier (smodel);
return oldval;
}
#endif
EXPORT_ALIAS (SIZE(exchange));
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 <libatomic_i.h>
#define NAME add
#define OP(X,Y) ((X) + (Y))
/* Defer to HAVE_ATOMIC_FETCH_ADD, which some targets implement specially,
even if HAVE_ATOMIC_FETCH_OP is not defined. */
#if !SIZE(HAVE_ATOMIC_FETCH_OP)
# undef HAVE_ATOMIC_FETCH_OP_1
# undef HAVE_ATOMIC_FETCH_OP_2
# undef HAVE_ATOMIC_FETCH_OP_4
# undef HAVE_ATOMIC_FETCH_OP_8
# undef HAVE_ATOMIC_FETCH_OP_16
# define HAVE_ATOMIC_FETCH_OP_1 HAVE_ATOMIC_FETCH_ADD_1
# define HAVE_ATOMIC_FETCH_OP_2 HAVE_ATOMIC_FETCH_ADD_2
# define HAVE_ATOMIC_FETCH_OP_4 HAVE_ATOMIC_FETCH_ADD_4
# define HAVE_ATOMIC_FETCH_OP_8 HAVE_ATOMIC_FETCH_ADD_8
# define HAVE_ATOMIC_FETCH_OP_16 HAVE_ATOMIC_FETCH_ADD_16
#endif
#include "fop_n.c"
#define NAME and
#define OP(X,Y) ((X) & (Y))
#include "fop_n.c"
#define NAME or
#define OP(X,Y) ((X) | (Y))
#include "fop_n.c"
#define NAME nand
#define OP(X,Y) ~((X) & (Y))
#include "fop_n.c"
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 <libatomic_i.h>
/* This file is included multiple times with required defines:
NAME the name of the operation that we're implementing;
OP a two-operand functional macro the implements the operation.
*/
/* If we support the builtin, just use it. */
#if !DONE && SIZE(HAVE_ATOMIC_FETCH_OP)
UTYPE
SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_ACQ_REL);
else
return C2(__atomic_fetch_,NAME) (mptr, opval, __ATOMIC_SEQ_CST);
}
UTYPE
SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_ACQ_REL);
else
return C3(__atomic_,NAME,_fetch) (mptr, opval, __ATOMIC_SEQ_CST);
}
#define DONE 1
#endif /* HAVE_ATOMIC_FETCH_OP */
#if !DONE && defined(atomic_compare_exchange_n)
UTYPE
SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
{
UTYPE oldval, t;
pre_barrier (smodel);
oldval = *mptr;
do
{
t = OP(oldval, opval);
}
while (!atomic_compare_exchange_n (mptr, &oldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
post_barrier (smodel);
return oldval;
}
UTYPE
SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
{
UTYPE oldval, t;
pre_barrier (smodel);
oldval = *mptr;
do
{
t = OP(oldval, opval);
}
while (!atomic_compare_exchange_n (mptr, &oldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
post_barrier (smodel);
return t;
}
#define DONE 1
#endif /* atomic_compare_exchange_n */
/* If this type is no larger than word-sized, fall back to a word-sized
compare-and-swap loop. */
#if !DONE && N < WORDSIZE && defined(atomic_compare_exchange_w)
UTYPE
SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel)
{
UWORD mask, shift, woldval, wopval, t, *wptr;
pre_barrier (smodel);
wptr = (UWORD *)mptr;
shift = 0;
mask = -1;
wopval = (UWORD)opval << shift;
woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
do
{
t = (woldval & ~mask) | (OP(woldval, wopval) & mask);
}
while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
post_barrier (smodel);
return woldval >> shift;
}
UTYPE
SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel)
{
UWORD mask, shift, woldval, wopval, t, *wptr;
pre_barrier (smodel);
wptr = (UWORD *)mptr;
shift = 0;
mask = -1;
wopval = (UWORD)opval << shift;
woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
do
{
t = (woldval & ~mask) | (OP(woldval, wopval) & mask);
}
while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
post_barrier (smodel);
return t >> shift;
}
#define DONE 1
#endif /* atomic_compare_exchange_w */
/* Otherwise, fall back to some sort of protection mechanism. */
#if !DONE
UTYPE
SIZE(C2(libat_fetch_,NAME)) (UTYPE *mptr, UTYPE opval, int smodel UNUSED)
{
UTYPE ret;
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
ret = *mptr;
*mptr = OP(ret, opval);
protect_end (mptr, magic);
post_seq_barrier (smodel);
return ret;
}
UTYPE
SIZE(C3(libat_,NAME,_fetch)) (UTYPE *mptr, UTYPE opval, int smodel UNUSED)
{
UTYPE ret;
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
ret = OP (*mptr, opval);
*mptr = ret;
protect_end (mptr, magic);
post_seq_barrier (smodel);
return ret;
}
#endif
EXPORT_ALIAS (SIZE(C2(fetch_,NAME)));
EXPORT_ALIAS (SIZE(C2(NAME,_fetch)));
#define NAME sub
#define OP(X,Y) ((X) - (Y))
#include "fop_n.c"
#define NAME xor
#define OP(X,Y) ((X) ^ (Y))
#include "fop_n.c"
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we natively support the cas, and if we're unconcerned with extra
barriers (e.g. fully in-order cpu for which barriers are a nop), then
go ahead and expand the operation inline. */
#if !defined(WANT_SPECIALCASE_RELAXED) && !defined(__OPTIMIZE_SIZE__)
# define EXACT_INLINE(N) \
if (C2(HAVE_ATOMIC_CAS_,N)) \
return __atomic_compare_exchange_n \
(PTR(N,mptr), PTR(N,eptr), *PTR(N,dptr), false, smodel, fmodel)
#else
# define EXACT_INLINE(N)
#endif
/* ... and if all that fails, invoke the function we generated elsewhere.
Worst case, this will *also* use locks. */
#define EXACT(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if ((uintptr_t)mptr & (N - 1)) break; \
EXACT_INLINE (N); \
return C3(local_,compare_exchange_,N) \
(PTR(N,mptr), PTR(N,eptr), *PTR(N,dptr), smodel, fmodel); \
} while (0)
#define LARGER(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if (!C2(HAVE_ATOMIC_LDST_,N)) break; \
if (!C2(MAYBE_HAVE_ATOMIC_CAS_,N)) break; \
r = (uintptr_t)mptr & (N - 1); \
a = (uintptr_t)mptr & -N; \
if (r + n <= N) \
{ \
pre_barrier (smodel); \
u.C2(i,N) = __atomic_load_n (PTR(N,a), __ATOMIC_RELAXED); \
do { \
if (memcmp (u.b + r, eptr, n) != 0) goto Lfail; \
v = u; memcpy (v.b + r, dptr, n); \
} while (!(C2(HAVE_ATOMIC_CAS_,N) \
? __atomic_compare_exchange_n (PTR(N,a), \
&u.C2(i,N), v.C2(i,N), true, \
__ATOMIC_RELAXED, __ATOMIC_RELAXED) \
: C3(local_,compare_exchange_,N) (PTR(N,a), \
&u.C2(i,N), v.C2(i,N), \
__ATOMIC_RELAXED, __ATOMIC_RELAXED))); \
goto Lsucc; \
} \
} while (0)
bool
libat_compare_exchange (size_t n, void *mptr, void *eptr, void *dptr,
int smodel, int fmodel)
{
union max_size_u u, v;
uintptr_t r, a;
bool ret;
switch (n)
{
case 0: return true;
case 1: EXACT(1); goto L4;
case 2: EXACT(2); goto L4;
case 4: EXACT(4); goto L8;
case 8: EXACT(8); goto L16;
case 16: EXACT(16); break;
case 3: L4: LARGER(4); /* FALLTHRU */
case 5 ... 7: L8: LARGER(8); /* FALLTHRU */
case 9 ... 15: L16: LARGER(16); break;
Lsucc:
post_barrier (smodel);
return true;
Lfail:
post_barrier (fmodel);
memcpy (eptr, u.b + r, n);
return false;
}
pre_seq_barrier (smodel);
libat_lock_n (mptr, n);
ret = memcmp (mptr, eptr, n) == 0;
memcpy ((ret ? mptr : eptr), (ret ? dptr : mptr), n);
libat_unlock_n (mptr, n);
post_seq_barrier (ret ? smodel : fmodel);
return ret;
}
EXPORT_ALIAS (compare_exchange);
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we natively support the exchange, and if we're unconcerned with extra
barriers (e.g. fully in-order cpu for which barriers are a nop), then
go ahead and expand the operation inline. */
#if !defined(WANT_SPECIALCASE_RELAXED) && !defined(__OPTIMIZE_SIZE__)
# define EXACT_INLINE(N) \
if (C2(HAVE_ATOMIC_EXCHANGE_,N)) \
{ \
*PTR(N,rptr) = __atomic_exchange_n \
(PTR(N,mptr), *PTR(N,vptr), smodel); \
return; \
}
#else
# define EXACT_INLINE(N)
#endif
#define EXACT(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if ((uintptr_t)mptr & (N - 1)) break; \
EXACT_INLINE (N); \
*PTR(N,rptr) = C3(local_,exchange_,N) \
(PTR(N,mptr), *PTR(N,vptr), smodel); \
return; \
} while (0)
#define LARGER(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if (!C2(MAYBE_HAVE_ATOMIC_CAS_,N)) break; \
r = (uintptr_t)mptr & (N - 1); \
a = (uintptr_t)mptr & -N; \
if (r + n <= N) \
{ \
pre_barrier (smodel); \
u.C2(i,N) = *PTR(N,a); \
do { \
v = u; \
memcpy (v.b + r, vptr, n); \
} while (!(C2(HAVE_ATOMIC_CAS_,N) \
? __atomic_compare_exchange_n (PTR(N,a), \
&u.C2(i,N), v.C2(i,N), true, \
__ATOMIC_RELAXED, __ATOMIC_RELAXED) \
: C3(local_,compare_exchange_,N) (PTR(N,a), \
&u.C2(i,N), v.C2(i,N), \
__ATOMIC_RELAXED, __ATOMIC_RELAXED))); \
goto Lfinish; \
} \
} while (0)
static void __attribute__((noinline))
libat_exchange_large_inplace (size_t n, void *mptr, void *vptr)
{
#define BUF 1024
char temp[BUF];
size_t i = 0;
for (i = 0; n >= BUF; i += BUF, n -= BUF)
{
memcpy (temp, mptr + i, BUF);
memcpy (mptr + i, vptr + i, BUF);
memcpy (vptr + i, temp, BUF);
}
if (n > 0)
{
memcpy (temp, mptr + i, n);
memcpy (mptr + i, vptr + i, n);
memcpy (vptr + i, temp, n);
}
#undef BUF
}
void
libat_exchange (size_t n, void *mptr, void *vptr, void *rptr, int smodel)
{
union max_size_u u, v;
uintptr_t r, a;
switch (n)
{
case 0: return;
case 1: EXACT(1); goto L4;
case 2: EXACT(2); goto L4;
case 4: EXACT(4); goto L8;
case 8: EXACT(8); goto L16;
case 16: EXACT(16); break;
case 3: L4: LARGER(4); /* FALLTHRU */
case 5 ... 7: L8: LARGER(8); /* FALLTHRU */
case 9 ... 15: L16: LARGER(16); break;
Lfinish:
post_barrier (smodel);
memcpy (rptr, u.b + r, n);
return;
}
pre_seq_barrier (smodel);
libat_lock_n (mptr, n);
if (vptr != rptr)
{
memcpy (rptr, mptr, n);
memcpy (mptr, vptr, n);
}
else
libat_exchange_large_inplace (n, mptr, vptr);
libat_unlock_n (mptr, n);
post_seq_barrier (smodel);
}
EXPORT_ALIAS (exchange);
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
#define EXACT(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if ((uintptr_t)ptr & (N - 1)) break; \
if (__atomic_always_lock_free(N, 0)) return true; \
if (C2(MAYBE_HAVE_ATOMIC_CAS_,N)) return true; \
} while (0)
#define LARGER(N) \
do { \
uintptr_t r = (uintptr_t)ptr & (N - 1); \
if (!C2(HAVE_INT,N)) break; \
if (!C2(HAVE_ATOMIC_LDST_,N)) break; \
if (!C2(MAYBE_HAVE_ATOMIC_CAS_,N)) break; \
if (r + n <= N) return true; \
} while (0)
bool
libat_is_lock_free (size_t n, void *ptr)
{
switch (n)
{
case 0: return true;
case 1: EXACT(1); goto L4;
case 2: EXACT(2); goto L4;
case 4: EXACT(4); goto L8;
case 8: EXACT(8); goto L16;
case 16: EXACT(16); break;
case 3: L4: LARGER(4); /* FALLTHRU */
case 5 ... 7: L8: LARGER(8); /* FALLTHRU */
case 9 ... 15: L16: LARGER(16); break;
}
return false;
}
EXPORT_ALIAS (is_lock_free);
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we natively support the load, and if we're unconcerned with extra
barriers (e.g. fully in-order cpu for which barriers are a nop), then
go ahead and expand the operation inline. */
#if !defined(WANT_SPECIALCASE_RELAXED) && !defined(__OPTIMIZE_SIZE__)
# define EXACT_INLINE(N, DEST, SRC, DONE) \
if (C2(HAVE_ATOMIC_LDST_,N)) \
{ \
DEST = __atomic_load_n (SRC, smodel); \
DONE; \
}
#else
# define EXACT_INLINE(N, DEST, SRC, DONE)
#endif
#define EXACT_(N, DEST, SRC, DONE) \
do { \
EXACT_INLINE (N, DEST, SRC, DONE); \
DEST = C3(local_,load_,N) (SRC, smodel); \
DONE; \
} while (0)
#define EXACT(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if ((uintptr_t)mptr & (N - 1)) break; \
EXACT_(N, *PTR(N,rptr), PTR(N,mptr), return); \
} while (0)
#define LARGER(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
r = (uintptr_t)mptr & (N - 1); \
a = (uintptr_t)mptr & -N; \
if (r + n <= N) \
EXACT_ (N, u.C2(i,N), PTR(N,a), goto Lfinish); \
} while (0)
void
libat_load (size_t n, void *mptr, void *rptr, int smodel)
{
union max_size_u u;
uintptr_t r, a;
switch (n)
{
case 0: return;
case 1: EXACT(1); goto L4;
case 2: EXACT(2); goto L4;
case 4: EXACT(4); goto L8;
case 8: EXACT(8); goto L16;
case 16: EXACT(16); break;
case 3: L4: LARGER(4); /* FALLTHRU */
case 5 ... 7: L8: LARGER(8); /* FALLTHRU */
case 9 ... 15: L16: LARGER(16); break;
Lfinish:
memcpy (rptr, u.b + r, n);
return;
}
pre_seq_barrier (smodel);
libat_lock_n (mptr, n);
memcpy (rptr, mptr, n);
libat_unlock_n (mptr, n);
post_seq_barrier (smodel);
}
EXPORT_ALIAS (load);
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we natively support the store, and if we're unconcerned with extra
barriers (e.g. fully in-order cpu for which barriers are a nop), then
go ahead and expand the operation inline. */
#if !defined(WANT_SPECIALCASE_RELAXED) && !defined(__OPTIMIZE_SIZE__)
# define EXACT_INLINE(N) \
if (C2(HAVE_ATOMIC_LDST_,N)) \
{ \
__atomic_store_n (PTR(N,mptr), *PTR(N,vptr), smodel); \
return; \
}
#else
# define EXACT_INLINE(N)
#endif
#define EXACT(N) \
do { \
if (!C2(HAVE_INT,N)) break; \
if ((uintptr_t)mptr & (N - 1)) break; \
EXACT_INLINE (N); \
C3(local_,store_,N) (PTR(N,mptr), *PTR(N,vptr), smodel); \
return; \
} while (0)
#define LARGER(N) \
do { \
union max_size_u u, v; \
uintptr_t r, a; \
if (!C2(HAVE_INT,N)) break; \
if (!C2(MAYBE_HAVE_ATOMIC_CAS_,N)) break; \
r = (uintptr_t)mptr & (N - 1); \
a = (uintptr_t)mptr & -N; \
if (r + n <= N) \
{ \
pre_barrier (smodel); \
/* This load need not be atomic, as the CAS \
below will validate it. */ \
u.C2(i,N) = *PTR(N,a); \
do { \
v = u; memcpy (v.b + r, vptr, n); \
} while (!(C2(HAVE_ATOMIC_CAS_,N) \
? __atomic_compare_exchange_n (PTR(N,a), \
&u.C2(i,N), v.C2(i,N), true, \
__ATOMIC_RELAXED, __ATOMIC_RELAXED) \
: C3(local_,compare_exchange_,N) (PTR(N,a), \
&u.C2(i,N), v.C2(i,N), \
__ATOMIC_RELAXED, __ATOMIC_RELAXED))); \
post_barrier (smodel); \
return; \
} \
} while (0)
void
libat_store (size_t n, void *mptr, void *vptr, int smodel)
{
switch (n)
{
case 0: return;
case 1: EXACT(1); goto L4;
case 2: EXACT(2); goto L4;
case 4: EXACT(4); goto L8;
case 8: EXACT(8); goto L16;
case 16: EXACT(16); break;
case 3: L4: LARGER(4); /* FALLTHRU */
case 5 ... 7: L8: LARGER(8); /* FALLTHRU */
case 9 ... 15: L16: LARGER(16); break;
}
pre_seq_barrier (smodel);
libat_lock_n (mptr, n);
memcpy (mptr, vptr, n);
libat_unlock_n (mptr, n);
post_seq_barrier (smodel);
}
EXPORT_ALIAS (store);
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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/>. */
/* Included after all more target-specific host-config.h. */
/* The target may have some OS specific way to implement compare-and-swap. */
#if !defined(atomic_compare_exchange_n) && SIZE(HAVE_ATOMIC_CAS)
# define atomic_compare_exchange_n __atomic_compare_exchange_n
#endif
#if !defined(atomic_compare_exchange_w) && WSIZE(HAVE_ATOMIC_CAS)
# define atomic_compare_exchange_w __atomic_compare_exchange_n
#endif
/* For some targets, it may be significantly faster to avoid all barriers
if the user only wants relaxed memory order. Sometimes we don't want
the extra code bloat. In all cases, use the input to avoid warnings. */
#if defined(WANT_SPECIALCASE_RELAXED) && !defined(__OPTIMIZE_SIZE__)
# define maybe_specialcase_relaxed(x) ((x) == __ATOMIC_RELAXED)
#else
# define maybe_specialcase_relaxed(x) ((x) & 0)
#endif
/* Similar, but for targets for which the seq_cst model is sufficiently
more expensive than the acq_rel model. */
#if defined(WANT_SPECIALCASE_ACQREL) && !defined(__OPTIMIZE_SIZE__)
# define maybe_specialcase_acqrel(x) ((x) != __ATOMIC_SEQ_CST)
#else
# define maybe_specialcase_acqrel(x) ((x) & 0)
#endif
/* The target may have some OS specific way to emit barriers. */
#ifndef pre_post_barrier
static inline void __attribute__((always_inline, artificial))
pre_barrier(int model)
{
if (!maybe_specialcase_relaxed(model))
{
if (maybe_specialcase_acqrel(model))
__atomic_thread_fence (__ATOMIC_ACQ_REL);
else
__atomic_thread_fence (__ATOMIC_SEQ_CST);
}
}
static inline void __attribute__((always_inline, artificial))
post_barrier(int model)
{
pre_barrier(model);
}
#define pre_post_barrier 1
#endif /* pre_post_barrier */
/* Similar, but assume that acq_rel is already handled via locks. */
#ifndef pre_post_seq_barrier
static inline void __attribute__((always_inline, artificial))
pre_seq_barrier(int model)
{
}
static inline void __attribute__((always_inline, artificial))
post_seq_barrier(int model)
{
}
#define pre_post_seq_barrier 1
#endif
/* No runtime initialization needed. */
LIBATOMIC_1.0 {
global:
__atomic_load;
__atomic_store;
__atomic_exchange;
__atomic_compare_exchange;
__atomic_is_lock_free;
__atomic_add_fetch_1;
__atomic_add_fetch_2;
__atomic_add_fetch_4;
__atomic_add_fetch_8;
__atomic_add_fetch_16;
__atomic_and_fetch_1;
__atomic_and_fetch_2;
__atomic_and_fetch_4;
__atomic_and_fetch_8;
__atomic_and_fetch_16;
__atomic_compare_exchange_1;
__atomic_compare_exchange_2;
__atomic_compare_exchange_4;
__atomic_compare_exchange_8;
__atomic_compare_exchange_16;
__atomic_exchange_1;
__atomic_exchange_2;
__atomic_exchange_4;
__atomic_exchange_8;
__atomic_exchange_16;
__atomic_fetch_add_1;
__atomic_fetch_add_2;
__atomic_fetch_add_4;
__atomic_fetch_add_8;
__atomic_fetch_add_16;
__atomic_fetch_and_1;
__atomic_fetch_and_2;
__atomic_fetch_and_4;
__atomic_fetch_and_8;
__atomic_fetch_and_16;
__atomic_fetch_nand_1;
__atomic_fetch_nand_2;
__atomic_fetch_nand_4;
__atomic_fetch_nand_8;
__atomic_fetch_nand_16;
__atomic_fetch_or_1;
__atomic_fetch_or_2;
__atomic_fetch_or_4;
__atomic_fetch_or_8;
__atomic_fetch_or_16;
__atomic_fetch_sub_1;
__atomic_fetch_sub_2;
__atomic_fetch_sub_4;
__atomic_fetch_sub_8;
__atomic_fetch_sub_16;
__atomic_fetch_xor_1;
__atomic_fetch_xor_2;
__atomic_fetch_xor_4;
__atomic_fetch_xor_8;
__atomic_fetch_xor_16;
__atomic_load_1;
__atomic_load_2;
__atomic_load_4;
__atomic_load_8;
__atomic_load_16;
__atomic_nand_fetch_1;
__atomic_nand_fetch_2;
__atomic_nand_fetch_4;
__atomic_nand_fetch_8;
__atomic_nand_fetch_16;
__atomic_or_fetch_1;
__atomic_or_fetch_2;
__atomic_or_fetch_4;
__atomic_or_fetch_8;
__atomic_or_fetch_16;
__atomic_store_1;
__atomic_store_2;
__atomic_store_4;
__atomic_store_8;
__atomic_store_16;
__atomic_sub_fetch_1;
__atomic_sub_fetch_2;
__atomic_sub_fetch_4;
__atomic_sub_fetch_8;
__atomic_sub_fetch_16;
__atomic_test_and_set_1;
__atomic_test_and_set_2;
__atomic_test_and_set_4;
__atomic_test_and_set_8;
__atomic_test_and_set_16;
__atomic_xor_fetch_1;
__atomic_xor_fetch_2;
__atomic_xor_fetch_4;
__atomic_xor_fetch_8;
__atomic_xor_fetch_16;
local:
*;
};
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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.
Libatomic 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/>. */
/* This file contains data types and function declarations that are
private to the implementation of libatomic. */
#ifndef LIBATOMIC_H
#define LIBATOMIC_H 1
#include "auto-config.h"
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <string.h>
/* Symbol concatenation macros. */
#define C2_(X,Y) X ## Y
#define C2(X,Y) C2_(X,Y)
#define C3_(X,Y,Z) X ## Y ## Z
#define C3(X,Y,Z) C3_(X,Y,Z)
#define C4_(W,X,Y,Z) W ## X ## Y ## Z
#define C4(W,X,Y,Z) C4_(W,X,Y,Z)
/* Stringification macros. */
#define S2(X) #X
#define S(X) S2(X)
/* All of the primitive types on which we operate. */
typedef unsigned U_1 __attribute__((mode(QI)));
#if HAVE_INT2
typedef unsigned U_2 __attribute__((mode(HI)));
#endif
#if HAVE_INT4
typedef unsigned U_4 __attribute__((mode(SI)));
#endif
#if HAVE_INT8
typedef unsigned U_8 __attribute__((mode(DI)));
#endif
#if HAVE_INT16
typedef unsigned U_16 __attribute__((mode(TI)));
#endif
/* The widest type that we support. */
#if HAVE_INT16
# define MAX_SIZE 16
#elif HAVE_INT8
# define MAX_SIZE 8
#elif HAVE_INT4
# define MAX_SIZE 4
#elif HAVE_INT2
# define MAX_SIZE 2
#else
# define MAX_SIZE 1
#endif
typedef C2(U_,MAX_SIZE) U_MAX;
/* Provide dummy fallback types so that stuff is syntactically correct
without having to overdo the ifdefs. The code using these should
always be protected with the HAVE_INT{n} macros. */
#if !HAVE_INT2
typedef U_MAX U_2;
#endif
#if !HAVE_INT4
typedef U_MAX U_4;
#endif
#if !HAVE_INT8
typedef U_MAX U_8;
#endif
#if !HAVE_INT16
typedef U_MAX U_16;
#endif
union max_size_u
{
U_1 b[MAX_SIZE];
U_2 i2;
U_4 i4;
U_8 i8;
U_16 i16;
};
/* The "word" size of the machine. */
typedef unsigned UWORD __attribute__((mode(word)));
/* Macros for handing sub-word sized quantities. */
#define MASK_1 ((UWORD)0xff)
#define MASK_2 ((UWORD)0xffff)
#define MASK_4 ((UWORD)0xffffffff)
#define INVERT_MASK_1 ((UWORD)WORDS_BIGENDIAN << ((WORDSIZE - 1) * CHAR_BIT))
#define INVERT_MASK_2 ((UWORD)WORDS_BIGENDIAN << ((WORDSIZE - 2) * CHAR_BIT))
#define INVERT_MASK_4 ((UWORD)WORDS_BIGENDIAN << ((WORDSIZE - 4) * CHAR_BIT))
/* Most of the files in this library are compiled multiple times with
N defined to be a power of 2 between 1 and 16. The SIZE macro is
then used to append _N to the symbol being manipulated. */
#define SIZE(X) C3(X,_,N)
#define WSIZE(X) C3(X,_,WORDSIZE)
#define PTR(N,X) ((C2(U_,N) *)X)
/* And thus, the type on which this compilation will be operating. */
#define ITYPE SIZE(I)
#define UTYPE SIZE(U)
/* Utility macros for GCC attributes. */
#define UNUSED __attribute__((unused))
#ifdef HAVE_ATTRIBUTE_VISIBILITY
# define HIDDEN __attribute__((visibility("hidden")))
#else
# define HIDDEN
#endif
/* Occasionally we have to play games with internal and external symbol
names, in order to work around builtin functions of the same name.
This macro sets the external name of the function appropriately. */
#define ASMNAME(X) __asm__(S(C2(__USER_LABEL_PREFIX__,X)))
/* Locking for a "small" operation. In the bare-metal single processor
cases this could be implemented by disabling interrupts. Thus the extra
word passed between the two functions, saving the interrupt level.
It is assumed that the object being locked does not cross the locking
granularity.
Not actually declared here so that they can be defined static inline
in a target-specfic <host-config.h>.
UWORD protect_start (void *ptr);
void protect_end (void *ptr, UWORD);
*/
/* Locking for a "large' operation. This should always be some sort of
test-and-set operation, as we assume that the interrupt latency would
be unreasonably large. */
void libat_lock_n (void *ptr, size_t n);
void libat_unlock_n (void *ptr, size_t n);
/* We'll need to declare all of the sized functions a few times... */
#define DECLARE_ALL_SIZED(N) DECLARE_ALL_SIZED_(N,C2(U_,N))
#define DECLARE_ALL_SIZED_(N,T) \
DECLARE_1(T, C2(load_,N), (T *mptr, int)); \
DECLARE_1(void, C2(store_,N), (T *mptr, T val, int)); \
DECLARE_1(T, C2(exchange_,N), (T *mptr, T, int)); \
DECLARE_1(bool, C2(compare_exchange_,N), (T *mptr, T *, T, int, int)); \
DECLARE_1(bool, C2(test_and_set_,N), (T *mptr, int)); \
DECLARE_1(T, C2(fetch_add_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(fetch_sub_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(fetch_and_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(fetch_xor_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(fetch_or_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(fetch_nand_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(add_fetch_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(sub_fetch_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(and_fetch_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(xor_fetch_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(or_fetch_,N), (T *mptr, T, int)); \
DECLARE_1(T, C2(nand_fetch_,N), (T *mptr, T, int))
/* All sized operations are implemented in hidden functions prefixed with
"libat_". These are either renamed or aliased to the expected prefix
of "__atomic". Some amount of renaming is required to avoid hiding or
conflicting with the builtins of the same name, but this additional
use of hidden symbols (where appropriate) avoids unnecessary PLT entries
on relevant targets. */
#if IFUNC_ALT
# define MAN(X) ASMNAME(C4(libat_,X,_i,IFUNC_ALT)) HIDDEN
#elif defined(HAVE_ATTRIBUTE_ALIAS)
# define MAN(X) HIDDEN
#else
# define MAN(X) ASMNAME(C2(__atomic_,X))
#endif
#if !defined(N) && HAVE_IFUNC
# define DECLARE_1(RET,NAME,ARGS) \
RET C2(libat_,NAME) ARGS MAN(NAME); \
RET C2(ifunc_,NAME) ARGS ASMNAME(C2(__atomic_,NAME))
#else
# define DECLARE_1(RET,NAME,ARGS) RET C2(libat_,NAME) ARGS MAN(NAME)
#endif
/* Prefix to use when calling internal, possibly ifunc'ed functions. */
#if HAVE_IFUNC
# define local_ ifunc_
#else
# define local_ libat_
#endif
DECLARE_ALL_SIZED(1);
DECLARE_ALL_SIZED(2);
DECLARE_ALL_SIZED(4);
DECLARE_ALL_SIZED(8);
DECLARE_ALL_SIZED(16);
#undef DECLARE_1
#undef DECLARE_ALL_SIZED
#undef DECLARE_ALL_SIZED_
/* And the generic sized versions. */
void libat_load (size_t, void *, void *, int) MAN(load);
void libat_store (size_t, void *, void *, int) MAN(store);
void libat_exchange (size_t, void *, void *, void *, int) MAN(exchange);
bool libat_compare_exchange (size_t, void *, void *, void *, int, int)
MAN(compare_exchange);
bool libat_is_lock_free (size_t, void *) MAN(is_lock_free);
#undef MAN
#include <host-config.h>
/* We don't have IFUNC_NCOND until after host-config.h. */
#if !HAVE_IFUNC
# define IFUNC_NCOND(N) 0
#endif
#if IFUNC_ALT
# define EXPORT_ALIAS(X) /* exported symbol in non-alternate file */
#elif defined(N) && IFUNC_NCOND(N)
# if IFUNC_NCOND(N) == 1
# define GEN_SELECTOR(X) \
extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \
static void * C2(select_,X) (void) \
{ \
if (IFUNC_COND_1) \
return C3(libat_,X,_i1); \
return C2(libat_,X); \
}
# elif IFUNC_NCOND(N) == 2
# define GEN_SELECTOR(X) \
extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \
extern typeof(C2(libat_,X)) C3(libat_,X,_i2) HIDDEN; \
static void * C2(select_,X) (void) \
{ \
if (IFUNC_COND_1) \
return C3(libat_,X,_i1); \
if (IFUNC_COND_2) \
return C3(libat_,X,_i2); \
return C2(libat_,X); \
}
# elif IFUNC_NCOND(N) == 3
# define GEN_SELECTOR(X) \
extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \
extern typeof(C2(libat_,X)) C3(libat_,X,_i2) HIDDEN; \
extern typeof(C2(libat_,X)) C3(libat_,X,_i3) HIDDEN; \
static void * C2(select_,X) (void) \
{ \
if (IFUNC_COND_1) \
return C3(libat_,X,_i1); \
if (IFUNC_COND_2) \
return C3(libat_,X,_i2); \
if (IFUNC_COND_3) \
return C3(libat_,X,_i3); \
return C2(libat_,X); \
}
# else
# error "Unsupported number of ifunc alternatives."
# endif
# define EXPORT_ALIAS(X) \
GEN_SELECTOR(X) \
typeof(C2(libat_,X)) C2(ifunc_,X) \
ASMNAME(C2(__atomic_,X)) \
__attribute__((ifunc(S(C2(select_,X)))))
#elif defined(HAVE_ATTRIBUTE_ALIAS)
# define EXPORT_ALIAS(X) \
extern typeof(C2(libat_,X)) C2(export_,X) \
ASMNAME(C2(__atomic_,X)) \
__attribute__((alias(S(C2(libat_,X)))))
#else
# define EXPORT_ALIAS(X) /* original symbol is exported */
#endif
#endif /* LIBATOMIC_H */
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we support the builtin, just use it. */
#if !DONE && SIZE(HAVE_ATOMIC_LDST)
UTYPE
SIZE(libat_load) (UTYPE *mptr, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
return __atomic_load_n (mptr, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
/* Note that REL and ACQ_REL are not valid for loads. */
return __atomic_load_n (mptr, __ATOMIC_ACQUIRE);
else
return __atomic_load_n (mptr, __ATOMIC_SEQ_CST);
}
#define DONE 1
#endif /* HAVE_ATOMIC_LOAD */
/* If we have compare-and-swap, use it to swap 0 with 0 and as a side
effect load the original value. */
#if !DONE && defined(atomic_compare_exchange_n)
UTYPE
SIZE(libat_load) (UTYPE *mptr, int smodel)
{
UTYPE t = 0;
if (maybe_specialcase_relaxed(smodel))
atomic_compare_exchange_n (mptr, &t, 0, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
atomic_compare_exchange_n (mptr, &t, 0, true,
__ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
else
atomic_compare_exchange_n (mptr, &t, 0, true,
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
return t;
}
#define DONE 1
#endif /* atomic_compare_exchange_n */
/* Similar, but only assume a word-sized compare-and-swap. */
#if !DONE && N < WORDSIZE && defined(atomic_compare_exchange_w)
UTYPE
SIZE(libat_load) (UTYPE *mptr, int smodel)
{
UWORD shift, t, *wptr;
pre_barrier (smodel);
wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ SIZE(INVERT_MASK);
/* Exchange 0 with 0, placing the old value of *WPTR in T. */
t = 0;
atomic_compare_exchange_w (wptr, &t, 0);
post_barrier (smodel);
return t >> shift;
}
#define DONE 1
#endif /* HAVE_ATOMIC_CAS && N < WORDSIZE */
/* Otherwise, fall back to some sort of protection mechanism. */
#if !DONE
UTYPE
SIZE(libat_load) (UTYPE *mptr, int smodel)
{
UTYPE ret;
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
ret = *mptr;
protect_end (mptr, magic);
post_seq_barrier (smodel);
return ret;
}
#endif
EXPORT_ALIAS (SIZE(load));
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we support the builtin, just use it. */
#if !DONE && SIZE(HAVE_ATOMIC_LDST)
void
SIZE(libat_store) (UTYPE *mptr, UTYPE newval, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
__atomic_store_n (mptr, newval, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
/* Note that ACQ and ACQ_REL are not valid for store. */
__atomic_store_n (mptr, newval, __ATOMIC_RELEASE);
else
__atomic_store_n (mptr, newval, __ATOMIC_SEQ_CST);
}
#define DONE 1
#endif /* HAVE_ATOMIC_STORE */
/* If we have compare-and-swap, use it perform the store. */
#if !DONE && defined(atomic_compare_exchange_n)
void
SIZE(libat_store) (UTYPE *mptr, UTYPE newval, int smodel)
{
UTYPE oldval;
pre_barrier (smodel);
oldval = *mptr;
while (!atomic_compare_exchange_n (mptr, &oldval, newval, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED))
continue;
post_barrier (smodel);
}
#define DONE 1
#endif /* atomic_compare_exchange_n */
/* If this type is smaller than word-sized, fall back to a word-sized
compare-and-swap loop. */
#if !DONE && N < WORDSIZE && defined(atomic_compare_exchange_w)
void
SIZE(libat_store) (UTYPE *mptr, UTYPE newval, int smodel)
{
UWORD mask, shift, woldval, wnewval, t, *wptr;
pre_barrier (smodel);
wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
shift = (((uintptr_t)mptr % WORDSIZE) * CHAR_BIT) ^ SIZE(INVERT_MASK);
mask = SIZE(MASK) << shift;
wnewval = (UWORD)newval << shift;
woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
do
{
t = (woldval & ~mask) | wnewval;
}
while (!atomic_compare_exchange_w (wptr, &woldval, t));
post_barrier (smodel);
}
#define DONE 1
#endif /* N < WORDSIZE && atomic_compare_exchange_w */
/* Otherwise, fall back to some sort of protection mechanism. */
#if !DONE
void
SIZE(libat_store) (UTYPE *mptr, UTYPE newval, int smodel)
{
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
*mptr = newval;
protect_end (mptr, magic);
post_seq_barrier (smodel);
}
#endif
EXPORT_ALIAS (SIZE(store));
/* Copyright (C) 2012 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>.
This file is part of the GNU Atomic Library (libatomic).
Libatomic 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 of the License, or
(at your option) any later version.
Libatomic 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 "libatomic_i.h"
/* If we support the builtin, just use it. */
#if !DONE && SIZE(HAVE_ATOMIC_TAS)
bool
SIZE(libat_test_and_set) (UTYPE *mptr, int smodel)
{
if (maybe_specialcase_relaxed(smodel))
return __atomic_test_and_set (mptr, __ATOMIC_RELAXED);
else if (maybe_specialcase_acqrel(smodel))
return __atomic_test_and_set (mptr, __ATOMIC_ACQ_REL);
else
return __atomic_test_and_set (mptr, __ATOMIC_SEQ_CST);
}
#define DONE 1
#endif /* HAVE_ATOMIC_TAS */
/* If this type is smaller than word-sized, fall back to a word-sized
compare-and-swap loop. */
#if !DONE && N <= WORDSIZE && defined(atomic_compare_exchange_w)
bool
SIZE(libat_test_and_set) (UTYPE *mptr, int smodel)
{
UWORD wval, woldval, shift, *wptr, t;
pre_barrier (smodel);
if (N < WORDSIZE)
{
wptr = (UWORD *)((uintptr_t)mptr & -WORDSIZE);
shift = SIZE(INVERT_MASK);
}
else
{
wptr = (UWORD *)mptr;
shift = 0;
}
wval = (UWORD)__GCC_ATOMIC_TEST_AND_SET_TRUEVAL << shift;
woldval = __atomic_load_n (wptr, __ATOMIC_RELAXED);
do
{
t = woldval | wval;
}
while (!atomic_compare_exchange_w (wptr, &woldval, t, true,
__ATOMIC_RELAXED, __ATOMIC_RELAXED));
post_barrier (smodel);
return woldval != 0;
}
#define DONE 1
#endif /* HAVE_ATOMIC_CAS && N < WORDSIZE */
/* Otherwise, fall back to some sort of protection mechanism. */
#if !DONE && N == 1
bool
SIZE(libat_test_and_set) (UTYPE *mptr, int smodel)
{
UTYPE oldval, newval;
UWORD magic;
pre_seq_barrier (smodel);
magic = protect_start (mptr);
oldval = *mptr;
*mptr = __GCC_ATOMIC_TEST_AND_SET_TRUEVAL;
protect_end (mptr, magic);
post_seq_barrier (smodel);
return ret != 0;
}
#define DONE 1
#endif /* N == 1 */
#if !DONE
bool
SIZE(libat_test_and_set) (UTYPE *mptr, int smodel UNUSED)
{
return libat_test_and_set_1 ((U_1 *)mptr, smodel);
}
#endif
EXPORT_ALIAS (SIZE(test_and_set));
## Process this file with automake to produce Makefile.in.
AUTOMAKE_OPTIONS = foreign dejagnu
# May be used by various substitution variables.
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
EXPECT = $(shell if test -f $(top_builddir)/../expect/expect; then \
echo $(top_builddir)/../expect/expect; else echo expect; fi)
_RUNTEST = $(shell if test -f $(top_srcdir)/../dejagnu/runtest; then \
echo $(top_srcdir)/../dejagnu/runtest; else echo runtest; fi)
RUNTEST = "$(_RUNTEST) $(AM_RUNTESTFLAGS)"
# Copyright (C) 2011 Free Software Foundation, Inc.
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
load_lib "standard.exp"
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
proc libatomic-dg-test { prog do_what extra_tool_flags } {
return [gcc-dg-test-1 libatomic_target_compile $prog $do_what $extra_tool_flags]
}
proc libatomic-dg-prune { system text } {
return [gcc-dg-prune $system $text]
}
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# Damn dejagnu for not having proper library search paths for load_lib.
# We have to explicitly load everything that gcc-dg.exp wants to load.
proc load_gcc_lib { filename } {
global srcdir loaded_libs
load_file $srcdir/../../gcc/testsuite/lib/$filename
set loaded_libs($filename) ""
}
load_lib dg.exp
load_gcc_lib file-format.exp
load_gcc_lib target-supports.exp
load_gcc_lib target-supports-dg.exp
load_gcc_lib scanasm.exp
load_gcc_lib scandump.exp
load_gcc_lib scanrtl.exp
load_gcc_lib scantree.exp
load_gcc_lib scanipa.exp
load_gcc_lib prune.exp
load_gcc_lib target-libpath.exp
load_gcc_lib wrapper.exp
load_gcc_lib gcc-defs.exp
load_gcc_lib torture-options.exp
load_gcc_lib timeout.exp
load_gcc_lib timeout-dg.exp
load_gcc_lib fortran-modules.exp
load_gcc_lib gcc-dg.exp
set dg-do-what-default run
#
# GCC_UNDER_TEST is the compiler under test.
#
set libatomic_compile_options ""
#
# libatomic_init
#
if [info exists TOOL_OPTIONS] {
set multilibs [get_multilibs $TOOL_OPTIONS]
} else {
set multilibs [get_multilibs]
}
proc libatomic_init { args } {
global srcdir blddir objdir tool_root_dir
global libatomic_initialized
global tmpdir
global blddir
global gluefile wrap_flags
global ALWAYS_CFLAGS
global CFLAGS
global TOOL_EXECUTABLE TOOL_OPTIONS
global GCC_UNDER_TEST
global TESTING_IN_BUILD_TREE
global target_triplet
global always_ld_library_path
set blddir [lookfor_file [get_multilibs] libatomic]
# We set LC_ALL and LANG to C so that we get the same error
# messages as expected.
setenv LC_ALL C
setenv LANG C
if ![info exists GCC_UNDER_TEST] then {
if [info exists TOOL_EXECUTABLE] {
set GCC_UNDER_TEST $TOOL_EXECUTABLE
} else {
set GCC_UNDER_TEST "[find_gcc]"
}
}
if ![info exists tmpdir] {
set tmpdir "/tmp"
}
if [info exists gluefile] {
unset gluefile
}
if {![info exists CFLAGS]} {
set CFLAGS ""
}
# Locate libgcc.a so we don't need to account for different values of
# SHLIB_EXT on different platforms
set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a]
if {$gccdir != ""} {
set gccdir [file dirname $gccdir]
}
# Compute what needs to be put into LD_LIBRARY_PATH
set always_ld_library_path ".:${blddir}/.libs"
# Compute what needs to be added to the existing LD_LIBRARY_PATH.
if {$gccdir != ""} {
# Add AIX pthread directory first.
if { [llength [glob -nocomplain ${gccdir}/pthread/libgcc_s*.a]] >= 1 } {
append always_ld_library_path ":${gccdir}/pthread"
}
append always_ld_library_path ":${gccdir}"
set compiler [lindex $GCC_UNDER_TEST 0]
if { [is_remote host] == 0 && [which $compiler] != 0 } {
foreach i "[exec $compiler --print-multi-lib]" {
set mldir ""
regexp -- "\[a-z0-9=_/\.-\]*;" $i mldir
set mldir [string trimright $mldir "\;@"]
if { "$mldir" == "." } {
continue
}
if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] >= 1 } {
append always_ld_library_path ":${gccdir}/${mldir}"
}
}
}
}
set ALWAYS_CFLAGS ""
if { $blddir != "" } {
lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/"
lappend ALWAYS_CFLAGS "additional_flags=-I${blddir}"
lappend ALWAYS_CFLAGS "ldflags=-L${blddir}/.libs"
}
lappend ALWAYS_CFLAGS "additional_flags=-I${srcdir}/.."
if [istarget *-*-darwin*] {
lappend ALWAYS_CFLAGS "additional_flags=-shared-libgcc"
}
if [info exists TOOL_OPTIONS] {
lappend ALWAYS_CFLAGS "additional_flags=$TOOL_OPTIONS"
}
# Make sure that lines are not wrapped. That can confuse the
# error-message parsing machinery.
lappend ALWAYS_CFLAGS "additional_flags=-fmessage-length=0"
# Turn off builtin support for atomics so that we test the library.
lappend ALWAYS_CFLAGS "additional_flags=-fno-inline-atomics"
lappend ALWAYS_CFLAGS "ldflags=-latomic"
}
#
# libatomic_target_compile -- compile a source file
#
proc libatomic_target_compile { source dest type options } {
global blddir
global libatomic_compile_options
global gluefile wrap_flags
global ALWAYS_CFLAGS
global GCC_UNDER_TEST
global lang_test_file
global lang_library_path
global lang_link_flags
if { [info exists lang_test_file] } {
if { $blddir != "" } {
lappend options "ldflags=-L${blddir}/${lang_library_path}"
}
lappend options "ldflags=${lang_link_flags}"
}
if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } {
lappend options "libs=${gluefile}"
lappend options "ldflags=${wrap_flags}"
}
lappend options "additional_flags=[libio_include_flags]"
lappend options "timeout=[timeout_value]"
lappend options "compiler=$GCC_UNDER_TEST"
set options [concat $libatomic_compile_options $options]
if [info exists ALWAYS_CFLAGS] {
set options [concat "$ALWAYS_CFLAGS" $options]
}
set options [dg-additional-files-options $options $source]
set result [target_compile $source $dest $type $options]
return $result
}
proc libatomic_option_help { } {
send_user " --additional_options,OPTIONS\t\tUse OPTIONS to compile the testcase files. OPTIONS should be comma-separated.\n"
}
proc libatomic_option_proc { option } {
if [regexp "^--additional_options," $option] {
global libatomic_compile_options
regsub "--additional_options," $option "" option
foreach x [split $option ","] {
lappend libatomic_compile_options "additional_flags=$x"
}
return 1
} else {
return 0
}
}
/* Test __atomic routines for existence and proper execution on 1 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_char_short } */
/* Test the execution of the __atomic_compare_exchange_n builtin for a char. */
extern void abort(void);
char v = 0;
char expected = 0;
char max = ~0;
char desired = ~0;
char zero = 0;
#define STRONG 0
#define WEAK 1
main ()
{
if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
/* Now test the generic version. */
v = 0;
if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
return 0;
}
/* Test __atomic routines for existence and proper execution on 2 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_char_short } */
/* Test the execution of the __atomic_compare_exchange_n builtin for a short. */
extern void abort(void);
short v = 0;
short expected = 0;
short max = ~0;
short desired = ~0;
short zero = 0;
#define STRONG 0
#define WEAK 1
main ()
{
if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
/* Now test the generic version. */
v = 0;
if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
return 0;
}
/* Test __atomic routines for existence and proper execution on 4 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_int_long } */
/* Test the execution of the __atomic_compare_exchange_n builtin for an int. */
extern void abort(void);
int v = 0;
int expected = 0;
int max = ~0;
int desired = ~0;
int zero = 0;
#define STRONG 0
#define WEAK 1
main ()
{
if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
/* Now test the generic version. */
v = 0;
if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
return 0;
}
/* Test __atomic routines for existence and proper execution on 8 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_long_long_runtime } */
/* { dg-options "" } */
/* { dg-options "-march=pentium" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
/* Test the execution of __atomic_compare_exchange_n builtin for a long_long. */
extern void abort(void);
long long v = 0;
long long expected = 0;
long long max = ~0;
long long desired = ~0;
long long zero = 0;
#define STRONG 0
#define WEAK 1
main ()
{
if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
/* Now test the generic version. */
v = 0;
if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
return 0;
}
/* Test __atomic routines for existence and proper execution on 16 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_int_128_runtime } */
/* { dg-options "-mcx16" { target { i?86-*-* x86_64-*-* } } } */
/* Test the execution of __atomic_compare_exchange_n builtin for an int_128. */
extern void abort(void);
__int128_t v = 0;
__int128_t expected = 0;
__int128_t max = ~0;
__int128_t desired = ~0;
__int128_t zero = 0;
#define STRONG 0
#define WEAK 1
main ()
{
if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
/* Now test the generic version. */
v = 0;
if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED))
abort ();
if (expected != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
abort ();
if (expected != max)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE))
abort ();
if (expected != max)
abort ();
if (v != 0)
abort ();
if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE))
abort ();
if (expected != 0)
abort ();
if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
abort ();
if (expected != 0)
abort ();
if (v != max)
abort ();
return 0;
}
/* Test __atomic routines for existence and proper execution on 1 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_char_short } */
/* Test the execution of the __atomic_exchange_n builtin for a char. */
extern void abort(void);
char v, count, ret;
main ()
{
v = 0;
count = 0;
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++)
abort ();
/* Now test the generic version. */
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST);
if (ret != count - 1 || v != count)
abort ();
count++;
return 0;
}
/* Test __atomic routines for existence and proper execution on 2 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_char_short } */
/* Test the execution of the __atomic_X builtin for a short. */
extern void abort(void);
short v, count, ret;
main ()
{
v = 0;
count = 0;
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++)
abort ();
/* Now test the generic version. */
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST);
if (ret != count - 1 || v != count)
abort ();
count++;
return 0;
}
/* Test __atomic routines for existence and proper execution on 4 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_int_long } */
/* Test the execution of the __atomic_X builtin for an int. */
extern void abort(void);
int v, count, ret;
main ()
{
v = 0;
count = 0;
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++)
abort ();
/* Now test the generic version. */
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST);
if (ret != count - 1 || v != count)
abort ();
count++;
return 0;
}
/* Test __atomic routines for existence and proper execution on 8 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_long_long_runtime } */
/* { dg-options "" } */
/* { dg-options "-march=pentium" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
/* Test the execution of the __atomic_X builtin for a long_long. */
extern void abort(void);
long long v, count, ret;
main ()
{
v = 0;
count = 0;
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++)
abort ();
/* Now test the generic version. */
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST);
if (ret != count - 1 || v != count)
abort ();
count++;
return 0;
}
/* Test __atomic routines for existence and proper execution on 16 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_int_128_runtime } */
/* { dg-options "-mcx16" { target { i?86-*-* x86_64-*-* } } } */
/* Test the execution of the __atomic_X builtin for a 16 byte value. */
extern void abort(void);
__int128_t v, count, ret;
main ()
{
v = 0;
count = 0;
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++)
abort ();
if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++)
abort ();
/* Now test the generic version. */
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL);
if (ret != count - 1 || v != count)
abort ();
count++;
__atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST);
if (ret != count - 1 || v != count)
abort ();
count++;
return 0;
}
/* Test generic __atomic routines for proper function calling.
memory model. */
/* { dg-options "-w" } */
/* { dg-do run } */
/* Test that the generioc atomic builtins execute as expected..
sync-mem-generic-aux.c supplies a functional external entry point for
the 4 generic functions. */
#include <stdlib.h>
#include <stdbool.h>
extern void abort();
typedef struct test {
int array[10];
} test_struct;
test_struct zero = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
test_struct ones = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
test_struct a,b;
int size = sizeof (test_struct);
/* Test for consistency on sizes 1, 2, 4, 8, 16 and 32. */
main ()
{
test_struct c;
__atomic_store (&a, &zero, __ATOMIC_RELAXED);
if (memcmp (&a, &zero, size))
abort ();
__atomic_exchange (&a, &ones, &c, __ATOMIC_SEQ_CST);
if (memcmp (&c, &zero, size))
abort ();
if (memcmp (&a, &ones, size))
abort ();
__atomic_load (&a, &b, __ATOMIC_RELAXED);
if (memcmp (&b, &ones, size))
abort ();
if (!__atomic_compare_exchange (&a, &b, &zero, false, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))
abort();
if (memcmp (&a, &zero, size))
abort ();
if (__atomic_compare_exchange (&a, &b, &ones, false, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE))
abort();
if (memcmp (&b, &zero, size))
abort ();
return 0;
}
/* Test __atomic routines for existence and proper execution on 1 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_char_short } */
/* Test the execution of the __atomic_load_n builtin for a char. */
extern void abort(void);
char v, count;
main ()
{
v = 0;
count = 0;
if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++)
abort();
else
v++;
/* Now test the generic variants. */
__atomic_load (&v, &count, __ATOMIC_RELAXED);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_ACQUIRE);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_CONSUME);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_SEQ_CST);
if (count != v)
abort();
else
v++;
return 0;
}
/* Test __atomic routines for existence and proper execution on 2 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_char_short } */
/* Test the execution of the __atomic_load_n builtin for a short. */
extern void abort(void);
short v, count;
main ()
{
v = 0;
count = 0;
if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++)
abort();
else
v++;
/* Now test the generic variants. */
__atomic_load (&v, &count, __ATOMIC_RELAXED);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_ACQUIRE);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_CONSUME);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_SEQ_CST);
if (count != v)
abort();
else
v++;
return 0;
}
/* Test __atomic routines for existence and proper execution on 4 byte
values with each valid memory model. */
/* { dg-do run } */
/* { dg-require-effective-target sync_int_long } */
extern void abort(void);
int v, count;
main ()
{
v = 0;
count = 0;
if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++)
abort();
else
v++;
if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++)
abort();
else
v++;
/* Now test the generic variants. */
__atomic_load (&v, &count, __ATOMIC_RELAXED);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_ACQUIRE);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_CONSUME);
if (count != v)
abort();
else
v++;
__atomic_load (&v, &count, __ATOMIC_SEQ_CST);
if (count != v)
abort();
else
v++;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment