Skip to content

Commit dd9fcca

Browse files
authored
Merge pull request #425 from qwe661234/Add_LLVM_T2C
Implement tier-2 JIT compiler to accelerate ISS
2 parents 40ea0b5 + 5fb1609 commit dd9fcca

File tree

9 files changed

+1193
-20
lines changed

9 files changed

+1193
-20
lines changed

.github/workflows/main.yml

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ jobs:
4444
sudo apt-get update -q -y
4545
sudo apt-get install -q -y libsdl2-dev libsdl2-mixer-dev
4646
.ci/riscv-toolchain-install.sh
47+
wget https://apt.llvm.org/llvm.sh
48+
sudo chmod +x ./llvm.sh
49+
sudo ./llvm.sh 17
4750
shell: bash
4851
- name: default build
4952
run: make
@@ -65,14 +68,14 @@ jobs:
6568
make distclean ENABLE_GDBSTUB=1 gdbstub-test
6669
- name: JIT test
6770
run: |
68-
make clean && make ENABLE_JIT=1 check -j$(nproc)
69-
make clean && make ENABLE_EXT_A=0 ENABLE_JIT=1 check -j$(nproc)
70-
make clean && make ENABLE_EXT_F=0 ENABLE_JIT=1 check -j$(nproc)
71-
make clean && make ENABLE_EXT_C=0 ENABLE_JIT=1 check -j$(nproc)
71+
make ENABLE_JIT=1 clean && make ENABLE_JIT=1 check -j$(nproc)
72+
make ENABLE_JIT=1 clean && make ENABLE_EXT_A=0 ENABLE_JIT=1 check -j$(nproc)
73+
make ENABLE_JIT=1 clean && make ENABLE_EXT_F=0 ENABLE_JIT=1 check -j$(nproc)
74+
make ENABLE_JIT=1 clean && make ENABLE_EXT_C=0 ENABLE_JIT=1 check -j$(nproc)
7275
- name: undefined behavior test
7376
run: |
7477
make clean && make ENABLE_UBSAN=1 check -j$(nproc)
75-
make clean && make ENABLE_JIT=1 ENABLE_UBSAN=1 check -j$(nproc)
78+
make ENABLE_JIT=1 clean clean && make ENABLE_JIT=1 ENABLE_UBSAN=1 check -j$(nproc)
7679
7780
host-arm64:
7881
needs: [detect-code-related-file-changes]
@@ -91,18 +94,21 @@ jobs:
9194
# No 'sudo' is available
9295
install: |
9396
apt-get update -q -y
94-
apt-get install -q -y git build-essential libsdl2-dev libsdl2-mixer-dev
97+
apt-get install -q -y git build-essential libsdl2-dev libsdl2-mixer-dev lsb-release wget software-properties-common gnupg
9598
git config --global --add safe.directory ${{ github.workspace }}
9699
git config --global --add safe.directory ${{ github.workspace }}/src/softfloat
97100
git config --global --add safe.directory ${{ github.workspace }}/src/mini-gdbstub
101+
wget https://apt.llvm.org/llvm.sh
102+
chmod +x ./llvm.sh
103+
./llvm.sh 17
98104
# Append custom commands here
99105
run: |
100106
make -j$(nproc)
101107
make check -j$(nproc)
102-
make clean && make ENABLE_JIT=1 check -j$(nproc)
103-
make clean && make ENABLE_EXT_A=0 ENABLE_JIT=1 check -j$(nproc)
104-
make clean && make ENABLE_EXT_F=0 ENABLE_JIT=1 check -j$(nproc)
105-
make clean && make ENABLE_EXT_C=0 ENABLE_JIT=1 check -j$(nproc)
108+
make ENABLE_JIT=1 clean && make ENABLE_JIT=1 check -j$(nproc)
109+
make ENABLE_JIT=1 clean && make ENABLE_EXT_A=0 ENABLE_JIT=1 check -j$(nproc)
110+
make ENABLE_JIT=1 clean && make ENABLE_EXT_F=0 ENABLE_JIT=1 check -j$(nproc)
111+
make ENABLE_JIT=1 clean && make ENABLE_EXT_C=0 ENABLE_JIT=1 check -j$(nproc)
106112
107113
coding-style:
108114
needs: [detect-code-related-file-changes]
@@ -132,7 +138,8 @@ jobs:
132138
- name: run scan-build without JIT
133139
run: make distclean && scan-build -v -o ~/scan-build --status-bugs --use-cc=clang --force-analyze-debug-code --show-description -analyzer-config stable-report-filename=true -enable-checker valist,nullability make ENABLE_EXT_F=0 ENABLE_SDL=0 ENABLE_JIT=0
134140
- name: run scan-build with JIT
135-
run: make distclean && scan-build -v -o ~/scan-build --status-bugs --use-cc=clang --force-analyze-debug-code --show-description -analyzer-config stable-report-filename=true -enable-checker valist,nullability make ENABLE_EXT_F=0 ENABLE_SDL=0 ENABLE_JIT=1
141+
run: |
142+
make ENABLE_JIT=1 distclean && scan-build -v -o ~/scan-build --status-bugs --use-cc=clang --force-analyze-debug-code --show-description -analyzer-config stable-report-filename=true -enable-checker valist,nullability make ENABLE_EXT_F=0 ENABLE_SDL=0 ENABLE_JIT=1
136143
137144
compliance-test:
138145
needs: [detect-code-related-file-changes]

