diff --git a/include/llir_type.h b/include/llir_type.h index faebbdc..38309d7 100644 --- a/include/llir_type.h +++ b/include/llir_type.h @@ -1,5 +1,6 @@ #pragma once +#include "common.h" #include #include namespace antlrSysY { @@ -69,6 +70,14 @@ public: ArrayType() : Type(TypeTag::ArrayType) {} ArrayType(TypePtr_t element_type, int element_count) : Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {} + static std::shared_ptr build_from_list(const std::vector &dim_list) { + TypePtr_t array_type = TypeHelper::TYPE_I32; + sysy_assert(dim_list.size() != 0); + for (auto itr = dim_list.rbegin(); itr != dim_list.rend(); ++itr) { + array_type = std::make_shared(array_type, *itr); + } + return std::dynamic_pointer_cast(array_type); + } }; class PointerType : public Type { diff --git a/include/llir_value.h b/include/llir_value.h index c9c240b..c4a2b7a 100644 --- a/include/llir_value.h +++ b/include/llir_value.h @@ -5,6 +5,7 @@ #include #include +#include "common.h" #include "llir_type.h" namespace antlrSysY { @@ -50,18 +51,46 @@ public: } }; -class ConstantInt : public Value { +typedef std::shared_ptr ValuePtr_t; +typedef std::shared_ptr BasicBlockPtr_t; +typedef std::shared_ptr FunctionPtr_t; + +class Constant : public Value { public: - int value; - ConstantInt(const std::string &name, int value) : Value(name, TypeHelper::TYPE_I32), value(value) {} + Constant(const std::string &name, TypePtr_t type) : Value(name, type) {} }; -class ConstantArr : public Value {}; - -class GlobalVarInt : public Value { +class ConstantInt : public Constant { public: - int init_value; - GlobalVarInt(const std::string &name, int init_value) : Value(name, TypeHelper::TYPE_I32), init_value(init_value) {} + int value; + ConstantInt(const std::string &name, int value) : Constant(name, TypeHelper::TYPE_I32), value(value) {} + static std::shared_ptr make_shared(int value) { + return std::make_shared("", value); + } +}; + +class ConstantArr : public Constant { +public: + std::vector value_list; + ConstantArr(const std::string &name, const std::vector &value_list, std::shared_ptr type) + : Constant(name, type), value_list(value_list) {} + static std::shared_ptr make_shared(const std::string &name, const std::vector &value_list, + std::shared_ptr type) { + return std::make_shared(name, value_list, type); + } +}; + +typedef std::shared_ptr ConstantPtr_t; + +class GlobalVar : public Value { +public: + ConstantPtr_t init_value; + bool is_const; + GlobalVar(const std::string &name, ConstantPtr_t init_value, bool is_const) + : Value(name, init_value->type), init_value(init_value), is_const(is_const) {} + static std::shared_ptr make_shared(const std::string &name, ConstantPtr_t init_value, bool is_const) { + return std::make_shared(name, init_value, is_const); + } }; enum class InstTag { @@ -93,9 +122,6 @@ enum class InstTag { ExtractEle }; -typedef std::shared_ptr ValuePtr_t; -typedef std::shared_ptr BasicBlockPtr_t; -typedef std::shared_ptr FunctionPtr_t; class Instruction : public Value { public: InstTag tag; @@ -107,9 +133,8 @@ public: class InstAlloca : public Instruction { public: - bool isInit = false; - InstAlloca(TypePtr_t alloc_type, bool isInit, std::shared_ptr parent_bb) - : Instruction(InstTag::Alloca, std::make_shared(alloc_type), parent_bb), isInit(isInit) {} + InstAlloca(TypePtr_t alloc_type, std::shared_ptr parent_bb) + : Instruction(InstTag::Alloca, std::make_shared(alloc_type), parent_bb) {} }; class InstStore : public Instruction { @@ -177,8 +202,46 @@ public: InstCall(FunctionPtr_t func, const std::vector &args, BasicBlockPtr_t parent_bb) : Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) { operand_list.push_back(func); - for (auto arg : args) { - operand_list.push_back(arg); + operand_list.insert(operand_list.end(), args.begin(), args.end()); + } +}; + +// getelementptr , ptr {, [inrange] }* +// Example: lea arr[2][3] from arr[5][4]: +// &arr[2][3] = GEP [5x[4xi32]], [5x[4xi32]]* arr, i32 0, i32 2, i32 3 +class InstGEP : public Instruction { +public: + ValuePtr_t aim_to; + TypePtr_t element_type; + InstGEP(ValuePtr_t pointer, const std::vector &indices, BasicBlockPtr_t parent_bb) + : Instruction(InstTag::GEP, std::make_shared(extract_type(pointer, indices)), parent_bb) { + if (typeid(pointer) == typeid(std::shared_ptr)) { + aim_to = std::dynamic_pointer_cast(pointer)->aim_to; + } + else { + sysy_assert(typeid(pointer) == typeid(std::shared_ptr) || + typeid(pointer) == typeid(std::shared_ptr)); + aim_to = pointer; + } + element_type = extract_type(pointer, indices); + operand_list.push_back(pointer); + operand_list.insert(operand_list.end(), indices.begin(), indices.end()); + } + + // get the inner + static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector &indices) { + auto pointer_type = std::dynamic_pointer_cast(pointer->type); + auto pointed_type = pointer_type->pointed_type; + if (pointed_type->type_tag == Type::TypeTag::ArrayType) { + for (int i = 1; i < indices.size() - 1; ++i) { + pointed_type = std::dynamic_pointer_cast(pointed_type)->element_type; + } + } + if (pointed_type->type_tag == Type::TypeTag::IntegerType) { + return pointed_type; + } + else { + panic("Unmatch indices and array pointer"); } } }; diff --git a/include/visitor.h b/include/visitor.h index 62313f0..b0b08c3 100644 --- a/include/visitor.h +++ b/include/visitor.h @@ -29,7 +29,7 @@ std::shared_ptr build_InstLoad(std::shared_ptr value, TypePtr_t std::shared_ptr build_InstStore(std::shared_ptr value, std::shared_ptr pointer, std::shared_ptr parent_bb); -std::shared_ptr build_InstAlloca(TypePtr_t type, bool isInit, std::shared_ptr parent_bb); +std::shared_ptr build_InstAlloca(TypePtr_t type, std::shared_ptr parent_bb); std::shared_ptr build_InstBinary(InstTag inst_tag, std::shared_ptr op1, std::shared_ptr op2, std::shared_ptr parent_bb); @@ -47,18 +47,22 @@ std::shared_ptr build_InstReturn(BasicBlockPtr_t parent_bb); std::shared_ptr build_InstCall(FunctionPtr_t func, const std::vector &args, BasicBlockPtr_t parent_bb); +std::shared_ptr build_InstGEP(ValuePtr_t pointer, const std::vector &indices, + BasicBlockPtr_t parent_bb); + #pragma endregion class Visitor : public antlrSysY::SysyBaseVisitor { private: struct VisitorState { - bool isGlobalInt = false; + bool isGlobalIint = false; bool isConstInt = false; bool isRealParam = false; bool isCondExp = false; std::shared_ptr current_func = {}; std::shared_ptr current_bb = {}; - + std::vector *arr_dim_list = nullptr; + int arr_dim_index = 0; struct loop_record { BasicBlockPtr_t cond, body, next; int id; diff --git a/scripts/compiler.py b/scripts/compiler.py index 8fa21dd..089a626 100644 --- a/scripts/compiler.py +++ b/scripts/compiler.py @@ -18,6 +18,8 @@ class Compiler: self.obj_template = f"build/test_results/{{testcase}}/obj/{scheme}.o" self.bin_template = f"build/test_results/{{testcase}}/bin/{scheme}" self.compile_log = f"build/log/compile_log/{{testcase}}/{scheme}.log" + + self.count_error = 0 for testcase in testcases: self.__generate_path(testcase) @@ -64,6 +66,7 @@ class Compiler: completed = subprocess.run(frontend_instr.format(header=header, sy=sy, ir=ir).split(), stdout=log_file, stderr=log_file, bufsize=1) if completed.returncode != 0: Print_C.print_error(f"Generating {self.scheme}.ll failed! See {log}") + self.count_error += 1 log_file.close() @@ -142,5 +145,8 @@ class Compiler: for testcase in self.testcases: Print_C.print_subheader(f"[Compiling {self.scheme} | {testcase}]") self.sy_to_ir(frontend_instr=frontend_instr, testcase=testcase, category=category) + if self.count_error >= 10: + Print_C.print_error(f"Test script stopped due to too many errors") + return \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9dcd838..31d095b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -59,6 +59,9 @@ int main(int argc, const char **argv) { #pragma endregion std::ifstream ifs_source_file(source_file); + if (!ifs_source_file.good()) { + LOG(ERROR) << "Source file " << source_file << " not found."; + } ANTLRInputStream input(ifs_source_file); SysyLexer lexer(&input); CommonTokenStream tokens(&lexer); diff --git a/src/visit_factory.cpp b/src/visit_factory.cpp index 1aadf62..d78da0e 100644 --- a/src/visit_factory.cpp +++ b/src/visit_factory.cpp @@ -31,8 +31,8 @@ std::shared_ptr build_InstStore(std::shared_ptr value, std::sh return inst_store; } -std::shared_ptr build_InstAlloca(TypePtr_t type, bool isInit, std::shared_ptr parent_bb) { - auto inst_alloca = std::make_shared(type, isInit, parent_bb); +std::shared_ptr build_InstAlloca(TypePtr_t type, std::shared_ptr parent_bb) { + auto inst_alloca = std::make_shared(type, parent_bb); parent_bb->inst_list.push_back(inst_alloca); return inst_alloca; } @@ -91,4 +91,11 @@ std::shared_ptr build_InstCall(FunctionPtr_t func, const std::vector build_InstGEP(ValuePtr_t pointer, const std::vector &indices, + BasicBlockPtr_t parent_bb) { + auto inst = std::make_shared(pointer, indices, parent_bb); + parent_bb->inst_list.push_back(inst); + return inst; +} + } // namespace antlrSysY \ No newline at end of file diff --git a/src/visitor.cpp b/src/visitor.cpp index f16cdad..a92d7d1 100644 --- a/src/visitor.cpp +++ b/src/visitor.cpp @@ -1,4 +1,5 @@ #include "visitor.h" +#include "3rdparty/easylogging++.h" #include "common.h" #include "llir_type.h" #include "llir_value.h" @@ -19,7 +20,7 @@ namespace antlrSysY { return value; \ } -ValuePtr_t any_to_Value(const std::any &fuck_any) { +static ValuePtr_t any_to_Value(const std::any &fuck_any) { ANY2VALUE(Value) ANY2VALUE(User) ANY2VALUE(FParam) @@ -27,7 +28,8 @@ ValuePtr_t any_to_Value(const std::any &fuck_any) { ANY2VALUE(BasicBlock) ANY2VALUE(ConstantInt) ANY2VALUE(ConstantArr) - ANY2VALUE(GlobalVarInt) + ANY2VALUE(Constant) + ANY2VALUE(GlobalVar) ANY2VALUE(Instruction) ANY2VALUE(InstAlloca) ANY2VALUE(InstStore) @@ -48,101 +50,273 @@ std::any Visitor::visitConstDecl(SysyParser::ConstDeclContext *ctx) { return {}; } +// constInitVal is compulsory // constDef : IDENT ('[' constExp ']')* '=' constInitVal ';' std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) { - auto name = ctx->IDENT()->getText(); - LOG(DEBUG) << "Visiting ConstDef " << name; - if (_scope_tab.get_name(name, _scope_tab.get_level()).has_value()) + const auto const_name = ctx->IDENT()->getText(); + LOG(DEBUG) << "Visiting ConstDef " << const_name; + if (_scope_tab.get_name(const_name, _scope_tab.get_level()).has_value()) throw GrammarException("Duplicate const def"); // not array if (ctx->constExp().empty()) { - if (ctx->constInitVal() != nullptr) { - auto result = std::any_cast(visit(ctx->constInitVal())); - auto constint = build_ConstantInt(name, result); - _scope_tab.push_name(name, constint); + auto result = std::any_cast>(visitConstInitVal(ctx->constInitVal())); + _scope_tab.push_name(const_name, result); + } + // const array + else { + std::vector dim_list; + auto const_exp_list = ctx->constExp(); + // collect size of each dimension + for (auto const_exp : const_exp_list) { + auto n_elem = std::any_cast>(visitConstExp(const_exp)); + dim_list.push_back(n_elem->value); + } + auto array_type = ArrayType::build_from_list(dim_list); + // anyways, first collect init value + _state.arr_dim_index = 0; + _state.arr_dim_list = &dim_list; + auto array_value = std::any_cast>(visitConstInitVal(ctx->constInitVal())); + _state.arr_dim_list = nullptr; + sysy_assert(_state.arr_dim_index == 0); + + if (_scope_tab.get_level()) { + // local const array + // Keep a pointer to the base address, alloca_ = &array, *alloca_ = &array[0] + auto alloca_ = build_InstAlloca(array_type, _state.current_bb); + _scope_tab.push_name(const_name, alloca_); + // first dim base, ptr = *alloca_ = &array[0] + auto base_ptr = build_InstGEP(alloca_, {CONST0, CONST0}, _state.current_bb); + // get the first element's base, final ptr = &a[0][0]...[0] + for (int i = 1; i < dim_list.size(); ++i) { + base_ptr = build_InstGEP(base_ptr, {CONST0, CONST0}, _state.current_bb); + } + // we store the elements in 1-dim shape + build_InstStore(array_value[0], base_ptr, _state.current_bb); + for (int i = 1; i < array_value.size(); ++i) { + auto ptr = build_InstGEP(base_ptr, {ConstantInt::make_shared(i)}, _state.current_bb); + build_InstStore(array_value[i], ptr, _state.current_bb); + } + } + else { + // global const array + auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type); + auto global_var = GlobalVar::make_shared(const_name, const_arr, true); + _scope_tab.push_name(const_name, global_var); } } return {}; } +// initVal is optional +// varDef: IDENT ('[' constExp ']')* ('=' initVal)?; std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) { - auto name = ctx->IDENT()->getText(); - LOG(DEBUG) << "Visiting VarDef " << name; - if (_scope_tab.get_name(name, _scope_tab.get_level()).has_value()) + auto var_name = ctx->IDENT()->getText(); + LOG(DEBUG) << "Visiting VarDef " << var_name; + if (_scope_tab.get_name(var_name, _scope_tab.get_level()).has_value()) panic("Duplicate const def"); // Not Array if (ctx->constExp().empty()) { // global variable if (_scope_tab.get_level() == 0) { // global variable must be initialized, either specified or zeroed - int result = 0; if (ctx->initVal()) { - _state.isGlobalInt = true; - result = std::any_cast(visit(ctx->initVal())); - _state.isGlobalInt = false; + _state.isGlobalIint = true; + auto result = std::any_cast>(visitInitVal(ctx->initVal())); + _state.isGlobalIint = false; + auto global_var_int = std::make_shared(var_name, result, false); + _scope_tab.push_name(var_name, global_var_int); + } + else { + auto global_var_int = std::make_shared(var_name, CONST0, false); + _scope_tab.push_name(var_name, global_var_int); } - auto global_var_int = std::make_shared(name, result); - _scope_tab.push_name(name, global_var_int); } // local variable else { - auto alloca = build_InstAlloca(TypeHelper::TYPE_I32, false, _state.current_bb); - _scope_tab.push_name(name, alloca); + auto alloca_ = build_InstAlloca(TypeHelper::TYPE_I32, _state.current_bb); + _scope_tab.push_name(var_name, alloca_); if (ctx->initVal()) { auto init_val = any_to_Value(visitInitVal(ctx->initVal())); - build_InstStore(init_val, alloca, _state.current_bb); + build_InstStore(init_val, alloca_, _state.current_bb); } } } else { - // Array - panic("To be implemented"); + std::vector dim_list; + auto const_exp_list = ctx->constExp(); + // collect size of each dimension + for (auto const_exp : const_exp_list) { + auto n_elem = std::any_cast>(visitConstExp(const_exp)); + dim_list.push_back(n_elem->value); + } + auto array_type = ArrayType::build_from_list(dim_list); + // local array + if (_scope_tab.get_level()) { + auto alloca_ = build_InstAlloca(array_type, _state.current_bb); + _scope_tab.push_name(var_name, alloca_); + if (ctx->initVal()) { + _state.arr_dim_index = 0; + _state.arr_dim_list = &dim_list; + auto array_value = std::any_cast>(visitInitVal(ctx->initVal())); + _state.arr_dim_list = nullptr; + sysy_assert(_state.arr_dim_index == 0); + // Build GEP + auto base_ptr = build_InstGEP(alloca_, {CONST0, CONST0}, _state.current_bb); + for (int i = 1; i < dim_list.size(); ++i) { + base_ptr = build_InstGEP(base_ptr, {CONST0, CONST0}, _state.current_bb); + } + // TODO: BAAU-2021 calls memset in `libc` (not sysylib) to optimize this process + build_InstStore(array_value[0], base_ptr, _state.current_bb); + for (int i = 1; i < array_value.size(); ++i) { + auto ptr = build_InstGEP(base_ptr, {ConstantInt::make_shared(i)}, _state.current_bb); + build_InstStore(array_value[i], ptr, _state.current_bb); + } + } + // If there is no init expr, let it be + } + // global array, generally the same as constant global array + else { + if (ctx->initVal()) { + // first collect init value + _state.isGlobalIint = true; + _state.arr_dim_index = 0; + _state.arr_dim_list = &dim_list; + auto array_value = std::any_cast>(visitInitVal(ctx->initVal())); + _state.arr_dim_list = nullptr; + sysy_assert(_state.arr_dim_index == 0); + _state.isGlobalIint = false; + auto const_arr = ConstantArr::make_shared("var_arr", array_value, array_type); + auto global_var = GlobalVar::make_shared(var_name, const_arr, false); + _scope_tab.push_name(var_name, global_var); + } + else { + auto global_var = GlobalVar::make_shared(var_name, CONST0, false); + _scope_tab.push_name(var_name, global_var); + } + } } return {}; } std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) { if (ctx->exp()) { - if (_state.isGlobalInt) + if (_state.isGlobalIint) _state.isConstInt = true; - auto retval = visit(ctx->exp()); - if (_state.isGlobalInt) + auto retval = visitExp(ctx->exp()); + if (_state.isGlobalIint) _state.isConstInt = false; return retval; } // Array - panic("To be implemented"); -} - -std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) { - if (ctx->constExp() != nullptr /*&& ctx->arrDim.size() == 0*/) { - return visit(ctx->constExp()); + else { + sysy_assert(_state.arr_dim_list); + int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index); + int elem_size = 1; + std::vector cur_arr; + for (int i = _state.arr_dim_index + 1; i < _state.arr_dim_list->size(); ++i) { + elem_size *= _state.arr_dim_list->at(i); + } + for (auto init_val : ctx->initVal()) { + if (init_val->exp()) { + if (_state.isGlobalIint) { + auto const_value = any_to_Value(visitInitVal(init_val)); + // should evaluate to const int + sysy_assert(typeid(const_value) == typeid(std::shared_ptr)); + cur_arr.push_back(const_value); + } + else { + // God knows what it evaluates to + auto exp_value = any_to_Value(visitInitVal(init_val)); + cur_arr.push_back(exp_value); + } + } + else { + // evaluate sub-array + // before evaluate the new sub-array, first fill up the last one + const int pos = cur_arr.size(); + // the additional `%elem_size`: what if the last dim is {}? + for (int i = 0; i < (elem_size - (pos % elem_size)) % elem_size; ++i) { + cur_arr.push_back(CONST0); + } + _state.arr_dim_index++; + auto sub_array = std::any_cast>(visitInitVal(init_val)); + _state.arr_dim_index--; + cur_arr.insert(cur_arr.end(), sub_array.begin(), sub_array.end()); + } + } + // fill up the rest + for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) { + cur_arr.push_back(CONST0); + } + return cur_arr; } - panic("To be implemented"); } +// TODO: Replace all any to ConstantInt +// constInitVal: constExp | ('{' (constInitVal (',' constInitVal)*)? '}'); +std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) { + if (ctx->constExp() != nullptr) { + return visitConstExp(ctx->constExp()); + } + else { + sysy_assert(_state.arr_dim_list); + int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index); + int elem_size = 1; + std::vector cur_arr; + for (int i = _state.arr_dim_index + 1; i < _state.arr_dim_list->size(); ++i) { + elem_size *= _state.arr_dim_list->at(i); + } + for (auto init_val : ctx->constInitVal()) { + if (init_val->constExp()) { + // evaluate to const int + auto const_value = any_to_Value(visitConstInitVal(init_val)); + sysy_assert(TypeHelper::isIntegerType(const_value->type)); + cur_arr.push_back(const_value); + } + else { + // evaluate to sub-array + // before evaluate the new sub-array, first fill up the last one + int pos = cur_arr.size(); + // the additional `%elem_size`: what if the last dim is {}? + for (int i = 0; i < (elem_size - (pos % elem_size)) % elem_size; ++i) { + cur_arr.push_back(CONST0); + } + _state.arr_dim_index++; + auto sub_array = std::any_cast>(visitConstInitVal(init_val)); + _state.arr_dim_index--; + cur_arr.insert(cur_arr.end(), sub_array.begin(), sub_array.end()); + } + } + // fill up the rest + for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) { + cur_arr.push_back(CONST0); + } + return cur_arr; + } +} + +// @retval: int std::any Visitor::visitConstExp(SysyParser::ConstExpContext *ctx) { if (ctx->addExp() == nullptr) panic("Unreachable"); _state.isConstInt = true; - int result = std::any_cast(visit(ctx->addExp())); + auto result = std::any_cast>(visitAddExp(ctx->addExp())); _state.isConstInt = false; - LOG(DEBUG) << "ConstExp Eval to " << result; + LOG(DEBUG) << "ConstExp Eval to " << result->value; return {result}; } // addExp: mulExp | addExp ('+' | '-') mulExp; std::any Visitor::visitAddExp(SysyParser::AddExpContext *ctx) { if (_state.isConstInt) { - int result = std::any_cast(visit(ctx->mulExp())); - int add_result = 0; + auto result = std::any_cast>(visitMulExp(ctx->mulExp())); if (ctx->addExp()) { - add_result = std::any_cast(visit(ctx->addExp())); + auto add_result = std::any_cast>(visitAddExp(ctx->addExp())); if (ctx->ADD()) - result = add_result + result; + result->value = add_result->value + result->value; else if (ctx->SUB()) - result = add_result - result; + result->value = add_result->value - result->value; else panic("missing operator"); } @@ -173,17 +347,17 @@ std::any Visitor::visitAddExp(SysyParser::AddExpContext *ctx) { std::any Visitor::visitMulExp(SysyParser::MulExpContext *ctx) { if (_state.isConstInt) { - int result = std::any_cast(visitUnaryExp(ctx->unaryExp())); + auto result = std::any_cast>(visitUnaryExp(ctx->unaryExp())); if (ctx->mulExp()) { - int mul_result = std::any_cast(visit(ctx->mulExp())); + auto mul_result = std::any_cast>(visitMulExp(ctx->mulExp())); if (ctx->MUL()) { - result = mul_result * result; + result->value = mul_result->value * result->value; } else if (ctx->DIV()) { - result = mul_result / result; + result->value = mul_result->value / result->value; } else if (ctx->MOD()) { - result = mul_result % result; + result->value = mul_result->value % result->value; } else panic("Unreachable"); @@ -299,13 +473,13 @@ std::any Visitor::visitLOrExp(SysyParser::LOrExpContext *ctx) { std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) { if (_state.isConstInt) { if (ctx->unaryExp()) { - int result = std::any_cast(visit(ctx->unaryExp())); + auto result = std::any_cast>(visitUnaryExp(ctx->unaryExp())); if (ctx->unaryOp()->ADD()) - result = +result; + result->value = +result->value; else if (ctx->unaryOp()->SUB()) - result = -result; + result->value = -result->value; else if (ctx->unaryOp()->NOT()) - result = !result; + result->value = !result->value; else panic("Unreachable"); return {result}; @@ -376,7 +550,7 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) { return visitExp(ctx->exp()); } else if (ctx->lVal()) { - auto value = any_to_Value(visit(ctx->lVal())); + auto value = any_to_Value(visitLVal(ctx->lVal())); auto constint = std::dynamic_pointer_cast(value); // actually, it is only a type assertion return constint->value; @@ -418,32 +592,26 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) { } panic("Unreachable"); } - return {}; } -// @retval: int +// @retval: ConstantInt std::any Visitor::visitNumber(SysyParser::NumberContext *ctx) { - auto int_const = std::any_cast(visit(ctx->intConst())); - if (_state.isConstInt) { - return int_const; - } - else { - return std::dynamic_pointer_cast(build_ConstantInt("", int_const)); - } + return visitIntConst(ctx->intConst()); } -// @retval: int +// @retval: ConstantInt std::any Visitor::visitIntConst(SysyParser::IntConstContext *ctx) { + int const_int = 0; if (ctx->DECIMAL_CONST()) { - return std::stoi(ctx->DECIMAL_CONST()->getText(), nullptr, 10); + const_int = std::stoi(ctx->DECIMAL_CONST()->getText(), nullptr, 10); } else if (ctx->HEXADECIMAL_CONST()) { - return std::stoi(ctx->HEXADECIMAL_CONST()->getText(), nullptr, 16); + const_int = std::stoi(ctx->HEXADECIMAL_CONST()->getText(), nullptr, 16); } else if (ctx->OCTAL_CONST()) { - return std::stoi(ctx->OCTAL_CONST()->getText(), nullptr, 8); + const_int = std::stoi(ctx->OCTAL_CONST()->getText(), nullptr, 8); } - return {}; + return build_ConstantInt("", const_int); } // lVal: IDENT ('[' exp ']')*; @@ -460,17 +628,107 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) { } if (lval->type->type_tag == Type::TypeTag::PointerType) { auto ptr_type = std::dynamic_pointer_cast(lval->type); - if (ptr_type->pointed_type->type_tag == Type::TypeTag::IntegerType) { - // @retval: InstAlloca + switch (ptr_type->pointed_type->type_tag) { + case Type::TypeTag::IntegerType: { + // Int if (ctx->exp().empty()) { + // int ref + // @retval: InstAlloca return lval; } else { - panic("To be implemented"); + LOG(WARNING) << "Unexpected array referece"; + // array index, perhaps + // @retval: InstGEP + auto gep = lval; + for (auto exp_ctx : ctx->exp()) { + auto exp = any_to_Value(visitExp(exp_ctx)); + gep = build_InstGEP(gep, {exp}, _state.current_bb); + } + return gep; + } + }; + case Type::TypeTag::PointerType: { + if (ctx->exp().empty()) { + // ??? Pointer + // @retval: InstLoad + LOG(WARNING) << "Unexpected pointer"; + auto pointed_type = std::dynamic_pointer_cast(lval)->pointed_type; + auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb); + return inst_load; + } + else { + // fparam array, whose first dim is represented by a pointer + auto pointed_type = std::dynamic_pointer_cast(lval)->pointed_type; + sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType); + auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb); + + auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb); + pointed_type = std::dynamic_pointer_cast(ptr->type)->pointed_type; + ValuePtr_t offset = ConstantInt::make_shared(0); + auto exp_list = ctx->exp(); + // calculate offset by hand: offset = (offset + exp[i]) * dim_size[i] + for (int i = 0; i < exp_list.size() - 1; ++i) { + sysy_assert(typeid(pointed_type) == typeid(std::shared_ptr)); + auto array_type = std::dynamic_pointer_cast(pointed_type); + auto exp_val = any_to_Value(visitExp(exp_list[i])); + auto dim_size = ConstantInt::make_shared(array_type->element_count); + auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb); + auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb); + offset = inst_mul; + pointed_type = array_type->element_type; + ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb); + } + + // visit the last dimension, mul is not needed + auto exp_val = any_to_Value(visitExp(exp_list.back())); + auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb); + offset = inst_add; // finally, we get the offset + pointed_type = std::dynamic_pointer_cast(ptr->type)->pointed_type; + if (TypeHelper::isIntegerType(pointed_type)) { + // return the address of the array element + auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb); + return arr_elem_ptr; + } + else { + panic("Should be int"); + } } } - else { - panic("To be implemented"); + case Type::TypeTag::ArrayType: { + sysy_assert(!ctx->exp().empty()); + // get &array[0] + auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb); + auto pointed_type = std::dynamic_pointer_cast(ptr->type)->pointed_type; + ValuePtr_t offset = ConstantInt::make_shared(0); + auto exp_list = ctx->exp(); + // calculate offset by hand: offset = (offset + exp[i]) * dim_size[i] + for (int i = 0; i < exp_list.size() - 1; ++i) { + sysy_assert(typeid(pointed_type) == typeid(std::shared_ptr)); + auto array_type = std::dynamic_pointer_cast(pointed_type); + auto exp_val = any_to_Value(visitExp(exp_list[i])); + auto dim_size = ConstantInt::make_shared(array_type->element_count); + auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb); + auto inst_mul = build_InstBinary(InstTag::Mul, inst_add, dim_size, _state.current_bb); + offset = inst_mul; + pointed_type = array_type->element_type; + ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb); + } + auto exp_val = any_to_Value(visitExp(exp_list.back())); + auto inst_add = build_InstBinary(InstTag::Add, offset, exp_val, _state.current_bb); + offset = inst_add; // finally, we get the offset + pointed_type = std::dynamic_pointer_cast(ptr->type)->pointed_type; + if (TypeHelper::isIntegerType(pointed_type)) { + // return the address of the array element + auto arr_elem_ptr = build_InstGEP(ptr, {offset}, _state.current_bb); + return arr_elem_ptr; + } + else { + panic("Should be int"); + } + } + default: + panic("Unreachable"); } } panic("Unreachable"); @@ -494,7 +752,7 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) { if (ctx->funcFParams()) { visitFuncFParams(ctx->funcFParams()); } - visit(ctx->block()); + visitBlock(ctx->block()); // add return // _scope_tab.leave_scope(); // TODO: avoid duplicate ret @@ -507,36 +765,47 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) { return {}; } +// @retval: any +// Directly add to function, rather than return something... std::any Visitor::visitFuncFParams(SysyParser::FuncFParamsContext *ctx) { - for (auto fparam : ctx->funcFParam()) { - auto fparam_type = std::any_cast(visit(fparam)); - auto fparam_name = fparam->getText(); - auto fparam_ptr = std::make_shared(fparam_name, fparam_type); - _state.current_func->fparam_list.push_back(fparam_ptr); - if (fparam->LBRACKET().empty()) { - auto alloca = build_InstAlloca(TypeHelper::TYPE_I32, false, _state.current_bb); - auto store = build_InstStore(fparam_ptr, alloca, _state.current_bb); - _scope_tab.push_name(fparam_name, alloca); - _state.current_func->fparam_list.push_back(fparam_ptr); - } - else { - panic("To be implemented"); - } + for (auto fparam_ctx : ctx->funcFParam()) { + auto fparam_type = std::any_cast(visitFuncFParam(fparam_ctx)); + auto fparam_name = fparam_ctx->getText(); + auto fparam = std::make_shared(fparam_name, fparam_type); + _state.current_func->fparam_list.push_back(fparam); + auto alloca_ = build_InstAlloca(fparam_type, _state.current_bb); + build_InstStore(fparam, alloca_, _state.current_bb); + _scope_tab.push_name(fparam_name, alloca_); + _state.current_func->fparam_list.push_back(fparam); } return {}; } +// funcFParam: bType IDENT ('[' ']' ('[' exp ']')*)?; std::any Visitor::visitFuncFParam(SysyParser::FuncFParamContext *ctx) { if (ctx->LBRACKET().empty()) { + // int type return {TypeHelper::TYPE_I32}; } - panic("To be implemented"); + else { + // array type + std::vector dim_list; // the first dim must be empty, though + for (auto exp_ctx : ctx->exp()) { + _state.isConstInt = true; + auto exp_val = std::dynamic_pointer_cast(any_to_Value(visitExp(exp_ctx))); + _state.isConstInt = false; + dim_list.push_back(exp_val->value); + } + auto array_type = ArrayType::build_from_list(dim_list); + auto true_array_type = std::make_shared(array_type); + return {true_array_type}; + } } std::any Visitor::visitBlock(SysyParser::BlockContext *ctx) { _scope_tab.enter_scope(); for (auto block_item : ctx->blockItem()) { - visit(block_item); + visitBlockItem(block_item); } _scope_tab.leave_scope(); return {}; @@ -556,8 +825,8 @@ stmt: lVal '=' exp ';' # assignStmt */ std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) { - auto lval = any_to_Value(visit(ctx->lVal())); - auto rhs = any_to_Value(visit(ctx->exp())); + auto lval = any_to_Value(visitLVal(ctx->lVal())); + auto rhs = any_to_Value(visitExp(ctx->exp())); auto store = build_InstStore(rhs, lval, _state.current_bb); return {}; }