# Final Project: Improve ria-jit
###### tags: `Computer Architecture`
## Getting Started
### Environment Setup
:::info
OS: Kali GNU/Linux Rolling
Kernel version: Linux version 5.14.0-kali2-amd64
:::
To run [ria-jit](https://github.com/ria-jit/ria-jit), we must first install [RISC-V GNU Compiler Toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain). Notice that we should install the Newlib cross-compiler instead of the Linux one or we might encounter the error:
```
$ ./translator -f a.out
Syscall 226 is not yet implemented
: error while loading shared libraries: cannot apply additional memory protection after relocation: Function not implemented
```
Also, if we configure RISC-V compiler toolchain using the default option, it will build RV64GC. However, C extension is not supported by ria-jit. The error message is shown below:
```
$ ./translator -f a.out
Critical: C ABI is not yet supported - not yet implemented
Fatal error: FAIL_NOT_IMPL (6)
```
To avoid the problem above, add `--with-arch` and `--with-abi` options and choose the target architecture which is supported by ria-jit. We can install RISC-V compiler toolchain using the commands:
```bash
./configure --prefix=/opt/riscv --with-arch=rv64imafd --with-abi=lp64d
make
```
Let's compile a C program:
```c
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}
```
Follow the instructions in README, we should build ria-jit without any problem. Run the tests with command `./test`:

We can then execute the compiled RISC-V program with ria-jit:
```
$ ./translator -f a.out
Hello World
```
It works!
## Requirements and Expectations
1. Build and execute ria-jit and its two [forks](https://github.com/ria-jit/ria-jit/network).
2. Ensure ria-jit and its two forks can pass [RISC-V Architecture Test](https://github.com/riscv-non-isa/riscv-arch-test)
3. According to its paper, write a test program which shows its optimization strategies.
4. Observe ria-jit and its optimization strategies and describe it with the test program that you wrote.
## Run ria-jit and Its Forks

1. https://github.com/aengelke/ria-jit
2. https://github.com/bauen1/ria-jit
These projects can be built using the commands described in README:
> After checking out the git repository (and running `git submodule update --init` to fetch the dependencies), the translator can be built via
> 1. `sudo apt-get -y install gcc g++ cmake make autoconf meson` (required dependencies)
> 2. `mkdir build && cd build && cmake .. && make`
>
> We can execute binaries compiled via the RISC-V toolchain gcc and the options `-static -march=rv64imafd -mabi=lp64d`.
After successfully building all these projects, the hello world program which is compiled in RISC-V can be executed through the translator:
```
$ ./translator -f a.out
Hello World
```
## RISC-V Architecture Test
To run RISC-V Architecture Test, we must follow the instructions in [README](https://github.com/riscv-non-isa/riscv-arch-test/blob/master/doc/README.adoc) and create a directory structure under `riscv-target/` as shown:

I modified these files from [spike](https://github.com/riscv-software-src/riscv-isa-sim/tree/master/arch_test_target/spike).
Because ria-jit has not yet supported C extension, only the tests for I and M extension are available in this case and we only need to preserve these two directories. The directory structure is shown below:
```
$ tree ria-jit
ria-jit
├── device
│ └── rv64i_m
│ ├── I
│ │ └── Makefile.include
│ └── M
│ └── Makefile.include
├── link.ld
└── model_test.h
4 directories, 4 files
```
`Makefile.include` becomes:
```
TARGET_SIM ?= /home/axwl03/Desktop/ria-jit/build/translator
TARGET_FLAGS ?= $(RISCV_TARGET_FLAGS)
ifeq ($(shell command -v $(TARGET_SIM) 2> /dev/null),)
$(error Target simulator executable '$(TARGET_SIM)` not found)
endif
RISCV_PREFIX ?= riscv64-unknown-elf-
RISCV_GCC ?= $(RISCV_PREFIX)gcc
RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump
RISCV_GCC_OPTS ?= -g -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles $(RVTEST_DEFINES)
COMPILE_CMD = $$(RISCV_GCC) $(1) $$(RISCV_GCC_OPTS) \
-I$(ROOTDIR)/riscv-test-suite/env/ \
-I$(TARGETDIR)/$(RISCV_TARGET)/ \
-T$(TARGETDIR)/$(RISCV_TARGET)/link.ld \
$$(<) -o $$@
OBJ_CMD = $$(RISCV_OBJDUMP) $$@ -D > $$@.objdump; \
$$(RISCV_OBJDUMP) $$@ --source > $$@.debug
COMPILE_TARGET=\
$(COMPILE_CMD); \
if [ $$$$? -ne 0 ] ; \
then \
echo "\e[31m$$(RISCV_GCC) failed for target $$(@) \e[39m" ; \
exit 1 ; \
fi ; \
$(OBJ_CMD); \
if [ $$$$? -ne 0 ] ; \
then \
echo "\e[31m $$(RISCV_OBJDUMP) failed for target $$(@) \e[39m" ; \
exit 1 ; \
fi ;
RUN_CMD = $(TARGET_SIM) -f $<
RUN_TARGET=\
$(RUN_CMD)
```
`TARGET_SIM` points to ria-jit translator and `RUN_CMD` is adjusted to adapt to the commandline format of ria-jit. To perform the test, execute the command:
```
make compile simulate verify
```
However, the program hangs. It does not exit or continue the execution:
```
$ make simulate
============================ VARIABLE INFO ==================================
ROOTDIR: /home/axwl03/Desktop/riscv-arch-test [origin: file]
WORK: /home/axwl03/Desktop/riscv-arch-test/work [origin: file]
TARGETDIR: /home/axwl03/Desktop/riscv-arch-test/riscv-target [origin: file]
RISCV_TARGET: ria-jit [origin: file]
XLEN: 64 [origin: file]
RISCV_DEVICE: I [origin: file]
=============================================================================
make -j1 \
RISCV_TARGET=ria-jit \
RISCV_DEVICE=I \
run -C /home/axwl03/Desktop/riscv-arch-test/riscv-test-suite/rv64i_m/I
make[1]: Entering directory '/home/axwl03/Desktop/riscv-arch-test/riscv-test-suite/rv64i_m/I'
Execute /home/axwl03/Desktop/riscv-arch-test/work/rv64i_m/I/add-01.log
(It hangs here)
```
I directly execute the command to test it: `./translator -g -f /home/axwl03/Desktop/riscv-arch-test/work/rv64i_m/I/add-01.elf`
The additional `-g` flag shows us the general messages:
```
[general] Execute block at 0x80006f3c, cache loc 0x77ff8100c0a0
[general] chaining: ...
[general] Execute block at 0x80007038, cache loc 0x77ff8100c250
[general] chaining: ...
[general] Execute block at 0x80007134, cache loc 0x77ff8100c400
[general] chaining: ...
[general] Execute block at 0x80007230, cache loc 0x77ff8100c5b0
[general] chaining: ...
[general] Execute block at 0x8000732c, cache loc 0x77ff8100c740
[general] chaining: ...
[general] Execute block at 0x80007420, cache loc 0x77ff8100c8e0
[general] chaining: ...
[general] Execute block at 0x80007420, cache loc 0x77ff8100c8e0
(It hangs here)
```
After checking the objdump for `add-01.elf`, the last instruction is at `0x80007420`, which corresponds to the intruction defined in `model_test.h`.
objdump:
```
0000000080007418 <write_tohost>:
80007418: 00001f17 auipc t5,0x1
8000741c: be1f2423 sw ra,-1048(t5) # 80008000 <tohost>
0000000080007420 <self_loop>:
80007420: 0000006f j 80007420 <self_loop>
...
```
The macro `RVMODEL_HALT` is defined in `model_test.h`:
```c
//RV_COMPLIANCE_HALT
#define RVMODEL_HALT \
addi x1, x1, 4; \
li x1, 1; \
write_tohost: \
sw x1, tohost, t5; \
self_loop: j self_loop;
```
This is where the halt occurred. It is an infinite loop. From the spec, we know that this macro is used when the test ended:
> `RVMODEL_HALT`: This macros must define the test-target halt mechanism. This macro is called when the test is to be terminated either due to completion or due to unsupported behavior. This macro could also include routines to dump the signature region to a file on the host system which can be used for comparison.
However, other targets (ex. spike) also have similar instructions without hanging for some reason. After testing it manually using other testcases, I find out that some testcases failed. For example, `bne`:
```
$ ./translator -g -f /home/axwl03/Desktop/riscv-arch-test/work/rv64i_m/I/bne-01.elf
...
[general] Generating context storing block...
[general] Generating context executing block...
[general] Execute block at 0x80000000, cache loc 0x77ff81000120
[general] chaining: ...
[general] Execute block at 0x800000fc, cache loc 0x77ff810002e0
[general] chaining: ...
[general] Execute block at 0x800001f8, cache loc 0x77ff810004a0
Assembly error after generating basic block.
Fatal error: FAIL_ASSEMBLY_ERR (5)
```
Other testcases for branch instructions also have the same problems, including `jal` and `jalr`. Using the same method, I also tested aengelke's and bauen1's ria-jit. Both have the same problems. While tracing the source code, I found this comment:
```c
//check failed flag
if (err != 0) {
//terminate if we encounter errors. this most likely is a bug in a RISC-V instruction's translation
dprintf(2, "Assembly error after generating basic block.\n");
panic(FAIL_ASSEMBLY_ERR);
}
```
Using `-i` and `-o` options, I observed the instruction translated while running `bne` testcase:
```
...
[code-in] Instruction ADDIW at 0x800003a4 (type 1) - (rs1: x0/zero) - (rs2: INVALID/INVALID) - (rd: x19/s3) - (imm: 0x1)
[jit-gen] Translate ADDIW...
[code-in] Instruction SLLI at 0x800003a8 (type 1) - (rs1: x19/s3) - (rs2: INVALID/INVALID) - (rd: x19/s3) - (imm: 0x31)
[jit-gen] Translate SLLI...
[code-in] Instruction PATTERN at 0x800003ac (type 10) - (rs1: x0/zero) - (rs2: INVALID/INVALID) - (rd: x6/t1) - (imm: 0x0)
[jit-gen] Translate Pattern...
[jit-gen] emit pattern 11: ADDI as MV at 0x800003ac
[code-in] Instruction AUIPC at 0x800003b0 (type 1) - (rs1: x0/zero) - (rs2: x0/zero) - (rd: x0/zero) - (imm: 0x4)
[jit-gen] Translate AUIPC...
[code-in] Instruction BNE at 0x800003bc (type 4) - (rs1: x25/s9) - (rs2: x19/s3) - (rd: INVALID/INVALID) - (imm: 0x40)
[jit-gen] Translate BRANCH BNE
Assembly error after generating basic block.
Fatal error: FAIL_ASSEMBLY_ERR (5)
```
The corresponding assembly code is:
```
...
80000398: fff00c9b addiw s9,zero,-1
8000039c: 03fc9c93 slli s9,s9,0x3f
800003a0: fffc8c93 addi s9,s9,-1
800003a4: 0010099b addiw s3,zero,1
800003a8: 03199993 slli s3,s3,0x31
800003ac: 00000313 li t1,0
800003b0: 00c0006f j 800003bc <inst_0+0x24>
800003b4: 00130313 addi t1,t1,1
800003b8: 04c0006f j 80000404 <inst_0+0x6c>
800003bc: 053c9063 bne s9,s3,800003fc <inst_0+0x64>
800003c0: 00230313 addi t1,t1,2
800003c4: 0400006f j 80000404 <inst_0+0x6c>
...
```
Probably, there might be some errors in the implementation or misconfiguration in my settings. Further investigation is needed.
In summary, there are two problems that I haven't resolved yet:
1. ria-jit does not stop after executing the code defined in `RVMODEL_HALT`.
2. "Assembly error" message is shown when testing branch instructions.
## Optimization Strategies