Skip to content

Commit 8b3a4af

Browse files
authored
Merge pull request #331 from qwe661234/link_BB
Enforce doubly-linked chained block
2 parents 71053f1 + e266b69 commit 8b3a4af

File tree

7 files changed

+164
-141
lines changed

7 files changed

+164
-141
lines changed

src/cache.c

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ static struct mpool *cache_mp;
2727
/* hash function for the cache */
2828
HASH_FUNC_IMPL(cache_hash, cache_size_bits, cache_size)
2929

30-
struct list_head {
31-
struct list_head *prev, *next;
32-
};
33-
3430
struct hlist_head {
3531
struct hlist_node *first;
3632
};
@@ -58,64 +54,6 @@ typedef struct cache {
5854
uint32_t capacity;
5955
} cache_t;
6056

61-
static inline void INIT_LIST_HEAD(struct list_head *head)
62-
{
63-
head->next = head;
64-
head->prev = head;
65-
}
66-
67-
static inline int list_empty(const struct list_head *head)
68-
{
69-
return (head->next == head);
70-
}
71-
72-
static inline void list_add(struct list_head *node, struct list_head *head)
73-
{
74-
struct list_head *next = head->next;
75-
76-
next->prev = node;
77-
node->next = next;
78-
node->prev = head;
79-
head->next = node;
80-
}
81-
82-
static inline void list_del(struct list_head *node)
83-
{
84-
struct list_head *next = node->next;
85-
struct list_head *prev = node->prev;
86-
87-
next->prev = prev;
88-
prev->next = next;
89-
}
90-
91-
static inline void list_del_init(struct list_head *node)
92-
{
93-
list_del(node);
94-
INIT_LIST_HEAD(node);
95-
}
96-
97-
#define list_entry(node, type, member) container_of(node, type, member)
98-
99-
#define list_first_entry(head, type, member) \
100-
list_entry((head)->next, type, member)
101-
102-
#define list_last_entry(head, type, member) \
103-
list_entry((head)->prev, type, member)
104-
105-
#ifdef __HAVE_TYPEOF
106-
#define list_for_each_entry_safe(entry, safe, head, member) \
107-
for (entry = list_entry((head)->next, __typeof__(*entry), member), \
108-
safe = list_entry(entry->member.next, __typeof__(*entry), member); \
109-
&entry->member != (head); entry = safe, \
110-
safe = list_entry(safe->member.next, __typeof__(*entry), member))
111-
#else
112-
#define list_for_each_entry_safe(entry, safe, head, member, type) \
113-
for (entry = list_entry((head)->next, type, member), \
114-
safe = list_entry(entry->member.next, type, member); \
115-
&entry->member != (head); \
116-
entry = safe, safe = list_entry(safe->member.next, type, member))
117-
#endif
118-
11957
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
12058

12159
static inline void INIT_HLIST_NODE(struct hlist_node *h)

src/emulate.c

Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,11 @@ static block_t *block_alloc(riscv_t *rv)
301301
block_t *block = mpool_alloc(rv->block_mp);
302302
assert(block);
303303
block->n_insn = 0;
304-
block->predict = NULL;
305304
#if RV32_HAS(JIT)
306305
block->translatable = true;
307306
block->hot = false;
308307
block->backward = false;
308+
INIT_LIST_HEAD(&block->list);
309309
#endif
310310
return block;
311311
}
@@ -979,6 +979,49 @@ static block_t *block_find_or_translate(riscv_t *rv)
979979
/* insert the block into block cache */
980980
block_t *delete_target = cache_put(rv->block_cache, rv->PC, &(*next));
981981
if (delete_target) {
982+
if (prev == delete_target)
983+
prev = NULL;
984+
chain_entry_t *entry, *safe;
985+
/* correctly remove deleted block from its chained block */
986+
rv_insn_t *taken = delete_target->ir_tail->branch_taken,
987+
*untaken = delete_target->ir_tail->branch_untaken;
988+
if (taken && taken->pc != delete_target->pc_start) {
989+
block_t *target = cache_get(rv->block_cache, taken->pc);
990+
bool flag = false;
991+
list_for_each_entry_safe (entry, safe, &target->list, list) {
992+
if (entry->block == delete_target) {
993+
list_del_init(&entry->list);
994+
mpool_free(rv->chain_entry_mp, entry);
995+
flag = true;
996+
}
997+
}
998+
assert(flag);
999+
}
1000+
if (untaken && untaken->pc != delete_target->pc_start) {
1001+
block_t *target = cache_get(rv->block_cache, untaken->pc);
1002+
assert(target);
1003+
bool flag = false;
1004+
list_for_each_entry_safe (entry, safe, &target->list, list) {
1005+
if (entry->block == delete_target) {
1006+
list_del_init(&entry->list);
1007+
mpool_free(rv->chain_entry_mp, entry);
1008+
flag = true;
1009+
}
1010+
}
1011+
assert(flag);
1012+
}
1013+
/* correctly remove deleted block from the block chained to it */
1014+
list_for_each_entry_safe (entry, safe, &delete_target->list, list) {
1015+
if (entry->block == delete_target)
1016+
continue;
1017+
rv_insn_t *target = entry->block->ir_tail;
1018+
if (target->branch_taken == delete_target->ir_head)
1019+
target->branch_taken = NULL;
1020+
else if (target->branch_untaken == delete_target->ir_head)
1021+
target->branch_untaken = NULL;
1022+
mpool_free(rv->chain_entry_mp, entry);
1023+
}
1024+
/* free deleted block */
9821025
uint32_t idx;
9831026
rv_insn_t *ir, *next;
9841027
for (idx = 0, ir = delete_target->ir_head;
@@ -990,13 +1033,6 @@ static block_t *block_find_or_translate(riscv_t *rv)
9901033
mpool_free(rv->block_mp, delete_target);
9911034
}
9921035
#endif
993-
/* update the block prediction.
994-
* When translating a new block, the block predictor may benefit,
995-
* but updating it after finding a particular block may penalize
996-
* significantly.
997-
*/
998-
if (prev)
999-
prev->predict = next;
10001036
}
10011037

