|
|
0c4d3e |
From 38ac4778744fb7137e04708998d4e856ada1c8b8 Mon Sep 17 00:00:00 2001
|
|
|
0c4d3e |
From: Nicolas Ojeda Bar <n.oje.bar@gmail.com>
|
|
|
0c4d3e |
Date: Fri, 27 Oct 2017 17:05:25 +0200
|
|
|
0c4d3e |
Subject: [PATCH 4/8] Add RISC-V backend
|
|
|
0c4d3e |
|
|
|
0c4d3e |
---
|
|
|
0c4d3e |
README.adoc | 1 +
|
|
|
0c4d3e |
asmcomp/riscv/CSE.ml | 36 ++
|
|
|
0c4d3e |
asmcomp/riscv/arch.ml | 87 +++++
|
|
|
0c4d3e |
asmcomp/riscv/emit.mlp | 653 ++++++++++++++++++++++++++++++++++++
|
|
|
0c4d3e |
asmcomp/riscv/proc.ml | 301 +++++++++++++++++
|
|
|
0c4d3e |
asmcomp/riscv/reload.ml | 16 +
|
|
|
0c4d3e |
asmcomp/riscv/scheduling.ml | 19 ++
|
|
|
0c4d3e |
asmcomp/riscv/selection.ml | 72 ++++
|
|
|
0c4d3e |
asmrun/riscv.S | 424 +++++++++++++++++++++++
|
|
|
0c4d3e |
byterun/caml/stack.h | 5 +
|
|
|
0c4d3e |
config/gnu/config.guess | 5 +-
|
|
|
0c4d3e |
configure | 5 +-
|
|
|
0c4d3e |
12 files changed, 1622 insertions(+), 2 deletions(-)
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/CSE.ml
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/arch.ml
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/emit.mlp
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/proc.ml
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/reload.ml
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/scheduling.ml
|
|
|
0c4d3e |
create mode 100644 asmcomp/riscv/selection.ml
|
|
|
0c4d3e |
create mode 100644 asmrun/riscv.S
|
|
|
0c4d3e |
|
|
|
0c4d3e |
diff --git a/README.adoc b/README.adoc
|
|
|
0c4d3e |
index 74d1ec258..ac6c6eac3 100644
|
|
|
0c4d3e |
--- a/README.adoc
|
|
|
0c4d3e |
+++ b/README.adoc
|
|
|
0c4d3e |
@@ -47,6 +47,7 @@ AMD64:: FreeBSD, OpenBSD, NetBSD
|
|
|
0c4d3e |
IA32 (Pentium):: NetBSD, OpenBSD, Solaris 9
|
|
|
0c4d3e |
PowerPC:: NetBSD
|
|
|
0c4d3e |
ARM:: NetBSD
|
|
|
0c4d3e |
+RISC-V:: Linux
|
|
|
0c4d3e |
|
|
|
0c4d3e |
Other operating systems for the processors above have not been tested, but
|
|
|
0c4d3e |
the compiler may work under other operating systems with little work.
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/CSE.ml b/asmcomp/riscv/CSE.ml
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..302811a99
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/CSE.ml
|
|
|
0c4d3e |
@@ -0,0 +1,36 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2106 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* CSE for the RISC-V *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+open Arch
|
|
|
0c4d3e |
+open Mach
|
|
|
0c4d3e |
+open CSEgen
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+class cse = object (_self)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+inherit cse_generic as super
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+method! class_of_operation op =
|
|
|
0c4d3e |
+ match op with
|
|
|
0c4d3e |
+ | Ispecific(Imultaddf _ | Imultsubf _) -> Op_pure
|
|
|
0c4d3e |
+ | _ -> super#class_of_operation op
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+method! is_cheap_operation op =
|
|
|
0c4d3e |
+ match op with
|
|
|
0c4d3e |
+ | Iconst_int n -> n <= 0x7FFn && n >= -0x800n
|
|
|
0c4d3e |
+ | _ -> false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let fundecl f =
|
|
|
0c4d3e |
+ (new cse)#fundecl f
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/arch.ml b/asmcomp/riscv/arch.ml
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..22c807c49
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/arch.ml
|
|
|
0c4d3e |
@@ -0,0 +1,87 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2016 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Specific operations for the RISC-V processor *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+open Format
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Machine-specific command-line options *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let command_line_options = []
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Specific operations *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+type specific_operation =
|
|
|
0c4d3e |
+ | Imultaddf of bool (* multiply, optionally negate, and add *)
|
|
|
0c4d3e |
+ | Imultsubf of bool (* multiply, optionally negate, and subtract *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let spacetime_node_hole_pointer_is_live_before = function
|
|
|
0c4d3e |
+ | Imultaddf _ | Imultsubf _ -> false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Addressing modes *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+type addressing_mode =
|
|
|
0c4d3e |
+ | Iindexed of int (* reg + displ *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let is_immediate n =
|
|
|
0c4d3e |
+ (n <= 2047) && (n >= -2048)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Sizes, endianness *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let big_endian = false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let rv64 =
|
|
|
0c4d3e |
+ match Config.model with "riscv64" -> true | "riscv32" -> false | _ -> assert false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let size_addr = if rv64 then 8 else 4
|
|
|
0c4d3e |
+let size_int = size_addr
|
|
|
0c4d3e |
+let size_float = 8
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let allow_unaligned_access = false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Behavior of division *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let division_crashes_on_overflow = false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Operations on addressing modes *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let identity_addressing = Iindexed 0
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let offset_addressing addr delta =
|
|
|
0c4d3e |
+ match addr with
|
|
|
0c4d3e |
+ | Iindexed n -> Iindexed(n + delta)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let num_args_addressing = function
|
|
|
0c4d3e |
+ | Iindexed _ -> 1
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Printing operations and addressing modes *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let print_addressing printreg addr ppf arg =
|
|
|
0c4d3e |
+ match addr with
|
|
|
0c4d3e |
+ | Iindexed n ->
|
|
|
0c4d3e |
+ let idx = if n <> 0 then Printf.sprintf " + %i" n else "" in
|
|
|
0c4d3e |
+ fprintf ppf "%a%s" printreg arg.(0) idx
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let print_specific_operation printreg op ppf arg =
|
|
|
0c4d3e |
+ match op with
|
|
|
0c4d3e |
+ | Imultaddf false ->
|
|
|
0c4d3e |
+ fprintf ppf "%a *f %a +f %a"
|
|
|
0c4d3e |
+ printreg arg.(0) printreg arg.(1) printreg arg.(2)
|
|
|
0c4d3e |
+ | Imultaddf true ->
|
|
|
0c4d3e |
+ fprintf ppf "-f (%a *f %a +f %a)"
|
|
|
0c4d3e |
+ printreg arg.(0) printreg arg.(1) printreg arg.(2)
|
|
|
0c4d3e |
+ | Imultsubf false ->
|
|
|
0c4d3e |
+ fprintf ppf "%a *f %a -f %a"
|
|
|
0c4d3e |
+ printreg arg.(0) printreg arg.(1) printreg arg.(2)
|
|
|
0c4d3e |
+ | Imultsubf true ->
|
|
|
0c4d3e |
+ fprintf ppf "-f (%a *f %a -f %a)"
|
|
|
0c4d3e |
+ printreg arg.(0) printreg arg.(1) printreg arg.(2)
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..51165d0f1
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/emit.mlp
|
|
|
0c4d3e |
@@ -0,0 +1,653 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2016 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Emission of RISC-V assembly code *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+open Misc
|
|
|
0c4d3e |
+open Cmm
|
|
|
0c4d3e |
+open Arch
|
|
|
0c4d3e |
+open Proc
|
|
|
0c4d3e |
+open Reg
|
|
|
0c4d3e |
+open Mach
|
|
|
0c4d3e |
+open Linearize
|
|
|
0c4d3e |
+open Emitaux
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Layout of the stack. The stack is kept 16-aligned. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let stack_offset = ref 0
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let frame_size () =
|
|
|
0c4d3e |
+ let size =
|
|
|
0c4d3e |
+ !stack_offset + (* Trap frame, outgoing parameters *)
|
|
|
0c4d3e |
+ size_int * num_stack_slots.(0) + (* Local int variables *)
|
|
|
0c4d3e |
+ size_float * num_stack_slots.(1) + (* Local float variables *)
|
|
|
0c4d3e |
+ (if !contains_calls then size_addr else 0) in (* The return address *)
|
|
|
0c4d3e |
+ Misc.align size 16
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let slot_offset loc cls =
|
|
|
0c4d3e |
+ match loc with
|
|
|
0c4d3e |
+ | Local n ->
|
|
|
0c4d3e |
+ if cls = 0
|
|
|
0c4d3e |
+ then !stack_offset + num_stack_slots.(1) * size_float + n * size_int
|
|
|
0c4d3e |
+ else !stack_offset + n * size_float
|
|
|
0c4d3e |
+ | Incoming n -> frame_size() + n
|
|
|
0c4d3e |
+ | Outgoing n -> n
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Output a symbol *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_symbol s =
|
|
|
0c4d3e |
+ Emitaux.emit_symbol '.' s
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Output a label *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let label_prefix = "L"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_label lbl =
|
|
|
0c4d3e |
+ emit_string label_prefix; emit_int lbl
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Section switching *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let data_space =
|
|
|
0c4d3e |
+ ".section .data"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let code_space =
|
|
|
0c4d3e |
+ ".section .text"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let rodata_space =
|
|
|
0c4d3e |
+ ".section .rodata"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let reg_tmp1 = phys_reg 21 (* used by the assembler *)
|
|
|
0c4d3e |
+let reg_tmp2 = phys_reg 22
|
|
|
0c4d3e |
+let reg_t2 = phys_reg 16
|
|
|
0c4d3e |
+(* let reg_fp = phys_reg 23 *)
|
|
|
0c4d3e |
+let reg_trap = phys_reg 24
|
|
|
0c4d3e |
+let reg_alloc_ptr = phys_reg 25
|
|
|
0c4d3e |
+let reg_alloc_lim = phys_reg 26
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Names of instructions that differ in 32 and 64-bit modes *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let lg = if rv64 then "ld" else "lw"
|
|
|
0c4d3e |
+let stg = if rv64 then "sd" else "sw"
|
|
|
0c4d3e |
+let datag = if rv64 then ".quad" else ".long"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Output a pseudo-register *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_reg = function
|
|
|
0c4d3e |
+ | {loc = Reg r} -> emit_string (register_name r)
|
|
|
0c4d3e |
+ | _ -> fatal_error "Emit.emit_reg"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Adjust sp by the given byte amount *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_stack_adjustment = function
|
|
|
0c4d3e |
+ | 0 -> ()
|
|
|
0c4d3e |
+ | n when is_immediate n ->
|
|
|
0c4d3e |
+ ` addi sp, sp, {emit_int n}\n`
|
|
|
0c4d3e |
+ | n ->
|
|
|
0c4d3e |
+ ` li {emit_reg reg_tmp1}, {emit_int n}\n`;
|
|
|
0c4d3e |
+ ` add sp, sp, {emit_reg reg_tmp1}\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let reload_ra n =
|
|
|
0c4d3e |
+ let ofs = n - size_addr in
|
|
|
0c4d3e |
+ if is_immediate ofs then
|
|
|
0c4d3e |
+ ` {emit_string lg} ra, {emit_int ofs}(sp)\n`
|
|
|
0c4d3e |
+ else begin
|
|
|
0c4d3e |
+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`;
|
|
|
0c4d3e |
+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`;
|
|
|
0c4d3e |
+ ` {emit_string lg} ra, 0({emit_reg reg_tmp1})\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let store_ra n =
|
|
|
0c4d3e |
+ let ofs = n - size_addr in
|
|
|
0c4d3e |
+ if is_immediate ofs then
|
|
|
0c4d3e |
+ ` {emit_string stg} ra, {emit_int(n - size_addr)}(sp)\n`
|
|
|
0c4d3e |
+ else begin
|
|
|
0c4d3e |
+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`;
|
|
|
0c4d3e |
+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`;
|
|
|
0c4d3e |
+ ` {emit_string stg} ra, 0({emit_reg reg_tmp1})\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_store stg src ofs =
|
|
|
0c4d3e |
+ if is_immediate ofs then
|
|
|
0c4d3e |
+ ` {emit_string stg} {emit_reg src}, {emit_int ofs}(sp)\n`
|
|
|
0c4d3e |
+ else begin
|
|
|
0c4d3e |
+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`;
|
|
|
0c4d3e |
+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`;
|
|
|
0c4d3e |
+ ` {emit_string stg} {emit_reg src}, 0({emit_reg reg_tmp1})\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_load lg dst ofs =
|
|
|
0c4d3e |
+ if is_immediate ofs then
|
|
|
0c4d3e |
+ ` {emit_string lg} {emit_reg dst}, {emit_int ofs}(sp)\n`
|
|
|
0c4d3e |
+ else begin
|
|
|
0c4d3e |
+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`;
|
|
|
0c4d3e |
+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`;
|
|
|
0c4d3e |
+ ` {emit_string lg} {emit_reg dst}, 0({emit_reg reg_tmp1})\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Record live pointers at call points *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let record_frame_label ?label live raise_ dbg =
|
|
|
0c4d3e |
+ let lbl =
|
|
|
0c4d3e |
+ match label with
|
|
|
0c4d3e |
+ | None -> new_label()
|
|
|
0c4d3e |
+ | Some label -> label
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ let live_offset = ref [] in
|
|
|
0c4d3e |
+ Reg.Set.iter
|
|
|
0c4d3e |
+ (function
|
|
|
0c4d3e |
+ {typ = Val; loc = Reg r} ->
|
|
|
0c4d3e |
+ live_offset := (r lsl 1) + 1 :: !live_offset
|
|
|
0c4d3e |
+ | {typ = Val; loc = Stack s} as reg ->
|
|
|
0c4d3e |
+ live_offset := slot_offset s (register_class reg) :: !live_offset
|
|
|
0c4d3e |
+ | {typ = Addr} as r ->
|
|
|
0c4d3e |
+ Misc.fatal_error ("bad GC root " ^ Reg.name r)
|
|
|
0c4d3e |
+ | _ -> ()
|
|
|
0c4d3e |
+ )
|
|
|
0c4d3e |
+ live;
|
|
|
0c4d3e |
+ record_frame_descr ~label:lbl ~frame_size:(frame_size())
|
|
|
0c4d3e |
+ ~live_offset:!live_offset ~raise_frame:raise_ dbg;
|
|
|
0c4d3e |
+ lbl
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let record_frame ?label live raise_ dbg =
|
|
|
0c4d3e |
+ let lbl = record_frame_label ?label live raise_ dbg in
|
|
|
0c4d3e |
+ `{emit_label lbl}:\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Record calls to the GC -- we've moved them out of the way *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+type gc_call =
|
|
|
0c4d3e |
+ { gc_lbl: label; (* Entry label *)
|
|
|
0c4d3e |
+ gc_return_lbl: label; (* Where to branch after GC *)
|
|
|
0c4d3e |
+ gc_frame_lbl: label } (* Label of frame descriptor *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let call_gc_sites = ref ([] : gc_call list)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_call_gc gc =
|
|
|
0c4d3e |
+ `{emit_label gc.gc_lbl}:\n`;
|
|
|
0c4d3e |
+ ` call {emit_symbol "caml_call_gc"}\n`;
|
|
|
0c4d3e |
+ `{emit_label gc.gc_frame_lbl}:\n`;
|
|
|
0c4d3e |
+ ` j {emit_label gc.gc_return_lbl}\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Record calls to caml_ml_array_bound_error.
|
|
|
0c4d3e |
+ In debug mode, we maintain one call to caml_ml_array_bound_error
|
|
|
0c4d3e |
+ per bound check site. Otherwise, we can share a single call. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+type bound_error_call =
|
|
|
0c4d3e |
+ { bd_lbl: label; (* Entry label *)
|
|
|
0c4d3e |
+ bd_frame_lbl: label } (* Label of frame descriptor *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let bound_error_sites = ref ([] : bound_error_call list)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let bound_error_label ?label dbg =
|
|
|
0c4d3e |
+ if !Clflags.debug || !bound_error_sites = [] then begin
|
|
|
0c4d3e |
+ let lbl_bound_error = new_label() in
|
|
|
0c4d3e |
+ let lbl_frame = record_frame_label ?label Reg.Set.empty false dbg in
|
|
|
0c4d3e |
+ bound_error_sites :=
|
|
|
0c4d3e |
+ { bd_lbl = lbl_bound_error;
|
|
|
0c4d3e |
+ bd_frame_lbl = lbl_frame } :: !bound_error_sites;
|
|
|
0c4d3e |
+ lbl_bound_error
|
|
|
0c4d3e |
+ end else
|
|
|
0c4d3e |
+ let bd = List.hd !bound_error_sites in
|
|
|
0c4d3e |
+ bd.bd_lbl
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_call_bound_error bd =
|
|
|
0c4d3e |
+ `{emit_label bd.bd_lbl}:\n`;
|
|
|
0c4d3e |
+ ` call {emit_symbol "caml_ml_array_bound_error"}\n`;
|
|
|
0c4d3e |
+ `{emit_label bd.bd_frame_lbl}:\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Record floating-point literals *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let float_literals = ref ([] : (int64 * int) list)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Names for various instructions *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let name_for_intop = function
|
|
|
0c4d3e |
+ | Iadd -> "add"
|
|
|
0c4d3e |
+ | Isub -> "sub"
|
|
|
0c4d3e |
+ | Imul -> "mul"
|
|
|
0c4d3e |
+ | Imulh -> "mulh"
|
|
|
0c4d3e |
+ | Idiv -> "div"
|
|
|
0c4d3e |
+ | Iand -> "and"
|
|
|
0c4d3e |
+ | Ior -> "or"
|
|
|
0c4d3e |
+ | Ixor -> "xor"
|
|
|
0c4d3e |
+ | Ilsl -> "sll"
|
|
|
0c4d3e |
+ | Ilsr -> "srl"
|
|
|
0c4d3e |
+ | Iasr -> "sra"
|
|
|
0c4d3e |
+ | Imod -> "rem"
|
|
|
0c4d3e |
+ | _ -> fatal_error "Emit.Intop"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let name_for_intop_imm = function
|
|
|
0c4d3e |
+ | Iadd -> "addi"
|
|
|
0c4d3e |
+ | Iand -> "andi"
|
|
|
0c4d3e |
+ | Ior -> "ori"
|
|
|
0c4d3e |
+ | Ixor -> "xori"
|
|
|
0c4d3e |
+ | Ilsl -> "slli"
|
|
|
0c4d3e |
+ | Ilsr -> "srli"
|
|
|
0c4d3e |
+ | Iasr -> "srai"
|
|
|
0c4d3e |
+ | _ -> fatal_error "Emit.Intop_imm"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let name_for_floatop1 = function
|
|
|
0c4d3e |
+ | Inegf -> "fneg.d"
|
|
|
0c4d3e |
+ | Iabsf -> "fabs.d"
|
|
|
0c4d3e |
+ | _ -> fatal_error "Emit.Iopf1"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let name_for_floatop2 = function
|
|
|
0c4d3e |
+ | Iaddf -> "fadd.d"
|
|
|
0c4d3e |
+ | Isubf -> "fsub.d"
|
|
|
0c4d3e |
+ | Imulf -> "fmul.d"
|
|
|
0c4d3e |
+ | Idivf -> "fdiv.d"
|
|
|
0c4d3e |
+ | _ -> fatal_error "Emit.Iopf2"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let name_for_specific = function
|
|
|
0c4d3e |
+ | Imultaddf false -> "fmadd.d"
|
|
|
0c4d3e |
+ | Imultaddf true -> "fnmadd.d"
|
|
|
0c4d3e |
+ | Imultsubf false -> "fmsub.d"
|
|
|
0c4d3e |
+ | Imultsubf true -> "fnmsub.d"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Name of current function *)
|
|
|
0c4d3e |
+let function_name = ref ""
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Entry point for tail recursive calls *)
|
|
|
0c4d3e |
+let tailrec_entry_point = ref 0
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Output the assembly code for an instruction *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_instr i =
|
|
|
0c4d3e |
+ match i.desc with
|
|
|
0c4d3e |
+ Lend -> ()
|
|
|
0c4d3e |
+ | Lop(Imove | Ispill | Ireload) ->
|
|
|
0c4d3e |
+ let src = i.arg.(0) and dst = i.res.(0) in
|
|
|
0c4d3e |
+ if src.loc <> dst.loc then begin
|
|
|
0c4d3e |
+ match (src, dst) with
|
|
|
0c4d3e |
+ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Reg _} ->
|
|
|
0c4d3e |
+ ` mv {emit_reg dst}, {emit_reg src}\n`
|
|
|
0c4d3e |
+ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = Float} ->
|
|
|
0c4d3e |
+ ` fmv.d {emit_reg dst}, {emit_reg src}\n`
|
|
|
0c4d3e |
+ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Stack s} ->
|
|
|
0c4d3e |
+ let ofs = slot_offset s (register_class dst) in
|
|
|
0c4d3e |
+ emit_store stg src ofs
|
|
|
0c4d3e |
+ | {loc = Reg _; typ = Float}, {loc = Stack s} ->
|
|
|
0c4d3e |
+ let ofs = slot_offset s (register_class dst) in
|
|
|
0c4d3e |
+ emit_store "fsd" src ofs
|
|
|
0c4d3e |
+ | {loc = Stack s; typ = (Val | Int | Addr)}, {loc = Reg _} ->
|
|
|
0c4d3e |
+ let ofs = slot_offset s (register_class src) in
|
|
|
0c4d3e |
+ emit_load lg dst ofs
|
|
|
0c4d3e |
+ | {loc = Stack s; typ = Float}, {loc = Reg _} ->
|
|
|
0c4d3e |
+ let ofs = slot_offset s (register_class src) in
|
|
|
0c4d3e |
+ emit_load "fld" dst ofs
|
|
|
0c4d3e |
+ | _ ->
|
|
|
0c4d3e |
+ fatal_error "Emit: Imove"
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Lop(Iconst_int n) ->
|
|
|
0c4d3e |
+ ` li {emit_reg i.res.(0)}, {emit_nativeint n}\n`
|
|
|
0c4d3e |
+ | Lop(Iconst_float f) ->
|
|
|
0c4d3e |
+ let lbl = new_label() in
|
|
|
0c4d3e |
+ float_literals := (f, lbl) :: !float_literals;
|
|
|
0c4d3e |
+ ` fld {emit_reg i.res.(0)}, {emit_label lbl}, {emit_reg reg_tmp1}\n`
|
|
|
0c4d3e |
+ | Lop(Iconst_symbol s) ->
|
|
|
0c4d3e |
+ ` la {emit_reg i.res.(0)}, {emit_symbol s}\n`
|
|
|
0c4d3e |
+ | Lop(Icall_ind {label_after = label}) ->
|
|
|
0c4d3e |
+ ` jalr {emit_reg i.arg.(0)}\n`;
|
|
|
0c4d3e |
+ record_frame ~label i.live false i.dbg
|
|
|
0c4d3e |
+ | Lop(Icall_imm {func; label_after = label}) ->
|
|
|
0c4d3e |
+ ` call {emit_symbol func}\n`;
|
|
|
0c4d3e |
+ record_frame ~label i.live false i.dbg
|
|
|
0c4d3e |
+ | Lop(Itailcall_ind {label_after = _}) ->
|
|
|
0c4d3e |
+ let n = frame_size() in
|
|
|
0c4d3e |
+ if !contains_calls then reload_ra n;
|
|
|
0c4d3e |
+ emit_stack_adjustment n;
|
|
|
0c4d3e |
+ ` jr {emit_reg i.arg.(0)}\n`
|
|
|
0c4d3e |
+ | Lop(Itailcall_imm {func; label_after = _}) ->
|
|
|
0c4d3e |
+ if func = !function_name then begin
|
|
|
0c4d3e |
+ ` j {emit_label !tailrec_entry_point}\n`
|
|
|
0c4d3e |
+ end else begin
|
|
|
0c4d3e |
+ let n = frame_size() in
|
|
|
0c4d3e |
+ if !contains_calls then reload_ra n;
|
|
|
0c4d3e |
+ emit_stack_adjustment n;
|
|
|
0c4d3e |
+ ` tail {emit_symbol func}\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Lop(Iextcall{func; alloc = true; label_after = label}) ->
|
|
|
0c4d3e |
+ ` la {emit_reg reg_t2}, {emit_symbol func}\n`;
|
|
|
0c4d3e |
+ ` call {emit_symbol "caml_c_call"}\n`;
|
|
|
0c4d3e |
+ record_frame ~label i.live false i.dbg
|
|
|
0c4d3e |
+ | Lop(Iextcall{func; alloc = false; label_after = _}) ->
|
|
|
0c4d3e |
+ ` call {emit_symbol func}\n`
|
|
|
0c4d3e |
+ | Lop(Istackoffset n) ->
|
|
|
0c4d3e |
+ assert (n mod 16 = 0);
|
|
|
0c4d3e |
+ emit_stack_adjustment (-n);
|
|
|
0c4d3e |
+ stack_offset := !stack_offset + n
|
|
|
0c4d3e |
+ | Lop(Iload(Single, Iindexed ofs)) ->
|
|
|
0c4d3e |
+ ` flw {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`;
|
|
|
0c4d3e |
+ ` fcvt.d.s {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
|
|
|
0c4d3e |
+ | Lop(Iload(chunk, Iindexed ofs)) ->
|
|
|
0c4d3e |
+ let instr =
|
|
|
0c4d3e |
+ match chunk with
|
|
|
0c4d3e |
+ | Byte_unsigned -> "lbu"
|
|
|
0c4d3e |
+ | Byte_signed -> "lb"
|
|
|
0c4d3e |
+ | Sixteen_unsigned -> "lhu"
|
|
|
0c4d3e |
+ | Sixteen_signed -> "lh"
|
|
|
0c4d3e |
+ | Thirtytwo_unsigned -> if rv64 then "lwu" else "lw"
|
|
|
0c4d3e |
+ | Thirtytwo_signed -> "lw"
|
|
|
0c4d3e |
+ | Word_int | Word_val -> lg
|
|
|
0c4d3e |
+ | Single -> assert false
|
|
|
0c4d3e |
+ | Double | Double_u -> "fld"
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`
|
|
|
0c4d3e |
+ | Lop(Istore(Single, Iindexed ofs, _)) ->
|
|
|
0c4d3e |
+ ` fmv.x.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}\n`;
|
|
|
0c4d3e |
+ ` fcvt.s.d {emit_reg i.arg.(0)}, {emit_reg i.arg.(0)}\n`;
|
|
|
0c4d3e |
+ ` fsw {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n`;
|
|
|
0c4d3e |
+ ` fmv.d.x {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}\n`
|
|
|
0c4d3e |
+ | Lop(Istore(chunk, Iindexed ofs, _)) ->
|
|
|
0c4d3e |
+ let instr =
|
|
|
0c4d3e |
+ match chunk with
|
|
|
0c4d3e |
+ | Byte_unsigned | Byte_signed -> "sb"
|
|
|
0c4d3e |
+ | Sixteen_unsigned | Sixteen_signed -> "sh"
|
|
|
0c4d3e |
+ | Thirtytwo_unsigned | Thirtytwo_signed -> "sw"
|
|
|
0c4d3e |
+ | Word_int | Word_val -> stg
|
|
|
0c4d3e |
+ | Single -> assert false
|
|
|
0c4d3e |
+ | Double | Double_u -> "fsd"
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n`
|
|
|
0c4d3e |
+ | Lop(Ialloc {words = n; label_after_call_gc = label; _}) ->
|
|
|
0c4d3e |
+ let lbl_frame_lbl = record_frame_label ?label i.live false i.dbg in
|
|
|
0c4d3e |
+ let lbl_redo = new_label () in
|
|
|
0c4d3e |
+ let lbl_call_gc = new_label () in
|
|
|
0c4d3e |
+ `{emit_label lbl_redo}:\n`;
|
|
|
0c4d3e |
+ ` addi {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, -{emit_int n}\n`;
|
|
|
0c4d3e |
+ ` addi {emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, {emit_int size_addr}\n`;
|
|
|
0c4d3e |
+ ` bltu {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_lim}, {emit_label lbl_call_gc}\n`;
|
|
|
0c4d3e |
+ call_gc_sites :=
|
|
|
0c4d3e |
+ { gc_lbl = lbl_call_gc;
|
|
|
0c4d3e |
+ gc_return_lbl = lbl_redo;
|
|
|
0c4d3e |
+ gc_frame_lbl = lbl_frame_lbl } :: !call_gc_sites
|
|
|
0c4d3e |
+ | Lop(Iintop(Icomp cmp)) ->
|
|
|
0c4d3e |
+ begin match cmp with
|
|
|
0c4d3e |
+ | Isigned Clt ->
|
|
|
0c4d3e |
+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
|
|
|
0c4d3e |
+ | Isigned Cge ->
|
|
|
0c4d3e |
+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
|
|
|
0c4d3e |
+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`;
|
|
|
0c4d3e |
+ | Isigned Cgt ->
|
|
|
0c4d3e |
+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`
|
|
|
0c4d3e |
+ | Isigned Cle ->
|
|
|
0c4d3e |
+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`;
|
|
|
0c4d3e |
+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`;
|
|
|
0c4d3e |
+ | Isigned Ceq | Iunsigned Ceq ->
|
|
|
0c4d3e |
+ ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
|
|
|
0c4d3e |
+ ` seqz {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
|
|
|
0c4d3e |
+ | Isigned Cne | Iunsigned Cne ->
|
|
|
0c4d3e |
+ ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
|
|
|
0c4d3e |
+ ` snez {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n`
|
|
|
0c4d3e |
+ | Iunsigned Clt ->
|
|
|
0c4d3e |
+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
|
|
|
0c4d3e |
+ | Iunsigned Cge ->
|
|
|
0c4d3e |
+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`;
|
|
|
0c4d3e |
+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`;
|
|
|
0c4d3e |
+ | Iunsigned Cgt ->
|
|
|
0c4d3e |
+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`
|
|
|
0c4d3e |
+ | Iunsigned Cle ->
|
|
|
0c4d3e |
+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`;
|
|
|
0c4d3e |
+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`;
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Lop(Iintop (Icheckbound {label_after_error = label; _})) ->
|
|
|
0c4d3e |
+ let lbl = bound_error_label ?label i.dbg in
|
|
|
0c4d3e |
+ ` bleu {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Lop(Iintop op) ->
|
|
|
0c4d3e |
+ let instr = name_for_intop op in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
|
|
|
0c4d3e |
+ | Lop(Iintop_imm(Isub, n)) ->
|
|
|
0c4d3e |
+ ` addi {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int(-n)}\n`
|
|
|
0c4d3e |
+ | Lop(Iintop_imm(Icomp _, _)) ->
|
|
|
0c4d3e |
+ fatal_error "Emit.emit_instr (Iintop_imm (Icomp _, _))"
|
|
|
0c4d3e |
+ | Lop(Iintop_imm(Icheckbound {label_after_error = label; _}, n)) ->
|
|
|
0c4d3e |
+ let lbl = bound_error_label ?label i.dbg in
|
|
|
0c4d3e |
+ ` li {emit_reg reg_tmp1}, {emit_int n}\n`;
|
|
|
0c4d3e |
+ ` bleu {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Lop(Iintop_imm(op, n)) ->
|
|
|
0c4d3e |
+ let instr = name_for_intop_imm op in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int n}\n`
|
|
|
0c4d3e |
+ | Lop(Inegf | Iabsf as op) ->
|
|
|
0c4d3e |
+ let instr = name_for_floatop1 op in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n`
|
|
|
0c4d3e |
+ | Lop(Iaddf | Isubf | Imulf | Idivf as op) ->
|
|
|
0c4d3e |
+ let instr = name_for_floatop2 op in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`
|
|
|
0c4d3e |
+ | Lop(Ifloatofint) ->
|
|
|
0c4d3e |
+ let name = if rv64 then "fcvt.d.l" else "fcvt.d.w" in
|
|
|
0c4d3e |
+ ` {emit_string name} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n`
|
|
|
0c4d3e |
+ | Lop(Iintoffloat) ->
|
|
|
0c4d3e |
+ let name = if rv64 then "fcvt.l.d" else "fcvt.w.d" in
|
|
|
0c4d3e |
+ ` {emit_string name} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n`
|
|
|
0c4d3e |
+ | Lop(Ispecific sop) ->
|
|
|
0c4d3e |
+ let instr = name_for_specific sop in
|
|
|
0c4d3e |
+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(2)}\n`
|
|
|
0c4d3e |
+ | Lop (Iname_for_debugger _) ->
|
|
|
0c4d3e |
+ ()
|
|
|
0c4d3e |
+ | Lreloadretaddr ->
|
|
|
0c4d3e |
+ let n = frame_size () in
|
|
|
0c4d3e |
+ reload_ra n
|
|
|
0c4d3e |
+ | Lreturn ->
|
|
|
0c4d3e |
+ let n = frame_size() in
|
|
|
0c4d3e |
+ emit_stack_adjustment n;
|
|
|
0c4d3e |
+ ` ret\n`
|
|
|
0c4d3e |
+ | Llabel lbl ->
|
|
|
0c4d3e |
+ `{emit_label lbl}:\n`
|
|
|
0c4d3e |
+ | Lbranch lbl ->
|
|
|
0c4d3e |
+ ` j {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Lcondbranch(tst, lbl) ->
|
|
|
0c4d3e |
+ begin match tst with
|
|
|
0c4d3e |
+ | Itruetest ->
|
|
|
0c4d3e |
+ ` bnez {emit_reg i.arg.(0)}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Ifalsetest ->
|
|
|
0c4d3e |
+ ` beqz {emit_reg i.arg.(0)}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Iinttest cmp ->
|
|
|
0c4d3e |
+ let name = match cmp with
|
|
|
0c4d3e |
+ | Iunsigned Ceq | Isigned Ceq -> "beq"
|
|
|
0c4d3e |
+ | Iunsigned Cne | Isigned Cne -> "bne"
|
|
|
0c4d3e |
+ | Iunsigned Cle -> "bleu" | Isigned Cle -> "ble"
|
|
|
0c4d3e |
+ | Iunsigned Cge -> "bgeu" | Isigned Cge -> "bge"
|
|
|
0c4d3e |
+ | Iunsigned Clt -> "bltu" | Isigned Clt -> "blt"
|
|
|
0c4d3e |
+ | Iunsigned Cgt -> "bgtu" | Isigned Cgt -> "bgt"
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ ` {emit_string name} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Iinttest_imm _ ->
|
|
|
0c4d3e |
+ fatal_error "Emit.emit_instr (Iinttest_imm _)"
|
|
|
0c4d3e |
+ | Ifloattest(cmp, neg) ->
|
|
|
0c4d3e |
+ let neg = match cmp with
|
|
|
0c4d3e |
+ | Ceq -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg
|
|
|
0c4d3e |
+ | Cne -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; not neg
|
|
|
0c4d3e |
+ | Clt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg
|
|
|
0c4d3e |
+ | Cgt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg
|
|
|
0c4d3e |
+ | Cle -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg
|
|
|
0c4d3e |
+ | Cge -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ if neg then
|
|
|
0c4d3e |
+ ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ else
|
|
|
0c4d3e |
+ ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Ioddtest ->
|
|
|
0c4d3e |
+ ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`;
|
|
|
0c4d3e |
+ ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Ieventest ->
|
|
|
0c4d3e |
+ ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`;
|
|
|
0c4d3e |
+ ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Lcondbranch3(lbl0, lbl1, lbl2) ->
|
|
|
0c4d3e |
+ ` addi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, -1\n`;
|
|
|
0c4d3e |
+ begin match lbl0 with
|
|
|
0c4d3e |
+ | None -> ()
|
|
|
0c4d3e |
+ | Some lbl -> ` bltz {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ end;
|
|
|
0c4d3e |
+ begin match lbl1 with
|
|
|
0c4d3e |
+ | None -> ()
|
|
|
0c4d3e |
+ | Some lbl -> ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ end;
|
|
|
0c4d3e |
+ begin match lbl2 with
|
|
|
0c4d3e |
+ | None -> ()
|
|
|
0c4d3e |
+ | Some lbl -> ` bgtz {emit_reg reg_tmp1}, {emit_label lbl}\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Lswitch jumptbl -> (* FIXME FIXME ? *)
|
|
|
0c4d3e |
+ let lbl = new_label() in
|
|
|
0c4d3e |
+ ` la {emit_reg reg_tmp1}, {emit_label lbl}\n`;
|
|
|
0c4d3e |
+ ` slli {emit_reg reg_tmp2}, {emit_reg i.arg.(0)}, 2\n`;
|
|
|
0c4d3e |
+ ` add {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_reg reg_tmp2}\n`;
|
|
|
0c4d3e |
+ ` jr {emit_reg reg_tmp1}\n`;
|
|
|
0c4d3e |
+ `{emit_label lbl}:\n`;
|
|
|
0c4d3e |
+ for i = 0 to Array.length jumptbl - 1 do
|
|
|
0c4d3e |
+ ` j {emit_label jumptbl.(i)}\n`
|
|
|
0c4d3e |
+ done
|
|
|
0c4d3e |
+ | Lsetuptrap lbl ->
|
|
|
0c4d3e |
+ ` addi sp, sp, -16\n`;
|
|
|
0c4d3e |
+ ` jal {emit_label lbl}\n`
|
|
|
0c4d3e |
+ | Lpushtrap ->
|
|
|
0c4d3e |
+ stack_offset := !stack_offset + 16;
|
|
|
0c4d3e |
+ ` {emit_string stg} ra, {emit_int size_addr}(sp)\n`;
|
|
|
0c4d3e |
+ ` {emit_string stg} {emit_reg reg_trap}, 0(sp)\n`;
|
|
|
0c4d3e |
+ ` mv {emit_reg reg_trap}, sp\n`
|
|
|
0c4d3e |
+ | Lpoptrap ->
|
|
|
0c4d3e |
+ ` {emit_string lg} {emit_reg reg_trap}, 0(sp)\n`;
|
|
|
0c4d3e |
+ ` addi sp, sp, 16\n`;
|
|
|
0c4d3e |
+ stack_offset := !stack_offset - 16
|
|
|
0c4d3e |
+ | Lraise k ->
|
|
|
0c4d3e |
+ begin match !Clflags.debug, k with
|
|
|
0c4d3e |
+ | true, Cmm.Raise_withtrace ->
|
|
|
0c4d3e |
+ ` call {emit_symbol "caml_raise_exn"}\n`;
|
|
|
0c4d3e |
+ record_frame Reg.Set.empty true i.dbg
|
|
|
0c4d3e |
+ | false, _
|
|
|
0c4d3e |
+ | true, Cmm.Raise_notrace ->
|
|
|
0c4d3e |
+ ` mv sp, {emit_reg reg_trap}\n`;
|
|
|
0c4d3e |
+ ` {emit_string lg} {emit_reg reg_tmp1}, {emit_int size_addr}(sp)\n`;
|
|
|
0c4d3e |
+ ` {emit_string lg} {emit_reg reg_trap}, 0(sp)\n`;
|
|
|
0c4d3e |
+ ` addi sp, sp, 16\n`;
|
|
|
0c4d3e |
+ ` jalr {emit_reg reg_tmp1}\n`
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Emit a sequence of instructions *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let rec emit_all = function
|
|
|
0c4d3e |
+ | {desc = Lend} -> () | i -> emit_instr i; emit_all i.next
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Emission of a function declaration *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let fundecl fundecl =
|
|
|
0c4d3e |
+ function_name := fundecl.fun_name;
|
|
|
0c4d3e |
+ tailrec_entry_point := new_label();
|
|
|
0c4d3e |
+ stack_offset := 0;
|
|
|
0c4d3e |
+ call_gc_sites := [];
|
|
|
0c4d3e |
+ bound_error_sites := [];
|
|
|
0c4d3e |
+ float_literals := [];
|
|
|
0c4d3e |
+ ` .globl {emit_symbol fundecl.fun_name}\n`;
|
|
|
0c4d3e |
+ ` .type {emit_symbol fundecl.fun_name}, @function\n`;
|
|
|
0c4d3e |
+ ` {emit_string code_space}\n`;
|
|
|
0c4d3e |
+ ` .align 2\n`;
|
|
|
0c4d3e |
+ `{emit_symbol fundecl.fun_name}:\n`;
|
|
|
0c4d3e |
+ let n = frame_size() in
|
|
|
0c4d3e |
+ emit_stack_adjustment (-n);
|
|
|
0c4d3e |
+ if !contains_calls then store_ra n;
|
|
|
0c4d3e |
+ `{emit_label !tailrec_entry_point}:\n`;
|
|
|
0c4d3e |
+ emit_all fundecl.fun_body;
|
|
|
0c4d3e |
+ List.iter emit_call_gc !call_gc_sites;
|
|
|
0c4d3e |
+ List.iter emit_call_bound_error !bound_error_sites;
|
|
|
0c4d3e |
+ ` .size {emit_symbol fundecl.fun_name}, .-{emit_symbol fundecl.fun_name}\n`;
|
|
|
0c4d3e |
+ (* Emit the float literals *)
|
|
|
0c4d3e |
+ if !float_literals <> [] then begin
|
|
|
0c4d3e |
+ ` {emit_string rodata_space}\n`;
|
|
|
0c4d3e |
+ ` .align 3\n`;
|
|
|
0c4d3e |
+ List.iter
|
|
|
0c4d3e |
+ (fun (f, lbl) ->
|
|
|
0c4d3e |
+ `{emit_label lbl}:\n`;
|
|
|
0c4d3e |
+ if rv64
|
|
|
0c4d3e |
+ then emit_float64_directive ".quad" f
|
|
|
0c4d3e |
+ else emit_float64_split_directive ".long" f)
|
|
|
0c4d3e |
+ !float_literals;
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Emission of data *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let declare_global_data s =
|
|
|
0c4d3e |
+ ` .globl {emit_symbol s}\n`;
|
|
|
0c4d3e |
+ ` .type {emit_symbol s}, @object\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let emit_item = function
|
|
|
0c4d3e |
+ | Cglobal_symbol s ->
|
|
|
0c4d3e |
+ declare_global_data s
|
|
|
0c4d3e |
+ | Cdefine_symbol s ->
|
|
|
0c4d3e |
+ `{emit_symbol s}:\n`;
|
|
|
0c4d3e |
+ | Cint8 n ->
|
|
|
0c4d3e |
+ ` .byte {emit_int n}\n`
|
|
|
0c4d3e |
+ | Cint16 n ->
|
|
|
0c4d3e |
+ ` .short {emit_int n}\n`
|
|
|
0c4d3e |
+ | Cint32 n ->
|
|
|
0c4d3e |
+ ` .long {emit_nativeint n}\n`
|
|
|
0c4d3e |
+ | Cint n ->
|
|
|
0c4d3e |
+ ` {emit_string datag} {emit_nativeint n}\n`
|
|
|
0c4d3e |
+ | Csingle f ->
|
|
|
0c4d3e |
+ emit_float32_directive ".long" (Int32.bits_of_float f)
|
|
|
0c4d3e |
+ | Cdouble f ->
|
|
|
0c4d3e |
+ if rv64
|
|
|
0c4d3e |
+ then emit_float64_directive ".quad" (Int64.bits_of_float f)
|
|
|
0c4d3e |
+ else emit_float64_split_directive ".long" (Int64.bits_of_float f)
|
|
|
0c4d3e |
+ | Csymbol_address s ->
|
|
|
0c4d3e |
+ ` {emit_string datag} {emit_symbol s}\n`
|
|
|
0c4d3e |
+ | Cstring s ->
|
|
|
0c4d3e |
+ emit_bytes_directive " .byte " s
|
|
|
0c4d3e |
+ | Cskip n ->
|
|
|
0c4d3e |
+ if n > 0 then ` .space {emit_int n}\n`
|
|
|
0c4d3e |
+ | Calign n ->
|
|
|
0c4d3e |
+ ` .align {emit_int (Misc.log2 n)}\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let data l =
|
|
|
0c4d3e |
+ ` {emit_string data_space}\n`;
|
|
|
0c4d3e |
+ List.iter emit_item l
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Beginning / end of an assembly file *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let begin_assembly() =
|
|
|
0c4d3e |
+ ` .file \"\"\n`; (* PR#7073 *)
|
|
|
0c4d3e |
+ (* Emit the beginning of the segments *)
|
|
|
0c4d3e |
+ let lbl_begin = Compilenv.make_symbol (Some "data_begin") in
|
|
|
0c4d3e |
+ ` {emit_string data_space}\n`;
|
|
|
0c4d3e |
+ declare_global_data lbl_begin;
|
|
|
0c4d3e |
+ `{emit_symbol lbl_begin}:\n`;
|
|
|
0c4d3e |
+ let lbl_begin = Compilenv.make_symbol (Some "code_begin") in
|
|
|
0c4d3e |
+ ` {emit_string code_space}\n`;
|
|
|
0c4d3e |
+ declare_global_data lbl_begin;
|
|
|
0c4d3e |
+ `{emit_symbol lbl_begin}:\n`
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let end_assembly() =
|
|
|
0c4d3e |
+ ` {emit_string code_space}\n`;
|
|
|
0c4d3e |
+ let lbl_end = Compilenv.make_symbol (Some "code_end") in
|
|
|
0c4d3e |
+ declare_global_data lbl_end;
|
|
|
0c4d3e |
+ `{emit_symbol lbl_end}:\n`;
|
|
|
0c4d3e |
+ ` .long 0\n`;
|
|
|
0c4d3e |
+ ` {emit_string data_space}\n`;
|
|
|
0c4d3e |
+ let lbl_end = Compilenv.make_symbol (Some "data_end") in
|
|
|
0c4d3e |
+ declare_global_data lbl_end;
|
|
|
0c4d3e |
+ `{emit_symbol lbl_end}:\n`;
|
|
|
0c4d3e |
+ ` {emit_string datag} 0\n`;
|
|
|
0c4d3e |
+ (* Emit the frame descriptors *)
|
|
|
0c4d3e |
+ ` {emit_string rodata_space}\n`;
|
|
|
0c4d3e |
+ let lbl = Compilenv.make_symbol (Some "frametable") in
|
|
|
0c4d3e |
+ declare_global_data lbl;
|
|
|
0c4d3e |
+ `{emit_symbol lbl}:\n`;
|
|
|
0c4d3e |
+ emit_frames
|
|
|
0c4d3e |
+ { efa_code_label = (fun l -> ` {emit_string datag} {emit_label l}\n`);
|
|
|
0c4d3e |
+ efa_data_label = (fun l -> ` {emit_string datag} {emit_label l}\n`);
|
|
|
0c4d3e |
+ efa_16 = (fun n -> ` .short {emit_int n}\n`);
|
|
|
0c4d3e |
+ efa_32 = (fun n -> ` .long {emit_int32 n}\n`);
|
|
|
0c4d3e |
+ efa_word = (fun n -> ` {emit_string datag} {emit_int n}\n`);
|
|
|
0c4d3e |
+ efa_align = (fun n -> ` .align {emit_int (Misc.log2 n)}\n`);
|
|
|
0c4d3e |
+ efa_label_rel = (fun lbl ofs ->
|
|
|
0c4d3e |
+ ` .long ({emit_label lbl} - .) + {emit_int32 ofs}\n`);
|
|
|
0c4d3e |
+ efa_def_label = (fun l -> `{emit_label l}:\n`);
|
|
|
0c4d3e |
+ efa_string = (fun s -> emit_bytes_directive " .byte " (s ^ "\000"))
|
|
|
0c4d3e |
+ }
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/proc.ml b/asmcomp/riscv/proc.ml
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..c0b0dcdb8
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/proc.ml
|
|
|
0c4d3e |
@@ -0,0 +1,301 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2016 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Description of the RISC-V *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+open Misc
|
|
|
0c4d3e |
+open Cmm
|
|
|
0c4d3e |
+open Reg
|
|
|
0c4d3e |
+open Arch
|
|
|
0c4d3e |
+open Mach
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Instruction selection *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let word_addressed = false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Registers available for register allocation *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Integer register map:
|
|
|
0c4d3e |
+ zero always zero
|
|
|
0c4d3e |
+ ra return address
|
|
|
0c4d3e |
+ sp, gp, tp stack pointer, global pointer, thread pointer (preserved by C)
|
|
|
0c4d3e |
+ a0 - a7 0 - 7 arguments/results
|
|
|
0c4d3e |
+ s2 - s9 8 - 15 arguments/results (preserved by C)
|
|
|
0c4d3e |
+ t2 - t6 16 - 20 temporary
|
|
|
0c4d3e |
+ t0 21 temporary (used by assembler)
|
|
|
0c4d3e |
+ t1 22 temporary (reserved for code gen)
|
|
|
0c4d3e |
+ s0 23 frame pointer (preserved by C)
|
|
|
0c4d3e |
+ s1 24 trap pointer (preserved by C)
|
|
|
0c4d3e |
+ s10 25 allocation pointer (preserved by C)
|
|
|
0c4d3e |
+ s11 26 allocation limit (preserved by C)
|
|
|
0c4d3e |
+ Floating-point register map:
|
|
|
0c4d3e |
+ ft0 - ft7 100 - 107 temporary
|
|
|
0c4d3e |
+ fs0 - fs1 108 - 109 general purpose (preserved by C)
|
|
|
0c4d3e |
+ fa0 - fa7 110 - 117 arguments/results
|
|
|
0c4d3e |
+ fs2 - fs9 118 - 125 arguments/results (preserved by C)
|
|
|
0c4d3e |
+ fs10 - fs11 126 - 127 general purpose (preserved by C)
|
|
|
0c4d3e |
+ ft8 - ft11 128 - 131 temporary
|
|
|
0c4d3e |
+*)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let int_reg_name =
|
|
|
0c4d3e |
+ [| "a0"; "a1"; "a2"; "a3"; "a4"; "a5"; "a6"; "a7";
|
|
|
0c4d3e |
+ "s2"; "s3"; "s4"; "s5"; "s6"; "s7"; "s8"; "s9";
|
|
|
0c4d3e |
+ "t2"; "t3"; "t4"; "t5"; "t6";
|
|
|
0c4d3e |
+ "t0"; "t1";
|
|
|
0c4d3e |
+ "s0"; "s1"; "s10"; "s11" |]
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let float_reg_name =
|
|
|
0c4d3e |
+ [| "ft0"; "ft1"; "ft2"; "ft3"; "ft4"; "ft5"; "ft6"; "ft7";
|
|
|
0c4d3e |
+ "fs0"; "fs1";
|
|
|
0c4d3e |
+ "fa0"; "fa1"; "fa2"; "fa3"; "fa4"; "fa5"; "fa6"; "fa7";
|
|
|
0c4d3e |
+ "fs2"; "fs3"; "fs4"; "fs5"; "fs6"; "fs7"; "fs8"; "fs9"; "fs10"; "fs11";
|
|
|
0c4d3e |
+ "ft8"; "ft9"; "ft10"; "ft11" |]
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let num_register_classes = 2
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let register_class r =
|
|
|
0c4d3e |
+ match r.typ with
|
|
|
0c4d3e |
+ | Val | Int | Addr -> 0
|
|
|
0c4d3e |
+ | Float -> 1
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let num_available_registers = [| 21; 32 |]
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let first_available_register = [| 0; 100 |]
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let register_name r =
|
|
|
0c4d3e |
+ if r < 100 then int_reg_name.(r) else float_reg_name.(r - 100)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let rotate_registers = true
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Representation of hard registers by pseudo-registers *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let hard_int_reg =
|
|
|
0c4d3e |
+ let v = Array.make 27 Reg.dummy in
|
|
|
0c4d3e |
+ for i = 0 to 26 do
|
|
|
0c4d3e |
+ v.(i) <- Reg.at_location Int (Reg i)
|
|
|
0c4d3e |
+ done;
|
|
|
0c4d3e |
+ v
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let hard_float_reg =
|
|
|
0c4d3e |
+ let v = Array.make 32 Reg.dummy in
|
|
|
0c4d3e |
+ for i = 0 to 31 do
|
|
|
0c4d3e |
+ v.(i) <- Reg.at_location Float (Reg(100 + i))
|
|
|
0c4d3e |
+ done;
|
|
|
0c4d3e |
+ v
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let all_phys_regs =
|
|
|
0c4d3e |
+ Array.append hard_int_reg hard_float_reg
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let phys_reg n =
|
|
|
0c4d3e |
+ if n < 100 then hard_int_reg.(n) else hard_float_reg.(n - 100)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let stack_slot slot ty =
|
|
|
0c4d3e |
+ Reg.at_location ty (Stack slot)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Calling conventions *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let calling_conventions
|
|
|
0c4d3e |
+ first_int last_int first_float last_float make_stack arg =
|
|
|
0c4d3e |
+ let loc = Array.make (Array.length arg) Reg.dummy in
|
|
|
0c4d3e |
+ let int = ref first_int in
|
|
|
0c4d3e |
+ let float = ref first_float in
|
|
|
0c4d3e |
+ let ofs = ref 0 in
|
|
|
0c4d3e |
+ for i = 0 to Array.length arg - 1 do
|
|
|
0c4d3e |
+ match arg.(i).typ with
|
|
|
0c4d3e |
+ | Val | Int | Addr as ty ->
|
|
|
0c4d3e |
+ if !int <= last_int then begin
|
|
|
0c4d3e |
+ loc.(i) <- phys_reg !int;
|
|
|
0c4d3e |
+ incr int
|
|
|
0c4d3e |
+ end else begin
|
|
|
0c4d3e |
+ loc.(i) <- stack_slot (make_stack !ofs) ty;
|
|
|
0c4d3e |
+ ofs := !ofs + size_int
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Float ->
|
|
|
0c4d3e |
+ if !float <= last_float then begin
|
|
|
0c4d3e |
+ loc.(i) <- phys_reg !float;
|
|
|
0c4d3e |
+ incr float
|
|
|
0c4d3e |
+ end else begin
|
|
|
0c4d3e |
+ loc.(i) <- stack_slot (make_stack !ofs) Float;
|
|
|
0c4d3e |
+ ofs := !ofs + size_float
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ done;
|
|
|
0c4d3e |
+ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let incoming ofs = Incoming ofs
|
|
|
0c4d3e |
+let outgoing ofs = Outgoing ofs
|
|
|
0c4d3e |
+let not_supported _ = fatal_error "Proc.loc_results: cannot call"
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let max_arguments_for_tailcalls = 16
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_spacetime_node_hole = Reg.dummy (* Spacetime unsupported *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* OCaml calling convention:
|
|
|
0c4d3e |
+ first integer args in a0 .. a7, s2 .. s9
|
|
|
0c4d3e |
+ first float args in fa0 .. fa7, fs2 .. fs9
|
|
|
0c4d3e |
+ remaining args on stack.
|
|
|
0c4d3e |
+ Return values in a0 .. a7, s2 .. s9 or fa0 .. fa7, fs2 .. fs9. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let single_regs arg = Array.map (fun arg -> [| arg |]) arg
|
|
|
0c4d3e |
+let ensure_single_regs res =
|
|
|
0c4d3e |
+ Array.map (function
|
|
|
0c4d3e |
+ | [| res |] -> res
|
|
|
0c4d3e |
+ | _ -> failwith "proc.ensure_single_regs"
|
|
|
0c4d3e |
+ ) res
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_arguments arg =
|
|
|
0c4d3e |
+ calling_conventions 0 15 110 125 outgoing arg
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_parameters arg =
|
|
|
0c4d3e |
+ let (loc, _ofs) =
|
|
|
0c4d3e |
+ calling_conventions 0 15 110 125 incoming arg
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ loc
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_results res =
|
|
|
0c4d3e |
+ let (loc, _ofs) =
|
|
|
0c4d3e |
+ calling_conventions 0 15 110 125 not_supported res
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ loc
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* C calling convention:
|
|
|
0c4d3e |
+ first integer args in a0 .. a7
|
|
|
0c4d3e |
+ first float args in fa0 .. fa7
|
|
|
0c4d3e |
+ remaining args on stack.
|
|
|
0c4d3e |
+ Return values in a0 .. a1 or fa0 .. fa1. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let external_calling_conventions
|
|
|
0c4d3e |
+ first_int last_int first_float last_float make_stack arg =
|
|
|
0c4d3e |
+ let loc = Array.make (Array.length arg) [| Reg.dummy |] in
|
|
|
0c4d3e |
+ let int = ref first_int in
|
|
|
0c4d3e |
+ let float = ref first_float in
|
|
|
0c4d3e |
+ let ofs = ref 0 in
|
|
|
0c4d3e |
+ for i = 0 to Array.length arg - 1 do
|
|
|
0c4d3e |
+ match arg.(i) with
|
|
|
0c4d3e |
+ | [| arg |] ->
|
|
|
0c4d3e |
+ begin match arg.typ with
|
|
|
0c4d3e |
+ | Val | Int | Addr as ty ->
|
|
|
0c4d3e |
+ if !int <= last_int then begin
|
|
|
0c4d3e |
+ loc.(i) <- [| phys_reg !int |];
|
|
|
0c4d3e |
+ incr int;
|
|
|
0c4d3e |
+ incr float;
|
|
|
0c4d3e |
+ end else begin
|
|
|
0c4d3e |
+ loc.(i) <- [| stack_slot (make_stack !ofs) ty |];
|
|
|
0c4d3e |
+ ofs := !ofs + size_int
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | Float ->
|
|
|
0c4d3e |
+ if !float <= last_float then begin
|
|
|
0c4d3e |
+ loc.(i) <- [| phys_reg !float |];
|
|
|
0c4d3e |
+ incr float;
|
|
|
0c4d3e |
+ incr int;
|
|
|
0c4d3e |
+ end else begin
|
|
|
0c4d3e |
+ loc.(i) <- [| stack_slot (make_stack !ofs) Float |];
|
|
|
0c4d3e |
+ ofs := !ofs + size_float
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | [| arg1; arg2 |] ->
|
|
|
0c4d3e |
+ (* Passing of 64-bit quantities to external functions on 32-bit
|
|
|
0c4d3e |
+ platform. *)
|
|
|
0c4d3e |
+ assert (size_int = 4);
|
|
|
0c4d3e |
+ begin match arg1.typ, arg2.typ with
|
|
|
0c4d3e |
+ | Int, Int ->
|
|
|
0c4d3e |
+ int := Misc.align !int 2;
|
|
|
0c4d3e |
+ if !int <= last_int - 1 then begin
|
|
|
0c4d3e |
+ let reg_lower = phys_reg !int in
|
|
|
0c4d3e |
+ let reg_upper = phys_reg (!int + 1) in
|
|
|
0c4d3e |
+ loc.(i) <- [| reg_lower; reg_upper |];
|
|
|
0c4d3e |
+ int := !int + 2
|
|
|
0c4d3e |
+ end else begin
|
|
|
0c4d3e |
+ let size_int64 = 8 in
|
|
|
0c4d3e |
+ ofs := Misc.align !ofs size_int64;
|
|
|
0c4d3e |
+ let ofs_lower = !ofs in
|
|
|
0c4d3e |
+ let ofs_upper = !ofs + size_int in
|
|
|
0c4d3e |
+ let stack_lower = stack_slot (make_stack ofs_lower) Int in
|
|
|
0c4d3e |
+ let stack_upper = stack_slot (make_stack ofs_upper) Int in
|
|
|
0c4d3e |
+ loc.(i) <- [| stack_lower; stack_upper |];
|
|
|
0c4d3e |
+ ofs := !ofs + size_int64
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | _ ->
|
|
|
0c4d3e |
+ let f = function Int -> "I" | Addr -> "A" | Val -> "V" | Float -> "F" in
|
|
|
0c4d3e |
+ fatal_error (Printf.sprintf "Proc.calling_conventions: bad register \
|
|
|
0c4d3e |
+ type(s) for multi-register argument: %s, %s"
|
|
|
0c4d3e |
+ (f arg1.typ) (f arg2.typ))
|
|
|
0c4d3e |
+ end
|
|
|
0c4d3e |
+ | _ ->
|
|
|
0c4d3e |
+ fatal_error "Proc.calling_conventions: bad number of register for \
|
|
|
0c4d3e |
+ multi-register argument"
|
|
|
0c4d3e |
+ done;
|
|
|
0c4d3e |
+ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_external_arguments arg =
|
|
|
0c4d3e |
+ external_calling_conventions 0 7 110 117 outgoing arg
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_external_results res =
|
|
|
0c4d3e |
+ let (loc, _ofs) =
|
|
|
0c4d3e |
+ external_calling_conventions 0 1 110 111 not_supported (single_regs res)
|
|
|
0c4d3e |
+ in
|
|
|
0c4d3e |
+ ensure_single_regs loc
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Exceptions are in GPR 3 *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let loc_exn_bucket = phys_reg 0
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Volatile registers: none *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let regs_are_volatile _ = false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Registers destroyed by operations *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let destroyed_at_c_call =
|
|
|
0c4d3e |
+ Array.of_list(List.map phys_reg
|
|
|
0c4d3e |
+ [0; 1; 2; 3; 4; 5; 6; 7; 16; 17; 18; 19; 20; (* 21; 22; *)
|
|
|
0c4d3e |
+ 100; 101; 102; 103; 104; 105; 106; 107; 110; 111; 112; 113; 114; 115; 116;
|
|
|
0c4d3e |
+ 117; 128; 129; 130; 131])
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let destroyed_at_oper = function
|
|
|
0c4d3e |
+ | Iop(Icall_ind _ | Icall_imm _ | Iextcall{alloc = true; _}) -> all_phys_regs
|
|
|
0c4d3e |
+ | Iop(Iextcall{alloc = false; _}) -> destroyed_at_c_call
|
|
|
0c4d3e |
+ | _ -> [||]
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let destroyed_at_raise = all_phys_regs
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Maximal register pressure *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let safe_register_pressure = function
|
|
|
0c4d3e |
+ | Iextcall _ -> 15
|
|
|
0c4d3e |
+ | _ -> 21
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let max_register_pressure = function
|
|
|
0c4d3e |
+ | Iextcall _ -> [| 15; 18 |]
|
|
|
0c4d3e |
+ | _ -> [| 21; 30 |]
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Pure operations (without any side effect besides updating their result
|
|
|
0c4d3e |
+ registers). *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let op_is_pure = function
|
|
|
0c4d3e |
+ | Icall_ind _ | Icall_imm _ | Itailcall_ind _ | Itailcall_imm _
|
|
|
0c4d3e |
+ | Iextcall _ | Istackoffset _ | Istore _ | Ialloc _
|
|
|
0c4d3e |
+ | Iintop(Icheckbound _) | Iintop_imm(Icheckbound _, _) -> false
|
|
|
0c4d3e |
+ | Ispecific(Imultaddf _ | Imultsubf _) -> true
|
|
|
0c4d3e |
+ | _ -> true
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Layout of the stack *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let num_stack_slots = [| 0; 0 |]
|
|
|
0c4d3e |
+let contains_calls = ref false
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Calling the assembler *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let assemble_file infile outfile =
|
|
|
0c4d3e |
+ Ccomp.command
|
|
|
0c4d3e |
+ (Config.asm ^ " -o " ^ Filename.quote outfile ^ " " ^ Filename.quote infile)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let init () = ()
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/reload.ml b/asmcomp/riscv/reload.ml
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..85b970342
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/reload.ml
|
|
|
0c4d3e |
@@ -0,0 +1,16 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2016 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Reloading for the RISC-V *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let fundecl f =
|
|
|
0c4d3e |
+ (new Reloadgen.reload_generic)#fundecl f
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/scheduling.ml b/asmcomp/riscv/scheduling.ml
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..e436be1cc
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/scheduling.ml
|
|
|
0c4d3e |
@@ -0,0 +1,19 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2016 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Instruction scheduling for the RISC-V *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let _ = let module M = Schedgen in () (* to create a dependency *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Scheduling is turned off. *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let fundecl f = f
|
|
|
0c4d3e |
diff --git a/asmcomp/riscv/selection.ml b/asmcomp/riscv/selection.ml
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..092ca88aa
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmcomp/riscv/selection.ml
|
|
|
0c4d3e |
@@ -0,0 +1,72 @@
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* OCaml *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Nicolas Ojeda Bar <n.oje.bar@gmail.com> *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(* Copyright 2016 Institut National de Recherche en Informatique et *)
|
|
|
0c4d3e |
+(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
0c4d3e |
+(* under the terms of the Q Public License version 1.0. *)
|
|
|
0c4d3e |
+(* *)
|
|
|
0c4d3e |
+(***********************************************************************)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Instruction selection for the RISC-V processor *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+open Cmm
|
|
|
0c4d3e |
+open Arch
|
|
|
0c4d3e |
+open Mach
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Instruction selection *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+class selector = object (self)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+inherit Selectgen.selector_generic as super
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+method is_immediate n = is_immediate n
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+method select_addressing _ = function
|
|
|
0c4d3e |
+ | Cop(Cadda, [arg; Cconst_int n], _) when self#is_immediate n ->
|
|
|
0c4d3e |
+ (Iindexed n, arg)
|
|
|
0c4d3e |
+ | Cop(Cadda, [arg1; Cop(Caddi, [arg2; Cconst_int n], _)], dbg) when self#is_immediate n ->
|
|
|
0c4d3e |
+ (Iindexed n, Cop(Caddi, [arg1; arg2], dbg))
|
|
|
0c4d3e |
+ | arg ->
|
|
|
0c4d3e |
+ (Iindexed 0, arg)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+method! select_operation op args dbg =
|
|
|
0c4d3e |
+ match (op, args) with
|
|
|
0c4d3e |
+ (* RISC-V does not support immediate operands for multiply high *)
|
|
|
0c4d3e |
+ | (Cmulhi, _) -> (Iintop Imulh, args)
|
|
|
0c4d3e |
+ (* Recognize (neg-)mult-add and (neg-)mult-sub instructions *)
|
|
|
0c4d3e |
+ | (Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3])
|
|
|
0c4d3e |
+ | (Caddf, [arg3; Cop(Cmulf, [arg1; arg2], _)]) ->
|
|
|
0c4d3e |
+ (Ispecific (Imultaddf false), [arg1; arg2; arg3])
|
|
|
0c4d3e |
+ | (Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3]) ->
|
|
|
0c4d3e |
+ (Ispecific (Imultsubf false), [arg1; arg2; arg3])
|
|
|
0c4d3e |
+ | (Cnegf, [Cop(Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) ->
|
|
|
0c4d3e |
+ (Ispecific (Imultsubf true), [arg1; arg2; arg3])
|
|
|
0c4d3e |
+ | (Cnegf, [Cop(Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) ->
|
|
|
0c4d3e |
+ (Ispecific (Imultaddf true), [arg1; arg2; arg3])
|
|
|
0c4d3e |
+ (* RISC-V does not support immediate operands for comparison operators *)
|
|
|
0c4d3e |
+ | (Ccmpi comp, args) -> (Iintop(Icomp (Isigned comp)), args)
|
|
|
0c4d3e |
+ | (Ccmpa comp, args) -> (Iintop(Icomp (Iunsigned comp)), args)
|
|
|
0c4d3e |
+ | (Cmuli, _) -> (Iintop Imul, args)
|
|
|
0c4d3e |
+ | _ ->
|
|
|
0c4d3e |
+ super#select_operation op args dbg
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+(* Instruction selection for conditionals *)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+method! select_condition = function
|
|
|
0c4d3e |
+ | Cop(Ccmpi cmp, args, _) ->
|
|
|
0c4d3e |
+ (Iinttest(Isigned cmp), Ctuple args)
|
|
|
0c4d3e |
+ | Cop(Ccmpa cmp, args, _) ->
|
|
|
0c4d3e |
+ (Iinttest(Iunsigned cmp), Ctuple args)
|
|
|
0c4d3e |
+ | Cop(Ccmpf cmp, args, _) ->
|
|
|
0c4d3e |
+ (Ifloattest(cmp, false), Ctuple args)
|
|
|
0c4d3e |
+ | Cop(Cand, [arg; Cconst_int 1], _) ->
|
|
|
0c4d3e |
+ (Ioddtest, arg)
|
|
|
0c4d3e |
+ | arg ->
|
|
|
0c4d3e |
+ (Itruetest, arg)
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+end
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+let fundecl f = (new selector)#emit_fundecl f
|
|
|
0c4d3e |
diff --git a/asmrun/riscv.S b/asmrun/riscv.S
|
|
|
0c4d3e |
new file mode 100644
|
|
|
0c4d3e |
index 000000000..a82048efc
|
|
|
0c4d3e |
--- /dev/null
|
|
|
0c4d3e |
+++ b/asmrun/riscv.S
|
|
|
0c4d3e |
@@ -0,0 +1,424 @@
|
|
|
0c4d3e |
+/***********************************************************************/
|
|
|
0c4d3e |
+/* */
|
|
|
0c4d3e |
+/* OCaml */
|
|
|
0c4d3e |
+/* */
|
|
|
0c4d3e |
+/* Nicolas Ojeda Bar <n.oje.bar@gmail.com> */
|
|
|
0c4d3e |
+/* */
|
|
|
0c4d3e |
+/* Copyright 1996 Institut National de Recherche en Informatique et */
|
|
|
0c4d3e |
+/* en Automatique. All rights reserved. This file is distributed */
|
|
|
0c4d3e |
+/* under the terms of the GNU Library General Public License, with */
|
|
|
0c4d3e |
+/* the special exception on linking described in file ../LICENSE. */
|
|
|
0c4d3e |
+/* */
|
|
|
0c4d3e |
+/***********************************************************************/
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* Asm part of the runtime system, RISC-V processor, 64-bit mode */
|
|
|
0c4d3e |
+/* Must be preprocessed by cpp */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+#define TRAP_PTR s1
|
|
|
0c4d3e |
+#define ALLOC_PTR s10
|
|
|
0c4d3e |
+#define ALLOC_LIMIT s11
|
|
|
0c4d3e |
+#define TMP0 t0
|
|
|
0c4d3e |
+#define TMP1 t1
|
|
|
0c4d3e |
+#define ARG t2
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+#if defined(MODEL_riscv64)
|
|
|
0c4d3e |
+#define store sd
|
|
|
0c4d3e |
+#define load ld
|
|
|
0c4d3e |
+#define WSZ 8
|
|
|
0c4d3e |
+#else
|
|
|
0c4d3e |
+#define store sw
|
|
|
0c4d3e |
+#define load lw
|
|
|
0c4d3e |
+#define WSZ 4
|
|
|
0c4d3e |
+#endif
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+#if defined(__PIC__)
|
|
|
0c4d3e |
+ .option pic
|
|
|
0c4d3e |
+#else
|
|
|
0c4d3e |
+ .option nopic
|
|
|
0c4d3e |
+#endif
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .section .text
|
|
|
0c4d3e |
+/* Invoke the garbage collector. */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .globl caml_system__code_begin
|
|
|
0c4d3e |
+caml_system__code_begin:
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_call_gc
|
|
|
0c4d3e |
+ .type caml_call_gc, @function
|
|
|
0c4d3e |
+caml_call_gc:
|
|
|
0c4d3e |
+ /* Record return address */
|
|
|
0c4d3e |
+ store ra, caml_last_return_address, TMP0
|
|
|
0c4d3e |
+ /* Record lowest stack address */
|
|
|
0c4d3e |
+ mv TMP1, sp
|
|
|
0c4d3e |
+ store sp, caml_bottom_of_stack, TMP0
|
|
|
0c4d3e |
+.Lcaml_call_gc:
|
|
|
0c4d3e |
+ /* Set up stack space, saving return address */
|
|
|
0c4d3e |
+ /* (1 reg for RA, 1 reg for FP, 21 allocatable int regs, 20 caller-save float regs) * 8 */
|
|
|
0c4d3e |
+ /* + 1 for alignment */
|
|
|
0c4d3e |
+ addi sp, sp, -0x160
|
|
|
0c4d3e |
+ mv s0, sp
|
|
|
0c4d3e |
+ store ra, 0x8(sp)
|
|
|
0c4d3e |
+ store s0, 0x0(sp)
|
|
|
0c4d3e |
+ /* Save allocatable integer registers on the stack,
|
|
|
0c4d3e |
+ in the order given in proc.ml */
|
|
|
0c4d3e |
+ store a0, 0x10(sp)
|
|
|
0c4d3e |
+ store a1, 0x18(sp)
|
|
|
0c4d3e |
+ store a2, 0x20(sp)
|
|
|
0c4d3e |
+ store a3, 0x28(sp)
|
|
|
0c4d3e |
+ store a4, 0x30(sp)
|
|
|
0c4d3e |
+ store a5, 0x38(sp)
|
|
|
0c4d3e |
+ store a6, 0x40(sp)
|
|
|
0c4d3e |
+ store a7, 0x48(sp)
|
|
|
0c4d3e |
+ store s2, 0x50(sp)
|
|
|
0c4d3e |
+ store s3, 0x58(sp)
|
|
|
0c4d3e |
+ store s4, 0x60(sp)
|
|
|
0c4d3e |
+ store s5, 0x68(sp)
|
|
|
0c4d3e |
+ store s6, 0x70(sp)
|
|
|
0c4d3e |
+ store s7, 0x78(sp)
|
|
|
0c4d3e |
+ store s8, 0x80(sp)
|
|
|
0c4d3e |
+ store s9, 0x88(sp)
|
|
|
0c4d3e |
+ store t2, 0x90(sp)
|
|
|
0c4d3e |
+ store t3, 0x98(sp)
|
|
|
0c4d3e |
+ store t4, 0xa0(sp)
|
|
|
0c4d3e |
+ store t5, 0xa8(sp)
|
|
|
0c4d3e |
+ store t6, 0xb0(sp)
|
|
|
0c4d3e |
+ /* Save caller-save floating-point registers on the stack
|
|
|
0c4d3e |
+ (callee-saves are preserved by caml_garbage_collection) */
|
|
|
0c4d3e |
+ fsd ft0, 0xb8(sp)
|
|
|
0c4d3e |
+ fsd ft1, 0xc0(sp)
|
|
|
0c4d3e |
+ fsd ft2, 0xc8(sp)
|
|
|
0c4d3e |
+ fsd ft3, 0xd0(sp)
|
|
|
0c4d3e |
+ fsd ft4, 0xd8(sp)
|
|
|
0c4d3e |
+ fsd ft5, 0xe0(sp)
|
|
|
0c4d3e |
+ fsd ft6, 0xe8(sp)
|
|
|
0c4d3e |
+ fsd ft7, 0xf0(sp)
|
|
|
0c4d3e |
+ fsd fa0, 0xf8(sp)
|
|
|
0c4d3e |
+ fsd fa1, 0x100(sp)
|
|
|
0c4d3e |
+ fsd fa2, 0x108(sp)
|
|
|
0c4d3e |
+ fsd fa3, 0x110(sp)
|
|
|
0c4d3e |
+ fsd fa4, 0x118(sp)
|
|
|
0c4d3e |
+ fsd fa5, 0x120(sp)
|
|
|
0c4d3e |
+ fsd fa6, 0x128(sp)
|
|
|
0c4d3e |
+ fsd fa7, 0x130(sp)
|
|
|
0c4d3e |
+ fsd ft8, 0x138(sp)
|
|
|
0c4d3e |
+ fsd ft9, 0x140(sp)
|
|
|
0c4d3e |
+ fsd ft9, 0x148(sp)
|
|
|
0c4d3e |
+ fsd ft10, 0x150(sp)
|
|
|
0c4d3e |
+ fsd ft11, 0x158(sp)
|
|
|
0c4d3e |
+ /* Store pointer to saved integer registers in caml_gc_regs */
|
|
|
0c4d3e |
+ addi TMP1, sp, 16
|
|
|
0c4d3e |
+ store TMP1, caml_gc_regs, TMP0
|
|
|
0c4d3e |
+ /* Save current allocation pointer for debugging purposes */
|
|
|
0c4d3e |
+ store ALLOC_PTR, caml_young_ptr, TMP0
|
|
|
0c4d3e |
+ /* Save trap pointer in case an exception is raised during GC */
|
|
|
0c4d3e |
+ store TRAP_PTR, caml_exception_pointer, TMP0
|
|
|
0c4d3e |
+ /* Call the garbage collector */
|
|
|
0c4d3e |
+ call caml_garbage_collection
|
|
|
0c4d3e |
+ /* Restore registers */
|
|
|
0c4d3e |
+ load a0, 0x10(sp)
|
|
|
0c4d3e |
+ load a1, 0x18(sp)
|
|
|
0c4d3e |
+ load a2, 0x20(sp)
|
|
|
0c4d3e |
+ load a3, 0x28(sp)
|
|
|
0c4d3e |
+ load a4, 0x30(sp)
|
|
|
0c4d3e |
+ load a5, 0x38(sp)
|
|
|
0c4d3e |
+ load a6, 0x40(sp)
|
|
|
0c4d3e |
+ load a7, 0x48(sp)
|
|
|
0c4d3e |
+ load s2, 0x50(sp)
|
|
|
0c4d3e |
+ load s3, 0x58(sp)
|
|
|
0c4d3e |
+ load s4, 0x60(sp)
|
|
|
0c4d3e |
+ load s5, 0x68(sp)
|
|
|
0c4d3e |
+ load s6, 0x70(sp)
|
|
|
0c4d3e |
+ load s7, 0x78(sp)
|
|
|
0c4d3e |
+ load s8, 0x80(sp)
|
|
|
0c4d3e |
+ load s9, 0x88(sp)
|
|
|
0c4d3e |
+ load t2, 0x90(sp)
|
|
|
0c4d3e |
+ load t3, 0x98(sp)
|
|
|
0c4d3e |
+ load t4, 0xa0(sp)
|
|
|
0c4d3e |
+ load t5, 0xa8(sp)
|
|
|
0c4d3e |
+ load t6, 0xb0(sp)
|
|
|
0c4d3e |
+ fld ft0, 0xb8(sp)
|
|
|
0c4d3e |
+ fld ft1, 0xc0(sp)
|
|
|
0c4d3e |
+ fld ft2, 0xc8(sp)
|
|
|
0c4d3e |
+ fld ft3, 0xd0(sp)
|
|
|
0c4d3e |
+ fld ft4, 0xd8(sp)
|
|
|
0c4d3e |
+ fld ft5, 0xe0(sp)
|
|
|
0c4d3e |
+ fld ft6, 0xe8(sp)
|
|
|
0c4d3e |
+ fld ft7, 0xf0(sp)
|
|
|
0c4d3e |
+ fld fa0, 0xf8(sp)
|
|
|
0c4d3e |
+ fld fa1, 0x100(sp)
|
|
|
0c4d3e |
+ fld fa2, 0x108(sp)
|
|
|
0c4d3e |
+ fld fa3, 0x110(sp)
|
|
|
0c4d3e |
+ fld fa4, 0x118(sp)
|
|
|
0c4d3e |
+ fld fa5, 0x120(sp)
|
|
|
0c4d3e |
+ fld fa6, 0x128(sp)
|
|
|
0c4d3e |
+ fld fa7, 0x130(sp)
|
|
|
0c4d3e |
+ fld ft8, 0x138(sp)
|
|
|
0c4d3e |
+ fld ft9, 0x140(sp)
|
|
|
0c4d3e |
+ fld ft9, 0x148(sp)
|
|
|
0c4d3e |
+ fld ft10, 0x150(sp)
|
|
|
0c4d3e |
+ fld ft11, 0x158(sp)
|
|
|
0c4d3e |
+ /* Reload new allocation pointer and allocation limit */
|
|
|
0c4d3e |
+ load ALLOC_PTR, caml_young_ptr
|
|
|
0c4d3e |
+ load ALLOC_LIMIT, caml_young_limit
|
|
|
0c4d3e |
+ /* Free stack space and return to caller */
|
|
|
0c4d3e |
+ load ra, 0x8(sp)
|
|
|
0c4d3e |
+ load s0, 0x0(sp)
|
|
|
0c4d3e |
+ addi sp, sp, 0x160
|
|
|
0c4d3e |
+ ret
|
|
|
0c4d3e |
+ .size caml_call_gc, .-caml_call_gc
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* Call a C function from OCaml */
|
|
|
0c4d3e |
+/* Function to call is in ARG */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_c_call
|
|
|
0c4d3e |
+ .type caml_c_call, @function
|
|
|
0c4d3e |
+caml_c_call:
|
|
|
0c4d3e |
+ /* Preserve return address in callee-save register s2 */
|
|
|
0c4d3e |
+ mv s2, ra
|
|
|
0c4d3e |
+ /* Record lowest stack address and return address */
|
|
|
0c4d3e |
+ store ra, caml_last_return_address, TMP0
|
|
|
0c4d3e |
+ store sp, caml_bottom_of_stack, TMP0
|
|
|
0c4d3e |
+ /* Make the exception handler alloc ptr available to the C code */
|
|
|
0c4d3e |
+ store ALLOC_PTR, caml_young_ptr, TMP0
|
|
|
0c4d3e |
+ store TRAP_PTR, caml_exception_pointer, TMP0
|
|
|
0c4d3e |
+ /* Call the function */
|
|
|
0c4d3e |
+ jalr ARG
|
|
|
0c4d3e |
+ /* Reload alloc ptr and alloc limit */
|
|
|
0c4d3e |
+ load ALLOC_PTR, caml_young_ptr
|
|
|
0c4d3e |
+ load TRAP_PTR, caml_exception_pointer
|
|
|
0c4d3e |
+ /* Return */
|
|
|
0c4d3e |
+ jr s2
|
|
|
0c4d3e |
+ .size caml_c_call, .-caml_c_call
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* Raise an exception from OCaml */
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_raise_exn
|
|
|
0c4d3e |
+ .type caml_raise_exn, @function
|
|
|
0c4d3e |
+caml_raise_exn:
|
|
|
0c4d3e |
+ /* Test if backtrace is active */
|
|
|
0c4d3e |
+ load TMP1, caml_backtrace_active
|
|
|
0c4d3e |
+ bnez TMP1, 2f
|
|
|
0c4d3e |
+1: /* Cut stack at current trap handler */
|
|
|
0c4d3e |
+ mv sp, TRAP_PTR
|
|
|
0c4d3e |
+ /* Pop previous handler and jump to it */
|
|
|
0c4d3e |
+ load TMP1, 8(sp)
|
|
|
0c4d3e |
+ load TRAP_PTR, 0(sp)
|
|
|
0c4d3e |
+ addi sp, sp, 16
|
|
|
0c4d3e |
+ jr TMP1
|
|
|
0c4d3e |
+2: /* Preserve exception bucket in callee-save register s2 */
|
|
|
0c4d3e |
+ mv s2, a0
|
|
|
0c4d3e |
+ /* Stash the backtrace */
|
|
|
0c4d3e |
+ mv a1, ra
|
|
|
0c4d3e |
+ mv a2, sp
|
|
|
0c4d3e |
+ mv a3, TRAP_PTR
|
|
|
0c4d3e |
+ call caml_stash_backtrace
|
|
|
0c4d3e |
+ /* Restore exception bucket and raise */
|
|
|
0c4d3e |
+ mv a0, s2
|
|
|
0c4d3e |
+ j 1b
|
|
|
0c4d3e |
+ .size caml_raise_exn, .-caml_raise_exn
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .globl caml_reraise_exn
|
|
|
0c4d3e |
+ .type caml_reraise_exn, @function
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* Raise an exception from C */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_raise_exception
|
|
|
0c4d3e |
+ .type caml_raise_exception, @function
|
|
|
0c4d3e |
+caml_raise_exception:
|
|
|
0c4d3e |
+ load TRAP_PTR, caml_exception_pointer
|
|
|
0c4d3e |
+ load ALLOC_PTR, caml_young_ptr
|
|
|
0c4d3e |
+ load ALLOC_LIMIT, caml_young_limit
|
|
|
0c4d3e |
+ load TMP1, caml_backtrace_active
|
|
|
0c4d3e |
+ bnez TMP1, 2f
|
|
|
0c4d3e |
+1: /* Cut stack at current trap handler */
|
|
|
0c4d3e |
+ mv sp, TRAP_PTR
|
|
|
0c4d3e |
+ load TMP1, 8(sp)
|
|
|
0c4d3e |
+ load TRAP_PTR, 0(sp)
|
|
|
0c4d3e |
+ addi sp, sp, 16
|
|
|
0c4d3e |
+ jr TMP1
|
|
|
0c4d3e |
+2: /* Preserve exception bucket in callee-save register s2 */
|
|
|
0c4d3e |
+ mv s2, a0
|
|
|
0c4d3e |
+ load a1, caml_last_return_address
|
|
|
0c4d3e |
+ load a2, caml_bottom_of_stack
|
|
|
0c4d3e |
+ mv a3, TRAP_PTR
|
|
|
0c4d3e |
+ call caml_stash_backtrace
|
|
|
0c4d3e |
+ mv a0, s2
|
|
|
0c4d3e |
+ j 1b
|
|
|
0c4d3e |
+ .size caml_raise_exception, .-caml_raise_exception
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* Start the OCaml program */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_start_program
|
|
|
0c4d3e |
+ .type caml_start_program, @function
|
|
|
0c4d3e |
+caml_start_program:
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ la ARG, caml_program
|
|
|
0c4d3e |
+ /* Code shared with caml_callback* */
|
|
|
0c4d3e |
+ /* Address of OCaml code to call is in ARG */
|
|
|
0c4d3e |
+ /* Arguments to the OCaml code are in a0 ... a7 */
|
|
|
0c4d3e |
+.Ljump_to_caml:
|
|
|
0c4d3e |
+ /* Set up stack frame and save callee-save registers */
|
|
|
0c4d3e |
+ addi sp, sp, -0xd0
|
|
|
0c4d3e |
+ store ra, 0xc0(sp)
|
|
|
0c4d3e |
+ store s0, 0x0(sp)
|
|
|
0c4d3e |
+ store s1, 0x8(sp)
|
|
|
0c4d3e |
+ store s2, 0x10(sp)
|
|
|
0c4d3e |
+ store s3, 0x18(sp)
|
|
|
0c4d3e |
+ store s4, 0x20(sp)
|
|
|
0c4d3e |
+ store s5, 0x28(sp)
|
|
|
0c4d3e |
+ store s6, 0x30(sp)
|
|
|
0c4d3e |
+ store s7, 0x38(sp)
|
|
|
0c4d3e |
+ store s8, 0x40(sp)
|
|
|
0c4d3e |
+ store s9, 0x48(sp)
|
|
|
0c4d3e |
+ store s10, 0x50(sp)
|
|
|
0c4d3e |
+ store s11, 0x58(sp)
|
|
|
0c4d3e |
+ fsd fs0, 0x60(sp)
|
|
|
0c4d3e |
+ fsd fs1, 0x68(sp)
|
|
|
0c4d3e |
+ fsd fs2, 0x70(sp)
|
|
|
0c4d3e |
+ fsd fs3, 0x78(sp)
|
|
|
0c4d3e |
+ fsd fs4, 0x80(sp)
|
|
|
0c4d3e |
+ fsd fs5, 0x88(sp)
|
|
|
0c4d3e |
+ fsd fs6, 0x90(sp)
|
|
|
0c4d3e |
+ fsd fs7, 0x98(sp)
|
|
|
0c4d3e |
+ fsd fs8, 0xa0(sp)
|
|
|
0c4d3e |
+ fsd fs9, 0xa8(sp)
|
|
|
0c4d3e |
+ fsd fs10, 0xb0(sp)
|
|
|
0c4d3e |
+ fsd fs11, 0xb8(sp)
|
|
|
0c4d3e |
+ addi sp, sp, -32
|
|
|
0c4d3e |
+ /* Setup a callback link on the stack */
|
|
|
0c4d3e |
+ load TMP1, caml_bottom_of_stack
|
|
|
0c4d3e |
+ store TMP1, 0(sp)
|
|
|
0c4d3e |
+ load TMP1, caml_last_return_address
|
|
|
0c4d3e |
+ store TMP1, 8(sp)
|
|
|
0c4d3e |
+ load TMP1, caml_gc_regs
|
|
|
0c4d3e |
+ store TMP1, 16(sp)
|
|
|
0c4d3e |
+ /* set up a trap frame */
|
|
|
0c4d3e |
+ addi sp, sp, -16
|
|
|
0c4d3e |
+ load TMP1, caml_exception_pointer
|
|
|
0c4d3e |
+ store TMP1, 0(sp)
|
|
|
0c4d3e |
+ lla TMP0, .Ltrap_handler
|
|
|
0c4d3e |
+ store TMP0, 8(sp)
|
|
|
0c4d3e |
+ mv TRAP_PTR, sp
|
|
|
0c4d3e |
+ load ALLOC_PTR, caml_young_ptr
|
|
|
0c4d3e |
+ load ALLOC_LIMIT, caml_young_limit
|
|
|
0c4d3e |
+ store x0, caml_last_return_address, TMP0
|
|
|
0c4d3e |
+ jalr ARG
|
|
|
0c4d3e |
+.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */
|
|
|
0c4d3e |
+ load TMP1, 0(sp)
|
|
|
0c4d3e |
+ store TMP1, caml_exception_pointer, TMP0
|
|
|
0c4d3e |
+ addi sp, sp, 16
|
|
|
0c4d3e |
+.Lreturn_result: /* pop callback link, restoring global variables */
|
|
|
0c4d3e |
+ load TMP1, 0(sp)
|
|
|
0c4d3e |
+ store TMP1, caml_bottom_of_stack, TMP0
|
|
|
0c4d3e |
+ load TMP1, 8(sp)
|
|
|
0c4d3e |
+ store TMP1, caml_last_return_address, TMP0
|
|
|
0c4d3e |
+ load TMP1, 16(sp)
|
|
|
0c4d3e |
+ store TMP1, caml_gc_regs, TMP0
|
|
|
0c4d3e |
+ addi sp, sp, 32
|
|
|
0c4d3e |
+ /* Update allocation pointer */
|
|
|
0c4d3e |
+ store ALLOC_PTR, caml_young_ptr, TMP0
|
|
|
0c4d3e |
+ /* reload callee-save registers and return */
|
|
|
0c4d3e |
+ load ra, 0xc0(sp)
|
|
|
0c4d3e |
+ load s0, 0x0(sp)
|
|
|
0c4d3e |
+ load s1, 0x8(sp)
|
|
|
0c4d3e |
+ load s2, 0x10(sp)
|
|
|
0c4d3e |
+ load s3, 0x18(sp)
|
|
|
0c4d3e |
+ load s4, 0x20(sp)
|
|
|
0c4d3e |
+ load s5, 0x28(sp)
|
|
|
0c4d3e |
+ load s6, 0x30(sp)
|
|
|
0c4d3e |
+ load s7, 0x38(sp)
|
|
|
0c4d3e |
+ load s8, 0x40(sp)
|
|
|
0c4d3e |
+ load s9, 0x48(sp)
|
|
|
0c4d3e |
+ load s10, 0x50(sp)
|
|
|
0c4d3e |
+ load s11, 0x58(sp)
|
|
|
0c4d3e |
+ fld fs0, 0x60(sp)
|
|
|
0c4d3e |
+ fld fs1, 0x68(sp)
|
|
|
0c4d3e |
+ fld fs2, 0x70(sp)
|
|
|
0c4d3e |
+ fld fs3, 0x78(sp)
|
|
|
0c4d3e |
+ fld fs4, 0x80(sp)
|
|
|
0c4d3e |
+ fld fs5, 0x88(sp)
|
|
|
0c4d3e |
+ fld fs6, 0x90(sp)
|
|
|
0c4d3e |
+ fld fs7, 0x98(sp)
|
|
|
0c4d3e |
+ fld fs8, 0xa0(sp)
|
|
|
0c4d3e |
+ fld fs9, 0xa8(sp)
|
|
|
0c4d3e |
+ fld fs10, 0xb0(sp)
|
|
|
0c4d3e |
+ fld fs11, 0xb8(sp)
|
|
|
0c4d3e |
+ addi sp, sp, 0xd0
|
|
|
0c4d3e |
+ ret
|
|
|
0c4d3e |
+.Ltrap_handler:
|
|
|
0c4d3e |
+ store TRAP_PTR, caml_exception_pointer, TMP0
|
|
|
0c4d3e |
+ ori a0, a0, 2
|
|
|
0c4d3e |
+ j .Lreturn_result
|
|
|
0c4d3e |
+ .size caml_start_program, .-caml_start_program
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* Callback from C to OCaml */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_callback_exn
|
|
|
0c4d3e |
+ .type caml_callback_exn, @function
|
|
|
0c4d3e |
+caml_callback_exn:
|
|
|
0c4d3e |
+ /* Initial shuffling of arguments (a0 = closure, a1 = first arg) */
|
|
|
0c4d3e |
+ mv TMP1, a0
|
|
|
0c4d3e |
+ mv a0, a1 /* a0 = first arg */
|
|
|
0c4d3e |
+ mv a1, TMP1 /* a1 = closure environment */
|
|
|
0c4d3e |
+ load ARG, 0(TMP1) /* code pointer */
|
|
|
0c4d3e |
+ j .Ljump_to_caml
|
|
|
0c4d3e |
+ .size caml_callback_exn, .-caml_callback_exn
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_callback2_exn
|
|
|
0c4d3e |
+ .type caml_callback2_exn, @function
|
|
|
0c4d3e |
+caml_callback2_exn:
|
|
|
0c4d3e |
+ /* Initial shuffling of arguments (a0 = closure, a1 = arg1, a2 = arg2) */
|
|
|
0c4d3e |
+ mv TMP1, a0
|
|
|
0c4d3e |
+ mv a0, a1
|
|
|
0c4d3e |
+ mv a1, a2
|
|
|
0c4d3e |
+ mv a2, TMP1
|
|
|
0c4d3e |
+ la ARG, caml_apply2
|
|
|
0c4d3e |
+ j .Ljump_to_caml
|
|
|
0c4d3e |
+ .size caml_callback2_exn, .-caml_callback2_exn
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_callback3_exn
|
|
|
0c4d3e |
+ .type caml_callback3_exn, @function
|
|
|
0c4d3e |
+caml_callback3_exn:
|
|
|
0c4d3e |
+ /* Initial shuffling of argumnets */
|
|
|
0c4d3e |
+ /* (a0 = closure, a1 = arg1, a2 = arg2, a3 = arg3) */
|
|
|
0c4d3e |
+ mv TMP1, a0
|
|
|
0c4d3e |
+ mv a0, a1
|
|
|
0c4d3e |
+ mv a1, a2
|
|
|
0c4d3e |
+ mv a2, a3
|
|
|
0c4d3e |
+ mv a3, TMP1
|
|
|
0c4d3e |
+ la ARG, caml_apply3
|
|
|
0c4d3e |
+ j .Ljump_to_caml
|
|
|
0c4d3e |
+ .size caml_callback3_exn, .-caml_callback3_exn
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .align 2
|
|
|
0c4d3e |
+ .globl caml_ml_array_bound_error
|
|
|
0c4d3e |
+ .type caml_ml_array_bound_error, @function
|
|
|
0c4d3e |
+caml_ml_array_bound_error:
|
|
|
0c4d3e |
+ /* Load address of [caml_array_bound_error] in ARG */
|
|
|
0c4d3e |
+ la ARG, caml_array_bound_error
|
|
|
0c4d3e |
+ /* Call that function */
|
|
|
0c4d3e |
+ j caml_c_call
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .globl caml_system__code_end
|
|
|
0c4d3e |
+caml_system__code_end:
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+/* GC roots for callback */
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
+ .section .data
|
|
|
0c4d3e |
+ .align 3
|
|
|
0c4d3e |
+ .globl caml_system__frametable
|
|
|
0c4d3e |
+ .type caml_system__frametable, @object
|
|
|
0c4d3e |
+caml_system__frametable:
|
|
|
0c4d3e |
+ .quad 1 /* one descriptor */
|
|
|
0c4d3e |
+ .quad .Lcaml_retaddr /* return address into callback */
|
|
|
0c4d3e |
+ .short -1 /* negative frame size => use callback link */
|
|
|
0c4d3e |
+ .short 0 /* no roots */
|
|
|
0c4d3e |
+ .align 3
|
|
|
0c4d3e |
+ .size caml_system__frametable, .-caml_system__frametable
|
|
|
0c4d3e |
diff --git a/byterun/caml/stack.h b/byterun/caml/stack.h
|
|
|
0c4d3e |
index 266863986..e198be0a6 100644
|
|
|
0c4d3e |
--- a/byterun/caml/stack.h
|
|
|
0c4d3e |
+++ b/byterun/caml/stack.h
|
|
|
0c4d3e |
@@ -70,6 +70,11 @@
|
|
|
0c4d3e |
#define Callback_link(sp) ((struct caml_context *)((sp) + 16))
|
|
|
0c4d3e |
#endif
|
|
|
0c4d3e |
|
|
|
0c4d3e |
+#ifdef TARGET_riscv /* FIXME FIXME */
|
|
|
0c4d3e |
+#define Saved_return_address(sp) *((intnat *)((sp) - 8))
|
|
|
0c4d3e |
+#define Callback_link(sp) ((struct caml_context *)((sp) + 16))
|
|
|
0c4d3e |
+#endif
|
|
|
0c4d3e |
+
|
|
|
0c4d3e |
/* Structure of OCaml callback contexts */
|
|
|
0c4d3e |
|
|
|
0c4d3e |
struct caml_context {
|
|
|
0c4d3e |
diff --git a/config/gnu/config.guess b/config/gnu/config.guess
|
|
|
0c4d3e |
index b79252d6b..8335398b2 100755
|
|
|
0c4d3e |
--- a/config/gnu/config.guess
|
|
|
0c4d3e |
+++ b/config/gnu/config.guess
|
|
|
0c4d3e |
@@ -2,7 +2,7 @@
|
|
|
0c4d3e |
# Attempt to guess a canonical system name.
|
|
|
0c4d3e |
# Copyright 1992-2013 Free Software Foundation, Inc.
|
|
|
0c4d3e |
|
|
|
0c4d3e |
-timestamp='2013-06-10'
|
|
|
0c4d3e |
+timestamp='2016-10-23'
|
|
|
0c4d3e |
|
|
|
0c4d3e |
# This file is free software; you can redistribute it and/or modify it
|
|
|
0c4d3e |
# under the terms of the GNU General Public License as published by
|
|
|
0c4d3e |
@@ -1001,6 +1001,9 @@ EOF
|
|
|
0c4d3e |
ppcle:Linux:*:*)
|
|
|
0c4d3e |
echo powerpcle-unknown-linux-${LIBC}
|
|
|
0c4d3e |
exit ;;
|
|
|
0c4d3e |
+ riscv*:Linux:*:*)
|
|
|
0c4d3e |
+ echo ${UNAME_MACHINE}-unknown-linux
|
|
|
0c4d3e |
+ exit ;;
|
|
|
0c4d3e |
s390:Linux:*:* | s390x:Linux:*:*)
|
|
|
0c4d3e |
echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
|
|
|
0c4d3e |
exit ;;
|
|
|
0c4d3e |
diff --git a/configure b/configure
|
|
|
0c4d3e |
index 53f45f85b..cf5a4a02a 100755
|
|
|
0c4d3e |
--- a/configure
|
|
|
0c4d3e |
+++ b/configure
|
|
|
0c4d3e |
@@ -928,6 +928,7 @@ if $with_sharedlibs; then
|
|
|
0c4d3e |
arm*-*-freebsd*) natdynlink=true;;
|
|
|
0c4d3e |
earm*-*-netbsd*) natdynlink=true;;
|
|
|
0c4d3e |
aarch64-*-linux*) natdynlink=true;;
|
|
|
0c4d3e |
+ riscv*-*-linux*) natdynlink=true;;
|
|
|
0c4d3e |
esac
|
|
|
0c4d3e |
fi
|
|
|
0c4d3e |
|
|
|
0c4d3e |
@@ -1004,6 +1005,8 @@ case "$target" in
|
|
|
0c4d3e |
x86_64-*-mingw*) arch=amd64; system=mingw;;
|
|
|
0c4d3e |
aarch64-*-linux*) arch=arm64; system=linux;;
|
|
|
0c4d3e |
x86_64-*-cygwin*) arch=amd64; system=cygwin;;
|
|
|
0c4d3e |
+ riscv32-*-linux*) arch=riscv; model=riscv32; system=linux;;
|
|
|
0c4d3e |
+ riscv64-*-linux*) arch=riscv; model=riscv64; system=linux;;
|
|
|
0c4d3e |
esac
|
|
|
0c4d3e |
|
|
|
0c4d3e |
# Some platforms exist both in 32-bit and 64-bit variants, not distinguished
|
|
|
0c4d3e |
@@ -1062,7 +1065,7 @@ case "$arch,$system" in
|
|
|
0c4d3e |
aspp="${TOOLPREF}cc -c";;
|
|
|
0c4d3e |
*,freebsd) as="${TOOLPREF}as"
|
|
|
0c4d3e |
aspp="${TOOLPREF}cc -c";;
|
|
|
0c4d3e |
- amd64,*|arm,*|arm64,*|i386,*|power,bsd*|power,netbsd)
|
|
|
0c4d3e |
+ amd64,*|arm,*|arm64,*|i386,*|power,bsd*|power,netbsd|riscv,*)
|
|
|
0c4d3e |
as="${TOOLPREF}as"
|
|
|
0c4d3e |
case "$ccfamily" in
|
|
|
0c4d3e |
clang-*)
|
|
|
0c4d3e |
--
|
|
|
0c4d3e |
2.17.1
|
|
|
0c4d3e |
|