ia64-test-nat-asm.S revision 05feedabeaa8eb45bc75b40309f7d2c365ebf581
1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2004 Hewlett-Packard Co
3	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5This file is part of libunwind.
6
7Permission is hereby granted, free of charge, to any person obtaining
8a copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sublicense, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice shall be
16included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
25
26	.text
27
28#define CALL_NEXT_PTR(gp_save_reg, arg0, arg1)				\
29	ld8 r2 = [arg0], 8;;	/* read the next function pointer */	\
30	ld8 r3 = [r2], 8;;	/* read the function's entry-point */	\
31	ld8 r2 = [r2];;		/* read the function's gp */		\
32	mov b6 = r3;							\
33	mov gp_save_reg = gp;						\
34	mov out0 = arg0;						\
35	mov out1 = arg1;						\
36	mov gp = r2;							\
37	br.call.sptk.many rp = b6;;					\
38	mov gp = gp_save_reg
39
40#define CALL_NEXT(gp_save_reg)	CALL_NEXT_PTR(gp_save_reg, in0, in1)
41
42#define LOAD_VAL(reg)				\
43	ld8 reg = [in1], 8;;			\
44	tbit.nz p15, p0 = reg, 0;;		\
45(p15)	ld8.s reg = [r0]
46
47
48	.global flushrs
49	.proc flushrs
50flushrs:
51	flushrs;;
52	br.ret.sptk.many rp
53	.endp flushrs
54
55	/* Save r4-r7 into stacked registers, load them up with the
56	   values passed via the pointer in in1 and then call the
57	   function passed via the pointer in in0.  */
58
59	.global save_static_to_stacked
60	.proc save_static_to_stacked
61save_static_to_stacked:
62	.prologue
63	.regstk 2, 7, 2, 0
64	.save ar.pfs, loc0
65	alloc loc0 = ar.pfs, 2, 7, 2, 0
66	.save rp, loc1
67	mov loc1 = rp
68	.spillreg r4, loc2
69	mov loc2 = r4
70	.spillreg r5, loc3
71	mov loc3 = r5
72	.spillreg r6, loc4
73	mov loc4 = r6
74	.spillreg r7, loc5
75	mov loc5 = r7
76	.body
77	LOAD_VAL(r4)
78	LOAD_VAL(r5)
79	LOAD_VAL(r6)
80	LOAD_VAL(r7)
81	CALL_NEXT(loc6)
82
83	mov r4 = loc2
84	mov r5 = loc3
85	mov r6 = loc4
86	mov r7 = loc5
87
88	mov ar.pfs = loc0
89	mov rp = loc1
90	br.ret.sptk.many rp
91	.endp save_static_to_stacked
92
93	/* Save f2 to the memory stack, save r4 to f2, then load
94	   r4 with the value passed via in1 and call the function
95	   passed via in0.  */
96
97	.global save_static_to_fr
98	.proc save_static_to_fr
99save_static_to_fr:
100	.prologue
101	.regstk 2, 3, 2, 0
102	.save ar.pfs, loc0
103	alloc loc0 = ar.pfs, 2, 3, 2, 0
104	.save rp, loc1
105	mov loc1 = rp
106	.fframe 16
107	.spillpsp f2, 0
108	stf.spill [sp] = f2, -16
109	.spillreg r4, f2
110	setf.sig f2 = r4
111
112	.body
113
114	ld8 r4 = [in1], 8;;
115	tbit.nz p6, p0 = r4, 0;;
116(p6)	ld8.s r4 = [r0]
117
118	CALL_NEXT(loc2)
119
120	getf.sig r4 = f2		// restore r4
121	.restore sp
122	add sp = 16, sp;;
123	ldf.fill f2 = [sp]		// restore r2
124
125	mov ar.pfs = loc0
126	mov rp = loc1
127	br.ret.sptk.many rp
128	.endp save_static_to_fr
129
130	/* If r4 is not a NaT, save b3 to a stacked register and
131	   then save r4 in b3.  The non-NaTness of r4 is saved in
132	   p1.  */
133
134	.global save_static_to_br
135	.proc save_static_to_br
136save_static_to_br:
137	.prologue
138	.regstk 2, 6, 2, 0
139	.save ar.pfs, loc0
140	alloc loc0 = ar.pfs, 2, 6, 2, 0
141	.save rp, loc1
142	mov loc1 = rp
143
144	.save pr, loc2
145	mov loc2 = pr			// save predicates
146
147	.spillreg b3, loc3
148	mov loc3 = b3
149
150	tnat.z p1, p2 = r4;;
151	.spillreg.p p1, r4, b3
152(p1)	mov b3 = r4
153	.spillreg.p p2, r4, loc4
154(p2)	mov loc4 = r4
155
156	.body
157
158	LOAD_VAL(r4)
159	CALL_NEXT(loc5)
160
161	.pred.rel.mutex p1, p2
162(p1)	mov r4 = b3			// restore r4
163(p2)	mov r4 = loc4
164
165	mov ar.pfs = loc0
166	mov rp = loc1
167	mov pr = loc2, -1
168	mov b3 = loc3			// restore b3
169	br.ret.sptk.many rp
170	.endp save_static_to_br
171
172	/* Spill r4 into memory and then save r5 in r4.  */
173
174	.global save_static_to_mem
175	.proc save_static_to_mem
176save_static_to_mem:
177	.prologue
178	.regstk 2, 4, 2, 0
179	.save ar.pfs, loc0
180	alloc loc0 = ar.pfs, 2, 4, 2, 0
181	.save rp, loc1
182	mov loc1 = rp
183	.save ar.unat, loc2
184	mov loc2 = ar.unat
185
186	.fframe 16
187	.spillpsp r4, 0
188	st8.spill [sp] = r4, -16
189
190	.spillreg r5, r4
191	mov r4 = r5
192
193	.body
194
195	LOAD_VAL(r5)
196	CALL_NEXT(loc3)
197
198	mov r5 = r4			// restore r5
199	.restore sp
200	add sp = 16, sp;;
201	ld8.fill r4 = [sp]		// restore r4
202
203	mov ar.pfs = loc0
204	mov rp = loc1
205	mov ar.unat = loc2		// restore ar.unat
206	br.ret.sptk.many rp
207	.endp save_static_to_mem
208
209	/* Spill r6 into memory and save primary ar.unat in a register.  */
210
211	.global save_static_to_mem2
212	.proc save_static_to_mem2
213save_static_to_mem2:
214	.prologue
215	.regstk 2, 5, 2, 0
216	.save ar.pfs, loc0
217	alloc loc0 = ar.pfs, 2, 5, 2, 0
218	.save rp, loc1
219	mov loc1 = rp
220	.save ar.unat, loc2
221	mov loc2 = ar.unat
222
223	.fframe 16
224	.spillpsp r6, 0
225	st8.spill [sp] = r6, -16;;
226	.save @priunat, loc3
227	mov loc3 = ar.unat
228	mov ar.unat = 0			// trash ar.unat
229
230	.body
231
232	LOAD_VAL(r6)
233	CALL_NEXT(loc4)
234
235	mov ar.unat = loc3		// restore primary UNaT
236	.restore sp
237	add sp = 16, sp;;
238	ld8.fill r6 = [sp]		// restore r6
239
240	mov ar.pfs = loc0
241	mov rp = loc1
242	mov ar.unat = loc2		// restore ar.unat
243	br.ret.sptk.many rp
244	.endp save_static_to_mem2
245
246	/* Spill r6 into memory and save primary ar.unat in memory.  */
247
248	.global save_static_to_mem3
249	.proc save_static_to_mem3
250save_static_to_mem3:
251	.prologue
252	.regstk 2, 5, 2, 0
253	.save ar.pfs, loc0
254	alloc loc0 = ar.pfs, 2, 5, 2, 0
255	.save rp, loc1
256	mov loc1 = rp
257	.save ar.unat, loc2
258	mov loc2 = ar.unat
259
260	add r2 = 8, sp
261	.fframe 16
262	.spillpsp r6, 0
263	st8.spill [sp] = r6, -16;;
264	mov r3 = ar.unat;;
265	.savepsp @priunat, -8
266	st8 [r2] = r3
267	mov ar.unat = 0			// trash ar.unat
268
269	.body
270
271	LOAD_VAL(r6)
272	CALL_NEXT(loc4)
273
274	add r2 = 24, sp;;
275	ld8 r3 = [r2];;
276	mov ar.unat = r3		// restore primary UNaT
277	.restore sp
278	add sp = 16, sp;;
279	ld8.fill r6 = [sp]		// restore r6
280
281	mov ar.pfs = loc0
282	mov rp = loc1
283	mov ar.unat = loc2		// restore ar.unat
284	br.ret.sptk.many rp
285	.endp save_static_to_mem3
286
287	/* Spill r6 into memory and save primary ar.unat in register,
288	   then in memory.  */
289
290	.global save_static_to_mem4
291	.proc save_static_to_mem4
292save_static_to_mem4:
293	.prologue
294	.regstk 2, 5, 2, 0
295	.save ar.pfs, loc0
296	alloc loc0 = ar.pfs, 2, 5, 2, 0
297	.save rp, loc1
298	mov loc1 = rp
299	.save ar.unat, loc2
300	mov loc2 = ar.unat
301
302	add r2 = 8, sp
303	.fframe 16
304	.spillpsp r6, 0
305	st8.spill [sp] = r6, -16;;
306	.save @priunat, r3
307	mov r3 = ar.unat;;
308	mov ar.unat = 0			// trash ar.unat
309	.savepsp @priunat, -8
310	st8 [r2] = r3
311	mov r3 = r0			// trash register pri UNaT location
312	.body
313
314	LOAD_VAL(r6)
315	CALL_NEXT(loc4)
316
317	add r2 = 24, sp;;
318	ld8 r3 = [r2];;
319	mov ar.unat = r3		// restore primary UNaT
320	.restore sp
321	add sp = 16, sp;;
322	ld8.fill r6 = [sp]		// restore r6
323
324	mov ar.pfs = loc0
325	mov rp = loc1
326	mov ar.unat = loc2		// restore ar.unat
327	br.ret.sptk.many rp
328	.endp save_static_to_mem4
329
330	/* Spill r6 into memory and save primary ar.unat in register,
331	   then in memory.  */
332
333	.global save_static_to_mem5
334	.proc save_static_to_mem5
335save_static_to_mem5:
336	.prologue
337	.regstk 2, 5, 2, 0
338	.save ar.pfs, loc0
339	alloc loc0 = ar.pfs, 2, 5, 2, 0
340	.save rp, loc1
341	mov loc1 = rp
342	.save ar.unat, loc2
343	mov loc2 = ar.unat
344
345	add r2 = 8, sp
346	.fframe 16
347	.spillpsp r6, 0
348	st8.spill [sp] = r6, -16;;
349	mov r3 = ar.unat;;
350	mov ar.unat = 0			// trash ar.unat
351	.savepsp @priunat, -8
352	st8 [r2] = r3
353	.save @priunat, loc3
354	mov loc3 = r3
355	st8 [r2] = r0			// trash memory pri UNaT location
356	.body
357
358	LOAD_VAL(r6)
359	CALL_NEXT(loc4)
360
361	add r2 = 24, sp;;
362	ld8 r3 = [r2];;
363	mov ar.unat = loc3		// restore primary UNaT
364	.restore sp
365	add sp = 16, sp;;
366	ld8.fill r6 = [sp]		// restore r6
367
368	mov ar.pfs = loc0
369	mov rp = loc1
370	mov ar.unat = loc2		// restore ar.unat
371	br.ret.sptk.many rp
372	.endp save_static_to_mem5
373
374	/* Save r4-r7 to various scratch registers, then trigger
375	   a segfault.  */
376
377	.global save_static_to_scratch
378	.proc save_static_to_scratch
379save_static_to_scratch:
380	.prologue
381
382	.spillreg r4, r16
383	mov r16 = r4			// save r4 in r16
384	tnat.nz p6, p7 = r5;;
385	.spillreg.p p6, r5, f31
386(p6)	setf.sig f31 = r5		// save r5 in f31 if it's a NaT
387	.spillreg.p p7, r5, b6
388(p7)	mov b6 = r5			//         in  b6 if it not
389	.spillreg r6, f32
390	setf.sig f32 = r6		// save r6 in f32 (fph partition)
391	.spillsp r7, 0
392	st8.spill [sp] = r7		// save r7 in the scratch stack space
393	.spillreg f4, f6
394	mov f6 = f4;;
395	.body
396
397	LOAD_VAL(r4)
398	LOAD_VAL(r5)
399	LOAD_VAL(r6)
400	LOAD_VAL(r7)
401	setf.sig f4 = r4
402
403	/* Now force a SIGSEGV.  Make sure the ld8 is at the beginning of a
404	   bundle, so the signal-handler can skip over it simply by
405	   incrementing the IP.  */
406	{
407		.mmi
408		ld8 r2 = [r0]
409		nop.m 0
410		nop.i 0 ;;
411	}
412
413	mov f4 = f6
414	mov r4 = r16
415	.pred.rel.mutex p6, p7
416(p6)	getf.sig r5 = f31
417(p7)	mov r5 = b6
418	getf.sig r6 = f32
419	ld8.fill r7 = [sp]
420
421	br.ret.sptk.many rp
422	.endp save_static_to_scratch
423
424	/* Rotate registers a bit in a vain attempt to sow some confusion.
425	   Care must be taken not to write any rotating general register
426	   after rotation, because we keep the preserved state
427	   there... */
428
429	.global rotate_regs
430	.proc rotate_regs
431rotate_regs:
432	.prologue
433	.regstk 2, 14, 2, 16
434	.save ar.pfs, loc0
435	alloc loc0 = ar.pfs, 2, 14, 2, 16
436	.save rp, loc1
437	mov loc1 = rp
438	.save pr, loc2
439	mov loc2 = pr
440	.save ar.lc, loc3
441	mov loc3 = ar.lc
442	.spillreg r4, loc4
443	mov loc4 = r4
444
445	ld8 r2 = [in1], 8;;
446	mov pr = r2, -1
447
448	ld8 r2 = [in1], 8;;
449	mov r8 = in0
450	mov r9 = in1
451	and r2 = 127, r2;;
452	mov ar.ec = 0
453	mov ar.lc = r2;;
454
455	// use p6 to preserve p63 as it gets rotated into p16:
456(p16)	cmp.eq.unc p6,p0 = r0,r0;;
4571:
458(p6)	cmp.eq.unc p16,p0 = r0,r0
459(p63)	cmp.eq.unc p6,p0 = r0,r0
460	br.ctop.dptk.few 1b;;
461
462(p6)	cmp.eq.unc p63,p0 = r0,r0
463
464	CALL_NEXT_PTR(r4, r8, r9)
465
466	clrrrb
467
468	mov ar.pfs = loc0
469	mov rp = loc1
470	mov pr = loc2, -1
471	mov ar.lc = loc3
472	mov r4 = loc4
473	br.ret.sptk.many rp
474
475	.endp rotate_regs
476
477	.global save_pr
478	.proc save_pr
479save_pr:
480	.prologue
481	.regstk 2, 4, 2, 0
482	.save ar.pfs, loc0
483	alloc loc0 = ar.pfs, 2, 4, 2, 0
484	.save rp, loc1
485	mov loc1 = rp
486	.save pr, loc2
487	mov loc2 = pr
488
489	ld8 r2 = [in1], 8;;
490	mov pr = r2, -1
491
492	CALL_NEXT(loc3)
493
494	mov ar.pfs = loc0
495	mov rp = loc1
496	mov pr = loc2, -1
497	br.ret.sptk.many rp
498
499	.endp save_pr
500