Skip to content

Commit cd1b921

Browse files
agattidpgeorge
authored andcommitted
py/asmarm: Implement the full set of Viper load/store operations.
This commit expands the implementation of Viper load/store operations that are optimised for the Arm platform. Now both load and store emitters should generate the shortest possible sequence in all cases. Redundant specialised operation emitters have been folded into the general case implementation - this was the case of integer-indexed load/store operations with a fixed offset of zero. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent a8e0369 commit cd1b921

File tree

3 files changed

+46
-34
lines changed

3 files changed

+46
-34
lines changed

py/asmarm.c

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838

3939
#define REG_TEMP ASM_ARM_REG_R8
4040

41-
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000)
42-
4341
// Insert word into instruction flow
4442
static void emit(asm_arm_t *as, uint op) {
4543
uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
@@ -347,11 +345,6 @@ void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offse
347345
}
348346
}
349347

350-
void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) {
351-
// ldrh rd, [rn]
352-
emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12));
353-
}
354-
355348
void asm_arm_ldrh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
356349
// ldrh doesn't support scaled register index
357350
emit_al(as, 0x1a00080 | (REG_TEMP << 12) | rn); // mov temp, rn, lsl #1
@@ -370,16 +363,23 @@ void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offs
370363
}
371364
}
372365

373-
void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) {
374-
// ldrb rd, [rn]
375-
emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12));
376-
}
377-
378366
void asm_arm_ldrb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
379367
// ldrb rd, [rm, rn]
380368
emit_al(as, 0x7d00000 | (rm << 16) | (rd << 12) | rn);
381369
}
382370

371+
void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) {
372+
if (byte_offset < 0x1000) {
373+
// ldrb rd, [rn, #off]
374+
emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12) | byte_offset);
375+
} else {
376+
// mov temp, #off
377+
// ldrb rd, [rn, temp]
378+
asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset);
379+
emit_al(as, 0x7d00000 | (rn << 16) | (rd << 12) | REG_TEMP);
380+
}
381+
}
382+
383383
void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
384384
// ldr rd, [rm, rn, lsl #2]
385385
emit_al(as, 0x7900100 | (rm << 16) | (rd << 12) | rn);
@@ -397,14 +397,28 @@ void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offse
397397
}
398398
}
399399

400-
void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) {
401-
// strh rd, [rm]
402-
emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12));
400+
void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) {
401+
if (byte_offset < 0x100) {
402+
// strh rd, [rn, #off]
403+
emit_al(as, 0x1c000b0 | (rn << 16) | (rd << 12) | ((byte_offset & 0xf0) << 4) | (byte_offset & 0xf));
404+
} else {
405+
// mov temp, #off
406+
// strh rd, [rn, temp]
407+
asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset);
408+
emit_al(as, 0x18000b0 | (rn << 16) | (rd << 12) | REG_TEMP);
409+
}
403410
}
404411

405-
void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) {
406-
// strb rd, [rm]
407-
emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12));
412+
void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset) {
413+
if (byte_offset < 0x1000) {
414+
// strb rd, [rm, #off]
415+
emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12) | byte_offset);
416+
} else {
417+
// mov temp, #off
418+
// strb rd, [rm, temp]
419+
asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset);
420+
emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | REG_TEMP);
421+
}
408422
}
409423

410424
void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) {
@@ -430,7 +444,7 @@ void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) {
430444
rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction
431445
rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted
432446

433-
if (SIGNED_FIT24(rel)) {
447+
if (MP_FIT_SIGNED(24, rel)) {
434448
emit(as, cond | 0xa000000 | (rel & 0xffffff));
435449
} else {
436450
printf("asm_arm_bcc: branch does not fit in 24 bits\n");

py/asmarm.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,11 @@ void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs);
110110

111111
// memory
112112
void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset);
113-
void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn);
114113
void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset);
115-
void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn);
114+
void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset);
116115
void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset);
117-
void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm);
118-
void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm);
116+
void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset);
117+
void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset);
119118

120119
// load from array
121120
void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn);
@@ -209,16 +208,19 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src);
209208
#define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src))
210209

211210
#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset))
212-
#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base))
213-
#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base))
214-
#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (uint16_offset))
215-
#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg_offset((as), (reg_dest), (reg_base), 0)
211+
#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0)
212+
#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_arm_ldrb_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset))
213+
#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0)
214+
#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (halfword_offset))
215+
#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0)
216216
#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg_offset((as), (reg_dest), (reg_base), 4 * (word_offset))
217217

218218
#define ASM_STORE_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), (word_offset))
219-
#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base))
220-
#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base))
221-
#define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg_offset((as), (reg_value), (reg_base), 0)
219+
#define ASM_STORE8_REG_REG(as, reg_value, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_value), (reg_base), 0)
220+
#define ASM_STORE8_REG_REG_OFFSET(as, reg_value, reg_base, byte_offset) asm_arm_strb_reg_reg_offset((as), (reg_value), (reg_base), (byte_offset))
221+
#define ASM_STORE16_REG_REG(as, reg_value, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_value), (reg_base), 0)
222+
#define ASM_STORE16_REG_REG_OFFSET(as, reg_value, reg_base, halfword_offset) asm_arm_strh_reg_reg_offset((as), (reg_value), (reg_base), 2 * (halfword_offset))
223+
#define ASM_STORE32_REG_REG(as, reg_value, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), 0)
222224
#define ASM_STORE32_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) asm_arm_str_reg_reg_offset((as), (reg_value), (reg_base), 4 * (word_offset))
223225

224226
#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldrb_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index))

py/emitnative.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,10 +1785,6 @@ static void emit_native_store_subscr(emit_t *emit) {
17851785
if (index_value != 0) {
17861786
// index is non-zero
17871787
ASM_MOV_REG_IMM(emit->as, reg_index, index_value);
1788-
#if N_ARM
1789-
asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index);
1790-
break;
1791-
#endif
17921788
ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base
17931789
reg_base = reg_index;
17941790
}

0 commit comments

Comments
 (0)