rust/src/boot/llvm/llasm.ml
2010-06-23 21:03:09 -07:00

193 lines
5.0 KiB
OCaml

(*
* machine-specific assembler routines.
*)
open Common;;
type asm_glue =
{
asm_activate_glue : Llvm.llvalue;
asm_yield_glue : Llvm.llvalue;
asm_upcall_glues : Llvm.llvalue array;
}
;;
let n_upcall_glues = 7
;;
(* x86-specific asm. *)
let x86_glue
(llctx:Llvm.llcontext)
(llmod:Llvm.llmodule)
(abi:Llabi.abi)
(sess:Session.sess)
: asm_glue =
let (prefix,align) =
match sess.Session.sess_targ with
Linux_x86_elf
| Win32_x86_pe -> ("",4)
| MacOS_x86_macho -> ("_", 16)
in
let save_callee_saves =
["pushl %ebp";
"pushl %edi";
"pushl %esi";
"pushl %ebx";]
in
let restore_callee_saves =
["popl %ebx";
"popl %esi";
"popl %edi";
"popl %ebp";]
in
let load_esp_from_rust_sp = ["movl 12(%edx), %esp"] in
let load_esp_from_runtime_sp = ["movl 8(%edx), %esp"] in
let store_esp_to_rust_sp = ["movl %esp, 12(%edx)"] in
let store_esp_to_runtime_sp = ["movl %esp, 8(%edx)"] in
let list_init i f = (Array.to_list (Array.init i f)) in
let list_init_concat i f = List.concat (list_init i f) in
let glue =
[
("rust_activate_glue",
String.concat "\n\t"
(["movl 4(%esp), %edx # edx = rust_task"]
@ save_callee_saves
@ store_esp_to_runtime_sp
@ load_esp_from_rust_sp
(*
* This 'add' instruction is a bit surprising.
* See lengthy comment in boot/be/x86.ml activate_glue.
*)
@ ["addl $20, 12(%edx)"]
@ restore_callee_saves
@ ["ret"]));
("rust_yield_glue",
String.concat "\n\t"
(["movl 0(%esp), %edx # edx = rust_task"]
@ load_esp_from_rust_sp
@ save_callee_saves
@ store_esp_to_rust_sp
@ load_esp_from_runtime_sp
@ restore_callee_saves
@ ["ret"]))
]
@ list_init n_upcall_glues
begin
fun i ->
(*
* 0, 4, 8, 12 are callee-saves
* 16 is retpc
* 20 is taskptr
* 24 is callee
* 28 .. (7+i) * 4 are args
*)
((Printf.sprintf "rust_upcall_%d" i),
String.concat "\n\t"
(save_callee_saves
@ ["movl %esp, %ebp # ebp = rust_sp";
"movl 20(%esp), %edx # edx = rust_task"]
@ store_esp_to_rust_sp
@ load_esp_from_runtime_sp
@ [Printf.sprintf
"subl $%d, %%esp # esp -= args" ((i+1)*4);
"andl $~0xf, %esp # align esp down";
"movl %edx, (%esp) # arg[0] = rust_task "]
@ (list_init_concat i
begin
fun j ->
[ Printf.sprintf "movl %d(%%ebp),%%edx" ((j+7)*4);
Printf.sprintf "movl %%edx,%d(%%esp)" ((j+1)*4) ]
end)
@ ["movl 24(%ebp), %edx # edx = callee";
"call *%edx # call *%edx";
"movl 20(%ebp), %edx # edx = rust_task"]
@ load_esp_from_rust_sp
@ restore_callee_saves
@ ["ret"]))
end
in
let _ =
Llvm.set_module_inline_asm llmod
begin
String.concat "\n"
begin
List.map
begin
fun (sym,asm) ->
Printf.sprintf
"\t.globl %s%s\n\t.balign %d\n%s%s:\n\t%s"
prefix sym align prefix sym asm
end
glue
end
end
in
let decl_cdecl_fn name out_ty arg_tys =
let ty = Llvm.function_type out_ty arg_tys in
let fn = Llvm.declare_function name ty llmod in
Llvm.set_function_call_conv Llvm.CallConv.c fn;
fn
in
let decl_glue s =
let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in
let void_ty = Llvm.void_type llctx in
decl_cdecl_fn s void_ty [| task_ptr_ty |]
in
let decl_upcall n =
let task_ptr_ty = Llvm.pointer_type abi.Llabi.task_ty in
let word_ty = abi.Llabi.word_ty in
let callee_ty = word_ty in
let args_ty =
Array.append
[| task_ptr_ty; callee_ty |]
(Array.init n (fun _ -> word_ty))
in
let name = Printf.sprintf "rust_upcall_%d" n in
decl_cdecl_fn name word_ty args_ty
in
{
asm_activate_glue = decl_glue "rust_activate_glue";
asm_yield_glue = decl_glue "rust_yield_glue";
asm_upcall_glues = Array.init n_upcall_glues decl_upcall;
}
;;
(* x64-specific asm. *)
(* arm-specific asm. *)
(* ... *)
let get_glue
(llctx:Llvm.llcontext)
(llmod:Llvm.llmodule)
(abi:Llabi.abi)
(sess:Session.sess)
: asm_glue =
match sess.Session.sess_targ with
Linux_x86_elf
| Win32_x86_pe
| MacOS_x86_macho ->
x86_glue llctx llmod abi sess
;;
(*
* Local Variables:
* fill-column: 78;
* indent-tabs-mode: nil
* buffer-file-coding-system: utf-8-unix
* compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
* End:
*)