Skip to content

Commit

Permalink
Merge pull request #12700 from xavierleroy/gen-prims
Browse files Browse the repository at this point in the history
Generate runtime/prims.c with the correct types in primitive declarations
  • Loading branch information
xavierleroy authored Oct 31, 2023
2 parents 8cc728b + d3f15b1 commit 217d42e
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 70 deletions.
4 changes: 4 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ Working version
`CAMLprim`, or remove them entirely if no longer used.
(Xavier Leroy, review by David Allsopp)

- #12700, continuing #11763 and trying to address #12660:
Use the correct types for primitives when generating the table of primitives
used by ocamlrun.
(Xavier Leroy, motivation, review and improvements by Antonin Décimo)

### Code generation and optimizations:

Expand Down
47 changes: 9 additions & 38 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1251,48 +1251,19 @@ runtime/ld.conf: $(ROOTDIR)/Makefile.config
$(V_GEN)echo "$(STUBLIBDIR)" > $@ && \
echo "$(LIBDIR)" >> $@

# If primitives contain duplicated lines (e.g. because the code is defined
# like
# #ifdef X
# CAMLprim value caml_foo() ...
# #else
# CAMLprim value caml_foo() ...
# #endif), horrible things will happen: duplicated entries in Runtimedef ->
# double registration in Symtable -> empty entry in the PRIM table ->
# the bytecode interpreter is confused.
# We sort the primitive file and remove duplicates to avoid this problem.

# Warning: we use "sort | uniq" instead of "sort -u" because in the MSVC
# port, the "sort" program in the path is Microsoft's and not cygwin's

# Warning: POSIX sort is locale dependent, that's why we set LC_ALL explicitly.
# Sort is unstable for "is_directory" and "isatty"
# see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html:
# "using sort to process pathnames, it is recommended that LC_ALL .. set to C"

# To speed up builds, we avoid changing "primitives" when files
# containing primitives change but the primitives table does not
runtime/primitives: \
$(shell runtime/gen_primitives.sh > runtime/primitives.new; \
runtime/primitives: runtime/gen_primitives.sh \
$(shell runtime/gen_primitives.sh $(runtime_BYTECODE_C_SOURCES) \
> runtime/primitives.new; \
cmp -s runtime/primitives runtime/primitives.new || \
echo runtime/primitives.new)
$(V_GEN)cp $^ $@

runtime/prims.c : runtime/primitives
$(V_GEN)export LC_ALL=C; \
(echo '#include "caml/config.h"'; \
echo 'typedef intnat value;'; \
echo 'typedef value (*c_primitive)(void);'; \
echo; \
sed -e 's/.*/extern value &(void);/' $<; \
echo; \
echo 'const c_primitive caml_builtin_cprim[] = {'; \
sed -e 's/.*/ &,/' $<; \
echo ' 0 };'; \
echo; \
echo 'const char * const caml_names_of_builtin_cprim[] = {'; \
sed -e 's/.*/ "&",/' $<; \
echo ' 0 };') > $@
$(V_GEN)cp runtime/primitives.new $@

runtime/prims.c: runtime/gen_primsc.sh runtime/primitives
$(V_GEN)runtime/gen_primsc.sh \
runtime/primitives $(runtime_BYTECODE_C_SOURCES) \
> $@

runtime/caml/opnames.h : runtime/caml/instruct.h
$(V_GEN)tr -d '\r' < $< | \
Expand Down
7 changes: 4 additions & 3 deletions runtime/dune
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
;**************************************************************************

(rule
(targets primitives)
(targets primitives prims.c)
(mode fallback)
(deps
; matches the line structure of files in gen_primitives.sh
Expand All @@ -25,8 +25,9 @@
runtime_events.c sync.c
dynlink.c backtrace_byt.c backtrace.c afl.c bigarray.c prng.c)
(action
(chdir ..
(with-stdout-to %{targets} (run %{dep:gen_primitives.sh})))))
(progn
(with-stdout-to primitives (run %{dep:gen_primitives.sh} %{deps}))
(with-stdout-to prims.c (run %{dep:gen_primsc.sh} primitives %{deps})))))

(rule
(targets libcamlrun.a)
Expand Down
24 changes: 9 additions & 15 deletions runtime/floats.c
Original file line number Diff line number Diff line change
Expand Up @@ -1100,16 +1100,6 @@ CAMLprim value caml_signbit_float(value f)
return caml_signbit(Double_val(f));
}

CAMLprim value caml_neq_float(value f, value g)
{
return Val_bool(Double_val(f) != Double_val(g));
}

#define DEFINE_NAN_CMP(op) (value f, value g) \
{ \
return Val_bool(Double_val(f) op Double_val(g)); \
}

