Fix: allow clang to build liburcu on RISC-V
[urcu.git] / include / urcu / uatomic / s390.h
1 // SPDX-FileCopyrightText: 2009 Novell, Inc.
2 // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 //
4 // SPDX-License-Identifier: MIT
5
6 #ifndef _URCU_UATOMIC_ARCH_S390_H
7 #define _URCU_UATOMIC_ARCH_S390_H
8
9 /*
10 * Atomic exchange operations for the S390 architecture. Based on information
11 * taken from the Principles of Operation Appendix A "Conditional Swapping
12 * Instructions (CS, CDS)".
13 *
14 * Author: Jan Blunck <jblunck@suse.de>
15 */
16
17 #include <urcu/compiler.h>
18 #include <urcu/system.h>
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
25 #define COMPILER_HAVE_SHORT_MEM_OPERAND
26 #endif
27
28 /*
29 * MEMOP assembler operand rules:
30 * - op refer to MEMOP_IN operand
31 * - MEMOP_IN can expand to more than a single operand. Use it at the end of
32 * operand list only.
33 */
34
35 #ifdef COMPILER_HAVE_SHORT_MEM_OPERAND
36
37 #define MEMOP_OUT(addr) "=Q" (*(addr))
38 #define MEMOP_IN(addr) "Q" (*(addr))
39 #define MEMOP_REF(op) #op /* op refer to MEMOP_IN operand */
40
41 #else /* !COMPILER_HAVE_SHORT_MEM_OPERAND */
42
43 #define MEMOP_OUT(addr) "=m" (*(addr))
44 #define MEMOP_IN(addr) "a" (addr), "m" (*(addr))
45 #define MEMOP_REF(op) "0(" #op ")" /* op refer to MEMOP_IN operand */
46
47 #endif /* !COMPILER_HAVE_SHORT_MEM_OPERAND */
48
49 /*
50 * The __hp() macro casts the void pointer @x to a pointer to a structure
51 * containing an array of char of the specified size. This allows passing the
52 * @addr arguments of the following inline functions as "m" and "+m" operands
53 * to the assembly. The @size parameter should be a constant to support
54 * compilers such as clang which do not support VLA. Create typedefs because
55 * C++ does not allow types be defined in casts.
56 */
57
58 typedef struct { char v[4]; } __hp_4;
59 typedef struct { char v[8]; } __hp_8;
60
61 #define __hp(size, x) ((__hp_##size *)(x))
62
63 /* xchg */
64
65 static inline __attribute__((always_inline))
66 unsigned long _uatomic_exchange(volatile void *addr, unsigned long val, int len)
67 {
68 switch (len) {
69 case 4:
70 {
71 unsigned int old_val;
72
73 __asm__ __volatile__(
74 "0: cs %0,%2," MEMOP_REF(%3) "\n"
75 " brc 4,0b\n"
76 : "=&r" (old_val), MEMOP_OUT (__hp(4, addr))
77 : "r" (val), MEMOP_IN (__hp(4, addr))
78 : "memory", "cc");
79 return old_val;
80 }
81 #if (CAA_BITS_PER_LONG == 64)
82 case 8:
83 {
84 unsigned long old_val;
85
86 __asm__ __volatile__(
87 "0: csg %0,%2," MEMOP_REF(%3) "\n"
88 " brc 4,0b\n"
89 : "=&r" (old_val), MEMOP_OUT (__hp(8, addr))
90 : "r" (val), MEMOP_IN (__hp(8, addr))
91 : "memory", "cc");
92 return old_val;
93 }
94 #endif
95 default:
96 __asm__ __volatile__(".long 0xd00d00");
97 }
98
99 return 0;
100 }
101
102 #define uatomic_xchg(addr, v) \
103 (__typeof__(*(addr))) _uatomic_exchange((addr), \
104 caa_cast_long_keep_sign(v), \
105 sizeof(*(addr)))
106
107 /* cmpxchg */
108
109 static inline __attribute__((always_inline))
110 unsigned long _uatomic_cmpxchg(void *addr, unsigned long old,
111 unsigned long _new, int len)
112 {
113 switch (len) {
114 case 4:
115 {
116 unsigned int old_val = (unsigned int)old;
117
118 __asm__ __volatile__(
119 " cs %0,%2," MEMOP_REF(%3) "\n"
120 : "+r" (old_val), MEMOP_OUT (__hp(4, addr))
121 : "r" (_new), MEMOP_IN (__hp(4, addr))
122 : "memory", "cc");
123 return old_val;
124 }
125 #if (CAA_BITS_PER_LONG == 64)
126 case 8:
127 {
128 __asm__ __volatile__(
129 " csg %0,%2," MEMOP_REF(%3) "\n"
130 : "+r" (old), MEMOP_OUT (__hp(8, addr))
131 : "r" (_new), MEMOP_IN (__hp(8, addr))
132 : "memory", "cc");
133 return old;
134 }
135 #endif
136 default:
137 __asm__ __volatile__(".long 0xd00d00");
138 }
139
140 return 0;
141 }
142
143 #define uatomic_cmpxchg(addr, old, _new) \
144 (__typeof__(*(addr))) _uatomic_cmpxchg((addr), \
145 caa_cast_long_keep_sign(old), \
146 caa_cast_long_keep_sign(_new),\
147 sizeof(*(addr)))
148
149 #ifdef __cplusplus
150 }
151 #endif
152
153 #include <urcu/uatomic/generic.h>
154
155 #endif /* _URCU_UATOMIC_ARCH_S390_H */
This page took 0.0323 seconds and 4 git commands to generate.