1 /***********************************************************************/
5 /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
7 /* Copyright 1996 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the Q Public License version 1.0. */
11 /***********************************************************************/
13 /* $Id: ia64.S 9341 2009-09-17 13:05:47Z xleroy $ */
15 /* Asm part of the runtime system, IA64 processor */
17 #undef BROKEN_POSTINCREMENT
19 #define ADDRGLOBAL(reg,symb) \
20 add reg = @ltoff(symb), gp;; ld8 reg = [reg]
21 #define LOADGLOBAL(reg,symb) \
22 add r3 = @ltoff(symb), gp;; ld8 r3 = [r3];; ld8 reg = [r3]
23 #define STOREGLOBAL(reg,symb) \
24 add r3 = @ltoff(symb), gp;; ld8 r3 = [r3];; st8 [r3] = reg
26 #define ST8OFF(a,b,d) st8 [a] = b, d
27 #define LD8OFF(a,b,d) ld8 a = [b], d
28 #define STFDOFF(a,b,d) stfd [a] = b, d
29 #define LDFDOFF(a,b,d) ldfd a = [b], d
30 #define STFSPILLOFF(a,b,d) stf.spill [a] = b, d
31 #define LDFFILLOFF(a,b,d) ldf.fill a = [b], d
33 #define SAVE2(a,b) ST8OFF(r2, a, 16); ST8OFF(r3, b, 16)
34 #define SAVE4(a,b,c,d) SAVE2(a,b);; SAVE2(c,d)
35 #define SAVE8(a,b,c,d,e,f,g,h) SAVE4(a,b,c,d);; SAVE4(e,f,g,h)
37 #define LOAD2(a,b) LD8OFF(a, r2, 16); LD8OFF(b, r3, 16)
38 #define LOAD4(a,b,c,d) LOAD2(a,b);; LOAD2(c,d)
39 #define LOAD8(a,b,c,d,e,f,g,h) LOAD4(a,b,c,d);; LOAD4(e,f,g,h)
41 #define FSAVE2(a,b) STFDOFF(r2, a, 16); STFDOFF(r3, b, 16)
42 #define FSAVE4(a,b,c,d) FSAVE2(a,b);; FSAVE2(c,d)
43 #define FSAVE8(a,b,c,d,e,f,g,h) FSAVE4(a,b,c,d);; FSAVE4(e,f,g,h)
45 #define FLOAD2(a,b) LDFDOFF(a, r2, 16); LDFDOFF(b, r3, 16)
46 #define FLOAD4(a,b,c,d) FLOAD2(a,b);; FLOAD2(c,d)
47 #define FLOAD8(a,b,c,d,e,f,g,h) FLOAD4(a,b,c,d);; FLOAD4(e,f,g,h)
49 #define FSPILL2(a,b) STFSPILLOFF(r2, a, 32); STFSPILLOFF(r3, b, 32)
50 #define FSPILL4(a,b,c,d) FSPILL2(a,b);; FSPILL2(c,d)
51 #define FSPILL8(a,b,c,d,e,f,g,h) FSPILL4(a,b,c,d);; FSPILL4(e,f,g,h)
53 #define FFILL2(a,b) LDFFILLOFF(a, r2, 32); LDFFILLOFF(b, r3, 32)
54 #define FFILL4(a,b,c,d) FFILL2(a,b);; FFILL2(c,d)
55 #define FFILL8(a,b,c,d,e,f,g,h) FFILL4(a,b,c,d);; FFILL4(e,f,g,h)
64 /* caml_allocN: all code generator registers preserved,
65 gp preserved, r2 = requested size */
69 cmp.ltu p0, p6 = r4, r5
70 (p6) br.ret.sptk b0 ;;
71 /* Fall through caml_call_gc */
72 br.sptk.many caml_call_gc#
76 /* caml_call_gc: all code generator registers preserved,
77 gp preserved, r2 = requested size */
83 /* Allocate stack frame */
84 add sp = -(16 + 16 + 80*8 + 42*8), sp ;;
86 /* Save requested size and GP on stack */
91 /* Record lowest stack address, return address, GC regs */
93 STOREGLOBAL(r2, caml_last_return_address#)
94 add r2 = (16 + 16 + 80*8 + 42*8), sp ;;
95 STOREGLOBAL(r2, caml_bottom_of_stack#)
96 add r2 = (16 + 16), sp ;;
97 STOREGLOBAL(r2, caml_gc_regs#)
99 /* Save all integer regs used by the code generator in the context */
100 .L100: add r3 = 8, r2 ;;
101 SAVE4(r8,r9,r10,r11) ;;
102 SAVE8(r16,r17,r18,r19,r20,r21,r22,r23) ;;
103 SAVE8(r24,r25,r26,r27,r28,r29,r30,r31) ;;
104 SAVE8(r32,r33,r34,r35,r36,r37,r38,r39) ;;
105 SAVE8(r40,r41,r42,r43,r44,r45,r46,r47) ;;
106 SAVE8(r48,r49,r50,r51,r52,r53,r54,r55) ;;
107 SAVE8(r56,r57,r58,r59,r60,r61,r62,r63) ;;
108 SAVE8(r64,r65,r66,r67,r68,r69,r70,r71) ;;
109 SAVE8(r72,r73,r74,r75,r76,r77,r78,r79) ;;
110 SAVE8(r80,r81,r82,r83,r84,r85,r86,r87) ;;
111 SAVE4(r88,r89,r90,r91) ;;
113 /* Save all floating-point registers not preserved by C */
115 FSAVE8(f8,f9,f10,f11,f12,f13,f14,f15) ;;
116 FSAVE8(f32,f33,f34,f35,f36,f37,f38,f39) ;;
117 FSAVE8(f40,f41,f42,f43,f44,f45,f46,f47) ;;
118 FSAVE8(f48,f49,f50,f51,f52,f53,f54,f55) ;;
119 FSAVE8(f56,f57,f58,f59,f60,f61,f62,f63) ;;
121 /* Save current allocation pointer for debugging purposes */
122 STOREGLOBAL(r4, caml_young_ptr#)
124 /* Save trap pointer in case an exception is raised */
125 STOREGLOBAL(r6, caml_exception_pointer#)
127 /* Call the garbage collector */
128 br.call.sptk b0 = caml_garbage_collection# ;;
134 /* Restore all integer regs from GC context */
135 add r2 = (16 + 16), sp ;;
137 LOAD4(r8,r9,r10,r11) ;;
138 LOAD8(r16,r17,r18,r19,r20,r21,r22,r23) ;;
139 LOAD8(r24,r25,r26,r27,r28,r29,r30,r31) ;;
140 LOAD8(r32,r33,r34,r35,r36,r37,r38,r39) ;;
141 LOAD8(r40,r41,r42,r43,r44,r45,r46,r47) ;;
142 LOAD8(r48,r49,r50,r51,r52,r53,r54,r55) ;;
143 LOAD8(r56,r57,r58,r59,r60,r61,r62,r63) ;;
144 LOAD8(r64,r65,r66,r67,r68,r69,r70,r71) ;;
145 LOAD8(r72,r73,r74,r75,r76,r77,r78,r79) ;;
146 LOAD8(r80,r81,r82,r83,r84,r85,r86,r87) ;;
147 LOAD4(r88,r89,r90,r91) ;;
149 /* Restore all floating-point registers not preserved by C */
151 FLOAD8(f8,f9,f10,f11,f12,f13,f14,f15) ;;
152 FLOAD8(f32,f33,f34,f35,f36,f37,f38,f39) ;;
153 FLOAD8(f40,f41,f42,f43,f44,f45,f46,f47) ;;
154 FLOAD8(f48,f49,f50,f51,f52,f53,f54,f55) ;;
155 FLOAD8(f56,f57,f58,f59,f60,f61,f62,f63) ;;
157 /* Reload new allocation pointer and allocation limit */
158 LOADGLOBAL(r4, caml_young_ptr#)
159 LOADGLOBAL(r5, caml_young_limit#)
161 /* Allocate space for the block */
165 cmp.ltu p6, p0 = r4, r5 /* enough space? */
166 (p6) br.cond.spnt .L100 ;; /* no: call GC again */
168 /* Reload return address and say that we are back into Caml code */
169 ADDRGLOBAL(r3, caml_last_return_address#) ;;
173 /* Return to caller */
175 add sp = (16 + 16 + 80*8 + 42*8), sp ;;
180 /* Call a C function from Caml */
181 /* Function to call is in r2 */
188 /* The Caml code that called us does not expect any
189 code-generator registers to be preserved */
191 /* Recover entry point from the function pointer in r2 */
195 /* Preserve gp in r7 */
198 /* Record lowest stack address and return address */
200 STOREGLOBAL(sp, caml_bottom_of_stack#) ;;
201 STOREGLOBAL(r14, caml_last_return_address#)
203 /* Make the exception handler and alloc ptr available to the C code */
204 STOREGLOBAL(r4, caml_young_ptr#)
205 STOREGLOBAL(r6, caml_exception_pointer#)
207 /* Recover gp from the function pointer in r2 */
210 /* Call the function */
211 br.call.sptk b0 = b6 ;;
216 /* Reload alloc ptr and alloc limit */
217 LOADGLOBAL(r4, caml_young_ptr#)
218 LOADGLOBAL(r5, caml_young_limit#)
220 /* Reload return address and say that we are back into Caml code */
221 ADDRGLOBAL(r3, caml_last_return_address#) ;;
225 /* Return to caller */
231 /* Start the Caml program */
233 .global caml_start_program#
234 .proc caml_start_program#
238 ADDRGLOBAL(r2, caml_program#) ;;
241 /* Code shared with caml_callback* */
243 /* Allocate 64 "out" registers (for the Caml code) and no locals */
244 alloc r3 = ar.pfs, 0, 0, 64, 0
245 add sp = -(56 * 8), sp ;;
247 /* Save all callee-save registers on stack */
249 ST8OFF(r2, r3, 8) /* 0 : ar.pfs */
251 ST8OFF(r2, r3, 8) ;; /* 1 : return address */
252 ST8OFF(r2, gp, 8) /* 2 : gp */
254 ST8OFF(r2, r3, 8) /* 3 : predicates */
256 ST8OFF(r2, r3, 8) /* 4 : ar.fpsr */
258 ST8OFF(r2, r3, 8) /* 5 : ar.unat */
260 ST8OFF(r2, r3, 8) /* 6 : ar.lc */
262 ST8OFF(r2, r3, 8) /* 7 - 11 : b1 - b5 */
273 SAVE4(r4,r5,r6,r7) ;; /* 12 - 15 : r4 - r7 */
275 add r3 = 16, r2 ;; /* 16 - 55 : f2 - f5, f16 - f31 */
276 FSPILL4(f2,f3,f4,f5) ;;
277 FSPILL8(f16,f17,f18,f19,f20,f21,f22,f23) ;;
278 FSPILL8(f24,f25,f26,f27,f28,f29,f30,f31) ;;
280 /* Set up a callback link on the stack. In addition to
281 the normal callback link contents (saved values of
282 caml_bottom_of_stack, caml_last_return_address and
283 caml_gc_regs), we also save there caml_saved_bsp
284 and caml_saved_rnat */
286 LOADGLOBAL(r3, caml_bottom_of_stack#)
289 LOADGLOBAL(r3, caml_last_return_address#) ;;
291 LOADGLOBAL(r3, caml_gc_regs#) ;;
293 LOADGLOBAL(r3, caml_saved_bsp#) ;;
295 LOADGLOBAL(r3, caml_saved_rnat#) ;;
298 /* Set up a trap frame to catch exceptions escaping the Caml code */
301 LOADGLOBAL(r3, caml_exception_pointer#)
304 .L110: mov r3 = ip ;;
305 add r3 = .L101 - .L110, r3 ;;
308 /* Save ar.bsp, flush register window, and save ar.rnat */
310 STOREGLOBAL(r2, caml_saved_bsp#) ;;
312 and r2 = ~0x3, r14;; /* set rsc.mode = 0 */
313 mov ar.rsc = r2 ;; /* RSE is in enforced lazy mode */
314 flushrs ;; /* must be first instr in group */
316 STOREGLOBAL(r2, caml_saved_rnat#)
317 mov ar.rsc = r14 /* restore original RSE mode */
319 /* Reload allocation pointers */
320 LOADGLOBAL(r4, caml_young_ptr#)
321 LOADGLOBAL(r5, caml_young_limit#)
323 /* We are back into Caml code */
324 STOREGLOBAL(r0, caml_last_return_address#)
326 /* Call the Caml code */
327 br.call.sptk b0 = b6 ;;
330 /* Pop the trap frame, restoring caml_exception_pointer */
333 STOREGLOBAL(r2, caml_exception_pointer#)
336 /* Pop the callback link, restoring the global variables */
338 LD8OFF(r2, r14, 8) ;;
339 STOREGLOBAL(r2, caml_bottom_of_stack#)
340 LD8OFF(r2, r14, 8) ;;
341 STOREGLOBAL(r2, caml_last_return_address#)
342 LD8OFF(r2, r14, 8) ;;
343 STOREGLOBAL(r2, caml_gc_regs#)
344 LD8OFF(r2, r14, 8) ;;
345 STOREGLOBAL(r2, caml_saved_bsp#)
346 LD8OFF(r2, r14, 8) ;;
347 STOREGLOBAL(r2, caml_saved_rnat#)
350 /* Update allocation pointer */
351 STOREGLOBAL(r4, caml_young_ptr#)
353 /* Restore all callee-save registers from stack */
355 LD8OFF(r3, r2, 8) ;; /* 0 : ar.pfs */
357 LD8OFF(r3, r2, 8) ;; /* 1 : return address */
359 LD8OFF(gp, r2, 8) ;; /* 2 : gp */
360 LD8OFF(r3, r2, 8) ;; /* 3 : predicates */
362 LD8OFF(r3, r2, 8) ;; /* 4 : ar.fpsr */
364 LD8OFF(r3, r2, 8) ;; /* 5 : ar.unat */
366 LD8OFF(r3, r2, 8) ;; /* 6 : ar.lc */
368 LD8OFF(r3, r2, 8) ;; /* 7 - 11 : b1 - b5 */
380 LOAD4(r4,r5,r6,r7) ;; /* 12 - 15 : r4 - r7 */
382 add r3 = 16, r2 ;; /* 16 - 55 : f2 - f5, f16 - f31 */
383 FFILL4(f2,f3,f4,f5) ;;
384 FFILL8(f16,f17,f18,f19,f20,f21,f22,f23) ;;
385 FFILL8(f24,f25,f26,f27,f28,f29,f30,f31) ;;
387 /* Pop stack frame and return */
388 add sp = (56 * 8), sp
389 br.ret.sptk.many b0 ;;
391 /* The trap handler */
393 /* Save exception pointer */
394 STOREGLOBAL(r6, caml_exception_pointer#)
396 /* Encode exception bucket as exception result */
402 .endp caml_start_program#
404 /* Raise an exception from C */
406 .global caml_raise_exception#
407 .proc caml_raise_exception#
409 caml_raise_exception:
410 /* Allocate 64 "out" registers (for the Caml code) and no locals */
411 /* Since we don't return, don't bother saving the PFS */
412 alloc r2 = ar.pfs, 0, 0, 64, 0
414 /* Move exn bucket where Caml expects it */
417 /* Perform "context switch" as per the Software Conventions Guide,
419 flushrs ;; /* flush dirty registers to stack */
421 and r2 = ~0x3, r14;; /* set rsc.mode = 0 */
422 dep r2 = r0, r2, 16, 4 ;; /* clear rsc.loadrs */
423 mov ar.rsc = r2 ;; /* RSE is in enforced lazy mode */
424 invala ;; /* Invalidate ALAT */
425 LOADGLOBAL(r2, caml_saved_bsp#) ;;
426 mov ar.bspstore = r2 /* Restore ar.bspstore */
427 LOADGLOBAL(r2, caml_saved_rnat#) ;;
428 mov ar.rnat = r2 /* Restore ar.rnat */
429 mov ar.rsc = r14 ;; /* Restore original RSE mode */
431 /* Reload allocation pointers and exception pointer */
432 LOADGLOBAL(r4, caml_young_ptr#)
433 LOADGLOBAL(r5, caml_young_limit#)
434 LOADGLOBAL(r6, caml_exception_pointer#)
436 /* Say that we're back into Caml */
437 STOREGLOBAL(r0, caml_last_return_address#)
439 /* Raise the exception proper */
446 /* Branch to handler. Must use a call so as to set up the
447 CFM and PFS correctly. */
448 br.call.sptk.many b0 = b6
450 .endp caml_raise_exception
452 /* Callbacks from C to Caml */
454 .global caml_callback_exn#
455 .proc caml_callback_exn#
458 /* Initial shuffling of arguments */
459 ld8 r3 = [r32] /* code pointer */
461 mov r32 = r33 ;; /* first arg */
462 mov r33 = r2 /* environment */
466 .endp caml_callback_exn#
468 .global caml_callback2_exn#
469 .proc caml_callback2_exn#
472 /* Initial shuffling of arguments */
473 ADDRGLOBAL(r3, caml_apply2) /* code pointer */
475 mov r32 = r33 /* first arg */
476 mov r33 = r34 ;; /* second arg */
477 mov r34 = r2 /* environment */
481 .endp caml_callback2_exn#
483 .global caml_callback3_exn#
484 .proc caml_callback3_exn#
487 /* Initial shuffling of arguments */
488 ADDRGLOBAL(r3, caml_apply3) /* code pointer */
490 mov r32 = r33 /* first arg */
491 mov r33 = r34 /* second arg */
492 mov r34 = r35 ;; /* third arg */
493 mov r35 = r2 /* environment */
497 .endp caml_callback3_exn#
499 /* Glue code to call [caml_array_bound_error] */
501 .global caml_ml_array_bound_error#
502 .proc caml_ml_array_bound_error#
504 caml_ml_array_bound_error:
505 ADDRGLOBAL(r2, @fptr(caml_array_bound_error#))
506 br.sptk caml_c_call /* never returns */
510 .global caml_system__frametable#
511 .type caml_system__frametable#, @object
512 .size caml_system__frametable#, 8
513 caml_system__frametable:
514 data8 1 /* one descriptor */
515 data8 .L102 /* return address into callback */
516 data2 -1 /* negative frame size => use callback link */
517 data2 0 /* no roots here */
520 /* Global variables used by caml_raise_exception */
522 .common caml_saved_bsp#, 8, 8
523 .common caml_saved_rnat#, 8, 8