finish live analysis
This commit is contained in:
@ -1,95 +1,12 @@
|
||||
#include "cfg.h"
|
||||
#include <string>
|
||||
CFGNodeCollection GetCFGNodeCollectionsIntersection(const CFGNodeCollection &a, const CFGNodeCollection &b) {
|
||||
// assume that thety are both sorted
|
||||
CFGNodeCollection res;
|
||||
auto ita = a.begin();
|
||||
auto itb = b.begin();
|
||||
while (ita != a.end() && itb != b.end()) {
|
||||
if (*ita == *itb) {
|
||||
res.push_back(*ita);
|
||||
ita++;
|
||||
itb++;
|
||||
} else if (*ita < *itb) {
|
||||
ita++;
|
||||
} else {
|
||||
itb++;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CFGNodeCollection GetCFGNodeCollectionsUnion(const CFGNodeCollection &a, const CFGNodeCollection &b) {
|
||||
// assume that thety are both sorted
|
||||
CFGNodeCollection res;
|
||||
auto ita = a.begin();
|
||||
auto itb = b.begin();
|
||||
while (ita != a.end() && itb != b.end()) {
|
||||
if (*ita == *itb) {
|
||||
res.push_back(*ita);
|
||||
ita++;
|
||||
itb++;
|
||||
} else if (*ita < *itb) {
|
||||
res.push_back(*ita);
|
||||
ita++;
|
||||
} else {
|
||||
res.push_back(*itb);
|
||||
itb++;
|
||||
}
|
||||
}
|
||||
while (ita != a.end()) {
|
||||
res.push_back(*ita);
|
||||
ita++;
|
||||
}
|
||||
while (itb != b.end()) {
|
||||
res.push_back(*itb);
|
||||
itb++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CFGNodeCollection GetCFGNodeCollectionsDifference(const CFGNodeCollection &a, const CFGNodeCollection &b) {
|
||||
// assume that thety are both sorted
|
||||
CFGNodeCollection res;
|
||||
auto ita = a.begin();
|
||||
auto itb = b.begin();
|
||||
while (ita != a.end() && itb != b.end()) {
|
||||
if (*ita == *itb) {
|
||||
ita++;
|
||||
itb++;
|
||||
} else if (*ita < *itb) {
|
||||
res.push_back(*ita);
|
||||
ita++;
|
||||
} else {
|
||||
itb++;
|
||||
}
|
||||
}
|
||||
while (ita != a.end()) {
|
||||
res.push_back(*ita);
|
||||
ita++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CFGNodeCollectionIsSame(const CFGNodeCollection &a, const CFGNodeCollection &b) {
|
||||
auto ita = a.begin();
|
||||
auto itb = b.begin();
|
||||
while (ita != a.end() && itb != b.end()) {
|
||||
if (*ita != *itb) {
|
||||
return false;
|
||||
}
|
||||
ita++;
|
||||
itb++;
|
||||
}
|
||||
return ita == a.end() && itb == b.end();
|
||||
}
|
||||
|
||||
CFGType BuildCFGForFunction(const std::shared_ptr<FunctionDefItem> &func) {
|
||||
CFGType res;
|
||||
auto init_block=func->init_block;
|
||||
auto init_block = func->init_block;
|
||||
if (!func->init_block) {
|
||||
// throw std::runtime_error("Function does not have an init block");
|
||||
if(func->basic_blocks.size()==0) throw std::runtime_error("Function does not have any block");
|
||||
if (func->basic_blocks.size() == 0) throw std::runtime_error("Function does not have any block");
|
||||
init_block = func->basic_blocks[0];
|
||||
}
|
||||
res.label_to_block[init_block->label_full] = init_block.get();
|
||||
|
217
src/opt/liveanalysis.cpp
Normal file
217
src/opt/liveanalysis.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include "liveanalysis.h"
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
#include "IR/IR_basic.h"
|
||||
#include "cfg.h"
|
||||
#include "tools.h"
|
||||
|
||||
void VarCollect(CFGType &cfg, std::vector<std::string> &id_to_var, std::unordered_map<std::string, size_t> &var_to_id) {
|
||||
for (auto node : cfg.nodes) {
|
||||
auto block = node->corresponding_block;
|
||||
for (auto act : block->actions) {
|
||||
if (auto bin_act = std::dynamic_pointer_cast<BinaryOperationAction>(act)) {
|
||||
id_to_var.push_back(bin_act->result_full);
|
||||
var_to_id[bin_act->result_full] = id_to_var.size() - 1;
|
||||
} else if (auto load_act = std::dynamic_pointer_cast<LoadAction>(act)) {
|
||||
id_to_var.push_back(load_act->result_full);
|
||||
var_to_id[load_act->result_full] = id_to_var.size() - 1;
|
||||
} else if (auto get_act = std::dynamic_pointer_cast<GetElementPtrAction>(act)) {
|
||||
id_to_var.push_back(get_act->result_full);
|
||||
var_to_id[get_act->result_full] = id_to_var.size() - 1;
|
||||
} else if (auto icmp_act = std::dynamic_pointer_cast<ICMPAction>(act)) {
|
||||
id_to_var.push_back(icmp_act->result_full);
|
||||
var_to_id[icmp_act->result_full] = id_to_var.size() - 1;
|
||||
} else if (auto call_act = std::dynamic_pointer_cast<CallItem>(act)) {
|
||||
if (!std::holds_alternative<LLVMVOIDType>(call_act->return_type)) {
|
||||
id_to_var.push_back(call_act->result_full);
|
||||
var_to_id[call_act->result_full] = id_to_var.size() - 1;
|
||||
}
|
||||
} else if (auto select_act = std::dynamic_pointer_cast<SelectItem>(act)) {
|
||||
id_to_var.push_back(select_act->result_full);
|
||||
var_to_id[select_act->result_full] = id_to_var.size() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UseDefCollect(CFGType &cfg, [[maybe_unused]] std::vector<std::string> &id_to_var,
|
||||
std::unordered_map<std::string, size_t> &var_to_id) {
|
||||
for (auto node : cfg.nodes) {
|
||||
auto block = node->corresponding_block;
|
||||
std::vector<size_t> cur_node_use;
|
||||
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;
|
||||
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]);
|
||||
}
|
||||
} else if (auto bin_act = std::dynamic_pointer_cast<BinaryOperationAction>(act)) {
|
||||
if (var_to_id.find(bin_act->operand1_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[bin_act->operand1_full]);
|
||||
}
|
||||
if (bin_act->operand2_full != bin_act->operand1_full &&
|
||||
var_to_id.find(bin_act->operand2_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[bin_act->operand2_full]);
|
||||
}
|
||||
if (var_to_id.find(bin_act->result_full) != var_to_id.end()) {
|
||||
cur_act_def.push_back(var_to_id[bin_act->result_full]);
|
||||
}
|
||||
} else if (auto load_act = std::dynamic_pointer_cast<LoadAction>(act)) {
|
||||
if (var_to_id.find(load_act->ptr_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[load_act->ptr_full]);
|
||||
}
|
||||
if (var_to_id.find(load_act->result_full) != var_to_id.end()) {
|
||||
cur_act_def.push_back(var_to_id[load_act->result_full]);
|
||||
}
|
||||
} else if (auto store_act = std::dynamic_pointer_cast<StoreAction>(act)) {
|
||||
if (var_to_id.find(store_act->value_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[store_act->value_full]);
|
||||
}
|
||||
if (store_act->ptr_full == store_act->value_full)
|
||||
throw std::runtime_error("store action should not have the same ptr and value");
|
||||
if (var_to_id.find(store_act->ptr_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[store_act->ptr_full]);
|
||||
}
|
||||
} else if (auto get_act = std::dynamic_pointer_cast<GetElementPtrAction>(act)) {
|
||||
std::unordered_set<std::string> used_vars;
|
||||
if (var_to_id.find(get_act->ptr_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[get_act->ptr_full]);
|
||||
used_vars.insert(get_act->ptr_full);
|
||||
}
|
||||
for (auto idx : get_act->indices) {
|
||||
if (used_vars.find(idx) != used_vars.end()) continue;
|
||||
if (var_to_id.find(idx) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[idx]);
|
||||
used_vars.insert(idx);
|
||||
}
|
||||
}
|
||||
if (var_to_id.find(get_act->result_full) != var_to_id.end()) {
|
||||
cur_act_def.push_back(var_to_id[get_act->result_full]);
|
||||
}
|
||||
} else if (auto icmp_act = std::dynamic_pointer_cast<ICMPAction>(act)) {
|
||||
if (var_to_id.find(icmp_act->operand1_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[icmp_act->operand1_full]);
|
||||
}
|
||||
if (icmp_act->operand2_full != icmp_act->operand1_full &&
|
||||
var_to_id.find(icmp_act->operand2_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[icmp_act->operand2_full]);
|
||||
}
|
||||
if (var_to_id.find(icmp_act->result_full) != var_to_id.end()) {
|
||||
cur_act_def.push_back(var_to_id[icmp_act->result_full]);
|
||||
}
|
||||
} else if (auto call_act = std::dynamic_pointer_cast<CallItem>(act)) {
|
||||
std::unordered_set<std::string> used_vars;
|
||||
for (auto arg : call_act->args_val_full) {
|
||||
if (used_vars.find(arg) != used_vars.end()) continue;
|
||||
if (var_to_id.find(arg) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[arg]);
|
||||
used_vars.insert(arg);
|
||||
}
|
||||
}
|
||||
if (!std::holds_alternative<LLVMVOIDType>(call_act->return_type) &&
|
||||
var_to_id.find(call_act->result_full) != var_to_id.end()) {
|
||||
cur_act_def.push_back(var_to_id[call_act->result_full]);
|
||||
}
|
||||
} else if (auto select_act = std::dynamic_pointer_cast<SelectItem>(act)) {
|
||||
if (var_to_id.find(select_act->cond_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[select_act->cond_full]);
|
||||
}
|
||||
if (select_act->true_val_full != select_act->cond_full &&
|
||||
var_to_id.find(select_act->true_val_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[select_act->true_val_full]);
|
||||
}
|
||||
if (select_act->false_val_full != select_act->cond_full &&
|
||||
select_act->false_val_full != select_act->cond_full &&
|
||||
var_to_id.find(select_act->false_val_full) != var_to_id.end()) {
|
||||
cur_act_use.push_back(var_to_id[select_act->false_val_full]);
|
||||
}
|
||||
if (var_to_id.find(select_act->result_full) != var_to_id.end()) {
|
||||
cur_act_def.push_back(var_to_id[select_act->result_full]);
|
||||
}
|
||||
}
|
||||
std::sort(cur_act_use.begin(), cur_act_use.end());
|
||||
std::sort(cur_act_def.begin(), cur_act_def.end());
|
||||
for (size_t i = 1; i < cur_act_use.size(); i++) {
|
||||
if (cur_act_use[i] == cur_act_use[i - 1]) {
|
||||
throw std::runtime_error("use variable appears twice in one action");
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < cur_act_def.size(); i++) {
|
||||
if (cur_act_def[i] == cur_act_def[i - 1]) {
|
||||
throw std::runtime_error("def variable appears twice in one action");
|
||||
}
|
||||
}
|
||||
if (!use_def_init) {
|
||||
use_def_init = true;
|
||||
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);
|
||||
cur_node_use = GetCollectionsUnion(use_p, GetCollectionsDifference(use_n, def_p));
|
||||
cur_node_def = GetCollectionsUnion(def_p, use_n);
|
||||
}
|
||||
}
|
||||
node->use_vars = cur_node_use;
|
||||
node->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);
|
||||
std::vector<CFGNodeType *> exists;
|
||||
for (auto node : cfg.nodes) {
|
||||
node->in_active_vars = node->use_vars;
|
||||
if (node->successors.size() == 0) {
|
||||
exists.push_back(node.get());
|
||||
}
|
||||
}
|
||||
bool all_data_unchanged;
|
||||
do {
|
||||
all_data_unchanged = true;
|
||||
for (auto node : cfg.nodes) {
|
||||
node->visited = false;
|
||||
}
|
||||
std::queue<CFGNodeType *> Q;
|
||||
for (auto e : exists) {
|
||||
Q.push(e);
|
||||
e->visited = true;
|
||||
}
|
||||
while (Q.size() > 0) {
|
||||
auto cur_node = Q.front();
|
||||
Q.pop();
|
||||
for (auto pred : cur_node->predecessors) {
|
||||
if (!pred->visited) {
|
||||
pred->visited = true;
|
||||
Q.push(pred);
|
||||
}
|
||||
}
|
||||
std::vector<size_t> out_active_vars;
|
||||
for (auto succ : cur_node->successors) {
|
||||
out_active_vars = GetCollectionsUnion(out_active_vars, succ->in_active_vars);
|
||||
}
|
||||
if (!GetCollectionsIsSame(cur_node->out_active_vars, out_active_vars)) {
|
||||
all_data_unchanged = false;
|
||||
cur_node->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)) {
|
||||
all_data_unchanged = false;
|
||||
cur_node->in_active_vars = std::move(in_active_vars);
|
||||
}
|
||||
}
|
||||
} while (!all_data_unchanged);
|
||||
}
|
@ -36,11 +36,11 @@ void BuildDomForFunction(const std::shared_ptr<FunctionDefItem> &func, const CFG
|
||||
if (cur->predecessors.size() > 0) {
|
||||
CFGNodeCollection tmp = cur->predecessors[0]->dom;
|
||||
for (size_t i = 1; i < cur->predecessors.size(); i++) {
|
||||
tmp = GetCFGNodeCollectionsIntersection(tmp, cur->predecessors[i]->dom);
|
||||
tmp = GetCollectionsIntersection(tmp, cur->predecessors[i]->dom);
|
||||
}
|
||||
new_dom = GetCFGNodeCollectionsUnion(new_dom, tmp);
|
||||
new_dom = GetCollectionsUnion(new_dom, tmp);
|
||||
}
|
||||
if (!CFGNodeCollectionIsSame(new_dom, cur->dom)) {
|
||||
if (!GetCollectionsIsSame(new_dom, cur->dom)) {
|
||||
all_dom_unchanged = false;
|
||||
cur->dom = new_dom;
|
||||
}
|
||||
@ -59,10 +59,10 @@ void BuildDomForFunction(const std::shared_ptr<FunctionDefItem> &func, const CFG
|
||||
for (auto node : cfg.nodes) {
|
||||
CFGNodeCollection is_frontier_of;
|
||||
CFGNodeCollection tmp1 = {node.get()};
|
||||
tmp1 = GetCFGNodeCollectionsDifference(node->dom, tmp1);
|
||||
tmp1 = GetCollectionsDifference(node->dom, tmp1);
|
||||
for (auto pred : node->predecessors) {
|
||||
CFGNodeCollection tmp2 = GetCFGNodeCollectionsDifference(pred->dom, tmp1);
|
||||
is_frontier_of = GetCFGNodeCollectionsUnion(is_frontier_of, tmp2);
|
||||
CFGNodeCollection tmp2 = GetCollectionsDifference(pred->dom, tmp1);
|
||||
is_frontier_of = GetCollectionsUnion(is_frontier_of, tmp2);
|
||||
}
|
||||
for (auto frontier_node : is_frontier_of) {
|
||||
frontier_node->dom_frontier.push_back(node.get());
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
using namespace opt;
|
||||
|
||||
void ConductPhiEliminateForFunction([[maybe_unused]] std::shared_ptr<FunctionDefItem> func, CFGType &cfg) {
|
||||
void ConductPhiEliminateForFunction(std::shared_ptr<FunctionDefItem> func, CFGType &cfg) {
|
||||
size_t new_block_cnt = 0;
|
||||
for (auto cur_node : cfg.nodes) {
|
||||
auto cur_block = cur_node->corresponding_block;
|
||||
@ -22,14 +22,23 @@ void ConductPhiEliminateForFunction([[maybe_unused]] std::shared_ptr<FunctionDef
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unordered_map<std::string, BlockItem *> src_changed;
|
||||
for (auto [_, phi_act] : cur_block->phi_map) {
|
||||
for (auto [src_val, src_label] : phi_act->values) {
|
||||
auto src_block = cfg.label_to_block[src_label];
|
||||
auto src_node = cfg.block_to_node[src_block];
|
||||
if (src_node->successors.size() > 1 && cur_node->predecessors.size() > 1) {
|
||||
if (src_changed.find(src_label) != src_changed.end()) {
|
||||
src_block = src_changed[src_label];
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = src_val;
|
||||
new_move->dest_full = phi_act->result_full;
|
||||
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
|
||||
auto new_block = std::make_shared<BlockItem>();
|
||||
func->basic_blocks.push_back(new_block);
|
||||
new_block->label_full = cur_block->label_full + ".phieliminate." + std::to_string(new_block_cnt++);
|
||||
src_changed[src_label] = new_block.get();
|
||||
new_block->exit_action = std::make_shared<UNConditionJMPAction>();
|
||||
std::dynamic_pointer_cast<UNConditionJMPAction>(new_block->exit_action)->label_full = cur_block->label_full;
|
||||
auto src_block_exit_action = std::dynamic_pointer_cast<BRAction>(src_block->exit_action);
|
||||
@ -43,7 +52,9 @@ void ConductPhiEliminateForFunction([[maybe_unused]] std::shared_ptr<FunctionDef
|
||||
src_block_exit_action->false_label_full = new_block->label_full;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"something strange happened: src block of a critical edge cannot find the corresponding label");
|
||||
"something strange happened: src block of a critical edge cannot find the corresponding label, src "
|
||||
"block label=" +
|
||||
src_block->label_full);
|
||||
}
|
||||
auto new_move = std::make_shared<MoveInstruct>();
|
||||
new_move->src_full = src_val;
|
||||
|
@ -1 +1,15 @@
|
||||
#include "regalloc.h"
|
||||
#include "regalloc.h"
|
||||
|
||||
void ConductRegAllocForFunction([[maybe_unused]] std::shared_ptr<FunctionDefItem> func, CFGType &cfg) {
|
||||
LiveAnalysis(cfg);
|
||||
}
|
||||
|
||||
std::shared_ptr<ModuleItem> RegAlloc(std::shared_ptr<ModuleItem> src) {
|
||||
auto res = src;
|
||||
for (auto &func : res->function_defs) {
|
||||
// func = std::make_shared<FunctionDefItem>(*func);
|
||||
auto cfg = BuildCFGForFunction(func);
|
||||
ConductRegAllocForFunction(func, cfg);
|
||||
}
|
||||
return res;
|
||||
}
|
Reference in New Issue
Block a user