Compare commits

...

No commits in common. 'cfc2c6207dd3618efa970dfc5e61988dff8f52ab' and 'dab3153471de35d1af0e333516aca2303b171a90' have entirely different histories.

3
.gitignore vendored

@ -0,0 +1,3 @@
.DS_STORE
cmake-build-debug/
build/

@ -0,0 +1,37 @@
project(SysYFCompiler)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -Wall -Wextra -Wno-unused -Wshadow -g -pedantic")
# include generated files in project environment
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/AST)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/ErrorReporter)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/Frontend)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/SysYFIR)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/SysYFIRBuilder)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/AST)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/ErrorReporter)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/Frontend)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/SysYFIR)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/SysYFIRBuilder)
add_executable(
SysYFCompiler
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
)
target_link_libraries(
SysYFCompiler
SysYFIRBuilder
IRLib
Driver
ASTPrinter
ErrReporter
)

@ -1,2 +1,117 @@
# pw__6 # PW6 实验文档
- [PW6 实验文档](#pw6-实验文档)
- [0. 前言](#0-前言)
- [主要工作](#主要工作)
- [1. 实验要求](#1-实验要求)
- [1.1 目录结构](#11-目录结构)
- [1.2 提交要求和评分标准](#12-提交要求和评分标准)
## 0. 前言
本次实验分为3关为组队实验。**本次实验请务必使用git提交**。
本次实验的目的是让大家熟悉生成中间代码所需要的相关知识: LLVM IR、 SysYF IRLLVM IR的轻量级C++接口并实际实现一个IR Builder。
在开始实验之前请确保LLVM的版本不低于10.0.1且PATH环境变量配置正确。可以通过`lli --version`命令是否可以输出10.0.1的版本信息来验证。
### 主要工作
1. 第一部分: 了解LLVM IR。通过clang生成的.ll了解LLVM IR与c代码的对应关系。相应文档见[phase1.md](./doc/phase1.md)
2. 第二部分: 了解SysYF IR。通过助教提供的c++例子了解SysYF IR的c++接口及实现。相应文档见[phase2.md](./doc/phase2.md)
3. 第三部分: 使用SysYF IR实现一个IR Builder使其可以通过抽象语法树生成LLVM兼容的IR代码。相应文档见[phase3.md](./doc/phase3.md)
4. 实验报告:在[report.md](./report/report.md)中撰写报告。
## 1. 实验要求
### 1.1 目录结构
除了下面指明你所要修改或提交的文件,其他文件请勿修改。
``` log
.
├── CMakeLists.txt
├── README.md <-
├── doc
│   ├── AST.md
│   ├── phase1.md <-
│   ├── phase2.md
│   ├── phase3.md
│   ├── SysYF语言定义.pdf
| └── SysYFIR.md <- SysYF IR
├── report
│   ├── report.md <-
│   └── contribution.md <-
├── include <-
│   ├── ...
│   └── SysYFIR
├── src
│   ├── ...
│   ├── SysYFIR
│   └── SysYFIRBuilder
| ├── CMakeLists.txt
| └── IRBuilder.cpp <-
└── Student
├── task1 <-
| ├── ll <- LLVM IR(.ll)
| | ├── assign_hand.ll
|   │   ├── fun_hand.ll
|   │   ├── if_hand.ll
|   │   └── while_hand.ll
| ├── sy
| | ├── assign_test.sy
|   │   ├── fun_test.sy
|   │   ├── if_test.sy
|   │   └── while_test.sy
| └── demo
|      └── go_upstairs.c
├── task2 <-
├── CMakeLists.txt
| ├── cpp <- .cpp
| | ├── CMakeLists.txt
| | ├── assign_gen.cpp
|   │   ├── fun_gen.cpp
|   │   ├── if_gen.cpp
|   │   └── while_gen.cpp
| ├── sy
| | ├── assign_test.sy
|   │   ├── fun_test.sy
|   │   ├── if_test.sy
|   │   └── while_test.sy
| └── demo
|      |── CMakeLists.txt
|      |── go_upstairs.sy
|      └── go_upstairs_gen.cpp <- go_upstairs.llcpp
└── task3
└── test
├── test.py <-
└── test <-
```
### 1.2 提交要求和评分标准
* 提交要求
本实验的提交要求分为两部分: 实验部分的文件和报告。
* 实验部分:
* 需要完成 `./Student/task1/ll`目录下的4个文件
* 需要完成 `./Student/task2/cpp`目录下的4个文件
* 需要完成 `./src/SysYFIRBuilder/IRBuilder.cpp`
* 需要在 `./report/report.md` 中撰写实验报告
* 实验报告内容包括:
* 实验要求、问题回答、实验设计、实验难点及解决方案、实验总结、实验反馈、组间交流(具体参考[report.md](./report.md))
* 本次实验报告**参与**评分标准.
* 提交规范:
* 不破坏目录结构(`report.md`如果需要放图片,请新建`figs`文件夹放在`./report`下,并将图片放在`figs`文件夹内)
* 不上传临时文件(凡是自动生成的文件和临时文件请不要上传)
* **组队实验要求**
* 由队长在 `./report/contribution.md` 中解释每位队员的贡献,并说明贡献比例
* 组队实验意味着合作,但是小组间的交流是受限的,且**严格禁止**代码的共享。除此之外,如果小组和其它组进行了交流,必须在 `./report/report.md` 中记录交流的小组和你们之间交流内容
* 评分标准: 本次实验分为3部分, 为组队实验, 请合理安排分工, 我们会根据组长填写的贡献比进行分数分配如果对贡献比有异议的组员可根据git的提交记录申请仲裁建议利用好git的分支功能
* **禁止执行恶意代码违者本次实验0分处理**
* 第一部分10分: `.ll`运行结果正确(1个2分, 注释共2分)
* 第二部分20分: `.cpp`运行结果正确(1个5分)
* 第三部分70分: 该部分成绩由5部分组成(团队代码得分, 实验报告得分, 迟交天数, 组员贡献比, 组长奖励加分)
* 实验检查
* 线上: 助教会在educoder上检查前两部分
* 线下: 线下检查只检查第三部分, 组长带组员到负责组长的助教处检查, 选做部分请找本次实验负责助教检查
* 迟交规定
* 迟交需要邮件通知助教:
* 邮箱: xuchaijun@mail.ustc.edu.cn
* 邮件主题: PW6迟交-学号
* 内容: 包括迟交原因、最后版本commit ID、迟交时间等
* 关于抄袭和雷同
经过助教和老师判定属于作业抄袭或雷同情况,所有参与方一律零分,不接受任何解释和反驳。
如有任何问题欢迎提issue进行批判指正。

@ -0,0 +1,28 @@
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];
}

@ -0,0 +1,30 @@
define i32 @main() #0 {
; alloc b and store 1.8 to b
%1 = alloca float, align 4 ;b
store float 0x3FFCCCCCC0000000, float* %1, align 4
; alloc a[2] and store 2 to a[0]
%2 = alloca [2 x i32], align 4 ;a
%3 = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 0, i64 0 ;a[0]
store i32 2, i32* %3
; load b
%4 = load float, float* %1, align 4
; load a[0] and convert to float
%5 = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 0, i64 0 ;a[0]
%6 = load i32, i32* %5, align 4
%7 = sitofp i32 %6 to float ;a[0] to float
; calculate b * a[0]
%8 = fmul float %4, %7
%9 = fptosi float %8 to i32
; store to a[1]
%10 = getelementptr inbounds [2 x i32], [2 x i32]* %2, i64 0, i64 1 ;a[1]
store i32 %9, i32* %10, align 4;
%11 = load i32, i32* %10, align 4
; return a[1]
ret i32 %11
}

@ -0,0 +1,51 @@
; clang -S -emit-llvm
; ModuleID = 'func_test.c'
source_filename = "func_test.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-pc-linux-gnu"
define dso_local i32 @add(i32 %0, i32 %1) #0 {
%3 = alloca i32, align 4
store i32 %0, i32* %3, align 4 ; alloca a
%4 = alloca i32, align 4
store i32 %1, i32* %4, align 4 ; alloca b
%5 = load i32, i32* %3, align 4
%6 = load i32, i32* %4, align 4
%7 = add nsw i32 %5, %6 ; a+b
%8 = sub nsw i32 %7, 1 ; a+b-1
ret i32 %8 ; return a+b-1
}
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 3, i32* %1, align 4 ; a=3
store i32 2, i32* %2, align 4 ; b=2
store i32 5, i32* %3, align 4 ; c=5
%4 = load i32, i32* %1, align 4
%5 = load i32, i32* %2, align 4
%6 = load i32, i32* %3, align 4
%7 = call i32 @add(i32 %4, i32 %5) ; add(a, b)
%8 = add nsw i32 %6, %7 ; c+add(a,b)
ret i32 %8
}
attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 1}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"Ubuntu clang version 14.0.0-1ubuntu1.1"}

@ -0,0 +1,11 @@
@a = common global i32 0, align 4
define i32 @main() #0 {
store i32 10, i32* @a, align 4
%1 = load i32, i32* @a, align 4
%2 = icmp sgt i32 %1, 0
br i1 %2, label %3, label %4
3:
ret i32 %1
4:
ret i32 0
}

@ -0,0 +1,49 @@
; clang -S -emit-llvm
;
; ModuleID = 'while_test.c'
source_filename = "while_test.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-pc-linux-gnu"
@b = common dso_local global i32 0, align 4 ; int b
@a = common dso_local global i32 0, align 4 ; int a
define dso_local i32 @main() #0 {
store i32 0, i32* @b, align 4 ; b = 0
store i32 3, i32* @a, align 4 ; a = 3
br label %1
1: ; label 1
%2 = load i32, i32* @a, align 4
%3 = icmp sgt i32 %2, 0 ; a > 0?
br i1 %3, label %4, label %9 ; true->4 false->9
4: ; label 4 while true
%5 = load i32, i32* @b, align 4 ; [b]+a
%6 = load i32, i32* @a, align 4 ; b+[a]
%7 = add nsw i32 %5, %6 ; b+a
store i32 %7, i32* @b, align 4; b = b+a
%8 = sub nsw i32 %6 , 1 ; a-1
store i32 %8, i32* @a, align 4 ; a = a-1
br label %1
9: ; label 9
%10 = load i32, i32* @b, align 4
ret i32 %10 ; return b
}
; LLVM
attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2, !3, !4} ; LLVM
!llvm.ident = !{!5} ; LLVM
!0 = !{i32 1, !"wchar_size", i32 4} ; LLVMwchar_t4
!1 = !{i32 7, !"PIC Level", i32 2} ; LLVM2
!2 = !{i32 7, !"PIE Level", i32 2} ; LLVM2
!3 = !{i32 7, !"uwtable", i32 1} ; LLVM
!4 = !{i32 7, !"frame-pointer", i32 2} ; LLVM使2
!5 = !{!"Ubuntu clang version 14.0.0-1ubuntu1.1"} ; LLVM使Ubuntu clang version 14.0.0-1ubuntu1.1
!6 = distinct !{!6, !7} ; distinct
!7 = !{!"llvm.loop.mustprogress"} ; LLVM

@ -0,0 +1,6 @@
int main(){
float b = 1.8;
int a[2] = {2};
a[1] = a[0] * b;
return a[1];
}

