py: Improve inline assembler; improve compiler constant folding.

This commit is contained in:
Damien George 2014-04-12 17:54:52 +01:00
parent 2813cb6043
commit a26dc50968
7 changed files with 191 additions and 61 deletions

View File

@ -275,10 +275,10 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) {
asm_thumb_write_op16(as, 0x4600 | op_lo); asm_thumb_write_op16(as, 0x4600 | op_lo);
} }
#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)) #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))
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) { void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) {
asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b)); asm_thumb_write_op16(as, OP_ADD_RLO_RLO_RLO(rlo_dest, rlo_src_a, rlo_src_b));
} }
#define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest)) #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) {
asm_thumb_write_op16(as, OP_CMP_RLO_I8(rlo, i8)); asm_thumb_write_op16(as, OP_CMP_RLO_I8(rlo, i8));
} }
#define OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
#define OP_STR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset) (0x6000 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) {
asm_thumb_write_op16(as, OP_LDR_RLO_RLO_I5(rlo_dest, rlo_base, word_offset));
}
void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) {
asm_thumb_write_op16(as, OP_STR_RLO_RLO_I5(rlo_src, rlo_base, word_offset));
}
void asm_thumb_ite_ge(asm_thumb_t *as) { void asm_thumb_ite_ge(asm_thumb_t *as) {
asm_thumb_write_op16(as, 0xbfac); asm_thumb_write_op16(as, 0xbfac);
} }
@ -424,7 +435,6 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
#define OP_BLX(reg) (0x4780 | ((reg) << 3)) #define OP_BLX(reg) (0x4780 | ((reg) << 3))
#define OP_SVC(arg) (0xdf00 | (arg)) #define OP_SVC(arg) (0xdf00 | (arg))
#define OP_LDR_FROM_BASE_OFFSET(rlo_dest, rlo_base, word_offset) (0x6800 | (((word_offset) << 6) & 0x07c0) | ((rlo_base) << 3) | (rlo_dest))
void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp) { void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp) {
/* TODO make this use less bytes /* 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
asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr); asm_thumb_mov_reg_i32(as, reg_temp, (machine_uint_t)fun_ptr);
asm_thumb_write_op16(as, OP_BLX(reg_temp)); asm_thumb_write_op16(as, OP_BLX(reg_temp));
} else if (1) { } else if (1) {
asm_thumb_write_op16(as, OP_LDR_FROM_BASE_OFFSET(reg_temp, REG_R7, fun_id)); asm_thumb_write_op16(as, OP_LDR_RLO_RLO_I5(reg_temp, REG_R7, fun_id));
asm_thumb_write_op16(as, OP_BLX(reg_temp)); asm_thumb_write_op16(as, OP_BLX(reg_temp));
} else { } else {
// use SVC // use SVC

View File

@ -62,10 +62,12 @@ void asm_thumb_movs_rlo_i8(asm_thumb_t *as, uint rlo_dest, int i8_src);
void asm_thumb_movw_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src); void asm_thumb_movw_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
void asm_thumb_movt_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src); void asm_thumb_movt_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src);
void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src);
void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b); void asm_thumb_add_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b);
void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src); void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src);
void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b); void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b);
void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8); void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8);
void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset);
void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset);
void asm_thumb_ite_ge(asm_thumb_t *as); void asm_thumb_ite_ge(asm_thumb_t *as);
void asm_thumb_b_n(asm_thumb_t *as, uint label); void asm_thumb_b_n(asm_thumb_t *as, uint label);
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label); void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);

View File

@ -17,6 +17,7 @@
#include "obj.h" #include "obj.h"
#include "compile.h" #include "compile.h"
#include "runtime.h" #include "runtime.h"
#include "builtin.h"
#include "smallint.h" #include "smallint.h"
// TODO need to mangle __attr names // TODO need to mangle __attr names
@ -100,17 +101,44 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
pns->nodes[i] = fold_constants(pns->nodes[i]); pns->nodes[i] = fold_constants(pns->nodes[i]);
} }
// now try to fold this parse node
switch (MP_PARSE_NODE_STRUCT_KIND(pns)) { switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
case PN_atom_paren:
if (n == 1 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0])) {
// (int)
pn = pns->nodes[0];
}
break;
case PN_expr:
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
// int | int
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
}
break;
case PN_and_expr:
if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
// int & int
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
}
break;
case PN_shift_expr: case PN_shift_expr:
if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) { if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]); machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]); machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
#if MICROPY_EMIT_CPYTHON // int << int
// can overflow; enabled only to compare with CPython if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
#endif }
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
// int >> int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
} else { } else {
// shouldn't happen // shouldn't happen
@ -125,14 +153,17 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]); machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]); machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
// int + int
arg0 += arg1; arg0 += arg1;
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
// int - int
arg0 -= arg1; arg0 -= arg1;
} else { } else {
// shouldn't happen // shouldn't happen
assert(0); assert(0);
} }
if (MP_PARSE_FITS_SMALL_INT(arg0)) { if (MP_PARSE_FITS_SMALL_INT(arg0)) {
//printf("%ld + %ld\n", arg0, arg1);
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
} }
} }
@ -143,6 +174,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]); machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]); machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
// int * int
if (!mp_small_int_mul_overflow(arg0, arg1)) { if (!mp_small_int_mul_overflow(arg0, arg1)) {
arg0 *= arg1; arg0 *= arg1;
if (MP_PARSE_FITS_SMALL_INT(arg0)) { if (MP_PARSE_FITS_SMALL_INT(arg0)) {
@ -150,11 +182,14 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
} }
} }
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
; // pass // int / int
// pass
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
// int%int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1)); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
if (arg1 != 0) { if (arg1 != 0) {
// int // int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1)); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
} }
} else { } else {
@ -168,10 +203,13 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) { if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]); machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
// +int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_MINUS)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_MINUS)) {
// -int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, -arg); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, -arg);
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_TILDE)) { } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_TILDE)) {
// ~int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg); pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
} else { } else {
// shouldn't happen // shouldn't happen
@ -184,7 +222,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (0) { if (0) {
#if MICROPY_EMIT_CPYTHON #if MICROPY_EMIT_CPYTHON
} 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])) { } 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])) {
// int**x // int ** x
// can overflow; enabled only to compare with CPython // can overflow; enabled only to compare with CPython
mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2]; mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) { 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
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
assert(MP_PARSE_NODE_IS_STRUCT(nodes[i])); assert(MP_PARSE_NODE_IS_STRUCT(nodes[i]));
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)nodes[i]; mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)nodes[i];
assert(MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_expr_stmt); if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_pass_stmt) {
// no instructions
continue;
} else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_expr_stmt) {
// an instruction; fall through
} else {
// not an instruction; error
compile_syntax_error(comp, nodes[i], "inline assembler expecting an instruction");
return;
}
assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])); assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0]));
assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[1])); assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[1]));
pns2 = (mp_parse_node_struct_t*)pns2->nodes[0]; 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
} }
if (comp->pass > PASS_1) { if (comp->pass > PASS_1) {
EMIT_INLINE_ASM(end_pass); bool success = EMIT_INLINE_ASM(end_pass);
if (!success) {
comp->had_error = true;
}
} }
} }
#endif #endif
@ -3330,7 +3380,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
comp->emit_inline_asm = emit_inline_thumb; comp->emit_inline_asm = emit_inline_thumb;
comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table; comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
compile_scope_inline_asm(comp, s, PASS_2); compile_scope_inline_asm(comp, s, PASS_2);
compile_scope_inline_asm(comp, s, PASS_3); if (!comp->had_error) {
compile_scope_inline_asm(comp, s, PASS_3);
}
#endif #endif
} else { } else {
@ -3374,7 +3426,9 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
// compile pass 2 and pass 3 // compile pass 2 and pass 3
compile_scope(comp, s, PASS_2); compile_scope(comp, s, PASS_2);
compile_scope(comp, s, PASS_3); if (!comp->had_error) {
compile_scope(comp, s, PASS_3);
}
} }
} }

View File

@ -133,7 +133,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t;
typedef struct _emit_inline_asm_method_table_t { typedef struct _emit_inline_asm_method_table_t {
void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope); void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope);
void (*end_pass)(emit_inline_asm_t *emit); bool (*end_pass)(emit_inline_asm_t *emit);
int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params); int (*count_params)(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params);
void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id); void (*label)(emit_inline_asm_t *emit, uint label_num, qstr label_id);
void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args); void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args);

View File

@ -185,6 +185,7 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
#ifdef WRITE_CODE #ifdef WRITE_CODE
if (fp_write_code != NULL) { if (fp_write_code != NULL) {
fwrite(fun_data, len, 1, fp_write_code); fwrite(fun_data, len, 1, fp_write_code);
fflush(fp_write_code);
} }
#endif #endif
#endif #endif

View File

@ -1,6 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <assert.h> #include <assert.h>
#include "misc.h" #include "misc.h"
@ -17,13 +18,23 @@
#if MICROPY_EMIT_INLINE_THUMB #if MICROPY_EMIT_INLINE_THUMB
struct _emit_inline_asm_t { struct _emit_inline_asm_t {
int pass; uint16_t pass;
uint16_t success;
scope_t *scope; scope_t *scope;
uint max_num_labels; uint max_num_labels;
qstr *label_lookup; qstr *label_lookup;
asm_thumb_t *as; asm_thumb_t *as;
}; };
void emit_inline_thumb_error(emit_inline_asm_t *emit, const char *fmt, ...) {
printf("SyntaxError: ");
emit->success = false;
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
emit_inline_asm_t *emit_inline_thumb_new(uint max_num_labels) { emit_inline_asm_t *emit_inline_thumb_new(uint max_num_labels) {
emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);
emit->max_num_labels = max_num_labels; emit->max_num_labels = max_num_labels;
@ -41,12 +52,13 @@ void emit_inline_thumb_free(emit_inline_asm_t *emit) {
STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope) { STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope) {
emit->pass = pass; emit->pass = pass;
emit->success = true;
emit->scope = scope; emit->scope = scope;
asm_thumb_start_pass(emit->as, pass); asm_thumb_start_pass(emit->as, pass);
asm_thumb_entry(emit->as, 0); asm_thumb_entry(emit->as, 0);
} }
STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { STATIC bool emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
asm_thumb_exit(emit->as); asm_thumb_exit(emit->as);
asm_thumb_end_pass(emit->as); asm_thumb_end_pass(emit->as);
@ -54,21 +66,23 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
void *f = asm_thumb_get_code(emit->as); void *f = asm_thumb_get_code(emit->as);
mp_emit_glue_assign_inline_asm_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params); mp_emit_glue_assign_inline_asm_code(emit->scope->unique_code_id, f, asm_thumb_get_code_size(emit->as), emit->scope->num_params);
} }
return emit->success;
} }
STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params) { STATIC int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, mp_parse_node_t *pn_params) {
if (n_params > 4) { if (n_params > 4) {
printf("SyntaxError: can only have up to 4 parameters to inline thumb assembly\n"); emit_inline_thumb_error(emit, "can only have up to 4 parameters to inline thumb assembly\n");
return 0; return 0;
} }
for (int i = 0; i < n_params; i++) { for (int i = 0; i < n_params; i++) {
if (!MP_PARSE_NODE_IS_ID(pn_params[i])) { if (!MP_PARSE_NODE_IS_ID(pn_params[i])) {
printf("SyntaxError: parameter to inline assembler must be an identifier\n"); emit_inline_thumb_error(emit, "parameter to inline assembler must be an identifier\n");
return 0; return 0;
} }
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i])); const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[i]));
if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) {
printf("SyntaxError: parameter %d to inline assembler must be r%d\n", i + 1, i); emit_inline_thumb_error(emit, "parameter %d to inline assembler must be r%d\n", i + 1, i);
return 0; return 0;
} }
} }
@ -81,28 +95,59 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, uint label_num, qst
asm_thumb_label_assign(emit->as, label_num); asm_thumb_label_assign(emit->as, label_num);
} }
STATIC uint get_arg_rlo(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) { typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;
if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) { STATIC const reg_name_t reg_name_table[] = {
printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num); {0, "r0\0"},
return 0; {1, "r1\0"},
{2, "r2\0"},
{3, "r3\0"},
{4, "r4\0"},
{5, "r5\0"},
{6, "r6\0"},
{7, "r7\0"},
{8, "r8\0"},
{9, "r9\0"},
{10, "r10"},
{11, "r11"},
{12, "r12"},
{13, "r13"},
{14, "r14"},
{15, "r15"},
{10, "sl\0"},
{11, "fp\0"},
{13, "sp\0"},
{14, "lr\0"},
{15, "pc\0"},
};
STATIC uint get_arg_reg(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, uint wanted_arg_num, uint max_reg) {
if (MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
const char *reg_str = qstr_str(reg_qstr);
for (uint i = 0; i < sizeof(reg_name_table) / sizeof(reg_name_table[0]); i++) {
const reg_name_t *r = &reg_name_table[i];
if (reg_str[0] == r->name[0] && reg_str[1] == r->name[1] && reg_str[2] == r->name[2] && (reg_str[2] == '\0' || reg_str[3] == '\0')) {
if (r->reg > max_reg) {
emit_inline_thumb_error(emit, "'%s' expects at most r%d in position %d\n", op, max_reg, wanted_arg_num);
return 0;
} else {
return r->reg;
}
}
}
} }
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); emit_inline_thumb_error(emit, "'%s' expects a register in position %d\n", op, wanted_arg_num);
const char *reg_str = qstr_str(reg_qstr); return 0;
if (!(strlen(reg_str) == 2 && reg_str[0] == 'r' && ('0' <= reg_str[1] && reg_str[1] <= '7'))) {
printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num);
return 0;
}
return reg_str[1] - '0';
} }
STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) { STATIC int get_arg_i(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) {
if (!MP_PARSE_NODE_IS_SMALL_INT(pn_args[wanted_arg_num])) { if (!MP_PARSE_NODE_IS_SMALL_INT(pn_args[wanted_arg_num])) {
printf("SyntaxError: '%s' expects an integer in position %d\n", op, wanted_arg_num); emit_inline_thumb_error(emit, "'%s' expects an integer in position %d\n", op, wanted_arg_num);
return 0; return 0;
} }
int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn_args[wanted_arg_num]); int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn_args[wanted_arg_num]);
if ((i & (~fit_mask)) != 0) { if ((i & (~fit_mask)) != 0) {
printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask); emit_inline_thumb_error(emit, "'%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask);
return 0; return 0;
} }
return i; return i;
@ -110,7 +155,7 @@ STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_nu
STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) { STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) {
if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) { if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
printf("SyntaxError: '%s' expects a label in position %d\n", op, wanted_arg_num); emit_inline_thumb_error(emit, "'%s' expects a label in position %d\n", op, wanted_arg_num);
return 0; return 0;
} }
qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
@ -121,7 +166,7 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
} }
// only need to have the labels on the last pass // only need to have the labels on the last pass
if (emit->pass == PASS_3) { if (emit->pass == PASS_3) {
printf("SyntaxError: label '%s' not defined\n", qstr_str(label_qstr)); emit_inline_thumb_error(emit, "label '%s' not defined\n", qstr_str(label_qstr));
} }
return 0; return 0;
} }
@ -189,24 +234,31 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
} else if (n_args == 2) { } else if (n_args == 2) {
if (strcmp(op_str, "mov") == 0) { if (strcmp(op_str, "mov") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_src = get_arg_rlo(op_str, pn_args, 1); uint rlo_src = get_arg_reg(emit, op_str, pn_args, 1, 7);
asm_thumb_mov_reg_reg(emit->as, rlo_dest, rlo_src); asm_thumb_mov_reg_reg(emit->as, rlo_dest, rlo_src);
} else if (strcmp(op_str, "movs") == 0) { } else if (strcmp(op_str, "movs") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
int i_src = get_arg_i(op_str, pn_args, 1, 0xff); int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xff);
asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src); asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src);
} else if (strcmp(op_str, "movw") == 0) { } else if (strcmp(op_str, "movw") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi uint reg_dest = get_arg_reg(emit, op_str, pn_args, 0, 15);
int i_src = get_arg_i(op_str, pn_args, 1, 0xffff); int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xffff);
asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src); asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src);
} else if (strcmp(op_str, "movt") == 0) { } else if (strcmp(op_str, "movt") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi uint reg_dest = get_arg_reg(emit, op_str, pn_args, 0, 15);
int i_src = get_arg_i(op_str, pn_args, 1, 0xffff); int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xffff);
asm_thumb_movt_reg_i16(emit->as, rlo_dest, i_src); asm_thumb_movt_reg_i16(emit->as, reg_dest, i_src);
} else if (strcmp(op_str, "movwt") == 0) {
// this is a convenience instruction
// we clear the MSB since it might be set from extracting the small int value
uint reg_dest = get_arg_reg(emit, op_str, pn_args, 0, 15);
int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xffffffff);
asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src & 0xffff);
asm_thumb_movt_reg_i16(emit->as, reg_dest, (i_src >> 16) & 0x7fff);
} else if (strcmp(op_str, "cmp") == 0) { } else if (strcmp(op_str, "cmp") == 0) {
uint rlo = get_arg_rlo(op_str, pn_args, 0); uint rlo = get_arg_reg(emit, op_str, pn_args, 0, 7);
int i8 = get_arg_i(op_str, pn_args, 1, 0xff); int i8 = get_arg_i(emit, op_str, pn_args, 1, 0xff);
asm_thumb_cmp_rlo_i8(emit->as, rlo, i8); asm_thumb_cmp_rlo_i8(emit->as, rlo, i8);
} else { } else {
goto unknown_op; goto unknown_op;
@ -214,15 +266,26 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
} else if (n_args == 3) { } else if (n_args == 3) {
if (strcmp(op_str, "add") == 0) { if (strcmp(op_str, "add") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_src_a = get_arg_rlo(op_str, pn_args, 1); uint rlo_src_a = get_arg_reg(emit, op_str, pn_args, 1, 7);
uint rlo_src_b = get_arg_rlo(op_str, pn_args, 2); uint rlo_src_b = get_arg_reg(emit, op_str, pn_args, 2, 7);
asm_thumb_add_reg_reg_reg(emit->as, rlo_dest, rlo_src_a, rlo_src_b); asm_thumb_add_rlo_rlo_rlo(emit->as, rlo_dest, rlo_src_a, rlo_src_b);
} else if (strcmp(op_str, "subs") == 0) { } else if (strcmp(op_str, "subs") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_src = get_arg_rlo(op_str, pn_args, 1); uint rlo_src = get_arg_reg(emit, op_str, pn_args, 1, 7);
int i3_src = get_arg_i(op_str, pn_args, 2, 0x7); int i3_src = get_arg_i(emit, op_str, pn_args, 2, 0x7);
asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src); asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src);
} else if (strcmp(op_str, "ldr") == 0) {
// TODO maybe use ldr(rd, [rb, 4]) syntax?
uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_base = get_arg_reg(emit, op_str, pn_args, 1, 7);
int i5 = get_arg_i(emit, op_str, pn_args, 2, 0x7c);
asm_thumb_ldr_rlo_rlo_i5(emit->as, rlo_dest, rlo_base, i5 >> 2);
} else if (strcmp(op_str, "str") == 0) {
uint rlo_src = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_base = get_arg_reg(emit, op_str, pn_args, 1, 7);
int i5 = get_arg_i(emit, op_str, pn_args, 2, 0x7c);
asm_thumb_str_rlo_rlo_i5(emit->as, rlo_src, rlo_base, i5 >> 2);
} else { } else {
goto unknown_op; goto unknown_op;
} }
@ -234,7 +297,7 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m
return; return;
unknown_op: unknown_op:
printf("SyntaxError: unsupported ARM Thumb instruction '%s' with %d arguments\n", op_str, n_args); emit_inline_thumb_error(emit, "unsupported Thumb instruction '%s' with %d arguments\n", op_str, n_args);
} }
const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { const emit_inline_asm_method_table_t emit_inline_thumb_method_table = {

View File

@ -1058,7 +1058,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
#if N_X64 #if N_X64
asm_x64_add_r64_to_r64(emit->as, REG_ARG_3, REG_ARG_2); asm_x64_add_r64_to_r64(emit->as, REG_ARG_3, REG_ARG_2);
#elif N_THUMB #elif N_THUMB
asm_thumb_add_reg_reg_reg(emit->as, REG_ARG_2, REG_ARG_2, REG_ARG_3); asm_thumb_add_rlo_rlo_rlo(emit->as, REG_ARG_2, REG_ARG_2, REG_ARG_3);
#endif #endif
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
} else if (op == MP_BINARY_OP_LESS) { } else if (op == MP_BINARY_OP_LESS) {