Skip to content

Fix T2C in system simulation #593

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2025
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
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,9 @@ jobs:
env:
CC: ${{ steps.install_cc.outputs.cc }}
run: |
make distclean && make INITRD_SIZE=32 ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_T2C=0 ENABLE_MOP_FUSION=0 $PARALLEL && make ENABLE_SYSTEM=1 artifact $PARALLEL
make distclean && make INITRD_SIZE=32 ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_MOP_FUSION=0 $PARALLEL && make ENABLE_SYSTEM=1 artifact $PARALLEL
bash -c "${BOOT_LINUX_TEST}"
make ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_T2C=0 ENABLE_MOP_FUSION=0 clean
make ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_MOP_FUSION=0 clean
if: ${{ always() }}
- name: Architecture test
env:
Expand Down Expand Up @@ -484,9 +484,9 @@ jobs:
env:
CC: ${{ steps.install_cc.outputs.cc }}
run: |
make distclean && make INITRD_SIZE=32 ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_T2C=0 ENABLE_MOP_FUSION=0 $PARALLEL && make ENABLE_SYSTEM=1 artifact $PARALLEL
make distclean && make INITRD_SIZE=32 ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_MOP_FUSION=0 $PARALLEL && make ENABLE_SYSTEM=1 artifact $PARALLEL
bash -c "${BOOT_LINUX_TEST}"
make ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_T2C=0 ENABLE_MOP_FUSION=0 clean
make ENABLE_SYSTEM=1 ENABLE_JIT=1 ENABLE_MOP_FUSION=0 clean
if: ${{ always() }}
- name: Architecture test
env:
Expand Down
7 changes: 4 additions & 3 deletions src/jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ typedef void (*exec_t2c_func_t)(riscv_t *);
#define N_JIT_CACHE_ENTRIES (1 << 12)

struct jit_cache {
uint64_t pc; /* program counter, easy to build LLVM IR with 64-bit width */
void *entry; /* entry of JIT-ed code */
uint64_t key; /* program counter, composed to satp if it's in system
simulation */
void *entry; /* entry of JIT-ed code */
};

struct jit_cache *jit_cache_init();
void jit_cache_exit(struct jit_cache *cache);
void jit_cache_update(struct jit_cache *cache, uint32_t pc, void *entry);
void jit_cache_update(struct jit_cache *cache, uint64_t key, void *entry);
void jit_cache_clear(struct jit_cache *cache);
#endif
12 changes: 6 additions & 6 deletions src/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ static uint32_t mmu_ifetch(riscv_t *rv, const uint32_t vaddr)
return memory_ifetch(ppn | offset);
}

static uint32_t mmu_read_w(riscv_t *rv, const uint32_t vaddr)
uint32_t mmu_read_w(riscv_t *rv, const uint32_t vaddr)
{
uint32_t addr = rv->io.mem_translate(rv, vaddr, R);

Expand All @@ -235,7 +235,7 @@ static uint32_t mmu_read_w(riscv_t *rv, const uint32_t vaddr)
__UNREACHABLE;
}

static uint16_t mmu_read_s(riscv_t *rv, const uint32_t vaddr)
uint16_t mmu_read_s(riscv_t *rv, const uint32_t vaddr)
{
uint32_t addr = rv->io.mem_translate(rv, vaddr, R);

Expand All @@ -247,7 +247,7 @@ static uint16_t mmu_read_s(riscv_t *rv, const uint32_t vaddr)
return memory_read_s(addr);
}

static uint8_t mmu_read_b(riscv_t *rv, const uint32_t vaddr)
uint8_t mmu_read_b(riscv_t *rv, const uint32_t vaddr)
{
uint32_t addr = rv->io.mem_translate(rv, vaddr, R);

Expand All @@ -266,7 +266,7 @@ static uint8_t mmu_read_b(riscv_t *rv, const uint32_t vaddr)
__UNREACHABLE;
}

static void mmu_write_w(riscv_t *rv, const uint32_t vaddr, const uint32_t val)
void mmu_write_w(riscv_t *rv, const uint32_t vaddr, const uint32_t val)
{
uint32_t addr = rv->io.mem_translate(rv, vaddr, W);

Expand All @@ -285,7 +285,7 @@ static void mmu_write_w(riscv_t *rv, const uint32_t vaddr, const uint32_t val)
#endif
}

static void mmu_write_s(riscv_t *rv, const uint32_t vaddr, const uint16_t val)
void mmu_write_s(riscv_t *rv, const uint32_t vaddr, const uint16_t val)
{
uint32_t addr = rv->io.mem_translate(rv, vaddr, W);

Expand All @@ -300,7 +300,7 @@ static void mmu_write_s(riscv_t *rv, const uint32_t vaddr, const uint16_t val)
memory_write_s(addr, (uint8_t *) &val);
}

