15750821961 4 years ago
commit 1670909a3f

@ -1,5 +1,4 @@
# PW6 实验文档
本实验由黄庄湫、吴毓辰助教设计
- [PW6 实验文档](#pw6-实验文档)
- [0. 前言](#0-前言)
- [主要工作](#主要工作)
@ -95,12 +94,12 @@
* 实验要求、问题回答、实验设计、实验难点及解决方案、实验总结、实验反馈、组间交流(具体参考[report.md](./report.md))
* 本次实验报告**参与**评分标准.
* 提交规范:
* 不破坏目录结构(`report.md`如果需要放图片,请新建`figs`文件夹放在`./report`下)
* 不破坏目录结构(`report.md`如果需要放图片,请新建`figs`文件夹放在`./report`下,并将图片放在`figs`文件夹内)
* 不上传临时文件(凡是自动生成的文件和临时文件请不要上传)
* **组队实验要求**
* 由队长在 `./report/contribution.md` 中解释每位队员的贡献,并说明贡献比例
* 组队实验意味着合作,但是小组间的交流是受限的,且**严格禁止**代码的共享。除此之外,如果小组和其它组进行了交流,必须在 `./report/report.md` 中记录交流的小组和你们之间交流内容
* 评分标准: 本次实验分为3部分, 为组队实验, 请合理安排分工, 我们会根据组长填写的贡献比进行分数分配如果对贡献比有异议的组员可根据git的提交记录申请仲裁建议利用好`git branch`
* 评分标准: 本次实验分为3部分, 为组队实验, 请合理安排分工, 我们会根据组长填写的贡献比进行分数分配如果对贡献比有异议的组员可根据git的提交记录申请仲裁建议利用好git的分支功能
* **禁止执行恶意代码违者本次实验0分处理**
* 第一部分10分: `.ll`运行结果正确(1个2分, 注释共2分)
* 第二部分20分: `.cpp`运行结果正确(1个5分)

@ -1,33 +1,68 @@
# IR实验阶段一
本实验由黄庄湫、吴毓辰助教设计
[TOC]
## 0 前言
本次实验的目的是让大家熟悉阶段三所需相关知识:
LLVM IR
---
## 1 任务描述
[了解LLVM IR](#llvm-ir介绍)
[通过clang生成的.ll了解LLVM IR与c代码的对应关系](#例子-利用clang生成的ll)
[根据c程序手写.ll文件实现相同功能](#你需要做-手动编写ll)
### 任务描述
本关任务熟悉LLVM IR并根据给出的4个sy程序手写ll文件以实现相同功能。
## 2 实验内容
### 2.1 LLVM IR介绍
### 相关知识
#### LLVM IR介绍
根据[维基百科](https://zh.wikipedia.org/zh-cn/LLVM)的介绍LLVM是一个自由软件项目它是一种编译器基础设施以C++写成包含一系列模块化的编译器组件和工具链用来开发编译器前端和后端。IR的全称是Intermediate Representation即中间表示。LLVM IR是一种类似于汇编的底层语言。
LLVM IR的具体指令可以参考[Reference Manual](http://llvm.org/docs/LangRef.html)。但是你会发现其内容庞杂。虽然助教认为,高效地查阅官方文档及手册是非常必要的一项技能,但是由于其手册过于复杂,因此助教筛选了后续实验中将要用到的子集,总结为了[精简的IR Reference手册](./SysYIR.md)
LLVM IR的具体指令可以参考[Reference Manual](http://llvm.org/docs/LangRef.html)。但是你会发现其内容庞杂。虽然助教认为,高效地查阅官方文档及手册是非常必要的一项技能,但是由于其手册过于复杂,因此助教筛选了后续实验中将要用到的子集,总结为了**精简的IR Reference手册**`doc/SysYIR.md`
作为一开始的参考,你可以先阅读其中`IR Features`和`IR Format`两节,后续有需要再反复参考。
### 2.2 例子: 利用clang生成的.ll
阅读`SysYF_Student/SysYF_Task1/ta_demo/go_upstairs.c`
在对应文件夹内输入`clang -S -emit-llvm go_upstairs.c`指令,你可以得到对应的`go_upstairs.ll`
你需要结合`go_upstairs.c`阅读`go_upstairs.ll`理解其中每条LLVM IR指令与c代码的对应情况。
#### 样例学习
<details>
<summary> go_upstairs.c点击展开 </summary>
```c
int num[2] = {4, 8};
int x[1];
int n;
int tmp = 1;
int climbStairs(int n) {
if(n < 4)
return n;
int dp[10];
dp[0] = 0;
dp[1] = 1;
dp[2] = 2;
int i;
i = 3;
while(i<n+1){
dp[i] = dp[i-1] + dp[i-2];
i = i + 1;
}
return dp[n];
}
int main(){
int res;
n=num[0];
x[0] = num[tmp];
res = climbStairs(n + tmp);
return res - x[0];
}
```
</details>
阅读`SysYF_Student/SysYF_Task1/ta_demo/go_upstairs.c`。
在`SysYF_Student/SysYF_Task1/ta_demo`文件夹内输入`clang -S -emit-llvm go_upstairs.c`指令,你可以得到对应的`go_upstairs.ll`。
你需要结合`go_upstairs.c`阅读`go_upstairs.ll`理解其中每条LLVM IR指令与C代码的对应情况。
通过`lli go_upstairs.ll; echo $?`指令,你可以测试`go_upstairs.ll`执行结果的正确性。
### 2.3 你需要做: 手动编写.ll
助教在`SysYF_Student/SysYF_Task1/student_sy/`内提供了四个简单的sy程序assign_test.syfunc_test.syif_test.sywhile_test.sy
你需要在`SysYF_Student/SysYF_Task1/student_ll/`内手工完成自己的assign_test.llfunc_test.llif_test.llwhile_test.ll文件以实现与上述C程序相同的逻辑功能。你需要添加必要的注释`.ll`文件的注释是以`;`开头的
必要的情况下,你可以参考`clang -S -emit-llvm`的输出,但是你提交的结果必须避免同此输出一字不差
注:`.sy`文件是我们定义的语言文件,`clang`无法直接识别
### 本关具体任务
1. 助教在`SysYF_Student/SysYF_Task1/student_sy/`内提供了四个简单的sy程序`assign_test.sy``func_test.sy``if_test.sy``while_test.sy`。
你需要在`SysYF_Student/SysYF_Task1/student_ll/`内手工完成自己的`assign_test.ll``func_test.ll``if_test.ll``while_test.ll`文件以实现与上述C程序相同的逻辑功能。
你需要在`ll`文件内添加必要的注释,`ll`文件的注释是以`;`开头的。
必要的情况下,你可以参考`clang -S -emit-llvm`的输出,但是你提交的结果必须避免同此输出一字不差。
2. 在`report.md`内回答[思考题](#思考题)
### 2.4 运行.ll文件
### 运行说明
- `lli`会运行`*.ll`文件
- `$?`的内容是上一条命令所返回的结果,而`echo $?`可以将其输出到终端中
- 使用`clang`时,注意`sy`文件是我们定义的语言文件,`clang`是无法直接识别的
### 思考题
请在`report/report.md`中详细回答下述思考题。

@ -1,28 +1,110 @@
# IR实验阶段二
本实验由黄庄湫、吴毓辰助教设计
[TOC]
## 0 前言
本次实验的目的是让大家熟悉阶段三所需相关知识:
SysY IR由助教编写的LLVM IR的轻量级C++接口)。
---
## 1 任务描述
[了解SysY IR](#sysy-ir---llvm-ir的c接口)
[通过助教提供的C++例子了解SysY IR的C++接口及实现](#例子-利用sysy-ir--cpp-生成ll)
[根据c程序手写C++文件调用SysY IR的API生成相同功能的.ll文件](#你需要做-利用sysy-ir--c编写生成ll的程序)
### 任务描述
本关任务熟悉SysY IR接口并根据给出的4个C程序手写C++代码调用SysY IR接口生成与sy文件功能相同的ll文件。
## 2 实验内容
### 2.1 SysY IR - LLVM IR的C++接口
由于LLVM IR官方的C++接口的文档同样过于冗长助教提供了SysY IR这一C++接口库。你需要阅读[SysY IR核心类的介绍](./SysYIR.md)
### 相关知识
#### SysY IR - LLVM IR的C++接口
由于LLVM IR官方的C++接口的文档同样过于冗长助教提供了SysY IR这一C++接口库。你需要阅读**SysY IR核心类的介绍**`doc/SysYIR.md`
本关会要求大家通过SysY IR根据AST构建生成LLVM IR。所以你需要仔细阅读文档了解其接口的设计。
### 2.2 例子: 利用SysY IR + C++ 生成.ll
为了让大家更直观地感受并学会LightIR接口的使用助教提供了`SysYF_Student/SysYF_Task2/ta_demo/go_upstairs_gen.cpp`。
#### 样例学习
<details>
<summary> go_upstairs_gen.cpp核心部分点击展开 </summary>
```cpp
// 全局数组,num,x
auto *arrayType_num = ArrayType::get(Int32Type, 2);
auto *arrayType_x = ArrayType::get(Int32Type, 1);
auto zero_initializer = ConstantZero::get(Int32Type, module);
std::vector<Constant *> init_val;
init_val.push_back(CONST_INT(4));
init_val.push_back(CONST_INT(8));
auto num_initializer = ConstantArray::get(arrayType_num, init_val);
auto num = GlobalVariable::create("num", module, arrayType_num, false, num_initializer);// 是否是常量定义,初始化常量(ConstantZero类)
auto x = GlobalVariable::create("x", module, arrayType_x, false, zero_initializer);// 参数解释: 名字name所属module全局变量类型type
auto n = GlobalVariable::create("n", module, Int32Type, false, zero_initializer);
auto tmp = GlobalVariable::create("tmp", module, Int32Type, false, CONST_INT(1));
// climbStairs函数
// 函数参数类型的vector
std::vector<Type *> Ints(1, Int32Type);
//通过返回值类型与参数类型列表得到函数类型
auto climbStairsFunTy = FunctionType::get(Int32Type, Ints);
// 由函数类型得到函数
auto climbStairsFun = Function::create(climbStairsFunTy,
"climbStairs", module);
// BB的名字在生成中无所谓,但是可以方便阅读
auto bb = BasicBlock::create(module, "entry", climbStairsFun);
builder->set_insert_point(bb); // 一个BB的开始,将当前插入指令点的位置设在bb
auto retAlloca = builder->create_alloca(Int32Type); // 在内存中分配返回值的位置
auto nAlloca = builder->create_alloca(Int32Type); // 在内存中分配参数n的位置
std::vector<Value *> args; // 获取climbStairs函数的形参,通过Function中的iterator
for (auto arg = climbStairsFun->arg_begin(); arg != climbStairsFun->arg_end(); arg++) {
args.push_back(*arg); // * 号运算符是从迭代器中取出迭代器当前指向的元素
}
builder->create_store(args[0], nAlloca); // store参数n
auto retBB = BasicBlock::create(
module, "", climbStairsFun); // return分支,提前create,以便true分支可以br
auto nLoad = builder->create_load(nAlloca); // 将参数n load上来
auto icmp = builder->create_icmp_lt(nLoad, CONST_INT(4)); // n和4的比较,注意ICMPLT
auto trueBB = BasicBlock::create(module, "trueBB_if", climbStairsFun); // true分支
auto falseBB = BasicBlock::create(module, "falseBB_if", climbStairsFun); // false分支
builder->create_cond_br(icmp, trueBB, falseBB); // 条件BR
DEBUG_OUTPUT // 我调试的时候故意留下来的,以醒目地提醒你这个调试用的宏定义方法
builder->set_insert_point(trueBB); // if true; 分支的开始需要SetInsertPoint设置
nLoad = builder->create_load(nAlloca);
builder->create_store(nLoad, retAlloca);
builder->create_br(retBB); // br retBB
builder->set_insert_point(falseBB); // if false
auto *arrayType_dp = ArrayType::get(Int32Type, 10);
auto dpAlloca = builder->create_alloca(arrayType_dp);
auto dp0Gep = builder->create_gep(dpAlloca, {CONST_INT(0), CONST_INT(0)});
builder->create_store(CONST_INT(0), dp0Gep);
auto dp1Gep = builder->create_gep(dpAlloca, {CONST_INT(0), CONST_INT(1)});
builder->create_store(CONST_INT(1), dp1Gep);
auto dp2Gep = builder->create_gep(dpAlloca, {CONST_INT(0), CONST_INT(2)});
builder->create_store(CONST_INT(2), dp2Gep);
auto iAlloca = builder->create_alloca(Int32Type);
builder->create_store(CONST_INT(3), iAlloca);
auto condBB = BasicBlock::create(module, "condBB_while", climbStairsFun); // 条件BB
trueBB = BasicBlock::create(module, "trueBB_while", climbStairsFun); // true分支
falseBB = BasicBlock::create(module, "falseBB_while", climbStairsFun); // false分支
builder->create_br(condBB);
builder->set_insert_point(condBB);
//后略, 详细见代码文件
```
</details>
为了让大家更直观地感受并学会SysY IR接口的使用助教提供了`SysYF_Student/SysYF_Task2/ta_demo/go_upstairs_gen.cpp`。
该C++程序会生成与go_upstairs.c逻辑相同的LLVM IR文件。助教提供了详尽的注释一定要好好利用
### 2.3 你需要做: 利用SysY IR + C++编写生成.ll的程序
你需要在`SysYF_Student/SysYF_Task2/student_cpp/`文件夹中调用SysY IR接口编写自己的assign_gen.cppfunc_gen.cppif_gen.cppwhile_gen.cpp程序以生成与phase1的四个sy程序相同逻辑功能的`.ll`文件。
### 本关具体任务
1. 你需要在`SysYF_Student/SysYF_Task2/student_cpp/`文件夹中调用SysY IR接口编写自己的`assign_gen.cpp``func_gen.cpp``if_gen.cpp``while_gen.cpp`程序以生成与phase1的四个sy程序相同逻辑功能的ll文件。
2. 在`report.md`内回答[思考题](#思考题)
### 2.4 编译、运行和验证
### 编译、运行和验证
`SysYF_Student/SysYF_Task2/build/` 下执行:
``` shell
# 如果存在 CMakeCache.txt 要先删除
@ -30,9 +112,16 @@ SysY IR由助教编写的LLVM IR的轻量级C++接口)。
cmake ..
make
```
你可以得到对应`assign_gen.cpp``func_gen.cpp``if_gen.cpp``while_gen.cpp``go_upstairs_gen.cpp`的可执行文件`assign_generator``func_generator``if_generator``while_generator``go_upstairs_generator`
之后直接执行可执行文件即可得到对应`.ll`文件:
你可以得到对应`assign_gen.cpp``func_gen.cpp``if_gen.cpp``while_gen.cpp``go_upstairs_gen.cpp`的可执行文件`assign_generator``func_generator``if_generator``while_generator``go_upstairs_generator`
之后直接执行可执行文件即可得到对应ll文件
``` shell
# 在build文件夹内
./go_upstairs_generator
```
### 思考题
请在`report/report.md`中详细回答下述思考题。
1. 请给出`SysYIR.md`中提到的两种getelementptr用法的区别, 并解释原因:
- `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
- `%2 = getelementptr i32, i32* %1, i32 %0`

@ -1,24 +1,15 @@
# IR实验阶段三
本实验由黄庄湫、吴毓辰助教设计
[TOC]
## 0 前言
本次实验我们要使用访问者模式来实现 IR 自动生成。
对于产生的IR 我们可以调用 clang 生成可执行文件,这样一个初级的 SysYF 编译器就完成啦!
---
## 1 任务描述
阅读[SysYF 的语义规则](../SysYF语言定义.pdf),注意本次实验必做部分语言可能与前几次实验有不同
阅读[SysY IR 核心类介绍](./SysYIR.md)
阅读[实验框架](#实验框架),理解如何使用框架以及注意事项
修改 `src/SysYBuilder/SysYBuilder.cpp` 来实现自动 IR 产生的算法,使得它能正确编译任何合法的 SysYF 程序
注: 本次实验不需要实现多维数组
## 2 实验框架
### 任务描述
本关任务:编写`SysYBuilder.cpp`文件,以实现 IR 的自动生成
### 相关知识
#### 实验框架
本次实验使用了由 C++ 编写的 SysY IR 来生成 LLVM IR。为了便于大家进行实验该框架自动完成了语法树到 C++ 上的抽象语法树的转换。
在SysYBuilder.hpp中我们还定义了一个用于存储作用域的类`Scope`。它的作用是辅助我们在遍历语法树时,管理不同作用域中的变量。它提供了以下接口:
在`SysYBuilder.hpp`中,我们还定义了一个用于存储作用域的类`Scope`。它的作用是辅助我们在遍历语法树时,管理不同作用域中的变量。它提供了以下接口:
```cpp
// 进入一个新的作用域
void enter();
@ -28,16 +19,19 @@ void exit();
bool push(std::string name, Value *val);
// 根据名字以及是否为函数的bool值寻找到对应值
// isfunc 为 true 时为寻找函数,否则为寻找其他变量对应的值
// 思考:将函数单独处理的目的
Value* find(std::string name, bool isfunc);
// 判断当前是否在全局作用域内
bool in_global();
```
你们需要根据语义合理调用`enter`与`exit`,并且在变量声明和使用时正确调用`push`与`find`。在类`SysYfBuilder`中,有一个`Scope`类型的成员变量`scope`,它在初始化时已经将特殊函数加入了作用域中。因此,你们在进行名字查找时不需要顾虑是否需要对特殊函数进行特殊操作。
## 3 运行与调试
### 本关具体任务
1. 你需要在`src/SysYBuilder`文件夹中调用SysY IR接口填写`SysYBuilder.cpp`文件,以实现 IR 的自动生成。
2. 在`report.md`内回答[思考题](#思考题)
### 编译、运行与验证
### 3.1 运行 SysYCompiler
#### 编译运行 SysYCompiler
```sh
mkdir build
@ -46,19 +40,25 @@ cmake ..
make
```
编译后会产生 `SysYCompiler` 程序,它能将`.sy`文件输出为LLVM IR可以利用clang将IR编译成二进制文件。
当需要对 `.sy` 文件测试时,可以这样使用:
编译后会产生 `SysYCompiler` 程序它能将sy文件输出为LLVM IR。
当需要对 sy 文件测试时,可以这样使用:
```sh
SysYCompiler test.sy -emit-ir -o test.ll
```
得到对应的ll文件。
### 3.2 自动测试
#### 自动测试
助教提供了自动评测脚本, 在`SysYF_Student/SysYF_Task3/Test_H/`目录下执行`python3 test_H.py`, 即可得到评测信息
## 4 选做
### 思考题
请在`report/report.md`中详细回答下述思考题。
1. 在`scope`内单独处理`func`的好处有哪些。
2.
### 选做
对于学有余力的小组, 我们提供了选做环节, 若小组能完成选做部分, 将会有额外加分(仅针对本次实验的团队代码得分, 并且分数不能超过该部分得分上限)
@ -68,7 +68,7 @@ SysYCompiler test.sy -emit-ir -o test.ll
- 多维数组
### 4.1 多维数组
#### 多维数组
目前给出的SysY IR接口并不支持多维数组的实现因此你需要修改接口以实现多维数组的声明、初始化和使用你可以修改的内容为文件夹`include/SysYIR``include/SysYBuilder``src/SysYIR``src/SysYBuilder`内的所有内容
@ -80,8 +80,7 @@ SysYCompiler test.sy -emit-ir -o test.ll
`int a[5][2] = {1,{2,3},{4},{5,6,7}}`
`int a[5][2] = {{1,0},{2,3},{4,0},{5,6},{7,0}}`
## 5 备注
### 备注
测试样例并不止公开的20个样例, 助教准备了许多隐藏测例来考验大家:), 隐藏测例并不会放在平台上

@ -4,10 +4,6 @@
## 问题回答
请给出`SysYIR.md`中提到的两种getelementptr用法的区别, 并解释原因:
- `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
- `%2 = getelementptr i32, i32* %1, i32 %0`
## 实验设计
## 实验难点及解决方案

@ -3,7 +3,7 @@
#define CONST_INT(num) ConstantInt::get(num, module.get())
#define CONST_FLOAT(num) ConstantFloat::get(num, module.get())
// You can define global variables here
// You can define global variables and functions here
// to store state
// store temporary value
@ -29,86 +29,46 @@ void SysYBuilder::visit(SyntaxTree::Assembly &node) {
}
}
void SysYBuilder::visit(SyntaxTree::InitVal &node) {
return;
}
// You need to fill them
void SysYBuilder::visit(SyntaxTree::FuncDef &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::InitVal &node) {}
void SysYBuilder::visit(SyntaxTree::FuncFParamList &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::FuncDef &node) {}
void SysYBuilder::visit(SyntaxTree::FuncParam &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::FuncFParamList &node) {}
void SysYBuilder::visit(SyntaxTree::VarDef &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::FuncParam &node) {}
void SysYBuilder::visit(SyntaxTree::AssignStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::VarDef &node) {}
void SysYBuilder::visit(SyntaxTree::LVal &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::LVal &node) {}
void SysYBuilder::visit(SyntaxTree::Literal &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::AssignStmt &node) {}
void SysYBuilder::visit(SyntaxTree::ReturnStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::Literal &node) {}
void SysYBuilder::visit(SyntaxTree::BlockStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::ReturnStmt &node) {}
void SysYBuilder::visit(SyntaxTree::EmptyStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::BlockStmt &node) {}
void SysYBuilder::visit(SyntaxTree::ExprStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::EmptyStmt &node) {}
void SysYBuilder::visit(SyntaxTree::UnaryCondExpr &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::ExprStmt &node) {}
void SysYBuilder::visit(SyntaxTree::BinaryCondExpr &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::UnaryCondExpr &node) {}
void SysYBuilder::visit(SyntaxTree::BinaryExpr &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::BinaryCondExpr &node) {}
void SysYBuilder::visit(SyntaxTree::UnaryExpr &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::BinaryExpr &node) {}
void SysYBuilder::visit(SyntaxTree::FuncCallStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::UnaryExpr &node) {}
void SysYBuilder::visit(SyntaxTree::IfStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::FuncCallStmt &node) {}
void SysYBuilder::visit(SyntaxTree::WhileStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::IfStmt &node) {}
void SysYBuilder::visit(SyntaxTree::BreakStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::WhileStmt &node) {}
void SysYBuilder::visit(SyntaxTree::ContinueStmt &node) {
return;
}
void SysYBuilder::visit(SyntaxTree::BreakStmt &node) {}
void SysYBuilder::visit(SyntaxTree::ContinueStmt &node) {}

Loading…
Cancel
Save