Skip to content

Commit 8456cc0

Browse files
committed
py: Compress load-int, load-fast, store-fast, unop, binop bytecodes.
There is a lot potential in compress bytecodes and make more use of the coding space. This patch introduces "multi" bytecodes which have their argument included in the bytecode (by addition). UNARY_OP and BINARY_OP now no longer take a 1 byte argument for the opcode. Rather, the opcode is included in the first byte itself. LOAD_FAST_[0,1,2] and STORE_FAST_[0,1,2] are removed in favour of their multi versions, which can take an argument between 0 and 15 inclusive. The majority of LOAD_FAST/STORE_FAST codes fit in this range and so this saves a byte for each of these. LOAD_CONST_SMALL_INT_MULTI is used to load small ints between -16 and 47 inclusive. Such ints are quite common and now only need 1 byte to store, and now have much faster decoding. In all this patch saves about 2% RAM for typically bytecode (1.8% on 64-bit test, 2.5% on pyboard test). It also reduces the binary size (because bytecodes are simplified) and doesn't harm performance.
1 parent 1084b0f commit 8456cc0

5 files changed

Lines changed: 159 additions & 174 deletions

File tree

py/bc0.h

Lines changed: 75 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -31,92 +31,90 @@
3131
#define MP_BC_LOAD_CONST_NONE (0x11)
3232
#define MP_BC_LOAD_CONST_TRUE (0x12)
3333
#define MP_BC_LOAD_CONST_ELLIPSIS (0x13)
34-
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // 24-bit, in excess
34+
#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int
3535
#define MP_BC_LOAD_CONST_INT (0x15) // qstr
3636
#define MP_BC_LOAD_CONST_DEC (0x16) // qstr
37-
#define MP_BC_LOAD_CONST_BYTES (0x18) // qstr
38-
#define MP_BC_LOAD_CONST_STRING (0x19) // qstr
39-
#define MP_BC_LOAD_NULL (0x1a)
37+
#define MP_BC_LOAD_CONST_BYTES (0x17) // qstr
38+
#define MP_BC_LOAD_CONST_STRING (0x18) // qstr
39+
#define MP_BC_LOAD_NULL (0x19)
4040

41-
#define MP_BC_LOAD_FAST_0 (0x20)
42-
#define MP_BC_LOAD_FAST_1 (0x21)
43-
#define MP_BC_LOAD_FAST_2 (0x22)
44-
#define MP_BC_LOAD_FAST_N (0x23) // uint
45-
#define MP_BC_LOAD_DEREF (0x25) // uint
46-
#define MP_BC_LOAD_NAME (0x26) // qstr
47-
#define MP_BC_LOAD_GLOBAL (0x27) // qstr
48-
#define MP_BC_LOAD_ATTR (0x28) // qstr
49-
#define MP_BC_LOAD_METHOD (0x29) // qstr
50-
#define MP_BC_LOAD_BUILD_CLASS (0x2a)
51-
#define MP_BC_LOAD_SUBSCR (0x2b)
41+
#define MP_BC_LOAD_FAST_N (0x1a) // uint
42+
#define MP_BC_LOAD_DEREF (0x1b) // uint
43+
#define MP_BC_LOAD_NAME (0x1c) // qstr
44+
#define MP_BC_LOAD_GLOBAL (0x1d) // qstr
45+
#define MP_BC_LOAD_ATTR (0x1e) // qstr
46+
#define MP_BC_LOAD_METHOD (0x1f) // qstr
47+
#define MP_BC_LOAD_BUILD_CLASS (0x20)
48+
#define MP_BC_LOAD_SUBSCR (0x21)
5249

53-
#define MP_BC_STORE_FAST_0 (0x30)
54-
#define MP_BC_STORE_FAST_1 (0x31)
55-
#define MP_BC_STORE_FAST_2 (0x32)
56-
#define MP_BC_STORE_FAST_N (0x33) // uint
57-
#define MP_BC_STORE_DEREF (0x34) // uint
58-
#define MP_BC_STORE_NAME (0x35) // qstr
59-
#define MP_BC_STORE_GLOBAL (0x36) // qstr
60-
#define MP_BC_STORE_ATTR (0x37) // qstr
61-
#define MP_BC_STORE_SUBSCR (0x38)
50+
#define MP_BC_STORE_FAST_N (0x22) // uint
51+
#define MP_BC_STORE_DEREF (0x23) // uint
52+
#define MP_BC_STORE_NAME (0x24) // qstr
53+
#define MP_BC_STORE_GLOBAL (0x25) // qstr
54+
#define MP_BC_STORE_ATTR (0x26) // qstr
55+
#define MP_BC_STORE_SUBSCR (0x27)
6256

