1/* Copyright (C) 2012-2015 Free Software Foundation, Inc. 2 Contributed by Richard Henderson <rth@redhat.com>. 3 4 This file is part of the GNU Atomic Library (libatomic). 5 6 Libatomic is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 more details. 15 16 Under Section 7 of GPL version 3, you are granted additional 17 permissions described in the GCC Runtime Library Exception, version 18 3.1, as published by the Free Software Foundation. 19 20 You should have received a copy of the GNU General Public License and 21 a copy of the GCC Runtime Library Exception along with this program; 22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 <http://www.gnu.org/licenses/>. */ 24 25/* This file contains data types and function declarations that are 26 private to the implementation of libatomic. */ 27 28#ifndef LIBATOMIC_H 29#define LIBATOMIC_H 1 30 31#include "auto-config.h" 32#include <stdbool.h> 33#include <stdint.h> 34#include <stddef.h> 35#include <limits.h> 36#include <string.h> 37 38 39/* Symbol concatenation macros. */ 40#define C2_(X,Y) X ## Y 41#define C2(X,Y) C2_(X,Y) 42#define C3_(X,Y,Z) X ## Y ## Z 43#define C3(X,Y,Z) C3_(X,Y,Z) 44#define C4_(W,X,Y,Z) W ## X ## Y ## Z 45#define C4(W,X,Y,Z) C4_(W,X,Y,Z) 46 47/* Stringification macros. */ 48#define S2(X) #X 49#define S(X) S2(X) 50 51/* All of the primitive types on which we operate. */ 52typedef unsigned U_1 __attribute__((mode(QI))); 53#if HAVE_INT2 54typedef unsigned U_2 __attribute__((mode(HI))); 55#endif 56#if HAVE_INT4 57typedef unsigned U_4 __attribute__((mode(SI))); 58#endif 59#if HAVE_INT8 60typedef unsigned U_8 __attribute__((mode(DI))); 61#endif 62#if HAVE_INT16 63typedef unsigned U_16 __attribute__((mode(TI))); 64#endif 65 66/* The widest type that we support. */ 67#if HAVE_INT16 68# define MAX_SIZE 16 69#elif HAVE_INT8 70# define MAX_SIZE 8 71#elif HAVE_INT4 72# define MAX_SIZE 4 73#elif HAVE_INT2 74# define MAX_SIZE 2 75#else 76# define MAX_SIZE 1 77#endif 78typedef C2(U_,MAX_SIZE) U_MAX; 79 80/* Provide dummy fallback types so that stuff is syntactically correct 81 without having to overdo the ifdefs. The code using these should 82 always be protected with the HAVE_INT{n} macros. */ 83#if !HAVE_INT2 84typedef U_MAX U_2; 85#endif 86#if !HAVE_INT4 87typedef U_MAX U_4; 88#endif 89#if !HAVE_INT8 90typedef U_MAX U_8; 91#endif 92#if !HAVE_INT16 93typedef U_MAX U_16; 94#endif 95 96union max_size_u 97{ 98 U_1 b[MAX_SIZE]; 99 U_2 i2; 100 U_4 i4; 101 U_8 i8; 102 U_16 i16; 103}; 104 105/* The "word" size of the machine. */ 106typedef unsigned UWORD __attribute__((mode(word))); 107 108/* Macros for handing sub-word sized quantities. */ 109#define MASK_1 ((UWORD)0xff) 110#define MASK_2 ((UWORD)0xffff) 111#define MASK_4 ((UWORD)0xffffffff) 112#define INVERT_MASK_1 ((UWORD)WORDS_BIGENDIAN << ((WORDSIZE - 1) * CHAR_BIT)) 113#define INVERT_MASK_2 ((UWORD)WORDS_BIGENDIAN << ((WORDSIZE - 2) * CHAR_BIT)) 114#define INVERT_MASK_4 ((UWORD)WORDS_BIGENDIAN << ((WORDSIZE - 4) * CHAR_BIT)) 115 116/* Most of the files in this library are compiled multiple times with 117 N defined to be a power of 2 between 1 and 16. The SIZE macro is 118 then used to append _N to the symbol being manipulated. */ 119#define SIZE(X) C3(X,_,N) 120#define WSIZE(X) C3(X,_,WORDSIZE) 121#define PTR(N,X) ((C2(U_,N) *)X) 122 123/* And thus, the type on which this compilation will be operating. */ 124#define ITYPE SIZE(I) 125#define UTYPE SIZE(U) 126 127/* Utility macros for GCC attributes. */ 128#define UNUSED __attribute__((unused)) 129#ifdef HAVE_ATTRIBUTE_VISIBILITY 130# define HIDDEN __attribute__((visibility("hidden"))) 131#else 132# define HIDDEN 133#endif 134 135/* Occasionally we have to play games with internal and external symbol 136 names, in order to work around builtin functions of the same name. 137 This macro sets the external name of the function appropriately. */ 138#define ASMNAME(X) __asm__(S(C2(__USER_LABEL_PREFIX__,X))) 139 140/* Locking for a "small" operation. In the bare-metal single processor 141 cases this could be implemented by disabling interrupts. Thus the extra 142 word passed between the two functions, saving the interrupt level. 143 It is assumed that the object being locked does not cross the locking 144 granularity. 145 146 Not actually declared here so that they can be defined static inline 147 in a target-specfic <host-config.h>. 148 149UWORD protect_start (void *ptr); 150void protect_end (void *ptr, UWORD); 151*/ 152 153/* Locking for a "large' operation. This should always be some sort of 154 test-and-set operation, as we assume that the interrupt latency would 155 be unreasonably large. */ 156void libat_lock_n (void *ptr, size_t n); 157void libat_unlock_n (void *ptr, size_t n); 158 159/* We'll need to declare all of the sized functions a few times... */ 160#define DECLARE_ALL_SIZED(N) DECLARE_ALL_SIZED_(N,C2(U_,N)) 161#define DECLARE_ALL_SIZED_(N,T) \ 162 DECLARE_1(T, C2(load_,N), (T *mptr, int)); \ 163 DECLARE_1(void, C2(store_,N), (T *mptr, T val, int)); \ 164 DECLARE_1(T, C2(exchange_,N), (T *mptr, T, int)); \ 165 DECLARE_1(bool, C2(compare_exchange_,N), (T *mptr, T *, T, int, int)); \ 166 DECLARE_1(bool, C2(test_and_set_,N), (T *mptr, int)); \ 167 DECLARE_1(T, C2(fetch_add_,N), (T *mptr, T, int)); \ 168 DECLARE_1(T, C2(fetch_sub_,N), (T *mptr, T, int)); \ 169 DECLARE_1(T, C2(fetch_and_,N), (T *mptr, T, int)); \ 170 DECLARE_1(T, C2(fetch_xor_,N), (T *mptr, T, int)); \ 171 DECLARE_1(T, C2(fetch_or_,N), (T *mptr, T, int)); \ 172 DECLARE_1(T, C2(fetch_nand_,N), (T *mptr, T, int)); \ 173 DECLARE_1(T, C2(add_fetch_,N), (T *mptr, T, int)); \ 174 DECLARE_1(T, C2(sub_fetch_,N), (T *mptr, T, int)); \ 175 DECLARE_1(T, C2(and_fetch_,N), (T *mptr, T, int)); \ 176 DECLARE_1(T, C2(xor_fetch_,N), (T *mptr, T, int)); \ 177 DECLARE_1(T, C2(or_fetch_,N), (T *mptr, T, int)); \ 178 DECLARE_1(T, C2(nand_fetch_,N), (T *mptr, T, int)) 179 180/* All sized operations are implemented in hidden functions prefixed with 181 "libat_". These are either renamed or aliased to the expected prefix 182 of "__atomic". Some amount of renaming is required to avoid hiding or 183 conflicting with the builtins of the same name, but this additional 184 use of hidden symbols (where appropriate) avoids unnecessary PLT entries 185 on relevant targets. */ 186 187#if IFUNC_ALT 188# define MAN(X) ASMNAME(C4(libat_,X,_i,IFUNC_ALT)) HIDDEN 189#elif defined(HAVE_ATTRIBUTE_ALIAS) 190# define MAN(X) HIDDEN 191#else 192# define MAN(X) ASMNAME(C2(__atomic_,X)) 193#endif 194 195#if !defined(N) && HAVE_IFUNC 196# define DECLARE_1(RET,NAME,ARGS) \ 197 RET C2(libat_,NAME) ARGS MAN(NAME); \ 198 RET C2(ifunc_,NAME) ARGS ASMNAME(C2(__atomic_,NAME)) 199#else 200# define DECLARE_1(RET,NAME,ARGS) RET C2(libat_,NAME) ARGS MAN(NAME) 201#endif 202 203/* Prefix to use when calling internal, possibly ifunc'ed functions. */ 204#if HAVE_IFUNC 205# define local_ ifunc_ 206#else 207# define local_ libat_ 208#endif 209 210DECLARE_ALL_SIZED(1); 211DECLARE_ALL_SIZED(2); 212DECLARE_ALL_SIZED(4); 213DECLARE_ALL_SIZED(8); 214DECLARE_ALL_SIZED(16); 215 216#undef DECLARE_1 217#undef DECLARE_ALL_SIZED 218#undef DECLARE_ALL_SIZED_ 219 220/* And the generic sized versions. */ 221void libat_load (size_t, void *, void *, int) MAN(load); 222void libat_store (size_t, void *, void *, int) MAN(store); 223void libat_exchange (size_t, void *, void *, void *, int) MAN(exchange); 224bool libat_compare_exchange (size_t, void *, void *, void *, int, int) 225 MAN(compare_exchange); 226bool libat_is_lock_free (size_t, void *) MAN(is_lock_free); 227 228#undef MAN 229 230#include <host-config.h> 231 232/* We don't have IFUNC_NCOND until after host-config.h. */ 233#if !HAVE_IFUNC 234# define IFUNC_NCOND(N) 0 235#endif 236 237#if IFUNC_ALT 238# define EXPORT_ALIAS(X) /* exported symbol in non-alternate file */ 239#elif defined(N) && IFUNC_NCOND(N) 240# if IFUNC_NCOND(N) == 1 241# define GEN_SELECTOR(X) \ 242 extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \ 243 static void * C2(select_,X) (void) \ 244 { \ 245 if (IFUNC_COND_1) \ 246 return C3(libat_,X,_i1); \ 247 return C2(libat_,X); \ 248 } 249# elif IFUNC_NCOND(N) == 2 250# define GEN_SELECTOR(X) \ 251 extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \ 252 extern typeof(C2(libat_,X)) C3(libat_,X,_i2) HIDDEN; \ 253 static void * C2(select_,X) (void) \ 254 { \ 255 if (IFUNC_COND_1) \ 256 return C3(libat_,X,_i1); \ 257 if (IFUNC_COND_2) \ 258 return C3(libat_,X,_i2); \ 259 return C2(libat_,X); \ 260 } 261# elif IFUNC_NCOND(N) == 3 262# define GEN_SELECTOR(X) \ 263 extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \ 264 extern typeof(C2(libat_,X)) C3(libat_,X,_i2) HIDDEN; \ 265 extern typeof(C2(libat_,X)) C3(libat_,X,_i3) HIDDEN; \ 266 static void * C2(select_,X) (void) \ 267 { \ 268 if (IFUNC_COND_1) \ 269 return C3(libat_,X,_i1); \ 270 if (IFUNC_COND_2) \ 271 return C3(libat_,X,_i2); \ 272 if (IFUNC_COND_3) \ 273 return C3(libat_,X,_i3); \ 274 return C2(libat_,X); \ 275 } 276# else 277# error "Unsupported number of ifunc alternatives." 278# endif 279# define EXPORT_ALIAS(X) \ 280 GEN_SELECTOR(X) \ 281 typeof(C2(libat_,X)) C2(ifunc_,X) \ 282 ASMNAME(C2(__atomic_,X)) \ 283 __attribute__((ifunc(S(C2(select_,X))))) 284#elif defined(HAVE_ATTRIBUTE_ALIAS) 285# define EXPORT_ALIAS(X) \ 286 extern typeof(C2(libat_,X)) C2(export_,X) \ 287 ASMNAME(C2(__atomic_,X)) \ 288 __attribute__((alias(S(C2(libat_,X))))) 289#else 290# define EXPORT_ALIAS(X) /* original symbol is exported */ 291#endif 292 293#endif /* LIBATOMIC_H */ 294