Skip to content

Commit 4399786

Browse files
committed
Allow for less opcodes based on version of OTP compiler
Filter opcodes that are not supported by VM. Further filtering can be done by looking at coverage of OTP compiler tests to figure out which opcodes compilers no longer generate. Also implement nif_start/0 (OTP25) and executable_line/2 (OTP27) Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent f583afc commit 4399786

File tree

6 files changed

+157
-10
lines changed

6 files changed

+157
-10
lines changed

.github/workflows/run-tests-with-beam.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ jobs:
107107
id: cache
108108
with:
109109
path: 'build/tests/**/*.beam'
110-
key: ${{ matrix.otp }}-${{ hashFiles('**/run-tests-with-beam.yaml', 'tests/**/*.erl') }}
110+
key: ${{ matrix.otp }}-${{ hashFiles('**/run-tests-with-beam.yaml', 'tests/**/*.erl', 'tests/**/CMakeLists.txt') }}
111111

112112
- name: "Build: run cmake"
113113
working-directory: build

src/libAtomVM/opcodes.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@
4747
#define OP_LOOP_REC_END 24
4848
#define OP_WAIT 25
4949
#define OP_WAIT_TIMEOUT 26
50+
// Unimplemented by BEAM from OTP 21
51+
// #define OP_M_PLUS 27
52+
// #define OP_M_MINUS 28
53+
// #define OP_M_TIMES 29
54+
// #define OP_M_DIV 30
55+
// #define OP_INT_DIV 31
56+
// #define OP_INT_REM 32
57+
// #define OP_INT_BAND 33
58+
// #define OP_INT_BOR 34
59+
// #define OP_INT_BXOR 35
60+
// #define OP_INT_BSL 36
61+
// #define OP_INT_BSR 37
62+
// #define OP_INT_BNOT 38
5063
#define OP_IS_LT 39
5164
#define OP_IS_GE 40
5265
#define OP_IS_EQUAL 41
@@ -62,6 +75,8 @@
6275
#define OP_IS_PORT 51
6376
#define OP_IS_NIL 52
6477
#define OP_IS_BINARY 53
78+
// Unimplemented by BEAM from OTP 21
79+
// #define OP_IS_CONSTANT 54
6580
#define OP_IS_LIST 55
6681
#define OP_IS_NONEMPTY_LIST 56
6782
#define OP_IS_TUPLE 57
@@ -75,18 +90,35 @@
7590
#define OP_GET_LIST 65
7691
#define OP_GET_TUPLE_ELEMENT 66
7792
#define OP_SET_TUPLE_ELEMENT 67
93+
// Unimplemented by BEAM from OTP 21
94+
// #define OP_PUT_STRING 68
7895
#define OP_PUT_LIST 69
7996
#define OP_PUT_TUPLE 70
8097
#define OP_PUT 71
8198
#define OP_BADMATCH 72
8299
#define OP_IF_END 73
83100
#define OP_CASE_END 74
84101
#define OP_CALL_FUN 75
102+
// Unimplemented by BEAM from OTP 21
103+
// #define OP_MAKE_FUN 76
85104
#define OP_IS_FUNCTION 77
86105
#define OP_CALL_EXT_ONLY 78
106+
// Unimplemented by BEAM from OTP 21
107+
// #define OP_BS_START_MATCH 79
108+
// #define OP_BS_GET_INTEGER 80
109+
// #define OP_BS_GET_FLOAT 81
110+
// #define OP_BS_GET_BINARY 82
111+
// #define OP_BS_SKIP_BITS 83
112+
// #define OP_BS_TEST_FAIL 84
113+
// #define OP_BS_SAVE 85
114+
// #define OP_BS_RESTORE 86
115+
// #define OP_BS_INIT 87
116+
// #define OP_BS_FINAL 88
87117
#define OP_BS_PUT_INTEGER 89
88118
#define OP_BS_PUT_BINARY 90
89119
#define OP_BS_PUT_STRING 92
120+
// Unimplemented by BEAM from OTP 21
121+
// #define OP_BS_NEED_BUF 93
90122
#define OP_FCLEARERROR 94
91123
#define OP_FCHECKERROR 95
92124
#define OP_FMOVE 96
@@ -103,6 +135,8 @@
103135
#define OP_TRY_CASE_END 107
104136
#define OP_RAISE 108
105137
#define OP_BS_INIT2 109
138+
// Unimplemented by BEAM from OTP 21
139+
// #define OP_BS_BITS_TO_BYTES 110
106140
#define OP_BS_ADD 111
107141
#define OP_APPLY 112
108142
#define OP_APPLY_LAST 113
@@ -118,6 +152,10 @@
118152
#define OP_BS_RESTORE2 123
119153
#define OP_GC_BIF1 124
120154
#define OP_GC_BIF2 125
155+
// Unimplemented by BEAM from OTP 21
156+
// #define OP_BS_FINAL2 126
157+
// #define OP_BS_BITS_TO_BYTES2 127
158+
// #define OP_PUT_LITERAL 128
121159
#define OP_IS_BITSTR 129
122160
#define OP_BS_CONTEXT_TO_BINARY 130
123161
#define OP_BS_TEST_UNIT 131
@@ -152,23 +190,31 @@
152190
#define OP_RAW_RAISE 161
153191
#define OP_GET_HD 162
154192
#define OP_GET_TL 163
193+
// Introduced in OTP 22
155194
#define OP_PUT_TUPLE2 164
156195
#define OP_BS_GET_TAIL 165
157196
#define OP_BS_START_MATCH3 166
158197
#define OP_BS_GET_POSITION 167
159198
#define OP_BS_SET_POSITION 168
199+
// Introduced in OTP 23
160200
#define OP_SWAP 169
161201
#define OP_BS_START_MATCH4 170
202+
// Introduced in OTP 24
162203
#define OP_MAKE_FUN3 171
163204
#define OP_INIT_YREGS 172
164205
#define OP_RECV_MARKER_BIND 173
165206
#define OP_RECV_MARKER_CLEAR 174
166207
#define OP_RECV_MARKER_RESERVE 175
167208
#define OP_RECV_MARKER_USE 176
209+
// Introduced in OTP 25
168210
#define OP_BS_CREATE_BIN 177
169211
#define OP_CALL_FUN2 178
212+
#define OP_NIF_START 179
170213
#define OP_BADRECORD 180
214+
// Introduced in OTP 26
171215
#define OP_UPDATE_RECORD 181
172216
#define OP_BS_MATCH 182
217+
// Introduced in OTP 27
218+
#define OP_EXECUTABLE_LINE 183
173219

