diff --git a/Reports/.gitignore b/Reports/.gitignore index 5f6db2b6056d3a0518a23e09f6deabc4050f0b49..9419aaf52277c1f04aeee94a94b97495bfd2ba6b 100644 --- a/Reports/.gitignore +++ b/Reports/.gitignore @@ -1 +1,2 @@ 1-parser/*.pdf +2-ir-gen-warmup/*.pdf diff --git a/Reports/2-ir-gen-warmup/figures/CALC_AST.png b/Reports/2-ir-gen-warmup/figures/CALC_AST.png new file mode 100644 index 0000000000000000000000000000000000000000..b0425709b87f9e1d533638f8e6c38e1a16428d78 Binary files /dev/null and b/Reports/2-ir-gen-warmup/figures/CALC_AST.png differ diff --git a/Reports/2-ir-gen-warmup/figures/assign.png b/Reports/2-ir-gen-warmup/figures/assign.png new file mode 100644 index 0000000000000000000000000000000000000000..836250eff8ed175243de55bdfe8d88a02316d1ec Binary files /dev/null and b/Reports/2-ir-gen-warmup/figures/assign.png differ diff --git a/Reports/2-ir-gen-warmup/figures/fun.png b/Reports/2-ir-gen-warmup/figures/fun.png new file mode 100644 index 0000000000000000000000000000000000000000..0eb9cc2c5e6c94b7a790e7ae0b7f00a038ac1181 Binary files /dev/null and b/Reports/2-ir-gen-warmup/figures/fun.png differ diff --git a/Reports/2-ir-gen-warmup/figures/if.png b/Reports/2-ir-gen-warmup/figures/if.png new file mode 100644 index 0000000000000000000000000000000000000000..60ab39adc8d8beb75797d00068cf1c98cba2a872 Binary files /dev/null and b/Reports/2-ir-gen-warmup/figures/if.png differ diff --git a/Reports/2-ir-gen-warmup/figures/while.png b/Reports/2-ir-gen-warmup/figures/while.png new file mode 100644 index 0000000000000000000000000000000000000000..8a53edf6376d3b5b28fc60e178d9a06f5a143504 Binary files /dev/null and b/Reports/2-ir-gen-warmup/figures/while.png differ diff --git a/Reports/2-ir-gen-warmup/report.md b/Reports/2-ir-gen-warmup/report.md index 1bcaa633a27312acb23d95c053c59e2908908ddd..f3d956e9f1779b1bc0ccbb8586748d7177b64273 100644 --- a/Reports/2-ir-gen-warmup/report.md +++ b/Reports/2-ir-gen-warmup/report.md @@ -1,24 +1,85 @@ # lab2 实验报告 -学号 姓名 + +PB20111654 李晓奇 ## 问题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 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0` + + %2是`i32*`类型。 + + 我的理解是,这条指令相当于`%2=&%1[0][%0]`,其中将`%1`看成指向至少有两层结构的指针,GEP指令最后边的两个数字一是用来指定进入的层数,一是用来指定每层的偏移量。 + + 第一个`i32 0`表示指向第一个`[10 x i32]`块 + + 第二个`i32 %0`表示在第一个`[10 x i32]`块中指向第`%0`个元素 + + GEP指令返回这个元素的指针,赋值给%2 + +- `%2 = getelementptr i32, i32* %1 i32 %0` + + %2同样是`i32*`类型。 + + %1是指针,不同于上式(%1指向数组),本式%1指向`i32`类型,所以填入一个偏移数字,即GEP指令返回`%1[%0]`的指针,赋值给%2。 ## 问题2: cpp 与 .ll 的对应 + 请说明你的 cpp 代码片段和 .ll 的每个 BasicBlock 的对应关系。 +### assign.c + +![](figures/assign.png) + +### fun.c + +![](figures/fun.png) + +### if.c + +![](figures/if.png) + +### while.c + +![](figures/while.png) + ## 问题3: Visitor Pattern -分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为: + +分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为: + 1. 请画出该表达式对应的抽象语法树(使用 `calc_ast.hpp` 中的 `CalcAST*` 类型和在该类型中存储的值来表示),并给节点使用数字编号。 -2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。 + + AST如下,略去了CalcAST中的root: + + ![](figures/CALC_AST.png) -序列请按如下格式指明(序号为问题 2.1 中的编号): -3->2->5->1 +2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。 + + CalcBuilder类从AST的树根开始,访问每个节点,具体行为如下: + + - 如果节点是中间节点,则visit会触发该节点内部的每一个子节点的accept函数,经过一次或多次调用又触发CalcBuilder的visit,所以进行递归。 + + - 如果节点是叶子节点,即CalcASTNum类型,则可以直接读出这个节点的数值,保存在CalcBuilder类中的val中,回溯时会使用到。 + + 所以CalcBuilder访问AST是个深度优先递归遍历的过程。 + + 遍历顺序是: + + 1->2->3->4->5->7->8->9->11->14->16->12->15->10->13->6 + + > 个人感觉这个过程像是根据分析树构建语法树。过程中通过val保存一次visit调用的结果,只有在涉及到翻译的节点,即加减乘除运算时才做输出。 ## 实验难点 + 描述在实验中遇到的问题、分析和解决方案。 +- 理解GEP指令和指针的关系:阅读[资料](https://llvm.org/docs/GetElementPtr.html#what-effect-do-address-spaces-have-on-geps)。 + +- lightIR API的使用方法:相比[代码](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/tree/master/include/lightir),[文档](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/blob/master/Documentations/common/LightIR.md#c-apis)中有更多有助于理解的信息。所以先扫一遍文档获得宏观上的理解,再读[示例](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/blob/master/tests/2-ir-gen-warmup/ta_gcd/gcd_array_generator.cpp)。对于API中的每个类,文档和代码配合着看,大致就能理解了。 + +- 理解CalcAST和CalcBuilder的行为:读一遍代码就能懂了。 + ## 实验反馈 -吐槽?建议? + +暂无~ diff --git a/tests/2-ir-gen-warmup/calculator/calc.cpp b/tests/2-ir-gen-warmup/calculator/calc.cpp index 26d01a84cc5997fdc1006ea0bc7fb73d48b46924..71775d1ae9d953e7a986a3ea9c78bd1d24b788a3 100644 --- a/tests/2-ir-gen-warmup/calculator/calc.cpp +++ b/tests/2-ir-gen-warmup/calculator/calc.cpp @@ -1,6 +1,6 @@ extern "C" { - #include "syntax_tree.h" - extern syntax_tree *parse(const char*); +#include "syntax_tree.h" +extern syntax_tree *parse(const char *); } #include #include @@ -10,8 +10,8 @@ using namespace std::literals::string_literals; int main(int argc, char *argv[]) { - syntax_tree *tree = NULL; - const char *input = NULL; + syntax_tree *tree = NULL; + const char *input = NULL; if (argc >= 3) { printf("usage: %s\n", argv[0]); @@ -22,22 +22,24 @@ int main(int argc, char *argv[]) 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"); + printf("Input an arithmatic expression (press Ctrl+D in a new line " + "after you finish the expression):\n"); } tree = parse(input); - CalcAST ast(tree); + CalcAST ast(tree); CalcBuilder builder; - auto module = builder.build(ast); - auto IR = module->print(); + auto module = builder.build(ast); + auto IR = module->print(); std::ofstream output_stream; - auto output_file = "result.ll"; + 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 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"); diff --git a/tests/2-ir-gen-warmup/calculator/calc_ast.hpp b/tests/2-ir-gen-warmup/calculator/calc_ast.hpp index fd3d2f538fcd7eb63102a6f90d78e0ebd25ce576..d37312b1e30568a1a29a08ec3993846a7ebd3d3d 100644 --- a/tests/2-ir-gen-warmup/calculator/calc_ast.hpp +++ b/tests/2-ir-gen-warmup/calculator/calc_ast.hpp @@ -1,8 +1,8 @@ #ifndef _CALC_AST_HPP_ #define _CALC_AST_HPP_ extern "C" { - #include "syntax_tree.h" - extern syntax_tree *parse(const char *input); +#include "syntax_tree.h" +extern syntax_tree *parse(const char *input); } #include #include @@ -32,59 +32,68 @@ struct CalcASTFactor; class CalcASTVisitor; -class CalcAST { -public: +class CalcAST +{ + public: CalcAST() = delete; CalcAST(syntax_tree *); - CalcAST(CalcAST &&tree) { - root = tree.root; + 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 *); + CalcASTInput *get_root() { return root.get(); } + void run_visitor(CalcASTVisitor &visitor); + + private: + CalcASTNode *transform_node_iter(syntax_tree_node *); std::shared_ptr root = nullptr; }; -struct CalcASTNode { +struct CalcASTNode +{ virtual void accept(CalcASTVisitor &) = 0; }; -struct CalcASTInput: CalcASTNode { - virtual void accept(CalcASTVisitor &) override final; +struct CalcASTInput : CalcASTNode +{ + virtual void accept(CalcASTVisitor &) override final; std::shared_ptr expression; }; -struct CalcASTFactor: CalcASTNode { +struct CalcASTFactor : CalcASTNode +{ virtual void accept(CalcASTVisitor &) override; }; -struct CalcASTNum: CalcASTFactor { +struct CalcASTNum : CalcASTFactor +{ virtual void accept(CalcASTVisitor &) override final; - int val; + int val; }; -struct CalcASTExpression: CalcASTFactor { - virtual void accept(CalcASTVisitor &) override final; +struct CalcASTExpression : CalcASTFactor +{ + virtual void accept(CalcASTVisitor &) override final; std::shared_ptr expression; - AddOp op; - std::shared_ptr term; + AddOp op; + std::shared_ptr term; }; -struct CalcASTTerm : CalcASTNode { - virtual void accept(CalcASTVisitor &) override final; - std::shared_ptr term; - MulOp op; +struct CalcASTTerm : CalcASTNode +{ + virtual void accept(CalcASTVisitor &) override final; + std::shared_ptr term; + MulOp op; std::shared_ptr factor; }; - -class CalcASTVisitor { -public: - virtual void visit(CalcASTInput &) = 0; - virtual void visit(CalcASTNum &) = 0; +class CalcASTVisitor +{ + public: + virtual void visit(CalcASTInput &) = 0; + virtual void visit(CalcASTNum &) = 0; virtual void visit(CalcASTExpression &) = 0; - virtual void visit(CalcASTTerm &) = 0; + virtual void visit(CalcASTTerm &) = 0; }; #endif diff --git a/tests/2-ir-gen-warmup/calculator/calc_builder.cpp b/tests/2-ir-gen-warmup/calculator/calc_builder.cpp index 9b5c36bf155736ba56d4327a0e3338e4e45195c6..426af96e3fe261b498bc1ed0ff216afe91714ea0 100644 --- a/tests/2-ir-gen-warmup/calculator/calc_builder.cpp +++ b/tests/2-ir-gen-warmup/calculator/calc_builder.cpp @@ -1,21 +1,17 @@ #include "calc_builder.hpp" -std::unique_ptr -CalcBuilder::build(CalcAST &ast) { - module = std::unique_ptr(new Module("Cminus code")); - builder = new IRBuilder(nullptr, module.get()); +std::unique_ptr CalcBuilder::build(CalcAST &ast) +{ + module = std::unique_ptr(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()); + TyInt32 = Type::get_int32_type(module.get()); std::vector 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 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); @@ -23,10 +19,9 @@ CalcBuilder::build(CalcAST &ast) { 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) { +void CalcBuilder::visit(CalcASTInput &node) { node.expression->accept(*this); } +void CalcBuilder::visit(CalcASTExpression &node) +{ if (node.expression == nullptr) { node.term->accept(*this); } else { @@ -35,17 +30,18 @@ void CalcBuilder::visit(CalcASTExpression &node) { 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; + 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) { +void CalcBuilder::visit(CalcASTTerm &node) +{ if (node.term == nullptr) { node.factor->accept(*this); } else { @@ -54,16 +50,17 @@ void CalcBuilder::visit(CalcASTTerm &node) { 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; + 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) { +void CalcBuilder::visit(CalcASTNum &node) +{ val = ConstantInt::get(node.val, module.get()); } diff --git a/tests/2-ir-gen-warmup/calculator/calc_builder.hpp b/tests/2-ir-gen-warmup/calculator/calc_builder.hpp index b4e2f5e0fb70b0f8ec9413769ffc364b92f605bd..c5fe10e4e5206bbeaf6ca5383dad8e6956e32375 100644 --- a/tests/2-ir-gen-warmup/calculator/calc_builder.hpp +++ b/tests/2-ir-gen-warmup/calculator/calc_builder.hpp @@ -7,18 +7,20 @@ #include "Module.h" #include "Type.h" #include "calc_ast.hpp" -class CalcBuilder: public CalcASTVisitor { -public: +class CalcBuilder : public CalcASTVisitor +{ + public: std::unique_ptr build(CalcAST &ast); -private: + + 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; + IRBuilder *builder; + Value *val; + Type *TyInt32; std::unique_ptr module; }; #endif diff --git a/tests/2-ir-gen-warmup/stu_cpp/fun_generator.cpp b/tests/2-ir-gen-warmup/stu_cpp/fun_generator.cpp index dd4649fa75bf560a4751b9862ee6ab9aa27a138b..f7348723ded03c0cdf343e77b5cf159d99811280 100644 --- a/tests/2-ir-gen-warmup/stu_cpp/fun_generator.cpp +++ b/tests/2-ir-gen-warmup/stu_cpp/fun_generator.cpp @@ -10,7 +10,7 @@ int main() { - auto mod = new Module("Cminus code"); // module name是什么无关紧要 + auto mod = new Module("fun.cpp"); auto bud = new IRBuilder(nullptr, mod); Type *I32Type = Type::get_int32_type(mod); std::vector OneIntArg(1, I32Type);