Skip to content

Commit a8e0369

Browse files
agattidpgeorge
authored andcommitted
py/asmrv32: Implement the full set of Viper load/store operations.
This commit expands the implementation of Viper load/store operations that are optimised for the RV32 platform. Given the way opcodes are encoded, all value sizes are implemented with only two functions - one for loads and one for stores. This should reduce duplication with existing operations and should, in theory, save space as some code is removed. Both load and store emitters will generate the shortest possible sequence (as long as the stack pointer is not involved), using compressed opcodes when possible. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent 703d5ac commit a8e0369

3 files changed

Lines changed: 58 additions & 74 deletions

File tree

py/asmrv32.c

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -450,31 +450,37 @@ void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t
450450
asm_rv32_opcode_cadd(state, rd, ASM_RV32_REG_SP);
451451
}
452452

453-
void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) {
454-
mp_int_t scaled_offset = offset * sizeof(ASM_WORD_SIZE);
453+
static const uint8_t RV32_LOAD_OPCODE_TABLE[3] = {
454+
0x04, 0x05, 0x02
455+
};
455456

456-
if (scaled_offset >= 0 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && FIT_UNSIGNED(scaled_offset, 6)) {
457+
void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) {
458+
assert(operation_size <= 2 && "Operation size value out of range.");
459+
460+
int32_t scaled_offset = offset << operation_size;
461+
462+
if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) {
457463
// c.lw rd', offset(rs')
458464
asm_rv32_opcode_clw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset);
459465
return;
460466
}
461467

462-
if (FIT_SIGNED(scaled_offset, 12)) {
463-
// lw rd, offset(rs)
464-
asm_rv32_opcode_lw(state, rd, rs, scaled_offset);
468+
if (MP_FIT_SIGNED(12, scaled_offset)) {
469+
// lbu|lhu|lw rd, offset(rs)
470+
asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_TABLE[operation_size], rd, rs, scaled_offset));
465471
return;
466472
}
467473

468474
mp_uint_t upper = 0;
469475
mp_uint_t lower = 0;
470476
split_immediate(scaled_offset, &upper, &lower);
471477

472-
// lui rd, HI(offset) ; Or c.lui if possible
473-
// c.add rd, rs
474-
// lw rd, LO(offset)(rd)
478+
// lui rd, HI(offset) ; Or c.lui if possible
479+
// c.add rd, rs
480+
// lbu|lhu|lw rd, LO(offset)(rd)
475481
load_upper_immediate(state, rd, upper);
476482
asm_rv32_opcode_cadd(state, rd, rs);
477-
asm_rv32_opcode_lw(state, rd, rd, lower);
483+
asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_TABLE[operation_size], rd, rd, lower));
478484
}
479485

480486
void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) {
@@ -497,25 +503,33 @@ void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) {
497503
asm_rv32_opcode_jalr(state, ASM_RV32_REG_ZERO, REG_TEMP2, lower);
498504
}
499505

500-
void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) {
501-
mp_int_t scaled_offset = offset * ASM_WORD_SIZE;
506+
void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) {
507+
assert(operation_size <= 2 && "Operation size value out of range.");
508+
509+
int32_t scaled_offset = offset << operation_size;
502510

503-
if (FIT_SIGNED(scaled_offset, 12)) {
504-
// sw rd, offset(rs)
505-
asm_rv32_opcode_sw(state, rd, rs, scaled_offset);
511+
if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) {
512+
// c.sw rd', offset(rs')
513+
asm_rv32_opcode_csw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset);
514+
return;
515+
}
516+
517+
if (MP_FIT_SIGNED(12, scaled_offset)) {
518+
// sb|sh|sw rd, offset(rs)
519+
asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, rs, rd, scaled_offset));
506520
return;
507521
}
508522

509523
mp_uint_t upper = 0;
510524
mp_uint_t lower = 0;
511525
split_immediate(scaled_offset, &upper, &lower);
512526

513-
// lui temporary, HI(offset) ; Or c.lui if possible
514-
// c.add temporary, rs
515-
// sw rd, LO(offset)(temporary)
527+
// lui temporary, HI(offset) ; Or c.lui if possible
528+
// c.add temporary, rs
529+
// sb|sh|sw rd, LO(offset)(temporary)
516530
load_upper_immediate(state, REG_TEMP2, upper);
517531
asm_rv32_opcode_cadd(state, REG_TEMP2, rs);
518-
asm_rv32_opcode_sw(state, rd, REG_TEMP2, lower);
532+
asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, REG_TEMP2, rd, lower));
519533
}
520534

