buggy mem2reg

This commit is contained in:
ridethepig 2023-05-20 10:46:46 +08:00
parent 7140d0bf2b
commit 2a36406e3d
16 changed files with 1831 additions and 160 deletions

2
.vscode/launch.json vendored
View File

@ -9,7 +9,7 @@
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/sysy",
"args": ["testcases/functional/64_calculator.sy", "-S", "-o", "build/manual-test/21_my.ll"],
"args": ["../sysytests/functional_2022/21_if_test2.sy", "-S", "-o", "build/21_my.ll", "-emit-llvm"],
"cwd": "${workspaceFolder}"
}
]

View File

@ -21,7 +21,8 @@ file(GLOB MY_HEADERS "include/*.h")
include(formatting.cmake)
clang_format(format ${MY_SOURCES} ${MY_HEADERS})
# clang_format_check(format_check ${MY_SOURCES} ${MY_HEADERS})
# add_compile_options(-fsanitize=address)
# add_link_options(-fsanitize=address)
add_executable(sysy ${SOURCES})
# message(STATUS "${SOURCES}")
target_link_libraries(sysy antlr4_static)
target_link_libraries(sysy antlr4_static)

1201
docs/LLVM-promoteAlloca.cpp Normal file

File diff suppressed because it is too large Load Diff

11
include/algos.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "llir.h"
#include "passes.h"
namespace antlrSysY {
void gen_dominance(FunctionPtr_t func);
void gen_dominance_frontier(FunctionPtr_t func);
void update_dfs_numbers(BasicBlockPtr_t bb, bool rst);
} // namespace antlrSysY

View File

