first sysy2asm all function pass
This commit is contained in:
parent
988534f446
commit
6bf4093bfb
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
@ -9,8 +9,9 @@
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceFolder}/build/sysy",
|
||||
"args": ["../sysytests/functional_2022/28_while_test3.sy", "-S", "-o", "build/my.s", "-O1", "-emit-llvm"],
|
||||
// "args": ["../sysytests/functional_2021/069_greatest_common_divisor.sy", "-S", "-o", "build/my.s", "-O1", "-emit-llvm"],
|
||||
"args" : ["-S", "../sysytests/functional_2022/88_many_params2.sy", "-o", "build/my.s", "-emit-llvm", "-O1"],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -45,15 +45,16 @@ inline sptr(DST) strict_shared_cast(SRC src) {
|
||||
throw GrammarException(__FILE__, __LINE__, (message)); \
|
||||
} while (0)
|
||||
|
||||
#define sysy_assert(cond) \
|
||||
do { \
|
||||
if (!(cond)) throw GrammarException(__FILE__, __LINE__, #cond); \
|
||||
} while (0)
|
||||
|
||||
#define DEF_PTR_T(type) \
|
||||
class type; \
|
||||
typedef std::shared_ptr<type> type##Ptr_t
|
||||
|
||||
#define GET_MACRO(_1, _2, NAME, ...) NAME
|
||||
#define _sysy_assert1(expr) assert(expr)
|
||||
#define _sysy_assert2(expr, info) \
|
||||
(static_cast<bool>(expr) ? void(0) : ([&]() { info }(), __assert_fail(#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)))
|
||||
#define sysy_assert(...) GET_MACRO(__VA_ARGS__, _sysy_assert2, _sysy_assert1)(__VA_ARGS__)
|
||||
|
||||
namespace CompSysY {
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -116,7 +116,7 @@ public:
|
||||
int type_size = 0; // = dim_size * size(elem_type)
|
||||
ArrayType() : Type(TypeTag::ArrayType) {}
|
||||
ArrayType(TypePtr_t element_type, int element_count)
|
||||
: Type(TypeTag::ArrayType), elem_count(element_count), elem_type(element_type) {}
|
||||
: Type(TypeTag::ArrayType), elem_type(element_type), elem_count(element_count) {}
|
||||
static std::shared_ptr<ArrayType> build_from_list(const std::vector<int> &dim_list) {
|
||||
TypePtr_t array_type = TypeHelper::TYPE_I32;
|
||||
sysy_assert(dim_list.size() != 0);
|
||||
|
||||
@ -95,8 +95,6 @@ inline const char *enum_to_string(const MOpTag &tag) {
|
||||
return _str_tab[(unsigned)tag];
|
||||
}
|
||||
|
||||
// TODO Basic idea: value = id of globalvar in glob_list
|
||||
|
||||
class MOperand {
|
||||
public:
|
||||
MOpTag op_type = MOpTag::Invalid;
|
||||
@ -140,8 +138,8 @@ public:
|
||||
bool is_precolored() const {
|
||||
return op_type == MOpTag::PreColor;
|
||||
}
|
||||
bool need_clr() const {
|
||||
return is_precolored() || op_type == MOpTag::Virt;
|
||||
bool is_virt() const {
|
||||
return op_type == MOpTag::Virt;
|
||||
}
|
||||
bool is_imm() const {
|
||||
return op_type == MOpTag::Imm;
|
||||
@ -152,7 +150,7 @@ public:
|
||||
bool is_reg() const {
|
||||
return op_type == MOpTag::PreColor || op_type == MOpTag::Virt || op_type == MOpTag::Colored;
|
||||
}
|
||||
std::string to_string();
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
struct MOperandHash {
|
||||
@ -206,6 +204,9 @@ inline MInstTag inverse_cond(MInstTag src_tag) {
|
||||
}
|
||||
}
|
||||
|
||||
// Instruction insertion type
|
||||
enum class InsType { Before, After, Head, Tail };
|
||||
|
||||
class MInst {
|
||||
public:
|
||||
MInstTag inst_tag;
|
||||
@ -215,11 +216,18 @@ public:
|
||||
// Similarly, it makes difference when computing address
|
||||
int width = 4;
|
||||
|
||||
std::list<sptr(MInst)>::iterator itr;
|
||||
sptr(MBasicBlock) parent_bb;
|
||||
MInst(MInstTag tag, sptr(MBasicBlock) parent_bb) : inst_tag(tag), parent_bb(parent_bb) {}
|
||||
virtual ~MInst() = default;
|
||||
virtual std::vector<MOperand> get_def() = 0;
|
||||
virtual std::vector<MOperand> get_use() = 0;
|
||||
virtual std::vector<MOperand> get_def() const = 0;
|
||||
virtual std::vector<MOperand> get_use() const = 0;
|
||||
virtual bool is_transfer() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void PostNew(sptr(MInst) inst, sptr(MBasicBlock) parent_bb, InsType ins_ty);
|
||||
static void PostNew(sptr(MInst) inst, sptr(MInst) rel_inst, InsType ins_ty);
|
||||
};
|
||||
|
||||
class MBasicBlock {
|
||||
@ -260,8 +268,7 @@ public:
|
||||
std::vector<sptr(GlobalVar)> global_list;
|
||||
std::unordered_map<sptr(GlobalVar), int> global_id_map;
|
||||
void IR2MC(const Module &ir_module);
|
||||
void MC2ASM(std::ostream &ostr) const;
|
||||
bool debug1 = false;
|
||||
void MC2ASM(std::ostream &ostr, bool debug = false) const;
|
||||
};
|
||||
|
||||
class MInstBinary : public MInst {
|
||||
@ -271,14 +278,24 @@ public:
|
||||
MOperand op2;
|
||||
MInstBinary(MInstTag type, sptr(MBasicBlock) parent_bb) : MInst(type, parent_bb) {}
|
||||
|
||||
static sptr(MInstBinary) New(MInstTag type, sptr(MBasicBlock) parent_bb, int width) {
|
||||
static sptr(MInstBinary) New(MInstTag type, sptr(MBasicBlock) parent_bb, int width, InsType ins_ty = InsType::Tail) {
|
||||
auto inst = make_shared<MInstBinary>(type, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
inst->width = width;
|
||||
MInst::PostNew(inst, parent_bb, ins_ty);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
static sptr(MInstBinary) New(MInstTag type, sptr(MInst) rel_inst, int width, bool insert_after = false) {
|
||||
auto parent_bb = rel_inst->parent_bb;
|
||||
auto inst = make_shared<MInstBinary>(type, parent_bb);
|
||||
inst->width = width;
|
||||
auto rel_inst_itr = STD_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;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
};
|
||||
|
||||
class MInstJump : public MInst {
|
||||
@ -291,8 +308,11 @@ public:
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
bool is_transfer() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstBranch : public MInst {
|
||||
@ -307,8 +327,11 @@ public:
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
bool is_transfer() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstLoad : public MInst {
|
||||
@ -334,8 +357,8 @@ public:
|
||||
inst->width = width;
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
};
|
||||
|
||||
class MInstStore : public MInst {
|
||||
@ -361,8 +384,8 @@ public:
|
||||
inst->width = width;
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
};
|
||||
|
||||
class MInstMove : public MInst {
|
||||
@ -387,8 +410,8 @@ public:
|
||||
parent_bb->inst_list.insert(rel_inst_itr, inst);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
};
|
||||
|
||||
// class MInstSymbol : public MInst {
|
||||
@ -417,8 +440,11 @@ public:
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
bool is_transfer() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstComment : public MInst {
|
||||
@ -430,8 +456,17 @@ public:
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
static sptr(MInstComment) New(sptr(MInst) rel_inst, bool insert_after = false) {
|
||||
auto parent_bb = rel_inst->parent_bb;
|
||||
auto inst = make_shared<MInstComment>(parent_bb);
|
||||
auto rel_inst_itr = STD_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;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
};
|
||||
|
||||
class MInstCall : public MInst {
|
||||
@ -443,12 +478,9 @@ public:
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
virtual std::vector<MOperand> get_def() override;
|
||||
virtual std::vector<MOperand> get_use() override;
|
||||
virtual std::vector<MOperand> get_def() const override;
|
||||
virtual std::vector<MOperand> get_use() const override;
|
||||
};
|
||||
|
||||
void get_inst_defuse(sptr(MInst) inst, std::vector<MOperand> &def, std::vector<MOperand> &use);
|
||||
void get_inst_defuse(sptr(MInst) inst, std::vector<MOperand *> &def, std::vector<MOperand *> &use);
|
||||
void set_bb_def_use(sptr(MFunction) func);
|
||||
|
||||
} // namespace CompSysY
|
||||
@ -15,13 +15,13 @@ public:
|
||||
virtual void run(const Module &module) = 0;
|
||||
};
|
||||
|
||||
class PassMem2Reg : public Pass {
|
||||
class PassMem2Reg final : public Pass {
|
||||
public:
|
||||
PassMem2Reg() : Pass("mem2reg") {}
|
||||
virtual void run(const Module &module) override;
|
||||
};
|
||||
|
||||
class PassBuildCFG : public Pass {
|
||||
class PassBuildCFG final : public Pass {
|
||||
public:
|
||||
PassBuildCFG() : Pass("build_cfg") {}
|
||||
virtual void run(const Module &module) override;
|
||||
@ -35,12 +35,23 @@ public:
|
||||
virtual void run(const MCModule &module) = 0;
|
||||
};
|
||||
|
||||
class PassRegAlloc : public MCPass {
|
||||
class PassRegAlloc final : public MCPass {
|
||||
public:
|
||||
PassRegAlloc() : MCPass("regalloc") {}
|
||||
virtual void run(const MCModule &module) override;
|
||||
const static int K = 32 - 5; // Not Allocate-able: x0, gp, tp; Reserve: sp, ra
|
||||
// exclude: x0, ra, sp, gp, tp (0, 1, 2, 3, 4)
|
||||
static inline std::unordered_set<int> _ok_colors = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
||||
|
||||
private:
|
||||
struct MvCmp {
|
||||
bool operator()(MInstMove *const &lhs, const MInstMove *const &rhs) const {
|
||||
if (lhs->dst != rhs->dst) return lhs->dst < rhs->dst;
|
||||
if (lhs->src != rhs->src) return lhs->src < rhs->src;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
/*以下这些集合**各不相交**
|
||||
precolored:机器寄存器集合,每个寄存器都预先指派了一种颜色
|
||||
initial:临时寄存器集合,其中的元素既没有预着色,也没有被处理
|
||||
@ -57,7 +68,7 @@ private:
|
||||
void add_edge(const MOperand &u, const MOperand &v);
|
||||
void make_work_list(sptr(MFunction) func);
|
||||
bool move_related(const MOperand &n);
|
||||
std::set<sptr(MInstMove)> node_moves(const MOperand &n);
|
||||
std::set<MInstMove *, MvCmp> node_moves(const MOperand &n);
|
||||
std::set<MOperand> adjacent(const MOperand &n);
|
||||
void decrement_degree(const MOperand &m);
|
||||
void enable_moves(const MOperand &n);
|
||||
@ -66,17 +77,18 @@ private:
|
||||
void add_work_list(const MOperand &u);
|
||||
bool OK(const MOperand &t, const MOperand &r);
|
||||
bool conservative(const std::set<MOperand> &nodes);
|
||||
MOperand get_alias(MOperand n);
|
||||
MOperand get_alias(const MOperand &n);
|
||||
void combine(const MOperand &u, const MOperand &v);
|
||||
void freeze();
|
||||
void freeze_moves(const MOperand &u);
|
||||
void select_spill();
|
||||
void assign_colors(sptr(MFunction) func);
|
||||
void rewrite_program(sptr(MFunction) func);
|
||||
void clear();
|
||||
std::map<MOperand, std::set<MOperand>> adj_list;
|
||||
std::set<std::pair<MOperand, MOperand>> adj_set;
|
||||
std::map<MOperand, unsigned> degree;
|
||||
std::map<MOperand, std::set<sptr(MInstMove)>> move_list;
|
||||
std::map<MOperand, std::set<MInstMove *, MvCmp>> move_list;
|
||||
std::map<MOperand, MOperand> color;
|
||||
std::map<MOperand, MOperand> alias;
|
||||
std::set<MOperand> initial;
|
||||
@ -87,13 +99,12 @@ private:
|
||||
std::set<MOperand> coalesced_nodes;
|
||||
std::set<MOperand> colored_nodes;
|
||||
std::vector<MOperand> select_stack;
|
||||
std::set<sptr(MInstMove)> coalesced_moves;
|
||||
std::set<sptr(MInstMove)> constrained_moves;
|
||||
std::set<sptr(MInstMove)> frozen_moves;
|
||||
std::set<sptr(MInstMove)> worklist_moves;
|
||||
std::set<sptr(MInstMove)> active_moves;
|
||||
|
||||
void clear();
|
||||
std::set<MInstMove *, MvCmp> coalesced_moves;
|
||||
std::set<MInstMove *, MvCmp> constrained_moves;
|
||||
std::set<MInstMove *, MvCmp> frozen_moves;
|
||||
std::set<MInstMove *, MvCmp> worklist_moves;
|
||||
std::set<MInstMove *, MvCmp> active_moves;
|
||||
std::map<MOperand, int> spill_space;
|
||||
};
|
||||
|
||||
} // namespace CompSysY
|
||||
@ -118,6 +118,7 @@ class Compiler:
|
||||
log_file = open(log, "a+")
|
||||
Print_C.print_procedure(f"Generating {asm}")
|
||||
completed = subprocess.run(sy_asm_instr.format(asm=asm, sy=sy).split(), stdout=log_file, stderr=log_file, bufsize=1)
|
||||
# print(sy_asm_instr.format(asm=asm, sy=sy))
|
||||
log_file.close()
|
||||
if completed.returncode != 0:
|
||||
Print_C.print_error(f"Generate {bin} failed! See {log}")
|
||||
@ -233,7 +234,7 @@ scheme_ref = {
|
||||
|
||||
scheme_my = {
|
||||
"name": "my",
|
||||
"sy_ir": f"build/sysy -S {{sy}} -o {{ir}} -emit-llvm -O1",
|
||||
"sy_ir": f"build/sysy -S {{sy}} -o {{ir}} -emit-llvm -O1 -no-asm",
|
||||
"ir_asm": "llc --march=x86 --relocation-model=pic {ir} -o {asm}",
|
||||
"asm_obj": "as --32 {asm} -o {obj}",
|
||||
"obj_bin": f"clang -m32 -Ofast -fPIE {{obj}} {LIB_PATH} -o {{bin}}",
|
||||
|
||||
@ -5,15 +5,15 @@ namespace CompSysY {
|
||||
|
||||
static void _bitwise_and(std::vector<bool> &op1, const std::vector<bool> &op2) {
|
||||
for (int i = 0; i < op1.size(); ++i) {
|
||||
op1[i] = op1[i] & op2[i];
|
||||
op1[i] = op1[i] && op2[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void _bitwise_set(std::vector<bool> &op1, int l, int r, bool val) {
|
||||
for (int i = l; i < r; ++i) {
|
||||
op1[i] = val;
|
||||
}
|
||||
}
|
||||
// static void _bitwise_set(std::vector<bool> &op1, int l, int r, bool val) {
|
||||
// for (int i = l; i < r; ++i) {
|
||||
// op1[i] = val;
|
||||
// }
|
||||
// }
|
||||
|
||||
static void _gen_dom_level(BasicBlockPtr_t bb, int level) {
|
||||
bb->dom_level = level;
|
||||
@ -28,7 +28,6 @@ void gen_dominance(FunctionPtr_t func) {
|
||||
// Basic iterative idea: Dom(n) = {n} union (intersect Dom(pred(n)))
|
||||
std::vector<BasicBlockPtr_t> bb_list;
|
||||
const int N = func->bb_list.size();
|
||||
auto itr = func->bb_list.begin();
|
||||
for (auto basicblock : func->bb_list) {
|
||||
basicblock->idom_set.clear();
|
||||
basicblock->DOM_set.clear();
|
||||
@ -46,7 +45,6 @@ void gen_dominance(FunctionPtr_t func) {
|
||||
bool changed = true;
|
||||
while (changed) {
|
||||
changed = false;
|
||||
int i = 0;
|
||||
for (int i = 1; i < N; ++i) {
|
||||
auto cur_bb = bb_list[i];
|
||||
std::vector<bool> temp(N, 1);
|
||||
|
||||
@ -76,6 +76,7 @@ int main(int argc, const char **argv) {
|
||||
defaultConf.set(el::Level::Info, el::ConfigurationType::Format, "%levshort %loc %msg");
|
||||
defaultConf.set(el::Level::Verbose, el::ConfigurationType::Format, "%levshort%vlevel %loc %msg");
|
||||
defaultConf.set(el::Level::Trace, el::ConfigurationType::Format, "%levshort %msg");
|
||||
defaultConf.setGlobally(el::ConfigurationType::ToFile, "false");
|
||||
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
|
||||
el::Loggers::reconfigureLogger("default", defaultConf);
|
||||
#pragma endregion
|
||||
@ -141,9 +142,7 @@ int main(int argc, const char **argv) {
|
||||
// asm before reg alloc
|
||||
auto virt_asm_file = output_file.substr(0, output_file.rfind(".")) + "_virt.asm";
|
||||
std::ofstream ofs_virt_asm_file(virt_asm_file);
|
||||
mc_module.debug1 = true;
|
||||
mc_module.MC2ASM(ofs_virt_asm_file);
|
||||
mc_module.debug1 = false;
|
||||
mc_module.MC2ASM(ofs_virt_asm_file, true);
|
||||
ofs_virt_asm_file.close();
|
||||
|
||||
std::vector<sptr(MCPass)> mc_passes = {std::make_shared<PassRegAlloc>()};
|
||||
|
||||
@ -158,11 +158,11 @@ static void emit_cmp(std::ostream &ostr, sptr(MInstBinary) inst) {
|
||||
break;
|
||||
case MInstTag::Eq:
|
||||
ostr << fmt::format("\t{}\t{}, {}, {}", opcode, rd, rs1, rs2) << endl;
|
||||
ostr << fmt::format("\tseqz\t{}, {}, 1", rd, rd) << endl;
|
||||
ostr << fmt::format("\tseqz\t{}, {}", rd, rd) << endl;
|
||||
break;
|
||||
case MInstTag::Ne:
|
||||
ostr << fmt::format("\t{}\t{}, {}, {}", opcode, rd, rs1, rs2) << endl;
|
||||
ostr << fmt::format("\tsnez\t{}, {}, 1", rd, rd) << endl;
|
||||
ostr << fmt::format("\tsnez\t{}, {}", rd, rd) << endl;
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
@ -225,6 +225,9 @@ static void emit_load(std::ostream &ostr, sptr(MInstLoad) inst) {
|
||||
}
|
||||
|
||||
static void emit_store(std::ostream &ostr, sptr(MInstStore) inst) {
|
||||
if (!(inst->offset.is_imm() && !inst->addr.is_imm() && !inst->data.is_imm())) {
|
||||
LOG(ERROR) << "shit";
|
||||
}
|
||||
assert(inst->offset.is_imm() && !inst->addr.is_imm() && !inst->data.is_imm());
|
||||
auto data = inst->data.to_string();
|
||||
auto offset = inst->offset.to_string();
|
||||
@ -284,6 +287,9 @@ static void emit_array(std::ostream &ostr, sptr(ConstantArr) arr) {
|
||||
zero_cnt++;
|
||||
}
|
||||
}
|
||||
if (zero_cnt) {
|
||||
ostr << fmt::format("\t.zero\t{}\n", zero_cnt * 4);
|
||||
}
|
||||
}
|
||||
|
||||
static void stack_postprocess(sptr(MFunction) func) {
|
||||
@ -368,14 +374,14 @@ void emit_function(std::ostream &ostr, sptr(MFunction) func) {
|
||||
ostr << fmt::format("/* -- End Function {} --*/", func->ir_func->name) << endl;
|
||||
}
|
||||
|
||||
void MCModule::MC2ASM(std::ostream &ostr) const {
|
||||
void MCModule::MC2ASM(std::ostream &ostr, bool debug) const {
|
||||
// header, specifying align and arch
|
||||
ostr << "\t.text\n"
|
||||
<< "\t.attribute\t4,\t16\n"
|
||||
<< "\t.attribute\t5,\t\"rv64i2p0_m2p0_f2p0_d2p0\"\n";
|
||||
ostr << "\t.file\t\"" << this->file_name << "\"\n" << endl;
|
||||
for (auto func : this->function_list) {
|
||||
if (!debug1) stack_postprocess(func);
|
||||
if (!debug) stack_postprocess(func);
|
||||
emit_function(ostr, func);
|
||||
}
|
||||
|
||||
|
||||
@ -14,12 +14,17 @@ static auto gen_imm(int imm, sptr(MBasicBlock) mc_bb, bool force_reg = false) {
|
||||
return operand;
|
||||
}
|
||||
// load to register, should use pseudo `mv`
|
||||
// TODO TrivialCompiler added a opt trick here, insert before a control tansfer?
|
||||
// ! TrivialCompiler added a opt trick here, insert before a control tansfer?
|
||||
// * No, it is for phi elimination, in case you insert after a jump, which break the bb
|
||||
if (imm == 0) {
|
||||
return MOperand::PreClrReg(RV64Reg::x0);
|
||||
}
|
||||
auto vr = MOperand::VirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
auto inst_move = MInstMove::New(mc_bb);
|
||||
sptr(MInstMove) inst_move;
|
||||
if (!mc_bb->inst_list.empty() && mc_bb->inst_list.back()->is_transfer())
|
||||
inst_move = MInstMove::New(mc_bb->inst_list.back());
|
||||
else
|
||||
inst_move = MInstMove::New(mc_bb);
|
||||
inst_move->src = operand;
|
||||
inst_move->dst = vr;
|
||||
return vr;
|
||||
@ -62,7 +67,12 @@ static MOperand value2moperand(
|
||||
width = 4;
|
||||
else if (shared_cast<PointerType>(fparam->type))
|
||||
width = XLEN;
|
||||
auto inst_load = MInstLoad::New(mc_bb, width); // ld vr, (i-8)*8(sp)
|
||||
sptr(MInstLoad) inst_load;
|
||||
// ld vr, (i-8)*8(sp)
|
||||
if (!mc_bb->inst_list.empty() && mc_bb->inst_list.back()->is_transfer())
|
||||
inst_load = MInstLoad::New(mc_bb->inst_list.back(), width);
|
||||
else
|
||||
inst_load = MInstLoad::New(mc_bb, width);
|
||||
// auto inst_move = MInstMove::New(inst_load); // lui vr_t,
|
||||
inst_load->addr = MOperand::PreClrReg(RV64Reg::sp);
|
||||
inst_load->offset = MOperand::Imm((fparam_ndx - 8) * XLEN);
|
||||
@ -72,10 +82,10 @@ static MOperand value2moperand(
|
||||
return vr;
|
||||
}
|
||||
else if (auto glob = shared_cast<GlobalVar>(ir_value)) {
|
||||
auto itr = val2mop.find(ir_value);
|
||||
if (itr != val2mop.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
// auto itr = val2mop.find(ir_value);
|
||||
// if (itr != val2mop.end()) {
|
||||
// return itr->second;
|
||||
// }
|
||||
// auto inst_symld = MInstSymbol::New(mc_bb->parent_func->bb_list.front(), true);
|
||||
// auto vr = MOperand::VirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
// val2mop.insert({ir_value, vr});
|
||||
@ -86,7 +96,7 @@ static MOperand value2moperand(
|
||||
if (force_reg) {
|
||||
auto inst_la = MInstMove::New(mc_bb);
|
||||
auto vr = MOperand::VirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
val2mop.insert({ir_value, vr});
|
||||
// val2mop.insert({ir_value, vr});
|
||||
inst_la->dst = vr;
|
||||
inst_la->src = op_glob;
|
||||
return vr;
|
||||
@ -129,7 +139,7 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
this->function_list.push_back(mc_func);
|
||||
mc_func->ir_func = func;
|
||||
mc_func->id = fn_id_cnt++;
|
||||
|
||||
bb_id_cnt = 0;
|
||||
// copy pred/succ info
|
||||
std::unordered_map<sptr(BasicBlock), sptr(MBasicBlock)> bb_ir2mc;
|
||||
for (auto bb : func->bb_list) {
|
||||
@ -174,10 +184,10 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
auto addr = value2moperand(st->operand_list[1], mc_bb, mp_val2op, true);
|
||||
int width = XLEN;
|
||||
if (shared_cast<IntegerType>(st->operand_list[0]->type)) width = 4;
|
||||
auto mc_li = MInstStore::New(mc_bb, width);
|
||||
mc_li->addr = addr;
|
||||
mc_li->data = data;
|
||||
mc_li->offset = MOperand::Imm(0);
|
||||
auto mc_st = MInstStore::New(mc_bb, width);
|
||||
mc_st->addr = addr;
|
||||
mc_st->data = data;
|
||||
mc_st->offset = MOperand::Imm(0);
|
||||
continue;
|
||||
}
|
||||
if (auto gep = shared_cast<InstGEP>(inst)) {
|
||||
@ -278,7 +288,7 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
auto target_func = cal->operand_list[0];
|
||||
int nparams = cal->operand_list.size() - 1;
|
||||
for (int i = 1; i < cal->operand_list.size(); ++i) {
|
||||
auto rparam = value2moperand(cal->operand_list[i], mc_bb, mp_val2op);
|
||||
auto rparam = value2moperand(cal->operand_list[i], mc_bb, mp_val2op, true);
|
||||
if (i <= 8) {
|
||||
auto inst_move = MInstMove::New(mc_bb);
|
||||
inst_move->src = rparam;
|
||||
@ -295,7 +305,7 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
}
|
||||
if (nparams > 8) {
|
||||
// sp -= (n-8)*8
|
||||
auto add_inst = new MInstBinary(MInstTag::Sub, mc_bb);
|
||||
auto add_inst = MInstBinary::New(MInstTag::Sub, mc_bb, 8);
|
||||
add_inst->dst = MOperand::PreClrReg(RV64Reg::sp);
|
||||
add_inst->op1 = MOperand::PreClrReg(RV64Reg::sp);
|
||||
add_inst->op2 = gen_imm(XLEN * (nparams - 8), mc_bb);
|
||||
@ -306,7 +316,7 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
|
||||
if (nparams > 8) {
|
||||
// sp += (n-8)*8
|
||||
auto add_inst = new MInstBinary(MInstTag::Add, mc_bb);
|
||||
auto add_inst = MInstBinary::New(MInstTag::Add, mc_bb, 8);
|
||||
add_inst->dst = MOperand::PreClrReg(RV64Reg::sp);
|
||||
add_inst->op1 = MOperand::PreClrReg(RV64Reg::sp);
|
||||
add_inst->op2 = gen_imm(XLEN * (nparams - 8), mc_bb);
|
||||
@ -465,8 +475,6 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
LOG(WARNING) << "Condition without branch";
|
||||
}
|
||||
}
|
||||
// else if (InstTag::And <= bin->tag && bin->tag <= InstTag::Or)
|
||||
else {
|
||||
MInstTag minst_tag;
|
||||
switch (bin->tag) {
|
||||
case InstTag::Add: minst_tag = MInstTag::Add; break;
|
||||
@ -489,7 +497,6 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
inst_bin->dst = dst;
|
||||
inst_bin->op1 = mc_op1;
|
||||
inst_bin->op2 = mc_op2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (auto zxt = shared_cast<InstZext>(inst)) {
|
||||
@ -535,12 +542,16 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
par_mv_pred.insert({pred_mc_bb, {vr, phi_src_op}});
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pmv : par_mv_cur) {
|
||||
auto inst_mv = MInstMove::New(mc_bb, true);
|
||||
inst_mv->src = pmv.src;
|
||||
inst_mv->dst = pmv.dst;
|
||||
}
|
||||
for (auto &pmv_pair : par_mv_pred) {
|
||||
sysy_assert(pmv_pair.first->inst_list.back()->is_transfer(), {
|
||||
LOG(ERROR) << (int)(pmv_pair.first->inst_list.back()->inst_tag) << " " << pmv_pair.first->id;
|
||||
});
|
||||
auto inst_mv = MInstMove::New(pmv_pair.first->inst_list.back());
|
||||
inst_mv->src = pmv_pair.second.src;
|
||||
inst_mv->dst = pmv_pair.second.dst;
|
||||
@ -549,65 +560,6 @@ void MCModule::IR2MC(const Module &ir_module) {
|
||||
}
|
||||
}
|
||||
|
||||
void get_inst_defuse(sptr(MInst) inst, std::vector<MOperand> &def, std::vector<MOperand> &use) {
|
||||
if (auto bin = shared_cast<MInstBinary>(inst)) {
|
||||
def.push_back(bin->dst);
|
||||
use.push_back(bin->op1);
|
||||
use.push_back(bin->op2);
|
||||
return;
|
||||
}
|
||||
if (auto mov = shared_cast<MInstMove>(inst)) {
|
||||
def.push_back(mov->dst);
|
||||
use.push_back(mov->src);
|
||||
return;
|
||||
}
|
||||
if (auto ld = shared_cast<MInstLoad>(inst)) {
|
||||
def.push_back(ld->dst);
|
||||
use.push_back(ld->addr);
|
||||
// use.push_back(ld->offset);
|
||||
return;
|
||||
}
|
||||
if (auto st = shared_cast<MInstStore>(inst)) {
|
||||
use.push_back(st->addr);
|
||||
use.push_back(st->data);
|
||||
// use.push_back(st->offset);
|
||||
return;
|
||||
}
|
||||
if (auto cal = shared_cast<MInstCall>(inst)) {
|
||||
// arg-occupied regs get implicitly used here
|
||||
for (int i = 0; i < cal->ir_func->fparam_list.size() && i < 8; ++i) {
|
||||
use.push_back(MOperand::PreClrReg(RV64_RegOffset(RV64Reg::a0, i)));
|
||||
}
|
||||
// caller-saved regs should also be considered as re-defined
|
||||
// a0-a7
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
def.push_back(MOperand::PreClrReg(RV64_RegOffset(RV64Reg::a0, i)));
|
||||
}
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t0));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t1));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t2));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t3));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t4));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t5));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t6));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::ra));
|
||||
return;
|
||||
}
|
||||
if (auto br = shared_cast<MInstBranch>(inst)) {
|
||||
use.push_back(br->op1);
|
||||
use.push_back(br->op2);
|
||||
return;
|
||||
}
|
||||
if (auto bin = shared_cast<MInstReturn>(inst)) {
|
||||
use.push_back(MOperand::PreClrReg(RV64Reg::a0));
|
||||
return;
|
||||
}
|
||||
// if (auto sym = shared_cast<MInstSymbol>(inst)) {
|
||||
// def.push_back(sym->dst);
|
||||
// return;
|
||||
// }
|
||||
}
|
||||
|
||||
void get_inst_defuse(sptr(MInst) inst, std::vector<MOperand *> &def, std::vector<MOperand *> &use) {
|
||||
if (auto bin = shared_cast<MInstBinary>(inst)) {
|
||||
def.push_back(&bin->dst);
|
||||
@ -643,24 +595,4 @@ void get_inst_defuse(sptr(MInst) inst, std::vector<MOperand *> &def, std::vector
|
||||
// }
|
||||
}
|
||||
|
||||
void set_bb_def_use(sptr(MFunction) func) {
|
||||
for (auto bb : func->bb_list) {
|
||||
bb->def.clear();
|
||||
bb->use.clear();
|
||||
auto add_def = [&](MOperand &def) {
|
||||
if (def.need_clr()) bb->def.insert(def);
|
||||
};
|
||||
auto add_use = [&](MOperand &use) {
|
||||
if (use.need_clr()) bb->use.insert(use);
|
||||
};
|
||||
for (auto inst : bb->inst_list) {
|
||||
std::vector<MOperand> def;
|
||||
std::vector<MOperand> use;
|
||||
get_inst_defuse(inst, def, use);
|
||||
for (auto &elem : def) add_def(elem);
|
||||
for (auto &elem : use) add_use(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace CompSysY
|
||||
106
src/mc_inst.cpp
106
src/mc_inst.cpp
@ -3,11 +3,11 @@
|
||||
namespace CompSysY {
|
||||
|
||||
std::string MBasicBlock::to_string() {
|
||||
std::string str = "LBB" + std::to_string(parent_func->id) + "_" + std::to_string(id);
|
||||
std::string str = "L_BB" + std::to_string(parent_func->id) + "_" + std::to_string(id);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string MOperand::to_string() {
|
||||
std::string MOperand::to_string() const {
|
||||
std::string ret;
|
||||
switch (op_type) {
|
||||
case MOpTag::Imm: ret = fmt::format("{}", value); break;
|
||||
@ -20,85 +20,117 @@ std::string MOperand::to_string() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstBinary::get_def() {
|
||||
std::vector<MOperand> MInstBinary::get_def() const {
|
||||
return {dst};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstJump::get_def() {
|
||||
std::vector<MOperand> MInstJump::get_def() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstBranch::get_def() {
|
||||
std::vector<MOperand> MInstBranch::get_def() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstLoad::get_def() {
|
||||
std::vector<MOperand> MInstLoad::get_def() const {
|
||||
return {dst};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstStore::get_def() {
|
||||
std::vector<MOperand> MInstStore::get_def() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstMove::get_def() {
|
||||
std::vector<MOperand> MInstMove::get_def() const {
|
||||
return {dst};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstReturn::get_def() {
|
||||
std::vector<MOperand> MInstReturn::get_def() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstComment::get_def() {
|
||||
std::vector<MOperand> MInstComment::get_def() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstCall::get_def() {
|
||||
std::vector<MOperand> def;
|
||||
std::vector<MOperand> MInstCall::get_def() const {
|
||||
// caller-saved regs should also be considered as re-defined
|
||||
// a0-a7
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
def.push_back(MOperand::PreClrReg(RV64_RegOffset(RV64Reg::a0, i)));
|
||||
}
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t0));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t1));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t2));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t3));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t4));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t5));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::t6));
|
||||
def.push_back(MOperand::PreClrReg(RV64Reg::ra));
|
||||
return def;
|
||||
return {
|
||||
MOperand::PreClrReg(RV64Reg::a0),
|
||||
MOperand::PreClrReg(RV64Reg::a1),
|
||||
MOperand::PreClrReg(RV64Reg::a2),
|
||||
MOperand::PreClrReg(RV64Reg::a3),
|
||||
MOperand::PreClrReg(RV64Reg::a4),
|
||||
MOperand::PreClrReg(RV64Reg::a5),
|
||||
MOperand::PreClrReg(RV64Reg::a6),
|
||||
MOperand::PreClrReg(RV64Reg::a7),
|
||||
MOperand::PreClrReg(RV64Reg::t0),
|
||||
MOperand::PreClrReg(RV64Reg::t1),
|
||||
MOperand::PreClrReg(RV64Reg::t2),
|
||||
MOperand::PreClrReg(RV64Reg::t3),
|
||||
MOperand::PreClrReg(RV64Reg::t4),
|
||||
MOperand::PreClrReg(RV64Reg::t5),
|
||||
MOperand::PreClrReg(RV64Reg::t6),
|
||||
MOperand::PreClrReg(RV64Reg::ra),
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<MOperand> MInstBinary::get_use() {
|
||||
return {op1, op2};
|
||||
std::vector<MOperand> MInstBinary::get_use() const {
|
||||
std::vector<MOperand> use;
|
||||
if (op1.is_reg()) use.push_back(op1);
|
||||
if (op2.is_reg()) use.push_back(op2);
|
||||
return use;
|
||||
}
|
||||
std::vector<MOperand> MInstJump::get_use() {
|
||||
std::vector<MOperand> MInstJump::get_use() const {
|
||||
return {};
|
||||
}
|
||||
std::vector<MOperand> MInstBranch::get_use() {
|
||||
return {op1, op2};
|
||||
std::vector<MOperand> MInstBranch::get_use() const {
|
||||
std::vector<MOperand> use;
|
||||
if (op1.is_reg()) use.push_back(op1);
|
||||
if (op2.is_reg()) use.push_back(op2);
|
||||
return use;
|
||||
}
|
||||
std::vector<MOperand> MInstLoad::get_use() {
|
||||
std::vector<MOperand> MInstLoad::get_use() const {
|
||||
// addr must be reg, offset must not be reg
|
||||
return {addr};
|
||||
}
|
||||
std::vector<MOperand> MInstStore::get_use() {
|
||||
std::vector<MOperand> MInstStore::get_use() const {
|
||||
// both addr and data must be reg, offset must not be reg
|
||||
return {addr, data};
|
||||
}
|
||||
std::vector<MOperand> MInstMove::get_use() {
|
||||
return {src};
|
||||
std::vector<MOperand> MInstMove::get_use() const {
|
||||
std::vector<MOperand> use;
|
||||
if (src.is_reg()) use.push_back(src);
|
||||
return use;
|
||||
}
|
||||
std::vector<MOperand> MInstReturn::get_use() {
|
||||
std::vector<MOperand> MInstReturn::get_use() const {
|
||||
return {MOperand::PreClrReg(RV64Reg::a0)};
|
||||
}
|
||||
std::vector<MOperand> MInstComment::get_use() {
|
||||
std::vector<MOperand> MInstComment::get_use() const {
|
||||
return {};
|
||||
}
|
||||
std::vector<MOperand> MInstCall::get_use() {
|
||||
std::vector<MOperand> MInstCall::get_use() const {
|
||||
// arg-occupied regs get implicitly used here
|
||||
std::vector<MOperand> use;
|
||||
for (int i = 0; i < ir_func->fparam_list.size() && i < 8; ++i) {
|
||||
use.push_back(MOperand::PreClrReg(RV64_RegOffset(RV64Reg::a0, i)));
|
||||
}
|
||||
return use;
|
||||
}
|
||||
|
||||
void MInst::PostNew(sptr(MInst) inst, sptr(MBasicBlock) parent_bb, InsType ins_ty) {
|
||||
switch (ins_ty) {
|
||||
case InsType::Head: inst->itr = parent_bb->inst_list.insert(parent_bb->inst_list.begin(), inst); break;
|
||||
case InsType::Tail: inst->itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst); break;
|
||||
default: sysy_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void MInst::PostNew(sptr(MInst) inst, sptr(MInst) rel_inst, InsType ins_ty) {
|
||||
switch (ins_ty) {
|
||||
case InsType::Before:
|
||||
case InsType::After:
|
||||
default: sysy_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace CompSysY
|
||||
@ -13,17 +13,34 @@ static std::set<T> set_union(const std::set<T> &u1, const std::set<T> &u2) {
|
||||
pred/succ和前面LLIR里面的定义一致,直接是从那边复制的
|
||||
|
||||
def和use集合,说的是在一个bb里面定值/使用的变量的集合
|
||||
def[bb] = {var | var is assigned in this bb}
|
||||
use[bb] = {var | var is used in this bb }
|
||||
def[inst] = {var | var is assigned in this inst}
|
||||
:在基本块B中定值,但是定值前在B中没有被引用的变量的集合
|
||||
use[inst] = {var | var is used in this inst }
|
||||
:在基本块B中引用,但是引用前在B中没有被定值的变量集合
|
||||
live(on one edge) 存在一条从该edge通向var的一个use,且中间不经过任何的def
|
||||
live-in 一个变量在所有的in-edge上都是live的
|
||||
live-out 一个变量在所有的out-edge上都是live的
|
||||
|
||||
|
||||
data-flow equation:
|
||||
livein[n] = use[n] union (liveout[n] - def[n])
|
||||
liveout[n] = union livein[s], for s in succ[n]
|
||||
*/
|
||||
static void liveness_analysis(sptr(MFunction) func) {
|
||||
// re-set def/use for each bb
|
||||
for (auto bb : func->bb_list) {
|
||||
bb->def.clear();
|
||||
bb->use.clear();
|
||||
for (auto inst : bb->inst_list) {
|
||||
for (auto &u : inst->get_use()) {
|
||||
if (!ASSOC_FOUND(bb->def, u)) bb->use.insert(u);
|
||||
}
|
||||
for (auto &d : inst->get_def()) {
|
||||
if (!ASSOC_FOUND(bb->use, d)) bb->def.insert(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this will be run for multiple times, thus have to clear
|
||||
for (auto bb : func->bb_list) {
|
||||
bb->livein = bb->use;
|
||||
@ -49,6 +66,19 @@ static void liveness_analysis(sptr(MFunction) func) {
|
||||
}
|
||||
bb->livein = newin;
|
||||
}
|
||||
// std::set<MOperand> outquote = bb->liveout;
|
||||
// std::set<MOperand> inquote = bb->livein;
|
||||
// bb->livein = bb->use;
|
||||
// for (auto elem : bb->liveout) {
|
||||
// if (!ASSOC_FOUND(bb->def, elem)) bb->livein.insert(elem);
|
||||
// }
|
||||
// bb->liveout.clear();
|
||||
// for (auto succ : bb->succ_list) {
|
||||
// bb->liveout.insert(succ->livein.begin(), succ->livein.end());
|
||||
// }
|
||||
// if (bb->liveout != outquote || bb->livein != inquote) {
|
||||
// changed = true;
|
||||
// }
|
||||
}
|
||||
}
|
||||
LOG(TRACE) << "Live Analysis done for " << func->ir_func->name;
|
||||
@ -113,37 +143,36 @@ void PassRegAlloc::build(sptr(MFunction) func) {
|
||||
// forall I \in instructions(b) in reversed-order
|
||||
for (auto inst_it = bb->inst_list.rbegin(); inst_it != bb->inst_list.rend(); ++inst_it) {
|
||||
// if isMoveInst(I)
|
||||
std::vector<MOperand> def_I;
|
||||
std::vector<MOperand> use_I;
|
||||
get_inst_defuse(*inst_it, def_I, use_I);
|
||||
std::vector<MOperand> def_I = (*inst_it)->get_def();
|
||||
std::vector<MOperand> use_I = (*inst_it)->get_use();
|
||||
if (auto inst_mv = shared_cast<MInstMove>(*inst_it)) {
|
||||
if (inst_mv->dst.need_clr() && inst_mv->src.need_clr()) {
|
||||
// make sure it is a reg-reg move
|
||||
if (use_I.size()) {
|
||||
// live <- live - use(I)
|
||||
live.erase(inst_mv->src);
|
||||
// forall n in def(I) UNION use(I)
|
||||
// moveList[n] <- moveList[n] UNION {I}
|
||||
move_list[inst_mv->dst].insert(inst_mv);
|
||||
move_list[inst_mv->src].insert(inst_mv);
|
||||
move_list[inst_mv->dst].insert(inst_mv.get());
|
||||
move_list[inst_mv->src].insert(inst_mv.get());
|
||||
// worklistMoves <- worklistMoves UNION {I}
|
||||
worklist_moves.insert(inst_mv);
|
||||
worklist_moves.insert(inst_mv.get());
|
||||
}
|
||||
}
|
||||
// live <- live UNION def(I)
|
||||
for (auto &d : def_I) {
|
||||
if (d.need_clr()) live.insert(d);
|
||||
live.insert(d);
|
||||
}
|
||||
// forall d in def(I)
|
||||
for (auto &d : def_I) {
|
||||
if (!d.need_clr()) continue;
|
||||
// forall l in live
|
||||
for (auto &l : live) add_edge(l, d);
|
||||
}
|
||||
// live <- use(I) UNION (live - def(I))
|
||||
for (auto &d : def_I) {
|
||||
if (d.need_clr()) live.erase(d);
|
||||
live.erase(d);
|
||||
}
|
||||
for (auto &u : use_I) {
|
||||
if (u.need_clr()) live.insert(u);
|
||||
live.insert(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,9 +192,7 @@ void PassRegAlloc::make_work_list(sptr(MFunction) func) {
|
||||
else // 低度数mv无关节点表
|
||||
simplifyWorklist <- simplifyWorklist U {n}
|
||||
*/
|
||||
// initial 其实就是所有的虚拟寄存器
|
||||
for (auto i = 0; i < func->virt_reg_cnt; ++i) {
|
||||
auto vr = MOperand::VirtReg(i);
|
||||
for (auto vr : initial) {
|
||||
if (degree[vr] >= K) {
|
||||
spill_worklist.insert(vr);
|
||||
}
|
||||
@ -176,10 +203,11 @@ void PassRegAlloc::make_work_list(sptr(MFunction) func) {
|
||||
simplify_worklist.insert(vr);
|
||||
}
|
||||
}
|
||||
initial.clear();
|
||||
}
|
||||
|
||||
// movelist[n] INTERSECT (activemoves UNION worklistmoves)
|
||||
std::set<sptr(MInstMove)> PassRegAlloc::node_moves(const MOperand &n) {
|
||||
std::set<MInstMove *, PassRegAlloc::MvCmp> PassRegAlloc::node_moves(const MOperand &n) {
|
||||
// for empty set, it does not even exists, so do not use `.at(n)`
|
||||
auto ret = move_list[n];
|
||||
for (auto itr = ret.begin(); itr != ret.end();) {
|
||||
@ -247,12 +275,13 @@ void PassRegAlloc::simplify() {
|
||||
simplify_worklist.erase(simplify_worklist.begin());
|
||||
select_stack.push_back(n);
|
||||
auto adjacent_n = adjacent(n);
|
||||
for (auto &m : adjacent_n) {
|
||||
for (auto const &m : adjacent_n) {
|
||||
decrement_degree(m);
|
||||
}
|
||||
}
|
||||
|
||||
void PassRegAlloc::coalesce() {
|
||||
// for any t in Adjacent(v), s.t. OK(t,u)
|
||||
auto _adj_ok = [&](const MOperand &u, const MOperand &v) -> bool {
|
||||
auto adj_v = adjacent(v);
|
||||
for (auto &t : adj_v)
|
||||
@ -260,9 +289,11 @@ void PassRegAlloc::coalesce() {
|
||||
return true;
|
||||
};
|
||||
auto m = *worklist_moves.begin();
|
||||
auto u = get_alias(m->dst);
|
||||
auto v = get_alias(m->src);
|
||||
if (v.op_type == MOpTag::PreColor) {
|
||||
auto u = get_alias(m->dst); // x
|
||||
auto v = get_alias(m->src); // y
|
||||
// if y in precolored then (u, v) = (y, x)
|
||||
// else (u,v)=(x,y)
|
||||
if (v.is_precolored()) {
|
||||
std::swap(u, v);
|
||||
}
|
||||
worklist_moves.erase(m);
|
||||
@ -270,12 +301,12 @@ void PassRegAlloc::coalesce() {
|
||||
coalesced_moves.insert(m);
|
||||
add_work_list(u);
|
||||
}
|
||||
else if (v.op_type == MOpTag::PreColor || ASSOC_FOUND(adj_set, std::make_pair(u, v))) {
|
||||
else if (v.is_precolored() || ASSOC_FOUND(adj_set, std::make_pair(u, v))) {
|
||||
constrained_moves.insert(m);
|
||||
add_work_list(u);
|
||||
add_work_list(v);
|
||||
}
|
||||
else if ((u.op_type == MOpTag::PreColor && _adj_ok(u, v)) || (u.op_type != MOpTag::PreColor && conservative(set_union(adjacent(u), adjacent(v))))) {
|
||||
else if ((u.is_precolored() && _adj_ok(u, v)) || (!u.is_precolored() && conservative(set_union(adjacent(u), adjacent(v))))) {
|
||||
coalesced_moves.insert(m);
|
||||
combine(u, v);
|
||||
add_work_list(u);
|
||||
@ -285,19 +316,27 @@ void PassRegAlloc::coalesce() {
|
||||
}
|
||||
}
|
||||
|
||||
// 把一个节点放回去继续简化
|
||||
void PassRegAlloc::add_work_list(const MOperand &u) {
|
||||
if (u.op_type != MOpTag::PreColor && !move_related(u) && degree.at(u) < K) {
|
||||
if (!u.is_precolored() && !move_related(u) && degree.at(u) < K) {
|
||||
freeze_worklist.erase(u);
|
||||
simplify_worklist.insert(u);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
degree[t] < K || t in precolored || (t,r) in adjSet
|
||||
*/
|
||||
bool PassRegAlloc::OK(const MOperand &t, const MOperand &r) {
|
||||
return degree[t] < K || t.op_type == MOpTag::PreColor || ASSOC_FOUND(adj_set, std::make_pair(t, r));
|
||||
return degree[t] < K || t.is_precolored() || ASSOC_FOUND(adj_set, std::make_pair(t, r));
|
||||
}
|
||||
|
||||
MOperand PassRegAlloc::get_alias(MOperand n) {
|
||||
while (ASSOC_FOUND(coalesced_nodes, n)) n = alias[n];
|
||||
/*
|
||||
if n in coalescedNodes then
|
||||
GetAlias(alias[n])
|
||||
else n
|
||||
*/
|
||||
MOperand PassRegAlloc::get_alias(const MOperand &n) {
|
||||
if (ASSOC_FOUND(coalesced_nodes, n)) return get_alias(alias[n]);
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -318,10 +357,8 @@ void PassRegAlloc::combine(const MOperand &u, const MOperand &v) {
|
||||
coalesced_nodes.insert(v);
|
||||
alias[v] = u;
|
||||
// movelist[u] <- movelist[u] UNION movelist[v]
|
||||
auto &movelist_u = move_list.at(u);
|
||||
auto &movelist_v = move_list.at(v);
|
||||
for (auto mv : movelist_v) {
|
||||
movelist_u.insert(mv);
|
||||
for (auto mv : move_list.at(v)) {
|
||||
move_list[u].insert(mv);
|
||||
}
|
||||
// TODO: TrivialCompiler skipped the enablemoves below
|
||||
enable_moves(v);
|
||||
@ -344,9 +381,10 @@ void PassRegAlloc::freeze() {
|
||||
|
||||
void PassRegAlloc::freeze_moves(const MOperand &u) {
|
||||
for (auto &m : node_moves(u)) {
|
||||
auto x = get_alias(m->src);
|
||||
auto v = get_alias(m->dst);
|
||||
if (v == get_alias(u)) v = x;
|
||||
auto &x = m->dst;
|
||||
auto &y = m->src;
|
||||
auto v = get_alias(y);
|
||||
if (v == get_alias(u)) v = get_alias(x);
|
||||
active_moves.erase(m);
|
||||
frozen_moves.insert(m);
|
||||
if (node_moves(v).empty() && degree[v] < K) {
|
||||
@ -366,25 +404,24 @@ void PassRegAlloc::select_spill() {
|
||||
}
|
||||
}
|
||||
// TODO: heuristic to be improved, other than simply select the max degree
|
||||
spill_worklist.erase(m);
|
||||
simplify_worklist.insert(m);
|
||||
freeze_moves(m);
|
||||
spill_worklist.erase(m);
|
||||
}
|
||||
|
||||
void PassRegAlloc::assign_colors(sptr(MFunction) func) {
|
||||
while (!select_stack.empty()) {
|
||||
auto n = select_stack.back();
|
||||
select_stack.pop_back();
|
||||
// exclude: x0, ra, sp, gp, tp (0, 1, 2, 3, 4)
|
||||
std::unordered_set<int> ok_colors = {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
||||
// directly copy from pre-defined ok_colors
|
||||
std::unordered_set<int> ok_colors = _ok_colors;
|
||||
for (auto &w : adj_list[n]) {
|
||||
auto alias = get_alias(w);
|
||||
if (alias.op_type == MOpTag::PreColor || alias.op_type == MOpTag::Colored) {
|
||||
if (alias.op_type == MOpTag::PreColor) {
|
||||
ok_colors.erase(alias.value);
|
||||
}
|
||||
else if (ASSOC_FOUND(color, alias)) {
|
||||
auto color_alias = color[alias];
|
||||
else if (ASSOC_FOUND(colored_nodes, alias)) {
|
||||
auto color_alias = color.at(alias);
|
||||
ok_colors.erase(color_alias.value);
|
||||
}
|
||||
}
|
||||
@ -403,23 +440,16 @@ void PassRegAlloc::assign_colors(sptr(MFunction) func) {
|
||||
else
|
||||
color[n] = color[n_alias];
|
||||
}
|
||||
// patch all the color info back to the MCIR tree, note the pointer type here
|
||||
for (auto bb : func->bb_list) {
|
||||
for (auto inst : bb->inst_list) {
|
||||
std::vector<MOperand *> def;
|
||||
std::vector<MOperand *> use;
|
||||
get_inst_defuse(inst, def, use);
|
||||
for (auto d : def) {
|
||||
if (ASSOC_FOUND(color, *d)) *d = color.at(*d);
|
||||
}
|
||||
for (auto u : use) {
|
||||
if (ASSOC_FOUND(color, *u)) *u = color.at(*u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PassRegAlloc::rewrite_program(sptr(MFunction) func) {
|
||||
std::set<MOperand> new_temps;
|
||||
#if 0
|
||||
auto gen_tmp_reg = [&]() {
|
||||
auto vr = func->virt_reg_cnt++;
|
||||
new_temps.insert(MOperand::VirtReg(vr));
|
||||
return vr;
|
||||
};
|
||||
for (auto v : spilled_nodes) {
|
||||
LOG(TRACE) << "Spill node " << v.to_string();
|
||||
for (auto bb : func->bb_list) {
|
||||
@ -432,13 +462,13 @@ void PassRegAlloc::rewrite_program(sptr(MFunction) func) {
|
||||
get_inst_defuse(inst, def, use);
|
||||
for (auto d : def) {
|
||||
if (*d != v) continue;
|
||||
if (vr < 0) vr = func->virt_reg_cnt++;
|
||||
if (vr < 0) vr = gen_tmp_reg();
|
||||
d->value = vr;
|
||||
lastdef = inst;
|
||||
}
|
||||
for (auto u : use) {
|
||||
if (*u != v) continue;
|
||||
if (vr < 0) vr = func->virt_reg_cnt++;
|
||||
if (vr < 0) vr = gen_tmp_reg();
|
||||
u->value = vr;
|
||||
if (!lastdef && !firstuse) firstuse = inst;
|
||||
}
|
||||
@ -446,13 +476,15 @@ void PassRegAlloc::rewrite_program(sptr(MFunction) func) {
|
||||
}
|
||||
auto gen_off = [&](sptr(MInst) inst) {
|
||||
auto off_imm = MOperand::Imm(func->stack_size);
|
||||
return off_imm;
|
||||
if (is_in_imm_range(off_imm.value)) {
|
||||
return off_imm;
|
||||
}
|
||||
else {
|
||||
assert(0); //TODO bug here
|
||||
auto inst_mv = MInstMove::New(inst);
|
||||
inst_mv->src = off_imm;
|
||||
inst_mv->dst = MOperand::VirtReg(func->virt_reg_cnt++);
|
||||
inst_mv->dst = MOperand::VirtReg(gen_tmp_reg());
|
||||
return inst_mv->dst;
|
||||
}
|
||||
};
|
||||
@ -471,12 +503,56 @@ void PassRegAlloc::rewrite_program(sptr(MFunction) func) {
|
||||
}
|
||||
func->stack_size += XLEN;
|
||||
}
|
||||
#else
|
||||
for (auto v : spilled_nodes) {
|
||||
LOG(TRACE) << "Spill node " << v.to_string();
|
||||
for (auto bb : func->bb_list) {
|
||||
for (auto inst : bb->inst_list) {
|
||||
std::vector<MOperand *> def;
|
||||
std::vector<MOperand *> use;
|
||||
get_inst_defuse(inst, def, use);
|
||||
for (auto d : def) {
|
||||
if (*d != v) continue;
|
||||
auto vr = MOperand::VirtReg(func->virt_reg_cnt++);
|
||||
new_temps.insert(vr);
|
||||
auto inst_st = MInstStore::New(inst, XLEN, true);
|
||||
inst_st->addr = MOperand::PreClrReg(RV64Reg::sp);
|
||||
inst_st->data = vr;
|
||||
inst_st->offset = MOperand::Imm(func->stack_size);
|
||||
auto cmt = MInstComment::New(inst_st);
|
||||
cmt->comment = fmt::format("spill def {} to stack", d->to_string());
|
||||
d->value = vr.value;
|
||||
}
|
||||
for (auto u : use) {
|
||||
if (*u != v) continue;
|
||||
auto vr = MOperand::VirtReg(func->virt_reg_cnt++);
|
||||
new_temps.insert(vr);
|
||||
auto inst_ld = MInstLoad::New(inst, XLEN);
|
||||
inst_ld->addr = MOperand::PreClrReg(RV64Reg::sp);
|
||||
inst_ld->dst = vr;
|
||||
inst_ld->offset = MOperand::Imm(func->stack_size);
|
||||
auto cmt = MInstComment::New(inst_ld);
|
||||
cmt->comment = fmt::format("load from spilled use {}", u->to_string());
|
||||
u->value = vr.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
func->stack_size += XLEN;
|
||||
}
|
||||
#endif
|
||||
spilled_nodes.clear();
|
||||
initial = colored_nodes;
|
||||
initial.insert(coalesced_nodes.begin(), coalesced_nodes.end());
|
||||
initial.insert(new_temps.begin(), new_temps.end());
|
||||
colored_nodes.clear();
|
||||
coalesced_nodes.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
Internal util for initialize data structures
|
||||
*/
|
||||
void PassRegAlloc::clear() {
|
||||
// initial.clear();
|
||||
adj_list.clear();
|
||||
adj_set.clear();
|
||||
degree.clear();
|
||||
@ -495,9 +571,11 @@ void PassRegAlloc::clear() {
|
||||
frozen_moves.clear();
|
||||
worklist_moves.clear();
|
||||
active_moves.clear();
|
||||
|
||||
spill_space.clear();
|
||||
// pre-define each pre-colored register's degree as inf
|
||||
for (int reg = 0; reg < 32; ++reg) degree.insert({MOperand::PreClrReg((RV64Reg)reg), INF});
|
||||
for (int reg = 0; reg < 32; ++reg) {
|
||||
degree.insert({MOperand::PreClrReg((RV64Reg)reg), INF});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -516,10 +594,13 @@ void emit_function(std::ostream &ostr, sptr(MFunction) func);
|
||||
|
||||
void PassRegAlloc::reg_alloc(sptr(MFunction) func) {
|
||||
clear();
|
||||
set_bb_def_use(func);
|
||||
liveness_analysis(func);
|
||||
// std::ofstream dbg("dbgfunc.asm", std::ios::app);
|
||||
// emit_function(dbg, func);
|
||||
// dbg.close();
|
||||
build(func);
|
||||
make_work_list(func);
|
||||
LOG(TRACE) << "Simplify start for " << func->ir_func->name;
|
||||
bool flag = true;
|
||||
do {
|
||||
flag = false;
|
||||
@ -527,15 +608,15 @@ void PassRegAlloc::reg_alloc(sptr(MFunction) func) {
|
||||
simplify();
|
||||
flag = true;
|
||||
}
|
||||
if (!worklist_moves.empty()) {
|
||||
else if (!worklist_moves.empty()) {
|
||||
coalesce();
|
||||
flag = true;
|
||||
}
|
||||
if (!freeze_worklist.empty()) {
|
||||
else if (!freeze_worklist.empty()) {
|
||||
freeze();
|
||||
flag = true;
|
||||
}
|
||||
if (!spill_worklist.empty()) {
|
||||
else if (!spill_worklist.empty()) {
|
||||
select_spill();
|
||||
flag = true;
|
||||
}
|
||||
@ -544,7 +625,6 @@ void PassRegAlloc::reg_alloc(sptr(MFunction) func) {
|
||||
assign_colors(func);
|
||||
if (!spilled_nodes.empty()) {
|
||||
rewrite_program(func);
|
||||
emit_function(std::cout, func);
|
||||
reg_alloc(func);
|
||||
}
|
||||
}
|
||||
@ -552,7 +632,27 @@ void PassRegAlloc::reg_alloc(sptr(MFunction) func) {
|
||||
void PassRegAlloc::run(const MCModule &module) {
|
||||
for (auto func : module.function_list) {
|
||||
LOG(INFO) << "Run " << pass_name << " for func " << func->ir_func->name;
|
||||
// 初始化initial集合为所有的虚拟寄存器
|
||||
initial.clear();
|
||||
for (int i = 0; i < func->virt_reg_cnt; ++i) {
|
||||
auto vr = MOperand::VirtReg(i);
|
||||
initial.insert(vr);
|
||||
}
|
||||
reg_alloc(func);
|
||||
// patch all the color info back to the MCIR tree, note the pointer type here
|
||||
for (auto bb : func->bb_list) {
|
||||
for (auto inst : bb->inst_list) {
|
||||
std::vector<MOperand *> def;
|
||||
std::vector<MOperand *> use;
|
||||
get_inst_defuse(inst, def, use);
|
||||
for (auto d : def) {
|
||||
if (ASSOC_FOUND(color, *d)) *d = color.at(*d);
|
||||
}
|
||||
for (auto u : use) {
|
||||
if (ASSOC_FOUND(color, *u)) *u = color.at(*u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -511,7 +511,6 @@ void Visitor::llir_gen(std::ostream &ostr) {
|
||||
<< " " << 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<ArrayType>(global_var_type->pointed_type);
|
||||
auto init_value = std::dynamic_pointer_cast<ConstantArr>(global_var->init_value);
|
||||
if (init_value != nullptr) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user