xref: /freebsd/sys/contrib/ck/include/gcc/x86/ck_pr.h (revision 74e9b5f29ad0056bbe11a30c91dfa0705fa19cd5)
11fb62fb0SOlivier Houchard /*
21fb62fb0SOlivier Houchard  * Copyright 2009-2015 Samy Al Bahra.
31fb62fb0SOlivier Houchard  * Copyright 2011 Devon H. O'Dell <devon.odell@gmail.com>
41fb62fb0SOlivier Houchard  * All rights reserved.
51fb62fb0SOlivier Houchard  *
61fb62fb0SOlivier Houchard  * Redistribution and use in source and binary forms, with or without
71fb62fb0SOlivier Houchard  * modification, are permitted provided that the following conditions
81fb62fb0SOlivier Houchard  * are met:
91fb62fb0SOlivier Houchard  * 1. Redistributions of source code must retain the above copyright
101fb62fb0SOlivier Houchard  *    notice, this list of conditions and the following disclaimer.
111fb62fb0SOlivier Houchard  * 2. Redistributions in binary form must reproduce the above copyright
121fb62fb0SOlivier Houchard  *    notice, this list of conditions and the following disclaimer in the
131fb62fb0SOlivier Houchard  *    documentation and/or other materials provided with the distribution.
141fb62fb0SOlivier Houchard  *
151fb62fb0SOlivier Houchard  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161fb62fb0SOlivier Houchard  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171fb62fb0SOlivier Houchard  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181fb62fb0SOlivier Houchard  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191fb62fb0SOlivier Houchard  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201fb62fb0SOlivier Houchard  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211fb62fb0SOlivier Houchard  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221fb62fb0SOlivier Houchard  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231fb62fb0SOlivier Houchard  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241fb62fb0SOlivier Houchard  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251fb62fb0SOlivier Houchard  * SUCH DAMAGE.
261fb62fb0SOlivier Houchard  */
271fb62fb0SOlivier Houchard 
281fb62fb0SOlivier Houchard #ifndef CK_PR_X86_H
291fb62fb0SOlivier Houchard #define CK_PR_X86_H
301fb62fb0SOlivier Houchard 
311fb62fb0SOlivier Houchard #ifndef CK_PR_H
321fb62fb0SOlivier Houchard #error Do not include this file directly, use ck_pr.h
331fb62fb0SOlivier Houchard #endif
341fb62fb0SOlivier Houchard 
351fb62fb0SOlivier Houchard #include <ck_cc.h>
361fb62fb0SOlivier Houchard #include <ck_md.h>
371fb62fb0SOlivier Houchard #include <ck_stdint.h>
381fb62fb0SOlivier Houchard 
391fb62fb0SOlivier Houchard /*
401fb62fb0SOlivier Houchard  * The following represent supported atomic operations.
411fb62fb0SOlivier Houchard  * These operations may be emulated.
421fb62fb0SOlivier Houchard  */
431fb62fb0SOlivier Houchard #include "ck_f_pr.h"
441fb62fb0SOlivier Houchard 
451fb62fb0SOlivier Houchard /* Minimum requirements for the CK_PR interface are met. */
461fb62fb0SOlivier Houchard #define CK_F_PR
471fb62fb0SOlivier Houchard 
481fb62fb0SOlivier Houchard /*
49271ce402SOlivier Houchard  * Prevent speculative execution in busy-wait loops (P4 <=) or "predefined
50271ce402SOlivier Houchard  * delay".
511fb62fb0SOlivier Houchard  */
521fb62fb0SOlivier Houchard CK_CC_INLINE static void
ck_pr_stall(void)531fb62fb0SOlivier Houchard ck_pr_stall(void)
541fb62fb0SOlivier Houchard {
551fb62fb0SOlivier Houchard 	__asm__ __volatile__("pause" ::: "memory");
561fb62fb0SOlivier Houchard 	return;
571fb62fb0SOlivier Houchard }
581fb62fb0SOlivier Houchard 
59271ce402SOlivier Houchard #ifdef CK_MD_UMP
60271ce402SOlivier Houchard #define CK_PR_LOCK_PREFIX
61271ce402SOlivier Houchard #define CK_PR_FENCE(T, I)				\
62271ce402SOlivier Houchard 	CK_CC_INLINE static void			\
63271ce402SOlivier Houchard 	ck_pr_fence_strict_##T(void)			\
64271ce402SOlivier Houchard 	{						\
65271ce402SOlivier Houchard 		__asm__ __volatile__("" ::: "memory");	\
66271ce402SOlivier Houchard 		return;					\
67271ce402SOlivier Houchard 	}
68271ce402SOlivier Houchard #else
69271ce402SOlivier Houchard #define CK_PR_LOCK_PREFIX "lock "
701fb62fb0SOlivier Houchard #define CK_PR_FENCE(T, I)				\
711fb62fb0SOlivier Houchard 	CK_CC_INLINE static void			\
721fb62fb0SOlivier Houchard 	ck_pr_fence_strict_##T(void)			\
731fb62fb0SOlivier Houchard 	{						\
741fb62fb0SOlivier Houchard 		__asm__ __volatile__(I ::: "memory");	\
75271ce402SOlivier Houchard 		return;					\
761fb62fb0SOlivier Houchard 	}
77271ce402SOlivier Houchard #endif /* CK_MD_UMP */
781fb62fb0SOlivier Houchard 
79271ce402SOlivier Houchard #if defined(CK_MD_SSE_DISABLE)
80271ce402SOlivier Houchard /* If SSE is disabled, then use atomic operations for serialization. */
81271ce402SOlivier Houchard #define CK_MD_X86_MFENCE "lock addl $0, (%%esp)"
82271ce402SOlivier Houchard #define CK_MD_X86_SFENCE CK_MD_X86_MFENCE
83271ce402SOlivier Houchard #define CK_MD_X86_LFENCE CK_MD_X86_MFENCE
84271ce402SOlivier Houchard #else
85271ce402SOlivier Houchard #define CK_MD_X86_SFENCE "sfence"
86271ce402SOlivier Houchard #define CK_MD_X86_LFENCE "lfence"
87271ce402SOlivier Houchard #define CK_MD_X86_MFENCE "mfence"
88271ce402SOlivier Houchard #endif /* !CK_MD_SSE_DISABLE */
89271ce402SOlivier Houchard 
90271ce402SOlivier Houchard CK_PR_FENCE(atomic, "")
91271ce402SOlivier Houchard CK_PR_FENCE(atomic_store, "")
92271ce402SOlivier Houchard CK_PR_FENCE(atomic_load, "")
93271ce402SOlivier Houchard CK_PR_FENCE(store_atomic, "")
94271ce402SOlivier Houchard CK_PR_FENCE(load_atomic, "")
95271ce402SOlivier Houchard CK_PR_FENCE(load, CK_MD_X86_LFENCE)
96271ce402SOlivier Houchard CK_PR_FENCE(load_store, CK_MD_X86_MFENCE)
97271ce402SOlivier Houchard CK_PR_FENCE(store, CK_MD_X86_SFENCE)
98271ce402SOlivier Houchard CK_PR_FENCE(store_load, CK_MD_X86_MFENCE)
99271ce402SOlivier Houchard CK_PR_FENCE(memory, CK_MD_X86_MFENCE)
100271ce402SOlivier Houchard CK_PR_FENCE(release, CK_MD_X86_MFENCE)
101271ce402SOlivier Houchard CK_PR_FENCE(acquire, CK_MD_X86_MFENCE)
102271ce402SOlivier Houchard CK_PR_FENCE(acqrel, CK_MD_X86_MFENCE)
103271ce402SOlivier Houchard CK_PR_FENCE(lock, CK_MD_X86_MFENCE)
104271ce402SOlivier Houchard CK_PR_FENCE(unlock, CK_MD_X86_MFENCE)
1051fb62fb0SOlivier Houchard 
1061fb62fb0SOlivier Houchard #undef CK_PR_FENCE
1071fb62fb0SOlivier Houchard 
1081fb62fb0SOlivier Houchard /*
1091fb62fb0SOlivier Houchard  * Atomic fetch-and-store operations.
1101fb62fb0SOlivier Houchard  */
1111fb62fb0SOlivier Houchard #define CK_PR_FAS(S, M, T, C, I)				\
1121fb62fb0SOlivier Houchard 	CK_CC_INLINE static T					\
1131fb62fb0SOlivier Houchard 	ck_pr_fas_##S(M *target, T v)				\
1141fb62fb0SOlivier Houchard 	{							\
1151fb62fb0SOlivier Houchard 		__asm__ __volatile__(I " %0, %1"		\
1161fb62fb0SOlivier Houchard 					: "+m" (*(C *)target),	\
1171fb62fb0SOlivier Houchard 					  "+q" (v)		\
1181fb62fb0SOlivier Houchard 					:			\
1191fb62fb0SOlivier Houchard 					: "memory");		\
1201fb62fb0SOlivier Houchard 		return v;					\
1211fb62fb0SOlivier Houchard 	}
1221fb62fb0SOlivier Houchard 
123*74e9b5f2SOlivier Houchard CK_PR_FAS(ptr, void, void *, uint32_t, "xchgl")
1241fb62fb0SOlivier Houchard 
1251fb62fb0SOlivier Houchard #define CK_PR_FAS_S(S, T, I) CK_PR_FAS(S, T, T, T, I)
1261fb62fb0SOlivier Houchard 
1271fb62fb0SOlivier Houchard CK_PR_FAS_S(char, char, "xchgb")
1281fb62fb0SOlivier Houchard CK_PR_FAS_S(uint, unsigned int, "xchgl")
1291fb62fb0SOlivier Houchard CK_PR_FAS_S(int, int, "xchgl")
1301fb62fb0SOlivier Houchard CK_PR_FAS_S(32, uint32_t, "xchgl")
1311fb62fb0SOlivier Houchard CK_PR_FAS_S(16, uint16_t, "xchgw")
1321fb62fb0SOlivier Houchard CK_PR_FAS_S(8,  uint8_t,  "xchgb")
1331fb62fb0SOlivier Houchard 
1341fb62fb0SOlivier Houchard #undef CK_PR_FAS_S
1351fb62fb0SOlivier Houchard #undef CK_PR_FAS
1361fb62fb0SOlivier Houchard 
1371fb62fb0SOlivier Houchard #define CK_PR_LOAD(S, M, T, C, I)					\
1381fb62fb0SOlivier Houchard 	CK_CC_INLINE static T						\
1391fb62fb0SOlivier Houchard 	ck_pr_md_load_##S(const M *target)				\
1401fb62fb0SOlivier Houchard 	{								\
1411fb62fb0SOlivier Houchard 		T r;							\
1421fb62fb0SOlivier Houchard 		__asm__ __volatile__(I " %1, %0"			\
1431fb62fb0SOlivier Houchard 					: "=q" (r)			\
1441fb62fb0SOlivier Houchard 					: "m"  (*(const C *)target)	\
1451fb62fb0SOlivier Houchard 					: "memory");			\
1461fb62fb0SOlivier Houchard 		return (r);						\
1471fb62fb0SOlivier Houchard 	}
1481fb62fb0SOlivier Houchard 
149*74e9b5f2SOlivier Houchard CK_PR_LOAD(ptr, void, void *, uint32_t, "movl")
1501fb62fb0SOlivier Houchard 
1511fb62fb0SOlivier Houchard #define CK_PR_LOAD_S(S, T, I) CK_PR_LOAD(S, T, T, T, I)
1521fb62fb0SOlivier Houchard 
1531fb62fb0SOlivier Houchard CK_PR_LOAD_S(char, char, "movb")
1541fb62fb0SOlivier Houchard CK_PR_LOAD_S(uint, unsigned int, "movl")
1551fb62fb0SOlivier Houchard CK_PR_LOAD_S(int, int, "movl")
1561fb62fb0SOlivier Houchard CK_PR_LOAD_S(32, uint32_t, "movl")
1571fb62fb0SOlivier Houchard CK_PR_LOAD_S(16, uint16_t, "movw")
1581fb62fb0SOlivier Houchard CK_PR_LOAD_S(8,  uint8_t,  "movb")
1591fb62fb0SOlivier Houchard 
1601fb62fb0SOlivier Houchard #undef CK_PR_LOAD_S
1611fb62fb0SOlivier Houchard #undef CK_PR_LOAD
1621fb62fb0SOlivier Houchard 
1631fb62fb0SOlivier Houchard #define CK_PR_STORE(S, M, T, C, I)				\
1641fb62fb0SOlivier Houchard 	CK_CC_INLINE static void				\
1651fb62fb0SOlivier Houchard 	ck_pr_md_store_##S(M *target, T v)			\
1661fb62fb0SOlivier Houchard 	{							\
1671fb62fb0SOlivier Houchard 		__asm__ __volatile__(I " %1, %0"		\
1681fb62fb0SOlivier Houchard 					: "=m" (*(C *)target)	\
1691fb62fb0SOlivier Houchard 					: CK_CC_IMM "q" (v)	\
1701fb62fb0SOlivier Houchard 					: "memory");		\
1711fb62fb0SOlivier Houchard 		return;						\
1721fb62fb0SOlivier Houchard 	}
1731fb62fb0SOlivier Houchard 
174*74e9b5f2SOlivier Houchard CK_PR_STORE(ptr, void, const void *, uint32_t, "movl")
1751fb62fb0SOlivier Houchard 
1761fb62fb0SOlivier Houchard #define CK_PR_STORE_S(S, T, I) CK_PR_STORE(S, T, T, T, I)
1771fb62fb0SOlivier Houchard 
1781fb62fb0SOlivier Houchard CK_PR_STORE_S(char, char, "movb")
1791fb62fb0SOlivier Houchard CK_PR_STORE_S(uint, unsigned int, "movl")
1801fb62fb0SOlivier Houchard CK_PR_STORE_S(int, int, "movl")
1811fb62fb0SOlivier Houchard CK_PR_STORE_S(32, uint32_t, "movl")
1821fb62fb0SOlivier Houchard CK_PR_STORE_S(16, uint16_t, "movw")
1831fb62fb0SOlivier Houchard CK_PR_STORE_S(8,  uint8_t, "movb")
1841fb62fb0SOlivier Houchard 
1851fb62fb0SOlivier Houchard #undef CK_PR_STORE_S
1861fb62fb0SOlivier Houchard #undef CK_PR_STORE
1871fb62fb0SOlivier Houchard 
1881fb62fb0SOlivier Houchard /*
1891fb62fb0SOlivier Houchard  * Atomic fetch-and-add operations.
1901fb62fb0SOlivier Houchard  */
1911fb62fb0SOlivier Houchard #define CK_PR_FAA(S, M, T, C, I)					\
1921fb62fb0SOlivier Houchard 	CK_CC_INLINE static T						\
1931fb62fb0SOlivier Houchard 	ck_pr_faa_##S(M *target, T d)					\
1941fb62fb0SOlivier Houchard 	{								\
1951fb62fb0SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0"	\
1961fb62fb0SOlivier Houchard 					: "+m" (*(C *)target),		\
1971fb62fb0SOlivier Houchard 					  "+q" (d)			\
1981fb62fb0SOlivier Houchard 					:				\
1991fb62fb0SOlivier Houchard 					: "memory", "cc");		\
2001fb62fb0SOlivier Houchard 		return (d);						\
2011fb62fb0SOlivier Houchard 	}
2021fb62fb0SOlivier Houchard 
203*74e9b5f2SOlivier Houchard CK_PR_FAA(ptr, void, uintptr_t, uint32_t, "xaddl")
2041fb62fb0SOlivier Houchard 
2051fb62fb0SOlivier Houchard #define CK_PR_FAA_S(S, T, I) CK_PR_FAA(S, T, T, T, I)
2061fb62fb0SOlivier Houchard 
2071fb62fb0SOlivier Houchard CK_PR_FAA_S(char, char, "xaddb")
2081fb62fb0SOlivier Houchard CK_PR_FAA_S(uint, unsigned int, "xaddl")
2091fb62fb0SOlivier Houchard CK_PR_FAA_S(int, int, "xaddl")
2101fb62fb0SOlivier Houchard CK_PR_FAA_S(32, uint32_t, "xaddl")
2111fb62fb0SOlivier Houchard CK_PR_FAA_S(16, uint16_t, "xaddw")
2121fb62fb0SOlivier Houchard CK_PR_FAA_S(8,  uint8_t,  "xaddb")
2131fb62fb0SOlivier Houchard 
2141fb62fb0SOlivier Houchard #undef CK_PR_FAA_S
2151fb62fb0SOlivier Houchard #undef CK_PR_FAA
2161fb62fb0SOlivier Houchard 
2171fb62fb0SOlivier Houchard /*
2181fb62fb0SOlivier Houchard  * Atomic store-only unary operations.
2191fb62fb0SOlivier Houchard  */
2201fb62fb0SOlivier Houchard #define CK_PR_UNARY(K, S, T, C, I)				\
2211fb62fb0SOlivier Houchard 	CK_PR_UNARY_R(K, S, T, C, I)				\
2221fb62fb0SOlivier Houchard 	CK_PR_UNARY_V(K, S, T, C, I)
2231fb62fb0SOlivier Houchard 
2241fb62fb0SOlivier Houchard #define CK_PR_UNARY_R(K, S, T, C, I)				\
2251fb62fb0SOlivier Houchard 	CK_CC_INLINE static void				\
2261fb62fb0SOlivier Houchard 	ck_pr_##K##_##S(T *target)				\
2271fb62fb0SOlivier Houchard 	{							\
2281fb62fb0SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0"	\
2291fb62fb0SOlivier Houchard 					: "+m" (*(C *)target)	\
2301fb62fb0SOlivier Houchard 					:			\
2311fb62fb0SOlivier Houchard 					: "memory", "cc");	\
2321fb62fb0SOlivier Houchard 		return;						\
2331fb62fb0SOlivier Houchard 	}
2341fb62fb0SOlivier Houchard 
2351fb62fb0SOlivier Houchard #define CK_PR_UNARY_V(K, S, T, C, I)					\
236725de581SAndriy Gapon 	CK_CC_INLINE static bool					\
237725de581SAndriy Gapon 	ck_pr_##K##_##S##_is_zero(T *target)				\
2381fb62fb0SOlivier Houchard 	{								\
239725de581SAndriy Gapon 		bool ret;						\
2401fb62fb0SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %0; setz %1"	\
2411fb62fb0SOlivier Houchard 					: "+m" (*(C *)target),		\
242*74e9b5f2SOlivier Houchard 					  "=qm" (ret)			\
2431fb62fb0SOlivier Houchard 					:				\
2441fb62fb0SOlivier Houchard 					: "memory", "cc");		\
245725de581SAndriy Gapon 		return ret;						\
2461fb62fb0SOlivier Houchard 	}
2471fb62fb0SOlivier Houchard 
2481fb62fb0SOlivier Houchard #define CK_PR_UNARY_S(K, S, T, I) CK_PR_UNARY(K, S, T, T, I)
2491fb62fb0SOlivier Houchard 
2501fb62fb0SOlivier Houchard #define CK_PR_GENERATE(K)				\
251*74e9b5f2SOlivier Houchard 	CK_PR_UNARY(K, ptr, void, uint32_t, #K "l") 	\
2521fb62fb0SOlivier Houchard 	CK_PR_UNARY_S(K, char, char, #K "b")		\
2531fb62fb0SOlivier Houchard 	CK_PR_UNARY_S(K, int, int, #K "l")		\
2541fb62fb0SOlivier Houchard 	CK_PR_UNARY_S(K, uint, unsigned int, #K "l")	\
2551fb62fb0SOlivier Houchard 	CK_PR_UNARY_S(K, 32, uint32_t, #K "l")		\
2561fb62fb0SOlivier Houchard 	CK_PR_UNARY_S(K, 16, uint16_t, #K "w")		\
2571fb62fb0SOlivier Houchard 	CK_PR_UNARY_S(K, 8, uint8_t, #K "b")
2581fb62fb0SOlivier Houchard 
2591fb62fb0SOlivier Houchard CK_PR_GENERATE(inc)
2601fb62fb0SOlivier Houchard CK_PR_GENERATE(dec)
2611fb62fb0SOlivier Houchard CK_PR_GENERATE(neg)
2621fb62fb0SOlivier Houchard 
2631fb62fb0SOlivier Houchard /* not does not affect condition flags. */
2641fb62fb0SOlivier Houchard #undef CK_PR_UNARY_V
2651fb62fb0SOlivier Houchard #define CK_PR_UNARY_V(a, b, c, d, e)
2661fb62fb0SOlivier Houchard CK_PR_GENERATE(not)
2671fb62fb0SOlivier Houchard 
2681fb62fb0SOlivier Houchard #undef CK_PR_GENERATE
2691fb62fb0SOlivier Houchard #undef CK_PR_UNARY_S
2701fb62fb0SOlivier Houchard #undef CK_PR_UNARY_V
2711fb62fb0SOlivier Houchard #undef CK_PR_UNARY_R
2721fb62fb0SOlivier Houchard #undef CK_PR_UNARY
2731fb62fb0SOlivier Houchard 
2741fb62fb0SOlivier Houchard /*
2751fb62fb0SOlivier Houchard  * Atomic store-only binary operations.
2761fb62fb0SOlivier Houchard  */
2771fb62fb0SOlivier Houchard #define CK_PR_BINARY(K, S, M, T, C, I)					\
2781fb62fb0SOlivier Houchard 	CK_CC_INLINE static void					\
2791fb62fb0SOlivier Houchard 	ck_pr_##K##_##S(M *target, T d)					\
2801fb62fb0SOlivier Houchard 	{								\
2811fb62fb0SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %1, %0"	\
2821fb62fb0SOlivier Houchard 					: "+m" (*(C *)target)		\
2831fb62fb0SOlivier Houchard 					: CK_CC_IMM "q" (d)		\
2841fb62fb0SOlivier Houchard 					: "memory", "cc");		\
2851fb62fb0SOlivier Houchard 		return;							\
2861fb62fb0SOlivier Houchard 	}
2871fb62fb0SOlivier Houchard 
2881fb62fb0SOlivier Houchard #define CK_PR_BINARY_S(K, S, T, I) CK_PR_BINARY(K, S, T, T, T, I)
2891fb62fb0SOlivier Houchard 
2901fb62fb0SOlivier Houchard #define CK_PR_GENERATE(K)					\
291*74e9b5f2SOlivier Houchard 	CK_PR_BINARY(K, ptr, void, uintptr_t, uint32_t, #K "l")	\
2921fb62fb0SOlivier Houchard 	CK_PR_BINARY_S(K, char, char, #K "b")			\
2931fb62fb0SOlivier Houchard 	CK_PR_BINARY_S(K, int, int, #K "l")			\
2941fb62fb0SOlivier Houchard 	CK_PR_BINARY_S(K, uint, unsigned int, #K "l")		\
2951fb62fb0SOlivier Houchard 	CK_PR_BINARY_S(K, 32, uint32_t, #K "l")			\
2961fb62fb0SOlivier Houchard 	CK_PR_BINARY_S(K, 16, uint16_t, #K "w")			\
2971fb62fb0SOlivier Houchard 	CK_PR_BINARY_S(K, 8, uint8_t, #K "b")
2981fb62fb0SOlivier Houchard 
2991fb62fb0SOlivier Houchard CK_PR_GENERATE(add)
3001fb62fb0SOlivier Houchard CK_PR_GENERATE(sub)
3011fb62fb0SOlivier Houchard CK_PR_GENERATE(and)
3021fb62fb0SOlivier Houchard CK_PR_GENERATE(or)
3031fb62fb0SOlivier Houchard CK_PR_GENERATE(xor)
3041fb62fb0SOlivier Houchard 
3051fb62fb0SOlivier Houchard #undef CK_PR_GENERATE
3061fb62fb0SOlivier Houchard #undef CK_PR_BINARY_S
3071fb62fb0SOlivier Houchard #undef CK_PR_BINARY
3081fb62fb0SOlivier Houchard 
3091fb62fb0SOlivier Houchard /*
310*74e9b5f2SOlivier Houchard  * Atomic compare and swap, with a variant that sets *v to the old value of target.
3111fb62fb0SOlivier Houchard  */
312*74e9b5f2SOlivier Houchard #ifdef __GCC_ASM_FLAG_OUTPUTS__
313*74e9b5f2SOlivier Houchard #define CK_PR_CAS(S, M, T, C, I)						\
314*74e9b5f2SOlivier Houchard 	CK_CC_INLINE static bool						\
315*74e9b5f2SOlivier Houchard 	ck_pr_cas_##S(M *target, T compare, T set)				\
316*74e9b5f2SOlivier Houchard 	{									\
317*74e9b5f2SOlivier Houchard 		bool z;								\
318*74e9b5f2SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %3, %0"		\
319*74e9b5f2SOlivier Houchard 					: "+m"    (*(C *)target),		\
320*74e9b5f2SOlivier Houchard 					  "=@ccz" (z),				\
321*74e9b5f2SOlivier Houchard 					  /* RAX is clobbered by cmpxchg. */	\
322*74e9b5f2SOlivier Houchard 					  "+a"    (compare)			\
323*74e9b5f2SOlivier Houchard 					: "q"     (set)				\
324*74e9b5f2SOlivier Houchard 					: "memory", "cc");			\
325*74e9b5f2SOlivier Houchard 		return z;							\
326*74e9b5f2SOlivier Houchard 	}									\
327*74e9b5f2SOlivier Houchard 										\
328*74e9b5f2SOlivier Houchard 	CK_CC_INLINE static bool						\
329*74e9b5f2SOlivier Houchard 	ck_pr_cas_##S##_value(M *target, T compare, T set, M *v)		\
330*74e9b5f2SOlivier Houchard 	{									\
331*74e9b5f2SOlivier Houchard 		bool z;								\
332*74e9b5f2SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %3, %0;"		\
333*74e9b5f2SOlivier Houchard 					: "+m"    (*(C *)target),		\
334*74e9b5f2SOlivier Houchard 					  "=@ccz" (z),				\
335*74e9b5f2SOlivier Houchard 					  "+a"    (compare)			\
336*74e9b5f2SOlivier Houchard 					: "q"     (set)				\
337*74e9b5f2SOlivier Houchard 					: "memory", "cc");			\
338*74e9b5f2SOlivier Houchard 		*(T *)v = compare;						\
339*74e9b5f2SOlivier Houchard 		return z;							\
340*74e9b5f2SOlivier Houchard 	}
341*74e9b5f2SOlivier Houchard #else
3421fb62fb0SOlivier Houchard #define CK_PR_CAS(S, M, T, C, I)						\
3431fb62fb0SOlivier Houchard 	CK_CC_INLINE static bool						\
3441fb62fb0SOlivier Houchard 	ck_pr_cas_##S(M *target, T compare, T set)				\
3451fb62fb0SOlivier Houchard 	{									\
3461fb62fb0SOlivier Houchard 		bool z;								\
3471fb62fb0SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %2, %0; setz %1"	\
3481fb62fb0SOlivier Houchard 					: "+m"  (*(C *)target),			\
3491fb62fb0SOlivier Houchard 					  "=a"  (z)				\
3501fb62fb0SOlivier Houchard 					: "q"   (set),				\
3511fb62fb0SOlivier Houchard 					  "a"   (compare)			\
3521fb62fb0SOlivier Houchard 					: "memory", "cc");			\
3531fb62fb0SOlivier Houchard 		return z;							\
354*74e9b5f2SOlivier Houchard 	}									\
355*74e9b5f2SOlivier Houchard 										\
356*74e9b5f2SOlivier Houchard 	CK_CC_INLINE static bool						\
357*74e9b5f2SOlivier Houchard 	ck_pr_cas_##S##_value(M *target, T compare, T set, M *v)		\
358*74e9b5f2SOlivier Houchard 	{									\
359*74e9b5f2SOlivier Houchard 		bool z;								\
360*74e9b5f2SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I " %3, %0;"		\
361*74e9b5f2SOlivier Houchard 				     "setz %1;"					\
362*74e9b5f2SOlivier Houchard 					: "+m"  (*(C *)target),			\
363*74e9b5f2SOlivier Houchard 					  "=q"  (z),				\
364*74e9b5f2SOlivier Houchard 					  "+a"  (compare)			\
365*74e9b5f2SOlivier Houchard 					: "q"   (set)				\
366*74e9b5f2SOlivier Houchard 					: "memory", "cc");			\
367*74e9b5f2SOlivier Houchard 		*(T *)v = compare;						\
368*74e9b5f2SOlivier Houchard 		return z;							\
3691fb62fb0SOlivier Houchard 	}
370*74e9b5f2SOlivier Houchard #endif
3711fb62fb0SOlivier Houchard 
372*74e9b5f2SOlivier Houchard CK_PR_CAS(ptr, void, void *, uint32_t, "cmpxchgl")
3731fb62fb0SOlivier Houchard 
3741fb62fb0SOlivier Houchard #define CK_PR_CAS_S(S, T, I) CK_PR_CAS(S, T, T, T, I)
3751fb62fb0SOlivier Houchard 
3761fb62fb0SOlivier Houchard CK_PR_CAS_S(char, char, "cmpxchgb")
3771fb62fb0SOlivier Houchard CK_PR_CAS_S(int, int, "cmpxchgl")
3781fb62fb0SOlivier Houchard CK_PR_CAS_S(uint, unsigned int, "cmpxchgl")
3791fb62fb0SOlivier Houchard CK_PR_CAS_S(32, uint32_t, "cmpxchgl")
3801fb62fb0SOlivier Houchard CK_PR_CAS_S(16, uint16_t, "cmpxchgw")
3811fb62fb0SOlivier Houchard CK_PR_CAS_S(8,  uint8_t,  "cmpxchgb")
3821fb62fb0SOlivier Houchard 
3831fb62fb0SOlivier Houchard #undef CK_PR_CAS_S
3841fb62fb0SOlivier Houchard #undef CK_PR_CAS
3851fb62fb0SOlivier Houchard 
3861fb62fb0SOlivier Houchard /*
3871fb62fb0SOlivier Houchard  * Atomic bit test operations.
3881fb62fb0SOlivier Houchard  */
3891fb62fb0SOlivier Houchard #define CK_PR_BT(K, S, T, P, C, I)					\
3901fb62fb0SOlivier Houchard 	CK_CC_INLINE static bool					\
3911fb62fb0SOlivier Houchard 	ck_pr_##K##_##S(T *target, unsigned int b)			\
3921fb62fb0SOlivier Houchard 	{								\
3931fb62fb0SOlivier Houchard 		bool c;							\
3941fb62fb0SOlivier Houchard 		__asm__ __volatile__(CK_PR_LOCK_PREFIX I "; setc %1"	\
3951fb62fb0SOlivier Houchard 					: "+m" (*(C *)target),		\
3961fb62fb0SOlivier Houchard 					  "=q" (c)			\
3971fb62fb0SOlivier Houchard 					: "q"  ((P)b)			\
3981fb62fb0SOlivier Houchard 					: "memory", "cc");		\
3991fb62fb0SOlivier Houchard 		return (bool)c;						\
4001fb62fb0SOlivier Houchard 	}
4011fb62fb0SOlivier Houchard 
4021fb62fb0SOlivier Houchard #define CK_PR_BT_S(K, S, T, I) CK_PR_BT(K, S, T, T, T, I)
4031fb62fb0SOlivier Houchard 
4041fb62fb0SOlivier Houchard #define CK_PR_GENERATE(K)						\
405*74e9b5f2SOlivier Houchard 	CK_PR_BT(K, ptr, void, uint32_t, uint32_t, #K "l %2, %0")	\
4061fb62fb0SOlivier Houchard 	CK_PR_BT_S(K, uint, unsigned int, #K "l %2, %0")		\
4071fb62fb0SOlivier Houchard 	CK_PR_BT_S(K, int, int, #K "l %2, %0")				\
4081fb62fb0SOlivier Houchard 	CK_PR_BT_S(K, 32, uint32_t, #K "l %2, %0")			\
4091fb62fb0SOlivier Houchard 	CK_PR_BT_S(K, 16, uint16_t, #K "w %w2, %0")
4101fb62fb0SOlivier Houchard 
4111fb62fb0SOlivier Houchard CK_PR_GENERATE(btc)
4121fb62fb0SOlivier Houchard CK_PR_GENERATE(bts)
4131fb62fb0SOlivier Houchard CK_PR_GENERATE(btr)
4141fb62fb0SOlivier Houchard 
4151fb62fb0SOlivier Houchard #undef CK_PR_GENERATE
4161fb62fb0SOlivier Houchard #undef CK_PR_BT
4171fb62fb0SOlivier Houchard 
4181fb62fb0SOlivier Houchard #endif /* CK_PR_X86_H */
4191fb62fb0SOlivier Houchard 
420