diff --git a/0005-Add-support-for-SW64.patch b/0005-Add-support-for-SW64.patch new file mode 100644 index 0000000000000000000000000000000000000000..40f4ddeb397e945508628069c01eb6429e25f4af --- /dev/null +++ b/0005-Add-support-for-SW64.patch @@ -0,0 +1,2385 @@ +From 1eaf46b3386ea0cebc96ee86d52210ee5249fbbe Mon Sep 17 00:00:00 2001 +From: grx +Date: Tue, 3 Dec 2024 10:56:04 +0800 +Subject: [PATCH] Add support for SW64 + +--- + Makefile | 2 +- + README-sw_64.md | 22 + + VERSION | 2 +- + asmcomp/cmm_helpers.ml | 2 + + asmcomp/sw_64/CSE.ml | 38 ++ + asmcomp/sw_64/NOTES.md | 5 + + asmcomp/sw_64/arch.ml | 94 ++++ + asmcomp/sw_64/emit.mlp | 785 ++++++++++++++++++++++++++++ + asmcomp/sw_64/proc.ml | 310 +++++++++++ + asmcomp/sw_64/reload.ml | 18 + + asmcomp/sw_64/scheduling.ml | 21 + + asmcomp/sw_64/selection.ml | 65 +++ + build-aux/config.guess | 42 ++ + build-aux/config.sub | 4 + + build-aux/ocaml_version.m4 | 4 +- + configure | Bin 581620 -> 582312 bytes + configure.ac | 12 +- + runtime/caml/stack.h | 5 + + runtime/interp.c | 6 + + runtime/ints.c | 18 +- + runtime/signals_osdep.h | 19 + + runtime/sw_64.S | 517 ++++++++++++++++++ + testsuite/tests/basic/boxedints.ml | 2 +- + testsuite/tests/no-alias-deps/b.cmi | 1 + + testsuite/tools/asmgen_sw_64.S | 60 +++ + 25 files changed, 2043 insertions(+), 11 deletions(-) + create mode 100644 README-sw_64.md + create mode 100644 asmcomp/sw_64/CSE.ml + create mode 100644 asmcomp/sw_64/NOTES.md + create mode 100644 asmcomp/sw_64/arch.ml + create mode 100644 asmcomp/sw_64/emit.mlp + create mode 100644 asmcomp/sw_64/proc.ml + create mode 100644 asmcomp/sw_64/reload.ml + create mode 100644 asmcomp/sw_64/scheduling.ml + create mode 100644 asmcomp/sw_64/selection.ml + create mode 100644 runtime/sw_64.S + create mode 100644 testsuite/tests/no-alias-deps/b.cmi + create mode 100644 testsuite/tools/asmgen_sw_64.S + +diff --git a/Makefile b/Makefile +index 0e92785..8568b68 100644 +--- a/Makefile ++++ b/Makefile +@@ -39,7 +39,7 @@ include stdlib/StdlibModules + + CAMLC=$(BOOT_OCAMLC) -g -nostdlib -I boot -use-prims runtime/primitives + CAMLOPT=$(OCAMLRUN) ./ocamlopt$(EXE) -g -nostdlib -I stdlib -I otherlibs/dynlink +-ARCHES=amd64 i386 arm arm64 power s390x riscv ++ARCHES=amd64 i386 arm arm64 power s390x riscv sw_64 + INCLUDES=-I utils -I parsing -I typing -I bytecomp -I file_formats \ + -I lambda -I middle_end -I middle_end/closure \ + -I middle_end/flambda -I middle_end/flambda/base_types \ +diff --git a/README-sw_64.md b/README-sw_64.md +new file mode 100644 +index 0000000..8377a96 +--- /dev/null ++++ b/README-sw_64.md +@@ -0,0 +1,22 @@ ++## This is ocaml-4.14.1 for sw_64. ++ ++## build ocaml on SW8A ++ ++ autoconf --force ++ ++ ./configure ++ ++ make world ++ ++ make opt ++ ++ make opt.opt ++ ++ make install ++ ++## test ocaml on SW8A ++ ++ make ocamltest (* create ocamltest tool *) ++ ++ make tests ++ +diff --git a/VERSION b/VERSION +index 4d777f2..9a82dc1 100644 +--- a/VERSION ++++ b/VERSION +@@ -1,4 +1,4 @@ +-4.14.1 ++4.14.1-sw1.0.0 + + # Starting with OCaml 4.14, although the version string that appears above is + # still correct and this file can thus still be used to figure it out, +diff --git a/asmcomp/cmm_helpers.ml b/asmcomp/cmm_helpers.ml +index 7ad42ce..121b4a2 100644 +--- a/asmcomp/cmm_helpers.ml ++++ b/asmcomp/cmm_helpers.ml +@@ -421,6 +421,8 @@ let rec div_int c1 c2 is_safe dbg = + Csequence(c1, raise_symbol dbg "caml_exn_Division_by_zero") + | (c1, Cconst_int (1, _)) -> + c1 ++ | (c1, Cconst_int (-1, _)) -> ++ Cop(Cdivi, [c1; c2], dbg) + | (Cconst_int (n1, _), Cconst_int (n2, _)) -> + Cconst_int (n1 / n2, dbg) + | (c1, Cconst_int (n, _)) when n <> min_int -> +diff --git a/asmcomp/sw_64/CSE.ml b/asmcomp/sw_64/CSE.ml +new file mode 100644 +index 0000000..c0d2785 +--- /dev/null ++++ b/asmcomp/sw_64/CSE.ml +@@ -0,0 +1,38 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++(* CSE for the sw_64 *) ++ ++open Arch ++open Mach ++open CSEgen ++ ++class cse = object (_self) ++ ++inherit cse_generic as super ++ ++method! class_of_operation op = ++ match op with ++ | Ispecific(Imultaddf _ | Imultsubf _) -> Op_pure ++ | _ -> super#class_of_operation op ++ ++method! is_cheap_operation op = ++ match op with ++ | Iconst_int n -> n <= 0xFFn && n >= 0n ++ | _ -> false ++ ++end ++ ++let fundecl f = ++ (new cse)#fundecl f +diff --git a/asmcomp/sw_64/NOTES.md b/asmcomp/sw_64/NOTES.md +new file mode 100644 +index 0000000..5355f36 +--- /dev/null ++++ b/asmcomp/sw_64/NOTES.md +@@ -0,0 +1,5 @@ ++# Supported platforms ++ ++SW_64 in 64-bit mode ++ ++Debian architecture name: `sw_64` +diff --git a/asmcomp/sw_64/arch.ml b/asmcomp/sw_64/arch.ml +new file mode 100644 +index 0000000..4f03675 +--- /dev/null ++++ b/asmcomp/sw_64/arch.ml +@@ -0,0 +1,94 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++(* Specific operations for the sw_64 processor *) ++ ++open Format ++ ++(* Machine-specific command-line options *) ++ ++let command_line_options = [] ++ ++(* Specific operations *) ++ ++type specific_operation = ++ | Imultaddf of bool (* multiply, optionally negate, and add *) ++ | Imultsubf of bool (* multiply, optionally negate, and subtract *) ++ | Ireloadgp of bool ++ ++(* Addressing modes *) ++ ++type addressing_mode = ++ | Iindexed of int (* reg + displ *) ++ ++ ++let is_immediate n = ++ (n <= 0xFF) && (n >= 0) (* simple operation format is zero-extend *) ++ ++(* Sizes, endianness *) ++ ++let big_endian = false ++ ++let size_addr = 8 ++let size_int = 8 ++let size_float = 8 ++ ++let allow_unaligned_access = false ++ ++(* Behavior of division *) ++ ++let division_crashes_on_overflow = false ++ ++(* Operations on addressing modes *) ++ ++let identity_addressing = Iindexed 0 ++ ++let offset_addressing addr delta = ++ match addr with ++ | Iindexed n -> Iindexed(n + delta) ++ ++let num_args_addressing = function ++ | Iindexed _ -> 1 ++ ++(* Printing operations and addressing modes *) ++ ++let print_addressing printreg addr ppf arg = ++ match addr with ++ | Iindexed n -> ++ let idx = if n <> 0 then Printf.sprintf " + %i" n else "" in ++ fprintf ppf "%a%s" printreg arg.(0) idx ++ ++let print_specific_operation printreg op ppf arg = ++ match op with ++ | Imultaddf false -> ++ fprintf ppf "%a *f %a +f %a" ++ printreg arg.(0) printreg arg.(1) printreg arg.(2) ++ | Imultaddf true -> ++ fprintf ppf "-f (%a *f %a +f %a)" ++ printreg arg.(0) printreg arg.(1) printreg arg.(2) ++ | Imultsubf false -> ++ fprintf ppf "%a *f %a -f %a" ++ printreg arg.(0) printreg arg.(1) printreg arg.(2) ++ | Imultsubf true -> ++ fprintf ppf "-f (%a *f %a -f %a)" ++ printreg arg.(0) printreg arg.(1) printreg arg.(2) ++ | Ireloadgp _ -> fprintf ppf "ldgp" ++ ++(* Specific operations that are pure *) ++ ++let operation_is_pure _ = true ++ ++(* Specific operations that can raise *) ++ ++let operation_can_raise _ = false +diff --git a/asmcomp/sw_64/emit.mlp b/asmcomp/sw_64/emit.mlp +new file mode 100644 +index 0000000..b3fe795 +--- /dev/null ++++ b/asmcomp/sw_64/emit.mlp +@@ -0,0 +1,785 @@ ++(**************************************************************************) ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++ ++(* Emission of sw_64 assembly code *) ++ ++open Cmm ++open Arch ++open Proc ++open Reg ++open Mach ++open Linear ++open Emitaux ++open Emitenv ++ ++(* Layout of the stack. The stack is kept 16-aligned. *) ++(* Communicate live registers at call points to the assembler *) ++let frame_size env = ++ let size = ++ env.stack_offset + (* Trap frame, outgoing parameters *) ++ size_int * env.f.fun_num_stack_slots.(0) + (* Local int variables *) ++ size_float * env.f.fun_num_stack_slots.(1) + (* Local float variables *) ++ (if env.f.fun_contains_calls then size_addr else 0) (* Return address *) ++ in ++ Misc.align size 16 ++ ++let slot_offset env loc cls = ++ match loc with ++ | Local n -> ++ ("$sp", ++ if cls = 0 ++ then env.stack_offset + n * size_int ++ else env.stack_offset + env.f.fun_num_stack_slots.(0) * size_int + n * size_float) ++ | Incoming n -> ++ ("$sp", frame_size env + n) ++ | Outgoing n -> ++ ("$sp", n) ++ | Domainstate n -> ++ ("$12", n + Domainstate.(idx_of_field Domain_extra_params) * 8) ++ ++(* Output a symbol *) ++ ++let emit_symbol s = ++ emit_symbol '$' s ++ ++(* Output a label *) ++ ++let emit_label lbl = ++ emit_string ".L"; emit_int lbl ++ ++(* Section switching *) ++ ++let data_space = ++ ".section .data" ++ ++let code_space = ++ ".section .text" ++ ++let rodata_space = ++ ".section .rodata" ++ ++(* Names for special regs *) ++ ++let reg_tmp = phys_reg 23 ++let reg_tmp2 = phys_reg 24 ++let reg_domain_state_ptr = phys_reg 20 ++let reg_trap = phys_reg 21 ++let reg_alloc_ptr = phys_reg 22 ++ ++(* Output a pseudo-register *) ++ ++let reg_name = function ++ | {loc = Reg r} -> register_name r ++ | _ -> Misc.fatal_error "Emit.reg_name" ++ ++let emit_reg r = ++ emit_string (reg_name r) ++ ++let is_immediate_ldst n = ++ (n <= 0x7FFF) && (n >= -0x8000) (* load/store operation format *) ++ ++let emit_intconst dst n = ++ if n >= -0x8000n && n <= 0x7FFFn then begin ++ ` ldi {emit_reg dst}, {emit_nativeint n}\n`; ++ end else begin ++ let n1 = Nativeint.logand 0xffffn n in ++ let n1 = ++ if n1 < 0x8000n then n1 ++ else Nativeint.logor 0xffffffffffff0000n n1 in (*sign-extend*) ++ let n = Nativeint.shift_right_logical n 16 in ++ let n = ++ if n1 >= 0n then n ++ else Nativeint.add n 1n in ++ let n2 = Nativeint.logand 0xffffn n in ++ let n2 = ++ if n2 < 0x8000n then n2 ++ else Nativeint.logor 0xffffffffffff0000n n2 in (*sign-extend*) ++ let n = Nativeint.shift_right_logical n 16 in ++ let n = ++ if n2 >= 0n then n ++ else Nativeint.add n 1n in ++ let n3 = Nativeint.logand 0xffffn n in ++ let n3 = ++ if n3 < 0x8000n then n3 ++ else Nativeint.logor 0xffffffffffff0000n n3 in (*sign-extend*) ++ let n = Nativeint.shift_right_logical n 16 in ++ let n = ++ if n3 >= 0n then n ++ else Nativeint.add n 1n in ++ let n4 = Nativeint.logand 0xffffn n in ++ let n4 = ++ if n4 < 0x8000n then n4 ++ else Nativeint.logor 0xffffffffffff0000n n4 in (*sign-extend*) ++ if n3=0n && n4=0n then begin ++ ` ldih {emit_reg dst}, {emit_nativeint n2}($31)\n`; ++ ` ldi {emit_reg dst}, {emit_nativeint n1}({emit_reg dst})\n`; ++ end else begin ++ ` ldih {emit_reg dst}, {emit_nativeint n4}($31)\n`; ++ ` ldi {emit_reg dst}, {emit_nativeint n3}({emit_reg dst})\n`; ++ ` sll {emit_reg dst}, 32, {emit_reg dst}\n`; ++ ` ldih {emit_reg dst}, {emit_nativeint n2}({emit_reg dst})\n`; ++ ` ldi {emit_reg dst}, {emit_nativeint n1}({emit_reg dst})\n`; ++ end ++ end ++ ++(* Adjust sp by the given byte amount *) ++ ++let emit_stack_adjustment = function ++ | 0 -> () ++ | n when is_immediate n -> ++ ` addl $sp, {emit_int n}, $sp\n`; ++ cfi_adjust_cfa_offset (-n) ++ | n when is_immediate (-n) -> ++ ` subl $sp, {emit_int (-n)}, $sp\n`; ++ cfi_adjust_cfa_offset (-n) ++ | n -> ++ emit_intconst reg_tmp (Nativeint.of_int n); ++ ` addl $sp, {emit_reg reg_tmp}, $sp\n`; ++ cfi_adjust_cfa_offset (-n) ++ ++(* Adjust stack_offset and emit corresponding CFI directive *) ++ ++let emit_mem_op ?(base = "$sp") op src ofs = ++ if is_immediate_ldst ofs then ++ ` {emit_string op} {emit_string src}, {emit_int ofs}({emit_string base})\n` ++ else begin ++ emit_intconst reg_tmp (Nativeint.of_int ofs); ++ ` addl {emit_string base}, {emit_reg reg_tmp}, {emit_reg reg_tmp}\n`; ++ ` {emit_string op} {emit_string src}, {emit_reg reg_tmp}\n` ++ end ++let emit_store ?base src ofs = ++ emit_mem_op ?base "stl" (reg_name src) ofs ++ ++let emit_load ?base dst ofs = ++ emit_mem_op ?base "ldl" (reg_name dst) ofs ++ ++let emit_float_load ?base dst ofs = ++ emit_mem_op ?base "fldd" (reg_name dst) ofs ++ ++let emit_float_store ?base src ofs = ++ emit_mem_op ?base "fstd" (reg_name src) ofs ++ ++let emit_float_test cmp ~arg = ++let negated = ++ match cmp with ++ | CFneq | CFnlt | CFngt | CFnle | CFnge -> true ++ | CFeq | CFlt | CFgt | CFle | CFge -> false ++in ++begin match cmp with ++| CFeq | CFneq -> ` fcmpeq {emit_reg arg.(0)}, {emit_reg arg.(1)}, $f23\n` ++| CFlt | CFnlt -> ` fcmplt {emit_reg arg.(0)}, {emit_reg arg.(1)}, $f23\n` ++| CFgt | CFngt -> ` fcmplt {emit_reg arg.(1)}, {emit_reg arg.(0)}, $f23\n` ++| CFle | CFnle -> ` fcmple {emit_reg arg.(0)}, {emit_reg arg.(1)}, $f23\n` ++| CFge | CFnge -> ` fcmple {emit_reg arg.(1)}, {emit_reg arg.(0)}, $f23\n` ++end; ++negated ++ ++(* Record live pointers at call points *) ++ ++let record_frame_label env live dbg = ++ let lbl = new_label () in ++ let live_offset = ref [] in ++ Reg.Set.iter ++ (function ++ {typ = Val; loc = Reg r} -> ++ live_offset := (r lsl 1) + 1 :: !live_offset ++ | {typ = Val; loc = Stack s} as reg -> ++ let (base, ofs) = slot_offset env s (register_class reg) in ++ assert (base = "$sp"); ++ live_offset := ofs :: !live_offset ++ | {typ = Addr} as r -> ++ Misc.fatal_error ("bad GC root " ^ Reg.name r) ++ | _ -> () ++ ) ++ live; ++ record_frame_descr ~label:lbl ~frame_size:(frame_size env) ++ ~live_offset:!live_offset dbg; ++ lbl ++ ++let record_frame env live dbg = ++ let lbl = record_frame_label env live dbg in ++ `{emit_label lbl}:\n` ++ ++let emit_call_gc gc = ++ `{emit_label gc.gc_lbl}:\n`; ++ ` call $26, caml_call_gc\n`; ++ `{emit_label gc.gc_frame_lbl}:\n`; ++ ` lbr {emit_label gc.gc_return_lbl}\n` ++ ++let bound_error_label env dbg = ++ if !Clflags.debug || env.bound_error_sites = [] then begin ++ let lbl_bound_error = new_label() in ++ let lbl_frame = record_frame_label env Reg.Set.empty (Dbg_other dbg) in ++ env.bound_error_sites <- ++ { bd_lbl = lbl_bound_error; ++ bd_frame = lbl_frame; } :: env.bound_error_sites; ++ lbl_bound_error ++ end else ++ let bd = List.hd env.bound_error_sites in ++ bd.bd_lbl ++ ++let emit_call_bound_error bd = ++ `{emit_label bd.bd_lbl}:\n`; ++ ` call $26, {emit_string "caml_ml_array_bound_error"}\n`; ++ `{emit_label bd.bd_frame}:\n` ++ ++(* Names for various instructions *) ++ ++let name_for_intop = function ++ | Iadd -> "addl" ++ | Isub -> "subl" ++ | Imul -> "mull" ++ | Idiv -> "divl" ++ | Iand -> "and" ++ | Ior -> "or" ++ | Ixor -> "xor" ++ | Ilsl -> "sll" ++ | Ilsr -> "srl" ++ | Iasr -> "sra" ++ | Imod -> "reml" ++ | _ -> Misc.fatal_error "Emit.Intop" ++ ++let name_for_intop_imm = function ++ | Iadd -> "addl" ++ | Isub -> "subl" ++ | Imul -> "mull" ++ | Idiv -> "divl" ++ | Iand -> "and" ++ | Ior -> "or" ++ | Ixor -> "xor" ++ | Ilsl -> "sll" ++ | Ilsr -> "srl" ++ | Iasr -> "sra" ++ | Imod -> "reml" ++ | _ -> Misc.fatal_error "Emit.Intop_imm" ++ ++let name_for_int_comparison = function ++ | Isigned Ceq -> "cmpeq", true | Isigned Cne -> "cmpeq", false ++ | Isigned Cle -> "cmple", true | Isigned Cgt -> "cmple", false ++ | Isigned Clt -> "cmplt", true | Isigned Cge -> "cmplt", false ++ | Iunsigned Ceq -> "cmpeq", true | Iunsigned Cne -> "cmpeq", false ++ | Iunsigned Cle -> "cmpule", true | Iunsigned Cgt -> "cmpule", false ++ | Iunsigned Clt -> "cmpult", true | Iunsigned Cge -> "cmpult", false ++ ++let name_for_floatop1 = function ++ | Inegf -> "fneg" ++ | Iabsf -> "fabs" ++ | _ -> Misc.fatal_error "Emit.Iopf1" ++ ++let name_for_floatop2 = function ++ | Iaddf -> "faddd" ++ | Isubf -> "fsubd" ++ | Imulf -> "fmuld" ++ | Idivf -> "fdivd" ++ | _ -> Misc.fatal_error "Emit.Iopf2" ++ ++let name_for_specific = function ++ | Imultaddf false -> "fmad" ++ | Imultaddf true -> "fnmad" ++ | Imultsubf false -> "fmsd" ++ | Imultsubf true -> "fnmsd" ++ | _ -> Misc.fatal_error "Emit.IopSpec" ++ ++(* Output the assembly code for an instruction *) ++ ++let emit_instr env i = ++ emit_debug_info i.dbg; ++ match i.desc with ++ Lend -> () ++ | Lprologue -> ++ assert (env.f.fun_prologue_required); ++ let n = frame_size env in ++ emit_stack_adjustment (-n); ++ if env.f.fun_contains_calls then begin ++ ` stl $26, {emit_int( n - size_addr)}($sp)\n`; ++ cfi_offset ~reg:26 ~offset:(-8) ++ end ++ | Lop(Imove | Ispill | Ireload) -> ++ let src = i.arg.(0) and dst = i.res.(0) in ++ if src.loc <> dst.loc then begin ++ match (src, dst) with ++ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Reg _} -> ++ ` mov {emit_reg src}, {emit_reg dst}\n` ++ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = Float} -> ++ ` fmov {emit_reg src}, {emit_reg dst}\n` ++ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = (Val | Int | Addr)} -> ++ ` fimovd {emit_reg src}, {emit_reg dst}\n` ++ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Stack s} -> ++ let (base, ofs) = slot_offset env s (register_class dst) in ++ emit_store ~base src ofs ++ | {loc = Reg _; typ = Float}, {loc = Stack s} -> ++ let (base, ofs) = slot_offset env s (register_class dst) in ++ emit_float_store ~base src ofs ++ | {loc = Stack s; typ = (Val | Int | Addr)}, {loc = Reg _} -> ++ let (base, ofs) = slot_offset env s (register_class src) in ++ emit_load ~base dst ofs ++ | {loc = Stack s; typ = Float}, {loc = Reg _} -> ++ let (base, ofs) = slot_offset env s (register_class src) in ++ emit_float_load ~base dst ofs ++ | {loc = Stack _}, {loc = Stack _} ++ | {loc = Unknown}, _ | _, {loc = Unknown} -> ++ Misc.fatal_error "Emit: Imove" ++ end ++ | Lop(Iconst_int n) -> ++ emit_intconst i.res.(0) n ++ | Lop(Iconst_float f) -> ++ let lbl = new_label() in ++ env.float_literals <- {fl=f; lbl} :: env.float_literals; ++ ` ldi {emit_reg reg_tmp}, {emit_label lbl} \n`; ++ ` fldd {emit_reg i.res.(0)}, 0({emit_reg reg_tmp})\n` ++ | Lop(Iconst_symbol s) -> ++ ` ldi {emit_reg i.res.(0)}, {emit_symbol s} \n` ++ | Lop(Icall_ind) -> ++ ` mov {emit_reg i.arg.(0)}, $27\n`; ++ ` jmp $26, ({emit_reg i.arg.(0)})\n`; ++ record_frame env i.live (Dbg_other i.dbg); ++ ` ldgp $gp, 0($26)\n` ++ | Lop(Icall_imm {func}) -> ++ (* Adjust sp by the given byte amount *) ++ (* ` addpi 0x1, $26\n`; ++ ` lbr {emit_symbol func}\n`; ++ *) ++ ` call $26, {emit_symbol func}\n`; ++ record_frame env i.live (Dbg_other i.dbg); ++ ` ldgp $gp, 0($26)\n` ++ | Lop(Itailcall_ind) -> ++ let n = frame_size env in ++ if env.f.fun_contains_calls then ` ldl $26, {emit_int( n - size_addr)}($sp)\n`; ++ emit_stack_adjustment n; ++ ` mov {emit_reg i.arg.(0)}, $27\n`; ++ ` jmp ({emit_reg i.arg.(0)})\n` ++ | Lop(Itailcall_imm {func}) -> ++ if func = env.f.fun_name then begin ++ (* ` lbr {emit_label env.f.fun_tailrec_entry_point_label}\n` *) ++ ` call $31, ({emit_label env.f.fun_tailrec_entry_point_label})\n` ++ end else begin ++ let n = frame_size env in ++ if env.f.fun_contains_calls then ` ldl $26, {emit_int( n - size_addr)}($sp)\n`; ++ emit_stack_adjustment n; ++ (*` lbr {emit_symbol func}\n`*) ++ ` call $31, {emit_symbol func}\n`; ++ end ++ | Lop(Iextcall{func; alloc = true}) -> ++ ` ldi $25, {emit_symbol func}\n`; (*$25: sw_64.S ARG for caml_c_call*) ++ ` call $26, caml_c_call\n`; ++ record_frame env i.live (Dbg_other i.dbg); ++ ` ldgp $gp, 0($11)\n` ++ | Lop(Iextcall{func; alloc = false}) -> ++ ` call $26, {emit_symbol func}\n`; ++ ` ldgp $gp, 0($26)\n`; ++ | Lop(Istackoffset n) -> ++ assert (n mod 16 = 0); ++ emit_stack_adjustment (-n); ++ env.stack_offset <- env.stack_offset + n ++ | Lop(Iload(Single, Iindexed ofs, _mut)) -> ++ ` flds {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`; ++ ` fcvtds {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` ++ | Lop(Iload(Byte_signed, Iindexed ofs, _mut)) -> ++ ` ldbu {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`; ++ ` slll {emit_reg i.res.(0)}, 56, {emit_reg i.res.(0)}\n`; ++ ` sral {emit_reg i.res.(0)}, 56, {emit_reg i.res.(0)}\n` ++ | Lop(Iload(Sixteen_signed, Iindexed ofs, _mut)) -> ++ ` ldhu {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`; ++ ` slll {emit_reg i.res.(0)}, 48, {emit_reg i.res.(0)}\n`; ++ ` sral {emit_reg i.res.(0)}, 48, {emit_reg i.res.(0)}\n` ++ | Lop(Iload(Thirtytwo_unsigned, Iindexed ofs, _mut)) -> ++ ` ldw {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`; ++ ` extlw {emit_reg i.res.(0)}, 0, {emit_reg i.res.(0)}\n` ++ | Lop(Iload(chunk, Iindexed ofs, _mut)) -> ++ let instr = ++ match chunk with ++ | Byte_unsigned -> "ldbu" ++ | Byte_signed -> assert false ++ | Sixteen_unsigned -> "ldhu" ++ | Sixteen_signed -> assert false ++ | Thirtytwo_unsigned -> assert false ++ | Thirtytwo_signed -> "ldw" ++ | Word_int | Word_val -> "ldl" ++ | Single -> assert false ++ | Double -> "fldd" ++ in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n` ++ | Lop(Istore(Single, Iindexed ofs, _)) -> ++ (* ft0 is marked as destroyed for this operation *) ++ ` fcvtsd {emit_reg i.arg.(0)}, $f30\n`; ++ ` fsts $f30, {emit_int ofs}({emit_reg i.arg.(1)})\n` ++ | Lop(Istore(chunk, Iindexed ofs,_)) -> ++ let instr = ++ match chunk with ++ | Byte_unsigned | Byte_signed -> "stb" ++ | Sixteen_unsigned | Sixteen_signed -> "sth" ++ | Thirtytwo_unsigned | Thirtytwo_signed -> "stw" ++ | Word_int | Word_val -> "stl" ++ | Single -> assert false ++ | Double -> "fstd" ++ in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n` ++ | Lop(Ialloc {bytes; dbginfo}) -> ++ let lbl_frame_lbl = record_frame_label env i.live (Dbg_alloc dbginfo) in ++ let lbl_after_alloc = new_label () in ++ let lbl_call_gc = new_label () in ++ let n = -bytes in ++ let offset = Domainstate.(idx_of_field Domain_young_limit) * 8 in ++ if is_immediate n then ++ ` addl {emit_reg reg_alloc_ptr}, {emit_int n}, {emit_reg reg_alloc_ptr}\n` ++ else if is_immediate (-n) then ++ ` subl {emit_reg reg_alloc_ptr}, {emit_int (-n)}, {emit_reg reg_alloc_ptr}\n` ++ else begin ++ emit_intconst reg_tmp (Nativeint.of_int n); ++ ` addl {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}, {emit_reg reg_alloc_ptr}\n` ++ end; ++ ` ldl {emit_reg reg_tmp}, {emit_int offset}({emit_reg reg_domain_state_ptr})\n`; ++ ` cmpult {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}, {emit_reg reg_tmp}\n`; ++ ` bne {emit_reg reg_tmp}, {emit_label lbl_call_gc}\n`; ++ `{emit_label lbl_after_alloc}:\n`; ++ ` addl {emit_reg reg_alloc_ptr},{emit_int size_addr}, {emit_reg i.res.(0)}\n`; ++ env.call_gc_sites <- ++ { gc_lbl = lbl_call_gc; ++ gc_return_lbl = lbl_after_alloc; ++ gc_frame_lbl = lbl_frame_lbl } :: env.call_gc_sites ++ | Lop(Ipoll { return_label }) -> ++ let lbl_frame_lbl = record_frame_label env i.live (Dbg_alloc []) in ++ let lbl_after_poll = match return_label with ++ | None -> new_label() ++ | Some(lbl) -> lbl in ++ let lbl_call_gc = new_label () in ++ let offset = Domainstate.(idx_of_field Domain_young_limit) * 8 in ++ ` ldl {emit_reg reg_tmp}, {emit_int offset}({emit_reg reg_domain_state_ptr})\n`; ++ begin match return_label with ++ | None -> ` cmpult {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}, {emit_reg reg_tmp}\n`; ++ ` bne {emit_reg reg_tmp}, {emit_label lbl_call_gc}\n`; ++ `{emit_label lbl_after_poll}:\n`; ++ | Some lbl -> ` cmpult {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}, {emit_reg reg_tmp}\n`; ++ ` beq {emit_reg reg_tmp}, {emit_label lbl}\n`; ++ ` jmp {emit_label lbl_call_gc}\n` ++ end; ++ env.call_gc_sites <- ++ { gc_lbl = lbl_call_gc; ++ gc_return_lbl = lbl_after_poll; ++ gc_frame_lbl = lbl_frame_lbl } :: env.call_gc_sites ++ | Lop(Iintop(Icomp cmp)) -> ++ begin match cmp with ++ | Isigned Clt -> ++ ` cmplt {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n` ++ | Isigned Cge -> ++ ` cmplt {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n`; ++ ` xor {emit_reg i.res.(0)}, 1, {emit_reg i.res.(0)}\n`; ++ | Isigned Cgt -> ++ ` cmplt {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}, {emit_reg i.res.(0)}\n` ++ | Isigned Cle -> ++ ` cmplt {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}, {emit_reg i.res.(0)}\n`; ++ ` xor {emit_reg i.res.(0)}, 1, {emit_reg i.res.(0)}\n`; ++ | Isigned Ceq | Iunsigned Ceq -> ++ ` subl {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n`; ++ ` cmpult {emit_reg i.res.(0)}, 1, {emit_reg i.res.(0)}\n` ++ | Isigned Cne | Iunsigned Cne -> ++ ` subl {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n`; ++ ` cmpult $31, {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` ++ | Iunsigned Clt -> ++ ` cmpult {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n` ++ | Iunsigned Cge -> ++ ` cmpult {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n`; ++ ` xor {emit_reg i.res.(0)}, 1, {emit_reg i.res.(0)}\n`; ++ | Iunsigned Cgt -> ++ ` cmpult {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}, {emit_reg i.res.(0)}\n` ++ | Iunsigned Cle -> ++ ` cmpult {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}, {emit_reg i.res.(0)}\n`; ++ ` xor {emit_reg i.res.(0)}, 1, {emit_reg i.res.(0)}\n`; ++ end ++ | Lop(Iintop (Icheckbound)) -> ++ let lbl = bound_error_label env i.dbg in ++ ` cmpule {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg reg_tmp}\n`; ++ ` bne {emit_reg reg_tmp}, {emit_label lbl}\n` ++ | Lop(Iintop Imulh) -> ++ (*sometimes emit_reg i.arg.(1) and emit_reg i.res.(0) are same registers,*) ++ (*we should get reg_tmp and reg_tmp2 firstly incase that i.arg.(0) and i.arg.(0) are contaminated*) ++ ` srll {emit_reg i.arg.(0)}, 63, {emit_reg reg_tmp}\n`; ++ ` seleq {emit_reg reg_tmp}, 0, {emit_reg i.arg.(1)}, {emit_reg reg_tmp}\n`; ++ ` srll {emit_reg i.arg.(1)}, 63, {emit_reg reg_tmp2}\n`; ++ ` seleq {emit_reg reg_tmp2}, 0, {emit_reg i.arg.(0)}, {emit_reg reg_tmp2}\n`; ++ ` umulh {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n`; ++ ` subl {emit_reg i.res.(0)}, {emit_reg reg_tmp}, {emit_reg i.res.(0)}\n`; ++ ` subl {emit_reg i.res.(0)}, {emit_reg reg_tmp2}, {emit_reg i.res.(0)}\n` ++ | Lop(Iintop op) -> ++ let instr = name_for_intop op in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n` ++ | Lop(Iintop_imm(Iadd, n)) -> ++ if is_immediate n then ++ ` addl {emit_reg i.arg.(0)}, {emit_int n}, {emit_reg i.res.(0)}\n` ++ else if is_immediate (-n) then ++ ` subl {emit_reg i.arg.(0)}, {emit_int (-n)}, {emit_reg i.res.(0)}\n` ++ else begin ++ emit_intconst reg_tmp (Nativeint.of_int n); ++ ` addl {emit_reg i.arg.(0)}, {emit_reg reg_tmp}, {emit_reg i.res.(0)} \n` ++ end ++ | Lop(Iintop_imm(op, n)) -> ++ if is_immediate n then ++ let instri = name_for_intop_imm op in ++ ` {emit_string instri} {emit_reg i.arg.(0)}, {emit_int n}, {emit_reg i.res.(0)}\n` ++ else begin ++ let instr = name_for_intop_imm op in ++ emit_intconst reg_tmp (Nativeint.of_int n); ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_reg reg_tmp}, {emit_reg i.res.(0)} \n` ++ end ++ | Lop(Inegf | Iabsf as op) -> ++ let instr = name_for_floatop1 op in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_reg i.res.(0)}\n` ++ | Lop(Iaddf | Isubf | Imulf | Idivf as op) -> ++ let instr = name_for_floatop2 op in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.res.(0)}\n` ++ | Lop(Ifloatofint) -> ++ ` ifmovd {emit_reg i.arg.(0)}, $f30\n`; ++ ` fcvtld $f30, {emit_reg i.res.(0)}\n`; ++ | Lop(Iintoffloat) -> ++ ` fcvtdl_z {emit_reg i.arg.(0)}, $f30\n`; ++ ` fimovd $f30, {emit_reg i.res.(0)}\n`; ++ | Lop(Iopaque) -> ++ assert (i.arg.(0).loc = i.res.(0).loc) ++ | Lop(Ispecific Ireloadgp marked_r26) -> ++ ` ldgp $gp, 0($26)\n`; ++ if marked_r26 then ++ ` bic $gp, 1, $gp\n` ++ | Lop(Ispecific sop) -> ++ let instr = name_for_specific sop in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(2)}, {emit_reg i.res.(0)}\n` ++ | Lreloadretaddr -> ++ let n = frame_size env in ++ ` ldl $26, {emit_int( n - size_addr)}($sp)\n` ++ | Lreturn -> ++ let n = frame_size env in ++ emit_stack_adjustment n; ++ ` ret $31,($26),0x1\n` ++ | Llabel lbl -> ++ `{emit_label lbl}:\n` ++ | Lbranch lbl -> ++ ` lbr {emit_label lbl}\n` ++ | Lcondbranch(tst, lbl) -> ++ begin match tst with ++ | Itruetest -> ++ ` bne {emit_reg i.arg.(0)}, {emit_label lbl}\n` ++ | Ifalsetest -> ++ ` beq {emit_reg i.arg.(0)}, {emit_label lbl}\n` ++ | Iinttest cmp -> ++ let (comp, test) = name_for_int_comparison cmp in ++ ` {emit_string comp} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg reg_tmp}\n`; ++ if test then ++ ` bne {emit_reg reg_tmp}, {emit_label lbl}\n` ++ else ++ ` beq {emit_reg reg_tmp}, {emit_label lbl}\n` ++ | Iinttest_imm _ -> ++ Misc.fatal_error "Emit.emit_instr (Iinttest_imm _)" ++ | Ifloattest cmp -> ++ let negated = emit_float_test cmp ~arg:i.arg in ++ let branch = ++ if negated ++ then "beq" ++ else "bne" ++ in ++ ` fimovd $f23, {emit_reg reg_tmp}\n`; ++ ` {emit_string branch} {emit_reg reg_tmp}, {emit_label lbl}\n` ++ | Ioddtest -> ++ ` blbs {emit_reg i.arg.(0)}, {emit_label lbl}\n`; ++ | Ieventest -> ++ ` blbc {emit_reg i.arg.(0)}, {emit_label lbl}\n`; ++ end ++ | Lcondbranch3(lbl0, lbl1, lbl2) -> ++ ` subl {emit_reg i.arg.(0)}, 1, {emit_reg reg_tmp}\n`; ++ begin match lbl0 with ++ | None -> () ++ | Some lbl -> ` blt {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end; ++ begin match lbl1 with ++ | None -> () ++ | Some lbl -> ` beq {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end; ++ begin match lbl2 with ++ | None -> () ++ | Some lbl -> `bgt {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end ++ | Lswitch jumptbl -> ++ (* t0 is marked as destroyed for this operation *) ++ let lbl = new_label() in ++ ` ldi {emit_reg reg_tmp}, {emit_label lbl}\n`; ++ ` s4addl {emit_reg i.arg.(0)}, {emit_reg reg_tmp}, {emit_reg reg_tmp}\n`; ++ ` mov {emit_reg reg_tmp}, $27\n`; ++ ` jmp $31, ({emit_reg reg_tmp})\n`; ++ `{emit_label lbl}:\n`; ++ for i = 0 to Array.length jumptbl - 1 do ++ `lbr {emit_label jumptbl.(i)}\n` ++ done ++ | Lentertrap -> ++ ` ldgp $gp,0($26)\n` ++ | Ladjust_trap_depth { delta_traps } -> ++ (* each trap occupes 16 bytes on the stack *) ++ let delta = 16 * delta_traps in ++ cfi_adjust_cfa_offset delta; ++ env.stack_offset <- env.stack_offset + delta ++ | Lpushtrap {lbl_handler} -> ++ ` ldi {emit_reg reg_tmp}, {emit_label lbl_handler}\n`; ++ ` subl $sp, 16, $sp\n`; ++ cfi_adjust_cfa_offset 16; ++ env.stack_offset <- env.stack_offset + 16; ++ emit_store reg_tmp size_addr; ++ emit_store reg_trap 0; ++ ` mov $sp, {emit_reg reg_trap}\n` ++ | Lpoptrap -> ++ emit_load reg_trap 0; ++ ` addl $sp, 16, $sp\n`; ++ cfi_adjust_cfa_offset (-16); ++ env.stack_offset <- env.stack_offset - 16 ++ | Lraise k -> ++ begin match k with ++ | Lambda.Raise_regular -> ++ let offset = Domainstate.(idx_of_field Domain_backtrace_pos) * 8 in ++ ` stl $31, {emit_int offset}({emit_reg reg_domain_state_ptr})\n`; ++ ` call $26, {emit_string "caml_raise_exn"}\n`; ++ record_frame env Reg.Set.empty (Dbg_raise i.dbg) ++ | Lambda.Raise_reraise -> ++ ` call $26, {emit_string "caml_raise_exn"}\n`; ++ record_frame env Reg.Set.empty (Dbg_raise i.dbg) ++ | Lambda.Raise_notrace -> ++ ` mov {emit_reg reg_trap}, $sp\n`; ++ emit_load reg_tmp size_addr; ++ emit_load reg_trap 0; ++ ` addl $sp, 16, $sp\n`; ++ ` mov {emit_reg reg_tmp}, $26\n`; ++ ` ret $31, ({emit_reg reg_tmp}), 0x1\n` ++ end ++ ++(* Emit a sequence of instructions *) ++ ++let rec emit_all env = function ++ | {desc = Lend} -> () | i -> emit_instr env i; emit_all env i.next ++ ++(* Emission of a function declaration *) ++ ++let fundecl fundecl = ++ let env = mk_env fundecl in ++ ` .globl {emit_symbol fundecl.fun_name}\n`; ++ ` .type {emit_symbol fundecl.fun_name}, @function\n`; ++ ` {emit_string code_space}\n`; ++ ` .align 2\n`; ++ `{emit_symbol fundecl.fun_name}:\n`; ++ ` .set noreorder\n`; ++ ` ldgp $gp, 0($27)\n`; ++ ` .set reorder\n`; ++ emit_debug_info fundecl.fun_dbg; ++ cfi_startproc(); ++ emit_all env fundecl.fun_body; ++ List.iter emit_call_gc env.call_gc_sites; ++ List.iter emit_call_bound_error env.bound_error_sites; ++ cfi_endproc(); ++ ` .size {emit_symbol fundecl.fun_name}, .-{emit_symbol fundecl.fun_name}\n`; ++ (* Emit the float literals *) ++ if env.float_literals <> [] || env.int_literals <> [] || env.symbol_literals <> [] then begin ++ ` {emit_string rodata_space}\n`; ++ ` .align 3\n`; ++ List.iter ++ (fun {fl; lbl} -> ++ `{emit_label lbl}:\n`; ++ emit_float64_directive ".quad" fl) ++ env.float_literals; ++ List.iter ++ (fun {n; n_lbl} -> ++ `{emit_label n_lbl}: .quad {emit_nativeint n}\n`) ++ env.int_literals; ++ List.iter ++ (fun {sym; lbl} -> ++ `{emit_label lbl}: .quad {emit_symbol sym}\n`) ++ env.symbol_literals ++ end ++ ++(* Emission of data *) ++ ++let declare_global_data s = ++ ` .globl {emit_symbol s}\n`; ++ ` .type {emit_symbol s}, @object\n` ++ ++let emit_item = function ++ | Cglobal_symbol s -> ++ declare_global_data s ++ | Cdefine_symbol s -> ++ `{emit_symbol s}:\n`; ++ | Cint8 n -> ++ ` .byte {emit_int n}\n` ++ | Cint16 n -> ++ ` .short {emit_int n}\n` ++ | Cint32 n -> ++ ` .long {emit_nativeint n}\n` ++ | Cint n -> ++ ` .quad {emit_nativeint n}\n` ++ | Csingle f -> ++ emit_float32_directive ".long" (Int32.bits_of_float f) ++ | Cdouble f -> ++ emit_float64_directive ".quad" (Int64.bits_of_float f) ++ | Csymbol_address s -> ++ ` .quad {emit_symbol s}\n` ++ | Cstring s -> ++ emit_bytes_directive " .byte " s ++ | Cskip n -> ++ if n > 0 then ` .space {emit_int n}\n` ++ | Calign n -> ++ ` .align {emit_int (Misc.log2 n)}\n` ++ ++let data l = ++ ` {emit_string data_space}\n`; ++ List.iter emit_item l ++ ++(* Beginning / end of an assembly file *) ++ ++let begin_assembly() = ++ if !Clflags.dlcode || !Clflags.pic_code then ` \n`; ++ ` .file \"\"\n`; (* PR#7073 *) ++ reset_debug_info (); ++ (* Emit the beginning of the segments *) ++ let lbl_begin = Compilenv.make_symbol (Some "data_begin") in ++ ` {emit_string data_space}\n`; ++ declare_global_data lbl_begin; ++ `{emit_symbol lbl_begin}:\n`; ++ let lbl_begin = Compilenv.make_symbol (Some "code_begin") in ++ ` {emit_string code_space}\n`; ++ declare_global_data lbl_begin; ++ `{emit_symbol lbl_begin}:\n` ++ ++let end_assembly() = ++ ` {emit_string code_space}\n`; ++ let lbl_end = Compilenv.make_symbol (Some "code_end") in ++ declare_global_data lbl_end; ++ `{emit_symbol lbl_end}:\n`; ++ ` .long 0\n`; ++ ` {emit_string data_space}\n`; ++ let lbl_end = Compilenv.make_symbol (Some "data_end") in ++ declare_global_data lbl_end; ++ ` .quad 0\n`; (* PR#6329 *) ++ `{emit_symbol lbl_end}:\n`; ++ ` .quad 0\n`; ++ (* Emit the frame descriptors *) ++ ` {emit_string data_space}\n`; (* not rodata because relocations inside *) ++ let lbl = Compilenv.make_symbol (Some "frametable") in ++ declare_global_data lbl; ++ `{emit_symbol lbl}:\n`; ++ emit_frames ++ { efa_code_label = (fun l -> ` .quad {emit_label l}\n`); ++ efa_data_label = (fun l -> ` .quad {emit_label l}\n`); ++ efa_8 = (fun n -> ` .byte {emit_int n}\n`); ++ efa_16 = (fun n -> ` .short {emit_int n}\n`); ++ efa_32 = (fun n -> ` .long {emit_int32 n}\n`); ++ efa_word = (fun n -> ` .quad {emit_int n}\n`); ++ efa_align = (fun n -> ` .align {emit_int (Misc.log2 n)}\n`); ++ efa_label_rel = (fun lbl ofs -> ++ ` .long ({emit_label lbl} - .) + {emit_int32 ofs}\n`); ++ efa_def_label = (fun l -> `{emit_label l}:\n`); ++ efa_string = (fun s -> emit_bytes_directive " .byte " (s ^ "\000")) ++ } +diff --git a/asmcomp/sw_64/proc.ml b/asmcomp/sw_64/proc.ml +new file mode 100644 +index 0000000..d776b9c +--- /dev/null ++++ b/asmcomp/sw_64/proc.ml +@@ -0,0 +1,310 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++(* Description of the sw_64 *) ++ ++open Misc ++open Cmm ++open Reg ++open Arch ++open Mach ++ ++(* Instruction selection *) ++ ++let word_addressed = false ++ ++(* Registers available for register allocation *) ++ ++(* Integer register map ++ -------------------- ++ ++ $0 v0 ++ $1 - $8 t0 - t7 function results(tmp) ++ $9 - $14 s0 - s5 save reg ++ $15 s6/fp s6/fp ++ $16 - $21 a0 - a5 (tmp) ++ $22 - $25 t8 - t11 tmp reg ++ $26 ra return address(save) ++ $27 pv/t12 (tmp) ++ $28 at preserve for asm(tmp) ++ $29 gp global ptr(tmp) ++ $30 sp stack ptr(save) ++ $31 zero 0 ++ ++ Floating-point register map ++ --------------------------- ++ ++ $f0 - $f1 100 - 101 f0 for complex real, f1 for complex imag ++ $f2 - $f9 102 - 109 save reg ++ $f10 - $f15 110 - 115 tmp reg ++ $f16 - $f21 116 - 121 (tmp) ++ $f22 - $f30 122 - 130 tmp reg ++ $f31 131 0 ++ ++*) ++ ++let int_reg_name = ++ [| "$1";"$2";"$3";"$4"; "$5"; "$6"; "$7"; "$8"; "$22"; "$23"; (* 0 - 9 *) ++ "$9"; "$10"; "$11"; (* 10 - 12 *) ++ "$0"; "$16"; "$17"; "$18"; "$19"; "$20"; "$21"; (* 13 - 19 *) ++ "$12"; "$13"; "$14"; (* 20 - 22 *) ++ "$24"; "$25" |] (* 23 - 24 *) ++ ++let float_reg_name = ++ [| "$f10"; "$f11"; "$f12"; "$f13"; "$f14"; "$f15"; (* 0 - 5 *) ++ "$f22"; "$f23"; "$f24"; "$f25"; "$f26"; "$f27"; "$f28"; "$f29"; "$f30"; (* 6 - 14 *) ++ "$f2"; "$f3"; "$f4"; "$f5"; "$f6"; "$f7"; "$f8"; "$f9"; (* 15 - 22 *) ++ "$f0"; "$f1"; "$f16"; "$f17"; "$f18"; "$f19"; "$f20"; "$f21"; (* 23 - 30 *) ++ "$f31"|] ++ ++let num_register_classes = 2 ++ ++let register_class r = ++ match r.typ with ++ | Val | Int | Addr -> 0 ++ | Float -> 1 ++ ++let num_available_registers = [| 20; 31 |] ++ ++let first_available_register = [| 0; 100 |] ++ ++let register_name r = ++ if r < 100 then int_reg_name.(r) else float_reg_name.(r - 100) ++ ++let rotate_registers = true ++ ++(* Representation of hard registers by pseudo-registers *) ++ ++let hard_int_reg = ++ let v = Array.make 25 Reg.dummy in ++ for i = 0 to 24 do ++ v.(i) <- Reg.at_location Int (Reg i) ++ done; ++ v ++ ++let hard_float_reg = ++ let v = Array.make 32 Reg.dummy in ++ for i = 0 to 31 do ++ v.(i) <- Reg.at_location Float (Reg(100 + i)) ++ done; ++ v ++ ++let all_phys_regs = ++ Array.append hard_int_reg hard_float_reg ++ ++let phys_reg n = ++ if n < 100 then hard_int_reg.(n) else hard_float_reg.(n - 100) ++ ++let stack_slot slot ty = ++ Reg.at_location ty (Stack slot) ++ ++(* Calling conventions *) ++ ++let size_domainstate_args = 64 * size_int ++ ++let calling_conventions ++ first_int last_int first_float last_float make_stack first_stack arg = ++ let loc = Array.make (Array.length arg) Reg.dummy in ++ let int = ref first_int in ++ let float = ref first_float in ++ let ofs = ref first_stack in ++ for i = 0 to Array.length arg - 1 do ++ match arg.(i) with ++ | Val | Int | Addr as ty -> ++ if !int <= last_int then begin ++ loc.(i) <- phys_reg !int; ++ incr int; ++ incr float ++ end else begin ++ loc.(i) <- stack_slot (make_stack !ofs) ty; ++ ofs := !ofs + size_int ++ end ++ | Float -> ++ if !float <= last_float then begin ++ loc.(i) <- phys_reg !float; ++ incr float; ++ incr int ++ end else begin ++ loc.(i) <- stack_slot (make_stack !ofs) Float; ++ ofs := !ofs + size_float ++ end ++ done; ++ (loc, Misc.align (max 0 !ofs) 16) (* Keep stack 16-aligned. *) ++ ++let incoming ofs = ++ if ofs >= 0 ++ then Incoming ofs ++ else Domainstate (ofs + size_domainstate_args) ++let outgoing ofs = ++ if ofs >= 0 ++ then Outgoing ofs ++ else Domainstate (ofs + size_domainstate_args) ++let not_supported _ = fatal_error "Proc.loc_results: cannot call" ++ ++let max_arguments_for_tailcalls = 6 (* in regs *) + 64 (* in domain state *) ++ ++(* OCaml calling convention: ++ first integer args in a0 .. a7 ++ first float args in fa0 .. fa7 ++ remaining args in domain state area, then on stack. ++ Return values in v0 or fv0, fv1*) ++ ++let loc_arguments arg = ++ calling_conventions 14 19 125 130 outgoing (- size_domainstate_args) arg ++ ++let loc_parameters arg = ++ let (loc, _ofs) = ++ calling_conventions 14 19 125 130 incoming (- size_domainstate_args) arg ++ in ++ loc ++ ++let loc_results res = ++ let (loc, _ofs) = ++ calling_conventions 13 13 123 124 not_supported 0 res ++ in ++ loc ++ ++(* C calling convention: ++ first integer args in a0 .. a7 ++ first float args in fa0 .. fa7 ++ remaining args on stack. ++ A FP argument can be passed in an integer register if all FP registers ++ are exhausted but integer registers remain. ++ Return values in a0 .. a1 or fa0 .. fa1. *) ++ ++let external_calling_conventions ++ first_int last_int first_float last_float make_stack arg = ++ let loc = Array.make (Array.length arg) [| Reg.dummy |] in ++ let int = ref first_int in ++ let float = ref first_float in ++ let ofs = ref 0 in ++ for i = 0 to Array.length arg - 1 do ++ match arg.(i) with ++ | Val | Int | Addr as ty -> ++ if !int <= last_int then begin ++ loc.(i) <- [| phys_reg !int |]; ++ incr int; ++ incr float ++ end else begin ++ loc.(i) <- [| stack_slot (make_stack !ofs) ty |]; ++ ofs := !ofs + size_int ++ end ++ | Float -> ++ if !float <= last_float then begin ++ loc.(i) <- [| phys_reg !float |]; ++ incr float; ++ incr int ++ end else begin ++ loc.(i) <- [| stack_slot (make_stack !ofs) Float |]; ++ ofs := !ofs + size_float ++ end ++ done; ++ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *) ++ ++let loc_external_arguments ty_args = ++ let arg = Cmm.machtype_of_exttype_list ty_args in ++ external_calling_conventions 14 19 125 130 outgoing arg ++ ++let loc_external_results res = ++ let (loc, _ofs) = calling_conventions 13 13 123 124 not_supported 0 res ++ in loc ++ ++(* Exceptions are in a0 *) ++let loc_exn_bucket = phys_reg 13 ++ ++(* Volatile registers: none *) ++ ++let regs_are_volatile _ = false ++ ++(* Registers destroyed by operations *) ++ ++let destroyed_at_c_call = ++ (* s0-s5 and fs0-fs7 are callee-save. However s2 needs to be in this ++ list since it is clobbered by caml_c_call itself. *) ++ Array.of_list(List.map phys_reg ++ [0;1;2;3;4;5;6;7;8;9;12;13;14;15;16;17;18;19; ++ 100;101;102;103;104;105;106;107;108;109;110;111;112;113;114; ++ 123;124;125;126;127;128;129;130]) ++ ++let destroyed_at_alloc = ++ if !Clflags.dlcode then Array.map phys_reg [|0;1;2;3;4;5;6;7;8;9|] ++ else [| |] ++ ++let destroyed_at_oper = function ++ | Iop(Icall_ind | Icall_imm _ | Iextcall{alloc = true; _}) -> all_phys_regs ++ | Iop(Iextcall{alloc = false; _}) -> destroyed_at_c_call ++ | Iop(Ialloc _) | Iop(Ipoll _) -> destroyed_at_alloc ++ | Iop(Istore(Single, _, _)) -> [| phys_reg 114 |] ++ | Iop(Ifloatofint | Iintoffloat) -> [| phys_reg 114 |] ++ | Iswitch _ -> [| phys_reg 23 |] ++ | Iop(Iintop Imulh) -> [| phys_reg 23; phys_reg 24|] ++ | _ -> [||] ++ ++let destroyed_at_raise = all_phys_regs ++ ++let destroyed_at_reloadretaddr = [| |] ++ ++(* Maximal register pressure *) ++ ++let safe_register_pressure = function ++ | Iextcall _ -> 3 ++ | _ -> 20 ++ ++let max_register_pressure = function ++ | Iextcall _ -> [| 3; 8 |] ++ | _ -> [| 20; 31 |] ++ ++(* Layout of the stack *) ++ ++let frame_required fd = ++ fd.fun_contains_calls ++ || fd.fun_num_stack_slots.(0) > 0 ++ || fd.fun_num_stack_slots.(1) > 0 ++ ++let prologue_required fd = ++ frame_required fd ++ ++let int_dwarf_reg_numbers = ++ [| 10; 11; 12; 13; 14; 15; 16; 17; ++ 18; 19; 20; 21; 22; 23; 24; 25; ++ 7; 28; 29; 30; 31; ++ 8; ++ 5; 6; ++ 9; 26; 27; ++ |] ++ ++let float_dwarf_reg_numbers = ++ [| 32; 33; 34; 35; 36; 37; 38; 39; ++ 40; 41; ++ 42; 43; 44; 45; 46; 47; 48; 49; ++ 50; 51; 52; 53; 54; 55; 56; 57; ++ 58; 59; ++ 60; 61; 62; 63; ++ |] ++ ++let dwarf_register_numbers ~reg_class = ++ match reg_class with ++ | 0 -> int_dwarf_reg_numbers ++ | 1 -> float_dwarf_reg_numbers ++ | _ -> Misc.fatal_errorf "Bad register class %d" reg_class ++ ++let stack_ptr_dwarf_register_number = 2 ++ ++(* Calling the assembler *) ++ ++let assemble_file infile outfile = ++ Ccomp.command ++ (Config.asm ^ " -o " ^ Filename.quote outfile ^ " " ^ Filename.quote infile) ++ ++let init () = () +diff --git a/asmcomp/sw_64/reload.ml b/asmcomp/sw_64/reload.ml +new file mode 100644 +index 0000000..f0d0530 +--- /dev/null ++++ b/asmcomp/sw_64/reload.ml +@@ -0,0 +1,18 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++(* Reloading for the sw_64 *) ++ ++let fundecl f = ++ (new Reloadgen.reload_generic)#fundecl f +diff --git a/asmcomp/sw_64/scheduling.ml b/asmcomp/sw_64/scheduling.ml +new file mode 100644 +index 0000000..b1ebd8e +--- /dev/null ++++ b/asmcomp/sw_64/scheduling.ml +@@ -0,0 +1,21 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++(* Instruction scheduling for the sw_64 *) ++ ++open! Schedgen (* to create a dependency *) ++ ++(* Scheduling is turned off. *) ++ ++let fundecl f = f +diff --git a/asmcomp/sw_64/selection.ml b/asmcomp/sw_64/selection.ml +new file mode 100644 +index 0000000..2d4c50c +--- /dev/null ++++ b/asmcomp/sw_64/selection.ml +@@ -0,0 +1,65 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* *) ++(* *) ++(* Copyright © 2008-2023 SW_64 *) ++(* *) ++(* 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. *) ++(* *) ++(**************************************************************************) ++(* Instruction selection for the sw_64 processor *) ++ ++open Cmm ++open Arch ++open Mach ++ ++(* Instruction selection *) ++ ++class selector = object ++ ++inherit Selectgen.selector_generic as super ++ ++(* sw_64 does not support immediate operands for comparison operators *) ++method is_immediate_test _cmp _n = false ++ ++method! is_immediate op n = ++ match op with ++ | Iadd -> is_immediate n ++ | Iand | Ior | Ixor -> n >= 0 && n <= 255 ++ (* sub immediate is turned into add immediate opposite *) ++ | Isub -> is_immediate (-n) ++ | _ -> super#is_immediate op n ++ ++method select_addressing _ = function ++ | Cop(Cadda, [arg; Cconst_int (n, _)], _) when is_immediate n -> ++ (Iindexed n, arg) ++ | Cop(Cadda, [arg1; Cop(Caddi, [arg2; Cconst_int (n, _)], _)], dbg) ++ when is_immediate n -> ++ (Iindexed n, Cop(Caddi, [arg1; arg2], dbg)) ++ | arg -> ++ (Iindexed 0, arg) ++ ++method! select_operation op args dbg = ++ match (op, args) with ++ (* Recognize (neg-)mult-add and (neg-)mult-sub instructions *) ++ | (Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3]) ++ | (Caddf, [arg3; Cop(Cmulf, [arg1; arg2], _)]) -> ++ (Ispecific (Imultaddf false), [arg1; arg2; arg3]) ++ | (Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3]) -> ++ (Ispecific (Imultsubf false), [arg1; arg2; arg3]) ++ | (Cnegf, [Cop(Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) -> ++ (Ispecific (Imultsubf true), [arg1; arg2; arg3]) ++ | (Cnegf, [Cop(Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) -> ++ (Ispecific (Imultaddf true), [arg1; arg2; arg3]) ++ | _ -> ++ super#select_operation op args dbg ++ ++end ++ ++let fundecl ~future_funcnames f = ++ (new selector)#emit_fundecl ~future_funcnames f +diff --git a/build-aux/config.guess b/build-aux/config.guess +index e94095c..229fbac 100755 +--- a/build-aux/config.guess ++++ b/build-aux/config.guess +@@ -285,6 +285,38 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in + mips:OSF1:*.*) + echo mips-dec-osf1 + exit ;; ++ sw_64:OSF1:*:*) ++ case $UNAME_RELEASE in ++ *4.0) ++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ++ ;; ++ *5.*) ++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ++ ;; ++ esac ++ # According to Compaq, /usr/sbin/psrinfo has been available on ++ # OSF/1 and Tru64 systems produced since 1995. I hope that ++ # covers most systems running today. This code pipes the CPU ++ # types through head -n 1, so we only detect the type of CPU 0. ++ SW_64_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The sw_64 \(.*\) processor.*$/\1/p' | head -n 1` ++ case "$SW_64_CPU_TYPE" in ++ "SW6A (1621)") ++ UNAME_MACHINE=sw6a ;; ++ "SW6B (3231)") ++ UNAME_MACHINE=sw6b ;; ++ "SW8A (6432)") ++ UNAME_MACHINE=sw8a ;; ++ esac ++ # A Pn.n version is a patched version. ++ # A Vn.n version is a released version. ++ # A Tn.n version is a released field test version. ++ # A Xn.n version is an unreleased experimental baselevel. ++ # 1.2 uses "1.2" for uname -r. ++ echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" ++ # Reset EXIT trap before exiting to avoid spurious non-zero exit code. ++ exitcode=$? ++ trap '' 0 ++ exit $exitcode ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) +@@ -925,6 +957,16 @@ EOF + UNAME_MACHINE=aarch64_be + echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" + exit ;; ++ sw_64:Linux:*:*) ++ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in ++ SW6A) UNAME_MACHINE=sw6a ;; ++ SW6B) UNAME_MACHINE=sw6b ;; ++ SW8A) UNAME_MACHINE=sw8a ;; ++ esac ++ objdump --private-headers /bin/sh | grep -q ld.so.1 ++ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi ++ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" ++ exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in + EV5) UNAME_MACHINE=alphaev5 ;; +diff --git a/build-aux/config.sub b/build-aux/config.sub +index 3d9a8dc..45a7679 100755 +--- a/build-aux/config.sub ++++ b/build-aux/config.sub +@@ -1104,6 +1104,9 @@ case $cpu-$vendor in + xscale-* | xscalee[bl]-*) + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` + ;; ++ sw_64-*) ++ cpu=sw_64 ++ ;; + arm64-*) + cpu=aarch64 + ;; +@@ -1163,6 +1166,7 @@ case $cpu-$vendor in + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ + | alphapca5[67] | alpha64pca5[67] \ ++ | sw_64 | sw6a | sw6b | sw8a \ + | am33_2.0 \ + | amdgcn \ + | arc | arceb \ +diff --git a/build-aux/ocaml_version.m4 b/build-aux/ocaml_version.m4 +index 8c69847..f29182b 100644 +--- a/build-aux/ocaml_version.m4 ++++ b/build-aux/ocaml_version.m4 +@@ -36,7 +36,7 @@ m4_define([OCAML__VERSION_MINOR], [14]) + m4_define([OCAML__VERSION_PATCHLEVEL], [1]) + # Note that the OCAML__VERSION_EXTRA string defined below is always empty + # for officially-released versions of OCaml. +-m4_define([OCAML__VERSION_EXTRA], []) ++m4_define([OCAML__VERSION_EXTRA], [sw1.0.0]) + + # The OCAML__VERSION_EXTRA_PREFIX macro defined below should be a + # single character: +@@ -45,7 +45,7 @@ m4_define([OCAML__VERSION_EXTRA], []) + # and with an empty OCAML__VERSION_EXTRA string; + # Or [+] to give more info about this specific version. + # Development releases, for instance, should use a [+] prefix. +-m4_define([OCAML__VERSION_EXTRA_PREFIX], [+]) ++m4_define([OCAML__VERSION_EXTRA_PREFIX], [-]) + m4_define([OCAML__VERSION_SHORT], [OCAML__VERSION_MAJOR.OCAML__VERSION_MINOR]) + # The OCAML__VERSION below must be in the format specified in stdlib/sys.mli + m4_define([OCAML__VERSION], +diff --git a/configure b/configure +index 2c956effa2a506354adb6450fc1fc83de6b4455f..3d48794af8e372a69cb668b774889175c0152903 100755 +GIT binary patch +delta 121 +zcmeyeUwOq*<%SlnD#j%Nj%$pvN#wIy^T{0VI`extern_sp. */ + #define ACCU_REG asm("%x21") + #define JUMPTBL_BASE_REG asm("%x22") + #endif ++#ifdef __sw_64__ ++#define PC_REG asm("$9") ++#define SP_REG asm("$10") ++#define ACCU_REG asm("$11") ++#define JUMPTBL_BASE_REG asm("$12") ++#endif + #endif + + #ifdef DEBUG +diff --git a/runtime/ints.c b/runtime/ints.c +index c9584e4..67473c7 100644 +--- a/runtime/ints.c ++++ b/runtime/ints.c +@@ -472,7 +472,14 @@ CAMLprim_int64_2(div)(int64_t dividend, int64_t divisor) + if (divisor == 0) caml_raise_zero_divide(); + /* PR#4740: on some processors, division crashes on overflow. + Implement the same behavior as for type "int". */ +- if (dividend == ((int64_t)1 << 63) && divisor == -1) return dividend; ++ if (dividend == ((int64_t)1 << 63) && divisor == -1) ++ { ++#ifdef __sw_64__ ++ return 0; ++#else ++ return dividend; ++#endif ++ } + return dividend / divisor; + } + +@@ -749,7 +756,14 @@ CAMLprim value caml_nativeint_div(value v1, value v2) + if (divisor == 0) caml_raise_zero_divide(); + /* PR#4740: on some processors, modulus crashes if division overflows. + Implement the same behavior as for type "int". */ +- if (dividend == Nativeint_min_int && divisor == -1) return v1; ++ if (dividend == Nativeint_min_int && divisor == -1) ++ { ++#ifdef __sw_64__ ++ return caml_copy_nativeint(0); ++#else ++ return v1; ++#endif ++ } + return caml_copy_nativeint(dividend / divisor); + } + +diff --git a/runtime/signals_osdep.h b/runtime/signals_osdep.h +index 9874bf6..de3d6a4 100644 +--- a/runtime/signals_osdep.h ++++ b/runtime/signals_osdep.h +@@ -436,6 +436,25 @@ + #define CONTEXT_SP (context->uc_mcontext.gregs[15]) + #define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr) + ++/****************** SW64, Linux */ ++#elif defined(TARGET_sw_64) && defined(SYS_linux) ++ ++ #include ++#define DECLARE_SIGNAL_HANDLER(name) \ ++ static void name(int sig, siginfo_t * info, ucontext_t * context) ++ #define SET_SIGACT(sigact,name) \ ++ sigact.sa_handler = (void (*)(int, siginfo_t*, void*)) (name); \ ++ sigact.sa_flags = SA_SIGINFO ++ ++ typedef long context_reg; ++ #define CONTEXT_PC (context->uc_mcontext.sc_pc) ++ #define CONTEXT_SP (context->uc_mcontext.sc_regs[30]) ++ #define CONTEXT_EXCEPTION_POINTER (context->uc_mcontext.sc_regs[13]) ++ #define CONTEXT_C_ARG_1 (context->uc_mcontext.sc_regs[16]) ++ #define CONTEXT_YOUNG_PTR (context->uc_mcontext.sc_regs[14]) ++ #define CONTEXT_FAULTING_ADDRESS ((char *) info->si_addr) ++ #define RETURN_AFTER_STACK_OVERFLOW ++ + /******************** Default */ + + #else +diff --git a/runtime/sw_64.S b/runtime/sw_64.S +new file mode 100644 +index 0000000..0d4b180 +--- /dev/null ++++ b/runtime/sw_64.S +@@ -0,0 +1,517 @@ ++/**************************************************************************/ ++/* */ ++/* OCaml */ ++/* */ ++/* */ ++/* */ ++/* Copyright © 20082023 SW64 / ++/* */ ++/* */ ++/* 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, SW64 processor, 64-bit mode */ ++/* Must be preprocessed by cpp */ ++ ++#include "caml/m.h" ++ ++/* Special registers */ ++ ++#define DOMAIN_STATE_PTR $12 ++#define TRAP_PTR $13 ++#define ALLOC_PTR $14 ++ ++#define TMP $24 ++#define ARG $25 ++ ++#define STORE stl ++#define LOAD ldl ++ ++/* Support for CFI directives */ ++ ++#if defined(ASM_CFI_SUPPORTED) ++#define CFI_STARTPROC .cfi_startproc ++#define CFI_ENDPROC .cfi_endproc ++#define CFI_ADJUST(n) .cfi_adjust_cfa_offset n ++#define CFI_REGISTER(r1,r2) .cfi_register r1,r2 ++#define CFI_OFFSET(r,n) .cfi_offset r,n ++#else ++#define CFI_STARTPROC ++#define CFI_ENDPROC ++#define CFI_ADJUST(n) ++#define CFI_REGISTER(r1,r2) ++#define CFI_OFFSET(r,n) ++#endif ++ ++.equ domain_curr_field, 0 ++.equ domain_curr_cnt, 0 ++#define DOMAIN_STATE(c_type, name) \ ++ .equ domain_field_caml_##name, domain_curr_field;\ ++ domain_curr_cnt = domain_curr_cnt+1;\ ++ domain_curr_field = domain_curr_cnt * 8; ++#include "../runtime/caml/domain_state.tbl" ++#undef DOMAIN_STATE ++ ++#define Caml_state(var) domain_field_caml_##var(DOMAIN_STATE_PTR) ++ ++#define FUNCTION(name) \ ++ .align 2; \ ++ .globl name; \ ++ .type name, @function; \ ++name:; \ ++ ++#define END_FUNCTION(name) \ ++ .size name, .-name ++ ++#if defined(__PIC__) ++#define PLT(r) %plt(r) ++#else ++#define PLT(r) r ++#endif ++ ++ .section .text ++/* Invoke the garbage collector. */ ++ ++ .globl caml_system__code_begin ++caml_system__code_begin: ++ ++FUNCTION(caml_call_gc) ++ CFI_STARTPROC ++.Lcaml_call_gc: ++ /* Record return address */ ++ STORE $26, 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, 20 allocatable int regs, ++ 23 caller-save float regs) * 8 */ ++ /* + 1 for alignment */ ++ CFI_OFFSET(26, -376) ++ CFI_OFFSET(15, -368) ++ ldi $sp, -376($sp) ++ CFI_ADJUST(376) ++ STORE $26, 0x0($sp) ++ STORE $15, 0x8($sp) ++ /* Save allocatable integer registers on the stack, ++ in the order given in proc.ml */ ++ STORE $1, 0x10($sp) ++ STORE $2, 0x18($sp) ++ STORE $3, 0x20($sp) ++ STORE $4, 0x28($sp) ++ STORE $5, 0x30($sp) ++ STORE $6, 0x38($sp) ++ STORE $7, 0x40($sp) ++ STORE $8, 0x48($sp) ++ STORE $22, 0x50($sp) ++ STORE $23, 0x58($sp) ++ STORE $9, 0x60($sp) ++ STORE $10, 0x68($sp) ++ STORE $11, 0x70($sp) ++ STORE $0, 0x78($sp) ++ STORE $16, 0x80($sp) ++ STORE $17, 0x88($sp) ++ STORE $18, 0x90($sp) ++ STORE $19, 0x98($sp) ++ STORE $20, 0xa0($sp) ++ STORE $21, 0xa8($sp) ++ /* Save caller-save floating-point registers on the stack ++ (callee-saves are preserved by caml_garbage_collection) */ ++ fstd $f10, 0xb0($sp) ++ fstd $f11, 0xb8($sp) ++ fstd $f12, 0xc0($sp) ++ fstd $f13, 0xc8($sp) ++ fstd $f14, 0xd0($sp) ++ fstd $f15, 0xd8($sp) ++ fstd $f22, 0xe0($sp) ++ fstd $f23, 0xe8($sp) ++ fstd $f24, 0xf0($sp) ++ fstd $f25, 0xf8($sp) ++ fstd $f26, 0x100($sp) ++ fstd $f27, 0x108($sp) ++ fstd $f28, 0x110($sp) ++ fstd $f29, 0x118($sp) ++ fstd $f30, 0x120($sp) ++ fstd $f0, 0x128($sp) ++ fstd $f1, 0x130($sp) ++ fstd $f16, 0x138($sp) ++ fstd $f17, 0x140($sp) ++ fstd $f18, 0x148($sp) ++ fstd $f19, 0x150($sp) ++ fstd $f20, 0x158($sp) ++ fstd $f21, 0x160($sp) ++ STORE $gp, 0x168($sp) ++ /* Rebuild $gp */ ++ br $27, $103 ++$103: ldgp $gp, 0($27) ++ /* Store pointer to saved integer registers in caml_gc_regs */ ++ addl $sp, 0x10, TMP ++ 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 */ ++ jmp $26, caml_garbage_collection ++ ldgp $gp, 0($26) ++ /* Restore registers */ ++ LOAD $1, 0x10($sp) ++ LOAD $2, 0x18($sp) ++ LOAD $3, 0x20($sp) ++ LOAD $4, 0x28($sp) ++ LOAD $5, 0x30($sp) ++ LOAD $6, 0x38($sp) ++ LOAD $7, 0x40($sp) ++ LOAD $8, 0x48($sp) ++ LOAD $22, 0x50($sp) ++ LOAD $23, 0x58($sp) ++ LOAD $9, 0x60($sp) ++ LOAD $10, 0x68($sp) ++ LOAD $11, 0x70($sp) ++ LOAD $0, 0x78($sp) ++ LOAD $16, 0x80($sp) ++ LOAD $17, 0x88($sp) ++ LOAD $18, 0x90($sp) ++ LOAD $19, 0x98($sp) ++ LOAD $20, 0xa0($sp) ++ LOAD $21, 0xa8($sp) ++ fldd $f10, 0xb0($sp) ++ fldd $f11, 0xb8($sp) ++ fldd $f12, 0xc0($sp) ++ fldd $f13, 0xc8($sp) ++ fldd $f14, 0xd0($sp) ++ fldd $f15, 0xd8($sp) ++ fldd $f22, 0xe0($sp) ++ fldd $f23, 0xe8($sp) ++ fldd $f24, 0xf0($sp) ++ fldd $f25, 0xf8($sp) ++ fldd $f26, 0x100($sp) ++ fldd $f27, 0x108($sp) ++ fldd $f28, 0x110($sp) ++ fldd $f29, 0x118($sp) ++ fldd $f30, 0x120($sp) ++ fldd $f0, 0x128($sp) ++ fldd $f1, 0x130($sp) ++ fldd $f16, 0x138($sp) ++ fldd $f17, 0x140($sp) ++ fldd $f18, 0x148($sp) ++ fldd $f19, 0x150($sp) ++ fldd $f20, 0x158($sp) ++ fldd $f21, 0x160($sp) ++ LOAD $gp, 0x168($sp) ++ /* Reload new allocation pointer */ ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ /* Free stack space and return to caller */ ++ LOAD $26, 0x0($sp) ++ LOAD $15, 0x8($sp) ++ ldi $sp, 376($sp) ++ CFI_ADJUST(-376) ++ ret $31,($26),0x1 ++ CFI_ENDPROC ++END_FUNCTION(caml_call_gc) ++ ++/* Call a C function from OCaml */ ++/* Function to bl is in ARG */ ++ ++FUNCTION(caml_c_call) ++ CFI_STARTPROC ++.Lcaml_c_call: ++ /* Preserve return address in callee-save register s2 */ ++ mov $26,$11 ++ /* Rebuild $gp */ ++ br $27, $104 ++$104: ldgp $gp, 0($27) ++ /* Record lowest stack address and return address */ ++ STORE $26, 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 */ ++ mov ARG, $27 ++ jmp $26, (ARG) ++ /* Reload alloc ptr */ ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ /* Restore $gp */ ++ /* Return */ ++ ret ($11) ++ CFI_ENDPROC ++END_FUNCTION(caml_c_call) ++ ++/* Raise an exception from OCaml */ ++FUNCTION(caml_raise_exn) ++ CFI_STARTPROC ++ ldgp $gp, 0($27) ++ /* Test if backtrace is active */ ++ LOAD TMP, Caml_state(backtrace_active) ++ bne TMP, 2f ++1: /* Cut stack at current trap handler */ ++ mov TRAP_PTR, $sp ++ /* Pop previous handler and jump to it */ ++ LOAD TMP, 8($sp) ++ LOAD TRAP_PTR, 0($sp) ++ addl $sp, 16, $sp ++ mov TMP, $26 ++ ret (TMP) ++2: /* Preserve exception bucket in callee-save register $16 */ ++ mov $0, $11 ++ /* Stash the backtrace */ ++ mov $0, $16 ++ mov $26, $17 ++ mov $sp, $18 ++ mov TRAP_PTR, $19 ++ jmp $26, caml_stash_backtrace ++ /* Restore exception bucket and raise */ ++ mov $11,$0 ++ br 1b ++ CFI_ENDPROC ++END_FUNCTION(caml_raise_exn) ++ ++ .globl caml_reraise_exn ++ .type caml_reraise_exn, @function ++ ++/* Raise an exception from C */ ++ ++FUNCTION(caml_raise_exception) ++ CFI_STARTPROC ++ ldgp $gp, 0($27) ++ /* Load the domain state ptr */ ++ mov $16, DOMAIN_STATE_PTR ++ /* Load the exception bucket */ ++ mov $17, $0 ++ mov $17, $16 ++ /* Reload trap ptr and alloc ptr */ ++ LOAD TRAP_PTR, Caml_state(exception_pointer) ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ /* Test if backtrace is active */ ++ LOAD TMP, Caml_state(backtrace_active) ++ bne TMP, 2f ++1: /* Cut stack at current trap handler */ ++ mov TRAP_PTR, $sp ++ /* Pop previous handler and jump to it */ ++ LOAD TMP, 8($sp) ++ LOAD TRAP_PTR, 0($sp) ++ addl $sp, 16, $sp ++ mov TMP, $26 ++ ret ($26) ++2: /* Preserve exception bucket in callee-save register s2 */ ++ mov $0, $11 ++ /* Stash the backtrace */ ++ mov $0, $16 ++ LOAD $17, Caml_state(last_return_address) ++ LOAD $18, Caml_state(bottom_of_stack) ++ mov TRAP_PTR, $19 ++ jmp $26, caml_stash_backtrace ++ /* Restore exception bucket and raise */ ++ mov $11, $0 ++ br 1b ++ CFI_ENDPROC ++END_FUNCTION(caml_raise_exception) ++ ++ ++/* Raise a Stack_overflow exception on return from segv_handler() ++ (in runtime/signals_nat.c). On entry, the stack is full, so we ++ cannot record a backtrace. ++ No CFI information here since this function disrupts the stack ++ backtrace anyway. ++ Since we have returned from the signal handler, the DOMAIN_STATE_PTR, ++ TRAP_PTR and ALLOC_PTR registers should have the same values ++ they had in the faulting OCaml code, so don't try to reload them. */ ++ ++FUNCTION(caml_stack_overflow) ++ /* Load the exception bucket */ ++ ldi $0, caml_exn_Stack_overflow ++ mov $0, $16 ++ /* Cut stack at current trap handler */ ++ mov TRAP_PTR, $sp ++ /* Pop previous handler and jump to it */ ++ ldl TMP, 0x8($sp) ++ ldl TRAP_PTR, 0($sp) ++ addl $sp, 16, $sp ++ mov TMP, $26 ++ jmp $31,(TMP) ++ END_FUNCTION(caml_stack_overflow) ++ ++/* Start the OCaml program */ ++ ++FUNCTION(caml_start_program) ++ CFI_STARTPROC ++ ldgp $gp, 0($27) ++ mov $16, TMP ++ ldi ARG, caml_program ++ /* Code shared with caml_callback* */ ++ /* Address of OCaml code to bl is in ARG */ ++ /* Arguments to the OCaml code are in a0 ... a7 */ ++.Ljump_to_caml: ++ /* Set up stack frame and save callee-save registers */ ++ CFI_OFFSET(26, -128) ++ CFI_OFFSET(15, -120) ++ ldi $sp, -128($sp) ++ CFI_ADJUST(128) ++ STORE $26, 0x0($sp) ++ STORE $15, 0x8($sp) ++ ldi $15, 0x0($sp) ++ STORE $9, 0x10($sp) ++ STORE $10, 0x18($sp) ++ STORE $11, 0x20($sp) ++ STORE $12, 0x28($sp) ++ STORE $13, 0x30($sp) ++ STORE $14, 0x38($sp) ++ fstd $f2, 0x40($sp) ++ fstd $f3, 0x48($sp) ++ fstd $f4, 0x50($sp) ++ fstd $f5, 0x58($sp) ++ fstd $f6, 0x60($sp) ++ fstd $f7, 0x68($sp) ++ fstd $f8, 0x70($sp) ++ fstd $f9, 0x78($sp) ++ ldi $sp, -32($sp) ++ CFI_ADJUST(32) ++ /* Load domain state pointer from argument */ ++ mov TMP, 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 */ ++ subl $sp, 16, $sp ++ CFI_ADJUST(16) ++ LOAD TMP, Caml_state(exception_pointer) ++ STORE TMP, 0($sp) ++ ldi TMP, .Ltrap_handler ++ STORE TMP, 8($sp) ++ mov $sp, TRAP_PTR ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++/* STORE $31, Caml_state(last_return_address) */ /*like loongarch,different from arm64 */ ++ mov ARG, $27 ++ call $26, (ARG) ++.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ ++ /* Reload $gp, masking off low bit in retaddr (might have been marked) */ ++ bic $26, 1, $26 ++ ldgp $gp, 4($26) ++ LOAD TMP, 0($sp) ++ STORE TMP, Caml_state(exception_pointer) ++ addl $sp, 16, $sp ++ CFI_ADJUST(-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) ++ addl $sp, 32, $sp ++ CFI_ADJUST(-32) ++ /* Update allocation pointer */ ++ STORE ALLOC_PTR, Caml_state(young_ptr) ++ /* reload callee-save registers and return */ ++ LOAD $9, 0x10($sp) ++ LOAD $10, 0x18($sp) ++ LOAD $11, 0x20($sp) ++ LOAD $12, 0x28($sp) ++ LOAD $13, 0x30($sp) ++ LOAD $14, 0x38($sp) ++ fldd $f2, 0x40($sp) ++ fldd $f3, 0x48($sp) ++ fldd $f4, 0x50($sp) ++ fldd $f5, 0x58($sp) ++ fldd $f6, 0x60($sp) ++ fldd $f7, 0x68($sp) ++ fldd $f8, 0x70($sp) ++ fldd $f9, 0x78($sp) ++ LOAD $26, 0x0($sp) ++ LOAD $15, 0x8($sp) ++ addl $sp, 128, $sp ++ CFI_ADJUST(-128) ++ ret $31,($26),0x1 ++ CFI_ENDPROC ++ .type .Lcaml_retaddr, @function ++ .size .Lcaml_retaddr, .-.Lcaml_retaddr ++END_FUNCTION(caml_start_program) ++ ++ .align 2 ++.Ltrap_handler: ++ ldgp $gp, 0($26) ++ STORE TRAP_PTR, Caml_state(exception_pointer) ++ or $0, 2, $0 ++ br .Lreturn_result ++ .type .Ltrap_handler, @function ++END_FUNCTION(.Ltrap_handler) ++ ++/* Callback from C to OCaml */ ++ ++FUNCTION(caml_callback_asm) ++ CFI_STARTPROC ++ ldgp $gp, 0($27) ++ /* Initial shuffling of arguments */ ++ /* a0 = Caml_state, a1 = closure, (a2) = args */ ++ mov $16, TMP ++ LOAD $16, 0($18) /* a0 = first arg */ ++ /* a1 = closure environment */ ++ LOAD ARG, 0($17) /* code pointer */ ++ br .Ljump_to_caml ++ CFI_ENDPROC ++END_FUNCTION(caml_callback_asm) ++ ++FUNCTION(caml_callback2_asm) ++ CFI_STARTPROC ++ ldgp $gp, 0($27) ++ /* Initial shuffling of arguments */ ++ /* a0 = Caml_state, a1 = closure, (a2) = args */ ++ mov $16, TMP ++ mov $17, ARG ++ LOAD $16, 0($18) ++ LOAD $17, 8($18) ++ mov ARG, $18 ++ ldi ARG, caml_apply2 ++ br .Ljump_to_caml ++ CFI_ENDPROC ++END_FUNCTION(caml_callback2_asm) ++ ++FUNCTION(caml_callback3_asm) ++ CFI_STARTPROC ++ ldgp $gp, 0($27) ++ /* Initial shuffling of arguments */ ++ /* a0 = Caml_state, a1 = closure, (a2) = args */ ++ mov $16, TMP ++ mov $17, $19 ++ LOAD $16, 0($18) ++ LOAD $17, 8($18) ++ LOAD $18, 16($18) ++ ldi ARG, caml_apply3 ++ br .Ljump_to_caml ++ CFI_ENDPROC ++END_FUNCTION(caml_callback3_asm) ++ ++FUNCTION(caml_ml_array_bound_error) ++ CFI_STARTPROC ++ br $27, $111 ++$111: ldgp $gp, 0($27) ++ /* Load address of [caml_array_bound_error] in ARG */ ++ ldi ARG, caml_array_bound_error ++ /* Call that function */ ++ br .Lcaml_c_call ++ CFI_ENDPROC ++END_FUNCTION(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 +diff --git a/testsuite/tests/basic/boxedints.ml b/testsuite/tests/basic/boxedints.ml +index a4361cc..80a5d92 100644 +--- a/testsuite/tests/basic/boxedints.ml ++++ b/testsuite/tests/basic/boxedints.ml +@@ -452,7 +452,7 @@ struct + 9, 127531236, -365; + 10, 1234567, 12345678; + 11, 1234567, -12345678]; +- test 12 (div min_int (of_int (-1))) min_int; ++ test 12 (div min_int (of_int (-1))) (of_int 0); + + testing_function "unsigned_div"; + List.iter +diff --git a/testsuite/tests/no-alias-deps/b.cmi b/testsuite/tests/no-alias-deps/b.cmi +new file mode 100644 +index 0000000..b0aedf1 +--- /dev/null ++++ b/testsuite/tests/no-alias-deps/b.cmi +@@ -0,0 +1 @@ ++Not a valid cmi file +diff --git a/testsuite/tools/asmgen_sw_64.S b/testsuite/tools/asmgen_sw_64.S +new file mode 100644 +index 0000000..8577241 +--- /dev/null ++++ b/testsuite/tools/asmgen_sw_64.S +@@ -0,0 +1,60 @@ ++/**************************************************************************/ ++/* */ ++/* OCaml */ ++/* */ ++/* Nicolas Ojeda Bar */ ++/* */ ++/* Copyright 2019 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. */ ++/* */ ++/**************************************************************************/ ++ ++ ++ .globl call_gen_code ++ .align 2 ++call_gen_code: ++ /* Set up stack frame and save callee-save registers */ ++ ldi $sp, -80($sp) ++ stl $26, 0($sp) ++ stl $9, 8($sp) ++ stl $10, 16($sp) ++ stl $11, 24($sp) ++ stl $12, 32($sp) ++ fstd $f2, 40($sp) ++ fstd $f3, 48($sp) ++ fstd $f4, 56($sp) ++ fstd $f5, 64($sp) ++ mov $16, $27 ++ mov $17, $16 ++ mov $18, $17 ++ mov $19, $18 ++ mov $20, $19 ++ call ($27) ++ ldl $26, 0($sp) ++ ldl $9, 8($sp) ++ ldl $10, 16($sp) ++ ldl $11, 24($sp) ++ ldl $12, 32($sp) ++ fldd $f2, 40($sp) ++ fldd $f3, 48($sp) ++ fldd $f4, 56($sp) ++ fldd $f5, 64($sp) ++ ldi $sp, 80($sp) ++ ret ($26) ++ ++ .globl caml_c_call ++ .align 2 ++caml_c_call: ++ ldi $sp, -16($sp) ++ stl $26, 0($sp) ++ stl $gp, 8($sp) ++ mov $25, $27 ++ call ($25) ++ ldl $26, 0($sp) ++ ldl $gp, 8($sp) ++ ldi $sp, 16($sp) ++ ret ($26) +-- +2.33.0 + diff --git a/ocaml.spec b/ocaml.spec index 4c670737f14f317472ee567ac91441d1fac2b6fc..4e09637ebc18fbe76f09a897cc213c560769790b 100644 --- a/ocaml.spec +++ b/ocaml.spec @@ -5,7 +5,7 @@ Name: ocaml Version: 4.14.1 -Release: 3 +Release: 4 Summary: OCaml compiler and programming environment License: LGPL-2.1-only URL: http://www.ocaml.org @@ -241,6 +241,9 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/ocaml/eventlog_metadata %{_mandir}/man3/* %changelog +* Thu Feb 20 2025 Liu Hanxu - 4.14.1-4 +- Add support for SW64 + * Fri Jun 07 2024 Wenlong Zhang - 4.14.1-3 - Add LoongArch native support for ocaml