Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Apply branch prediction for indirect jump #269

Merged
merged 1 commit into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ typedef struct {
uint8_t opcode;
} opcode_fuse_t;

#define HISTORY_SIZE 16
typedef struct {
uint32_t PC;
struct rv_insn *branch_target;
} branch_history_entry_t;

typedef struct rv_insn {
union {
int32_t imm;
Expand Down Expand Up @@ -294,7 +300,8 @@ typedef struct rv_insn {
* specific IR array without the need for additional copying.
*/
struct rv_insn *branch_taken, *branch_untaken;

uint8_t branch_table_count;
branch_history_entry_t *branch_table;
} rv_insn_t;

/* decode the RISC-V instruction */
Expand Down
40 changes: 24 additions & 16 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,21 +371,21 @@ static bool is_branch_taken = false;
static uint32_t last_pc = 0;

/* Interpreter-based execution path */
#define RVOP(inst, code) \
static bool do_##inst(riscv_t *rv, const rv_insn_t *ir, uint64_t cycle, \
uint32_t PC) \
{ \
cycle++; \
code; \
nextop: \
PC += __rv_insn_##inst##_len; \
if (unlikely(RVOP_NO_NEXT(ir))) { \
rv->csr_cycle = cycle; \
rv->PC = PC; \
return true; \
} \
const rv_insn_t *next = ir->next; \
MUST_TAIL return next->impl(rv, next, cycle, PC); \
#define RVOP(inst, code) \
static bool do_##inst(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, \
uint32_t PC) \
{ \
cycle++; \
code; \
nextop: \
PC += __rv_insn_##inst##_len; \
if (unlikely(RVOP_NO_NEXT(ir))) { \
rv->csr_cycle = cycle; \
rv->PC = PC; \
return true; \
} \
const rv_insn_t *next = ir->next; \
MUST_TAIL return next->impl(rv, next, cycle, PC); \
}

#include "rv32_template.c"
Expand Down Expand Up @@ -633,8 +633,16 @@ static void block_translate(riscv_t *rv, block_t *block)
block->n_insn++;
prev_ir = ir;
/* stop on branch */
if (insn_is_branch(ir->opcode))
if (insn_is_branch(ir->opcode)) {
if (ir->opcode == rv_insn_jalr
#if RV32_HAS(EXT_C)
|| ir->opcode == rv_insn_cjalr || ir->opcode == rv_insn_cjr
#endif
)
ir->branch_table =
qwe661234 marked this conversation as resolved.
Show resolved Hide resolved
calloc(1, HISTORY_SIZE * sizeof(branch_history_entry_t));
break;
}

ir = mpool_alloc(rv->block_ir_mp);
}
Expand Down
1 change: 1 addition & 0 deletions src/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void block_map_clear(riscv_t *rv)
for (idx = 0, ir = block->ir_head; idx < block->n_insn;
idx++, ir = next) {
free(ir->fuse);
free(ir->branch_table);
next = ir->next;
mpool_free(rv->block_ir_mp, ir);
}
Expand Down
36 changes: 27 additions & 9 deletions src/rv32_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,30 @@ RVOP(jal, {
return true;
})

/* The branch history table records historical data pertaining to indirect jump
* targets. This functionality alleviates the need to invoke block_find() and
* incurs overhead only when the indirect jump targets are not previously
* recorded. Additionally, the C code generator can reference the branch history
* table to link he indirect jump targets.
*/
#define LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE() \
jserv marked this conversation as resolved.
Show resolved Hide resolved
/* lookup branch history table */ \
for (int i = 0; i < ir->branch_table_count; i++) { \
if (ir->branch_table[i].PC == PC) { \
MUST_TAIL return ir->branch_table[i].branch_target->impl( \
rv, ir->branch_table[i].branch_target, cycle, PC); \
} \
} \
block_t *block = block_find(&rv->block_map, PC); \
if (block) { \
/* update branch history table */ \
ir->branch_table_count = (ir->branch_table_count + 1) % HISTORY_SIZE; \
ir->branch_table[ir->branch_table_count].PC = PC; \
ir->branch_table[ir->branch_table_count].branch_target = \
block->ir_head; \
MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, PC); \
}

/* The indirect jump instruction JALR uses the I-type encoding. The target
* address is obtained by adding the sign-extended 12-bit I-immediate to the
* register rs1, then setting the least-significant bit of the result to zero.
Expand All @@ -57,9 +81,7 @@ RVOP(jalr, {
rv->X[ir->rd] = pc + 4;
/* check instruction misaligned */
RV_EXC_MISALIGN_HANDLER(pc, insn, false, 0);
block_t *block = block_find(&rv->block_map, PC);
if (block)
MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, PC);
LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE();
rv->csr_cycle = cycle;
rv->PC = PC;
return true;
Expand Down Expand Up @@ -1016,9 +1038,7 @@ RVOP(clwsp, {
/* C.JR */
RVOP(cjr, {
PC = rv->X[ir->rs1];
block_t *block = block_find(&rv->block_map, PC);
if (block)
MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, PC);
LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE();
rv->csr_cycle = cycle;
rv->PC = PC;
return true;
Expand All @@ -1043,9 +1063,7 @@ RVOP(cjalr, {
rv->X[rv_reg_ra] = PC + 2;
PC = jump_to;
RV_EXC_MISALIGN_HANDLER(PC, insn, true, 0);
block_t *block = block_find(&rv->block_map, PC);
if (block)
MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, PC);
LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE();
rv->csr_cycle = cycle;
rv->PC = PC;
return true;
Expand Down
Loading