RISCV LLVM Backend可行性报告 copy - DailinH/llvm-riscv-backend GitHub Wiki
本项目是东南大学计算机科学与工程16级综合课程设计项目的一部分,我和@Vigilans同学负责编译器部分,采取前后端分离的开发方式。我负责的内容为LLVM bitcode -> RISCV Assembly,预计2020年1月中旬完成整个项目。在正式开始写后端之前,先尝试在linux系统下利用clang/llvm交叉编译至riscv指令。
编译器
graph LR
A[code] --> |LLVM Frontend|B[LLVM IR]
B --> C[LLVM bitcode]
C --> D[Target Machine Assembly: RISCV]
操作系统: Ubuntu 18.04.3 LTS
$ sudo apt-get update
$ sudo apt-get -y dist-upgrade
$ sudo apt-get -y install \
> binutils build-essential libtool texinfo \
> gzip zip unzip patchutils curl git \
> make cmake ninja-build automake bison flex gperf \
> grep sed gawk python bc \
> zlib1g-dev libexpat1-dev libmpc-dev \
> libglib2.0-dev libfdt-dev libpixman-1-dev 注意这里cmake的最低版本需要3.4.3[3].
测试代码 hello.c:
#include <stdio.h>
int main(){
printf("Hello RISCV!\n");
return 0;
} 使用clang编译,执行命令
$ clang -O3 hello.c -c -o hello.bc
$ llvm-dis < hello.bc | less编译出的bitcode为
; ModuleID = '<stdin>'
source_filename = "hello.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@str = private unnamed_addr constant [13 x i8] c"Hello RISCV!\00", align 1
; Function Attrs: nofree nounwind uwtable
define dso_local i32 @main() local_unnamed_addr #0 {
entry:
%puts = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([13 x i8], [13 x i8]* @str, i64 0, i64 0))
ret i32 0
}
; Function Attrs: nofree nounwind
declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #1
attributes #0 = { nofree nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nofree nounwind }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git bffbeecb44a4a727784b1777e56fe8c9a0fea3fb)"}
使用llc从hello.bc编译至hello.s
$ llc -march=riscv32 hello.bc -o hello.s .text
.file "hello.c"
.globl main # -- Begin function main
.p2align 2
.type main,@function
main: # @main
.cfi_startproc
# %bb.0: # %entry
addi sp, sp, -16
.cfi_def_cfa_offset 16
sw ra, 12(sp)
.cfi_offset ra, -4
lui a0, %hi(.Lstr)
addi a0, a0, %lo(.Lstr)
call puts
mv a0, zero
lw ra, 12(sp)
.cfi_restore ra
addi sp, sp, 16
.cfi_def_cfa_offset 0
ret
.Lfunc_end0:
.size main, .Lfunc_end0-main
.cfi_endproc
# -- End function
.type .Lstr,@object # @str
.section .rodata.str1.1,"aMS",@progbits,1
.Lstr:
.asciz "Hello RISCV!"
.size .Lstr, 13
.ident "clang version 10.0.0 (https://github.com/llvm/llvm-project.git bffbeecb44a4a727784b1777e56fe8c9a0fea3fb)"
.section ".note.GNU-stack","",@progbits
- 创建TargetMachine类的子类,描述目标机的特性
- 描述目标机的寄存器集合
- 描述目标机的指令集
- 描述从LLVM IR到DAG的选择与转换
- 在AsmPrinter下写一个子类,完成LLVM bitcode到riscv的转换
- 在TargetSubtarget下写一个子类以增加对多种任务的支持
参见[5]
QEMU是一个虚拟化应用程序,在与硬件接轨之前,我们先在Linux上通过QEMU测试RISCV Assembly是否可以运行。
[1] M. Pandey, S. Sarda. LLVM Cookbook
[2] sifive/riscv-llvm, https://github.com/sifive/riscv-llvm
[3] Building LLVM with CMake, https://llvm.org/docs/CMake.html
[4] Writing an LLVM Backend https://llvm.org/docs/WritingAnLLVMBackend.html
[5] LLVM Language Reference Manual https://llvm.org/docs/LangRef.html
[6] QEMU简介 https://www.ibm.com/developerworks/cn/linux/l-qemu/index.html