521535
void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label) {
@@ -530,27 +544,6 @@ void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t labe
530544
asm_rv32_opcode_addi(state, rd, rd, lower);
531545
}
532546

533-
void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) {
534-
mp_int_t scaled_offset = offset * sizeof(uint16_t);
535-
536-
if (FIT_SIGNED(scaled_offset, 12)) {
537-
// lhu rd, offset(rs)
538-
asm_rv32_opcode_lhu(state, rd, rs, scaled_offset);
539-
return;
540-
}
541-
542-
mp_uint_t upper = 0;
543-
mp_uint_t lower = 0;
544-
split_immediate(scaled_offset, &upper, &lower);
545-
546-
// lui rd, HI(offset) ; Or c.lui if possible
547-
// c.add rd, rs
548-
// lhu rd, LO(offset)(rd)
549-
load_upper_immediate(state, rd, upper);
550-
asm_rv32_opcode_cadd(state, rd, rs);
551-
asm_rv32_opcode_lhu(state, rd, rd, lower);
552-
}
553-
554547
void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) {
555548
if (rs == rd) {
556549
// c.li rd, 0

py/asmrv32.h

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -709,14 +709,13 @@ void asm_rv32_emit_call_ind(asm_rv32_t *state, mp_uint_t index);
709709
void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label);
710710
void asm_rv32_emit_jump_if_reg_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t label);
711711
void asm_rv32_emit_jump_if_reg_nonzero(asm_rv32_t *state, mp_uint_t rs, mp_uint_t label);
712-
void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset);
713-
void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset);
712+
void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size);
714713
void asm_rv32_emit_mov_local_reg(asm_rv32_t *state, mp_uint_t local, mp_uint_t rs);
715714
void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local);
716715
void asm_rv32_emit_mov_reg_local(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local);
717716
void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label);
718717
void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs);
719-
void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, mp_int_t offset);
718+
void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, int32_t offset, mp_uint_t operation_size);
720719

