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]
Loading

实验环境

操作系统: 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

自行构造LLVM后端

步骤

  1. 创建TargetMachine类的子类,描述目标机的特性
  2. 描述目标机的寄存器集合
  3. 描述目标机的指令集
  4. 描述从LLVM IR到DAG的选择与转换
  5. 在AsmPrinter下写一个子类,完成LLVM bitcode到riscv的转换
  6. 在TargetSubtarget下写一个子类以增加对多种任务的支持

LLVM语言规范

参见[5]

RISCV Assembly测试

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

⚠️ **GitHub.com Fallback** ⚠️