summaryrefslogtreecommitdiff
path: root/libatomic/libatomic_i.h
diff options
context:
space:
mode:
Diffstat (limited to 'libatomic/libatomic_i.h')
-rw-r--r--libatomic/libatomic_i.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/libatomic/libatomic_i.h b/libatomic/libatomic_i.h
new file mode 100644
index 00000000000..c3722520bdd
--- /dev/null
+++ b/libatomic/libatomic_i.h
@@ -0,0 +1,293 @@
+/* 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 */