63-
#define MP_BC_DELETE_FAST (0x39) // uint
64-
#define MP_BC_DELETE_DEREF (0x3a) // uint
65-
#define MP_BC_DELETE_NAME (0x3b) // qstr
66-
#define MP_BC_DELETE_GLOBAL (0x3c) // qstr
57+
#define MP_BC_DELETE_FAST (0x28) // uint
58+
#define MP_BC_DELETE_DEREF (0x29) // uint
59+
#define MP_BC_DELETE_NAME (0x2a) // qstr
60+
#define MP_BC_DELETE_GLOBAL (0x2b) // qstr
6761

68-
#define MP_BC_DUP_TOP (0x40)
69-
#define MP_BC_DUP_TOP_TWO (0x41)
70-
#define MP_BC_POP_TOP (0x42)
71-
#define MP_BC_ROT_TWO (0x43)
72-
#define MP_BC_ROT_THREE (0x44)
62+
#define MP_BC_DUP_TOP (0x30)
63+
#define MP_BC_DUP_TOP_TWO (0x31)
64+
#define MP_BC_POP_TOP (0x32)
65+
#define MP_BC_ROT_TWO (0x33)
66+
#define MP_BC_ROT_THREE (0x34)
7367

74-
#define MP_BC_JUMP (0x45) // rel byte code offset, 16-bit signed, in excess
75-
#define MP_BC_POP_JUMP_IF_TRUE (0x46) // rel byte code offset, 16-bit signed, in excess
76-
#define MP_BC_POP_JUMP_IF_FALSE (0x47) // rel byte code offset, 16-bit signed, in excess
77-
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x48) // rel byte code offset, 16-bit signed, in excess
78-
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x49) // rel byte code offset, 16-bit signed, in excess
79-
#define MP_BC_SETUP_WITH (0x4d) // rel byte code offset, 16-bit unsigned
80-
#define MP_BC_WITH_CLEANUP (0x4e)
81-
#define MP_BC_SETUP_EXCEPT (0x4f) // rel byte code offset, 16-bit unsigned
82-
#define MP_BC_SETUP_FINALLY (0x50) // rel byte code offset, 16-bit unsigned
83-
#define MP_BC_END_FINALLY (0x51)
84-
#define MP_BC_GET_ITER (0x52)
85-
#define MP_BC_FOR_ITER (0x53) // rel byte code offset, 16-bit unsigned
86-
#define MP_BC_POP_BLOCK (0x54)
87-
#define MP_BC_POP_EXCEPT (0x55)
88-
#define MP_BC_UNWIND_JUMP (0x56) // rel byte code offset, 16-bit signed, in excess; then a byte
68+
#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess
69+
#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess
70+
#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess
71+
#define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess
72+
#define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess
73+
#define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned
74+
#define MP_BC_WITH_CLEANUP (0x3e)
75+
#define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned
76+
#define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned
77+
#define MP_BC_END_FINALLY (0x41)
78+
#define MP_BC_GET_ITER (0x42)
79+
#define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned
80+
#define MP_BC_POP_BLOCK (0x44)
81+
#define MP_BC_POP_EXCEPT (0x45)
82+
#define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte
8983

90-
#define MP_BC_NOT (0x60)
91-
#define MP_BC_UNARY_OP (0x61) // byte
92-
#define MP_BC_BINARY_OP (0x62) // byte
84+
#define MP_BC_NOT (0x47)
9385

94-
#define MP_BC_BUILD_TUPLE (0x70) // uint
95-
#define MP_BC_BUILD_LIST (0x71) // uint
96-
#define MP_BC_LIST_APPEND (0x72) // uint
97-
#define MP_BC_BUILD_MAP (0x73) // uint
98-
#define MP_BC_STORE_MAP (0x74)
99-
#define MP_BC_MAP_ADD (0x75) // uint
100-
#define MP_BC_BUILD_SET (0x76) // uint
101-
#define MP_BC_SET_ADD (0x77) // uint
102-
#define MP_BC_BUILD_SLICE (0x78) // uint
103-
#define MP_BC_UNPACK_SEQUENCE (0x79) // uint
104-
#define MP_BC_UNPACK_EX (0x7a) // uint
86+
#define MP_BC_BUILD_TUPLE (0x50) // uint
87+
#define MP_BC_BUILD_LIST (0x51) // uint
88+
#define MP_BC_LIST_APPEND (0x52) // uint
89+
#define MP_BC_BUILD_MAP (0x53) // uint
90+
#define MP_BC_STORE_MAP (0x54)
91+
#define MP_BC_MAP_ADD (0x55) // uint
92+
#define MP_BC_BUILD_SET (0x56) // uint
93+
#define MP_BC_SET_ADD (0x57) // uint
94+
#define MP_BC_BUILD_SLICE (0x58) // uint
95+
#define MP_BC_UNPACK_SEQUENCE (0x59) // uint
96+
#define MP_BC_UNPACK_EX (0x5a) // uint
10597

