1*5d9d9091SRichard Lowe/*
2*5d9d9091SRichard Lowe * CDDL HEADER START
3*5d9d9091SRichard Lowe *
4*5d9d9091SRichard Lowe * The contents of this file are subject to the terms of the
5*5d9d9091SRichard Lowe * Common Development and Distribution License (the "License").
6*5d9d9091SRichard Lowe * You may not use this file except in compliance with the License.
7*5d9d9091SRichard Lowe *
8*5d9d9091SRichard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5d9d9091SRichard Lowe * or http://www.opensolaris.org/os/licensing.
10*5d9d9091SRichard Lowe * See the License for the specific language governing permissions
11*5d9d9091SRichard Lowe * and limitations under the License.
12*5d9d9091SRichard Lowe *
13*5d9d9091SRichard Lowe * When distributing Covered Code, include this CDDL HEADER in each
14*5d9d9091SRichard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5d9d9091SRichard Lowe * If applicable, add the following below this CDDL HEADER, with the
16*5d9d9091SRichard Lowe * fields enclosed by brackets "[]" replaced with your own identifying
17*5d9d9091SRichard Lowe * information: Portions Copyright [yyyy] [name of copyright owner]
18*5d9d9091SRichard Lowe *
19*5d9d9091SRichard Lowe * CDDL HEADER END
20*5d9d9091SRichard Lowe */
21*5d9d9091SRichard Lowe
22*5d9d9091SRichard Lowe/*
23*5d9d9091SRichard Lowe * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*5d9d9091SRichard Lowe * Use is subject to license terms.
25*5d9d9091SRichard Lowe */
26*5d9d9091SRichard Lowe
27*5d9d9091SRichard Lowe	.file	"atomic.s"
28*5d9d9091SRichard Lowe
29*5d9d9091SRichard Lowe#include <sys/asm_linkage.h>
30*5d9d9091SRichard Lowe
31*5d9d9091SRichard Lowe#if defined(_KERNEL)
32*5d9d9091SRichard Lowe	/*
33*5d9d9091SRichard Lowe	 * Legacy kernel interfaces; they will go away the moment our closed
34*5d9d9091SRichard Lowe	 * bins no longer require them.
35*5d9d9091SRichard Lowe	 */
36*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(cas8,atomic_cas_8,function)
37*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(cas32,atomic_cas_32,function)
38*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(cas64,atomic_cas_64,function)
39*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(caslong,atomic_cas_ulong,function)
40*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(casptr,atomic_cas_ptr,function)
41*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(atomic_and_long,atomic_and_ulong,function)
42*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(atomic_or_long,atomic_or_ulong,function)
43*5d9d9091SRichard Lowe	ANSI_PRAGMA_WEAK2(swapl,atomic_swap_32,function)
44*5d9d9091SRichard Lowe#endif
45*5d9d9091SRichard Lowe
46*5d9d9091SRichard Lowe	/*
47*5d9d9091SRichard Lowe	 * NOTE: If atomic_inc_8 and atomic_inc_8_nv are ever
48*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
49*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
50*5d9d9091SRichard Lowe	 * from atomic_inc_8_nv.
51*5d9d9091SRichard Lowe	 */
52*5d9d9091SRichard Lowe	ENTRY(atomic_inc_8)
53*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_8_nv)
54*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_uchar)
55*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_uchar_nv)
56*5d9d9091SRichard Lowe	ba	add_8
57*5d9d9091SRichard Lowe	  add	%g0, 1, %o1
58*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_uchar_nv)
59*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_uchar)
60*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_8_nv)
61*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_8)
62*5d9d9091SRichard Lowe
63*5d9d9091SRichard Lowe	/*
64*5d9d9091SRichard Lowe	 * NOTE: If atomic_dec_8 and atomic_dec_8_nv are ever
65*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
66*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
67*5d9d9091SRichard Lowe	 * from atomic_dec_8_nv.
68*5d9d9091SRichard Lowe	 */
69*5d9d9091SRichard Lowe	ENTRY(atomic_dec_8)
70*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_8_nv)
71*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_uchar)
72*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_uchar_nv)
73*5d9d9091SRichard Lowe	ba	add_8
74*5d9d9091SRichard Lowe	  sub	%g0, 1, %o1
75*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_uchar_nv)
76*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_uchar)
77*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_8_nv)
78*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_8)
79*5d9d9091SRichard Lowe
80*5d9d9091SRichard Lowe	/*
81*5d9d9091SRichard Lowe	 * NOTE: If atomic_add_8 and atomic_add_8_nv are ever
82*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
83*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
84*5d9d9091SRichard Lowe	 * from atomic_add_8_nv.
85*5d9d9091SRichard Lowe	 */
86*5d9d9091SRichard Lowe	ENTRY(atomic_add_8)
87*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_8_nv)
88*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_char)
89*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_char_nv)
90*5d9d9091SRichard Loweadd_8:
91*5d9d9091SRichard Lowe	and	%o0, 0x3, %o4		! %o4 = byte offset, left-to-right
92*5d9d9091SRichard Lowe	xor	%o4, 0x3, %g1		! %g1 = byte offset, right-to-left
93*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
94*5d9d9091SRichard Lowe	set	0xff, %o3		! %o3 = mask
95*5d9d9091SRichard Lowe	sll	%o3, %g1, %o3		! %o3 = shifted to bit offset
96*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
97*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single byte value
98*5d9d9091SRichard Lowe	andn	%o0, 0x3, %o0		! %o0 = word address
99*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
100*5d9d9091SRichard Lowe1:
101*5d9d9091SRichard Lowe	add	%o2, %o1, %o5		! add value to the old value
102*5d9d9091SRichard Lowe	and	%o5, %o3, %o5		! clear other bits
103*5d9d9091SRichard Lowe	andn	%o2, %o3, %o4		! clear target bits
104*5d9d9091SRichard Lowe	or	%o4, %o5, %o5		! insert the new value
105*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
106*5d9d9091SRichard Lowe	cmp	%o2, %o5
107*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
108*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
109*5d9d9091SRichard Lowe	add	%o2, %o1, %o5
110*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
111*5d9d9091SRichard Lowe	retl
112*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = new value
113*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_char_nv)
114*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_char)
115*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_8_nv)
116*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_8)
117*5d9d9091SRichard Lowe
118*5d9d9091SRichard Lowe	/*
119*5d9d9091SRichard Lowe	 * NOTE: If atomic_inc_16 and atomic_inc_16_nv are ever
120*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
121*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
122*5d9d9091SRichard Lowe	 * from atomic_inc_16_nv.
123*5d9d9091SRichard Lowe	 */
124*5d9d9091SRichard Lowe	ENTRY(atomic_inc_16)
125*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_16_nv)
126*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_ushort)
127*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_ushort_nv)
128*5d9d9091SRichard Lowe	ba	add_16
129*5d9d9091SRichard Lowe	  add	%g0, 1, %o1
130*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_ushort_nv)
131*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_ushort)
132*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_16_nv)
133*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_16)
134*5d9d9091SRichard Lowe
135*5d9d9091SRichard Lowe	/*
136*5d9d9091SRichard Lowe	 * NOTE: If atomic_dec_16 and atomic_dec_16_nv are ever
137*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
138*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
139*5d9d9091SRichard Lowe	 * from atomic_dec_16_nv.
140*5d9d9091SRichard Lowe	 */
141*5d9d9091SRichard Lowe	ENTRY(atomic_dec_16)
142*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_16_nv)
143*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_ushort)
144*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_ushort_nv)
145*5d9d9091SRichard Lowe	ba	add_16
146*5d9d9091SRichard Lowe	  sub	%g0, 1, %o1
147*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_ushort_nv)
148*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_ushort)
149*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_16_nv)
150*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_16)
151*5d9d9091SRichard Lowe
152*5d9d9091SRichard Lowe	/*
153*5d9d9091SRichard Lowe	 * NOTE: If atomic_add_16 and atomic_add_16_nv are ever
154*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
155*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
156*5d9d9091SRichard Lowe	 * from atomic_add_16_nv.
157*5d9d9091SRichard Lowe	 */
158*5d9d9091SRichard Lowe	ENTRY(atomic_add_16)
159*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_16_nv)
160*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_short)
161*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_short_nv)
162*5d9d9091SRichard Loweadd_16:
163*5d9d9091SRichard Lowe	and	%o0, 0x2, %o4		! %o4 = byte offset, left-to-right
164*5d9d9091SRichard Lowe	xor	%o4, 0x2, %g1		! %g1 = byte offset, right-to-left
165*5d9d9091SRichard Lowe	sll	%o4, 3, %o4		! %o4 = bit offset, left-to-right
166*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
167*5d9d9091SRichard Lowe	sethi	%hi(0xffff0000), %o3	! %o3 = mask
168*5d9d9091SRichard Lowe	srl	%o3, %o4, %o3		! %o3 = shifted to bit offset
169*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
170*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single short value
171*5d9d9091SRichard Lowe	andn	%o0, 0x2, %o0		! %o0 = word address
172*5d9d9091SRichard Lowe	! if low-order bit is 1, we will properly get an alignment fault here
173*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
174*5d9d9091SRichard Lowe1:
175*5d9d9091SRichard Lowe	add	%o1, %o2, %o5		! add value to the old value
176*5d9d9091SRichard Lowe	and	%o5, %o3, %o5		! clear other bits
177*5d9d9091SRichard Lowe	andn	%o2, %o3, %o4		! clear target bits
178*5d9d9091SRichard Lowe	or	%o4, %o5, %o5		! insert the new value
179*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
180*5d9d9091SRichard Lowe	cmp	%o2, %o5
181*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
182*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
183*5d9d9091SRichard Lowe	add	%o1, %o2, %o5
184*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
185*5d9d9091SRichard Lowe	retl
186*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = new value
187*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_short_nv)
188*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_short)
189*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_16_nv)
190*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_16)
191*5d9d9091SRichard Lowe
192*5d9d9091SRichard Lowe	/*
193*5d9d9091SRichard Lowe	 * NOTE: If atomic_inc_32 and atomic_inc_32_nv are ever
194*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
195*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
196*5d9d9091SRichard Lowe	 * from atomic_inc_32_nv.
197*5d9d9091SRichard Lowe	 */
198*5d9d9091SRichard Lowe	ENTRY(atomic_inc_32)
199*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_32_nv)
200*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_uint)
201*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_uint_nv)
202*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_ulong)
203*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_ulong_nv)
204*5d9d9091SRichard Lowe	ba	add_32
205*5d9d9091SRichard Lowe	  add	%g0, 1, %o1
206*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_ulong_nv)
207*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_ulong)
208*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_uint_nv)
209*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_uint)
210*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_32_nv)
211*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_32)
212*5d9d9091SRichard Lowe
213*5d9d9091SRichard Lowe	/*
214*5d9d9091SRichard Lowe	 * NOTE: If atomic_dec_32 and atomic_dec_32_nv are ever
215*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
216*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
217*5d9d9091SRichard Lowe	 * from atomic_dec_32_nv.
218*5d9d9091SRichard Lowe	 */
219*5d9d9091SRichard Lowe	ENTRY(atomic_dec_32)
220*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_32_nv)
221*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_uint)
222*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_uint_nv)
223*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_ulong)
224*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_ulong_nv)
225*5d9d9091SRichard Lowe	ba	add_32
226*5d9d9091SRichard Lowe	  sub	%g0, 1, %o1
227*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_ulong_nv)
228*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_ulong)
229*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_uint_nv)
230*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_uint)
231*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_32_nv)
232*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_32)
233*5d9d9091SRichard Lowe
234*5d9d9091SRichard Lowe	/*
235*5d9d9091SRichard Lowe	 * NOTE: If atomic_add_32 and atomic_add_32_nv are ever
236*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
237*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
238*5d9d9091SRichard Lowe	 * from atomic_add_32_nv.
239*5d9d9091SRichard Lowe	 */
240*5d9d9091SRichard Lowe	ENTRY(atomic_add_32)
241*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_32_nv)
242*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_int)
243*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_int_nv)
244*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_ptr)
245*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_ptr_nv)
246*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_long)
247*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_long_nv)
248*5d9d9091SRichard Loweadd_32:
249*5d9d9091SRichard Lowe	ld	[%o0], %o2
250*5d9d9091SRichard Lowe1:
251*5d9d9091SRichard Lowe	add	%o2, %o1, %o3
252*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o3
253*5d9d9091SRichard Lowe	cmp	%o2, %o3
254*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
255*5d9d9091SRichard Lowe	  mov	%o3, %o2
256*5d9d9091SRichard Lowe	retl
257*5d9d9091SRichard Lowe	add	%o2, %o1, %o0		! return new value
258*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_long_nv)
259*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_long)
260*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_ptr_nv)
261*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_ptr)
262*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_int_nv)
263*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_int)
264*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_32_nv)
265*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_32)
266*5d9d9091SRichard Lowe
267*5d9d9091SRichard Lowe	/*
268*5d9d9091SRichard Lowe	 * NOTE: If atomic_inc_64 and atomic_inc_64_nv are ever
269*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
270*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
271*5d9d9091SRichard Lowe	 * from atomic_inc_64_nv.
272*5d9d9091SRichard Lowe	 */
273*5d9d9091SRichard Lowe	ENTRY(atomic_inc_64)
274*5d9d9091SRichard Lowe	ALTENTRY(atomic_inc_64_nv)
275*5d9d9091SRichard Lowe	ba	add_64
276*5d9d9091SRichard Lowe	  add	%g0, 1, %o1
277*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_64_nv)
278*5d9d9091SRichard Lowe	SET_SIZE(atomic_inc_64)
279*5d9d9091SRichard Lowe
280*5d9d9091SRichard Lowe	/*
281*5d9d9091SRichard Lowe	 * NOTE: If atomic_dec_64 and atomic_dec_64_nv are ever
282*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
283*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
284*5d9d9091SRichard Lowe	 * from atomic_dec_64_nv.
285*5d9d9091SRichard Lowe	 */
286*5d9d9091SRichard Lowe	ENTRY(atomic_dec_64)
287*5d9d9091SRichard Lowe	ALTENTRY(atomic_dec_64_nv)
288*5d9d9091SRichard Lowe	ba	add_64
289*5d9d9091SRichard Lowe	  sub	%g0, 1, %o1
290*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_64_nv)
291*5d9d9091SRichard Lowe	SET_SIZE(atomic_dec_64)
292*5d9d9091SRichard Lowe
293*5d9d9091SRichard Lowe	/*
294*5d9d9091SRichard Lowe	 * NOTE: If atomic_add_64 and atomic_add_64_nv are ever
295*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
296*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
297*5d9d9091SRichard Lowe	 * from atomic_add_64_nv.
298*5d9d9091SRichard Lowe	 */
299*5d9d9091SRichard Lowe	ENTRY(atomic_add_64)
300*5d9d9091SRichard Lowe	ALTENTRY(atomic_add_64_nv)
301*5d9d9091SRichard Lowe	sllx	%o1, 32, %o1		! upper 32 in %o1, lower in %o2
302*5d9d9091SRichard Lowe	srl	%o2, 0, %o2
303*5d9d9091SRichard Lowe	add	%o1, %o2, %o1		! convert 2 32-bit args into 1 64-bit
304*5d9d9091SRichard Loweadd_64:
305*5d9d9091SRichard Lowe	ldx	[%o0], %o2
306*5d9d9091SRichard Lowe1:
307*5d9d9091SRichard Lowe	add	%o2, %o1, %o3
308*5d9d9091SRichard Lowe	casx	[%o0], %o2, %o3
309*5d9d9091SRichard Lowe	cmp	%o2, %o3
310*5d9d9091SRichard Lowe	bne,a,pn %xcc, 1b
311*5d9d9091SRichard Lowe	  mov	%o3, %o2
312*5d9d9091SRichard Lowe	add	%o2, %o1, %o1		! return lower 32-bits in %o1
313*5d9d9091SRichard Lowe	retl
314*5d9d9091SRichard Lowe	srlx	%o1, 32, %o0		! return upper 32-bits in %o0
315*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_64_nv)
316*5d9d9091SRichard Lowe	SET_SIZE(atomic_add_64)
317*5d9d9091SRichard Lowe
318*5d9d9091SRichard Lowe	/*
319*5d9d9091SRichard Lowe	 * NOTE: If atomic_or_8 and atomic_or_8_nv are ever
320*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
321*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
322*5d9d9091SRichard Lowe	 * from atomic_or_8_nv.
323*5d9d9091SRichard Lowe	 */
324*5d9d9091SRichard Lowe	ENTRY(atomic_or_8)
325*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_8_nv)
326*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_uchar)
327*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_uchar_nv)
328*5d9d9091SRichard Lowe	and	%o0, 0x3, %o4		! %o4 = byte offset, left-to-right
329*5d9d9091SRichard Lowe	xor	%o4, 0x3, %g1		! %g1 = byte offset, right-to-left
330*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
331*5d9d9091SRichard Lowe	set	0xff, %o3		! %o3 = mask
332*5d9d9091SRichard Lowe	sll	%o3, %g1, %o3		! %o3 = shifted to bit offset
333*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
334*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single byte value
335*5d9d9091SRichard Lowe	andn	%o0, 0x3, %o0		! %o0 = word address
336*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
337*5d9d9091SRichard Lowe1:
338*5d9d9091SRichard Lowe	or	%o2, %o1, %o5		! or in the new value
339*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
340*5d9d9091SRichard Lowe	cmp	%o2, %o5
341*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
342*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
343*5d9d9091SRichard Lowe	or	%o2, %o1, %o5
344*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
345*5d9d9091SRichard Lowe	retl
346*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = new value
347*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_uchar_nv)
348*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_uchar)
349*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_8_nv)
350*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_8)
351*5d9d9091SRichard Lowe
352*5d9d9091SRichard Lowe	/*
353*5d9d9091SRichard Lowe	 * NOTE: If atomic_or_16 and atomic_or_16_nv are ever
354*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
355*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
356*5d9d9091SRichard Lowe	 * from atomic_or_16_nv.
357*5d9d9091SRichard Lowe	 */
358*5d9d9091SRichard Lowe	ENTRY(atomic_or_16)
359*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_16_nv)
360*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_ushort)
361*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_ushort_nv)
362*5d9d9091SRichard Lowe	and	%o0, 0x2, %o4		! %o4 = byte offset, left-to-right
363*5d9d9091SRichard Lowe	xor	%o4, 0x2, %g1		! %g1 = byte offset, right-to-left
364*5d9d9091SRichard Lowe	sll	%o4, 3, %o4		! %o4 = bit offset, left-to-right
365*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
366*5d9d9091SRichard Lowe	sethi	%hi(0xffff0000), %o3	! %o3 = mask
367*5d9d9091SRichard Lowe	srl	%o3, %o4, %o3		! %o3 = shifted to bit offset
368*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
369*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single short value
370*5d9d9091SRichard Lowe	andn	%o0, 0x2, %o0		! %o0 = word address
371*5d9d9091SRichard Lowe	! if low-order bit is 1, we will properly get an alignment fault here
372*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
373*5d9d9091SRichard Lowe1:
374*5d9d9091SRichard Lowe	or	%o2, %o1, %o5		! or in the new value
375*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
376*5d9d9091SRichard Lowe	cmp	%o2, %o5
377*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
378*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
379*5d9d9091SRichard Lowe	or	%o2, %o1, %o5		! or in the new value
380*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
381*5d9d9091SRichard Lowe	retl
382*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = new value
383*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_ushort_nv)
384*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_ushort)
385*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_16_nv)
386*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_16)
387*5d9d9091SRichard Lowe
388*5d9d9091SRichard Lowe	/*
389*5d9d9091SRichard Lowe	 * NOTE: If atomic_or_32 and atomic_or_32_nv are ever
390*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
391*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
392*5d9d9091SRichard Lowe	 * from atomic_or_32_nv.
393*5d9d9091SRichard Lowe	 */
394*5d9d9091SRichard Lowe	ENTRY(atomic_or_32)
395*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_32_nv)
396*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_uint)
397*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_uint_nv)
398*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_ulong)
399*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_ulong_nv)
400*5d9d9091SRichard Lowe	ld	[%o0], %o2
401*5d9d9091SRichard Lowe1:
402*5d9d9091SRichard Lowe	or	%o2, %o1, %o3
403*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o3
404*5d9d9091SRichard Lowe	cmp	%o2, %o3
405*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
406*5d9d9091SRichard Lowe	  mov	%o3, %o2
407*5d9d9091SRichard Lowe	retl
408*5d9d9091SRichard Lowe	or	%o2, %o1, %o0		! return new value
409*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_ulong_nv)
410*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_ulong)
411*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_uint_nv)
412*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_uint)
413*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_32_nv)
414*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_32)
415*5d9d9091SRichard Lowe
416*5d9d9091SRichard Lowe	/*
417*5d9d9091SRichard Lowe	 * NOTE: If atomic_or_64 and atomic_or_64_nv are ever
418*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
419*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
420*5d9d9091SRichard Lowe	 * from atomic_or_64_nv.
421*5d9d9091SRichard Lowe	 */
422*5d9d9091SRichard Lowe	ENTRY(atomic_or_64)
423*5d9d9091SRichard Lowe	ALTENTRY(atomic_or_64_nv)
424*5d9d9091SRichard Lowe	sllx	%o1, 32, %o1		! upper 32 in %o1, lower in %o2
425*5d9d9091SRichard Lowe	srl	%o2, 0, %o2
426*5d9d9091SRichard Lowe	add	%o1, %o2, %o1		! convert 2 32-bit args into 1 64-bit
427*5d9d9091SRichard Lowe	ldx	[%o0], %o2
428*5d9d9091SRichard Lowe1:
429*5d9d9091SRichard Lowe	or	%o2, %o1, %o3
430*5d9d9091SRichard Lowe	casx	[%o0], %o2, %o3
431*5d9d9091SRichard Lowe	cmp	%o2, %o3
432*5d9d9091SRichard Lowe	bne,a,pn %xcc, 1b
433*5d9d9091SRichard Lowe	  mov	%o3, %o2
434*5d9d9091SRichard Lowe	or	%o2, %o1, %o1		! return lower 32-bits in %o1
435*5d9d9091SRichard Lowe	retl
436*5d9d9091SRichard Lowe	srlx	%o1, 32, %o0		! return upper 32-bits in %o0
437*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_64_nv)
438*5d9d9091SRichard Lowe	SET_SIZE(atomic_or_64)
439*5d9d9091SRichard Lowe
440*5d9d9091SRichard Lowe	/*
441*5d9d9091SRichard Lowe	 * NOTE: If atomic_and_8 and atomic_and_8_nv are ever
442*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
443*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
444*5d9d9091SRichard Lowe	 * from atomic_and_8_nv.
445*5d9d9091SRichard Lowe	 */
446*5d9d9091SRichard Lowe	ENTRY(atomic_and_8)
447*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_8_nv)
448*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_uchar)
449*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_uchar_nv)
450*5d9d9091SRichard Lowe	and	%o0, 0x3, %o4		! %o4 = byte offset, left-to-right
451*5d9d9091SRichard Lowe	xor	%o4, 0x3, %g1		! %g1 = byte offset, right-to-left
452*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
453*5d9d9091SRichard Lowe	set	0xff, %o3		! %o3 = mask
454*5d9d9091SRichard Lowe	sll	%o3, %g1, %o3		! %o3 = shifted to bit offset
455*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
456*5d9d9091SRichard Lowe	orn	%o1, %o3, %o1		! all ones in other bytes
457*5d9d9091SRichard Lowe	andn	%o0, 0x3, %o0		! %o0 = word address
458*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
459*5d9d9091SRichard Lowe1:
460*5d9d9091SRichard Lowe	and	%o2, %o1, %o5		! and in the new value
461*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
462*5d9d9091SRichard Lowe	cmp	%o2, %o5
463*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
464*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
465*5d9d9091SRichard Lowe	and	%o2, %o1, %o5
466*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
467*5d9d9091SRichard Lowe	retl
468*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = new value
469*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_uchar_nv)
470*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_uchar)
471*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_8_nv)
472*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_8)
473*5d9d9091SRichard Lowe
474*5d9d9091SRichard Lowe	/*
475*5d9d9091SRichard Lowe	 * NOTE: If atomic_and_16 and atomic_and_16_nv are ever
476*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
477*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
478*5d9d9091SRichard Lowe	 * from atomic_and_16_nv.
479*5d9d9091SRichard Lowe	 */
480*5d9d9091SRichard Lowe	ENTRY(atomic_and_16)
481*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_16_nv)
482*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_ushort)
483*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_ushort_nv)
484*5d9d9091SRichard Lowe	and	%o0, 0x2, %o4		! %o4 = byte offset, left-to-right
485*5d9d9091SRichard Lowe	xor	%o4, 0x2, %g1		! %g1 = byte offset, right-to-left
486*5d9d9091SRichard Lowe	sll	%o4, 3, %o4		! %o4 = bit offset, left-to-right
487*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
488*5d9d9091SRichard Lowe	sethi	%hi(0xffff0000), %o3	! %o3 = mask
489*5d9d9091SRichard Lowe	srl	%o3, %o4, %o3		! %o3 = shifted to bit offset
490*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
491*5d9d9091SRichard Lowe	orn	%o1, %o3, %o1		! all ones in the other half
492*5d9d9091SRichard Lowe	andn	%o0, 0x2, %o0		! %o0 = word address
493*5d9d9091SRichard Lowe	! if low-order bit is 1, we will properly get an alignment fault here
494*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
495*5d9d9091SRichard Lowe1:
496*5d9d9091SRichard Lowe	and	%o2, %o1, %o5		! and in the new value
497*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
498*5d9d9091SRichard Lowe	cmp	%o2, %o5
499*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
500*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
501*5d9d9091SRichard Lowe	and	%o2, %o1, %o5
502*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
503*5d9d9091SRichard Lowe	retl
504*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = new value
505*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_ushort_nv)
506*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_ushort)
507*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_16_nv)
508*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_16)
509*5d9d9091SRichard Lowe
510*5d9d9091SRichard Lowe	/*
511*5d9d9091SRichard Lowe	 * NOTE: If atomic_and_32 and atomic_and_32_nv are ever
512*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
513*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
514*5d9d9091SRichard Lowe	 * from atomic_and_32_nv.
515*5d9d9091SRichard Lowe	 */
516*5d9d9091SRichard Lowe	ENTRY(atomic_and_32)
517*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_32_nv)
518*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_uint)
519*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_uint_nv)
520*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_ulong)
521*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_ulong_nv)
522*5d9d9091SRichard Lowe	ld	[%o0], %o2
523*5d9d9091SRichard Lowe1:
524*5d9d9091SRichard Lowe	and	%o2, %o1, %o3
525*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o3
526*5d9d9091SRichard Lowe	cmp	%o2, %o3
527*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
528*5d9d9091SRichard Lowe	  mov	%o3, %o2
529*5d9d9091SRichard Lowe	retl
530*5d9d9091SRichard Lowe	and	%o2, %o1, %o0		! return new value
531*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_ulong_nv)
532*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_ulong)
533*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_uint_nv)
534*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_uint)
535*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_32_nv)
536*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_32)
537*5d9d9091SRichard Lowe
538*5d9d9091SRichard Lowe	/*
539*5d9d9091SRichard Lowe	 * NOTE: If atomic_and_64 and atomic_and_64_nv are ever
540*5d9d9091SRichard Lowe	 * separated, you need to also edit the libc sparc platform
541*5d9d9091SRichard Lowe	 * specific mapfile and remove the NODYNSORT attribute
542*5d9d9091SRichard Lowe	 * from atomic_and_64_nv.
543*5d9d9091SRichard Lowe	 */
544*5d9d9091SRichard Lowe	ENTRY(atomic_and_64)
545*5d9d9091SRichard Lowe	ALTENTRY(atomic_and_64_nv)
546*5d9d9091SRichard Lowe	sllx	%o1, 32, %o1		! upper 32 in %o1, lower in %o2
547*5d9d9091SRichard Lowe	srl	%o2, 0, %o2
548*5d9d9091SRichard Lowe	add	%o1, %o2, %o1		! convert 2 32-bit args into 1 64-bit
549*5d9d9091SRichard Lowe	ldx	[%o0], %o2
550*5d9d9091SRichard Lowe1:
551*5d9d9091SRichard Lowe	and	%o2, %o1, %o3
552*5d9d9091SRichard Lowe	casx	[%o0], %o2, %o3
553*5d9d9091SRichard Lowe	cmp	%o2, %o3
554*5d9d9091SRichard Lowe	bne,a,pn %xcc, 1b
555*5d9d9091SRichard Lowe	  mov	%o3, %o2
556*5d9d9091SRichard Lowe	and	%o2, %o1, %o1		! return lower 32-bits in %o1
557*5d9d9091SRichard Lowe	retl
558*5d9d9091SRichard Lowe	srlx	%o1, 32, %o0		! return upper 32-bits in %o0
559*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_64_nv)
560*5d9d9091SRichard Lowe	SET_SIZE(atomic_and_64)
561*5d9d9091SRichard Lowe
562*5d9d9091SRichard Lowe	ENTRY(atomic_cas_8)
563*5d9d9091SRichard Lowe	ALTENTRY(atomic_cas_uchar)
564*5d9d9091SRichard Lowe	and	%o0, 0x3, %o4		! %o4 = byte offset, left-to-right
565*5d9d9091SRichard Lowe	xor	%o4, 0x3, %g1		! %g1 = byte offset, right-to-left
566*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
567*5d9d9091SRichard Lowe	set	0xff, %o3		! %o3 = mask
568*5d9d9091SRichard Lowe	sll	%o3, %g1, %o3		! %o3 = shifted to bit offset
569*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
570*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single byte value
571*5d9d9091SRichard Lowe	sll	%o2, %g1, %o2		! %o2 = shifted to bit offset
572*5d9d9091SRichard Lowe	and	%o2, %o3, %o2		! %o2 = single byte value
573*5d9d9091SRichard Lowe	andn	%o0, 0x3, %o0		! %o0 = word address
574*5d9d9091SRichard Lowe	ld	[%o0], %o4		! read old value
575*5d9d9091SRichard Lowe1:
576*5d9d9091SRichard Lowe	andn	%o4, %o3, %o4		! clear target bits
577*5d9d9091SRichard Lowe	or	%o4, %o2, %o5		! insert the new value
578*5d9d9091SRichard Lowe	or	%o4, %o1, %o4		! insert the comparison value
579*5d9d9091SRichard Lowe	cas	[%o0], %o4, %o5
580*5d9d9091SRichard Lowe	cmp	%o4, %o5		! did we succeed?
581*5d9d9091SRichard Lowe	be,pt	%icc, 2f
582*5d9d9091SRichard Lowe	  and	%o5, %o3, %o4		! isolate the old value
583*5d9d9091SRichard Lowe	cmp	%o1, %o4		! should we have succeeded?
584*5d9d9091SRichard Lowe	be,a,pt	%icc, 1b		! yes, try again
585*5d9d9091SRichard Lowe	  mov	%o5, %o4		! %o4 = old value
586*5d9d9091SRichard Lowe2:
587*5d9d9091SRichard Lowe	retl
588*5d9d9091SRichard Lowe	srl	%o4, %g1, %o0		! %o0 = old value
589*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_uchar)
590*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_8)
591*5d9d9091SRichard Lowe
592*5d9d9091SRichard Lowe	ENTRY(atomic_cas_16)
593*5d9d9091SRichard Lowe	ALTENTRY(atomic_cas_ushort)
594*5d9d9091SRichard Lowe	and	%o0, 0x2, %o4		! %o4 = byte offset, left-to-right
595*5d9d9091SRichard Lowe	xor	%o4, 0x2, %g1		! %g1 = byte offset, right-to-left
596*5d9d9091SRichard Lowe	sll	%o4, 3, %o4		! %o4 = bit offset, left-to-right
597*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
598*5d9d9091SRichard Lowe	sethi	%hi(0xffff0000), %o3	! %o3 = mask
599*5d9d9091SRichard Lowe	srl	%o3, %o4, %o3		! %o3 = shifted to bit offset
600*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
601*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single short value
602*5d9d9091SRichard Lowe	sll	%o2, %g1, %o2		! %o2 = shifted to bit offset
603*5d9d9091SRichard Lowe	and	%o2, %o3, %o2		! %o2 = single short value
604*5d9d9091SRichard Lowe	andn	%o0, 0x2, %o0		! %o0 = word address
605*5d9d9091SRichard Lowe	! if low-order bit is 1, we will properly get an alignment fault here
606*5d9d9091SRichard Lowe	ld	[%o0], %o4		! read old value
607*5d9d9091SRichard Lowe1:
608*5d9d9091SRichard Lowe	andn	%o4, %o3, %o4		! clear target bits
609*5d9d9091SRichard Lowe	or	%o4, %o2, %o5		! insert the new value
610*5d9d9091SRichard Lowe	or	%o4, %o1, %o4		! insert the comparison value
611*5d9d9091SRichard Lowe	cas	[%o0], %o4, %o5
612*5d9d9091SRichard Lowe	cmp	%o4, %o5		! did we succeed?
613*5d9d9091SRichard Lowe	be,pt	%icc, 2f
614*5d9d9091SRichard Lowe	  and	%o5, %o3, %o4		! isolate the old value
615*5d9d9091SRichard Lowe	cmp	%o1, %o4		! should we have succeeded?
616*5d9d9091SRichard Lowe	be,a,pt	%icc, 1b		! yes, try again
617*5d9d9091SRichard Lowe	  mov	%o5, %o4		! %o4 = old value
618*5d9d9091SRichard Lowe2:
619*5d9d9091SRichard Lowe	retl
620*5d9d9091SRichard Lowe	srl	%o4, %g1, %o0		! %o0 = old value
621*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_ushort)
622*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_16)
623*5d9d9091SRichard Lowe
624*5d9d9091SRichard Lowe	ENTRY(atomic_cas_32)
625*5d9d9091SRichard Lowe	ALTENTRY(atomic_cas_uint)
626*5d9d9091SRichard Lowe	ALTENTRY(atomic_cas_ptr)
627*5d9d9091SRichard Lowe	ALTENTRY(atomic_cas_ulong)
628*5d9d9091SRichard Lowe	cas	[%o0], %o1, %o2
629*5d9d9091SRichard Lowe	retl
630*5d9d9091SRichard Lowe	mov	%o2, %o0
631*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_ulong)
632*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_ptr)
633*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_uint)
634*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_32)
635*5d9d9091SRichard Lowe
636*5d9d9091SRichard Lowe	ENTRY(atomic_cas_64)
637*5d9d9091SRichard Lowe	sllx	%o1, 32, %o1		! cmp's upper 32 in %o1, lower in %o2
638*5d9d9091SRichard Lowe	srl	%o2, 0, %o2		! convert 2 32-bit args into 1 64-bit
639*5d9d9091SRichard Lowe	add	%o1, %o2, %o1
640*5d9d9091SRichard Lowe	sllx	%o3, 32, %o2		! newval upper 32 in %o3, lower in %o4
641*5d9d9091SRichard Lowe	srl	%o4, 0, %o4		! setup %o2 to have newval
642*5d9d9091SRichard Lowe	add	%o2, %o4, %o2
643*5d9d9091SRichard Lowe	casx	[%o0], %o1, %o2
644*5d9d9091SRichard Lowe	srl	%o2, 0, %o1		! return lower 32-bits in %o1
645*5d9d9091SRichard Lowe	retl
646*5d9d9091SRichard Lowe	srlx	%o2, 32, %o0		! return upper 32-bits in %o0
647*5d9d9091SRichard Lowe	SET_SIZE(atomic_cas_64)
648*5d9d9091SRichard Lowe
649*5d9d9091SRichard Lowe	ENTRY(atomic_swap_8)
650*5d9d9091SRichard Lowe	ALTENTRY(atomic_swap_uchar)
651*5d9d9091SRichard Lowe	and	%o0, 0x3, %o4		! %o4 = byte offset, left-to-right
652*5d9d9091SRichard Lowe	xor	%o4, 0x3, %g1		! %g1 = byte offset, right-to-left
653*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
654*5d9d9091SRichard Lowe	set	0xff, %o3		! %o3 = mask
655*5d9d9091SRichard Lowe	sll	%o3, %g1, %o3		! %o3 = shifted to bit offset
656*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
657*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single byte value
658*5d9d9091SRichard Lowe	andn	%o0, 0x3, %o0		! %o0 = word address
659*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
660*5d9d9091SRichard Lowe1:
661*5d9d9091SRichard Lowe	andn	%o2, %o3, %o5		! clear target bits
662*5d9d9091SRichard Lowe	or	%o5, %o1, %o5		! insert the new value
663*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
664*5d9d9091SRichard Lowe	cmp	%o2, %o5
665*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
666*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
667*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
668*5d9d9091SRichard Lowe	retl
669*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = old value
670*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_uchar)
671*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_8)
672*5d9d9091SRichard Lowe
673*5d9d9091SRichard Lowe	ENTRY(atomic_swap_16)
674*5d9d9091SRichard Lowe	ALTENTRY(atomic_swap_ushort)
675*5d9d9091SRichard Lowe	and	%o0, 0x2, %o4		! %o4 = byte offset, left-to-right
676*5d9d9091SRichard Lowe	xor	%o4, 0x2, %g1		! %g1 = byte offset, right-to-left
677*5d9d9091SRichard Lowe	sll	%o4, 3, %o4		! %o4 = bit offset, left-to-right
678*5d9d9091SRichard Lowe	sll	%g1, 3, %g1		! %g1 = bit offset, right-to-left
679*5d9d9091SRichard Lowe	sethi	%hi(0xffff0000), %o3	! %o3 = mask
680*5d9d9091SRichard Lowe	srl	%o3, %o4, %o3		! %o3 = shifted to bit offset
681*5d9d9091SRichard Lowe	sll	%o1, %g1, %o1		! %o1 = shifted to bit offset
682*5d9d9091SRichard Lowe	and	%o1, %o3, %o1		! %o1 = single short value
683*5d9d9091SRichard Lowe	andn	%o0, 0x2, %o0		! %o0 = word address
684*5d9d9091SRichard Lowe	! if low-order bit is 1, we will properly get an alignment fault here
685*5d9d9091SRichard Lowe	ld	[%o0], %o2		! read old value
686*5d9d9091SRichard Lowe1:
687*5d9d9091SRichard Lowe	andn	%o2, %o3, %o5		! clear target bits
688*5d9d9091SRichard Lowe	or	%o5, %o1, %o5		! insert the new value
689*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o5
690*5d9d9091SRichard Lowe	cmp	%o2, %o5
691*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
692*5d9d9091SRichard Lowe	  mov	%o5, %o2		! %o2 = old value
693*5d9d9091SRichard Lowe	and	%o5, %o3, %o5
694*5d9d9091SRichard Lowe	retl
695*5d9d9091SRichard Lowe	srl	%o5, %g1, %o0		! %o0 = old value
696*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_ushort)
697*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_16)
698*5d9d9091SRichard Lowe
699*5d9d9091SRichard Lowe	ENTRY(atomic_swap_32)
700*5d9d9091SRichard Lowe	ALTENTRY(atomic_swap_uint)
701*5d9d9091SRichard Lowe	ALTENTRY(atomic_swap_ptr)
702*5d9d9091SRichard Lowe	ALTENTRY(atomic_swap_ulong)
703*5d9d9091SRichard Lowe	ld	[%o0], %o2
704*5d9d9091SRichard Lowe1:
705*5d9d9091SRichard Lowe	mov	%o1, %o3
706*5d9d9091SRichard Lowe	cas	[%o0], %o2, %o3
707*5d9d9091SRichard Lowe	cmp	%o2, %o3
708*5d9d9091SRichard Lowe	bne,a,pn %icc, 1b
709*5d9d9091SRichard Lowe	  mov	%o3, %o2
710*5d9d9091SRichard Lowe	retl
711*5d9d9091SRichard Lowe	mov	%o3, %o0
712*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_ulong)
713*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_ptr)
714*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_uint)
715*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_32)
716*5d9d9091SRichard Lowe
717*5d9d9091SRichard Lowe	ENTRY(atomic_swap_64)
718*5d9d9091SRichard Lowe	sllx	%o1, 32, %o1		! upper 32 in %o1, lower in %o2
719*5d9d9091SRichard Lowe	srl	%o2, 0, %o2
720*5d9d9091SRichard Lowe	add	%o1, %o2, %o1		! convert 2 32-bit args into 1 64-bit
721*5d9d9091SRichard Lowe	ldx	[%o0], %o2
722*5d9d9091SRichard Lowe1:
723*5d9d9091SRichard Lowe	mov	%o1, %o3
724*5d9d9091SRichard Lowe	casx	[%o0], %o2, %o3
725*5d9d9091SRichard Lowe	cmp	%o2, %o3
726*5d9d9091SRichard Lowe	bne,a,pn %xcc, 1b
727*5d9d9091SRichard Lowe	  mov	%o3, %o2
728*5d9d9091SRichard Lowe	srl	%o3, 0, %o1		! return lower 32-bits in %o1
729*5d9d9091SRichard Lowe	retl
730*5d9d9091SRichard Lowe	srlx	%o3, 32, %o0		! return upper 32-bits in %o0
731*5d9d9091SRichard Lowe	SET_SIZE(atomic_swap_64)
732*5d9d9091SRichard Lowe
733*5d9d9091SRichard Lowe	ENTRY(atomic_set_long_excl)
734*5d9d9091SRichard Lowe	mov	1, %o3
735*5d9d9091SRichard Lowe	slln	%o3, %o1, %o3
736*5d9d9091SRichard Lowe	ldn	[%o0], %o2
737*5d9d9091SRichard Lowe1:
738*5d9d9091SRichard Lowe	andcc	%o2, %o3, %g0		! test if the bit is set
739*5d9d9091SRichard Lowe	bnz,a,pn %ncc, 2f		! if so, then fail out
740*5d9d9091SRichard Lowe	  mov	-1, %o0
741*5d9d9091SRichard Lowe	or	%o2, %o3, %o4		! set the bit, and try to commit it
742*5d9d9091SRichard Lowe	casn	[%o0], %o2, %o4
743*5d9d9091SRichard Lowe	cmp	%o2, %o4
744*5d9d9091SRichard Lowe	bne,a,pn %ncc, 1b		! failed to commit, try again
745*5d9d9091SRichard Lowe	  mov	%o4, %o2
746*5d9d9091SRichard Lowe	mov	%g0, %o0
747*5d9d9091SRichard Lowe2:
748*5d9d9091SRichard Lowe	retl
749*5d9d9091SRichard Lowe	nop
750*5d9d9091SRichard Lowe	SET_SIZE(atomic_set_long_excl)
751*5d9d9091SRichard Lowe
752*5d9d9091SRichard Lowe	ENTRY(atomic_clear_long_excl)
753*5d9d9091SRichard Lowe	mov	1, %o3
754*5d9d9091SRichard Lowe	slln	%o3, %o1, %o3
755*5d9d9091SRichard Lowe	ldn	[%o0], %o2
756*5d9d9091SRichard Lowe1:
757*5d9d9091SRichard Lowe	andncc	%o3, %o2, %g0		! test if the bit is clear
758*5d9d9091SRichard Lowe	bnz,a,pn %ncc, 2f		! if so, then fail out
759*5d9d9091SRichard Lowe	  mov	-1, %o0
760*5d9d9091SRichard Lowe	andn	%o2, %o3, %o4		! clear the bit, and try to commit it
761*5d9d9091SRichard Lowe	casn	[%o0], %o2, %o4
762*5d9d9091SRichard Lowe	cmp	%o2, %o4
763*5d9d9091SRichard Lowe	bne,a,pn %ncc, 1b		! failed to commit, try again
764*5d9d9091SRichard Lowe	  mov	%o4, %o2
765*5d9d9091SRichard Lowe	mov	%g0, %o0
766*5d9d9091SRichard Lowe2:
767*5d9d9091SRichard Lowe	retl
768*5d9d9091SRichard Lowe	nop
769*5d9d9091SRichard Lowe	SET_SIZE(atomic_clear_long_excl)
770*5d9d9091SRichard Lowe
771*5d9d9091SRichard Lowe#if !defined(_KERNEL)
772*5d9d9091SRichard Lowe
773*5d9d9091SRichard Lowe	/*
774*5d9d9091SRichard Lowe	 * Spitfires and Blackbirds have a problem with membars in the
775*5d9d9091SRichard Lowe	 * delay slot (SF_ERRATA_51).  For safety's sake, we assume
776*5d9d9091SRichard Lowe	 * that the whole world needs the workaround.
777*5d9d9091SRichard Lowe	 */
778*5d9d9091SRichard Lowe	ENTRY(membar_enter)
779*5d9d9091SRichard Lowe	membar	#StoreLoad|#StoreStore
780*5d9d9091SRichard Lowe	retl
781*5d9d9091SRichard Lowe	nop
782*5d9d9091SRichard Lowe	SET_SIZE(membar_enter)
783*5d9d9091SRichard Lowe
784*5d9d9091SRichard Lowe	ENTRY(membar_exit)
785*5d9d9091SRichard Lowe	membar	#LoadStore|#StoreStore
786*5d9d9091SRichard Lowe	retl
787*5d9d9091SRichard Lowe	nop
788*5d9d9091SRichard Lowe	SET_SIZE(membar_exit)
789*5d9d9091SRichard Lowe
790*5d9d9091SRichard Lowe	ENTRY(membar_producer)
791*5d9d9091SRichard Lowe	membar	#StoreStore
792*5d9d9091SRichard Lowe	retl
793*5d9d9091SRichard Lowe	nop
794*5d9d9091SRichard Lowe	SET_SIZE(membar_producer)
795*5d9d9091SRichard Lowe
796*5d9d9091SRichard Lowe	ENTRY(membar_consumer)
797*5d9d9091SRichard Lowe	membar	#LoadLoad
798*5d9d9091SRichard Lowe	retl
799*5d9d9091SRichard Lowe	nop
800*5d9d9091SRichard Lowe	SET_SIZE(membar_consumer)
801*5d9d9091SRichard Lowe
802*5d9d9091SRichard Lowe#endif	/* !_KERNEL */
803