添加了项目部署脚本,修改了ReadMe
This commit is contained in:
442
README.md
442
README.md
@ -1,410 +1,40 @@
|
||||
# Our SysY compiler in Parallel Compilation and Optimization
|
||||
# SysY 编译器 by 32bit Brain Storm
|
||||
|
||||
## Original ReadMe ↓
|
||||
SysY 编译器是一个基于 ANTLR4 的编译器,支持 SysY 语言的解析和编译。该编译器使用 C++ 实现,并提供了一些简单的命令行操作来处理 SysY 源代码。
|
||||
|
||||
---
|
||||
|
||||
# CCRG SysY Compiler
|
||||
|
||||
用于实现SysY编译器的代码框架。
|
||||
|
||||
## Getting Started
|
||||
|
||||
建议使用Ubuntu 22.04系统,原生版本与WSL版本均可。
|
||||
|
||||
[Ubuntu下载与安装说明](https://ubuntu.com/download/desktop)
|
||||
|
||||
[WSL Ubuntu安装说明](https://learn.microsoft.com/en-us/windows/wsl/install)
|
||||
|
||||
SysY编译器前端基于[ANTLR](https://www.antlr.org/index.html)工具实现,本仓库已经包含ANTLR 4.12.0版本的可执行程序与C++运行时库,但编译ANTLR运行时库存在一些依赖,需要提前安装。
|
||||
### 项目配置。
|
||||
|
||||
> 请确保你已经安装了CMake。
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y uuid-dev libutfcpp-dev pkg-config make git cmake openjdk-11-jre
|
||||
```
|
||||
|
||||
依赖安装完成后,可以开始构建SysY编译器(构建过程包含了ANTLR运行时库的构建)。
|
||||
|
||||
```bash
|
||||
git clone https://gitee.com/xsu1989/sysy.git
|
||||
cd sysy
|
||||
cmake -S . -B build
|
||||
cmake --build build --target all -- -j $(nproc)
|
||||
cmake --build build --target all -- -j $(nproc) -DCMAKE_BUILD_TYPE=Debug
|
||||
```
|
||||
|
||||
构建完成后,可以运行一个小的测试用例。该测试将逗号分隔的整数或字符串列表进行格式化后重新输出,即将相邻参数之间的分隔统一调整为逗号外加一个空格。
|
||||
|
||||
```bash
|
||||
cat /test/funcrparams.sysy
|
||||
# -> 1,0xa , 011, "hellow"
|
||||
./build/bin/sysyc -f test/funcrparams.sy
|
||||
# -> 1, 0xa, 011, "hellow"
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
|
||||
所有资料均存放于`doc`目录
|
||||
|
||||
[ANTLR手册](doc/The%20Definitive%20ANTLR%204%20Reference.pdf)
|
||||
|
||||
[SysY语言规范](doc/sysy-2022-spec.pdf)
|
||||
|
||||
[SysY运行时库](doc/sysy-2022-runtime.pdf)
|
||||
|
||||
[ARM相关资料](doc/arm/)
|
||||
|
||||
[RISC-V相关资料](doc/riscv/)
|
||||
|
||||
## 实验1:用ANTLR实现SysY词法/语法分析器
|
||||
|
||||
当前的代码框架已经部署好了编译环境,同学们可专注于程序开发。
|
||||
|
||||
在实验1中,同学们需要完成的任务包括
|
||||
|
||||
- 参照SysY语言规范,修改`src/SysY.g4`文件,实现SysY词法/语法的完整定义
|
||||
- (进阶内容)SysY格式化器。修改`src/ASTPrinter.h`与`src/ASTPrinter.cpp`,实现从AST输出源程序,但输出的源程序是经过格式化的,测试用例为`test/format-test.sy`,格式化后的参考结果为`test/format-ref.sy`
|
||||
|
||||
修改代码后只需要执行`cmake --build build`命令重新构建项目,ANTLR工具会从`SysY.g4`生成词法/语法分析器,生成的文件位于`./build/src`目录。
|
||||
|
||||
```bash
|
||||
$ ls build/src/
|
||||
CMakeFiles SysYBaseVisitor.cpp SysY.interp SysYLexer.h SysYLexer.tokens SysYParser.h SysYVisitor.cpp
|
||||
cmake_install.cmake SysYBaseVisitor.h SysYLexer.cpp SysYLexer.interp SysYParser.cpp SysY.tokens SysYVisitor.h
|
||||
```
|
||||
|
||||
完成实验1后,可以通过执行`sysyc`观察生成的IR。
|
||||
|
||||
```bash
|
||||
./build/sysyc -s ast test/funcrparams.sy
|
||||
```
|
||||
|
||||
完成格式化器进阶内容后,可以通过执行`sysyc`观察格式化器的执行效果。
|
||||
|
||||
```bash
|
||||
./build/bin/sysyc -f test/format-test.sy
|
||||
```
|
||||
|
||||
## 实验2:从AST生成中间表示
|
||||
|
||||
代码框架提供的基础设施包括
|
||||
|
||||
- IR相关数据结构的定义:`src/IR.h`
|
||||
- 创建IR对象的工具类`src/IRBuilder.h`
|
||||
- IR生成器的示例代码`src/SysYIRGenerator.h`
|
||||
|
||||
在实验2中,同学们需要完成的任务包括
|
||||
|
||||
- 熟悉掌握IR定义与相关数据结构
|
||||
- 向`src/SysYIRGenerator.h`、`src/SysYIRGenerator.cpp`中增加相关代码,从AST生成IR(基于visitor机制)。
|
||||
|
||||
完成实验2后,可以通过执行`sysyc`观察生成的IR。
|
||||
|
||||
```bash
|
||||
./build/bin/sysyc -s ir test/01_add.sy
|
||||
```
|
||||
|
||||
请同学们仔细阅读代码学习IR的定义。可以使用doxygen工具自动生成HTML文档
|
||||
|
||||
```bash
|
||||
sudo apt install doxygen graphviz
|
||||
doxygen doc/Doxyfile
|
||||
```
|
||||
|
||||
上述命令执行完毕后,将在doxygen/html下找到生成的代码文档。
|
||||
|
||||
该版本还未实现数组初始化定义等功能
|
||||
|
||||
## 实验3:从SysY IR 生成ARMv7汇编代码
|
||||
|
||||
### 后端相关源码
|
||||
|
||||
当前ref2分支为ARMv7后端代码实验,已经包含了后端代码生成的代码框架,包含
|
||||
|
||||
- 后端生成代码头文件`src/Backend.h`
|
||||
- 后端生成代码源文件`src/Backend.cpp`
|
||||
|
||||
本实验需要基于以上两个源文件添加ARMv7后端生成代码,完成这两个源文件中所有空函数的实现.
|
||||
也可以按照自己的设计重头编写整个后端生成代码,不局限于本实验提供的后端代码框架,自由设计自己的ARMv7后端实现.
|
||||
|
||||
### 后端代码的编译与运行
|
||||
|
||||
在`src/sysyc.cpp`中调用了后端生成的最顶层函数接口`code_gen()`,该函数会逐层调用各层级的代码生成函数并最终生成ARMv7汇编代码并打印至屏幕。
|
||||
|
||||
通过下列命令运行编译产生的sysyc
|
||||
|
||||
```bash
|
||||
./build/sysyc 01_add.sy
|
||||
```
|
||||
|
||||
或者通过下列命令只生成SysY IR代码
|
||||
|
||||
```bash
|
||||
./build/sysyc 01_add.sy ir
|
||||
```
|
||||
|
||||
### 测试
|
||||
|
||||
本实验提供了2个sysy源文件用于调测试,分别是 test/01_add.sy (基础) 和 test/11_add2.sy (带函数调用); 当完成sysyc的编译器后端后,可以通过test下的Makefile文件编译生成测试程序的可
|
||||
执行二进制.
|
||||
|
||||
#### 在x86平台编译运行测试代码
|
||||
|
||||
##### 下载并配置ARMv7交叉编译器工具链
|
||||
|
||||
在[Arm GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)下载安装交叉编译工具链,并设置环境变量PATH来使用交叉编译工具链
|
||||
|
||||
```bash
|
||||
export PATH=${your_arm-gnu-toolchain_path}/bin:$PATH;
|
||||
```
|
||||
|
||||
##### 安装qemu模拟器
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install qemu-system-arm qemu-user
|
||||
```
|
||||
|
||||
##### 编译测试程序
|
||||
|
||||
使用如下命令调用完成后端实现的sysyc生成ARMv7汇编代码,并调用ARMv7交叉编译工具链汇编并链接生成可执行文件.
|
||||
|
||||
```bash
|
||||
cd test
|
||||
../build/sysyc 01_add.sy > 01_add.s
|
||||
arm-none-linux-gnueabihf-gcc 01_add.s -o 01_add.out -static #注意使用-static选项来静态链接
|
||||
```
|
||||
|
||||
##### 使用qemu-arm模拟运行测试程序
|
||||
|
||||
```bash
|
||||
cd test
|
||||
qemu-arm ./01_add.out
|
||||
echo $? #查看测试程序返回值
|
||||
```
|
||||
|
||||
##### 使用makefile编译与运行
|
||||
|
||||
```bash
|
||||
cd test
|
||||
make all -r #利用sysyc编译两个测试程序
|
||||
make run -r #使用qemu-arm模拟运行两个测试程序
|
||||
```
|
||||
|
||||
#### 在树莓派上编译运行测试代码
|
||||
|
||||
参见'Raspberry.pdf'设置树莓派的编译运行环境,也可以在自己的x86电脑上利用ARMv7交叉编译工具链来编译测试程序, 将编译产生的可执行文件上传到树莓派上运行.
|
||||
|
||||
### 交叉编译器生成汇编代码
|
||||
|
||||
可以通过如下的命令让交叉编译器生成汇编代码,以参考gcc后端的编译行为.
|
||||
|
||||
```bash
|
||||
cd test
|
||||
cp 01_add.sy 01_add.c # 修改代码后缀名
|
||||
arm-none-linux-gnueabihf-gcc 01_add.c -O0 -S -o 01_add.S #O0编译优化
|
||||
```
|
||||
|
||||
请自己构造一些简单的c程序,阅读交叉编译器编译产生的汇编代码来理解ARMv7汇编代码与编译器后端行为.
|
||||
|
||||
### 实验考核
|
||||
|
||||
实验考核使用的sysy程序是 test/10_test.sy,考核时需要展示完整测试过程,包括(1)调用实现了后端代码生成功能的sysyc生成汇编代码,(2)经过汇编链接生成二进制可执行文件,(3)在Qemu或
|
||||
树莓派平台上运行结果正确
|
||||
|
||||
### 参考文档
|
||||
|
||||
参见doc/backend/下的ARMv7相关文档
|
||||
|
||||
## 实验4:标量优化
|
||||
|
||||
### 实验任务
|
||||
|
||||
在前三次实验打通编译器前端-中端-后端基本功能的基础上,在编译中端增加标量优化支持
|
||||
|
||||
- 优化一: 循环优化,在控制流图中找出循环,完成循环不变量外提和强度削弱 (选作)
|
||||
- 优化二:冗余删除,在公用子表达式删除、死代码删除、值编号、常数折叠和常数传播四种冗余优化中,选择完成至少一种优化。
|
||||
- 进阶内容:在中端增加遍管理器支持
|
||||
|
||||
### 实验目标
|
||||
|
||||
通过实验,掌握到达定值分析、活跃变量分析、可用表达式分析等数据流分析方法,能够利用数据流分析和公用子表达式删除、死代码删除、值编号、常数折叠和常数传播等冗余优化算法实现相应的代码优化。
|
||||
|
||||
### 实验方法与主要步骤
|
||||
|
||||
1. 在编译中端增加到达定值分析、活跃变量分析、可用表达式分析等数据流分析遍
|
||||
2. 实现所选循环优化和冗余删除任务种对应的优化算法,实现为对应的优化遍
|
||||
3. 进阶内容:在中端增加遍管理器,管理实现的多个分析遍和优化遍,以更灵活的方式配置编译遍顺序
|
||||
|
||||
### 测试与验证
|
||||
|
||||
测试源程序为test/20_test_licm_sr.sy,test/21_test_cse.sy,test/22_test_dce.sy,test/23_test_vn.sy,test/24_test_cp_cf.sy,经过实验四生成的sysyc编译器能够
|
||||
|
||||
1. 生成经过循环优化或冗余删除优化后的汇编代码,交叉编译后的二进制文件可以在Qemu模拟器/树莓派上正确运行;
|
||||
2. 对比查看优化前和优化后的IR,是否达到了要实现的优化目标。
|
||||
|
||||
## 实验5:寄存器分配
|
||||
|
||||
### 实验任务
|
||||
|
||||
在编译后端增加寄存器分配支持,选择一种分配方法实现寄存器分配
|
||||
|
||||
- 使用计数寄存器分配方法
|
||||
- 进阶内容:图着色寄存器分配方法或线性扫描寄存器分配方法
|
||||
|
||||
### 实验目标
|
||||
|
||||
通过实验理解和掌握编译后端的寄存器分配方法,理解不同寄存器分配方法的优缺点
|
||||
|
||||
### 实验方法与主要步骤
|
||||
|
||||
1. 将ARMv7的R0-R10, R12作为可用寄存器资源
|
||||
2. 遍历所有Function, 在每个Function内部,做寄存器分配
|
||||
3. 维护RegTable符号表,记录哪些LocalValue分配到寄存器,以及具体寄存器编号
|
||||
4. 维护StackTable符号表,记录哪些LocalValue分配到栈上,以及栈上的位置
|
||||
|
||||
### 测试与验证
|
||||
|
||||
测试源程序为test/30_test_reg_alloc.sy,验证经过实验五生成的sysyc编译器,能够生成完成了寄存器分配的的汇编代码,交叉编译后的二进制文件可以在Qemu模拟器/树莓派上正确运行。
|
||||
|
||||
1. 功能验证:能够生成完成了寄存器分配的的汇编代码,交叉编译后的二进制文件可以在Qemu模拟器/树莓派上运行且结果正确;
|
||||
2. 性能验证:经寄存器分配后的代码在树莓派上的运行时间有效缩短。
|
||||
|
||||
|
||||
## 实验6:循环优化
|
||||
|
||||
### 实验任务
|
||||
|
||||
在之前实现编译器的基础上,在编译中端增加循环优化支持。
|
||||
|
||||
+ 任务一
|
||||
针对特定的测试用例,手动应用循环变换技术,如循环展开、循环融合、循环拆分等循环优化手段。对比变换前后的程序性能,例如程序执行时间、资源消耗等指标的测量和评估,分析优化效果。
|
||||
+ 任务二
|
||||
SROA(标量替换),在编译中端增加标量替换的优化遍,能够对循环进行一致性依赖分析,识别循环中存在的可替换内存访问模式,并将其替换为标量变量,以减少内存访问开销并可能揭示更多的优化机会。
|
||||
+ 任务三
|
||||
循环展开,在编译中端增加循环展开的优化遍,增加指令级并行性,减少循环控制开销。同时分析循环展开对程序性能的影响,包括执行速度提升和潜在的代码膨胀问题。
|
||||
+ 进阶内容:在编译中端增加循环分块(Loop Tiling)的优化遍。将循环嵌套划分为更小、更规则的块,以提高数据局部性和缓存利用率。探索循环分块对程序性能的具体影响,以及如何根据目标硬件特性调整分块策略。
|
||||
|
||||
|
||||
### 实验目标
|
||||
|
||||
通过实验,加深学生对编译器中循环优化算法的理解,提升他们在实际编译器开发中应用这些技术的能力。
|
||||
|
||||
### 实验方法与主要步骤
|
||||
|
||||
#### 实验方法
|
||||
|
||||
+ 可以从现有的成熟编译器入手,例如LLVM,分析LLVM中关于循环优化遍的实现。通过LLVM中的工具,对循环变化前后的控制流图进行输出,方便直观感受循环变换对循环结构带来的影响。
|
||||
+ 之后根据课堂上的理论知识,设计所需的循环优化算法,并将其实现为编译器中端的新优化遍。
|
||||
+ 最后,对优化结果进行评估,根据性能分析结果调整优化策略。
|
||||
|
||||
#### 主要步骤
|
||||
|
||||
1. 在编译器中端实现循环分析遍,该遍能够识别程序中的循环结构,并收集循环相关的信息,如循环边界、循环内的变量及其数据依赖关系等。
|
||||
2. 根据实验任务要求,依次实现标量替换优化遍、循环展开优化遍和循环分块优化遍。
|
||||
3. 如果在实验四中实现了遍管理器,将本实验实现的循环优化遍进行管理。
|
||||
4. 将测试程序依次经过三个优化遍处理,对每次优化前后的程序进行基准测试,收集性能数据。分析每种优化方案对程序带来的性能提升,考虑不同优化顺序对性能优化带来的影响。
|
||||
|
||||
### 实验测试
|
||||
|
||||
测试程序为test/40_mm1.sy, test/41_mm2.sy, test/42_mm3.sy。经过实验六生成的sysyc编译器
|
||||
|
||||
1. 能够生成经过标量替换、循环展开或循环分块优化后的汇编代码,交叉编译后的二进制文件可以在Qemu模拟器/树莓派上运行且结果正确
|
||||
2. 对比优化前和优化后的IR,查看是否达到了要实现的优化目标。
|
||||
3. 对程序的性能指标进行分析,如程序执行时间、程序大小、访存次数等,计算优化带来的性能收益,并分析其中的原因。
|
||||
|
||||
|
||||
# 实验7:自动向量化
|
||||
|
||||
### 实验任务
|
||||
|
||||
在已有编译器框架的基础上,实验任务分为三个部分,旨在逐步引导学生掌握向量化技术的应用与开发。
|
||||
+ 任务一:测试现有编译器的向量化支持,通过给定的测试用例,对Clang编译器的自动向量化功能进行测试。熟悉Clang编译器在自动向量化和编译指导向量化方面的使用方法。分析给定循环的向量化可能性,判断循环是否适合向量化,并用Clang编译器进行测试,对比循环向量化前后的中间表示(IR),理解向量化对IR的影响。
|
||||
+ 任务二:从理论出发,设计并实现编译器中端的向量化优化遍。通过循环分析,识别适合向量化的循环,并进行必要的变换以满足向量化条件。
|
||||
+ 任务三:探索NEON指令集扩展在向量化中的应用,并通过Intrinsic函数实现向量化。
|
||||
+ 进阶任务:实现循环的多版本控制,从硬件角度看,由于向量运算的启动开销比变量运算大,所以当向量长度较小时,向量运算速度可能会低于对应的标量运算速度。所以进阶任务是对循环进行版本控制,为循环生成一个标量执行版本和向量执行版本。当迭代次数小时,用标量计算该循环,反之用向量计算。
|
||||
|
||||
### 实验目标
|
||||
|
||||
通过实验,理解向量化的基本概念,包括SIMD架构、自动向量化和编译指导向量化的原理。熟悉Clang编译器的自动向量化功能,理解编译指导向量化的使用方法。最终设计并实现编译器中端的向量化优化遍,通过循环分析识别并转换适合向量化的循环。
|
||||
|
||||
### 实验方法与主要步骤
|
||||
|
||||
#### 实验方法
|
||||
|
||||
可以先从简单的向量化场景出发,针对特定的指令进行向量化操作,然后在此基础上进行补充,考虑更全面的向量化场景。
|
||||
例如,可以先对循环中的以下两种指令进行循环向量化:
|
||||
1. 循环体中的```dst[i] = c``` (c是常数, i是迭代变量)
|
||||
2. 循环体中的```dst[i]=src[i]```
|
||||
|
||||
在确定要并行化的循环形式之后,对原始循环按照如下流程实现向量化:
|
||||
1. 检查循环体中的指令,确保符合向量化的基本条件。
|
||||
例如,循环迭代步为1,迭代变量递增,比较指令为小于等。
|
||||
2. 识别循环体中可以向量化的语句: ```dst[i] = c``` 或 ```dst[i]=src[i]```
|
||||
3. 更新循环的迭代步: ```i=i+1``` => ```i=i+4```
|
||||
4. 尾循环处理。
|
||||
上述就是针对简单场景进行循环向量化的实现流程,进而可以扩展到更复杂的应用场景中。
|
||||
|
||||
#### 主要步骤
|
||||
1. 实现循环向量化所需要的分析遍,例如数据依赖分析。同时,为了对不能进行向量化的循环进行转化以实现向量化,还需要实现基本的循环优化遍,例如循环分裂、循环剥除等。
|
||||
2. 编码实现循环向量化优化遍,将设计的算法集成到编译器中端。
|
||||
3. 如果在实验四中实现了遍管理器,将本实验实现的循环向量化优化遍进行管理。
|
||||
4. 分析性能数据,评估向量化对性能的具体影响,并根据测试结果调整优化策略。
|
||||
|
||||
### 实验测试
|
||||
测试程序包括test/40_mm1.sy, test/41_mm2.sy, test/42_mm3.sy。通过本实验七生成的 sysyc 编译器需要满足以下要求:
|
||||
|
||||
1. 能够生成经过循环向量化优化后的汇编代码,交叉编译后的二进制文件可以在Qemu模拟器/树莓派上运行且结果正确。
|
||||
2. 对比优化前和优化后的IR,查看是否达到了要实现的优化目标。分析 IR 的变化,理解向量化对代码结构的影响。
|
||||
3. 对程序的性能指标进行分析,如程序执行时间、程序大小、访存次数等,计算优化带来的性能收益,并分析其中的原因。
|
||||
|
||||
|
||||
|
||||
# 实验8:自动并行化
|
||||
|
||||
### 实验任务
|
||||
|
||||
在已有编译器框架的基础上,实现多线程并行技术。
|
||||
+ 任务一:对给定的测试程序进行手工并行化,使用OpenMP的编译指导命令来指导编译器生成并行代码。对比并行化前后的性能,包括但不限于执行时间、资源消耗等,分析并行化带来的性能提升原因。
|
||||
+ 任务二:在编译器中端开发一个并行化优化遍,自动将给定的矩阵相乘的串行程序进行并行化处理,以提高计算效率。对于不满足并行化的循环程序,能够进行适当的循环变换,暴露循环中的并行特征。
|
||||
+ 任务三:通过交叉编译,将并行化后的程序部署到开发板上,检查程序输出的正确性,确保并行化没有改变程序的逻辑结果。记录并行化前后的程序性能数据,如执行时间、内存使用情况等,并计算加速比。
|
||||
+ 进阶任务:选择一个复杂算法(如快速傅里叶变换、LU分解等),分析其并行化潜力。在编译器中实现对该算法的并行化优化遍,对比并行化前后的性能数据,分析并行化在不同算法中的应用效果。
|
||||
|
||||
|
||||
### 实验目标
|
||||
|
||||
深入理解并行化的判定条件,能够对不满足并行化的循环进行简单的循环变换从而实现并行化,实现基本的并行化优化遍。通过矩阵乘法等计算密集型程序的优化,实际演示并行化技术对提升程序性能的效果,并与现有的成熟自动并行化编译器进行效果比较,从而分析并行化性能提升的原因。
|
||||
|
||||
### 实验方法与主要步骤
|
||||
|
||||
#### 实验方法
|
||||
|
||||
+ 以矩阵乘测试程序为例,首先需要对程序中的循环进行依赖性检查,识别出其中不存在跨迭代依赖的循环。对于不满足并行化条件的循环进行必要的循环优化,暴露出其中的并行化机会。
|
||||
|
||||
+ 识别出可并行化的循环后,需要对线程任务进行划分。
|
||||
|
||||
+ 由于线程创建、销毁和同步等操作具有性能损耗,以矩阵乘为例,在并行化时要使线程处理的任务粒度足够大,尽可能并行化最外层循环。
|
||||
|
||||
+ 计算新的循环结构,确定每个线程要处理循环的上下界。
|
||||
最后修改循环结构,并在循环前后分别插入线程创建(```_thread_create```)和线程等待(```_thread_join```)函数。
|
||||
|
||||
#### 主要步骤
|
||||
|
||||
1. 实现循环并行所需要的分析遍,例如数据依赖分析。同时,为了对不能进行并行化的循环进行转化以实现并行化,还需要实现基本的循环优化遍,例如循环分裂、循环剥除等。
|
||||
2. 实现循环并行化对应的优化算法,实现对应的循环并行化优化遍
|
||||
3. 如果在实验四中实现了遍管理器,将本实验实现的循环并行化优化遍进行管理。
|
||||
4. 在开发板上运行并行化后的程序,验证其输出的正确性。并收集并行化前后的性能数据,计算并行化前后的加速比,量化并行化带来的性能提升。
|
||||
|
||||
### 实验测试
|
||||
|
||||
测试程序包括 test/40_mm1.sy, test/41_mm2.sy, test/42_mm3.sy。通过本实验八生成的 sysyc 编译器需要满足以下要求:
|
||||
|
||||
1. 能够生成经过循环并行化优化后的汇编代码,交叉编译后的二进制文件可以在Qemu模拟器/树莓派上运行且结果正确。
|
||||
2. 对比优化前和优化后的IR,查看是否达到了要实现的优化目标。
|
||||
3. 记录并行化前后的程序性能数据,包括但不限于执行时间、内存使用、处理器负载等,计算加速比,评估并行化对程序性能的提升效果。
|
||||
|
||||
|
||||
## 致谢
|
||||
|
||||
[全国大学生计算机系统能力大赛](https://compiler.educg.net): 本实验使用全国大学生计算机系统能力大赛-编译系统实现赛SysY语言规范,测试用例部分参考大赛设计。
|
||||
|
||||
mysysy/ $ bash setup.sh
|
||||
```
|
||||
|
||||
### 常用操作
|
||||
|
||||
- 查看帮助信息:
|
||||
```bash
|
||||
mysysy/ $ build/bin/sysyc -h
|
||||
```
|
||||
- 运行并打印IR:
|
||||
```bash
|
||||
mysysy/ $ build/bin/sysyc -s ir testdata/functional/21_if_test2.sy
|
||||
```
|
||||
- 运行并打印汇编码:
|
||||
```bash
|
||||
build/bin/sysyc -s asm testdata/functional/21_if_test2.sy
|
||||
```
|
||||
或者输出到文件中:
|
||||
```bash
|
||||
build/bin/sysyc -S testdata/functional/21_if_test2.sy -o 21_if_test2.s
|
||||
```
|
||||
- 运行并打印IR(包含调试信息):
|
||||
```bash
|
||||
build/bin/sysyc -s ird testdata/functional/21_if_test2.sy
|
||||
```
|
||||
- 运行并打印汇编码(包含调试信息):
|
||||
```bash
|
||||
build/bin/sysyc -s asmd testdata/functional/21_if_test2.sy
|
||||
```
|
||||
|
||||
### 配套脚本
|
||||
(TODO: 需要完善)
|
||||
94
TODO.md
94
TODO.md
@ -1,94 +0,0 @@
|
||||
要打通从SysY到RISC-V的完整编译流程,以下是必须实现的核心模块和关键步骤(按编译流程顺序)。在你们当前IR生成阶段,可以优先实现这些基础模块来快速获得可工作的RISC-V汇编输出:
|
||||
|
||||
### 1. **前端必须模块**
|
||||
- **词法/语法分析**(已完成):
|
||||
- `SysYLexer`/`SysYParser`:ANTLR生成的解析器
|
||||
- **IR生成核心**:(已完成)
|
||||
- `SysYIRGenerator`:将AST转换为中间表示(IR)
|
||||
- `IRBuilder`:构建指令和基本块的工具类(你们正在实现的部分)
|
||||
- **IR打印器**:(基本完成)
|
||||
- `SysYIRPrinter`: 打印llvm ir格式的指令,优化遍后查看优化效果,la指令,subarray数组翻译范式需要改进
|
||||
|
||||
### 2. **中端必要优化(最小集合)**
|
||||
- **CFG优化**:(待测试)
|
||||
- `SysYIROptPre`:CFG优化顺便解决IR生成的缺陷(void自动添加ret指令,合并嵌套if/while语句生成的多个exit(后续可以实现回填机制))
|
||||
|
||||
常量传播
|
||||
| 优化阶段 | 关键作用 | 是否必须 |
|
||||
|-------------------|----------------------------------|----------|
|
||||
| `Mem2Reg` | 消除冗余内存访问,转换为SSA形式 | ✅ 核心 |(必须)
|
||||
| `DCE` (死代码消除) | 移除无用指令 | ✅ 必要 |(必须)
|
||||
| `DFE` (死函数消除) | 移除未使用的函数 | ✅ 必要 |(必须)
|
||||
| `Global2Local` | 全局变量降级为局部变量 | ✅ 重要 |
|
||||
|
||||
还需要做 Reg2Mem
|
||||
|
||||
|
||||
### 3. **后端核心流程(必须实现)**
|
||||
```mermaid
|
||||
graph LR
|
||||
A[IR指令选择] --> B[寄存器分配]
|
||||
B --> C[指令调度]
|
||||
C --> D[汇编生成]
|
||||
```
|
||||
|
||||
1. **指令选择**(关键步骤):
|
||||
- `DAGBuilder`:将IR转换为有向无环图(DAG)
|
||||
- `DAGCoverage`:DAG到目标指令的映射
|
||||
- `Mid2End`:IR到机器指令的转换接口
|
||||
|
||||
2. **寄存器分配**:
|
||||
- `RegisterAlloc`:基础寄存器分配器(可先实现简单算法如线性扫描)
|
||||
|
||||
3. **汇编生成**:
|
||||
- `RiscvPrinter`:将机器指令输出为RISC-V汇编
|
||||
- 实现基础指令集:`add`/`sub`/`lw`/`sw`/`beq`/`jal`等
|
||||
|
||||
### 4. **最小可工作流程**
|
||||
```cpp
|
||||
// 精简版编译流程(跳过复杂优化)
|
||||
int main() {
|
||||
// 1. 前端解析
|
||||
auto module = sysy::SysYIRGenerator().genIR(input);
|
||||
|
||||
// 2. 关键中端优化
|
||||
sysy::Mem2Reg(module).run(); // 必须
|
||||
sysy::Global2Local(module).run(); // 必须
|
||||
sysy::DCE(module).run(); // 推荐
|
||||
|
||||
// 3. 后端代码生成
|
||||
auto backendModule = mid2end::CodeGenerater().run(module);
|
||||
riscv::RiscvPrinter().print("output.s", backendModule);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. **当前开发优先级建议**
|
||||
1. **完成IR生成**:
|
||||
- 确保能构建基本块、函数、算术/内存/控制流指令
|
||||
- 实现`createCall`/`createLoad`/`createStore`等核心方法
|
||||
|
||||
2. **实现Mem2Reg**:
|
||||
- 插入Phi节点
|
||||
- 变量重命名(关键算法)
|
||||
|
||||
3. **构建基础后端**:
|
||||
- 指令选择:实现IR到RISC-V的简单映射(例如:`IRAdd` → `add`)
|
||||
- 寄存器分配:使用无限寄存器方案(后期替换为真实分配)
|
||||
- 汇编打印:支持基础指令输出
|
||||
|
||||
> **注意**:循环优化、函数内联、高级寄存器分配等可在基础流程打通后逐步添加。初期可跳过复杂优化。
|
||||
|
||||
### 6. 调试建议
|
||||
- 添加IR打印模块(`SysYPrinter`)验证前端输出
|
||||
- 使用简化测试用例:
|
||||
```c
|
||||
int main() {
|
||||
int a = 1;
|
||||
int b = a + 2;
|
||||
return b;
|
||||
}
|
||||
```
|
||||
- 逐步扩展支持:
|
||||
1. 算术运算 → 2. 条件分支 → 3. 函数调用 → 4. 数组访问
|
||||
|
||||
通过聚焦这些核心模块,你们可以快速打通从SysY到RISC-V的基础编译流程,后续再逐步添加优化传递提升代码质量。
|
||||
BIN
antlr_src.tar.gz
Normal file
BIN
antlr_src.tar.gz
Normal file
Binary file not shown.
9
setup.sh
Normal file
9
setup.sh
Normal file
@ -0,0 +1,9 @@
|
||||
tar -xzf antlr_src.tar.gz
|
||||
mkdir -p build
|
||||
cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build -- -j$(nproc)
|
||||
|
||||
echo "构建成功。用此命令启动SysY编译器: build/bin/sysyc -h"
|
||||
echo "后续重新构建命令:"
|
||||
echo "cmake -B build -S . -DCMAKE_BUILD_TYPE=Debug"
|
||||
echo "cmake --build build -- -j$(nproc)"
|
||||
Reference in New Issue
Block a user