(root)/
gcc-13.2.0/
libgcc/
config/
arm/
freebsd-atomic.c
       1  /* FreeBSD specific atomic operations for ARM EABI.
       2     Copyright (C) 2015-2023 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  #include <sys/types.h>
      26  
      27  #define HIDDEN __attribute__ ((visibility ("hidden")))
      28  
      29  #define ARM_VECTORS_HIGH 0xffff0000U
      30  #define ARM_TP_ADDRESS   (ARM_VECTORS_HIGH + 0x1000)
      31  #define ARM_RAS_START    (ARM_TP_ADDRESS + 4)
      32  
      33  void HIDDEN
      34  __sync_synchronize (void)
      35  {
      36  #if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__)       \
      37      || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__)  \
      38      || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__)  \
      39      || defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
      40  #if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
      41      __asm __volatile ("dmb" : : : "memory");
      42  #else
      43      __asm __volatile ("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
      44  #endif
      45  #else
      46      __asm __volatile ("nop" : : : "memory");
      47  #endif
      48  }
      49  
      50  #if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__)        \
      51      || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__)   \
      52      || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__)   \
      53      || defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
      54  
      55  /* These systems should be supported by the compiler.  */
      56  
      57  #else /* __ARM_ARCH_5__  */
      58  
      59  #define	SYNC_LOCK_TEST_AND_SET_N(N, TYPE, LDR, STR)			\
      60  TYPE HIDDEN    								\
      61  __sync_lock_test_and_set_##N (TYPE *mem, TYPE val)			\
      62  {									\
      63          unsigned int old, temp, ras_start;                              \
      64                                                                          \
      65          ras_start = ARM_RAS_START;					\
      66          __asm volatile (						\
      67                  /* Set up Restartable Atomic Sequence.  */		\
      68                  "1:"							\
      69                  "\tadr   %2, 1b\n"					\
      70                  "\tstr   %2, [%5]\n"					\
      71                  "\tadr   %2, 2f\n"					\
      72                  "\tstr   %2, [%5, #4]\n"				\
      73                                                                          \
      74                  "\t"LDR" %0, %4\n"	/* Load old value.  */		\
      75                  "\t"STR" %3, %1\n"	/* Store new value.  */		\
      76                                                                          \
      77                  /* Tear down Restartable Atomic Sequence.  */		\
      78                  "2:"							\
      79                  "\tmov   %2, #0x00000000\n"				\
      80                  "\tstr   %2, [%5]\n"					\
      81                  "\tmov   %2, #0xffffffff\n"				\
      82                  "\tstr   %2, [%5, #4]\n"				\
      83                  : "=&r" (old), "=m" (*mem), "=&r" (temp)		\
      84                  : "r" (val), "m" (*mem), "r" (ras_start));		\
      85          return (old);							\
      86  }
      87  
      88  #define SYNC_LOCK_RELEASE_N(N, TYPE)					\
      89  void HIDDEN								\
      90  __sync_lock_release_##N (TYPE *ptr)     				\
      91  {					       				\
      92      /* All writes before this point must be seen before we release	\
      93         the lock itself.  */						\
      94      __sync_synchronize ();     						\
      95      *ptr = 0;								\
      96  }
      97  
      98  #define	SYNC_VAL_CAS_N(N, TYPE, LDR, STREQ)             		\
      99  TYPE HIDDEN    								\
     100  __sync_val_compare_and_swap_##N (TYPE *mem, TYPE expected,		\
     101      TYPE desired)							\
     102  {									\
     103          unsigned int old, temp, ras_start;                              \
     104                                                                          \
     105          ras_start = ARM_RAS_START;					\
     106          __asm volatile (						\
     107                  /* Set up Restartable Atomic Sequence.  */		\
     108                  "1:"							\
     109                  "\tadr   %2, 1b\n"					\
     110                  "\tstr   %2, [%6]\n"					\
     111                  "\tadr   %2, 2f\n"					\
     112                  "\tstr   %2, [%6, #4]\n"				\
     113                                                                          \
     114                  "\t"LDR" %0, %5\n"     /* Load old value.  */		\
     115                  "\tcmp   %0, %3\n"     /* Compare to expected value.  */\
     116                  "\t"STREQ" %4, %1\n"   /* Store new value.  */		\
     117                                                                          \
     118                  /* Tear down Restartable Atomic Sequence.  */		\
     119                  "2:"							\
     120                  "\tmov   %2, #0x00000000\n"				\
     121                  "\tstr   %2, [%6]\n"					\
     122                  "\tmov   %2, #0xffffffff\n"				\
     123                  "\tstr   %2, [%6, #4]\n"				\
     124                  : "=&r" (old), "=m" (*mem), "=&r" (temp)		\
     125                  : "r" (expected), "r" (desired), "m" (*mem),		\
     126                    "r" (ras_start));					\
     127          return (old);							\
     128  }
     129  
     130  typedef unsigned char bool;
     131  
     132  #define SYNC_BOOL_CAS_N(N, TYPE)                                        \
     133  bool HIDDEN								\
     134  __sync_bool_compare_and_swap_##N (TYPE *ptr, TYPE oldval,		\
     135                                    TYPE newval)                          \
     136  {									\
     137      TYPE actual_oldval							\
     138        = __sync_val_compare_and_swap_##N (ptr, oldval, newval);          \
     139      return (oldval == actual_oldval);					\
     140  }
     141  
     142  #define	SYNC_FETCH_AND_OP_N(N, TYPE, LDR, STR, NAME, OP)		\
     143  TYPE HIDDEN								\
     144  __sync_fetch_and_##NAME##_##N (TYPE *mem, TYPE val)	       		\
     145  {									\
     146          unsigned int old, temp, ras_start;                              \
     147                                                                          \
     148          ras_start = ARM_RAS_START;					\
     149          __asm volatile (						\
     150                  /* Set up Restartable Atomic Sequence.  */		\
     151                  "1:"							\
     152                  "\tadr   %2, 1b\n"					\
     153                  "\tstr   %2, [%5]\n"					\
     154                  "\tadr   %2, 2f\n"					\
     155                  "\tstr   %2, [%5, #4]\n"				\
     156                                                                          \
     157                  "\t"LDR" %0, %4\n"	/* Load old value.  */		\
     158                  "\t"OP"  %2, %0, %3\n"	/* Calculate new value.  */	\
     159                  "\t"STR" %2, %1\n"	/* Store new value.  */		\
     160                                                                          \
     161                  /* Tear down Restartable Atomic Sequence.  */		\
     162                  "2:"							\
     163                  "\tmov   %2, #0x00000000\n"				\
     164                  "\tstr   %2, [%5]\n"					\
     165                  "\tmov   %2, #0xffffffff\n"				\
     166                  "\tstr   %2, [%5, #4]\n"				\
     167                  : "=&r" (old), "=m" (*mem), "=&r" (temp)		\
     168                  : "r" (val), "m" (*mem), "r" (ras_start));		\
     169          return (old);							\
     170  }
     171  
     172  #define	SYNC_OP_AND_FETCH_N(N, TYPE, LDR, STR, NAME, OP)		\
     173  TYPE HIDDEN   								\
     174  __sync_##NAME##_and_fetch_##N (TYPE *mem, TYPE val)			\
     175  {									\
     176          unsigned int old, temp, ras_start, res;                         \
     177                                                                          \
     178          ras_start = ARM_RAS_START;					\
     179          __asm volatile (						\
     180                  /* Set up Restartable Atomic Sequence.  */		\
     181                  "1:"							\
     182                  "\tadr   %2, 1b\n"					\
     183                  "\tstr   %2, [%6]\n"					\
     184                  "\tadr   %2, 2f\n"					\
     185                  "\tstr   %2, [%6, #4]\n"				\
     186                                                                          \
     187                  "\t"LDR" %0, %5\n"	/* Load old value.  */		\
     188                  "\t"OP"  %3, %0, %4\n"	/* Calculate new value.  */	\
     189                  "\t"STR" %3, %1\n"	/* Store new value.  */		\
     190                                                                          \
     191                  /* Tear down Restartable Atomic Sequence.  */		\
     192                  "2:"							\
     193                  "\tmov   %2, #0x00000000\n"				\
     194                  "\tstr   %2, [%6]\n"					\
     195                  "\tmov   %2, #0xffffffff\n"				\
     196                  "\tstr   %2, [%6, #4]\n"				\
     197                  : "=&r" (old), "=m" (*mem), "=&r" (temp), "=&r" (res)	\
     198                  : "r" (val), "m" (*mem), "r" (ras_start));		\
     199          return (res);							\
     200  }
     201  
     202  #define	EMIT_ALL_OPS_N(N, TYPE, LDR, STR, STREQ)			\
     203  SYNC_LOCK_TEST_AND_SET_N (N, TYPE, LDR, STR)				\
     204  SYNC_LOCK_RELEASE_N (N, TYPE)                                           \
     205  SYNC_VAL_CAS_N (N, TYPE, LDR, STREQ)	                		\
     206  SYNC_BOOL_CAS_N (N, TYPE)                                               \
     207  SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, add, "add")		        \
     208  SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, and, "and")		        \
     209  SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, or, "orr")		        \
     210  SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, sub, "sub")		        \
     211  SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, xor, "eor")                     \
     212  SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, add, "add")		        \
     213  SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, and, "and")		        \
     214  SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, or, "orr")		        \
     215  SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, sub, "sub")		        \
     216  SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, xor, "eor")
     217  
     218  
     219  
     220  EMIT_ALL_OPS_N (1, unsigned char, "ldrb", "strb", "streqb")
     221  EMIT_ALL_OPS_N (2, unsigned short, "ldrh", "strh", "streqh")
     222  EMIT_ALL_OPS_N (4, unsigned int, "ldr", "str", "streq")
     223  
     224  #endif