static void mmu_write_b(riscv_t *rv, const uint32_t vaddr, const uint8_t val)
void mmu_write_b(riscv_t *rv, const uint32_t vaddr, const uint8_t val)
{
uint32_t addr = rv->io.mem_translate(rv, vaddr, W);

Expand Down
7 changes: 7 additions & 0 deletions src/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,10 @@ uint32_t *mmu_walk(riscv_t *rv, const uint32_t addr, uint32_t *level);
offset = level == 1 ? vaddr & MASK((RV_PG_SHIFT + 10)) \
: vaddr & MASK(RV_PG_SHIFT); \
} while (0)

uint8_t mmu_read_b(riscv_t *rv, const uint32_t vaddr);
uint16_t mmu_read_s(riscv_t *rv, const uint32_t vaddr);
uint32_t mmu_read_w(riscv_t *rv, const uint32_t vaddr);
void mmu_write_b(riscv_t *rv, const uint32_t vaddr, const uint8_t val);
void mmu_write_s(riscv_t *rv, const uint32_t vaddr, const uint16_t val);
void mmu_write_w(riscv_t *rv, const uint32_t vaddr, const uint32_t val);
106 changes: 66 additions & 40 deletions src/t2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,21 @@ FORCE_INLINE LLVMBasicBlockRef t2c_block_map_search(struct LLVM_block_map *map,
return NULL;
}

#define T2C_OP(inst, code) \
static void t2c_##inst( \
LLVMBuilderRef *builder UNUSED, LLVMTypeRef *param_types UNUSED, \
LLVMValueRef start UNUSED, LLVMBasicBlockRef *entry UNUSED, \
LLVMBuilderRef *taken_builder UNUSED, \
LLVMBuilderRef *untaken_builder UNUSED, riscv_t *rv UNUSED, \
uint64_t mem_base UNUSED, rv_insn_t *ir UNUSED) \
{ \
LLVMValueRef timer_ptr = t2c_gen_timer_addr(start, builder, ir); \
LLVMValueRef timer = \
LLVMBuildLoad2(*builder, LLVMInt64Type(), timer_ptr, ""); \
timer = LLVMBuildAdd(*builder, timer, \
LLVMConstInt(LLVMInt64Type(), 1, false), ""); \
LLVMBuildStore(*builder, timer, timer_ptr); \
code; \
#define T2C_OP(inst, code) \
static void t2c_##inst( \
LLVMBuilderRef *builder UNUSED, LLVMTypeRef *param_types UNUSED, \
LLVMValueRef start UNUSED, LLVMBasicBlockRef *entry UNUSED, \
LLVMBuilderRef *taken_builder UNUSED, \
LLVMBuilderRef *untaken_builder UNUSED, riscv_t *rv UNUSED, \
uint64_t mem_base UNUSED, block_t *block UNUSED, rv_insn_t *ir UNUSED) \
{ \
LLVMValueRef timer_ptr = t2c_gen_timer_addr(start, builder, ir); \
LLVMValueRef timer = \
LLVMBuildLoad2(*builder, LLVMInt64Type(), timer_ptr, ""); \
timer = LLVMBuildAdd(*builder, timer, \
LLVMConstInt(LLVMInt64Type(), 1, false), ""); \
LLVMBuildStore(*builder, timer, timer_ptr); \
code; \
}

#define T2C_LLVM_GEN_ADDR(reg, rv_member, ir_member) \
Expand Down Expand Up @@ -190,17 +190,20 @@ typedef void (*t2c_codegen_block_func_t)(LLVMBuilderRef *builder UNUSED,
LLVMBuilderRef *untaken_builder UNUSED,
riscv_t *rv UNUSED,
uint64_t mem_base UNUSED,
block_t *block UNUSED,
rv_insn_t *ir UNUSED);

