Commit a26dc509 authored by Damien George's avatar Damien George
Browse files

py: Improve inline assembler; improve compiler constant folding.

parent 2813cb60
......@@ -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);
}
#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) {
asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, 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_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))
......@@ -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));
}
#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) {
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_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) {
/* 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_write_op16(as, OP_BLX(reg_temp));
} 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));
} else {
// use SVC
......
......@@ -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_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_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_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_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_b_n(asm_thumb_t *as, uint label);
void asm_thumb_bcc_n(asm_thumb_t *as, int cond, uint label);
......
......@@ -17,6 +17,7 @@
#include "obj.h"
#include "compile.h"
#include "runtime.h"
#include "builtin.h"
#include "smallint.h"
// 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]);
}
// now try to fold this parse node
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:
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]);
int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
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]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
#if MICROPY_EMIT_CPYTHON
// can overflow; enabled only to compare with CPython
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
#endif
// int << int
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);
}
} 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);
} else {
// 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 arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
// int + int
arg0 += arg1;
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
// int - int
arg0 -= arg1;
} else {
// shouldn't happen
assert(0);
}
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);
}
}
......@@ -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 arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
// int * int
if (!mp_small_int_mul_overflow(arg0, arg1)) {
arg0 *= arg1;
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)) {
; // pass
// int / int
// pass
} 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));
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
if (arg1 != 0) {
// int // int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
}
} 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])) {
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)) {
// +int
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)) {
// -int
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)) {
// ~int
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
} else {
// shouldn't happen
......@@ -184,7 +222,7 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
if (0) {
#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])) {
// int**x
// int ** x
// can overflow; enabled only to compare with CPython
mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
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++) {
assert(MP_PARSE_NODE_IS_STRUCT(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_NULL(pns2->nodes[1]));
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) {
EMIT_INLINE_ASM(end_pass);
bool success = EMIT_INLINE_ASM(end_pass);
if (!success) {
comp->had_error = true;
}
}
}
#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_method_table = &emit_inline_thumb_method_table;
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
} 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_scope(comp, s, PASS_2);
compile_scope(comp, s, PASS_3);
if (!comp->had_error) {
compile_scope(comp, s, PASS_3);
}
}
}
......
......@@ -133,7 +133,7 @@ typedef struct _emit_inline_asm_t emit_inline_asm_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 (*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);
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);
......
......@@ -185,6 +185,7 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
#ifdef WRITE_CODE
if (fp_write_code != NULL) {
fwrite(fun_data, len, 1, fp_write_code);
fflush(fp_write_code);
}
#endif
#endif
......
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include "misc.h"
......@@ -17,13 +18,23 @@
#if MICROPY_EMIT_INLINE_THUMB
struct _emit_inline_asm_t {
int pass;
uint16_t pass;
uint16_t success;
scope_t *scope;
uint max_num_labels;
qstr *label_lookup;
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 = m_new_obj(emit_inline_asm_t);
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) {
emit->pass = pass;
emit->success = true;
emit->scope = scope;
asm_thumb_start_pass(emit->as, pass);
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_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);
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) {
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;
}
for (int i = 0; i < n_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;
}
const char *p = qstr_str(MP_PARSE_NODE_LEAF_ARG(pn_params[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;
}
}
......@@ -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);
}
STATIC uint get_arg_rlo(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) {
if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) {
printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num);
return 0;
}
qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]);
const char *reg_str = qstr_str(reg_qstr);
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;
typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;
STATIC const reg_name_t reg_name_table[] = {
{0, "r0\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;
}
}
}
}
return reg_str[1] - '0';
emit_inline_thumb_error(emit, "'%s' expects a register in position %d\n", op, wanted_arg_num);
return 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])) {
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;
}
int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn_args[wanted_arg_num]);
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 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) {
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;
}
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
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;
}
......@@ -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) {
if (strcmp(op_str, "mov") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
uint rlo_src = get_arg_rlo(op_str, pn_args, 1);
uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_src = get_arg_reg(emit, op_str, pn_args, 1, 7);
asm_thumb_mov_reg_reg(emit->as, rlo_dest, rlo_src);
} else if (strcmp(op_str, "movs") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
int i_src = get_arg_i(op_str, pn_args, 1, 0xff);
uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
int i_src = get_arg_i(emit, op_str, pn_args, 1, 0xff);
asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src);
} 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
int i_src = get_arg_i(op_str, pn_args, 1, 0xffff);
asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src);
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, 0xffff);
asm_thumb_movw_reg_i16(emit->as, reg_dest, i_src);
} 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
int i_src = get_arg_i(op_str, pn_args, 1, 0xffff);
asm_thumb_movt_reg_i16(emit->as, rlo_dest, i_src);
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, 0xffff);
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) {
uint rlo = get_arg_rlo(op_str, pn_args, 0);
int i8 = get_arg_i(op_str, pn_args, 1, 0xff);
uint rlo = get_arg_reg(emit, op_str, pn_args, 0, 7);
int i8 = get_arg_i(emit, op_str, pn_args, 1, 0xff);
asm_thumb_cmp_rlo_i8(emit->as, rlo, i8);
} else {
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) {
if (strcmp(op_str, "add") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
uint rlo_src_a = get_arg_rlo(op_str, pn_args, 1);
uint rlo_src_b = get_arg_rlo(op_str, pn_args, 2);
asm_thumb_add_reg_reg_reg(emit->as, rlo_dest, rlo_src_a, rlo_src_b);
uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_src_a = get_arg_reg(emit, op_str, pn_args, 1, 7);
uint rlo_src_b = get_arg_reg(emit, op_str, pn_args, 2, 7);
asm_thumb_add_rlo_rlo_rlo(emit->as, rlo_dest, rlo_src_a, rlo_src_b);
} else if (strcmp(op_str, "subs") == 0) {
uint rlo_dest = get_arg_rlo(op_str, pn_args, 0);
uint rlo_src = get_arg_rlo(op_str, pn_args, 1);
int i3_src = get_arg_i(op_str, pn_args, 2, 0x7);
uint rlo_dest = get_arg_reg(emit, op_str, pn_args, 0, 7);
uint rlo_src = get_arg_reg(emit, op_str, pn_args, 1, 7);
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);
} 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 {
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;
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 = {
......
......@@ -1058,7 +1058,7 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
#if N_X64
asm_x64_add_r64_to_r64(emit->as, REG_ARG_3, REG_ARG_2);
#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
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
} else if (op == MP_BINARY_OP_LESS) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment