Skip to content

Commit 6948346

Browse files
authored
flambda-backend: Check amd64 extension support at startup (#2220)
1 parent 5b03ed6 commit 6948346

File tree

12 files changed

+398
-4
lines changed

12 files changed

+398
-4
lines changed

Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,7 @@ runtime4_COMMON_C_SOURCES = \
634634
interp \
635635
ints \
636636
io \
637+
isa \
637638
lexing \
638639
main \
639640
major_gc \
@@ -673,7 +674,8 @@ runtime4_NATIVE_ONLY_C_SOURCES = \
673674
fail_nat \
674675
roots_nat \
675676
startup_nat \
676-
signals_nat
677+
signals_nat \
678+
isa
677679

678680
# Runtime system source files (v5)
679681

@@ -702,6 +704,7 @@ runtime_COMMON_C_SOURCES = \
702704
intern \
703705
ints \
704706
io \
707+
isa \
705708
lexing \
706709
lf_skiplist \
707710
main \
@@ -744,7 +747,8 @@ runtime_NATIVE_ONLY_C_SOURCES = \
744747
fail_nat \
745748
frame_descriptors \
746749
startup_nat \
747-
signals_nat
750+
signals_nat \
751+
isa
748752

749753
# The runtime system
750754

runtime/caml/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
(interp.h as caml/interp.h)
6666
(intext.h as caml/intext.h)
6767
(io.h as caml/io.h)
68+
(isa.h as caml/isa.h)
6869
(lf_skiplist.h as caml/lf_skiplist.h)
6970
(m.h as caml/m.h)
7071
(major_gc.h as caml/major_gc.h)

runtime/caml/isa.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**************************************************************************/
2+
/* */
3+
/* OCaml */
4+
/* */
5+
/* Max Slater, Jane Street */
6+
/* */
7+
/* Copyright 2024 Jane Street Group LLC */
8+
/* */
9+
/* All rights reserved. This file is distributed under the terms of */
10+
/* the GNU Lesser General Public License version 2.1, with the */
11+
/* special exception on linking described in the file LICENSE. */
12+
/* */
13+
/**************************************************************************/
14+
15+
#ifndef CAML_ISA_H
16+
#define CAML_ISA_H
17+
18+
#include "misc.h"
19+
20+
#ifdef CAML_INTERNALS
21+
CAMLextern void caml_assert_arch_extensions(void);
22+
extern uintnat caml_skip_arch_extension_check;
23+
#endif
24+
25+
#endif /* CAML_ISA_H */

runtime/isa.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/**************************************************************************/
2+
/* */
3+
/* OCaml */
4+
/* */
5+
/* Max Slater, Jane Street */
6+
/* */
7+
/* Copyright 2024 Jane Street Group LLC */
8+
/* */
9+
/* All rights reserved. This file is distributed under the terms of */
10+
/* the GNU Lesser General Public License version 2.1, with the */
11+
/* special exception on linking described in the file LICENSE. */
12+
/* */
13+
/**************************************************************************/
14+
15+
#define CAML_INTERNALS
16+
17+
#include "caml/isa.h"
18+
19+
uintnat caml_skip_arch_extension_check = 0;
20+
21+
// Weak symbols are only supported in ELF
22+
23+
#if defined __x86_64__ && defined __ELF__
24+
25+
// Must be kept in sync with amd64/emit.mlp
26+
27+
// We declare each architecture flag as a separate weak symbol.
28+
// These symbols are not defined (i.e. are not assigned an address)
29+
// in this compilation unit. They compile to [.weak symbol_name].
30+
//
31+
// Other compilation units may define the symbol by associating
32+
// its name with a label [symbol_name: ...].
33+
//
34+
// If multiple compilation units define the symbol, the linker
35+
// will choose one arbitrarily, and the symbol's address will
36+
// point into that unit. If the symbols are never defined,
37+
// their address will be NULL. This allows us to check for
38+
// their presence in the final executable below.
39+
40+
CAMLweakdef extern intnat caml_arch_popcnt;
41+
CAMLweakdef extern intnat caml_arch_prefetchw;
42+
CAMLweakdef extern intnat caml_arch_prefetchwt1;
43+
CAMLweakdef extern intnat caml_arch_sse3;
44+
CAMLweakdef extern intnat caml_arch_ssse3;
45+
CAMLweakdef extern intnat caml_arch_sse4_1;
46+
CAMLweakdef extern intnat caml_arch_sse4_2;
47+
CAMLweakdef extern intnat caml_arch_clmul;
48+
CAMLweakdef extern intnat caml_arch_lzcnt;
49+
CAMLweakdef extern intnat caml_arch_bmi;
50+
CAMLweakdef extern intnat caml_arch_bmi2;
51+
52+
// CPUID with EAX = 1, result in ECX
53+
54+
#define SSE3_BIT (1 << 0)
55+
#define PCLMULQDQ_BIT (1 << 1)
56+
#define SSSE3_BIT (1 << 9)
57+
#define SSSE4_1_BIT (1 << 19)
58+
#define SSSE4_2_BIT (1 << 20)
59+
#define POPCNT_BIT (1 << 23)
60+
61+
// CPUID with EAX = 0x80000001, result in ECX
62+
63+
#define LZCNT_BIT (1 << 5)
64+
#define PREFETCHW_BIT (1 << 8)
65+
66+
// CPUID with EAX = 7, ECX = 0, result in EBX
67+
68+
#define BMI_BIT (1 << 3)
69+
#define BMI2_BIT (1 << 8)
70+
71+
// CPUID with EAX = 7, ECX = 0, result in ECX
72+
73+
#define PREFETCHWT1_BIT (1 << 0)
74+
75+
//////////////////////////////////////////////////////////////////////////
76+
77+
static void caml_cpuid(int info[4], int eax, int ecx) {
78+
#ifdef _MSC_VER
79+
__cpuidex((int *)info, eax, ecx);
80+
#else
81+
asm volatile (
82+
"cpuid"
83+
: "=a" (info[0]), "=b" (info[1]), "=c" (info[2]), "=d" (info[3])
84+
: "a" (eax), "c" (ecx)
85+
);
86+
#endif
87+
}
88+
89+
CAMLexport void caml_assert_arch_extensions(void) {
90+
91+
if(caml_skip_arch_extension_check) return;
92+
93+
int info[4];
94+
caml_cpuid(info, 1, 0);
95+
96+
// If a weak symbol is not defined, its address is NULL
97+
98+
if(&caml_arch_popcnt) {
99+
if(!(info[2] & POPCNT_BIT)) {
100+
caml_fatal_error("Binary compiled with -fpopcnt, but this CPU lacks support.");
101+
}
102+
}
103+
if(&caml_arch_sse3) {
104+
if(!(info[2] & SSE3_BIT)) {
105+
caml_fatal_error("Binary compiled with -fsse3, but this CPU lacks support.");
106+
}
107+
}
108+
if(&caml_arch_ssse3) {
109+
if(!(info[2] & SSSE3_BIT)) {
110+
caml_fatal_error("Binary compiled with -fssse3, but this CPU lacks support.");
111+
}
112+
}
113+
if(&caml_arch_sse4_1) {
114+
if(!(info[2] & SSSE4_1_BIT)) {
115+
caml_fatal_error("Binary compiled with -fsse41, but this CPU lacks support.");
116+
}
117+
}
118+
if(&caml_arch_sse4_2) {
119+
if(!(info[2] & SSSE4_2_BIT)) {
120+
caml_fatal_error("Binary compiled with -fsse42, but this CPU lacks support.");
121+
}
122+
}
123+
if(&caml_arch_clmul) {
124+
if(!(info[2] & PCLMULQDQ_BIT)) {
125+
caml_fatal_error("Binary compiled with -fpclmul, but this CPU lacks support.");
126+
}
127+
}
128+
129+
caml_cpuid(info, 0x80000001, 0);
130+
131+
if(&caml_arch_prefetchw) {
132+
if(!(info[2] & PREFETCHW_BIT)) {
133+
caml_fatal_error("Binary compiled with -fprefetchw, but this CPU lacks support.");
134+
}
135+
}
136+
if(&caml_arch_lzcnt) {
137+
if(!(info[2] & LZCNT_BIT)) {
138+
caml_fatal_error("Binary compiled with -flzcnt, but this CPU lacks support.");
139+
}
140+
}
141+
142+
caml_cpuid(info, 7, 0);
143+
144+
if(&caml_arch_bmi) {
145+
if(!(info[1] & BMI_BIT)) {
146+
caml_fatal_error("Binary compiled with -fbmi, but this CPU lacks support.");
147+
}
148+
}
149+
if(&caml_arch_bmi2) {
150+
if(!(info[1] & BMI2_BIT)) {
151+
caml_fatal_error("Binary compiled with -fbmi2, but this CPU lacks support.");
152+
}
153+
}
154+
if(&caml_arch_prefetchwt1) {
155+
if(!(info[2] & PREFETCHWT1_BIT)) {
156+
caml_fatal_error("Binary compiled with -fprefetchwt1, but this CPU lacks support.");
157+
}
158+
}
159+
}
160+
161+
#else // No extensions for other architectures are currently available.
162+
163+
CAMLexport void caml_assert_arch_extensions(void) {}
164+
165+
#endif

runtime/startup_aux.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
and native code. */
2222

2323
#include <stdio.h>
24+
#include "caml/isa.h"
2425
#include "caml/backtrace.h"
2526
#include "caml/memory.h"
2627
#include "caml/callback.h"
@@ -114,6 +115,7 @@ void caml_parse_ocamlrunparam(void)
114115
case 'v': scanmult (opt, (uintnat *)&caml_verb_gc); break;
115116
case 'V': scanmult (opt, &params.verify_heap); break;
116117
case 'W': scanmult (opt, &caml_runtime_warnings); break;
118+
case 'X': scanmult (opt, &caml_skip_arch_extension_check); break;
117119
case ',': continue;
118120
}
119121
while (*opt != '\0'){

runtime/startup_nat.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "caml/stack.h"
3939
#include "caml/startup_aux.h"
4040
#include "caml/sys.h"
41+
#include "caml/isa.h"
4142

4243
extern int caml_parser_trace;
4344
extern char caml_system__code_begin, caml_system__code_end;
@@ -92,6 +93,7 @@ value caml_startup_common(char_os **argv, int pooling)
9293

9394
/* Determine options */
9495
caml_parse_ocamlrunparam();
96+
caml_assert_arch_extensions();
9597

9698
#ifdef DEBUG
9799
// Silenced in flambda-backend to make it easier to run tests that

runtime4/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ BYTECODE_C_SOURCES := $(addsuffix .c, \
2525
signals_byt printexc backtrace_byt backtrace compare ints eventlog prng \
2626
floats simd str array io extern intern hash sys meta parsing gc_ctrl md5 obj \
2727
lexing callback debugger weak compact finalise custom dynlink \
28-
afl $(UNIX_OR_WIN32) bigarray main memprof domain \
28+
afl $(UNIX_OR_WIN32) bigarray main memprof domain isa \
2929
skiplist codefrag)
3030

3131
NATIVE_C_SOURCES := $(addsuffix .c, \
@@ -34,7 +34,7 @@ NATIVE_C_SOURCES := $(addsuffix .c, \
3434
floats simd str array io extern intern hash sys parsing gc_ctrl eventlog prng md5 obj \
3535
lexing $(UNIX_OR_WIN32) printexc callback weak compact finalise custom \
3636
globroots backtrace_nat backtrace dynlink_nat debugger meta \
37-
dynlink clambda_checks afl bigarray \
37+
dynlink clambda_checks afl bigarray isa \
3838
memprof domain skiplist codefrag)
3939

4040
# Header files generated by configure

runtime4/caml/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
(interp.h as caml/interp.h)
7575
(intext.h as caml/intext.h)
7676
(io.h as caml/io.h)
77+
(isa.h as caml/isa.h)
7778
(jumptbl.h as caml/jumptbl.h)
7879
(m.h as caml/m.h)
7980
(major_gc.h as caml/major_gc.h)

runtime4/caml/isa.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**************************************************************************/
2+
/* */
3+
/* OCaml */
4+
/* */
5+
/* Max Slater, Jane Street */
6+
/* */
7+
/* Copyright 2024 Jane Street Group LLC */
8+
/* */
9+
/* All rights reserved. This file is distributed under the terms of */
10+
/* the GNU Lesser General Public License version 2.1, with the */
11+
/* special exception on linking described in the file LICENSE. */
12+
/* */
13+
/**************************************************************************/
14+
15+
#ifndef CAML_ISA_H
16+
#define CAML_ISA_H
17+
18+
#include "misc.h"
19+
20+
#ifdef CAML_INTERNALS
21+
CAMLextern void caml_assert_arch_extensions(void);
22+
extern uintnat caml_skip_arch_extension_check;
23+
#endif
24+
25+
#endif /* CAML_ISA_H */

0 commit comments

Comments
 (0)