intnat caml_float_compare_unboxed(double f, double g)
{
/* If one or both of f and g is NaN, order according to the convention
Expand All @@ -1124,11 +1114,15 @@ intnat caml_float_compare_unboxed(double f, double g)
return res;
}

CAMLprim value caml_eq_float DEFINE_NAN_CMP(==)
CAMLprim value caml_le_float DEFINE_NAN_CMP(<=)
CAMLprim value caml_lt_float DEFINE_NAN_CMP(<)
CAMLprim value caml_ge_float DEFINE_NAN_CMP(>=)
CAMLprim value caml_gt_float DEFINE_NAN_CMP(>)
#define FLOAT_CMP(op, f, g) \
return Val_bool(Double_val(f) op Double_val(g));

CAMLprim value caml_neq_float(value f, value g) { FLOAT_CMP(!=, f, g) }
CAMLprim value caml_eq_float(value f, value g) { FLOAT_CMP(==, f, g) }
CAMLprim value caml_le_float(value f, value g) { FLOAT_CMP(<=, f, g) }
CAMLprim value caml_lt_float(value f, value g) { FLOAT_CMP(<, f, g) }
CAMLprim value caml_ge_float(value f, value g) { FLOAT_CMP(>=, f, g) }
CAMLprim value caml_gt_float(value f, value g) { FLOAT_CMP(>, f, g) }

CAMLprim value caml_float_compare(value vf, value vg)
{
Expand Down
39 changes: 25 additions & 14 deletions runtime/gen_primitives.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,29 @@
#* *
#**************************************************************************

# #8985: the meaning of character range a-z depends on the locale, so force C
# locale throughout.
# If primitives contain duplicated lines (e.g. because the code is defined
# like
# #ifdef X
# CAMLprim value caml_foo() ...
# #else
# CAMLprim value caml_foo() ...
# #endif), horrible things will happen: duplicated entries in Runtimedef ->
# double registration in Symtable -> empty entry in the PRIM table ->
# the bytecode interpreter is confused.
# We sort the primitive file and remove duplicates to avoid this problem.

# Warning: we use "sort | uniq" instead of "sort -u" because in the MSVC
# port, the "sort" program in the path is Microsoft's and not cygwin's

# Warning: POSIX sort is locale dependent, that's why we set LC_ALL explicitly.
# Sort is unstable for "is_directory" and "isatty"
# see http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html:
# "using sort to process pathnames, it is recommended that LC_ALL .. set to C"

# #8985: in sed, the meaning of character range a-z depends on the locale,
# so force C locale throughout.

export LC_ALL=C
(
for prim in \
alloc array compare extern floats gc_ctrl hash intern interp ints io \
lexing md5 meta memprof obj parsing signals str sys callback weak \
finalise domain platform fiber memory startup_aux runtime_events sync \
dynlink backtrace_byt backtrace afl \
bigarray prng
do
sed -n -e 's/^CAMLprim value \([a-z0-9_][a-z0-9_]*\).*/\1/p' \
"runtime/$prim.c"
done
) | sort | uniq

sed -n -e 's/^CAMLprim value \([a-z][a-z0-9_]*\).*$/\1/p' "$@" | \
sort | uniq
63 changes: 63 additions & 0 deletions runtime/gen_primsc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/sh

#**************************************************************************
#* *
#* OCaml *
#* *
#* Xavier Leroy, Collège de France and Inria *
#* *
#* Copyright 2023 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. *
#* *
#**************************************************************************

# Build the runtime/prims.c file, with proper C declarations of the primitives

export LC_ALL=C

case $# in
0) echo "Usage: gen_primsc.sh <primitives file> <.c files>" 1>&2
exit 2;;
*) primitives="$1"; shift;;
esac

cat <<'EOF'
/* Generated file, do not edit */
#define CAML_INTERNALS
#include "caml/mlvalues.h"
#include "caml/prims.h"
EOF

# Extract the beginning of primitive definitions:
# from 'CAMLprim' at beginning of line to the first closing parenthesis.
# The first pattern below matches single-line definitions such as
# CAMLprim value foo(value x) {
# The second pattern matches multi-line definitions such as
# CAMLprim value foo(value x,
# value y)
sed -n \
-e '/^CAMLprim value .*)/p' \
-e '/^CAMLprim value [^)]*$/,/)/p' \
"$@" |
# Transform these definitions into "CAMLextern" declarations
sed \
-e 's/^CAMLprim /CAMLextern /' \
-e 's/).*$/);/'

# Generate the table of primitives
echo
echo 'const c_primitive caml_builtin_cprim[] = {'
sed -e 's/.*/ (c_primitive) &,/' "$primitives"
echo ' 0 };'

# Generate the table of primitive names
echo
echo 'const char * const caml_names_of_builtin_cprim[] = {'
sed -e 's/.*/ "&",/' "$primitives"
echo ' 0 };'

0 comments on commit 217d42e

Please sign in to comment.