Home | History | Annotate | Line # | Download | only in tilepro
      1   1.1  mrg /* Macros for atomic functionality for tile.
      2  1.10  mrg    Copyright (C) 2011-2022 Free Software Foundation, Inc.
      3   1.1  mrg    Contributed by Walter Lee (walt (at) tilera.com)
      4   1.1  mrg 
      5   1.1  mrg    This file is free software; you can redistribute it and/or modify it
      6   1.1  mrg    under the terms of the GNU General Public License as published by the
      7   1.1  mrg    Free Software Foundation; either version 3, or (at your option) any
      8   1.1  mrg    later version.
      9   1.1  mrg 
     10   1.1  mrg    This file is distributed in the hope that it will be useful, but
     11   1.1  mrg    WITHOUT ANY WARRANTY; without even the implied warranty of
     12   1.1  mrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13   1.1  mrg    General Public License for more details.
     14   1.1  mrg 
     15   1.1  mrg    Under Section 7 of GPL version 3, you are granted additional
     16   1.1  mrg    permissions described in the GCC Runtime Library Exception, version
     17   1.1  mrg    3.1, as published by the Free Software Foundation.
     18   1.1  mrg 
     19   1.1  mrg    You should have received a copy of the GNU General Public License and
     20   1.1  mrg    a copy of the GCC Runtime Library Exception along with this program;
     21   1.1  mrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     22   1.1  mrg    <http://www.gnu.org/licenses/>.  */
     23   1.1  mrg 
     24   1.1  mrg 
     25   1.1  mrg /* Provides macros for common atomic functionality.  */
     26   1.1  mrg 
     27   1.1  mrg #ifndef _ATOMIC_H_
     28   1.1  mrg #define _ATOMIC_H_
     29   1.1  mrg 
     30   1.1  mrg #ifdef __tilegx__
     31   1.1  mrg /* Atomic instruction macros
     32   1.1  mrg 
     33   1.1  mrg    The macros provided by atomic.h simplify access to the TILE-Gx
     34   1.1  mrg    architecture's atomic instructions.  The architecture provides a
     35   1.1  mrg    variety of atomic instructions, including "exchange", "compare and
     36   1.1  mrg    exchange", "fetch and ADD", "fetch and AND", "fetch and OR", and
     37   1.1  mrg    "fetch and ADD if greater than or equal to zero".
     38   1.1  mrg 
     39   1.1  mrg    No barrier or fence semantics are implied by any of the atomic
     40   1.1  mrg    instructions for manipulating memory; you must specify the barriers
     41   1.1  mrg    that you wish explicitly, using the provided macros.
     42   1.1  mrg 
     43   1.1  mrg    Any integral 32- or 64-bit value can be used as the argument
     44   1.1  mrg    to these macros, such as "int", "long long", "unsigned long", etc.
     45   1.1  mrg    The pointers must be aligned to 4 or 8 bytes for 32- or 64-bit data.
     46   1.1  mrg    The "exchange" and "compare and exchange" macros may also take
     47   1.1  mrg    pointer values.  We use the pseudo-type "VAL" in the documentation
     48   1.1  mrg    to indicate the use of an appropriate type.  */
     49   1.1  mrg #else
     50   1.1  mrg /* Atomic instruction macros
     51   1.1  mrg 
     52   1.1  mrg    The macros provided by atomic.h simplify access to the Tile
     53   1.1  mrg    architecture's atomic instructions.  Since the architecture
     54   1.1  mrg    supports test-and-set as its only in-silicon atomic operation, many
     55   1.1  mrg    of the operations provided by this header are implemented as
     56   1.1  mrg    fast-path calls to Linux emulation routines.
     57   1.1  mrg 
     58   1.1  mrg    Using the kernel for atomic operations allows userspace to take
     59   1.1  mrg    advantage of the kernel's existing atomic-integer support (managed
     60   1.1  mrg    by a distributed array of locks).  The kernel provides proper
     61   1.1  mrg    ordering among simultaneous atomic operations on different cores,
     62   1.8  mrg    and guarantees a process cannot be context-switched part way
     63   1.1  mrg    through an atomic operation.  By virtue of sharing the kernel
     64   1.1  mrg    atomic implementation, the userspace atomic operations
     65   1.1  mrg    are compatible with the atomic methods provided by the kernel's
     66   1.1  mrg    futex() syscall API.  Note that these operations never cause Linux
     67   1.1  mrg    kernel scheduling, and are in fact invisible to the kernel; they
     68   1.1  mrg    simply act as regular function calls but with an elevated privilege
     69   1.1  mrg    level.  Note that the kernel's distributed lock array is hashed by
     70   1.1  mrg    using only VA bits from the atomic value's address (to avoid the
     71   1.1  mrg    performance hit of page table locking and multiple page-table
     72   1.1  mrg    lookups to get the PA) and only the VA bits that are below page
     73   1.1  mrg    granularity (to properly lock simultaneous accesses to the same
     74   1.1  mrg    page mapped at different VAs).  As a result, simultaneous atomic
     75   1.1  mrg    operations on values whose addresses are at the same offset on a
     76   1.1  mrg    page will contend in the kernel for the same lock array element.
     77   1.1  mrg 
     78   1.1  mrg    No barrier or fence semantics are implied by any of the atomic
     79   1.1  mrg    instructions for manipulating memory; you must specify the barriers
     80   1.1  mrg    that you wish explicitly, using the provided macros.
     81   1.1  mrg 
     82   1.1  mrg    Any integral 32- or 64-bit value can be used as the argument
     83   1.1  mrg    to these macros, such as "int", "long long", "unsigned long", etc.
     84   1.1  mrg    The pointers must be aligned to 4 or 8 bytes for 32- or 64-bit data.
     85   1.1  mrg    The "exchange" and "compare and exchange" macros may also take
     86   1.1  mrg    pointer values.  We use the pseudo-type "VAL" in the documentation
     87   1.1  mrg    to indicate the use of an appropriate type.
     88   1.1  mrg 
     89   1.1  mrg    The 32-bit routines are implemented using a single kernel fast
     90   1.1  mrg    syscall, as is the 64-bit compare-and-exchange.  The other 64-bit
     91   1.1  mrg    routines are implemented by looping over the 64-bit
     92   1.1  mrg    compare-and-exchange routine, so may be potentially less efficient.  */
     93   1.1  mrg #endif
     94   1.1  mrg 
     95   1.1  mrg #ifdef __tilegx__
     96   1.6  mrg #define SPR_CMPEXCH_VALUE 0x2780
     97   1.1  mrg #else
     98   1.6  mrg #define __NR_FAST_cmpxchg	-1
     99   1.6  mrg #define __NR_FAST_atomic_update	-2
    100   1.6  mrg #define __NR_FAST_cmpxchg64	-3
    101   1.1  mrg #endif
    102   1.1  mrg 
    103   1.1  mrg 
    104   1.1  mrg /* 32-bit integer compare-and-exchange.  */
    105   1.1  mrg static __inline __attribute__ ((always_inline))
    106   1.1  mrg      int arch_atomic_val_compare_and_exchange_4 (volatile int *mem,
    107   1.1  mrg 						 int oldval, int newval)
    108   1.1  mrg {
    109   1.1  mrg #ifdef __tilegx__
    110   1.1  mrg   __insn_mtspr (SPR_CMPEXCH_VALUE, oldval);
    111   1.1  mrg   return __insn_cmpexch4 (mem, newval);
    112   1.1  mrg #else
    113   1.1  mrg   int result;
    114   1.1  mrg   __asm__ __volatile__ ("swint1":"=R00" (result),
    115   1.1  mrg 			"=m" (*mem):"R10" (__NR_FAST_cmpxchg), "R00" (mem),
    116   1.1  mrg 			"R01" (oldval), "R02" (newval), "m" (*mem):"r20",
    117   1.1  mrg 			"r21", "r22", "r23", "r24", "r25", "r26", "r27",
    118   1.1  mrg 			"r28", "r29", "memory");
    119   1.1  mrg   return result;
    120   1.1  mrg #endif
    121   1.1  mrg }
    122   1.1  mrg 
    123   1.1  mrg /* 64-bit integer compare-and-exchange.  */
    124   1.1  mrg static __inline __attribute__ ((always_inline))
    125   1.1  mrg      long long arch_atomic_val_compare_and_exchange_8 (volatile long long
    126   1.1  mrg 						       *mem, long long oldval,
    127   1.1  mrg 						       long long newval)
    128   1.1  mrg {
    129   1.1  mrg #ifdef __tilegx__
    130   1.1  mrg   __insn_mtspr (SPR_CMPEXCH_VALUE, oldval);
    131   1.1  mrg   return __insn_cmpexch (mem, newval);
    132   1.1  mrg #else
    133   1.1  mrg   unsigned int result_lo, result_hi;
    134   1.1  mrg   unsigned int oldval_lo = oldval & 0xffffffffu, oldval_hi = oldval >> 32;
    135   1.1  mrg   unsigned int newval_lo = newval & 0xffffffffu, newval_hi = newval >> 32;
    136   1.1  mrg   __asm__ __volatile__ ("swint1":"=R00" (result_lo), "=R01" (result_hi),
    137   1.1  mrg 			"=m" (*mem):"R10" (__NR_FAST_cmpxchg64), "R00" (mem),
    138   1.1  mrg 			"R02" (oldval_lo), "R03" (oldval_hi),
    139   1.1  mrg 			"R04" (newval_lo), "R05" (newval_hi),
    140   1.1  mrg 			"m" (*mem):"r20", "r21", "r22", "r23", "r24", "r25",
    141   1.1  mrg 			"r26", "r27", "r28", "r29", "memory");
    142   1.1  mrg   return ((long long) result_hi) << 32 | result_lo;
    143   1.1  mrg #endif
    144   1.1  mrg }
    145   1.1  mrg 
    146   1.1  mrg /* This non-existent symbol is called for sizes other than "4" and "8",
    147   1.1  mrg    indicating a bug in the caller.  */
    148   1.1  mrg extern int __arch_atomic_error_bad_argument_size (void)
    149   1.1  mrg   __attribute__ ((warning ("sizeof atomic argument not 4 or 8")));
    150   1.1  mrg 
    151   1.1  mrg 
    152   1.1  mrg #define arch_atomic_val_compare_and_exchange(mem, o, n)                 \
    153   1.1  mrg   __extension__ ({                                                      \
    154   1.1  mrg     (__typeof(*(mem)))(__typeof(*(mem)-*(mem)))                         \
    155   1.1  mrg       ((sizeof(*(mem)) == 8) ?                                          \
    156   1.1  mrg        arch_atomic_val_compare_and_exchange_8(                          \
    157   1.1  mrg          (volatile long long*)(mem), (__typeof((o)-(o)))(o),            \
    158   1.1  mrg          (__typeof((n)-(n)))(n)) :                                      \
    159   1.1  mrg        (sizeof(*(mem)) == 4) ?                                          \
    160   1.1  mrg        arch_atomic_val_compare_and_exchange_4(                          \
    161   1.1  mrg          (volatile int*)(mem), (__typeof((o)-(o)))(o),                  \
    162   1.1  mrg          (__typeof((n)-(n)))(n)) :                                      \
    163   1.1  mrg        __arch_atomic_error_bad_argument_size());                        \
    164   1.1  mrg   })
    165   1.1  mrg 
    166   1.1  mrg #define arch_atomic_bool_compare_and_exchange(mem, o, n)                \
    167   1.1  mrg   __extension__ ({                                                      \
    168   1.1  mrg     __typeof(o) __o = (o);                                              \
    169   1.1  mrg     __builtin_expect(                                                   \
    170   1.1  mrg       __o == arch_atomic_val_compare_and_exchange((mem), __o, (n)), 1); \
    171   1.1  mrg   })
    172   1.1  mrg 
    173   1.1  mrg 
    174   1.1  mrg /* Loop with compare_and_exchange until we guess the correct value.
    175   1.1  mrg    Normally "expr" will be an expression using __old and __value.  */
    176   1.1  mrg #define __arch_atomic_update_cmpxchg(mem, value, expr)                  \
    177   1.1  mrg   __extension__ ({                                                      \
    178   1.1  mrg     __typeof(value) __value = (value);                                  \
    179   1.1  mrg     __typeof(*(mem)) *__mem = (mem), __old = *__mem, __guess;           \
    180   1.1  mrg     do {                                                                \
    181   1.1  mrg       __guess = __old;                                                  \
    182   1.1  mrg       __old = arch_atomic_val_compare_and_exchange(__mem, __old, (expr));    \
    183   1.1  mrg     } while (__builtin_expect(__old != __guess, 0));                    \
    184   1.1  mrg     __old;                                                              \
    185   1.1  mrg   })
    186   1.1  mrg 
    187   1.1  mrg #ifdef __tilegx__
    188   1.1  mrg 
    189   1.1  mrg /* Generic atomic op with 8- or 4-byte variant.
    190   1.1  mrg    The _mask, _addend, and _expr arguments are ignored on tilegx.  */
    191   1.1  mrg #define __arch_atomic_update(mem, value, op, _mask, _addend, _expr)     \
    192   1.1  mrg   __extension__ ({                                                      \
    193   1.1  mrg     ((__typeof(*(mem)))                                                 \
    194   1.1  mrg      ((sizeof(*(mem)) == 8) ? (__typeof(*(mem)-*(mem)))__insn_##op(     \
    195   1.1  mrg         (volatile void *)(mem),                                         \
    196   1.1  mrg         (long long)(__typeof((value)-(value)))(value)) :                \
    197   1.1  mrg       (sizeof(*(mem)) == 4) ? (int)__insn_##op##4(                      \
    198   1.1  mrg         (volatile void *)(mem),                                         \
    199   1.1  mrg         (int)(__typeof((value)-(value)))(value)) :                      \
    200   1.1  mrg       __arch_atomic_error_bad_argument_size()));                        \
    201   1.1  mrg   })
    202   1.1  mrg 
    203   1.1  mrg #else
    204   1.1  mrg 
    205   1.1  mrg /* This uses TILEPro's fast syscall support to atomically compute:
    206   1.1  mrg 
    207   1.1  mrg    int old = *ptr;
    208   1.1  mrg    *ptr = (old & mask) + addend;
    209   1.1  mrg    return old;
    210   1.1  mrg 
    211   1.1  mrg    This primitive can be used for atomic exchange, add, or, and.
    212   1.1  mrg    Only 32-bit support is provided.  */
    213   1.1  mrg static __inline __attribute__ ((always_inline))
    214   1.1  mrg      int
    215   1.1  mrg      __arch_atomic_update_4 (volatile int *mem, int mask, int addend)
    216   1.1  mrg {
    217   1.1  mrg   int result;
    218   1.1  mrg   __asm__ __volatile__ ("swint1":"=R00" (result),
    219   1.1  mrg 			"=m" (*mem):"R10" (__NR_FAST_atomic_update),
    220   1.1  mrg 			"R00" (mem), "R01" (mask), "R02" (addend),
    221   1.1  mrg 			"m" (*mem):"r20", "r21", "r22", "r23", "r24", "r25",
    222   1.1  mrg 			"r26", "r27", "r28", "r29", "memory");
    223   1.1  mrg   return result;
    224   1.1  mrg }
    225   1.1  mrg 
    226   1.1  mrg /* Generic atomic op with 8- or 4-byte variant.
    227   1.1  mrg    The _op argument is ignored on tilepro.  */
    228   1.1  mrg #define __arch_atomic_update(mem, value, _op, mask, addend, expr)       \
    229   1.1  mrg   __extension__ ({                                                      \
    230   1.1  mrg     (__typeof(*(mem)))(__typeof(*(mem)-*(mem)))                         \
    231   1.1  mrg       ((sizeof(*(mem)) == 8) ?                                          \
    232   1.1  mrg        __arch_atomic_update_cmpxchg((mem), (value), (expr)) :           \
    233   1.1  mrg        (sizeof(*(mem)) == 4) ?                                          \
    234   1.1  mrg        __arch_atomic_update_4((volatile int*)(mem),                     \
    235   1.1  mrg                               (__typeof((mask)-(mask)))(mask),          \
    236   1.1  mrg                               (__typeof((addend)-(addend)))(addend)) :  \
    237   1.1  mrg        __arch_atomic_error_bad_argument_size());                        \
    238   1.1  mrg   })
    239   1.1  mrg 
    240   1.1  mrg #endif /* __tilegx__ */
    241   1.1  mrg 
    242   1.1  mrg 
    243   1.1  mrg #define arch_atomic_exchange(mem, newvalue) \
    244   1.1  mrg   __arch_atomic_update(mem, newvalue, exch, 0, newvalue, __value)
    245   1.1  mrg 
    246   1.1  mrg #define arch_atomic_add(mem, value) \
    247   1.1  mrg   __arch_atomic_update(mem, value, fetchadd, -1, value, __old + __value)
    248   1.1  mrg 
    249   1.1  mrg #define arch_atomic_sub(mem, value) arch_atomic_add((mem), -(value))
    250   1.1  mrg 
    251   1.1  mrg #define arch_atomic_increment(mem) arch_atomic_add((mem), 1)
    252   1.1  mrg 
    253   1.1  mrg #define arch_atomic_decrement(mem) arch_atomic_add((mem), -1)
    254   1.1  mrg 
    255   1.1  mrg #define arch_atomic_and(mem, mask) \
    256   1.1  mrg   __arch_atomic_update(mem, mask, fetchand, mask, 0, __old & __value)
    257   1.1  mrg 
    258   1.1  mrg #define arch_atomic_or(mem, mask) \
    259   1.1  mrg   __arch_atomic_update(mem, mask, fetchor, ~mask, mask, __old | __value)
    260   1.1  mrg 
    261   1.1  mrg #define arch_atomic_xor(mem, mask) \
    262   1.1  mrg   __arch_atomic_update_cmpxchg(mem, mask, __old ^ __value)
    263   1.1  mrg 
    264   1.1  mrg #define arch_atomic_nand(mem, mask) \
    265   1.1  mrg   __arch_atomic_update_cmpxchg(mem, mask, ~(__old & __value))
    266   1.1  mrg 
    267   1.1  mrg #define arch_atomic_bit_set(mem, bit)                                   \
    268   1.1  mrg   __extension__ ({                                                      \
    269   1.1  mrg     __typeof(*(mem)) __mask = (__typeof(*(mem)))1 << (bit);             \
    270   1.1  mrg     __mask & arch_atomic_or((mem), __mask);                             \
    271   1.1  mrg   })
    272   1.1  mrg 
    273   1.1  mrg #define arch_atomic_bit_clear(mem, bit)                                 \
    274   1.1  mrg   __extension__ ({                                                      \
    275   1.1  mrg     __typeof(*(mem)) __mask = (__typeof(*(mem)))1 << (bit);             \
    276   1.1  mrg     __mask & arch_atomic_and((mem), ~__mask);                           \
    277   1.1  mrg   })
    278   1.1  mrg 
    279   1.1  mrg #ifdef __tilegx__
    280   1.1  mrg /* Atomically store a new value to memory.
    281   1.1  mrg    Note that you can freely use types of any size here, unlike the
    282   1.1  mrg    other atomic routines, which require 32- or 64-bit types.
    283   1.1  mrg    This accessor is provided for compatibility with TILEPro, which
    284   1.1  mrg    required an explicit atomic operation for stores that needed
    285   1.1  mrg    to be atomic with respect to other atomic methods in this header.  */
    286   1.1  mrg #define arch_atomic_write(mem, value) ((void) (*(mem) = (value)))
    287   1.1  mrg #else
    288   1.1  mrg #define arch_atomic_write(mem, value)                                   \
    289   1.1  mrg   do {                                                                  \
    290   1.1  mrg     __typeof(mem) __aw_mem = (mem);                                     \
    291   1.1  mrg     __typeof(value) __aw_val = (value);                                 \
    292   1.1  mrg     unsigned int *__aw_mem32, __aw_intval, __aw_val32, __aw_off, __aw_mask; \
    293   1.1  mrg     __aw_intval = (__typeof((value) - (value)))__aw_val;                \
    294   1.1  mrg     switch (sizeof(*__aw_mem)) {                                        \
    295   1.1  mrg     case 8:                                                             \
    296   1.1  mrg       __arch_atomic_update_cmpxchg(__aw_mem, __aw_val, __value);        \
    297   1.1  mrg       break;                                                            \
    298   1.1  mrg     case 4:                                                             \
    299   1.1  mrg       __arch_atomic_update_4((int *)__aw_mem, 0, __aw_intval);          \
    300   1.1  mrg       break;                                                            \
    301   1.1  mrg     case 2:                                                             \
    302   1.1  mrg       __aw_off = 8 * ((long)__aw_mem & 0x2);                            \
    303   1.1  mrg       __aw_mask = 0xffffU << __aw_off;                                  \
    304   1.1  mrg       __aw_mem32 = (unsigned int *)((long)__aw_mem & ~0x2);             \
    305   1.1  mrg       __aw_val32 = (__aw_intval << __aw_off) & __aw_mask;               \
    306   1.1  mrg       __arch_atomic_update_cmpxchg(__aw_mem32, __aw_val32,              \
    307   1.1  mrg                                    (__old & ~__aw_mask) | __value);     \
    308   1.1  mrg       break;                                                            \
    309   1.1  mrg     case 1:                                                             \
    310   1.1  mrg       __aw_off = 8 * ((long)__aw_mem & 0x3);                            \
    311   1.1  mrg       __aw_mask = 0xffU << __aw_off;                                    \
    312   1.1  mrg       __aw_mem32 = (unsigned int *)((long)__aw_mem & ~0x3);             \
    313   1.1  mrg       __aw_val32 = (__aw_intval << __aw_off) & __aw_mask;               \
    314   1.1  mrg       __arch_atomic_update_cmpxchg(__aw_mem32, __aw_val32,              \
    315   1.1  mrg                                    (__old & ~__aw_mask) | __value);     \
    316   1.1  mrg       break;                                                            \
    317   1.1  mrg     }                                                                   \
    318   1.1  mrg   } while (0)
    319   1.1  mrg #endif
    320   1.1  mrg 
    321   1.1  mrg /* Compiler barrier.
    322   1.1  mrg 
    323   1.1  mrg    This macro prevents loads or stores from being moved by the compiler
    324   1.1  mrg    across the macro.  Any loaded value that was loaded before this
    325   1.1  mrg    macro must then be reloaded by the compiler.  */
    326   1.1  mrg #define arch_atomic_compiler_barrier() __asm__ __volatile__("" ::: "memory")
    327   1.1  mrg 
    328   1.1  mrg /* Full memory barrier.
    329   1.1  mrg 
    330   1.1  mrg    This macro has the semantics of arch_atomic_compiler_barrer(), but also
    331   1.1  mrg    ensures that previous stores are visible to other cores, and that
    332   1.1  mrg    all previous loaded values have been placed into their target
    333   1.1  mrg    register on this core.  */
    334   1.1  mrg #define arch_atomic_full_barrier() __insn_mf()
    335   1.1  mrg 
    336   1.1  mrg /* Read memory barrier.
    337   1.1  mrg 
    338   1.1  mrg    Ensure that all reads by this processor that occurred prior to the
    339   1.1  mrg    read memory barrier have completed, and that no reads that occur
    340   1.1  mrg    after the read memory barrier on this processor are initiated
    341   1.1  mrg    before the barrier.
    342   1.1  mrg 
    343   1.1  mrg    On current TILE chips a read barrier is implemented as a full barrier,
    344   1.1  mrg    but this may not be true in later versions of the architecture.
    345   1.1  mrg 
    346   1.1  mrg    See also arch_atomic_acquire_barrier() for the appropriate idiom to use
    347   1.1  mrg    to ensure no reads are lifted above an atomic lock instruction.  */
    348   1.1  mrg #define arch_atomic_read_barrier() arch_atomic_full_barrier()
    349   1.1  mrg 
    350   1.1  mrg /* Write memory barrier.
    351   1.1  mrg 
    352   1.1  mrg    Ensure that all writes by this processor that occurred prior to the
    353   1.1  mrg    write memory barrier have completed, and that no writes that occur
    354   1.1  mrg    after the write memory barrier on this processor are initiated
    355   1.1  mrg    before the barrier.
    356   1.1  mrg 
    357   1.1  mrg    On current TILE chips a write barrier is implemented as a full barrier,
    358   1.1  mrg    but this may not be true in later versions of the architecture.
    359   1.1  mrg 
    360   1.1  mrg    See also arch_atomic_release_barrier() for the appropriate idiom to use
    361   1.1  mrg    to ensure all writes are complete prior to an atomic unlock instruction.  */
    362   1.1  mrg #define arch_atomic_write_barrier() arch_atomic_full_barrier()
    363   1.1  mrg 
    364   1.1  mrg /* Lock acquisition barrier.
    365   1.1  mrg 
    366   1.1  mrg    Ensure that no load operations that follow this macro in the
    367   1.1  mrg    program can issue prior to the barrier.  Without such a barrier,
    368   1.1  mrg    the compiler can reorder them to issue earlier, or the hardware can
    369   1.1  mrg    issue them speculatively.  The latter is not currently done in the
    370   1.1  mrg    Tile microarchitecture, but using this operation improves
    371   1.1  mrg    portability to future implementations.
    372   1.1  mrg 
    373   1.1  mrg    This operation is intended to be used as part of the "acquire"
    374   1.1  mrg    path for locking, that is, when entering a critical section.
    375   1.1  mrg    This should be done after the atomic operation that actually
    376   1.1  mrg    acquires the lock, and in conjunction with a "control dependency"
    377   1.1  mrg    that checks the atomic operation result to see if the lock was
    378   1.1  mrg    in fact acquired.  See the arch_atomic_read_barrier() macro
    379   1.1  mrg    for a heavier-weight barrier to use in certain unusual constructs,
    380   1.1  mrg    or arch_atomic_acquire_barrier_value() if no control dependency exists.  */
    381   1.1  mrg #define arch_atomic_acquire_barrier() arch_atomic_compiler_barrier()
    382   1.1  mrg 
    383   1.1  mrg /* Lock release barrier.
    384   1.1  mrg 
    385   1.1  mrg    Ensure that no store operations that precede this macro in the
    386   1.1  mrg    program complete subsequent to the barrier.  Without such a
    387   1.1  mrg    barrier, the compiler can reorder stores to issue later, or stores
    388   1.1  mrg    can be still outstanding in the memory network.
    389   1.1  mrg 
    390   1.1  mrg    This operation is intended to be used as part of the "release" path
    391   1.1  mrg    for locking, that is, when leaving a critical section.  This should
    392   1.1  mrg    be done before the operation (such as a store of zero) that
    393   1.1  mrg    actually releases the lock.  */
    394   1.1  mrg #define arch_atomic_release_barrier() arch_atomic_write_barrier()
    395   1.1  mrg 
    396   1.1  mrg /* Barrier until the read of a particular value is complete.
    397   1.1  mrg 
    398   1.1  mrg    This is occasionally useful when constructing certain locking
    399   1.1  mrg    scenarios.  For example, you might write a routine that issues an
    400   1.1  mrg    atomic instruction to enter a critical section, then reads one or
    401   1.1  mrg    more values within the critical section without checking to see if
    402   1.1  mrg    the critical section was in fact acquired, and only later checks
    403   1.1  mrg    the atomic instruction result to see if the lock was acquired.  If
    404   1.1  mrg    so the routine could properly release the lock and know that the
    405   1.1  mrg    values that were read were valid.
    406   1.1  mrg 
    407   1.1  mrg    In this scenario, it is required to wait for the result of the
    408   1.1  mrg    atomic instruction, even if the value itself is not checked.  This
    409   1.1  mrg    guarantees that if the atomic instruction succeeded in taking the lock,
    410   1.1  mrg    the lock was held before any reads in the critical section issued.  */
    411   1.1  mrg #define arch_atomic_acquire_barrier_value(val) \
    412   1.1  mrg   __asm__ __volatile__("move %0, %0" :: "r"(val))
    413   1.1  mrg 
    414   1.1  mrg /* Access the given variable in memory exactly once.
    415   1.1  mrg 
    416   1.1  mrg    In some contexts, an algorithm may need to force access to memory,
    417   1.1  mrg    since otherwise the compiler may think it can optimize away a
    418   1.1  mrg    memory load or store; for example, in a loop when polling memory to
    419   1.1  mrg    see if another cpu has updated it yet.  Generally this is only
    420   1.1  mrg    required for certain very carefully hand-tuned algorithms; using it
    421   1.1  mrg    unnecessarily may result in performance losses.
    422   1.1  mrg 
    423   1.1  mrg    A related use of this macro is to ensure that the compiler does not
    424   1.1  mrg    rematerialize the value of "x" by reloading it from memory
    425   1.1  mrg    unexpectedly; the "volatile" marking will prevent the compiler from
    426   1.1  mrg    being able to rematerialize.  This is helpful if an algorithm needs
    427   1.1  mrg    to read a variable without locking, but needs it to have the same
    428   1.1  mrg    value if it ends up being used several times within the algorithm.
    429   1.1  mrg 
    430   1.1  mrg    Note that multiple uses of this macro are guaranteed to be ordered,
    431   1.1  mrg    i.e. the compiler will not reorder stores or loads that are wrapped
    432   1.1  mrg    in arch_atomic_access_once().  */
    433   1.1  mrg #define arch_atomic_access_once(x) (*(volatile __typeof(x) *)&(x))
    434   1.1  mrg 
    435   1.1  mrg 
    436   1.1  mrg 
    437   1.1  mrg #endif /* !_ATOMIC_H_ */
    438