set up structure for reg alloc
This commit is contained in:
@ -248,7 +248,7 @@ class BlockItem : public LLVMIRItemBase {
|
||||
public:
|
||||
std::string label_full;
|
||||
std::unordered_map<std::string, std::shared_ptr<PhiItem>> phi_map; // this is used to store phi items when optimizing
|
||||
std::vector<std::shared_ptr<ActionItem>> actions;
|
||||
std::list<std::shared_ptr<ActionItem>> actions;
|
||||
std::shared_ptr<JMPActionItem> exit_action;
|
||||
|
||||
BlockItem() = default;
|
||||
|
@ -18,10 +18,15 @@ class CFGNodeType {
|
||||
std::vector<CFGNodeType *> successors_in_dom_tree;
|
||||
CFGNodeCollection dom_frontier;
|
||||
|
||||
std::vector<size_t> in_active_vars;
|
||||
std::vector<size_t> out_active_vars;
|
||||
std::vector<size_t> use_vars;
|
||||
std::vector<size_t> def_vars;
|
||||
std::vector<size_t> block_in_active_vars;
|
||||
std::vector<size_t> block_out_active_vars;
|
||||
std::vector<size_t> block_use_vars;
|
||||
std::vector<size_t> block_def_vars;
|
||||
|
||||
std::unordered_map<ActionItem *, std::vector<size_t>> action_use_vars;
|
||||
std::unordered_map<ActionItem *, std::vector<size_t>> action_def_vars;
|
||||
std::unordered_map<ActionItem *, std::vector<size_t>> action_in_active_vars;
|
||||
std::unordered_map<ActionItem *, std::vector<size_t>> action_out_active_vars;
|
||||
};
|
||||
|
||||
class CFGType {
|
||||
@ -30,6 +35,9 @@ class CFGType {
|
||||
CFGNodeType *entry;
|
||||
std::unordered_map<BlockItem *, CFGNodeType *> block_to_node;
|
||||
std::unordered_map<std::string, BlockItem *> label_to_block;
|
||||
std::vector<std::string> id_to_var;
|
||||
std::unordered_map<std::string, size_t> var_to_id;
|
||||
FunctionDefItem *corresponding_func;
|
||||
};
|
||||
|
||||
template <typename Container, typename Compare = std::less<typename Container::value_type>>
|
||||
|
@ -1,4 +1,36 @@
|
||||
#pragma once
|
||||
#include "IR/IR_basic.h"
|
||||
#include "cfg.h"
|
||||
#include "tools.h"
|
||||
|
||||
void LiveAnalysis(CFGType &cfg);
|
||||
void LiveAnalysis(CFGType &cfg);
|
||||
|
||||
namespace opt {
|
||||
class ForceDef : public ActionItem {
|
||||
public:
|
||||
std::string var_full;
|
||||
LLVMType ty;
|
||||
ForceDef() = default;
|
||||
void RecursivePrint(std::ostream &os) const {
|
||||
throw std::runtime_error("ForceDef instruction is not an actual LLVM IR instruction");
|
||||
}
|
||||
};
|
||||
class ForceUse : public ActionItem {
|
||||
public:
|
||||
std::string var_full;
|
||||
ForceUse() = default;
|
||||
void RecursivePrint(std::ostream &os) const {
|
||||
throw std::runtime_error("ForceUse instruction is not an actual LLVM IR instruction");
|
||||
}
|
||||
};
|
||||
class LoadSpilledArgs : public ActionItem {
|
||||
public:
|
||||
size_t arg_id; // [8,+inf)
|
||||
std::string var_full;
|
||||
LLVMType ty;
|
||||
LoadSpilledArgs() = default;
|
||||
void RecursivePrint(std::ostream &os) const {
|
||||
throw std::runtime_error("LoadSpilledArgs instruction is not an actual LLVM IR instruction");
|
||||
}
|
||||
};
|
||||
} // namespace opt
|
@ -7,6 +7,7 @@ class MoveInstruct : public ActionItem {
|
||||
public:
|
||||
std::string src_full;
|
||||
std::string dest_full;
|
||||
LLVMType ty;
|
||||
MoveInstruct() = default;
|
||||
void RecursivePrint([[maybe_unused]] std::ostream &os) const {
|
||||
throw std::runtime_error("Move instruction is not an actual LLVM IR instruction");
|
||||
|
@ -91,13 +91,13 @@ inline bool operator==(const ExprTypeInfo &l, const ExprTypeInfo &r) {
|
||||
return true;
|
||||
}
|
||||
if (std::holds_alternative<IdentifierType>(l)) {
|
||||
bool x = std::holds_alternative<IdentifierType>(r);
|
||||
// bool x = std::holds_alternative<IdentifierType>(r);
|
||||
std::string a = std::get<IdentifierType>(l);
|
||||
std::string b = std::get<IdentifierType>(r);
|
||||
return std::holds_alternative<IdentifierType>(r) && std::get<IdentifierType>(l) == std::get<IdentifierType>(r);
|
||||
}
|
||||
if (std::holds_alternative<ArrayType>(l)) {
|
||||
bool x = std::holds_alternative<ArrayType>(r);
|
||||
// bool x = std::holds_alternative<ArrayType>(r);
|
||||
return std::holds_alternative<ArrayType>(r) && std::get<ArrayType>(l) == std::get<ArrayType>(r);
|
||||
}
|
||||
throw std::runtime_error("something strange happened");
|
||||
|
@ -41,5 +41,6 @@ CFGType BuildCFGForFunction(const std::shared_ptr<FunctionDefItem> &func) {
|
||||
throw std::runtime_error("Block does not have an exit action");
|
||||
}
|
||||
}
|
||||
res.corresponding_func = func.get();
|
||||
return res;
|
||||
}
|
@ -42,8 +42,8 @@ void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector<std::string> &id_t
|
||||
std::vector<size_t> cur_node_def;
|
||||
bool use_def_init = false;
|
||||
for (auto act : block->actions) {
|
||||
std::vector<size_t> cur_act_use;
|
||||
std::vector<size_t> cur_act_def;
|
||||
std::vector<size_t> &cur_act_use = node->action_use_vars[act.get()];
|
||||
std::vector<size_t> &cur_act_def = node->action_def_vars[act.get()];
|
||||
if (auto br_act = std::dynamic_pointer_cast<BRAction>(act)) {
|
||||
if (var_to_id.find(br_act->cond) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[br_act->cond]);
|
||||
@ -153,27 +153,50 @@ void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector<std::string> &id_t
|
||||
cur_node_use = cur_act_use;
|
||||
cur_node_def = cur_act_def;
|
||||
} else {
|
||||
auto use_p = std::move(cur_node_use);
|
||||
auto def_p = std::move(cur_node_def);
|
||||
auto use_n = std::move(cur_act_use);
|
||||
auto def_n = std::move(cur_act_def);
|
||||
const auto &use_p = cur_node_use;
|
||||
const auto &def_p = cur_node_def;
|
||||
const auto &use_n = cur_act_use;
|
||||
const auto &def_n = cur_act_def;
|
||||
cur_node_use = GetCollectionsUnion(use_p, GetCollectionsDifference(use_n, def_p));
|
||||
cur_node_def = GetCollectionsUnion(def_p, use_n);
|
||||
cur_node_def = GetCollectionsUnion(def_p, def_n);
|
||||
}
|
||||
}
|
||||
node->use_vars = cur_node_use;
|
||||
node->def_vars = cur_node_def;
|
||||
{
|
||||
auto act = block->exit_action;
|
||||
std::vector<size_t> &cur_act_use = node->action_use_vars[act.get()];
|
||||
std::vector<size_t> &cur_act_def = node->action_def_vars[act.get()];
|
||||
if (auto br_act = std::dynamic_pointer_cast<BRAction>(act)) {
|
||||
if (var_to_id.find(br_act->cond) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[br_act->cond]);
|
||||
}
|
||||
} else if (auto ret_act = std::dynamic_pointer_cast<RETAction>(act)) {
|
||||
if (!std::holds_alternative<LLVMVOIDType>(ret_act->type) && var_to_id.find(ret_act->value) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[ret_act->value]);
|
||||
}
|
||||
}
|
||||
if (!use_def_init) {
|
||||
use_def_init = true;
|
||||
cur_node_use = cur_act_use;
|
||||
cur_node_def = cur_act_def;
|
||||
} else {
|
||||
const auto &use_p = cur_node_use;
|
||||
const auto &def_p = cur_node_def;
|
||||
const auto &use_n = cur_act_use;
|
||||
const auto &def_n = cur_act_def;
|
||||
cur_node_use = GetCollectionsUnion(use_p, GetCollectionsDifference(use_n, def_p));
|
||||
cur_node_def = GetCollectionsUnion(def_p, def_n);
|
||||
}
|
||||
}
|
||||
node->block_use_vars = cur_node_use;
|
||||
node->block_def_vars = cur_node_def;
|
||||
}
|
||||
}
|
||||
|
||||
void LiveAnalysis(CFGType &cfg) {
|
||||
std::vector<std::string> id_to_var;
|
||||
std::unordered_map<std::string, size_t> var_to_id;
|
||||
VarCollect(cfg, id_to_var, var_to_id);
|
||||
UseDefCollect(cfg, id_to_var, var_to_id);
|
||||
void BlockLevelTracking(CFGType &cfg, [[maybe_unused]] std::vector<std::string> &id_to_var,
|
||||
[[maybe_unused]] std::unordered_map<std::string, size_t> &var_to_id) {
|
||||
std::vector<CFGNodeType *> exists;
|
||||
for (auto node : cfg.nodes) {
|
||||
node->in_active_vars = node->use_vars;
|
||||
node->block_in_active_vars = node->block_use_vars;
|
||||
if (node->successors.size() == 0) {
|
||||
exists.push_back(node.get());
|
||||
}
|
||||
@ -200,18 +223,56 @@ void LiveAnalysis(CFGType &cfg) {
|
||||
}
|
||||
std::vector<size_t> out_active_vars;
|
||||
for (auto succ : cur_node->successors) {
|
||||
out_active_vars = GetCollectionsUnion(out_active_vars, succ->in_active_vars);
|
||||
out_active_vars = GetCollectionsUnion(out_active_vars, succ->block_in_active_vars);
|
||||
}
|
||||
if (!GetCollectionsIsSame(cur_node->out_active_vars, out_active_vars)) {
|
||||
if (!GetCollectionsIsSame(cur_node->block_out_active_vars, out_active_vars)) {
|
||||
all_data_unchanged = false;
|
||||
cur_node->out_active_vars = std::move(out_active_vars);
|
||||
cur_node->block_out_active_vars = std::move(out_active_vars);
|
||||
}
|
||||
std::vector<size_t> in_active_vars = GetCollectionsUnion(
|
||||
cur_node->use_vars, GetCollectionsDifference(cur_node->out_active_vars, cur_node->def_vars));
|
||||
if (!GetCollectionsIsSame(cur_node->in_active_vars, in_active_vars)) {
|
||||
std::vector<size_t> in_active_vars =
|
||||
GetCollectionsUnion(cur_node->block_use_vars,
|
||||
GetCollectionsDifference(cur_node->block_out_active_vars, cur_node->block_def_vars));
|
||||
if (!GetCollectionsIsSame(cur_node->block_in_active_vars, in_active_vars)) {
|
||||
all_data_unchanged = false;
|
||||
cur_node->in_active_vars = std::move(in_active_vars);
|
||||
cur_node->block_in_active_vars = std::move(in_active_vars);
|
||||
}
|
||||
}
|
||||
} while (!all_data_unchanged);
|
||||
}
|
||||
|
||||
void ActionLevelTracking(CFGType &cfg, CFGNodeType *node) {
|
||||
if (node->corresponding_block->actions.size() == 0) {
|
||||
node->action_in_active_vars[node->corresponding_block->exit_action.get()] = node->block_in_active_vars;
|
||||
node->action_out_active_vars[node->corresponding_block->exit_action.get()] = node->block_out_active_vars;
|
||||
return;
|
||||
}
|
||||
node->action_in_active_vars[node->corresponding_block->actions.front().get()] = node->block_in_active_vars;
|
||||
node->action_out_active_vars[node->corresponding_block->exit_action.get()] = node->block_out_active_vars;
|
||||
node->action_in_active_vars[node->corresponding_block->exit_action.get()] = GetCollectionsUnion(
|
||||
node->action_use_vars[node->corresponding_block->exit_action.get()],
|
||||
GetCollectionsDifference(node->action_out_active_vars[node->corresponding_block->exit_action.get()],
|
||||
node->action_def_vars[node->corresponding_block->exit_action.get()]));
|
||||
node->action_out_active_vars[node->corresponding_block->actions.back().get()] =
|
||||
node->action_in_active_vars[node->corresponding_block->exit_action.get()];
|
||||
if (node->corresponding_block->actions.size() == 1) return;
|
||||
auto it = node->corresponding_block->actions.end();
|
||||
--it;
|
||||
while (true) {
|
||||
node->action_in_active_vars[it->get()] = GetCollectionsUnion(
|
||||
node->action_use_vars[it->get()],
|
||||
GetCollectionsDifference(node->action_out_active_vars[it->get()], node->action_def_vars[it->get()]));
|
||||
auto tmp = node->action_in_active_vars[it->get()];
|
||||
--it;
|
||||
if (it == node->corresponding_block->actions.begin()) break;
|
||||
node->action_out_active_vars[it->get()] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void LiveAnalysis(CFGType &cfg) {
|
||||
VarCollect(cfg, cfg.id_to_var, cfg.var_to_id);
|
||||
UseDefCollect(cfg, cfg.id_to_var, cfg.var_to_id);
|
||||
BlockLevelTracking(cfg, cfg.id_to_var, cfg.var_to_id);
|
||||
for (auto node : cfg.nodes) {
|
||||
ActionLevelTracking(cfg, node.get());
|
||||
}
|
||||
}
|
@ -97,7 +97,7 @@ std::unordered_map<std::string, size_t> InNodeReplace(
|
||||
std::unordered_map<std::string, std::stack<std::string>> &var_to_name_stk) {
|
||||
std::unordered_map<std::string, size_t> var_to_versions_pushed;
|
||||
BlockItem *cur_block = cur_node->corresponding_block;
|
||||
std::vector<std::shared_ptr<ActionItem>> new_actions;
|
||||
std::list<std::shared_ptr<ActionItem>> new_actions;
|
||||
std::unordered_map<std::string, std::string> is_an_alias_generated_by_load;
|
||||
for (auto [origin_var_name, _] : var_to_version) {
|
||||
if (cur_block->phi_map.find(origin_var_name) != cur_block->phi_map.end()) {
|
||||
|
@ -9,7 +9,7 @@ void ConductPhiEliminateForFunction(std::shared_ptr<FunctionDefItem> func, CFGTy
|
||||
for (auto cur_node : cfg.nodes) {
|
||||
auto cur_block = cur_node->corresponding_block;
|
||||
if (cur_block->actions.size() > 0) {
|
||||
if (auto phi_act = std::dynamic_pointer_cast<PhiItem>(cur_block->actions[0])) {
|
||||
if (auto phi_act = std::dynamic_pointer_cast<PhiItem>(cur_block->actions.front())) {
|
||||
// simple phi action caused by and, or and ternary operator, no need to insert extra blocks, just remove it and
|
||||
// add phi values to the corresponding blocks
|
||||
cur_block->actions.erase(cur_block->actions.begin());
|
||||
@ -18,6 +18,7 @@ void ConductPhiEliminateForFunction(std::shared_ptr<FunctionDefItem> func, CFGTy
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = src_val;
|
||||
new_move->dest_full = phi_act->result_full;
|
||||
new_move->ty = phi_act->ty;
|
||||
src_block->actions.push_back(new_move);
|
||||
}
|
||||
}
|
||||
@ -32,6 +33,7 @@ void ConductPhiEliminateForFunction(std::shared_ptr<FunctionDefItem> func, CFGTy
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = src_val;
|
||||
new_move->dest_full = phi_act->result_full;
|
||||
new_move->ty = phi_act->ty;
|
||||
src_block->actions.push_back(new_move);
|
||||
} else if (src_node->successors.size() > 1 && cur_node->predecessors.size() > 1) {
|
||||
// it is a critical edge, need to insert a new block
|
||||
@ -59,11 +61,13 @@ void ConductPhiEliminateForFunction(std::shared_ptr<FunctionDefItem> func, CFGTy
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = src_val;
|
||||
new_move->dest_full = phi_act->result_full;
|
||||
new_move->ty = phi_act->ty;
|
||||
new_block->actions.push_back(new_move);
|
||||
} else {
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = src_val;
|
||||
new_move->dest_full = phi_act->result_full;
|
||||
new_move->ty = phi_act->ty;
|
||||
cur_block->actions.push_back(new_move);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,77 @@
|
||||
#include "regalloc.h"
|
||||
#include "IR/IR_basic.h"
|
||||
#include "liveanalysis.h"
|
||||
#include "tools.h"
|
||||
|
||||
// RISC-V calling convention compatible
|
||||
static std::vector<std::string> held_tmp_regs = {"x28", "x29", "x30", "x31"};
|
||||
static std::vector<std::string> callee_saved_regs = {"x3", "x4", "x9", "x18", "x19", "x20", "x21",
|
||||
"x22", "x23", "x24", "x25", "x26", "x27"};
|
||||
static std::vector<std::string> caller_saved_regs = {"x5", "x6", "x7", "x10", "x11", "x12",
|
||||
"x13", "x14", "x15", "x16", "x17"};
|
||||
static std::vector<std::string> arg_regs = {"x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"};
|
||||
static std::string zero = "x0", sp = "x2", ra = "x1", fp = "x8";
|
||||
void EnforcePhysicalRegs(CFGType &cfg) {
|
||||
using namespace opt;
|
||||
// process callee side
|
||||
auto entry_node = cfg.entry;
|
||||
auto func = cfg.corresponding_func;
|
||||
for (size_t i = 0; i < 8 && i < func->args_full_name.size(); i++) {
|
||||
auto new_def = std::make_shared<ForceDef>();
|
||||
new_def->var_full = "%reg." + arg_regs[i];
|
||||
new_def->ty = func->args[i];
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = "%reg." + arg_regs[i];
|
||||
new_move->dest_full = func->args_full_name[i];
|
||||
new_move->ty = func->args[i];
|
||||
entry_node->corresponding_block->actions.push_front(new_move);
|
||||
entry_node->corresponding_block->actions.push_front(new_def);
|
||||
}
|
||||
for (size_t i = 8; i < func->args_full_name.size(); i++) {
|
||||
auto arg_load = std::make_shared<LoadSpilledArgs>();
|
||||
arg_load->arg_id = i;
|
||||
arg_load->var_full = func->args_full_name[i];
|
||||
arg_load->ty = func->args[i];
|
||||
entry_node->corresponding_block->actions.push_front(arg_load);
|
||||
}
|
||||
for (auto callee_saved_reg : callee_saved_regs) {
|
||||
auto new_def = std::make_shared<ForceDef>();
|
||||
new_def->var_full = "%reg." + callee_saved_reg;
|
||||
new_def->ty = LLVMIRIntType(32);
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = new_def->var_full;
|
||||
new_move->dest_full = "%calleesave." + callee_saved_reg;
|
||||
new_move->ty = LLVMIRIntType(32);
|
||||
entry_node->corresponding_block->actions.push_front(new_move);
|
||||
entry_node->corresponding_block->actions.push_front(new_def);
|
||||
}
|
||||
for (auto node : cfg.nodes) {
|
||||
auto block = node->corresponding_block;
|
||||
if (std::dynamic_pointer_cast<RETAction>(block->exit_action)) {
|
||||
for (auto callee_saved_reg : callee_saved_regs) {
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = "%calleesave." + callee_saved_reg;
|
||||
new_move->dest_full = "%reg." + callee_saved_reg;
|
||||
new_move->ty = LLVMIRIntType(32);
|
||||
auto new_use = std::make_shared<ForceUse>();
|
||||
new_use->var_full = "%reg." + callee_saved_reg;
|
||||
block->actions.push_back(new_move);
|
||||
block->actions.push_back(new_use);
|
||||
}
|
||||
if (!std::holds_alternative<LLVMVOIDType>(std::dynamic_pointer_cast<RETAction>(block->exit_action)->type)) {
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = std::dynamic_pointer_cast<RETAction>(block->exit_action)->value;
|
||||
new_move->dest_full = "%reg.x10";
|
||||
new_move->ty = std::dynamic_pointer_cast<RETAction>(block->exit_action)->type;
|
||||
block->actions.push_back(new_move);
|
||||
std::dynamic_pointer_cast<RETAction>(block->exit_action)->value = "%reg.x10";
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: process caller side
|
||||
}
|
||||
void ConductRegAllocForFunction([[maybe_unused]] std::shared_ptr<FunctionDefItem> func, CFGType &cfg) {
|
||||
EnforcePhysicalRegs(cfg);
|
||||
LiveAnalysis(cfg);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user