From ab890b5542e4aaa9aada6f167452391a8d0c72d0 Mon Sep 17 00:00:00 2001 From: LiXiaoQi Date: Thu, 27 Oct 2022 21:21:29 +0800 Subject: [PATCH] 36 points --- Reports/3-ir-gen/report.md | 29 ++++++- src/cminusfc/cminusf_builder.cpp | 83 +++++++++++++++---- .../testcases/lv1/assign_int_var_local.ll | 19 +++++ 3 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 tests/3-ir-gen/testcases/lv1/assign_int_var_local.ll diff --git a/Reports/3-ir-gen/report.md b/Reports/3-ir-gen/report.md index b3e1e41..c3bb393 100644 --- a/Reports/3-ir-gen/report.md +++ b/Reports/3-ir-gen/report.md @@ -66,9 +66,36 @@ PB20111654 李晓奇 6. 记录遇到的坑 - 形如这种产生式子`term→term mulop factor ∣ factor`,我为了图方便先求了`factor`,在根据`term`的有调用`accept()`,但是这样会导致左右操作数颠倒。 + - 我对于类型转换的控制比较严格,没考虑到的一率abort,因此很快发现了漏掉了bool类型的转换。 + - 接上条,一些类型转换的bug:`i32`到`i1`也是需要转换的,开始做的时候还没意识到这些(主要是没意识到`i1`的存在)。 - - 接上条,关于 + + - **核心问题**:函数调用是值传递,比如`f(a)`,这里在中间代码看来,a返回的是一个指针,需要load出来再传过去。 + + 但是对于字面量,又不需这样提取数据。可以使用`dynamic_cast`尝试解决。 + + 但是出现了加减乘除时,这个又不能动态类型转换。 + + 换句话说,访问`ASTCall`时,需要依次调用args的`accept()`,但是这个args!!!!expression应该返回的就是值才对。问题出现在变量的访问那里。 + + 这个在访问`ASTVar`时解决掉: + + - 如果做左值,返回指针元素 + + - 如果做右值,返回值 + + ```cpp + struct ASTCall : ASTFactor { + virtual void accept(ASTVisitor &) override final; + std::string id; + std::vector> args; + }; + ``` + + - 全局变量要特殊对待 + + - 数组下标为负时要调用`neg_idx_except()` ## 实验设计 diff --git a/src/cminusfc/cminusf_builder.cpp b/src/cminusfc/cminusf_builder.cpp index 850acc7..9d57792 100644 --- a/src/cminusfc/cminusf_builder.cpp +++ b/src/cminusfc/cminusf_builder.cpp @@ -16,6 +16,7 @@ // definitions if you need to. // the latest return value +bool LV = false; Value *cur_value = nullptr; // function that is being built Function *cur_fun = nullptr; @@ -28,6 +29,10 @@ Type *INT32PTR_T; Type *FLOAT_T; Type *FLOATPTR_T; +// initializer +ConstantZero *I32Initializer; +ConstantZero *FloatInitializer; + /* * use CMinusfBuilder::Scope to construct scopes * scope.enter: enter a new scope @@ -72,6 +77,8 @@ void CminusfBuilder::visit(ASTProgram &node) { INT32PTR_T = Type::get_int32_ptr_type(module.get()); FLOAT_T = Type::get_float_type(module.get()); FLOATPTR_T = Type::get_float_ptr_type(module.get()); + I32Initializer = ConstantZero::get(INT32_T, builder->get_module()); + FloatInitializer = ConstantZero::get(FLOAT_T, builder->get_module()); for (auto decl : node.declarations) { decl->accept(*this); @@ -99,29 +106,37 @@ void CminusfBuilder::visit(ASTNum &node) { void CminusfBuilder::visit(ASTVarDeclaration &node) { //!TODO: This function is empty now. // Add some code here. + bool global = (builder->get_insert_block() == nullptr); if (node.num) { // declares an array // // get array size node.num->accept(*this); // - // type cast - if (Type::is_eq_type(cur_value->get_type(), FLOAT_T)) - cur_value = builder->create_fptosi(cur_value, INT32_T); - int size = static_cast(cur_value)->get_value(); + // !no type cast here! + if (not(node.num->type == TYPE_INT)) + error_exit("size of array has non-integer type"); + + int size = node.num->i_val; if (size <= 0) error_exit("array size[" + std::to_string(size) + "] <= 0"); switch (node.type) { case TYPE_INT: { auto I32Array_T = Type::get_array_type(INT32_T, size); - cur_value = builder->create_alloca(I32Array_T); + if (global) + GlobalVariable::create(node.id, builder->get_module(), I32Array_T, false, I32Initializer); + else + builder->create_alloca(I32Array_T); break; } case TYPE_FLOAT: { auto FloatArray_T = Type::get_array_type(FLOAT_T, size); - cur_value = builder->create_alloca(FloatArray_T); + if (global) + GlobalVariable::create(node.id, builder->get_module(), FloatArray_T, false, FloatInitializer); + else + builder->create_alloca(FloatArray_T); break; } default: @@ -129,19 +144,29 @@ void CminusfBuilder::visit(ASTVarDeclaration &node) { } } else { + // flat int or float type switch (node.type) { case TYPE_INT: - cur_value = builder->create_alloca(INT32_T); + if (global) + GlobalVariable::create(node.id, builder->get_module(), INT32_T, false, I32Initializer); + else + builder->create_alloca(INT32_T); break; + case TYPE_FLOAT: - cur_value = builder->create_alloca(FLOAT_T); + if (global) + GlobalVariable::create(node.id, builder->get_module(), FLOAT_T, false, FloatInitializer); + else + builder->create_alloca(INT32_T); break; default: error_exit("Variable type(not array) is not int or float"); } } + if (not scope.push(node.id, cur_value)) error_exit("variable redefined: " + node.id); + LOG_DEBUG << "add entry: " << node.id << " " << cur_value; } // Done @@ -325,6 +350,8 @@ void CminusfBuilder::visit(ASTReturnStmt &node) { } // Done +// if LV is marked, return memory addr +// else return value stored inside void CminusfBuilder::visit(ASTVar &node) { //!TODO: This function is empty now. // Add some code here. @@ -337,6 +364,7 @@ void CminusfBuilder::visit(ASTVar &node) { Value *addr; if (memory == nullptr) error_exit("variable " + node.id + " not declared"); + LOG_DEBUG << "find entry: " << node.id << " " << memory; if (node.expression) { // e.g. int a[10]; // mem is [i32 x 10]* node.expression->accept(*this); if (not Type::is_eq_type(cur_value->get_type(), INT32_T)) { @@ -346,13 +374,27 @@ void CminusfBuilder::visit(ASTVar &node) { error_exit("bad type for subscription"); } - // now it's + auto cond = builder->create_icmp_lt(cur_value, CONST_INT(0)); + auto except_func = scope.find("neg_idx_except"); + auto TBB = BasicBlock::create(builder->get_module(), "BadIdx", cur_fun); + auto FBB = BasicBlock::create(builder->get_module(), "Pass", cur_fun); + builder->create_cond_br(cond, TBB, FBB); + + builder->set_insert_point(TBB); + builder->create_call(except_func, {}); + + builder->set_insert_point(FBB); + addr = builder->create_gep(memory, {0, cur_value}); } else { // e.g. int a; // a is i32* addr = memory; } - cur_value = addr; + if (LV) + cur_value = addr; + else { + cur_value = builder->create_load(addr); + } } // Done @@ -360,16 +402,18 @@ void CminusfBuilder::visit(ASTAssignExpression &node) { //!TODO: This function is empty now. // Add some code here. // + LV = true; node.var->accept(*this); - auto left = cur_value; + LV = false; + auto addr = cur_value; node.expression->accept(*this); - assert(left->get_type()->get_pointer_element_type() != nullptr); + assert(addr->get_type()->get_pointer_element_type() != nullptr); // type cast: left is a pointer type, pointed to i32 or float - if (not Type::is_eq_type(left->get_type()->get_pointer_element_type(), cur_value->get_type())) { + if (not Type::is_eq_type(addr->get_type()->get_pointer_element_type(), cur_value->get_type())) { if (cur_value->get_type()->is_float_type()) cur_value = builder->create_fptosi(cur_value, INT32_T); - else if (left->get_type()->get_pointer_element_type()->is_float_type()) + else if (addr->get_type()->get_pointer_element_type()->is_float_type()) cur_value = builder->create_sitofp(cur_value, FLOAT_T); else if (Type::is_eq_type(cur_value->get_type(), INT1_T)) cur_value = builder->create_zext(cur_value, INT32_T); @@ -377,7 +421,7 @@ void CminusfBuilder::visit(ASTAssignExpression &node) { error_exit("bad type for assignment"); } // gen code - builder->create_store(left, cur_value); + builder->create_store(addr, cur_value); } // Done @@ -522,10 +566,19 @@ void CminusfBuilder::visit(ASTCall &node) { if (node.args.size() != func->get_num_of_args()) error_exit("expect " + std::to_string(func->get_num_of_args()) + " params, but " + std::to_string(node.args.size()) + " is given"); + // check every argument for (int i = 0; i != node.args.size(); ++i) { + // ith parameter's type Type *param_type = func->get_function_type()->get_param_type(i); node.args[i]->accept(*this); + /* if (dynamic_cast(cur_value) != nullptr) { + * // this is literal + * cur_value = dynamic_cast(cur_value); + * } else { + * // this is variable + * cur_value = builder->create_load(cur_value); + * } */ // type cast if (not Type::is_eq_type(param_type, cur_value->get_type())) { if (param_type->is_pointer_type()) { diff --git a/tests/3-ir-gen/testcases/lv1/assign_int_var_local.ll b/tests/3-ir-gen/testcases/lv1/assign_int_var_local.ll new file mode 100644 index 0000000..3f7e954 --- /dev/null +++ b/tests/3-ir-gen/testcases/lv1/assign_int_var_local.ll @@ -0,0 +1,19 @@ +; ModuleID = 'cminus' +source_filename = "assign_int_var_local.cminus" + +declare i32 @input() + +declare void @output(i32) + +declare void @outputFloat(float) + +declare void @neg_idx_except() + +define void @main() { +label_entry: + %op0 = alloca i32 + store i32* %op0, i32 1234 + %op1 = load i32, i32* %op0 + call void @output(i32 %op1) + ret void +} -- GitLab