set up structure for reg alloc

This commit is contained in:
2024-10-19 16:25:52 +00:00
parent 24b18756e8
commit 18105a9bf5
10 changed files with 210 additions and 32 deletions

View File

@ -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;

View File

@ -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>>

View File

@ -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

View File

@ -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");

View File

@ -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");

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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()) {

View File

@ -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);
}
}

View File

@ -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);
}