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