1/*	$NetBSD: atomic.h,v 1.6 2020/05/25 20:47:24 christos Exp $	*/
2
3/*
4 * Copyright (C) 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/* Id: atomic.h,v 1.6 2008/01/24 23:47:00 tbox Exp  */
20
21#ifndef ISC_ATOMIC_H
22#define ISC_ATOMIC_H 1
23
24#include <isc/platform.h>
25#include <isc/types.h>
26
27#ifdef ISC_PLATFORM_USEGCCASM
28
29/* We share the gcc-version with x86_32 */
30#error "impossible case.  check build configuration"
31
32#elif defined(ISC_PLATFORM_USESTDASM)
33/*
34 * The followings are "generic" assembly code which implements the same
35 * functionality in case the gcc extension cannot be used.  It should be
36 * better to avoid inlining below, since we directly refer to specific
37 * registers for arguments, which would not actually correspond to the
38 * intended address or value in the embedded mnemonic.
39 */
40#include <isc/util.h>		/* for 'UNUSED' macro */
41
42static isc_int32_t
43isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
44	UNUSED(p);
45	UNUSED(val);
46
47	__asm (
48		"movq %rdi, %rdx\n"
49		"movl %esi, %eax\n"
50#ifdef ISC_PLATFORM_USETHREADS
51		"lock;"
52#endif
53		"xadd %eax, (%rdx)\n"
54		/*
55		 * XXX: assume %eax will be used as the return value.
56		 */
57		);
58}
59
60#ifdef ISC_PLATFORM_HAVEXADDQ
61static isc_int64_t
62isc_atomic_xaddq(isc_int64_t *p, isc_int64_t val) {
63	UNUSED(p);
64	UNUSED(val);
65
66	__asm (
67		"movq %rdi, %rdx\n"
68		"movq %rsi, %rax\n"
69#ifdef ISC_PLATFORM_USETHREADS
70		"lock;"
71#endif
72		"xaddq %rax, (%rdx)\n"
73		/*
74		 * XXX: assume %rax will be used as the return value.
75		 */
76		);
77}
78#endif
79
80static void
81isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
82	UNUSED(p);
83	UNUSED(val);
84
85	__asm (
86		"movq %rdi, %rax\n"
87		"movl %esi, %edx\n"
88#ifdef ISC_PLATFORM_USETHREADS
89		"lock;"
90#endif
91		"xchgl (%rax), %edx\n"
92		/*
93		 * XXX: assume %rax will be used as the return value.
94		 */
95		);
96}
97
98static isc_int32_t
99isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
100	UNUSED(p);
101	UNUSED(cmpval);
102	UNUSED(val);
103
104	__asm (
105		"movl %edx, %ecx\n"
106		"movl %esi, %eax\n"
107		"movq %rdi, %rdx\n"
108
109#ifdef ISC_PLATFORM_USETHREADS
110		"lock;"
111#endif
112		/*
113		 * If (%rdi) == %eax then (%rdi) := %edx.
114		 * %eax is set to old (%ecx), which will be the return value.
115		 */
116		"cmpxchgl %ecx, (%rdx)"
117		);
118}
119
120#else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
121
122#error "unsupported compiler.  disable atomic ops by --disable-atomic"
123
124#endif
125#endif /* ISC_ATOMIC_H */
126