174220
#endif

src/libAtomVM/opcodesswitch.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@
4545
#include "trace.h"
4646

4747
// These constants can be used to reduce the size of the VM for a specific
48-
// range of compiler versions
48+
// range of compiler versions. It's difficult to assert whether a compiler still
49+
// generates a given opcode, we're mostly using heuristics here.
50+
// @bjorng suggested using compiler test suites and coverage to find out
4951
#define MINIMUM_OTP_COMPILER_VERSION 21
50-
#define MAXIMUM_OTP_COMPILER_VERSION 26
52+
#define MAXIMUM_OTP_COMPILER_VERSION 27
5153

5254
#ifdef __cplusplus
5355
extern "C" {
@@ -2370,6 +2372,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
23702372
break;
23712373
}
23722374

2375+
#if MINIMUM_OTP_COMPILER_VERSION < 27
2376+
// Not executable by OTP27 or higher
23732377
case OP_ALLOCATE_ZERO: {
23742378
uint32_t stack_need;
23752379
DECODE_LITERAL(stack_need, pc);
@@ -2395,8 +2399,10 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
23952399
#endif
23962400
break;
23972401
}
2402+
#endif
23982403

23992404
#if MINIMUM_OTP_COMPILER_VERSION <= 23
2405+
// Not executable by OTP27 or higher
24002406
case OP_ALLOCATE_HEAP_ZERO: {
24012407
uint32_t stack_need;
24022408
DECODE_LITERAL(stack_need, pc);
@@ -2457,6 +2463,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
24572463
break;
24582464
}
24592465