106-
#define MP_BC_RETURN_VALUE (0x80)
107-
#define MP_BC_RAISE_VARARGS (0x81) // byte
108-
#define MP_BC_YIELD_VALUE (0x82)
109-
#define MP_BC_YIELD_FROM (0x83)
98+
#define MP_BC_RETURN_VALUE (0x5b)
99+
#define MP_BC_RAISE_VARARGS (0x5c) // byte
100+
#define MP_BC_YIELD_VALUE (0x5d)
101+
#define MP_BC_YIELD_FROM (0x5e)
110102

111-
#define MP_BC_MAKE_FUNCTION (0x90) // uint
112-
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x91) // uint
113-
#define MP_BC_MAKE_CLOSURE (0x92) // uint
114-
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x93) // uint
115-
#define MP_BC_CALL_FUNCTION (0x94) // uint
116-
#define MP_BC_CALL_FUNCTION_VAR_KW (0x95) // uint
117-
#define MP_BC_CALL_METHOD (0x96) // uint
118-
#define MP_BC_CALL_METHOD_VAR_KW (0x97) // uint
103+
#define MP_BC_MAKE_FUNCTION (0x60) // uint
104+
#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint
105+
#define MP_BC_MAKE_CLOSURE (0x62) // uint
106+
#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint
107+
#define MP_BC_CALL_FUNCTION (0x64) // uint
108+
#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint
109+
#define MP_BC_CALL_METHOD (0x66) // uint
110+
#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint
119111

120-
#define MP_BC_IMPORT_NAME (0xe0) // qstr
121-
#define MP_BC_IMPORT_FROM (0xe1) // qstr
122-
#define MP_BC_IMPORT_STAR (0xe2)
112+
#define MP_BC_IMPORT_NAME (0x68) // qstr
113+
#define MP_BC_IMPORT_FROM (0x69) // qstr
114+
#define MP_BC_IMPORT_STAR (0x6a)
115+
116+
#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64)
117+
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
118+
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
119+
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(5)
120+
#define MP_BC_BINARY_OP_MULTI (0xd5) // + op(35)

py/emitbc.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,11 @@ STATIC void emit_bc_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
469469

470470
STATIC void emit_bc_load_const_small_int(emit_t *emit, mp_int_t arg) {
471471
emit_bc_pre(emit, 1);
472-
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
472+
if (-16 <= arg && arg <= 47) {
473+
emit_write_bytecode_byte(emit, MP_BC_LOAD_CONST_SMALL_INT_MULTI + 16 + arg);
474+
} else {
475+
emit_write_bytecode_byte_int(emit, MP_BC_LOAD_CONST_SMALL_INT, arg);
476+
}
473477
}
474478

475479
STATIC void emit_bc_load_const_int(emit_t *emit, qstr qst) {
@@ -499,11 +503,10 @@ STATIC void emit_bc_load_null(emit_t *emit) {
499503
STATIC void emit_bc_load_fast(emit_t *emit, qstr qst, mp_uint_t id_flags, mp_uint_t local_num) {
500504
assert(local_num >= 0);
501505
emit_bc_pre(emit, 1);
502-
switch (local_num) {
503-
case 0: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_0); break;
504-
case 1: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_1); break;
505-
case 2: emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_2); break;
506-
default: emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num); break;
506+
if (local_num <= 15) {
507+
emit_write_bytecode_byte(emit, MP_BC_LOAD_FAST_MULTI + local_num);
508+
} else {
509+
emit_write_bytecode_byte_uint(emit, MP_BC_LOAD_FAST_N, local_num);
507510
}
508511
}
509512