Makefile

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,32 @@ endif
125125
ENABLE_JIT ?= 0
126126
$(call set-feature, JIT)
127127
ifeq ($(call has, JIT), 1)
128-
OBJS_EXT += jit.o
128+
OBJS_EXT += jit.o
129+
# tier-2 JIT compiler powered LLVM
130+
LLVM_CONFIG = llvm-config-17
131+
LLVM_CONFIG := $(shell which $(LLVM_CONFIG))
132+
ifndef LLVM_CONFIG
133+
# Try Homebrew on macOS
134+
LLVM_CONFIG = /opt/homebrew/opt/llvm@17/bin/llvm-config
135+
LLVM_CONFIG := $(shell which $(LLVM_CONFIG))
136+
ifdef LLVM_CONFIG
137+
LDFLAGS += -L/opt/homebrew/opt/llvm@17/lib
138+
endif
139+
endif
140+
ifneq ("$(LLVM_CONFIG)", "")
141+
ifneq ("$(findstring -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS, "$(shell $(LLVM_CONFIG) --cflags)")", "")
142+
ENABLE_T2C := 1
143+
$(call set-feature, T2C)
144+
OBJS_EXT += t2c.o
145+
CFLAGS += -g $(shell $(LLVM_CONFIG) --cflags)
146+
LDFLAGS += $(shell $(LLVM_CONFIG) --libs)
147+
else
148+
ENABLE_T2C := 0
149+
$(call set-feature, T2C)
150+
$(warning No llvm-config-17 installed. Check llvm-config-17 installation in advance)
151+
endif
152+
endif
153+
129154
ifneq ($(processor),$(filter $(processor),x86_64 aarch64 arm64))
130155
$(error JIT mode only supports for x64 and arm64 target currently.)
131156
endif
@@ -136,6 +161,10 @@ src/rv32_jit.c:
136161
$(OUT)/jit.o: src/jit.c src/rv32_jit.c
137162
$(VECHO) " CC\t$@\n"
138163
$(Q)$(CC) -o $@ $(CFLAGS) -c -MMD -MF $@.d $<
164+
165+
$(OUT)/t2c.o: src/t2c.c src/t2c_template.c
166+
$(VECHO) " CC\t$@\n"
167+
$(Q)$(CC) -o $@ $(CFLAGS) -c -MMD -MF $@.d $<
139168
endif
140169
# For tail-call elimination, we need a specific set of build flags applied.
141170
# FIXME: On macOS + Apple Silicon, -fno-stack-protector might have a negative impact.

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Features:
3030
* Implementation of commonly used newlib system calls
3131
* Experimental SDL-based display/event/audio system calls for running video games
3232
* Support for remote GDB debugging
33-
* Experimental JIT compiler for performance boost while maintaining a small footprint
33+
* Tiered JIT compilation for performance boost while maintaining a small footprint
3434

3535
## Build and Verify
3636

