Commit 3b086a0e authored by 李晓奇's avatar 李晓奇

Merge branch 'master' of 202.38.79.174:compiler_staff/2022fall-compiler_cminus

parents 7804af88 91e15b7b
......@@ -3,10 +3,25 @@ cmake_minimum_required( VERSION 3.4 )
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -std=c99")
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_C_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
set(CMAKE_C_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
SET(CMAKE_CXX_FLAGS_ASAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined -fsanitize=address")
set(default_build_type "Debug")
if(NOT(CMAKE_BUILD_TYPE_SHADOW STREQUAL CMAKE_BUILD_TYPE))
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}'")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
else()
message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode")
endif()
set(CMAKE_BUILD_TYPE_SHADOW ${CMAKE_BUILD_TYPE} CACHE STRING "used to detect changes in build type" FORCE)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(FLEX REQUIRED)
find_package(BISON REQUIRED)
......@@ -32,6 +47,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR})
include_directories(include/lightir)
add_subdirectory(src)
add_subdirectory(tests)
......@@ -250,6 +250,7 @@ int main(void) {
* 提交异常:如果遇到在平台上提交异常的问题,请通过邮件联系助教,助教将收取截止日期之前,学生在 gitlab 仓库最近一次 commit 内容进行评测。
* 迟交规定
<<<<<<< HEAD
* Soft Deadline:2022-09-30 23:59:59 (UTC+8)
......@@ -270,6 +271,28 @@ int main(void) {
final_grade = grade * (0.9)^x, 0 < x <= 7
final_grade = 0, x > 7
```
=======
* Soft Deadline:2022-10-03 23:59:59 (UTC+8)
* Hard Deadline:2022-10-10 23:59:59 (UTC+8)
* 补交请邮件提醒 TA:
* 邮箱:`zhenghy22@mail.ustc.edu.cn` 抄送 `chen16614@mail.ustc.edu.cn`
* 邮件主题:lab1迟交-学号
* 内容:迟交原因、最后版本commitID、迟交时间
* 迟交分数
* x 为相对 Soft Deadline 迟交天数,grade 满分 100
```
final_grade = grade, x = 0
final_grade = grade * (0.9)^x, 0 < x <= 7
final_grade = 0, x > 7
```
>>>>>>> 91e15b7b5e67900d4f6e90afe5bdab681dd82e89
* 评分标准:
实验一最终分数组成如下:
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# logging 工具使用
## 介绍
为了方便同学们在之后的实验中 debug,为大家设计了一个C++简单实用的分级日志工具。该工具将日志输出信息从低到高分成四种等级:`DEBUG``INFO``WARNING``ERROR`。通过设定环境变量`LOGV`的值,来选择输出哪些等级的日志。`LOGV`的取值是**0~3**,分别对应到上述的4种级别(`0:DEBUG`,`1:INFO`,`2:WARNING`,`3:ERROR`)。此外输出中还会包含打印该日志的代码所在位置。
## 使用
项目编译好之后,可以在`build`目录下运行`test_logging`,该文件的源代码在`tests/test_logging.cpp`。用法如下:
```cpp
#include "logging.hpp"
// 引入头文件
int main(){
LOG(DEBUG) << "This is DEBUG log item.";
// 使用关键字LOG,括号中填入要输出的日志等级
// 紧接着就是<<以及日志的具体信息,就跟使用std::cout一样
LOG(INFO) << "This is INFO log item";
LOG(WARNING) << "This is WARNING log item";
LOG(ERROR) << "This is ERROR log item";
return 0;
}
```
接着在运行该程序的时候,设定环境变量`LOGV=0`,那么程序就会输出级别**大于等于0**日志信息:
```bash
user@user:${ProjectDir}/build$ LOGV=0 ./test_logging
[DEBUG] (test_logging.cpp:5L main)This is DEBUG log item.
[INFO] (test_logging.cpp:6L main)This is INFO log item
[WARNING] (test_logging.cpp:7L main)This is WARNING log item
[ERROR] (test_logging.cpp:8L main)This is ERROR log item
```
输出中除了包含日志级别和用户想打印的信息,在圆括号中还包含了打印该信息代码的具体位置(包括文件名称、所在行、所在函数名称),可以很方便地定位到出问题的地方。
假如我们觉得程序已经没有问题了,不想看那么多的DEBUG信息,那么我们就可以设定环境变量`LOGV=1`,选择只看**级别大于等于1**的日志信息:
```bash
user@user:${ProjectDir}/build$ LOGV=0 ./test_logging
[INFO] (test_logging.cpp:6L main)This is INFO log item
[WARNING] (test_logging.cpp:7L main)This is WARNING log item
[ERROR] (test_logging.cpp:8L main)This is ERROR log item
```
当然`LOGV`值越大,日志的信息将更加简略。如果没有设定`LOGV`的环境变量,将默认不输出任何信息。
这里再附带一个小技巧,如果日志内容多,在终端观看体验较差,可以输入以下命令将日志输出到文件中:
```
user@user:${ProjectDir}/build$ LOGV=0 ./test_logging > log
```
然后就可以输出到文件名为log的文件中啦~
# CPP 简介
C++是一门面向对象的语言,从名字可以看出,C++从C中获得了许多灵感。但是随着C++的发展,它和C的差异也越来越大,一个典型的例子是C是弱类型的语言,而C++越来越支持强类型。因此我们不能直接认为C++兼容C,而应该先了解二者的区别。好在本次实验并不需要你们使用高级的C++特性,所以在此简单介绍一下部分特性便于理解。如果对C++有更深的兴趣,可以从Milo Yip的[游戏程序员的学习之路](https://github.com/miloyip/game-programmer/blob/master/game-programmer-zh-cn.jpg?raw=true)的C++部分开始看。
注:本介绍假设你有基本的C语言认知(略高于程设课标准),如果有不懂的C语言术语建议去搜索一下
## class
class是C++面向对象的基础,它相当于对C中的结构体的扩展。除了保留了原来的结构体成员(即成员对象),它增加了成员函数、访问控制、继承和多态等。
假设某类为`Animal`,一个它的实例为`animal`,我们可以在`Animal`的定义中增加函数声明`void eat();`,这样声明的函数即是成员函数。成员函数的作用域中自带一个`Animal*`类型的指针`this`,指向调用该成员函数的实例。我们可以通过`animal.eat()`一样,用类似访问成员的方法访问该函数。
```cpp
// 注:C++中struct也会定义结构体,只是访问控制的默认选项有所区别
struct Animal {
void eat()
}
```
类的访问控制指的是在定义class时,可以用`public``private`标签,指定接下来的成员是私有或是公开成员。公开成员可以在外部函数使用该类的实例时访问,而内部成员只有该类的成员函数能访问。访问控制的作用是对使用者隐藏实现的细节,而关注于设计者想要公开的接口,从而让使用者能更容易理解如何使用该类。详细介绍在[access specifiers](https://en.cppreference.com/w/cpp/language/access)
类的继承是一种面向对象语言常用的代码复用方法,也是一种非常直观的抽象方式。我们可以定义`struct Cat : Animal`来声明`Cat`类是`Animal`类的子类,也就是`Cat`继承了`Animal`类。此时,新的`Cat`类从`Animal`类中继承了`void eat();`成员函数,并且可以在此之上定义额外的成员函数`void nyan()`。同理,我们也可以定义`struct Dog : Animal`来定义`Dog`类。
```cpp
struct Cat : Animal {
// 从Animal中继承了void eat();
void nyan()
};
struct Dog : Animal {
// 从Animal中继承了void eat();
void wang()
};
```
我们可以通过合理的继承结构来将函数定义在合适的位置,使得大部分通用函数可以共享。
同学们可能会想到同是`Animal``Cat``Dog`可能会有相同名称与参数的函数,但是却有着不同的实现,这时我们就要用到虚函数了。子类中可以定义虚函数的实现,从而使得不同子类对于同一个名字的成员函数有不同实现。虚函数在调用时会通过虚函数表查找到对应的函数实现,而不是和普通类一样查找对应类型的函数实现。
```cpp
struct Animal {
// = 0 表示该虚函数在Animal类中没有实现
virtual void say() = 0;
};
struct Cat : Animal {
// override表示覆盖父函数中的实现,下同
void say() override {
std::cout << "I'm a cat" << std::endl;
}
};
struct Dog : Animal {
void say() override{
std::cout << "I'm a dog" << std::endl;
}
};
// 试一试
int main() {
Cat c;
Dog d;
Animal* a;
c.say();
d.say();
a = &c;
a->say();
a = &d;
a->say();
return 0;
}
```
## 函数
C++中的函数可以重载,即可以有同名函数,但是要求它们的形参必须不同。如果想进一步了解,可以阅读[详细规则](https://en.cppreference.com/w/cpp/language/overload_resolution)。下面是函数重载的示例:
```cpp
struct Point {
int x;
int y;
};
struct Line {
Point first;
Point second;
};
void print(Point p) {
printf("(%d, %d)", p.x, p.y);
}
void print(Line s) {
print(s.first) // s.first == Point { ... }
printf("->");
print(s.second) // s.second == Point { ... }
}
```
我们可以看到上面的示例定义了两个`print`函数,并且它们的参数列表的类型不同。它们实际上是两个不同的函数(并且拥有不同的内部名字),但是C++能够正确的识别函数调用时使用了哪一个定义(前提是你正确使用了这一特性),并且在编译时就会链接上正确的实现。我们可以看到,这种特性非常符合人的直觉,并且没有带来额外开销。
## 泛型
不同于C中使用void指针来实现泛型函数(如`qsort`),C++中使用模板来帮助定义泛型类型与泛型函数等。由于模板过于复杂,这里不做深入介绍。这里你们需要理解的是,C++中的模板定义正如其名,在实例化前只是一个模板而不是参与编译的代码。只有在你使用的过程中指定了参数,编译器才会自动根据模板产生相应的代码,也就是实例化该参数对应的代码。比如`std::vector`是C++中常用的数组容器,在使用时必须指定参数,如果要实例化`int`类型的数组容器,必须要使用`std::vector<int>`
## 内存分配
C中,只能使用标准库中的`malloc``free`来进行内存分配,并且需要手动在内存上初始化类型。C++中增加了`new``delete`关键字,你可以使用`new classname(params)`的完成申请一块内存,利用构造函数(`classname(params)`即代表调用`classname`类型的一个构造函数)来完成内存初始化。而`delete variable`可以调用变量对应类型函数的析构函数来完成数据结构的清理和回收内存。但是它存在着和C一样的二次回收导致报错或忘记回收导致内存泄漏的问题。于是C++11引入了许多智能指针类型,本实验中用到的有两种,分别是:
1. `std::shared_ptr`: 引用计数智能指针,使用一个共享变量来记录指针管理的对象被引用了几次。当对象引用计数为0时,说明当前该对象不再有引用,并且进程也无法再通过其它方式来引用它,也就意味着可以回收内存,这相当于低级的垃圾回收策略。
2. `std::unique_ptr`: 表示所有权的智能指针,该指针要求它所管理的对象智能有一次引用,主要用于语义上不允许共享的对象(比如`llvm::Module`)。当引用计数为0时,它也会回收内存。
......@@ -5,7 +5,10 @@
## 目前已布置的实验
* [lab1](./Documentations/1-parser/)
+ DDL:2022-09-30 23:59:59 (UTC+8)
+ DDL:2022-10-03 23:59:59 (UTC+8)
* [lab2](./Documentations/2-ir-gen-warmup/)
+ DDL:2022-10-23 23:59:59 (UTC+8)
## FAQ: How to merge upstream remote branches
......
# lab2 实验报告
学号 姓名
## 问题1: getelementptr
请给出 `IR.md` 中提到的两种 getelementptr 用法的区别,并稍加解释:
- `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
- `%2 = getelementptr i32, i32* %1 i32 %0`
## 问题2: cpp 与 .ll 的对应
请说明你的 cpp 代码片段和 .ll 的每个 BasicBlock 的对应关系。
## 问题3: Visitor Pattern
分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为:
1. 请画出该表达式对应的抽象语法树(使用 `calc_ast.hpp` 中的 `CalcAST*` 类型和在该类型中存储的值来表示),并给节点使用数字编号。
2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。
序列请按如下格式指明(序号为问题 2.1 中的编号):
3->2->5->1
## 实验难点
描述在实验中遇到的问题、分析和解决方案。
## 实验反馈
吐槽?建议?
#ifndef SYSYC_BASICBLOCK_H
#define SYSYC_BASICBLOCK_H
#include "Instruction.h"
#include "Value.h"
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <set>
#include <string>
class Function;
class Instruction;
class Module;
class BasicBlock : public Value, public llvm::ilist_node<BasicBlock> {
public:
static BasicBlock *create(Module *m, const std::string &name, Function *parent) {
auto prefix = name.empty() ? "" : "label_";
return new BasicBlock(m, prefix + name, parent);
}
// return parent, or null if none.
Function *get_parent() { return parent_; }
Module *get_module();
/****************api about cfg****************/
std::list<BasicBlock *> &get_pre_basic_blocks() { return pre_bbs_; }
std::list<BasicBlock *> &get_succ_basic_blocks() { return succ_bbs_; }
void add_pre_basic_block(BasicBlock *bb) { pre_bbs_.push_back(bb); }
void add_succ_basic_block(BasicBlock *bb) { succ_bbs_.push_back(bb); }
void remove_pre_basic_block(BasicBlock *bb) { pre_bbs_.remove(bb); }
void remove_succ_basic_block(BasicBlock *bb) { succ_bbs_.remove(bb); }
/****************api about cfg****************/
/// Returns the terminator instruction if the block is well formed or null
/// if the block is not well formed.
const Instruction *get_terminator() const;
Instruction *get_terminator() {
return const_cast<Instruction *>(static_cast<const BasicBlock *>(this)->get_terminator());
}
void add_instruction(Instruction *instr);
void add_instr_begin(Instruction *instr);
void delete_instr(Instruction *instr);
bool empty() { return instr_list_.empty(); }
int get_num_of_instr() { return instr_list_.size(); }
llvm::ilist<Instruction> &get_instructions() { return instr_list_; }
void erase_from_parent();
virtual std::string print() override;
private:
explicit BasicBlock(Module *m, const std::string &name, Function *parent);
std::list<BasicBlock *> pre_bbs_;
std::list<BasicBlock *> succ_bbs_;
// std::list<Instruction *> instr_list_;
llvm::ilist<Instruction> instr_list_;
Function *parent_;
};
#endif // SYSYC_BASICBLOCK_H
//
// Created by cqy on 2020/6/29.
//
#ifndef SYSYC_CONSTANT_H
#define SYSYC_CONSTANT_H
#include "User.h"
#include "Value.h"
#include "Type.h"
class Constant : public User
{
private:
// int value;
public:
Constant(Type *ty, const std::string &name = "", unsigned num_ops = 0)
: User(ty, name, num_ops) {}
~Constant() = default;
};
class ConstantInt : public Constant
{
private:
int value_;
ConstantInt(Type* ty,int val)
: Constant(ty,"",0),value_(val) {}
public:
static int get_value(ConstantInt *const_val) { return const_val->value_; }
int get_value() { return value_; }
static ConstantInt *get(int val, Module *m);
static ConstantInt *get(bool val, Module *m);
virtual std::string print() override;
};
class ConstantArray : public Constant
{
private:
std::vector<Constant*> const_array;
ConstantArray(ArrayType *ty, const std::vector<Constant*> &val);
public:
~ConstantArray()=default;
Constant* get_element_value(int index);
unsigned get_size_of_array() { return const_array.size(); }
static ConstantArray *get(ArrayType *ty, const std::vector<Constant*> &val);
virtual std::string print() override;
};
class ConstantZero : public Constant
{
private:
ConstantZero(Type *ty)
: Constant(ty,"",0) {}
public:
static ConstantZero *get(Type *ty, Module *m);
virtual std::string print() override;
};
class ConstantFP : public Constant
{
private:
float val_;
ConstantFP(Type *ty, float val)
: Constant(ty,"",0), val_(val) {}
public:
static ConstantFP *get(float val, Module *m);
float get_value() { return val_; }
virtual std::string print() override;
};
#endif //SYSYC_CONSTANT_H
#ifndef SYSYC_FUNCTION_H
#define SYSYC_FUNCTION_H
#include "BasicBlock.h"
#include "Type.h"
#include "User.h"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <map>
#include <memory>
class Module;
class Argument;
class Type;
class FunctionType;
class Function : public Value, public llvm::ilist_node<Function> {
public:
Function(FunctionType *ty, const std::string &name, Module *parent);
virtual ~Function();
static Function *create(FunctionType *ty, const std::string &name, Module *parent);
FunctionType *get_function_type() const;
Type *get_return_type() const;
void add_basic_block(BasicBlock *bb);
unsigned get_num_of_args() const;
unsigned get_num_basic_blocks() const;
Module *get_parent() const;
std::list<Argument *>::iterator arg_begin() { return arguments_.begin(); }
std::list<Argument *>::iterator arg_end() { return arguments_.end(); }
void remove(BasicBlock *bb);
BasicBlock *get_entry_block() { return &*basic_blocks_.begin(); }
llvm::ilist<BasicBlock> &get_basic_blocks() { return basic_blocks_; }
std::list<Argument *> &get_args() { return arguments_; }
bool is_declaration() { return basic_blocks_.empty(); }
void set_instr_name();
std::string print();
private:
void build_args();
private:
llvm::ilist<BasicBlock> basic_blocks_; // basic blocks
std::list<Argument *> arguments_; // arguments
Module *parent_;
unsigned seq_cnt_;
// unsigned num_args_;
// We don't need this, all value inside function should be unnamed
// std::map<std::string, Value*> sym_table_; // Symbol table of args/instructions
};
// Argument of Function, does not contain actual value
class Argument : public Value {
public:
/// Argument constructor.
explicit Argument(Type *ty, const std::string &name = "", Function *f = nullptr, unsigned arg_no = 0)
: Value(ty, name), parent_(f), arg_no_(arg_no) {}
virtual ~Argument() {}
inline const Function *get_parent() const { return parent_; }
inline Function *get_parent() { return parent_; }
/// For example in "void foo(int a, float b)" a is 0 and b is 1.
unsigned get_arg_no() const {
assert(parent_ && "can't get number of unparented arg");
return arg_no_;
}
virtual std::string print() override;
private:
Function *parent_;
unsigned arg_no_; // argument No.
};
#endif // SYSYC_FUNCTION_H
//
// Created by cqy on 2020/6/29.
//
#ifndef SYSYC_GLOBALVARIABLE_H
#define SYSYC_GLOBALVARIABLE_H
#include "Constant.h"
#include "User.h"
#include <llvm/ADT/ilist_node.h>
class Module;
class GlobalVariable : public User, public llvm::ilist_node<GlobalVariable> {
private:
bool is_const_;
Constant *init_val_;
GlobalVariable(std::string name, Module *m, Type *ty, bool is_const, Constant *init = nullptr);
public:
static GlobalVariable *create(std::string name, Module *m, Type *ty, bool is_const, Constant *init);
virtual ~GlobalVariable() = default;
Constant *get_init() { return init_val_; }
bool is_const() { return is_const_; }
std::string print();
};
#endif // SYSYC_GLOBALVARIABLE_H
#ifndef SYSYC_IRBUILDER_H
#define SYSYC_IRBUILDER_H
#include "BasicBlock.h"
#include "Function.h"
#include "Instruction.h"
#include "Value.h"
class IRBuilder {
private:
BasicBlock *BB_;
Module *m_;
public:
IRBuilder(BasicBlock *bb, Module *m) : BB_(bb), m_(m){};
~IRBuilder() = default;
Module *get_module() { return m_; }
BasicBlock *get_insert_block() { return this->BB_; }
void set_insert_point(BasicBlock *bb) { this->BB_ = bb; } // 在某个基本块中插入指令
BinaryInst *create_iadd(Value *lhs, Value *rhs) {
return BinaryInst::create_add(lhs, rhs, this->BB_, m_);
} // 创建加法指令(以及其他算术指令)
BinaryInst *create_isub(Value *lhs, Value *rhs) { return BinaryInst::create_sub(lhs, rhs, this->BB_, m_); }
BinaryInst *create_imul(Value *lhs, Value *rhs) { return BinaryInst::create_mul(lhs, rhs, this->BB_, m_); }
BinaryInst *create_isdiv(Value *lhs, Value *rhs) { return BinaryInst::create_sdiv(lhs, rhs, this->BB_, m_); }
CmpInst *create_icmp_eq(Value *lhs, Value *rhs) {
return CmpInst::create_cmp(CmpInst::EQ, lhs, rhs, this->BB_, m_);
}
CmpInst *create_icmp_ne(Value *lhs, Value *rhs) {
return CmpInst::create_cmp(CmpInst::NE, lhs, rhs, this->BB_, m_);
}
CmpInst *create_icmp_gt(Value *lhs, Value *rhs) {
return CmpInst::create_cmp(CmpInst::GT, lhs, rhs, this->BB_, m_);
}
CmpInst *create_icmp_ge(Value *lhs, Value *rhs) {
return CmpInst::create_cmp(CmpInst::GE, lhs, rhs, this->BB_, m_);
}
CmpInst *create_icmp_lt(Value *lhs, Value *rhs) {
return CmpInst::create_cmp(CmpInst::LT, lhs, rhs, this->BB_, m_);
}
CmpInst *create_icmp_le(Value *lhs, Value *rhs) {
return CmpInst::create_cmp(CmpInst::LE, lhs, rhs, this->BB_, m_);
}
CallInst *create_call(Value *func, std::vector<Value *> args) {
assert(dynamic_cast<Function *>(func) && "func must be Function * type");
return CallInst::create(static_cast<Function *>(func), args, this->BB_);
}
BranchInst *create_br(BasicBlock *if_true) { return BranchInst::create_br(if_true, this->BB_); }
BranchInst *create_cond_br(Value *cond, BasicBlock *if_true, BasicBlock *if_false) {
return BranchInst::create_cond_br(cond, if_true, if_false, this->BB_);
}
ReturnInst *create_ret(Value *val) { return ReturnInst::create_ret(val, this->BB_); }
ReturnInst *create_void_ret() { return ReturnInst::create_void_ret(this->BB_); }
GetElementPtrInst *create_gep(Value *ptr, std::vector<Value *> idxs) {
return GetElementPtrInst::create_gep(ptr, idxs, this->BB_);
}
StoreInst *create_store(Value *val, Value *ptr) { return StoreInst::create_store(val, ptr, this->BB_); }
LoadInst *create_load(Type *ty, Value *ptr) { return LoadInst::create_load(ty, ptr, this->BB_); }
LoadInst *create_load(Value *ptr) {
assert(ptr->get_type()->is_pointer_type() && "ptr must be pointer type");
return LoadInst::create_load(ptr->get_type()->get_pointer_element_type(), ptr, this->BB_);
}
AllocaInst *create_alloca(Type *ty) { return AllocaInst::create_alloca(ty, this->BB_); }
ZextInst *create_zext(Value *val, Type *ty) { return ZextInst::create_zext(val, ty, this->BB_); }
SiToFpInst *create_sitofp(Value *val, Type *ty) { return SiToFpInst::create_sitofp(val, ty, this->BB_); }
FpToSiInst *create_fptosi(Value *val, Type *ty) { return FpToSiInst::create_fptosi(val, ty, this->BB_); }
FCmpInst *create_fcmp_ne(Value *lhs, Value *rhs) {
return FCmpInst::create_fcmp(FCmpInst::NE, lhs, rhs, this->BB_, m_);
}
FCmpInst *create_fcmp_lt(Value *lhs, Value *rhs) {
return FCmpInst::create_fcmp(FCmpInst::LT, lhs, rhs, this->BB_, m_);
}
FCmpInst *create_fcmp_le(Value *lhs, Value *rhs) {
return FCmpInst::create_fcmp(FCmpInst::LE, lhs, rhs, this->BB_, m_);
}
FCmpInst *create_fcmp_ge(Value *lhs, Value *rhs) {
return FCmpInst::create_fcmp(FCmpInst::GE, lhs, rhs, this->BB_, m_);
}
FCmpInst *create_fcmp_gt(Value *lhs, Value *rhs) {
return FCmpInst::create_fcmp(FCmpInst::GT, lhs, rhs, this->BB_, m_);
}
FCmpInst *create_fcmp_eq(Value *lhs, Value *rhs) {
return FCmpInst::create_fcmp(FCmpInst::EQ, lhs, rhs, this->BB_, m_);
}
BinaryInst *create_fadd(Value *lhs, Value *rhs) { return BinaryInst::create_fadd(lhs, rhs, this->BB_, m_); }
BinaryInst *create_fsub(Value *lhs, Value *rhs) { return BinaryInst::create_fsub(lhs, rhs, this->BB_, m_); }
BinaryInst *create_fmul(Value *lhs, Value *rhs) { return BinaryInst::create_fmul(lhs, rhs, this->BB_, m_); }
BinaryInst *create_fdiv(Value *lhs, Value *rhs) { return BinaryInst::create_fdiv(lhs, rhs, this->BB_, m_); }
};
#endif // SYSYC_IRBUILDER_H
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "GlobalVariable.h"
#include "Instruction.h"
#include "Module.h"
#include "Type.h"
#include "User.h"
#include "Value.h"
std::string print_as_op(Value *v, bool print_ty);
std::string print_cmp_type(CmpInst::CmpOp op);
std::string print_fcmp_type(FCmpInst::CmpOp op);
This diff is collapsed.
#ifndef SYSYC_MODULE_H
#define SYSYC_MODULE_H
#include "Function.h"
#include "GlobalVariable.h"
#include "Instruction.h"
#include "Type.h"
#include "Value.h"
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <map>
#include <memory>
#include <string>
class GlobalVariable;
class Function;
class Module {
public:
explicit Module(std::string name);
~Module();
Type *get_void_type();
Type *get_label_type();
IntegerType *get_int1_type();
IntegerType *get_int32_type();
PointerType *get_int32_ptr_type();
FloatType *get_float_type();
PointerType *get_float_ptr_type();
PointerType *get_pointer_type(Type *contained);
ArrayType *get_array_type(Type *contained, unsigned num_elements);
FunctionType *get_function_type(Type *retty, std::vector<Type *> &args);
void add_function(Function *f);
llvm::ilist<Function> &get_functions();
void add_global_variable(GlobalVariable *g);
llvm::ilist<GlobalVariable> &get_global_variable();
std::string get_instr_op_name(Instruction::OpID instr) { return instr_id2string_[instr]; }
void set_print_name();
std::string print();
private:
llvm::ilist<GlobalVariable> global_list_; // The Global Variables in the module
llvm::ilist<Function> function_list_; // The Functions in the module
std::map<std::string, Value *> value_sym_; // Symbol table for values
std::map<Instruction::OpID, std::string> instr_id2string_; // Instruction from opid to string
std::string module_name_; // Human readable identifier for the module
std::string source_file_name_; // Original source file name for module, for test and debug
private:
std::unique_ptr<IntegerType> int1_ty_;
std::unique_ptr<IntegerType> int32_ty_;
std::unique_ptr<Type> label_ty_;
std::unique_ptr<Type> void_ty_;
std::unique_ptr<FloatType> float32_ty_;
std::map<Type *, std::unique_ptr<PointerType>> pointer_map_;
std::map<std::pair<Type *, int>, std::unique_ptr<ArrayType>> array_map_;
std::map<std::pair<Type *, std::vector<Type *>>, std::unique_ptr<FunctionType>> function_map_;
};
#endif // SYSYC_MODULE_H
#ifndef SYSYC_TYPE_H
#define SYSYC_TYPE_H
#include <iostream>
#include <vector>
class Module;
class IntegerType;
class FunctionType;
class ArrayType;
class PointerType;
class FloatType;
class Type {
public:
enum TypeID {
VoidTyID, // Void
LabelTyID, // Labels, e.g., BasicBlock
IntegerTyID, // Integers, include 32 bits and 1 bit
FunctionTyID, // Functions
ArrayTyID, // Arrays
PointerTyID, // Pointer
FloatTyID // float
};
explicit Type(TypeID tid, Module *m);
~Type() = default;
TypeID get_type_id() const { return tid_; }
bool is_void_type() const { return get_type_id() == VoidTyID; }
bool is_label_type() const { return get_type_id() == LabelTyID; }
bool is_integer_type() const { return get_type_id() == IntegerTyID; }
bool is_function_type() const { return get_type_id() == FunctionTyID; }
bool is_array_type() const { return get_type_id() == ArrayTyID; }
bool is_pointer_type() const { return get_type_id() == PointerTyID; }
bool is_float_type() const { return get_type_id() == FloatTyID; }
static bool is_eq_type(Type *ty1, Type *ty2);
static Type *get_void_type(Module *m);
static Type *get_label_type(Module *m);
static IntegerType *get_int1_type(Module *m);
static IntegerType *get_int32_type(Module *m);
static PointerType *get_int32_ptr_type(Module *m);
static FloatType *get_float_type(Module *m);
static PointerType *get_float_ptr_type(Module *m);
static PointerType *get_pointer_type(Type *contained);
static ArrayType *get_array_type(Type *contained, unsigned num_elements);
Type *get_pointer_element_type();
Type *get_array_element_type();
int get_size();
Module *get_module();
std::string print();
private:
TypeID tid_;
Module *m_;
};
class IntegerType : public Type {
public:
explicit IntegerType(unsigned num_bits, Module *m);
static IntegerType *get(unsigned num_bits, Module *m);
unsigned get_num_bits();
private:
unsigned num_bits_;
};
class FunctionType : public Type {
public:
FunctionType(Type *result, std::vector<Type *> params);
static bool is_valid_return_type(Type *ty);
static bool is_valid_argument_type(Type *ty);
static FunctionType *get(Type *result, std::vector<Type *> params);
unsigned get_num_of_args() const;
Type *get_param_type(unsigned i) const;
std::vector<Type *>::iterator param_begin() { return args_.begin(); }
std::vector<Type *>::iterator param_end() { return args_.end(); }
Type *get_return_type() const;
private:
Type *result_;
std::vector<Type *> args_;
};
class ArrayType : public Type {
public:
ArrayType(Type *contained, unsigned num_elements);
static bool is_valid_element_type(Type *ty);
static ArrayType *get(Type *contained, unsigned num_elements);
Type *get_element_type() const { return contained_; }
unsigned get_num_of_elements() const { return num_elements_; }
private:
Type *contained_; // The element type of the array.
unsigned num_elements_; // Number of elements in the array.
};
class PointerType : public Type {
public:
PointerType(Type *contained);
Type *get_element_type() const { return contained_; }
static PointerType *get(Type *contained);
private:
Type *contained_; // The element type of the ptr.
};
class FloatType : public Type {
public:
FloatType(Module *m);
static FloatType *get(Module *m);
private:
};
#endif // SYSYC_TYPE_H
\ No newline at end of file
#ifndef SYSYC_USER_H
#define SYSYC_USER_H
#include "Value.h"
#include <vector>
// #include <memory>
class User : public Value {
public:
User(Type *ty, const std::string &name = "", unsigned num_ops = 0);
virtual ~User() = default;
std::vector<Value *> &get_operands();
// start from 0
Value *get_operand(unsigned i) const;
// start from 0
void set_operand(unsigned i, Value *v);
void add_operand(Value *v);
unsigned get_num_operand() const;
void remove_use_of_ops();
void remove_operands(int index1, int index2);
private:
// std::unique_ptr< std::list<Value *> > operands_; // operands of this value
std::vector<Value *> operands_; // operands of this value
unsigned num_ops_;
};
#endif // SYSYC_USER_H
#ifndef SYSYC_VALUE_H
#define SYSYC_VALUE_H
#include <iostream>
#include <list>
#include <string>
class Type;
class Value;
struct Use {
Value *val_;
unsigned arg_no_; // the no. of operand, e.g., func(a, b), a is 0, b is 1
Use(Value *val, unsigned no) : val_(val), arg_no_(no) {}
};
class Value {
public:
explicit Value(Type *ty, const std::string &name = "");
virtual ~Value() = default;
Type *get_type() const { return type_; }
std::list<Use> &get_use_list() { return use_list_; }
void add_use(Value *val, unsigned arg_no = 0);
bool set_name(std::string name) {
if (name_ == "") {
name_ = name;
return true;
}
return false;
}
std::string get_name() const;
void replace_all_use_with(Value *new_val);
void remove_use(Value *val);
virtual std::string print() = 0;
private:
Type *type_;
std::list<Use> use_list_; // who use this value
std::string name_; // should we put name field here ?
};
#endif // SYSYC_VALUE_H
add_subdirectory(parser)
add_subdirectory(common)
\ No newline at end of file
add_subdirectory(common)
add_subdirectory(io)
add_subdirectory(lightir)
\ No newline at end of file
add_library(cminus_io io.c)
install(
TARGETS cminus_io
ARCHIVE DESTINATION lib
)
#include <stdio.h>
#include <stdlib.h>
int input() {
int a;
scanf("%d", &a);
return a;
}
void output(int a) { printf("%d\n", a); }
void outputFloat(float a) { printf("%f\n", a); }
void neg_idx_except() {
printf("negative index exception\n");
exit(0);
}
#include "BasicBlock.h"
#include "Function.h"
#include "IRprinter.h"
#include "Module.h"
#include <cassert>
BasicBlock::BasicBlock(Module *m, const std::string &name = "", Function *parent = nullptr)
: Value(Type::get_label_type(m), name), parent_(parent) {
assert(parent && "currently parent should not be nullptr");
parent_->add_basic_block(this);
}
Module *BasicBlock::get_module() { return get_parent()->get_parent(); }
void BasicBlock::add_instruction(Instruction *instr) { instr_list_.push_back(instr); }
void BasicBlock::add_instr_begin(Instruction *instr) { instr_list_.push_front(instr); }
void BasicBlock::delete_instr(Instruction *instr) {
instr_list_.remove(instr);
instr->remove_use_of_ops();
}
const Instruction *BasicBlock::get_terminator() const {
if (instr_list_.empty()) {
return nullptr;
}
switch (instr_list_.back().get_instr_type()) {
case Instruction::ret: return &instr_list_.back();
case Instruction::br: return &instr_list_.back();
default: return nullptr;
}
}
void BasicBlock::erase_from_parent() { this->get_parent()->remove(this); }
std::string BasicBlock::print() {
std::string bb_ir;
bb_ir += this->get_name();
bb_ir += ":";
// print prebb
if (!this->get_pre_basic_blocks().empty()) {
bb_ir += " ; preds = ";
}
for (auto bb : this->get_pre_basic_blocks()) {
if (bb != *this->get_pre_basic_blocks().begin())
bb_ir += ", ";
bb_ir += print_as_op(bb, false);
}
// print prebb
if (!this->get_parent()) {
bb_ir += "\n";
bb_ir += "; Error: Block without parent!";
}
bb_ir += "\n";
for (auto &instr : this->get_instructions()) {
bb_ir += " ";
bb_ir += instr.print();
bb_ir += "\n";
}
return bb_ir;
}
add_library(
IR_lib STATIC
Type.cpp
User.cpp
Value.cpp
BasicBlock.cpp
Constant.cpp
Function.cpp
GlobalVariable.cpp
Instruction.cpp
Module.cpp
IRprinter.cpp
)
target_link_libraries(
IR_lib
LLVMSupport
)
#include "Constant.h"
#include "Module.h"
#include <iostream>
#include <memory>
#include <sstream>
struct pair_hash {
template <typename T>
std::size_t operator()(const std::pair<T, Module *> val) const {
auto lhs = std::hash<T>()(val.first);
auto rhs = std::hash<uintptr_t>()(reinterpret_cast<uintptr_t>(val.second));
return lhs ^ rhs;
}
};
static std::unordered_map<std::pair<int, Module *>, std::unique_ptr<ConstantInt>, pair_hash> cached_int;
static std::unordered_map<std::pair<bool, Module *>, std::unique_ptr<ConstantInt>, pair_hash> cached_bool;
static std::unordered_map<std::pair<float, Module *>, std::unique_ptr<ConstantFP>, pair_hash> cached_float;
static std::unordered_map<Type *, std::unique_ptr<ConstantZero>> cached_zero;
ConstantInt *ConstantInt::get(int val, Module *m) {
if (cached_int.find(std::make_pair(val, m)) != cached_int.end())
return cached_int[std::make_pair(val, m)].get();
return (cached_int[std::make_pair(val, m)] =
std::unique_ptr<ConstantInt>(new ConstantInt(Type::get_int32_type(m), val)))
.get();
}
ConstantInt *ConstantInt::get(bool val, Module *m) {
if (cached_bool.find(std::make_pair(val, m)) != cached_bool.end())
return cached_bool[std::make_pair(val, m)].get();
return (cached_bool[std::make_pair(val, m)] =
std::unique_ptr<ConstantInt>(new ConstantInt(Type::get_int1_type(m), val ? 1 : 0)))
.get();
}
std::string ConstantInt::print() {
std::string const_ir;
Type *ty = this->get_type();
if (ty->is_integer_type() && static_cast<IntegerType *>(ty)->get_num_bits() == 1) {
// int1
const_ir += (this->get_value() == 0) ? "false" : "true";
} else {
// int32
const_ir += std::to_string(this->get_value());
}
return const_ir;
}
ConstantArray::ConstantArray(ArrayType *ty, const std::vector<Constant *> &val) : Constant(ty, "", val.size()) {
for (int i = 0; i < val.size(); i++)
set_operand(i, val[i]);
this->const_array.assign(val.begin(), val.end());
}
Constant *ConstantArray::get_element_value(int index) { return this->const_array[index]; }
ConstantArray *ConstantArray::get(ArrayType *ty, const std::vector<Constant *> &val) {
return new ConstantArray(ty, val);
}
std::string ConstantArray::print() {
std::string const_ir;
const_ir += this->get_type()->print();
const_ir += " ";
const_ir += "[";
for (int i = 0; i < this->get_size_of_array(); i++) {
Constant *element = get_element_value(i);
if (!dynamic_cast<ConstantArray *>(get_element_value(i))) {
const_ir += element->get_type()->print();
}
const_ir += element->print();
if (i < this->get_size_of_array()) {
const_ir += ", ";
}
}
const_ir += "]";
return const_ir;
}
ConstantFP *ConstantFP::get(float val, Module *m) {
if (cached_float.find(std::make_pair(val, m)) != cached_float.end())
return cached_float[std::make_pair(val, m)].get();
return (cached_float[std::make_pair(val, m)] =
std::unique_ptr<ConstantFP>(new ConstantFP(Type::get_float_type(m), val)))
.get();
}
std::string ConstantFP::print() {
std::stringstream fp_ir_ss;
std::string fp_ir;
double val = this->get_value();
fp_ir_ss << "0x" << std::hex << *(uint64_t *)&val << std::endl;
fp_ir_ss >> fp_ir;
return fp_ir;
}
ConstantZero *ConstantZero::get(Type *ty, Module *m) {
if (not cached_zero[ty])
cached_zero[ty] = std::unique_ptr<ConstantZero>(new ConstantZero(ty));
return cached_zero[ty].get();
}
std::string ConstantZero::print() { return "zeroinitializer"; }
#include "Function.h"
#include "IRprinter.h"
#include "Module.h"
Function::Function(FunctionType *ty, const std::string &name, Module *parent)
: Value(ty, name), parent_(parent), seq_cnt_(0) {
// num_args_ = ty->getNumParams();
parent->add_function(this);
build_args();
}
Function::~Function() {
for (auto *arg : arguments_)
delete arg;
}
Function *Function::create(FunctionType *ty, const std::string &name, Module *parent) {
return new Function(ty, name, parent);
}
FunctionType *Function::get_function_type() const { return static_cast<FunctionType *>(get_type()); }
Type *Function::get_return_type() const { return get_function_type()->get_return_type(); }
unsigned Function::get_num_of_args() const { return get_function_type()->get_num_of_args(); }
unsigned Function::get_num_basic_blocks() const { return basic_blocks_.size(); }
Module *Function::get_parent() const { return parent_; }
void Function::remove(BasicBlock *bb) {
basic_blocks_.remove(bb);
for (auto pre : bb->get_pre_basic_blocks()) {
pre->remove_succ_basic_block(bb);
}
for (auto succ : bb->get_succ_basic_blocks()) {
succ->remove_pre_basic_block(bb);
}
}
void Function::build_args() {
auto *func_ty = get_function_type();
unsigned num_args = get_num_of_args();
for (int i = 0; i < num_args; i++) {
arguments_.push_back(new Argument(func_ty->get_param_type(i), "", this, i));
}
}
void Function::add_basic_block(BasicBlock *bb) { basic_blocks_.push_back(bb); }
void Function::set_instr_name() {
std::map<Value *, int> seq;
for (const auto &arg : this->get_args()) {
if (seq.find(&*arg) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (arg->set_name("arg" + std::to_string(seq_num))) {
seq.insert({&*arg, seq_num});
}
}
}
for (auto &bb1 : basic_blocks_) {
auto bb = &bb1;
if (seq.find(bb) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (bb->set_name("label" + std::to_string(seq_num))) {
seq.insert({bb, seq_num});
}
}
for (auto &instr : bb->get_instructions()) {
if (!instr.is_void() && seq.find(&instr) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (instr.set_name("op" + std::to_string(seq_num))) {
seq.insert({&instr, seq_num});
}
}
}
}
seq_cnt_ += seq.size();
}
std::string Function::print() {
set_instr_name();
std::string func_ir;
if (this->is_declaration()) {
func_ir += "declare ";
} else {
func_ir += "define ";
}
func_ir += this->get_return_type()->print();
func_ir += " ";
func_ir += print_as_op(this, false);
func_ir += "(";
// print arg
if (this->is_declaration()) {
for (int i = 0; i < this->get_num_of_args(); i++) {
if (i)
func_ir += ", ";
func_ir += static_cast<FunctionType *>(this->get_type())->get_param_type(i)->print();
}
} else {
for (auto arg = this->arg_begin(); arg != arg_end(); arg++) {
if (arg != this->arg_begin()) {
func_ir += ", ";
}
func_ir += (*arg)->print();
}
}
func_ir += ")";
// print bb
if (this->is_declaration()) {
func_ir += "\n";
} else {
func_ir += " {";
func_ir += "\n";
for (auto &bb1 : this->get_basic_blocks()) {
auto bb = &bb1;
func_ir += bb->print();
}
func_ir += "}";
}
return func_ir;
}
std::string Argument::print() {
std::string arg_ir;
arg_ir += this->get_type()->print();
arg_ir += " %";
arg_ir += this->get_name();
return arg_ir;
}
\ No newline at end of file
//
// Created by cqy on 2020/6/29.
//
#include "GlobalVariable.h"
#include "IRprinter.h"
GlobalVariable::GlobalVariable(std::string name, Module *m, Type *ty, bool is_const, Constant *init)
: User(ty, name, init != nullptr), is_const_(is_const), init_val_(init) {
m->add_global_variable(this);
if (init) {
this->set_operand(0, init);
}
} // global操作数为initval
GlobalVariable *GlobalVariable::create(std::string name, Module *m, Type *ty, bool is_const, Constant *init = nullptr) {
return new GlobalVariable(name, m, PointerType::get(ty), is_const, init);
}
std::string GlobalVariable::print() {
std::string global_val_ir;
global_val_ir += print_as_op(this, false);
global_val_ir += " = ";
global_val_ir += (this->is_const() ? "constant " : "global ");
global_val_ir += this->get_type()->get_pointer_element_type()->print();
global_val_ir += " ";
global_val_ir += this->get_init()->print();
return global_val_ir;
}
\ No newline at end of file
#include "IRprinter.h"
std::string print_as_op(Value *v, bool print_ty) {
std::string op_ir;
if (print_ty) {
op_ir += v->get_type()->print();
op_ir += " ";
}
if (dynamic_cast<GlobalVariable *>(v)) {
op_ir += "@" + v->get_name();
} else if (dynamic_cast<Function *>(v)) {
op_ir += "@" + v->get_name();
} else if (dynamic_cast<Constant *>(v)) {
op_ir += v->print();
} else {
op_ir += "%" + v->get_name();
}
return op_ir;
}
std::string print_cmp_type(CmpInst::CmpOp op) {
switch (op) {
case CmpInst::GE: return "sge"; break;
case CmpInst::GT: return "sgt"; break;
case CmpInst::LE: return "sle"; break;
case CmpInst::LT: return "slt"; break;
case CmpInst::EQ: return "eq"; break;
case CmpInst::NE: return "ne"; break;
default: break;
}
return "wrong cmpop";
}
std::string print_fcmp_type(FCmpInst::CmpOp op) {
switch (op) {
case FCmpInst::GE: return "uge"; break;
case FCmpInst::GT: return "ugt"; break;
case FCmpInst::LE: return "ule"; break;
case FCmpInst::LT: return "ult"; break;
case FCmpInst::EQ: return "ueq"; break;
case FCmpInst::NE: return "une"; break;
default: break;
}
return "wrong fcmpop";
}
\ No newline at end of file
This diff is collapsed.
#include "Module.h"
#include "Function.h"
#include "GlobalVariable.h"
#include <memory>
Module::Module(std::string name) : module_name_(name) {
void_ty_ = std::make_unique<Type>(Type::VoidTyID, this);
label_ty_ = std::make_unique<Type>(Type::LabelTyID, this);
int1_ty_ = std::make_unique<IntegerType>(1, this);
int32_ty_ = std::make_unique<IntegerType>(32, this);
float32_ty_ = std::make_unique<FloatType>(this);
// init instr_id2string
instr_id2string_.insert({Instruction::ret, "ret"});
instr_id2string_.insert({Instruction::br, "br"});
instr_id2string_.insert({Instruction::add, "add"});
instr_id2string_.insert({Instruction::sub, "sub"});
instr_id2string_.insert({Instruction::mul, "mul"});
instr_id2string_.insert({Instruction::sdiv, "sdiv"});
instr_id2string_.insert({Instruction::fadd, "fadd"});
instr_id2string_.insert({Instruction::fsub, "fsub"});
instr_id2string_.insert({Instruction::fmul, "fmul"});
instr_id2string_.insert({Instruction::fdiv, "fdiv"});
instr_id2string_.insert({Instruction::alloca, "alloca"});
instr_id2string_.insert({Instruction::load, "load"});
instr_id2string_.insert({Instruction::store, "store"});
instr_id2string_.insert({Instruction::cmp, "icmp"});
instr_id2string_.insert({Instruction::fcmp, "fcmp"});
instr_id2string_.insert({Instruction::phi, "phi"});
instr_id2string_.insert({Instruction::call, "call"});
instr_id2string_.insert({Instruction::getelementptr, "getelementptr"});
instr_id2string_.insert({Instruction::zext, "zext"});
instr_id2string_.insert({Instruction::sitofp, "sitofp"});
instr_id2string_.insert({Instruction::fptosi, "fptosi"});
}
Module::~Module() {}
Type *Module::get_void_type() { return void_ty_.get(); }
Type *Module::get_label_type() { return label_ty_.get(); }
IntegerType *Module::get_int1_type() { return int1_ty_.get(); }
IntegerType *Module::get_int32_type() { return int32_ty_.get(); }
PointerType *Module::get_pointer_type(Type *contained) {
if (pointer_map_.find(contained) == pointer_map_.end()) {
pointer_map_[contained] = std::make_unique<PointerType>(contained);
}
return pointer_map_[contained].get();
}
ArrayType *Module::get_array_type(Type *contained, unsigned num_elements) {
if (array_map_.find({contained, num_elements}) == array_map_.end()) {
array_map_[{contained, num_elements}] = std::make_unique<ArrayType>(contained, num_elements);
}
return array_map_[{contained, num_elements}].get();
}
FunctionType *Module::get_function_type(Type *retty, std::vector<Type *> &args) {
if (not function_map_.count({retty, args})) {
function_map_[{retty, args}] = std::make_unique<FunctionType>(retty, args);
}
return function_map_[{retty, args}].get();
}
PointerType *Module::get_int32_ptr_type() { return get_pointer_type(int32_ty_.get()); }
FloatType *Module::get_float_type() { return float32_ty_.get(); }
PointerType *Module::get_float_ptr_type() { return get_pointer_type(float32_ty_.get()); }
void Module::add_function(Function *f) { function_list_.push_back(f); }
llvm::ilist<Function> &Module::get_functions() { return function_list_; }
void Module::add_global_variable(GlobalVariable *g) { global_list_.push_back(g); }
llvm::ilist<GlobalVariable> &Module::get_global_variable() { return global_list_; }
void Module::set_print_name() {
for (auto &func : this->get_functions()) {
func.set_instr_name();
}
return;
}
std::string Module::print() {
std::string module_ir;
for (auto &global_val : this->global_list_) {
module_ir += global_val.print();
module_ir += "\n";
}
for (auto &func : this->function_list_) {
module_ir += func.print();
module_ir += "\n";
}
return module_ir;
}
#include "Type.h"
#include "Module.h"
#include <cassert>
Type::Type(TypeID tid, Module *m) {
tid_ = tid;
m_ = m;
}
Module *Type::get_module() { return m_; }
bool Type::is_eq_type(Type *ty1, Type *ty2) { return ty1 == ty2; }
Type *Type::get_void_type(Module *m) { return m->get_void_type(); }
Type *Type::get_label_type(Module *m) { return m->get_label_type(); }
IntegerType *Type::get_int1_type(Module *m) { return m->get_int1_type(); }
IntegerType *Type::get_int32_type(Module *m) { return m->get_int32_type(); }
PointerType *Type::get_pointer_type(Type *contained) { return PointerType::get(contained); }
ArrayType *Type::get_array_type(Type *contained, unsigned num_elements) {
return ArrayType::get(contained, num_elements);
}
PointerType *Type::get_int32_ptr_type(Module *m) { return m->get_int32_ptr_type(); }
FloatType *Type::get_float_type(Module *m) { return m->get_float_type(); }
PointerType *Type::get_float_ptr_type(Module *m) { return m->get_float_ptr_type(); }
Type *Type::get_pointer_element_type() {
if (this->is_pointer_type())
return static_cast<PointerType *>(this)->get_element_type();
else
return nullptr;
}
Type *Type::get_array_element_type() {
if (this->is_array_type())
return static_cast<ArrayType *>(this)->get_element_type();
else
return nullptr;
}
int Type::get_size() {
if (this->is_integer_type()) {
auto bits = static_cast<IntegerType *>(this)->get_num_bits() / 8;
return bits > 0 ? bits : 1;
}
if (this->is_array_type()) {
auto element_size = static_cast<ArrayType *>(this)->get_element_type()->get_size();
auto num_elements = static_cast<ArrayType *>(this)->get_num_of_elements();
return element_size * num_elements;
}
if (this->is_pointer_type()) {
if (this->get_pointer_element_type()->is_array_type()) {
return this->get_pointer_element_type()->get_size();
} else {
return 4;
}
}
if (this->is_float_type()) {
return 4;
}
return 0;
}
std::string Type::print() {
std::string type_ir;
switch (this->get_type_id()) {
case VoidTyID: type_ir += "void"; break;
case LabelTyID: type_ir += "label"; break;
case IntegerTyID:
type_ir += "i";
type_ir += std::to_string(static_cast<IntegerType *>(this)->get_num_bits());
break;
case FunctionTyID:
type_ir += static_cast<FunctionType *>(this)->get_return_type()->print();
type_ir += " (";
for (int i = 0; i < static_cast<FunctionType *>(this)->get_num_of_args(); i++) {
if (i)
type_ir += ", ";
type_ir += static_cast<FunctionType *>(this)->get_param_type(i)->print();
}
type_ir += ")";
break;
case PointerTyID:
type_ir += this->get_pointer_element_type()->print();
type_ir += "*";
break;
case ArrayTyID:
type_ir += "[";
type_ir += std::to_string(static_cast<ArrayType *>(this)->get_num_of_elements());
type_ir += " x ";
type_ir += static_cast<ArrayType *>(this)->get_element_type()->print();
type_ir += "]";
break;
case FloatTyID: type_ir += "float"; break;
default: break;
}
return type_ir;
}
IntegerType::IntegerType(unsigned num_bits, Module *m) : Type(Type::IntegerTyID, m), num_bits_(num_bits) {}
IntegerType *IntegerType::get(unsigned num_bits, Module *m) {
if (num_bits == 1) {
return m->get_int1_type();
} else if (num_bits == 32) {
return m->get_int32_type();
} else {
assert("IntegerType::get has error num_bits");
}
}
unsigned IntegerType::get_num_bits() { return num_bits_; }
FunctionType::FunctionType(Type *result, std::vector<Type *> params) : Type(Type::FunctionTyID, nullptr) {
assert(is_valid_return_type(result) && "Invalid return type for function!");
result_ = result;
for (auto p : params) {
assert(is_valid_argument_type(p) && "Not a valid type for function argument!");
args_.push_back(p);
}
}
bool FunctionType::is_valid_return_type(Type *ty) {
return ty->is_integer_type() || ty->is_void_type() || ty->is_float_type();
}
bool FunctionType::is_valid_argument_type(Type *ty) {
return ty->is_integer_type() || ty->is_pointer_type() || ty->is_float_type();
}
FunctionType *FunctionType::get(Type *result, std::vector<Type *> params) {
return result->get_module()->get_function_type(result, params);
}
unsigned FunctionType::get_num_of_args() const { return args_.size(); }
Type *FunctionType::get_param_type(unsigned i) const { return args_[i]; }
Type *FunctionType::get_return_type() const { return result_; }
ArrayType::ArrayType(Type *contained, unsigned num_elements)
: Type(Type::ArrayTyID, contained->get_module()), num_elements_(num_elements) {
assert(is_valid_element_type(contained) && "Not a valid type for array element!");
contained_ = contained;
}
bool ArrayType::is_valid_element_type(Type *ty) {
return ty->is_integer_type() || ty->is_array_type() || ty->is_float_type();
}
ArrayType *ArrayType::get(Type *contained, unsigned num_elements) {
return contained->get_module()->get_array_type(contained, num_elements);
}
PointerType::PointerType(Type *contained) : Type(Type::PointerTyID, contained->get_module()), contained_(contained) {}
PointerType *PointerType::get(Type *contained) { return contained->get_module()->get_pointer_type(contained); }
FloatType::FloatType(Module *m) : Type(Type::FloatTyID, m) {}
FloatType *FloatType::get(Module *m) { return m->get_float_type(); }
#include "User.h"
#include <cassert>
User::User(Type *ty, const std::string &name, unsigned num_ops) : Value(ty, name), num_ops_(num_ops) {
// if (num_ops_ > 0)
// operands_.reset(new std::list<Value *>());
operands_.resize(num_ops_, nullptr);
}
std::vector<Value *> &User::get_operands() { return operands_; }
Value *User::get_operand(unsigned i) const { return operands_[i]; }
void User::set_operand(unsigned i, Value *v) {
assert(i < num_ops_ && "set_operand out of index");
// assert(operands_[i] == nullptr && "ith operand is not null");
operands_[i] = v;
v->add_use(this, i);
}
void User::add_operand(Value *v) {
operands_.push_back(v);
v->add_use(this, num_ops_);
num_ops_++;
}
unsigned User::get_num_operand() const { return num_ops_; }
void User::remove_use_of_ops() {
for (auto op : operands_) {
op->remove_use(this);
}
}
void User::remove_operands(int index1, int index2) {
for (int i = index1; i <= index2; i++) {
operands_[i]->remove_use(this);
}
operands_.erase(operands_.begin() + index1, operands_.begin() + index2 + 1);
// std::cout<<operands_.size()<<std::endl;
num_ops_ = operands_.size();
}
#include "Value.h"
#include "Type.h"
#include "User.h"
#include <cassert>
Value::Value(Type *ty, const std::string &name) : type_(ty), name_(name) {}
void Value::add_use(Value *val, unsigned arg_no) { use_list_.push_back(Use(val, arg_no)); }
std::string Value::get_name() const { return name_; }
void Value::replace_all_use_with(Value *new_val) {
for (auto use : use_list_) {
auto val = dynamic_cast<User *>(use.val_);
assert(val && "new_val is not a user");
val->set_operand(use.arg_no_, new_val);
}
}
void Value::remove_use(Value *val) {
auto is_val = [val](const Use &use) { return use.val_ == val; };
use_list_.remove_if(is_val);
}
add_subdirectory(calculator)
add_executable(
gcd_array_generator
ta_gcd/gcd_array_generator.cpp
)
target_link_libraries(
gcd_array_generator
IR_lib
)
# add_executable(
# stu_assign_generator
# stu_cpp/assign_generator.cpp
# )
# target_link_libraries(
# stu_assign_generator
# IR_lib
# )
# add_executable(
# stu_fun_generator
# stu_cpp/fun_generator.cpp
# )
# target_link_libraries(
# stu_fun_generator
# IR_lib
# )
# add_executable(
# stu_if_generator
# stu_cpp/if_generator.cpp
# )
# target_link_libraries(
# stu_if_generator
# IR_lib
# )
# add_executable(
# stu_while_generator
# stu_cpp/while_generator.cpp
# )
# target_link_libraries(
# stu_while_generator
# IR_lib
# )
int main(){
int a[10];
a[0] = 10;
a[1] = a[0] * 2;
return a[1];
}
int callee(int a){
return 2 * a;
}
int main(){
return callee(110);
}
int main(){
float a = 5.555;
if(a > 1)
return 233;
return 0;
}
int main(){
int a;
int i;
a = 10;
i = 0;
while(i < 10){
i = i + 1;
a = a + i;
}
return a;
}
flex_target(calc_lex calculator.l ${CMAKE_CURRENT_BINARY_DIR}/calc_lex.c)
bison_target(calc_syntax calculator.y
${CMAKE_CURRENT_BINARY_DIR}/calc_syntax.c
DEFINES_FILE ${PROJECT_BINARY_DIR}/calculator.h)
add_flex_bison_dependency(calc_lex calc_syntax)
add_library(calc_syntax STATIC
${BISON_calc_syntax_OUTPUTS}
${FLEX_calc_lex_OUTPUTS}
)
add_executable(
calc
calc.cpp
calc_ast.cpp
calc_builder.cpp
)
target_link_libraries(
calc
IR_lib
calc_syntax
common
)
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char*);
}
#include <cstdio>
#include <fstream>
#include "calc_ast.hpp"
#include "calc_builder.hpp"
using namespace std::literals::string_literals;
int main(int argc, char *argv[])
{
syntax_tree *tree = NULL;
const char *input = NULL;
if (argc >= 3) {
printf("usage: %s\n", argv[0]);
printf("usage: %s <cminus_file>\n", argv[0]);
return 1;
}
if (argc == 2) {
input = argv[1];
} else {
printf("Input an arithmatic expression (press Ctrl+D in a new line after you finish the expression):\n");
}
tree = parse(input);
CalcAST ast(tree);
CalcBuilder builder;
auto module = builder.build(ast);
auto IR = module->print();
std::ofstream output_stream;
auto output_file = "result.ll";
output_stream.open(output_file, std::ios::out);
output_stream << "; ModuleID = 'calculator'\n";
output_stream << IR;
output_stream.close();
auto command_string = "clang -O0 -w "s + "result.ll -o result -L. -lcminus_io";
auto ret = std::system(command_string.c_str());
if (ret) {
printf("something went wrong!\n");
} else {
printf("result and result.ll have been generated.\n");
}
return ret;
}
#include "calc_ast.hpp"
#include <cstring>
#include <stack>
#include <iostream>
#define _AST_NODE_ERROR_ \
std::cerr << "Abort due to node cast error."\
"Contact with TAs to solve your problem."\
<< std::endl;\
std::abort();
#define _STR_EQ(a, b) (strcmp((a), (b)) == 0)
void CalcAST::run_visitor(CalcASTVisitor &visitor) {
root->accept(visitor);
}
CalcAST::CalcAST(syntax_tree* s) {
if (s == nullptr) {
std::cerr << "empty input tree!" << std::endl;
std::abort();
}
auto node = transform_node_iter(s->root);
del_syntax_tree(s);
root = std::shared_ptr<CalcASTInput>(
static_cast<CalcASTInput*>(node));
}
CalcASTNode *
CalcAST::transform_node_iter(syntax_tree_node *n) {
if (_STR_EQ(n->name, "input")) {
auto node = new CalcASTInput();
auto expr_node =
static_cast<CalcASTExpression *>(
transform_node_iter(n->children[0]));
node->expression = std::shared_ptr<CalcASTExpression>(expr_node);
return node;
} else if (_STR_EQ(n->name, "expression")) {
auto node = new CalcASTExpression();
if (n->children_num == 3) {
auto add_expr_node =
static_cast<CalcASTExpression *>(
transform_node_iter(n->children[0]));
node->expression =
std::shared_ptr<CalcASTExpression>(add_expr_node);
auto op_name = n->children[1]->children[0]->name;
if (_STR_EQ(op_name, "+"))
node->op = OP_PLUS;
else if (_STR_EQ(op_name, "-"))
node->op = OP_MINUS;
auto term_node =
static_cast<CalcASTTerm *>(
transform_node_iter(n->children[2]));
node->term = std::shared_ptr<CalcASTTerm>(term_node);
} else {
auto term_node =
static_cast<CalcASTTerm *>(
transform_node_iter(n->children[0]));
node->term = std::shared_ptr<CalcASTTerm>(term_node);
}
return node;
} else if (_STR_EQ(n->name, "term")) {
auto node = new CalcASTTerm();
if (n->children_num == 3) {
auto term_node =
static_cast<CalcASTTerm *>(
transform_node_iter(n->children[0]));
node->term =
std::shared_ptr<CalcASTTerm>(term_node);
auto op_name = n->children[1]->children[0]->name;
if (_STR_EQ(op_name, "*"))
node->op = OP_MUL;
else if (_STR_EQ(op_name, "/"))
node->op = OP_DIV;
auto factor_node =
static_cast<CalcASTFactor *>(
transform_node_iter(n->children[2]));
node->factor = std::shared_ptr<CalcASTFactor>(factor_node);
} else {
auto factor_node =
static_cast<CalcASTFactor *>(
transform_node_iter(n->children[0]));
node->factor = std::shared_ptr<CalcASTFactor>(factor_node);
}
return node;
} else if (_STR_EQ(n->name, "factor")) {
if (n->children_num == 3) {
return transform_node_iter(n->children[1]);
} else {
auto num_node = new CalcASTNum();
num_node->val = std::stoi(n->children[0]->children[0]->name);
return num_node;
}
} else {
std::cerr << "[calc_ast]: transform failure!" << std::endl;
std::abort();
}
}
void CalcASTNum::accept(CalcASTVisitor &visitor) { visitor.visit(*this); }
void CalcASTTerm::accept(CalcASTVisitor &visitor) { visitor.visit(*this); }
void CalcASTExpression::accept(CalcASTVisitor &visitor) { visitor.visit(*this); }
void CalcASTInput::accept(CalcASTVisitor &visitor) { expression->accept(visitor); }
void CalcASTFactor::accept(CalcASTVisitor &visitor) {
auto expr =
dynamic_cast<CalcASTExpression *>(this);
if (expr) {
expr->accept(visitor);
return;
}
auto num =
dynamic_cast<CalcASTNum *>(this);
if (num) {
num->accept(visitor);
return;
}
_AST_NODE_ERROR_
}
#ifndef _CALC_AST_HPP_
#define _CALC_AST_HPP_
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char *input);
}
#include <vector>
#include <memory>
enum AddOp {
// +
OP_PLUS,
// -
OP_MINUS
};
enum MulOp {
// *
OP_MUL,
// /
OP_DIV
};
class CalcAST;
struct CalcASTNode;
struct CalcASTInput;
struct CalcASTExpression;
struct CalcASTNum;
struct CalcASTTerm;
struct CalcASTFactor;
class CalcASTVisitor;
class CalcAST {
public:
CalcAST() = delete;
CalcAST(syntax_tree *);
CalcAST(CalcAST &&tree) {
root = tree.root;
tree.root = nullptr;
};
CalcASTInput* get_root() { return root.get(); }
void run_visitor(CalcASTVisitor& visitor);
private:
CalcASTNode* transform_node_iter(syntax_tree_node *);
std::shared_ptr<CalcASTInput> root = nullptr;
};
struct CalcASTNode {
virtual void accept(CalcASTVisitor &) = 0;
};
struct CalcASTInput: CalcASTNode {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression;
};
struct CalcASTFactor: CalcASTNode {
virtual void accept(CalcASTVisitor &) override;
};
struct CalcASTNum: CalcASTFactor {
virtual void accept(CalcASTVisitor &) override final;
int val;
};
struct CalcASTExpression: CalcASTFactor {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression;
AddOp op;
std::shared_ptr<CalcASTTerm> term;
};
struct CalcASTTerm : CalcASTNode {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTTerm> term;
MulOp op;
std::shared_ptr<CalcASTFactor> factor;
};
class CalcASTVisitor {
public:
virtual void visit(CalcASTInput &) = 0;
virtual void visit(CalcASTNum &) = 0;
virtual void visit(CalcASTExpression &) = 0;
virtual void visit(CalcASTTerm &) = 0;
};
#endif
#include "calc_builder.hpp"
std::unique_ptr<Module>
CalcBuilder::build(CalcAST &ast) {
module = std::unique_ptr<Module>(new Module("Cminus code"));
builder = new IRBuilder(nullptr, module.get());
auto TyVoid = Type::get_void_type(module.get());
TyInt32 = Type::get_int32_type(module.get());
std::vector<Type *> output_params;
output_params.push_back(TyInt32);
auto output_type = FunctionType::get(TyVoid, output_params);
auto output_fun =
Function::create(
output_type,
"output",
module.get());
auto main = Function::create(FunctionType::get(TyInt32, {}),
"main", module.get());
auto bb = BasicBlock::create(module.get(), "entry", main);
builder->set_insert_point(bb);
ast.run_visitor(*this);
builder->create_call(output_fun, {val});
builder->create_ret(ConstantInt::get(0, module.get()));
return std::move(module);
}
void CalcBuilder::visit(CalcASTInput &node) {
node.expression->accept(*this);
}
void CalcBuilder::visit(CalcASTExpression &node) {
if (node.expression == nullptr) {
node.term->accept(*this);
} else {
node.expression->accept(*this);
auto l_val = val;
node.term->accept(*this);
auto r_val = val;
switch (node.op) {
case OP_PLUS:
val = builder->create_iadd(l_val, r_val);
break;
case OP_MINUS:
val = builder->create_isub(l_val, r_val);
break;
}
}
}
void CalcBuilder::visit(CalcASTTerm &node) {
if (node.term == nullptr) {
node.factor->accept(*this);
} else {
node.term->accept(*this);
auto l_val = val;
node.factor->accept(*this);
auto r_val = val;
switch (node.op) {
case OP_MUL:
val = builder->create_imul(l_val, r_val);
break;
case OP_DIV:
val = builder->create_isdiv(l_val, r_val);
break;
}
}
}
void CalcBuilder::visit(CalcASTNum &node) {
val = ConstantInt::get(node.val, module.get());
}
#ifndef _CALC_VISITOR_HPP_
#define _CALC_VISITOR_HPP_
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRBuilder.h"
#include "Module.h"
#include "Type.h"
#include "calc_ast.hpp"
class CalcBuilder: public CalcASTVisitor {
public:
std::unique_ptr<Module> build(CalcAST &ast);
private:
virtual void visit(CalcASTInput &) override final;
virtual void visit(CalcASTNum &) override final;
virtual void visit(CalcASTExpression &) override final;
virtual void visit(CalcASTTerm &) override final;
IRBuilder *builder;
Value *val;
Type *TyInt32;
std::unique_ptr<Module> module;
};
#endif
%option noyywrap
%{
/*****************声明和选项设置 begin*****************/
#include <stdio.h>
#include <stdlib.h>
#include "syntax_tree.h"
#include "calculator.h"
int lines;
int pos_start;
int pos_end;
void pass_node(char *text){
yylval.node = new_syntax_tree_node(text);
}
/*****************声明和选项设置 end*****************/
%}
%x COMMENT
%%
\+ {pos_start = pos_end; pos_end += 1; pass_node(yytext); return ADD;}
\- {pos_start = pos_end; pos_end += 1; pass_node(yytext); return SUB;}
\* {pos_start = pos_end; pos_end += 1; pass_node(yytext); return MUL;}
\/ {pos_start = pos_end; pos_end += 1; pass_node(yytext); return DIV;}
\( {pos_start = pos_end; pos_end += 1; pass_node(yytext); return LPARENTHESE;}
\) {pos_start = pos_end; pos_end += 1; pass_node(yytext); return RPARENTHESE;}
[0-9]+ { pos_start = pos_end; pos_end += strlen(yytext); pass_node(yytext); return NUM; }
\n {lines++; pos_start = 1; pos_end = 1;}
[ \t] {pos_start = pos_end; pos_end += 1;}
%%
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "syntax_tree.h"
// external functions from lex
extern int yylex();
extern int yyparse();
extern int yyrestart();
extern FILE * yyin;
// external variables from lexical_analyzer module
extern int lines;
extern char * yytext;
extern int pos_end;
extern int pos_start;
// Global syntax tree
syntax_tree *gt;
// Error reporting
void yyerror(const char *s);
syntax_tree_node *node(const char *node_name, int children_num, ...);
%}
%union {
struct _syntax_tree_node * node;
char * name;
}
%token <node> ADD
%token <node> SUB
%token <node> MUL
%token <node> DIV
%token <node> NUM
%token <node> LPARENTHESE
%token <node> RPARENTHESE
%type <node> input expression addop term mulop factor num
%start input
%%
input : expression {$$ = node( "input", 1, $1); gt->root = $$;}
;
expression : expression addop term {$$ = node( "expression", 3, $1, $2, $3);}
| term {$$ = node( "expression", 1, $1);}
;
addop : ADD {$$ = node( "addop", 1, $1);}
| SUB {$$ = node( "addop", 1, $1);}
;
term : term mulop factor {$$ = node( "term", 3, $1, $2, $3);}
| factor {$$ = node( "term", 1, $1);}
;
mulop : MUL {$$ = node( "mulop", 1, $1);}
| DIV {$$ = node( "mulop", 1, $1);}
;
factor : LPARENTHESE expression RPARENTHESE {$$ = node( "factor", 3, $1, $2, $3);}
| num {$$ = node( "factor", 1, $1);}
;
num : NUM {$$ = node( "num", 1, $1);}
%%
void yyerror(const char * s) {
fprintf(stderr, "error at line %d column %d: %s\n", lines, pos_start, s);
}
syntax_tree *parse(const char *input_path)
{
if (input_path != NULL) {
if (!(yyin = fopen(input_path, "r"))) {
fprintf(stderr, "[ERR] Open input file %s failed.\n", input_path);
exit(1);
}
} else {
yyin = stdin;
}
lines = pos_start = pos_end = 1;
gt = new_syntax_tree();
yyrestart(yyin);
yyparse();
return gt;
}
syntax_tree_node *node(const char *name, int children_num, ...)
{
syntax_tree_node *p = new_syntax_tree_node(name);
syntax_tree_node *child;
if (children_num == 0) {
child = new_syntax_tree_node("epsilon");
syntax_tree_add_child(p, child);
} else {
va_list ap;
va_start(ap, children_num);
for (int i = 0; i < children_num; ++i) {
child = va_arg(ap, syntax_tree_node *);
syntax_tree_add_child(p, child);
}
va_end(ap);
}
return p;
}
int x[1];
int y[1];
int gcd (int u, int v) {
if (v == 0) return u;
else return gcd(v, u - u / v * v);
}
int funArray (int u[], int v[]) {
int a;
int b;
int temp;
a = u[0];
b = v[0];
if (a < b) {
temp = a;
a = b;
b = temp;
}
return gcd(a, b);
}
int main(void) {
x[0] = 90;
y[0] = 18;
return funArray(x, y);
}
\ No newline at end of file
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRBuilder.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::get(num, module)
#define CONST_FP(num) ConstantFP::get(num, module) // 得到常数值的表示,方便后面多次用到
int main() {
auto module = new Module("Cminus code"); // module name是什么无关紧要
auto builder = new IRBuilder(nullptr, module);
Type *Int32Type = Type::get_int32_type(module);
// 全局数组,x,y
auto *arrayType = ArrayType::get(Int32Type, 1);
auto initializer = ConstantZero::get(Int32Type, module);
auto x = GlobalVariable::create("x", module, arrayType, false, initializer);// 参数解释: 名字name,所属module,全局变量类型type,
auto y = GlobalVariable::create("y", module, arrayType, false, initializer);// 是否是常量定义(cminus中没有常量概念,应全都是false),初始化常量(ConstantZero类)
// gcd函数
// 函数参数类型的vector
std::vector<Type *> Ints(2, Int32Type);
//通过返回值类型与参数类型列表得到函数类型
auto gcdFunTy = FunctionType::get(Int32Type, Ints);
// 由函数类型得到函数
auto gcdFun = Function::create(gcdFunTy,
"gcd", module);
// BB的名字在生成中无所谓,但是可以方便阅读
auto bb = BasicBlock::create(module, "entry", gcdFun);
builder->set_insert_point(bb); // 一个BB的开始,将当前插入指令点的位置设在bb
auto retAlloca = builder->create_alloca(Int32Type); // 在内存中分配返回值的位置
auto uAlloca = builder->create_alloca(Int32Type); // 在内存中分配参数u的位置
auto vAlloca = builder->create_alloca(Int32Type); // 在内存中分配参数v的位置
std::vector<Value *> args; // 获取gcd函数的形参,通过Function中的iterator
for (auto arg = gcdFun->arg_begin(); arg != gcdFun->arg_end(); arg++) {
args.push_back(*arg); // * 号运算符是从迭代器中取出迭代器当前指向的元素
}
builder->create_store(args[0], uAlloca); // 将参数u store下来
builder->create_store(args[1], vAlloca); // 将参数v store下来
auto vLoad = builder->create_load(vAlloca); // 将参数v load上来
auto icmp = builder->create_icmp_eq(vLoad, CONST_INT(0)); // v和0的比较,注意ICMPEQ
auto trueBB = BasicBlock::create(module, "trueBB", gcdFun); // true分支
auto falseBB = BasicBlock::create(module, "falseBB", gcdFun); // false分支
auto retBB = BasicBlock::create(
module, "", gcdFun); // return分支,提前create,以便true分支可以br
auto br = builder->create_cond_br(icmp, trueBB, falseBB); // 条件BR
DEBUG_OUTPUT // 调试的时候故意留下来的,以醒目地提醒你这个调试用的宏定义方法
builder->set_insert_point(trueBB); // if true; 分支的开始需要SetInsertPoint设置
auto uLoad = builder->create_load(uAlloca);
builder->create_store(uLoad, retAlloca);
builder->create_br(retBB); // br retBB
builder->set_insert_point(falseBB); // if false
uLoad = builder->create_load(uAlloca);
vLoad = builder->create_load(vAlloca);
auto div = builder->create_isdiv(uLoad, vLoad); // SDIV - div with S flag
auto mul = builder->create_imul(div, vLoad); // MUL - mul
auto sub = builder->create_isub(uLoad, mul); // the same
auto call = builder->create_call(gcdFun, {vLoad, sub}); // 创建call指令
// {vLoad, sub} - 参数array
builder->create_store(call, retAlloca);
builder->create_br(retBB); // br retBB
builder->set_insert_point(retBB); // ret分支
auto retLoad = builder->create_load(retAlloca);
builder->create_ret(retLoad);
// funArray函数
auto Int32PtrType = Type::get_int32_ptr_type(module); // 单个参数的类型,指针
std::vector<Type *> IntPtrs(2, Int32PtrType); // 参数列表类型
auto funArrayFunType = FunctionType::get(Int32Type, IntPtrs); // 函数类型
auto funArrayFun = Function::create(funArrayFunType, "funArray", module);
bb = BasicBlock::create(module, "entry", funArrayFun);
builder->set_insert_point(bb);
auto upAlloca = builder->create_alloca(Int32PtrType); // u的存放
auto vpAlloca = builder->create_alloca(Int32PtrType); // v的存放
auto aAlloca = builder->create_alloca(Int32Type); // a的存放
auto bAlloca = builder->create_alloca(Int32Type); // b的存放
auto tempAlloca = builder->create_alloca(Int32Type); // temp的存放
std::vector<Value *> args1; //获取funArrayFun函数的形参,通过Function中的iterator
for (auto arg = funArrayFun->arg_begin(); arg != funArrayFun->arg_end(); arg++) {
args1.push_back(*arg); // * 号运算符是从迭代器中取出迭代器当前指向的元素
}
builder->create_store(args1[0], upAlloca); // 将参数u store下来
builder->create_store(args1[1], vpAlloca); // 将参数v store下来
auto u0pLoad = builder->create_load(upAlloca); // 读取u
auto u0GEP = builder->create_gep(u0pLoad, {CONST_INT(0)}); // GEP: 获取u[0]地址
auto u0Load = builder->create_load(u0GEP); // 从u[0]地址 读取u[0]
builder->create_store(u0Load, aAlloca); // 将u[0] 写入 a
auto v0pLoad = builder->create_load(vpAlloca); // 同上
auto v0GEP = builder->create_gep(v0pLoad, {CONST_INT(0)});
auto v0Load = builder->create_load(v0GEP);
builder->create_store(v0Load, bAlloca);
auto aLoad = builder->create_load(aAlloca);
auto bLoad = builder->create_load(bAlloca);
icmp = builder->create_icmp_lt(aLoad, bLoad);
trueBB = BasicBlock::create(module, "trueBB", funArrayFun);
falseBB = BasicBlock::create(module, "falseBB", funArrayFun);
builder->create_cond_br(icmp, trueBB, falseBB);
builder->set_insert_point(trueBB);
builder->create_store(aLoad, tempAlloca);
builder->create_store(bLoad, aAlloca);
auto tempLoad = builder->create_load(tempAlloca);
builder->create_store(tempLoad, bAlloca);
builder->create_br(falseBB); // 注意在下一个BB之前要Br一下
builder->set_insert_point(falseBB);
aLoad = builder->create_load(aAlloca);
bLoad = builder->create_load(bAlloca);
call = builder->create_call(gcdFun, {aLoad, bLoad});
builder->create_ret(call);
// main函数
auto mainFun = Function::create(FunctionType::get(Int32Type, {}),
"main", module);
bb = BasicBlock::create(module, "entry", mainFun);
// BasicBlock的名字在生成中无所谓,但是可以方便阅读
builder->set_insert_point(bb);
retAlloca = builder->create_alloca(Int32Type);
builder->create_store(CONST_INT(0), retAlloca); // 默认 ret 0
auto x0GEP = builder->create_gep(x, {CONST_INT(0), CONST_INT(0)}); // GEP: 这里为什么是{0, 0}呢? (实验报告相关)
builder->create_store(CONST_INT(90), x0GEP);
auto y0GEP = builder->create_gep(y, {CONST_INT(0), CONST_INT(0)}); // GEP: 这里为什么是{0, 0}呢? (实验报告相关)
builder->create_store(CONST_INT(18), y0GEP);
x0GEP = builder->create_gep(x, {CONST_INT(0), CONST_INT(0)});
y0GEP = builder->create_gep(y, {CONST_INT(0), CONST_INT(0)});
call = builder->create_call(funArrayFun, {x0GEP, y0GEP}); // 为什么这里传的是{x0GEP, y0GEP}呢?
builder->create_ret(call);
// 尽管已经有很多注释,但可能还是会遇到很多bug
// 所以强烈建议配置AutoComplete,效率会大大提高!
// 如果猜不到某个IR指令对应的C++的函数,建议把指令翻译成英语然后在method列表中搜索一下。
// 最后,这个例子只涉及到了一些基本的指令生成,
// 对于额外的指令,包括数组,在之后的实验中可能需要大家自己搜索一下思考一下,
// 还有涉及到的C++语法,可以及时提问或者向大家提供指导哦!
// 对于这个例子里的代码风格/用法,如果有好的建议也欢迎提出!
std::cout << module->print();
delete module;
return 0;
}
add_subdirectory(parser)
add_subdirectory(2-ir-gen-warmup)
add_executable(test_ast test_ast.cpp)
add_executable(test_logging test_logging.cpp)
target_link_libraries(test_logging common)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment