Yet another RISC-V LLVM Backend. This is a project for learning how LLVM backend works and what RISC-V architecture is by reimplementing the official LLVM's RISC-V backend.
- Official RISC-V backend (LLVM 14.0.6): https://github.com/llvm/llvm-project/tree/f28c006a5895fc0e329fe15fead81e37457cb1d1/llvm/lib/Target/RISCV
- RISC-V specification: https://riscv.org/technical/specifications/
- RISC-V Assembly Manual: https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md
- Writing an LLVM Backend: https://llvm.org/docs/WritingAnLLVMBackend.html
Clone this repository:
git clone --recursive https://github.com/rhysd/toy-riscv-backend.git
Setup LLVM:
cd /path/to/toy-riscv-backend
./setup.bash
cd ./llvm-project/llvm
mkdir ./build && cd ./build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_TARGETS_TO_BUILD="X86;TOYRISCV;RISCV" -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" ..
ninja
setup.bash links all sources in llvm/ to llvm-project/llvm/ so that our
backend is built as a part of llc
compiler.
Setup RISC-V toolchain:
docker build . -t riscvback
docker run -it --rm -v $(pwd):/app riscvback /bin/bash
RISC-V toolchain like riscv64-unknown-elf-gcc
or spike
are available in the Docker container.
- Toy RISC-V 32bit CPU written in Chisel: https://github.com/rhysd/riscv32-cpu-chisel
Compile sources.
Setting triple as --target=riscv64-unknonw-linux-gnu
is necessary to emit LLVM IR targetting 64bit RISC-V processor.
-march
may not be necessary, but ensure that CPU arch is rv64g
. It emits source.bc
.
./llvm-project/llvm/build/bin/clang --target=riscv64-unknown-linux-gnu -march=rv64g -emit-llvm -c source.c
Compile LLVM bitcode to assembly code.
Set CPU arch to -march=riscv64
. Default value of -mcpu
is generic-v64
so it is not necessary but here we ensure it.
-mattr
specifies what CPU excentions can be used. In this example, we enable 'd' extension by adding +d
.
It emits source.s
.
./llvm-project/llvm/build/bin/llc -march=riscv64 -mcpu=generic-rv64 -mattr=+d -filetype=asm source.bc
Check the generated assembly code. The .attribute 5
is the attribute representing CPU arch. Check the CPU arch
supports all features you need.
.text
.attribute 4, 16
.attribute 5, "rv64i2p0_f2p0_d2p0"
.file "source.c"
.globl main
.p2align 2
.type main,@function
main:
...
When no feature is enabled, the CPU arch will be rv64i2p0
. If the assembly code tries to use a feature which is not
enabled by the processor, the following GCC command reports an error like below:
source.s:10: Error: ilp32d/lp64d ABI can't be used when d extension isn't supported
Finally compile the assembly code to an object file and run it via Spike simulator on Docker container.
riscv64-unknown-elf-gcc source.s -lc -o source.o
spike pk source.o
Note that compiling to an object file from LLVM bitcode via llc
with -filetype=obj
does not work.
Compile to LLVM bitcode using Clang with riscv64-unknown-elf
target.
./llvm-project/llvm/build/bin/clang --target=riscv64-unknown-elf -O3 hello.c -c -emit-llvm -o hello.bc
Then compile the bitcode to RISC-V 64bit assembly using our own TOYRISCV backend.
./llvm-project/llvm/build/bin/llc -debug -march=toyriscv64 -filetype=asm hello.bc -o hello.S
This project is licensed under the MIT license.