423 lines
14 KiB
ArmAsm
423 lines
14 KiB
ArmAsm
/**************************************************************************/
|
|
/* */
|
|
/* OCaml */
|
|
/* */
|
|
/* Nicolas Ojeda Bar <n.oje.bar@gmail.com> */
|
|
/* */
|
|
/* Copyright 2016 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. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
/* Asm part of the runtime system, RISC-V processor, 64-bit mode */
|
|
/* Must be preprocessed by cpp */
|
|
|
|
#define ARG_DOMAIN_STATE_PTR t0
|
|
#define DOMAIN_STATE_PTR s0
|
|
#define TRAP_PTR s1
|
|
#define ALLOC_PTR s10
|
|
#define ALLOC_LIMIT s11
|
|
#define TMP t1
|
|
#define ARG t2
|
|
|
|
#define STORE sd
|
|
#define LOAD ld
|
|
|
|
.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)(s0)
|
|
|
|
#define FUNCTION(name) \
|
|
.align 2; \
|
|
.globl name; \
|
|
.type name, @function; \
|
|
name:
|
|
|
|
#if defined(__PIC__)
|
|
.option pic
|
|
#define PLT(r) r@plt
|
|
#else
|
|
.option nopic
|
|
#define PLT(r) r
|
|
#endif
|
|
|
|
.section .text
|
|
/* Invoke the garbage collector. */
|
|
|
|
.globl caml_system__code_begin
|
|
caml_system__code_begin:
|
|
|
|
FUNCTION(caml_call_gc)
|
|
.Lcaml_call_gc:
|
|
/* Record return address */
|
|
STORE ra, Caml_state(last_return_address)
|
|
/* Record lowest stack address */
|
|
STORE sp, Caml_state(bottom_of_stack)
|
|
/* Set up stack space, saving return address */
|
|
/* (1 reg for RA, 1 reg for FP, 22 allocatable int regs,
|
|
20 caller-save float regs) * 8 */
|
|
addi sp, sp, -0x160
|
|
STORE ra, 0x8(sp)
|
|
STORE s0, 0x0(sp)
|
|
/* Save allocatable integer registers on the stack,
|
|
in the order given in proc.ml */
|
|
STORE a0, 0x10(sp)
|
|
STORE a1, 0x18(sp)
|
|
STORE a2, 0x20(sp)
|
|
STORE a3, 0x28(sp)
|
|
STORE a4, 0x30(sp)
|
|
STORE a5, 0x38(sp)
|
|
STORE a6, 0x40(sp)
|
|
STORE a7, 0x48(sp)
|
|
STORE s2, 0x50(sp)
|
|
STORE s3, 0x58(sp)
|
|
STORE s4, 0x60(sp)
|
|
STORE s5, 0x68(sp)
|
|
STORE s6, 0x70(sp)
|
|
STORE s7, 0x78(sp)
|
|
STORE s8, 0x80(sp)
|
|
STORE s9, 0x88(sp)
|
|
STORE t2, 0x90(sp)
|
|
STORE t3, 0x98(sp)
|
|
STORE t4, 0xa0(sp)
|
|
STORE t5, 0xa8(sp)
|
|
STORE t6, 0xb0(sp)
|
|
STORE t0, 0xb8(sp)
|
|
/* Save caller-save floating-point registers on the stack
|
|
(callee-saves are preserved by caml_garbage_collection) */
|
|
fsd ft0, 0xc0(sp)
|
|
fsd ft1, 0xc8(sp)
|
|
fsd ft2, 0xd0(sp)
|
|
fsd ft3, 0xd8(sp)
|
|
fsd ft4, 0xe0(sp)
|
|
fsd ft5, 0xe8(sp)
|
|
fsd ft6, 0xf0(sp)
|
|
fsd ft7, 0xf8(sp)
|
|
fsd fa0, 0x100(sp)
|
|
fsd fa1, 0x108(sp)
|
|
fsd fa2, 0x110(sp)
|
|
fsd fa3, 0x118(sp)
|
|
fsd fa4, 0x120(sp)
|
|
fsd fa5, 0x128(sp)
|
|
fsd fa6, 0x130(sp)
|
|
fsd fa7, 0x138(sp)
|
|
fsd ft8, 0x140(sp)
|
|
fsd ft9, 0x148(sp)
|
|
fsd ft10, 0x150(sp)
|
|
fsd ft11, 0x158(sp)
|
|
/* Store pointer to saved integer registers in caml_gc_regs */
|
|
addi TMP, sp, 0x10
|
|
STORE TMP, Caml_state(gc_regs)
|
|
/* Save current allocation pointer for debugging purposes */
|
|
STORE ALLOC_PTR, Caml_state(young_ptr)
|
|
/* Save trap pointer in case an exception is raised during GC */
|
|
STORE TRAP_PTR, Caml_state(exception_pointer)
|
|
/* Call the garbage collector */
|
|
call PLT(caml_garbage_collection)
|
|
/* Restore registers */
|
|
LOAD a0, 0x10(sp)
|
|
LOAD a1, 0x18(sp)
|
|
LOAD a2, 0x20(sp)
|
|
LOAD a3, 0x28(sp)
|
|
LOAD a4, 0x30(sp)
|
|
LOAD a5, 0x38(sp)
|
|
LOAD a6, 0x40(sp)
|
|
LOAD a7, 0x48(sp)
|
|
LOAD s2, 0x50(sp)
|
|
LOAD s3, 0x58(sp)
|
|
LOAD s4, 0x60(sp)
|
|
LOAD s5, 0x68(sp)
|
|
LOAD s6, 0x70(sp)
|
|
LOAD s7, 0x78(sp)
|
|
LOAD s8, 0x80(sp)
|
|
LOAD s9, 0x88(sp)
|
|
LOAD t2, 0x90(sp)
|
|
LOAD t3, 0x98(sp)
|
|
LOAD t4, 0xa0(sp)
|
|
LOAD t5, 0xa8(sp)
|
|
LOAD t6, 0xb0(sp)
|
|
LOAD t0, 0xb8(sp)
|
|
fld ft0, 0xc0(sp)
|
|
fld ft1, 0xc8(sp)
|
|
fld ft2, 0xd0(sp)
|
|
fld ft3, 0xd8(sp)
|
|
fld ft4, 0xe0(sp)
|
|
fld ft5, 0xe8(sp)
|
|
fld ft6, 0xf0(sp)
|
|
fld ft7, 0xf8(sp)
|
|
fld fa0, 0x100(sp)
|
|
fld fa1, 0x108(sp)
|
|
fld fa2, 0x110(sp)
|
|
fld fa3, 0x118(sp)
|
|
fld fa4, 0x120(sp)
|
|
fld fa5, 0x128(sp)
|
|
fld fa6, 0x130(sp)
|
|
fld fa7, 0x138(sp)
|
|
fld ft8, 0x140(sp)
|
|
fld ft9, 0x148(sp)
|
|
fld ft10, 0x150(sp)
|
|
fld ft11, 0x158(sp)
|
|
/* Reload new allocation pointer and allocation limit */
|
|
LOAD ALLOC_PTR, Caml_state(young_ptr)
|
|
LOAD ALLOC_LIMIT, Caml_state(young_limit)
|
|
/* Free stack space and return to caller */
|
|
LOAD ra, 0x8(sp)
|
|
LOAD s0, 0x0(sp)
|
|
addi sp, sp, 0x160
|
|
ret
|
|
.size caml_call_gc, .-caml_call_gc
|
|
|
|
/* Call a C function from OCaml */
|
|
/* Function to call is in ARG */
|
|
|
|
FUNCTION(caml_c_call)
|
|
/* Preserve return address in callee-save register s2 */
|
|
mv s2, ra
|
|
/* Record lowest stack address and return address */
|
|
STORE ra, Caml_state(last_return_address)
|
|
STORE sp, Caml_state(bottom_of_stack)
|
|
/* Make the exception handler alloc ptr available to the C code */
|
|
STORE ALLOC_PTR, Caml_state(young_ptr)
|
|
STORE TRAP_PTR, Caml_state(exception_pointer)
|
|
/* Call the function */
|
|
jalr ARG
|
|
/* Reload alloc ptr and alloc limit */
|
|
LOAD ALLOC_PTR, Caml_state(young_ptr)
|
|
LOAD ALLOC_LIMIT, Caml_state(young_limit)
|
|
/* Return */
|
|
jr s2
|
|
.size caml_c_call, .-caml_c_call
|
|
|
|
/* Raise an exception from OCaml */
|
|
FUNCTION(caml_raise_exn)
|
|
/* Test if backtrace is active */
|
|
LOAD TMP, Caml_state(backtrace_active)
|
|
bnez TMP, 2f
|
|
1: /* Cut stack at current trap handler */
|
|
mv sp, TRAP_PTR
|
|
/* Pop previous handler and jump to it */
|
|
LOAD TMP, 8(sp)
|
|
LOAD TRAP_PTR, 0(sp)
|
|
addi sp, sp, 16
|
|
jr TMP
|
|
2: /* Preserve exception bucket in callee-save register s2 */
|
|
mv s2, a0
|
|
/* Stash the backtrace */
|
|
mv a1, ra
|
|
mv a2, sp
|
|
mv a3, TRAP_PTR
|
|
call PLT(caml_stash_backtrace)
|
|
/* Restore exception bucket and raise */
|
|
mv a0, s2
|
|
j 1b
|
|
.size caml_raise_exn, .-caml_raise_exn
|
|
|
|
.globl caml_reraise_exn
|
|
.type caml_reraise_exn, @function
|
|
|
|
/* Raise an exception from C */
|
|
|
|
FUNCTION(caml_raise_exception)
|
|
mv DOMAIN_STATE_PTR, a0
|
|
mv a0, a1
|
|
LOAD TRAP_PTR, Caml_state(exception_pointer)
|
|
LOAD ALLOC_PTR, Caml_state(young_ptr)
|
|
LOAD ALLOC_LIMIT, Caml_state(young_limit)
|
|
LOAD TMP, Caml_state(backtrace_active)
|
|
bnez TMP, 2f
|
|
1: /* Cut stack at current trap handler */
|
|
mv sp, TRAP_PTR
|
|
LOAD TMP, 8(sp)
|
|
LOAD TRAP_PTR, 0(sp)
|
|
addi sp, sp, 16
|
|
jr TMP
|
|
2: /* Preserve exception bucket in callee-save register s2 */
|
|
mv s2, a0
|
|
LOAD a1, Caml_state(last_return_address)
|
|
LOAD a2, Caml_state(bottom_of_stack)
|
|
mv a3, TRAP_PTR
|
|
call PLT(caml_stash_backtrace)
|
|
mv a0, s2
|
|
j 1b
|
|
.size caml_raise_exception, .-caml_raise_exception
|
|
|
|
/* Start the OCaml program */
|
|
|
|
FUNCTION(caml_start_program)
|
|
mv ARG_DOMAIN_STATE_PTR, a0
|
|
la ARG, caml_program
|
|
/* Code shared with caml_callback* */
|
|
/* Address of OCaml code to call is in ARG */
|
|
/* Arguments to the OCaml code are in a0 ... a7 */
|
|
.Ljump_to_caml:
|
|
/* Set up stack frame and save callee-save registers */
|
|
addi sp, sp, -0xd0
|
|
STORE ra, 0xc0(sp)
|
|
STORE s0, 0x0(sp)
|
|
STORE s1, 0x8(sp)
|
|
STORE s2, 0x10(sp)
|
|
STORE s3, 0x18(sp)
|
|
STORE s4, 0x20(sp)
|
|
STORE s5, 0x28(sp)
|
|
STORE s6, 0x30(sp)
|
|
STORE s7, 0x38(sp)
|
|
STORE s8, 0x40(sp)
|
|
STORE s9, 0x48(sp)
|
|
STORE s10, 0x50(sp)
|
|
STORE s11, 0x58(sp)
|
|
fsd fs0, 0x60(sp)
|
|
fsd fs1, 0x68(sp)
|
|
fsd fs2, 0x70(sp)
|
|
fsd fs3, 0x78(sp)
|
|
fsd fs4, 0x80(sp)
|
|
fsd fs5, 0x88(sp)
|
|
fsd fs6, 0x90(sp)
|
|
fsd fs7, 0x98(sp)
|
|
fsd fs8, 0xa0(sp)
|
|
fsd fs9, 0xa8(sp)
|
|
fsd fs10, 0xb0(sp)
|
|
fsd fs11, 0xb8(sp)
|
|
addi sp, sp, -32
|
|
/* Load domain state pointer from argument */
|
|
mv DOMAIN_STATE_PTR, ARG_DOMAIN_STATE_PTR
|
|
/* Setup a callback link on the stack */
|
|
LOAD TMP, Caml_state(bottom_of_stack)
|
|
STORE TMP, 0(sp)
|
|
LOAD TMP, Caml_state(last_return_address)
|
|
STORE TMP, 8(sp)
|
|
LOAD TMP, Caml_state(gc_regs)
|
|
STORE TMP, 16(sp)
|
|
/* set up a trap frame */
|
|
addi sp, sp, -16
|
|
LOAD TMP, Caml_state(exception_pointer)
|
|
STORE TMP, 0(sp)
|
|
lla TMP, .Ltrap_handler
|
|
STORE TMP, 8(sp)
|
|
mv TRAP_PTR, sp
|
|
LOAD ALLOC_PTR, Caml_state(young_ptr)
|
|
LOAD ALLOC_LIMIT, Caml_state(young_limit)
|
|
STORE x0, Caml_state(last_return_address)
|
|
jalr ARG
|
|
.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */
|
|
LOAD TMP, 0(sp)
|
|
STORE TMP, Caml_state(exception_pointer)
|
|
addi sp, sp, 16
|
|
.Lreturn_result: /* pop callback link, restoring global variables */
|
|
LOAD TMP, 0(sp)
|
|
STORE TMP, Caml_state(bottom_of_stack)
|
|
LOAD TMP, 8(sp)
|
|
STORE TMP, Caml_state(last_return_address)
|
|
LOAD TMP, 16(sp)
|
|
STORE TMP, Caml_state(gc_regs)
|
|
addi sp, sp, 32
|
|
/* Update allocation pointer */
|
|
STORE ALLOC_PTR, Caml_state(young_ptr)
|
|
/* reload callee-save registers and return */
|
|
LOAD ra, 0xc0(sp)
|
|
LOAD s0, 0x0(sp)
|
|
LOAD s1, 0x8(sp)
|
|
LOAD s2, 0x10(sp)
|
|
LOAD s3, 0x18(sp)
|
|
LOAD s4, 0x20(sp)
|
|
LOAD s5, 0x28(sp)
|
|
LOAD s6, 0x30(sp)
|
|
LOAD s7, 0x38(sp)
|
|
LOAD s8, 0x40(sp)
|
|
LOAD s9, 0x48(sp)
|
|
LOAD s10, 0x50(sp)
|
|
LOAD s11, 0x58(sp)
|
|
fld fs0, 0x60(sp)
|
|
fld fs1, 0x68(sp)
|
|
fld fs2, 0x70(sp)
|
|
fld fs3, 0x78(sp)
|
|
fld fs4, 0x80(sp)
|
|
fld fs5, 0x88(sp)
|
|
fld fs6, 0x90(sp)
|
|
fld fs7, 0x98(sp)
|
|
fld fs8, 0xa0(sp)
|
|
fld fs9, 0xa8(sp)
|
|
fld fs10, 0xb0(sp)
|
|
fld fs11, 0xb8(sp)
|
|
addi sp, sp, 0xd0
|
|
ret
|
|
.type .Lcaml_retaddr, @function
|
|
.size .Lcaml_retaddr, .-.Lcaml_retaddr
|
|
.size caml_start_program, .-caml_start_program
|
|
|
|
.align 2
|
|
.Ltrap_handler:
|
|
STORE TRAP_PTR, Caml_state(exception_pointer)
|
|
ori a0, a0, 2
|
|
j .Lreturn_result
|
|
.type .Ltrap_handler, @function
|
|
.size .Ltrap_handler, .-.Ltrap_handler
|
|
|
|
/* Callback from C to OCaml */
|
|
|
|
FUNCTION(caml_callback_asm)
|
|
/* Initial shuffling of arguments */
|
|
/* a0 = Caml_state, a1 = closure, (a2) = args */
|
|
mv ARG_DOMAIN_STATE_PTR, a0
|
|
LOAD a0, 0(a2) /* a0 = first arg */
|
|
/* a1 = closure environment */
|
|
LOAD ARG, 0(a1) /* code pointer */
|
|
j .Ljump_to_caml
|
|
.size caml_callback_asm, .-caml_callback_asm
|
|
|
|
FUNCTION(caml_callback2_asm)
|
|
/* Initial shuffling of arguments */
|
|
/* a0 = Caml_state, a1 = closure, (a2) = args */
|
|
mv ARG_DOMAIN_STATE_PTR, a0
|
|
mv TMP, a1
|
|
LOAD a0, 0(a2)
|
|
LOAD a1, 8(a2)
|
|
mv a2, TMP
|
|
la ARG, caml_apply2
|
|
j .Ljump_to_caml
|
|
.size caml_callback2_asm, .-caml_callback2_asm
|
|
|
|
FUNCTION(caml_callback3_asm)
|
|
/* Initial shuffling of arguments */
|
|
/* a0 = Caml_state, a1 = closure, (a2) = args */
|
|
mv ARG_DOMAIN_STATE_PTR, a0
|
|
mv a3, a1
|
|
LOAD a0, 0(a2)
|
|
LOAD a1, 8(a2)
|
|
LOAD a2, 16(a2)
|
|
la ARG, caml_apply3
|
|
j .Ljump_to_caml
|
|
.size caml_callback3_asm, .-caml_callback3_asm
|
|
|
|
FUNCTION(caml_ml_array_bound_error)
|
|
/* Load address of [caml_array_bound_error] in ARG */
|
|
la ARG, caml_array_bound_error
|
|
/* Call that function */
|
|
tail caml_c_call
|
|
.size caml_ml_array_bound_error, .-caml_ml_array_bound_error
|
|
|
|
.globl caml_system__code_end
|
|
caml_system__code_end:
|
|
|
|
/* GC roots for callback */
|
|
|
|
.section .data
|
|
.align 3
|
|
.globl caml_system__frametable
|
|
.type caml_system__frametable, @object
|
|
caml_system__frametable:
|
|
.quad 1 /* one descriptor */
|
|
.quad .Lcaml_retaddr /* return address into callback */
|
|
.short -1 /* negative frame size => use callback link */
|
|
.short 0 /* no roots */
|
|
.align 3
|
|
.size caml_system__frametable, .-caml_system__frametable
|