10000 py/emitinlinerv32: Refactor opcode arguments validation. · micropython/micropython@3da5295 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3da5295

Browse files
agattidpgeorge
authored andcommitted
py/emitinlinerv32: Refactor opcode arguments validation.
This commit simplifies the way arguments are validated when processing RV32 inline assembler opcodes. Opcode arguments were handled in two separate passes, one that performed a pure validation (with an early rejection in case of errors), and another that converted the parse node into a serialised value but without any error checking. Considering that the validation pass effectively performed the parse node conversion and then discarded its result once validated, it is preferable to hold onto the serialised result to reuse it later at opcode generation time. With these changes, those two passes are merged into one single operation when applicable (basically any opcode that doesn't use an integer offset), removing a fair amount of duplicate code. The size savings should be around half a kilobyte, with no other changes in the assembler's behaviour. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent 27b7bf3 commit 3da5295

File tree

1 file changed

+49
-100
lines changed

1 file changed

+49
-100
lines changed

py/emitinlinerv32.c

Lines changed: 49 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ typedef enum {
196196
CALL_R, // Opcode Register
197197
CALL_RL, // Opcode Register, Label
198198
CALL_N, // Opcode
199-
CALL_I, // Opcode Immediate
200199
CALL_RII, // Opcode Register, Register, Immediate
201200
CALL_RIR, // Opcode Register, Immediate(Register)
202201
CALL_COUNT
@@ -210,7 +209,6 @@ typedef enum {
210209
#define U (1 << 2) // Unsigned immediate
211210
#define Z (1 << 3) // Non-zero
212211

213-
typedef void (*call_l_t)(asm_rv32_t *state, mp_uint_t label_index);
214212
typedef void (*call_ri_t)(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate);
215213
typedef void (*call_rri_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_int_t immediate);
216214
typedef void (*call_rii_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate1, mp_int_t immediate2);
@@ -439,8 +437,7 @@ static bool validate_integer(mp_uint_t value, mp_uint_t mask, mp_uint_t flags) {
439437
#define ET_WRONG_ARGUMENTS_COUNT MP_ERROR_TEXT("opcode '%q': expecting %d arguments")
440438
#define ET_OUT_OF_RANGE MP_ERROR_TEXT("opcode '%q' argument %d: out of range")
441439

442-
static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
443-
const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index) {
440+
static bool serialise_argument(emit_inline_asm_t *emit, const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index, mp_uint_t *serialised) {
444441
assert((node_index < 3) && "Invalid argument node number.");
445442

446443
uint32_t kind = 0;
@@ -470,29 +467,31 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
470467
break;
471468
}
472469

470+
mp_uint_t serialised_value = 0;
471+
473472
switch (kind & 0x03) {
474473
case N:
475474
assert(mask == OPCODE_MASKS[MASK_NOT_USED] && "Invalid mask index for missing operand.");
476-
return true;
475+
break;
477476

478477
case R: {
479478
mp_uint_t register_index;
480479
if (!parse_register_node(node, &register_index, false)) {
481480
emit_inline_rv32_error_exc(emit,
482481
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
483-
ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_register));
482+
ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_register));
484483
return false;
485484
}
486485

487486
if ((mask & (1U << register_index)) == 0) {
488487
emit_inline_rv32_error_exc(emit,
489488
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
490489
MP_ERROR_TEXT("opcode '%q' argument %d: unknown register"),
491-
opcode_qstr, node_index + 1));
490+
opcode->qstring, node_index + 1));
492491
return false;
493492
}
494493

495-
return true;
494+
serialised_value = (kind & C) ? RV32_MAP_IN_C_REGISTER_WINDOW(register_index) : register_index;
496495
}
497496
break;
498497

@@ -501,7 +500,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
501500
if (!mp_parse_node_get_int_maybe(node, &object)) {
502501
emit_inline_rv32_error_exc(emit,
503502
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
504-
ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_integer));
503+
ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_integer));
505504
return false;
506505
}
507506

@@ -520,15 +519,15 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
520519
goto zero_immediate;
521520
}
522521

523-
return true;
522+
serialised_value = immediate;
524523
}
525524
break;
526525