10021038
return next;
@@ -1015,17 +1051,18 @@ void rv_step(riscv_t *rv, int32_t cycles)
10151051

10161052
/* loop until hitting the cycle target */
10171053
while (rv->csr_cycle < cycles_target && !rv->halt) {
1018-
block_t *block;
1019-
/* try to predict the next block */
1020-
if (prev && prev->predict && prev->predict->pc_start == rv->PC) {
1021-
block = prev->predict;
1022-
} else {
1023-
/* lookup the next block in block map or translate a new block,
1024-
* and move onto the next block.
1025-
*/
1026-
block = block_find_or_translate(rv);
1054+
if (prev && prev->pc_start != last_pc) {
1055+
/* update previous block */
1056+
#if !RV32_HAS(JIT)
1057+
prev = block_find(&rv->block_map, last_pc);
1058+
#else
1059+
prev = cache_get(rv->block_cache, last_pc);
1060+
#endif
10271061
}
1028-
1062+
/* lookup the next block in block map or translate a new block,
1063+
* and move onto the next block.
1064+
*/
1065+
block_t *block = block_find_or_translate(rv);
10291066
/* by now, a block should be available */
10301067
assert(block);
10311068

@@ -1034,28 +1071,38 @@ void rv_step(riscv_t *rv, int32_t cycles)
10341071
* assigned to either the branch_taken or branch_untaken pointer of
10351072
* the previous block.
10361073
*/
1074+
10371075
if (prev) {
1038-
/* update previous block */
1039-
if (prev->pc_start != last_pc)
1040-
#if !RV32_HAS(JIT)
1041-
prev = block_find(&rv->block_map, last_pc);
1042-
#else
1043-
prev = cache_get(rv->block_cache, last_pc);
1076+
rv_insn_t *last_ir = prev->ir_tail;
1077+
/* chain block */
1078+
if (!insn_is_unconditional_branch(last_ir->opcode)) {
1079+
if (is_branch_taken && !last_ir->branch_taken) {
1080+
last_ir->branch_taken = block->ir_head;
1081+
#if RV32_HAS(JIT)
1082+
chain_entry_t *new_entry = mpool_alloc(rv->chain_entry_mp);
1083+
new_entry->block = prev;
1084+
list_add(&new_entry->list, &block->list);
10441085
#endif
1045-
if (prev) {
1046-
rv_insn_t *last_ir = prev->ir_tail;
1047-
/* chain block */
1048-
if (!insn_is_unconditional_branch(last_ir->opcode)) {
1049-
if (is_branch_taken)
1050-
last_ir->branch_taken = block->ir_head;
1051-
else if (!is_branch_taken)
1052-
last_ir->branch_untaken = block->ir_head;
1053-
} else if (IF_insn(last_ir, jal)
1086+
} else if (!is_branch_taken && !last_ir->branch_untaken) {
1087+
last_ir->branch_untaken = block->ir_head;
1088+
#if RV32_HAS(JIT)
1089+
chain_entry_t *new_entry = mpool_alloc(rv->chain_entry_mp);
1090+
new_entry->block = prev;
1091+
list_add(&new_entry->list, &block->list);
1092+
#endif
1093+
}
1094+
} else if (IF_insn(last_ir, jal)
10541095
#if RV32_HAS(EXT_C)
1055-
|| IF_insn(last_ir, cj) || IF_insn(last_ir, cjal)
1096+
|| IF_insn(last_ir, cj) || IF_insn(last_ir, cjal)
10561097
#endif
1057-
) {
1098+
) {
1099+
if (!last_ir->branch_taken) {
10581100
last_ir->branch_taken = block->ir_head;
1101+
#if RV32_HAS(JIT)
1102+
chain_entry_t *new_entry = mpool_alloc(rv->chain_entry_mp);
1103+
new_entry->block = prev;
1104+
list_add(&new_entry->list, &block->list);
1105+
#endif
10591106
}
10601107
}
10611108
}

src/jit.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,14 +1496,14 @@ static void translate_chained_block(struct jit_state *state,
14961496
offset_map_insert(state, block->pc_start);
14971497
translate(state, rv, block);
14981498
rv_insn_t *ir = block->ir_tail;
1499-
if (ir->branch_untaken && !set_has(set, ir->pc + 4)) {
1500-
block_t *block1 = cache_get(rv->block_cache, ir->pc + 4);
1501-
if (block1 && block1->translatable)
1499+
if (ir->branch_untaken && !set_has(set, ir->branch_untaken->pc)) {
1500+
block_t *block1 = cache_get(rv->block_cache, ir->branch_untaken->pc);
1501+
if (block1->translatable)
15021502
translate_chained_block(state, rv, block1, set);
15031503
}
1504-
if (ir->branch_taken && !set_has(set, ir->pc + ir->imm)) {
1505-
block_t *block1 = cache_get(rv->block_cache, ir->pc + ir->imm);
1506-
if (block1 && block1->translatable)
1504+
if (ir->branch_taken && !set_has(set, ir->branch_taken->pc)) {
1505+
block_t *block1 = cache_get(rv->block_cache, ir->branch_taken->pc);
1506+
if (block1->translatable)
15071507
translate_chained_block(state, rv, block1, set);
15081508
}
15091509
}

src/riscv.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ riscv_t *rv_create(const riscv_io_t *io,
134134
/* initialize the block map */
135135
block_map_init(&rv->block_map, BLOCK_MAP_CAPACITY_BITS);
136136
#else
137+
rv->chain_entry_mp =
138+
mpool_create(sizeof(chain_entry_t) << BLOCK_IR_MAP_CAPACITY_BITS,
139+
sizeof(chain_entry_t));
137140
rv->jit_state = jit_state_init(CODE_CACHE_SIZE);
138141
rv->block_cache = cache_create(BLOCK_MAP_CAPACITY_BITS);
139142
assert(rv->block_cache);
@@ -165,6 +168,7 @@ void rv_delete(riscv_t *rv)
165168
#if !RV32_HAS(JIT)
166169
block_map_destroy(rv);
167170
#else
171+
mpool_destroy(rv->chain_entry_mp);
168172
jit_state_exit(rv->jit_state);
169173
cache_free(rv->block_cache);
170174
#endif

src/riscv_private.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#endif
1313
#include "decode.h"
1414
#include "riscv.h"
15+
#include "utils.h"
1516
#if RV32_HAS(JIT)
1617
#include "cache.h"
1718
#endif
@@ -59,7 +60,6 @@ enum {
5960
typedef struct block {
6061
uint32_t n_insn; /**< number of instructions encompased */
6162
uint32_t pc_start, pc_end; /**< address range of the basic block */
62-
struct block *predict; /**< block prediction */
6363

6464
rv_insn_t *ir_head, *ir_tail; /**< the first and last ir for this block */
6565
bool backward;
@@ -68,9 +68,17 @@ typedef struct block {
6868
uint32_t offset;
6969
bool
7070
translatable; /**< Determine the block has RV32AF insturctions or not */
71+
struct list_head list;
7172
#endif
7273
} block_t;
7374

75+
#if RV32_HAS(JIT)
76+
typedef struct {
77+
block_t *block;
78+
struct list_head list;
79+
} chain_entry_t;
80+
#endif
81+
7482
typedef struct {
7583
uint32_t block_capacity; /**< max number of entries in the block map */
7684
uint32_t size; /**< number of entries currently in the map */
@@ -117,6 +125,7 @@ struct riscv_internal {
117125
block_map_t block_map; /**< basic block map */
118126
#else
119127
struct cache *block_cache;
128+
struct mpool *chain_entry_mp;
120129
#endif
121130
struct mpool *block_mp, *block_ir_mp;
122131
/* print exit code on syscall_exit */

0 commit comments

Comments
 (0)