diff --git a/.gitignore b/.gitignore index 33b0bdd..3505209 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,3 @@ /ocaml-*.tar.gz /ocaml-*.tar.xz /ocaml-*-refman.pdf -/4.11.0.tar.gz -/4.13.1.tar.gz diff --git a/0001-Don-t-add-rpaths-to-libraries.patch b/0001-Don-t-add-rpaths-to-libraries.patch index 6bf857a..6665489 100644 --- a/0001-Don-t-add-rpaths-to-libraries.patch +++ b/0001-Don-t-add-rpaths-to-libraries.patch @@ -1,25 +1,27 @@ -From 04e523e937625bf30d775681c11e00f6dc6fc00a Mon Sep 17 00:00:00 2001 +From 8ddacdf1283fe3d7054f51a4b764bc6b44d7a342 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 24 Jun 2014 10:00:15 +0100 -Subject: [PATCH 1/2] Don't add rpaths to libraries. +Subject: [PATCH 1/8] Don't add rpaths to libraries. --- - configure.ac | 2 -- - 1 file changed, 2 deletions(-) + tools/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) -diff --git a/configure.ac b/configure.ac -index 3754ad8a39..fb60c7c14c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1422,8 +1422,6 @@ AS_IF([test x"$enable_shared" != "xno"], - [[*-*-openbsd7.[3-9]|*-*-openbsd[89].*]], - [mkdll_flags="${mkdll_flags} -Wl,--no-execute-only"]) - oc_ldflags="$oc_ldflags -Wl,-E" -- rpath="-Wl,-rpath," -- mksharedlibrpath="-Wl,-rpath," - natdynlinkopts="-Wl,-E" - supports_shared_libraries=true], - [mkdll='shared-libs-not-available']) +diff --git a/tools/Makefile b/tools/Makefile +index 78d2a1068..fbec019ed 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -157,8 +157,8 @@ $(call byte_and_opt,ocamlmklib,ocamlmklibconfig.cmo config.cmo misc.cmo \ + ocamlmklibconfig.ml: ../config/Makefile Makefile + (echo 'let bindir = "$(BINDIR)"'; \ + echo 'let supports_shared_libraries = $(SUPPORTS_SHARED_LIBRARIES)';\ +- echo 'let default_rpath = "$(RPATH)"'; \ +- echo 'let mksharedlibrpath = "$(MKSHAREDLIBRPATH)"'; \ ++ echo 'let default_rpath = ""'; \ ++ echo 'let mksharedlibrpath = ""'; \ + echo 'let toolpref = "$(TOOLPREF)"'; \ + sed -n -e 's/^#ml //p' ../config/Makefile) \ + > ocamlmklibconfig.ml -- -2.52.0 +2.17.1 diff --git a/0002-configure-Allow-user-defined-C-compiler-flags.patch b/0002-configure-Allow-user-defined-C-compiler-flags.patch deleted file mode 100644 index 74de99b..0000000 --- a/0002-configure-Allow-user-defined-C-compiler-flags.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ef549c9a97838331877b139f407269db2a0fc691 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 29 May 2012 20:44:18 +0100 -Subject: [PATCH 2/2] configure: Allow user defined C compiler flags. - ---- - configure.ac | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index fb60c7c14c..f6a493ccf5 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3243,7 +3243,7 @@ AC_CONFIG_COMMANDS_PRE([ - [mkexedebugflag="${mkexe_ldflags_prefix}${mkexedebugflag}"]) - mkdll_ldflags="" - AS_IF([test -n "${LDFLAGS}"], -- [for flag in ${LDFLAGS}; do -+ [for flag in "${LDFLAGS}"; do - mkdll_ldflags="${mkdll_ldflags} ${mkexe_ldflags_prefix}${flag}" - done - mkdll_ldflags_exp="$mkdll_ldflags"]) --- -2.52.0 - diff --git a/0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch b/0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch new file mode 100644 index 0000000..9195dce --- /dev/null +++ b/0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch @@ -0,0 +1,240 @@ +From 118057a71576cb39d71633bf80a37815bf4ff932 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 29 May 2012 20:40:36 +0100 +Subject: [PATCH 2/8] ocamlbyteinfo, ocamlplugininfo: Useful utilities from + Debian, sent upstream. + +See: +http://git.debian.org/?p=pkg-ocaml-maint/packages/ocaml.git;a=tree;f=debian/ocamlbyteinfo;hb=HEAD +--- + ocamlbyteinfo.ml | 101 +++++++++++++++++++++++++++++++++++++++++ + ocamlplugininfo.ml | 109 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 210 insertions(+) + create mode 100644 ocamlbyteinfo.ml + create mode 100644 ocamlplugininfo.ml + +diff --git a/ocamlbyteinfo.ml b/ocamlbyteinfo.ml +new file mode 100644 +index 000000000..0a537e4d5 +--- /dev/null ++++ b/ocamlbyteinfo.ml +@@ -0,0 +1,101 @@ ++(***********************************************************************) ++(* *) ++(* Objective Caml *) ++(* *) ++(* Xavier Leroy, projet Gallium, INRIA Rocquencourt *) ++(* *) ++(* Copyright 2009 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the GNU Library General Public License, with *) ++(* the special exception on linking described in file ../../LICENSE. *) ++(* *) ++(***********************************************************************) ++ ++(* $Id$ *) ++ ++(* Dumps a bytecode binary file *) ++ ++open Sys ++open Dynlinkaux ++ ++let input_stringlist ic len = ++ let get_string_list sect len = ++ let rec fold s e acc = ++ if e != len then ++ if sect.[e] = '\000' then ++ fold (e+1) (e+1) (String.sub sect s (e-s) :: acc) ++ else fold s (e+1) acc ++ else acc ++ in fold 0 0 [] ++ in ++ let sect = Bytes.create len in ++ let _ = really_input ic sect 0 len in ++ get_string_list (Bytes.to_string sect) len ++ ++let print = Printf.printf ++let perr s = ++ Printf.eprintf "%s\n" s; ++ exit(1) ++let p_title title = print "%s:\n" title ++ ++let p_section title format pdata = function ++ | [] -> () ++ | l -> ++ p_title title; ++ List.iter ++ (fun (name, data) -> print format (pdata data) name) ++ l ++ ++let p_list title format = function ++ | [] -> () ++ | l -> ++ p_title title; ++ List.iter ++ (fun name -> print format name) ++ l ++ ++let _ = ++ try ++ let input_name = Sys.argv.(1) in ++ let ic = open_in_bin input_name in ++ Bytesections.read_toc ic; ++ List.iter ++ (fun section -> ++ try ++ let len = Bytesections.seek_section ic section in ++ if len > 0 then match section with ++ | "CRCS" -> ++ p_section ++ "Imported Units" ++ "\t%s\t%s\n" ++ Digest.to_hex ++ (input_value ic : (string * Digest.t) list) ++ | "DLLS" -> ++ p_list ++ "Used Dlls" "\t%s\n" ++ (input_stringlist ic len) ++ | "DLPT" -> ++ p_list ++ "Additional Dll paths" ++ "\t%s\n" ++ (input_stringlist ic len) ++ | "PRIM" -> ++ let prims = (input_stringlist ic len) in ++ print "Uses unsafe features: "; ++ begin match prims with ++ [] -> print "no\n" ++ | l -> print "YES\n"; ++ p_list "Primitives declared in this module" ++ "\t%s\n" ++ l ++ end ++ | _ -> () ++ with Not_found | Failure _ | Invalid_argument _ -> () ++ ) ++ ["CRCS"; "DLLS"; "DLPT"; "PRIM"]; ++ close_in ic ++ with ++ | Sys_error msg -> ++ perr msg ++ | Invalid_argument("index out of bounds") -> ++ perr (Printf.sprintf "Usage: %s filename" Sys.argv.(0)) +diff --git a/ocamlplugininfo.ml b/ocamlplugininfo.ml +new file mode 100644 +index 000000000..e28800f31 +--- /dev/null ++++ b/ocamlplugininfo.ml +@@ -0,0 +1,109 @@ ++(***********************************************************************) ++(* *) ++(* Objective Caml *) ++(* *) ++(* Xavier Leroy, projet Gallium, INRIA Rocquencourt *) ++(* *) ++(* Copyright 2009 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the GNU Library General Public License, with *) ++(* the special exception on linking described in file ../../LICENSE. *) ++(* *) ++(***********************************************************************) ++ ++(* $Id$ *) ++ ++(* Dumps a .cmxs file *) ++ ++open Natdynlink ++open Format ++ ++let file = ++ try ++ Sys.argv.(1) ++ with _ -> begin ++ Printf.eprintf "Usage: %s file.cmxs\n" Sys.argv.(0); ++ exit(1) ++ end ++ ++exception Abnormal_exit ++ ++let error s e = ++ let eprint = Printf.eprintf in ++ let print_exc s = function ++ | End_of_file -> ++ eprint "%s: %s\n" s file ++ | Abnormal_exit -> ++ eprint "%s\n" s ++ | e -> eprint "%s\n" (Printexc.to_string e) ++ in ++ print_exc s e; ++ exit(1) ++ ++let read_in command = ++ let cmd = Printf.sprintf command file in ++ let ic = Unix.open_process_in cmd in ++ try ++ let line = input_line ic in ++ begin match (Unix.close_process_in ic) with ++ | Unix.WEXITED 0 -> Str.split (Str.regexp "[ ]+") line ++ | Unix.WEXITED _ | Unix.WSIGNALED _ | Unix.WSTOPPED _ -> ++ error ++ (Printf.sprintf ++ "Command \"%s\" exited abnormally" ++ cmd ++ ) ++ Abnormal_exit ++ end ++ with e -> error "File is empty" e ++ ++let get_offset adr_off adr_sec = ++ try ++ let adr = List.nth adr_off 4 in ++ let off = List.nth adr_off 5 in ++ let sec = List.hd adr_sec in ++ ++ let (!) x = Int64.of_string ("0x" ^ x) in ++ let (+) = Int64.add in ++ let (-) = Int64.sub in ++ ++ Int64.to_int (!off + !sec - !adr) ++ ++ with Failure _ | Invalid_argument _ -> ++ error ++ "Command output doesn't have the expected format" ++ Abnormal_exit ++ ++let print_infos name crc defines cmi cmx = ++ let print_name_crc (name, crc) = ++ printf "@ %s (%s)" name (Digest.to_hex crc) ++ in ++ let pr_imports ppf imps = List.iter print_name_crc imps in ++ printf "Name: %s@." name; ++ printf "CRC of implementation: %s@." (Digest.to_hex crc); ++ printf "@[Globals defined:"; ++ List.iter (fun s -> printf "@ %s" s) defines; ++ printf "@]@."; ++ printf "@[Interfaces imported:%a@]@." pr_imports cmi; ++ printf "@[Implementations imported:%a@]@." pr_imports cmx ++ ++let _ = ++ let adr_off = read_in "objdump -h %s | grep ' .data '" in ++ let adr_sec = read_in "objdump -T %s | grep ' caml_plugin_header$'" in ++ ++ let ic = open_in file in ++ let _ = seek_in ic (get_offset adr_off adr_sec) in ++ let header = (input_value ic : Natdynlink.dynheader) in ++ if header.magic <> Natdynlink.dyn_magic_number then ++ raise(Error(Natdynlink.Not_a_bytecode_file file)) ++ else begin ++ List.iter ++ (fun ui -> ++ print_infos ++ ui.name ++ ui.crc ++ ui.defines ++ ui.imports_cmi ++ ui.imports_cmx) ++ header.units ++ end +-- +2.17.1 + diff --git a/0003-configure-Allow-user-defined-C-compiler-flags.patch b/0003-configure-Allow-user-defined-C-compiler-flags.patch new file mode 100644 index 0000000..5fb4967 --- /dev/null +++ b/0003-configure-Allow-user-defined-C-compiler-flags.patch @@ -0,0 +1,27 @@ +From 8ddd2fb4909bf6ed1a3506723126432da8fcf0c4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 29 May 2012 20:44:18 +0100 +Subject: [PATCH 3/8] configure: Allow user defined C compiler flags. + +--- + configure | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/configure b/configure +index 1316b3c1e..53f45f85b 100755 +--- a/configure ++++ b/configure +@@ -2050,6 +2050,10 @@ if $flat_float_array; then + echo "#define FLAT_FLOAT_ARRAY" >> m.h + fi + ++# Allow user defined C Compiler flags ++bytecccompopts="$bytecccompopts $CFLAGS" ++nativecccompopts="$nativecccompopts $CFLAGS" ++ + # Finish generated files + + cclibs="$cclibs $mathlib" +-- +2.17.1 + diff --git a/0004-Add-RISC-V-backend.patch b/0004-Add-RISC-V-backend.patch new file mode 100644 index 0000000..22d8fe3 --- /dev/null +++ b/0004-Add-RISC-V-backend.patch @@ -0,0 +1,1768 @@ +From 38ac4778744fb7137e04708998d4e856ada1c8b8 Mon Sep 17 00:00:00 2001 +From: Nicolas Ojeda Bar +Date: Fri, 27 Oct 2017 17:05:25 +0200 +Subject: [PATCH 4/8] Add RISC-V backend + +--- + README.adoc | 1 + + asmcomp/riscv/CSE.ml | 36 ++ + asmcomp/riscv/arch.ml | 87 +++++ + asmcomp/riscv/emit.mlp | 653 ++++++++++++++++++++++++++++++++++++ + asmcomp/riscv/proc.ml | 301 +++++++++++++++++ + asmcomp/riscv/reload.ml | 16 + + asmcomp/riscv/scheduling.ml | 19 ++ + asmcomp/riscv/selection.ml | 72 ++++ + asmrun/riscv.S | 424 +++++++++++++++++++++++ + byterun/caml/stack.h | 5 + + config/gnu/config.guess | 5 +- + configure | 5 +- + 12 files changed, 1622 insertions(+), 2 deletions(-) + create mode 100644 asmcomp/riscv/CSE.ml + create mode 100644 asmcomp/riscv/arch.ml + create mode 100644 asmcomp/riscv/emit.mlp + create mode 100644 asmcomp/riscv/proc.ml + create mode 100644 asmcomp/riscv/reload.ml + create mode 100644 asmcomp/riscv/scheduling.ml + create mode 100644 asmcomp/riscv/selection.ml + create mode 100644 asmrun/riscv.S + +diff --git a/README.adoc b/README.adoc +index 74d1ec258..ac6c6eac3 100644 +--- a/README.adoc ++++ b/README.adoc +@@ -47,6 +47,7 @@ AMD64:: FreeBSD, OpenBSD, NetBSD + IA32 (Pentium):: NetBSD, OpenBSD, Solaris 9 + PowerPC:: NetBSD + ARM:: NetBSD ++RISC-V:: Linux + + Other operating systems for the processors above have not been tested, but + the compiler may work under other operating systems with little work. +diff --git a/asmcomp/riscv/CSE.ml b/asmcomp/riscv/CSE.ml +new file mode 100644 +index 000000000..302811a99 +--- /dev/null ++++ b/asmcomp/riscv/CSE.ml +@@ -0,0 +1,36 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2106 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* CSE for the RISC-V *) ++ ++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 <= 0x7FFn && n >= -0x800n ++ | _ -> false ++ ++end ++ ++let fundecl f = ++ (new cse)#fundecl f +diff --git a/asmcomp/riscv/arch.ml b/asmcomp/riscv/arch.ml +new file mode 100644 +index 000000000..22c807c49 +--- /dev/null ++++ b/asmcomp/riscv/arch.ml +@@ -0,0 +1,87 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2016 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* Specific operations for the RISC-V 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 *) ++ ++let spacetime_node_hole_pointer_is_live_before = function ++ | Imultaddf _ | Imultsubf _ -> false ++ ++(* Addressing modes *) ++ ++type addressing_mode = ++ | Iindexed of int (* reg + displ *) ++ ++let is_immediate n = ++ (n <= 2047) && (n >= -2048) ++ ++(* Sizes, endianness *) ++ ++let big_endian = false ++ ++let rv64 = ++ match Config.model with "riscv64" -> true | "riscv32" -> false | _ -> assert false ++ ++let size_addr = if rv64 then 8 else 4 ++let size_int = size_addr ++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) +diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp +new file mode 100644 +index 000000000..51165d0f1 +--- /dev/null ++++ b/asmcomp/riscv/emit.mlp +@@ -0,0 +1,653 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2016 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* Emission of RISC-V assembly code *) ++ ++open Misc ++open Cmm ++open Arch ++open Proc ++open Reg ++open Mach ++open Linearize ++open Emitaux ++ ++(* Layout of the stack. The stack is kept 16-aligned. *) ++ ++let stack_offset = ref 0 ++ ++let frame_size () = ++ let size = ++ !stack_offset + (* Trap frame, outgoing parameters *) ++ size_int * num_stack_slots.(0) + (* Local int variables *) ++ size_float * num_stack_slots.(1) + (* Local float variables *) ++ (if !contains_calls then size_addr else 0) in (* The return address *) ++ Misc.align size 16 ++ ++let slot_offset loc cls = ++ match loc with ++ | Local n -> ++ if cls = 0 ++ then !stack_offset + num_stack_slots.(1) * size_float + n * size_int ++ else !stack_offset + n * size_float ++ | Incoming n -> frame_size() + n ++ | Outgoing n -> n ++ ++(* Output a symbol *) ++ ++let emit_symbol s = ++ Emitaux.emit_symbol '.' s ++ ++(* Output a label *) ++ ++let label_prefix = "L" ++ ++let emit_label lbl = ++ emit_string label_prefix; emit_int lbl ++ ++(* Section switching *) ++ ++let data_space = ++ ".section .data" ++ ++let code_space = ++ ".section .text" ++ ++let rodata_space = ++ ".section .rodata" ++ ++let reg_tmp1 = phys_reg 21 (* used by the assembler *) ++let reg_tmp2 = phys_reg 22 ++let reg_t2 = phys_reg 16 ++(* let reg_fp = phys_reg 23 *) ++let reg_trap = phys_reg 24 ++let reg_alloc_ptr = phys_reg 25 ++let reg_alloc_lim = phys_reg 26 ++ ++(* Names of instructions that differ in 32 and 64-bit modes *) ++ ++let lg = if rv64 then "ld" else "lw" ++let stg = if rv64 then "sd" else "sw" ++let datag = if rv64 then ".quad" else ".long" ++ ++(* Output a pseudo-register *) ++ ++let emit_reg = function ++ | {loc = Reg r} -> emit_string (register_name r) ++ | _ -> fatal_error "Emit.emit_reg" ++ ++(* Adjust sp by the given byte amount *) ++ ++let emit_stack_adjustment = function ++ | 0 -> () ++ | n when is_immediate n -> ++ ` addi sp, sp, {emit_int n}\n` ++ | n -> ++ ` li {emit_reg reg_tmp1}, {emit_int n}\n`; ++ ` add sp, sp, {emit_reg reg_tmp1}\n` ++ ++let reload_ra n = ++ let ofs = n - size_addr in ++ if is_immediate ofs then ++ ` {emit_string lg} ra, {emit_int ofs}(sp)\n` ++ else begin ++ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; ++ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; ++ ` {emit_string lg} ra, 0({emit_reg reg_tmp1})\n` ++ end ++ ++let store_ra n = ++ let ofs = n - size_addr in ++ if is_immediate ofs then ++ ` {emit_string stg} ra, {emit_int(n - size_addr)}(sp)\n` ++ else begin ++ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; ++ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; ++ ` {emit_string stg} ra, 0({emit_reg reg_tmp1})\n` ++ end ++ ++let emit_store stg src ofs = ++ if is_immediate ofs then ++ ` {emit_string stg} {emit_reg src}, {emit_int ofs}(sp)\n` ++ else begin ++ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; ++ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; ++ ` {emit_string stg} {emit_reg src}, 0({emit_reg reg_tmp1})\n` ++ end ++ ++let emit_load lg dst ofs = ++ if is_immediate ofs then ++ ` {emit_string lg} {emit_reg dst}, {emit_int ofs}(sp)\n` ++ else begin ++ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; ++ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; ++ ` {emit_string lg} {emit_reg dst}, 0({emit_reg reg_tmp1})\n` ++ end ++ ++(* Record live pointers at call points *) ++ ++let record_frame_label ?label live raise_ dbg = ++ let lbl = ++ match label with ++ | None -> new_label() ++ | Some label -> 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 -> ++ live_offset := slot_offset s (register_class reg) :: !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()) ++ ~live_offset:!live_offset ~raise_frame:raise_ dbg; ++ lbl ++ ++let record_frame ?label live raise_ dbg = ++ let lbl = record_frame_label ?label live raise_ dbg in ++ `{emit_label lbl}:\n` ++ ++(* Record calls to the GC -- we've moved them out of the way *) ++ ++type gc_call = ++ { gc_lbl: label; (* Entry label *) ++ gc_return_lbl: label; (* Where to branch after GC *) ++ gc_frame_lbl: label } (* Label of frame descriptor *) ++ ++let call_gc_sites = ref ([] : gc_call list) ++ ++let emit_call_gc gc = ++ `{emit_label gc.gc_lbl}:\n`; ++ ` call {emit_symbol "caml_call_gc"}\n`; ++ `{emit_label gc.gc_frame_lbl}:\n`; ++ ` j {emit_label gc.gc_return_lbl}\n` ++ ++(* Record calls to caml_ml_array_bound_error. ++ In debug mode, we maintain one call to caml_ml_array_bound_error ++ per bound check site. Otherwise, we can share a single call. *) ++ ++type bound_error_call = ++ { bd_lbl: label; (* Entry label *) ++ bd_frame_lbl: label } (* Label of frame descriptor *) ++ ++let bound_error_sites = ref ([] : bound_error_call list) ++ ++let bound_error_label ?label dbg = ++ if !Clflags.debug || !bound_error_sites = [] then begin ++ let lbl_bound_error = new_label() in ++ let lbl_frame = record_frame_label ?label Reg.Set.empty false dbg in ++ bound_error_sites := ++ { bd_lbl = lbl_bound_error; ++ bd_frame_lbl = lbl_frame } :: !bound_error_sites; ++ lbl_bound_error ++ end else ++ let bd = List.hd !bound_error_sites in ++ bd.bd_lbl ++ ++let emit_call_bound_error bd = ++ `{emit_label bd.bd_lbl}:\n`; ++ ` call {emit_symbol "caml_ml_array_bound_error"}\n`; ++ `{emit_label bd.bd_frame_lbl}:\n` ++ ++(* Record floating-point literals *) ++ ++let float_literals = ref ([] : (int64 * int) list) ++ ++(* Names for various instructions *) ++ ++let name_for_intop = function ++ | Iadd -> "add" ++ | Isub -> "sub" ++ | Imul -> "mul" ++ | Imulh -> "mulh" ++ | Idiv -> "div" ++ | Iand -> "and" ++ | Ior -> "or" ++ | Ixor -> "xor" ++ | Ilsl -> "sll" ++ | Ilsr -> "srl" ++ | Iasr -> "sra" ++ | Imod -> "rem" ++ | _ -> fatal_error "Emit.Intop" ++ ++let name_for_intop_imm = function ++ | Iadd -> "addi" ++ | Iand -> "andi" ++ | Ior -> "ori" ++ | Ixor -> "xori" ++ | Ilsl -> "slli" ++ | Ilsr -> "srli" ++ | Iasr -> "srai" ++ | _ -> fatal_error "Emit.Intop_imm" ++ ++let name_for_floatop1 = function ++ | Inegf -> "fneg.d" ++ | Iabsf -> "fabs.d" ++ | _ -> fatal_error "Emit.Iopf1" ++ ++let name_for_floatop2 = function ++ | Iaddf -> "fadd.d" ++ | Isubf -> "fsub.d" ++ | Imulf -> "fmul.d" ++ | Idivf -> "fdiv.d" ++ | _ -> fatal_error "Emit.Iopf2" ++ ++let name_for_specific = function ++ | Imultaddf false -> "fmadd.d" ++ | Imultaddf true -> "fnmadd.d" ++ | Imultsubf false -> "fmsub.d" ++ | Imultsubf true -> "fnmsub.d" ++ ++(* Name of current function *) ++let function_name = ref "" ++ ++(* Entry point for tail recursive calls *) ++let tailrec_entry_point = ref 0 ++ ++(* Output the assembly code for an instruction *) ++ ++let emit_instr i = ++ match i.desc with ++ Lend -> () ++ | 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 _} -> ++ ` mv {emit_reg dst}, {emit_reg src}\n` ++ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = Float} -> ++ ` fmv.d {emit_reg dst}, {emit_reg src}\n` ++ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Stack s} -> ++ let ofs = slot_offset s (register_class dst) in ++ emit_store stg src ofs ++ | {loc = Reg _; typ = Float}, {loc = Stack s} -> ++ let ofs = slot_offset s (register_class dst) in ++ emit_store "fsd" src ofs ++ | {loc = Stack s; typ = (Val | Int | Addr)}, {loc = Reg _} -> ++ let ofs = slot_offset s (register_class src) in ++ emit_load lg dst ofs ++ | {loc = Stack s; typ = Float}, {loc = Reg _} -> ++ let ofs = slot_offset s (register_class src) in ++ emit_load "fld" dst ofs ++ | _ -> ++ fatal_error "Emit: Imove" ++ end ++ | Lop(Iconst_int n) -> ++ ` li {emit_reg i.res.(0)}, {emit_nativeint n}\n` ++ | Lop(Iconst_float f) -> ++ let lbl = new_label() in ++ float_literals := (f, lbl) :: !float_literals; ++ ` fld {emit_reg i.res.(0)}, {emit_label lbl}, {emit_reg reg_tmp1}\n` ++ | Lop(Iconst_symbol s) -> ++ ` la {emit_reg i.res.(0)}, {emit_symbol s}\n` ++ | Lop(Icall_ind {label_after = label}) -> ++ ` jalr {emit_reg i.arg.(0)}\n`; ++ record_frame ~label i.live false i.dbg ++ | Lop(Icall_imm {func; label_after = label}) -> ++ ` call {emit_symbol func}\n`; ++ record_frame ~label i.live false i.dbg ++ | Lop(Itailcall_ind {label_after = _}) -> ++ let n = frame_size() in ++ if !contains_calls then reload_ra n; ++ emit_stack_adjustment n; ++ ` jr {emit_reg i.arg.(0)}\n` ++ | Lop(Itailcall_imm {func; label_after = _}) -> ++ if func = !function_name then begin ++ ` j {emit_label !tailrec_entry_point}\n` ++ end else begin ++ let n = frame_size() in ++ if !contains_calls then reload_ra n; ++ emit_stack_adjustment n; ++ ` tail {emit_symbol func}\n` ++ end ++ | Lop(Iextcall{func; alloc = true; label_after = label}) -> ++ ` la {emit_reg reg_t2}, {emit_symbol func}\n`; ++ ` call {emit_symbol "caml_c_call"}\n`; ++ record_frame ~label i.live false i.dbg ++ | Lop(Iextcall{func; alloc = false; label_after = _}) -> ++ ` call {emit_symbol func}\n` ++ | Lop(Istackoffset n) -> ++ assert (n mod 16 = 0); ++ emit_stack_adjustment (-n); ++ stack_offset := !stack_offset + n ++ | Lop(Iload(Single, Iindexed ofs)) -> ++ ` flw {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`; ++ ` fcvt.d.s {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` ++ | Lop(Iload(chunk, Iindexed ofs)) -> ++ let instr = ++ match chunk with ++ | Byte_unsigned -> "lbu" ++ | Byte_signed -> "lb" ++ | Sixteen_unsigned -> "lhu" ++ | Sixteen_signed -> "lh" ++ | Thirtytwo_unsigned -> if rv64 then "lwu" else "lw" ++ | Thirtytwo_signed -> "lw" ++ | Word_int | Word_val -> lg ++ | Single -> assert false ++ | Double | Double_u -> "fld" ++ in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n` ++ | Lop(Istore(Single, Iindexed ofs, _)) -> ++ ` fmv.x.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}\n`; ++ ` fcvt.s.d {emit_reg i.arg.(0)}, {emit_reg i.arg.(0)}\n`; ++ ` fsw {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n`; ++ ` fmv.d.x {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}\n` ++ | Lop(Istore(chunk, Iindexed ofs, _)) -> ++ let instr = ++ match chunk with ++ | Byte_unsigned | Byte_signed -> "sb" ++ | Sixteen_unsigned | Sixteen_signed -> "sh" ++ | Thirtytwo_unsigned | Thirtytwo_signed -> "sw" ++ | Word_int | Word_val -> stg ++ | Single -> assert false ++ | Double | Double_u -> "fsd" ++ in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n` ++ | Lop(Ialloc {words = n; label_after_call_gc = label; _}) -> ++ let lbl_frame_lbl = record_frame_label ?label i.live false i.dbg in ++ let lbl_redo = new_label () in ++ let lbl_call_gc = new_label () in ++ `{emit_label lbl_redo}:\n`; ++ ` addi {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, -{emit_int n}\n`; ++ ` addi {emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, {emit_int size_addr}\n`; ++ ` bltu {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_lim}, {emit_label lbl_call_gc}\n`; ++ call_gc_sites := ++ { gc_lbl = lbl_call_gc; ++ gc_return_lbl = lbl_redo; ++ gc_frame_lbl = lbl_frame_lbl } :: !call_gc_sites ++ | Lop(Iintop(Icomp cmp)) -> ++ begin match cmp with ++ | Isigned Clt -> ++ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | Isigned Cge -> ++ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ++ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; ++ | Isigned Cgt -> ++ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` ++ | Isigned Cle -> ++ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; ++ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; ++ | Isigned Ceq | Iunsigned Ceq -> ++ ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ++ ` seqz {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` ++ | Isigned Cne | Iunsigned Cne -> ++ ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ++ ` snez {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` ++ | Iunsigned Clt -> ++ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | Iunsigned Cge -> ++ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ++ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; ++ | Iunsigned Cgt -> ++ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` ++ | Iunsigned Cle -> ++ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; ++ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; ++ end ++ | Lop(Iintop (Icheckbound {label_after_error = label; _})) -> ++ let lbl = bound_error_label ?label i.dbg in ++ ` bleu {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n` ++ | Lop(Iintop op) -> ++ let instr = name_for_intop op in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | Lop(Iintop_imm(Isub, n)) -> ++ ` addi {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int(-n)}\n` ++ | Lop(Iintop_imm(Icomp _, _)) -> ++ fatal_error "Emit.emit_instr (Iintop_imm (Icomp _, _))" ++ | Lop(Iintop_imm(Icheckbound {label_after_error = label; _}, n)) -> ++ let lbl = bound_error_label ?label i.dbg in ++ ` li {emit_reg reg_tmp1}, {emit_int n}\n`; ++ ` bleu {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ | Lop(Iintop_imm(op, n)) -> ++ let instr = name_for_intop_imm op in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int n}\n` ++ | Lop(Inegf | Iabsf as op) -> ++ let instr = name_for_floatop1 op in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n` ++ | Lop(Iaddf | Isubf | Imulf | Idivf as op) -> ++ let instr = name_for_floatop2 op in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | Lop(Ifloatofint) -> ++ let name = if rv64 then "fcvt.d.l" else "fcvt.d.w" in ++ ` {emit_string name} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n` ++ | Lop(Iintoffloat) -> ++ let name = if rv64 then "fcvt.l.d" else "fcvt.w.d" in ++ ` {emit_string name} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n` ++ | Lop(Ispecific sop) -> ++ let instr = name_for_specific sop in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(2)}\n` ++ | Lop (Iname_for_debugger _) -> ++ () ++ | Lreloadretaddr -> ++ let n = frame_size () in ++ reload_ra n ++ | Lreturn -> ++ let n = frame_size() in ++ emit_stack_adjustment n; ++ ` ret\n` ++ | Llabel lbl -> ++ `{emit_label lbl}:\n` ++ | Lbranch lbl -> ++ ` j {emit_label lbl}\n` ++ | Lcondbranch(tst, lbl) -> ++ begin match tst with ++ | Itruetest -> ++ ` bnez {emit_reg i.arg.(0)}, {emit_label lbl}\n` ++ | Ifalsetest -> ++ ` beqz {emit_reg i.arg.(0)}, {emit_label lbl}\n` ++ | Iinttest cmp -> ++ let name = match cmp with ++ | Iunsigned Ceq | Isigned Ceq -> "beq" ++ | Iunsigned Cne | Isigned Cne -> "bne" ++ | Iunsigned Cle -> "bleu" | Isigned Cle -> "ble" ++ | Iunsigned Cge -> "bgeu" | Isigned Cge -> "bge" ++ | Iunsigned Clt -> "bltu" | Isigned Clt -> "blt" ++ | Iunsigned Cgt -> "bgtu" | Isigned Cgt -> "bgt" ++ in ++ ` {emit_string name} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n` ++ | Iinttest_imm _ -> ++ fatal_error "Emit.emit_instr (Iinttest_imm _)" ++ | Ifloattest(cmp, neg) -> ++ let neg = match cmp with ++ | Ceq -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg ++ | Cne -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; not neg ++ | Clt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg ++ | Cgt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg ++ | Cle -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg ++ | Cge -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg ++ in ++ if neg then ++ ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ else ++ ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ | Ioddtest -> ++ ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`; ++ ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ | Ieventest -> ++ ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`; ++ ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ end ++ | Lcondbranch3(lbl0, lbl1, lbl2) -> ++ ` addi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, -1\n`; ++ begin match lbl0 with ++ | None -> () ++ | Some lbl -> ` bltz {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ end; ++ begin match lbl1 with ++ | None -> () ++ | Some lbl -> ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ end; ++ begin match lbl2 with ++ | None -> () ++ | Some lbl -> ` bgtz {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ end ++ | Lswitch jumptbl -> (* FIXME FIXME ? *) ++ let lbl = new_label() in ++ ` la {emit_reg reg_tmp1}, {emit_label lbl}\n`; ++ ` slli {emit_reg reg_tmp2}, {emit_reg i.arg.(0)}, 2\n`; ++ ` add {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_reg reg_tmp2}\n`; ++ ` jr {emit_reg reg_tmp1}\n`; ++ `{emit_label lbl}:\n`; ++ for i = 0 to Array.length jumptbl - 1 do ++ ` j {emit_label jumptbl.(i)}\n` ++ done ++ | Lsetuptrap lbl -> ++ ` addi sp, sp, -16\n`; ++ ` jal {emit_label lbl}\n` ++ | Lpushtrap -> ++ stack_offset := !stack_offset + 16; ++ ` {emit_string stg} ra, {emit_int size_addr}(sp)\n`; ++ ` {emit_string stg} {emit_reg reg_trap}, 0(sp)\n`; ++ ` mv {emit_reg reg_trap}, sp\n` ++ | Lpoptrap -> ++ ` {emit_string lg} {emit_reg reg_trap}, 0(sp)\n`; ++ ` addi sp, sp, 16\n`; ++ stack_offset := !stack_offset - 16 ++ | Lraise k -> ++ begin match !Clflags.debug, k with ++ | true, Cmm.Raise_withtrace -> ++ ` call {emit_symbol "caml_raise_exn"}\n`; ++ record_frame Reg.Set.empty true i.dbg ++ | false, _ ++ | true, Cmm.Raise_notrace -> ++ ` mv sp, {emit_reg reg_trap}\n`; ++ ` {emit_string lg} {emit_reg reg_tmp1}, {emit_int size_addr}(sp)\n`; ++ ` {emit_string lg} {emit_reg reg_trap}, 0(sp)\n`; ++ ` addi sp, sp, 16\n`; ++ ` jalr {emit_reg reg_tmp1}\n` ++ end ++ ++(* Emit a sequence of instructions *) ++ ++let rec emit_all = function ++ | {desc = Lend} -> () | i -> emit_instr i; emit_all i.next ++ ++(* Emission of a function declaration *) ++ ++let fundecl fundecl = ++ function_name := fundecl.fun_name; ++ tailrec_entry_point := new_label(); ++ stack_offset := 0; ++ call_gc_sites := []; ++ bound_error_sites := []; ++ float_literals := []; ++ ` .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`; ++ let n = frame_size() in ++ emit_stack_adjustment (-n); ++ if !contains_calls then store_ra n; ++ `{emit_label !tailrec_entry_point}:\n`; ++ emit_all fundecl.fun_body; ++ List.iter emit_call_gc !call_gc_sites; ++ List.iter emit_call_bound_error !bound_error_sites; ++ ` .size {emit_symbol fundecl.fun_name}, .-{emit_symbol fundecl.fun_name}\n`; ++ (* Emit the float literals *) ++ if !float_literals <> [] then begin ++ ` {emit_string rodata_space}\n`; ++ ` .align 3\n`; ++ List.iter ++ (fun (f, lbl) -> ++ `{emit_label lbl}:\n`; ++ if rv64 ++ then emit_float64_directive ".quad" f ++ else emit_float64_split_directive ".long" f) ++ !float_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 -> ++ ` {emit_string datag} {emit_nativeint n}\n` ++ | Csingle f -> ++ emit_float32_directive ".long" (Int32.bits_of_float f) ++ | Cdouble f -> ++ if rv64 ++ then emit_float64_directive ".quad" (Int64.bits_of_float f) ++ else emit_float64_split_directive ".long" (Int64.bits_of_float f) ++ | Csymbol_address s -> ++ ` {emit_string datag} {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() = ++ ` .file \"\"\n`; (* PR#7073 *) ++ (* 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; ++ `{emit_symbol lbl_end}:\n`; ++ ` {emit_string datag} 0\n`; ++ (* Emit the frame descriptors *) ++ ` {emit_string rodata_space}\n`; ++ let lbl = Compilenv.make_symbol (Some "frametable") in ++ declare_global_data lbl; ++ `{emit_symbol lbl}:\n`; ++ emit_frames ++ { efa_code_label = (fun l -> ` {emit_string datag} {emit_label l}\n`); ++ efa_data_label = (fun l -> ` {emit_string datag} {emit_label l}\n`); ++ efa_16 = (fun n -> ` .short {emit_int n}\n`); ++ efa_32 = (fun n -> ` .long {emit_int32 n}\n`); ++ efa_word = (fun n -> ` {emit_string datag} {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/riscv/proc.ml b/asmcomp/riscv/proc.ml +new file mode 100644 +index 000000000..c0b0dcdb8 +--- /dev/null ++++ b/asmcomp/riscv/proc.ml +@@ -0,0 +1,301 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2016 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* Description of the RISC-V *) ++ ++open Misc ++open Cmm ++open Reg ++open Arch ++open Mach ++ ++(* Instruction selection *) ++ ++let word_addressed = false ++ ++(* Registers available for register allocation *) ++ ++(* Integer register map: ++ zero always zero ++ ra return address ++ sp, gp, tp stack pointer, global pointer, thread pointer (preserved by C) ++ a0 - a7 0 - 7 arguments/results ++ s2 - s9 8 - 15 arguments/results (preserved by C) ++ t2 - t6 16 - 20 temporary ++ t0 21 temporary (used by assembler) ++ t1 22 temporary (reserved for code gen) ++ s0 23 frame pointer (preserved by C) ++ s1 24 trap pointer (preserved by C) ++ s10 25 allocation pointer (preserved by C) ++ s11 26 allocation limit (preserved by C) ++ Floating-point register map: ++ ft0 - ft7 100 - 107 temporary ++ fs0 - fs1 108 - 109 general purpose (preserved by C) ++ fa0 - fa7 110 - 117 arguments/results ++ fs2 - fs9 118 - 125 arguments/results (preserved by C) ++ fs10 - fs11 126 - 127 general purpose (preserved by C) ++ ft8 - ft11 128 - 131 temporary ++*) ++ ++let int_reg_name = ++ [| "a0"; "a1"; "a2"; "a3"; "a4"; "a5"; "a6"; "a7"; ++ "s2"; "s3"; "s4"; "s5"; "s6"; "s7"; "s8"; "s9"; ++ "t2"; "t3"; "t4"; "t5"; "t6"; ++ "t0"; "t1"; ++ "s0"; "s1"; "s10"; "s11" |] ++ ++let float_reg_name = ++ [| "ft0"; "ft1"; "ft2"; "ft3"; "ft4"; "ft5"; "ft6"; "ft7"; ++ "fs0"; "fs1"; ++ "fa0"; "fa1"; "fa2"; "fa3"; "fa4"; "fa5"; "fa6"; "fa7"; ++ "fs2"; "fs3"; "fs4"; "fs5"; "fs6"; "fs7"; "fs8"; "fs9"; "fs10"; "fs11"; ++ "ft8"; "ft9"; "ft10"; "ft11" |] ++ ++let num_register_classes = 2 ++ ++let register_class r = ++ match r.typ with ++ | Val | Int | Addr -> 0 ++ | Float -> 1 ++ ++let num_available_registers = [| 21; 32 |] ++ ++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 27 Reg.dummy in ++ for i = 0 to 26 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 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).typ with ++ | Val | Int | Addr as ty -> ++ if !int <= last_int then begin ++ loc.(i) <- phys_reg !int; ++ incr int ++ 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 ++ 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 incoming ofs = Incoming ofs ++let outgoing ofs = Outgoing ofs ++let not_supported _ = fatal_error "Proc.loc_results: cannot call" ++ ++let max_arguments_for_tailcalls = 16 ++ ++let loc_spacetime_node_hole = Reg.dummy (* Spacetime unsupported *) ++ ++(* OCaml calling convention: ++ first integer args in a0 .. a7, s2 .. s9 ++ first float args in fa0 .. fa7, fs2 .. fs9 ++ remaining args on stack. ++ Return values in a0 .. a7, s2 .. s9 or fa0 .. fa7, fs2 .. fs9. *) ++ ++let single_regs arg = Array.map (fun arg -> [| arg |]) arg ++let ensure_single_regs res = ++ Array.map (function ++ | [| res |] -> res ++ | _ -> failwith "proc.ensure_single_regs" ++ ) res ++ ++let loc_arguments arg = ++ calling_conventions 0 15 110 125 outgoing arg ++ ++let loc_parameters arg = ++ let (loc, _ofs) = ++ calling_conventions 0 15 110 125 incoming arg ++ in ++ loc ++ ++let loc_results res = ++ let (loc, _ofs) = ++ calling_conventions 0 15 110 125 not_supported res ++ in ++ loc ++ ++(* C calling convention: ++ first integer args in a0 .. a7 ++ first float args in fa0 .. fa7 ++ remaining args on stack. ++ 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 ++ | [| arg |] -> ++ begin match arg.typ 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 ++ end ++ | [| arg1; arg2 |] -> ++ (* Passing of 64-bit quantities to external functions on 32-bit ++ platform. *) ++ assert (size_int = 4); ++ begin match arg1.typ, arg2.typ with ++ | Int, Int -> ++ int := Misc.align !int 2; ++ if !int <= last_int - 1 then begin ++ let reg_lower = phys_reg !int in ++ let reg_upper = phys_reg (!int + 1) in ++ loc.(i) <- [| reg_lower; reg_upper |]; ++ int := !int + 2 ++ end else begin ++ let size_int64 = 8 in ++ ofs := Misc.align !ofs size_int64; ++ let ofs_lower = !ofs in ++ let ofs_upper = !ofs + size_int in ++ let stack_lower = stack_slot (make_stack ofs_lower) Int in ++ let stack_upper = stack_slot (make_stack ofs_upper) Int in ++ loc.(i) <- [| stack_lower; stack_upper |]; ++ ofs := !ofs + size_int64 ++ end ++ | _ -> ++ let f = function Int -> "I" | Addr -> "A" | Val -> "V" | Float -> "F" in ++ fatal_error (Printf.sprintf "Proc.calling_conventions: bad register \ ++ type(s) for multi-register argument: %s, %s" ++ (f arg1.typ) (f arg2.typ)) ++ end ++ | _ -> ++ fatal_error "Proc.calling_conventions: bad number of register for \ ++ multi-register argument" ++ done; ++ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *) ++ ++let loc_external_arguments arg = ++ external_calling_conventions 0 7 110 117 outgoing arg ++ ++let loc_external_results res = ++ let (loc, _ofs) = ++ external_calling_conventions 0 1 110 111 not_supported (single_regs res) ++ in ++ ensure_single_regs loc ++ ++(* Exceptions are in GPR 3 *) ++ ++let loc_exn_bucket = phys_reg 0 ++ ++(* Volatile registers: none *) ++ ++let regs_are_volatile _ = false ++ ++(* Registers destroyed by operations *) ++ ++let destroyed_at_c_call = ++ Array.of_list(List.map phys_reg ++ [0; 1; 2; 3; 4; 5; 6; 7; 16; 17; 18; 19; 20; (* 21; 22; *) ++ 100; 101; 102; 103; 104; 105; 106; 107; 110; 111; 112; 113; 114; 115; 116; ++ 117; 128; 129; 130; 131]) ++ ++let destroyed_at_oper = function ++ | Iop(Icall_ind _ | Icall_imm _ | Iextcall{alloc = true; _}) -> all_phys_regs ++ | Iop(Iextcall{alloc = false; _}) -> destroyed_at_c_call ++ | _ -> [||] ++ ++let destroyed_at_raise = all_phys_regs ++ ++(* Maximal register pressure *) ++ ++let safe_register_pressure = function ++ | Iextcall _ -> 15 ++ | _ -> 21 ++ ++let max_register_pressure = function ++ | Iextcall _ -> [| 15; 18 |] ++ | _ -> [| 21; 30 |] ++ ++(* Pure operations (without any side effect besides updating their result ++ registers). *) ++ ++let op_is_pure = function ++ | Icall_ind _ | Icall_imm _ | Itailcall_ind _ | Itailcall_imm _ ++ | Iextcall _ | Istackoffset _ | Istore _ | Ialloc _ ++ | Iintop(Icheckbound _) | Iintop_imm(Icheckbound _, _) -> false ++ | Ispecific(Imultaddf _ | Imultsubf _) -> true ++ | _ -> true ++ ++(* Layout of the stack *) ++ ++let num_stack_slots = [| 0; 0 |] ++let contains_calls = ref false ++ ++(* 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/riscv/reload.ml b/asmcomp/riscv/reload.ml +new file mode 100644 +index 000000000..85b970342 +--- /dev/null ++++ b/asmcomp/riscv/reload.ml +@@ -0,0 +1,16 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2016 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* Reloading for the RISC-V *) ++ ++let fundecl f = ++ (new Reloadgen.reload_generic)#fundecl f +diff --git a/asmcomp/riscv/scheduling.ml b/asmcomp/riscv/scheduling.ml +new file mode 100644 +index 000000000..e436be1cc +--- /dev/null ++++ b/asmcomp/riscv/scheduling.ml +@@ -0,0 +1,19 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2016 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* Instruction scheduling for the RISC-V *) ++ ++let _ = let module M = Schedgen in () (* to create a dependency *) ++ ++(* Scheduling is turned off. *) ++ ++let fundecl f = f +diff --git a/asmcomp/riscv/selection.ml b/asmcomp/riscv/selection.ml +new file mode 100644 +index 000000000..092ca88aa +--- /dev/null ++++ b/asmcomp/riscv/selection.ml +@@ -0,0 +1,72 @@ ++(***********************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* Nicolas Ojeda Bar *) ++(* *) ++(* Copyright 2016 Institut National de Recherche en Informatique et *) ++(* en Automatique. All rights reserved. This file is distributed *) ++(* under the terms of the Q Public License version 1.0. *) ++(* *) ++(***********************************************************************) ++ ++(* Instruction selection for the RISC-V processor *) ++ ++open Cmm ++open Arch ++open Mach ++ ++(* Instruction selection *) ++ ++class selector = object (self) ++ ++inherit Selectgen.selector_generic as super ++ ++method is_immediate n = is_immediate n ++ ++method select_addressing _ = function ++ | Cop(Cadda, [arg; Cconst_int n], _) when self#is_immediate n -> ++ (Iindexed n, arg) ++ | Cop(Cadda, [arg1; Cop(Caddi, [arg2; Cconst_int n], _)], dbg) when self#is_immediate n -> ++ (Iindexed n, Cop(Caddi, [arg1; arg2], dbg)) ++ | arg -> ++ (Iindexed 0, arg) ++ ++method! select_operation op args dbg = ++ match (op, args) with ++ (* RISC-V does not support immediate operands for multiply high *) ++ | (Cmulhi, _) -> (Iintop Imulh, args) ++ (* 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]) ++ (* RISC-V does not support immediate operands for comparison operators *) ++ | (Ccmpi comp, args) -> (Iintop(Icomp (Isigned comp)), args) ++ | (Ccmpa comp, args) -> (Iintop(Icomp (Iunsigned comp)), args) ++ | (Cmuli, _) -> (Iintop Imul, args) ++ | _ -> ++ super#select_operation op args dbg ++ ++(* Instruction selection for conditionals *) ++ ++method! select_condition = function ++ | Cop(Ccmpi cmp, args, _) -> ++ (Iinttest(Isigned cmp), Ctuple args) ++ | Cop(Ccmpa cmp, args, _) -> ++ (Iinttest(Iunsigned cmp), Ctuple args) ++ | Cop(Ccmpf cmp, args, _) -> ++ (Ifloattest(cmp, false), Ctuple args) ++ | Cop(Cand, [arg; Cconst_int 1], _) -> ++ (Ioddtest, arg) ++ | arg -> ++ (Itruetest, arg) ++ ++end ++ ++let fundecl f = (new selector)#emit_fundecl f +diff --git a/asmrun/riscv.S b/asmrun/riscv.S +new file mode 100644 +index 000000000..a82048efc +--- /dev/null ++++ b/asmrun/riscv.S +@@ -0,0 +1,424 @@ ++/***********************************************************************/ ++/* */ ++/* OCaml */ ++/* */ ++/* Nicolas Ojeda Bar */ ++/* */ ++/* Copyright 1996 Institut National de Recherche en Informatique et */ ++/* en Automatique. All rights reserved. This file is distributed */ ++/* under the terms of the GNU Library General Public License, with */ ++/* the special exception on linking described in file ../LICENSE. */ ++/* */ ++/***********************************************************************/ ++ ++/* Asm part of the runtime system, RISC-V processor, 64-bit mode */ ++/* Must be preprocessed by cpp */ ++ ++#define TRAP_PTR s1 ++#define ALLOC_PTR s10 ++#define ALLOC_LIMIT s11 ++#define TMP0 t0 ++#define TMP1 t1 ++#define ARG t2 ++ ++#if defined(MODEL_riscv64) ++#define store sd ++#define load ld ++#define WSZ 8 ++#else ++#define store sw ++#define load lw ++#define WSZ 4 ++#endif ++ ++#if defined(__PIC__) ++ .option pic ++#else ++ .option nopic ++#endif ++ ++ .section .text ++/* Invoke the garbage collector. */ ++ ++ .globl caml_system__code_begin ++caml_system__code_begin: ++ ++ .align 2 ++ .globl caml_call_gc ++ .type caml_call_gc, @function ++caml_call_gc: ++ /* Record return address */ ++ store ra, caml_last_return_address, TMP0 ++ /* Record lowest stack address */ ++ mv TMP1, sp ++ store sp, caml_bottom_of_stack, TMP0 ++.Lcaml_call_gc: ++ /* Set up stack space, saving return address */ ++ /* (1 reg for RA, 1 reg for FP, 21 allocatable int regs, 20 caller-save float regs) * 8 */ ++ /* + 1 for alignment */ ++ addi sp, sp, -0x160 ++ mv s0, sp ++ store ra, 0x8(sp) ++ store s0, 0x0(sp) ++ /* Save allocatable integer registers on the stack, ++ in the order given in proc.ml */ ++ store a0, 0x10(sp) ++ store a1, 0x18(sp) ++ store a2, 0x20(sp) ++ store a3, 0x28(sp) ++ store a4, 0x30(sp) ++ store a5, 0x38(sp) ++ store a6, 0x40(sp) ++ store a7, 0x48(sp) ++ store s2, 0x50(sp) ++ store s3, 0x58(sp) ++ store s4, 0x60(sp) ++ store s5, 0x68(sp) ++ store s6, 0x70(sp) ++ store s7, 0x78(sp) ++ store s8, 0x80(sp) ++ store s9, 0x88(sp) ++ store t2, 0x90(sp) ++ store t3, 0x98(sp) ++ store t4, 0xa0(sp) ++ store t5, 0xa8(sp) ++ store t6, 0xb0(sp) ++ /* Save caller-save floating-point registers on the stack ++ (callee-saves are preserved by caml_garbage_collection) */ ++ fsd ft0, 0xb8(sp) ++ fsd ft1, 0xc0(sp) ++ fsd ft2, 0xc8(sp) ++ fsd ft3, 0xd0(sp) ++ fsd ft4, 0xd8(sp) ++ fsd ft5, 0xe0(sp) ++ fsd ft6, 0xe8(sp) ++ fsd ft7, 0xf0(sp) ++ fsd fa0, 0xf8(sp) ++ fsd fa1, 0x100(sp) ++ fsd fa2, 0x108(sp) ++ fsd fa3, 0x110(sp) ++ fsd fa4, 0x118(sp) ++ fsd fa5, 0x120(sp) ++ fsd fa6, 0x128(sp) ++ fsd fa7, 0x130(sp) ++ fsd ft8, 0x138(sp) ++ fsd ft9, 0x140(sp) ++ fsd ft9, 0x148(sp) ++ fsd ft10, 0x150(sp) ++ fsd ft11, 0x158(sp) ++ /* Store pointer to saved integer registers in caml_gc_regs */ ++ addi TMP1, sp, 16 ++ store TMP1, caml_gc_regs, TMP0 ++ /* Save current allocation pointer for debugging purposes */ ++ store ALLOC_PTR, caml_young_ptr, TMP0 ++ /* Save trap pointer in case an exception is raised during GC */ ++ store TRAP_PTR, caml_exception_pointer, TMP0 ++ /* Call the garbage collector */ ++ call caml_garbage_collection ++ /* Restore registers */ ++ load a0, 0x10(sp) ++ load a1, 0x18(sp) ++ load a2, 0x20(sp) ++ load a3, 0x28(sp) ++ load a4, 0x30(sp) ++ load a5, 0x38(sp) ++ load a6, 0x40(sp) ++ load a7, 0x48(sp) ++ load s2, 0x50(sp) ++ load s3, 0x58(sp) ++ load s4, 0x60(sp) ++ load s5, 0x68(sp) ++ load s6, 0x70(sp) ++ load s7, 0x78(sp) ++ load s8, 0x80(sp) ++ load s9, 0x88(sp) ++ load t2, 0x90(sp) ++ load t3, 0x98(sp) ++ load t4, 0xa0(sp) ++ load t5, 0xa8(sp) ++ load t6, 0xb0(sp) ++ fld ft0, 0xb8(sp) ++ fld ft1, 0xc0(sp) ++ fld ft2, 0xc8(sp) ++ fld ft3, 0xd0(sp) ++ fld ft4, 0xd8(sp) ++ fld ft5, 0xe0(sp) ++ fld ft6, 0xe8(sp) ++ fld ft7, 0xf0(sp) ++ fld fa0, 0xf8(sp) ++ fld fa1, 0x100(sp) ++ fld fa2, 0x108(sp) ++ fld fa3, 0x110(sp) ++ fld fa4, 0x118(sp) ++ fld fa5, 0x120(sp) ++ fld fa6, 0x128(sp) ++ fld fa7, 0x130(sp) ++ fld ft8, 0x138(sp) ++ fld ft9, 0x140(sp) ++ fld ft9, 0x148(sp) ++ fld ft10, 0x150(sp) ++ fld ft11, 0x158(sp) ++ /* Reload new allocation pointer and allocation limit */ ++ load ALLOC_PTR, caml_young_ptr ++ load ALLOC_LIMIT, caml_young_limit ++ /* Free stack space and return to caller */ ++ load ra, 0x8(sp) ++ load s0, 0x0(sp) ++ addi sp, sp, 0x160 ++ ret ++ .size caml_call_gc, .-caml_call_gc ++ ++/* Call a C function from OCaml */ ++/* Function to call is in ARG */ ++ ++ .align 2 ++ .globl caml_c_call ++ .type caml_c_call, @function ++caml_c_call: ++ /* Preserve return address in callee-save register s2 */ ++ mv s2, ra ++ /* Record lowest stack address and return address */ ++ store ra, caml_last_return_address, TMP0 ++ store sp, caml_bottom_of_stack, TMP0 ++ /* Make the exception handler alloc ptr available to the C code */ ++ store ALLOC_PTR, caml_young_ptr, TMP0 ++ store TRAP_PTR, caml_exception_pointer, TMP0 ++ /* Call the function */ ++ jalr ARG ++ /* Reload alloc ptr and alloc limit */ ++ load ALLOC_PTR, caml_young_ptr ++ load TRAP_PTR, caml_exception_pointer ++ /* Return */ ++ jr s2 ++ .size caml_c_call, .-caml_c_call ++ ++/* Raise an exception from OCaml */ ++ .align 2 ++ .globl caml_raise_exn ++ .type caml_raise_exn, @function ++caml_raise_exn: ++ /* Test if backtrace is active */ ++ load TMP1, caml_backtrace_active ++ bnez TMP1, 2f ++1: /* Cut stack at current trap handler */ ++ mv sp, TRAP_PTR ++ /* Pop previous handler and jump to it */ ++ load TMP1, 8(sp) ++ load TRAP_PTR, 0(sp) ++ addi sp, sp, 16 ++ jr TMP1 ++2: /* Preserve exception bucket in callee-save register s2 */ ++ mv s2, a0 ++ /* Stash the backtrace */ ++ mv a1, ra ++ mv a2, sp ++ mv a3, TRAP_PTR ++ call caml_stash_backtrace ++ /* Restore exception bucket and raise */ ++ mv a0, s2 ++ j 1b ++ .size caml_raise_exn, .-caml_raise_exn ++ ++ .globl caml_reraise_exn ++ .type caml_reraise_exn, @function ++ ++/* Raise an exception from C */ ++ ++ .align 2 ++ .globl caml_raise_exception ++ .type caml_raise_exception, @function ++caml_raise_exception: ++ load TRAP_PTR, caml_exception_pointer ++ load ALLOC_PTR, caml_young_ptr ++ load ALLOC_LIMIT, caml_young_limit ++ load TMP1, caml_backtrace_active ++ bnez TMP1, 2f ++1: /* Cut stack at current trap handler */ ++ mv sp, TRAP_PTR ++ load TMP1, 8(sp) ++ load TRAP_PTR, 0(sp) ++ addi sp, sp, 16 ++ jr TMP1 ++2: /* Preserve exception bucket in callee-save register s2 */ ++ mv s2, a0 ++ load a1, caml_last_return_address ++ load a2, caml_bottom_of_stack ++ mv a3, TRAP_PTR ++ call caml_stash_backtrace ++ mv a0, s2 ++ j 1b ++ .size caml_raise_exception, .-caml_raise_exception ++ ++/* Start the OCaml program */ ++ ++ .align 2 ++ .globl caml_start_program ++ .type caml_start_program, @function ++caml_start_program: ++ ++ la ARG, caml_program ++ /* Code shared with caml_callback* */ ++ /* Address of OCaml code to call is in ARG */ ++ /* Arguments to the OCaml code are in a0 ... a7 */ ++.Ljump_to_caml: ++ /* Set up stack frame and save callee-save registers */ ++ addi sp, sp, -0xd0 ++ store ra, 0xc0(sp) ++ store s0, 0x0(sp) ++ store s1, 0x8(sp) ++ store s2, 0x10(sp) ++ store s3, 0x18(sp) ++ store s4, 0x20(sp) ++ store s5, 0x28(sp) ++ store s6, 0x30(sp) ++ store s7, 0x38(sp) ++ store s8, 0x40(sp) ++ store s9, 0x48(sp) ++ store s10, 0x50(sp) ++ store s11, 0x58(sp) ++ fsd fs0, 0x60(sp) ++ fsd fs1, 0x68(sp) ++ fsd fs2, 0x70(sp) ++ fsd fs3, 0x78(sp) ++ fsd fs4, 0x80(sp) ++ fsd fs5, 0x88(sp) ++ fsd fs6, 0x90(sp) ++ fsd fs7, 0x98(sp) ++ fsd fs8, 0xa0(sp) ++ fsd fs9, 0xa8(sp) ++ fsd fs10, 0xb0(sp) ++ fsd fs11, 0xb8(sp) ++ addi sp, sp, -32 ++ /* Setup a callback link on the stack */ ++ load TMP1, caml_bottom_of_stack ++ store TMP1, 0(sp) ++ load TMP1, caml_last_return_address ++ store TMP1, 8(sp) ++ load TMP1, caml_gc_regs ++ store TMP1, 16(sp) ++ /* set up a trap frame */ ++ addi sp, sp, -16 ++ load TMP1, caml_exception_pointer ++ store TMP1, 0(sp) ++ lla TMP0, .Ltrap_handler ++ store TMP0, 8(sp) ++ mv TRAP_PTR, sp ++ load ALLOC_PTR, caml_young_ptr ++ load ALLOC_LIMIT, caml_young_limit ++ store x0, caml_last_return_address, TMP0 ++ jalr ARG ++.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ ++ load TMP1, 0(sp) ++ store TMP1, caml_exception_pointer, TMP0 ++ addi sp, sp, 16 ++.Lreturn_result: /* pop callback link, restoring global variables */ ++ load TMP1, 0(sp) ++ store TMP1, caml_bottom_of_stack, TMP0 ++ load TMP1, 8(sp) ++ store TMP1, caml_last_return_address, TMP0 ++ load TMP1, 16(sp) ++ store TMP1, caml_gc_regs, TMP0 ++ addi sp, sp, 32 ++ /* Update allocation pointer */ ++ store ALLOC_PTR, caml_young_ptr, TMP0 ++ /* reload callee-save registers and return */ ++ load ra, 0xc0(sp) ++ load s0, 0x0(sp) ++ load s1, 0x8(sp) ++ load s2, 0x10(sp) ++ load s3, 0x18(sp) ++ load s4, 0x20(sp) ++ load s5, 0x28(sp) ++ load s6, 0x30(sp) ++ load s7, 0x38(sp) ++ load s8, 0x40(sp) ++ load s9, 0x48(sp) ++ load s10, 0x50(sp) ++ load s11, 0x58(sp) ++ fld fs0, 0x60(sp) ++ fld fs1, 0x68(sp) ++ fld fs2, 0x70(sp) ++ fld fs3, 0x78(sp) ++ fld fs4, 0x80(sp) ++ fld fs5, 0x88(sp) ++ fld fs6, 0x90(sp) ++ fld fs7, 0x98(sp) ++ fld fs8, 0xa0(sp) ++ fld fs9, 0xa8(sp) ++ fld fs10, 0xb0(sp) ++ fld fs11, 0xb8(sp) ++ addi sp, sp, 0xd0 ++ ret ++.Ltrap_handler: ++ store TRAP_PTR, caml_exception_pointer, TMP0 ++ ori a0, a0, 2 ++ j .Lreturn_result ++ .size caml_start_program, .-caml_start_program ++ ++/* Callback from C to OCaml */ ++ ++ .align 2 ++ .globl caml_callback_exn ++ .type caml_callback_exn, @function ++caml_callback_exn: ++ /* Initial shuffling of arguments (a0 = closure, a1 = first arg) */ ++ mv TMP1, a0 ++ mv a0, a1 /* a0 = first arg */ ++ mv a1, TMP1 /* a1 = closure environment */ ++ load ARG, 0(TMP1) /* code pointer */ ++ j .Ljump_to_caml ++ .size caml_callback_exn, .-caml_callback_exn ++ ++ .align 2 ++ .globl caml_callback2_exn ++ .type caml_callback2_exn, @function ++caml_callback2_exn: ++ /* Initial shuffling of arguments (a0 = closure, a1 = arg1, a2 = arg2) */ ++ mv TMP1, a0 ++ mv a0, a1 ++ mv a1, a2 ++ mv a2, TMP1 ++ la ARG, caml_apply2 ++ j .Ljump_to_caml ++ .size caml_callback2_exn, .-caml_callback2_exn ++ ++ .align 2 ++ .globl caml_callback3_exn ++ .type caml_callback3_exn, @function ++caml_callback3_exn: ++ /* Initial shuffling of argumnets */ ++ /* (a0 = closure, a1 = arg1, a2 = arg2, a3 = arg3) */ ++ mv TMP1, a0 ++ mv a0, a1 ++ mv a1, a2 ++ mv a2, a3 ++ mv a3, TMP1 ++ la ARG, caml_apply3 ++ j .Ljump_to_caml ++ .size caml_callback3_exn, .-caml_callback3_exn ++ ++ .align 2 ++ .globl caml_ml_array_bound_error ++ .type caml_ml_array_bound_error, @function ++caml_ml_array_bound_error: ++ /* Load address of [caml_array_bound_error] in ARG */ ++ la ARG, caml_array_bound_error ++ /* Call that function */ ++ j caml_c_call ++ ++ .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/byterun/caml/stack.h b/byterun/caml/stack.h +index 266863986..e198be0a6 100644 +--- a/byterun/caml/stack.h ++++ b/byterun/caml/stack.h +@@ -70,6 +70,11 @@ + #define Callback_link(sp) ((struct caml_context *)((sp) + 16)) + #endif + ++#ifdef TARGET_riscv /* FIXME FIXME */ ++#define Saved_return_address(sp) *((intnat *)((sp) - 8)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) ++#endif ++ + /* Structure of OCaml callback contexts */ + + struct caml_context { +diff --git a/config/gnu/config.guess b/config/gnu/config.guess +index b79252d6b..8335398b2 100755 +--- a/config/gnu/config.guess ++++ b/config/gnu/config.guess +@@ -2,7 +2,7 @@ + # Attempt to guess a canonical system name. + # Copyright 1992-2013 Free Software Foundation, Inc. + +-timestamp='2013-06-10' ++timestamp='2016-10-23' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -1001,6 +1001,9 @@ EOF + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; ++ riscv*:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux ++ exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; +diff --git a/configure b/configure +index 53f45f85b..cf5a4a02a 100755 +--- a/configure ++++ b/configure +@@ -928,6 +928,7 @@ if $with_sharedlibs; then + arm*-*-freebsd*) natdynlink=true;; + earm*-*-netbsd*) natdynlink=true;; + aarch64-*-linux*) natdynlink=true;; ++ riscv*-*-linux*) natdynlink=true;; + esac + fi + +@@ -1004,6 +1005,8 @@ case "$target" in + x86_64-*-mingw*) arch=amd64; system=mingw;; + aarch64-*-linux*) arch=arm64; system=linux;; + x86_64-*-cygwin*) arch=amd64; system=cygwin;; ++ riscv32-*-linux*) arch=riscv; model=riscv32; system=linux;; ++ riscv64-*-linux*) arch=riscv; model=riscv64; system=linux;; + esac + + # Some platforms exist both in 32-bit and 64-bit variants, not distinguished +@@ -1062,7 +1065,7 @@ case "$arch,$system" in + aspp="${TOOLPREF}cc -c";; + *,freebsd) as="${TOOLPREF}as" + aspp="${TOOLPREF}cc -c";; +- amd64,*|arm,*|arm64,*|i386,*|power,bsd*|power,netbsd) ++ amd64,*|arm,*|arm64,*|i386,*|power,bsd*|power,netbsd|riscv,*) + as="${TOOLPREF}as" + case "$ccfamily" in + clang-*) +-- +2.17.1 + diff --git a/0005-Copyright-untabify.patch b/0005-Copyright-untabify.patch new file mode 100644 index 0000000..da7749a --- /dev/null +++ b/0005-Copyright-untabify.patch @@ -0,0 +1,717 @@ +From 2e4038b6b8073f55012613f18cb19a4c99e8219d Mon Sep 17 00:00:00 2001 +From: Nicolas Ojeda Bar +Date: Fri, 1 Dec 2017 14:39:46 +0100 +Subject: [PATCH 5/8] Copyright, untabify + +--- + asmrun/riscv.S | 608 ++++++++++++++++++++++++------------------------- + 1 file changed, 304 insertions(+), 304 deletions(-) + +diff --git a/asmrun/riscv.S b/asmrun/riscv.S +index a82048efc..88d7ab924 100644 +--- a/asmrun/riscv.S ++++ b/asmrun/riscv.S +@@ -4,7 +4,7 @@ + /* */ + /* Nicolas Ojeda Bar */ + /* */ +-/* Copyright 1996 Institut National de Recherche en Informatique et */ ++/* Copyright 2017 Institut National de Recherche en Informatique et */ + /* en Automatique. All rights reserved. This file is distributed */ + /* under the terms of the GNU Library General Public License, with */ + /* the special exception on linking described in file ../LICENSE. */ +@@ -37,388 +37,388 @@ + .option nopic + #endif + +- .section .text ++ .section .text + /* Invoke the garbage collector. */ + +- .globl caml_system__code_begin ++ .globl caml_system__code_begin + caml_system__code_begin: + +- .align 2 +- .globl caml_call_gc +- .type caml_call_gc, @function ++ .align 2 ++ .globl caml_call_gc ++ .type caml_call_gc, @function + caml_call_gc: + /* Record return address */ +- store ra, caml_last_return_address, TMP0 ++ store ra, caml_last_return_address, TMP0 + /* Record lowest stack address */ +- mv TMP1, sp +- store sp, caml_bottom_of_stack, TMP0 ++ mv TMP1, sp ++ store sp, caml_bottom_of_stack, TMP0 + .Lcaml_call_gc: +- /* Set up stack space, saving return address */ ++ /* Set up stack space, saving return address */ + /* (1 reg for RA, 1 reg for FP, 21 allocatable int regs, 20 caller-save float regs) * 8 */ + /* + 1 for alignment */ +- addi sp, sp, -0x160 +- mv s0, sp +- store ra, 0x8(sp) +- store s0, 0x0(sp) ++ addi sp, sp, -0x160 ++ mv s0, sp ++ store ra, 0x8(sp) ++ store s0, 0x0(sp) + /* Save allocatable integer registers on the stack, + in the order given in proc.ml */ +- store a0, 0x10(sp) +- store a1, 0x18(sp) +- store a2, 0x20(sp) +- store a3, 0x28(sp) +- store a4, 0x30(sp) +- store a5, 0x38(sp) +- store a6, 0x40(sp) +- store a7, 0x48(sp) +- store s2, 0x50(sp) +- store s3, 0x58(sp) +- store s4, 0x60(sp) +- store s5, 0x68(sp) +- store s6, 0x70(sp) +- store s7, 0x78(sp) +- store s8, 0x80(sp) +- store s9, 0x88(sp) +- store t2, 0x90(sp) +- store t3, 0x98(sp) +- store t4, 0xa0(sp) +- store t5, 0xa8(sp) +- store t6, 0xb0(sp) ++ store a0, 0x10(sp) ++ store a1, 0x18(sp) ++ store a2, 0x20(sp) ++ store a3, 0x28(sp) ++ store a4, 0x30(sp) ++ store a5, 0x38(sp) ++ store a6, 0x40(sp) ++ store a7, 0x48(sp) ++ store s2, 0x50(sp) ++ store s3, 0x58(sp) ++ store s4, 0x60(sp) ++ store s5, 0x68(sp) ++ store s6, 0x70(sp) ++ store s7, 0x78(sp) ++ store s8, 0x80(sp) ++ store s9, 0x88(sp) ++ store t2, 0x90(sp) ++ store t3, 0x98(sp) ++ store t4, 0xa0(sp) ++ store t5, 0xa8(sp) ++ store t6, 0xb0(sp) + /* Save caller-save floating-point registers on the stack + (callee-saves are preserved by caml_garbage_collection) */ +- fsd ft0, 0xb8(sp) +- fsd ft1, 0xc0(sp) +- fsd ft2, 0xc8(sp) +- fsd ft3, 0xd0(sp) +- fsd ft4, 0xd8(sp) +- fsd ft5, 0xe0(sp) +- fsd ft6, 0xe8(sp) +- fsd ft7, 0xf0(sp) +- fsd fa0, 0xf8(sp) +- fsd fa1, 0x100(sp) +- fsd fa2, 0x108(sp) +- fsd fa3, 0x110(sp) +- fsd fa4, 0x118(sp) +- fsd fa5, 0x120(sp) +- fsd fa6, 0x128(sp) +- fsd fa7, 0x130(sp) +- fsd ft8, 0x138(sp) +- fsd ft9, 0x140(sp) +- fsd ft9, 0x148(sp) +- fsd ft10, 0x150(sp) +- fsd ft11, 0x158(sp) ++ fsd ft0, 0xb8(sp) ++ fsd ft1, 0xc0(sp) ++ fsd ft2, 0xc8(sp) ++ fsd ft3, 0xd0(sp) ++ fsd ft4, 0xd8(sp) ++ fsd ft5, 0xe0(sp) ++ fsd ft6, 0xe8(sp) ++ fsd ft7, 0xf0(sp) ++ fsd fa0, 0xf8(sp) ++ fsd fa1, 0x100(sp) ++ fsd fa2, 0x108(sp) ++ fsd fa3, 0x110(sp) ++ fsd fa4, 0x118(sp) ++ fsd fa5, 0x120(sp) ++ fsd fa6, 0x128(sp) ++ fsd fa7, 0x130(sp) ++ fsd ft8, 0x138(sp) ++ fsd ft9, 0x140(sp) ++ fsd ft9, 0x148(sp) ++ fsd ft10, 0x150(sp) ++ fsd ft11, 0x158(sp) + /* Store pointer to saved integer registers in caml_gc_regs */ +- addi TMP1, sp, 16 +- store TMP1, caml_gc_regs, TMP0 ++ addi TMP1, sp, 16 ++ store TMP1, caml_gc_regs, TMP0 + /* Save current allocation pointer for debugging purposes */ +- store ALLOC_PTR, caml_young_ptr, TMP0 ++ store ALLOC_PTR, caml_young_ptr, TMP0 + /* Save trap pointer in case an exception is raised during GC */ +- store TRAP_PTR, caml_exception_pointer, TMP0 ++ store TRAP_PTR, caml_exception_pointer, TMP0 + /* Call the garbage collector */ +- call caml_garbage_collection ++ call caml_garbage_collection + /* Restore registers */ +- load a0, 0x10(sp) +- load a1, 0x18(sp) +- load a2, 0x20(sp) +- load a3, 0x28(sp) +- load a4, 0x30(sp) +- load a5, 0x38(sp) +- load a6, 0x40(sp) +- load a7, 0x48(sp) +- load s2, 0x50(sp) +- load s3, 0x58(sp) +- load s4, 0x60(sp) +- load s5, 0x68(sp) +- load s6, 0x70(sp) +- load s7, 0x78(sp) +- load s8, 0x80(sp) +- load s9, 0x88(sp) +- load t2, 0x90(sp) +- load t3, 0x98(sp) +- load t4, 0xa0(sp) +- load t5, 0xa8(sp) +- load t6, 0xb0(sp) +- fld ft0, 0xb8(sp) +- fld ft1, 0xc0(sp) +- fld ft2, 0xc8(sp) +- fld ft3, 0xd0(sp) +- fld ft4, 0xd8(sp) +- fld ft5, 0xe0(sp) +- fld ft6, 0xe8(sp) +- fld ft7, 0xf0(sp) +- fld fa0, 0xf8(sp) +- fld fa1, 0x100(sp) +- fld fa2, 0x108(sp) +- fld fa3, 0x110(sp) +- fld fa4, 0x118(sp) +- fld fa5, 0x120(sp) +- fld fa6, 0x128(sp) +- fld fa7, 0x130(sp) +- fld ft8, 0x138(sp) +- fld ft9, 0x140(sp) +- fld ft9, 0x148(sp) +- fld ft10, 0x150(sp) +- fld ft11, 0x158(sp) ++ load a0, 0x10(sp) ++ load a1, 0x18(sp) ++ load a2, 0x20(sp) ++ load a3, 0x28(sp) ++ load a4, 0x30(sp) ++ load a5, 0x38(sp) ++ load a6, 0x40(sp) ++ load a7, 0x48(sp) ++ load s2, 0x50(sp) ++ load s3, 0x58(sp) ++ load s4, 0x60(sp) ++ load s5, 0x68(sp) ++ load s6, 0x70(sp) ++ load s7, 0x78(sp) ++ load s8, 0x80(sp) ++ load s9, 0x88(sp) ++ load t2, 0x90(sp) ++ load t3, 0x98(sp) ++ load t4, 0xa0(sp) ++ load t5, 0xa8(sp) ++ load t6, 0xb0(sp) ++ fld ft0, 0xb8(sp) ++ fld ft1, 0xc0(sp) ++ fld ft2, 0xc8(sp) ++ fld ft3, 0xd0(sp) ++ fld ft4, 0xd8(sp) ++ fld ft5, 0xe0(sp) ++ fld ft6, 0xe8(sp) ++ fld ft7, 0xf0(sp) ++ fld fa0, 0xf8(sp) ++ fld fa1, 0x100(sp) ++ fld fa2, 0x108(sp) ++ fld fa3, 0x110(sp) ++ fld fa4, 0x118(sp) ++ fld fa5, 0x120(sp) ++ fld fa6, 0x128(sp) ++ fld fa7, 0x130(sp) ++ fld ft8, 0x138(sp) ++ fld ft9, 0x140(sp) ++ fld ft9, 0x148(sp) ++ fld ft10, 0x150(sp) ++ fld ft11, 0x158(sp) + /* Reload new allocation pointer and allocation limit */ +- load ALLOC_PTR, caml_young_ptr +- load ALLOC_LIMIT, caml_young_limit ++ load ALLOC_PTR, caml_young_ptr ++ load ALLOC_LIMIT, caml_young_limit + /* Free stack space and return to caller */ +- load ra, 0x8(sp) +- load s0, 0x0(sp) +- addi sp, sp, 0x160 ++ load ra, 0x8(sp) ++ load s0, 0x0(sp) ++ addi sp, sp, 0x160 + ret +- .size caml_call_gc, .-caml_call_gc ++ .size caml_call_gc, .-caml_call_gc + + /* Call a C function from OCaml */ + /* Function to call is in ARG */ + +- .align 2 +- .globl caml_c_call +- .type caml_c_call, @function ++ .align 2 ++ .globl caml_c_call ++ .type caml_c_call, @function + caml_c_call: + /* Preserve return address in callee-save register s2 */ +- mv s2, ra ++ mv s2, ra + /* Record lowest stack address and return address */ +- store ra, caml_last_return_address, TMP0 +- store sp, caml_bottom_of_stack, TMP0 ++ store ra, caml_last_return_address, TMP0 ++ store sp, caml_bottom_of_stack, TMP0 + /* Make the exception handler alloc ptr available to the C code */ +- store ALLOC_PTR, caml_young_ptr, TMP0 +- store TRAP_PTR, caml_exception_pointer, TMP0 ++ store ALLOC_PTR, caml_young_ptr, TMP0 ++ store TRAP_PTR, caml_exception_pointer, TMP0 + /* Call the function */ +- jalr ARG ++ jalr ARG + /* Reload alloc ptr and alloc limit */ +- load ALLOC_PTR, caml_young_ptr +- load TRAP_PTR, caml_exception_pointer ++ load ALLOC_PTR, caml_young_ptr ++ load TRAP_PTR, caml_exception_pointer + /* Return */ +- jr s2 +- .size caml_c_call, .-caml_c_call ++ jr s2 ++ .size caml_c_call, .-caml_c_call + + /* Raise an exception from OCaml */ +- .align 2 +- .globl caml_raise_exn +- .type caml_raise_exn, @function ++ .align 2 ++ .globl caml_raise_exn ++ .type caml_raise_exn, @function + caml_raise_exn: + /* Test if backtrace is active */ +- load TMP1, caml_backtrace_active +- bnez TMP1, 2f ++ load TMP1, caml_backtrace_active ++ bnez TMP1, 2f + 1: /* Cut stack at current trap handler */ +- mv sp, TRAP_PTR ++ mv sp, TRAP_PTR + /* Pop previous handler and jump to it */ +- load TMP1, 8(sp) +- load TRAP_PTR, 0(sp) +- addi sp, sp, 16 +- jr TMP1 ++ load TMP1, 8(sp) ++ load TRAP_PTR, 0(sp) ++ addi sp, sp, 16 ++ jr TMP1 + 2: /* Preserve exception bucket in callee-save register s2 */ +- mv s2, a0 ++ mv s2, a0 + /* Stash the backtrace */ +- mv a1, ra +- mv a2, sp +- mv a3, TRAP_PTR +- call caml_stash_backtrace ++ mv a1, ra ++ mv a2, sp ++ mv a3, TRAP_PTR ++ call caml_stash_backtrace + /* Restore exception bucket and raise */ +- mv a0, s2 +- j 1b +- .size caml_raise_exn, .-caml_raise_exn ++ mv a0, s2 ++ j 1b ++ .size caml_raise_exn, .-caml_raise_exn + +- .globl caml_reraise_exn +- .type caml_reraise_exn, @function ++ .globl caml_reraise_exn ++ .type caml_reraise_exn, @function + + /* Raise an exception from C */ + +- .align 2 +- .globl caml_raise_exception +- .type caml_raise_exception, @function ++ .align 2 ++ .globl caml_raise_exception ++ .type caml_raise_exception, @function + caml_raise_exception: +- load TRAP_PTR, caml_exception_pointer +- load ALLOC_PTR, caml_young_ptr +- load ALLOC_LIMIT, caml_young_limit +- load TMP1, caml_backtrace_active +- bnez TMP1, 2f ++ load TRAP_PTR, caml_exception_pointer ++ load ALLOC_PTR, caml_young_ptr ++ load ALLOC_LIMIT, caml_young_limit ++ load TMP1, caml_backtrace_active ++ bnez TMP1, 2f + 1: /* Cut stack at current trap handler */ +- mv sp, TRAP_PTR +- load TMP1, 8(sp) +- load TRAP_PTR, 0(sp) +- addi sp, sp, 16 +- jr TMP1 ++ mv sp, TRAP_PTR ++ load TMP1, 8(sp) ++ load TRAP_PTR, 0(sp) ++ addi sp, sp, 16 ++ jr TMP1 + 2: /* Preserve exception bucket in callee-save register s2 */ +- mv s2, a0 +- load a1, caml_last_return_address +- load a2, caml_bottom_of_stack +- mv a3, TRAP_PTR +- call caml_stash_backtrace +- mv a0, s2 +- j 1b +- .size caml_raise_exception, .-caml_raise_exception ++ mv s2, a0 ++ load a1, caml_last_return_address ++ load a2, caml_bottom_of_stack ++ mv a3, TRAP_PTR ++ call caml_stash_backtrace ++ mv a0, s2 ++ j 1b ++ .size caml_raise_exception, .-caml_raise_exception + + /* Start the OCaml program */ + +- .align 2 +- .globl caml_start_program +- .type caml_start_program, @function ++ .align 2 ++ .globl caml_start_program ++ .type caml_start_program, @function + caml_start_program: + +- la ARG, caml_program ++ la ARG, caml_program + /* Code shared with caml_callback* */ + /* Address of OCaml code to call is in ARG */ + /* Arguments to the OCaml code are in a0 ... a7 */ + .Ljump_to_caml: +- /* Set up stack frame and save callee-save registers */ +- addi sp, sp, -0xd0 +- store ra, 0xc0(sp) +- store s0, 0x0(sp) +- store s1, 0x8(sp) +- store s2, 0x10(sp) +- store s3, 0x18(sp) +- store s4, 0x20(sp) +- store s5, 0x28(sp) +- store s6, 0x30(sp) +- store s7, 0x38(sp) +- store s8, 0x40(sp) +- store s9, 0x48(sp) +- store s10, 0x50(sp) +- store s11, 0x58(sp) +- fsd fs0, 0x60(sp) +- fsd fs1, 0x68(sp) +- fsd fs2, 0x70(sp) +- fsd fs3, 0x78(sp) +- fsd fs4, 0x80(sp) +- fsd fs5, 0x88(sp) +- fsd fs6, 0x90(sp) +- fsd fs7, 0x98(sp) +- fsd fs8, 0xa0(sp) +- fsd fs9, 0xa8(sp) +- fsd fs10, 0xb0(sp) +- fsd fs11, 0xb8(sp) +- addi sp, sp, -32 ++ /* Set up stack frame and save callee-save registers */ ++ addi sp, sp, -0xd0 ++ store ra, 0xc0(sp) ++ store s0, 0x0(sp) ++ store s1, 0x8(sp) ++ store s2, 0x10(sp) ++ store s3, 0x18(sp) ++ store s4, 0x20(sp) ++ store s5, 0x28(sp) ++ store s6, 0x30(sp) ++ store s7, 0x38(sp) ++ store s8, 0x40(sp) ++ store s9, 0x48(sp) ++ store s10, 0x50(sp) ++ store s11, 0x58(sp) ++ fsd fs0, 0x60(sp) ++ fsd fs1, 0x68(sp) ++ fsd fs2, 0x70(sp) ++ fsd fs3, 0x78(sp) ++ fsd fs4, 0x80(sp) ++ fsd fs5, 0x88(sp) ++ fsd fs6, 0x90(sp) ++ fsd fs7, 0x98(sp) ++ fsd fs8, 0xa0(sp) ++ fsd fs9, 0xa8(sp) ++ fsd fs10, 0xb0(sp) ++ fsd fs11, 0xb8(sp) ++ addi sp, sp, -32 + /* Setup a callback link on the stack */ +- load TMP1, caml_bottom_of_stack +- store TMP1, 0(sp) +- load TMP1, caml_last_return_address +- store TMP1, 8(sp) +- load TMP1, caml_gc_regs +- store TMP1, 16(sp) +- /* set up a trap frame */ +- addi sp, sp, -16 +- load TMP1, caml_exception_pointer +- store TMP1, 0(sp) +- lla TMP0, .Ltrap_handler +- store TMP0, 8(sp) +- mv TRAP_PTR, sp +- load ALLOC_PTR, caml_young_ptr +- load ALLOC_LIMIT, caml_young_limit +- store x0, caml_last_return_address, TMP0 +- jalr ARG +-.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ +- load TMP1, 0(sp) +- store TMP1, caml_exception_pointer, TMP0 +- addi sp, sp, 16 +-.Lreturn_result: /* pop callback link, restoring global variables */ +- load TMP1, 0(sp) +- store TMP1, caml_bottom_of_stack, TMP0 +- load TMP1, 8(sp) +- store TMP1, caml_last_return_address, TMP0 +- load TMP1, 16(sp) +- store TMP1, caml_gc_regs, TMP0 +- addi sp, sp, 32 +- /* Update allocation pointer */ +- store ALLOC_PTR, caml_young_ptr, TMP0 +- /* reload callee-save registers and return */ +- load ra, 0xc0(sp) +- load s0, 0x0(sp) +- load s1, 0x8(sp) +- load s2, 0x10(sp) +- load s3, 0x18(sp) +- load s4, 0x20(sp) +- load s5, 0x28(sp) +- load s6, 0x30(sp) +- load s7, 0x38(sp) +- load s8, 0x40(sp) +- load s9, 0x48(sp) +- load s10, 0x50(sp) +- load s11, 0x58(sp) +- fld fs0, 0x60(sp) +- fld fs1, 0x68(sp) +- fld fs2, 0x70(sp) +- fld fs3, 0x78(sp) +- fld fs4, 0x80(sp) +- fld fs5, 0x88(sp) +- fld fs6, 0x90(sp) +- fld fs7, 0x98(sp) +- fld fs8, 0xa0(sp) +- fld fs9, 0xa8(sp) +- fld fs10, 0xb0(sp) +- fld fs11, 0xb8(sp) +- addi sp, sp, 0xd0 +- ret ++ load TMP1, caml_bottom_of_stack ++ store TMP1, 0(sp) ++ load TMP1, caml_last_return_address ++ store TMP1, 8(sp) ++ load TMP1, caml_gc_regs ++ store TMP1, 16(sp) ++ /* set up a trap frame */ ++ addi sp, sp, -16 ++ load TMP1, caml_exception_pointer ++ store TMP1, 0(sp) ++ lla TMP0, .Ltrap_handler ++ store TMP0, 8(sp) ++ mv TRAP_PTR, sp ++ load ALLOC_PTR, caml_young_ptr ++ load ALLOC_LIMIT, caml_young_limit ++ store x0, caml_last_return_address, TMP0 ++ jalr ARG ++.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ ++ load TMP1, 0(sp) ++ store TMP1, caml_exception_pointer, TMP0 ++ addi sp, sp, 16 ++.Lreturn_result: /* pop callback link, restoring global variables */ ++ load TMP1, 0(sp) ++ store TMP1, caml_bottom_of_stack, TMP0 ++ load TMP1, 8(sp) ++ store TMP1, caml_last_return_address, TMP0 ++ load TMP1, 16(sp) ++ store TMP1, caml_gc_regs, TMP0 ++ addi sp, sp, 32 ++ /* Update allocation pointer */ ++ store ALLOC_PTR, caml_young_ptr, TMP0 ++ /* reload callee-save registers and return */ ++ load ra, 0xc0(sp) ++ load s0, 0x0(sp) ++ load s1, 0x8(sp) ++ load s2, 0x10(sp) ++ load s3, 0x18(sp) ++ load s4, 0x20(sp) ++ load s5, 0x28(sp) ++ load s6, 0x30(sp) ++ load s7, 0x38(sp) ++ load s8, 0x40(sp) ++ load s9, 0x48(sp) ++ load s10, 0x50(sp) ++ load s11, 0x58(sp) ++ fld fs0, 0x60(sp) ++ fld fs1, 0x68(sp) ++ fld fs2, 0x70(sp) ++ fld fs3, 0x78(sp) ++ fld fs4, 0x80(sp) ++ fld fs5, 0x88(sp) ++ fld fs6, 0x90(sp) ++ fld fs7, 0x98(sp) ++ fld fs8, 0xa0(sp) ++ fld fs9, 0xa8(sp) ++ fld fs10, 0xb0(sp) ++ fld fs11, 0xb8(sp) ++ addi sp, sp, 0xd0 ++ ret + .Ltrap_handler: +- store TRAP_PTR, caml_exception_pointer, TMP0 +- ori a0, a0, 2 +- j .Lreturn_result +- .size caml_start_program, .-caml_start_program ++ store TRAP_PTR, caml_exception_pointer, TMP0 ++ ori a0, a0, 2 ++ j .Lreturn_result ++ .size caml_start_program, .-caml_start_program + + /* Callback from C to OCaml */ + +- .align 2 +- .globl caml_callback_exn +- .type caml_callback_exn, @function ++ .align 2 ++ .globl caml_callback_exn ++ .type caml_callback_exn, @function + caml_callback_exn: + /* Initial shuffling of arguments (a0 = closure, a1 = first arg) */ +- mv TMP1, a0 +- mv a0, a1 /* a0 = first arg */ +- mv a1, TMP1 /* a1 = closure environment */ +- load ARG, 0(TMP1) /* code pointer */ +- j .Ljump_to_caml +- .size caml_callback_exn, .-caml_callback_exn ++ mv TMP1, a0 ++ mv a0, a1 /* a0 = first arg */ ++ mv a1, TMP1 /* a1 = closure environment */ ++ load ARG, 0(TMP1) /* code pointer */ ++ j .Ljump_to_caml ++ .size caml_callback_exn, .-caml_callback_exn + +- .align 2 +- .globl caml_callback2_exn +- .type caml_callback2_exn, @function ++ .align 2 ++ .globl caml_callback2_exn ++ .type caml_callback2_exn, @function + caml_callback2_exn: + /* Initial shuffling of arguments (a0 = closure, a1 = arg1, a2 = arg2) */ +- mv TMP1, a0 +- mv a0, a1 +- mv a1, a2 +- mv a2, TMP1 +- la ARG, caml_apply2 +- j .Ljump_to_caml +- .size caml_callback2_exn, .-caml_callback2_exn ++ mv TMP1, a0 ++ mv a0, a1 ++ mv a1, a2 ++ mv a2, TMP1 ++ la ARG, caml_apply2 ++ j .Ljump_to_caml ++ .size caml_callback2_exn, .-caml_callback2_exn + +- .align 2 +- .globl caml_callback3_exn +- .type caml_callback3_exn, @function ++ .align 2 ++ .globl caml_callback3_exn ++ .type caml_callback3_exn, @function + caml_callback3_exn: + /* Initial shuffling of argumnets */ + /* (a0 = closure, a1 = arg1, a2 = arg2, a3 = arg3) */ +- mv TMP1, a0 +- mv a0, a1 +- mv a1, a2 +- mv a2, a3 +- mv a3, TMP1 +- la ARG, caml_apply3 +- j .Ljump_to_caml +- .size caml_callback3_exn, .-caml_callback3_exn ++ mv TMP1, a0 ++ mv a0, a1 ++ mv a1, a2 ++ mv a2, a3 ++ mv a3, TMP1 ++ la ARG, caml_apply3 ++ j .Ljump_to_caml ++ .size caml_callback3_exn, .-caml_callback3_exn + +- .align 2 +- .globl caml_ml_array_bound_error +- .type caml_ml_array_bound_error, @function ++ .align 2 ++ .globl caml_ml_array_bound_error ++ .type caml_ml_array_bound_error, @function + caml_ml_array_bound_error: + /* Load address of [caml_array_bound_error] in ARG */ +- la ARG, caml_array_bound_error ++ la ARG, caml_array_bound_error + /* Call that function */ +- j caml_c_call ++ j caml_c_call + +- .globl caml_system__code_end ++ .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 ++ .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 ++ .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 +-- +2.17.1 + diff --git a/0006-fix-caml_c_call-reload-caml_young_limit.patch b/0006-fix-caml_c_call-reload-caml_young_limit.patch new file mode 100644 index 0000000..a41c53c --- /dev/null +++ b/0006-fix-caml_c_call-reload-caml_young_limit.patch @@ -0,0 +1,25 @@ +From 207fbbc2616ee44e048dd5bb133e52f252cd1caf Mon Sep 17 00:00:00 2001 +From: Nicolas Ojeda Bar +Date: Sat, 2 Dec 2017 10:44:41 +0100 +Subject: [PATCH 6/8] fix caml_c_call: reload caml_young_limit + +--- + asmrun/riscv.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/asmrun/riscv.S b/asmrun/riscv.S +index 88d7ab924..121f8ba71 100644 +--- a/asmrun/riscv.S ++++ b/asmrun/riscv.S +@@ -187,7 +187,7 @@ caml_c_call: + jalr ARG + /* Reload alloc ptr and alloc limit */ + load ALLOC_PTR, caml_young_ptr +- load TRAP_PTR, caml_exception_pointer ++ load ALLOC_LIMIT, caml_young_limit + /* Return */ + jr s2 + .size caml_c_call, .-caml_c_call +-- +2.17.1 + diff --git a/0007-Adapt-to-4.07.patch b/0007-Adapt-to-4.07.patch new file mode 100644 index 0000000..0cda82d --- /dev/null +++ b/0007-Adapt-to-4.07.patch @@ -0,0 +1,67 @@ +From a89427d52a20633be40056fe008b7eeec5ded7dd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Nicol=C3=A1s=20Ojeda=20B=C3=A4r?= +Date: Tue, 15 May 2018 07:17:06 +0000 +Subject: [PATCH 7/8] Adapt to 4.07 + +--- + asmcomp/riscv/emit.mlp | 28 +++++++++++++++++----------- + asmcomp/riscv/selection.ml | 2 +- + 2 files changed, 18 insertions(+), 12 deletions(-) + +diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp +index 51165d0f1..718dca080 100644 +--- a/asmcomp/riscv/emit.mlp ++++ b/asmcomp/riscv/emit.mlp +@@ -461,19 +461,25 @@ let emit_instr i = + ` {emit_string name} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n` + | Iinttest_imm _ -> + fatal_error "Emit.emit_instr (Iinttest_imm _)" +- | Ifloattest(cmp, neg) -> +- let neg = match cmp with +- | Ceq -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg +- | Cne -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; not neg +- | Clt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg +- | Cgt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg +- | Cle -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg +- | Cge -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg +- in +- if neg then ++ | Ifloattest cmp -> ++ begin match cmp with ++ | CFeq | CFneq -> ++ ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | CFlt | CFnlt -> ++ ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | CFgt | CFngt -> ++ ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` ++ | CFle | CFnle -> ++ ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` ++ | CFge | CFnge -> ++ ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` ++ end; ++ begin match cmp with ++ | CFneq | CFnlt | CFngt | CFnle | CFnge -> + ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` +- else ++ | CFeq | CFlt | CFgt | CFle | CFge -> + ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` ++ end + | Ioddtest -> + ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`; + ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` +diff --git a/asmcomp/riscv/selection.ml b/asmcomp/riscv/selection.ml +index 092ca88aa..1f0af6abc 100644 +--- a/asmcomp/riscv/selection.ml ++++ b/asmcomp/riscv/selection.ml +@@ -61,7 +61,7 @@ method! select_condition = function + | Cop(Ccmpa cmp, args, _) -> + (Iinttest(Iunsigned cmp), Ctuple args) + | Cop(Ccmpf cmp, args, _) -> +- (Ifloattest(cmp, false), Ctuple args) ++ (Ifloattest cmp, Ctuple args) + | Cop(Cand, [arg; Cconst_int 1], _) -> + (Ioddtest, arg) + | arg -> +-- +2.17.1 + diff --git a/0008-riscv-Emit-debug-info.patch b/0008-riscv-Emit-debug-info.patch new file mode 100644 index 0000000..6d72833 --- /dev/null +++ b/0008-riscv-Emit-debug-info.patch @@ -0,0 +1,40 @@ +From af276d83f41cb9eb9f1e50a75a9be205c9b2fee6 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 5 Jun 2018 19:48:08 +0000 +Subject: [PATCH 8/8] riscv: Emit debug info. + +--- + asmcomp/riscv/emit.mlp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp +index 718dca080..e42ee9770 100644 +--- a/asmcomp/riscv/emit.mlp ++++ b/asmcomp/riscv/emit.mlp +@@ -261,6 +261,7 @@ let tailrec_entry_point = ref 0 + (* Output the assembly code for an instruction *) + + let emit_instr i = ++ emit_debug_info i.dbg; + match i.desc with + Lend -> () + | Lop(Imove | Ispill | Ireload) -> +@@ -560,6 +561,7 @@ let fundecl fundecl = + emit_stack_adjustment (-n); + if !contains_calls then store_ra n; + `{emit_label !tailrec_entry_point}:\n`; ++ emit_debug_info fundecl.fun_dbg; + emit_all fundecl.fun_body; + List.iter emit_call_gc !call_gc_sites; + List.iter emit_call_bound_error !bound_error_sites; +@@ -619,6 +621,7 @@ let data l = + + let begin_assembly() = + ` .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`; +-- +2.17.1 + diff --git a/gating.yaml b/gating.yaml deleted file mode 100755 index 2c7ed80..0000000 --- a/gating.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- !Policy -product_versions: - - rhel-* -decision_context: osci_compose_gate -rules: - - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} diff --git a/macros.ocaml-rpm b/macros.ocaml-rpm deleted file mode 100644 index ac94c48..0000000 --- a/macros.ocaml-rpm +++ /dev/null @@ -1,69 +0,0 @@ -# Make %files lists from an installed tree of files. -# Options: -# -s: separate packaging; every subdirectory of %%{ocamldir}, except stublibs, -# is placed in its own package. This option requires the existence of opam -# *.install files in the build tree. -# -n: suppress creation of a devel subpackage. -%ocaml_files(sn) %{python3} /usr/lib/rpm/redhat/ocaml_files.py %{-s} %{-n} %{buildroot} %{ocamldir} - -# Internal macro holding the common parts of ocaml_install and dune_install -%ocaml_install_common(sn) %{expand: -rm -rf %{buildroot}%{_prefix}/doc -mlis=$(find %{buildroot}%{_libdir}/ocaml -name '*.mli') -rm -f ${mlis//.mli/.ml} -%ocaml_files %{-s} %{-n}} - -# Install files listed in opam *.install files. -# Options: -# -s: separate packaging; every subdirectory of %%{ocamldir}, except stublibs, -# is placed in its own package. -# -n: suppress creation of a devel subpackage. -%ocaml_install(sn) %{expand: -%{python3} /usr/lib/rpm/redhat/ocaml_files.py -i %{-s} %{-n} %{buildroot} %{ocamldir} -%ocaml_install_common %{-s} %{-n}} - -# Add smp_mflags to arguments if no -j release option is given. -# Add --release to arguments if no -p or --release option is given. -# Add --verbose to arguments if it is not given. -%dune_add_flags(-) %{lua: - has_j = false - has_p = false - has_v = false - for _, flag in pairs(arg) do - if flag:find("^-j") then - has_j = true - elseif flag:find("^-p") or flag:find("^--release)") then - has_p = true - elseif flag:find("^--verbose") then - has_v = true - end - end - if not has_j then - table.insert(arg, 1, rpm.expand("%{?_smp_mflags}")) - end - if not has_p then - table.insert(arg, 1, "--release") - end - if not has_v then - table.insert(arg, 1, "--verbose") - end - print(table.concat(arg, " ")) -} - -# Build with dune -%dune_build(-) dune build %{dune_add_flags %*} - -# Run tests with dune -%dune_check(-) dune runtest %{dune_add_flags %*} - -# Install with dune -# Options: -# -s: separate packaging; every subdirectory of %%{ocamldir}, except stublibs, -# is placed in its own package. -# -n: suppress creation of a devel subpackage. -%dune_install(sn) %{expand: -dune install --destdir=%{buildroot} %{dune_add_flags %*} -if [ -d _build/default/_doc/_html ]; then - find _build/default/_doc/_html -name .dune-keep -delete -fi -%ocaml_install_common %{-s} %{-n}} diff --git a/ocaml.spec b/ocaml.spec index 3b39d37..5050261 100644 --- a/ocaml.spec +++ b/ocaml.spec @@ -1,6 +1,3 @@ -# Don't add -Wl,-dT, -%undefine _package_note_flags - # OCaml has a bytecode backend that works on anything with a C # compiler, and a native code backend available on a subset of # architectures. A further subset of architectures support native @@ -18,39 +15,33 @@ %global natdynlink 0 %endif -%global giturl https://github.com/ocaml/ocaml - -# i686 support was dropped in OCaml 5 / Fedora 39. -ExcludeArch: %{ix86} - # These are all the architectures that the tests run on. The tests # take a long time to run, so don't run them on slow machines. -%global test_arches %{arm64} %{power64} %{riscv64} s390x %{x86_64} +%global test_arches aarch64 %{power64} x86_64 # These are the architectures for which the tests must pass otherwise # the build will fail. -#global test_arches_required aarch64 ppc64le x86_64 -%global test_arches_required NONE +%global test_arches_required aarch64 ppc64le x86_64 # Architectures where parallel builds fail. -#global no_parallel_build_arches aarch64 +#%global no_parallel_build_arches aarch64 -#global rcver +git -%global rcver %{nil} +# If you want to bootstrap OCaml on a brand new architecture, or if +# you want to build OCaml without requiring an existing OCaml package, +# or if you want to build OCaml exactly as it is built upstream (using +# a binary ocamlc from the previous build), then use ‘--with bootstrap’. +%bcond_with bootstrap Name: ocaml -Version: 5.5.0 -Release: 2%{?dist} +Version: 4.07.0 +Release: 4%{?dist} Summary: OCaml compiler and programming environment -License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception +License: QPL and (LGPLv2+ with exceptions) -URL: https://www.ocaml.org -VCS: git:%{giturl}.git +URL: http://www.ocaml.org -Source0: %{giturl}/archive/%{version}%{rcver}/%{name}-%{version}%{rcver}.tar.gz -Source1: macros.ocaml-rpm -Source2: ocaml_files.py +Source0: http://caml.inria.fr/pub/distrib/ocaml-4.07/ocaml-%{version}.tar.xz # IMPORTANT NOTE: # @@ -61,55 +52,68 @@ Source2: ocaml_files.py # # https://pagure.io/fedora-ocaml # -# Current branch: fedora-45-5.4.1 +# Current branch: fedora-29-4.07.0 # # ALTERNATIVELY add a patch to the end of the list (leaving the # existing patches unchanged) adding a comment to note that it should # be incorporated into the git repo at a later time. +# -# Fedora-specific patches -Patch: 0001-Don-t-add-rpaths-to-libraries.patch -Patch: 0002-configure-Allow-user-defined-C-compiler-flags.patch +# Fedora-specific downstream patches. +Patch0001: 0001-Don-t-add-rpaths-to-libraries.patch +Patch0002: 0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch +Patch0003: 0003-configure-Allow-user-defined-C-compiler-flags.patch + +# Out of tree patch for RISC-V support. +# https://github.com/nojb/riscv-ocaml +Patch0004: 0004-Add-RISC-V-backend.patch +Patch0005: 0005-Copyright-untabify.patch +Patch0006: 0006-fix-caml_c_call-reload-caml_young_limit.patch +Patch0007: 0007-Adapt-to-4.07.patch + +# RISC-V patch to add debuginfo (DWARF) generation. +# Sent upstream 2018-06-05. +Patch0008: 0008-riscv-Emit-debug-info.patch + +%if ! %{with bootstrap} +BuildRequires: ocaml +%endif -BuildRequires: make -BuildRequires: git-core BuildRequires: gcc -BuildRequires: autoconf +BuildRequires: binutils-devel +BuildRequires: ncurses-devel +BuildRequires: gdbm-devel +BuildRequires: emacs BuildRequires: gawk BuildRequires: perl-interpreter -BuildRequires: annobin-annocheck -BuildRequires: pkgconfig(libzstd) +BuildRequires: util-linux +BuildRequires: libICE-devel +BuildRequires: libSM-devel +BuildRequires: libX11-devel +BuildRequires: libXaw-devel +BuildRequires: libXext-devel +BuildRequires: libXft-devel +BuildRequires: libXmu-devel +BuildRequires: libXrender-devel +BuildRequires: libXt-devel +BuildRequires: chrpath -# Documentation requirements -BuildRequires: asciidoc - -# ocamlopt runs gcc to link binaries. Because Fedora includes -# hardening flags automatically, redhat-rpm-config is also required. -# Compressed marshaling requires libzstd-devel. Requires: gcc -Requires: redhat-rpm-config -Requires: libzstd-devel%{?_isa} # Because we pass -c flag to ocaml-find-requires (to avoid circular # dependencies) we also have to explicitly depend on the right version # of ocaml-runtime. -Requires: ocaml-runtime%{?_isa} = %{version}-%{release} +Requires: ocaml-runtime = %{version}-%{release} -# Force ocaml-srpm-macros to be at the latest version, both for builds -# and installs, since OCaml 5.2 has a different set of native code -# generators than previous versions. -BuildRequires: ocaml-srpm-macros >= 10 -Requires: ocaml-srpm-macros >= 10 +# Bundles an MD5 implementation in byterun/md5.{c,h} +Provides: bundled(md5-plumb) Provides: ocaml(compiler) = %{version} -%if %{native_compiler} -%global __ocaml_requires_opts -c -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' -i Dynlink_cmo_format -i Dynlink_cmxs_format -%else -%global __ocaml_requires_opts -c -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' -i Backend_intf -i Inlining_decision_intf -i Simplify_boxed_integer_ops_intf -%endif +%global __ocaml_requires_opts -c -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' %global __ocaml_provides_opts -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' + %description OCaml is a high-level, strongly-typed, functional and object-oriented programming language from the ML family of languages. @@ -121,16 +125,10 @@ and a comprehensive library. %package runtime -# LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception: the project as a whole -# LicenseRef-Fedora-Public-Domain: the MD5 implementation in runtime/caml/md5.h -# and runtime/md5.c -License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception AND LicenseRef-Fedora-Public-Domain Summary: OCaml runtime environment +Requires: util-linux Provides: ocaml(runtime) = %{version} -# Bundles an MD5 implementation in runtime/caml/md5.h and runtime/md5.c -Provides: bundled(md5-plumb) - %description runtime OCaml is a high-level, strongly-typed, functional and object-oriented programming language from the ML family of languages. @@ -141,27 +139,41 @@ bytecode. %package source Summary: Source code for OCaml libraries -Requires: ocaml%{?_isa} = %{version}-%{release} +Requires: ocaml = %{version}-%{release} %description source Source code for OCaml libraries. +%package x11 +Summary: X11 support for OCaml +Requires: ocaml-runtime = %{version}-%{release} +Requires: libX11-devel + +%description x11 +X11 support for OCaml. + + %package ocamldoc -# LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception: the project as a whole -# LicenseRef-Fedora-Public-Domain: ocamldoc/ocamldoc.sty -License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception AND LicenseRef-Fedora-Public-Domain Summary: Documentation generator for OCaml -Requires: ocaml%{?_isa} = %{version}-%{release} -Provides: ocamldoc = %{version} +Requires: ocaml = %{version}-%{release} +Provides: ocamldoc %description ocamldoc Documentation generator for OCaml. +%package emacs +Summary: Emacs mode for OCaml +Requires: ocaml = %{version}-%{release} +Requires: emacs(bin) + +%description emacs +Emacs mode for OCaml. + + %package docs Summary: Documentation for OCaml -BuildArch: noarch Requires: ocaml = %{version}-%{release} @@ -174,7 +186,7 @@ This package contains man pages. %package compiler-libs Summary: Compiler libraries for OCaml -Requires: ocaml%{?_isa} = %{version}-%{release} +Requires: ocaml = %{version}-%{release} %description compiler-libs @@ -187,253 +199,211 @@ Note that this exposes internal details of the OCaml compiler which may not be portable between versions. -%package rpm-macros -# LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception: the project as a whole -# BSD-3-Clause: ocaml_files.py -License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception AND BSD-3-Clause -Summary: RPM macros for building OCaml packages -BuildArch: noarch -Requires: ocaml = %{version}-%{release} -Requires: python3 - - -%description rpm-macros -This package contains macros that are useful for building OCaml RPMs. - - %prep -%autosetup -S git -n %{name}-%{version}%{rcver} -# Patches touch configure.ac, so rebuild it: -autoconf --force - +%setup -q -T -b 0 -n %{name}-%{version} +%autopatch -p1 +%if ! %{with bootstrap} +cp %{_bindir}/ocamlc.byte boot/ocamlc +cp %{_bindir}/ocamllex.byte boot/ocamllex +%endif %build %ifnarch %{no_parallel_build_arches} -make="%make_build" +make="make %{?_smp_mflags}" %else unset MAKEFLAGS make=make %endif -# Set ocamlmklib default flags to include Fedora linker flags -sed -i '/ld_opts/s|\[\]|["%{build_ldflags}"]|' tools/ocamlmklib.ml - -# Expose a dependency on the math library -sed -i '/^EXTRACAMLFLAGS=/aLINKOPTS=-cclib -lm' otherlibs/unix/Makefile - -# Don't use %%configure macro because it sets --build, --host which -# breaks some incorrect assumptions made by OCaml's configure.ac -# -# See also: -# https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/2O4HBOK6PTQZAFAVIRDVMZGG2PYB2QHM/ -# https://github.com/ocaml/ocaml/issues/8647 -# -# We set --libdir to the unusual directory because we want OCaml to -# install its libraries and other files into a subdirectory. -# -# OC_CFLAGS/OC_LDFLAGS control what flags OCaml passes to the linker -# when doing final linking of OCaml binaries. Setting these is -# necessary to ensure that generated binaries have Fedora hardening -# features. +CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" \ ./configure \ - --prefix=%{_prefix} \ - --sysconfdir=%{_sysconfdir} \ - --mandir=%{_mandir} \ - --libdir=%{_libdir}/ocaml \ - --enable-flambda \ -%if %{native_compiler} - --enable-native-compiler \ - --enable-native-toplevel \ -%else - --disable-native-compiler \ - --disable-native-toplevel \ -%endif -%ifarch %{x86_64} %{arm64} -%if 0%{?_include_frame_pointers} - --enable-frame-pointers \ -%endif -%endif -%ifarch %{test_arches} - --enable-ocamltest \ -%else - --disable-ocamltest \ -%endif - OC_CFLAGS='%{build_cflags}' \ - OC_LDFLAGS='%{build_ldflags}' \ - %{nil} + -bindir %{_bindir} \ + -libdir %{_libdir}/ocaml \ + -x11lib %{_libdir} \ + -x11include %{_includedir} \ + -mandir %{_mandir}/man1 \ + -no-curses $make world %if %{native_compiler} $make opt $make opt.opt %endif +make -C emacs ocamltags -# Build the README and fix up references to other doc files -asciidoc -d book README.adoc -for fil in CONTRIBUTING.md HACKING.adoc INSTALL.adoc README.win32.adoc; do - sed -e "s,\"$fil\",\"https://github.com/ocaml/ocaml/blob/trunk/$fil\"," \ - -i README.html -done +# Currently these tools are supplied by Debian, but are expected +# to go upstream at some point. +includes="-nostdlib -I stdlib -I utils -I parsing -I typing -I bytecomp -I asmcomp -I driver -I otherlibs/unix -I otherlibs/str -I otherlibs/dynlink" +boot/ocamlrun ./ocamlc $includes dynlinkaux.cmo ocamlbyteinfo.ml -o ocamlbyteinfo +# ocamlplugininfo doesn't compile because it needs 'dynheader' (type +# decl) and I have no idea where that comes from +#cp otherlibs/dynlink/natdynlink.ml . +#boot/ocamlrun ./ocamlopt $includes unix.cmxa str.cmxa natdynlink.ml ocamlplugininfo.ml -o ocamlplugininfo %check -%ifarch %{ocaml_native_compiler} -# For information only, compile a binary and dump the annocheck data -# from it. Useful so we know if hardening is being enabled, but don't -# fail because not every hardening feature can be enabled here. -echo 'print_endline "hello, world"' > hello.ml -./ocamlopt.opt -verbose -I stdlib hello.ml -o hello ||: -annocheck -v hello ||: -%endif - %ifarch %{test_arches} +cd testsuite + %ifarch %{test_arches_required} -make -j1 tests +make -j1 all %else -make -j1 tests ||: +make -j1 all ||: %endif %endif %install -%make_install +make install \ + BINDIR=$RPM_BUILD_ROOT%{_bindir} \ + LIBDIR=$RPM_BUILD_ROOT%{_libdir}/ocaml \ + MANDIR=$RPM_BUILD_ROOT%{_mandir} +perl -pi -e "s|^$RPM_BUILD_ROOT||" $RPM_BUILD_ROOT%{_libdir}/ocaml/ld.conf -# OCaml 5.5.0 uses relative paths in ld.conf by default to support relocatable -# OCaml, which we don't need. Overwrite ld.conf with the absolute path. -echo %{_libdir}/ocaml/stublibs > $RPM_BUILD_ROOT%{_libdir}/ocaml/ld.conf +( + # install emacs files + cd emacs; + make install \ + BINDIR=$RPM_BUILD_ROOT%{_bindir} \ + EMACSDIR=$RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp + make install-ocamltags BINDIR=$RPM_BUILD_ROOT%{_bindir} +) echo %{version} > $RPM_BUILD_ROOT%{_libdir}/ocaml/fedora-ocaml-release -# Remove the installed documentation. We will install it using %%doc -rm -rf $RPM_BUILD_ROOT%{_docdir}/ocaml +# Remove rpaths from stublibs .so files. +chrpath --delete $RPM_BUILD_ROOT%{_libdir}/ocaml/stublibs/*.so -mkdir -p $RPM_BUILD_ROOT%{rpmmacrodir} -install -m 0644 %{SOURCE1} $RPM_BUILD_ROOT%{rpmmacrodir}/macros.ocaml-rpm +install -m 0755 ocamlbyteinfo $RPM_BUILD_ROOT%{_bindir} +#install -m 0755 ocamlplugininfo $RPM_BUILD_ROOT%{_bindir} -mkdir -p $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat -install -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat +find $RPM_BUILD_ROOT -name .ignore -delete + +# Remove .cmt and .cmti files, for now. We could package them later. +# See also: http://www.ocamlpro.com/blog/2012/08/20/ocamlpro-and-4.00.0.html +find $RPM_BUILD_ROOT \( -name '*.cmt' -o -name '*.cmti' \) -a -delete %files -%license LICENSE +%doc LICENSE %{_bindir}/ocaml +%{_bindir}/ocamlbyteinfo %{_bindir}/ocamlcmt -%{_bindir}/ocamlcp %{_bindir}/ocamldebug -%{_bindir}/ocamlmklib -%{_bindir}/ocamlmktop -%{_bindir}/ocamlprof +%{_bindir}/ocaml-instr-graph +%{_bindir}/ocaml-instr-report +#%{_bindir}/ocamlplugininfo %{_bindir}/ocamlyacc # symlink to either .byte or .opt version %{_bindir}/ocamlc +%{_bindir}/ocamlcp %{_bindir}/ocamldep %{_bindir}/ocamllex +%{_bindir}/ocamlmklib +%{_bindir}/ocamlmktop %{_bindir}/ocamlobjinfo +%{_bindir}/ocamloptp +%{_bindir}/ocamlprof # bytecode versions %{_bindir}/ocamlc.byte +%{_bindir}/ocamlcp.byte %{_bindir}/ocamldep.byte %{_bindir}/ocamllex.byte +%{_bindir}/ocamlmklib.byte +%{_bindir}/ocamlmktop.byte %{_bindir}/ocamlobjinfo.byte +%{_bindir}/ocamloptp.byte +%{_bindir}/ocamlprof.byte %if %{native_compiler} # native code versions %{_bindir}/ocamlc.opt +%{_bindir}/ocamlcp.opt %{_bindir}/ocamldep.opt %{_bindir}/ocamllex.opt +%{_bindir}/ocamlmklib.opt +%{_bindir}/ocamlmktop.opt %{_bindir}/ocamlobjinfo.opt +%{_bindir}/ocamloptp.opt +%{_bindir}/ocamlprof.opt %endif %if %{native_compiler} -%{_bindir}/ocamlnat %{_bindir}/ocamlopt %{_bindir}/ocamlopt.byte %{_bindir}/ocamlopt.opt -%{_bindir}/ocamloptp %endif +#%{_libdir}/ocaml/addlabels +#%{_libdir}/ocaml/scrapelabels +%{_libdir}/ocaml/camlheader +%{_libdir}/ocaml/camlheader_ur %{_libdir}/ocaml/expunge +%{_libdir}/ocaml/extract_crc +%{_libdir}/ocaml/ld.conf %{_libdir}/ocaml/Makefile.config - %{_libdir}/ocaml/*.a +%if %{natdynlink} +%{_libdir}/ocaml/*.cmxs +%endif %if %{native_compiler} %{_libdir}/ocaml/*.cmxa %{_libdir}/ocaml/*.cmx %{_libdir}/ocaml/*.o +%{_libdir}/ocaml/libasmrun_shared.so %endif %{_libdir}/ocaml/*.mli -%{_libdir}/ocaml/sys.ml.in - -%{_libdir}/ocaml/{dynlink,runtime_events,str,threads,unix}/*.mli +%{_libdir}/ocaml/libcamlrun_shared.so +%{_libdir}/ocaml/objinfo_helper +%{_libdir}/ocaml/vmthreads/*.mli +%{_libdir}/ocaml/vmthreads/*.a %if %{native_compiler} -%{_libdir}/ocaml/{dynlink,runtime_events,str,threads,unix}/*.a -%{_libdir}/ocaml/{dynlink,runtime_events,str,threads,unix}/*.cmxa -%{_libdir}/ocaml/{dynlink,profiling,runtime_events,str,threads,unix}/*.cmx -%{_libdir}/ocaml/profiling/*.o +%{_libdir}/ocaml/threads/*.a +%{_libdir}/ocaml/threads/*.cmxa +%{_libdir}/ocaml/threads/*.cmx %endif -%if %{natdynlink} -%{_libdir}/ocaml/{runtime_events,str,unix}/*.cmxs -%endif - -# headers %{_libdir}/ocaml/caml +%exclude %{_libdir}/ocaml/graphicsX11.mli %files runtime -%doc README.html Changes -%license LICENSE +%doc README.adoc LICENSE Changes %{_bindir}/ocamlrun -%{_bindir}/*ocamlrun-a100 %{_bindir}/ocamlrund -%{_bindir}/*ocamlrund-a100 %{_bindir}/ocamlruni -%{_bindir}/*ocamlruni-a100 %dir %{_libdir}/ocaml -%{_libdir}/ocaml/libasmrun*.so -%{_libdir}/ocaml/libcamlrun*.so +%{_libdir}/ocaml/VERSION %{_libdir}/ocaml/*.cmo %{_libdir}/ocaml/*.cmi %{_libdir}/ocaml/*.cma -%{_libdir}/ocaml/ld.conf %{_libdir}/ocaml/stublibs -%dir %{_libdir}/ocaml/dynlink -%{_libdir}/ocaml/dynlink/META -%{_libdir}/ocaml/dynlink/*.cmi -%{_libdir}/ocaml/dynlink/*.cma -%dir %{_libdir}/ocaml/profiling -%{_libdir}/ocaml/profiling/*.cmo -%{_libdir}/ocaml/profiling/*.cmi -%dir %{_libdir}/ocaml/runtime_events -%{_libdir}/ocaml/runtime_events/META -%{_libdir}/ocaml/runtime_events/*.cmi -%{_libdir}/ocaml/runtime_events/*.cma -%{_libdir}/ocaml/runtime-launch-info -%{_libdir}/ocaml/stdlib -%dir %{_libdir}/ocaml/str -%{_libdir}/ocaml/str/META -%{_libdir}/ocaml/str/*.cmi -%{_libdir}/ocaml/str/*.cma +%{_libdir}/ocaml/target_camlheaderd +%{_libdir}/ocaml/target_camlheaderi +%dir %{_libdir}/ocaml/vmthreads +%{_libdir}/ocaml/vmthreads/*.cmi +%{_libdir}/ocaml/vmthreads/*.cma %dir %{_libdir}/ocaml/threads -%{_libdir}/ocaml/threads/META %{_libdir}/ocaml/threads/*.cmi %{_libdir}/ocaml/threads/*.cma -%dir %{_libdir}/ocaml/unix -%{_libdir}/ocaml/unix/META -%{_libdir}/ocaml/unix/*.cmi -%{_libdir}/ocaml/unix/*.cma %{_libdir}/ocaml/fedora-ocaml-release +%exclude %{_libdir}/ocaml/graphicsX11.cmi %files source -%license LICENSE +%doc LICENSE %{_libdir}/ocaml/*.ml -%{_libdir}/ocaml/*.cmt* -%{_libdir}/ocaml/*/*.cmt* + + +%files x11 +%doc LICENSE +%{_libdir}/ocaml/graphicsX11.cmi +%{_libdir}/ocaml/graphicsX11.mli %files ocamldoc -%license LICENSE +%doc LICENSE %doc ocamldoc/Changes.txt %{_bindir}/ocamldoc* %{_libdir}/ocaml/ocamldoc @@ -444,249 +414,28 @@ install -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat %{_mandir}/man3/* +%files emacs +%doc emacs/README +%{_datadir}/emacs/site-lisp/* +%{_bindir}/ocamltags + + %files compiler-libs -%license LICENSE -%{_libdir}/ocaml/compiler-libs - - -%files rpm-macros -%{rpmmacrodir}/macros.ocaml-rpm -%{_rpmconfigdir}/redhat/ocaml_files.py +%doc LICENSE +%dir %{_libdir}/ocaml/compiler-libs +%{_libdir}/ocaml/compiler-libs/*.mli +%{_libdir}/ocaml/compiler-libs/*.cmi +%{_libdir}/ocaml/compiler-libs/*.cmo +%{_libdir}/ocaml/compiler-libs/*.cma +%if %{native_compiler} +%{_libdir}/ocaml/compiler-libs/*.a +%{_libdir}/ocaml/compiler-libs/*.cmxa +%{_libdir}/ocaml/compiler-libs/*.cmx +%{_libdir}/ocaml/compiler-libs/*.o +%endif %changelog -* Thu Jul 16 2026 Fedora Release Engineering - 5.5.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild - -* Tue Jun 23 2026 Jerry James - 5.5.0-1 -- New upstream version 5.5.0 (RHBZ#2442622) -- Drop upstreamed fix for arm64 frame pointers -- Reenable LTO -- Move ld.conf, libasmrun, and libcamlrun to ocaml-runtime -- Drop hardlink dependency; rpm now does this by default -- Drop unused utilx-linux dependency - -* Thu Feb 26 2026 Richard W.M. Jones - 5.4.1-4 -- Backport fix for arm64 frame pointers - -* Fri Feb 20 2026 Richard W.M. Jones - 5.4.1-1 -- New upstream version 5.4.1 (RHBZ#2440356) - -* Fri Jan 16 2026 Fedora Release Engineering - 5.4.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild - -* Mon Oct 13 2025 Richard W.M. Jones - 5.4.0-1 -- New upstream version 5.4.0 (RHBZ#2368289) - -* Thu Jul 24 2025 Fedora Release Engineering - 5.3.0-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Sun Jun 22 2025 Yaakov Selkowitz - 5.3.0-3 -- Fix RPM macros for Python 3.14 - -* Fri Jan 17 2025 Fedora Release Engineering - 5.3.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Thu Jan 9 2025 Jerry James - 5.3.0-1 -- New upstream version 5.3.0 -- Drop upstreamed patches -- BR git-core instead of git - -* Thu Jul 18 2024 Fedora Release Engineering - 5.2.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Wed Jun 19 2024 Richard W.M. Jones - 5.2.0-2 -- Add fix for ppc64le code generation issue found after 5.2.0 was released - -* Thu May 23 2024 Jerry James - 5.2.0-1 -- New upstream version 5.2.0 (RHBZ#2269805) -- Drop upstreamed frame pointer and s390x patches - -* Thu Jan 25 2024 Fedora Release Engineering - 5.1.1-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Sun Jan 21 2024 Fedora Release Engineering - 5.1.1-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Mon Dec 18 2023 Richard W.M. Jones - 5.1.1-2 -- Add s390x code generation fix - https://github.com/ocaml/ocaml/issues/12829 - -* Mon Dec 11 2023 Richard W.M. Jones - 5.1.1-1 -- New upstream version 5.1.1 (RHBZ#2239227) - -* Tue Nov 14 2023 Yaakov Selkowitz - 5.1.0-5 -- Drop unused BR parallel - -* Fri Oct 06 2023 Richard W.M. Jones - 5.1.0-4 -- Use BR ocaml-srpm-macros to force latest to be built against - -* Thu Oct 05 2023 Richard W.M. Jones - 5.1.0-3 -- Rebuild against updated ocaml-srpm-macros - -* Thu Oct 5 2023 Richard W.M. Jones - 5.1.0-2 -- Add upstream patch added after 5.1.0 - -* Wed Oct 4 2023 Jerry James - 5.1.0-1 -- Version 5.1.0 -- Add LicenseRef-Fedora-Public-Domain to the runtime License field -- New ocaml-rpm-macros subpackage -- Depend on libzstd-devel for compressed marshaling -- Disable LTO - -* Thu Jul 20 2023 Fedora Release Engineering - 5.0.0-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild - -* Wed Jul 12 2023 Richard W.M. Jones - 5.0.0-3 -- Force ocaml-srpm-macros to be the latest version. - -* Wed Jun 14 2023 Jerry James - 5.0.0-2 -- Version 5.0.0 -- Convert License tag to SPDX -- Ship HTML documentation instead of asciidoc source -- Set ocamlmklib default flags to the Fedora linker flags -- Enable frame pointers on x86_64 - -* Mon Jan 23 2023 Richard W.M. Jones - 4.14.0-5 -- Rebuild OCaml packages for F38 - -* Thu Jan 19 2023 Fedora Release Engineering - 4.14.0-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild - -* Mon Sep 5 2022 Richard W.M. Jones - 4.14.0-3 -- Include more upstream patches from 4.14 branch - -* Fri Jul 22 2022 Fedora Release Engineering - 4.14.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild - -* Sat Jun 18 2022 Richard W.M. Jones - 4.14.0-1 -- New upstream version 4.14.0 - -* Thu Jun 9 2022 Jerry James - 4.13.1-4 -- Fix the Source0 URL -- chrpath is no longer needed -- Use the %%license macro -- Build the test binaries so the tests will run - -* Fri Feb 04 2022 Richard W.M. Jones - 4.13.1-4 -- Rebuild 4.13.1 to remove package notes - -* Wed Jan 26 2022 Richard W.M. Jones - 4.13.1-3 -- Disable package note misfeature -- Remove duplicate flags from mkexe - -* Thu Jan 20 2022 Fedora Release Engineering - 4.13.1-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild - -* Mon Oct 04 2021 Richard W.M. Jones - 4.13.1-1 -- New upstream version 4.13.1 - -* Thu Jul 22 2021 Fedora Release Engineering - 4.12.0-3 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild - -* Wed Jun 23 2021 Richard W.M. Jones - 4.12.0-2 -- Move to final version of upstream patch for non-constant SIGSTKSZ - -* Sun Feb 28 2021 Richard W.M. Jones - 4.12.0-1 -- OCaml 4.12.0 release (RHBZ#1893381). -- Workaround for glibc non-constant SIGSTKSZ - (https://github.com/ocaml/ocaml/issues/10250) -- Package *.cmt and *.cmti files. -- Remove objinfo_helper since it is no longer built. - -* Tue Jan 26 2021 Fedora Release Engineering - 4.11.1-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild - -* Tue Sep 01 2020 Richard W.M. Jones - 4.11.1-1 -- OCaml 4.11.1 release (RHBZ#1870368#c26). - -* Fri Aug 21 2020 Richard W.M. Jones - 4.11.0-1 -- OCaml 4.11.0 release (RHBZ#1870368). - -* Tue Aug 04 2020 Richard W.M. Jones - 4.11.0-0.9.dev2 -- Bump and rebuild to fix DWARF versioning issues. -- Enable LTO again. - -* Tue Jul 28 2020 Fedora Release Engineering - 4.11.0-0.7.dev2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild - -* Tue Jul 14 2020 Tom Stellard - 4.11.0-0.6.dev2 -- Use make macros -- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro - -* Wed Jul 01 2020 Jeff Law - 4.11.0-0.5.dev2.fc33 -- Disable LTO - -* Mon May 04 2020 Richard W.M. Jones - 4.11.0-0.4.dev2.fc33 -- Move to OCaml 4.11.0+dev2-2020-04-22. -- Backport upstream RISC-V backend from 4.12 + fixes. -- Enable tests on riscv64. -- Disable ocaml-instr-* tools on riscv64. - -* Tue Apr 21 2020 Richard W.M. Jones - 4.11.0-0.3.pre.fc33 -- Add fixes for various issues found in the previous build. - -* Fri Apr 17 2020 Richard W.M. Jones - 4.11.0-0.2.pre.fc33 -- Move to OCaml 4.11.0 pre-release with support for RISC-V. - -* Sat Apr 11 2020 Richard W.M. Jones - 4.10.0-4.fc33 -- Fix RISC-V backend. - -* Thu Apr 02 2020 Richard W.M. Jones - 4.10.0-3.fc33 -- Update all OCaml dependencies for RPM 4.16. - -* Thu Feb 27 2020 Richard W.M. Jones - 4.10.0-2.fc33 -- Add dist tag. - -* Tue Feb 25 2020 Richard W.M. Jones - 4.10.0-1 -- OCaml 4.10.0 final. - -* Wed Jan 29 2020 Fedora Release Engineering - 4.10.0-0.beta1.0.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild - -* Sat Jan 18 2020 Richard W.M. Jones - 4.10.0-0.beta1 -- OCaml 4.10.0+beta1. - -* Tue Jan 07 2020 Richard W.M. Jones - 4.09.0-13 -- Bump release and rebuild. - -* Tue Jan 07 2020 Richard W.M. Jones - 4.09.0-4 -- OCaml 4.09.0 for riscv64 - -* Tue Dec 10 2019 Richard W.M. Jones - 4.09.0-3 -- Require redhat-rpm-config to get hardening flags when linking. - -* Thu Dec 05 2019 Richard W.M. Jones - 4.09.0-2 -- OCaml 4.09.0 final. -- Use autosetup, remove old setup line. -- Remove ocamloptp binaries. -- Rename target_camlheader[di] -> camlheader[di] files. -- Remove vmthreads - old threading library which is no longer built. -- Remove x11 subpackage which is obsolete. -- Further fixes to CFLAGS and annobin. - -* Fri Aug 16 2019 Richard W.M. Jones - 4.08.1-1 -- OCaml 4.08.1 final. - -* Tue Jul 30 2019 Richard W.M. Jones - 4.08.1-0.rc2.1 -- OCaml 4.08.1+rc2. -- Include fix for miscompilation of off_t on 32 bit architectures. - -* Thu Jul 25 2019 Fedora Release Engineering - 4.08.0-2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild - -* Thu Jun 27 2019 Richard W.M. Jones - 4.08.0-1 -- OCaml 4.08.0 (RHBZ#1673688). - -* Fri Apr 26 2019 Richard W.M. Jones - 4.08.0-0.beta3.1 -- OCaml 4.08.0 beta 3 (RHBZ#1673688). -- emacs subpackage has been dropped (from upstream): - https://github.com/ocaml/ocaml/pull/2078#issuecomment-443322613 - https://github.com/Chris00/caml-mode -- Remove ocamlbyteinfo and ocamlpluginfo, neither can be compiled. -- Disable tests on all architectures, temporarily hopefully. -- Package threads/*.mli files. - * Fri Feb 01 2019 Fedora Release Engineering - 4.07.0-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild diff --git a/ocaml_files.py b/ocaml_files.py deleted file mode 100644 index 0e4658e..0000000 --- a/ocaml_files.py +++ /dev/null @@ -1,451 +0,0 @@ -# Copyright 2022-3, Jerry James -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the -# distribution. -# 3. Neither the name of Red Hat nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import argparse -import os -import shutil -import string -import sys -from collections.abc import Iterable, Iterator -from enum import Enum, auto -from typing import Callable, final - -# Version of this script -version=2 - -# -# BUILDROOT CATEGORIZATION -# - -# Directories to ignore when generating %dir entries -root_dirs: set[str] = { - '/', - '/etc', - '/usr', - '/usr/bin', - '/usr/lib', - '/usr/lib/ocaml', - '/usr/lib/ocaml/caml', - '/usr/lib/ocaml/stublibs', - '/usr/lib/ocaml/threads', - '/usr/lib64', - '/usr/lib64/ocaml', - '/usr/lib64/ocaml/caml', - '/usr/lib64/ocaml/stublibs', - '/usr/lib64/ocaml/threads', - '/usr/libexec', - '/usr/sbin', - '/usr/share', - '/usr/share/doc' -} - -def find_buildroot_toplevel(buildroot: str) -> list[str]: - """Find toplevel files and directories in the buildroot. - - :param str buildroot: path to the buildroot - :return: a list of toplevel files and directories in the buildroot - """ - bfiles: list[str] = [] - for path, dirs, files in os.walk(buildroot): - for i in range(len(dirs) - 1, -1, -1): - d = os.path.join(path, dirs[i])[len(buildroot):] - if d not in root_dirs and not d.startswith('/usr/share/man'): - bfiles.append(d) - del dirs[i] - for f in files: - realfile = os.path.join(path, f)[len(buildroot):] - if realfile.startswith('/usr/share/man'): - bfiles.append(realfile + '*') - else: - bfiles.append(realfile) - return bfiles - -# File suffixes that go into a devel subpackage -dev_suffixes: set[str] = { - 'a', 'cmo', 'cmt', 'cmti', 'cmx', 'cmxa', 'h', 'idl', 'ml', 'mli', 'o' -} - -def is_devel_file(filname: str) -> bool: - """Determine whether a file belongs to a devel subpackage. - - :param str filname: the filename to check - :return: True if the file belongs to a devel subpackage, else False - """ - return (filname == 'dune-package' or filname == 'opam' or - (os.path.splitext(filname)[1][1:] in dev_suffixes - and not filname.endswith('_top_init.ml'))) - -def find_buildroot_all(buildroot: str, devel: bool, add_star: bool) -> list[set[str]]: - """Find all files and directories in the buildroot and optionally - categorize them as 'main' or 'devel'. - - :param Namespace args: parsed command line arguments - :param bool devel: True to split into 'main' and 'devel', False otherwise - :param bool add_star: True to add a star to man page filenames - :return: a list of files and directories, in this order: main files, - main directories, devel files, and devel directories - """ - bfiles: list[set[str]] = [set(), set(), set()] - bdirs: set[str] = set() - for path, dirs, files in os.walk(buildroot): - for d in dirs: - realdir = os.path.join(path, d)[len(buildroot):] - if realdir not in root_dirs and not realdir.startswith('/usr/share/man'): - bdirs.add(realdir) - for f in files: - realfile = os.path.join(path, f)[len(buildroot):] - if devel and is_devel_file(os.path.basename(realfile)): - bfiles[2].add(realfile) - else: - if add_star and realfile.startswith('/usr/share/man'): - bfiles[0].add(realfile + '*') - else: - bfiles[0].add(realfile) - parentdir = os.path.dirname(realfile) - if parentdir in bdirs: - bfiles[1].add(parentdir) - bdirs.remove(parentdir) - # Catch intermediate directories, as in ocaml-mtime - parentdir = os.path.dirname(parentdir) - if parentdir in bdirs: - bfiles[1].add(parentdir) - bdirs.remove(parentdir) - bfiles.append(bdirs) - return bfiles - -# -# INSTALL FILE LEXER AND PARSER -# - -class TokenType(Enum): - """The types of tokens that can appear in an opam *.install file.""" - ERROR = auto() - COLON = auto() - LBRACE = auto() - RBRACE = auto() - LBRACK = auto() - RBRACK = auto() - STRING = auto() - FIELD = auto() - -@final -class InstallFileLexer(Iterator[tuple[TokenType, str]]): - """Convert an opam *.install file into a sequence of tokens.""" - __slots__ = ['index', 'text'] - - def __init__(self, filname: str) -> None: - """Create an opam *.install file lexer. - - :param str filname: the name of the file to read from - """ - self.index = 0 - with open(filname, 'r') as f: - # Limit reads to 4 MB in case this file is bogus. - # Most install files are under 4K. - self.text = f.read(4194304) - - def skip_whitespace(self) -> None: - """Skip over whitespace in the input.""" - while self.index < len(self.text) and \ - (self.text[self.index] == '#' or - self.text[self.index] in string.whitespace): - if self.text[self.index] == '#': - while (self.index < len(self.text) and - self.text[self.index] != '\n' and - self.text[self.index] != '\r'): - self.index += 1 - else: - self.index += 1 - - def __next__(self) -> tuple[TokenType, str]: - """Get the next token from the opam *.install file. - - :return: a pair containing the type and text of the next token - """ - self.skip_whitespace() - if self.index < len(self.text): - ch = self.text[self.index] - if ch == ':': - self.index += 1 - return (TokenType.COLON, ch) - if ch == '{': - self.index += 1 - return (TokenType.LBRACE, ch) - if ch == '}': - self.index += 1 - return (TokenType.RBRACE, ch) - if ch == '[': - self.index += 1 - return (TokenType.LBRACK, ch) - if ch == ']': - self.index += 1 - return (TokenType.RBRACK, ch) - if ch == '"': - start = self.index + 1 - end = start - while end < len(self.text) and self.text[end] != '"': - end += 2 if self.text[end] == '\\' else 1 - self.index = end + 1 - return (TokenType.STRING, self.text[start:end]) - if ch in string.ascii_letters: - start = self.index - end = start + 1 - while (end < len(self.text) and - (self.text[end] == '_' or - self.text[end] in string.ascii_letters)): - end += 1 - self.index = end - return (TokenType.FIELD, self.text[start:end]) - return (TokenType.ERROR, ch) - else: - raise StopIteration - -@final -class InstallFileParser(Iterable[tuple[str, bool, str, str]]): - """Parse opam *.install files.""" - - __slots__ = ['pkgname', 'lexer', 'libdir'] - - def __init__(self, filname: str, libdir: str) -> None: - """Initialize an OCaml .install file parser. - - :param str filname: name of the .install file to parse - :param str libdir: the OCaml library directory - """ - self.pkgname = os.path.splitext(os.path.basename(filname))[0] - self.lexer = InstallFileLexer(filname) - self.libdir = libdir - - def __iter__(self) -> Iterator[tuple[str, bool, str, str]]: - """Parse a .install file. - If there are any parse errors, we assume this file is not really an - opam .install file and abandon the parse. - """ - # Map opam installer names to directories - opammap: dict[str, str] = { - 'lib': os.path.join(self.libdir, self.pkgname), - 'lib_root': self.libdir, - 'libexec': os.path.join(self.libdir, self.pkgname), - 'libexec_root': self.libdir, - 'bin': '/usr/bin', - 'sbin': '/usr/sbin', - 'toplevel': os.path.join(self.libdir, 'toplevel'), - 'share': os.path.join('/usr/share', self.pkgname), - 'share_root': '/usr/share', - 'etc': os.path.join('/etc', self.pkgname), - 'doc': os.path.join('/usr/doc', self.pkgname), - 'stublibs': os.path.join(self.libdir, 'stublibs'), - 'man': '/usr/share/man' - } - - # Parse the file - try: - toktyp, token = next(self.lexer) - while toktyp == TokenType.FIELD: - libname = token - toktyp, token = next(self.lexer) - if toktyp != TokenType.COLON: - return - - toktyp, token = next(self.lexer) - if toktyp != TokenType.LBRACK: - return - - directory = opammap.get(libname) - if not directory: - return - - toktyp, token = next(self.lexer) - while toktyp == TokenType.STRING: - source = token - optional = source[0] == '?' - if optional: - source = source[1:] - nexttp, nexttk = next(self.lexer) - if nexttp == TokenType.LBRACE: - nexttp, nexttk = next(self.lexer) - if nexttp == TokenType.STRING: - filname = os.path.join(directory, nexttk) - bracetp, bractk = next(self.lexer) - if bracetp != TokenType.RBRACE: - return - nexttp, nexttk = next(self.lexer) - else: - return - elif libname == 'man': - index = token.rfind('.') - if index < 0: - return - mandir = os.path.join(directory, 'man' + token[index+1:]) - filname = os.path.join(mandir, os.path.basename(token)) - else: - filname = os.path.join(directory, os.path.basename(token)) - toktyp, token = nexttp, nexttk - yield (self.pkgname, optional, source, filname) - - if toktyp != TokenType.RBRACK: - return - toktyp, token = next(self.lexer) - except StopIteration: - return - -def install_files(buildroot: str, libdir: str) -> None: - """Install the files listed in opam .install files in the buildroot. - - For some projects, there are install files in both the project root - directory and somewhere under "_build", so be careful not to parse the same - install file twice. - - :param str buildroot: path to the buildroot - :param str libdir: the OCaml library directory - """ - install_files = set() - for path, dirs, files in os.walk('.'): - for f in files: - if f.endswith('.install') and f not in install_files: - install_files.add(f) - parser = InstallFileParser(os.path.join(path, f), libdir) - for _, optional, source, filname in parser: - if not optional or os.path.exists(source): - installpath = os.path.join(buildroot, filname[1:]) - os.makedirs(os.path.dirname(installpath), exist_ok=True) - shutil.copy2(source, installpath) - -def get_package_map(buildroot: str, libdir: str, devel: bool) -> dict[str, set[str]]: - """Create a map from package names to installed files from the opam .install - files in the buildroot. - - For some projects, there are install files in both the project root - directory and somewhere under "_build", so be careful not to parse the same - install file twice.""" - - pmap: dict[str, set[str]] = dict() - install_files = set() - - def add_pkg(pkgname: str, filname: str) -> None: - """Add a mapping from a package name to a filename. - - :param str pkgname: the package that acts as the map key - :param str filname: the filename to add to the package set - """ - if pkgname not in pmap: - pmap[pkgname] = set() - pmap[pkgname].add(filname) - - installed = find_buildroot_all(buildroot, devel, False) - for path, dirs, files in os.walk('.'): - for f in files: - if f.endswith('.install') and f not in install_files: - install_files.add(f) - parser = InstallFileParser(os.path.join(path, f), libdir) - for pkgname, _, _, filname in parser: - if filname in installed[0]: - if filname.startswith('/usr/share/man'): - add_pkg(pkgname, filname + '*') - else: - add_pkg(pkgname, filname) - dirname = os.path.dirname(filname) - if dirname in installed[1]: - add_pkg(pkgname, '%dir ' + dirname) - installed[1].remove(dirname) - elif filname in installed[2]: - if filname.startswith('/usr/share/man'): - add_pkg(pkgname + '-devel', filname + '*') - else: - add_pkg(pkgname + '-devel', filname) - dirname = os.path.dirname(filname) - if dirname in installed[3]: - add_pkg(pkgname + '-devel', '%dir ' + dirname) - installed[3].remove(dirname) - return pmap - -# -# MAIN INTERFACE -# - -def ocaml_files(no_devel: bool, separate: bool, install: bool, buildroot: str, - libdir: str) -> None: - """Generate %files lists from an installed buildroot. - - :param bool no_devel: False to split files into a main package and a devel - package - :param bool separate: True to place each OCaml module in an RPM package - :param bool install: True to install files, False to generate %files - :param str buildroot: the installed buildroot - :param str libdir: the OCaml library directory - """ - if install: - install_files(buildroot, libdir) - elif separate: - pkgmap = get_package_map(buildroot, libdir, not no_devel) - for pkg in pkgmap: - with open('.ofiles-' + pkg, 'w') as f: - for entry in pkgmap[pkg]: - f.write(entry + '\n') - elif no_devel: - with open('.ofiles', 'w') as f: - for entry in find_buildroot_toplevel(buildroot): - f.write(entry + '\n') - else: - files = find_buildroot_all(buildroot, True, True) - with open('.ofiles', 'w') as f: - for entry in files[0]: - f.write(entry + '\n') - for entry in files[1]: - f.write('%dir ' + entry + '\n') - with open('.ofiles-devel', 'w') as f: - for entry in files[2]: - f.write(entry + '\n') - for entry in files[3]: - f.write('%dir ' + entry + '\n') - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description='Support for building OCaml RPM packages') - parser.add_argument('-i', '--install', - action='store_true', - default=False, - help='install files instead of generating %%files') - parser.add_argument('-n', '--no-devel', - action='store_true', - default=False, - help='suppress creation of a devel subpackage') - parser.add_argument('-s', '--separate', - action='store_true', - default=False, - help='separate packaging. Each OCaml module is in a distinct RPM package. All modules are in a single RPM package by default.') - parser.add_argument('-v', '--version', - action='version', - version=f'%(prog)s {str(version)}') - parser.add_argument('buildroot', help='RPM build root') - parser.add_argument('libdir', help='OCaml library directory') - args = parser.parse_args() - ocaml_files(args.no_devel, - args.separate, - args.install, - args.buildroot, - args.libdir) diff --git a/sources b/sources index 7c0afd0..c116389 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ocaml-5.5.0.tar.gz) = bf13c18cd1fc7b2e5e9623024ea8623710f646ff2fbc0f59dab70e4d4318ed8623bdcc3ec59ce37af07af2b767f520dea23fb474c26297b3e858b6c8e080b4e6 +SHA512 (ocaml-4.07.0.tar.xz) = 1c27c2c81919af6b51824fb69f203ebca009ab093af0dffb0dbe66d08ba980525ee14e9426edf142c527315144602ac9ef6e36d2266714b5f7ccc7c063e75ac8 diff --git a/tests/basic-test.sh b/tests/basic-test.sh deleted file mode 100755 index 514bea0..0000000 --- a/tests/basic-test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -set -e -set -x - -# Compile a trivial program and run it. -echo 'print_endline "hello, world"' > hello.ml -ocamlc.opt hello.ml -o hello -./hello -ocamlopt.opt hello.ml -o hello -./hello diff --git a/tests/tests.yml b/tests/tests.yml deleted file mode 100755 index b9ec89a..0000000 --- a/tests/tests.yml +++ /dev/null @@ -1,11 +0,0 @@ -- hosts: localhost - roles: - - role: standard-test-basic - tags: - - classic - required_packages: - - ocaml - tests: - - simple: - dir: . - run: ./basic-test.sh