@@ -545,11 +548,10 @@ STATIC void emit_bc_load_subscr(emit_t *emit) {
545548
STATIC void emit_bc_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
546549
assert(local_num >= 0);
547550
emit_bc_pre(emit, -1);
548-
switch (local_num) {
549-
case 0: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_0); break;
550-
case 1: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_1); break;
551-
case 2: emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_2); break;
552-
default: emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num); break;
551+
if (local_num <= 15) {
552+
emit_write_bytecode_byte(emit, MP_BC_STORE_FAST_MULTI + local_num);
553+
} else {
554+
emit_write_bytecode_byte_uint(emit, MP_BC_STORE_FAST_N, local_num);
553555
}
554556
}
555557

@@ -724,12 +726,12 @@ STATIC void emit_bc_pop_except(emit_t *emit) {
724726
STATIC void emit_bc_unary_op(emit_t *emit, mp_unary_op_t op) {
725727
if (op == MP_UNARY_OP_NOT) {
726728
emit_bc_pre(emit, 0);
727-
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, MP_UNARY_OP_BOOL);
729+
emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_BOOL);
728730
emit_bc_pre(emit, 0);
729731
emit_write_bytecode_byte(emit, MP_BC_NOT);
730732
} else {
731733
emit_bc_pre(emit, 0);
732-
emit_write_bytecode_byte_byte(emit, MP_BC_UNARY_OP, op);
734+
emit_write_bytecode_byte(emit, MP_BC_UNARY_OP_MULTI + op);
733735
}
734736
}
735737

@@ -743,7 +745,7 @@ STATIC void emit_bc_binary_op(emit_t *emit, mp_binary_op_t op) {
743745
op = MP_BINARY_OP_IS;
744746
}
745747
emit_bc_pre(emit, -1);
746-
emit_write_bytecode_byte_byte(emit, MP_BC_BINARY_OP, op);
748+
emit_write_bytecode_byte(emit, MP_BC_BINARY_OP_MULTI + op);
747749
if (invert) {
748750
emit_bc_pre(emit, 0);
749751
emit_write_bytecode_byte(emit, MP_BC_NOT);

py/showbc.c

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -190,18 +190,6 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
190190
printf("LOAD_NULL");
191191
break;
192192

193-
case MP_BC_LOAD_FAST_0:
194-
printf("LOAD_FAST_0");
195-
break;
196-
197-
case MP_BC_LOAD_FAST_1:
198-
printf("LOAD_FAST_1");
199-
break;
200-
201-
case MP_BC_LOAD_FAST_2:
202-
printf("LOAD_FAST_2");
203-
break;
204-
205193
case MP_BC_LOAD_FAST_N:
206194
DECODE_UINT;
207195
printf("LOAD_FAST_N " UINT_FMT, unum);
@@ -240,18 +228,6 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
240228
printf("LOAD_SUBSCR");
241229
break;
242230

243-
case MP_BC_STORE_FAST_0:
244-
printf("STORE_FAST_0");
245-
break;
246-
247-
case MP_BC_STORE_FAST_1:
248-
printf("STORE_FAST_1");
249-
break;
250-
251-
case MP_BC_STORE_FAST_2:
252-
printf("STORE_FAST_2");
253-
break;
254-
255231
case MP_BC_STORE_FAST_N:
256232
DECODE_UINT;
257233
printf("STORE_FAST_N " UINT_FMT, unum);
@@ -397,16 +373,6 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
397373
printf("NOT");
398374
break;
399375

400-
case MP_BC_UNARY_OP:
401-
unum = *ip++;
402-
printf("UNARY_OP " UINT_FMT, unum);
403-
break;
404-
405-
case MP_BC_BINARY_OP:
406-
unum = *ip++;
407-
printf("BINARY_OP " UINT_FMT, unum);
408-
break;
409-
410376
case MP_BC_BUILD_TUPLE:
411377
DECODE_UINT;
412378
printf("BUILD_TUPLE " UINT_FMT, unum);
@@ -534,9 +500,22 @@ void mp_bytecode_print2(const byte *ip, mp_uint_t len) {
534500
break;
535501

536502
default:
537-
printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]);
538-
assert(0);
539-
return;
503+
if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) {
504+
printf("LOAD_CONST_SMALL_INT " INT_FMT, (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16);
505+
} else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) {
506+
printf("LOAD_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI);
507+
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
508+
printf("STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
509+
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 5) {
510+
printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
511+
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
512+
printf("BINARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_BINARY_OP_MULTI);
513+
} else {
514+
printf("code %p, byte code 0x%02x not implemented\n", ip, ip[-1]);
515+
assert(0);
516+
return;
517+
}
518+
break;
540519
}
541520
printf("\n");
542521
}

0 commit comments

Comments
 (0)