721720
#define ASM_T asm_rv32_t
722721
#define ASM_ENTRY(state, labels) asm_rv32_entry(state, labels)
@@ -733,11 +732,12 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_
733732
#define ASM_JUMP_IF_REG_ZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_eq(state, rs, ASM_RV32_REG_ZERO, label)
734733
#define ASM_JUMP_REG(state, rs) asm_rv32_opcode_cjr(state, rs)
735734
#define ASM_LOAD_REG_REG_OFFSET(state, rd, rs, offset) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset)
736-
#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load16_reg_reg_offset(state, rd, rs, offset)
737-
#define ASM_LOAD16_REG_REG(state, rd, rs) asm_rv32_opcode_lhu(state, rd, rs, 0)
735+
#define ASM_LOAD8_REG_REG(state, rd, rs) ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, 0)
736+
#define ASM_LOAD16_REG_REG(state, rd, rs) ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, 0)
738737
#define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, 0)
739-
#define ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset)
740-
#define ASM_LOAD8_REG_REG(state, rd, rs) asm_rv32_opcode_lbu(state, rd, rs, 0)
738+
#define ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 0)
739+
#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 1)
740+
#define ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 2)
741741
#define ASM_LSL_REG_REG(state, rd, rs) asm_rv32_opcode_sll(state, rd, rd, rs)
742742
#define ASM_LSR_REG_REG(state, rd, rs) asm_rv32_opcode_srl(state, rd, rd, rs)
743743
#define ASM_MOV_LOCAL_REG(state, local, rs) asm_rv32_emit_mov_local_reg(state, local, rs)
@@ -751,13 +751,20 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_
751751
#define ASM_NOT_REG(state, rd) asm_rv32_opcode_xori(state, rd, rd, -1)
752752
#define ASM_OR_REG_REG(state, rd, rs) asm_rv32_opcode_or(state, rd, rd, rs)
753753
#define ASM_STORE_REG_REG_OFFSET(state, rd, rs, offset) ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset)
754-
#define ASM_STORE16_REG_REG(state, rs1, rs2) asm_rv32_opcode_sh(state, rs1, rs2, 0)
754+
#define ASM_STORE8_REG_REG(state, rs1, rs2) ASM_STORE8_REG_REG_OFFSET(state, rs1, rs2, 0)
755+
#define ASM_STORE16_REG_REG(state, rs1, rs2) ASM_STORE16_REG_REG_OFFSET(state, rs1, rs2, 0)
755756
#define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG_OFFSET(state, rs1, rs2, 0)
756-
#define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset)
757-
#define ASM_STORE8_REG_REG(state, rs1, rs2) asm_rv32_opcode_sb(state, rs1, rs2, 0)
757+
#define ASM_STORE8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 0)
758+
#define ASM_STORE16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 1)
759+
#define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 2)
758760
#define ASM_SUB_REG_REG(state, rd, rs) asm_rv32_opcode_sub(state, rd, rd, rs)
759761
#define ASM_XOR_REG_REG(state, rd, rs) asm_rv32_emit_optimised_xor(state, rd, rs)
760762
#define ASM_CLR_REG(state, rd)
763+
#define ASM_LOAD8_REG_REG_REG(state, rd, rs1, rs2) \
764+
do { \
765+
asm_rv32_opcode_cadd(state, rs1, rs2); \
766+
asm_rv32_opcode_lbu(state, rd, rs1, 0); \
767+
} while (0)
761768
#define ASM_LOAD16_REG_REG_REG(state, rd, rs1, rs2) \
762769
do { \
763770
asm_rv32_opcode_slli(state, rs2, rs2, 1); \
@@ -770,6 +777,11 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_
770777
asm_rv32_opcode_cadd(state, rs1, rs2); \
771778
asm_rv32_opcode_lw(state, rd, rs1, 0); \
772779
} while (0)
780+
#define ASM_STORE8_REG_REG_REG(state, rd, rs1, rs2) \
781+
do { \
782+
asm_rv32_opcode_cadd(state, rs1, rs2); \
783+
asm_rv32_opcode_sb(state, rd, rs1, 0); \
784+
} while (0)
773785
#define ASM_STORE16_REG_REG_REG(state, rd, rs1, rs2) \
774786
do { \
775787
asm_rv32_opcode_slli(state, rs2, rs2, 1); \

py/emitnative.c

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,6 @@ static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {REG_LOCAL_1, RE
180180
*emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \
181181
} while (0)
182182

183-
#if N_RV32
184-
#define FIT_SIGNED(value, bits) \
185-
((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \
186-
(((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1)))
187-
#endif
188-
189183
typedef enum {
190184
STACK_VALUE,
191185
STACK_REG,
@@ -1540,12 +1534,7 @@ static void emit_native_load_subscr(emit_t *emit) {
15401534
#ifdef ASM_LOAD8_REG_REG_OFFSET
15411535
ASM_LOAD8_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value);
15421536
#else
1543-
#if N_RV32
1544-
if (FIT_SIGNED(index_value, 12)) {
1545-
asm_rv32_opcode_lbu(emit->as, REG_RET, reg_base, index_value);
1546-
break;
1547-
}
1548-
#elif N_XTENSA || N_XTENSAWIN
1537+
#if N_XTENSA || N_XTENSAWIN
15491538
if (index_value >= 0 && index_value < 256) {
15501539
asm_xtensa_op_l8ui(emit->as, REG_RET, reg_base, index_value);
15511540
break;
@@ -1787,12 +1776,7 @@ static void emit_native_store_subscr(emit_t *emit) {
17871776
#ifdef ASM_STORE8_REG_REG_OFFSET
17881777
ASM_STORE8_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value);
17891778
#else
1790-
#if N_RV32
1791-
if (FIT_SIGNED(index_value, 12)) {
1792-
asm_rv32_opcode_sb(emit->as, reg_value, reg_base, index_value);
1793-
break;
1794-
}
1795-
#elif N_XTENSA || N_XTENSAWIN
1779+
#if N_XTENSA || N_XTENSAWIN
17961780
if (index_value >= 0 && index_value < 256) {
17971781
asm_xtensa_op_s8i(emit->as, reg_value, reg_base, index_value);
17981782
break;
@@ -1817,12 +1801,7 @@ static void emit_native_store_subscr(emit_t *emit) {
18171801
#ifdef ASM_STORE16_REG_REG_OFFSET
18181802
ASM_STORE16_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value);
18191803
#else
1820-
#if N_RV32
1821-
if (FIT_SIGNED(index_value, 11)) {
1822-
asm_rv32_opcode_sh(emit->as, reg_value, reg_base, index_value << 1);
1823-
break;
1824-
}
1825-
#elif N_XTENSA || N_XTENSAWIN
1804+
#if N_XTENSA || N_XTENSAWIN
18261805
if (index_value >= 0 && index_value < 256) {
18271806
asm_xtensa_op_s16i(emit->as, reg_value, reg_base, index_value);
18281807
break;

0 commit comments

Comments
 (0)