[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`以了解其接口的设计。 #### 样例学习
go_upstairs_gen.cpp核心部分(点击展开) ```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> 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> 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> 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); //后略, 详细见代码文件 ```
为了更直观地感受并学会使用 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`