py/emitinlinethumb: Use 16 bit encodings for PUSH LR and POP PC.

The Thumb instruction set has special 16 bit encodings for PUSH involving
LR and POP involving PC, which are commonly used in nested functions.

Using this encoding is particularly important for ARMv6-M, where the more
general 32 bit encoding of PUSH and POP is unavailable.
This commit is contained in:
Christian Zietz 2022-04-03 13:12:43 +02:00 committed by Damien George
parent 1daeeb2430
commit b0bcb3862b
1 changed files with 14 additions and 4 deletions

View File

@ -621,8 +621,13 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSIE_I);
} else if (op == MP_QSTR_push) {
mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
if ((reglist & 0xff00) == 0) {
asm_thumb_op16(&emit->as, 0xb400 | reglist);
if ((reglist & 0xbf00) == 0) {
if ((reglist & (1 << 14)) == 0) {
asm_thumb_op16(&emit->as, 0xb400 | reglist);
} else {
// 16-bit encoding for pushing low registers and LR
asm_thumb_op16(&emit->as, 0xb500 | (reglist & 0xff));
}
} else {
if (!ARMV7M) {
goto unknown_op;
@ -631,8 +636,13 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
}
} else if (op == MP_QSTR_pop) {
mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
if ((reglist & 0xff00) == 0) {
asm_thumb_op16(&emit->as, 0xbc00 | reglist);
if ((reglist & 0x7f00) == 0) {
if ((reglist & (1 << 15)) == 0) {
asm_thumb_op16(&emit->as, 0xbc00 | reglist);
} else {
// 16-bit encoding for popping low registers and PC, i.e., returning
asm_thumb_op16(&emit->as, 0xbd00 | (reglist & 0xff));
}
} else {
if (!ARMV7M) {
goto unknown_op;