1/*-
2 * Copyright (c) 1998 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28/*-
29 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
30 * All rights reserved.
31 *
32 * Author: Chris G. Demetriou
33 *
34 * Permission to use, copy, modify and distribute this software and
35 * its documentation is hereby granted, provided that both the copyright
36 * notice and this permission notice appear in all copies of the
37 * software, derivative works or modified versions, and any portions
38 * thereof, and that both notices appear in supporting documentation.
39 *
40 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
41 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
42 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 *
44 * Carnegie Mellon requests users of this software to return to
45 *
46 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
47 *  School of Computer Science
48 *  Carnegie Mellon University
49 *  Pittsburgh PA 15213-3890
50 *
51 * any improvements or extensions that they make and grant Carnegie the
52 * rights to redistribute these changes.
53 */
54
55#include <machine/asm.h>
56#include <machine/ia64_cpu.h>
57#include <assym.s>
58
59	.text
60
61ENTRY(fusufault, 0)
62{	.mib
63	st8.rel		[r15]=r0		// Clear onfault.
64	add		ret0=-1,r0
65	br.ret.sptk	rp
66	;;
67}
68END(fusufault)
69
70/*
71 * casuword(u_long *p, u_long old, u_long new)
72 *	Perform a compare-exchange in user space.
73 */
74ENTRY(casuword, 3)
75{	.mlx
76	ld8.acq		r15=[r13]		// r15 = curthread
77	movl		r14=VM_MAXUSER_ADDRESS
78	;;
79}
80{	.mib
81	add		r15=TD_PCB,r15
82	cmp.geu		p6,p0=in0,r14
83(p6)	br.dpnt.few	1f
84	;;
85}
86{	.mlx
87	ld8		r15=[r15]		// r15 = PCB
88	movl		r14=fusufault
89	;;
90}
91{	.mmi
92	mov		ar.ccv=in1
93	add		r15=PCB_ONFAULT,r15
94	nop		0
95	;;
96}
97{	.mmi
98	st8		[r15]=r14		// Set onfault
99	;;
100	cmpxchg8.rel	ret0=[in0],in2,ar.ccv
101	nop		0
102	;;
103}
104{	.mib
105	st8.rel		[r15]=r0		// Clear onfault
106	nop		0
107	br.ret.sptk	rp
108	;;
109}
1101:
111{	.mib
112	add		ret0=-1,r0
113	nop		0
114	br.ret.sptk	rp
115	;;
116}
117END(casuword)
118
119/*
120 * casuword32(uint32_t *p, uint32_t old, uint32_t new)
121 *	Perform a 32-bit compare-exchange in user space.
122 */
123ENTRY(casuword32, 3)
124{	.mlx
125	movl		r14=VM_MAXUSER_ADDRESS
126	;;
127}
128{	.mib
129	ld8.acq		r15=[r13]		// r15 = curthread
130	cmp.geu		p6,p0=in0,r14
131(p6)	br.dpnt.few	1f
132	;;
133}
134{	.mlx
135	add		r15=TD_PCB,r15
136	movl		r14=fusufault
137	;;
138}
139{	.mmi
140	ld8		r15=[r15]		// r15 = PCB
141	;;
142	mov		ar.ccv=in1
143	add		r15=PCB_ONFAULT,r15
144	;;
145}
146{	.mmi
147	st8		[r15]=r14		// Set onfault
148	;;
149	cmpxchg4.rel	ret0=[in0],in2,ar.ccv
150	nop		0
151	;;
152}
153{	.mib
154	st8.rel		[r15]=r0		// Clear onfault
155	nop		0
156	br.ret.sptk	rp
157	;;
158}
1591:
160{	.mib
161	add		ret0=-1,r0
162	nop		0
163	br.ret.sptk	rp
164	;;
165}
166END(casuword32)
167
168/*
169 * subyte(void *addr, int byte)
170 * suword16(void *addr, int word)
171 * suword32(void *addr, int word)
172 * suword64|suword(void *addr, long word)
173 *	Store in user space
174 */
175
176ENTRY(subyte, 2)
177{	.mlx
178	movl		r14=VM_MAXUSER_ADDRESS
179	;;
180}
181{	.mib
182	ld8.acq		r15=[r13]		// r15 = curthread
183	cmp.geu		p6,p0=in0,r14
184(p6)	br.dpnt.few	1f
185	;;
186}
187{	.mlx
188	add		r15=TD_PCB,r15
189	movl		r14=fusufault
190	;;
191}
192{	.mmi
193	ld8		r15=[r15]		// r15 = PCB
194	;;
195	nop		0
196	add		r15=PCB_ONFAULT,r15
197	;;
198}
199{	.mmi
200	st8		[r15]=r14		// Set onfault
201	;;
202	st1.rel		[in0]=in1
203	nop		0
204	;;
205}
206{	.mib
207	st8.rel		[r15]=r0		// Clear onfault
208	mov		ret0=r0
209	br.ret.sptk	rp
210	;;
211}
2121:
213{	.mib
214	add		ret0=-1,r0
215	nop		0
216	br.ret.sptk	rp
217	;;
218}
219END(subyte)
220
221ENTRY(suword16, 2)
222{	.mlx
223	movl		r14=VM_MAXUSER_ADDRESS
224	;;
225}
226{	.mib
227	ld8.acq		r15=[r13]		// r15 = curthread
228	cmp.geu		p6,p0=in0,r14
229(p6)	br.dpnt.few	1f
230	;;
231}
232{	.mlx
233	add		r15=TD_PCB,r15
234	movl		r14=fusufault
235	;;
236}
237{	.mmi
238	ld8		r15=[r15]		// r15 = PCB
239	;;
240	nop		0
241	add		r15=PCB_ONFAULT,r15
242	;;
243}
244{	.mmi
245	st8		[r15]=r14		// Set onfault
246	;;
247	st2.rel		[in0]=in1
248	nop		0
249	;;
250}
251{	.mib
252	st8.rel		[r15]=r0		// Clear onfault
253	mov		ret0=r0
254	br.ret.sptk	rp
255	;;
256}
2571:
258{	.mib
259	add		ret0=-1,r0
260	nop		0
261	br.ret.sptk	rp
262	;;
263}
264END(suword16)
265
266ENTRY(suword32, 2)
267{	.mlx
268	movl		r14=VM_MAXUSER_ADDRESS
269	;;
270}
271{	.mib
272	ld8.acq		r15=[r13]		// r15 = curthread
273	cmp.geu		p6,p0=in0,r14
274(p6)	br.dpnt.few	1f
275	;;
276}
277{	.mlx
278	add		r15=TD_PCB,r15
279	movl		r14=fusufault
280	;;
281}
282{	.mmi
283	ld8		r15=[r15]		// r15 = PCB
284	;;
285	nop		0
286	add		r15=PCB_ONFAULT,r15
287	;;
288}
289{	.mmi
290	st8		[r15]=r14		// Set onfault
291	;;
292	st4.rel		[in0]=in1
293	nop		0
294	;;
295}
296{	.mib
297	st8.rel		[r15]=r0		// Clear onfault
298	mov		ret0=r0
299	br.ret.sptk	rp
300	;;
301}
3021:
303{	.mib
304	add		ret0=-1,r0
305	nop		0
306	br.ret.sptk	rp
307	;;
308}
309END(suword32)
310
311ENTRY(suword64, 2)
312XENTRY(suword)
313{	.mlx
314	movl		r14=VM_MAXUSER_ADDRESS
315	;;
316}
317{	.mib
318	ld8.acq		r15=[r13]		// r15 = curthread
319	cmp.geu		p6,p0=in0,r14
320(p6)	br.dpnt.few	1f
321	;;
322}
323{	.mlx
324	add		r15=TD_PCB,r15
325	movl		r14=fusufault
326	;;
327}
328{	.mmi
329	ld8		r15=[r15]		// r15 = PCB
330	;;
331	nop		0
332	add		r15=PCB_ONFAULT,r15
333	;;
334}
335{	.mmi
336	st8		[r15]=r14		// Set onfault
337	;;
338	st8.rel		[in0]=in1
339	nop		0
340	;;
341}
342{	.mib
343	st8.rel		[r15]=r0		// Clear onfault
344	mov		ret0=r0
345	br.ret.sptk	rp
346	;;
347}
3481:
349{	.mib
350	add		ret0=-1,r0
351	nop		0
352	br.ret.sptk	rp
353	;;
354}
355END(suword64)
356
357/*
358 * fubyte(void *addr, int byte)
359 * fuword16(void *addr, int word)
360 * fuword32(void *addr, int word)
361 * fuword64|fuword(void *addr, long word)
362 *	Fetch from user space
363 */
364
365ENTRY(fubyte, 1)
366{	.mlx
367	movl		r14=VM_MAXUSER_ADDRESS
368	;;
369}
370{	.mib
371	ld8.acq		r15=[r13]		// r15 = curthread
372	cmp.geu		p6,p0=in0,r14
373(p6)	br.dpnt.few	1f
374	;;
375}
376{	.mlx
377	add		r15=TD_PCB,r15
378	movl		r14=fusufault
379	;;
380}
381{	.mmi
382	ld8		r15=[r15]		// r15 = PCB
383	;;
384	nop		0
385	add		r15=PCB_ONFAULT,r15
386	;;
387}
388{	.mmi
389	st8		[r15]=r14		// Set onfault
390	;;
391	mf
392	nop		0
393	;;
394}
395{	.mmb
396	ld1		ret0=[in0]
397	st8.rel		[r15]=r0		// Clear onfault
398	br.ret.sptk	rp
399	;;
400}
4011:
402{	.mib
403	add		ret0=-1,r0
404	nop		0
405	br.ret.sptk	rp
406	;;
407}
408END(fubyte)
409
410ENTRY(fuword16, 2)
411{	.mlx
412	movl		r14=VM_MAXUSER_ADDRESS
413	;;
414}
415{	.mib
416	ld8.acq		r15=[r13]		// r15 = curthread
417	cmp.geu		p6,p0=in0,r14
418(p6)	br.dpnt.few	1f
419	;;
420}
421{	.mlx
422	add		r15=TD_PCB,r15
423	movl		r14=fusufault
424	;;
425}
426{	.mmi
427	ld8		r15=[r15]		// r15 = PCB
428	;;
429	nop		0
430	add		r15=PCB_ONFAULT,r15
431	;;
432}
433{	.mmi
434	st8		[r15]=r14		// Set onfault
435	;;
436	mf
437	nop		0
438	;;
439}
440{	.mmb
441	ld2		ret0=[in0]
442	st8.rel		[r15]=r0		// Clear onfault
443	br.ret.sptk	rp
444	;;
445}
4461:
447{	.mib
448	add		ret0=-1,r0
449	nop		0
450	br.ret.sptk	rp
451	;;
452}
453END(fuword16)
454
455ENTRY(fuword32, 2)
456{	.mlx
457	movl		r14=VM_MAXUSER_ADDRESS
458	;;
459}
460{	.mib
461	ld8.acq		r15=[r13]		// r15 = curthread
462	cmp.geu		p6,p0=in0,r14
463(p6)	br.dpnt.few	1f
464	;;
465}
466{	.mlx
467	add		r15=TD_PCB,r15
468	movl		r14=fusufault
469	;;
470}
471{	.mmi
472	ld8		r15=[r15]		// r15 = PCB
473	;;
474	nop		0
475	add		r15=PCB_ONFAULT,r15
476	;;
477}
478{	.mmi
479	st8		[r15]=r14		// Set onfault
480	;;
481	mf
482	nop		0
483	;;
484}
485{	.mmb
486	ld4		ret0=[in0]
487	st8.rel		[r15]=r0		// Clear onfault
488	br.ret.sptk	rp
489	;;
490}
4911:
492{	.mib
493	add		ret0=-1,r0
494	nop		0
495	br.ret.sptk	rp
496	;;
497}
498END(fuword32)
499
500ENTRY(fuword64, 2)
501XENTRY(fuword)
502{	.mlx
503	movl		r14=VM_MAXUSER_ADDRESS
504	;;
505}
506{	.mib
507	ld8.acq		r15=[r13]		// r15 = curthread
508	cmp.geu		p6,p0=in0,r14
509(p6)	br.dpnt.few	1f
510	;;
511}
512{	.mlx
513	add		r15=TD_PCB,r15
514	movl		r14=fusufault
515	;;
516}
517{	.mmi
518	ld8		r15=[r15]		// r15 = PCB
519	;;
520	nop		0
521	add		r15=PCB_ONFAULT,r15
522	;;
523}
524{	.mmi
525	st8		[r15]=r14		// Set onfault
526	;;
527	mf
528	nop		0
529	;;
530}
531{	.mmb
532	ld8		ret0=[in0]
533	st8.rel		[r15]=r0		// Clear onfault
534	br.ret.sptk	rp
535	;;
536}
5371:
538{	.mib
539	add		ret0=-1,r0
540	nop		0
541	br.ret.sptk	rp
542	;;
543}
544END(fuword64)
545
546/*
547 * fuswintr(void *addr)
548 * suswintr(void *addr)
549 */
550
551ENTRY(fuswintr, 1)
552{	.mib
553	add		ret0=-1,r0
554	nop		0
555	br.ret.sptk	rp
556	;;
557}
558END(fuswintr)
559
560ENTRY(suswintr, 0)
561{	.mib
562	add		ret0=-1,r0
563	nop		0
564	br.ret.sptk	rp
565	;;
566}
567END(suswintr)
568
569/**************************************************************************/
570
571/*
572 * Copy a null-terminated string within the kernel's address space.
573 * If lenp is not NULL, store the number of chars copied in *lenp
574 *
575 * int copystr(char *from, char *to, size_t len, size_t *lenp);
576 */
577ENTRY(copystr, 4)
578	mov	r14=in2			// r14 = i = len
579	cmp.eq	p6,p0=r0,in2
580(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
581
5821:	ld1	r15=[in0],1		// read one byte
583	;;
584	st1	[in1]=r15,1		// write that byte
585	add	in2=-1,in2		// len--
586	;;
587	cmp.eq	p6,p0=r0,r15
588	cmp.ne	p7,p0=r0,in2
589	;;
590(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
591(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
592
5932:	cmp.eq	p6,p0=r0,in3
594(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
595	sub	r14=r14,in2		// *lenp = (i - len)
596	;;
597	st8	[in3]=r14
598
5993:	cmp.eq	p6,p0=r0,r15
600(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
601
602	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
603	br.ret.sptk.few rp
604
6054:	mov	ret0=0			// return 0.
606	br.ret.sptk.few rp
607END(copystr)
608
609ENTRY(copyinstr, 4)
610	.prologue
611	.regstk	4, 3, 4, 0
612	.save	ar.pfs,loc0
613	alloc	loc0=ar.pfs,4,3,4,0
614	.save	rp,loc1
615	mov	loc1=rp
616	.body
617
618	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
619	;;
620	cmp.geu	p6,p0=in0,loc2			// is in user space.
621	;;
622(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
623	ld8.acq	r15=[r13]
624	movl	r14=copyerr			// set up fault handler.
625	;;
626	add	r15=TD_PCB,r15			// find pcb
627	;;
628	ld8	r15=[r15]
629	;;
630	add	loc2=PCB_ONFAULT,r15
631	;;
632	st8	[loc2]=r14
633	;;
634	mov	out0=in0
635	mov	out1=in1
636	mov	out2=in2
637	mov	out3=in3
638	;;
639	br.call.sptk.few rp=copystr		// do the copy.
640	st8	[loc2]=r0			// kill the fault handler.
641	mov	ar.pfs=loc0			// restore ar.pfs
642	mov	rp=loc1				// restore ra.
643	br.ret.sptk.few rp			// ret0 left over from copystr
644END(copyinstr)
645
646/*
647 * Not the fastest bcopy in the world.
648 */
649ENTRY(bcopy, 3)
650	mov	ret0=r0				// return zero for copy{in,out}
651	;;
652	cmp.le	p6,p0=in2,r0			// bail if len <= 0
653(p6)	br.ret.spnt.few rp
654
655	sub	r14=in1,in0 ;;			// check for overlap
656	cmp.ltu	p6,p0=r14,in2			// dst-src < len
657(p6)	br.cond.spnt.few 5f
658
659	extr.u	r14=in0,0,3			// src & 7
660	extr.u	r15=in1,0,3 ;;			// dst & 7
661	cmp.eq	p6,p0=r14,r15			// different alignment?
662(p6)	br.cond.spnt.few 2f			// branch if same alignment
663
6641:	ld1	r14=[in0],1 ;;			// copy bytewise
665	st1	[in1]=r14,1
666	add	in2=-1,in2 ;;			// len--
667	cmp.ne	p6,p0=r0,in2
668(p6)	br.cond.dptk.few 1b			// loop
669	br.ret.sptk.few rp			// done
670
6712:	cmp.eq	p6,p0=r14,r0			// aligned?
672(p6)	br.cond.sptk.few 4f
673
6743:	ld1	r14=[in0],1 ;;			// copy bytewise
675	st1	[in1]=r14,1
676	extr.u	r15=in0,0,3			// src & 7
677	add	in2=-1,in2 ;;			// len--
678	cmp.eq	p6,p0=r0,in2			// done?
679	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
680(p6)	br.ret.spnt.few rp			// return if done
681(p7)	br.cond.spnt.few 4f			// go to main copy
682	br.cond.sptk.few 3b			// more bytes to copy
683
684	// At this point, in2 is non-zero
685
6864:	mov	r14=8 ;;
687	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
688(p6)	br.cond.spnt.few 1b			// byte copy the end
689	ld8	r15=[in0],8 ;;			// copy word
690	st8	[in1]=r15,8
691	add	in2=-8,in2 ;;			// len -= 8
692	cmp.ne	p6,p0=r0,in2			// done?
693(p6)	br.cond.spnt.few 4b			// again
694
695	br.ret.sptk.few rp			// return
696
697	// Don't bother optimising overlap case
698
6995:	add	in0=in0,in2
700	add	in1=in1,in2 ;;
701	add	in0=-1,in0
702	add	in1=-1,in1 ;;
703
7046:	ld1	r14=[in0],-1 ;;
705	st1	[in1]=r14,-1
706	add	in2=-1,in2 ;;
707	cmp.ne	p6,p0=r0,in2
708(p6)	br.cond.spnt.few 6b
709
710	br.ret.sptk.few rp
711END(bcopy)
712
713ENTRY(memcpy,3)
714	mov	r14=in0 ;;
715	mov	in0=in1 ;;
716	mov	in1=r14
717	br.cond.sptk.few bcopy
718END(memcpy)
719
720ENTRY(copyin, 3)
721	.prologue
722	.regstk	3, 3, 3, 0
723	.save	ar.pfs,loc0
724	alloc	loc0=ar.pfs,3,3,3,0
725	.save	rp,loc1
726	mov	loc1=rp
727	.body
728
729	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
730	;;
731	cmp.geu	p6,p0=in0,loc2			// is in user space.
732	;;
733(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
734	ld8.acq	r15=[r13]
735	movl	r14=copyerr			// set up fault handler.
736	;;
737	add	r15=TD_PCB,r15			// find pcb
738	;;
739	ld8	r15=[r15]
740	;;
741	add	loc2=PCB_ONFAULT,r15
742	;;
743	st8	[loc2]=r14
744	;;
745	mov	out0=in0
746	mov	out1=in1
747	mov	out2=in2
748	;;
749	br.call.sptk.few rp=bcopy		// do the copy.
750	st8	[loc2]=r0			// kill the fault handler.
751	mov	ar.pfs=loc0			// restore ar.pfs
752	mov	rp=loc1				// restore ra.
753	br.ret.sptk.few rp			// ret0 left over from bcopy
754END(copyin)
755
756ENTRY(copyout, 3)
757	.prologue
758	.regstk	3, 3, 3, 0
759	.save	ar.pfs,loc0
760	alloc	loc0=ar.pfs,3,3,3,0
761	.save	rp,loc1
762	mov	loc1=rp
763	.body
764
765	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
766	;;
767	cmp.geu	p6,p0=in1,loc2			// is in user space.
768	;;
769(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
770	ld8.acq	r15=[r13]
771	movl	r14=copyerr			// set up fault handler.
772	;;
773	add	r15=TD_PCB,r15			// find pcb
774	;;
775	ld8	r15=[r15]
776	;;
777	add	loc2=PCB_ONFAULT,r15
778	;;
779	st8	[loc2]=r14
780	;;
781	mov	out0=in0
782	mov	out1=in1
783	mov	out2=in2
784	;;
785	br.call.sptk.few rp=bcopy		// do the copy.
786	st8	[loc2]=r0			// kill the fault handler.
787	mov	ar.pfs=loc0			// restore ar.pfs
788	mov	rp=loc1				// restore ra.
789	br.ret.sptk.few rp			// ret0 left over from bcopy
790END(copyout)
791
792ENTRY(copyerr, 0)
793	ld8.acq	r14=[r13] ;;
794	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
795	ld8	r14=[r14] ;;
796	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
797	st8	[r14]=r0			// reset fault handler
798
799	mov	ret0=EFAULT			// return EFAULT
800	br.ret.sptk.few rp
801END(copyerr)
802
803#if defined(GPROF)
804/*
805 * Important registers:
806 *      r8      structure return address
807 *      rp      our return address
808 *      in0     caller's ar.pfs
809 *      in1     caller's gp
810 *      in2     caller's rp
811 *      in3     GOT entry
812 *      ar.pfs  our pfs
813 */
814ENTRY_NOPROFILE(_mcount, 4)
815	alloc		loc0 = ar.pfs, 4, 3, 2, 0
816	mov		loc1 = r8
817	mov		loc2 = rp
818	;;
819	mov		out0 = in2
820	mov		out1 = rp
821	br.call.sptk	rp = __mcount
822	;;
8231:
824	mov		gp = in1
825	mov		r14 = ip
826	mov		b7 = loc2
827	;;
828	add		r14 = 2f - 1b, r14
829	mov		ar.pfs = loc0
830	mov		rp = in2
831	;;
832	mov		b7 = r14
833	mov		b6 = loc2
834	mov		r8 = loc1
835	mov		r14 = in0
836	br.ret.sptk	b7
837	;;
8382:
839	mov		ar.pfs = r14
840	br.sptk		b6
841	;;
842END(_mcount)
843#endif
844