Skip to content

Commit a26dc50

Browse files
committed
py: Improve inline assembler; improve compiler constant folding.
1 parent 2813cb6 commit a26dc50

7 files changed

Lines changed: 191 additions & 61 deletions

File tree

py/asmthumb.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,10 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
275275
asm_thumb_write_op16(as, 0x4600 | op_lo);
276276
}
277277

278-
#define OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
278+
#define OP_ADD_RLO_RLO_RLO(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest))
279279

280-
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
281-
asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b));
280+
void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
281+
asm_thumb_write_op16(as, OP_ADD_RLO_RLO_RLO(rlo_dest, rlo_src_a, rlo_src_b));
282282
}
283283

284284
#define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest))
@@ -302,6 +302,17 @@ void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) {
302302
asm_thumb_write_op16(as, OP_CMP_RLO_I8(rlo, i8));
303303
}
304304

305+
#define OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
306+
#define OP_STR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6000 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
307+
308+
void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) {
309+
asm_thumb_write_op16(as, OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset));
310+
}
311+
312+
void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) {
313+
asm_thumb_write_op16(as, OP_STR_RLO_RLO_I5(rlo_src, rlo_base, word_offset));
314+
}
315+
305316
void asm_thumb_ite_ge(asm_thumb_t *as) {
306317
asm_thumb_write_op16(as, 0xbfac);
307318
}
@@ -424,7 +435,6 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
424435

425436
#define OP_BLX(reg) (0x4780 | ((reg) << 3))
426437
#define OP_SVC(arg) (0xdf00 | (arg))
427-
#define OP_LDR_FROM_BASE_OFFSET(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
428438

