Home | History | Annotate | Line # | Download | only in libgcc
      1 /* Out-of-line libgcc versions of __sync_* builtins.  */
      2 /* Copyright (C) 2008-2022 Free Software Foundation, Inc.
      3 
      4 This file is part of GCC.
      5 
      6 GCC is free software; you can redistribute it and/or modify it under
      7 the terms of the GNU General Public License as published by the Free
      8 Software Foundation; either version 3, or (at your option) any later
      9 version.
     10 
     11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14 for 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 is used by targets whose makefiles define SYNC
     26    to "yes".  It is compiled with SYNC_CFLAGS and provides
     27    out-of-line versions of all relevant __sync_* primitives.
     28 
     29    These routines are intended for targets like MIPS that have two
     30    ISA encodings (the "normal" ISA and the MIPS16 ISA).  The normal
     31    ISA provides full synchronization capabilities but the MIPS16 ISA
     32    has no encoding for them.  MIPS16 code must therefore call external
     33    non-MIPS16 implementations of the __sync_* routines.
     34 
     35    The file is compiled once for each routine.  The following __foo
     36    routines are selected by defining a macro called L<foo>:
     37 
     38        __sync_synchronize
     39 
     40    The following __foo_N routines are selected by defining FN=foo
     41    and SIZE=N:
     42 
     43        __sync_fetch_and_add_N
     44        __sync_fetch_and_sub_N
     45        __sync_fetch_and_or_N
     46        __sync_fetch_and_and_N
     47        __sync_fetch_and_xor_N
     48        __sync_fetch_and_nand_N
     49        __sync_add_and_fetch_N
     50        __sync_sub_and_fetch_N
     51        __sync_or_and_fetch_N
     52        __sync_and_and_fetch_N
     53        __sync_xor_and_fetch_N
     54        __sync_nand_and_fetch_N
     55        __sync_bool_compare_and_swap_N
     56        __sync_val_compare_and_swap_N
     57        __sync_lock_test_and_set_N
     58 
     59    SIZE can be 1, 2, 4, 8 or 16.  __foo_N is omitted if the target does
     60    not provide __sync_compare_and_swap_N.
     61 
     62    Note that __sync_lock_release does not fall back on external
     63    __sync_lock_release_N functions.  The default implementation
     64    of __sync_lock_release is a call to __sync_synchronize followed
     65    by a store of zero, so we don't need separate library functions
     66    for it.  */
     67 
     68 #if defined FN
     69 
     70 /* Define functions called __sync_<NAME>_<UNITS>, with one macro per
     71    signature.  TYPE is a type that has UNITS bytes.  */
     72 
     73 #define DEFINE_V_PV(NAME, UNITS, TYPE)					\
     74   TYPE									\
     75   __##NAME##_##UNITS (TYPE *ptr, TYPE value)				\
     76   {									\
     77     return __##NAME (ptr, value);					\
     78   }
     79 
     80 #define DEFINE_V_PVV(NAME, UNITS, TYPE)					\
     81   TYPE									\
     82   __##NAME##_##UNITS (TYPE *ptr, TYPE value1, TYPE value2)		\
     83   {									\
     84     return __##NAME (ptr, value1, value2);				\
     85   }
     86 
     87 #define DEFINE_BOOL_PVV(NAME, UNITS, TYPE)				\
     88   _Bool									\
     89   __##NAME##_##UNITS (TYPE *ptr, TYPE value1, TYPE value2)		\
     90   {									\
     91     return __##NAME (ptr, value1, value2);				\
     92   }
     93 
     94 /* Map function names to the appropriate DEFINE_* macro.  */
     95 
     96 #define local_sync_fetch_and_add DEFINE_V_PV
     97 #define local_sync_fetch_and_sub DEFINE_V_PV
     98 #define local_sync_fetch_and_or DEFINE_V_PV
     99 #define local_sync_fetch_and_and DEFINE_V_PV
    100 #define local_sync_fetch_and_xor DEFINE_V_PV
    101 #define local_sync_fetch_and_nand DEFINE_V_PV
    102 
    103 #define local_sync_add_and_fetch DEFINE_V_PV
    104 #define local_sync_sub_and_fetch DEFINE_V_PV
    105 #define local_sync_or_and_fetch DEFINE_V_PV
    106 #define local_sync_and_and_fetch DEFINE_V_PV
    107 #define local_sync_xor_and_fetch DEFINE_V_PV
    108 #define local_sync_nand_and_fetch DEFINE_V_PV
    109 
    110 #define local_sync_bool_compare_and_swap DEFINE_BOOL_PVV
    111 #define local_sync_val_compare_and_swap DEFINE_V_PVV
    112 
    113 #define local_sync_lock_test_and_set DEFINE_V_PV
    114 
    115 /* Define the function __<NAME>_<UNITS>, given that TYPE is a type with
    116    UNITS bytes.  */
    117 #define DEFINE1(NAME, UNITS, TYPE) \
    118   static int unused[sizeof (TYPE) == UNITS ? 1 : -1]	\
    119     __attribute__((unused));				\
    120   local_##NAME (NAME, UNITS, TYPE);
    121 
    122 /* As above, but performing macro expansion on the arguments.  */
    123 #define DEFINE(NAME, UNITS, TYPE) DEFINE1 (NAME, UNITS, TYPE)
    124 
    125 /* Find an appropriate type TYPE for SIZE and invoke DEFINE (FN, SIZE, TYPE).
    126 
    127    The types chosen here may be incorrect for some targets.
    128    For example, targets with 16-byte atomicity support might not
    129    support OImode.  We would need some kind of target-specific
    130    override if that becomes a problem.  */
    131 
    132 #if SIZE == 1 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
    133 
    134 typedef unsigned int UQItype __attribute__((mode (QI)));
    135 DEFINE (FN, 1, UQItype)
    136 
    137 #elif SIZE == 2 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
    138 
    139 typedef unsigned int UHItype __attribute__((mode (HI)));
    140 DEFINE (FN, 2, UHItype)
    141 
    142 #elif SIZE == 4 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
    143 
    144 typedef unsigned int USItype __attribute__((mode (SI)));
    145 DEFINE (FN, 4, USItype)
    146 
    147 #elif SIZE == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
    148 
    149 typedef unsigned int UDItype __attribute__((mode (DI)));
    150 DEFINE (FN, 8, UDItype)
    151 
    152 #elif SIZE == 16 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
    153 
    154 typedef unsigned int UOItype __attribute__((mode (OI)));
    155 DEFINE (FN, 8, UOItype)
    156 
    157 #endif
    158 
    159 #elif __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 \
    160       || __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 \
    161       || __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 \
    162       || __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 \
    163       || __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16
    164 
    165 #if defined Lsync_synchronize
    166 
    167 void
    168 __sync_synchronize (void)
    169 {
    170   __sync_synchronize ();
    171 }
    172 
    173 #endif
    174 
    175 #endif
    176