5
5
6
6
#include <assert.h>
7
7
#include <stdbool.h>
8
+ #include <stdint.h>
8
9
#include <stdio.h>
9
10
#include <stdlib.h>
10
11
#include <string.h>
@@ -30,6 +31,7 @@ extern struct target_ops gdbstub_ops;
30
31
#endif
31
32
32
33
#include "decode.h"
34
+ #include "mpool.h"
33
35
#include "riscv.h"
34
36
#include "riscv_private.h"
35
37
#include "state.h"
@@ -277,16 +279,17 @@ static inline uint32_t hash(size_t k)
277
279
return k ;
278
280
}
279
281
282
+ static void block_translate (riscv_t * rv , block_map_t * map , block_t * block );
280
283
/* allocate a basic block */
281
- static block_t * block_alloc (const uint8_t bits )
284
+ static block_t * block_alloc (riscv_t * rv , block_map_t * map )
282
285
{
283
- block_t * block = malloc ( sizeof ( struct block ) );
286
+ block_t * block = mpool_alloc ( map -> block_mp );
284
287
assert (block );
285
- block -> insn_capacity = 1 << bits ;
286
288
block -> n_insn = 0 ;
287
289
block -> predict = NULL ;
288
- block -> ir = malloc (block -> insn_capacity * sizeof (rv_insn_t ));
289
- assert (block -> ir );
290
+
291
+ /* Initialize remaining part of block_t */
292
+ block_translate (rv , map , block );
290
293
return block ;
291
294
}
292
295
@@ -366,7 +369,7 @@ static uint32_t last_pc = 0;
366
369
rv->PC += ir->insn_len; \
367
370
if (unlikely(RVOP_NO_NEXT(ir))) \
368
371
return true; \
369
- const rv_insn_t *next = ir + 1; \
372
+ const rv_insn_t *next = ir->next; \
370
373
MUST_TAIL return next->impl(rv, next); \
371
374
}
372
375
@@ -395,36 +398,47 @@ enum {
395
398
#undef _
396
399
};
397
400
401
+ /* FIXME: This will simply find the n-th instruction by iterating
402
+ * the linked list linearly, we may want to find better approach. */
403
+ FORCE_INLINE rv_insn_t * next_nth_insn (rv_insn_t * ir , int32_t n )
404
+ {
405
+ rv_insn_t * tmp = ir ;
406
+ for (int32_t iter = 0 ; iter < n ; iter ++ )
407
+ tmp = tmp -> next ;
408
+ return tmp ;
409
+ }
410
+
398
411
/* multiple lui */
399
- static bool do_fuse1 (riscv_t * rv , const rv_insn_t * ir )
412
+ static bool do_fuse1 (riscv_t * rv , rv_insn_t * ir )
400
413
{
401
414
rv -> csr_cycle += ir -> imm2 ;
402
- for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
403
- const rv_insn_t * cur_ir = ir + i ;
415
+ int i ;
416
+ rv_insn_t * cur_ir ;
417
+ for (i = 0 , cur_ir = ir ; i < ir -> imm2 ; i ++ , cur_ir = cur_ir -> next ) {
404
418
rv -> X [cur_ir -> rd ] = cur_ir -> imm ;
405
419
}
406
420
rv -> PC += ir -> imm2 * ir -> insn_len ;
407
421
if (unlikely (RVOP_NO_NEXT (ir )))
408
422
return true;
409
- const rv_insn_t * next = ir + ir -> imm2 ;
423
+ const rv_insn_t * next = next_nth_insn ( ir , ir -> imm2 ) ;
410
424
MUST_TAIL return next -> impl (rv , next );
411
425
}
412
426
413
427
/* LUI + ADD */
414
- static bool do_fuse2 (riscv_t * rv , const rv_insn_t * ir )
428
+ static bool do_fuse2 (riscv_t * rv , rv_insn_t * ir )
415
429
{
416
430
rv -> csr_cycle += 2 ;
417
431
rv -> X [ir -> rd ] = ir -> imm ;
418
432
rv -> X [ir -> rs2 ] = rv -> X [ir -> rd ] + rv -> X [ir -> rs1 ];
419
433
rv -> PC += 2 * ir -> insn_len ;
420
434
if (unlikely (RVOP_NO_NEXT (ir )))
421
435
return true;
422
- const rv_insn_t * next = ir + 2 ;
436
+ const rv_insn_t * next = next_nth_insn ( ir , 2 ) ;
423
437
MUST_TAIL return next -> impl (rv , next );
424
438
}
425
439
426
440
/* multiple SW */
427
- static bool do_fuse3 (riscv_t * rv , const rv_insn_t * ir )
441
+ static bool do_fuse3 (riscv_t * rv , rv_insn_t * ir )
428
442
{
429
443
rv -> csr_cycle += ir -> imm2 ;
430
444
opcode_fuse_t * fuse = ir -> fuse ;
@@ -442,12 +456,12 @@ static bool do_fuse3(riscv_t *rv, const rv_insn_t *ir)
442
456
rv -> PC += ir -> imm2 * ir -> insn_len ;
443
457
if (unlikely (RVOP_NO_NEXT (ir )))
444
458
return true;
445
- const rv_insn_t * next = ir + ir -> imm2 ;
459
+ const rv_insn_t * next = next_nth_insn ( ir , ir -> imm2 ) ;
446
460
MUST_TAIL return next -> impl (rv , next );
447
461
}
448
462
449
463
/* multiple LW */
450
- static bool do_fuse4 (riscv_t * rv , const rv_insn_t * ir )
464
+ static bool do_fuse4 (riscv_t * rv , rv_insn_t * ir )
451
465
{
452
466
rv -> csr_cycle += ir -> imm2 ;
453
467
opcode_fuse_t * fuse = ir -> fuse ;
@@ -465,7 +479,7 @@ static bool do_fuse4(riscv_t *rv, const rv_insn_t *ir)
465
479
rv -> PC += ir -> imm2 * ir -> insn_len ;
466
480
if (unlikely (RVOP_NO_NEXT (ir )))
467
481
return true;
468
- const rv_insn_t * next = ir + ir -> imm2 ;
482
+ const rv_insn_t * next = next_nth_insn ( ir , ir -> imm2 ) ;
469
483
MUST_TAIL return next -> impl (rv , next );
470
484
}
471
485
@@ -479,7 +493,7 @@ static bool do_fuse5(riscv_t *rv, const rv_insn_t *ir)
479
493
rv -> PC = rv -> X [rv_reg_ra ] & ~1U ;
480
494
if (unlikely (RVOP_NO_NEXT (ir )))
481
495
return true;
482
- const rv_insn_t * next = ir + 1 ;
496
+ const rv_insn_t * next = ir -> next ;
483
497
MUST_TAIL return next -> impl (rv , next );
484
498
}
485
499
@@ -493,7 +507,7 @@ static bool do_fuse6(riscv_t *rv, const rv_insn_t *ir)
493
507
rv -> PC = rv -> X [rv_reg_ra ] & ~1U ;
494
508
if (unlikely (RVOP_NO_NEXT (ir )))
495
509
return true;
496
- const rv_insn_t * next = ir + 1 ;
510
+ const rv_insn_t * next = ir -> next ;
497
511
MUST_TAIL return next -> impl (rv , next );
498
512
}
499
513
@@ -541,15 +555,21 @@ FORCE_INLINE bool insn_is_unconditional_branch(uint8_t opcode)
541
555
return false;
542
556
}
543
557
544
- static void block_translate (riscv_t * rv , block_t * block )
558
+ static void block_translate (riscv_t * rv , block_map_t * map , block_t * block )
545
559
{
546
560
block -> pc_start = block -> pc_end = rv -> PC ;
547
561
562
+ rv_insn_t * prev_ir = NULL ;
563
+ rv_insn_t * ir = mpool_alloc (map -> block_ir_mp );
564
+ block -> ir_head = ir ;
565
+
548
566
/* translate the basic block */
549
- while (block -> n_insn < block -> insn_capacity ) {
550
- rv_insn_t * ir = block -> ir + block -> n_insn ;
567
+ while (true) {
551
568
memset (ir , 0 , sizeof (rv_insn_t ));
552
569
570
+ if (prev_ir )
571
+ prev_ir -> next = ir ;
572
+
553
573
/* fetch the next instruction */
554
574
const uint32_t insn = rv -> io .mem_ifetch (block -> pc_end );
555
575
@@ -564,21 +584,29 @@ static void block_translate(riscv_t *rv, block_t *block)
564
584
/* compute the end of pc */
565
585
block -> pc_end += ir -> insn_len ;
566
586
block -> n_insn ++ ;
587
+ prev_ir = ir ;
567
588
/* stop on branch */
568
589
if (insn_is_branch (ir -> opcode ))
569
590
break ;
591
+
592
+ ir = mpool_alloc (map -> block_ir_mp );
570
593
}
571
- block -> ir [block -> n_insn - 1 ].tailcall = true;
594
+
595
+ assert (prev_ir );
596
+ block -> ir_tail = prev_ir ;
597
+ block -> ir_tail -> tailcall = true;
572
598
}
573
599
574
600
#define COMBINE_MEM_OPS (RW ) \
575
601
count = 1; \
576
- next_ir = ir + 1; \
602
+ next_ir = ir->next; \
603
+ tmp_ir = next_ir; \
577
604
if (next_ir->opcode != IIF(RW)(rv_insn_lw, rv_insn_sw)) \
578
605
break; \
579
606
sign = (ir->imm - next_ir->imm) >> 31 ? -1 : 1; \
580
- for (uint32_t j = 1; j < block->n_insn - 1 - i; j++) { \
581
- next_ir = ir + j; \
607
+ next_ir = tmp_ir; \
608
+ for (uint32_t j = 1; j < block->n_insn - 1 - i; \
609
+ j++, next_ir = next_ir->next) { \
582
610
if (next_ir->opcode != IIF(RW)(rv_insn_lw, rv_insn_sw) || \
583
611
ir->rs1 != next_ir->rs1 || ir->imm - next_ir->imm != 4 * sign) \
584
612
break; \
@@ -590,8 +618,8 @@ static void block_translate(riscv_t *rv, block_t *block)
590
618
ir->imm2 = count; \
591
619
memcpy(ir->fuse, ir, sizeof(opcode_fuse_t)); \
592
620
ir->impl = dispatch_table[ir->opcode]; \
593
- for (int j = 1; j < count; j++) { \
594
- next_ir = ir + j; \
621
+ next_ir = tmp_ir; \
622
+ for (int j = 1; j < count; j++, next_ir = next_ir->next) { \
595
623
memcpy(ir->fuse + j, next_ir, sizeof(opcode_fuse_t)); \
596
624
} \
597
625
ir->tailcall = next_ir->tailcall; \
@@ -825,7 +853,7 @@ static bool detect_memcpy(riscv_t *rv, int lib)
825
853
826
854
static bool libc_substitute (riscv_t * rv , block_t * block )
827
855
{
828
- rv_insn_t * ir = block -> ir , * next_ir = NULL ;
856
+ rv_insn_t * ir = block -> ir_head , * next_ir = NULL ;
829
857
switch (ir -> opcode ) {
830
858
case rv_insn_addi :
831
859
/* Compare the target block with the first basic block of
@@ -835,10 +863,10 @@ static bool libc_substitute(riscv_t *rv, block_t *block)
835
863
* instruction sequence.
836
864
*/
837
865
if (ir -> imm == 15 && ir -> rd == rv_reg_t1 && ir -> rs1 == rv_reg_zero ) {
838
- next_ir = ir + 1 ;
866
+ next_ir = ir -> next ;
839
867
if (next_ir -> opcode == rv_insn_addi && next_ir -> rd == rv_reg_a4 &&
840
868
next_ir -> rs1 == rv_reg_a0 && next_ir -> rs2 == rv_reg_zero ) {
841
- next_ir = next_ir + 1 ;
869
+ next_ir = next_ir -> next ;
842
870
if (next_ir -> opcode == rv_insn_bgeu && next_ir -> imm == 60 &&
843
871
next_ir -> rs1 == rv_reg_t1 && next_ir -> rs2 == rv_reg_a2 ) {
844
872
if (detect_memset (rv , 1 )) {
@@ -851,7 +879,7 @@ static bool libc_substitute(riscv_t *rv, block_t *block)
851
879
}
852
880
} else if (ir -> imm == 0 && ir -> rd == rv_reg_t1 &&
853
881
ir -> rs1 == rv_reg_a0 ) {
854
- next_ir = ir + 1 ;
882
+ next_ir = ir -> next ;
855
883
if (next_ir -> opcode == rv_insn_beq && next_ir -> rs1 == rv_reg_a2 &&
856
884
next_ir -> rs2 == rv_reg_zero ) {
857
885
if (next_ir -> imm == 20 && detect_memset (rv , 2 )) {
@@ -876,14 +904,14 @@ static bool libc_substitute(riscv_t *rv, block_t *block)
876
904
*/
877
905
if (ir -> rd == rv_reg_a5 && ir -> rs1 == rv_reg_a0 &&
878
906
ir -> rs2 == rv_reg_a1 ) {
879
- next_ir = ir + 1 ;
907
+ next_ir = ir -> next ;
880
908
if (next_ir -> opcode == rv_insn_andi && next_ir -> imm == 3 &&
881
909
next_ir -> rd == rv_reg_a5 && next_ir -> rs1 == rv_reg_a5 ) {
882
- next_ir = next_ir + 1 ;
910
+ next_ir = next_ir -> next ;
883
911
if (next_ir -> opcode == rv_insn_add &&
884
912
next_ir -> rd == rv_reg_a7 && next_ir -> rs1 == rv_reg_a0 &&
885
913
next_ir -> rs2 == rv_reg_a2 ) {
886
- next_ir = next_ir + 1 ;
914
+ next_ir = next_ir -> next ;
887
915
if (next_ir -> opcode == rv_insn_bne && next_ir -> imm == 104 &&
888
916
next_ir -> rs1 == rv_reg_a5 &&
889
917
next_ir -> rs2 == rv_reg_zero ) {
@@ -912,12 +940,15 @@ static bool libc_substitute(riscv_t *rv, block_t *block)
912
940
*/
913
941
static void match_pattern (block_t * block )
914
942
{
915
- for (uint32_t i = 0 ; i < block -> n_insn - 1 ; i ++ ) {
916
- rv_insn_t * ir = block -> ir + i , * next_ir = NULL ;
943
+ uint32_t i ;
944
+ rv_insn_t * ir ;
945
+ for (i = 0 , ir = block -> ir_head ; i < block -> n_insn - 1 ;
946
+ i ++ , ir = ir -> next ) {
947
+ rv_insn_t * next_ir = NULL , * tmp_ir = NULL ;
917
948
int32_t count = 0 , sign = 1 ;
918
949
switch (ir -> opcode ) {
919
950
case rv_insn_lui :
920
- next_ir = ir + 1 ;
951
+ next_ir = ir -> next ;
921
952
switch (next_ir -> opcode ) {
922
953
case rv_insn_add :
923
954
if (ir -> rd == next_ir -> rs2 || ir -> rd == next_ir -> rs1 ) {
@@ -940,7 +971,7 @@ static void match_pattern(block_t *block)
940
971
count ++ ;
941
972
if (next_ir -> tailcall )
942
973
break ;
943
- next_ir ++ ;
974
+ next_ir = next_ir -> next ;
944
975
}
945
976
ir -> imm2 = count ;
946
977
ir -> opcode = rv_insn_fuse1 ;
@@ -994,8 +1025,10 @@ static void optimize_constant(riscv_t *rv, block_t *block)
994
1025
constopt_info_t constopt_info = {0 };
995
1026
constopt_info .is_constant [0 ] = true;
996
1027
assert (rv -> X [0 ] == 0 );
997
- for (uint32_t i = 0 ; i < block -> n_insn ; i ++ ) {
998
- rv_insn_t * ir = block -> ir + i ;
1028
+
1029
+ uint32_t i ;
1030
+ rv_insn_t * ir ;
1031
+ for (i = 0 , ir = block -> ir_head ; i < block -> n_insn ; i ++ , ir = ir -> next ) {
999
1032
((constopt_func_t ) constopt_table [ir -> opcode ])(ir , & constopt_info );
1000
1033
}
1001
1034
}
@@ -1014,10 +1047,7 @@ static block_t *block_find_or_translate(riscv_t *rv)
1014
1047
}
1015
1048
1016
1049
/* allocate a new block */
1017
- next = block_alloc (10 );
1018
-
1019
- /* translate the basic block */
1020
- block_translate (rv , next );
1050
+ next = block_alloc (rv , map );
1021
1051
1022
1052
if (!libc_substitute (rv , next )) {
1023
1053
optimize_constant (rv , next );
@@ -1075,27 +1105,27 @@ void rv_step(riscv_t *rv, int32_t cycles)
1075
1105
if (prev -> pc_start != last_pc )
1076
1106
prev = block_find (& rv -> block_map , last_pc );
1077
1107
1078
- rv_insn_t * last_ir = prev -> ir + prev -> n_insn - 1 ;
1108
+ rv_insn_t * last_ir = prev -> ir_tail ;
1079
1109
/* chain block */
1080
1110
if (!insn_is_unconditional_branch (last_ir -> opcode )) {
1081
1111
if (branch_taken && !last_ir -> branch_taken )
1082
- last_ir -> branch_taken = block -> ir ;
1112
+ last_ir -> branch_taken = block -> ir_head ;
1083
1113
else if (!last_ir -> branch_untaken )
1084
- last_ir -> branch_untaken = block -> ir ;
1114
+ last_ir -> branch_untaken = block -> ir_head ;
1085
1115
} else if (last_ir -> opcode == rv_insn_jal
1086
1116
#if RV32_HAS (EXT_C )
1087
1117
|| last_ir -> opcode == rv_insn_cj ||
1088
1118
last_ir -> opcode == rv_insn_cjal
1089
1119
#endif
1090
1120
) {
1091
1121
if (!last_ir -> branch_taken )
1092
- last_ir -> branch_taken = block -> ir ;
1122
+ last_ir -> branch_taken = block -> ir_head ;
1093
1123
}
1094
1124
}
1095
1125
last_pc = rv -> PC ;
1096
1126
1097
1127
/* execute the block */
1098
- const rv_insn_t * ir = block -> ir ;
1128
+ const rv_insn_t * ir = block -> ir_head ;
1099
1129
if (unlikely (!ir -> impl (rv , ir )))
1100
1130
break ;
1101
1131
0 commit comments