@ -0,0 +1,13 @@
int add(int a,int b){
return (a+b-1);
}
int main(){
int a;
int b;
int c;
a=3;
b=2;
c = 5;
return c + add(a,b);
}

@ -0,0 +1,9 @@
int a;
int main(){
a = 10;
if( a>0 ){
return a;
}
return 0;
}

@ -0,0 +1,11 @@
int a;
int b;
int main(){
b=0;
a=3;
while(a>0){
b = b+a;
a = a-1;
}
return b;
}

@ -0,0 +1,18 @@
project(task2)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -Wall -g -pedantic")
set(SYSYF_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# include generated files in project environment
include_directories(${SYSYF_SOURCE_DIR}include)
include_directories(${SYSYF_SOURCE_DIR}include/SysYFIR)
add_subdirectory(${SYSYF_SOURCE_DIR}src/SysYFIR src/SysYFIR)
add_subdirectory(demo)
add_subdirectory(cpp)

@ -0,0 +1,36 @@
add_executable(
assign_generator
assign_gen.cpp
)
target_link_libraries(
assign_generator
IRLib
)
add_executable(
func_generator
func_gen.cpp
)
target_link_libraries(
func_generator
IRLib
)
add_executable(
if_generator
if_gen.cpp
)
target_link_libraries(
if_generator
IRLib
)
add_executable(
while_generator
while_gen.cpp
)
target_link_libraries(
while_generator
IRLib
)

@ -0,0 +1,66 @@
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRStmtBuilder.h"
#include "Module.h"
#include "Type.h"
#include <iostream>
#include <memory>
#ifdef DEBUG
#define DEBUG_OUTPUT std::cout << __LINE__ << std::endl; // 输出行号的简单示例
#else
#define DEBUG_OUTPUT
#endif
#define CONST_INT(num) \
ConstantInt::create(num, module)
#define CONST_FP(num) \
ConstantFloat::create(num, module)
using namespace SysYF::IR;
int main() {
auto module = Module::create("Assign code");
auto builder = IRStmtBuilder::create(nullptr, module);
SysYF::Ptr<Type> Int32Type = Type::get_int32_type(module);
SysYF::Ptr<Type> FloatType = Type::get_float_type(module);
// main function
auto mainFun = Function::create(FunctionType::create(Int32Type, {}),
"main", module);
auto bb = BasicBlock::create(module, "entry", mainFun);
builder->set_insert_point(bb);
auto retAlloca = builder->create_alloca(Int32Type);
// b = 1.8
auto bAlloca = builder->create_alloca(FloatType);
builder->create_store(CONST_FP(1.8), bAlloca);
// a[2] = {2}
auto arrayType_a = ArrayType::get(Int32Type, 2);
auto aAlloca = builder->create_alloca(arrayType_a);
auto a0Gep = builder->create_gep(aAlloca, {CONST_INT(0), CONST_INT(0)});
builder->create_store(CONST_INT(2), a0Gep);
// a[0] * b
auto a0Load = builder->create_load(a0Gep);
auto a0Float = builder->create_sitofp(a0Load, FloatType);
auto bLoad = builder->create_load(FloatType, bAlloca);
auto a1res = builder->create_fmul(a0Float, bLoad);
// store to a[1]
auto a1res_int = builder->create_fptosi(a1res, Int32Type);
auto a1Gep = builder->create_gep(aAlloca, {CONST_INT(0), CONST_INT(1)});
builder->create_store(a1res_int, a1Gep);
// ret
builder->create_store(a1res_int, retAlloca);
auto retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
std::cout << module->print();
return 0;
}

@ -0,0 +1,113 @@
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRStmtBuilder.h"
#include "Module.h"
#include "Type.h"
#include <iostream>
#include <memory>
#ifdef DEBUG // 用于调试信息,大家可以在编译过程中通过" -DDEBUG"来开启这一选项
#define DEBUG_OUTPUT std::cout << __LINE__ << std::endl; // 输出行号的简单示例
#else
#define DEBUG_OUTPUT
#endif
#define CONST_INT(num) \
ConstantInt::create(num, module)
#define CONST_FP(num) \
ConstantFloat::create(num, module) // 得到常数值的表示,方便后面多次用到
using namespace SysYF::IR;
int main() {
auto module = Module::create("SysYF code"); // module name是什么无关紧要
auto builder = IRStmtBuilder::create(nullptr, module);
SysYF::Ptr<Type> Int32Type = Type::get_int32_type(module);
// add(a, b)
// 函数参数类型的vector
std::vector<SysYF::Ptr<Type>> Ints(2, Int32Type);
//通过返回值类型与参数类型列表得到函数类型
auto addFunTy = FunctionType::create(Int32Type, Ints);
// 由函数类型得到函数
auto addFun = Function::create(addFunTy,
"add", module);
// BB的名字在生成中无所谓,但是可以方便阅读
auto bb = BasicBlock::create(module, "entry", addFun);
builder->set_insert_point(bb); // 一个BB的开始,将当前插入指令点的位置设在bb
auto retAlloca = builder->create_alloca(Int32Type); // 在内存中分配返回值的位置
auto aAlloca = builder->create_alloca(Int32Type); // 在内存中分配参数a的位置
auto bAlloca = builder->create_alloca(Int32Type); // 在内存中分配参数b的位置
std::vector<SysYF::Ptr<Value>> args; // 获取add函数的形参,通过Function中的iterator
for (auto arg = addFun->arg_begin(); arg != addFun->arg_end(); arg++) {
args.push_back(*arg); // * 号运算符是从迭代器中取出迭代器当前指向的元素
}
builder->create_store(args[0], aAlloca); // store参数a
builder->create_store(args[1], bAlloca); // store参数b
auto aLoad = builder->create_load(aAlloca); // load参数a
auto bLoad = builder->create_load(bAlloca); // load参数b
// a+b
auto add = builder->create_iadd(aLoad, bLoad);
// a+b-1
auto sub = builder->create_isub(add, CONST_INT(1));
builder->create_store(sub, retAlloca);
auto retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
builder->create_ret(retLoad);
// main函数
auto mainFun = Function::create(FunctionType::create(Int32Type, {}),
"main", module);
bb = BasicBlock::create(module, "entry", mainFun);
// BasicBlock的名字在生成中无所谓,但是可以方便阅读
builder->set_insert_point(bb);
retAlloca = builder->create_alloca(Int32Type);
// int a;
auto a = builder->create_alloca(Int32Type);
// int b;
auto b = builder->create_alloca(Int32Type);
// int c;
auto c = builder->create_alloca(Int32Type);
// a = 3;
builder->create_store(CONST_INT(3), a);
// b = 2;
builder->create_store(CONST_INT(2), b);
// c = 5;
builder->create_store(CONST_INT(5), c);
// tmp = add(a, b);
aLoad = builder->create_load(a);
bLoad = builder->create_load(b);
auto tmp = builder->create_call(addFun, {aLoad, bLoad});
// ret = c + tmp;
auto cLoad = builder->create_load(c);
auto ret = builder->create_iadd(cLoad, tmp);
builder->create_store(ret, retAlloca);
retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
std::cout << module->print();
return 0;
}

@ -0,0 +1,61 @@
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRStmtBuilder.h"
#include "Module.h"
#include "Type.h"
#include <iostream>
#include <memory>
#ifdef DEBUG
#define DEBUG_OUTPUT std::cout << __LINE__ << std::endl; // 输出行号的简单示例
#else
#define DEBUG_OUTPUT
#endif
#define CONST_INT(num) \
ConstantInt::create(num, module)
#define CONST_FP(num) \
ConstantFloat::create(num, module)
using namespace SysYF::IR;
int main() {
auto module = Module::create("If code");
auto builder = IRStmtBuilder::create(nullptr, module);
SysYF::Ptr<Type> Int32Type = Type::get_int32_type(module);
SysYF::Ptr<Type> FloatType = Type::get_float_type(module);
auto zero_initializer = ConstantZero::create(Int32Type, module);
auto a = GlobalVariable::create("a", module, Int32Type, false, zero_initializer);
// main function
auto mainFun = Function::create(FunctionType::create(Int32Type, {}),
"main", module);
auto bb = BasicBlock::create(module, "entry", mainFun);
builder->set_insert_point(bb);
auto retAlloca = builder->create_alloca(Int32Type);
// store 10 to a
builder->create_store(CONST_INT(10), a);
auto aValue = builder->create_load(a);
// if(a > 0)
auto icmp = builder->create_icmp_gt(aValue, CONST_INT(0));
auto trueBB = BasicBlock::create(module, "trueBB_if", mainFun); // true分支
auto falseBB = BasicBlock::create(module, "falseBB_if", mainFun); // false分支
builder->create_cond_br(icmp, trueBB, falseBB); // 条件BR
// if true return a
builder->set_insert_point(trueBB);
builder->create_ret(aValue);
// if false return 0
builder->set_insert_point(falseBB);
builder->create_ret(CONST_INT(0));
std::cout << module->print();
return 0;
}

@ -0,0 +1,83 @@
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRStmtBuilder.h"
#include "Module.h"
#include "Type.h"
#include <iostream>
#include <memory>
#ifdef DEBUG // 用于调试信息,大家可以在编译过程中通过" -DDEBUG"来开启这一选项
#define DEBUG_OUTPUT std::cout << __LINE__ << std::endl; // 输出行号的简单示例
#else
#define DEBUG_OUTPUT
#endif
#define CONST_INT(num) \
ConstantInt::create(num, module)
#define CONST_FP(num) \
ConstantFloat::create(num, module) // 得到常数值的表示,方便后面多次用到
using namespace SysYF::IR;
int main() {
auto module = Module::create("SysYF code"); // module name是什么无关紧要
auto builder = IRStmtBuilder::create(nullptr, module);
SysYF::Ptr<Type> Int32Type = Type::get_int32_type(module);
// int a;
auto a = GlobalVariable::create("a", module, Int32Type, false, CONST_INT(0));
// int b;
auto b = GlobalVariable::create("b", module, Int32Type, false, CONST_INT(0));
// main函数
auto mainFun = Function::create(FunctionType::create(Int32Type, {}),
"main", module);
auto bb = BasicBlock::create(module, "entry", mainFun);
// BasicBlock的名字在生成中无所谓,但是可以方便阅读
builder->set_insert_point(bb);
auto retAlloca = builder->create_alloca(Int32Type);
// b=0;
builder->create_store(CONST_INT(0), b);
// a = 3;
builder->create_store(CONST_INT(3), a);
// whileBBs
auto condBB = BasicBlock::create(module, "condBB_while", mainFun);
auto trueBB = BasicBlock::create(module, "trueBB_while", mainFun);
auto falseBB = BasicBlock::create(module, "falseBB_while", mainFun);
builder->create_br(condBB);
// condBB
builder->set_insert_point(condBB);
auto aLoad = builder->create_load(a);
auto icmp = builder->create_icmp_gt(aLoad, CONST_INT(0));
builder->create_cond_br(icmp, trueBB, falseBB);
// trueBB
builder->set_insert_point(trueBB);
aLoad = builder->create_load(a);
auto bLoad = builder->create_load(b);
auto add = builder->create_iadd(bLoad, aLoad);
builder->create_store(add, b);
auto sub = builder->create_isub(aLoad, CONST_INT(1));
builder->create_store(sub, a);
builder->create_br(condBB);
// falseBB
builder->set_insert_point(falseBB);
bLoad = builder->create_load(b);
builder->create_store(bLoad, retAlloca);
auto retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
std::cout << module->print();
return 0;
}

@ -0,0 +1,8 @@
add_executable(
go_upstairs_generator
go_upstairs_gen.cpp
)
target_link_libraries(
go_upstairs_generator
IRLib
)

@ -0,0 +1,28 @@
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];
}