2466+
#if MINIMUM_OTP_COMPILER_VERSION < 27
2467+
// Not executable by OTP27 or higher (called init there)
24602468
case OP_KILL: {
24612469
uint32_t target;
24622470
DECODE_YREG(target, pc);
@@ -2468,6 +2476,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
24682476
#endif
24692477
break;
24702478
}
2479+
#endif
24712480

24722481
case OP_DEALLOCATE: {
24732482
uint32_t n_words;
@@ -3441,6 +3450,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
34413450
}
34423451

34433452
#if MINIMUM_OTP_COMPILER_VERSION <= 21
3453+
// Not executable by OTP27 or higher
34443454
case OP_PUT_TUPLE: {
34453455
uint32_t size;
34463456
DECODE_LITERAL(size, pc);
@@ -3710,6 +3720,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
37103720
break;
37113721
}
37123722

3723+
#if MINIMUM_OTP_COMPILER_VERSION < 27
3724+
// Not executable by OTP27 or higher
37133725
case OP_MAKE_FUN2: {
37143726
uint32_t fun_index;
37153727
DECODE_LITERAL(fun_index, pc)
@@ -3725,6 +3737,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
37253737
#endif
37263738
break;
37273739
}
3740+
#endif
37283741

37293742
case OP_TRY: {
37303743
DEST_REGISTER(dreg);
@@ -4654,6 +4667,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
46544667
#endif
46554668

46564669
#if MINIMUM_OTP_COMPILER_VERSION <= 21
4670+
// Not executable by OTP25 or higher
46574671
case OP_BS_START_MATCH2: {
46584672
uint32_t fail;
46594673
DECODE_LABEL(fail, pc)
@@ -4908,6 +4922,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
49084922
#endif
49094923

49104924
#if MINIMUM_OTP_COMPILER_VERSION <= 21
4925+
// Not executable by OTP25 or higher
49114926
case OP_BS_SAVE2: {
49124927
term src;
49134928
DECODE_COMPACT_TERM(src, pc);
@@ -4937,6 +4952,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
49374952
break;
49384953
}
49394954

4955+
// Not executable by OTP25 or higher
49404956
case OP_BS_RESTORE2: {
49414957
term src;
49424958
DECODE_COMPACT_TERM(src, pc);
@@ -5261,6 +5277,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
52615277
break;
52625278
}
52635279

5280+
#if MINIMUM_OTP_COMPILER_VERSION < 25
5281+
// Not executable by OTP25 or higher
52645282
case OP_BS_CONTEXT_TO_BINARY: {
52655283
// Do not check if dreg is a binary or not
52665284
// In case it is not a binary or a match state, dreg will not be changed.
@@ -5298,6 +5316,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
52985316
#endif
52995317
break;
53005318
}
5319+
#endif
53015320

53025321
case OP_APPLY: {
53035322
#ifdef IMPL_EXECUTE_LOOP
@@ -5679,6 +5698,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
56795698
#if MINIMUM_OTP_COMPILER_VERSION <= 23
56805699
//TODO: stub, implement recv_mark/1
56815700
//it looks like it can be safely left unimplemented
5701+
// Not executable by OTP27 or higher
56825702
case OP_RECV_MARK: {
56835703
uint32_t label;
56845704
DECODE_LABEL(label, pc);
@@ -5690,6 +5710,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
56905710

56915711
//TODO: stub, implement recv_set/1
56925712
//it looks like it can be safely left unimplemented
5713+
// Not executable by OTP27 or higher
56935714
case OP_RECV_SET: {
56945715
uint32_t label;
56955716
DECODE_LABEL(label, pc);
@@ -6040,12 +6061,14 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
60406061
}
60416062

60426063
#if MINIMUM_OTP_COMPILER_VERSION <= 23
6064+
// Not executable by OTP27 or higher
60436065
case OP_FCLEARERROR: {
60446066
// This can be a noop as we raise from bifs
60456067
TRACE("fclearerror/0\n");
60466068
break;
60476069
}
60486070

6071+
// Not executable by OTP27 or higher
60496072
case OP_FCHECKERROR: {
60506073
// This can be a noop as we raise from bifs
60516074
int fail_label;
@@ -6868,6 +6891,11 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
68686891
break;
68696892
}
68706893

6894+
case OP_NIF_START: {
6895+
TRACE("nif_start/0\n");
6896+
break;
6897+
}
6898+
68716899
case OP_BADRECORD: {
68726900
TRACE("badrecord/1\n");
68736901

@@ -7198,6 +7226,21 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
71987226
}
71997227
#endif
72007228

7229+
#if MAXIMUM_OTP_COMPILER_VERSION >= 27
7230+
case OP_EXECUTABLE_LINE: {
7231+
term arg1;
7232+
DECODE_COMPACT_TERM(arg1, pc);
7233+
term arg2;
7234+
DECODE_COMPACT_TERM(arg2, pc);
7235+
7236+
TRACE("executable_line/2 arg1=0x%lx, arg2=0x%lx\n", arg1, arg2);
7237+
7238+
USED_BY_TRACE(arg1);
7239+
USED_BY_TRACE(arg2);
7240+
break;
7241+
}
7242+
#endif
7243+
72017244
default:
72027245
printf("Undecoded opcode: %i\n", pc[-1]);
72037246
#ifdef IMPL_EXECUTE_LOOP

tests/erlang_tests/CMakeLists.txt

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,17 @@
2121
cmake_minimum_required (VERSION 3.13)
2222
project (erlang_tests)
2323

24-
function(compile_erlang module_name)
25-
add_custom_command(
26-
OUTPUT ${module_name}.beam
27-
COMMAND erlc ${CMAKE_CURRENT_SOURCE_DIR}/${module_name}.erl
28-
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${module_name}.erl
29-
COMMENT "Compiling ${module_name}.erl"
30-
)
24+
function(compile_erlang)
25+
cmake_parse_arguments(arg "" "" "ERLC_OPTIONS;MODULES" ${ARGN})
26+
27+
foreach(module_name ${arg_UNPARSED_ARGUMENTS} ${arg_MODULES})
28+
add_custom_command(
29+
OUTPUT ${module_name}.beam
30+
COMMAND erlc ${arg_ERLC_OPTIONS} ${CMAKE_CURRENT_SOURCE_DIR}/${module_name}.erl
31+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${module_name}.erl
32+
COMMENT "Compiling ${module_name}.erl"
33+
)
34+
endforeach()
3135
endfunction()
3236

3337
set(TO_HRL_PATH ${CMAKE_CURRENT_LIST_DIR})
@@ -499,6 +503,9 @@ compile_erlang(test_close_avm_pack)
499503

500504
compile_erlang(test_module_info)
501505

506+
# -compile attribute doesn't seem to work in OTP27
507+
compile_erlang(ERLC_OPTIONS +line_coverage MODULES test_executable_line)
508+
502509
compile_erlang(int64_build_binary)
503510

504511
compile_erlang(test_crypto_strong_rand_bytes)
@@ -982,6 +989,7 @@ add_custom_target(erlang_test_modules DEPENDS
982989
test_close_avm_pack.beam
983990

984991
test_module_info.beam
992+
test_executable_line.beam
985993

986994
int64_build_binary.beam
987995

0 commit comments

Comments
 (0)