diff --git a/Makefile b/Makefile index 313da59..036d19f 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,10 @@ build: @cd $(BUILD_DIR) && cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -Wno-dev .. @cd $(BUILD_DIR) && $(MAKE) -j4 -# 运行目标,运行生成的可执行文件 -run: +acturalrun: @cd $(BUILD_DIR) && ./zmxcc /dev/stdin -o /dev/stdout 2>/dev/null +# 运行目标,运行生成的可执行文件 +run: acturalrun @cat $(BUILTIN_ASM) >>/dev/stdout # 清理目标 diff --git a/include/IR/IR_basic.h b/include/IR/IR_basic.h index eafab9d..6de3ffd 100644 --- a/include/IR/IR_basic.h +++ b/include/IR/IR_basic.h @@ -71,9 +71,18 @@ class JMPActionItem : public ActionItem { public: std::shared_ptr corresponding_phi; }; +namespace NaiveBackend { +void ScanForVar(class FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); +void GenerateASM(std::shared_ptr act, std::vector &code_lines, FuncLayout &layout, + const std::unordered_map &low_level_class_info, bool process_phi); +} // namespace NaiveBackend class BRAction : public JMPActionItem { friend class IRBuilder; friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::string cond; std::string true_label_full; std::string false_label_full; @@ -88,6 +97,10 @@ class UNConditionJMPAction : public JMPActionItem { friend class IRBuilder; friend class FunctionDefItem; friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::string label_full; public: @@ -98,6 +111,10 @@ class RETAction : public JMPActionItem { friend class IRBuilder; friend class FunctionDefItem; friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); LLVMType type; std::string value; @@ -115,12 +132,14 @@ class RETAction : public JMPActionItem { } } }; -namespace NaiveBackend { -void ScanForVar(class FuncLayout &layout, std::shared_ptr action); -} + class BinaryOperationAction : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::string op; std::string operand1_full; std::string operand2_full; @@ -145,7 +164,7 @@ class BinaryOperationAction : public ActionItem { }; class AllocaAction : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); std::string name_full; LLVMType type; size_t num; @@ -169,7 +188,11 @@ class AllocaAction : public ActionItem { }; class LoadAction : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::string result_full; LLVMType ty; std::string ptr_full; @@ -190,7 +213,11 @@ class LoadAction : public ActionItem { }; class StoreAction : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); LLVMType ty; std::string value_full; std::string ptr_full; @@ -211,7 +238,7 @@ class StoreAction : public ActionItem { }; class GetElementPtrAction : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); std::string result_full; LLVMType ty; std::string ptr_full; @@ -239,7 +266,11 @@ class GetElementPtrAction : public ActionItem { }; class ICMPAction : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::string op; std::string operand1_full; std::string operand2_full; @@ -264,7 +295,7 @@ class BlockItem : public LLVMIRItemBase { friend class IRBuilder; friend class FunctionDefItem; friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); std::string label_full; std::vector> actions; std::shared_ptr exit_action; @@ -281,7 +312,11 @@ class BlockItem : public LLVMIRItemBase { }; class CallItem : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + NaiveBackend::FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::string result_full; LLVMType return_type; std::string func_name_raw; @@ -330,7 +365,7 @@ class CallItem : public ActionItem { class PhiItem : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); std::string result_full; LLVMType ty; std::vector> values; // (val_i_full, label_i_full) @@ -357,7 +392,7 @@ class PhiItem : public ActionItem { }; class SelectItem : public ActionItem { friend class IRBuilder; - friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action); + friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr action, const std::unordered_map &low_level_class_info); std::string result_full; std::string cond_full; std::string true_val_full; diff --git a/include/naivebackend/build_layout.hpp b/include/naivebackend/build_layout.hpp index b0d4894..cd32276 100644 --- a/include/naivebackend/build_layout.hpp +++ b/include/naivebackend/build_layout.hpp @@ -6,21 +6,8 @@ #include "tools.h" namespace NaiveBackend { -inline size_t CalcSize(const LLVMType &tp) { - if (std::holds_alternative(tp)) { - auto &int_tp = std::get(tp); - return (int_tp.bits + 7) / 8; - } else if (std::holds_alternative(tp)) { - return 4; - } else if (std::holds_alternative(tp)) { - throw std::runtime_error("Cannot calculate size of void type"); - return 0; - } else if (std::holds_alternative(tp)) { - throw std::runtime_error("Cannot calculate size of class type"); - } else - throw std::runtime_error("Unknown type"); -} -inline void ScanForVar(FuncLayout &layout, std::shared_ptr action) { +inline void ScanForVar(FuncLayout &layout, std::shared_ptr action, + const std::unordered_map &low_level_class_info) { if (std::dynamic_pointer_cast(action)) { throw std::runtime_error("JMPActionItem should not be in the layout"); } else if (auto binary_act = std::dynamic_pointer_cast(action)) { @@ -44,7 +31,19 @@ inline void ScanForVar(FuncLayout &layout, std::shared_ptr action) { if (get_element_act->result_full == "") { throw std::runtime_error("GetElementPtrAction should have a result_full"); } - layout.AllocateItem(get_element_act->result_full, CalcSize(get_element_act->ty)); + if (get_element_act->indices.size() == 1) { + layout.AllocateItem(get_element_act->result_full, CalcSize(get_element_act->ty)); + } else if (get_element_act->indices.size() == 2) { + if (get_element_act->indices[0] != "0") + throw std::runtime_error("GetElementPtrAction with non-zero base index is not supported"); + size_t element_idx = std::stoi(get_element_act->indices[1]); + auto class_ty = std::get(get_element_act->ty); + const IRClassInfo &class_info = low_level_class_info.at(class_ty.class_name_full); + size_t sz = class_info.member_var_size[element_idx]; + layout.AllocateItem(get_element_act->result_full, sz); + } else { + throw std::runtime_error("GetElementPtrAction with more than 2 indices is not supported"); + } } else if (auto icmp_act = std::dynamic_pointer_cast(action)) { if (icmp_act->result_full == "") { throw std::runtime_error("ICMPAction should have a result_full"); diff --git a/include/naivebackend/codegen.hpp b/include/naivebackend/codegen.hpp new file mode 100644 index 0000000..0f7277a --- /dev/null +++ b/include/naivebackend/codegen.hpp @@ -0,0 +1,136 @@ +#pragma once +#include +#include "naivebackend.h" +namespace NaiveBackend { +inline void GenerateASM(std::shared_ptr act, std::vector &code_lines, FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi = false) { + if (auto br_act = std::dynamic_pointer_cast(act)) { + IRVar2RISCVReg(br_act->cond, 1, "t0", layout, code_lines); + code_lines.push_back("bnez t0, .entrylabel." + br_act->true_label_full); + code_lines.push_back("j .entrylabel." + br_act->false_label_full); + } else if (auto jmp_act = std::dynamic_pointer_cast(act)) { + code_lines.push_back("j .entrylabel." + jmp_act->label_full); + } else if (auto ret_act = std::dynamic_pointer_cast(act)) { + if (!std::holds_alternative(ret_act->type)) { + size_t sz = CalcSize(ret_act->type); + IRVar2RISCVReg(ret_act->value, sz, "a0", layout, code_lines); + } + code_lines.push_back("lw ra, -4(s0)"); + code_lines.push_back("lw s0, -8(s0)"); + code_lines.push_back("addi sp, sp, " + std::to_string(layout.total_frame_size)); + code_lines.push_back("ret"); + } else if (auto binary_act = std::dynamic_pointer_cast(act)) { + size_t sz = CalcSize(binary_act->type); + IRVar2RISCVReg(binary_act->operand1_full, sz, "t0", layout, code_lines); + IRVar2RISCVReg(binary_act->operand2_full, sz, "t1", layout, code_lines); + if (binary_act->op == "add") { + code_lines.push_back("add t2, t0, t1"); + } else if (binary_act->op == "sub") { + code_lines.push_back("sub t2, t0, t1"); + } else if (binary_act->op == "mul") { + code_lines.push_back("mul t2, t0, t1"); + } else if (binary_act->op == "sdiv") { + code_lines.push_back("div t2, t0, t1"); + } else if (binary_act->op == "srem") { + code_lines.push_back("rem t2, t0, t1"); + } else if (binary_act->op == "and") { + code_lines.push_back("and t2, t0, t1"); + } else if (binary_act->op == "or") { + code_lines.push_back("or t2, t0, t1"); + } else if (binary_act->op == "xor") { + code_lines.push_back("xor t2, t0, t1"); + } else if (binary_act->op == "shl") { + code_lines.push_back("sll t2, t0, t1"); + } else if (binary_act->op == "ashr") { + code_lines.push_back("sra t2, t0, t1"); + } else { + throw std::runtime_error("Unknown binary operation"); + } + GenerateWriteAccess(binary_act->result_full, sz, "t2", layout, code_lines); + } else if (auto alloca_act = std::dynamic_pointer_cast(act)) { + // just do nothing + } else if (auto load_act = std::dynamic_pointer_cast(act)) { + size_t sz = CalcSize(load_act->ty); + IRVar2RISCVReg(load_act->ptr_full, 4, "t0", layout, code_lines); + if (sz == 1) { + code_lines.push_back("lb t1, 0(t0)"); + } else if (sz == 4) { + code_lines.push_back("lw t1, 0(t0)"); + } else { + throw std::runtime_error("Unknown bytes"); + } + GenerateWriteAccess(load_act->result_full, sz, "t1", layout, code_lines); + } else if (auto store_act = std::dynamic_pointer_cast(act)) { + size_t sz = CalcSize(store_act->ty); + IRVar2RISCVReg(store_act->ptr_full, 4, "t0", layout, code_lines); + IRVar2RISCVReg(store_act->value_full, sz, "t1", layout, code_lines); + if (sz == 1) { + code_lines.push_back("sb t1, 0(t0)"); + } else if (sz == 4) { + code_lines.push_back("sw t1, 0(t0)"); + } else { + throw std::runtime_error("Unknown bytes"); + } + } else if (auto get_element_act = std::dynamic_pointer_cast(act)) { + // TODO: implement this + } else if (auto icmp_act = std::dynamic_pointer_cast(act)) { + size_t sz = CalcSize(icmp_act->type); + IRVar2RISCVReg(icmp_act->operand1_full, sz, "t0", layout, code_lines); + IRVar2RISCVReg(icmp_act->operand2_full, sz, "t1", layout, code_lines); + if (icmp_act->op == "eq") { + code_lines.push_back("xor t2, t0, t1"); + code_lines.push_back("seqz t2, t2"); + } else if (icmp_act->op == "ne") { + code_lines.push_back("xor t2, t0, t1"); + code_lines.push_back("snez t2, t2"); + } else if (icmp_act->op == "slt") { + code_lines.push_back("slt t2, t0, t1"); + } else if (icmp_act->op == "sle") { + code_lines.push_back("slt t2, t1, t0"); + code_lines.push_back("xori t2, t2, 1"); + } else if (icmp_act->op == "sgt") { + code_lines.push_back("slt t2, t1, t0"); + } else if (icmp_act->op == "sge") { + code_lines.push_back("slt t2, t0, t1"); + code_lines.push_back("xori t2, t2, 1"); + } else { + throw std::runtime_error("Unknown icmp operation"); + } + GenerateWriteAccess(icmp_act->result_full, 1, "t2", layout, code_lines); + } else if (auto call_act = std::dynamic_pointer_cast(act)) { + size_t num_of_args = call_act->args_ty.size(); + if (call_act->args_ty.size() != call_act->args_val_full.size()) { + throw std::runtime_error("args_ty and args_full_name should have the same size"); + } + for (size_t i = 0; i < num_of_args && i < 8; i++) { + IRVar2RISCVReg(call_act->args_val_full[i], CalcSize(call_act->args_ty[i]), "a" + std::to_string(i), layout, + code_lines); + } + if (num_of_args >= 8) { + size_t ps_delta = (num_of_args * 4 + 15) / 16 * 16; + code_lines.push_back("addi sp, sp, -" + std::to_string(ps_delta)); + for (size_t i = 8; i < num_of_args; i++) { + IRVar2RISCVReg(call_act->args_val_full[i], CalcSize(call_act->args_ty[i]), "t0", layout, code_lines); + code_lines.push_back("sw t0, " + std::to_string((i - 8) * 4) + "(sp)"); + } + } + code_lines.push_back("call " + call_act->func_name_raw); + if (call_act->result_full != "") { + size_t ret_sz = CalcSize(call_act->return_type); + GenerateWriteAccess(call_act->result_full, ret_sz, "a0", layout, code_lines); + } + } else if (auto phi_act = std::dynamic_pointer_cast(act)) { + if (!process_phi) { + return; // for efficiency, phi actions are implemented as store action in the previous block + } + // TODO: implement this + // throw std::runtime_error("not implemented"); + } else if (auto select_act = std::dynamic_pointer_cast(act)) { + // TODO: implement this + // throw std::runtime_error("not implemented"); + } else { + throw std::runtime_error("Unknown action type"); + } +} +} // namespace NaiveBackend \ No newline at end of file diff --git a/include/naivebackend/naivebackend.h b/include/naivebackend/naivebackend.h index 9cc1f48..619e5f7 100644 --- a/include/naivebackend/naivebackend.h +++ b/include/naivebackend/naivebackend.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -93,8 +94,12 @@ class FuncLayout { friend void ::GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); friend void GenerateReadAccess(std::string val, size_t bytes, std::string output_reg, FuncLayout &layout, std::vector &code_lines); - friend inline void GenerateWriteAccess(std::string val, size_t bytes, std::string data_reg, FuncLayout &layout, - std::vector &code_lines); + friend void GenerateWriteAccess(std::string val, size_t bytes, std::string data_reg, FuncLayout &layout, + std::vector &code_lines); + friend void NaiveBackend::GenerateASM(std::shared_ptr act, std::vector &code_lines, + FuncLayout &layout, + const std::unordered_map &low_level_class_info, + bool process_phi); std::unordered_map local_items; std::unordered_map arg_offset; size_t cur_pos; @@ -127,7 +132,8 @@ inline void GenerateReadAccess(std::string val, size_t bytes, std::string output } size_t offset = layout.arg_offset.at(val); if (offset < 8) { - output_reg = "a" + std::to_string(offset); + std::string src_reg = "a" + std::to_string(offset); + code_lines.push_back("mv " + output_reg + ", " + src_reg); } else { size_t spilled_offset = (offset - 8) * 4; // just*4, which is different from the real riscv std::string cmd; @@ -137,7 +143,7 @@ inline void GenerateReadAccess(std::string val, size_t bytes, std::string output cmd = "lw"; else throw std::runtime_error("Unknown bytes"); - cmd += " " + output_reg + ", " + std::to_string(spilled_offset) + "(fp)"; + cmd += " " + output_reg + ", " + std::to_string(spilled_offset) + "(s0)"; code_lines.push_back(cmd); } } else if (val.size() > 13 && val.substr(0, 13) == "@.var.global.") { @@ -147,22 +153,49 @@ inline void GenerateReadAccess(std::string val, size_t bytes, std::string output } else if (val.size() > 12 && val.substr(0, 12) == "%.var.local.") { // local variable address keeper size_t offset = layout.QueryOffeset(val); - code_lines.push_back("addi " + output_reg + ", fp, -" + std::to_string(offset)); + code_lines.push_back("addi " + output_reg + ", s0, -" + std::to_string(offset)); } else if (val.size() > 10 && val.substr(0, 10) == "%.var.tmp.") { // tmp variable, not address keeper size_t offset = layout.QueryOffeset(val); - code_lines.push_back("addi " + output_reg + ", fp, -" + std::to_string(offset)); if (bytes == 1) { - code_lines.push_back("lb " + output_reg + ", 0(" + output_reg + ")"); + code_lines.push_back("lb " + output_reg + ", -" + std::to_string(offset) + "(s0)"); } else if (bytes == 4) { - code_lines.push_back("lw " + output_reg + ", 0(" + output_reg + ")"); + code_lines.push_back("lw " + output_reg + ", -" + std::to_string(offset) + "(s0)"); } else { throw std::runtime_error("Unknown bytes"); } + } else if (val.size() > 6 && val.substr(0, 6) == "@.str.") { + code_lines.push_back("la " + output_reg.substr(1, output_reg.size() - 1) + ", " + val); } else { throw std::runtime_error("Unknown variable type with name=" + val); } } +inline void StoreImmToReg(int imm, std::string reg, std::vector &code_lines) { + // if (imm >= 2048) { + // code_lines.push_back("lui " + reg + ", " + std::to_string(imm >> 12)); + // code_lines.push_back("ori " + reg + ", " + reg + ", " + std::to_string(imm & 0x7ff)); + // } else { + // code_lines.push_back("ori " + reg + ", x0, " + std::to_string(imm)); + // } + code_lines.push_back("li " + reg + ", " + std::to_string(imm)); +} +inline void IRVar2RISCVReg(std::string val, size_t bytes, std::string output_reg, FuncLayout &layout, + std::vector &code_lines) { + if (val[0] == '-') { + if (val == "-1") { + StoreImmToReg(-1, output_reg, code_lines); + return; + } + throw std::runtime_error("Negative imm in IR is not supported"); + } + if (val == "null") { + StoreImmToReg(0, output_reg, code_lines); + } else if (std::isdigit(val[0])) { + StoreImmToReg(std::stoull(val), output_reg, code_lines); + } else { + GenerateReadAccess(val, bytes, output_reg, layout, code_lines); + } +} inline void GenerateWriteAccess(std::string val, size_t bytes, std::string data_reg, FuncLayout &layout, std::vector &code_lines) { if (val.size() > 4 && val.substr(val.size() - 4, 4) == ".val") { @@ -177,11 +210,10 @@ inline void GenerateWriteAccess(std::string val, size_t bytes, std::string data_ } else if (val.size() > 10 && val.substr(0, 10) == "%.var.tmp.") { // tmp variable, not address keeper size_t offset = layout.QueryOffeset(val); - code_lines.push_back("addi " + data_reg + ", fp, -" + std::to_string(offset)); if (bytes == 1) { - code_lines.push_back("sb " + data_reg + ", 0(" + data_reg + ")"); + code_lines.push_back("sb " + data_reg + ", -" + std::to_string(offset) + "(s0)"); } else if (bytes == 4) { - code_lines.push_back("sw " + data_reg + ", 0(" + data_reg + ")"); + code_lines.push_back("sw " + data_reg + ", -" + std::to_string(offset) + "(s0)"); } else { throw std::runtime_error("Unknown bytes"); } @@ -189,6 +221,20 @@ inline void GenerateWriteAccess(std::string val, size_t bytes, std::string data_ throw std::runtime_error("Unknown variable type with name=" + val); } } +inline size_t CalcSize(const LLVMType &tp) { + if (std::holds_alternative(tp)) { + auto &int_tp = std::get(tp); + return (int_tp.bits + 7) / 8; + } else if (std::holds_alternative(tp)) { + return 4; + } else if (std::holds_alternative(tp)) { + throw std::runtime_error("Cannot calculate size of void type"); + return 0; + } else if (std::holds_alternative(tp)) { + throw std::runtime_error("Cannot calculate size of class type"); + } else + throw std::runtime_error("Unknown type"); +} } // namespace NaiveBackend void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog); \ No newline at end of file diff --git a/src/IR/IRBuilder.cpp b/src/IR/IRBuilder.cpp index d3af6ab..f41586c 100644 --- a/src/IR/IRBuilder.cpp +++ b/src/IR/IRBuilder.cpp @@ -359,8 +359,24 @@ void IRBuilder::ActuralVisit(JmpStatement_ASTNode *node) { // return if (node->return_value) { node->return_value->accept(this); + std::string res = node->return_value->IR_result_full; + if (res[0] == '#') { + res = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = res; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = node->return_value->IR_result_full.substr(1); + } else if (res[0] == '!') { + // inline builder + auto inline_builder = inline_builders[res.substr(1)]; + res = std::dynamic_pointer_cast(inline_builder->exit_action)->value; + for (auto &act : inline_builder->actions) { + cur_block->actions.push_back(act); + } + } cur_block->exit_action = std::make_shared(); - std::dynamic_pointer_cast(cur_block->exit_action)->value = node->return_value->IR_result_full; + std::dynamic_pointer_cast(cur_block->exit_action)->value = res; } else { cur_block->exit_action = std::make_shared(); } @@ -534,9 +550,25 @@ void IRBuilder::ActuralVisit(NewExpr_ASTNode *node) { void IRBuilder::ActuralVisit(AccessExpr_ASTNode *node) { if (!node->is_function) { node->base->accept(this); + std::string base_res = node->base->IR_result_full; + if (base_res[0] == '#') { + base_res = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = base_res; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = node->base->IR_result_full.substr(1); + } else if (base_res[0] == '!') { + // inline builder + auto inline_builder = inline_builders[base_res.substr(1)]; + base_res = std::dynamic_pointer_cast(inline_builder->exit_action)->value; + for (auto &act : inline_builder->actions) { + cur_block->actions.push_back(act); + } + } std::string type_of_base = std::get(node->base->expr_type_info); IRClassInfo class_info = global_scope->fetch_class_info(type_of_base); - std::string base_ptr = node->base->IR_result_full; + std::string base_ptr = base_res; size_t idx = class_info.member_var_offset[node->member]; auto member_addr_cal = std::make_shared(); cur_block->actions.push_back(member_addr_cal); @@ -557,16 +589,48 @@ void IRBuilder::ActuralVisit(AccessExpr_ASTNode *node) { } } else { node->base->accept(this); + std::string base_res = node->base->IR_result_full; + if (base_res[0] == '#') { + base_res = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = base_res; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = node->base->IR_result_full.substr(1); + } else if (base_res[0] == '!') { + // inline builder + auto inline_builder = inline_builders[base_res.substr(1)]; + base_res = std::dynamic_pointer_cast(inline_builder->exit_action)->value; + for (auto &act : inline_builder->actions) { + cur_block->actions.push_back(act); + } + } std::string type_of_base; if (std::holds_alternative(node->base->expr_type_info)) type_of_base = std::get(node->base->expr_type_info); - std::string base_ptr = node->base->IR_result_full; + std::string base_ptr = base_res; std::string func_name = type_of_base + "." + node->member; if (std::holds_alternative(node->base->expr_type_info)) func_name = ".builtin.GetArrayLength"; std::vector arg_val; for (size_t i = 0; i < node->arguments.size(); i++) { node->arguments[i]->accept(this); - arg_val.push_back(node->arguments[i]->IR_result_full); + std::string arg_value = node->arguments[i]->IR_result_full; + if (arg_value[0] == '#') { + arg_value = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = arg_value; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = node->arguments[i]->IR_result_full.substr(1); + } else if (arg_value[0] == '!') { + // inline builder + auto inline_builder = inline_builders[arg_value.substr(1)]; + arg_value = std::dynamic_pointer_cast(inline_builder->exit_action)->value; + for (auto &act : inline_builder->actions) { + cur_block->actions.push_back(act); + } + } + arg_val.push_back(arg_value); } auto call_act = std::make_shared(); cur_block->actions.push_back(call_act); @@ -969,7 +1033,7 @@ void IRBuilder::ActuralVisit(LAndExpr_ASTNode *node) { auto right_block_end = cur_block; std::dynamic_pointer_cast(cur_block->exit_action)->label_full = new_block->label_full; cur_block->exit_action->corresponding_phi = phi_act; - + cur_func->basic_blocks.push_back(new_block); cur_block = new_block; phi_act->result_full = "%.var.tmp." + std::to_string(tmp_var_counter++); @@ -1005,7 +1069,7 @@ void IRBuilder::ActuralVisit(LOrExpr_ASTNode *node) { std::dynamic_pointer_cast(cur_block->exit_action)->false_label_full = right_cal_block->label_full; std::dynamic_pointer_cast(cur_block->exit_action)->cond = node->left->IR_result_full; cur_block->exit_action->corresponding_phi = phi_act; - + cur_func->basic_blocks.push_back(right_cal_block); cur_block = right_cal_block; node->right->accept(this); @@ -1167,7 +1231,23 @@ void IRBuilder::ActuralVisit(FunctionCallExpr_ASTNode *node) { call->args_ty.push_back(LLVMIRPTRType()); for (auto &arg : node->arguments) { arg->accept(this); - call->args_val_full.push_back(arg->IR_result_full); + std::string arg_value = arg->IR_result_full; + if (arg_value[0] == '#') { + arg_value = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = arg_value; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = arg->IR_result_full.substr(1); + } else if (arg_value[0] == '!') { + // inline builder + auto inline_builder = inline_builders[arg_value.substr(1)]; + arg_value = std::dynamic_pointer_cast(inline_builder->exit_action)->value; + for (auto &act : inline_builder->actions) { + cur_block->actions.push_back(act); + } + } + call->args_val_full.push_back(arg_value); call->args_ty.push_back(Type_AST2LLVM(arg->expr_type_info)); } cur_block->actions.push_back(call); @@ -1181,7 +1261,23 @@ void IRBuilder::ActuralVisit(FunctionCallExpr_ASTNode *node) { call->func_name_raw = node->func_name; for (auto &arg : node->arguments) { arg->accept(this); - call->args_val_full.push_back(arg->IR_result_full); + std::string arg_value = arg->IR_result_full; + if (arg_value[0] == '#') { + arg_value = "%.var.tmp." + std::to_string(tmp_var_counter++); + auto const_array_construct_call = std::make_shared(); + cur_block->actions.push_back(const_array_construct_call); + const_array_construct_call->result_full = arg_value; + const_array_construct_call->return_type = LLVMIRPTRType(); + const_array_construct_call->func_name_raw = arg->IR_result_full.substr(1); + } else if (arg_value[0] == '!') { + // inline builder + auto inline_builder = inline_builders[arg_value.substr(1)]; + arg_value = std::dynamic_pointer_cast(inline_builder->exit_action)->value; + for (auto &act : inline_builder->actions) { + cur_block->actions.push_back(act); + } + } + call->args_val_full.push_back(arg_value); call->args_ty.push_back(Type_AST2LLVM(arg->expr_type_info)); } cur_block->actions.push_back(call); diff --git a/src/main.cpp b/src/main.cpp index d19208a..1488487 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,6 +28,7 @@ int main(int argc, char **argv) { try { SemanticCheck(fin, ast); auto IR = BuildIR(ast); + // IR->RecursivePrint(fout); return 0; IR->RecursivePrint(std::cerr); GenerateNaiveASM(fout, IR); } catch (const SemanticError &err) { diff --git a/src/naivebackend/naivebackend.cpp b/src/naivebackend/naivebackend.cpp index fd26048..b73d08b 100644 --- a/src/naivebackend/naivebackend.cpp +++ b/src/naivebackend/naivebackend.cpp @@ -2,6 +2,7 @@ #include #include "IR/IR_basic.h" #include "build_layout.hpp" +#include "codegen.hpp" using namespace NaiveBackend; void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog) { auto riscv = std::make_shared(); @@ -21,12 +22,12 @@ void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog) { for (auto func_def : prog->function_defs) { if (func_def->init_block) { for (auto act : func_def->init_block->actions) { - ScanForVar(func_layouts[func_def->func_name_raw], act); + ScanForVar(func_layouts[func_def->func_name_raw], act, prog->low_level_class_info); } } for (auto block : func_def->basic_blocks) { for (auto act : block->actions) { - ScanForVar(func_layouts[func_def->func_name_raw], act); + ScanForVar(func_layouts[func_def->func_name_raw], act, prog->low_level_class_info); } } FuncLayout &layout = func_layouts[func_def->func_name_raw]; @@ -47,11 +48,36 @@ void GenerateNaiveASM(std::ostream &os, std::shared_ptr prog) { auto func_asm = std::make_shared(); riscv->funcs.push_back(func_asm); func_asm->full_label = func_def->func_name_raw; + FuncLayout &layout = func_layouts[func_def->func_name_raw]; + func_asm->code_lines.push_back("addi sp, sp, -" + std::to_string(layout.total_frame_size)); + func_asm->code_lines.push_back("sw ra, " + std::to_string(layout.total_frame_size - 4) + "(sp)"); + func_asm->code_lines.push_back("sw s0, " + std::to_string(layout.total_frame_size - 8) + "(sp)"); + func_asm->code_lines.push_back("addi s0, sp, " + std::to_string(layout.total_frame_size)); if (func_def->init_block) { func_asm->code_lines.push_back(".entrylabel." + func_def->init_block->label_full + ":"); + for (auto act : func_def->init_block->actions) { + NaiveBackend::GenerateASM(act, func_asm->code_lines, func_layouts[func_def->func_name_raw], + prog->low_level_class_info); + } + if (func_def->init_block->exit_action->corresponding_phi) { + NaiveBackend::GenerateASM(func_def->init_block->exit_action->corresponding_phi, func_asm->code_lines, + func_layouts[func_def->func_name_raw], prog->low_level_class_info, true); + } + NaiveBackend::GenerateASM(func_def->init_block->exit_action, func_asm->code_lines, + func_layouts[func_def->func_name_raw], prog->low_level_class_info); } for (auto block : func_def->basic_blocks) { func_asm->code_lines.push_back(".entrylabel." + block->label_full + ":"); + for (auto act : block->actions) { + NaiveBackend::GenerateASM(act, func_asm->code_lines, func_layouts[func_def->func_name_raw], + prog->low_level_class_info); + } + if (block->exit_action->corresponding_phi) { + NaiveBackend::GenerateASM(block->exit_action->corresponding_phi, func_asm->code_lines, + func_layouts[func_def->func_name_raw], prog->low_level_class_info, true); + } + NaiveBackend::GenerateASM(block->exit_action, func_asm->code_lines, func_layouts[func_def->func_name_raw], + prog->low_level_class_info); } }