mirror of
https://github.com/micropython/micropython.git
synced 2025-12-16 09:50:15 +01:00
py/emitnative: Improve Viper register-indexed code for Thumb.
This commit lets the Viper code generator use optimised code sequence for register-indexed load and store operations when generating Thumb code. Register-indexed load and store operations for Thumb now can take at most two machine opcodes for halfword and word values, and just a single machine opcode for byte values. The original implementation could generate up to four opcodes in the worst case (dealing with word values). Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
This commit is contained in:
@@ -491,6 +491,26 @@ void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint r
|
||||
}
|
||||
}
|
||||
|
||||
void asm_thumb_ldrh_reg_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_base, uint reg_index) {
|
||||
asm_thumb_lsl_rlo_rlo_i5(as, reg_index, reg_index, 1);
|
||||
asm_thumb_ldrh_rlo_rlo_rlo(as, reg_dest, reg_base, reg_index);
|
||||
}
|
||||
|
||||
void asm_thumb_ldr_reg_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_base, uint reg_index) {
|
||||
asm_thumb_lsl_rlo_rlo_i5(as, reg_index, reg_index, 2);
|
||||
asm_thumb_ldr_rlo_rlo_rlo(as, reg_dest, reg_base, reg_index);
|
||||
}
|
||||
|
||||
void asm_thumb_strh_reg_reg_reg(asm_thumb_t *as, uint reg_val, uint reg_base, uint reg_index) {
|
||||
asm_thumb_lsl_rlo_rlo_i5(as, reg_index, reg_index, 1);
|
||||
asm_thumb_strh_rlo_rlo_rlo(as, reg_val, reg_base, reg_index);
|
||||
}
|
||||
|
||||
void asm_thumb_str_reg_reg_reg(asm_thumb_t *as, uint reg_val, uint reg_base, uint reg_index) {
|
||||
asm_thumb_lsl_rlo_rlo_i5(as, reg_index, reg_index, 2);
|
||||
asm_thumb_str_rlo_rlo_rlo(as, reg_val, reg_base, reg_index);
|
||||
}
|
||||
|
||||
// this could be wrong, because it should have a range of +/- 16MiB...
|
||||
#define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff))
|
||||
#define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff))
|
||||
|
||||
@@ -251,6 +251,50 @@ static inline void asm_thumb_bx_reg(asm_thumb_t *as, uint r_src) {
|
||||
asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_BX, 0, r_src);
|
||||
}
|
||||
|
||||
// FORMAT 7: load/store with register offset
|
||||
// FORMAT 8: load/store sign-extended byte/halfword
|
||||
|
||||
#define ASM_THUMB_FORMAT_7_LDR (0x5800)
|
||||
#define ASM_THUMB_FORMAT_7_STR (0x5000)
|
||||
#define ASM_THUMB_FORMAT_7_WORD_TRANSFER (0x0000)
|
||||
#define ASM_THUMB_FORMAT_7_BYTE_TRANSFER (0x0400)
|
||||
#define ASM_THUMB_FORMAT_8_LDRH (0x5A00)
|
||||
#define ASM_THUMB_FORMAT_8_STRH (0x5200)
|
||||
|
||||
#define ASM_THUMB_FORMAT_7_8_ENCODE(op, rlo_dest, rlo_base, rlo_index) \
|
||||
((op) | ((rlo_index) << 6) | ((rlo_base) << 3) | ((rlo_dest)))
|
||||
|
||||
static inline void asm_thumb_format_7_8(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint rlo_index) {
|
||||
assert(rlo_dest < ASM_THUMB_REG_R8);
|
||||
assert(rlo_base < ASM_THUMB_REG_R8);
|
||||
assert(rlo_index < ASM_THUMB_REG_R8);
|
||||
asm_thumb_op16(as, ASM_THUMB_FORMAT_7_8_ENCODE(op, rlo_dest, rlo_base, rlo_index));
|
||||
}
|
||||
|
||||
static inline void asm_thumb_ldrb_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) {
|
||||
asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_LDR | ASM_THUMB_FORMAT_7_BYTE_TRANSFER, rlo_dest, rlo_base, rlo_index);
|
||||
}
|
||||
|
||||
static inline void asm_thumb_ldrh_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) {
|
||||
asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_8_LDRH, rlo_dest, rlo_base, rlo_index);
|
||||
}
|
||||
|
||||
static inline void asm_thumb_ldr_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) {
|
||||
asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_LDR | ASM_THUMB_FORMAT_7_WORD_TRANSFER, rlo_dest, rlo_base, rlo_index);
|
||||
}
|
||||
|
||||
static inline void asm_thumb_strb_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint rlo_index) {
|
||||
asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_STR | ASM_THUMB_FORMAT_7_BYTE_TRANSFER, rlo_src, rlo_base, rlo_index);
|
||||
}
|
||||
|
||||
static inline void asm_thumb_strh_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) {
|
||||
asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_8_STRH, rlo_dest, rlo_base, rlo_index);
|
||||
}
|
||||
|
||||
static inline void asm_thumb_str_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint rlo_index) {
|
||||
asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_STR | ASM_THUMB_FORMAT_7_WORD_TRANSFER, rlo_src, rlo_base, rlo_index);
|
||||
}
|
||||
|
||||
// FORMAT 9: load/store with immediate offset
|
||||
// For word transfers the offset must be aligned, and >>2
|
||||
|
||||
@@ -341,6 +385,11 @@ void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label);
|
||||
void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset); // convenience
|
||||
void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset); // convenience
|
||||
|
||||
void asm_thumb_ldrh_reg_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_base, uint reg_index);
|
||||
void asm_thumb_ldr_reg_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_base, uint reg_index);
|
||||
void asm_thumb_strh_reg_reg_reg(asm_thumb_t *as, uint reg_val, uint reg_base, uint reg_index);
|
||||
void asm_thumb_str_reg_reg_reg(asm_thumb_t *as, uint reg_val, uint reg_base, uint reg_index);
|
||||
|
||||
void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch
|
||||
void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch
|
||||
void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp); // convenience
|
||||
|
||||
@@ -1641,6 +1641,9 @@ static void emit_native_load_subscr(emit_t *emit) {
|
||||
#if N_ARM
|
||||
asm_arm_ldrb_reg_reg_reg(emit->as, REG_RET, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_THUMB
|
||||
asm_thumb_ldrb_rlo_rlo_rlo(emit->as, REG_RET, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#endif
|
||||
// TODO optimise to use thumb ldrb r1, [r2, r3]
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
@@ -1652,6 +1655,9 @@ static void emit_native_load_subscr(emit_t *emit) {
|
||||
#if N_ARM
|
||||
asm_arm_ldrh_reg_reg_reg(emit->as, REG_RET, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_THUMB
|
||||
asm_thumb_ldrh_reg_reg_reg(emit->as, REG_RET, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_XTENSA || N_XTENSAWIN
|
||||
asm_xtensa_op_addx2(emit->as, REG_ARG_1, reg_index, REG_ARG_1);
|
||||
asm_xtensa_op_l16ui(emit->as, REG_RET, REG_ARG_1, 0);
|
||||
@@ -1667,6 +1673,9 @@ static void emit_native_load_subscr(emit_t *emit) {
|
||||
#if N_ARM
|
||||
asm_arm_ldr_reg_reg_reg(emit->as, REG_RET, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_THUMB
|
||||
asm_thumb_ldr_reg_reg_reg(emit->as, REG_RET, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_RV32
|
||||
asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2);
|
||||
asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2);
|
||||
@@ -1944,6 +1953,9 @@ static void emit_native_store_subscr(emit_t *emit) {
|
||||
#if N_ARM
|
||||
asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_THUMB
|
||||
asm_thumb_strb_rlo_rlo_rlo(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#endif
|
||||
ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base
|
||||
ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index)
|
||||
@@ -1954,6 +1966,9 @@ static void emit_native_store_subscr(emit_t *emit) {
|
||||
#if N_ARM
|
||||
asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_THUMB
|
||||
asm_thumb_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_XTENSA || N_XTENSAWIN
|
||||
asm_xtensa_op_addx2(emit->as, REG_ARG_1, reg_index, REG_ARG_1);
|
||||
asm_xtensa_op_s16i(emit->as, reg_value, REG_ARG_1, 0);
|
||||
@@ -1969,6 +1984,9 @@ static void emit_native_store_subscr(emit_t *emit) {
|
||||
#if N_ARM
|
||||
asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_THUMB
|
||||
asm_thumb_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index);
|
||||
break;
|
||||
#elif N_RV32
|
||||
asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2);
|
||||
asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2);
|
||||
|
||||
Reference in New Issue
Block a user