527526
case L: {
528527
if (!MP_PARSE_NODE_IS_ID(node)) {
529528
emit_inline_rv32_error_exc(emit,
530529
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
531-
ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_label));
530+
ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_label));
532531
return false;
533532
}
534533

@@ -538,7 +537,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
538537
emit_inline_rv32_error_exc(emit,
539538
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
540539
MP_ERROR_TEXT("opcode '%q' argument %d: undefined label '%q'"),
541-
opcode_qstr, node_index + 1, qstring));
540+
opcode->qstring, node_index + 1, qstring));
542541
return false;
543542
}
544543

@@ -552,27 +551,33 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr,
552551
goto out_of_range;
553552
}
554553
}
555-
return true;
554+
555+
serialised_value = displacement;
556556
}
557557
break;
558558

559559
default:
560560
assert(!"Unknown argument kind");
561+
MP_UNREACHABLE;
561562
break;
562563
}
563564

564-
return false;
565+
if (serialised != NULL) {
566+
*serialised = serialised_value;
567+
}
568+
569+
return true;
565570

566571
out_of_range:
567572
emit_inline_rv32_error_exc(emit,
568-
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, node_index + 1));
573+
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode->qstring, node_index + 1));
569574
return false;
570575

571576
zero_immediate:
572577
emit_inline_rv32_error_exc(emit,
573578
mp_obj_new_exception_msg_varg(&mp_type_SyntaxError,
574579
MP_ERROR_TEXT("opcode '%q' argument %d: must not be zero"),
575-
opcode_qstr, node_index + 1));
580+
opcode->qstring, node_index + 1));
576581
return false;
577582
}
578583

@@ -618,14 +623,14 @@ static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr
618623
return false;
619624
}
620625
} else {
621-
if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 1)) {
626+
if (!serialise_argument(emit, opcode_data, node_struct->nodes[0], 1, NULL)) {
622627
return false;
623628
}
624629
}
625630

626631
*offset_node = node_struct->nodes[0];
627632
node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1];
628-
if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 2)) {
633+
if (!serialise_argument(emit, opcode_data, node_struct->nodes[0], 2, NULL)) {
629634
return false;
630635
}
631636
*register_node = node_struct->nodes[0];
@@ -638,115 +643,58 @@ static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr
638643
return false;
639644
}
640645

