diff --git a/.clang-format b/.clang-format index 7f98392..3ef109f 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,4 @@ +# https://releases.llvm.org/15.0.0/tools/clang/docs/ClangFormatStyleOptions.html --- Language: Cpp BasedOnStyle: LLVM @@ -21,8 +22,8 @@ AllowShortLoopsOnASingleLine: true AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: true -BinPackParameters: true +BinPackArguments: false +BinPackParameters: false BraceWrapping: AfterCaseLabel: false AfterClass: false @@ -87,13 +88,13 @@ MaxEmptyLinesToKeep: 1 NamespaceIndentation: None PackConstructorInitializers: NextLine PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakBeforeFirstCallParameter: 15 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyExcessCharacter: 10000 +PenaltyReturnTypeOnItsOwnLine: 100000 PointerAlignment: Right ReflowComments: true SortIncludes: true diff --git a/.vscode/launch.json b/.vscode/launch.json index 2320521..bb7292e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "request": "launch", "name": "Debug", "program": "${workspaceFolder}/build/sysy", - "args": ["testcases/functional/55_sort_test1.sy", "-S", "-o", "sss"], + "args": ["build/ManualTest/a.c", "-S", "-o", "sss"], "cwd": "${workspaceFolder}" } ] diff --git a/include/common.h b/include/common.h index 94a26de..a8c9156 100644 --- a/include/common.h +++ b/include/common.h @@ -1,6 +1,5 @@ #pragma once #include "3rdparty/easylogging++.h" - #include #include #include @@ -14,8 +13,7 @@ #define sysy_assert(cond) \ do { \ - if (!(cond)) \ - throw GrammarException(__FILE__, __LINE__, #cond); \ + if (!(cond)) throw GrammarException(__FILE__, __LINE__, #cond); \ } while (0) namespace antlrSysY { diff --git a/include/llir_instruction.h b/include/llir_instruction.h index 5983234..331fd54 100644 --- a/include/llir_instruction.h +++ b/include/llir_instruction.h @@ -1,5 +1,10 @@ #pragma once +#include "common.h" +#include "llir_type.h" #include "llir_value.h" +#include +#include +#include namespace antlrSysY { enum class InstTag { @@ -33,65 +38,40 @@ enum class InstTag { class Instruction : public Value { public: + int ir_seqno = -1; InstTag tag; std::shared_ptr parent_bb; std::vector> operand_list; Instruction(InstTag inst_tag, TypePtr_t type, std::shared_ptr parent_bb) - : Value("", type), tag(inst_tag), parent_bb(parent_bb) {} + : Value("", type), tag(inst_tag), parent_bb(parent_bb) {} virtual std::string to_string() override { switch (tag) { - case InstTag::Add: - return "Add"; - case InstTag::Sub: - return "Sub"; - case InstTag::Mod: - return "Mod"; - case InstTag::Mul: - return "Mul"; - case InstTag::Div: - return "Div"; - case InstTag::Lt: - return "Lt"; - case InstTag::Le: - return "Le"; - case InstTag::Ge: - return "Ge"; - case InstTag::Gt: - return "Gt"; - case InstTag::Eq: - return "Eq"; - case InstTag::Ne: - return "Ne"; - case InstTag::And: - return "And"; - case InstTag::Or: - return "Or"; - case InstTag::Br: - return "Br"; - case InstTag::Call: - return "Call"; - case InstTag::Ret: - return "Ret"; - case InstTag::Alloca: - return "Alloca"; - case InstTag::Load: - return "Load"; - case InstTag::Store: - return "Store"; - case InstTag::GEP: - return "GEP"; - case InstTag::Zext: - return "Zext"; - case InstTag::Phi: - return "Phi"; - case InstTag::MemPhi: - return "MemPhi"; - case InstTag::LoadDep: - return "LoadDep"; - case InstTag::InsertEle: - return "InsertEle"; - case InstTag::ExtractEle: - return "ExtractEle"; + case InstTag::Add: return "add"; + case InstTag::Sub: return "sub"; + case InstTag::Mod: return "srem"; + case InstTag::Mul: return "mul"; + case InstTag::Div: return "sdiv"; + case InstTag::Lt: return "icmp slt"; + case InstTag::Le: return "icmp sle"; + case InstTag::Ge: return "icmp sge"; + case InstTag::Gt: return "icmp sgt"; + case InstTag::Eq: return "icmp eq"; + case InstTag::Ne: return "icmp ne"; + case InstTag::And: return "and"; + case InstTag::Or: return "or"; + case InstTag::Br: return "br"; + case InstTag::Call: return "call"; + case InstTag::Ret: return "ret"; + case InstTag::Alloca: return "alloca"; + case InstTag::Load: return "load"; + case InstTag::Store: return "store"; + case InstTag::GEP: return "GEP"; + case InstTag::Zext: return "zext"; + case InstTag::Phi: return "Phi"; + case InstTag::MemPhi: return "MemPhi"; + case InstTag::LoadDep: return "LoadDep"; + case InstTag::InsertEle: return "InsertEle"; + case InstTag::ExtractEle: return "ExtractEle"; } } }; @@ -99,13 +79,17 @@ public: class InstAlloca : public Instruction { public: InstAlloca(TypePtr_t alloc_type, std::shared_ptr parent_bb) - : Instruction(InstTag::Alloca, std::make_shared(alloc_type), parent_bb) {} + : Instruction(InstTag::Alloca, std::make_shared(alloc_type), parent_bb) {} + virtual std::string to_IR_string() override { + std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); + return str; + } }; class InstStore : public Instruction { public: InstStore(std::shared_ptr value, std::shared_ptr pointer, std::shared_ptr parent_bb) - : Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) { + : Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) { operand_list.push_back(value); operand_list.push_back(pointer); } @@ -114,41 +98,60 @@ public: class InstLoad : public Instruction { public: InstLoad(std::shared_ptr value, TypePtr_t type, std::shared_ptr parent_bb) - : Instruction(InstTag::Load, type, parent_bb) { + : Instruction(InstTag::Load, type, parent_bb) { operand_list.push_back(value); } + virtual std::string to_IR_string() override { + std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); + return str; + } }; class InstBinary : public Instruction { public: - InstBinary(InstTag inst_tag, TypePtr_t val_type, std::shared_ptr op1, std::shared_ptr op2, - std::shared_ptr parent_bb) - : Instruction(inst_tag, val_type, parent_bb) { + InstBinary( + InstTag inst_tag, + TypePtr_t val_type, + std::shared_ptr op1, + std::shared_ptr op2, + std::shared_ptr parent_bb + ) + : Instruction(inst_tag, val_type, parent_bb) { operand_list.push_back(op1); operand_list.push_back(op2); } + virtual std::string to_IR_string() override { + std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); + return str; + } }; +// = zext to +// zext is integer type, i32 class InstZext : public Instruction { public: InstZext(std::shared_ptr op, std::shared_ptr parent_bb) - : Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) { + : Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) { operand_list.push_back(op); } + virtual std::string to_IR_string() override { + std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); + return str; + } }; class InstBranch : public Instruction { public: // conditional branch InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb) - : Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) { + : Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) { this->operand_list.push_back(cond); this->operand_list.push_back(true_block); this->operand_list.push_back(false_block); } // unconditional branch InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb) - : Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) { + : Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) { this->operand_list.push_back(target_block); } }; @@ -156,19 +159,27 @@ public: class InstReturn : public Instruction { public: InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb) - : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) { + : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) { this->operand_list.push_back(ret_val); } InstReturn(BasicBlockPtr_t parent_bb) : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {} }; +// call's type is the function's return type class InstCall : public Instruction { public: InstCall(FunctionPtr_t func, const std::vector &args, BasicBlockPtr_t parent_bb) - : Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) { + : Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) { operand_list.push_back(func); operand_list.insert(operand_list.end(), args.begin(), args.end()); } + virtual std::string to_IR_string() override { + if (Type::isType(type)) { + panic("No ret val"); + } + std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); + return str; + } }; // getelementptr , ptr {, [inrange] }* @@ -179,11 +190,11 @@ 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 (Value::isType(pointer)) { + : Instruction(InstTag::GEP, std::make_shared(extract_type(pointer, indices)), parent_bb) { + if (Value::isValueType(pointer)) { aim_to = std::dynamic_pointer_cast(pointer)->aim_to; } - else if (Value::isType(pointer) || Value::isType(pointer)){ + else if (Value::isValueType(pointer) || Value::isValueType(pointer)) { aim_to = pointer; } else { @@ -195,6 +206,11 @@ public: operand_list.insert(operand_list.end(), indices.begin(), indices.end()); } + virtual std::string to_IR_string() override { + std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); + return str; + } + // get the inner static TypePtr_t extract_type(ValuePtr_t pointer, const std::vector &indices) { auto pointer_type = std::dynamic_pointer_cast(pointer->type); @@ -215,4 +231,4 @@ public: } }; -} \ No newline at end of file +} // namespace antlrSysY \ No newline at end of file diff --git a/include/llir_module.h b/include/llir_module.h index f8a9f3d..9a45138 100644 --- a/include/llir_module.h +++ b/include/llir_module.h @@ -1,7 +1,7 @@ #pragma once +#include "llir_instruction.h" #include "llir_type.h" #include "llir_value.h" -#include "llir_instruction.h" #include #include @@ -11,4 +11,4 @@ struct Module { std::vector> global_var_list; std::vector> instruction_list; }; -} \ No newline at end of file +} // namespace antlrSysY \ No newline at end of file diff --git a/include/llir_type.h b/include/llir_type.h index ee15283..5a3b446 100644 --- a/include/llir_type.h +++ b/include/llir_type.h @@ -22,22 +22,29 @@ public: virtual ~Type() = default; virtual std::string to_string() { switch (type_tag) { - case TypeTag::IntegerType: - return "IntegerType"; - case TypeTag::FunctionType: - return "FunctionType"; - case TypeTag::ArrayType: - return "ArrayType"; - case TypeTag::PointerType: - return "PointerType"; - case TypeTag::VectorType: - return "VectorType"; - case TypeTag::VoidType: - return "VoidType"; - case TypeTag::LabelType: - return "LabelType"; + case TypeTag::IntegerType: return "IntegerType"; + case TypeTag::FunctionType: return "FunctionType"; + case TypeTag::ArrayType: return "ArrayType"; + case TypeTag::PointerType: return "PointerType"; + case TypeTag::VectorType: return "VectorType"; + case TypeTag::VoidType: return "VoidType"; + case TypeTag::LabelType: return "LabelType"; } } + template + static bool isType(std::shared_ptr ptr) { + if (ptr) { + return dynamic_cast(ptr.get()) != nullptr; + } + else { + return false; + } + } + template + static std::shared_ptr asType(std::shared_ptr ptr) { + return std::dynamic_pointer_cast(ptr); + } + virtual std::string to_IR_string() = 0; }; class IntegerType : public Type { @@ -51,16 +58,28 @@ public: bool isI1() { return int_type == IntTypes::I1; } + virtual std::string to_IR_string() override { + if (isI1()) + return "i1"; + else + return "i32"; + } }; class VoidType : public Type { public: VoidType() : Type(TypeTag::VoidType) {} + virtual std::string to_IR_string() override { + return "void"; + } }; class LabelType : public Type { public: LabelType() : Type(TypeTag::LabelType) {} + virtual std::string to_IR_string() override { + panic("Cannot generate LabelType"); + } }; typedef std::shared_ptr TypePtr_t; @@ -76,19 +95,19 @@ public: static bool isIntegerTypeI1(TypePtr_t &type) { return isIntegerType(type) && std::dynamic_pointer_cast(type)->isI1(); } - inline static TypePtr_t TYPE_I32 = std::make_shared(); - inline static TypePtr_t TYPE_I1 = std::make_shared(IntegerType::IntTypes::I1); + inline static TypePtr_t TYPE_I32 = std::make_shared(); + inline static TypePtr_t TYPE_I1 = std::make_shared(IntegerType::IntTypes::I1); inline static TypePtr_t TYPE_LABEL = std::make_shared(); - inline static TypePtr_t TYPE_VOID = std::make_shared(); + inline static TypePtr_t TYPE_VOID = std::make_shared(); }; class ArrayType : public Type { public: TypePtr_t element_type = TypeHelper::TYPE_I32; - int element_count = 0; + int element_count = 0; ArrayType() : Type(TypeTag::ArrayType) {} ArrayType(TypePtr_t element_type, int element_count) - : Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {} + : 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); @@ -100,6 +119,9 @@ public: virtual std::string to_string() override { return "Array[" + std::to_string(element_count) + " x " + element_type->to_string() + "]"; } + virtual std::string to_IR_string() override { + return "[" + std::to_string(element_count) + " x " + element_type->to_IR_string() + "]"; + } }; class PointerType : public Type { @@ -113,6 +135,12 @@ public: virtual std::string to_string() override { return "Pointer->" + pointed_type->to_string(); } + virtual std::string to_IR_string() override { + if (pointed_type->type_tag == TypeTag::IntegerType) { + return "i32*"; + } + panic("Unknown"); + } }; class FunctionType : public Type { @@ -121,7 +149,10 @@ public: std::vector params_type; FunctionType(TypePtr_t return_type) : Type(TypeTag::FunctionType), return_type(return_type) {} FunctionType(TypePtr_t return_type, const std::vector ¶ms_type) - : Type(TypeTag::FunctionType), return_type(return_type), params_type(params_type) {} + : Type(TypeTag::FunctionType), return_type(return_type), params_type(params_type) {} + virtual std::string to_IR_string() override { + panic("Cannot generate FunctionType"); + } }; } // namespace antlrSysY \ No newline at end of file diff --git a/include/llir_value.h b/include/llir_value.h index 694f44f..ecba172 100644 --- a/include/llir_value.h +++ b/include/llir_value.h @@ -1,13 +1,13 @@ #pragma once -#include -#include -#include -#include - #include "3rdparty/easylogging++.h" #include "common.h" #include "llir_type.h" +#include +#include +#include +#include +#include namespace antlrSysY { @@ -17,17 +17,31 @@ public: TypePtr_t type; Value(const std::string &name, TypePtr_t type) : name(name), type(type) {} virtual ~Value() = default; - template static bool isType(std::shared_ptr ptr) { + + template + static bool isValueType(std::shared_ptr ptr) { if (ptr.get()) { - auto &r = *ptr.get(); - return typeid(r) == typeid(TT); + // auto &r = *ptr.get(); + // return typeid(r) == typeid(TT); + return dynamic_cast(ptr.get()) != nullptr; } LOG(WARNING) << "Comparing with nullptr"; return false; } + + // it is caller's duty to check before use `asType` + template + static std::shared_ptr asValueType(std::shared_ptr ptr) { + return std::dynamic_pointer_cast(ptr); + } + virtual std::string to_string() { return name + ": " + type->to_string(); } + + virtual std::string to_IR_string() { + panic("No applicable for IR gen"); + } }; class User : public Value { @@ -39,13 +53,16 @@ class Instruction; class FParam : public Value { public: + int ir_seqno = -1; FParam(const std::string &name, TypePtr_t type) : Value(name, type) {} }; +typedef std::list>::iterator BasicBlockListNode_t; + class Function : public Value { public: std::vector> fparam_list; - std::vector> bb_list; + std::list> bb_list; // we use empty basic_block to represent lib function Function(const std::string &name, TypePtr_t ret_type) : Value(name, std::make_shared(ret_type)) {} std::shared_ptr get_type() { @@ -65,8 +82,10 @@ public: class BasicBlock : public Value { public: + int ir_seqno = -1; std::vector> inst_list; std::shared_ptr parent; + BasicBlockListNode_t itr; std::vector> successors; std::vector> predecessors; BasicBlock(const std::string &name, std::shared_ptr parent) : Value(name, TypeHelper::TYPE_LABEL) { @@ -90,17 +109,45 @@ public: static std::shared_ptr make_shared(int value) { return std::make_shared("", value); } + virtual std::string to_string() override { + std::string str = type->to_string() + " " + std::to_string(value); + return str; + } + virtual std::string to_IR_string() override { + return to_string(); + } }; 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) { + : Constant(name, type), value_list(value_list) {} + + int real_size() const { + return std::dynamic_pointer_cast(type)->element_count; + } + 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); } + virtual std::string to_string() override { + std::string str = "{"; + for (auto elem : value_list) { + if (elem) + str += elem->to_string() + ", "; + else + str += "{...}, "; + } + if (real_size() > value_list.size()) { + str += std::to_string(real_size() - value_list.size()) + " zeros"; + } + str += "}"; + return str; + } }; typedef std::shared_ptr ConstantPtr_t; @@ -111,10 +158,21 @@ public: ConstantPtr_t init_value; bool is_const; GlobalVar(const std::string &name, ConstantPtr_t init_value, bool is_const) - : Value(name, PointerType::make_shared(init_value->type)), init_value(init_value), is_const(is_const) {} + : Value(name, PointerType::make_shared(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); } + virtual std::string to_IR_string() override { + std::string str = type->to_IR_string() + " @" + name; + return str; + } }; +std::shared_ptr gen_arr_hierarchy( + const std::shared_ptr array_type, + const std::vector &const_array, + int base, + int length +); + } // namespace antlrSysY \ No newline at end of file diff --git a/include/scopetable.h b/include/scopetable.h index 9080276..b19e652 100644 --- a/include/scopetable.h +++ b/include/scopetable.h @@ -2,8 +2,8 @@ #include "common.h" namespace antlrSysY { -template class ScopeTable { - +template +class ScopeTable { typedef std::map ScopeTableEntry_t; private: @@ -23,22 +23,19 @@ public: sysy_assert(!pre_enter); return; } - if (pre_enter) - _pre_enter = true; + if (pre_enter) _pre_enter = true; _scope_list.push_back(ScopeTableEntry_t()); }; void leave_scope() { - if (_scope_list.size() <= 1) - throw GrammarException("Unable to leave global scope"); + if (_scope_list.size() <= 1) throw GrammarException("Unable to leave global scope"); _scope_list.pop_back(); }; void push_name(const std::string &name, const T_V &value) { auto ¤t_scope = _scope_list.back(); - if (current_scope.count(name)) - throw GrammarException("Duplicate name in current scope"); + if (current_scope.count(name)) throw GrammarException("Duplicate name in current scope"); current_scope[name] = value; }; diff --git a/include/visitor.h b/include/visitor.h index 9738097..fc56aea 100644 --- a/include/visitor.h +++ b/include/visitor.h @@ -1,45 +1,63 @@ #pragma once #include "3rdparty/easylogging++.h" #include "antlrgen/SysyBaseVisitor.h" - +#include "antlrgen/SysyLexer.h" +#include "antlrgen/SysyParser.h" +#include "common.h" +#include "llir_instruction.h" +#include "llir_module.h" +#include "llir_type.h" +#include "llir_value.h" +#include "scopetable.h" #include #include #include #include #include +#include #include #include -#include "antlrgen/SysyLexer.h" -#include "antlrgen/SysyParser.h" -#include "common.h" -#include "llir_module.h" -#include "llir_type.h" -#include "llir_value.h" -#include "llir_instruction.h" -#include "scopetable.h" - namespace antlrSysY { #pragma region FactoryFunctionDeclaration std::shared_ptr build_ConstantInt(const std::string &name, int value); -std::shared_ptr build_BasicBlock(const std::string &name, std::shared_ptr parent); +std::shared_ptr build_BasicBlock( + const std::string &name, + std::shared_ptr parent, + const BasicBlockListNode_t &cur_bb_itr +); -std::shared_ptr build_InstLoad(std::shared_ptr value, TypePtr_t type, - std::shared_ptr parent_bb); -std::shared_ptr build_InstStore(std::shared_ptr value, std::shared_ptr pointer, - std::shared_ptr parent_bb); +std::shared_ptr build_InstLoad( + std::shared_ptr value, + TypePtr_t type, + std::shared_ptr parent_bb +); + +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, 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); +std::shared_ptr build_InstBinary( + InstTag inst_tag, + std::shared_ptr op1, + std::shared_ptr op2, + std::shared_ptr parent_bb +); std::shared_ptr build_InstZext(std::shared_ptr op, std::shared_ptr parent_bb); -std::shared_ptr build_InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, - BasicBlockPtr_t parent_bb); +std::shared_ptr build_InstBranch( + ValuePtr_t cond, + BasicBlockPtr_t true_block, + BasicBlockPtr_t false_block, + BasicBlockPtr_t parent_bb +); std::shared_ptr build_InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb); @@ -47,35 +65,42 @@ std::shared_ptr build_InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t 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); +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 isGlobalIint = false; - bool isConstInt = false; - bool isRealParam = false; - bool isCondExp = 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; + std::vector *arr_dim_list = nullptr; + int arr_dim_index = 0; struct loop_record { BasicBlockPtr_t cond, body, next; int id; }; - int loop_stmt_count = 0; + int loop_stmt_count = 0; std::vector loop_stack = {}; }; - + ScopeTable> _scope_tab; ScopeTable> _func_tab; // var can have same name as func - VisitorState _state = {}; + VisitorState _state = {}; inline static std::shared_ptr CONST0 = std::make_shared("CONST0", 0); public: @@ -159,7 +184,7 @@ public: std::any visitLOrExp(SysyParser::LOrExpContext *ctx) override; - void llir_gen(); + void llir_gen(std::ostream &); }; } // namespace antlrSysY \ No newline at end of file diff --git a/scripts/manual-compile.py b/scripts/manual-compile.py new file mode 100644 index 0000000..b59c37e --- /dev/null +++ b/scripts/manual-compile.py @@ -0,0 +1,13 @@ +import sys +import os + +assert len(sys.argv) > 2 +print("compile {}".format(sys.argv[1])) +fullpath = sys.argv[1] +libpath = sys.argv[2] +(filename, extname) = os.path.splitext(sys.argv[1]) + +os.system(f"clang -emit-llvm -S {fullpath} -o {filename}.ll -O0 -fno-builtin") +os.system(f"llc{filename}.ll -o {filename}.s") +os.system(f"as {filename}.s -o {filename}.o") +os.system(f"clang {filename}.o {libpath} -o {filename}") \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index dd8d6bd..ebd9c22 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,15 @@ -#include -#include -#include - #include "3rdparty/easylogging++.h" #include "BaseErrorListener.h" #include "Exceptions.h" #include "antlr4-runtime.h" #include "antlrgen/SysyLexer.h" #include "antlrgen/SysyParser.h" -#include <3rdparty/argparse.hpp> - #include "common.h" #include "visitor.h" +#include <3rdparty/argparse.hpp> +#include +#include +#include INITIALIZE_EASYLOGGINGPP @@ -20,10 +18,17 @@ using namespace antlr4; class AbortErrorListener : public BaseErrorListener { public: - void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, size_t charPositionInLine, - const std::string &msg, std::exception_ptr e) override { - throw ParseCancellationException("line " + std::to_string(line) + ":" + std::to_string(charPositionInLine) + " " + - msg); + void syntaxError( + Recognizer *recognizer, + Token *offendingSymbol, + size_t line, + size_t charPositionInLine, + const std::string &msg, + std::exception_ptr e + ) override { + throw ParseCancellationException( + "line " + std::to_string(line) + ":" + std::to_string(charPositionInLine) + " " + msg + ); } }; @@ -44,7 +49,7 @@ int main(int argc, const char **argv) { } auto source_file = arg_parser.get("source"); auto output_file = arg_parser.get("-o"); - auto flg_O1 = arg_parser["-O1"] == true; + auto flg_O1 = arg_parser["-O1"] == true; // std::cout << source_file << " " << output_file << " " << flg_O1 << // std::endl; #pragma endregion @@ -62,6 +67,7 @@ int main(int argc, const char **argv) { std::ifstream ifs_source_file(source_file); if (!ifs_source_file.good()) { LOG(ERROR) << "Source file " << source_file << " not found."; + return 1; } ANTLRInputStream input(ifs_source_file); SysyLexer lexer(&input); @@ -79,6 +85,13 @@ int main(int argc, const char **argv) { auto tree = parser.program(); Visitor visitor(lexer); visitor.visitProgram(tree); + auto llir_file = source_file + ".ll"; + std::ofstream ofs_llir_file(llir_file); + if (!ofs_llir_file.good()) { + LOG(ERROR) << "Failed to create/overwrite LLIR output file " << llir_file; + return 1; + } + visitor.llir_gen(ofs_llir_file); #if 0 std::cout << tree->toStringTree(&parser) << std::endl << std::endl; #endif diff --git a/src/visitor.cpp b/src/visitor.cpp index 651f930..cb55e21 100644 --- a/src/visitor.cpp +++ b/src/visitor.cpp @@ -66,10 +66,10 @@ void _sysy_starttime(int lineno); void _sysy_stoptime(int lineno); */ -Visitor::Visitor(SysyLexer&) { +Visitor::Visitor(SysyLexer &) { #pragma region RegisterLibFunc - auto fparam_i32 = std::make_shared("", TypeHelper::TYPE_I32); - auto pointer_type = std::make_shared(TypeHelper::TYPE_I32); + auto fparam_i32 = std::make_shared("", TypeHelper::TYPE_I32); + auto pointer_type = std::make_shared(TypeHelper::TYPE_I32); auto fparam_ptr_i32 = std::make_shared("", pointer_type); auto func_getint = std::make_shared("getint", TypeHelper::TYPE_I32); @@ -88,22 +88,22 @@ Visitor::Visitor(SysyLexer&) { func_putint->fparam_list.push_back(fparam_i32); _func_tab.push_name("putint", func_putint); - auto func_putch = std::make_shared("putch", TypeHelper::TYPE_VOID); + auto func_putch = std::make_shared("putch", TypeHelper::TYPE_VOID); func_putch->fparam_list = {fparam_i32}; _func_tab.push_name("putch", func_putch); - auto func_putarray = std::make_shared("putarray", TypeHelper::TYPE_VOID); + auto func_putarray = std::make_shared("putarray", TypeHelper::TYPE_VOID); func_putarray->fparam_list = {fparam_ptr_i32, fparam_i32}; _func_tab.push_name("putarray", func_putarray); // auto func_putf = std::make_shared("putf", TypeHelper::TYPE_VOID); // should not be used - auto func_starttime = std::make_shared("_sysy_starttime", TypeHelper::TYPE_VOID); + auto func_starttime = std::make_shared("_sysy_starttime", TypeHelper::TYPE_VOID); func_starttime->fparam_list = {fparam_i32}; _func_tab.push_name("starttime", func_starttime); - auto func_stoptime = std::make_shared("_sysy_stoptime", TypeHelper::TYPE_VOID); + auto func_stoptime = std::make_shared("_sysy_stoptime", TypeHelper::TYPE_VOID); func_stoptime->fparam_list = {fparam_i32}; _func_tab.push_name("stoptime", func_stoptime); @@ -142,9 +142,9 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) { 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; + _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()) { @@ -167,7 +167,7 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) { } else { // global const array - auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type); + auto const_arr = ConstantArr::make_shared("const_arr", array_value, array_type); auto global_var = GlobalVar::make_shared(const_name, const_arr, true); module.global_var_list.push_back(global_var); _scope_tab.push_name(const_name, global_var); @@ -181,8 +181,7 @@ std::any Visitor::visitConstDef(SysyParser::ConstDefContext *ctx) { std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) { auto var_name = ctx->IDENT()->getText(); VLOG(5) << "Visiting VarDef " << var_name; - if (_scope_tab.get_name(var_name, _scope_tab.get_level()).has_value()) - panic("Duplicate const def"); + 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 @@ -190,7 +189,7 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) { // global variable must be initialized, either specified or zeroed if (ctx->initVal()) { _state.isGlobalIint = true; - auto result = std::any_cast>(visitInitVal(ctx->initVal())); + auto result = std::any_cast>(visitInitVal(ctx->initVal())); _state.isGlobalIint = false; auto global_var_int = std::make_shared(var_name, result, false); module.global_var_list.push_back(global_var_int); @@ -227,9 +226,9 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) { _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; + _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); @@ -249,15 +248,15 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) { else { if (ctx->initVal()) { // first collect init value - _state.isGlobalIint = true; + _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; + _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); + auto const_arr = ConstantArr::make_shared("var_arr", array_value, array_type); + auto global_var = GlobalVar::make_shared(var_name, const_arr, false); module.global_var_list.push_back(global_var); _scope_tab.push_name(var_name, global_var); } @@ -273,17 +272,15 @@ std::any Visitor::visitVarDef(SysyParser::VarDefContext *ctx) { std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) { if (ctx->exp()) { - if (_state.isGlobalIint) - _state.isConstInt = true; + if (_state.isGlobalIint) _state.isConstInt = true; auto retval = visitExp(ctx->exp()); - if (_state.isGlobalIint) - _state.isConstInt = false; + if (_state.isGlobalIint) _state.isConstInt = false; return retval; } // Array else { sysy_assert(_state.arr_dim_list); - int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index); + 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) { @@ -294,7 +291,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) { if (_state.isGlobalIint) { auto const_value = any_to_Value(visitInitVal(init_val)); // should evaluate to const int - sysy_assert(Value::isType(const_value)); + sysy_assert(Value::isValueType(const_value)); cur_arr.push_back(const_value); } else { @@ -309,7 +306,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) { 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); + cur_arr.push_back(nullptr); } _state.arr_dim_index++; auto sub_array = std::any_cast>(visitInitVal(init_val)); @@ -319,7 +316,7 @@ std::any Visitor::visitInitVal(SysyParser::InitValContext *ctx) { } // fill up the rest for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) { - cur_arr.push_back(CONST0); + cur_arr.push_back(nullptr); } return cur_arr; } @@ -333,7 +330,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) { } else { sysy_assert(_state.arr_dim_list); - int cur_dim = _state.arr_dim_list->at(_state.arr_dim_index); + 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) { @@ -352,7 +349,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) { 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); + cur_arr.push_back(nullptr); } _state.arr_dim_index++; auto sub_array = std::any_cast>(visitConstInitVal(init_val)); @@ -362,7 +359,7 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) { } // fill up the rest for (int i = cur_arr.size(); i < cur_dim * elem_size; ++i) { - cur_arr.push_back(CONST0); + cur_arr.push_back(nullptr); } return cur_arr; } @@ -370,10 +367,9 @@ std::any Visitor::visitConstInitVal(SysyParser::ConstInitValContext *ctx) { // @retval: int std::any Visitor::visitConstExp(SysyParser::ConstExpContext *ctx) { - if (ctx->addExp() == nullptr) - panic("Unreachable"); + if (ctx->addExp() == nullptr) panic("Unreachable"); _state.isConstInt = true; - auto result = std::any_cast>(visitAddExp(ctx->addExp())); + auto result = std::any_cast>(visitAddExp(ctx->addExp())); _state.isConstInt = false; VLOG(5) << "ConstExp Eval to " << result->value; return {result}; @@ -514,9 +510,9 @@ std::any Visitor::visitEqExp(SysyParser::EqExpContext *ctx) { std::any Visitor::visitLAndExp(SysyParser::LAndExpContext *ctx) { auto eq_exp_list = ctx->eqExp(); for (int i = 0; i < eq_exp_list.size(); ++i) { - auto next_block = build_BasicBlock("", _state.current_func); - auto eq_exp = any_to_Value(visitEqExp(eq_exp_list[i])); - auto condition = build_InstBinary(InstTag::Ne, eq_exp, CONST0, _state.current_bb); + auto next_block = build_BasicBlock("", _state.current_func, _state.current_bb->itr); + auto eq_exp = any_to_Value(visitEqExp(eq_exp_list[i])); + auto condition = build_InstBinary(InstTag::Ne, eq_exp, CONST0, _state.current_bb); build_InstBranch(condition, next_block, ctx->false_block, _state.current_bb); _state.current_bb = next_block; } @@ -529,17 +525,17 @@ std::any Visitor::visitLAndExp(SysyParser::LAndExpContext *ctx) { std::any Visitor::visitLOrExp(SysyParser::LOrExpContext *ctx) { VLOG(5) << "Eval to Cond(lOrExp); lineno=" << ctx->getStart()->getLine(); auto and_exp_list = ctx->lAndExp(); - auto n_and_exp = and_exp_list.size(); + auto n_and_exp = and_exp_list.size(); for (int i = 0; i < n_and_exp - 1; ++i) { - auto next_block = build_BasicBlock("", _state.current_func); - ctx->lAndExp(i)->true_block = ctx->true_block; + auto next_block = build_BasicBlock("", _state.current_func, _state.current_bb->itr); + ctx->lAndExp(i)->true_block = ctx->true_block; ctx->lAndExp(i)->false_block = next_block; visitLAndExp(and_exp_list[i]); _state.current_bb = next_block; } - ctx->lAndExp(n_and_exp - 1)->true_block = ctx->true_block; + ctx->lAndExp(n_and_exp - 1)->true_block = ctx->true_block; ctx->lAndExp(n_and_exp - 1)->false_block = ctx->false_block; - visitLAndExp(ctx->lAndExp(n_and_exp-1)); + visitLAndExp(ctx->lAndExp(n_and_exp - 1)); return {}; } @@ -575,7 +571,7 @@ std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) { } else { if (ctx->unaryExp()) { - auto _result = visitUnaryExp(ctx->unaryExp()); + auto _result = visitUnaryExp(ctx->unaryExp()); auto unary_exp = any_to_Value(_result); sysy_assert(unary_exp->type->type_tag == Type::TypeTag::IntegerType); if (std::dynamic_pointer_cast(unary_exp->type)->isI1()) { @@ -605,12 +601,12 @@ std::any Visitor::visitUnaryExp(SysyParser::UnaryExpContext *ctx) { std::vector args; // Directly parse RParams if (ctx->funcRParams()) { - auto rparams = ctx->funcRParams()->funcRParam(); + auto rparams = ctx->funcRParams()->funcRParam(); const auto &fparams = func->fparam_list; for (int i = 0; i < rparams.size(); ++i) { auto rparam = rparams[i]; auto fparam = fparams[i]; - auto exp = any_to_Value(visitExp(rparam->exp())); + auto exp = any_to_Value(visitExp(rparam->exp())); args.push_back(exp); } } @@ -654,7 +650,7 @@ std::any Visitor::visitPrimaryExp(SysyParser::PrimaryExpContext *ctx) { } else { auto child_ret = visitLVal(ctx->lVal()); - auto lval = any_to_Value(child_ret); + auto lval = any_to_Value(child_ret); // @retval: ConstantInt if (lval->type->type_tag == Type::TypeTag::IntegerType) { return lval; @@ -712,118 +708,117 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) { if (lval->type->type_tag == Type::TypeTag::PointerType) { auto ptr_type = std::dynamic_pointer_cast(lval->type); switch (ptr_type->pointed_type->type_tag) { - case Type::TypeTag::IntegerType: { - // Int - if (ctx->exp().empty()) { - // int ref - // @retval: InstAlloca - return lval; - } - else { - 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); + case Type::TypeTag::IntegerType: { + // Int + if (ctx->exp().empty()) { + // int ref + // @retval: InstAlloca + return lval; } - return gep; - } - }; - case Type::TypeTag::PointerType: { - sysy_assert(0); - if (ctx->exp().empty()) { - // ??? Pointer - // @retval: InstLoad - LOG(WARNING) << "Unexpected pointer"; - auto pointed_type = std::dynamic_pointer_cast(lval->type)->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->type)->pointed_type; - auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb); + else { + 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: { + sysy_assert(0); + if (ctx->exp().empty()) { + // ??? Pointer + // @retval: InstLoad + LOG(WARNING) << "Unexpected pointer"; + auto pointed_type = std::dynamic_pointer_cast(lval->type)->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->type)->pointed_type; + auto inst_load = build_InstLoad(lval, pointed_type, _state.current_bb); - LOG(INFO) << lval->to_string() << " " << lval->type->to_string(); - auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb); - pointed_type = std::dynamic_pointer_cast(ptr->type)->pointed_type; - LOG(INFO) << pointed_type->to_string(); - sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType); + LOG(INFO) << lval->to_string() << " " << lval->type->to_string(); + auto ptr = build_InstGEP(inst_load, {CONST0}, _state.current_bb); + pointed_type = std::dynamic_pointer_cast(ptr->type)->pointed_type; + LOG(INFO) << pointed_type->to_string(); + sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType); + 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"); + } + } + } + case Type::TypeTag::ArrayType: { + if (ctx->exp().empty()) { + // passing an array to function + auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb); + return ptr; + } + // 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(); + 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)); + sysy_assert(pointed_type->type_tag == Type::TypeTag::ArrayType); 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[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 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; + 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"); + // return the address of an sub array + auto array_type = std::dynamic_pointer_cast(pointed_type); + auto dim_size = ConstantInt::make_shared(array_type->element_count); + auto inst_mul = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb); + auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb); + return arr_elem_ptr; } } - } - case Type::TypeTag::ArrayType: { - if (ctx->exp().empty()) { - // passing an array to function - auto ptr = build_InstGEP(lval, {CONST0, CONST0}, _state.current_bb); - return ptr; - } - // 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(pointed_type->type_tag == Type::TypeTag::ArrayType); - 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 { - // return the address of an sub array - auto array_type = std::dynamic_pointer_cast(pointed_type); - auto dim_size = ConstantInt::make_shared(array_type->element_count); - auto inst_mul = build_InstBinary(InstTag::Mul, offset, dim_size, _state.current_bb); - auto arr_elem_ptr = build_InstGEP(ptr, {CONST0, offset}, _state.current_bb); - return arr_elem_ptr; - } - } - default: - panic("Unreachable"); + default: panic("Unreachable"); } } panic("Unreachable"); @@ -840,10 +835,10 @@ std::any Visitor::visitFuncDef(SysyParser::FuncDefContext *ctx) { auto func_obj = std::make_shared(func_name, func_ret_type); module.function_list.push_back(func_obj); _func_tab.push_name(func_name, func_obj); - auto basic_block = build_BasicBlock(func_name + "_ENTRY", func_obj); + auto basic_block = build_BasicBlock(func_name + "_ENTRY", func_obj, func_obj->bb_list.begin()); _scope_tab.enter_scope(true); _state.current_func = func_obj; - _state.current_bb = basic_block; + _state.current_bb = basic_block; if (ctx->funcFParams()) { visitFuncFParams(ctx->funcFParams()); } @@ -867,8 +862,8 @@ std::any Visitor::visitFuncFParams(SysyParser::FuncFParamsContext *ctx) { for (auto fparam_ctx : ctx->funcFParam()) { auto fparam_type = any_to_Type(visitFuncFParam(fparam_ctx)); auto fparam_name = fparam_ctx->IDENT()->getText(); - auto fparam = std::make_shared(fparam_name, fparam_type); - auto alloca_ = build_InstAlloca(fparam_type, _state.current_bb); + auto fparam = std::make_shared(fparam_name, fparam_type); + 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); @@ -887,7 +882,7 @@ std::any Visitor::visitFuncFParam(SysyParser::FuncFParamContext *ctx) { std::vector dim_list = {0}; // 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))); + auto exp_val = std::dynamic_pointer_cast(any_to_Value(visitExp(exp_ctx))); _state.isConstInt = false; dim_list.push_back(exp_val->value); } @@ -921,8 +916,8 @@ stmt: lVal '=' exp ';' # assignStmt */ std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) { - auto lval = any_to_Value(visitLVal(ctx->lVal())); - auto rhs = any_to_Value(visitExp(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 {}; } @@ -930,14 +925,14 @@ std::any Visitor::visitAssignStmt(SysyParser::AssignStmtContext *ctx) { // TODO: Remove RETURN in else stmt std::any Visitor::visitIfStmt(SysyParser::IfStmtContext *ctx) { VLOG(5) << "Visiting IfStmt " - << "; lineno=" << ctx->getStart()->getLine(); - auto true_block = build_BasicBlock("_then", _state.current_func); - auto next_block = build_BasicBlock("_next", _state.current_func); + << "; lineno=" << ctx->getStart()->getLine(); + auto true_block = build_BasicBlock("_then", _state.current_func, _state.current_bb->itr); + auto next_block = build_BasicBlock("_next", _state.current_func, true_block->itr); auto false_block = next_block; if (ctx->ELSE()) { - false_block = build_BasicBlock("_else", _state.current_func); + false_block = build_BasicBlock("_else", _state.current_func, true_block->itr); } - ctx->cond()->lOrExp()->true_block = true_block; + ctx->cond()->lOrExp()->true_block = true_block; ctx->cond()->lOrExp()->false_block = false_block; visitCond(ctx->cond()); @@ -956,17 +951,17 @@ std::any Visitor::visitIfStmt(SysyParser::IfStmtContext *ctx) { // TODO: backpatching? I am not sure whether it is necessary std::any Visitor::visitWhileStmt(SysyParser::WhileStmtContext *ctx) { VLOG(5) << "Visiting WhileStmt " - << "; lineno=" << ctx->getStart()->getLine(); - auto while_id = std::to_string(_state.loop_stmt_count); - auto cond_block = build_BasicBlock("_loop_cond_" + while_id, _state.current_func); - auto body_block = build_BasicBlock("_loop_body_" + while_id, _state.current_func); - auto next_block = build_BasicBlock("_loop_exit_" + while_id, _state.current_func); + << "; lineno=" << ctx->getStart()->getLine(); + auto while_id = std::to_string(_state.loop_stmt_count); + auto cond_block = build_BasicBlock("_loop_cond_" + while_id, _state.current_func, _state.current_bb->itr); + auto body_block = build_BasicBlock("_loop_body_" + while_id, _state.current_func, cond_block->itr); + auto next_block = build_BasicBlock("_loop_exit_" + while_id, _state.current_func, body_block->itr); build_InstBranch(cond_block, _state.current_bb); _state.loop_stack.push_back({cond_block, body_block, next_block, _state.loop_stmt_count++}); // condition - ctx->cond()->lOrExp()->true_block = body_block; + ctx->cond()->lOrExp()->true_block = body_block; ctx->cond()->lOrExp()->false_block = next_block; - _state.current_bb = cond_block; + _state.current_bb = cond_block; visitCond(ctx->cond()); // body _state.current_bb = body_block; @@ -981,14 +976,14 @@ std::any Visitor::visitWhileStmt(SysyParser::WhileStmtContext *ctx) { std::any Visitor::visitBreakStmt(SysyParser::BreakStmtContext *ctx) { sysy_assert(!_state.loop_stack.empty()); build_InstBranch(_state.loop_stack.back().next, _state.current_bb); - _state.current_bb = build_BasicBlock("_after_break", _state.current_func); + _state.current_bb = build_BasicBlock("_after_break", _state.current_func, _state.current_bb->itr); return {}; } std::any Visitor::visitContinueStmt(SysyParser::ContinueStmtContext *ctx) { sysy_assert(!_state.loop_stack.empty()); build_InstBranch(_state.loop_stack.back().cond, _state.current_bb); - _state.current_bb = build_BasicBlock("_after_continue", _state.current_func); + _state.current_bb = build_BasicBlock("_after_continue", _state.current_func, _state.current_bb->itr); return {}; } diff --git a/src/visitor_factory.cpp b/src/visitor_factory.cpp index d78da0e..7ba0d1d 100644 --- a/src/visitor_factory.cpp +++ b/src/visitor_factory.cpp @@ -11,34 +11,50 @@ std::shared_ptr build_ConstantInt(const std::string &name, int valu return lala; } -std::shared_ptr build_BasicBlock(const std::string &name, std::shared_ptr parent) { +std::shared_ptr build_BasicBlock( + const std::string &name, + std::shared_ptr parent, + const BasicBlockListNode_t &cur_bb_itr +) { auto basic_block = std::make_shared(name, parent); - parent->bb_list.push_back(basic_block); + basic_block->itr = parent->bb_list.insert(std::next(cur_bb_itr), basic_block); return basic_block; } -std::shared_ptr build_InstLoad(std::shared_ptr value, TypePtr_t type, - std::shared_ptr parent_bb) { +std::shared_ptr build_InstLoad( + std::shared_ptr value, + TypePtr_t type, + std::shared_ptr parent_bb +) { auto inst_load = std::make_shared(value, type, parent_bb); parent_bb->inst_list.push_back(inst_load); return inst_load; } -std::shared_ptr build_InstStore(std::shared_ptr value, std::shared_ptr pointer, - std::shared_ptr parent_bb) { +std::shared_ptr build_InstStore( + std::shared_ptr value, + std::shared_ptr pointer, + std::shared_ptr parent_bb +) { auto inst_store = std::make_shared(value, pointer, parent_bb); parent_bb->inst_list.push_back(inst_store); return inst_store; } +// a little bit different, we put all alloca in the head of each basic block 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); + parent_bb->inst_list.insert(parent_bb->inst_list.begin(), inst_alloca); + // parent_bb->inst_list.push_back(inst_alloca); return inst_alloca; } -std::shared_ptr build_InstBinary(InstTag inst_tag, std::shared_ptr op1, std::shared_ptr op2, - 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 +) { std::shared_ptr inst_binary; if (InstTag::Lt <= inst_tag && inst_tag <= InstTag::Or) { inst_binary = std::make_shared(inst_tag, TypeHelper::TYPE_I1, op1, op2, parent_bb); @@ -59,8 +75,12 @@ std::shared_ptr build_InstZext(std::shared_ptr op, std::shared_ return inst_zext; } -std::shared_ptr build_InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, - BasicBlockPtr_t parent_bb) { +std::shared_ptr build_InstBranch( + ValuePtr_t cond, + BasicBlockPtr_t true_block, + BasicBlockPtr_t false_block, + BasicBlockPtr_t parent_bb +) { auto inst = std::make_shared(cond, true_block, false_block, parent_bb); parent_bb->inst_list.push_back(inst); return inst; @@ -84,15 +104,21 @@ std::shared_ptr build_InstReturn(BasicBlockPtr_t parent_bb) { return inst; } -std::shared_ptr build_InstCall(FunctionPtr_t func, const std::vector &args, - BasicBlockPtr_t parent_bb) { +std::shared_ptr build_InstCall( + FunctionPtr_t func, + const std::vector &args, + BasicBlockPtr_t parent_bb +) { auto inst = std::make_shared(func, args, parent_bb); parent_bb->inst_list.push_back(inst); return inst; } -std::shared_ptr build_InstGEP(ValuePtr_t pointer, const std::vector &indices, - BasicBlockPtr_t parent_bb) { +std::shared_ptr 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; diff --git a/src/visitor_llir_gen.cpp b/src/visitor_llir_gen.cpp index ca40525..ca1cb94 100644 --- a/src/visitor_llir_gen.cpp +++ b/src/visitor_llir_gen.cpp @@ -1,9 +1,481 @@ +#include "3rdparty/easylogging++.h" +#include "common.h" +#include "llir_instruction.h" +#include "llir_type.h" +#include "llir_value.h" #include "visitor.h" +#include +#include +#include +#include +#include +#include namespace antlrSysY { -void Visitor::llir_gen() { - +const std::array libfunc_list = + {"getint", "getch", "getarray", "putint", "putch", "putarray", "starttime", "stoptime"}; + +// On generation, the array is flattened, thus we have to calculate them +std::shared_ptr gen_arr_hierarchy( + const std::shared_ptr array_type, + const std::vector &const_array, + int base, + int length +) { + int dim_n = array_type->element_count; + int dim_size = length / dim_n; + std::vector value_list; + if (array_type->element_type->type_tag == Type::TypeTag::IntegerType) { + sysy_assert(dim_size == 1); + for (int i = 0; i < dim_n; ++i) { + if (const_array[base + i]) { + value_list.push_back(const_array[base + i]); + } + else { + break; + } + } + if (!value_list.empty()) + return ConstantArr::make_shared("", value_list, array_type); + else + return nullptr; + } + else { + int last_non_null = -1; + for (int i = 0; i < dim_n; ++i) { + auto sub_arr = gen_arr_hierarchy( + std::dynamic_pointer_cast(array_type->element_type), const_array, dim_size * i, dim_size + ); + value_list.push_back(sub_arr); + if (sub_arr) last_non_null = i; + } + if (last_non_null == -1) { + return nullptr; + } + else { + // if (last_non_null + 1 < value_list.size()) + value_list.erase(value_list.begin() + last_non_null + 1, value_list.end()); + return ConstantArr::make_shared("", value_list, array_type); + } + } } -} \ No newline at end of file +static void _build_arr_init_list( + std::ostream &ostr, + std::shared_ptr arr, + std::shared_ptr arr_type +) { + if (arr_type->element_type->type_tag == Type::TypeTag::IntegerType) { + ostr << arr_type->to_IR_string(); + ostr << " ["; + for (int i = 0; i < arr->value_list.size(); ++i) { + ostr << "i32 " << std::dynamic_pointer_cast(arr->value_list[i])->value; + if (i < arr->value_list.size() - 1) { + ostr << ", "; + } + } + for (int i = 0; i < arr_type->element_count - arr->value_list.size(); ++i) { + ostr << ", i32 0"; + } + ostr << "]"; + } + else { + ostr << "["; + for (int i = 0; i < arr->value_list.size(); ++i) { + if (arr->value_list[i]) + _build_arr_init_list( + ostr, + std::dynamic_pointer_cast(arr->value_list[i]), + std::dynamic_pointer_cast(arr_type->element_type) + ); + else + ostr << arr_type->element_type->to_IR_string() << " zeroinitializer"; + if (i < arr->value_list.size() - 1) { + ostr << ", "; + } + } + for (int i = 0; i < arr_type->element_count - arr->value_list.size(); ++i) { + ostr << ", " << arr_type->element_type->to_IR_string() << " zeroinitializer"; + } + ostr << "]"; + } +} + +static void _gen_blocks(const std::list &block_list, int reg_count) { + std::stringstream ostr; + // first pass, allocate sequence number + for (auto block_itr = block_list.begin(); block_itr != block_list.end(); ++block_itr) { + auto block = *block_itr; + for (int j = 0; j < block->inst_list.size(); ++j) { + auto inst = block->inst_list[j]; + sysy_assert(inst->ir_seqno == -1); // multi-alloc is error + switch (inst->tag) { + // These are not to get a seqno + case InstTag::Br: + case InstTag::Ret: + case InstTag::Store: break; + // Call's seqno is dependent on its return type + case InstTag::Call: + if (inst->type->type_tag == Type::TypeTag::IntegerType) { + inst->ir_seqno = reg_count++; + } + break; + // These should have a seqno + case InstTag::Add: + case InstTag::Sub: + case InstTag::Mod: + case InstTag::Mul: + case InstTag::Div: + case InstTag::Lt: + case InstTag::Le: + case InstTag::Ge: + case InstTag::Gt: + case InstTag::Eq: + case InstTag::Ne: + case InstTag::And: + case InstTag::Or: + case InstTag::Load: + case InstTag::GEP: + case InstTag::Alloca: + case InstTag::Zext: inst->ir_seqno = reg_count++; break; + // These should not be generated in frontend stage + default: panic("Unexpected instruction"); + } + } + sysy_assert(block->ir_seqno == -1); // multi-alloc is error + if (block_itr != block_list.begin()) { + block->ir_seqno = reg_count++; + } + } + // second pass, generate IR + for (auto block_itr = block_list.begin(); block_itr != block_list.end(); ++block_itr) { + auto block = *block_itr; + if (block_itr != block_list.begin()) { + ostr << block->ir_seqno << ":" << std::endl; + } + for (int j = 0; j < block->inst_list.size(); ++j) { + auto _inst = block->inst_list[j]; + + switch (_inst->tag) { + case InstTag::Br: { + auto inst = Value::asValueType(_inst); + assert(inst->ir_seqno == -1); + std::stringstream ostr; + ostr << "br "; + if (inst->operand_list.size() == 1) { + assert(Value::isValueType(inst->operand_list[0])); + auto bb_dest = Value::asValueType(inst->operand_list[0]); + assert(bb_dest->ir_seqno >= 0); + ostr << "label %" << bb_dest->ir_seqno; + } + else { + assert(Value::isValueType(inst->operand_list[0])); + assert(Type::isType(inst->operand_list[0]->type)); + auto cond = Value::asValueType(inst->operand_list[0]); + auto bb_true = Value::asValueType(inst->operand_list[1]); + auto bb_false = Value::asValueType(inst->operand_list[2]); + if (!Type::asType(cond->type)->isI1()) { + LOG(ERROR) << "Expect cond evals to i1: " << cond->to_string(); + panic("Grammar check"); + } + assert(cond->ir_seqno >= 0); + assert(bb_true->ir_seqno >= 0); + assert(bb_false->ir_seqno >= 0); + ostr << "i1 " << cond->ir_seqno << ", label %" << bb_true->ir_seqno << ", label %" << bb_false->ir_seqno; + } + break; + } + case InstTag::Ret: { + auto inst = Value::asValueType(_inst); + assert(inst->ir_seqno == -1); + ostr << "ret "; + if (inst->operand_list.size() == 0) { + assert(Type::isType(inst->type)); + ostr << "void"; + } + else { + if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + assert(op0->ir_seqno >= 0); + ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno; + } + else if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + ostr << op0->to_string(); + } + else { + LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string(); + assert(0); + } + } + break; + } + case InstTag::Store: { + auto inst = Value::asValueType(_inst); + assert(inst->ir_seqno == -1); + ostr << "store "; + assert(Type::isType(inst->operand_list[0]->type)); + assert(Type::isType(inst->operand_list[1]->type)); + if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + assert(op0->ir_seqno >= 0); + ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno << ", "; + } + else if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + ostr << "i32 " << op0->value << ", "; + } + else { + LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string(); + assert(0); + } + if (Value::isValueType(inst->operand_list[1])) { + auto op1 = Value::asValueType(inst->operand_list[1]); + ostr << op1->type->to_IR_string() << " @" << op1->name; + } + else if (Value::isValueType(inst->operand_list[1])) { + auto op1 = Value::asValueType(inst->operand_list[1]); + assert(op1->ir_seqno >= 0); + ostr << op1->type->to_IR_string() << " %" << op1->ir_seqno; + } + else { + LOG(ERROR) << "Unexpected type of op1: " << inst->operand_list[1]->to_string(); + assert(0); + } + break; + } + // Call's seqno is dependent on its return type + case InstTag::Call: { + auto inst = Value::asValueType(_inst); + auto func = Value::asValueType(inst->operand_list[0]); + auto func_type = Type::asType(func->type); + if (Type::isType(func_type->return_type)) { + assert(inst->ir_seqno == -1); + ostr << "call void @"; + } + else { + assert(inst->ir_seqno >= 0); + ostr << "%" << inst->ir_seqno << " = call i32 @"; + } + ostr << func->name << "("; + if (inst->operand_list.size() > 1) { + for (int i = 1; i < inst->operand_list.size(); ++i) { + if (Value::isValueType(inst->operand_list[i])) { + auto op0 = Value::asValueType(inst->operand_list[i]); + assert(op0->ir_seqno >= 0); + ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno; + } + else if (Value::isValueType(inst->operand_list[i])) { + auto op0 = Value::asValueType(inst->operand_list[i]); + ostr << op0->to_string(); + } + else { + LOG(ERROR) << "Unexpected type of op_i: " << inst->operand_list[i]->to_string(); + assert(0); + } + if (i < inst->operand_list.size() - 1) ostr << ", "; + } + } + ostr << ")"; + break; + } + // These should have a seqno + case InstTag::Add: + case InstTag::Sub: + case InstTag::Mod: + case InstTag::Mul: + case InstTag::Div: + case InstTag::Lt: + case InstTag::Le: + case InstTag::Ge: + case InstTag::Gt: + case InstTag::Eq: + case InstTag::Ne: + case InstTag::And: + case InstTag::Or: { + auto inst = Value::asValueType(_inst); + ostr << "%" << inst->ir_seqno << " = " << inst->to_string(); + if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + assert(op0->ir_seqno >= 0); + ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno << ", "; + } + else if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + ostr << op0->to_string() << ", "; + } + else { + LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string(); + assert(0); + } + if (Value::isValueType(inst->operand_list[1])) { + auto op1 = Value::asValueType(inst->operand_list[1]); + assert(op1->ir_seqno >= 0); + ostr << "%" << op1->ir_seqno; + } + else if (Value::isValueType(inst->operand_list[1])) { + auto op1 = Value::asValueType(inst->operand_list[1]); + ostr << op1->value; + } + else { + LOG(ERROR) << "Unexpected type of op1: " << inst->operand_list[1]->to_string(); + assert(0); + } + break; + } + case InstTag::Load: { + auto inst = Value::asValueType(_inst); + assert(inst->ir_seqno != -1); + assert(Type::isType(inst->operand_list[0]->type)); + ostr << "%" << inst->ir_seqno << " = load " << inst->type->to_IR_string() << ", "; + if (Value::isValueType(inst->operand_list[0])) { + auto op1 = Value::asValueType(inst->operand_list[0]); + ostr << op1->type->to_IR_string() << " @" << op1->name; + } + else if (Value::isValueType(inst->operand_list[0])) { + auto op1 = Value::asValueType(inst->operand_list[0]); + assert(op1->ir_seqno >= 0); + ostr << op1->type->to_IR_string() << " %" << op1->ir_seqno; + } + else { + LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[1]->to_string(); + assert(0); + } + break; + } + case InstTag::GEP: { + auto inst = Value::asValueType(_inst); + + assert(inst->ir_seqno >= 0); + std::stringstream ostr; + auto pointer_type = Type::asType(inst->operand_list[0]->type); + ostr << "%" << inst->ir_seqno << " = getelementptr " << pointer_type->pointed_type->to_IR_string() << ", "; + if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + ostr << op0->to_IR_string(); + } + else if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno; + } + else { + LOG(WARNING) << "Unexpected type of op0: " << inst->operand_list[0]->to_string(); + assert(0); + } + for (int i = 1; i < inst->operand_list.size(); ++i) { + ostr << ", " << inst->operand_list[i]->to_IR_string(); + } + break; + } + case InstTag::Alloca: { + auto inst = Value::asValueType(_inst); + assert(inst->ir_seqno != -1); + ostr << "%" << inst->ir_seqno << " = alloca i32, align 4"; + break; + } + case InstTag::Zext: { + auto inst = Value::asValueType(_inst); + assert(inst->ir_seqno >= 0); + std::stringstream ostr; + ostr << "%" << inst->ir_seqno << " = zext "; + if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + assert(op0->ir_seqno >= 0); + ostr << op0->type->to_IR_string() << " %" << op0->ir_seqno << ", "; + } + else if (Value::isValueType(inst->operand_list[0])) { + auto op0 = Value::asValueType(inst->operand_list[0]); + ostr << op0->to_string() << ", "; + } + else { + LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string(); + assert(0); + } + ostr << "i32"; + break; + } + // These should not be generated in frontend stage + default: panic("Unexpected instruction"); + } + } + } +} + +void Visitor::llir_gen(std::ostream &ostr) { +#pragma region GenLibFuncDecl + for (auto &lib_func_name : libfunc_list) { + LOG(DEBUG) << "Gen LibFunc " << lib_func_name; + auto lib_func = _func_tab.get_name(lib_func_name).value(); + auto lib_func_type = std::dynamic_pointer_cast(lib_func->type); + ostr << "declare" + << " " << lib_func_type->return_type->to_IR_string() << " " + << "@" << lib_func_name << "("; + auto ¶m_list = lib_func->fparam_list; + for (int i = 0; i < (int)param_list.size() - 1; ++i) { + ostr << param_list[i]->type->to_IR_string() << ", "; + } + if (param_list.size()) ostr << param_list.back()->type->to_IR_string(); + ostr << ")" << std::endl; + } + // ostr.flush(); +#pragma endregion + +#pragma region GenGlobDecl + for (auto &global_var : module.global_var_list) { + // both int and arr have the same leading part + LOG(DEBUG) << "Gen Global " << global_var->name; + ostr << "@" << global_var->name << " = " + << "dso_local" + << " " << (global_var->is_const ? "const" : "global") << " "; + auto global_var_type = std::dynamic_pointer_cast(global_var->type); + if (global_var_type->pointed_type->type_tag == Type::TypeTag::IntegerType) { + auto init_value = std::dynamic_pointer_cast(global_var->init_value); + ostr << "i32" + << " " << init_value->value << std::endl; + } + else if (global_var_type->pointed_type->type_tag == Type::TypeTag::ArrayType) { + // sysy_assert(global_var->) + auto array_type = std::dynamic_pointer_cast(global_var_type->pointed_type); + auto init_value = std::dynamic_pointer_cast(global_var->init_value); + auto hierarchy_array = gen_arr_hierarchy(array_type, init_value->value_list, 0, init_value->value_list.size()); + if (hierarchy_array) { + // LOG(DEBUG) << hierarchy_array->to_string(); + ostr << array_type->to_IR_string() << " "; + _build_arr_init_list(ostr, hierarchy_array, array_type); + } + else { + ostr << array_type->to_IR_string() << " zeroinitializer"; + } + ostr << ", align 4" << std::endl; + } + else { + LOG(ERROR) << global_var->to_string(); + panic("Invalid Global Declaration"); + } + } +#pragma endregion + +#pragma region GenFunction + for (auto &func : module.function_list) { + if (func->is_libfunc()) { + LOG(WARNING) << "Lib func"; + continue; + } + int reg_count = 0; // allocate unique register name from %0 + auto func_type = std::dynamic_pointer_cast(func->type); + ostr << "define dso_local " << func_type->return_type->to_IR_string() << " @" << func->name; + ostr << "("; + auto ¶m_list = func->fparam_list; + for (int i = 0; i < (int)param_list.size() - 1; ++i) { + ostr << param_list[i]->type->to_IR_string() << " %" << reg_count++ << ", "; + } + if (param_list.size()) ostr << param_list.back()->type->to_IR_string(); + ostr << ") {" << std::endl; + _gen_blocks(func->bb_list, reg_count); + ostr << "}" << std::endl; + } +#pragma endregion +} + +} // namespace antlrSysY \ No newline at end of file