basically write codegen

This commit is contained in:
2024-08-28 14:21:05 +00:00
parent 46f659053b
commit f93e9f481c
8 changed files with 392 additions and 52 deletions

View File

@ -12,9 +12,10 @@ build:
@cd $(BUILD_DIR) && cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -Wno-dev .. @cd $(BUILD_DIR) && cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -Wno-dev ..
@cd $(BUILD_DIR) && $(MAKE) -j4 @cd $(BUILD_DIR) && $(MAKE) -j4
# 运行目标,运行生成的可执行文件 acturalrun:
run:
@cd $(BUILD_DIR) && ./zmxcc /dev/stdin -o /dev/stdout 2>/dev/null @cd $(BUILD_DIR) && ./zmxcc /dev/stdin -o /dev/stdout 2>/dev/null
# 运行目标,运行生成的可执行文件
run: acturalrun
@cat $(BUILTIN_ASM) >>/dev/stdout @cat $(BUILTIN_ASM) >>/dev/stdout
# 清理目标 # 清理目标

View File

@ -71,9 +71,18 @@ class JMPActionItem : public ActionItem {
public: public:
std::shared_ptr<class PhiItem> corresponding_phi; std::shared_ptr<class PhiItem> corresponding_phi;
}; };
namespace NaiveBackend {
void ScanForVar(class FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
void GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines, FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info, bool process_phi);
} // namespace NaiveBackend
class BRAction : public JMPActionItem { class BRAction : public JMPActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog); friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::string cond; std::string cond;
std::string true_label_full; std::string true_label_full;
std::string false_label_full; std::string false_label_full;
@ -88,6 +97,10 @@ class UNConditionJMPAction : public JMPActionItem {
friend class IRBuilder; friend class IRBuilder;
friend class FunctionDefItem; friend class FunctionDefItem;
friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog); friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::string label_full; std::string label_full;
public: public:
@ -98,6 +111,10 @@ class RETAction : public JMPActionItem {
friend class IRBuilder; friend class IRBuilder;
friend class FunctionDefItem; friend class FunctionDefItem;
friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog); friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
LLVMType type; LLVMType type;
std::string value; std::string value;
@ -115,12 +132,14 @@ class RETAction : public JMPActionItem {
} }
} }
}; };
namespace NaiveBackend {
void ScanForVar(class FuncLayout &layout, std::shared_ptr<ActionItem> action);
}
class BinaryOperationAction : public ActionItem { class BinaryOperationAction : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::string op; std::string op;
std::string operand1_full; std::string operand1_full;
std::string operand2_full; std::string operand2_full;
@ -145,7 +164,7 @@ class BinaryOperationAction : public ActionItem {
}; };
class AllocaAction : public ActionItem { class AllocaAction : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
std::string name_full; std::string name_full;
LLVMType type; LLVMType type;
size_t num; size_t num;
@ -169,7 +188,11 @@ class AllocaAction : public ActionItem {
}; };
class LoadAction : public ActionItem { class LoadAction : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::string result_full; std::string result_full;
LLVMType ty; LLVMType ty;
std::string ptr_full; std::string ptr_full;
@ -190,7 +213,11 @@ class LoadAction : public ActionItem {
}; };
class StoreAction : public ActionItem { class StoreAction : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
LLVMType ty; LLVMType ty;
std::string value_full; std::string value_full;
std::string ptr_full; std::string ptr_full;
@ -211,7 +238,7 @@ class StoreAction : public ActionItem {
}; };
class GetElementPtrAction : public ActionItem { class GetElementPtrAction : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
std::string result_full; std::string result_full;
LLVMType ty; LLVMType ty;
std::string ptr_full; std::string ptr_full;
@ -239,7 +266,11 @@ class GetElementPtrAction : public ActionItem {
}; };
class ICMPAction : public ActionItem { class ICMPAction : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::string op; std::string op;
std::string operand1_full; std::string operand1_full;
std::string operand2_full; std::string operand2_full;
@ -264,7 +295,7 @@ class BlockItem : public LLVMIRItemBase {
friend class IRBuilder; friend class IRBuilder;
friend class FunctionDefItem; friend class FunctionDefItem;
friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog); friend void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog);
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
std::string label_full; std::string label_full;
std::vector<std::shared_ptr<ActionItem>> actions; std::vector<std::shared_ptr<ActionItem>> actions;
std::shared_ptr<JMPActionItem> exit_action; std::shared_ptr<JMPActionItem> exit_action;
@ -281,7 +312,11 @@ class BlockItem : public LLVMIRItemBase {
}; };
class CallItem : public ActionItem { class CallItem : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
NaiveBackend::FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::string result_full; std::string result_full;
LLVMType return_type; LLVMType return_type;
std::string func_name_raw; std::string func_name_raw;
@ -330,7 +365,7 @@ class CallItem : public ActionItem {
class PhiItem : public ActionItem { class PhiItem : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
std::string result_full; std::string result_full;
LLVMType ty; LLVMType ty;
std::vector<std::pair<std::string, std::string>> values; // (val_i_full, label_i_full) std::vector<std::pair<std::string, std::string>> values; // (val_i_full, label_i_full)
@ -357,7 +392,7 @@ class PhiItem : public ActionItem {
}; };
class SelectItem : public ActionItem { class SelectItem : public ActionItem {
friend class IRBuilder; friend class IRBuilder;
friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action); friend void NaiveBackend::ScanForVar(class NaiveBackend::FuncLayout &layout, std::shared_ptr<ActionItem> action, const std::unordered_map<std::string, IRClassInfo> &low_level_class_info);
std::string result_full; std::string result_full;
std::string cond_full; std::string cond_full;
std::string true_val_full; std::string true_val_full;

View File

@ -6,21 +6,8 @@
#include "tools.h" #include "tools.h"
namespace NaiveBackend { namespace NaiveBackend {
inline size_t CalcSize(const LLVMType &tp) { inline void ScanForVar(FuncLayout &layout, std::shared_ptr<ActionItem> action,
if (std::holds_alternative<LLVMIRIntType>(tp)) { const std::unordered_map<std::string, IRClassInfo> &low_level_class_info) {
auto &int_tp = std::get<LLVMIRIntType>(tp);
return (int_tp.bits + 7) / 8;
} else if (std::holds_alternative<LLVMIRPTRType>(tp)) {
return 4;
} else if (std::holds_alternative<LLVMVOIDType>(tp)) {
throw std::runtime_error("Cannot calculate size of void type");
return 0;
} else if (std::holds_alternative<LLVMIRCLASSTYPE>(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<ActionItem> action) {
if (std::dynamic_pointer_cast<JMPActionItem>(action)) { if (std::dynamic_pointer_cast<JMPActionItem>(action)) {
throw std::runtime_error("JMPActionItem should not be in the layout"); throw std::runtime_error("JMPActionItem should not be in the layout");
} else if (auto binary_act = std::dynamic_pointer_cast<BinaryOperationAction>(action)) { } else if (auto binary_act = std::dynamic_pointer_cast<BinaryOperationAction>(action)) {
@ -44,7 +31,19 @@ inline void ScanForVar(FuncLayout &layout, std::shared_ptr<ActionItem> action) {
if (get_element_act->result_full == "") { if (get_element_act->result_full == "") {
throw std::runtime_error("GetElementPtrAction should have a result_full"); throw std::runtime_error("GetElementPtrAction should have a result_full");
} }
if (get_element_act->indices.size() == 1) {
layout.AllocateItem(get_element_act->result_full, CalcSize(get_element_act->ty)); 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<LLVMIRCLASSTYPE>(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<ICMPAction>(action)) { } else if (auto icmp_act = std::dynamic_pointer_cast<ICMPAction>(action)) {
if (icmp_act->result_full == "") { if (icmp_act->result_full == "") {
throw std::runtime_error("ICMPAction should have a result_full"); throw std::runtime_error("ICMPAction should have a result_full");

View File

@ -0,0 +1,136 @@
#pragma once
#include <stdexcept>
#include "naivebackend.h"
namespace NaiveBackend {
inline void GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines, FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi = false) {
if (auto br_act = std::dynamic_pointer_cast<BRAction>(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<UNConditionJMPAction>(act)) {
code_lines.push_back("j .entrylabel." + jmp_act->label_full);
} else if (auto ret_act = std::dynamic_pointer_cast<RETAction>(act)) {
if (!std::holds_alternative<LLVMVOIDType>(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<BinaryOperationAction>(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<AllocaAction>(act)) {
// just do nothing
} else if (auto load_act = std::dynamic_pointer_cast<LoadAction>(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<StoreAction>(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<GetElementPtrAction>(act)) {
// TODO: implement this
} else if (auto icmp_act = std::dynamic_pointer_cast<ICMPAction>(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<CallItem>(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<PhiItem>(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<SelectItem>(act)) {
// TODO: implement this
// throw std::runtime_error("not implemented");
} else {
throw std::runtime_error("Unknown action type");
}
}
} // namespace NaiveBackend

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <cctype>
#include <cstddef> #include <cstddef>
#include <ios> #include <ios>
#include <memory> #include <memory>
@ -93,8 +94,12 @@ class FuncLayout {
friend void ::GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog); friend void ::GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog);
friend void GenerateReadAccess(std::string val, size_t bytes, std::string output_reg, FuncLayout &layout, friend void GenerateReadAccess(std::string val, size_t bytes, std::string output_reg, FuncLayout &layout,
std::vector<std::string> &code_lines); std::vector<std::string> &code_lines);
friend inline void GenerateWriteAccess(std::string val, size_t bytes, std::string data_reg, FuncLayout &layout, friend void GenerateWriteAccess(std::string val, size_t bytes, std::string data_reg, FuncLayout &layout,
std::vector<std::string> &code_lines); std::vector<std::string> &code_lines);
friend void NaiveBackend::GenerateASM(std::shared_ptr<ActionItem> act, std::vector<std::string> &code_lines,
FuncLayout &layout,
const std::unordered_map<std::string, IRClassInfo> &low_level_class_info,
bool process_phi);
std::unordered_map<std::string, size_t> local_items; std::unordered_map<std::string, size_t> local_items;
std::unordered_map<std::string, size_t> arg_offset; std::unordered_map<std::string, size_t> arg_offset;
size_t cur_pos; 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); size_t offset = layout.arg_offset.at(val);
if (offset < 8) { 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 { } else {
size_t spilled_offset = (offset - 8) * 4; // just*4, which is different from the real riscv size_t spilled_offset = (offset - 8) * 4; // just*4, which is different from the real riscv
std::string cmd; std::string cmd;
@ -137,7 +143,7 @@ inline void GenerateReadAccess(std::string val, size_t bytes, std::string output
cmd = "lw"; cmd = "lw";
else else
throw std::runtime_error("Unknown bytes"); 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); code_lines.push_back(cmd);
} }
} else if (val.size() > 13 && val.substr(0, 13) == "@.var.global.") { } 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.") { } else if (val.size() > 12 && val.substr(0, 12) == "%.var.local.") {
// local variable address keeper // local variable address keeper
size_t offset = layout.QueryOffeset(val); 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.") { } else if (val.size() > 10 && val.substr(0, 10) == "%.var.tmp.") {
// tmp variable, not address keeper // tmp variable, not address keeper
size_t offset = layout.QueryOffeset(val); size_t offset = layout.QueryOffeset(val);
code_lines.push_back("addi " + output_reg + ", fp, -" + std::to_string(offset));
if (bytes == 1) { 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) { } 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 { } else {
throw std::runtime_error("Unknown bytes"); 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 { } else {
throw std::runtime_error("Unknown variable type with name=" + val); throw std::runtime_error("Unknown variable type with name=" + val);
} }
} }
inline void StoreImmToReg(int imm, std::string reg, std::vector<std::string> &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<std::string> &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, inline void GenerateWriteAccess(std::string val, size_t bytes, std::string data_reg, FuncLayout &layout,
std::vector<std::string> &code_lines) { std::vector<std::string> &code_lines) {
if (val.size() > 4 && val.substr(val.size() - 4, 4) == ".val") { 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.") { } else if (val.size() > 10 && val.substr(0, 10) == "%.var.tmp.") {
// tmp variable, not address keeper // tmp variable, not address keeper
size_t offset = layout.QueryOffeset(val); size_t offset = layout.QueryOffeset(val);
code_lines.push_back("addi " + data_reg + ", fp, -" + std::to_string(offset));
if (bytes == 1) { 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) { } 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 { } else {
throw std::runtime_error("Unknown bytes"); 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); throw std::runtime_error("Unknown variable type with name=" + val);
} }
} }
inline size_t CalcSize(const LLVMType &tp) {
if (std::holds_alternative<LLVMIRIntType>(tp)) {
auto &int_tp = std::get<LLVMIRIntType>(tp);
return (int_tp.bits + 7) / 8;
} else if (std::holds_alternative<LLVMIRPTRType>(tp)) {
return 4;
} else if (std::holds_alternative<LLVMVOIDType>(tp)) {
throw std::runtime_error("Cannot calculate size of void type");
return 0;
} else if (std::holds_alternative<LLVMIRCLASSTYPE>(tp)) {
throw std::runtime_error("Cannot calculate size of class type");
} else
throw std::runtime_error("Unknown type");
}
} // namespace NaiveBackend } // namespace NaiveBackend
void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog); void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog);

View File

@ -359,8 +359,24 @@ void IRBuilder::ActuralVisit(JmpStatement_ASTNode *node) {
// return // return
if (node->return_value) { if (node->return_value) {
node->return_value->accept(this); 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<CallItem>();
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<RETAction>(inline_builder->exit_action)->value;
for (auto &act : inline_builder->actions) {
cur_block->actions.push_back(act);
}
}
cur_block->exit_action = std::make_shared<RETAction>(); cur_block->exit_action = std::make_shared<RETAction>();
std::dynamic_pointer_cast<RETAction>(cur_block->exit_action)->value = node->return_value->IR_result_full; std::dynamic_pointer_cast<RETAction>(cur_block->exit_action)->value = res;
} else { } else {
cur_block->exit_action = std::make_shared<RETAction>(); cur_block->exit_action = std::make_shared<RETAction>();
} }
@ -534,9 +550,25 @@ void IRBuilder::ActuralVisit(NewExpr_ASTNode *node) {
void IRBuilder::ActuralVisit(AccessExpr_ASTNode *node) { void IRBuilder::ActuralVisit(AccessExpr_ASTNode *node) {
if (!node->is_function) { if (!node->is_function) {
node->base->accept(this); 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<CallItem>();
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<RETAction>(inline_builder->exit_action)->value;
for (auto &act : inline_builder->actions) {
cur_block->actions.push_back(act);
}
}
std::string type_of_base = std::get<IdentifierType>(node->base->expr_type_info); std::string type_of_base = std::get<IdentifierType>(node->base->expr_type_info);
IRClassInfo class_info = global_scope->fetch_class_info(type_of_base); 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]; size_t idx = class_info.member_var_offset[node->member];
auto member_addr_cal = std::make_shared<GetElementPtrAction>(); auto member_addr_cal = std::make_shared<GetElementPtrAction>();
cur_block->actions.push_back(member_addr_cal); cur_block->actions.push_back(member_addr_cal);
@ -557,16 +589,48 @@ void IRBuilder::ActuralVisit(AccessExpr_ASTNode *node) {
} }
} else { } else {
node->base->accept(this); 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<CallItem>();
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<RETAction>(inline_builder->exit_action)->value;
for (auto &act : inline_builder->actions) {
cur_block->actions.push_back(act);
}
}
std::string type_of_base; std::string type_of_base;
if (std::holds_alternative<IdentifierType>(node->base->expr_type_info)) if (std::holds_alternative<IdentifierType>(node->base->expr_type_info))
type_of_base = std::get<IdentifierType>(node->base->expr_type_info); type_of_base = std::get<IdentifierType>(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; std::string func_name = type_of_base + "." + node->member;
if (std::holds_alternative<ArrayType>(node->base->expr_type_info)) func_name = ".builtin.GetArrayLength"; if (std::holds_alternative<ArrayType>(node->base->expr_type_info)) func_name = ".builtin.GetArrayLength";
std::vector<std::string> arg_val; std::vector<std::string> arg_val;
for (size_t i = 0; i < node->arguments.size(); i++) { for (size_t i = 0; i < node->arguments.size(); i++) {
node->arguments[i]->accept(this); 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<CallItem>();
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<RETAction>(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<CallItem>(); auto call_act = std::make_shared<CallItem>();
cur_block->actions.push_back(call_act); cur_block->actions.push_back(call_act);
@ -1167,7 +1231,23 @@ void IRBuilder::ActuralVisit(FunctionCallExpr_ASTNode *node) {
call->args_ty.push_back(LLVMIRPTRType()); call->args_ty.push_back(LLVMIRPTRType());
for (auto &arg : node->arguments) { for (auto &arg : node->arguments) {
arg->accept(this); 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<CallItem>();
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<RETAction>(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)); call->args_ty.push_back(Type_AST2LLVM(arg->expr_type_info));
} }
cur_block->actions.push_back(call); cur_block->actions.push_back(call);
@ -1181,7 +1261,23 @@ void IRBuilder::ActuralVisit(FunctionCallExpr_ASTNode *node) {
call->func_name_raw = node->func_name; call->func_name_raw = node->func_name;
for (auto &arg : node->arguments) { for (auto &arg : node->arguments) {
arg->accept(this); 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<CallItem>();
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<RETAction>(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)); call->args_ty.push_back(Type_AST2LLVM(arg->expr_type_info));
} }
cur_block->actions.push_back(call); cur_block->actions.push_back(call);

View File

@ -28,6 +28,7 @@ int main(int argc, char **argv) {
try { try {
SemanticCheck(fin, ast); SemanticCheck(fin, ast);
auto IR = BuildIR(ast); auto IR = BuildIR(ast);
// IR->RecursivePrint(fout); return 0;
IR->RecursivePrint(std::cerr); IR->RecursivePrint(std::cerr);
GenerateNaiveASM(fout, IR); GenerateNaiveASM(fout, IR);
} catch (const SemanticError &err) { } catch (const SemanticError &err) {

View File

@ -2,6 +2,7 @@
#include <unordered_map> #include <unordered_map>
#include "IR/IR_basic.h" #include "IR/IR_basic.h"
#include "build_layout.hpp" #include "build_layout.hpp"
#include "codegen.hpp"
using namespace NaiveBackend; using namespace NaiveBackend;
void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog) { void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog) {
auto riscv = std::make_shared<RISCVProgItem>(); auto riscv = std::make_shared<RISCVProgItem>();
@ -21,12 +22,12 @@ void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog) {
for (auto func_def : prog->function_defs) { for (auto func_def : prog->function_defs) {
if (func_def->init_block) { if (func_def->init_block) {
for (auto act : func_def->init_block->actions) { 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 block : func_def->basic_blocks) {
for (auto act : block->actions) { 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]; FuncLayout &layout = func_layouts[func_def->func_name_raw];
@ -47,11 +48,36 @@ void GenerateNaiveASM(std::ostream &os, std::shared_ptr<ModuleItem> prog) {
auto func_asm = std::make_shared<RISCVFuncItem>(); auto func_asm = std::make_shared<RISCVFuncItem>();
riscv->funcs.push_back(func_asm); riscv->funcs.push_back(func_asm);
func_asm->full_label = func_def->func_name_raw; 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) { if (func_def->init_block) {
func_asm->code_lines.push_back(".entrylabel." + func_def->init_block->label_full + ":"); 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) { for (auto block : func_def->basic_blocks) {
func_asm->code_lines.push_back(".entrylabel." + block->label_full + ":"); 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);
} }
} }