From 6ee1e57a7a637c69da49d6f03eaa152eb3bf4f41 Mon Sep 17 00:00:00 2001 From: yueyaoqiang Date: Wed, 5 Jun 2024 13:46:08 +0800 Subject: [PATCH] Add loongarch64 and sw_64 support --- 0004-Add-loongarch64-native-support.patch | 4001 +++++++++++++++++++++ ocaml.spec | 23 +- 2 files changed, 4019 insertions(+), 5 deletions(-) create mode 100644 0004-Add-loongarch64-native-support.patch diff --git a/0004-Add-loongarch64-native-support.patch b/0004-Add-loongarch64-native-support.patch new file mode 100644 index 0000000..44e00ad --- /dev/null +++ b/0004-Add-loongarch64-native-support.patch @@ -0,0 +1,4001 @@ +diff -Naur ocaml-4.14.1/asmcomp/dune ocaml-4.14.1_bak/asmcomp/dune +--- ocaml-4.14.1/asmcomp/dune 2022-12-19 23:49:43.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/dune 2024-06-05 10:25:13.621079410 +0800 +@@ -22,7 +22,8 @@ + (glob_files i386/*.ml) + (glob_files power/*.ml) + (glob_files riscv/*.ml) +- (glob_files s390x/*.ml)) ++ (glob_files s390x/*.ml) ++` (glob_files loongarch64/*.ml)) + (action (bash "cp `grep '^ARCH=' %{conf} | cut -d'=' -f2`/*.ml ."))) + + (rule +@@ -35,7 +36,8 @@ + i386/emit.mlp + power/emit.mlp + riscv/emit.mlp +- s390x/emit.mlp) ++ s390x/emit.mlp ++ loongarch64/emit.mlp) + (action + (progn + (with-stdout-to contains-input-name +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/arch.ml ocaml-4.14.1_bak/asmcomp/loongarch64/arch.ml +--- ocaml-4.14.1/asmcomp/loongarch64/arch.ml 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/arch.ml 2024-06-05 10:28:51.281079410 +0800 +@@ -0,0 +1,91 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++(* Specific operations for the loongarch 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 *) ++ ++(* Addressing modes *) ++ ++type addressing_mode = ++ | Iindexed of int (* reg + displ *) ++ ++let is_immediate n = ++ (n <= 0x7FF) && (n >= -0x800) ++ ++(* Sizes, endianness *) ++ ++let big_endian = false ++ ++let size_addr = 8 ++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) ++ ++(* Specific operations that are pure *) ++ ++let operation_is_pure _ = true ++ ++(* Specific operations that can raise *) ++ ++let operation_can_raise _ = false +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/asmgen_loongarch64.S ocaml-4.14.1_bak/asmcomp/loongarch64/asmgen_loongarch64.S +--- ocaml-4.14.1/asmcomp/loongarch64/asmgen_loongarch64.S 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/asmgen_loongarch64.S 2024-06-05 10:28:51.293079410 +0800 +@@ -0,0 +1,75 @@ ++/**************************************************************************/ ++/* */ ++/* OCaml */ ++/* */ ++/* Nicolas Ojeda Bar */ ++/* */ ++/* Copyright 2019 Institut National de Recherche en Informatique et */ ++/* en Automatique. */ ++/* */ ++/* All rights reserved. This file is distributed under the terms of */ ++/* the GNU Lesser General Public License version 2.1, with the */ ++/* special exception on linking described in the file LICENSE. */ ++/* */ ++/**************************************************************************/ ++ ++#define STORE st.d ++#define LOAD ld.d ++ ++ .globl call_gen_code ++ .align 2 ++call_gen_code: ++ /* Set up stack frame and save callee-save registers */ ++ addi.d $sp, $sp, -208 ++ STORE $ra, $sp, 192 ++ STORE $s0, $sp, 0 ++ STORE $s1, $sp, 8 ++ STORE $s2, $sp, 16 ++ STORE $s3, $sp, 24 ++ STORE $s4, $sp, 32 ++ STORE $s5, $sp, 40 ++ STORE $s6, $sp, 48 ++ STORE $s7, $sp, 56 ++ STORE $s8, $sp, 64 ++ fst.d $fs0, $sp, 96 ++ fst.d $fs1, $sp, 104 ++ fst.d $fs2, $sp, 112 ++ fst.d $fs3, $sp, 120 ++ fst.d $fs4, $sp, 128 ++ fst.d $fs5, $sp, 136 ++ fst.d $fs6, $sp, 144 ++ fst.d $fs7, $sp, 152 ++ /* Shuffle arguments */ ++ move $t0, $a0 ++ move $a0, $a1 ++ move $a1, $a2 ++ move $a2, $a3 ++ move $a3, $a4 ++ /* Call generated asm */ ++ jirl $ra, $t0, 0 ++ /* Reload callee-save registers and return address */ ++ LOAD $ra, $sp, 192 ++ LOAD $s0, $sp, 0 ++ LOAD $s1, $sp, 8 ++ LOAD $s2, $sp ,16 ++ LOAD $s3, $sp ,24 ++ LOAD $s4, $sp ,32 ++ LOAD $s5, $sp ,40 ++ LOAD $s6, $sp ,48 ++ LOAD $s7, $sp ,56 ++ LOAD $s8, $sp ,64 ++ fld.d $fs0, $sp, 96 ++ fld.d $fs1, $sp, 104 ++ fld.d $fs2, $sp, 112 ++ fld.d $fs3, $sp, 120 ++ fld.d $fs4, $sp, 128 ++ fld.d $fs5, $sp, 136 ++ fld.d $fs6, $sp, 144 ++ fld.d $fs7, $sp, 152 ++ addi.d $sp, $sp, 208 ++ jr $ra ++ ++ .globl caml_c_call ++ .align 2 ++caml_c_call: ++ jr $t2 +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/configure.ac ocaml-4.14.1_bak/asmcomp/loongarch64/configure.ac +--- ocaml-4.14.1/asmcomp/loongarch64/configure.ac 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/configure.ac 2024-06-05 10:28:51.289079410 +0800 +@@ -0,0 +1,2016 @@ ++#************************************************************************** ++#* * ++#* OCaml * ++#* * ++#* Sebastien Hinderer, projet Gallium, INRIA Paris * ++#* * ++#* Copyright 2018 Institut National de Recherche en Informatique et * ++#* en Automatique. * ++#* * ++#* All rights reserved. This file is distributed under the terms of * ++#* the GNU Lesser General Public License version 2.1, with the * ++#* special exception on linking described in the file LICENSE. * ++#* * ++#************************************************************************** ++ ++# Process this file with autoconf to produce a configure script. ++ ++# Require Autoconf 2.69 for repeatability in CI ++AC_PREREQ([2.69]) ++AC_INIT([OCaml], ++ m4_esyscmd([head -n1 VERSION | tr -d '\r\n']), ++ [caml-list@inria.fr], ++ [ocaml], ++ [http://www.ocaml.org]) ++ ++AC_MSG_NOTICE([Configuring OCaml version AC_PACKAGE_VERSION]) ++ ++# Configuration variables ++ ++## Command-line arguments passed to configure ++CONFIGURE_ARGS="$*" ++ ++# Command-line tools section of the Unix manual ++programs_man_section=1 ++ ++# Library section of the Unix manual ++libraries_man_section=3 ++ ++# Command to build executalbes ++# In general this command is supposed to use the CFLAGs- and LDFLAGS- ++# related variables (OC_CFLAGS and OC_LDFLAGS for ocaml-specific ++# flags, CFLAGS and LDFLAGS for generic flags chosen by the user), but ++# at the moment they are not taken into account on Windows, because ++# flexlink, which is used to build executables on this platform, can ++# not handle them. ++mkexe="\$(CC) \$(OC_CFLAGS) \$(CFLAGS) \$(OC_LDFLAGS) \$(LDFLAGS)" ++ ++# Flags for building executable files with debugging symbols ++mkexedebugflag="-g" ++common_cflags="" ++common_cppflags="" ++internal_cflags="" ++internal_cppflags="" ++ocamlc_cflags="" ++ocamlc_cppflags="" ++oc_ldflags="" ++oc_dll_ldflags="" ++with_sharedlibs=true ++ostype="Unix" ++SO="so" ++toolchain="cc" ++profinfo=false ++profinfo_width=0 ++extralibs= ++instrumented_runtime=false ++instrumented_runtime_libs="" ++bootstrapping_flexdll=false ++ ++# Information about the package ++ ++## Source directory ++AC_CONFIG_SRCDIR([runtime/interp.c]) ++ ++## Directory containing auxiliary scripts used during build ++AC_CONFIG_AUX_DIR([build-aux]) ++ ++## Output variables ++ ++AC_SUBST([CONFIGURE_ARGS]) ++AC_SUBST([native_compiler]) ++AC_SUBST([VERSION], [AC_PACKAGE_VERSION]) ++AC_SUBST([CC]) ++# Note: This is present for the flexdll bootstrap where it exposed as the old ++# TOOLPREF variable. It would be better if flexdll where updated to require ++# WINDRES instead. ++AC_SUBST([DIRECT_CPP]) ++AC_SUBST([ac_tool_prefix]) ++AC_SUBST([exeext]) ++AC_SUBST([OBJEXT]) ++AC_SUBST([libext]) ++AC_SUBST([S]) ++AC_SUBST([SO]) ++AC_SUBST([arch]) ++AC_SUBST([arch64]) ++AC_SUBST([model]) ++AC_SUBST([system]) ++AC_SUBST([systhread_support]) ++AC_SUBST([unix_or_win32]) ++AC_SUBST([unixlib]) ++AC_SUBST([outputexe]) ++AC_SUBST([outputobj]) ++AC_SUBST([syslib]) ++AC_SUBST([extralibs]) ++AC_SUBST([programs_man_section]) ++AC_SUBST([libraries_man_section]) ++AC_SUBST([fpic]) ++AC_SUBST([mkexe]) ++AC_SUBST([mkexedebugflag]) ++AC_SUBST([ccomptype]) ++AC_SUBST([toolchain]) ++AC_SUBST([oc_cflags]) ++AC_SUBST([oc_cppflags]) ++AC_SUBST([oc_ldflags]) ++AC_SUBST([oc_dll_ldflags]) ++AC_SUBST([bytecclibs]) ++AC_SUBST([nativecclibs]) ++AC_SUBST([ocamlc_cflags]) ++AC_SUBST([ocamlc_cppflags]) ++AC_SUBST([flexdir]) ++AC_SUBST([bootstrapping_flexdll]) ++AC_SUBST([long_shebang]) ++AC_SUBST([shebangscripts]) ++AC_SUBST([AR]) ++AC_SUBST([RANLIB]) ++AC_SUBST([RANLIBCMD]) ++AC_SUBST([mklib]) ++AC_SUBST([supports_shared_libraries]) ++AC_SUBST([natdynlink]) ++AC_SUBST([natdynlinkopts]) ++AC_SUBST([cmxs]) ++AC_SUBST([debug_runtime]) ++AC_SUBST([instrumented_runtime]) ++AC_SUBST([instrumented_runtime_libs]) ++AC_SUBST([has_monotonic_clock]) ++AC_SUBST([otherlibraries]) ++AC_SUBST([cc_has_debug_prefix_map]) ++AC_SUBST([as_has_debug_prefix_map]) ++AC_SUBST([with_debugger]) # TODO: rename this variable ++AC_SUBST([with_camltex]) ++AC_SUBST([ocamldoc]) ++AC_SUBST([documentation_tool]) ++AC_SUBST([documentation_tool_cmd]) ++AC_SUBST([ocamltest]) ++AC_SUBST([ASPP]) ++AC_SUBST([endianness]) ++AC_SUBST([AS]) ++AC_SUBST([asm_cfi_supported]) ++AC_SUBST([sharedlib_cflags]) ++AC_SUBST([rpath]) ++AC_SUBST([mksharedlib]) ++AC_SUBST([mkmaindll]) ++AC_SUBST([mksharedlibrpath]) ++AC_SUBST([install_bytecode_programs]) ++AC_SUBST([install_source_artifacts]) ++AC_SUBST([profinfo]) ++AC_SUBST([profinfo_width]) ++AC_SUBST([frame_pointers]) ++AC_SUBST([flambda]) ++AC_SUBST([flambda_invariants]) ++AC_SUBST([cmm_invariants]) ++AC_SUBST([windows_unicode]) ++AC_SUBST([flat_float_array]) ++AC_SUBST([function_sections]) ++AC_SUBST([afl]) ++AC_SUBST([force_safe_string]) ++AC_SUBST([default_safe_string]) ++AC_SUBST([flexdll_chain]) ++AC_SUBST([flexlink_flags]) ++AC_SUBST([PACKLD]) ++AC_SUBST([stdlib_manpages]) ++AC_SUBST([compute_deps]) ++AC_SUBST([naked_pointers]) ++AC_SUBST([naked_pointers_checker]) ++ ++## Generated files ++ ++AC_CONFIG_FILES([Makefile.build_config]) ++AC_CONFIG_FILES([Makefile.config]) ++AC_CONFIG_FILES([tools/eventlog_metadata]) ++AC_CONFIG_HEADERS([runtime/caml/m.h]) ++AC_CONFIG_HEADERS([runtime/caml/s.h]) ++ ++# Checks for system types ++ ++AC_CANONICAL_BUILD ++AC_CANONICAL_HOST ++AC_CANONICAL_TARGET ++ ++AS_CASE([$host], ++ [*-pc-windows], ++ [CC=cl ++ ccomptype=msvc ++ S=asm ++ SO=dll ++ outputexe=-Fe ++ syslib='$(1).lib'], ++ [i386-*-solaris*], ++ [AC_MSG_ERROR([Building for 32 bits target is not supported. \ ++If your host is 64 bits, you can try with './configure CC="gcc -m64"' \ ++(or "cc -m64" if you don't have GCC).])], ++ [ccomptype=cc ++ S=s ++ SO=so ++ outputexe='-o $(EMPTY)' ++ syslib='-l$(1)']) ++ ++# Environment variables that are taken into account ++ ++AC_ARG_VAR([AS], [which assembler to use]) ++AC_ARG_VAR([ASPP], [which assembler (with preprocessor) to use]) ++AC_ARG_VAR([PARTIALLD], [how to build partial (relocatable) object files]) ++ ++# Command-line arguments to configure ++ ++AC_ARG_ENABLE([debug-runtime], ++ [AS_HELP_STRING([--disable-debug-runtime], ++ [do not build runtime with debugging support])]) ++ ++AC_ARG_ENABLE([debugger], ++ [AS_HELP_STRING([--enable-debugger], ++ [build the debugger @<:@default=auto@:>@])], ++ [], ++ [enable_debugger=auto]) ++ ++AC_ARG_ENABLE([dependency-generation], ++ [AS_HELP_STRING([--disable-dependency-generation], ++ [do not compute dependency information for C sources])], ++ [], ++ [enable_dependency_generation=auto]) ++ ++AC_ARG_VAR([DLLIBS], ++ [which libraries to use (in addition to -ldl) to load dynamic libs]) ++ ++AC_ARG_ENABLE([instrumented-runtime], ++ [AS_HELP_STRING([--enable-instrumented-runtime], ++ [build the instrumented runtime @<:@default=auto@:>@])], ++ [], ++ [enable_instrumented_runtime=auto]) ++ ++AC_ARG_ENABLE([vmthreads], [], ++ [AC_MSG_ERROR([The vmthreads library is no longer available. \ ++It was deleted in OCaml 4.09.])], ++ []) ++ ++AC_ARG_ENABLE([systhreads], ++ [AS_HELP_STRING([--disable-systhreads], ++ [disable the Win32/POSIX threads library])]) ++ ++AC_ARG_ENABLE([graph-lib], [], ++ [AC_MSG_ERROR([The graphics library is no longer distributed with OCaml \ ++since version 4.09. It is now distributed as a separate "graphics" package: \ ++https://github.com/ocaml/graphics])], ++ []) ++ ++AC_ARG_ENABLE([str-lib], ++ [AS_HELP_STRING([--disable-str-lib], ++ [do not build the str library])]) ++ ++AC_ARG_ENABLE([unix-lib], ++ [AS_HELP_STRING([--disable-unix-lib], ++ [do not build the unix library])]) ++ ++AC_ARG_ENABLE([bigarray-lib], ++ [AS_HELP_STRING([--disable-bigarray-lib], ++ [do not build the legacy separate bigarray library])]) ++ ++AC_ARG_ENABLE([ocamldoc], ++ [AS_HELP_STRING([--disable-ocamldoc], ++ [do not build the ocamldoc documentation system])], ++ [], ++ [ocamldoc=auto]) ++ ++AC_ARG_WITH([odoc], ++ [AS_HELP_STRING([--with-odoc], ++ [build documentation with odoc])]) ++ ++ ++AC_ARG_ENABLE([ocamltest], ++ [AS_HELP_STRING([--disable-ocamltest], ++ [do not build the ocamltest driver])]) ++ ++AC_ARG_ENABLE([frame-pointers], ++ [AS_HELP_STRING([--enable-frame-pointers], ++ [use frame pointers in runtime and generated code])]) ++ ++AC_ARG_ENABLE([naked-pointers], ++ [AS_HELP_STRING([--disable-naked-pointers], ++ [do not allow naked pointers])]) ++ ++AC_ARG_ENABLE([naked-pointers-checker], ++ [AS_HELP_STRING([--enable-naked-pointers-checker], ++ [enable the naked pointers checker])]) ++ ++AC_ARG_ENABLE([spacetime], [], ++ [AC_MSG_ERROR([spacetime profiling was deleted in OCaml 4.12.])], ++ []) ++ ++AC_ARG_ENABLE([cfi], ++ [AS_HELP_STRING([--disable-cfi], ++ [disable the CFI directives in assembly files])]) ++ ++AC_ARG_ENABLE([imprecise-c99-float-ops], ++ [AS_HELP_STRING([--enable-imprecise-c99-float-ops], ++ [enables potentially imprecise replacement implementations ++ of C99 float ops if unavailable on this platform])]) ++ ++AC_ARG_ENABLE([installing-source-artifacts], ++ [AS_HELP_STRING([--enable-installing-source-artifacts], ++ [install *.cmt* and *.mli files])]) ++AC_ARG_ENABLE([installing-bytecode-programs], ++ [AS_HELP_STRING([--enable-installing-bytecode-programs], ++ [also install the bytecode versions of programs])]) ++ ++AC_ARG_ENABLE([native-compiler], ++ [AS_HELP_STRING([--disable-native-compiler], ++ [do not build the native compiler])]) ++ ++AC_ARG_ENABLE([flambda], ++ [AS_HELP_STRING([--enable-flambda], ++ [enable flambda optimizations])]) ++ ++AC_ARG_ENABLE([flambda-invariants], ++ [AS_HELP_STRING([--enable-flambda-invariants], ++ [enable invariants checks in flambda])]) ++ ++AC_ARG_ENABLE([cmm-invariants], ++ [AS_HELP_STRING([--enable-cmm-invariants], ++ [enable invariants checks in Cmm])]) ++ ++AC_ARG_WITH([target-bindir], ++ [AS_HELP_STRING([--with-target-bindir], ++ [location of binary programs on target system])]) ++ ++AC_ARG_ENABLE([reserved-header-bits], ++ [AS_HELP_STRING([--enable-reserved-header-bits=BITS], ++ [reserve BITS (between 0 and 31) bits in block headers for profiling info])], ++ [AS_CASE([$enable_reserved_header_bits], ++ [0], ++ [with_profinfo=false ++ profinfo_width=0], ++ [[[1-9]]|[[1-2]][[0-9]]|3[[0-1]]], ++ [with_profinfo=true ++ profinfo_width="$enable_reserved_header_bits"], ++ [AC_MSG_ERROR([invalid argument to --enable-reserved-header-bits])])]) ++ ++AC_ARG_ENABLE([stdlib-manpages], ++ [AS_HELP_STRING([--disable-stdlib-manpages], ++ [do not build or install the library man pages])]) ++ ++AC_ARG_ENABLE([warn-error], ++ [AS_HELP_STRING([--enable-warn-error], ++ [treat C compiler warnings as errors])]) ++ ++AC_ARG_VAR([WINDOWS_UNICODE_MODE], ++ [how to handle Unicode under Windows: ansi, compatible]) ++ ++# There are two configure-time string safety options, ++# --(enable|disable)-force-safe-string and ++# DEFAULT_STRING=safe|unsafe that ++# interact with a compile-time (un)safe-string option. ++# ++# If --enable-force-safe-string is set at configure time, then the compiler ++# will always enforce that string and bytes are distinct: the ++# compile-time -unsafe-string option is disabled. This lets us ++# assume pervasive string immutability, for code optimizations and ++# in the C layer. ++# ++# If --disable-force-safe-string is set at configure-time, the compiler ++# will use the compile-time (un)safe-string option to decide whether ++# string and bytes are compatible on a per-file basis. The ++# configuration variable DEFAULT_STRING=safe|unsafe decides which ++# setting will be chosen by default, if no compile-time option is ++# explicitly passed. ++# ++# The configure-time behavior of OCaml 4.05 and older was equivalent ++# to --disable-force-safe-string DEFAULT_STRING=unsafe. With OCaml 4.06 ++# and older was equivalent to --disable-force-safe-string DEFAULT_STRING=safe. ++# With OCaml 4.10 and later use --enable-force-safe-string DEFAULT_STRING=safe. ++# We expect the --disable-force-safe-string and DEFAULT_STRING=unsafe options ++# to be removed in the future. ++ ++AC_ARG_ENABLE([force-safe-string], ++ [AS_HELP_STRING([--disable-force-safe-string], ++ [do not force strings to be safe])]) ++ ++AC_ARG_VAR([DEFAULT_STRING], ++ [whether strings should be safe (default) or unsafe]) ++ ++AC_ARG_ENABLE([flat-float-array], ++ [AS_HELP_STRING([--disable-flat-float-array], ++ [do not use flat float arrays])]) ++ ++AC_ARG_ENABLE([function-sections], ++ [AS_HELP_STRING([--disable-function-sections], ++ [do not emit each function in a separate section])], ++ [], ++ [enable_function_sections=auto]) ++ ++AC_ARG_WITH([afl], ++ [AS_HELP_STRING([--with-afl], ++ [use the AFL fuzzer])]) ++ ++AC_ARG_WITH([flexdll], ++ [AS_HELP_STRING([--with-flexdll], ++ [bootstrap FlexDLL from the given sources])], ++ [AS_IF([test x"$withval" = 'xyes'],[with_flexdll=flexdll])]) ++ ++AS_IF([test x"$enable_unix_lib" = "xno"], ++ [AS_IF([test x"$enable_debugger" = "xyes"], ++ [AC_MSG_ERROR([replay debugger requires the unix library])], ++ [enable_debugger="no"]) ++ AS_IF([test x"$enable_bigarray_lib" = "xyes"], ++ [AC_MSG_ERROR([legacy bigarray library requires the unix library])])]) ++ ++AS_IF([test x"$enable_unix_lib" = "xno" -o x"$enable_str_lib" = "xno"], ++ [AS_IF([test x"$enable_ocamldoc" = "xyes"], ++ [AC_MSG_ERROR([ocamldoc requires the unix and str libraries])], ++ [enable_ocamldoc="no" ++ with_camltex=""])], ++ [with_camltex="true"]) ++ ++# Initialization of libtool ++# Allow the MSVC linker to be found even if ld isn't installed. ++# User-specified LD still takes precedence. ++AC_CHECK_TOOLS([LD],[ld link]) ++# libtool expects host_os=mingw for native Windows ++# Also, it has been observed that, on some platforms (e.g. msvc) LT_INIT ++# alters the CFLAGS variable, so we save its value before calling the macro ++# and restore it after the call ++old_host_os=$host_os ++AS_IF([test x"$host_os" = "xwindows"],[host_os=mingw]) ++saved_CFLAGS="$CFLAGS" ++LT_INIT ++CFLAGS="$saved_CFLAGS" ++host_os=$old_host_os ++ ++AS_CASE([$host], ++ [sparc-sun-solaris*], ++ [DEP_CC="false"], ++ [*-pc-windows], ++ [AC_CHECK_TOOLS( ++ [DEP_CC], ++ [$DEP_CC gcc cc x86_64-w64-mingw32-gcc i686-w64-mingw32-gcc], ++ [false])], ++ [DEP_CC="$CC"]) ++ ++AS_CASE([$enable_dependency_generation], ++ [yes], ++ [AS_IF([test "$DEP_CC" = "false"], ++ [AC_MSG_ERROR(m4_normalize([The MSVC ports cannot generate dependency ++ information. Install gcc (or another CC-like compiler)]))], ++ [compute_deps=true])], ++ [no], [compute_deps=false], ++ [AS_IF([test -e .git], ++ [AS_IF([test "$DEP_CC" = "false"], ++ [compute_deps=false], ++ [compute_deps=true])], ++ [compute_deps=false])]) ++ ++# Extracting information from libtool's configuration ++AS_IF([test -n "$RANLIB" ], ++ [RANLIBCMD="$RANLIB"], ++ [RANLIB="$AR rs"; RANLIBCMD=""] ++) ++ ++AS_CASE([$host], ++ # In config/Makefile.mingw*, we had: ++ # TARGET=i686-w64-mingw32 and x86_64-w64-mingw32 ++ # TOOLPREF=$(TARGET)- ++ # ARCMD=$(TOOLPREF)ar ++ # RANLIB=$(TOOLPREF)ranlib ++ # RANLIBCMD=$(TOOLPREF)ranlib ++ # However autoconf and libtool seem to use ar and ranlib ++ # So we let them do, at the moment ++ [*-pc-windows], ++ [ ++ libext=lib ++ AR=""; RANLIB=echo; RANLIBCMD="" ++ AS_IF([test "$host_cpu" = "x86_64" ], ++ [machine="-machine:AMD64 "], ++ [machine=""]) ++ mklib="link -lib -nologo $machine /out:\$(1) \$(2)" ++ ], ++ [ ++ mklib="rm -f \$(1) && ${AR} rc \$(1) \$(2) && ${RANLIB} \$(1)" ++ ]) ++ ++## Find vendor of the C compiler ++OCAML_CC_VENDOR ++ ++## In cross-compilation mode, can we run executables produced? ++# At the moment, it's required, but the fact is used in C99 function detection ++OCAML_HOST_IS_EXECUTABLE ++ ++# Determine how to call the C preprocessor directly. ++# Most of the time, calling the C preprocessor through the C compiler is ++# desirable and even important. ++# In some cases, though, we want to use the C preprocessor only to ++# expand macros. In such cases, it is much more convenient to be able ++# to invoke it directly rather than through the C compiler, for instance ++# because, when invoked directly, the C preprocessor does not require ++# to be invoked on a file with a '.c' extension ++# We thus figure out how to invoke the C preprocessor directly but ++# let the CPP variable untouched, except for the MSVC port where we set it ++# manually to make sure the backward compatibility is preserved ++AS_CASE([$ocaml_cv_cc_vendor], ++ [xlc-*], ++ [CPP="$CC -E -qnoppline"], # suppress incompatible XLC line directives ++ [sunc-*], ++ [CPP="$CC -E -Qn"], # suppress generation of Sun PRO ident string ++ [msvc-*], ++ [CPP="$CC -nologo -EP"]) ++ ++# Libraries to build depending on the host ++ ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], ++ [unix_or_win32="win32" ++ unixlib="win32unix" ++ ], ++ [unix_or_win32="unix" ++ unixlib="unix"]) ++AS_CASE([$host], ++ [*-*-cygwin*|*-*-mingw32|*-pc-windows], ++ [exeext=".exe"], ++ [exeext='']) ++ ++otherlibraries="dynlink" ++AS_IF([test x"$enable_unix_lib" != "xno"], ++ [AS_IF([test x"$enable_bigarray_lib" != "xno"], ++ [otherlibraries="$otherlibraries $unixlib bigarray"], ++ [otherlibraries="$otherlibraries $unixlib"])]) ++AS_IF([test x"$enable_str_lib" != "xno"], ++ [otherlibraries="$otherlibraries str"]) ++ ++# Checks for system services ++ ++## Test whether #! scripts are supported ++## TODO: have two values, one for host and one for target ++AC_SYS_INTERPRETER ++ ++long_shebang=false ++AS_IF( ++ [test "x$interpval" = "xyes"], ++ [AS_CASE([$host], ++ [*-cygwin|*-*-mingw32|*-pc-windows], ++ [shebangscripts=false], ++ [shebangscripts=true ++ prev_exec_prefix="$exec_prefix" ++ AS_IF([test "x$exec_prefix" = "xNONE"],[exec_prefix="$prefix"]) ++ eval "expanded_bindir=\"$bindir\"" ++ exec_prefix="$prev_exec_prefix" ++ # Assume maximum shebang is 128 chars; less #!, /ocamlrun, an optional ++ # 1 char suffix and the \0 leaving 115 characters ++ AS_IF([test "${#expanded_bindir}" -gt 115],[long_shebang=true]) ++ ] ++ )], ++ [shebangscripts=false] ++) ++ ++# Are we building a cross-compiler ++ ++#AS_IF( ++# [test x"$host" = x"$target"], ++# [cross_compiler=false], ++# [cross_compiler=true]) ++cross_compiler=false ++ ++# Checks for programs ++ ++## Check for the C compiler: done by libtool ++## AC_PROG_CC ++ ++## Check for C99 support: done by libtool ++## AC_PROG_CC_C99 ++ ++## Determine which flags to use for the C compiler ++ ++AS_CASE([$ocaml_cv_cc_vendor], ++ [xlc-*], ++ [outputobj='-o $(EMPTY)' ++ warn_error_flag='' ++ cc_warnings='-qflag=i:i'], # all warnings enabled ++ [sunc-*], ++ [outputobj='-o $(EMPTY)'; cc_warnings=""], ++ [msvc-*], ++ [outputobj='-Fo' ++ warn_error_flag='-WX' ++ cc_warnings=''], ++ [outputobj='-o $(EMPTY)' ++ warn_error_flag='-Werror' ++ cc_warnings='-Wall -Wdeclaration-after-statement']) ++ ++AS_CASE([$enable_warn_error,AC_PACKAGE_VERSION], ++ [yes,*|,*+dev*], ++ [cc_warnings="$cc_warnings $warn_error_flag"]) ++ ++# We select high optimization levels, provided we can turn off: ++# - strict type-based aliasing analysis (too risky for the OCaml runtime) ++# - strict no-overflow conditions on signed integer arithmetic ++# (the OCaml runtime assumes Java-style behavior of signed integer arith.) ++# Concerning optimization level, -O3 is somewhat risky, so take -O2. ++# Concerning language version, gnu99 is ISO C99 plus GNU extensions ++# that are often used in standard headers. Older GCC versions ++# defaults to gnu89, which is not C99. Clang defaults to gnu99 or ++# gnu11, which is fine. ++ ++# Note: the vendor macro can not recognize MinGW because it calls the ++# C preprocessor directly so no compiler specific macro like __MING32__ ++# is defined. We thus catch MinGW first by looking at host and examine ++# the vendor only as a fall-back. We could put tis part of the logic ++# in the macro itself, too ++AS_CASE([$host], ++ [*-*-mingw32], ++ [AS_CASE([$ocaml_cv_cc_vendor], ++ [gcc-[[01234]]-*], ++ [AC_MSG_ERROR(m4_normalize([This version of Mingw GCC is too old. ++ Please use GCC version 5 or above.]))], ++ [gcc-*], ++ [internal_cflags="-Wno-unused $cc_warnings \ ++-fexcess-precision=standard" ++ # TODO: see whether the code can be fixed to avoid -Wno-unused ++ common_cflags="-O2 -fno-strict-aliasing -fwrapv -mms-bitfields" ++ internal_cppflags='-D__USE_MINGW_ANSI_STDIO=0 -DUNICODE -D_UNICODE' ++ internal_cppflags="$internal_cppflags -DWINDOWS_UNICODE=" ++ internal_cppflags="${internal_cppflags}\$(WINDOWS_UNICODE)"], ++ [AC_MSG_ERROR([Unsupported C compiler for a Mingw build])])], ++ [AS_CASE([$ocaml_cv_cc_vendor], ++ [clang-*], ++ [common_cflags="-O2 -fno-strict-aliasing -fwrapv"; ++ internal_cflags="$cc_warnings -fno-common"], ++ [gcc-[[012]]-*], ++ # Some versions known to miscompile OCaml, e,g, 2.7.2.1, some 2.96. ++ # Plus: C99 support unknown. ++ [AC_MSG_ERROR(m4_normalize([This version of GCC is too old. ++ Please use GCC version 4.2 or above.]))], ++ [gcc-3-*|gcc-4-[[01]]], ++ # No -fwrapv option before GCC 3.4. ++ # Known problems with -fwrapv fixed in 4.2 only. ++ [AC_MSG_WARN(m4_normalize([This version of GCC is rather old. ++ Reducing optimization level."])); ++ AC_MSG_WARN([Consider using GCC version 4.2 or above.]); ++ common_cflags="-std=gnu99 -O"; ++ internal_cflags="$cc_warnings"], ++ [gcc-4-[[234]]], ++ # No -fexcess-precision option before GCC 4.5 ++ [common_cflags="-std=gnu99 -O2 -fno-strict-aliasing -fwrapv \ ++-fno-builtin-memcmp"; ++ internal_cflags="$cc_warnings"], ++ [gcc-4-*], ++ [common_cflags="-std=gnu99 -O2 -fno-strict-aliasing -fwrapv \ ++-fno-builtin-memcmp"; ++ internal_cflags="$cc_warnings -fexcess-precision=standard"], ++ [gcc-*], ++ [common_cflags="-O2 -fno-strict-aliasing -fwrapv"; ++ internal_cflags="$cc_warnings -fno-common \ ++-fexcess-precision=standard"], ++ [msvc-*], ++ [common_cflags="-nologo -O2 -Gy- -MD $cc_warnings" ++ common_cppflags="-D_CRT_SECURE_NO_DEPRECATE" ++ internal_cppflags='-DUNICODE -D_UNICODE' ++ internal_cppflags="$internal_cppflags -DWINDOWS_UNICODE=" ++ internal_cppflags="${internal_cppflags}\$(WINDOWS_UNICODE)"], ++ [xlc-*], ++ [common_cflags="-O5 -qtune=balanced -qnoipa -qinline"; ++ internal_cflags="$cc_warnings"], ++ [sunc-*], # Optimization should be >= O4 to inline functions ++ # and prevent unresolved externals ++ [common_cflags="-O4 -xc99=all -D_XPG6 $CFLAGS"; ++ internal_cflags="$cc_warnings"], ++ [common_cflags="-O"])]) ++ ++# Allow CFLAGS and LDFLAGS to be added. ++common_cflags="$common_cflags $CFLAGS" ++cclibs="$cclibs $LDFLAGS" ++ ++internal_cppflags="-DCAML_NAME_SPACE $internal_cppflags" ++ ++# Enable SSE2 on x86 mingw to avoid using 80-bit registers. ++AS_CASE([$host], ++ [i686-*-mingw32], ++ [internal_cflags="$internal_cflags -mfpmath=sse -msse2"]) ++ ++# Use 64-bit file offset if possible ++# See also AC_SYS_LARGEFILE ++# Problem: flags are added to CC rather than CPPFLAGS ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], [], ++ [common_cppflags="$common_cppflags -D_FILE_OFFSET_BITS=64"]) ++ ++# Adjust according to target ++ ++# On Windows we do not take $enable_shared because it does not seem ++# to work. This should be better understood later ++#AS_CASE([$target], ++# [*-pc-windows], ++# [enable_shared=yes]) ++ ++AS_IF([test x"$enable_shared" = "xno"], ++ [with_sharedlibs=false ++ AS_CASE([$host], ++ [*-pc-windows|*-w64-mingw32], ++ [AC_MSG_ERROR([Cannot build native Win32 with --disable-shared])])]) ++ ++# Define flexlink chain and flags correctly for the different Windows ports ++AS_CASE([$host], ++ [i686-*-cygwin], ++ [flexdll_chain='cygwin' ++ flexlink_flags="-chain $flexdll_chain -merge-manifest -stack 16777216"], ++ [x86_64-*-cygwin], ++ [flexdll_chain='cygwin64' ++ flexlink_flags="-chain $flexdll_chain -merge-manifest -stack 16777216"], ++ [*-*-cygwin*], ++ [AC_MSG_ERROR([unknown cygwin variant])], ++ [i686-w64-mingw32], ++ [flexdll_chain='mingw' ++ flexlink_flags="-chain $flexdll_chain -stack 16777216"], ++ [x86_64-w64-mingw32], ++ [flexdll_chain='mingw64' ++ flexlink_flags="-chain $flexdll_chain -stack 33554432"], ++ [i686-pc-windows], ++ [flexdll_chain='msvc' ++ flexlink_flags="-merge-manifest -stack 16777216"], ++ [x86_64-pc-windows], ++ [flexdll_chain='msvc64' ++ flexlink_flags="-x64 -merge-manifest -stack 33554432"]) ++ ++AS_IF([test x"$enable_shared" != 'xno'], [ ++ AC_MSG_CHECKING([for flexdll sources]) ++ AS_IF([test x"$with_flexdll" = "xno"], ++ [flexdir='' ++ AC_MSG_RESULT([disabled])], ++ [flexmsg='' ++ AS_CASE([$target], ++ [*-*-cygwin*|*-w64-mingw32|*-pc-windows], ++ [AS_IF([test x"$with_flexdll" = 'x' -o x"$with_flexdll" = 'xflexdll'], ++ [AS_IF([test -f 'flexdll/flexdll.h'], ++ [flexdir=flexdll ++ iflexdir='$(ROOTDIR)/flexdll' ++ with_flexdll="$iflexdir"], ++ [AS_IF([test x"$with_flexdll" != 'x'], ++ [AC_MSG_RESULT([requested but not available]) ++ AC_MSG_ERROR([exiting])])])], ++ [rm -rf flexdll-sources ++ AS_IF([test -f "$with_flexdll/flexdll.h"], ++ [mkdir -p flexdll-sources ++ cp -r "$with_flexdll"/* flexdll-sources/ ++ flexdir='flexdll-sources' ++ iflexdir='$(ROOTDIR)/flexdll-sources' ++ flexmsg=" (from $with_flexdll)"], ++ [AC_MSG_RESULT([requested but not available]) ++ AC_MSG_ERROR([exiting])])]) ++ AS_IF([test x"$flexdir" = 'x'], ++ [AC_MSG_RESULT([no])], ++ [AC_MSG_RESULT([$iflexdir$flexmsg]) ++ bootstrapping_flexdll=true ++ # The submodule should be searched *before* any other -I paths ++ internal_cppflags="-I $iflexdir $internal_cppflags"])], ++ [AS_IF([test x"$with_flexdll" != 'x'], ++ [AC_MSG_RESULT([requested but not supported]) ++ AC_MSG_ERROR([exiting])])])]) ++ ++ AC_CHECK_PROG([flexlink],[flexlink],[flexlink]) ++ ++ AS_IF([test -n "$flexlink" -a -z "$flexdir"],[ ++ OCAML_TEST_FLEXLINK([$flexlink], [$flexdll_chain], ++ [$internal_cppflags], [$host]) ++ ++ AS_CASE([$host], ++ [*-w64-mingw32|*-pc-windows], ++ [flexlink_where="$(cmd /c "$flexlink" -where 2>/dev/null)" ++ AS_IF([test -z "$flexlink_where"], ++ [AC_MSG_ERROR([$flexlink is not executable from a native Win32 process]) ++ ])]) ++ ]) ++ ++ OCAML_TEST_FLEXDLL_H([$flexdir]) ++ ++ AS_IF([test -n "$flexlink" -a x"$have_flexdll_h" = 'xno'], ++ [OCAML_TEST_FLEXLINK_WHERE([$flexlink]) ++ AS_IF([test "x$have_flexdll_h" = 'xyes'], ++ [internal_cppflags="$internal_cppflags -I \"$flexlink_where\""]) ++ ]) ++]) ++ ++AS_IF([test x"$have_flexdll_h" = 'xno'], ++ [AS_CASE([$host], ++ [*-*-cygwin*], ++ [AS_IF([$with_sharedlibs], ++ [with_sharedlibs=false ++ AC_MSG_WARN([flexdll.h not found: shared library support disabled.]) ++ ])], ++ [*-w64-mingw32|*-pc-windows], ++ [AC_MSG_ERROR([flexdll.h is required for native Win32])])]) ++ ++AS_IF([test -z "$flexdir" -o x"$have_flexdll_h" = 'xno'], ++ [AS_CASE([$host], ++ [*-*-cygwin*], ++ [AS_IF([$with_sharedlibs], ++ [AS_IF([test -z "$flexlink"], ++ [with_sharedlibs=false ++ AC_MSG_WARN( ++ [flexlink/flexdll.h not found: shared library support disabled.]) ++ ])])], ++ [*-w64-mingw32|*-pc-windows], ++ [AS_IF([test -z "$flexlink"], ++ [AC_MSG_ERROR([flexlink is required for native Win32])])])]) ++ ++AS_CASE([$CC,$host], ++ [*,*-*-darwin*], ++ [mkexe="$mkexe -Wl,-no_compact_unwind"; ++ AC_DEFINE([HAS_ARCH_CODE32], [1])], ++ [*,*-*-haiku*], [mathlib=""], ++ [*,*-*-cygwin*], ++ [common_cppflags="$common_cppflags -U_WIN32" ++ AS_IF([$with_sharedlibs], ++ [mkexe='$(FLEXLINK) -exe $(if $(OC_LDFLAGS),-link "$(OC_LDFLAGS)")' ++ mkexedebugflag="-link -g"], ++ [mkexe="$mkexe -Wl,--stack,16777216" ++ oc_ldflags="-Wl,--stack,16777216"] ++ ) ++ ostype="Cygwin"], ++ [*,*-*-mingw32], ++ [AS_CASE([$host], ++ [i686-*-*], [oc_dll_ldflags="-static-libgcc"]) ++ mkexedebugflag="-link -g" ++ ostype="Win32" ++ toolchain="mingw" ++ mkexe='$(FLEXLINK) -exe $(if $(OC_LDFLAGS),-link "$(OC_LDFLAGS)")' ++ oc_ldflags='-municode' ++ SO="dll"], ++ [*,*-pc-windows], ++ [toolchain=msvc ++ ostype="Win32" ++ mkexe='$(FLEXLINK) -exe $(if $(OC_LDFLAGS),-link "$(OC_LDFLAGS)")' ++ oc_ldflags='/ENTRY:wmainCRTStartup' ++ mkexedebugflag=''], ++ [*,x86_64-*-linux*], ++ AC_DEFINE([HAS_ARCH_CODE32], [1]), ++ [xlc*,powerpc-ibm-aix*], ++ [mkexe="$mkexe " ++ oc_ldflags="-brtl -bexpfull" ++ AC_DEFINE([HAS_ARCH_CODE32], [1])], ++ [gcc*,powerpc-*-linux*], ++ [oc_ldflags="-mbss-plt"], ++) ++ ++ ++## Program to use to install files ++AC_PROG_INSTALL ++ ++# Checks for libraries ++ ++## Mathematical library ++AC_CHECK_LIB([m],[cos]) ++ ++AS_IF([test "x$ac_cv_lib_m_cos" = xyes ], [mathlib="-lm"], [mathlib=""]) ++ ++# Checks for header files ++ ++AC_CHECK_HEADER([math.h]) ++AC_CHECK_HEADERS([unistd.h],[AC_DEFINE([HAS_UNISTD])]) ++AC_CHECK_HEADER([stdint.h],[AC_DEFINE([HAS_STDINT_H])]) ++AC_CHECK_HEADER([dirent.h], [AC_DEFINE([HAS_DIRENT])], [], ++ [#include ]) ++ ++AC_CHECK_HEADER([sys/select.h], [AC_DEFINE([HAS_SYS_SELECT_H])], [], ++ [#include ]) ++ ++# Checks for types ++ ++## off_t ++AC_TYPE_OFF_T ++ ++# Checks for structures ++ ++# Checks for compiler characteristics ++ ++AC_CHECK_SIZEOF(int) ++AC_CHECK_SIZEOF(long) ++AC_CHECK_SIZEOF(long *) ++AC_CHECK_SIZEOF(short) ++AC_CHECK_SIZEOF(long long) ++ ++AS_IF( ++ [test "x$ac_cv_sizeof_long_p" = "x4" ], ++ [bits=32; arch64=false], ++ [test "x$ac_cv_sizeof_long_p" = "x8" ], ++ [bits=64; arch64=true ++ AC_DEFINE([ARCH_SIXTYFOUR], [1])], ++ [AC_MSG_ERROR([Neither 32 nor 64 bits architecture.])] ++) ++ ++AS_IF([test "x$ac_cv_sizeof_int" != "x4" && test "x$ac_cv_sizeof_long" != "x4" \ ++ && test "x$ac_cv_sizeof_short" != "x4"], ++ [AC_MSG_ERROR([Sorry, we can't find a 32-bit integer type.])] ++) ++ ++AS_IF( ++ [test "x$ac_cv_sizeof_long" != "x8" && ++ test "x$ac_cv_sizeof_long_long" != "x8"], ++ [AC_MSG_ERROR([Sorry, we can't find a 64-bit integer type.])] ++) ++ ++AC_DEFINE_UNQUOTED([SIZEOF_PTR], [$ac_cv_sizeof_long_p]) ++AC_DEFINE_UNQUOTED([SIZEOF_LONGLONG], [$ac_cv_sizeof_long_long]) ++ ++AC_MSG_NOTICE([Target is a $bits bits architecture]) ++ ++AC_C_BIGENDIAN( ++ [ ++ AC_DEFINE([ARCH_BIG_ENDIAN], [1]) ++ [endianness="be"] ++ ], ++ [endianness="le"], ++ [AC_MSG_ERROR([could not determine endianness.])], ++ [AC_MSG_ERROR([unable to handle universal endianness])] ++) ++ ++AC_CHECK_ALIGNOF([double]) ++AC_CHECK_ALIGNOF([long]) ++AC_CHECK_ALIGNOF([long long]) ++ ++AS_IF([! $arch64], ++ [AS_CASE([$target_cpu], ++ [i686], [], ++ [AS_IF([test "$ac_cv_alignof_double" -gt 4], ++ [AC_DEFINE([ARCH_ALIGN_DOUBLE], [1])]) ++ AS_IF([test "x$ac_cv_sizeof_long" = "x8" && ++ test "$ac_cv_alignof_long" -gt 4], ++ [AC_DEFINE([ARCH_ALIGN_INT64], [1])], ++ [AS_IF([test "x$ac_cv_sizeof_long_long" = "x8" && ++ test "$ac_cv_alignof_long_long" -gt 4], ++ [AC_DEFINE([ARCH_ALIGN_INT64], [1])])]) ++ ])]) ++ ++# Shared library support ++ ++shared_libraries_supported=false ++sharedlib_cflags='' ++mksharedlib='shared-libs-not-available' ++rpath='' ++mksharedlibrpath='' ++natdynlinkopts="" ++ ++AS_IF([test x"$enable_shared" != "xno"], ++ [AS_CASE([$host], ++ [*-apple-darwin*], ++ [mksharedlib="$CC -shared \ ++ -flat_namespace -undefined suppress -Wl,-no_compact_unwind \ ++ \$(LDFLAGS)" ++ shared_libraries_supported=true], ++ [*-*-mingw32], ++ [mksharedlib='$(FLEXLINK)' ++ mkmaindll='$(FLEXLINK) -maindll' ++ AS_IF([test -n "$oc_dll_ldflags"],[ ++ mksharedlib="$mksharedlib -link \"$oc_dll_ldflags\"" ++ mkmaindll="$mkmaindll -link \"$oc_dll_ldflags\""]) ++ shared_libraries_supported=$with_sharedlibs], ++ [*-pc-windows], ++ [mksharedlib='$(FLEXLINK)' ++ mkmaindll='$(FLEXLINK) -maindll' ++ shared_libraries_supported=$with_sharedlibs], ++ [*-*-cygwin*], ++ [mksharedlib='$(FLEXLINK)' ++ mkmaindll='$(FLEXLINK) -maindll' ++ shared_libraries_supported=$with_sharedlibs], ++ [powerpc-ibm-aix*], ++ [AS_CASE([$ocaml_cv_cc_vendor], ++ [xlc*], ++ [mksharedlib="$CC -qmkshrobj -G \$(LDFLAGS)" ++ shared_libraries_supported=true])], ++ [*-*-solaris*], ++ [sharedlib_cflags="-fPIC" ++ mksharedlib="$CC -shared" ++ rpath="-Wl,-rpath," ++ mksharedlibrpath="-Wl,-rpath," ++ shared_libraries_supported=true], ++ [[*-*-linux*|*-*-freebsd[3-9]*|*-*-freebsd[1-9][0-9]*\ ++ |*-*-openbsd*|*-*-netbsd*|*-*-dragonfly*|*-*-gnu*|*-*-haiku*]], ++ [sharedlib_cflags="-fPIC" ++ AS_CASE([$CC,$host], ++ [gcc*,powerpc-*-linux*], ++ [mksharedlib="$CC -shared -mbss-plt \$(LDFLAGS)"], ++ [mksharedlib="$CC -shared \$(LDFLAGS)"]) ++ oc_ldflags="$oc_ldflags -Wl,-E" ++ rpath="-Wl,-rpath," ++ mksharedlibrpath="-Wl,-rpath," ++ natdynlinkopts="-Wl,-E" ++ shared_libraries_supported=true])]) ++ ++AS_IF([test -z "$mkmaindll"], [mkmaindll=$mksharedlib]) ++ ++# Configure native dynlink ++ ++natdynlink=false ++ ++AS_IF([test x"$shared_libraries_supported" = 'xtrue'], ++ [AS_CASE(["$host"], ++ [*-*-cygwin*], [natdynlink=true], ++ [*-*-mingw32], [natdynlink=true], ++ [*-pc-windows], [natdynlink=true], ++ [[i[3456]86-*-linux*]], [natdynlink=true], ++ [[i[3456]86-*-gnu*]], [natdynlink=true], ++ [[x86_64-*-linux*]], [natdynlink=true], ++ [arm64-*-darwin*], [natdynlink=true], ++ [aarch64-*-darwin*], [natdynlink=true], ++ [x86_64-*-darwin*], [natdynlink=true], ++ [s390x*-*-linux*], [natdynlink=true], ++ [powerpc*-*-linux*], [natdynlink=true], ++ [x86_64-*-solaris*], [natdynlink=true], ++ [i686-*-kfreebsd*], [natdynlink=true], ++ [x86_64-*-kfreebsd*], [natdynlink=true], ++ [x86_64-*-dragonfly*], [natdynlink=true], ++ [[i[3456]86-*-freebsd*]], [natdynlink=true], ++ [x86_64-*-freebsd*], [natdynlink=true], ++ [[i[3456]86-*-openbsd*]], [natdynlink=true], ++ [x86_64-*-openbsd*], [natdynlink=true], ++ [[i[3456]86-*-netbsd*]], [natdynlink=true], ++ [x86_64-*-netbsd*], [natdynlink=true], ++ [i386-*-gnu0.3], [natdynlink=true], ++ [[i[3456]86-*-haiku*]], [natdynlink=true], ++ [arm*-*-linux*], [natdynlink=true], ++ [arm*-*-freebsd*], [natdynlink=true], ++ [earm*-*-netbsd*], [natdynlink=true], ++ [aarch64-*-linux*], [natdynlink=true], ++ [aarch64-*-freebsd*], [natdynlink=true], ++ [loongarch64-*-linux*], [natdynlink=true], ++ [riscv*-*-linux*], [natdynlink=true])]) ++ ++# Try to work around the Skylake/Kaby Lake processor bug. ++AS_CASE(["$CC,$host"], ++ [*gcc*,x86_64-*|*gcc*,i686-*], ++ [OCAML_CC_HAS_FNO_TREE_VRP ++ AS_IF([$cc_has_fno_tree_vrp], ++ [internal_cflags="$internal_cflags -fno-tree-vrp"])]) ++ ++OCAML_CC_SUPPORTS_ALIGNED ++ ++## Check whether __attribute__((optimize("tree-vectorize")))) is supported ++OCAML_CC_SUPPORTS_TREE_VECTORIZE ++ ++# Configure the native-code compiler ++ ++arch=none ++model=default ++system=unknown ++ ++AS_CASE([$host], ++ [[i[3456]86-*-linux*]], ++ [arch=i386; system=linux_elf], ++ [[i[3456]86-*-*bsd*]], ++ [arch=i386; system=bsd_elf], ++ [[i[3456]86-*-haiku*]], ++ [arch=i386; system=beos], ++ [[i[3456]86-*-cygwin]], ++ [arch=i386; system=cygwin], ++ [[i[3456]86-*-gnu*]], ++ [arch=i386; system=gnu], ++ [[i[3456]86-*-mingw32]], ++ [arch=i386; system=mingw], ++ [i686-pc-windows], ++ [arch=i386; system=win32], ++ [x86_64-pc-windows], ++ [arch=amd64; system=win64], ++ [[powerpc64le*-*-linux*]], ++ [arch=power; model=ppc64le; system=elf], ++ [[powerpc*-*-linux*]], ++ [arch=power; AS_IF([$arch64],[model=ppc64],[model=ppc]); system=elf], ++ [[s390x*-*-linux*]], ++ [arch=s390x; model=z10; system=elf], ++ # expected to match "gnueabihf" as well as "musleabihf" ++ [armv6*-*-linux-*eabihf], ++ [arch=arm; model=armv6; system=linux_eabihf], ++ [armv7*-*-linux-*eabihf], ++ [arch=arm; model=armv7; system=linux_eabihf], ++ [armv8*-*-linux-*eabihf], ++ [arch=arm; model=armv8; system=linux_eabihf], ++ [armv8*-*-linux-*eabi], ++ [arch=arm; model=armv8; system=linux_eabi], ++ [armv7*-*-linux-*eabi], ++ [arch=arm; model=armv7; system=linux_eabi], ++ [armv6t2*-*-linux-*eabi], ++ [arch=arm; model=armv6t2; system=linux_eabi], ++ [armv6*-*-linux-*eabi], ++ [arch=arm; model=armv6; system=linux_eabi], ++ [armv6*-*-freebsd*], ++ [arch=arm; model=armv6; system=freebsd], ++ [earmv6*-*-netbsd*], ++ [arch=arm; model=armv6; system=netbsd], ++ [earmv7*-*-netbsd*], ++ [arch=arm; model=armv7; system=netbsd], ++ [armv5te*-*-linux-*eabi], ++ [arch=arm; model=armv5te; system=linux_eabi], ++ [armv5*-*-linux-*eabi], ++ [arch=arm; model=armv5; system=linux_eabi], ++ [arm*-*-linux-*eabihf], ++ [arch=arm; system=linux_eabihf], ++ [arm*-*-linux-*eabi], ++ [arch=arm; system=linux_eabi], ++ [arm*-*-openbsd*], ++ [arch=arm; system=bsd], ++ [zaurus*-*-openbsd*], ++ [arch=arm; system=bsd], ++ [x86_64-*-linux*], ++ [arch=amd64; system=linux], ++ [x86_64-*-gnu*], ++ [arch=amd64; system=gnu], ++ [x86_64-*-dragonfly*], ++ [arch=amd64; system=dragonfly], ++ [x86_64-*-solaris*], ++ [arch=amd64; system=solaris], ++ [x86_64-*-freebsd*], ++ [arch=amd64; system=freebsd], ++ [x86_64-*-netbsd*], ++ [arch=amd64; system=netbsd], ++ [x86_64-*-openbsd*], ++ [arch=amd64; system=openbsd], ++ [arm64-*-darwin*], ++ [arch=arm64; system=macosx], ++ [aarch64-*-darwin*], ++ [arch=arm64; system=macosx], ++ [x86_64-*-darwin*], ++ [arch=amd64; system=macosx], ++ [x86_64-*-mingw32], ++ [arch=amd64; system=mingw64], ++ [aarch64-*-linux*], ++ [arch=arm64; system=linux], ++ [aarch64-*-freebsd*], ++ [arch=arm64; system=freebsd], ++ [x86_64-*-cygwin*], ++ [arch=amd64; system=cygwin], ++ [loongarch64-*-linux*], ++ [arch=loongarch64; system=linux], ++ [riscv64-*-linux*], ++ [arch=riscv; model=riscv64; system=linux] ++) ++ ++AS_IF([test x"$enable_native_compiler" = "xno"], ++ [native_compiler=false ++ AC_MSG_NOTICE([the native compiler is disabled])], ++ [native_compiler=true]) ++ ++AS_IF([! $native_compiler], [natdynlink=false]) ++ ++AS_IF([$natdynlink], [cmxs="cmxs"], [cmxs="cmx"]) ++ ++AC_DEFINE_UNQUOTED([OCAML_OS_TYPE], ["$ostype"]) ++ ++AC_CHECK_TOOL([DIRECT_LD],[ld]) ++AS_IF([test -z "$PARTIALLD"], ++ [AS_CASE(["$arch,$CC,$system,$model"], ++ [amd64,gcc*,macosx,*], [PACKLD_FLAGS=' -arch x86_64'], ++ [power,gcc*,elf,ppc], [PACKLD_FLAGS=' -m elf32ppclinux'], ++ [power,gcc*,elf,ppc64], [PACKLD_FLAGS=' -m elf64ppc'], ++ [power,gcc*,elf,ppc64le], [PACKLD_FLAGS=' -m elf64lppc'], ++ [PACKLD_FLAGS='']) ++ # The string for PACKLD must be capable of being concatenated with the ++ # output filename. Don't assume that all C compilers understand GNU -ofoo ++ # form, so ensure that the definition includes a space at the end (which is ++ # achieved using the $(EMPTY) expansion trick). ++ AS_IF([test x"$CC" = "xcl"], ++ # For the Microsoft C compiler there must be no space at the end of the ++ # string. ++ [PACKLD="link -lib -nologo $machine -out:"], ++ [PACKLD="$DIRECT_LD -r$PACKLD_FLAGS -o \$(EMPTY)"])], ++ [PACKLD="$PARTIALLD -o \$(EMPTY)"]) ++ ++# Disable PIE at link time when ocamlopt does not produce position-independent ++# code and the system produces PIE executables by default and demands PIC ++# object files to do so. ++# This issue does not affect amd64 (x86_64) and s390x (Z systems), ++# since ocamlopt produces PIC object files by default. ++# Currently the problem is known for Alpine Linux on platforms other ++# than amd64 and s390x (issue #7562), and probably affects all Linux ++# distributions that use the musl standard library and dynamic loader. ++# Other systems have PIE by default but can cope with non-PIC object files, ++# e.g. Ubuntu >= 17.10 for i386, which uses the glibc dynamic loader. ++ ++AS_CASE([$arch], ++ [amd64|s390x|none], ++ # ocamlopt generates PIC code or doesn't generate code at all ++ [], ++ [AS_CASE([$host], ++ # expected to match "*-linux-musl" as well as "*-linux-musleabi*" ++ [*-linux-musl*], ++ # Alpine and other musl-based Linux distributions ++ [common_cflags="-no-pie $common_cflags"], ++ [])]) ++ ++# Assembler ++ ++dnl AS_IF([test -n "$target_alias"], ++dnl [toolpref="${target_alias}-" ++dnl as_target="$target" ++dnl as_cpu="$target_cpu"], ++dnl [AS_IF([test -n "$host_alias"], ++dnl [toolpref="${host_alias}-" ++dnl as_target="$host" ++dnl as_cpu="$host_cpu"], ++dnl [toolpref="" ++dnl as_target="$build" ++dnl as_cpu="$build_cpu"])]) ++ ++# Finding the assembler ++# The OCaml build system distinguishes two different assemblers: ++# 1. AS, used to assemble the code generated by the ocamlopt native compiler ++# 2. ASPP, to assemble other assembly files that may require preprocessing ++# In general, "$CC -c" is used as a default value for both AS and ASPP. ++# On a few platforms (Windows) both values are overriden. ++# On other platforms, (Linux with GCC) the assembler AS is called directly ++# to avoiding forking a C compiler process for each compilation by ocamlopt. ++# Both AS and ASPP can be overriden by the user. ++ ++default_as="$CC -c" ++default_aspp="$CC -c" ++ ++AS_CASE([$as_target,$ocaml_cv_cc_vendor], ++ [*-*-linux*,gcc-*], ++ [AS_CASE([$as_cpu], ++ [x86_64|arm*|aarch64*|i[[3-6]]86|riscv*|loongarch*], ++ [default_as="${toolpref}as"])], ++ [i686-pc-windows,*], ++ [default_as="ml -nologo -coff -Cp -c -Fo" ++ default_aspp="$default_as"], ++ [x86_64-pc-windows,*], ++ [default_as="ml64 -nologo -Cp -c -Fo" ++ default_aspp="$default_as"], ++ [*-*-darwin*,clang-*], ++ [default_as="$default_as -Wno-trigraphs" ++ default_aspp="$default_as"], ++ []) ++ ++AS_IF([test "$with_pic"], ++ [fpic=true ++ AC_DEFINE([CAML_WITH_FPIC]) ++ internal_cflags="$internal_cflags $sharedlib_cflags" ++ default_aspp="$default_aspp $sharedlib_cflags"], ++ [fpic=false]) ++ ++AS_IF([test -z "$AS"], [AS="$default_as"]) ++ ++AS_IF([test -z "$ASPP"], [ASPP="$default_aspp"]) ++ ++# Utilities ++AC_CHECK_PROG([rlwrap],[rlwrap],[rlwrap]) ++AS_CASE([$rlwrap,$system], ++ [rlwrap,win*|rlwrap,mingw*], ++ [AC_MSG_NOTICE([rlwrap doesn't work with native win32 - disabling]) ++ rlwrap='']) ++ ++# Checks for library functions ++ ++## Check the semantics of signal handlers ++OCAML_SIGNAL_HANDLERS_SEMANTICS ++ ++## Check for C99 float ops ++ ++has_c99_float_ops=true ++AC_CHECK_FUNCS(m4_normalize([expm1 log1p hypot fma exp2 log2 cbrt acosh asinh ++ atanh erf erfc trunc round copysign]), [], [has_c99_float_ops=false]) ++ ++AS_IF([$has_c99_float_ops], ++ [AC_DEFINE([HAS_C99_FLOAT_OPS]) ++ # Check whether round works (known bug in mingw-w64) ++ OCAML_C99_CHECK_ROUND ++ # Check whether fma works (regressed in mingw-w64 8.0.0; present, but broken, ++ # in VS2013-2017 and present but unimplemented in Cygwin64) ++ OCAML_C99_CHECK_FMA], ++ [AS_IF([test x"$enable_imprecise_c99_float_ops" != "xyes" ], ++ [AS_CASE([$enable_imprecise_c99_float_ops,$ocaml_cv_cc_vendor], ++ [no,*], [hard_error=true], ++ [,msvc-*], [AS_IF([test "${ocaml_cv_cc_vendor#msvc-}" -lt 1800 ], ++ [hard_error=false], ++ [hard_error=true])], ++ [hard_error=true]) ++ AS_IF([test x"$hard_error" = 'xtrue'], ++ [AC_MSG_ERROR(m4_normalize([ ++ C99 float ops unavailable, enable replacements ++ with --enable-imprecise-c99-float-ops]))], ++ [AC_MSG_WARN(m4_normalize([ ++ C99 float ops unavailable, replacements enabled ++ (ancient Visual Studio)]))])])]) ++ ++## getrusage ++AC_CHECK_FUNC([getrusage], [AC_DEFINE([HAS_GETRUSAGE])]) ++ ++## times ++AC_CHECK_FUNC([times], [AC_DEFINE([HAS_TIMES])]) ++ ++## secure_getenv and __secure_getenv ++ ++saved_CPPFLAGS="$CPPFLAGS" ++CPPFLAGS="-D_GNU_SOURCE $CPPFLAGS" ++ ++AC_CHECK_FUNC([secure_getenv], ++ [AC_DEFINE([HAS_SECURE_GETENV])], ++ [AC_CHECK_FUNC([__secure_getenv], [AC_DEFINE([HAS___SECURE_GETENV])])]) ++ ++CPPFLAGS="$saved_CPPFLAGS" ++ ++## issetugid ++ ++AC_CHECK_FUNC([issetugid], [AC_DEFINE([HAS_ISSETUGID])]) ++ ++## Checking for monotonic clock source ++## On Windows MSVC, QueryPerformanceCounter and QueryPerformanceFrequency ++## are always available. ++## On Unix platforms, we check for the appropriate POSIX feature-test macros. ++## On MacOS clock_gettime's CLOCK_MONOTONIC flag is not actually monotonic. ++## mach_timebase_info and mach_absolute_time are used instead. ++ ++AS_CASE([$host], ++ [*-*-windows], ++ [has_monotonic_clock=true], ++ [*-apple-darwin*], [ ++ AC_CHECK_FUNCS([mach_timebase_info mach_absolute_time], ++ [ ++ has_monotonic_clock=true ++ AC_DEFINE([HAS_MACH_ABSOLUTE_TIME]) ++ ], ++ [has_monotonic_clock=false])], ++ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ ++ #include ++ #include ++ int main(void) ++ { ++ #if !(defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK) \ ++ && _POSIX_MONOTONIC_CLOCK != (-1)) ++ #error "no monotonic clock source" ++ #endif ++ return 0; ++ } ++ ]])], ++ [ ++ has_monotonic_clock=true ++ AC_DEFINE([HAS_POSIX_MONOTONIC_CLOCK]) ++ ], ++ [has_monotonic_clock=false]) ++ ] ++) ++ ++# The instrumented runtime is built by default ++# if the proper clock source is found. ++# If asked via --enable-instrumented-runtime, configuration fails if the proper ++# clock source is missing. ++AS_IF([test "x$enable_instrumented_runtime" != "xno" ], ++ [ ++ AS_CASE([$host], ++ [sparc-sun-solaris*], ++ [instrumented_runtime=false], ++ [*-*-windows], ++ [instrumented_runtime=true], ++ [*-apple-darwin*], [ ++ AS_CASE([$enable_instrumented_runtime,$has_monotonic_clock], ++ [*,true], ++ [instrumented_runtime=true], ++ [yes,false], [ ++ AC_MSG_ERROR([Instrumented runtime support requested \ ++but no proper monotonic clock source was found.]) ++ ], ++ [auto,false], ++ [instrumented_runtime=false] ++ )], ++ [AC_SEARCH_LIBS([clock_gettime], [rt], ++ [has_clock_gettime=true], ++ [has_clock_gettime=false]) ++ AS_CASE( ++ [$enable_instrumented_runtime,$has_clock_gettime,$has_monotonic_clock], ++ [auto,false,*], [instrumented_runtime=false], ++ [auto,*,false], [instrumented_runtime=false], ++ [*,true,true], ++ [ ++ instrumented_runtime=true ++ AS_IF([test "x$ac_cv_search_clock_gettime" = "xnone required"], ++ [instrumented_runtime_libs=""], ++ [instrumented_runtime_libs=$ac_cv_search_clock_gettime] ++ ) ++ ], ++ [yes,false,*], ++ [ ++ AC_MSG_ERROR([Instrumented runtime support requested \ ++but clock_gettime is missing.]) ++ ], ++ [yes,*,false], ++ [ ++ AC_MSG_ERROR([Instrumented runtime support requested \ ++but no proper monotonic clock source was found.]) ++ ] ++ )] ++ )] ++) ++ ++## Sockets ++ ++## TODO: check whether the different libraries are really useful ++ ++sockets=true ++ ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], ++ [cclibs="$cclibs -lws2_32" ++ AC_SEARCH_LIBS([socket], [ws2_32])], ++ [*-*-haiku], ++ [cclibs="$cclibs -lnetwork" ++ AC_SEARCH_LIBS([socket], [network])], ++ [*-*-solaris*], ++ [cclibs="$cclibs -lsocket -lnsl" ++ AC_SEARCH_LIBS([socket], [socket]) ++ AC_SEARCH_LIBS([inet_ntop], [nsl])], ++ [ ++ AC_CHECK_FUNCS( ++ [socket socketpair bind listen accept connect], ++ [], ++ [sockets=false]) ++ ] ++) ++ ++AS_IF([$sockets], [AC_DEFINE([HAS_SOCKETS])]) ++ ++## socklen_t ++ ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], ++ [AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T])], [], ++ [#include ])], ++ [AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T])], [], ++ [#include ])]) ++ ++AC_CHECK_FUNC([inet_aton], [AC_DEFINE([HAS_INET_ATON])]) ++ ++## IPv6 support ++ ++ipv6=true ++ ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], ++ [AC_CHECK_TYPE( ++ [struct sockaddr_in6], [], [ipv6=false], [#include ])], ++ [AC_CHECK_TYPE( ++ [struct sockaddr_in6], [], [ipv6=false], ++[ ++#include ++#include ++#include ++] ++ )] ++) ++ ++AS_IF([$ipv6], ++ [AC_CHECK_FUNC([getaddrinfo], [], [ipv6=false])]) ++ ++AS_IF([$ipv6], ++ [AC_CHECK_FUNC([getnameinfo], [], [ipv6=false])]) ++ ++AS_IF([$ipv6], ++ [AC_CHECK_FUNC([inet_pton], [], [ipv6=false])]) ++ ++AS_IF([$ipv6], ++ [AC_CHECK_FUNC([inet_ntop], [AC_DEFINE([HAS_IPV6])])]) ++ ++AC_CHECK_FUNC([rewinddir], [AC_DEFINE([HAS_REWINDDIR])]) ++ ++AC_CHECK_FUNC([lockf], [AC_DEFINE([HAS_LOCKF])]) ++ ++AC_CHECK_FUNC([mkfifo], [AC_DEFINE([HAS_MKFIFO])]) ++ ++AC_CHECK_FUNC([getcwd], [AC_DEFINE([HAS_GETCWD])]) ++ ++AC_CHECK_DECL([system], [AC_DEFINE([HAS_SYSTEM])], [], [[#include ]]) ++ ++## utime ++## Note: this was defined in config/s-nt.h but the autoconf macros do not ++# seem to detect it properly on Windows so we hardcode the definition ++# of HAS_UTIME on Windows but this will probably need to be clarified ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], [AC_DEFINE([HAS_UTIME])], ++ [AC_CHECK_HEADER([sys/types.h], ++ [AC_CHECK_HEADER([utime.h], ++ [AC_CHECK_FUNC([utime], [AC_DEFINE([HAS_UTIME])])])])]) ++ ++AC_CHECK_FUNC([utimes], [AC_DEFINE([HAS_UTIMES])]) ++ ++AC_CHECK_FUNC([fchmod], ++ [AC_CHECK_FUNC([fchown], [AC_DEFINE([HAS_FCHMOD])])]) ++ ++AC_CHECK_FUNC([truncate], ++ [AC_CHECK_FUNC([ftruncate], [AC_DEFINE([HAS_TRUNCATE])])]) ++ ++## select ++AC_CHECK_FUNC([select], ++ [AC_CHECK_TYPE([fd_set], ++ [AC_DEFINE([HAS_SELECT]) ++ select=true], [select=false], [ ++#include ++#include ++ ])]) ++ ++AC_CHECK_FUNC([nanosleep], [AC_DEFINE([HAS_NANOSLEEP])]) ++ ++AC_CHECK_FUNC([symlink], ++ [AC_CHECK_FUNC([readlink], ++ [AC_CHECK_FUNC([lstat], [AC_DEFINE([HAS_SYMLINK])])])]) ++ ++AC_CHECK_FUNC([realpath], [AC_DEFINE([HAS_REALPATH])]) ++ ++# wait ++AC_CHECK_FUNC( ++ [waitpid], ++ [ ++ wait=true ++ AC_DEFINE([HAS_WAITPID]) ++ ], ++ [wait=false]) ++ ++AC_CHECK_FUNC( ++ [wait4], ++ [ ++ has_wait=true ++ AC_DEFINE([HAS_WAIT4]) ++ ]) ++ ++## getgroups ++AC_CHECK_FUNC([getgroups], [AC_DEFINE([HAS_GETGROUPS])]) ++ ++## setgroups ++AC_CHECK_FUNC([setgroups], [AC_DEFINE([HAS_SETGROUPS])]) ++ ++## initgroups ++AC_CHECK_FUNC([initgroups], [AC_DEFINE([HAS_INITGROUPS])]) ++ ++## termios ++ ++AC_CHECK_HEADER([termios.h], ++ [AC_CHECK_FUNC([tcgetattr], ++ [AC_CHECK_FUNC([tcsetattr], ++ [AC_CHECK_FUNC([tcsendbreak], ++ [AC_CHECK_FUNC([tcflush], ++ [AC_CHECK_FUNC([tcflow], [AC_DEFINE([HAS_TERMIOS])])])])])])]) ++ ++## setitimer ++ ++AC_CHECK_FUNC([setitimer], ++ [ ++ setitimer=true ++ AC_DEFINE([HAS_SETITIMER]) ++ ], ++ [setitimer=false]) ++ ++## gethostname ++# Note: detection fails on Windows so hardcoding the result ++# (should be debugged later) ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], [AC_DEFINE([HAS_GETHOSTNAME])], ++ [AC_CHECK_FUNC([gethostname], [AC_DEFINE([HAS_GETHOSTNAME])])]) ++ ++## uname ++ ++AC_CHECK_HEADER([sys/utsname.h], ++ [AC_CHECK_FUNC([uname], [AC_DEFINE([HAS_UNAME])])]) ++ ++## gettimeofday ++ ++AC_CHECK_FUNC([gettimeofday], ++ [ ++ gettimeofday=true ++ AC_DEFINE([HAS_GETTIMEOFDAY]) ++ ], ++ [gettimeofday=false]) ++ ++## mktime ++ ++AC_CHECK_FUNC([mktime], [AC_DEFINE([HAS_MKTIME])]) ++ ++## setsid ++ ++AS_CASE([$host], ++ [*-cygwin|*-*-mingw32|*-pc-windows], [], ++ [AC_CHECK_FUNC([setsid], [AC_DEFINE([HAS_SETSID])])]) ++ ++## putenv ++ ++AC_CHECK_FUNC([putenv], [AC_DEFINE([HAS_PUTENV])]) ++ ++## setenv and unsetenv ++ ++AC_CHECK_FUNC([setenv], ++ [AC_CHECK_FUNC([unsetenv], [AC_DEFINE([HAS_SETENV_UNSETENV])])]) ++ ++## newlocale() and ++# Note: the detection fails on msvc so we hardcode the result ++# (should be debugged later) ++AS_CASE([$host], ++ [*-pc-windows], [AC_DEFINE([HAS_LOCALE_H])], ++ [AC_CHECK_HEADER([locale.h], ++ [AC_CHECK_FUNC([newlocale], ++ [AC_CHECK_FUNC([freelocale], ++ [AC_CHECK_FUNC([uselocale], [AC_DEFINE([HAS_LOCALE_H])])])])])]) ++ ++AC_CHECK_HEADER([xlocale.h], ++ [AC_CHECK_FUNC([newlocale], ++ [AC_CHECK_FUNC([freelocale], ++ [AC_CHECK_FUNC([uselocale], [AC_DEFINE([HAS_XLOCALE_H])])])])]) ++ ++## strtod_l ++# Note: not detected on MSVC so hardcoding the result ++# (should be debugged later) ++AS_CASE([$host], ++ [*-pc-windows], [AC_DEFINE([HAS_STRTOD_L])], ++ [AC_CHECK_FUNC([strtod_l], [AC_DEFINE([HAS_STRTOD_L])])]) ++ ++## shared library support ++AS_IF([$shared_libraries_supported], ++ [AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows|*-*-cygwin*], ++ [supports_shared_libraries=$shared_libraries_supported; DLLIBS=""], ++ [AC_CHECK_FUNC([dlopen], ++ [supports_shared_libraries=true DLLIBS=""], ++ [AC_CHECK_LIB([dl], [dlopen], ++ [supports_shared_libraries=true DLLIBS="-ldl $DLLIBS"], ++ [supports_shared_libraries=false])])])], ++ [supports_shared_libraries=false]) ++ ++AS_IF([$supports_shared_libraries], ++ [AC_MSG_NOTICE([Dynamic loading of shared libraries is supported.]) ++ AC_DEFINE([SUPPORT_DYNAMIC_LINKING])], ++ [AC_MSG_NOTICE([Dynamic loading of shared libraries is not supported.])]) ++ ++## mmap ++ ++AC_CHECK_HEADER([sys/mman.h], ++ [AC_CHECK_FUNC([mmap], ++ [AC_CHECK_FUNC([munmap], [AC_DEFINE([HAS_MMAP])])])]) ++ ++## pwrite ++ ++AC_CHECK_FUNC([pwrite], [AC_DEFINE([HAS_PWRITE])]) ++ ++## -fdebug-prefix-map support by the C compiler ++AS_CASE([$ocaml_cv_cc_vendor,$host], ++ [*,*-*-mingw32], [cc_has_debug_prefix_map=false], ++ [*,*-pc-windows], [cc_has_debug_prefix_map=false], ++ [xlc*,powerpc-ibm-aix*], [cc_has_debug_prefix_map=false], ++ [sunc*,sparc-sun-*], [cc_has_debug_prefix_map=false], ++ [OCAML_CC_HAS_DEBUG_PREFIX_MAP]) ++ ++## Does stat support nanosecond precision ++ ++AC_CHECK_MEMBER([struct stat.st_atim.tv_nsec], ++ [stat_has_ns_precision=true ++ AC_DEFINE([HAS_NANOSECOND_STAT], [1])], ++ [], ++ [ ++ AC_INCLUDES_DEFAULT ++ #include ++ ]) ++ ++ ++AS_IF([! $stat_has_ns_precision], ++ [AC_CHECK_MEMBER([struct stat.st_atimespec.tv_nsec], ++ [stat_has_ns_precision=true ++ AC_DEFINE([HAS_NANOSECOND_STAT], [2])], ++ [], ++ [ ++ AC_INCLUDES_DEFAULT ++ #include ++ ])]) ++ ++AS_IF([! $stat_has_ns_precision], ++ [AC_CHECK_MEMBER([struct stat.st_atimensec], ++ [stat_has_ns_precision=true ++ AC_DEFINE([HAS_NANOSECOND_STAT], [3])], ++ [], ++ [ ++ AC_INCLUDES_DEFAULT ++ #include ++ ])]) ++ ++AS_IF([$stat_has_ns_precision], ++ [AC_MSG_NOTICE([stat supports nanosecond precision])], ++ [AC_MSG_NOTICE([stat does not support nanosecond precision])]) ++ ++# Number of arguments of gethostbyname_r ++ ++AX_FUNC_WHICH_GETHOSTBYNAME_R ++ ++AS_CASE([$ac_cv_func_which_gethostbyname_r], ++ [six], [AC_DEFINE([HAS_GETHOSTBYNAME_R],[6])], ++ [five], [AC_DEFINE([HAS_GETHOSTBYNAME_R],[5])], ++ [three], [AC_MSG_WARN([OCaml does not support this variant])]) ++ ++# Number of arguments of gethostbyaddr_r ++ ++AX_FUNC_WHICH_GETHOSTBYADDR_R ++ ++AS_CASE([$ac_cv_func_which_gethostbyaddr_r], ++ [eight], [AC_DEFINE([HAS_GETHOSTBYADDR_R],[8])], ++ [seven], [AC_DEFINE([HAS_GETHOSTBYADDR_R],[7])]) ++ ++## mkstemp ++ ++AC_CHECK_FUNC([mkstemp], [AC_DEFINE([HAS_MKSTEMP])]) ++ ++## nice ++ ++AC_CHECK_FUNC([nice], [AC_DEFINE([HAS_NICE])]) ++ ++## dup3 ++ ++AC_CHECK_FUNC([dup3], [AC_DEFINE([HAS_DUP3])]) ++ ++## pipe2 ++ ++AC_CHECK_FUNC([pipe2], [AC_DEFINE([HAS_PIPE2])]) ++ ++## accept4 ++ ++AC_CHECK_FUNC([accept4], [AC_DEFINE([HAS_ACCEPT4])]) ++ ++## getauxval ++ ++AC_CHECK_FUNC([getauxval], [AC_DEFINE([HAS_GETAUXVAL])]) ++ ++## shmat ++AC_CHECK_HEADER([sys/shm.h], ++ [ ++ AC_DEFINE([HAS_SYS_SHM_H]) ++ AC_CHECK_FUNC([shmat], [AC_DEFINE([HAS_SHMAT])]) ++ ]) ++ ++## execvpe ++ ++AC_CHECK_FUNC([execvpe], [AC_DEFINE([HAS_EXECVPE])]) ++ ++## posix_spawn ++ ++AC_CHECK_HEADER([spawn.h], ++ [AC_CHECK_FUNC([posix_spawn], ++ [AC_CHECK_FUNC([posix_spawnp], [AC_DEFINE([HAS_POSIX_SPAWN])])])]) ++ ++## ffs or _BitScanForward ++ ++AC_CHECK_FUNC([ffs], [AC_DEFINE([HAS_FFS])]) ++AC_CHECK_FUNC([_BitScanForward], [AC_DEFINE([HAS_BITSCANFORWARD])]) ++ ++## Determine whether the debugger should/can be built ++ ++AS_CASE([$enable_debugger], ++ [no], ++ [with_debugger="" ++ AC_MSG_NOTICE([replay debugger disabled])], ++ [AS_IF([$sockets], ++ [with_debugger="ocamldebugger" ++ AC_MSG_NOTICE([replay debugger supported])], ++ [with_debugger="" ++ AC_MSG_NOTICE([replay debugger not supported])]) ++ ]) ++ ++## Should the runtime with debugging support be built ++AS_CASE([$enable_debug_runtime], ++ [no], [debug_runtime=false], ++ [debug_runtime=true]) ++ ++## Determine if system stack overflows can be detected ++ ++AC_MSG_CHECKING([whether stack overflows can be detected]) ++ ++AS_CASE([$arch,$system], ++ [i386,linux_elf|amd64,linux|amd64,macosx \ ++ |amd64,openbsd|i386,bsd_elf|arm64,linux|arm64,macosx], ++ [AC_DEFINE([HAS_STACK_OVERFLOW_DETECTION]) ++ AC_MSG_RESULT([yes])], ++ [AC_MSG_RESULT([no])]) ++ ++## Determine if the POSIX threads library is supported ++ ++AS_IF([test x"$enable_systhreads" = "xno"], ++ [systhread_support=false ++ AC_MSG_NOTICE([the Win32/POSIX threads library is disabled])], ++ [AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], ++ [systhread_support=true ++ otherlibraries="$otherlibraries systhreads" ++ AC_MSG_NOTICE([the Win32 threads library is supported])], ++ [AX_PTHREAD( ++ [systhread_support=true ++ otherlibraries="$otherlibraries systhreads" ++ common_cflags="$common_cflags $PTHREAD_CFLAGS" ++ AC_MSG_NOTICE([the POSIX threads library is supported]) ++ saved_CFLAGS="$CFLAGS" ++ saved_LIBS="$LIBS" ++ CFLAGS="$CFLAGS $PTHREAD_CFLAGS" ++ LIBS="$LIBS $PTHREAD_LIBS" ++ AC_CHECK_FUNC([sigwait], [AC_DEFINE([HAS_SIGWAIT])]) ++ LIBS="$saved_LIBS" ++ CFLAGS="$saved_CFLAGS"], ++ [AS_IF([test x"$enable_systhreads" = "xyes"], ++ [AC_MSG_ERROR([the POSIX thread library is not available])], ++ [systhread_support=false ++ AC_MSG_NOTICE([the POSIX threads library is not supported])])])])]) ++ ++## Does the assembler support debug prefix map and CFI directives ++as_has_debug_prefix_map=false ++asm_cfi_supported=false ++AS_IF([$native_compiler], ++ [AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], [], ++ [OCAML_AS_HAS_DEBUG_PREFIX_MAP ++ OCAML_AS_HAS_CFI_DIRECTIVES])]) ++ ++## Frame pointers ++ ++AS_IF([test x"$enable_frame_pointers" = "xyes"], ++ [AS_CASE(["$host,$CC"], ++ [x86_64-*-linux*,gcc*|x86_64-*-linux*,clang*], ++ [common_cflags="$common_cflags -g -fno-omit-frame-pointer" ++ frame_pointers=true ++ AC_DEFINE([WITH_FRAME_POINTERS]) ++ AC_MSG_NOTICE([using frame pointers])], ++ [AC_MSG_ERROR([frame pointers not supported on this platform])] ++ )], ++ [AC_MSG_NOTICE([not using frame pointers]) ++ frame_pointers=false]) ++ ++## No naked pointers ++ ++AS_IF([test x"$enable_naked_pointers" = "xno" ], ++ [naked_pointers=false ++ AC_DEFINE([NO_NAKED_POINTERS])], ++ [naked_pointers=true]) ++ ++AS_IF([test x"$enable_naked_pointers_checker" = "xyes" ], ++ [AS_IF([test x"$enable_naked_pointers" = "xno" ], ++ [AC_MSG_ERROR(m4_normalize([ ++ --enable-naked-pointers-checker and --disable-naked-pointers ++ are incompatible]))]) ++ AS_CASE(["$arch","$system"], ++ [amd64,linux|amd64,macosx \ ++ |amd64,openbsd|amd64,win64 \ ++ |amd64,freebsd|amd64,solaris \ ++ |arm64,linux|arm64,macosx], ++ [naked_pointers_checker=true ++ AC_DEFINE([NAKED_POINTERS_CHECKER])], ++ [*], ++ [AC_MSG_ERROR([naked pointers checker not supported on this platform])] ++ )], ++ [naked_pointers_checker=false]) ++ ++## Check for mmap support for huge pages and contiguous heap ++OCAML_MMAP_SUPPORTS_HUGE_PAGES ++ ++AC_DEFINE_UNQUOTED([PROFINFO_WIDTH], [$profinfo_width]) ++AS_IF([$profinfo], [AC_DEFINE([WITH_PROFINFO])]) ++ ++AS_IF([test x"$enable_installing_bytecode_programs" = "xno"], ++ [install_bytecode_programs=false], ++ [install_bytecode_programs=true]) ++ ++AS_IF([test x"$enable_installing_source_artifacts" = "xno"], ++ [install_source_artifacts=false], ++ [install_source_artifacts=true]) ++ ++AS_IF([test x"$enable_ocamldoc" = "xno"], ++ [ocamldoc=""], ++ [ocamldoc=ocamldoc]) ++ ++documentation_tool_cmd='' ++AC_ARG_WITH([odoc], ++ [AS_HELP_STRING([--with-odoc])], ++ [AS_CASE([$withval], ++ [yes],[documentation_tool='odoc'], ++ [no],[documentation_tool='ocamldoc'], ++ [documentation_tool_cmd="$withval" ++ documentation_tool='odoc'])], ++ [documentation_tool='ocamldoc']) ++AS_IF([test "x$documentation_tool_cmd" = 'x'] ++ [documentation_tool_cmd="$documentation_tool"]) ++ ++ ++ ++AS_CASE([$enable_ocamltest,AC_PACKAGE_VERSION], ++ [yes,*|,*+dev*],[ocamltest='ocamltest'], ++ [ocamltest='']) ++ ++AS_IF([test x"$enable_flambda" = "xyes"], ++ [flambda=true ++ AS_IF([test x"$enable_flambda_invariants" = "xyes"], ++ [flambda_invariants=true], ++ [flambda_invariants=false])], ++ [flambda=false ++ flambda_invariants=false]) ++ ++AS_IF([test x"$enable_cmm_invariants" = "xyes"], ++ [cmm_invariants=true], ++ [cmm_invariants=false]) ++ ++AS_IF([test x"$enable_flat_float_array" = "xno"], ++ [flat_float_array=false], ++ [AC_DEFINE([FLAT_FLOAT_ARRAY]) ++ flat_float_array=true]) ++ ++AS_IF([test x"$enable_function_sections" = "xno"], ++ [function_sections=false], ++ [AS_CASE([$arch], ++ [amd64|i386|arm64], # not supported on arm32, see issue #9124. ++ [AS_CASE([$target], ++ [*-cygwin*|*-mingw*|*-windows|*-apple-darwin*], ++ [function_sections=false; ++ AC_MSG_NOTICE([No support for function sections on $target.])], ++ [*], ++ [AS_CASE([$ocaml_cv_cc_vendor], ++ [gcc-[0123]-*|gcc-4-[01234567]], ++ [function_sections=false; ++ AC_MSG_NOTICE([Function sections are not ++ supported in GCC prior to version 4.8.])], ++ [clang-[012]-*|clang-3-[01234]], ++ [function_sections=false; ++ AC_MSG_NOTICE([Function sections are not supported ++ in Clang prior to version 3.5.])], ++ [gcc-*|clang-*], ++ [function_sections=true; ++ internal_cflags="$internal_cflags -ffunction-sections"; ++ AC_DEFINE([FUNCTION_SECTIONS])], ++ [*], ++ [function_sections=false; ++ AC_MSG_NOTICE([Function sections are not supported by ++ $ocaml_cv_cc_vendor.])])])], ++ [function_sections=false]); ++ AS_IF([test x"$function_sections" = "xfalse"], ++ [AS_IF([test x"$enable_function_sections" = "xyes"], ++ [AC_MSG_ERROR([Function sections are not supported.])], ++ [AC_MSG_NOTICE([Disabling function sections.])])], ++ [])]) ++ ++AS_IF([test x"$with_afl" = "xyes"], ++ [afl=true], ++ [afl=false]) ++ ++AS_IF([test x"$enable_force_safe_string" = "xno"], ++ [force_safe_string=false], ++ [AC_DEFINE([CAML_SAFE_STRING]) ++ force_safe_string=true]) ++ ++AS_IF([test x"$DEFAULT_STRING" = "xunsafe"], ++ [default_safe_string=false], ++ [default_safe_string=true]) ++ ++oc_cflags="$common_cflags $internal_cflags" ++oc_cppflags="$common_cppflags $internal_cppflags" ++ocamlc_cflags="$common_cflags $sharedlib_cflags \$(CFLAGS)" ++ocamlc_cppflags="$common_cppflags \$(CPPFLAGS)" ++cclibs="$cclibs $mathlib" ++ ++AS_CASE([$host], ++ [*-*-mingw32], ++ [bytecclibs="-lws2_32 -lversion" ++ nativecclibs="-lws2_32 -lversion"], ++ [*-pc-windows], ++ [bytecclibs="advapi32.lib ws2_32.lib version.lib" ++ nativecclibs="advapi32.lib ws2_32.lib version.lib"], ++ [bytecclibs="$cclibs $DLLIBS $PTHREAD_LIBS" ++ nativecclibs="$cclibs $DLLIBS"]) ++ ++AS_IF([test x"$libdir" = x'${exec_prefix}/lib'], ++ [libdir="$libdir"/ocaml]) ++ ++AS_IF([test x"$mandir" = x'${datarootdir}/man'], ++ [mandir='${prefix}/man']) ++ ++AS_CASE([$host], ++ [*-*-mingw32|*-pc-windows], ++ [AS_CASE([$WINDOWS_UNICODE_MODE], ++ [ansi], ++ [windows_unicode=0], ++ [compatible|""], ++ [windows_unicode=1], ++ [AC_MSG_ERROR([unexpected windows unicode mode])])], ++ [windows_unicode=0]) ++ ++# Define default prefix correctly for the different Windows ports ++AS_IF([test x"$prefix" = "xNONE"], ++ [AS_CASE([$host], ++ [i686-w64-mingw32], [prefix='C:/ocamlmgw'], ++ [x86_64-w64-mingw32], [prefix='C:/ocamlmgw64'], ++ [i686-pc-windows], [prefix='C:/ocamlms'], ++ [x86_64-pc-windows], [prefix='C:/ocamlms64'])], ++ [AS_IF([test x"$unix_or_win32" = "xwin32" \ ++ && test "$host_vendor-$host_os" != "$build_vendor-$build_os" ], ++ [AS_CASE([$build], ++ [*-pc-cygwin], [prefix="$(LC_ALL=C.UTF-8 cygpath -m "$prefix")"])])]) ++ ++# Define a few macros that were defined in config/m-nt.h ++# but whose value is not guessed properly by configure ++# (all this should be understood and fixed) ++AS_CASE([$host], ++ [*-*-mingw32], ++ [AC_DEFINE([HAS_BROKEN_PRINTF]) ++ AC_DEFINE([HAS_STRERROR]) ++ AC_DEFINE([HAS_NICE])], ++ [*-pc-windows], ++ [AC_DEFINE([HAS_BROKEN_PRINTF]) ++ AC_DEFINE([HAS_STRERROR]) ++ AC_DEFINE([HAS_IPV6]) ++ AC_DEFINE([HAS_NICE])], ++ [*-*-solaris*], ++ # This is required as otherwise floats are printed ++ # as "Infinity" and "Inf" instead of the expected "inf" ++ [AC_DEFINE([HAS_BROKEN_PRINTF])]) ++ ++AS_IF([test x"$enable_stdlib_manpages" != "xno"], ++ [stdlib_manpages=true],[stdlib_manpages=false]) ++ ++# Do not permanently cache the result of flexdll.h ++unset ac_cv_header_flexdll_h ++ ++AC_OUTPUT +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/CSE.ml ocaml-4.14.1_bak/asmcomp/loongarch64/CSE.ml +--- ocaml-4.14.1/asmcomp/loongarch64/CSE.ml 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/CSE.ml 2024-06-05 10:28:51.277079410 +0800 +@@ -0,0 +1,38 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++(* CSE for the loongarch *) ++ ++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 -Naur ocaml-4.14.1/asmcomp/loongarch64/emit.mlp ocaml-4.14.1_bak/asmcomp/loongarch64/emit.mlp +--- ocaml-4.14.1/asmcomp/loongarch64/emit.mlp 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/emit.mlp 2024-06-05 10:28:51.281079410 +0800 +@@ -0,0 +1,674 @@ ++(**************************************************************************) ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++ ++(* Emission of loongarch assembly code *) ++ ++open Cmm ++open Arch ++open Proc ++open Reg ++open Mach ++open Linear ++open Emitaux ++open Emitenv ++ ++(* Layout of the stack. The stack is kept 16-aligned. *) ++ ++let frame_size env = ++ let size = ++ env.stack_offset + (* Trap frame, outgoing parameters *) ++ size_int * env.f.fun_num_stack_slots.(0) + (* Local int variables *) ++ size_float * env.f.fun_num_stack_slots.(1) + (* Local float variables *) ++ (if env.f.fun_contains_calls then size_addr else 0) (* Return address *) ++ in ++ Misc.align size 16 ++ ++let slot_offset env loc cls = ++ match loc with ++ | Local n -> ++ if cls = 0 ++ then env.stack_offset + env.f.fun_num_stack_slots.(1) * size_float ++ + n * size_int ++ else env.stack_offset + n * size_float ++ | Incoming n -> frame_size env + n ++ | Outgoing n -> n ++ ++(* Output a symbol *) ++ ++let emit_symbol s = ++ emit_symbol '$' s ++ ++let emit_jump op s = ++ if !Clflags.dlcode || !Clflags.pic_code ++ then `{emit_string op} %plt({emit_symbol s})` ++ else `{emit_string op} {emit_symbol s}` ++ ++let emit_call = emit_jump "bl" ++let emit_tail = emit_jump "b" ++ ++(* Output a label *) ++ ++let emit_label lbl = ++ emit_string ".L"; emit_int lbl ++ ++(* Section switching *) ++ ++let data_space = ++ ".section .data" ++ ++let code_space = ++ ".section .text" ++ ++let rodata_space = ++ ".section .rodata" ++ ++(* Names for special regs *) ++ ++let reg_tmp = phys_reg 22 (* t1 *) ++let reg_t2 = phys_reg 13 (* t2 *) ++let reg_domain_state_ptr = phys_reg 25 (* s8 *) ++let reg_trap = phys_reg 23 (* s1 *) ++let reg_alloc_ptr = phys_reg 24 (* s7 *) ++ ++(* Output a pseudo-register *) ++ ++let reg_name = function ++ | {loc = Reg r} -> register_name r ++ | _ -> Misc.fatal_error "Emit.reg_name" ++ ++let emit_reg r = ++ emit_string (reg_name r) ++ ++(* Adjust sp by the given byte amount *) ++ ++let emit_stack_adjustment = function ++ | 0 -> () ++ | n when is_immediate n -> ++ ` addi.d $sp, $sp, {emit_int n}\n` ++ | n -> ++ ` li.d {emit_reg reg_tmp}, {emit_int n}\n`; ++ ` add.d $sp, $sp, {emit_reg reg_tmp}\n` ++ ++(* Adjust stack_offset and emit corresponding CFI directive *) ++ ++let emit_mem_op op src ofs = ++ if is_immediate ofs then ++ ` {emit_string op} {emit_string src}, $sp, {emit_int ofs}\n` ++ else begin ++ ` li.d {emit_reg reg_tmp}, {emit_int ofs}\n`; ++ ` add.d {emit_reg reg_tmp}, $sp, {emit_reg reg_tmp}\n`; ++ ` {emit_string op} {emit_string src}, {emit_reg reg_tmp}, 0\n` ++ end ++ ++let emit_store src ofs = ++ emit_mem_op "st.d" src ofs ++ ++let emit_load dst ofs = ++ emit_mem_op "ld.d" dst ofs ++ ++let reload_ra n = ++ emit_load "$ra" (n - size_addr) ++ ++let store_ra n = ++ emit_store "$ra" (n - size_addr) ++ ++let emit_store src ofs = ++ emit_store (reg_name src) ofs ++ ++let emit_load dst ofs = ++ emit_load (reg_name dst) ofs ++ ++let emit_float_load dst ofs = ++ emit_mem_op "fld.d" (reg_name dst) ofs ++ ++let emit_float_store src ofs = ++ emit_mem_op "fst.d" (reg_name src) ofs ++ ++let emit_float_test cmp ~arg ~res = ++let negated = ++ match cmp with ++ | CFneq | CFnlt | CFngt | CFnle | CFnge -> true ++ | CFeq | CFlt | CFgt | CFle | CFge -> false ++in ++begin match cmp with ++| CFeq | CFneq -> ` fcmp.ceq.d $fcc0, {emit_reg arg.(0)}, {emit_reg arg.(1)}\n movcf2gr {emit_reg res}, $fcc0\n` ++| CFlt | CFnlt -> ` fcmp.clt.d $fcc0, {emit_reg arg.(0)}, {emit_reg arg.(1)}\n movcf2gr {emit_reg res}, $fcc0\n` ++| CFgt | CFngt -> ` fcmp.clt.d $fcc0, {emit_reg arg.(1)}, {emit_reg arg.(0)}\n movcf2gr {emit_reg res}, $fcc0\n` ++| CFle | CFnle -> ` fcmp.cle.d $fcc0, {emit_reg arg.(0)}, {emit_reg arg.(1)}\n movcf2gr {emit_reg res}, $fcc0\n` ++| CFge | CFnge -> ` fcmp.cle.d $fcc0, {emit_reg arg.(1)}, {emit_reg arg.(0)}\n movcf2gr {emit_reg res}, $fcc0\n` ++end; ++negated ++ ++(* Record live pointers at call points *) ++ ++let record_frame_label env live dbg = ++ let lbl = new_label () in ++ let live_offset = ref [] in ++ Reg.Set.iter ++ (function ++ {typ = Val; loc = Reg r} -> ++ live_offset := (r lsl 1) + 1 :: !live_offset ++ | {typ = Val; loc = Stack s} as reg -> ++ live_offset := slot_offset env 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 env) ++ ~live_offset:!live_offset dbg; ++ lbl ++ ++let record_frame env live dbg = ++ let lbl = record_frame_label env live dbg in ++ `{emit_label lbl}:\n` ++ ++let emit_call_gc gc = ++ `{emit_label gc.gc_lbl}:\n`; ++ ` {emit_call "caml_call_gc"}\n`; ++ `{emit_label gc.gc_frame_lbl}:\n`; ++ ` b {emit_label gc.gc_return_lbl}\n` ++ ++let bound_error_label env dbg = ++ if !Clflags.debug || env.bound_error_sites = [] then begin ++ let lbl_bound_error = new_label() in ++ let lbl_frame = record_frame_label env Reg.Set.empty (Dbg_other dbg) in ++ env.bound_error_sites <- ++ { bd_lbl = lbl_bound_error; ++ bd_frame = lbl_frame; } :: env.bound_error_sites; ++ lbl_bound_error ++ end else ++ let bd = List.hd env.bound_error_sites in ++ bd.bd_lbl ++ ++let emit_call_bound_error bd = ++ `{emit_label bd.bd_lbl}:\n`; ++ ` {emit_call "caml_ml_array_bound_error"}\n`; ++ `{emit_label bd.bd_frame}:\n` ++ ++(* Names for various instructions *) ++ ++let name_for_intop = function ++ | Iadd -> "add.d" ++ | Isub -> "sub.d" ++ | Imul -> "mul.d" ++ | Imulh -> "mulh.d" ++ | Idiv -> "div.d" ++ | Iand -> "and" ++ | Ior -> "or" ++ | Ixor -> "xor" ++ | Ilsl -> "sll.d" ++ | Ilsr -> "srl.d" ++ | Iasr -> "sra.d" ++ | Imod -> "mod.d" ++ | _ -> Misc.fatal_error "Emit.Intop" ++ ++let name_for_intop_imm = function ++ | Iadd -> "addi.d" ++ | Iand -> "andi" ++ | Ior -> "ori" ++ | Ixor -> "xori" ++ | Ilsl -> "slli.d" ++ | Ilsr -> "srli.d" ++ | Iasr -> "srai.d" ++ | _ -> Misc.fatal_error "Emit.Intop_imm" ++ ++let name_for_floatop1 = function ++ | Inegf -> "fneg.d" ++ | Iabsf -> "fabs.d" ++ | _ -> Misc.fatal_error "Emit.Iopf1" ++ ++let name_for_floatop2 = function ++ | Iaddf -> "fadd.d" ++ | Isubf -> "fsub.d" ++ | Imulf -> "fmul.d" ++ | Idivf -> "fdiv.d" ++ | _ -> Misc.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" ++ ++(* Output the assembly code for an instruction *) ++ ++let emit_instr env i = ++ emit_debug_info i.dbg; ++ match i.desc with ++ Lend -> () ++ | Lprologue -> ++ assert (env.f.fun_prologue_required); ++ let n = frame_size env in ++ emit_stack_adjustment (-n); ++ if env.f.fun_contains_calls then store_ra n ++ | 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 _} -> ++ ` move {emit_reg dst}, {emit_reg src}\n` ++ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = Float} -> ++ ` fmov.d {emit_reg dst}, {emit_reg src}\n` ++ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = (Val | Int | Addr)} -> ++ ` movfr2gr.d {emit_reg dst}, {emit_reg src}\n` ++ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Stack s} -> ++ let ofs = slot_offset env s (register_class dst) in ++ emit_store src ofs ++ | {loc = Reg _; typ = Float}, {loc = Stack s} -> ++ let ofs = slot_offset env s (register_class dst) in ++ emit_float_store src ofs ++ | {loc = Stack s; typ = (Val | Int | Addr)}, {loc = Reg _} -> ++ let ofs = slot_offset env s (register_class src) in ++ emit_load dst ofs ++ | {loc = Stack s; typ = Float}, {loc = Reg _} -> ++ let ofs = slot_offset env s (register_class src) in ++ emit_float_load dst ofs ++ | {loc = Stack _}, {loc = Stack _} ++ | {loc = Unknown}, _ | _, {loc = Unknown} -> ++ Misc.fatal_error "Emit: Imove" ++ end ++ | Lop(Iconst_int n) -> ++ ` li.d {emit_reg i.res.(0)}, {emit_nativeint n}\n` ++ | Lop(Iconst_float f) -> ++ let lbl = new_label() in ++ env.float_literals <- {fl=f; lbl} :: env.float_literals; ++ ` la.local {emit_reg reg_tmp}, {emit_label lbl} \n`; ++ ` fld.d {emit_reg i.res.(0)}, {emit_reg reg_tmp}, 0\n` ++ | Lop(Iconst_symbol s) -> ++ ` pcaddi {emit_reg i.res.(0)}, 0 \n`; ++ ` b 7112233f\n`; ++ ` .dword {emit_symbol s}\n`; ++ ` 7112233: ld.d {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 8\n` ++ | Lop(Icall_ind) -> ++ ` jirl $ra, {emit_reg i.arg.(0)}, 0\n`; ++ record_frame env i.live (Dbg_other i.dbg) ++ | Lop(Icall_imm {func}) -> ++ ` {emit_call func}\n`; ++ record_frame env i.live (Dbg_other i.dbg) ++ | Lop(Itailcall_ind) -> ++ let n = frame_size env in ++ if env.f.fun_contains_calls then reload_ra n; ++ emit_stack_adjustment n; ++ ` jr {emit_reg i.arg.(0)}\n` ++ | Lop(Itailcall_imm {func}) -> ++ if func = env.f.fun_name then begin ++ ` b {emit_label env.f.fun_tailrec_entry_point_label}\n` ++ end else begin ++ let n = frame_size env in ++ if env.f.fun_contains_calls then reload_ra n; ++ emit_stack_adjustment n; ++ ` {emit_tail func}\n` ++ end ++ | Lop(Iextcall{func; alloc = true}) -> ++ ` la.global {emit_reg reg_t2}, {emit_symbol func}\n`; ++ ` {emit_call "caml_c_call"}\n`; ++ record_frame env i.live (Dbg_other i.dbg) ++ | Lop(Iextcall{func; alloc = false}) -> ++ ` {emit_call func}\n` ++ | Lop(Istackoffset n) -> ++ assert (n mod 16 = 0); ++ emit_stack_adjustment (-n); ++ env.stack_offset <- env.stack_offset + n ++ | Lop(Iload(Single, Iindexed ofs, _mut)) -> ++ ` fld.s {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int ofs}\n`; ++ ` fcvt.d.s {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` ++ | Lop(Iload(chunk, Iindexed ofs, _mut)) -> ++ let instr = ++ match chunk with ++ | Byte_unsigned -> "ld.bu" ++ | Byte_signed -> "ld.b" ++ | Sixteen_unsigned -> "ld.hu" ++ | Sixteen_signed -> "ld.h" ++ | Thirtytwo_unsigned -> "ld.wu" ++ | Thirtytwo_signed -> "ld.w" ++ | Word_int | Word_val -> "ld.d" ++ | Single -> assert false ++ | Double | Double_u -> "fld.d" ++ in ++ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int ofs}\n` ++ | Lop(Istore(Single, Iindexed ofs, _)) -> ++ (* ft0 is marked as destroyed for this operation *) ++ ` fcvt.s.d $ft0, {emit_reg i.arg.(0)}\n`; ++ ` fst.s $ft0, {emit_reg i.arg.(1)}, {emit_int ofs}\n` ++ | Lop(Istore(chunk, Iindexed ofs, _)) -> ++ let instr = ++ match chunk with ++ | Byte_unsigned | Byte_signed -> "st.b" ++ | Sixteen_unsigned | Sixteen_signed -> "st.h" ++ | Thirtytwo_unsigned | Thirtytwo_signed -> "st.w" ++ | Word_int | Word_val -> "st.d" ++ | Single -> assert false ++ | Double | Double_u -> "fst.d" ++ in ++ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)} ,{emit_int ofs}\n` ++ | Lop(Ialloc {bytes; dbginfo}) -> ++ let lbl_frame_lbl = record_frame_label env i.live (Dbg_alloc dbginfo) in ++ let lbl_after_alloc = new_label () in ++ let lbl_call_gc = new_label () in ++ let n = -bytes in ++ let offset = Domainstate.(idx_of_field Domain_young_limit) * 8 in ++ if is_immediate n then ++ ` addi.d {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, {emit_int n}\n` ++ else begin ++ ` li.d {emit_reg reg_tmp}, {emit_int n}\n`; ++ ` add.d {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}\n` ++ end; ++ ` ld.d {emit_reg reg_tmp}, {emit_reg reg_domain_state_ptr},{emit_int offset}\n`; ++ ` sltu {emit_reg reg_tmp}, {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}\n`; ++ ` bnez {emit_reg reg_tmp}, {emit_label lbl_call_gc}\n`; ++ `{emit_label lbl_after_alloc}:\n`; ++ ` addi.d {emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, {emit_int size_addr}\n`; ++ env.call_gc_sites <- ++ { gc_lbl = lbl_call_gc; ++ gc_return_lbl = lbl_after_alloc; ++ gc_frame_lbl = lbl_frame_lbl } :: env.call_gc_sites ++ | Lop(Ipoll { return_label }) -> ++ let lbl_frame_lbl = record_frame_label env i.live (Dbg_alloc []) in ++ let lbl_after_poll = match return_label with ++ | None -> new_label() ++ | Some(lbl) -> lbl in ++ let lbl_call_gc = new_label () in ++ let offset = Domainstate.(idx_of_field Domain_young_limit) * 8 in ++ ` ld.d {emit_reg reg_tmp}, {emit_reg reg_domain_state_ptr} ,{emit_int offset}\n`; ++ begin match return_label with ++ | None -> ` bltu {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}, {emit_label lbl_call_gc}\n`; ++ `{emit_label lbl_after_poll}:\n`; ++ | Some lbl -> ` bgeu {emit_reg reg_alloc_ptr}, {emit_reg reg_tmp}, {emit_label lbl}\n`; ++ ` b {emit_label lbl_call_gc}\n` ++ end; ++ env.call_gc_sites <- ++ { gc_lbl = lbl_call_gc; ++ gc_return_lbl = lbl_after_poll; ++ gc_frame_lbl = lbl_frame_lbl } :: env.call_gc_sites ++ | Lop(Iintop(Icomp cmp)) -> ++ begin match cmp with ++ | Isigned Clt -> ++ ` 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.d {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ++ ` sltui {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n` ++ | Isigned Cne | Iunsigned Cne -> ++ ` sub.d {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; ++ ` sltu {emit_reg i.res.(0)}, $zero, {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)) -> ++ let lbl = bound_error_label env 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.d {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int(-n)}\n` ++ | Lop(Iintop_imm(op, n)) -> (* FIXME *) ++ let instri = name_for_intop_imm op in ++ if n<0 then (* FIXME *) ++ let instr = name_for_intop op in ++ ` addi.d {emit_reg reg_tmp}, $zero, {emit_int n}\n {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg reg_tmp} \n` ++ else ++ ` {emit_string instri} {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) -> ++ ` movgr2fr.d $ft0, {emit_reg i.arg.(0)} \n`; ++ ` ffint.d.l {emit_reg i.res.(0)}, $ft0\n` ++ | Lop(Iintoffloat) -> ++ ` ftintrz.l.d $ft0, {emit_reg i.arg.(0)}\n`; ++ ` movfr2gr.d {emit_reg i.res.(0)}, $ft0 \n` ++ | Lop(Iopaque) -> ++ assert (i.arg.(0).loc = i.res.(0).loc) ++ | 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` ++ | Lreloadretaddr -> ++ let n = frame_size env in ++ reload_ra n ++ | Lreturn -> ++ let n = frame_size env in ++ emit_stack_adjustment n; ++ ` jr $ra\n` ++ | Llabel lbl -> ++ `{emit_label lbl}:\n` ++ | Lbranch lbl -> ++ ` b {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 _ -> ++ Misc.fatal_error "Emit.emit_instr (Iinttest_imm _)" ++ | Ifloattest cmp -> ++ let negated = emit_float_test cmp ~arg:i.arg ~res:reg_tmp in ++ let branch = ++ if negated ++ then "beqz" ++ else "bnez" ++ in ++ ` {emit_string branch} {emit_reg reg_tmp}, {emit_label lbl}\n` ++ | Ioddtest -> ++ ` andi {emit_reg reg_tmp}, {emit_reg i.arg.(0)}, 1\n`; ++ ` bnez {emit_reg reg_tmp}, {emit_label lbl}\n` ++ | Ieventest -> ++ ` andi {emit_reg reg_tmp}, {emit_reg i.arg.(0)}, 1\n`; ++ ` beqz {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end ++ | Lcondbranch3(lbl0, lbl1, lbl2) -> ++ ` addi.d {emit_reg reg_tmp}, {emit_reg i.arg.(0)}, -1\n`; ++ begin match lbl0 with ++ | None -> () ++ | Some lbl -> ` bltz {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end; ++ begin match lbl1 with ++ | None -> () ++ | Some lbl -> ` beqz {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end; ++ begin match lbl2 with ++ | None -> () ++ | Some lbl -> ` bgtz {emit_reg reg_tmp}, {emit_label lbl}\n` ++ end ++ | Lswitch jumptbl -> ++ (* t0 is marked as destroyed for this operation *) ++ let lbl = new_label() in ++ ` la.local {emit_reg reg_tmp}, {emit_label lbl}\n`; ++ ` slli.d $t0, {emit_reg i.arg.(0)}, 2\n`; ++ ` add.d {emit_reg reg_tmp}, {emit_reg reg_tmp}, $t0\n`; ++ ` jr {emit_reg reg_tmp}\n`; ++ `{emit_label lbl}:\n`; ++ for i = 0 to Array.length jumptbl - 1 do ++ ` b {emit_label jumptbl.(i)}\n` ++ done ++ | Lentertrap -> ++ () ++ | Ladjust_trap_depth { delta_traps } -> ++ (* each trap occupes 16 bytes on the stack *) ++ let delta = 16 * delta_traps in ++ env.stack_offset <- env.stack_offset + delta ++ | Lpushtrap {lbl_handler} -> ++ ` la.local {emit_reg reg_tmp}, {emit_label lbl_handler}\n`; ++ ` addi.d $sp, $sp, -16\n`; ++ env.stack_offset <- env.stack_offset + 16; ++ emit_store reg_tmp size_addr; ++ emit_store reg_trap 0; ++ ` move {emit_reg reg_trap}, $sp\n` ++ | Lpoptrap -> ++ emit_load reg_trap 0; ++ ` addi.d $sp, $sp, 16\n`; ++ env.stack_offset <- env.stack_offset - 16 ++ | Lraise k -> ++ begin match k with ++ | Lambda.Raise_regular -> ++ let offset = Domainstate.(idx_of_field Domain_backtrace_pos) * 8 in ++ ` st.d $zero, {emit_reg reg_domain_state_ptr},{emit_int offset}\n`; ++ ` {emit_call "caml_raise_exn"}\n`; ++ record_frame env Reg.Set.empty (Dbg_raise i.dbg) ++ | Lambda.Raise_reraise -> ++ ` {emit_call "caml_raise_exn"}\n`; ++ record_frame env Reg.Set.empty (Dbg_raise i.dbg) ++ | Lambda.Raise_notrace -> ++ ` move $sp, {emit_reg reg_trap}\n`; ++ emit_load reg_tmp size_addr; ++ emit_load reg_trap 0; ++ ` addi.d $sp, $sp, 16\n`; ++ ` jr {emit_reg reg_tmp}\n` ++ end ++ ++(* Emit a sequence of instructions *) ++ ++let rec emit_all env = function ++ | {desc = Lend} -> () | i -> emit_instr env i; emit_all env i.next ++ ++(* Emission of a function declaration *) ++ ++let fundecl fundecl = ++ let env = mk_env fundecl in ++ ` .globl {emit_symbol fundecl.fun_name}\n`; ++ ` .type {emit_symbol fundecl.fun_name}, @function\n`; ++ ` {emit_string code_space}\n`; ++ ` .align 2\n`; ++ `{emit_symbol fundecl.fun_name}:\n`; ++ emit_debug_info fundecl.fun_dbg; ++ cfi_startproc(); ++ emit_all env fundecl.fun_body; ++ List.iter emit_call_gc env.call_gc_sites; ++ List.iter emit_call_bound_error env.bound_error_sites; ++ cfi_endproc(); ++ ` .size {emit_symbol fundecl.fun_name}, .-{emit_symbol fundecl.fun_name}\n`; ++ (* Emit the float literals *) ++ if env.float_literals <> [] then begin ++ ` {emit_string rodata_space}\n`; ++ ` .align 3\n`; ++ List.iter ++ (fun {fl; lbl} -> ++ `{emit_label lbl}:\n`; ++ emit_float64_directive ".quad" fl) ++ env.float_literals; ++ end ++ ++(* Emission of data *) ++ ++let declare_global_data s = ++ ` .globl {emit_symbol s}\n`; ++ ` .type {emit_symbol s}, @object\n` ++ ++let emit_item = function ++ | Cglobal_symbol s -> ++ declare_global_data s ++ | Cdefine_symbol s -> ++ `{emit_symbol s}:\n`; ++ | Cint8 n -> ++ ` .byte {emit_int n}\n` ++ | Cint16 n -> ++ ` .short {emit_int n}\n` ++ | Cint32 n -> ++ ` .long {emit_nativeint n}\n` ++ | Cint n -> ++ ` .quad {emit_nativeint n}\n` ++ | Csingle f -> ++ emit_float32_directive ".long" (Int32.bits_of_float f) ++ | Cdouble f -> ++ emit_float64_directive ".quad" (Int64.bits_of_float f) ++ | Csymbol_address s -> ++ ` .quad {emit_symbol s}\n` ++ | Cstring s -> ++ emit_bytes_directive " .byte " s ++ | Cskip n -> ++ if n > 0 then ` .space {emit_int n}\n` ++ | Calign n -> ++ ` .align {emit_int (Misc.log2 n)}\n` ++ ++let data l = ++ ` {emit_string data_space}\n`; ++ List.iter emit_item l ++ ++(* Beginning / end of an assembly file *) ++ ++let begin_assembly() = ++ if !Clflags.dlcode || !Clflags.pic_code then ` \n`; ++ ` .file \"\"\n`; (* PR#7073 *) ++ reset_debug_info (); ++ (* Emit the beginning of the segments *) ++ let lbl_begin = Compilenv.make_symbol (Some "data_begin") in ++ ` {emit_string data_space}\n`; ++ declare_global_data lbl_begin; ++ `{emit_symbol lbl_begin}:\n`; ++ let lbl_begin = Compilenv.make_symbol (Some "code_begin") in ++ ` {emit_string code_space}\n`; ++ declare_global_data lbl_begin; ++ `{emit_symbol lbl_begin}:\n` ++ ++let end_assembly() = ++ ` {emit_string code_space}\n`; ++ let lbl_end = Compilenv.make_symbol (Some "code_end") in ++ declare_global_data lbl_end; ++ `{emit_symbol lbl_end}:\n`; ++ ` .long 0\n`; ++ ` {emit_string data_space}\n`; ++ let lbl_end = Compilenv.make_symbol (Some "data_end") in ++ declare_global_data lbl_end; ++ ` .quad 0\n`; (* PR#6329 *) ++ `{emit_symbol lbl_end}:\n`; ++ ` .quad 0\n`; ++ (* Emit the frame descriptors *) ++ ` {emit_string data_space}\n`; (* not rodata because relocations inside *) ++ let lbl = Compilenv.make_symbol (Some "frametable") in ++ declare_global_data lbl; ++ `{emit_symbol lbl}:\n`; ++ emit_frames ++ { efa_code_label = (fun l -> ` .quad {emit_label l}\n`); ++ efa_data_label = (fun l -> ` .quad {emit_label l}\n`); ++ efa_8 = (fun n -> ` .byte {emit_int n}\n`); ++ efa_16 = (fun n -> ` .short {emit_int n}\n`); ++ efa_32 = (fun n -> ` .long {emit_int32 n}\n`); ++ efa_word = (fun n -> ` .quad {emit_int n}\n`); ++ efa_align = (fun n -> ` .align {emit_int (Misc.log2 n)}\n`); ++ efa_label_rel = (fun lbl ofs -> ++ ` .long ({emit_label lbl} - .) + {emit_int32 ofs}\n`); ++ efa_def_label = (fun l -> `{emit_label l}:\n`); ++ efa_string = (fun s -> emit_bytes_directive " .byte " (s ^ "\000")) ++ } +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/loongarch64.S ocaml-4.14.1_bak/asmcomp/loongarch64/loongarch64.S +--- ocaml-4.14.1/asmcomp/loongarch64/loongarch64.S 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/loongarch64.S 2024-06-05 10:28:51.289079410 +0800 +@@ -0,0 +1,445 @@ ++/* ++************************************************************************* ++* * ++* OCaml * ++* * ++* yala * ++* * ++* Copyright © 2008-2023 LOONGSON * ++* * ++* All rights reserved. This file is distributed under the terms of * ++* the GNU Lesser General Public License version 2.1, with the * ++* special exception on linking described in the file LICENSE. * ++* * ++************************************************************************* ++*/ ++ ++/* Asm part of the runtime system, loongarch64 processor, 64-bit mode */ ++/* Must be preprocessed by cpp */ ++ ++#include "caml/m.h" ++ ++#define ARG_DOMAIN_STATE_PTR $t0 ++#define DOMAIN_STATE_PTR $s8 ++#define TRAP_PTR $s1 ++#define ALLOC_PTR $s7 ++#define TMP $t1 ++#define ARG $t2 ++ ++#define STORE st.d ++#define LOAD ld.d ++ ++#undef ASM_CFI_SUPPORTED ++#if defined(ASM_CFI_SUPPORTED) ++#define CFI_STARTPROC .cfi_startproc ++#define CFI_ENDPROC .cfi_endproc ++#define CFI_ADJUST(n) .cfi_adjust_cfa_offset n ++#define CFI_REGISTER(r1,r2) .cfi_register r1,r2 ++#define CFI_OFFSET(r,n) .cfi_offset r,n ++#else ++#define CFI_STARTPROC ++#define CFI_ENDPROC ++#define CFI_ADJUST(n) ++#define CFI_REGISTER(r1,r2) ++#define CFI_OFFSET(r,n) ++#endif ++ ++ .set domain_curr_field, 0 ++ .set domain_curr_cnt, 0 ++#define DOMAIN_STATE(c_type, name) \ ++ .equ domain_field_caml_##name, domain_curr_field ; \ ++ .set domain_curr_cnt, domain_curr_cnt + 1; \ ++ .set domain_curr_field, domain_curr_cnt*8 ++#include "../runtime/caml/domain_state.tbl" ++#undef DOMAIN_STATE ++ ++#define Caml_state(var) DOMAIN_STATE_PTR, domain_field_caml_##var ++ ++#define FUNCTION(name) \ ++ .align 2; \ ++ .globl name; \ ++ .type name, @function; \ ++name:; \ ++ CFI_STARTPROC ++ ++#define END_FUNCTION(name) \ ++ CFI_ENDPROC; \ ++ .size name, .-name ++ ++#if defined(__PIC__) ++#define PLT(r) %plt(r) ++#else ++#define PLT(r) r ++#endif ++ ++ .section .text ++/* Invoke the garbage collector. */ ++ ++ .globl caml_system__code_begin ++caml_system__code_begin: ++ ++FUNCTION(caml_call_gc) ++.Lcaml_call_gc: ++ /* Record return address */ ++ STORE $ra, Caml_state(last_return_address) ++ /* Record lowest stack address */ ++ STORE $sp, Caml_state(bottom_of_stack) ++ /* Set up stack space, saving return address */ ++ /* (1 reg for RA, 1 reg for FP, 23 allocatable int regs, ++ 20 caller-save float regs) * 8 */ ++ /* + 1 for alignment */ ++ addi.d $sp, $sp, -0x180 ++ CFI_ADJUST(0x180) ++ STORE $ra, $sp, 0x8 ++ CFI_OFFSET(ra, -0x180+8) ++ /* Save allocatable integer registers on the stack, ++ in the order given in proc.ml */ ++ STORE $a0, $sp, 0x10 ++ STORE $a1, $sp, 0x18 ++ STORE $a2, $sp, 0x20 ++ STORE $a3, $sp, 0x28 ++ STORE $a4, $sp, 0x30 ++ STORE $a5, $sp, 0x38 ++ STORE $a6, $sp, 0x40 ++ STORE $a7, $sp, 0x48 ++ STORE $s2, $sp, 0x50 ++ STORE $s3, $sp, 0x58 ++ STORE $s4, $sp, 0x60 ++ STORE $s5, $sp, 0x68 ++ STORE $s6, $sp, 0x70 ++ STORE $t2, $sp, 0x78 ++ STORE $t3, $sp, 0x80 ++ STORE $t4, $sp, 0x88 ++ STORE $t5, $sp, 0x90 ++ STORE $t6, $sp, 0x98 ++ STORE $t7, $sp, 0xa0 ++ STORE $t8, $sp, 0xa8 ++ STORE $s0, $sp, 0xb0 ++ /* Save caller-save floating-point registers on the stack ++ (callee-saves are preserved by caml_garbage_collection) */ ++ fst.d $ft0, $sp, 0xb8 ++ fst.d $ft1, $sp, 0xc0 ++ fst.d $ft2, $sp, 0xc8 ++ fst.d $ft3, $sp, 0xd0 ++ fst.d $ft4, $sp, 0xd8 ++ fst.d $ft5, $sp, 0xe0 ++ fst.d $ft6, $sp, 0xe8 ++ fst.d $ft7, $sp, 0xf0 ++ fst.d $fa0, $sp, 0xf8 ++ fst.d $fa1, $sp, 0x100 ++ fst.d $fa2, $sp, 0x108 ++ fst.d $fa3, $sp, 0x110 ++ fst.d $fa4, $sp, 0x118 ++ fst.d $fa5, $sp, 0x120 ++ fst.d $fa6, $sp, 0x128 ++ fst.d $fa7, $sp, 0x130 ++ fst.d $ft8, $sp, 0x138 ++ fst.d $ft9, $sp, 0x140 ++ fst.d $ft10, $sp, 0x148 ++ fst.d $ft11, $sp, 0x150 ++ fst.d $ft12, $sp, 0x158 ++ fst.d $ft13, $sp, 0x160 ++ fst.d $ft14, $sp, 0x168 ++ fst.d $ft15, $sp, 0x170 ++ /* Store pointer to saved integer registers in caml_gc_regs */ ++ addi.d TMP, $sp, 0x10 ++ STORE TMP, Caml_state(gc_regs) ++ /* Save current allocation pointer for debugging purposes */ ++ STORE ALLOC_PTR, Caml_state(young_ptr) ++ /* Save trap pointer in case an exception is raised during GC */ ++ STORE TRAP_PTR, Caml_state(exception_pointer) ++ /* Call the garbage collector */ ++ bl PLT(caml_garbage_collection) ++ /* Restore registers */ ++ LOAD $a0, $sp, 0x10 ++ LOAD $a1, $sp, 0x18 ++ LOAD $a2, $sp, 0x20 ++ LOAD $a3, $sp, 0x28 ++ LOAD $a4, $sp, 0x30 ++ LOAD $a5, $sp, 0x38 ++ LOAD $a6, $sp, 0x40 ++ LOAD $a7, $sp, 0x48 ++ LOAD $s2, $sp, 0x50 ++ LOAD $s3, $sp, 0x58 ++ LOAD $s4, $sp, 0x60 ++ LOAD $s5, $sp, 0x68 ++ LOAD $s6, $sp, 0x70 ++ LOAD $t2, $sp, 0x78 ++ LOAD $t3, $sp, 0x80 ++ LOAD $t4, $sp, 0x88 ++ LOAD $t5, $sp, 0x90 ++ LOAD $t6, $sp, 0x98 ++ LOAD $t7, $sp, 0xa0 ++ LOAD $t8, $sp, 0xa8 ++ LOAD $s0, $sp, 0xb0 ++ fld.d $ft0, $sp, 0xb8 ++ fld.d $ft1, $sp, 0xc0 ++ fld.d $ft2, $sp, 0xc8 ++ fld.d $ft3, $sp, 0xd0 ++ fld.d $ft4, $sp, 0xd8 ++ fld.d $ft5, $sp, 0xe0 ++ fld.d $ft6, $sp, 0xe8 ++ fld.d $ft7, $sp, 0xf0 ++ fld.d $fa0, $sp, 0xf8 ++ fld.d $fa1, $sp, 0x100 ++ fld.d $fa2, $sp, 0x108 ++ fld.d $fa3, $sp, 0x110 ++ fld.d $fa4, $sp, 0x118 ++ fld.d $fa5, $sp, 0x120 ++ fld.d $fa6, $sp, 0x128 ++ fld.d $fa7, $sp, 0x130 ++ fld.d $ft8, $sp, 0x138 ++ fld.d $ft9, $sp, 0x140 ++ fld.d $ft10, $sp, 0x148 ++ fld.d $ft11, $sp, 0x150 ++ fld.d $ft12, $sp, 0x158 ++ fld.d $ft13, $sp, 0x160 ++ fld.d $ft14, $sp, 0x168 ++ fld.d $ft15, $sp, 0x170 ++ /* Reload new allocation pointer */ ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ /* Free stack space and return to caller */ ++ LOAD $ra, $sp, 0x8 ++ addi.d $sp, $sp, 0x180 ++ CFI_ADJUST(-0x180) ++ jr $ra ++END_FUNCTION(caml_call_gc) ++ ++/* Call a C function from OCaml */ ++/* Function to bl is in ARG */ ++ ++FUNCTION(caml_c_call) ++ /* Preserve return address in callee-save register s2 */ ++ move $s2, $ra ++ CFI_REGISTER(ra, s2) ++ /* Record lowest stack address and return address */ ++ STORE $ra, Caml_state(last_return_address) ++ STORE $sp, Caml_state(bottom_of_stack) ++ /* Make the exception handler alloc ptr available to the C code */ ++ STORE ALLOC_PTR, Caml_state(young_ptr) ++ STORE TRAP_PTR, Caml_state(exception_pointer) ++ /* Call the function */ ++ jirl $ra, ARG, 0 ++ /* Reload alloc ptr */ ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ /* Return */ ++ jr $s2 ++END_FUNCTION(caml_c_call) ++ ++/* Raise an exception from OCaml */ ++FUNCTION(caml_raise_exn) ++ /* Test if backtrace is active */ ++ LOAD TMP, Caml_state(backtrace_active) ++ bnez TMP, 2f ++1: /* Cut stack at current trap handler */ ++ move $sp, TRAP_PTR ++ /* Pop previous handler and jump to it */ ++ LOAD TMP, $sp, 8 ++ LOAD TRAP_PTR, $sp, 0 ++ addi.d $sp, $sp, 16 ++ CFI_ADJUST(-16) ++ jr TMP ++2: /* Preserve exception bucket in callee-save register s2 */ ++ move $s2, $a0 ++ /* Stash the backtrace */ ++ move $a1, $ra ++ move $a2, $sp ++ move $a3, TRAP_PTR ++ bl PLT(caml_stash_backtrace) ++ /* Restore exception bucket and raise */ ++ move $a0, $s2 ++ b 1b ++END_FUNCTION(caml_raise_exn) ++ ++ .globl caml_reraise_exn ++ .type caml_reraise_exn, @function ++ ++/* Raise an exception from C */ ++ ++FUNCTION(caml_raise_exception) ++ move DOMAIN_STATE_PTR, $a0 ++ move $a0, $a1 ++ LOAD TRAP_PTR, Caml_state(exception_pointer) ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ LOAD TMP, Caml_state(backtrace_active) ++ bnez TMP, 2f ++1: /* Cut stack at current trap handler */ ++ move $sp, TRAP_PTR ++ LOAD TMP, $sp, 8 ++ LOAD TRAP_PTR, $sp, 0 ++ addi.d $sp, $sp, 16 ++ CFI_ADJUST(-16) ++ jr TMP ++2: /* Preserve exception bucket in callee-save register s2 */ ++ move $s2, $a0 ++ LOAD $a1, Caml_state(last_return_address) ++ LOAD $a2, Caml_state(bottom_of_stack) ++ move $a3, TRAP_PTR ++ bl PLT(caml_stash_backtrace) ++ move $a0, $s2 ++ b 1b ++END_FUNCTION(caml_raise_exception) ++ ++/* Start the OCaml program */ ++ ++FUNCTION(caml_start_program) ++ move ARG_DOMAIN_STATE_PTR, $a0 ++ la.global ARG, caml_program ++ /* Code shared with caml_callback* */ ++ /* Address of OCaml code to bl is in ARG */ ++ /* Arguments to the OCaml code are in a0 ... a7 */ ++.Ljump_to_caml: ++ /* Set up stack frame and save callee-save registers */ ++ addi.d $sp, $sp, -0xa0 ++ CFI_ADJUST(0xa0) ++ STORE $ra, $sp, 0x90 ++ CFI_OFFSET(ra, -0xa0+0xb0) ++ STORE $s0, $sp, 0x0 ++ STORE $s1, $sp, 0x8 ++ STORE $s2, $sp, 0x10 ++ STORE $s3, $sp, 0x18 ++ STORE $s4, $sp, 0x20 ++ STORE $s5, $sp, 0x28 ++ STORE $s6, $sp, 0x30 ++ STORE $s7, $sp, 0x38 ++ STORE $s8, $sp, 0x40 ++ fst.d $fs0, $sp, 0x48 ++ fst.d $fs1, $sp, 0x50 ++ fst.d $fs2, $sp, 0x58 ++ fst.d $fs3, $sp, 0x60 ++ fst.d $fs4, $sp, 0x68 ++ fst.d $fs5, $sp, 0x70 ++ fst.d $fs6, $sp, 0x78 ++ fst.d $fs7, $sp, 0x80 ++ addi.d $sp, $sp, -32 ++ CFI_ADJUST(32) ++ /* Load domain state pointer from argument */ ++ move DOMAIN_STATE_PTR, ARG_DOMAIN_STATE_PTR ++ /* Setup a callback link on the stack */ ++ LOAD TMP, Caml_state(bottom_of_stack) ++ STORE TMP, $sp, 0 ++ LOAD TMP, Caml_state(last_return_address) ++ STORE TMP, $sp, 8 ++ LOAD TMP, Caml_state(gc_regs) ++ STORE TMP, $sp, 16 ++ /* set up a trap frame */ ++ addi.d $sp, $sp, -16 ++ CFI_ADJUST(16) ++ LOAD TMP, Caml_state(exception_pointer) ++ STORE TMP, $sp, 0 ++ la.local TMP, .Ltrap_handler ++ STORE TMP, $sp, 8 ++ move TRAP_PTR, $sp ++ LOAD ALLOC_PTR, Caml_state(young_ptr) ++ STORE $zero, Caml_state(last_return_address) ++ jirl $ra, ARG, 0 ++.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ ++ LOAD TMP, $sp, 0 ++ STORE TMP, Caml_state(exception_pointer) ++ addi.d $sp, $sp, 16 ++ CFI_ADJUST(-16) ++.Lreturn_result: /* pop callback link, restoring global variables */ ++ LOAD TMP, $sp, 0 ++ STORE TMP, Caml_state(bottom_of_stack) ++ LOAD TMP, $sp, 8 ++ STORE TMP, Caml_state(last_return_address) ++ LOAD TMP, $sp, 16 ++ STORE TMP, Caml_state(gc_regs) ++ addi.d $sp, $sp, 32 ++ CFI_ADJUST(-32) ++ /* Update allocation pointer */ ++ STORE ALLOC_PTR, Caml_state(young_ptr) ++ /* reload callee-save registers and return */ ++ LOAD $ra, $sp, 0x90 ++ LOAD $s0, $sp, 0x0 ++ LOAD $s1, $sp, 0x8 ++ LOAD $s2, $sp, 0x10 ++ LOAD $s3, $sp, 0x18 ++ LOAD $s4, $sp, 0x20 ++ LOAD $s5, $sp, 0x28 ++ LOAD $s6, $sp, 0x30 ++ LOAD $s7, $sp, 0x38 ++ LOAD $s8, $sp, 0x40 ++ fld.d $fs0, $sp, 0x48 ++ fld.d $fs1, $sp, 0x50 ++ fld.d $fs2, $sp, 0x58 ++ fld.d $fs3, $sp, 0x60 ++ fld.d $fs4, $sp, 0x68 ++ fld.d $fs5, $sp, 0x70 ++ fld.d $fs6, $sp, 0x78 ++ fld.d $fs7, $sp, 0x80 ++ addi.d $sp, $sp, 0xa0 ++ CFI_ADJUST(-0xa0) ++ jr $ra ++ .type .Lcaml_retaddr, @function ++ .size .Lcaml_retaddr, .-.Lcaml_retaddr ++END_FUNCTION(caml_start_program) ++ ++ .align 2 ++.Ltrap_handler: ++ CFI_STARTPROC ++ STORE TRAP_PTR, Caml_state(exception_pointer) ++ ori $a0, $a0, 2 ++ b .Lreturn_result ++ .type .Ltrap_handler, @function ++END_FUNCTION(.Ltrap_handler) ++ ++/* Callback from C to OCaml */ ++ ++FUNCTION(caml_callback_asm) ++ /* Initial shuffling of arguments */ ++ /* a0 = Caml_state, a1 = closure, (a2) = args */ ++ move ARG_DOMAIN_STATE_PTR, $a0 ++ LOAD $a0, $a2, 0 /* a0 = first arg */ ++ /* a1 = closure environment */ ++ LOAD ARG, $a1, 0 /* code pointer */ ++ b .Ljump_to_caml ++END_FUNCTION(caml_callback_asm) ++ ++FUNCTION(caml_callback2_asm) ++ /* Initial shuffling of arguments */ ++ /* a0 = Caml_state, a1 = closure, (a2) = args */ ++ move ARG_DOMAIN_STATE_PTR, $a0 ++ move TMP, $a1 ++ LOAD $a0, $a2, 0 ++ LOAD $a1, $a2, 8 ++ move $a2, TMP ++ la.global ARG, caml_apply2 ++ b .Ljump_to_caml ++END_FUNCTION(caml_callback2_asm) ++ ++FUNCTION(caml_callback3_asm) ++ /* Initial shuffling of arguments */ ++ /* a0 = Caml_state, a1 = closure, (a2) = args */ ++ move ARG_DOMAIN_STATE_PTR, $a0 ++ move $a3, $a1 ++ LOAD $a0, $a2, 0 ++ LOAD $a1, $a2, 8 ++ LOAD $a2, $a2, 16 ++ la.global ARG, caml_apply3 ++ b .Ljump_to_caml ++END_FUNCTION(caml_callback3_asm) ++ ++FUNCTION(caml_ml_array_bound_error) ++ /* Load address of [caml_array_bound_error] in ARG */ ++ la.global ARG, caml_array_bound_error ++ /* Call that function */ ++ b caml_c_call ++END_FUNCTION(caml_ml_array_bound_error) ++ ++ .globl caml_system__code_end ++caml_system__code_end: ++ ++/* GC roots for callback */ ++ ++ .section .data ++ .align 3 ++ .globl caml_system__frametable ++ .type caml_system__frametable, @object ++caml_system__frametable: ++ .quad 1 /* one descriptor */ ++ .quad .Lcaml_retaddr /* return address into callback */ ++ .short -1 /* negative frame size => use callback link */ ++ .short 0 /* no roots */ ++ .align 3 ++ .size caml_system__frametable, .-caml_system__frametable +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/NOTES.md ocaml-4.14.1_bak/asmcomp/loongarch64/NOTES.md +--- ocaml-4.14.1/asmcomp/loongarch64/NOTES.md 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/NOTES.md 2024-06-05 10:28:51.277079410 +0800 +@@ -0,0 +1,13 @@ ++# Supported platforms ++ ++LoongArch in 64-bit mode ++ ++Debian architecture name: `loongarch64` ++ ++# Reference documents ++ ++* Instruction set specification: ++ - https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html ++ ++* ELF ABI specification: ++ - https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/proc.ml ocaml-4.14.1_bak/asmcomp/loongarch64/proc.ml +--- ocaml-4.14.1/asmcomp/loongarch64/proc.ml 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/proc.ml 2024-06-05 10:28:51.281079410 +0800 +@@ -0,0 +1,311 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++(* Description of the loongarch *) ++ ++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 ++ a0-a7 0-7 arguments/results ++ s2-s6 8-12 arguments/results (preserved by C) ++ t2-t8 13-19 temporary ++ s0 20 general purpose (preserved by C) ++ t0 21 temporary ++ t1 22 temporary (used by code generator) ++ s1 23 trap pointer (preserved by C) ++ s7 24 allocation pointer (preserved by C) ++ s8 25 domain pointer (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-fs7 118-123 arguments/results (preserved by C) ++ ft8-ft15 124-131 temporary ++ ++ Additional notes ++ ---------------- ++ ++ - t1 is used by the code generator, so not available for register ++ allocation. ++ ++ - t0-t6 may be used by PLT stubs, so should not be used to pass ++ arguments and may be clobbered by [Ialloc] in the presence of dynamic ++ linking. ++*) ++ ++let int_reg_name = ++ [| "$a0"; "$a1"; "$a2"; "$a3"; "$a4"; "$a5"; "$a6"; "$a7"; (* 0 - 7 *) ++ "$s2"; "$s3"; "$s4"; "$s5"; "$s6"; (* 8 - 12 *) ++ "$t2"; "$t3"; "$t4"; "$t5"; "$t6"; "$t7"; "$t8"; (* 13 - 19 *) ++ "$s0"; (* 20 *) ++ "$t0"; "$t1"; (* 21 - 22 *) ++ "$s1"; "$s7"; "$s8" |] (* 23 - 25 *) ++ ++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"; ++ "$ft8"; "$ft9"; "$ft10"; "$ft11"; "$ft12"; "$ft13"; "$ft14"; "$ft15"; |] ++ ++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 26 Reg.dummy in ++ for i = 0 to 25 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) 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 ++ ++(* 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 loc_arguments arg = ++ calling_conventions 0 12 110 123 outgoing arg ++ ++let loc_parameters arg = ++ let (loc, _ofs) = ++ calling_conventions 0 12 110 123 incoming arg ++ in ++ loc ++ ++let loc_results res = ++ let (loc, _ofs) = ++ calling_conventions 0 12 110 123 not_supported res ++ in ++ loc ++ ++(* C calling convention: ++ first integer args in a0 .. a7 ++ first float args in fa0 .. fa7 ++ remaining args on stack. ++ A FP argument can be passed in an integer register if all FP registers ++ are exhausted but integer registers remain. ++ Return values in a0 .. a1 or fa0 .. fa1. *) ++ ++let external_calling_conventions ++ first_int last_int first_float last_float make_stack arg = ++ let loc = Array.make (Array.length arg) [| Reg.dummy |] in ++ let int = ref first_int in ++ let float = ref first_float in ++ let ofs = ref 0 in ++ for i = 0 to Array.length arg - 1 do ++ match arg.(i) with ++ | Val | Int | Addr as ty -> ++ if !int <= last_int then begin ++ loc.(i) <- [| phys_reg !int |]; ++ incr int ++ 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 if !int <= last_int then begin ++ loc.(i) <- [| phys_reg !int |]; ++ incr int ++ end else begin ++ loc.(i) <- [| stack_slot (make_stack !ofs) Float |]; ++ ofs := !ofs + size_float ++ end ++ done; ++ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *) ++ ++let loc_external_arguments ty_args = ++ let arg = Cmm.machtype_of_exttype_list ty_args in ++ external_calling_conventions 0 7 110 117 outgoing arg ++ ++let loc_external_results res = ++ let (loc, _ofs) = calling_conventions 0 1 110 111 not_supported res ++ in loc ++ ++(* Exceptions are in a0 *) ++ ++let loc_exn_bucket = phys_reg 0 ++ ++(* Volatile registers: none *) ++ ++let regs_are_volatile _ = false ++ ++(* Registers destroyed by operations *) ++ ++let destroyed_at_c_call = ++ (* s0-s11 and fs0-fs11 are callee-save. However s2 needs to be in this ++ list since it is clobbered by caml_c_call itself. *) ++ Array.of_list(List.map phys_reg ++ [0; 1; 2; 3; 4; 5; 6; 7; 8; 13; 14; 15; 16; 17; 18; 19; ++ 100; 101; 102; 103; 104; 105; 106; 107; 110; 111; 112; 113; 114; 115; 116; ++ 117; 128; 129; 130; 131]) ++ ++let destroyed_at_alloc = ++ (* t0-t6 are used for PLT stubs *) ++ if !Clflags.dlcode then Array.map phys_reg [|13; 14; 15; 16; 17; 18; 19; 20; 21; 22|] ++ else [| |] ++ ++let destroyed_at_oper = function ++ | Iop(Icall_ind | Icall_imm _ | Iextcall{alloc = true; _}) -> all_phys_regs ++ | Iop(Iextcall{alloc = false; _}) -> destroyed_at_c_call ++ | Iop(Ialloc _) | Iop(Ipoll _) -> destroyed_at_alloc ++ | Iop(Istore(Single, _, _)) -> [| phys_reg 100 |] ++ | Iop(Ifloatofint | Iintoffloat) -> [| phys_reg 100 |] ++ | Iswitch _ -> [| phys_reg 21 |] (* t0 *) ++ | _ -> [||] ++ ++let destroyed_at_raise = all_phys_regs ++ ++let destroyed_at_reloadretaddr = [| |] ++ ++(* Maximal register pressure *) ++ ++let safe_register_pressure = function ++ | Iextcall _ -> 5 ++ | _ -> 21 ++ ++let max_register_pressure = function ++ | Iextcall _ -> [| 5; 8 |] ++ | _ -> [| 21; 30 |] ++ ++(* Layout of the stack *) ++ ++let frame_required fd = ++ fd.fun_contains_calls ++ || fd.fun_num_stack_slots.(0) > 0 ++ || fd.fun_num_stack_slots.(1) > 0 ++ ++let prologue_required fd = ++ frame_required fd ++ ++let int_dwarf_reg_numbers = ++ [| 10; 11; 12; 13; 14; 15; 16; 17; ++ 18; 19; 20; 21; 22; 23; 24; 25; ++ 7; 28; 29; 30; 31; ++ 8; ++ 5; 6; ++ 9; 26; 27; ++ |] ++ ++let float_dwarf_reg_numbers = ++ [| 32; 33; 34; 35; 36; 37; 38; 39; ++ 40; 41; ++ 42; 43; 44; 45; 46; 47; 48; 49; ++ 50; 51; 52; 53; 54; 55; 56; 57; ++ 58; 59; ++ 60; 61; 62; 63; ++ |] ++ ++let dwarf_register_numbers ~reg_class = ++ match reg_class with ++ | 0 -> int_dwarf_reg_numbers ++ | 1 -> float_dwarf_reg_numbers ++ | _ -> Misc.fatal_errorf "Bad register class %d" reg_class ++ ++let stack_ptr_dwarf_register_number = 2 ++ ++(* Calling the assembler *) ++ ++let assemble_file infile outfile = ++ Ccomp.command ++ (Config.asm ^ " -o " ^ Filename.quote outfile ^ " " ^ Filename.quote infile) ++ ++let init () = () +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/reload.ml ocaml-4.14.1_bak/asmcomp/loongarch64/reload.ml +--- ocaml-4.14.1/asmcomp/loongarch64/reload.ml 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/reload.ml 2024-06-05 10:28:51.285079410 +0800 +@@ -0,0 +1,18 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++(* Reloading for the loongarch *) ++ ++let fundecl f = ++ (new Reloadgen.reload_generic)#fundecl f +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/scheduling.ml ocaml-4.14.1_bak/asmcomp/loongarch64/scheduling.ml +--- ocaml-4.14.1/asmcomp/loongarch64/scheduling.ml 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/scheduling.ml 2024-06-05 10:28:51.285079410 +0800 +@@ -0,0 +1,21 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++(* Instruction scheduling for the loongarch *) ++ ++open! Schedgen (* to create a dependency *) ++ ++(* Scheduling is turned off. *) ++ ++let fundecl f = f +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/selection.ml ocaml-4.14.1_bak/asmcomp/loongarch64/selection.ml +--- ocaml-4.14.1/asmcomp/loongarch64/selection.ml 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/selection.ml 2024-06-05 10:28:51.285079410 +0800 +@@ -0,0 +1,64 @@ ++ ++(**************************************************************************) ++(* *) ++(* OCaml *) ++(* *) ++(* yala *) ++(* *) ++(* Copyright © 2008-2023 LOONGSON *) ++(* *) ++(* All rights reserved. This file is distributed under the terms of *) ++(* the GNU Lesser General Public License version 2.1, with the *) ++(* special exception on linking described in the file LICENSE. *) ++(* *) ++(**************************************************************************) ++(* Instruction selection for the loongarch processor *) ++ ++open Cmm ++open Arch ++open Mach ++ ++(* Instruction selection *) ++ ++class selector = object ++ ++inherit Selectgen.selector_generic as super ++ ++(* loongarch does not support immediate operands for comparison operators *) ++method is_immediate_test _cmp _n = false ++ ++method! is_immediate op n = ++ match op with ++ | Iadd | Iand | Ior | Ixor -> is_immediate n ++ (* sub immediate is turned into add immediate opposite *) ++ | Isub -> is_immediate (-n) ++ | _ -> super#is_immediate op n ++ ++method select_addressing _ = function ++ | Cop(Cadda, [arg; Cconst_int (n, _)], _) when is_immediate n -> ++ (Iindexed n, arg) ++ | Cop(Cadda, [arg1; Cop(Caddi, [arg2; Cconst_int (n, _)], _)], dbg) ++ when is_immediate n -> ++ (Iindexed n, Cop(Caddi, [arg1; arg2], dbg)) ++ | arg -> ++ (Iindexed 0, arg) ++ ++method! select_operation op args dbg = ++ match (op, args) with ++ (* Recognize (neg-)mult-add and (neg-)mult-sub instructions *) ++ | (Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3]) ++ | (Caddf, [arg3; Cop(Cmulf, [arg1; arg2], _)]) -> ++ (Ispecific (Imultaddf false), [arg1; arg2; arg3]) ++ | (Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3]) -> ++ (Ispecific (Imultsubf false), [arg1; arg2; arg3]) ++ | (Cnegf, [Cop(Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) -> ++ (Ispecific (Imultsubf true), [arg1; arg2; arg3]) ++ | (Cnegf, [Cop(Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) -> ++ (Ispecific (Imultaddf true), [arg1; arg2; arg3]) ++ | _ -> ++ super#select_operation op args dbg ++ ++end ++ ++let fundecl ~future_funcnames f = ++ (new selector)#emit_fundecl ~future_funcnames f +diff -Naur ocaml-4.14.1/asmcomp/loongarch64/stack.h ocaml-4.14.1_bak/asmcomp/loongarch64/stack.h +--- ocaml-4.14.1/asmcomp/loongarch64/stack.h 1970-01-01 08:00:00.000000000 +0800 ++++ ocaml-4.14.1_bak/asmcomp/loongarch64/stack.h 2024-06-05 10:28:51.289079410 +0800 +@@ -0,0 +1,152 @@ ++/**************************************************************************/ ++/* */ ++/* OCaml */ ++/* */ ++/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ ++/* */ ++/* Copyright 1996 Institut National de Recherche en Informatique et */ ++/* en Automatique. */ ++/* */ ++/* All rights reserved. This file is distributed under the terms of */ ++/* the GNU Lesser General Public License version 2.1, with the */ ++/* special exception on linking described in the file LICENSE. */ ++/* */ ++/**************************************************************************/ ++ ++/* Machine-dependent interface with the asm code */ ++ ++#ifndef CAML_STACK_H ++#define CAML_STACK_H ++ ++#ifdef CAML_INTERNALS ++ ++/* Macros to access the stack frame */ ++ ++#ifdef TARGET_i386 ++#define Saved_return_address(sp) *((intnat *)((sp) - 4)) ++#ifndef SYS_win32 ++#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) ++#else ++#define Callback_link(sp) ((struct caml_context *)((sp) + 8)) ++#endif ++#endif ++ ++#ifdef TARGET_power ++#if defined(MODEL_ppc) ++#define Saved_return_address(sp) *((intnat *)((sp) - 4)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) ++#elif defined(MODEL_ppc64) ++#define Saved_return_address(sp) *((intnat *)((sp) + 16)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + (48 + 32))) ++#elif defined(MODEL_ppc64le) ++#define Saved_return_address(sp) *((intnat *)((sp) + 16)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + (32 + 32))) ++#else ++#error "TARGET_power: wrong MODEL" ++#endif ++#define Already_scanned(sp, retaddr) ((retaddr) & 1) ++#define Mask_already_scanned(retaddr) ((retaddr) & ~1) ++#define Mark_scanned(sp, retaddr) Saved_return_address(sp) = (retaddr) | 1 ++#endif ++ ++#ifdef TARGET_s390x ++#define Saved_return_address(sp) *((intnat *)((sp) - SIZEOF_PTR)) ++#define Trap_frame_size 16 ++#define Callback_link(sp) ((struct caml_context *)((sp) + Trap_frame_size)) ++#endif ++ ++#ifdef TARGET_arm ++#define Saved_return_address(sp) *((intnat *)((sp) - 4)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + 8)) ++#endif ++ ++#ifdef TARGET_amd64 ++#define Saved_return_address(sp) *((intnat *)((sp) - 8)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) ++#endif ++ ++#ifdef TARGET_arm64 ++#define Saved_return_address(sp) *((intnat *)((sp) - 8)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) ++#endif ++ ++#ifdef TARGET_riscv ++#define Saved_return_address(sp) *((intnat *)((sp) - 8)) ++#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) ++#endif ++ ++#ifdef TARGET_loongarch64 ++#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 { ++ char * bottom_of_stack; /* beginning of OCaml stack chunk */ ++ uintnat last_retaddr; /* last return address in OCaml code */ ++ value * gc_regs; /* pointer to register block */ ++}; ++ ++/* Structure of frame descriptors */ ++ ++typedef struct { ++ uintnat retaddr; ++ unsigned short frame_size; ++ unsigned short num_live; ++ unsigned short live_ofs[1 /* num_live */]; ++ /* ++ If frame_size & 2, then allocation info follows: ++ unsigned char num_allocs; ++ unsigned char alloc_lengths[num_alloc]; ++ ++ If frame_size & 1, then debug info follows: ++ uint32_t debug_info_offset[num_debug]; ++ ++ Debug info is stored as relative offsets to debuginfo structures. ++ num_debug is num_alloc if frame_size & 2, otherwise 1. */ ++} frame_descr; ++ ++/* Allocation lengths are encoded as 0-255, giving sizes 1-256 */ ++#define Wosize_encoded_alloc_len(n) ((uintnat)(n) + 1) ++ ++/* Used to compute offsets in frame tables. ++ ty must have power-of-2 size */ ++#define Align_to(p, ty) \ ++ (void*)(((uintnat)(p) + sizeof(ty) - 1) & -sizeof(ty)) ++ ++ ++/* Hash table of frame descriptors */ ++ ++extern frame_descr ** caml_frame_descriptors; ++extern uintnat caml_frame_descriptors_mask; ++ ++#define Hash_retaddr(addr) \ ++ (((uintnat)(addr) >> 3) & caml_frame_descriptors_mask) ++ ++extern void caml_init_frame_descriptors(void); ++extern void caml_register_frametable(intnat *); ++extern void caml_unregister_frametable(intnat *); ++extern void caml_register_dyn_global(void *); ++ ++extern uintnat caml_stack_usage (void); ++extern uintnat (*caml_stack_usage_hook)(void); ++ ++/* Declaration of variables used in the asm code */ ++extern value * caml_globals[]; ++extern char caml_globals_map[]; ++extern intnat caml_globals_inited; ++extern intnat * caml_frametable[]; ++ ++/* Global variables moved to Caml_state in 4.10 */ ++#define caml_top_of_stack (Caml_state_field(top_of_stack)) ++#define caml_bottom_of_stack (Caml_state_field(bottom_of_stack)) ++#define caml_last_return_address (Caml_state_field(last_return_address)) ++#define caml_gc_regs (Caml_state_field(gc_regs)) ++#define caml_exception_pointer (Caml_state_field(exception_pointer)) ++ ++CAMLextern frame_descr * caml_next_frame_descriptor(uintnat * pc, char ** sp); ++ ++#endif /* CAML_INTERNALS */ ++ ++#endif /* CAML_STACK_H */ +diff -Naur ocaml-4.14.1/Makefile ocaml-4.14.1_bak/Makefile +--- ocaml-4.14.1/Makefile 2022-12-19 23:49:43.000000000 +0800 ++++ ocaml-4.14.1_bak/Makefile 2024-06-05 10:23:54.629079410 +0800 +@@ -39,7 +39,7 @@ + + CAMLC=$(BOOT_OCAMLC) -g -nostdlib -I boot -use-prims runtime/primitives + CAMLOPT=$(OCAMLRUN) ./ocamlopt$(EXE) -g -nostdlib -I stdlib -I otherlibs/dynlink +-ARCHES=amd64 i386 arm arm64 power s390x riscv ++ARCHES=amd64 i386 arm arm64 power s390x riscv loongarch64 + INCLUDES=-I utils -I parsing -I typing -I bytecomp -I file_formats \ + -I lambda -I middle_end -I middle_end/closure \ + -I middle_end/flambda -I middle_end/flambda/base_types \ diff --git a/ocaml.spec b/ocaml.spec index 2a9252f..9acc4be 100644 --- a/ocaml.spec +++ b/ocaml.spec @@ -1,10 +1,10 @@ -%ifnarch loongarch64 +%ifnarch loongarch64 sw_64 %global native_compiler 1 %else %global native_compiler 0 %endif -%ifnarch loongarch64 +%ifnarch loongarch64 sw_64 %global natdynlink 1 %else %global natdynlink 0 @@ -13,7 +13,7 @@ Name: ocaml Version: 4.14.1 -Release: 1 +Release: 3 Summary: OCaml compiler and programming environment License: LGPL-2.1-only URL: http://www.ocaml.org @@ -22,6 +22,7 @@ Source0: https://github.com/ocaml/ocaml/archive/refs/tags/%{name}-%{versi Patch0001: 0001-Don-t-add-rpaths-to-libraries.patch Patch0002: 0002-configure-Allow-user-defined-C-compiler-flags.patch Patch0003: 0003-configure-Remove-incorrect-assumption-about-cross-co.patch +Patch004: 0004-Add-loongarch64-native-support.patch BuildRequires: gcc binutils-devel ncurses-devel gdbm-devel gawk perl-interpreter BuildRequires: util-linux chrpath autoconf annobin make @@ -38,6 +39,12 @@ Obsoletes: %{name}-ocamldoc %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' +%ifarch loongarch64 +%global __requires_exclude %{?__requires_exclude:%{__requires_exclude}|}ocaml\\(Backend_intf\\)\.* +%global __requires_exclude %{?__requires_exclude:%{__requires_exclude}|}ocaml\\(Inlining_decision_intf\\)\.* +%global __requires_exclude %{?__requires_exclude:%{__requires_exclude}|}ocaml\\(Simplify_boxed_integer_ops_intf\\)\.* +%endif + %description OCaml is a high-level, strongly-typed, functional and object-oriented programming language from the ML family of languages. This package @@ -74,8 +81,8 @@ Help files for %{name} %autosetup -n %{name}-%{version} -p1 autoconf --force -# add for loongarch64 -%ifarch loongarch64 +# add for loongarch64 sw_64 +%ifarch loongarch64 sw_64 %_update_config_guess %_update_config_sub %endif @@ -99,6 +106,9 @@ bash -x tools/autogen OC_CFLAGS="$CFLAGS $EXTRA_CFLAGS" \ OC_LDFLAGS="$LDFLAGS" \ --libdir=%{_libdir}/ocaml \ +%ifarch sw_64 + --enable-imprecise-c99-float-ops \ +%endif --host=`./build-aux/config.guess` %make_build world %if %{native_compiler} @@ -248,6 +258,9 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/ocaml/eventlog_metadata %{_mandir}/man3/* %changelog +* Wed Jun 5 2024 yueyaoqiang -4.14.1-3 +- Add support for sw_64 and loongarch64 + * Fri Feb 2 2024 Jingwiw - 4.14.1-1 - Upgrade version to 4.14.1 -- Gitee