Skip to content

Commit 3612494

Browse files
committed
Doubly-link chained block
Previously, the chained block was a linear structure where previous block only pointed to the next block. Now, we have introduced additional information, allowing the next block to also reference the previous block. This modification enhance the deletion of replaced block. Close: #329
1 parent 3ebb25d commit 3612494

File tree

7 files changed

+164
-125
lines changed

7 files changed

+164
-125
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: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ static block_t *block_alloc(riscv_t *rv)
305305
block->translatable = true;
306306
block->hot = false;
307307
block->backward = false;
308+
INIT_LIST_HEAD(&block->list);
308309
#endif
309310
return block;
310311
}
@@ -978,6 +979,49 @@ static block_t *block_find_or_translate(riscv_t *rv)
978979
/* insert the block into block cache */
979980
block_t *delete_target = cache_put(rv->block_cache, rv->PC, &(*next));
980981
if (delete_target) {
982+
if (prev == delete_target)
983+
prev = NULL;
984+
chaining_entry_t *entry, *safe;
985+
/* correctly remove delete 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+
free(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+
free(entry);
1008+
flag = true;
1009+
}
1010+
}
1011+
assert(flag);
1012+
}
1013+
/* correctly remove delete 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+
free(entry);
1023+
}
1024+
/* free deleted block */
9811025
uint32_t idx;
9821026
rv_insn_t *ir, *next;
9831027
for (idx = 0, ir = delete_target->ir_head;
@@ -1007,12 +1051,18 @@ void rv_step(riscv_t *rv, int32_t cycles)
10071051

10081052
/* loop until hitting the cycle target */
10091053
while (rv->csr_cycle < cycles_target && !rv->halt) {
1010-
block_t *block;
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
1061+
}
10111062
/* lookup the next block in block map or translate a new block,
10121063
* and move onto the next block.
10131064
*/
1014-
block = block_find_or_translate(rv);
1015-
1065+
block_t *block = block_find_or_translate(rv);
10161066
/* by now, a block should be available */
10171067
assert(block);
10181068

@@ -1021,28 +1071,41 @@ void rv_step(riscv_t *rv, int32_t cycles)
10211071
* assigned to either the branch_taken or branch_untaken pointer of
10221072
* the previous block.
10231073
*/
1074+
10241075
if (prev) {
1025-
/* update previous block */
1026-
if (prev->pc_start != last_pc)
1027-
#if !RV32_HAS(JIT)
1028-
prev = block_find(&rv->block_map, last_pc);
1029-
#else
1030-
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+
chaining_entry_t *new_entry =
1083+
mpool_alloc(rv->chaining_entry_mp);
1084+
new_entry->block = prev;
1085+
list_add(&new_entry->list, &block->list);
10311086
#endif
1032-
if (prev) {
1033-
rv_insn_t *last_ir = prev->ir_tail;
1034-
/* chain block */
1035-
if (!insn_is_unconditional_branch(last_ir->opcode)) {
1036-
if (is_branch_taken)
1037-
last_ir->branch_taken = block->ir_head;
1038-
else if (!is_branch_taken)
1039-
last_ir->branch_untaken = block->ir_head;
1040-
} else if (IF_insn(last_ir, jal)
1087+
} else if (!is_branch_taken && !last_ir->branch_untaken) {
1088+
last_ir->branch_untaken = block->ir_head;
1089+
#if RV32_HAS(JIT)
1090+
chaining_entry_t *new_entry =
1091+
mpool_alloc(rv->chaining_entry_mp);
1092+
new_entry->block = prev;
1093+
list_add(&new_entry->list, &block->list);
1094+
#endif
1095+
}
1096+
} else if (IF_insn(last_ir, jal)
10411097
#if RV32_HAS(EXT_C)
1042-
|| IF_insn(last_ir, cj) || IF_insn(last_ir, cjal)
1098+
|| IF_insn(last_ir, cj) || IF_insn(last_ir, cjal)
10431099
#endif
1044-
) {
1100+
) {
1101+
if (!last_ir->branch_taken) {
10451102
last_ir->branch_taken = block->ir_head;
1103+
#if RV32_HAS(JIT)
1104+
chaining_entry_t *new_entry =
1105+
mpool_alloc(rv->chaining_entry_mp);
1106+
new_entry->block = prev;
1107+
list_add(&new_entry->list, &block->list);
1108+
#endif
10461109
}
10471110
}
10481111
}

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->chaining_entry_mp =
138+
mpool_create(sizeof(chaining_entry_t) << BLOCK_IR_MAP_CAPACITY_BITS,
139+
sizeof(chaining_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->chaining_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 & 0 deletions
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
@@ -67,9 +68,17 @@ typedef struct block {
6768
uint32_t offset;
6869
bool
6970
translatable; /**< Determine the block has RV32AF insturctions or not */
71+
struct list_head list;
7072
#endif
7173
} block_t;
7274

75+
#if RV32_HAS(JIT)
76+
typedef struct chaining_entry {
77+
block_t *block;
78+
struct list_head list;
79+
} chaining_entry_t;
80+
#endif
81+
7382
typedef struct {
7483
uint32_t block_capacity; /**< max number of entries in the block map */
7584
uint32_t size; /**< number of entries currently in the map */
@@ -116,6 +125,7 @@ struct riscv_internal {
116125
block_map_t block_map; /**< basic block map */
117126
#else
118127
struct cache *block_cache;
128+
struct mpool *chaining_entry_mp;
119129
#endif
120130
struct mpool *block_mp, *block_ir_mp;
121131
/* print exit code on syscall_exit */

src/rv32_template.c

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,6 @@ RVOP(
148148
struct rv_insn *taken = ir->branch_taken;
149149
if (taken) {
150150
#if RV32_HAS(JIT)
151-
block_t *block = cache_get(rv->block_cache, PC);
152-
if (!block) {
153-
ir->branch_taken = NULL;
154-
goto end_insn;
155-
}
156151
if (cache_hot(rv->block_cache, PC))
157152
goto end_insn;
158153
#endif
@@ -1863,11 +1858,6 @@ RVOP(
18631858
struct rv_insn *taken = ir->branch_taken;
18641859
if (taken) {
18651860
#if RV32_HAS(JIT)
1866-
block_t *block = cache_get(rv->block_cache, PC);
1867-
if (!block) {
1868-
ir->branch_taken = NULL;
1869-
goto end_insn;
1870-
}
18711861
if (cache_hot(rv->block_cache, PC))
18721862
goto end_insn;
18731863
#endif
@@ -2028,11 +2018,6 @@ RVOP(
20282018
struct rv_insn *taken = ir->branch_taken;
20292019
if (taken) {
20302020
#if RV32_HAS(JIT)
2031-
block_t *block = cache_get(rv->block_cache, PC);
2032-
if (!block) {
2033-
ir->branch_taken = NULL;
2034-
goto end_insn;
2035-
}
20362021
if (cache_hot(rv->block_cache, PC))
20372022
goto end_insn;
20382023
#endif
@@ -2065,12 +2050,6 @@ RVOP(
20652050
if (!untaken)
20662051
goto nextop;
20672052
#if RV32_HAS(JIT)
2068-
block_t *block = cache_get(rv->block_cache, PC + 2);
2069-
if (!block) {
2070-
ir->branch_untaken = NULL;
2071-
goto nextop;
2072-
}
2073-
untaken = ir->branch_untaken = block->ir_head;
20742053
if (cache_hot(rv->block_cache, PC + 2))
20752054
goto nextop;
20762055
#endif
@@ -2083,11 +2062,6 @@ RVOP(
20832062
struct rv_insn *taken = ir->branch_taken;
20842063
if (taken) {
20852064
#if RV32_HAS(JIT)
2086-
block_t *block = cache_get(rv->block_cache, PC);
2087-
if (!block) {
2088-
ir->branch_taken = NULL;
2089-
goto end_insn;
2090-
}
20912065
if (cache_hot(rv->block_cache, PC))
20922066
goto end_insn;
20932067
#endif
@@ -2129,12 +2103,6 @@ RVOP(
21292103
if (!untaken)
21302104
goto nextop;
21312105
#if RV32_HAS(JIT)
2132-
block_t *block = cache_get(rv->block_cache, PC + 2);
2133-
if (!block) {
2134-
ir->branch_untaken = NULL;
2135-
goto nextop;
2136-
}
2137-
untaken = ir->branch_untaken = block->ir_head;
21382106
if (cache_hot(rv->block_cache, PC + 2))
21392107
goto nextop;
21402108
#endif
@@ -2147,11 +2115,6 @@ RVOP(
21472115
struct rv_insn *taken = ir->branch_taken;
21482116
if (taken) {
21492117
#if RV32_HAS(JIT)
2150-
block_t *block = cache_get(rv->block_cache, PC);
2151-
if (!block) {
2152-
ir->branch_taken = NULL;
2153-
goto end_insn;
2154-
}
21552118
if (cache_hot(rv->block_cache, PC))
21562119
goto end_insn;
21572120
#endif

0 commit comments

Comments
 (0)