@@ -40,6 +40,12 @@ and [SDL2_Mixer library](https://wiki.libsdl.org/SDL2_mixer) installed.
4040
* macOS: `brew install sdl2 sdl2_mixer`
4141
* Ubuntu Linux / Debian: `sudo apt install libsdl2-dev libsdl2-mixer-dev`
4242

43+
### JIT compiler
44+
The tier-2 JIT compiler in `rv32emu` leverages LLVM for powerful optimization. Therefore, the target system must have [`LLVM`](https://llvm.org/) installed, with version 17 recommended. If `LLVM` is not installed, only the tier-1 JIT compiler will be used for performance enhancement.
45+
46+
* macOS: `brew install llvm@17`
47+
* Ubuntu Linux / Debian: `sudo apt-get install llvm-17`
48+
4349
Build the emulator.
4450
```shell
4551
$ make

src/emulate.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,9 @@ static block_t *block_alloc(riscv_t *rv)
304304
#if RV32_HAS(JIT)
305305
block->translatable = true;
306306
block->hot = false;
307+
block->hot2 = false;
307308
block->has_loops = false;
309+
block->n_invoke = 0;
308310
INIT_LIST_HEAD(&block->list);
309311
#endif
310312
return block;
@@ -911,8 +913,6 @@ static bool runtime_profiler(riscv_t *rv, block_t *block)
911913
return true;
912914
return false;
913915
}
914-
915-
typedef void (*exec_block_func_t)(riscv_t *rv, uintptr_t);
916916
#endif
917917

918918
void rv_step(void *arg)
@@ -985,15 +985,31 @@ void rv_step(void *arg)
985985
}
986986
last_pc = rv->PC;
987987
#if RV32_HAS(JIT)
988-
/* execute by tier-1 JIT compiler */
988+
#if RV32_HAS(T2C)
989+
/* executed through the tier-2 JIT compiler */
990+
if (block->hot2) {
991+
((exec_t2c_func_t) block->func)(rv);
992+
prev = NULL;
993+
continue;
994+
} /* check if the execution path is strong hotspot */
995+
if (block->n_invoke >= THRESHOLD) {
996+
t2c_compile(block,
997+
(uint64_t) ((memory_t *) PRIV(rv)->mem)->mem_base);
998+
((exec_t2c_func_t) block->func)(rv);
999+
prev = NULL;
1000+
continue;
1001+
}
1002+
#endif
1003+
/* executed through the tier-1 JIT compiler */
9891004
struct jit_state *state = rv->jit_state;
9901005
if (block->hot) {
1006+
block->n_invoke++;
9911007
((exec_block_func_t) state->buf)(
9921008
rv, (uintptr_t) (state->buf + block->offset));
9931009
prev = NULL;
9941010
continue;
995-
} /* check if using frequency of block exceed threshold */
996-
else if (block->translatable && runtime_profiler(rv, block)) {
1011+
} /* check if the execution path is potential hotspot */
1012+
if (block->translatable && runtime_profiler(rv, block)) {
9971013
jit_translate(rv, block);
9981014
((exec_block_func_t) state->buf)(
9991015
rv, (uintptr_t) (state->buf + block->offset));

src/feature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,10 @@
5252
#define RV32_FEATURE_JIT 0
5353
#endif
5454

55+
/* Experimental tier-2 just-in-time compiler */
56+
#ifndef RV32_FEATURE_T2C
57+
#define RV32_FEATURE_T2C 0
58+
#endif
59+
5560
/* Feature test macro */
5661
#define RV32_HAS(x) RV32_FEATURE_##x

src/jit.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,9 @@ struct host_reg {
4848
struct jit_state *jit_state_init(size_t size);
4949
void jit_state_exit(struct jit_state *state);
5050
void jit_translate(riscv_t *rv, block_t *block);
51+
typedef void (*exec_block_func_t)(riscv_t *rv, uintptr_t);
52+
53+
#if RV32_HAS(T2C)
54+
void t2c_compile(block_t *block, uint64_t mem_base);
55+
typedef void (*exec_t2c_func_t)(riscv_t *);
56+
#endif

src/riscv_private.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ typedef struct block {
6565

6666
rv_insn_t *ir_head, *ir_tail; /**< the first and last ir for this block */
6767
#if RV32_HAS(JIT)
68-
bool hot; /**< Determine the block is hotspot or not */
69-
uint32_t offset;
68+
bool hot; /**< Determine the block is potential hotspot or not */
69+
bool hot2; /**< Determine the block is strong hotspot or not */
7070
bool
7171
translatable; /**< Determine the block has RV32AF insturctions or not */
7272
bool has_loops; /**< Determine the block has loop or not */
73+
uint32_t offset; /**< The machine code offset in T1 code cache */
74+
uint32_t n_invoke; /**< The invoking times of T1 machine code */
75+
void *func; /**< The function pointer of T2 machine code */
7376
struct list_head list;
7477
#endif
7578
} block_t;

0 commit comments

Comments
 (0)