@ -0,0 +1,195 @@
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRStmtBuilder.h"
#include "Module.h"
#include "Type.h"
#include <iostream>
#include <memory>
#ifdef DEBUG // 用于调试信息,大家可以在编译过程中通过" -DDEBUG"来开启这一选项
#define DEBUG_OUTPUT std::cout << __LINE__ << std::endl; // 输出行号的简单示例
#else
#define DEBUG_OUTPUT
#endif
#define CONST_INT(num) \
ConstantInt::create(num, module)
#define CONST_FP(num) \
ConstantFloat::create(num, module) // 得到常数值的表示,方便后面多次用到
using namespace SysYF::IR;
int main() {
auto module = Module::create("SysYF code"); // module name是什么无关紧要
auto builder = IRStmtBuilder::create(nullptr, module);
SysYF::Ptr<Type> Int32Type = Type::get_int32_type(module);
// 全局数组,num,x
auto arrayType_num = ArrayType::get(Int32Type, 2);
auto arrayType_x = ArrayType::get(Int32Type, 1);
auto zero_initializer = ConstantZero::create(Int32Type, module);
std::vector<SysYF::Ptr<Constant>> init_val;
init_val.push_back(CONST_INT(4));
init_val.push_back(CONST_INT(8));
auto num_initializer = ConstantArray::create(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<SysYF::Ptr<Type>> Ints(1, Int32Type);
//通过返回值类型与参数类型列表得到函数类型
auto climbStairsFunTy = FunctionType::create(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<SysYF::Ptr<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);
auto iLoad = builder->create_load(iAlloca);
nLoad = builder->create_load(nAlloca);
auto add = builder->create_iadd(nLoad, CONST_INT(1));
icmp = builder->create_icmp_lt(iLoad, add);
builder->create_cond_br(icmp, trueBB, falseBB);
builder->set_insert_point(trueBB);
iLoad = builder->create_load(iAlloca);
auto sub = builder->create_isub(iLoad, CONST_INT(1));
auto dpGep = builder->create_gep(dpAlloca, {CONST_INT(0), sub});
auto dp1Load = builder->create_load(dpGep);
iLoad = builder->create_load(iAlloca);
sub = builder->create_isub(iLoad, CONST_INT(2));
dpGep = builder->create_gep(dpAlloca, {CONST_INT(0), sub});
auto dp2Load = builder->create_load(dpGep);
add = builder->create_iadd(dp1Load, dp2Load);
iLoad = builder->create_load(iAlloca);
dpGep = builder->create_gep(dpAlloca, {CONST_INT(0), iLoad});
builder->create_store(add, dpGep);
iLoad = builder->create_load(iAlloca);
add = builder->create_iadd(iLoad, CONST_INT(1));
builder->create_store(add, iAlloca);
builder->create_br(condBB);
builder->set_insert_point(falseBB);
nLoad = builder->create_load(nAlloca);
dpGep = builder->create_gep(dpAlloca, {CONST_INT(0), nLoad});
auto dpLoad = builder->create_load(dpGep);
builder->create_store(dpLoad, retAlloca);
builder->create_br(retBB);
builder->set_insert_point(retBB); // ret分支
auto retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
// main函数
auto mainFun = Function::create(FunctionType::create(Int32Type, {}),
"main", module);
bb = BasicBlock::create(module, "entry", mainFun);
// BasicBlock的名字在生成中无所谓,但是可以方便阅读
builder->set_insert_point(bb);
retAlloca = builder->create_alloca(Int32Type);
auto resAlloca = builder->create_alloca(Int32Type);
auto num0Gep = builder->create_gep(num, {CONST_INT(0), CONST_INT(0)}); // GEP: 这里为什么是{0, 0}呢? (实验报告相关)
auto num0Load = builder->create_load(num0Gep);
builder->create_store(num0Load, n);
auto tmpLoad = builder->create_load(tmp);
auto numGep = builder->create_gep(num, {CONST_INT(0), tmpLoad});
auto numLoad = builder->create_load(numGep);
auto x0Gep = builder->create_gep(x, {CONST_INT(0), CONST_INT(0)});
builder->create_store(numLoad, x0Gep);
nLoad = builder->create_load(n);
tmpLoad = builder->create_load(tmp);
add = builder->create_iadd(nLoad, tmpLoad);
auto call = builder->create_call(climbStairsFun, {add}); // 为什么这里传的是{add}呢?
builder->create_store(call, resAlloca);
auto resLoad = builder->create_load(resAlloca);
x0Gep = builder->create_gep(x, {CONST_INT(0), CONST_INT(0)});
auto x0Load = builder->create_load(x0Gep);
sub = builder->create_isub(resLoad, x0Load);
builder->create_store(sub, retAlloca);
retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
// 给这么多注释了,但是可能你们还是会弄很多bug
// 所以强烈建议配置AutoComplete,效率会大大提高!
// 别人配了AutoComplete,只花1小时coding
// 你没有配AutoComplete,找method花5小时,debug花5小时,肯定哭唧唧!
// 最后,如果猜不到某个IR指令对应的C++的函数,建议把指令翻译成英语然后在method列表中搜索一下
// 最后的最后,这个例子只涉及到了一点基本的指令生成,
// 对于额外的指令,包括数组,在之后的实验中可能需要大家好好搜索一下思考一下,
// 还有涉及到的C++语法,可以在gitlab上发issue提问或者向大家提供指导
// 对于这个例子里的代码风格/用法,如果有好的建议也欢迎提出!
std::cout << module->print();
return 0;
}

@ -0,0 +1,6 @@
int main(){
float b = 1.8;
int a[2] = {2};
a[1] = a[0] * b;
return a[1];
}

@ -0,0 +1,13 @@
int add(int a,int b){
return (a+b-1);
}
int main(){
int a;
int b;
int c;
a=3;
b=2;
c = 5;
return c + add(a,b);
}

@ -0,0 +1,9 @@
int a;
int main(){
a = 10;
if( a>0 ){
return a;
}
return 0;
}

@ -0,0 +1,11 @@
int a;
int b;
int main(){
b=0;
a=3;
while(a>0){
b = b+a;
a = a-1;
}
return b;
}

@ -0,0 +1,93 @@
#!/usr/bin/env python3
import subprocess
import os
IRBuild_ptn = '"{}" "-emit-ir" "-o" "{}" "{}"'
ExeGen_ptn = '"clang" "{}" "-o" "{}" "{}" "../../lib/lib.c"'
Exe_ptn = '"{}"'
def eval(EXE_PATH, TEST_BASE_PATH, optimization):
print('===========TEST START===========')
print('now in {}'.format(TEST_BASE_PATH))
dir_succ = True
for case in testcases:
print('Case %s:' % case, end='')
TEST_PATH = TEST_BASE_PATH + case
SY_PATH = TEST_BASE_PATH + case + '.sy'
LL_PATH = TEST_BASE_PATH + case + '.ll'
INPUT_PATH = TEST_BASE_PATH + case + '.in'
OUTPUT_PATH = TEST_BASE_PATH + case + '.out'
need_input = testcases[case]
IRBuild_result = subprocess.run(IRBuild_ptn.format(EXE_PATH, LL_PATH, SY_PATH), shell=True, stderr=subprocess.PIPE)
if IRBuild_result.returncode == 0:
input_option = None
if need_input:
with open(INPUT_PATH, "rb") as fin:
input_option = fin.read()
try:
subprocess.run(ExeGen_ptn.format(optimization, TEST_PATH, LL_PATH), shell=True, stderr=subprocess.PIPE)
result = subprocess.run(Exe_ptn.format(TEST_PATH), shell=True, input=input_option, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out = result.stdout.split(b'\n')
if result.returncode != b'':
out.append(str(result.returncode).encode())
for i in range(len(out)-1, -1, -1):
out[i] = out[i].strip(b'\r')
if out[i] == b'':
out.remove(b'')
case_succ = True
with open(OUTPUT_PATH, "rb") as fout:
print(out[i])
i = 0
for line in fout.readlines():
line = line.strip(b'\r').strip(b'\n')
if line == '':
continue
if out[i] != line:
dir_succ = False
case_succ = False
i = i + 1
if case_succ:
print('\t\033[32mPass\033[0m')
else:
print('\t\033[31mWrong Answer\033[0m')
except Exception as _:
dir_succ = False
print(_, end='')
print('\t\033[31mCodeGen or CodeExecute Fail\033[0m')
finally:
subprocess.call(["rm", "-rf", TEST_PATH, TEST_PATH])
subprocess.call(["rm", "-rf", TEST_PATH, TEST_PATH + ".o"])
subprocess.call(["rm", "-rf", TEST_PATH, TEST_PATH + ".ll"])
else:
dir_succ = False
print('\t\033[31mIRBuild Fail\033[0m')
if dir_succ:
print('\t\033[32mSuccess\033[0m in dir {}'.format(TEST_BASE_PATH))
else:
print('\t\033[31mFail\033[0m in dir {}'.format(TEST_BASE_PATH))
print('============TEST END============')
if __name__ == "__main__":
# you can only modify this to add your testcase
TEST_DIRS = [
'./test/',
]
# you can only modify this to add your testcase
optimization = "-O0" # -O0 -O1 -O2 -O3 -O4(currently = -O3) -Ofast
for TEST_BASE_PATH in TEST_DIRS:
testcases = {} # { name: need_input }
EXE_PATH = os.path.abspath('../../build/SysYFCompiler')
testcase_list = list(map(lambda x: x.split('.'), os.listdir(TEST_BASE_PATH)))
testcase_list.sort()
for i in range(len(testcase_list)):
testcases[testcase_list[i][0]] = False
for i in range(len(testcase_list)):
testcases[testcase_list[i][0]] = testcases[testcase_list[i][0]] | (testcase_list[i][1] == 'in')
eval(EXE_PATH, TEST_BASE_PATH, optimization=optimization)

@ -0,0 +1,3 @@
int main(){
return 0;
}

@ -0,0 +1,8 @@
int a,b;
int main(){
a=10;
b=5;
int c=a*2+b*1.1+3.6;
return c;
}

@ -0,0 +1,5 @@
int main() {
int a = 10;
;
return a * 2 + 1;
}

@ -0,0 +1,4 @@
int a[10];
int main(){
return 0;
}

@ -0,0 +1,5 @@
int a[10];
int main(){
a[0]=1;
return 0;
}

@ -0,0 +1,5 @@
const int x=4;
int main(){
return x;
}

@ -0,0 +1,7 @@
const int a[5]={0,1,2,3,4};
const int b = 3;
float c = a[b + 1];
int main(){
return a[4] + c;
}

@ -0,0 +1,8 @@
int defn(){
return 4;
}
int main(){
int a=defn();
return a;
}

@ -0,0 +1,13 @@
int a,b,c;
void add(int a,int b){
c=a+b;
return;
}
int main(){
a=3;
b=2;
add(a,b);
return c;
}

@ -0,0 +1,9 @@
int a;
int main(){
a = 10;
if( a>0 ){
return 1;
}
return 0;
}

@ -0,0 +1,10 @@
int a;
int main(){
a = 10;
if( a>0 ){
return 1;
}
else{
return 0;
}
}

@ -0,0 +1,11 @@
int a;
int b;
int main(){
b=0;
a=3;
while(a>0){
b = b+a;
a = a-1;
}
return b;
}

@ -0,0 +1,9 @@
int main(){
int a=10;
while(a>0){
a=a-1;
if(a==5)
break;
}
return a;
}

@ -0,0 +1,11 @@
int main(){
int a=10;
while(a>0){
if(a>5){
a=a-1;
continue;
}
return a;
}
return a;
}

@ -0,0 +1,5 @@
int main(){
int a;
a = getint();
return a;
}

@ -0,0 +1,23 @@
int a;
int myFunc(int a, int b, int c) {
a = 2;
{
int c;
c = 0;
if (c != 0) {
return 0;
}
}
while (b > 0) {
b = b - 1;
}
return (a)+(b);
}
int main() {
a = (3);
int b;
b = myFunc(1, 2, 1);
return ((a+b));
}

@ -0,0 +1,12 @@
int a;
int b;
int main(){
a = getint();
b = getint();
if ( a == b ){
return 1;
}
else{
return 0;
}
}

@ -0,0 +1,17 @@
const int a = 5;
int b;
int my_sum(int x, float y){
b = a + x - y;
return b;
}
int main(){
int a = 7;
{
const float a = 3.3;
my_sum(a, a);
}
my_sum(a, b);
return b;
}

@ -0,0 +1,34 @@
int n;
int gcd(int m,int n)
{
int t;
int r;
if(m<n) { t=m;m=n;n=t; }
r=m%n;
while(r!=0)
{
m=n;
n=r;
r=m%n;
}
return n;
}
int main()
{
//newline=10;
int i;
int m;
//m = 1478;
//int t;
i=getint();
m=getint();
return gcd(i,m);
}

@ -0,0 +1,5 @@
1 2, 1 3, 2 3, 1 2, 3 1, 3 2, 1 2, 1 3, 2 3, 2 1, 3 1, 2 3, 1 2, 1 3, 2 3,
1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3,
1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3,
1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3,
0

@ -0,0 +1,27 @@
void move(int x, int y)
{
putint(x); putch(32); putint(y); putch(44); putch(32);
}
void hanoi(int n, int one, int two, int three)
{
if (n == 1)
move(one, three);
else {
hanoi(n - 1, one, three, two);
move(one, three);
hanoi(n - 1, two, one, three);
}
}
int main()
{
int n = getint();
while (n > 0) {
hanoi(getint(), 1, 2, 3);
putch(10);
n = n - 1;
}
return 0;
}

@ -0,0 +1,8 @@
float a,b;
int main(){
a=10.2;
b=5.3;
float c=a*2+b*1.1+3.6;
return c;
}

@ -0,0 +1,5 @@
float a[2] = {1.2, 1.3};
int main(){
a[1] = 3.3;
return 0;
}

@ -0,0 +1,6 @@
const int x=4;
int main(){
const int x=4;
return x;
}

@ -0,0 +1,7 @@
const float a[5]={0.2,1.33,2.4,3.5,4.6};
const int b = 3;
float c = a[b + 1];
int main(){
return a[4] + c;
}

@ -0,0 +1,13 @@
float a,b,c;
void add(float a,float b){
c=a+b;
return;
}
int main(){
a=3.3;
b=2.8;
add(a,b);
return c;
}

@ -0,0 +1,15 @@
int a;
int main(){
a = -10;
if( a>0 ){
return 1;
}
else{
if(a > -5) {
return 2;
}
else {
return 0;
}
}
}

@ -0,0 +1,21 @@
int a;
int b;
int main(){
b=0;
a=3;
int sum = 0;
while(b<10){
b = b+1;
while(a > 0) {
a = a-1;
sum = sum + b;
}
sum = sum + b;
}
while(b < 12) {
sum = sum + 1;
b = b+1;
}
return sum;
}

@ -0,0 +1,22 @@
int a;
int b;
int main(){
a = getint();
b = getint();
if ( a == b ){
return 1;
}
if ( a <= b ){
return 2;
}
if ( a < b ){
return 3;
}
if ( a != b){
return 4;
}
if ( a >= b){
return 5;
}
return 0;
}

@ -0,0 +1,7 @@
int a[5][2] = {1,{2,3},{4},{5,6,7}};
int b[5][2] = {{1,0},{2,3},{4,0},{5,6},{7,0}};
int main(){
int i = a[3][1];
int j = b[3][1];
return (i-j);
}

@ -0,0 +1,7 @@
int main(){
int a[5][2] = {1,{2,3},{4},{5,6,7}};
int b[5][2] = {{1,0},{2,3},{4,0},{5,6},{7,0}};
int i = a[3][1];
int j = b[3][1];
return i - j;
}

@ -0,0 +1,473 @@
# AST
**源码链接:**
[SyntaxTree.h](../include/SyntaxTree.h)
[SyntaxTree.cpp](../src/SyntaxTree.cpp)
## 目录
[Ptr](#ptr)
[PtrLst](#ptrlist)
[Position](#position)
[Type](#type)
[Binop](#binop)
[UnaryOp](#unaryOp)
[UnaryCondOp](#unarycondop)
[BinaryCondOp](#binarycondop)
[Node](#node)
[Assembly](#assembly)
[InitVal](#initval)
[GlobalDef](#globaldef)
[FuncDef](#funcdef)
[VarDef](#vardef)
[Stmt](#stmt)
[AssignStmt](#assignstmt)
[ReturnStmt](#returnstmt)
[BlockStmt](#blockstmt)
[EmptyStmt](#emptystmt)
[ExprStmt](#exprstmt)
[Expr](#expr)
[CondExpr](#condexpr)
[AddExpr](#addexpr)
[UnaryCondExpr](#unarycondexpr)
[BinaryCondExpr](#binarycondexpr)
[BinaryExpr](#binaryexpr)
[UnaryExpr](#unaryexpr)
[LVal](#lval)
[Literal](#literal)
[FuncCallStmt](#funccallstmt)
[FuncParam](#funcparam)
[FuncFParamList](#funcfparamlist)
[IfStmt](#ifstmt)
[WhileStmt](#whilestmt)
[BreakStmt](#breakstmt)
[ContinueStmt](#continuestmt)
[Visitor](#visitor)
## Ptr
AST中使用的指针类型。实际上是`std::shared_ptr`
## PtrList
存放[Ptr](#ptr)的list实际上是`std::vector<Ptr>`
## Position
该节点代表的语法结构在源文件的位置信息,实际上是`yy::location`。由bison/flex自动生成。
## Type
包含SysY语言支持的数据类型`Type::INT`以及`Type::VOID`。
多出的`Type::STRING`类型用作系统调用的参数类型,`Type::BOOL`作为条件表达式类型。
## Binop
双目算术表达式的操作符。包含
`Binop::PLUS`
`Binop::MINUS`
`Binop::MULTIPLY`
`Binop::DIVIDE`
`Binop::MODULO`
## UnaryOp
单目算术表达式操作符,包含
`UnaryOp::PLUS`
`UnaryOp::MINUS`
## UnaryCondOp
单目条件表达式操作符,包含
`UnaryCondOp::NOT`
## BinaryCondOp
双目条件表达式操作符,包含
`BinaryCondOp::LT`小于
`BinaryCondOp::LTE`小于等于
`BinaryCondOp::GT`大于
`BinaryCondOp::GTE`大于等于
`BinaryCondOp::EQ`等于等于
`BinaryCondOp::NEQ`不等于
`BinaryCondOp::LAND`逻辑与
`BinaryCondOp::LOR`逻辑或
## Node
语法树所有结点的基类,
`Node::loc`是其在对应源文件的位置信息。类型为[Position](#position)
`virtual void Node::accept(Visitor &visitor)`为虚函数,用于访问者模式,接受一个[Visitor](#visitor)。需要进行重写。
## Assembly
AST的根结点
[PtrList](#ptrlist)<[GlobalDef](#globaldef)> `Assembly::global_defs`存放所有[GlobalDef](#globaldef)指针。
## InitVal
代表初值的结点。该结点为嵌套定义。以下类型的变量初值均可表示:
```c++
int a = 1 + 1;
int b[2] = {1,2};
int c[2][2] = {{1,2},{3,4}}
...
```
`bool InitVal::isExp`
为真时初值为[Expr](#expr)类型。为假时代表以`{...}`的形式进行赋初值
eg
```c++
int a = 3 + 1;//isExp=true
int c[2][2] = {{1,2},{3,4}};//isExp=false
```
所有`InitVal`结点最底层一定是[Expr](#expr)类型。也即`isExp`为true
[PtrList](#ptrlist)<[InitVal](#initval)> `InitVal::elementList`
当`isExp`为false时该域才有意义。是包含`{}`中其余`InitVal`结点指针的列表。
[Ptr](#ptr)<[Expr](#expr)> `InitVal::expr`
当`isExp`为true时该域才有意义。一个初值表达式的指针。
## GlobalDef
所有def结点的基类
## FuncDef
代表函数定义。
[Type](#type) `FuncDef::ret_type`
函数的返回值类型
[Ptr](#ptr)<[FuncFParamList](#funcfparamlist)> `FuncDef::param_list`
函数的形参指针
`std::string FuncDef::name`
函数名
[Ptr](#ptr)<[BlockStmt](#blockstmt)> `FuncDef::body`
函数体指针
## VarDef
代表变量定义
`bool VarDef::is_constant`
是否为常量
[Type](#type) `VarDef::btype`
变量类型(在sysY中只能是int)
`std::string VarDef::name`
变量名
`bool VarDef::is_inited`
是否初始化
[PtrList](#ptrlist)<[Expr](#expr)> `VarDef::array_length`
若为数组,则是存放各维长度表达式指针的列表,否则为空
[Ptr](#ptr)<[InitVal](#initval)> `VarDef::initializers`
若初始化,则是指向初值定义的指针
## Stmt
所有statement的基类
## AssignStmt
表示如下类型的语句:
```c++
target = value
```
即赋值型语句
[Ptr](#ptr)<[Lval](#lval)> `AssignStmt::target`
赋值表达式的左值指针
[Ptr](#ptr)<[Expr](#expr)> `AssignStmt::value`
赋值表达式右边表达式指针
## ReturnStmt
代表return 语句
[Ptr](#ptr)<[Expr](#expr)> `ReturnStmt::ret`
return 语句返回的表达式指针。空指针代表void return
## BlockStmt
代表使用`{}`括起来的stmt。
[PtrList](#ptrlist)<[Stmt](#stmt)> `BlockStmt::body`
该block中所有stmt指针的列表
## EmptyStmt
空语句
## ExprStmt
表达式语句
[Ptr](#ptr)<[Expr](#exp)> `ExprStmt::exp`
表达式语句对应表达式的指针
## Expr
所有表达式的基类
## CondExpr
所有条件表达式的基类
## AddExpr
所有算术表达式的基类
## UnaryCondExpr
单目条件表达式
`UnaryCondOp UnaryCondExpr::op`
操作符
[Ptr](#ptr)<[Expr](#expr)> `UnaryCondExpr::rhs`
操作符右端表达式指针
## BinaryCondExpr
双目条件表达式
`BinaryCondOp BinaryCondExpr::op`
操作符
[Ptr](#ptr)<[Expr](#expr)> `BinaryCondExpr::lhs, rhs`
操作符左右两端表达式指针
## BinaryExpr
双目算术表达式
`BinOp BinaryExpr::op`
操作符
[Ptr](#ptr)<[Expr](#expr)> `BinaryExpr::lhs, rhs`
操作符左右两端表达式指针
## UnaryExpr
单目算术表达式
`UnaryOp UnaryExpr::op`
操作符
[Ptr](#ptr)<[Expr](#expr)> `UnaryExpr::rhs`
操作符右端表达式指针
## LVal
左值表达式
`std::string Lval::name`
变量名
[PtrList](#ptrlist)<[Expr](#expr)> `LVal::array_index`
数组索引的指针列表。若不是数组,则为空
## Literal
语义值类型,包含整数和字符串
`bool Literal::is_int`
是否为整形
`int Literal::int_const`
整数语义值
`std::string Literal::str`
字符串语义值(未处理转义)
## FuncCallStmt
函数调用
`std::string FuncCallStmt::name`
被调用的函数名
[PtrList](#ptrlist)<[Expr](#expr)> `FuncCallStmt::params`
存放函数实参表达式指针的列表
## FuncParam
单个函数形参
`std::string FuncParam::name`
形参名
[Type](#type) `FuncParam::param_type`
形参类型
[PtrList](#ptrlist)<[Expr](#expr)> `FuncParam::array_index`
形参的数组维度列表,存放每一维的表达式指针。若非数组则为空
## FuncFParamList
存放一个函数的所有形参
[PtrList](#ptrlist)<[FuncParam](#funcparam)> `FuncFParamList::params`
存放所有形参指针的列表
## IfStmt
表示如下结构:
```c++
if(cond_exp)
if_stmt
if(cond_exp)
if_stmt
else
else_stmt
```
[Ptr](#ptr)<[Expr](#expr)> `IfStmt::cond_exp`
cond_exp的指针
[Ptr](#ptr)<[Stmt](#stmt)> `IfStmt::if_statement`
if_stmt的指针
[Ptr](#ptr)<[Stmt](#stmt)> `IfStmt::else_statement`
else_stmt的指针(若无else则为空)
## WhileStmt
表示如下结构
```c++
while(cond_exp)
stmt
```
[Ptr](#ptr)<[Expr](#expr)> `WhileStmt::cond_exp`
cond_exp的指针
[Ptr](#ptr)<[Stmt](#stmt)> `WhileStmt::statement`
stmt的指针
## BreakStmt
表示一个break语句
## ContinueStmt
表示一个continue语句
## Visitor
访问者模式的基类用于访问AST。需要重写其中的visit函数。

@ -0,0 +1,620 @@
# SysYF IR
- [SysYF IR](#sysyf-ir)
- [IR](#ir)
- [IR Features](#ir-features)
- [IR Format](#ir-format)
- [Instruction](#instruction)
- [Terminator Instructions](#terminator-instructions)
- [Ret](#ret)
- [Br](#br)
- [Standard binary operators](#standard-binary-operators)
- [Add FAdd](#add-fadd)
- [Sub FSub](#sub-fsub)
- [Mul FMul](#mul-fmul)
- [SDiv FDiv](#sdiv-fdiv)
- [SRem](#srem)
- [Memory operators](#memory-operators)
- [Alloca](#alloca)
- [Load](#load)
- [Store](#store)
- [CastInst](#castinst)
- [ZExt](#zext)
- [FpToSi](#fptosi)
- [SiToFp](#sitofp)
- [Other operators](#other-operators)
- [ICmp FCmp](#icmp-fcmp)
- [Call](#call)
- [GetElementPtr](#getelementptr)
- [C++ APIs](#c-apis)
- [核心类概念图](#核心类概念图)
- [BasicBlock](#basicblock)
- [Constant](#constant)
- [Function](#function)
- [GlobalVariable](#globalvariable)
- [IRStmtBuilder](#irstmtbuilder)
- [Instruction](#instruction-1)
- [Module](#module)
- [Type](#type)
- [User](#user)
- [Value](#value)
- [总结](#总结)
## IR
### IR Features
- 采用类型化三地址代码的方式
- 区别于 X86 汇编的目标和源寄存器共用的模式: ADD EAX, EBX
- %2 = add i32 %0, %1
- 静态单赋值 (SSA) 形式 + 无限寄存器
- 每个变量都只被赋值一次
- 容易确定操作间的依赖关系,便于优化分析
- 强类型系统
- 每个 Value 都具备自身的类型,
- IR类型系统
- `i1`1位宽的整数类型
- `i32`32位宽的整数类型
- `float`:单精度浮点数类型
- `pointer`:指针类型
- 例如:`i32*, [10 x i32*]`
- `label` bb的标识符类型
- `functiontype`函数类型,包括函数返回值类型与参数类型(下述文档未提及)
### IR Format
下面以`easy.c`与`easy.ll`为例进行说明。
通过命令`clang -S -emit-llvm easy.c`可以得到对应的`easy.ll`如下(其中增加了额外的注释)。`.ll`文件中注释以`;`开头。
- `easy.c`:
``` c
int main(){
int a;
int b;
a = 1;
b = 2;
if(a < b)
b = 3;
return a + b;
}
```
- `easy.ll`:
``` c
; 注释: .ll文件中注释以';'开头
; ModuleID = 'easy.c'
source_filename = "easy.c"
; 注释: target的开始
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"
; 注释: target的结束
; 注释: 全局main函数的定义
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
; 注释: 第一个基本块的开始
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 1, i32* %2, align 4
store i32 2, i32* %3, align 4
%4 = load i32, i32* %2, align 4
%5 = load i32, i32* %3, align 4
%6 = icmp slt i32 %4, %5
br i1 %6, label %7, label %8
; 注释: 第一个基本块的结束
; 注释: 第二个基本块的开始
7: ; preds = %0
store i32 3, i32* %3, align 4
br label %8
; 注释: 第二个基本块的结束
; 注释: 第三个基本块的开始
8: ; preds = %7, %0
%9 = load i32, i32* %2, align 4
%10 = load i32, i32* %3, align 4
%11 = add nsw i32 %9, %10
ret i32 %11 ; 注释: 返回语句
; 注释: 第三个基本块的结束
}
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "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" }
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 10.0.1 "}
```
每个program由1个或多个module组成每个module对应1个程序文件module之间由LLVM Linker进行链接形成1个可执行文件或者库。
每个module组成如下
- Target Information
``` 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"
```
- Global Symbols: main函数的定义
- Others:尾部其他信息
每个函数的组成如下:
- 头部:函数返回值类型、函数名、函数参数
- 一个或多个基本块:
- 每个基本块由Label和Instruction组成。
``` c
8: ; preds = %7, %0
%9 = load i32, i32* %2, align 4
%10 = load i32, i32* %3, align 4
%11 = add nsw i32 %9, %10
ret i32 %11
```
这个例子中,`8`就是Label。
`%9 = load i32, i32* %2, align 4`中的`%9`是目的操作数,`load`是指令助记符,`i32`是`int32`的类型,`i32*`是指向`int32`的地址类型,`%2`是源操作数,`align 4`表示对齐。
### Instruction
#### Terminator Instructions
**注**ret与br都是Terminator Instructions也就是终止指令在llvm基本块的定义里基本块是单进单出的因此只能有一条终止指令ret或br。当一个基本块有两条终止指令clang 在做解析时会认为第一个终结指令是此基本块的结束,并会开启一个新的匿名的基本块(并占用了下一个编号)。
##### Ret
- 格式
- `ret <type> <value>`
- `ret void`
- 例子:
- `ret i32 %0`
- `ret void`
- 概念:` ret`指令用于将控制流(以及可选的值)从函数返回给调用者。`ret`指令有两种形式:一种返回值,然后终结函数,另一种仅终结函数。
##### Br
- 格式:
- `br i1 <cond>, label <iftrue>, label <iffalse>`
- `br label <dest>`
- 例子:
- `br i1 %cond label %truebb label %falsebb`
- `br label %bb`
- 概念:`br`指令用于使控制流转移到当前功能中的另一个基本块。 该指令有两种形式,分别对应于条件分支和无条件分支。
#### Standard binary operators
##### Add FAdd
- 格式:
- `<result> = add <type> <op1>, <op2>`
- `<result> = fadd <type> <op1>, <op2>`
- 例子:
- `%2 = add i32 %1, %0`
- `%2 = fadd float %1, %0`
- 概念:`add`指令返回其两个`i32`类型的操作数之和,返回值为`i32`类型,`fadd`指令返回其两个`float`类型的操作数之和,返回值为`float`类型
##### Sub FSub
- 格式与例子与`add``fadd`类似
- 概念:`sub`指令返回其两个`i32`类型的操作数之差,返回值为`i32`类型,`fsub`指令返回其两个`float`类型的操作数之差,返回值为`float`类型
##### Mul FMul
- 格式与例子与`add``fadd`类似
- 概念:`mul`指令返回其两个`i32`类型的操作数之积,返回值为`i32`类型,`fmul`指令返回其两个`float`类型的操作数之积,返回值为`float`类型
##### SDiv FDiv
- 格式与例子与`add``fadd`类似
- 概念:`sdiv`指令返回其两个`i32`类型的操作数之商,返回值为`i32`类型,`fdiv`指令返回其两个`float`类型的操作数之商,返回值为`float`类型
##### SRem
- 格式与例子与`add`类似
- 概念:`srem`指令返回其两个`i32`类型的操作数之模,返回值为`i32`类型
#### Memory operators
##### Alloca
- 格式:`<result> = alloca <type>`
- 例子:
- `%ptr = alloca i32`
- `%ptr = alloca [10 x i32]`
- 概念: `alloca`指令在当前执行函数的栈帧上分配内存,当该函数返回其调用者时将自动释放该内存。 始终在地址空间中为数据布局中指示的分配资源分配对象
##### Load
- 格式:`<result> = load <type>, <type>* <pointer>`
- 例子:`%val = load i32, i32* %ptr`
- 概念:`load`指令用于从内存中读取。
##### Store
- 格式:`store <type> <value>, <type>* <pointer>`
- 例子:`store i32 3, i32* %ptr`
- 概念:`store`指令用于写入内存
#### CastInst
##### ZExt
- 格式:`<result> = zext <type> <value> to <type2>`
- 例子:`%1 = zext i1 %0 to i32`
- 概念:`zext`指令将其操作数**零**扩展为`type2`类型。
##### FpToSi
- 概念:`fptosi`指令将浮点值转换为`type2`(整数)类型。
- 格式:`<result> = fptosi <type> <value> to <type2>`
- 例子:`%Y = fptosi float 1.0E-247 to i32`
##### SiToFp
- 格式:`<result> = sitofp <type> <value> to <type2>`
- 例子:`%X = sitofp i32 257 to float`
- 概念:`sitofp`指令将有符号整数转换为`type2`(浮点数)类型。
#### Other operators
##### ICmp FCmp
- 格式:
- `<result> = icmp <cond> <type> <op1>, <op2>`
- `<cond> = eq | ne | sgt | sge | slt | sle`
- `<result> = fcmp <cond> <type> <op1>, <op2>`
- `<cond> = eq | ne | ugt | uge | ult | ule`
- 例子:`i1 %2 = icmp sge i32 %0, %1`
- 概念:`icmp`指令根据两个整数的比较返回布尔值,`fcmp`指令根据两个浮点数的比较返回布尔值。
##### Call
- 格式:
- `<result> = call <return ty> <func name>(<function args>) `
- 例子:
- `%0 = call i32 @func( i32 %1, i32* %0)`
- `call @func( i32 %arg)`
- 概念:`call`指令用于使控制流转移到指定的函数,其传入参数绑定到指定的值。 在被调用函数中执行`ret`指令后,控制流程将在函数调用后继续执行该指令,并且该函数的返回值绑定到`result`参数。
##### GetElementPtr
- 格式:`<result> = getelementptr <type>, <type>* <ptrval> [, <type> <idx>]`
- 例子:
- `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
- `%2 = getelementptr i32, i32* %1 i32 %0`
- 参数解释:第一个参数是计算基础类型,第二第三个参数表示索引开始的指针类型及指针,`[]`表示可重复参数,里面表示的数组索引的偏移类型及偏移值。(思考指针类型为`[10 x i32]`指针和`i32`指针`getelementptr`用法的不同)
- 概念:`getelementptr`指令用于获取数组结构的元素的地址。 它仅执行地址计算,并且不访问内存。
## C++ APIs
### 核心类概念图
![](figs/核心类概念图.png)
### BasicBlock
- 继承:从[value](#value)继承
- 含义:基本块,是一个是单入单出的代码块,该类维护了一个指令链表,基本块本身属于 Value, 类型是 \<label\>,会被分支指令调用
- 成员:
- instr_list_指令链表
- pre_bbs_ bb前驱集合
- succ_bbs_bb后继集合
- API:
```c++
// 创建并返回BB块参数分别是BB块所属的Modulename是其名字默认为空BB块所属的Function
static Ptr<BasicBlock> create(Ptr<Module> m, const std::string &name ,Ptr<Function> parent )
// 返回BB块所属的函数
Ptr<Function> get_parent();
// 返回BB块所属的Module
Ptr<Module> get_module();
// 返回BB块的终止指令(ret|br)若BB块最后一条指令不是终止指令返回null
Ptr<Instruction> get_terminator();
// 将instr指令添加到此BB块指令链表结尾调用IRBuilder里来创建函数会自动调用此方法
void add_instruction(Ptr<Instruction> instr);
// 将instr指令添加到此BB块指令链表开头
void add_instr_begin(Ptr<Instruction> instr);
// 将instr指令从BB块指令链表中移除同时调用api维护好instr的操作数的use链表
void delete_instr(Ptr<Instruction> instr);
// BB块中指令数为空返回true
bool empty();
// 返回BB块中指令的数目
int get_num_of_instr();
//返回BB块的指令链表
PtrList<Instruction> &get_instructions();
// 将此BB块从所属函数的bb链表中移除
void erase_from_parent();
/****************api about cfg****************/
PtrList<BasicBlock> &get_pre_basic_blocks() // 返回前驱块集合
PtrList<BasicBlock> &get_succ_basic_blocks() // 返回后继块集合
void add_pre_basic_block(Ptr<BasicBlock> bb) // 添加前驱块
void add_succ_basic_block(Ptr<BasicBlock> bb) // 添加后继块
void remove_pre_basic_block(Ptr<BasicBlock> bb) // 移除前驱块
void remove_succ_basic_block(Ptr<BasicBlock> bb) // 移除后继块
/****************api about cfg****************/
```
### Constant
- 继承:从[User](#user)继承
- 含义:常数,各种类型常量的基类
- 子类:
- ConstantInt
- 含义int类型的常数
- 成员
- value_常数值
- API
```cpp
int get_value() // 返回该常数类型中存的常数值
static int get_value(Ptr<ConstantInt> const_val)// 返回该常数类型const_val中存的常数值
static Ptr<ConstantInt> get(int val, Ptr<Module> m) // 以val值来创建常数类
static Ptr<ConstantInt> get(bool val, Ptr<Module> m) // 以val值来创建bool常数类
```
- ConstantFloat
- 含义float类型的常数
- 成员
- value_常数值
- API
```cpp
static Ptr<ConstantFloat> get(float val, Ptr<Module> m) // 以val值创建并返回浮点数常量类
float get_value() // 返回该常数类型中存的常数值
```
- ConstantZero
- 含义用于全局变量初始化的常量0值。
- API
```cpp
static Ptr<ConstantZero> get(Ptr<Type> ty, Ptr<Module> m);// 创建并返回ConstantZero常量类
```
- ConstantArray
- 含义:数组类型的常数
- 成员
- const_array数组常量值
- APIcminus语法不需要数组常量的支持本次实验不需要用到在此不过多解释。感兴趣可以自行查看源代码。
### Function
- 继承:从[Value](#value)继承
- 含义:函数,该类描述 LLVM 的一个简单过程,维护基本块表,格式化参数表
- 成员
- basic_blocks_基本块列表
- arguments_形参列表
- parent_函数属于的module
- API
```cpp
static Ptr<Function> create(Ptr<FunctionType> ty, const std::string &name, Ptr<Module> parent);
// 创建并返回Function参数依次是待创建函数类型ty、函数名字name(不可为空)、函数所属的Module
Ptr<FunctionType> get_function_type() const;
// 返回此函数类的函数类型
Ptr<Type> get_return_type() const;
// 返回此函数类型的返回值类型
void add_basic_block(Ptr<BasicBlock> bb);
// 将bb添加至Function的bb链表上调用bb里的创建函数时会自动调用此函数挂在function的bb链表上
unsigned get_num_of_args() const;
// 得到函数形参数数量
unsigned get_num_basic_blocks() const;
// 得到函数基本块数量
Ptr<Module> get_parent() const;
// 得到函数所属的Module
PtrList<Argument>::iterator arg_begin()
// 得到函数形参的list的起始迭代器
PtrList<Argument>::iterator arg_end()
// 得到函数形参的list的终止迭代器
void remove(Ptr<BasicBlock> bb)
// 从函数的bb链表中删除一个bb
PtrList<BasicBlock> &get_basic_blocks()
// 返回函数bb链表
PtrList<Argument> &get_args()
// 返回函数的形参链表
void set_instr_name();
// 给函数中未命名的基本块和指令命名
```
- 相关类
- Argument
- 含义:参数
- 成员
- arg_no_参数序号
- parent_参数属于哪个函数
- API
```cpp
Ptr<Function> get_parent() // 返回参数的所属函数
unsigned get_arg_no() const // 返回参数在所在函数的第几个参数
```
### GlobalVariable
- 继承:从[User](#user)继承
- 含义:全局变量,该类用于表示全局变量,是 GlobalValue 的子类,根据地址来访问
- 成员:
- is_const是否为常量
- init_val_初始值
- API由于cminusf语义要求所有的全局变量都默认初始化为0故`GlobalVariable`中成员和API再构造CminusFBuilder用不到
### IRStmtBuilder
- 含义生成IR的辅助类该类提供了独立的接口创建各种 IR 指令,并将它们插入基本块中, 该辅助类不做任何类型检查。
- API
```cpp
Ptr<BasicBlock> get_insert_block()// 返回正在插入指令的BB
void set_insert_point(Ptr<BasicBlock> bb)// 设置当前需要插入指令的bb
ptr<XXXInst> create_[instr_type]()// 创建instr_type(具体名字参考IRStmtBuilder.h代码)的指令并对应插入到正在插入的BB块这种类型的指令看函数名字和参数名字和IR文档是一一对应的。
```
### Instruction
- 继承:从[User](#user)继承
- 含义:指令,该类是所有 LLVM 指令的基类,主要维护指令的操作码(指令类别),指令所属的基本块,指令的操作数个数信息
- 成员
- parent_指令所属的BasicBlock
- op_id_指令的类型id
- num_ops_指令的操作数个数
- 子类
- BinaryInst双目运算指令包括add、sub、mul、div
- 其他子类和前述文档中提到的指令一一对应,不在此赘述。
- API所有指令的创建都要通过 IRStmtBuilder 进行不需要关注Instruction类的实现细节**注**:不通过 IRStmtBuilder 来创建指令,而直接调用指令子类的创建方法未经助教完善的测试)
### Module
- 含义:一个编译单元,在此源语言的意义下是一个文件
- 成员
- function_list_函数链表记录了这个编译单元的所有函数
- global_list_全局变量链表
- instr_id2string_通过指令类型id得到其打印的string
- module_name_, source_file_name未使用
- 从module中能取到的基本类型
- API
```cpp
Ptr<Type> get_void_type();
// 得到IR中的void类型其他类型可以用类似的API得到(推荐取得类型采用lab3助教提供的方法Type::get())
void add_function(Ptr<Function> f);
// 将f挂在module的function链表上在function被创建的时候会自动调用此方法来添加function
void add_global_variable(Ptr<GlobalVariable> g);
// 将g挂在module的GlobalVariable链表上在GlobalVariable被创建的时候会自动调用此方法来添加GlobalVariable
PtrList<GlobalVariable> &get_global_variable();
// 获取全局变量列表
std::string get_instr_op_name( Instruction::OpID instr )
// 获取instr对应的指令名(打印ir时调用)
void set_print_name();
// 设置打印ir的指令与bb名字
```
### Type
- 含义IR的类型该类是所有类型的超类
- 成员
- tid_枚举类型表示type的类型包含VoidType、LabelType、FloatType、Int1、Int32、ArrayType、PointerType
- 子类
- IntegerType
- 含义int 类型
- 成员
- num_bits长度i1或者i32
- API
```cpp
unsigned get_num_bits();// 返回int的位数
```
- FloatType
- 含义float 类型
- FunctionType
- 含义:函数类型
- 成员
- result_返回值类型
- args_参数类型列表
- API
```cpp
static Ptr<FunctionType> get(Ptr<Type> result, PtrVec<Type> params);
// 返回函数类型参数依次是返回值类型result形参类型列表params
unsigned get_num_of_args() const;
// 返回形参个数
Ptr<Type> get_param_type(unsigned i) const;
// 返回第i个形参的类型
PtrVec<Type>::iterator param_begin()
// 返回形参类型列表的起始迭代器
PtrVec<Type>::iterator param_end()
// 返回形参类型列表的终止迭代器
Ptr<Type> get_return_type() const;
// 返回函数类型中的返回值类型
```
- ArrayType
- 含义:数组类型
- 成员
- contained_数组成员的类型
- num_elements_数组维数
- API
```cpp
static Ptr<ArrayType> get(Ptr<Type> contained, unsigned num_elements);
// 返回数组类型,参数依次是 数组元素的类型contained数组元素个数num_elements
Ptr<Type> get_element_type() const
// 返回数组元素类型
unsigned get_num_of_elements() const
// 返回数组元素个数
```
- PointerType
- 含义:指针类型
- 成员
- contained_指针指向的类型
- API
```cpp
Ptr<Type> get_element_type() const { return contained_; }
// 返回指针指向的类型
static Ptr<PointerType> get(Ptr<Type> contained);
// 返回contained类型的指针类型
Ptr<Type> get_pointer_element_type();// 若是PointerType则返回指向的类型若不是则返回nullptr。
static Ptr<PointerType> create(Ptr<Type> contained);
// 创建指向contained类型的指针类型
```
- API
```cpp
bool is_void_type()// 判断是否是void类型其他类型有类似API请查看Type.h
static Ptr<Type> get_void_type(Ptr<Module> m);// 得到void类型
Ptr<Type> get_pointer_element_type();// 若是PointerType则返回指向的类型若不是则返回nullptr。
Ptr<Type> get_array_element_type();// 若是ArrayType则返回指向的类型若不是则返回nullptr。
```
### User
- 继承:从[value](#value)继承
- 含义:使用者,提供一个操作数表,表中每个操作数都直接指向一个 Value, 提供了 use-def 信息,它本身是 Value 的子类, Value 类会维护一个该数据使用者的列表提供def-use信息。简单来说操作数表表示我用了谁该数据使用者列表表示谁用了我。这两个表在后续的**优化实验**会比较重要请务必理解。
- 成员
- operands_参数列表表示这个使用者所用到的参数
- num_ops_表示该使用者使用的参数的个数
- API
```cpp
Ptr<Value> get_operand(unsigned i) const;
// 从user的操作数链表中取出第i个操作数
void set_operand(unsigned i, Ptr<Value> v);
// 将user的第i个操作数设为v
void add_operand(Ptr<Value> v);
// 将v挂到User的操作数链表上
unsigned get_num_operand() const;
// 得到操作数链表的大小
void remove_use_of_ops();
// 从User的操作数链表中的所有操作数处的use_list_ 移除该User;
void remove_operands(int index1, int index2);
// 移除操作数链表中索引为index1-index2的操作数例如想删除第0个操作数remove_operands(0,0)
```
### Value
- 含义:最基础的类,代表一个操作数,代表一个可能用于指令操作数的带类型数据
- 成员
- use_list_记录了所有使用该操作数的指令的列表
- name_名字
- type_类型一个type类表示操作数的类型
- API
```cpp
Ptr<Type> get_type() const //返回这个操作数的类型
std::list<Use> &get_use_list() // 返回value的使用者链表
void add_use(Ptr<Value> val, unsigned arg_no = 0);
// 添加val至this的使用者链表上
void replace_all_use_with(Ptr<Value> new_val);
// 将this在所有的地方用new_val替代并且维护好use_def与def_use链表
void remove_use(Ptr<Value> val);
// 将val从this的use_list_中移除
```
### 总结
在本文档里提供了为SysYF语言程序生成LLVM IR可能需要用到的SysYF IR应用编程接口如果对这些API有问题的请移步issue讨论本次`SysYF IR`应用编程接口由助教自行设计实现并做了大量测试如有对助教的实现方法有异议或者建议的也请移步issue讨论**除了选做内容无需修改助教代码**。

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@ -0,0 +1,79 @@
[TOC]
---
### 任务描述
**本关任务**熟悉LLVM IR并根据给出的4个SysYF程序(文件扩展名为sy)手写相应的LLVM IR的ll文件以实现相同功能。
### 相关知识
#### LLVM IR介绍
[LLVM](https://llvm.org/)是一个开源的编译器基础设施用C++语言编写包含一系列模块化的编译器组件和工具链用来支持编译器前端和后端的开发。IR的全称是Intermediate Representation即中间表示。LLVM IR是一种类型化的三地址中间表示是类似于汇编的底层语言。
LLVM IR的具体指令可以参考[Reference Manual](http://llvm.org/docs/LangRef.html)。但是你会发现其内容庞杂为便于你尽快了解本实训项目需要涉及的LLVM IR指令子集请查看本实训提供的**精简的IR Reference手册**`doc/SysYFIR.md`。
作为一开始的参考,你可以先阅读其中的`IR Features`和`IR Format`两节,后续有需要再反复参考。
#### 样例学习
<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>
- 阅读`Student/task1/demo/go_upstairs.c`。
- 进入`Student/task1/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`执行结果的正确性。
### 本关具体任务
1. 在`Student/task1/student_sy/`内提供了四个简单的SysYF 程序:`assign_test.sy``func_test.sy``if_test.sy``while_test.sy`。
你需要在`Student/task1/ll/`目录下手工编写`assign_hand.ll``func_hand.ll``if_hand.ll``while_hand.ll`文件,以实现与上述 SysYF 程序相同的逻辑功能。
你需要在`ll`文件内添加必要的注释,`ll`文件的注释是以`;`开头的。
必要的情况下,你可以参考`clang -S -emit-llvm`的输出,但是你提交的结果必须避免同此输出一字不差。
2. 在`report.md`内回答[思考题](#思考题)
### 运行说明
- 你需要使用 `clang --version``lli --version` 检查本机的Clang和LLVM版本
- 你可以使用 `which lli` 来查找 `lli` 命令的位置
- 利用LLVM的命令 `lli`,可以执行`*.ll`文件;如果版本过低,可能会遇到`error: expected top-level entity`等问题
- 你也可以使用 `clang go_upstairs.ll -o go_upstairs` 来生成可执行文件
- `$?`的内容是上一条命令所返回的结果,而`echo $?`可以将其输出到终端中
- 使用`clang`时,注意扩展名为`sy`的文件是SysYF语言的程序文件`clang`是无法直接识别的,你可以将`sy`文件复制为`c`文件来用`clang`编译
### 思考题
请在`report/report.md`中详细回答下述思考题:
1-1 请给出while语句对应的LLVM IR的代码布局特点重点解释其中涉及的几个`br`指令的含义(包含各个参数的含义)
1-2 请简述函数调用语句对应的LLVM IR的代码特点

@ -0,0 +1,128 @@
[TOC]
---
### 任务描述
**本关任务**熟悉SysYF IR的应用编程接口并根据给出的4个SysYF程序手写调用SysYF IR应用编程接口的C++代码生成与sy文件功能相同的ll文件。
### 相关知识
#### SysYF IR 应用编程接口
由于LLVM IR官方的C++应用编程接口的文档内容繁多本实训项目提供SysYF IR应用编程接口库该库用C++编写可以用于生成LLVM IR的子集。你需要阅读**SysYF IR核心类的介绍**`doc/SysYFIR.md`。
本关要求你根据AST使用SysYF IR应用编程接口来构建生成LLVM IR。你需要先仔细阅读文档`doc/SysYFIR.md`以了解其接口的设计。
#### 样例学习
<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::create(Int32Type, module);
std::vector<SysYF::Ptr<Constant>> init_val;
init_val.push_back(CONST_INT(4));
init_val.push_back(CONST_INT(8));
auto num_initializer = ConstantArray::create(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<SysYF::Ptr<Type>> Ints(1, Int32Type);
//通过返回值类型与参数类型列表得到函数类型
auto climbStairsFunTy = FunctionType::create(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<SysYF::Ptr<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>
为了更直观地感受并学会使用 SysYF IR应用编程接口本实训项目提供了示例代码位于`Student/task2/demo/go_upstairs_gen.cpp`。
该C++程序会生成与go_upstairs.c逻辑相同的LLVM IR文件在该C++程序中提供了详尽的注释,请阅读理解,以便更好地开展你的实验!
### 本关具体任务
1. 你需要在`Student/task2/cpp/`文件夹中调用SysYF IR应用编程接口编写自己的 `assign_gen.cpp``func_gen.cpp``if_gen.cpp``while_gen.cpp`程序以生成与第1关的四个sy 程序相同逻辑功能的ll文件。
2. 在`report.md`内回答[思考题](#思考题)
### 编译、运行和验证
`Student/task2/build/` 下执行:
``` shell
# 如果存在 CMakeCache.txt 要先删除
# rm CMakeCache.txt
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文件
``` shell
# 在build文件夹内
./go_upstairs_generator
```
### 思考题
请在`report/report.md`中详细回答下述思考题:
2-1. 请给出`SysYFIR.md`中提到的两种getelementptr用法的区别, 并解释原因:
- `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
- `%2 = getelementptr i32, i32* %1, i32 %0`

@ -0,0 +1,132 @@
[TOC]
---
### 任务描述
**本关任务**:编写`IRBuilder.cpp`文件实现低级中间代码生成器为SysYF语言程序生成兼容的LLVM IR代码。
### 相关知识
#### 实验框架
本实训项目提供用C++语言编写的SysYF IR 应用编程库,用于构建 LLVM IR的子集。为了简化你的实验本实训的实验框架代码已完成了SysYF源程序到 C++ 上的抽象语法树的转换。
##### Scope
在`IRBuilder.h`中,还定义了一个用于存储作用域的类`Scope`。它的作用是在遍历语法树时,辅助管理不同作用域中的变量。它提供了以下接口:
```cpp
// 进入一个新的作用域
void enter();
// 退出一个作用域
void exit();
// 往当前作用域插入新的名字->值映射
bool push(std::string name, Ptr<Value> val);
// 根据名字以及是否为函数的bool值寻找到对应值
// isfunc 为 true 时为寻找函数,否则为寻找其他变量对应的值
Ptr<Value> find(std::string name, bool isfunc);
// 判断当前是否在全局作用域内
bool in_global();
```
你需要根据语义合理调用`enter`与`exit`,并且在变量声明和使用时正确调用`push`与`find`。在类`SysYFIRBuilder`中,有一个`Scope`类型的成员变量`scope`,它在初始化时已经将特殊函数加入了作用域中。因此,你在进行名字查找时不需要顾虑是否需要对特殊函数进行特殊操作。
##### shared_ptr
为了防止内存泄漏,助教将框架中的裸指针换成了智能指针,相关的类型定义在`include/internal_types`中,其中以下的类型转换方法:
```cpp
using std::static_pointer_cast;
using std::dynamic_pointer_cast;
using std::const_pointer_cast;
```
static_pointer_cast和dynamic_pointer_cast用于智能指针的类型转换隐式完成了拆包、类型转换、重新包装和内存控制块维护const_pointer_cast在转换时去除const属性含义和使用方法类似于static_cast、dynamic_cast和const_cast
```cpp
std::vector<std::shared_ptr<Duck>> ducks;
ducks.push_back(std::static_pointer_cast<Duck>(std::make_shared<EdibleDuck>()));
```
##### shared_from_this
这是助教在更新代码框架时涉及的部分在实验中并不会用到有兴趣的同学了解即可。由于改成了智能指针我们在使用create方法创建IR中的Value对象时需要在初始化的时候生成它的智能指针并返回我们使用了`include/internal_macros.h`中的宏来定义使用了智能指针后新的初始化过程先创建该对象的智能指针然后对该智能指针调用init方法而在init的过程中可能会用到它自身的智能指针比如`src/SysYFIR\BasicBlock.cpp`中的`parent_->add_basic_block(dynamic_pointer_cast<BasicBlock>(shared_from_this()));`这时需要用shared_from_this原因参考[cpp smart pointer](https://www.cyhone.com/articles/right-way-to-use-cpp-smart-pointer/)。
当然如果你企图直接使用构造函数而不用create方法的话你会很惊讶地发现你做不到因为助教已经很贴心地将构造函数设为private或者protected了所以不用担心不小心的使用而之所以不在构造函数中使用原因参考[shared_from_this说明1](https://blog.csdn.net/weixin_38927079/article/details/115505724)和[shared_from_this说明2](https://blog.csdn.net/u012398613/article/details/52243764)
### 本关具体任务
1. 你需要在`src/SysYFIRBuilder`文件夹中调用SysYF IR应用编程接口填写`IRBuilder.cpp`文件,以实现 LLVM IR 的自动生成。注意以下几点:
* a. 创建include/SysYFIR中的对象时只能通过create方法而不能直接使用构造函数(原因参考[shared_from_this](#shared_from_this)),如下:
```cpp
auto fun = Function::create(fun_type, node.name, module);
```
而不是:
```cpp
auto fun = new Function(fun_type, node.name, module);
```
* b. 尽量不要使用裸指针而是使用shared_ptr和相关的类型转换方法即`include/internal_types`定义的类型和方法
2. 在`report.md`内回答[思考题](#思考题)
3. 在`contribution.md`内由组长填写各组员的贡献比
### 编译、运行与验证
#### 编译运行 SysYFCompiler
```sh
mkdir build
cd build
cmake ..
make
```
请注意你会发现CMakeLists.txt中的CMAKE_CXX_FLAGS多了很多参数我们介绍其中一部分(参考[gcc warning options](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html))
* -Wextra打印一些额外的warning信息
* -Wno-unused不警告未使用的变量框架中一些函数有一些不用的参数
* -Wshadow如果一个局部变量隐藏掉了其他的变量、参数等报告warning
* -Werror将所有的warning都视为error也就是说如果你觉得你的warning并不对程序正确性有影响你可以把-Werror删除。
编译后会产生 `SysYFCompiler` 程序它能将SysYF源程序sy文件输出为LLVM IR。
当需要对 sy 文件测试时,可以这样使用:
```sh
SysYFCompiler test.sy -emit-ir -o test.ll
```
得到对应的ll文件。
#### 自动测试
本实训项目提供了自动评测脚本, 在`Student/task3/`目录下执行`python3 test.py`, 即可得到评测信息
### 思考题
请在`report/report.md`中详细回答下述思考题。
3-1. 在`scope`内单独处理`func`的好处有哪些。
### 选做
本实训项目提供了选做内容, 若你能完成选做部分, 将会有额外加分(仅针对本次实验的团队代码得分, 并且分数不能超过该部分得分上限)。
选做部分验收方式为线下验收,你需要在线下检查时提供对应代码通过助教给出的选做部分测试样例,并且讲解你的代码。
选做部分说明如下:(每个班只展示一部分)
- H班:
- 多维数组
- 网安班:
- 多维数组
- 将一维数组指针作为参数
- 逻辑运算(\&\&, \|\|, \!), 重点考察短路计算
#### 多维数组
目前给出的SysYF IR应用编程接口并不支持多维数组的实现因此你需要修改接口以实现多维数组的声明、初始化和使用你可以修改的内容为文件夹`include/SysYFIR``include/SysYFIRBuilder``src/SysYFIR``src/SysYFIRBuilder`内的所有内容
多维数组在目前的接口基础上,一般有两种做法:
- 直接实现,可以参考 clang 生成的 LLVM IR修改当前接口使其支持多维的数组类型
- 展平,把高维数组当成一维数组存储,修改当前接口使其能保存一些必要信息
在初始化多维数组时,与一维数组不同的是,存在对齐问题,这里假设多维数组的初始化为完全对齐(在每个大括号处均对齐),以下两种初始化是等价的:
`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}}`
#### 数组指针参数 & 逻辑运算
目前给出的SysYF IR接口支持数组指针参数和逻辑运算的短路计算因此你不需要修改接口。
注意`pointer`和`array`的区别以及文法中`&&`和`||`的优先级。
### 备注
测试样例除了位于版本库中的公开测例外,还包含不开放的隐藏测例。
平台上第三关的评测只判断公开测例是否完全通过, 第三关的分数由助教线下检查后,根据公开测例和隐藏测例的通过情况确定, 因此请自行设计合法测例测试你们的代码,确保你们的代码考虑了足够多情况以通过尽可能多的隐藏测例。
请将你编写的测例代码上传到`Student/task3/test_stu/`。

@ -0,0 +1,329 @@
#ifndef _SYSYF_SYNTAX_TREE_H_
#define _SYSYF_SYNTAX_TREE_H_
#include <vector>
#include <memory>
#include <string>
#include "location.hh"
#include "internal_types.h"
namespace SysYF
{
namespace SyntaxTree
{
using Position = yy::location;
// Enumerations
enum class Type
{
INT = 0,
VOID,
STRING,
BOOL,
FLOAT
};
enum class BinOp
{
PLUS = 0,
MINUS,
MULTIPLY,
DIVIDE,
MODULO
};
enum class UnaryOp
{
PLUS = 0,
MINUS
};
enum class UnaryCondOp
{
NOT = 0
};
enum class BinaryCondOp
{
LT = 0,
LTE,
GT,
GTE,
EQ,
NEQ,
LAND,
LOR
};
// Forward declaration
struct Node;
struct Assembly;
struct GlobalDef;
struct FuncDef;
struct Expr;
struct CondExpr;
struct AddExpr;
struct BinaryExpr;
struct BinaryCondExpr;
struct UnaryCondExpr;
struct UnaryExpr;
struct LVal;
struct Literal;
struct Stmt;
struct VarDef;
struct AssignStmt;
struct FuncCallStmt;
struct ReturnStmt;
struct BlockStmt;
struct EmptyStmt;
struct ExprStmt;
struct FuncParam;
struct FuncFParamList;
struct IfStmt;
struct WhileStmt;
struct BreakStmt;
struct ContinueStmt;
struct InitVal;
class Visitor;
// Virtual base of all kinds of syntax tree nodes.
struct Node
{
Position loc;
// Used in Visitor. Irrelevant to syntax tree generation.
virtual void accept(Visitor &visitor) = 0;
};
//node for initial value
struct InitVal: Node{
bool isExp;
PtrVec<InitVal> elementList;
Ptr<Expr> expr;
void accept(Visitor &visitor) final;
};
// Root node of an ordinary syntax tree.
struct Assembly : Node
{
PtrVec<GlobalDef> global_defs;
void accept(Visitor &visitor) final;
};
// Virtual base of global definitions, function or variable one.
struct GlobalDef : virtual Node
{
void accept(Visitor &visitor) override = 0;
};
// Function definition.
struct FuncDef : GlobalDef
{
Type ret_type;
Ptr<FuncFParamList> param_list;
std::string name;
Ptr<BlockStmt> body;
void accept(Visitor &visitor) final;
};
// Virtual base for statements.
struct Stmt : virtual Node
{
void accept(Visitor &visitor) override = 0;
};
// Variable definition. Multiple of this would be both a statement and a global definition; however, itself only
// represents a single variable definition.
struct VarDef : Stmt, GlobalDef
{
bool is_constant;
Type btype;
std::string name;
bool is_inited; // This is used to verify `{}`
PtrVec<Expr> array_length; // empty for non-array variables
Ptr<InitVal> initializers;
void accept(Visitor &visitor) final;
};
// Assignment statement.
struct AssignStmt : Stmt
{
Ptr<LVal> target;
Ptr<Expr> value;
void accept(Visitor &visitor) final;
};
// Return statement.
struct ReturnStmt : Stmt
{
Ptr<Expr> ret; // nullptr for void return
void accept(Visitor &visitor) final;
};
// BlockStmt statement.
struct BlockStmt : Stmt
{
PtrVec<Stmt> body;
void accept(Visitor &visitor) final;
};
// Empty statement (aka a single ';').
struct EmptyStmt : Stmt
{
void accept(Visitor &visitor) final;
};
struct ExprStmt : Stmt
{
Ptr<Expr> exp;
void accept(Visitor &visitor) final;
};
// Virtual base of expressions.
struct Expr : Node
{
void accept(Visitor &visitor) override = 0;
};
struct CondExpr : Expr
{
void accept(Visitor &visitor) override = 0;
};
struct AddExpr : Expr
{
void accept(Visitor &visitor) override = 0;
};
struct UnaryCondExpr : CondExpr{
UnaryCondOp op;
Ptr<Expr> rhs;
void accept(Visitor &visitor) final;
};
struct BinaryCondExpr : CondExpr{
BinaryCondOp op;
Ptr<Expr> lhs,rhs;
void accept(Visitor &visitor) final;
};
// Expression like `lhs op rhs`.
struct BinaryExpr : AddExpr
{
BinOp op;
Ptr<Expr> lhs, rhs;
void accept(Visitor &visitor) final;
};
// Expression like `op rhs`.
struct UnaryExpr : AddExpr
{
UnaryOp op;
Ptr<Expr> rhs;
void accept(Visitor &visitor) final;
};
// Expression like `ident` or `ident[exp]`.
struct LVal : AddExpr
{
std::string name;
PtrVec<Expr> array_index; // nullptr if not indexed as array
void accept(Visitor &visitor) final;
};
// Expression constructed by a literal number.
struct Literal : AddExpr
{
Type literal_type;
int int_const;
// std::string str;
double float_const;
void accept(Visitor &visitor) final;
};
// Function call statement.
struct FuncCallStmt : AddExpr
{
std::string name;
PtrVec<Expr> params;
void accept(Visitor &visitor) final;
};
struct FuncParam : Node
{
std::string name;
Type param_type;
PtrVec<Expr> array_index; // nullptr if not indexed as array
void accept(Visitor &visitor) final;
};
struct FuncFParamList : Node
{
PtrVec<FuncParam> params;
void accept(Visitor &visitor) final;
};
struct IfStmt : Stmt
{
Ptr<Expr> cond_exp;
Ptr<Stmt> if_statement;
Ptr<Stmt> else_statement;
void accept(Visitor &visitor) final;
};
struct WhileStmt : Stmt
{
Ptr<Expr> cond_exp;
Ptr<Stmt> statement;
void accept(Visitor &visitor) final;
};
struct BreakStmt : Stmt
{
void accept(Visitor &visitor) final;
};
struct ContinueStmt : Stmt
{
void accept(Visitor &visitor) final;
};
// Visitor base type
class Visitor
{
public:
virtual void visit(Assembly &node) = 0;
virtual void visit(FuncDef &node) = 0;
virtual void visit(BinaryExpr &node) = 0;
virtual void visit(UnaryExpr &node) = 0;
virtual void visit(LVal &node) = 0;
virtual void visit(Literal &node) = 0;
virtual void visit(ReturnStmt &node) = 0;
virtual void visit(VarDef &node) = 0;
virtual void visit(AssignStmt &node) = 0;
virtual void visit(FuncCallStmt &node) = 0;
virtual void visit(BlockStmt &node) = 0;
virtual void visit(EmptyStmt &node) = 0;
virtual void visit(ExprStmt &node) = 0;
virtual void visit(FuncParam &node) = 0;
virtual void visit(FuncFParamList &node) = 0;
virtual void visit(IfStmt &node) = 0;
virtual void visit(WhileStmt &node) = 0;
virtual void visit(BreakStmt &node) = 0;
virtual void visit(ContinueStmt &node) = 0;
virtual void visit(UnaryCondExpr &node) = 0;
virtual void visit(BinaryCondExpr &node) = 0;
virtual void visit(InitVal &node) = 0;
};
}
}
#endif // _SYSYF_SYNTAX_TREE_H_

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save