static void t2c_trace_ebb(LLVMBuilderRef *builder,
LLVMTypeRef *param_types UNUSED,
LLVMValueRef start,
LLVMBasicBlockRef *entry,
riscv_t *rv,
rv_insn_t *ir,
block_t *block,
set_t *set,
struct LLVM_block_map *map)
{
rv_insn_t *ir = block->ir_head;

if (set_has(set, ir->pc))
return;
set_add(set, ir->pc);
Expand All @@ -210,7 +213,7 @@ static void t2c_trace_ebb(LLVMBuilderRef *builder,
while (1) {
((t2c_codegen_block_func_t) dispatch_table[ir->opcode])(
builder, param_types, start, entry, &tk, &utk, rv,
(uint64_t) ((memory_t *) PRIV(rv)->mem)->mem_base, ir);
(uint64_t) ((memory_t *) PRIV(rv)->mem)->mem_base, block, ir);
if (!ir->next)
break;
ir = ir->next;
Expand All @@ -222,30 +225,43 @@ static void t2c_trace_ebb(LLVMBuilderRef *builder,
LLVMBuildBr(utk,
t2c_block_map_search(map, ir->branch_untaken->pc));
else {
LLVMBasicBlockRef untaken_entry =
LLVMAppendBasicBlock(start,
"untaken_"
"entry");
LLVMBuilderRef untaken_builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(untaken_builder, untaken_entry);
LLVMBuildBr(utk, untaken_entry);
t2c_trace_ebb(&untaken_builder, param_types, start,
&untaken_entry, rv, ir->branch_untaken, set, map);
block_t *blk =
cache_get(rv->block_cache, ir->branch_untaken->pc, false);
if (blk && blk->translatable
#if RV32_HAS(SYSTEM)
&& blk->satp == block->satp
#endif
) {
LLVMBasicBlockRef untaken_entry =
LLVMAppendBasicBlock(start, "untaken_entry");
LLVMBuilderRef untaken_builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(untaken_builder, untaken_entry);
LLVMBuildBr(utk, untaken_entry);
t2c_trace_ebb(&untaken_builder, param_types, start,
&untaken_entry, rv, blk, set, map);
}
}
}
if (ir->branch_taken) {
if (set_has(set, ir->branch_taken->pc))
LLVMBuildBr(tk,
t2c_block_map_search(map, ir->branch_taken->pc));
else {
LLVMBasicBlockRef taken_entry = LLVMAppendBasicBlock(start,
"taken_"
"entry");
LLVMBuilderRef taken_builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(taken_builder, taken_entry);
LLVMBuildBr(tk, taken_entry);
t2c_trace_ebb(&taken_builder, param_types, start, &taken_entry,
rv, ir->branch_taken, set, map);
block_t *blk =
cache_get(rv->block_cache, ir->branch_taken->pc, false);
if (blk && blk->translatable
#if RV32_HAS(SYSTEM)
&& blk->satp == block->satp
#endif
) {
LLVMBasicBlockRef taken_entry =
LLVMAppendBasicBlock(start, "taken_entry");
LLVMBuilderRef taken_builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(taken_builder, taken_entry);
LLVMBuildBr(tk, taken_entry);
t2c_trace_ebb(&taken_builder, param_types, start,
&taken_entry, rv, blk, set, map);
}
}
}
}
Expand All @@ -254,6 +270,9 @@ static void t2c_trace_ebb(LLVMBuilderRef *builder,
void t2c_compile(riscv_t *rv, block_t *block)
{
LLVMModuleRef module = LLVMModuleCreateWithName("my_module");
/* FIXME: riscv_t structure would change according to different
* configuration. The linked block might jump to the wrong function pointer.
*/
LLVMTypeRef io_members[] = {
LLVMPointerType(LLVMVoidType(), 0), LLVMPointerType(LLVMVoidType(), 0),
LLVMPointerType(LLVMVoidType(), 0), LLVMPointerType(LLVMVoidType(), 0),
Expand Down Expand Up @@ -291,8 +310,7 @@ void t2c_compile(riscv_t *rv, block_t *block)
struct LLVM_block_map map;
map.count = 0;
/* Translate custon IR into LLVM IR */
t2c_trace_ebb(&builder, param_types, start, &entry, rv, block->ir_head,
&set, &map);
t2c_trace_ebb(&builder, param_types, start, &entry, rv, block, &set, &map);
/* Offload LLVM IR to LLVM backend */
char *error = NULL, *triple = LLVMGetDefaultTargetTriple();
LLVMExecutionEngineRef engine;
Expand All @@ -319,7 +337,15 @@ void t2c_compile(riscv_t *rv, block_t *block)

/* Return the function pointer of T2C generated machine code */
block->func = (exec_t2c_func_t) LLVMGetPointerToGlobal(engine, start);
jit_cache_update(rv->jit_cache, block->pc_start, block->func);

#if RV32_HAS(SYSTEM)
uint64_t key = (uint64_t) block->pc_start | ((uint64_t) block->satp << 32);
#else
uint64_t key = (uint64_t) block->pc_start;
#endif

jit_cache_update(rv->jit_cache, key, block->func);

block->hot2 = true;
}

Expand All @@ -333,11 +359,11 @@ void jit_cache_exit(struct jit_cache *cache)
free(cache);
}

void jit_cache_update(struct jit_cache *cache, uint32_t pc, void *entry)
void jit_cache_update(struct jit_cache *cache, uint64_t key, void *entry)
{
uint32_t pos = pc & (N_JIT_CACHE_ENTRIES - 1);
uint32_t pos = key & (N_JIT_CACHE_ENTRIES - 1);

cache[pos].pc = pc;
cache[pos].key = key;
cache[pos].entry = entry;
}

Expand Down
Loading
Loading