641-
static void handle_opcode(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *arguments) {
642-
mp_uint_t rd = 0;
643-
mp_uint_t rs1 = 0;
644-
mp_uint_t rs2 = 0;
645-
646+
static void handle_opcode(emit_inline_asm_t *emit, const opcode_t *opcode_data, mp_uint_t *arguments) {
646647
switch (opcode_data->calling_convention) {
647-
case CALL_RRR: {
648-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
649-
parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
650-
parse_register_node(arguments[2], &rs2, opcode_data->argument3_kind & C);
651-
((call_rrr_t)opcode_data->emitter)(&emit->as, rd, rs1, rs2);
648+
case CALL_RRR:
649+
((call_rrr_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]);
652650
break;
653-
}
654651

655-
case CALL_RR: {
656-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
657-
parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
658-
((call_rr_t)opcode_data->emitter)(&emit->as, rd, rs1);
652+
case CALL_RR:
653+
((call_rr_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1]);
659654
break;
660-
}
661655

662-
case CALL_RRI: {
663-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
664-
parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
665-
mp_obj_t object;
666-
mp_parse_node_get_int_maybe(arguments[2], &object);
667-
mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift;
668-
((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate);
656+
case CALL_RRI:
657+
((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]);
669658
break;
670-
}
671659

672-
case CALL_RI: {
673-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
674-
mp_obj_t object;
675-
mp_parse_node_get_int_maybe(arguments[1], &object);
676-
mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift;
677-
((call_ri_t)opcode_data->emitter)(&emit->as, rd, immediate);
660+
case CALL_RI:
661+
((call_ri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1]);
678662
break;
679-
}
680663

681-
case CALL_R: {
682-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
683-
((call_r_t)opcode_data->emitter)(&emit->as, rd);
664+
case CALL_R:
665+
((call_r_t)opcode_data->emitter)(&emit->as, arguments[0]);
684666
break;
685-
}
686667

687-
case CALL_RRL: {
688-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
689-
parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C);
690-
qstr qstring;
691-
mp_uint_t label_index = lookup_label(emit, arguments[2], &qstring);
692-
ptrdiff_t displacement = label_code_offset(emit, label_index);
693-
((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, displacement);
668+
case CALL_RRL:
669+
((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], (ptrdiff_t)arguments[2]);
694670
break;
695-
}
696671

697-
case CALL_RL: {
698-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
699-
qstr qstring;
700-
mp_uint_t label_index = lookup_label(emit, arguments[1], &qstring);
701-
ptrdiff_t displacement = label_code_offset(emit, label_index);
702-
((call_ri_t)opcode_data->emitter)(&emit->as, rd, displacement);
672+
case CALL_RL:
673+
((call_ri_t)opcode_data->emitter)(&emit->as, arguments[0], (ptrdiff_t)arguments[1]);
703674
break;
704-
}
705675

706-
case CALL_L: {
707-
qstr qstring;
708-
mp_uint_t label_index = lookup_label(emit, arguments[0], &qstring);
709-
ptrdiff_t displacement = label_code_offset(emit, label_index);
710-
((call_i_t)opcode_data->emitter)(&emit->as, displacement);
676+
case CALL_L:
677+
((call_i_t)opcode_data->emitter)(&emit->as, (ptrdiff_t)arguments[0]);
711678
break;
712-
}
713679

714680
case CALL_N:
715681
((call_n_t)opcode_data->emitter)(&emit->as);
716682
break;
717683

718-
case CALL_I: {
719-
mp_obj_t object;
720-
mp_parse_node_get_int_maybe(arguments[0], &object);
721-
mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument1_shift;
722-
((call_i_t)opcode_data->emitter)(&emit->as, immediate);
723-
break;
724-
}
725-
726-
case CALL_RII: {
727-
parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C);
728-
mp_obj_t object;
729-
mp_parse_node_get_int_maybe(arguments[1], &object);
730-
mp_uint_t immediate1 = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift;
731-
mp_parse_node_get_int_maybe(arguments[2], &object);
732-
mp_uint_t immediate2 = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift;
733-
((call_rii_t)opcode_data->emitter)(&emit->as, rd, immediate1, immediate2);
734-
break;
735-
}
736-
737-
case CALL_RIR:
738-
assert(!"Should not get here.");
684+
case CALL_RII:
685+
((call_rii_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]);
739686
break;
740687

741688
default:
742689
assert(!"Unhandled call convention.");
690+
MP_UNREACHABLE;
743691
break;
744692
}
745693
}
746694

747695
static bool handle_load_store_opcode_with_offset(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *argument_nodes) {
748696
mp_parse_node_t nodes[3] = {0};
749-
if (!validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) {
697+
if (!serialise_argument(emit, opcode_data, argument_nodes[0], 0, NULL)) {
750698
return false;
751699
}
752700
nodes[0] = argument_nodes[0];
@@ -806,16 +754,17 @@ static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uin
806754
ET_WRONG_ARGUMENTS_COUNT, opcode, opcode_data->arguments_count));
807755
return;
808756
}
809-
if (opcode_data->arguments_count >= 1 && !validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) {
757+
mp_uint_t serialised_arguments[3] = { 0 };
758+
if (opcode_data->arguments_count >= 1 && !serialise_argument(emit, opcode_data, argument_nodes[0], 0, &serialised_arguments[0])) {
810759
return;
811760
}
812-
if (opcode_data->arguments_count >= 2 && !validate_argument(emit, opcode, opcode_data, argument_nodes[1], 1)) {
761+
if (opcode_data->arguments_count >= 2 && !serialise_argument(emit, opcode_data, argument_nodes[1], 1, &serialised_arg 4861 uments[1])) {
813762
return;
814763
}
815-
if (opcode_data->arguments_count >= 3 && !validate_argument(emit, opcode, opcode_data, argument_nodes[2], 2)) {
764+
if (opcode_data->arguments_count >= 3 && !serialise_argument(emit, opcode_data, argument_nodes[2], 2, &serialised_arguments[2])) {
816765
return;
817766
}
818-
handle_opcode(emit, opcode, opcode_data, argument_nodes);
767+
handle_opcode(emit, opcode_data, serialised_arguments);
819768
return;
820769
}
821770

0 commit comments

Comments
 (0)
0