429439
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
430440
/* TODO make this use less bytes
@@ -442,7 +452,7 @@ void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp
442452
asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr);
443453
asm_thumb_write_op16(as, OP_BLX(reg_temp));
444454
} else if (1) {
445-
asm_thumb_write_op16(as, OP_LDR_FROM_BASE_OFFSET(reg_temp, REG_R7, fun_id));
455+
asm_thumb_write_op16(as, OP_LDR_RLO_RLO_I5(reg_temp, REG_R7, fun_id));
446456
asm_thumb_write_op16(as, OP_BLX(reg_temp));
447457
} else {
448458
// use SVC

py/asmthumb.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,12 @@ void asm_thumb_movs_rlo_i8(asm_thumb_t *as, uint rlo_dest, int i8_src);
6262
void asm_thumb_movw_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
6363
void asm_thumb_movt_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
6464
void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src);
65-
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b);
65+
void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b);
6666
void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src);
6767
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b);
6868
void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8);
69+
void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset);
70+
void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset);
6971
void asm_thumb_ite_ge(asm_thumb_t *as);
7072
void asm_thumb_b_n(asm_thumb_t *as, uint label);
7173
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);

py/compile.c

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "obj.h"
1818
#include "compile.h"
1919
#include "runtime.h"
20+
#include "builtin.h"
2021
#include "smallint.h"
2122

2223
// TODO need to mangle __attr names
@@ -100,17 +101,44 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
100101
pns->nodes[i] = fold_constants(pns->nodes[i]);
101102
}
102103

104+
// now try to fold this parse node
103105
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
106+
case PN_atom_paren:
107+
if (n == 1 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0])) {
108+
// (int)
109+
pn = pns->nodes[0];
110+
}
111+
break;
112+
113+
case PN_expr:
114+
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
115+
// int | int
116+
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
117+
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
118+
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
119+
}
120+
break;
121+
122+
case PN_and_expr:
123+
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
124+
// int & int
125+
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
126+
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
127+
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
128+
}
129+
break;
130+
104131
case PN_shift_expr:
105132
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
106-
int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
107-
int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
133+
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
134+
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
108135
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
109-
#if MICROPY_EMIT_CPYTHON
110-
// can overflow; enabled only to compare with CPython
111-
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
112-
#endif
136+
// int << int
137+
if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
138+
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
139+
}
113140
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
141+
// int >> int
114142
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
115143
} else {
116144
// shouldn't happen
@@ -125,14 +153,17 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
125153
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
126154
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
127155
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
156+
// int + int
128157
arg0 += arg1;
129158
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
159+
// int - int
130160
arg0 -= arg1;
131161
} else {
132162
// shouldn't happen
133163
assert(0);
134164
}
135165
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
166+
//printf("%ld + %ld\n", arg0, arg1);
136167
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
137168
}
138169
}
@@ -143,18 +174,22 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
143174
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
144175
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
145176
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
177+
// int * int
146178
if (!mp_small_int_mul_overflow(arg0, arg1)) {
147179
arg0 *= arg1;
148180
if (MP_PARSE_FITS_SMALL_INT(arg0)) {
149181
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
150182
}
151183
}
152184
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
153-
; // pass
185+
// int / int
186+
// pass
154187
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
188+
// int%int
155189
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
156190
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
157191
if (arg1 != 0) {
192+
// int // int
158193
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
159194
}
160195
} else {
@@ -168,10 +203,13 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
168203
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
169204
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
170205
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
206+
// +int
171207
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
172208
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_MINUS)) {
209+
// -int
173210
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, -arg);
174211
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_TILDE)) {
212+
// ~int
175213
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
176214
} else {
177215
// shouldn't happen
@@ -184,7 +222,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
184222
if (0) {
185223
#if MICROPY_EMIT_CPYTHON
186224
} else if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
187-
// int**x
225+
// int ** x
188226
// can overflow; enabled only to compare with CPython
189227
mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
190228
if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
@@ -3121,7 +3159,16 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
31213159
for (int i = 0; i < num; i++) {
31223160
assert(MP_PARSE_NODE_IS_STRUCT(nodes[i]));
31233161
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)nodes[i];
3124-
assert(MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_expr_stmt);
3162+
if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_pass_stmt) {
3163+
// no instructions
3164+
continue;
3165+
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_expr_stmt) {
3166+
// an instruction; fall through
3167+
} else {
3168+
// not an instruction; error
3169+
compile_syntax_error(comp, nodes[i], "inline assembler expecting an instruction");
3170+
return;
3171+
}
31253172
assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0]));
31263173
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[1]));
31273174
pns2 = (mp_parse_node_struct_t*)pns2->nodes[0];
@@ -3152,7 +3199,10 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass
31523199
}
31533200

31543201
if (comp->pass > PASS_1) {
3155-
EMIT_INLINE_ASM(end_pass);
3202+
bool success = EMIT_INLINE_ASM(end_pass);
3203+
if (!success) {
3204+
comp->had_error = true;
3205+
}
31563206
}
31573207
}
31583208
#endif
@@ -3330,7 +3380,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
33303380
comp->emit_inline_asm = emit_inline_thumb;
33313381
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
33323382
compile_scope_inline_asm(comp, s, PASS_2);
3333-
compile_scope_inline_asm(comp, s, PASS_3);
3383+
if (!comp->had_error) {
3384+
compile_scope_inline_asm(comp, s, PASS_3);
3385+
}
33343386
#endif
33353387

33363388
} else {
@@ -3374,7 +3426,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
33743426

33753427
// compile pass 2 and pass 3
33763428
compile_scope(comp, s, PASS_2);
3377-
compile_scope(comp, s, PASS_3);
3429+
if (!comp->had_error) {
3430+
compile_scope(comp, s, PASS_3);
3431+
}
33783432
}
33793433
}
33803434

py/emit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t;
133133

134134
typedef struct _emit_inline_asm_method_table_t {
135135
void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope);
136-
void (*end_pass)(emit_inline_asm_t *emit);
136+
bool (*end_pass)(emit_inline_asm_t *emit);
137137
int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params);
138138
void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id);
139139
void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args);

py/emitglue.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
185185
#ifdef WRITE_CODE
186186
if (fp_write_code != NULL) {
187187
fwrite(fun_data, len, 1, fp_write_code);
188+
fflush(fp_write_code);
188189
}
189190
#endif
190191
#endif

0 commit comments

Comments
 (0)