#pragma once #include "common.h" #include "llir.h" using std::make_shared; namespace codegen { // a?, t?, ra are caller-saved // s? are callee-saved // x0,gp,tp are preserved in user-space enum class RV64Reg { x0 = 0, // zero ra, // ra, caller sp, // sp, callee gp, // gp tp, // tp t0, // t0, caller t1, t2, // t1-2, caller s0, // s0/fp, callee s1, // s1, callee a0, a1, // a0-1,caller a2, a3, a4, a5, a6, a7, // a2-7,caller s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, // s2-11,callee t3, t4, t5, t6, // t3-6,caller }; // riscv calling convention see: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc const int XLEN = 8; inline std::string RV64_RegName(RV64Reg reg) { std::string regname = "x" + std::to_string((int)reg); return regname; } inline RV64Reg RV64_RegOffset(RV64Reg reg, int offset) { auto xi = (int)reg + offset; return (RV64Reg)xi; } class MOperand; class MInst; class MBasicBlock; class MFunction; class MOperand { public: enum class OpTag { Virt, Imm, Reg, } op_type = OpTag::Virt; int value = ~0; private: MOperand(OpTag tag, int val) : op_type(tag), value(val) {} public: static sptr(MOperand) NewVirtReg(int reg_no) { auto mop = std::make_shared(OpTag::Virt, reg_no); return mop; } static sptr(MOperand) NewImm(int imm_val) { auto mop = std::make_shared(OpTag::Imm, imm_val); return mop; } static sptr(MOperand) NewReg(RV64Reg phy_reg) { auto mop = std::make_shared(OpTag::Reg, (int)phy_reg); return mop; } }; class MInst { public: enum class MInstTag { Add, Sub, Rsb, Mul, Div, Mod, Lt, Le, Ge, Gt, Eq, Ne, And, Or, Move, // actually a pseudo, mv = addi rt, rs, 0 Branch, Jump, Return, Load, Store, Compare, Call, Global, } tag; sptr(MBasicBlock) parent_bb; MInst(MInstTag tag, sptr(MBasicBlock) parent_bb) : tag(tag), parent_bb(parent_bb) {} }; class MBasicBlock { public: sptr(antlrSysY::BasicBlock) ir_bb; sptr(MFunction) parent_func; std::list inst_list; std::list pred_list; std::list succ_list; std::unordered_set livein; std::unordered_set liveout; }; class MFunction { public: std::list bb_list; sptr(antlrSysY::Function) ir_func; std::list stack_arg_reloc; unsigned virt_reg_cnt = 0; }; class MGlobalVar { public: }; class MCModule { public: std::list function_list; std::list global_list; void IR2MC(const antlrSysY::Module &ir_module); }; class MInstBinary : public MInst { public: }; class MInstJump : public MInst { public: sptr(MBasicBlock) target; MInstJump(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Jump, parent_bb) {} static sptr(MInstJump) New(sptr(MBasicBlock) parent_bb) { auto inst = make_shared(parent_bb); parent_bb->inst_list.push_back(inst); return inst; } }; class MInstLoad : public MInst { public: sptr(MOperand) dst; sptr(MOperand) addr; sptr(MOperand) offset; MInstLoad(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Load, parent_bb) {} static sptr(MInstLoad) New(sptr(MBasicBlock) parent_bb) { auto inst = make_shared(parent_bb); parent_bb->inst_list.push_back(inst); return inst; } }; class MInstMove : public MInst { public: sptr(MOperand) dst; sptr(MOperand) src; MInstMove(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Move, parent_bb) {} static sptr(MInstMove) New(sptr(MBasicBlock) parent_bb, bool insert_begin = false) { auto inst = make_shared(parent_bb); if (insert_begin) parent_bb->inst_list.push_front(inst); else parent_bb->inst_list.push_back(inst); return inst; } static sptr(MInstMove) New(sptr(MInst) rel_inst, bool insert_after = false) { auto parent_bb = rel_inst->parent_bb; auto inst = make_shared(parent_bb); auto rel_inst_itr = FIND(parent_bb->inst_list, rel_inst); assert(rel_inst_itr != parent_bb->inst_list.end()); if (insert_after) std::advance(rel_inst_itr, 1); parent_bb->inst_list.insert(rel_inst_itr, inst); return inst; } }; } // namespace codegen