@ -16,6 +16,10 @@
if (!(cond)) throw GrammarException(__FILE__, __LINE__, #cond); \
} while (0)
#define DEF_PTR_T(type) \
class type; \
typedef std::shared_ptr<type> type##Ptr_t
namespace antlrSysY {
template <typename T>

View File

@ -7,6 +7,18 @@
#include <string>
namespace antlrSysY {
DEF_PTR_T(InstAlloca);
DEF_PTR_T(InstStore);
DEF_PTR_T(InstLoad);
DEF_PTR_T(InstBinary);
DEF_PTR_T(InstZext);
DEF_PTR_T(InstBranch);
DEF_PTR_T(InstReturn);
DEF_PTR_T(InstCall);
DEF_PTR_T(InstGEP);
DEF_PTR_T(InstPhi);
enum class InstTag {
Add,
Sub,
@ -41,6 +53,7 @@ public:
int ir_seqno = -1;
InstTag tag;
BasicBlockPtr_t parent_bb;
// decltype(parent_bb->inst_list.begin()) inst_itr_in_parent;
Instruction(InstTag inst_tag, TypePtr_t type, BasicBlockPtr_t parent_bb)
: User("", type), tag(inst_tag), parent_bb(parent_bb) {}
virtual std::string to_string() override {
@ -235,4 +248,28 @@ public:
}
};
class InstPhi : public Instruction {
public:
InstPhi(TypePtr_t type, const decltype(Function::bb_list) &incoming_vals, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Phi, type, parent_bb) {
for (auto incoming : incoming_vals) {
Add_Operand(incoming);
}
}
void set_incoming_val(unsigned index, ValuePtr_t val) {
auto old_op = operand_list[index];
operand_list[index] = val;
if (val) val->use_list.push_back({val, this, index});
if (old_op) {
if (std::find(operand_list.begin(), operand_list.end(), old_op) == operand_list.end()) {
old_op->u_remove_use(this);
}
}
}
virtual std::string to_IR_string() override {
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
return str;
}
};
} // namespace antlrSysY

View File

@ -4,10 +4,17 @@
#include <memory>
#include <string>
#include <vector>
#include <cassert>
namespace antlrSysY {
class Type;
typedef std::shared_ptr<Type> TypePtr_t;
DEF_PTR_T(Type);
DEF_PTR_T(IntegerType);
DEF_PTR_T(VoidType);
DEF_PTR_T(LabelType);
DEF_PTR_T(ArrayType);
DEF_PTR_T(PointerType);
DEF_PTR_T(FunctionType);
class Type {
public:
@ -139,6 +146,12 @@ public:
virtual std::string to_IR_string() override {
return pointed_type->to_IR_string() + "*";
}
static TypePtr_t pointedType(TypePtr_t ptr) {
assert(Type::isType<PointerType>(ptr));
auto pointer_type = Type::asType<PointerType>(ptr);
return pointer_type->pointed_type;
}
};
class FunctionType : public Type {

View File

@ -8,29 +8,33 @@
#include <memory>
#include <shared_mutex>
#include <string>
#include <vector>
#include <tuple>
#include <vector>
namespace antlrSysY {
class Value;
class BasicBlock;
class User;
class Function;
class Instruction;
typedef std::shared_ptr<Value> ValuePtr_t;
typedef std::shared_ptr<BasicBlock> BasicBlockPtr_t;
typedef std::shared_ptr<Function> FunctionPtr_t;
typedef std::shared_ptr<User> UserPtr_t;
typedef std::shared_ptr<Instruction> InstructionPtr_t;
typedef std::tuple<ValuePtr_t, UserPtr_t, int> UseEdge_t;
DEF_PTR_T(Value);
DEF_PTR_T(BasicBlock);
DEF_PTR_T(User);
DEF_PTR_T(Function);
DEF_PTR_T(Instruction);
DEF_PTR_T(Constant);
DEF_PTR_T(ConstantInt);
// typedef std::tuple<ValuePtr_t, UserPtr_t, int> UseEdge_t;
struct Use {
ValuePtr_t value;
User* user;
unsigned op_index;
};
// Define, User, operand-index
// for Instruction, inst `uses` op, so inst is the user
class Value {
public:
std::string name;
TypePtr_t type;
std::list<UseEdge_t> use_list;
std::list<Use> use_list; // a list of use-edge from this value
Value(const std::string &name, TypePtr_t type) : name(name), type(type) {}
virtual ~Value() = default;
@ -60,8 +64,24 @@ public:
virtual std::string to_IR_string() {
panic("No applicable for IR gen");
}
};
void u_remove_use(User* user) {
// use_list.erase(
// std::remove_if(
// use_list.begin(), use_list.end(), [user](const UseEdge_t &use) { return std::get<1>(use) == user; }
// ),
// use_list.end()
// );
for (auto itr = use_list.begin(); itr != use_list.end();) {
if (itr->user == user) {
itr = use_list.erase(itr);
}
else {
++ itr;
}
}
}
};
class User : public Value {
public:
@ -69,14 +89,34 @@ public:
User(const std::string &name, TypePtr_t type) : Value(name, type) {}
void Add_Operand(ValuePtr_t op) {
op->use_list.push_back({op, this, (unsigned)operand_list.size()});
operand_list.push_back(op);
use_list.push_back({op, std::make_shared<User>(this), operand_list.size()});
}
// make anything that use this value use the new value
void u_replace_users(ValuePtr_t value) {
if (value == nullptr) {
assert(!use_list.size() && "No one should use this");
return;
}
for (auto use : use_list) {
auto user = use.user;
auto index = use.op_index;
user->operand_list[index] = value;
assert(value);
value->use_list.push_back({value, user, index});
}
// all original uses are gone
use_list.clear();
}
// remove this user from its operands
void u_remove_from_usees() {
for (auto op : operand_list) {
assert(op);
op->u_remove_use(this);
}
}
};
class BasicBlock;
class Instruction;
class FParam : public Value {
public:
int ir_seqno = -1;
@ -115,18 +155,20 @@ public:
class BasicBlock : public Value {
public:
int ir_seqno = -1;
std::vector<std::shared_ptr<Instruction>> inst_list;
std::list<InstructionPtr_t> inst_list;
std::shared_ptr<Function> parent;
BasicBlockListNode_t itr;
std::list<std::shared_ptr<BasicBlock>> successors;
std::list<std::shared_ptr<BasicBlock>> predecessors;
std::list<BasicBlockPtr_t> successors;
std::list<BasicBlockPtr_t> predecessors;
BasicBlockPtr_t idomer;
std::list<BasicBlockPtr_t> idomee_list;
std::list<BasicBlockPtr_t> domer_list;
BasicBlockPtr_t idomer; // dominating node
std::list<BasicBlockPtr_t> idom_list; // immediate dominated nodes
std::list<BasicBlockPtr_t> dom_list; // dominated nodes
std::list<BasicBlockPtr_t> dom_frontier;
int dom_level;
int _dom_helper_index;
int dom_dfs_in;
int dom_dfs_out;
BasicBlock(const std::string &name, std::shared_ptr<Function> parent) : Value(name, TypeHelper::TYPE_LABEL) {
this->parent = parent;

View File

@ -12,7 +12,7 @@ public:
virtual void run(const Module &module) = 0;
};
class PassMem2Reg : public Pass {
class PassMem2Reg : public Pass {
public:
PassMem2Reg() : Pass("mem2reg") {}
virtual void run(const Module &module) override;

View File

@ -81,6 +81,8 @@ std::shared_ptr<InstGEP> build_InstGEP(
BasicBlockPtr_t parent_bb
);
InstPhiPtr_t build_InstPhi(TypePtr_t type, const decltype(Function::bb_list) &incoming_vals, BasicBlockPtr_t parent_bb);
#pragma endregion
class Visitor : public antlrSysY::SysyBaseVisitor {

137
src/algo_dominance.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "llir.h"
#include "visitor.h"
namespace antlrSysY {
static void _bitwise_and(std::vector<bool> &op1, const std::vector<bool> &op2) {
for (int i = 0; i < op1.size(); ++i) {
op1[i] = op1[i] & op2[i];
}
}
static void _bitwise_set(std::vector<bool> &op1, int l, int r, bool val) {
for (int i = l; i < r; ++i) {
op1[i] = val;
}
}
static void _gen_dom_level(BasicBlockPtr_t bb, int level) {
bb->dom_level = level;
for (auto succ : bb->idom_list) {
_gen_dom_level(succ, level + 1);
}
}
void gen_dominance(FunctionPtr_t func) {
// 编译器设计 2E 352 | Engineering A Compiler P479
// Note: n \in Dom(n)
// Basic iterative idea: Dom(n) = {n} union (intersect Dom(pred(n)))
std::vector<BasicBlockPtr_t> bb_list;
const int N = func->bb_list.size();
auto itr = func->bb_list.begin();
for (auto basicblock : func->bb_list) {
basicblock->idom_list.clear();
basicblock->dom_list.clear();
basicblock->_dom_helper_index = bb_list.size();
bb_list.push_back(basicblock);
}
std::vector<std::vector<bool>> dom(N);
dom[0].resize(N);
dom[0][0] = 1; // Dom(0) = {0}
// Dom(i) <- N (= {0, 1, 2,...})
for (int i = 1; i < N; ++i) {
dom[i].resize(N, 1);
}
bool changed = true;
while (changed) {
changed = false;
int i = 0;
for (int i = 1; i < N; ++i) {
auto cur_bb = bb_list[i];
std::vector<bool> temp(true, N);
// temp = {i} union (intersect Dom(j)), j in pred(i)
for (auto pred : cur_bb->predecessors) {
_bitwise_and(temp, dom[pred->_dom_helper_index]);
}
temp[i] = true;
// if temp != Dom(i)
if (temp != dom[i]) {
dom[i] = temp; // Dom(i) <- temp
changed = true; // changed <- true
}
}
}
// set each basicblock's domer
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
if (dom[i][j]) {
bb_list[i]->dom_list.push_back(bb_list[j]);
}
}
}
// get domees and immediate domer
for (int i = 0; i < N; ++i) {
for (auto domer1 : bb_list[i]->dom_list) {
if (domer1 == bb_list[i]) continue;
bool flag = true;
// if dom(i)[j] dom dom(i)[k], it cannot be the immediate domer of i
for (auto domer2 : bb_list[i]->dom_list) {
if (domer2 == bb_list[i] || domer2 == domer1) continue;
if (std::find(domer2->dom_list.begin(), domer2->dom_list.end(), domer1) != domer2->dom_list.end()) {
flag = false;
break;
}
}
if (flag) {
bb_list[i]->idomer = domer1;
domer1->idom_list.push_back(bb_list[i]);
break;
}
}
}
_gen_dom_level(bb_list[0], 0);
}
// DF is defined as:
// DF(n) = {m | (Exists q where n Dom q && q Pred m) && !(n SDom m)}
void gen_dominance_frontier(FunctionPtr_t func) {
// 编译器设计 2E 368
/*
for all node in CFG:
DF(n) <- Empty
for all node in CFG:
if n has multiple pred:
foreach pred of n:
runner <- p
while runner != idom(n):
DF(runner) <- DF(runner) union n
runner <- IDOM(runner)
*/
for (auto bb : func->bb_list) {
bb->dom_frontier.clear();
}
for (auto n : func->bb_list) {
if (n->predecessors.size() >= 2) {
for (auto pred : n->predecessors) {
auto runner = pred;
while (runner != n->idomer) {
runner->dom_frontier.push_back(n);
runner = runner->idomer;
}
}
}
}
}
void update_dfs_numbers(BasicBlockPtr_t bb, bool rst) {
static int dfs_num;
if (rst) dfs_num = 0;
bb->dom_dfs_in = dfs_num++;
for (auto child : bb->dom_list) {
update_dfs_numbers(child, false);
}
bb->dom_dfs_out = dfs_num++;
}
} // namespace antlrSysY

View File

@ -1,106 +0,0 @@
#include "llir.h"
#include "visitor.h"
#include <bitset>
namespace antlrSysY {
static void _bitwise_and(std::vector<bool>& op1, const std::vector<bool>& op2) {
for (int i = 0; i < op1.size(); ++ i) {
op1[i] = op1[i] & op2[i];
}
}
static void _bitwise_set(std::vector<bool>& op1, int l, int r,bool val) {
for (int i = l; i < r; ++ i) {
op1[i] = val;
}
}
static void _gen_dom_level(BasicBlockPtr_t bb, int level) {
bb->dom_level = level;
for (auto succ : bb->idomee_list) {
_gen_dom_level(succ, level + 1);
}
}
void gen_dominance(FunctionPtr_t func) {
// 编译器设计 2E 352 | Engineering A Compiler P479
// Note: n \in Dom(n)
// Basic iterative idea: Dom(n) = {n} union (intersect Dom(pred(n)))
std::vector<std::vector<bool>> domers;
std::vector<BasicBlockPtr_t> bb_list;
const int N = func->bb_list.size();
auto itr = func->bb_list.begin();
for (auto basicblock : func->bb_list) {
basicblock->idomee_list.clear();
basicblock->domer_list.clear();
domers.push_back({});
domers.back().resize(N, true); // Dom(i) <- N
basicblock->_dom_helper_index = bb_list.size();
bb_list.push_back(basicblock);
}
_bitwise_set(domers[0], 1, N, false); // Dom(0) <- {0}
bool changed = true;
while (changed) {
changed = false;
int i = 0;
for (int i = 1; i < N; ++ i) {
auto cur_bb = bb_list[i];
std::vector<bool> temp(true, N);
// temp = {i} union (intersect Dom(j)), j in pred(i)
for (auto pred : cur_bb->predecessors) {
_bitwise_and(temp, domers[pred->_dom_helper_index]);
}
temp[i] = true;
// if temp != Dom(i)
if (!(temp == domers[i])) {
domers[i] = temp; // Dom(i) <- temp
changed = true; // changed <- true
}
}
}
// set each basicblock's domer
for (int i = 0; i < N; ++ i) {
for (int j = 0; j < N; ++ j) {
if (domers[i][j]) {
bb_list[i]->domer_list.push_back(bb_list[j]);
}
}
}
// get domees and immediate domer
for (int i = 0; i < N; ++ i) {
for (auto domer1 : bb_list[i]->domer_list) {
if (domer1 == bb_list[i])
continue;
bool flag = true;
// if dom(i)[j] dom dom(i)[k], it cannot be the immediate domer of i
for (auto domer2 : bb_list[i]->domer_list) {
if (domer2 == bb_list[i] || domer2 == domer1)
continue;
if (std::find(domer2->domer_list.begin(), domer2->domer_list.end(), domer1) != domer2->domer_list.end()) {
flag = false;
break;
}
}
if (flag) {
bb_list[i]->idomer = domer1;
domer1->idomee_list.push_back(bb_list[i]);
break;
}
}
}
_gen_dom_level(bb_list[0], 0);
}
void gen_dominance_frontier(FunctionPtr_t func) {
// 编译器设计 2E 368
// for all node in CFG: DF(n) <- Empty
for (auto bb : func->bb_list) {
bb->dom_frontier.clear();
}
// for all node in CFG:
}
}

View File

@ -66,6 +66,7 @@ int main(int argc, const char **argv) {
defaultConf.set(el::Level::Warning, el::ConfigurationType::Format, "%level %loc %msg");
defaultConf.set(el::Level::Error, el::ConfigurationType::Format, "%level %loc %msg");
defaultConf.set(el::Level::Info, el::ConfigurationType::Format, "%level %loc %msg");
defaultConf.set(el::Level::Verbose, el::ConfigurationType::Format, "%level %loc %msg");
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
el::Loggers::reconfigureLogger("default", defaultConf);
#pragma endregion
@ -90,6 +91,16 @@ int main(int argc, const char **argv) {
auto tree = parser.program();
Visitor visitor(lexer);
visitor.visitProgram(tree);
std::vector<std::shared_ptr<Pass>> passes = {
std::make_shared<PassBuildCFG>(),
std::make_shared<PassMem2Reg>(),
};
for (auto pass : passes) {
pass->run(visitor.module);
}
if (emit_llvm) {
auto llir_file = output_file.substr(0, output_file.rfind(".")) + ".ll";
std::ofstream ofs_llir_file(llir_file);
@ -100,12 +111,6 @@ int main(int argc, const char **argv) {
visitor.llir_gen(ofs_llir_file);
}
std::vector<std::shared_ptr<Pass>> passes = {std::make_shared<PassBuildCFG>()};
for (auto pass : passes) {
pass->run(visitor.module);
}
// std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
return 0;

View File

@ -1,14 +1,293 @@
#include "passes.h"
#include "llir.h"
#include "3rdparty/easylogging++.h"
#include "algos.h"
#include "common.h"
#include "llir.h"
#include "passes.h"
#include "visitor.h"
#include <map>
#include <queue>
#include <unordered_set>
#include <vector>
namespace antlrSysY {
void PassMem2Reg::run(const Module& module) {
for (auto func : module.function_list) {
if (func->is_libfunc()) continue;
static bool is_alloca_promotable(InstAllocaPtr_t inst) {
for (const auto use : inst->use_list) {
auto user = use.user;
if (dynamic_cast<InstLoad*>(user)) {
const auto li = dynamic_cast<InstLoad*>(user);
if (li->type != inst->type) {
return false;
}
}
else if (dynamic_cast<InstStore*>(user)) {
const auto si = dynamic_cast<InstStore*>(user);
if (si->operand_list[1] == inst || si->type != inst->type) {
return false;
}
}
else if (dynamic_cast<InstGEP*>(user)) {
const auto gep = dynamic_cast<InstGEP*>(user);
for (int i = 1; i < gep->operand_list.size(); ++i) {
if (!Value::is<ConstantInt>(gep->operand_list[i]) || !Value::as<ConstantInt>(gep->operand_list[i])->value) {
return false;
}
}
}
else {
return false;
}
}
return true;
}
struct AllocaInfo {
std::vector<BasicBlockPtr_t> def_blocks = {};
std::vector<BasicBlockPtr_t> use_blocks = {};
bool only_in_1_block = true;
BasicBlockPtr_t only_block = nullptr;
InstStore* only_store = nullptr;
};
static void analyze_alloca(InstAllocaPtr_t ai, AllocaInfo &info) {
for (auto use : ai->use_list) {
auto user = dynamic_cast<Instruction*>(use.user);
if (dynamic_cast<InstStore*>(user)) {
const auto si = dynamic_cast<InstStore*>(user);
info.def_blocks.push_back(si->parent_bb);
info.only_store = si;
}
else {
assert(dynamic_cast<InstLoad*>(user));
const auto li = dynamic_cast<InstLoad*>(user);
info.use_blocks.push_back(li->parent_bb);
}
if (info.only_in_1_block) {
if (!info.only_block)
info.only_block = user->parent_bb;
else if (info.only_block != user->parent_bb)
info.only_in_1_block = false;
}
}
}
}
// static bool rewrite_single_store(InstAllocaPtr_t ai, AllocaInfo& alloca_info) {
// }
// live in analysis
static void live_in_blocks(
InstAllocaPtr_t ai,
AllocaInfo &alloca_info,
const std::unordered_set<BasicBlockPtr_t> &def_blocks,
std::unordered_set<BasicBlockPtr_t> &livein_blocks
) {
std::vector<BasicBlockPtr_t> worklist(alloca_info.use_blocks.begin(), alloca_info.use_blocks.end());
// for each block, compute whether alloca live in the block
// 检查每个block如果store before load就说明dead如果load before store说明live因为被用到了
for (int i = 0; i < worklist.size(); ++i) {
auto bb = worklist[i];
if (def_blocks.count(bb) == 0) continue;
for (auto itr : bb->inst_list) {
// a store to this alloca(variable) before a load, it is dead in this block
if (Value::is<InstStore>(itr) && Value::as<InstStore>(itr)->operand_list[1] == ai) {
worklist[i] = worklist.back();
worklist.pop_back();
--i;
break;
}
else if (Value::is<InstLoad>(itr)) {
// a load before store, it live in this block
if (Value::as<InstLoad>(itr)->operand_list[1] == ai) break;
}
}
}
// add predecessors to get the full region where the var is live
// 好像cs143里面就有讲过这个东西liveness分析好像是从后往前推的
while (!worklist.empty()) {
auto bb = worklist.back();
worklist.pop_back();
if (!livein_blocks.insert(bb).second) continue; // already done
// 如果alloca没有在某个块中被定义那么它一定是从前面的某个块里面live in过来的
// 所以把它也塞进队列进行处理
for (auto pred : bb->predecessors) {
if (def_blocks.count(pred)) continue;
worklist.push_back(pred);
}
}
}
struct RenameInfo {
BasicBlockPtr_t bb;
BasicBlockPtr_t pred;
std::vector<ValuePtr_t> value_list;
};
// llvm:PromoteMemoryToRegister.cpp
// https://roife.github.io/2022/02/07/mem2reg/
// https://github.com/Enna1/LLVM-Study-Notes/blob/master/source/ssa/SSA-Construction.rst
static void _mem_2_reg(FunctionPtr_t func) {
VLOG(4) << " Gen Dominance Tree & Frontier";
gen_dominance(func);
gen_dominance_frontier(func);
// actually, all variable alloca is placed at block head, so we collect them first
std::vector<InstAllocaPtr_t> alloca_list;
std::unordered_map<InstAllocaPtr_t, int> alloca_to_id;
std::unordered_map<BasicBlockPtr_t, int> bb_to_id;
std::unordered_map<InstPhiPtr_t, int> phi_to_allocaid;
std::queue<BasicBlockPtr_t> worklist;
for (auto bb : func->bb_list) {
for (auto inst : bb->inst_list) {
if (Value::is<InstAlloca>(inst)) {
assert(inst->parent_bb == bb);
assert(bb == func->bb_list.front() && "Alloca should be at front of a func");
auto ai = Value::as<InstAlloca>(inst);
// assert(is_alloca_promotable(ai) && "Invalid alloca");
if (!Type::isType<IntegerType>(PointerType::pointedType(ai->type)))
continue;
alloca_list.push_back(ai);
}
}
}
VLOG(4) << " alloca pruning & phi insertion";
for (unsigned i = 0; i != alloca_list.size(); ++i) {
auto ai = alloca_list[i];
// remove empty use
if (ai->use_list.empty()) {
ai->parent_bb->inst_list.remove(ai);
alloca_list[i] = alloca_list.back();
alloca_list.pop_back();
--i;
continue;
}
AllocaInfo alloca_info;
analyze_alloca(ai, alloca_info);
if (alloca_info.def_blocks.size() == 1) {
LOG(WARNING) << "To rewrite single store";
}
if (alloca_info.only_in_1_block) {
LOG(WARNING) << "To promote single block alloca";
}
// numbering bb
if (bb_to_id.empty()) {
int id = 0;
for (auto bb : func->bb_list) {
bb_to_id[bb] = id++;
}
}
alloca_to_id[alloca_list[i]] = i;
std::unordered_set<BasicBlockPtr_t> def_blocks(alloca_info.def_blocks.begin(), alloca_info.def_blocks.end());
std::unordered_set<BasicBlockPtr_t> livein_blocks;
live_in_blocks(ai, alloca_info, def_blocks, livein_blocks);
// llvm use IDF to calculate phi blocks.
// But that is too complicated
// SSA book Algo 3.1
std::vector<bool> visited(func->bb_list.size(), false);
for (auto bb : def_blocks) {
worklist.push(bb);
}
while (!worklist.empty()) {
auto bb = worklist.front();
worklist.pop();
for (auto frontier : bb->dom_frontier) {
auto frontier_index = bb_to_id.at(frontier);
if (!visited[frontier_index]) {
visited[frontier_index] = true;
if (livein_blocks.count(frontier)) {
auto inst_phi = build_InstPhi(TypeHelper::TYPE_I32, bb->predecessors, bb);
phi_to_allocaid.insert({inst_phi, i});
}
if (!def_blocks.count(frontier)) {
worklist.push(frontier);
}
}
}
}
}
if (alloca_list.empty()) return;
// renaming
VLOG(4) << " variable renaming";
std::vector<ValuePtr_t> _init_values;
for (int i = 0; i < alloca_list.size(); ++ i)
_init_values.push_back(ConstantInt::make_shared(0));
std::vector<RenameInfo> rename_list = {{func->bb_list.front(), nullptr, _init_values}};
std::vector<bool> visited(bb_to_id.size(), 0);
while (!rename_list.empty()) {
auto rename_info = rename_list.back();
rename_list.pop_back();
// replace block with more specific alloca
for (auto inst : rename_info.bb->inst_list) {
// phi only appear at block head
if (!Value::is<InstPhi>(inst)) break;
auto phi = Value::as<InstPhi>(inst);
auto alloca_index = phi_to_allocaid.at(phi);
int pred_index = -1;
for (auto pred : rename_info.bb->predecessors) {
pred_index++;
if (pred == rename_info.pred) break;
}
phi->set_incoming_val(pred_index, rename_info.value_list[alloca_index]);
}
// already processed, skip
if (visited[bb_to_id.at(rename_info.bb)]) continue;
visited[bb_to_id.at(rename_info.bb)] = true;
// process instruction
for (auto itr = rename_info.bb->inst_list.begin(); itr != rename_info.bb->inst_list.end();) {
auto inst = *itr++;
if (Value::is<InstAlloca>(inst)) {
assert(alloca_to_id.count(Value::as<InstAlloca>(inst)));
rename_info.bb->inst_list.remove(inst);
}
else if (Value::is<InstLoad>(inst)) {
auto li = Value::as<InstLoad>(inst);
if (!(Value::is<InstAlloca>(li->operand_list[0]))) {
continue;
}
auto ai = Value::as<InstAlloca>(li->operand_list[0]);
if (!Type::isType<IntegerType>(PointerType::pointedType(ai->type))) {
continue;
}
int alloca_index = alloca_to_id.at(ai);
rename_info.bb->inst_list.remove(inst);
li->u_replace_users(rename_info.value_list[alloca_index]);
inst->u_remove_from_usees();
}
else if (Value::is<InstStore>(inst)) {
auto si = Value::as<InstStore>(inst);
if (!(Value::is<InstAlloca>(si->operand_list[1]))) {
continue;
}
auto ai = Value::as<InstAlloca>(si->operand_list[1]);
if (!Type::isType<IntegerType>(PointerType::pointedType(ai->type))) {
continue;
}
int alloca_index = alloca_to_id.at(ai);
rename_info.value_list[alloca_index] = si->operand_list[0];
inst->u_remove_from_usees();
// I dont think anyone will use a store?
si->u_replace_users(nullptr);
rename_info.bb->inst_list.remove(inst);
}
else if (Value::is<InstPhi>(inst)) {
auto phi = Value::as<InstPhi>(inst);
int alloca_index = phi_to_allocaid.at(phi);
rename_info.value_list[alloca_index] = phi;
}
}
for (auto succ : rename_info.bb->successors) {
rename_list.push_back({succ, rename_info.bb, rename_info.value_list});
}
}
}
void PassMem2Reg::run(const Module &module) {
LOG(INFO) << "Run pass " << pass_name;
for (auto func : module.function_list) {
if (func->is_libfunc()) continue;
_mem_2_reg(func);
}
}
} // namespace antlrSysY

View File

@ -139,4 +139,14 @@ std::shared_ptr<InstGEP> build_InstGEP(
return inst;
}
InstPhiPtr_t build_InstPhi(
TypePtr_t type,
const decltype(Function::bb_list) &incoming_vals,
BasicBlockPtr_t parent_bb
) {
auto inst = std::make_shared<InstPhi>(type, incoming_vals, parent_bb);
parent_bb->inst_list.insert(parent_bb->inst_list.begin(), inst);
return inst;
}
} // namespace antlrSysY

View File

@ -107,8 +107,7 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
auto block = *block_itr;
sysy_assert(block->ir_seqno == -1); // multi-alloc is error
block->ir_seqno = reg_count++;
for (int j = 0; j < block->inst_list.size(); ++j) {
auto inst = block->inst_list[j];
for (auto inst : block->inst_list) {
sysy_assert(inst->ir_seqno == -1); // multi-alloc is error
switch (inst->tag) {
// These are not to get a seqno
@ -138,6 +137,7 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
case InstTag::Load:
case InstTag::GEP:
case InstTag::Alloca:
case InstTag::Phi:
case InstTag::Zext: inst->ir_seqno = reg_count++; break;
// These should not be generated in frontend stage
default: panic("Unexpected instruction");
@ -150,9 +150,8 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
if (block_itr != block_list.begin()) {
ostr << block->ir_seqno << ":" << std::endl;
}
for (int j = 0; j < block->inst_list.size(); ++j) {
for (auto _inst : block->inst_list) {
ostr << " ";
auto _inst = block->inst_list[j];
VLOG(5) << "Build inst" << _inst->ir_seqno << ": " << _inst->to_string();
switch (_inst->tag) {
case InstTag::Br: {
@ -351,13 +350,13 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
assert(Type::isType<PointerType>(inst->operand_list[0]->type));
ostr << "%" << inst->ir_seqno << " = load " << inst->type->to_IR_string() << ", ";
if (Value::is<GlobalVar>(inst->operand_list[0])) {
auto op1 = Value::as<GlobalVar>(inst->operand_list[0]);
ostr << op1->type->to_IR_string() << " @" << op1->name;
auto op = Value::as<GlobalVar>(inst->operand_list[0]);
ostr << op->type->to_IR_string() << " @" << op->name;
}
else if (Value::is<Instruction>(inst->operand_list[0])) {
auto op1 = Value::as<Instruction>(inst->operand_list[0]);
assert(op1->ir_seqno >= 0);
ostr << op1->type->to_IR_string() << " %" << op1->ir_seqno;
auto op = Value::as<Instruction>(inst->operand_list[0]);
assert(op->ir_seqno >= 0);
ostr << op->type->to_IR_string() << " %" << op->ir_seqno;
}
else if (Value::is<FParam>(inst->operand_list[0])) {
auto op0 = Value::as<FParam>(inst->operand_list[0]);
@ -428,6 +427,42 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
ostr << "i32";
break;
}
case InstTag::Phi: {
auto inst = Value::as<InstPhi>(_inst);
assert(inst->ir_seqno >= 0);
ostr << "%" << inst->ir_seqno << " = phi " << inst->type->to_IR_string() << " ";
for (int i = 0; i < inst->operand_list.size(); ++i) {
auto op = inst->operand_list[i];
ostr << "[";
if (Value::is<GlobalVar>(op)) {
auto op0 = Value::as<GlobalVar>(op);
ostr << "@" << op0->name;
}
else if (Value::is<Instruction>(op)) {
auto op0 = Value::as<Instruction>(op);
ostr << "%" << op0->ir_seqno;
}
else if (Value::is<FParam>(op)) {
auto op0 = Value::as<FParam>(op);
ostr << "%" << op0->ir_seqno;
}
else if (Value::is<ConstantInt>(op)) {
auto op0 = Value::as<ConstantInt>(op);
ostr << op0->value;
}
else {
LOG(WARNING) << "Unexpected type of op: " << op->to_string();
assert(0);
}
auto pred = inst->parent_bb->predecessors.begin();
std::advance(pred, i);
ostr << ", %" << (*pred)->ir_seqno << "]";
if (i < inst->operand_list.size() - 1) {
ostr << ", ";
}
}
break;
}
// These should not be generated in frontend stage
default: panic("Unexpected instruction");
}
@ -439,7 +474,7 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
void Visitor::llir_gen(std::ostream &ostr) {
#pragma region GenLibFuncDecl
for (auto &lib_func_name : libfunc_list) {
LOG(DEBUG) << "Gen LibFunc " << lib_func_name;
VLOG(6) << "Gen LibFunc " << lib_func_name;
auto lib_func = _func_tab.get_name(lib_func_name).value();
auto lib_func_type = std::dynamic_pointer_cast<FunctionType>(lib_func->type);
ostr << "declare"
@ -458,7 +493,7 @@ void Visitor::llir_gen(std::ostream &ostr) {
#pragma region GenGlobDecl
for (auto &global_var : module.global_var_list) {
// both int and arr have the same leading part
LOG(DEBUG) << "Gen Global " << global_var->name;
VLOG(5) << "Gen Global " << global_var->name;
ostr << "@" << global_var->name << " = "
<< "dso_local"
<< " " << (global_var->is_const ? "constant" : "global") << " ";