ocaml/runtime/power.S

677 lines
21 KiB
ArmAsm

/**************************************************************************/
/* */
/* OCaml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
/* */
/* Copyright 1996 Institut National de Recherche en Informatique et */
/* en Automatique. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/
#if defined(MODEL_ppc64le)
.abiversion 2
#endif
/* Special registers */
#define START_PRG_ARG 12
#define START_PRG_DOMAIN_STATE_PTR 7
#define C_CALL_FUN 25
#define C_CALL_TOC 26
#define C_CALL_RET_ADDR 27
#define DOMAIN_STATE_PTR 28
#define TRAP_PTR 29
#define ALLOC_LIMIT 30
#define ALLOC_PTR 31
#if defined(MODEL_ppc64) || defined(MODEL_ppc64le)
#define EITHER(a,b) b
#else
#define EITHER(a,b) a
#endif
#define WORD EITHER(4,8)
#define lg EITHER(lwz,ld)
#define lgu EITHER(lwzu,ldu)
#define stg EITHER(stw,std)
#define stgu EITHER(stwu,stdu)
#define datag EITHER(.long,.quad)
#define wordalign EITHER(2,3)
/* Stack layout */
#if defined(MODEL_ppc)
#define RESERVED_STACK 16
#define PARAM_SAVE_AREA 0
#define LR_SAVE 4
#define TRAP_SIZE 16
#define TRAP_HANDLER_OFFSET 0
#define TRAP_PREVIOUS_OFFSET 4
#define CALLBACK_LINK_SIZE 16
#define CALLBACK_LINK_OFFSET 0
#endif
#if defined(MODEL_ppc64)
#define RESERVED_STACK 48
#define PARAM_SAVE_AREA (8*8)
#define LR_SAVE 16
#define TOC_SAVE 40
#define TOC_SAVE_PARENT 8
#define TRAP_SIZE 32
#define TRAP_HANDLER_OFFSET 56
#define TRAP_PREVIOUS_OFFSET 64
#define CALLBACK_LINK_SIZE 32
#define CALLBACK_LINK_OFFSET 48
#endif
#if defined(MODEL_ppc64le)
#define RESERVED_STACK 32
#define PARAM_SAVE_AREA 0
#define LR_SAVE 16
#define TOC_SAVE_PARENT 8
#define TOC_SAVE 24
#define TRAP_SIZE 32
#define TRAP_HANDLER_OFFSET 40
#define TRAP_PREVIOUS_OFFSET 48
#define CALLBACK_LINK_SIZE 32
#define CALLBACK_LINK_OFFSET 32
#endif
/* Function definitions */
#if defined(MODEL_ppc)
#define FUNCTION(name) \
.section ".text"; \
.globl name; \
.type name, @function; \
.align 2; \
name:
#define ENDFUNCTION(name) \
.size name, . - name
#endif
#if defined(MODEL_ppc64)
#define FUNCTION(name) \
.section ".opd","aw"; \
.align 3; \
.globl name; \
.type name, @function; \
name: .quad .L.name,.TOC.@tocbase; \
.text; \
.align 2; \
.L.name:
#define ENDFUNCTION(name) \
.size name, . - .L.name
#endif
#if defined(MODEL_ppc64le)
#define FUNCTION(name) \
.section ".text"; \
.globl name; \
.type name, @function; \
.align 2; \
name: ; \
0: addis 2, 12, (.TOC. - 0b)@ha; \
addi 2, 2, (.TOC. - 0b)@l; \
.localentry name, . - 0b
#define ENDFUNCTION(name) \
.size name, . - name
#endif
/* Accessing global variables. */
#if defined(MODEL_ppc)
#define Addrglobal(reg,glob) \
addis reg, 0, glob@ha; \
addi reg, reg, glob@l
#endif
#if defined(MODEL_ppc64) || defined(MODEL_ppc64le)
#define LSYMB(glob) .L##glob
#define Addrglobal(reg,glob) \
ld reg, LSYMB(glob)@toc(2)
#endif
.set domain_curr_field, 0
#define DOMAIN_STATE(c_type, name) \
.equ domain_field_caml_##name, domain_curr_field ; \
.set domain_curr_field, domain_curr_field + 1
#include "../runtime/caml/domain_state.tbl"
#undef DOMAIN_STATE
#define Caml_state(var) 8*domain_field_caml_##var(28)
#if defined(MODEL_ppc64)
.section ".opd","aw"
#else
.section ".text"
#endif
.globl caml_system__code_begin
caml_system__code_begin:
/* Invoke the garbage collector. */
FUNCTION(caml_call_gc)
#define STACKSIZE (WORD*32 + 8*32 + PARAM_SAVE_AREA + RESERVED_STACK)
/* 32 integer registers + 32 float registers + space for C call */
/* Set up stack frame */
stwu 1, -STACKSIZE(1)
/* Record return address into OCaml code */
mflr 0
stg 0, Caml_state(last_return_address)
/* Record lowest stack address */
addi 0, 1, STACKSIZE
stg 0, Caml_state(bottom_of_stack)
/* Record pointer to register array */
addi 0, 1, 8*32 + PARAM_SAVE_AREA + RESERVED_STACK
stg 0, Caml_state(gc_regs)
/* Save current allocation pointer for debugging purposes */
stg ALLOC_PTR, Caml_state(young_ptr)
/* Save exception pointer (if e.g. a sighandler raises) */
stg TRAP_PTR, Caml_state(exception_pointer)
/* Save all registers used by the code generator */
addi 11, 1, 8*32 + PARAM_SAVE_AREA + RESERVED_STACK - WORD
stgu 3, WORD(11)
stgu 4, WORD(11)
stgu 5, WORD(11)
stgu 6, WORD(11)
stgu 7, WORD(11)
stgu 8, WORD(11)
stgu 9, WORD(11)
stgu 10, WORD(11)
stgu 14, WORD(11)
stgu 15, WORD(11)
stgu 16, WORD(11)
stgu 17, WORD(11)
stgu 18, WORD(11)
stgu 19, WORD(11)
stgu 20, WORD(11)
stgu 21, WORD(11)
stgu 22, WORD(11)
stgu 23, WORD(11)
stgu 24, WORD(11)
stgu 25, WORD(11)
stgu 26, WORD(11)
stgu 27, WORD(11)
stgu 28, WORD(11)
addi 11, 1, PARAM_SAVE_AREA + RESERVED_STACK - 8
stfdu 1, 8(11)
stfdu 2, 8(11)
stfdu 3, 8(11)
stfdu 4, 8(11)
stfdu 5, 8(11)
stfdu 6, 8(11)
stfdu 7, 8(11)
stfdu 8, 8(11)
stfdu 9, 8(11)
stfdu 10, 8(11)
stfdu 11, 8(11)
stfdu 12, 8(11)
stfdu 13, 8(11)
stfdu 14, 8(11)
stfdu 15, 8(11)
stfdu 16, 8(11)
stfdu 17, 8(11)
stfdu 18, 8(11)
stfdu 19, 8(11)
stfdu 20, 8(11)
stfdu 21, 8(11)
stfdu 22, 8(11)
stfdu 23, 8(11)
stfdu 24, 8(11)
stfdu 25, 8(11)
stfdu 26, 8(11)
stfdu 27, 8(11)
stfdu 28, 8(11)
stfdu 29, 8(11)
stfdu 30, 8(11)
stfdu 31, 8(11)
/* Call the GC */
bl caml_garbage_collection
#if defined(MODEL_ppc64) || defined(MODEL_ppc64le)
nop
#endif
/* Reload new allocation pointer and allocation limit */
lg ALLOC_PTR, Caml_state(young_ptr)
lg ALLOC_LIMIT, Caml_state(young_limit)
/* Restore all regs used by the code generator */
addi 11, 1, 8*32 + PARAM_SAVE_AREA + RESERVED_STACK - WORD
lgu 3, WORD(11)
lgu 4, WORD(11)
lgu 5, WORD(11)
lgu 6, WORD(11)
lgu 7, WORD(11)
lgu 8, WORD(11)
lgu 9, WORD(11)
lgu 10, WORD(11)
lgu 14, WORD(11)
lgu 15, WORD(11)
lgu 16, WORD(11)
lgu 17, WORD(11)
lgu 18, WORD(11)
lgu 19, WORD(11)
lgu 20, WORD(11)
lgu 21, WORD(11)
lgu 22, WORD(11)
lgu 23, WORD(11)
lgu 24, WORD(11)
lgu 25, WORD(11)
lgu 26, WORD(11)
lgu 27, WORD(11)
lgu 28, WORD(11)
addi 11, 1, PARAM_SAVE_AREA + RESERVED_STACK - 8
lfdu 1, 8(11)
lfdu 2, 8(11)
lfdu 3, 8(11)
lfdu 4, 8(11)
lfdu 5, 8(11)
lfdu 6, 8(11)
lfdu 7, 8(11)
lfdu 8, 8(11)
lfdu 9, 8(11)
lfdu 10, 8(11)
lfdu 11, 8(11)
lfdu 12, 8(11)
lfdu 13, 8(11)
lfdu 14, 8(11)
lfdu 15, 8(11)
lfdu 16, 8(11)
lfdu 17, 8(11)
lfdu 18, 8(11)
lfdu 19, 8(11)
lfdu 20, 8(11)
lfdu 21, 8(11)
lfdu 22, 8(11)
lfdu 23, 8(11)
lfdu 24, 8(11)
lfdu 25, 8(11)
lfdu 26, 8(11)
lfdu 27, 8(11)
lfdu 28, 8(11)
lfdu 29, 8(11)
lfdu 30, 8(11)
lfdu 31, 8(11)
/* Return to caller, resuming the allocation */
lg 11, Caml_state(last_return_address)
mtlr 11
/* For PPC64: restore the TOC that the caller saved at the usual place */
#ifdef TOC_SAVE
ld 2, (STACKSIZE + TOC_SAVE)(1)
#endif
/* Deallocate stack frame */
addi 1, 1, STACKSIZE
blr
#undef STACKSIZE
ENDFUNCTION(caml_call_gc)
/* Call a C function from OCaml */
FUNCTION(caml_c_call)
.cfi_startproc
/* Save return address in a callee-save register */
mflr C_CALL_RET_ADDR
.cfi_register 65, C_CALL_RET_ADDR
/* Record lowest stack address and return address */
stg 1, Caml_state(bottom_of_stack)
stg C_CALL_RET_ADDR, Caml_state(last_return_address)
/* Make the exception handler and alloc ptr available to the C code */
stg ALLOC_PTR, Caml_state(young_ptr)
stg TRAP_PTR, Caml_state(exception_pointer)
/* Call C function (address in C_CALL_FUN) */
#if defined(MODEL_ppc)
mtctr C_CALL_FUN
bctrl
#elif defined(MODEL_ppc64)
ld 0, 0(C_CALL_FUN)
mr C_CALL_TOC, 2 /* save current TOC in a callee-save register */
mtctr 0
ld 2, 8(C_CALL_FUN)
bctrl
mr 2, C_CALL_TOC /* restore current TOC */
#elif defined(MODEL_ppc64le)
mtctr C_CALL_FUN
mr 12, C_CALL_FUN
mr C_CALL_TOC, 2 /* save current TOC in a callee-save register */
bctrl
mr 2, C_CALL_TOC /* restore current TOC */
#else
#error "wrong MODEL"
#endif
/* Restore return address (in 27, preserved by the C function) */
mtlr C_CALL_RET_ADDR
/* Reload allocation pointer and allocation limit*/
lg ALLOC_PTR, Caml_state(young_ptr)
lg ALLOC_LIMIT, Caml_state(young_limit)
/* Return to caller */
blr
.cfi_endproc
ENDFUNCTION(caml_c_call)
/* Raise an exception from OCaml */
FUNCTION(caml_raise_exn)
lg 0, Caml_state(backtrace_active)
cmpwi 0, 0
bne .L111
.L110:
/* Pop trap frame */
lg 0, TRAP_HANDLER_OFFSET(TRAP_PTR)
mr 1, TRAP_PTR
mtctr 0
lg TRAP_PTR, TRAP_PREVIOUS_OFFSET(1)
addi 1, 1, TRAP_SIZE
/* Branch to handler */
bctr
.L111:
mr 27, 3 /* preserve exn bucket in callee-save reg */
/* arg1: exception bucket, already in r3 */
mflr 4 /* arg2: PC of raise */
mr 5, 1 /* arg3: SP of raise */
mr 6, TRAP_PTR /* arg4: SP of handler */
addi 1, 1, -(PARAM_SAVE_AREA + RESERVED_STACK)
/* reserve stack space for C call */
bl caml_stash_backtrace
#if defined(MODEL_ppc64) || defined(MODEL_ppc64le)
nop
#endif
mr 3, 27 /* restore exn bucket */
b .L110 /* raise the exn */
ENDFUNCTION(caml_raise_exn)
/* Raise an exception from C */
FUNCTION(caml_raise_exception)
/* Load domain state pointer */
mr DOMAIN_STATE_PTR, 3
mr 3, 4
lg 0, Caml_state(backtrace_active)
cmpwi 0, 0
bne .L121
.L120:
/* Reload OCaml global registers */
lg 1, Caml_state(exception_pointer)
lg ALLOC_PTR, Caml_state(young_ptr)
lg ALLOC_LIMIT, Caml_state(young_limit)
/* Pop trap frame */
lg 0, TRAP_HANDLER_OFFSET(1)
mtctr 0
lg TRAP_PTR, TRAP_PREVIOUS_OFFSET(1)
addi 1, 1, TRAP_SIZE
/* Branch to handler */
bctr
.L121:
mr 27, 3 /* preserve exn bucket in callee-save reg */
/* arg1: exception bucket, already in r3 */
lg 4, Caml_state(last_return_address) /* arg2: PC of raise */
lg 5, Caml_state(bottom_of_stack) /* arg3: SP of raise */
lg 6, Caml_state(exception_pointer) /* arg4: SP of handler */
addi 1, 1, -(PARAM_SAVE_AREA + RESERVED_STACK)
/* reserve stack space for C call */
bl caml_stash_backtrace
#if defined(MODEL_ppc64) || defined(MODEL_ppc64le)
nop
#endif
mr 3, 27 /* restore exn bucket */
b .L120 /* raise the exn */
ENDFUNCTION(caml_raise_exception)
/* Start the OCaml program */
FUNCTION(caml_start_program)
.cfi_startproc
#define STACKSIZE (WORD*18 + 8*18 + CALLBACK_LINK_SIZE + RESERVED_STACK)
/* 18 callee-save GPR14...GPR31 + 18 callee-save FPR14...FPR31 */
/* Domain state pointer is the first arg to caml_start_program. Move it */
mr START_PRG_DOMAIN_STATE_PTR, 3
Addrglobal(START_PRG_ARG, caml_program)
/* Code shared between caml_start_program and caml_callback */
.L102:
/* Allocate and link stack frame */
stgu 1, -STACKSIZE(1)
.cfi_adjust_cfa_offset STACKSIZE
/* Save return address */
mflr 0
stg 0, (STACKSIZE + LR_SAVE)(1)
.cfi_offset 65, LR_SAVE
/* Save TOC pointer if applicable */
#ifdef TOC_SAVE_PARENT
std 2, (STACKSIZE + TOC_SAVE_PARENT)(1)
#endif
/* Save all callee-save registers */
addi 11, 1, CALLBACK_LINK_SIZE + RESERVED_STACK - WORD
stgu 14, WORD(11)
stgu 15, WORD(11)
stgu 16, WORD(11)
stgu 17, WORD(11)
stgu 18, WORD(11)
stgu 19, WORD(11)
stgu 20, WORD(11)
stgu 21, WORD(11)
stgu 22, WORD(11)
stgu 23, WORD(11)
stgu 24, WORD(11)
stgu 25, WORD(11)
stgu 26, WORD(11)
stgu 27, WORD(11)
stgu 28, WORD(11)
stgu 29, WORD(11)
stgu 30, WORD(11)
stgu 31, WORD(11)
stfdu 14, 8(11)
stfdu 15, 8(11)
stfdu 16, 8(11)
stfdu 17, 8(11)
stfdu 18, 8(11)
stfdu 19, 8(11)
stfdu 20, 8(11)
stfdu 21, 8(11)
stfdu 22, 8(11)
stfdu 23, 8(11)
stfdu 24, 8(11)
stfdu 25, 8(11)
stfdu 26, 8(11)
stfdu 27, 8(11)
stfdu 28, 8(11)
stfdu 29, 8(11)
stfdu 30, 8(11)
stfdu 31, 8(11)
/* Load domain state pointer from argument */
mr DOMAIN_STATE_PTR, START_PRG_DOMAIN_STATE_PTR
/* Set up a callback link */
lg 11, Caml_state(bottom_of_stack)
stg 11, CALLBACK_LINK_OFFSET(1)
lg 11, Caml_state(last_return_address)
stg 11, (CALLBACK_LINK_OFFSET + WORD)(1)
lg 11, Caml_state(gc_regs)
stg 11, (CALLBACK_LINK_OFFSET + 2 * WORD)(1)
/* Build an exception handler to catch exceptions escaping out of OCaml */
bl .L103
b .L104
.L103:
addi 1, 1, -TRAP_SIZE
.cfi_adjust_cfa_offset TRAP_SIZE
mflr 0
stg 0, TRAP_HANDLER_OFFSET(1)
lg 11, Caml_state(exception_pointer)
stg 11, TRAP_PREVIOUS_OFFSET(1)
mr TRAP_PTR, 1
/* Reload allocation pointers */
lg ALLOC_PTR, Caml_state(young_ptr)
lg ALLOC_LIMIT, Caml_state(young_limit)
/* Call the OCaml code (address in r12) */
#if defined(MODEL_ppc)
mtctr 12
.L105: bctrl
#elif defined(MODEL_ppc64)
ld 0, 0(12)
mtctr 0
std 2, TOC_SAVE(1)
ld 2, 8(12)
.L105: bctrl
ld 2, TOC_SAVE(1)
#elif defined(MODEL_ppc64le)
mtctr 12
std 2, TOC_SAVE(1)
.L105: bctrl
ld 2, TOC_SAVE(1)
#else
#error "wrong MODEL"
#endif
/* Pop the trap frame, restoring caml_exception_pointer */
lg 0, TRAP_PREVIOUS_OFFSET(1)
stg 0, Caml_state(exception_pointer)
addi 1, 1, TRAP_SIZE
.cfi_adjust_cfa_offset -TRAP_SIZE
/* Pop the callback link, restoring the global variables */
.L106:
lg 0, CALLBACK_LINK_OFFSET(1)
stg 0, Caml_state(bottom_of_stack)
lg 0, (CALLBACK_LINK_OFFSET + WORD)(1)
stg 0, Caml_state(last_return_address)
lg 0, (CALLBACK_LINK_OFFSET + 2 * WORD)(1)
stg 0, Caml_state(gc_regs)
/* Update allocation pointer */
stg ALLOC_PTR, Caml_state(young_ptr)
/* Restore callee-save registers */
addi 11, 1, CALLBACK_LINK_SIZE + RESERVED_STACK - WORD
lgu 14, WORD(11)
lgu 15, WORD(11)
lgu 16, WORD(11)
lgu 17, WORD(11)
lgu 18, WORD(11)
lgu 19, WORD(11)
lgu 20, WORD(11)
lgu 21, WORD(11)
lgu 22, WORD(11)
lgu 23, WORD(11)
lgu 24, WORD(11)
lgu 25, WORD(11)
lgu 26, WORD(11)
lgu 27, WORD(11)
lgu 28, WORD(11)
lgu 29, WORD(11)
lgu 30, WORD(11)
lgu 31, WORD(11)
lfdu 14, 8(11)
lfdu 15, 8(11)
lfdu 16, 8(11)
lfdu 17, 8(11)
lfdu 18, 8(11)
lfdu 19, 8(11)
lfdu 20, 8(11)
lfdu 21, 8(11)
lfdu 22, 8(11)
lfdu 23, 8(11)
lfdu 24, 8(11)
lfdu 25, 8(11)
lfdu 26, 8(11)
lfdu 27, 8(11)
lfdu 28, 8(11)
lfdu 29, 8(11)
lfdu 30, 8(11)
lfdu 31, 8(11)
/* Reload return address */
lg 0, (STACKSIZE + LR_SAVE)(1)
mtlr 0
/* Return */
addi 1, 1, STACKSIZE
blr
/* The trap handler: */
.L104:
/* Restore TOC pointer */
#ifdef TOC_SAVE_PARENT
ld 2, (STACKSIZE + TOC_SAVE_PARENT)(1)
#endif
/* Update caml_exception_pointer */
stg TRAP_PTR, Caml_state(exception_pointer)
/* Encode exception bucket as an exception result and return it */
ori 3, 3, 2
b .L106
#undef STACKSIZE
.cfi_endproc
ENDFUNCTION(caml_start_program)
/* Callback from C to OCaml */
FUNCTION(caml_callback_asm)
/* Initial shuffling of arguments */
/* r3 = Caml_state, r4 = closure, 0(r5) = first arg */
mr START_PRG_DOMAIN_STATE_PTR, 3
lg 3, 0(5) /* r3 = Argument */
/* r4 = Closure */
lg START_PRG_ARG, 0(4) /* Code pointer */
b .L102
ENDFUNCTION(caml_callback_asm)
FUNCTION(caml_callback2_asm)
/* r3 = Caml_state, r4 = closure, 0(r5) = first arg,
WORD(r5) = second arg */
mr START_PRG_DOMAIN_STATE_PTR, 3
mr 0, 4
lg 3, 0(5) /* r3 = First argument */
lg 4, WORD(5) /* r4 = Second argument */
mr 5, 0 /* r5 = Closure */
Addrglobal(START_PRG_ARG, caml_apply2)
b .L102
ENDFUNCTION(caml_callback2_asm)
FUNCTION(caml_callback3_asm)
/* r3 = Caml_state, r4 = closure, 0(r5) = first arg, WORD(r5) = second arg,
2*WORD(r5) = third arg */
mr START_PRG_DOMAIN_STATE_PTR, 3
mr 6, 4 /* r6 = Closure */
lg 3, 0(5) /* r3 = First argument */
lg 4, WORD(5) /* r4 = Second argument */
lg 5, 2*WORD(5) /* r5 = Third argument */
Addrglobal(START_PRG_ARG, caml_apply3)
b .L102
ENDFUNCTION(caml_callback3_asm)
#if defined(MODEL_ppc64)
.section ".opd","aw"
#else
.section ".text"
#endif
.globl caml_system__code_end
caml_system__code_end:
/* Frame table */
.section ".data"
.globl caml_system__frametable
.type caml_system__frametable, @object
caml_system__frametable:
datag 1 /* one descriptor */
datag .L105 + 4 /* return address into callback */
.short -1 /* negative size count => use callback link */
.short 0 /* no roots here */
/* TOC entries */
#if defined(MODEL_ppc64) || defined(MODEL_ppc64le)
.section ".toc", "aw"
#define TOCENTRY(glob) LSYMB(glob): .quad glob
TOCENTRY(caml_apply2)
TOCENTRY(caml_apply3)
TOCENTRY(caml_program)
#endif
/* Mark stack as non-executable */
.section .note.GNU-stack,"",%progbits