buggy mem2reg
This commit is contained in:
parent
7140d0bf2b
commit
2a36406e3d
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -9,7 +9,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug",
|
"name": "Debug",
|
||||||
"program": "${workspaceFolder}/build/sysy",
|
"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}"
|
"cwd": "${workspaceFolder}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -21,7 +21,8 @@ file(GLOB MY_HEADERS "include/*.h")
|
|||||||
include(formatting.cmake)
|
include(formatting.cmake)
|
||||||
clang_format(format ${MY_SOURCES} ${MY_HEADERS})
|
clang_format(format ${MY_SOURCES} ${MY_HEADERS})
|
||||||
# clang_format_check(format_check ${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})
|
add_executable(sysy ${SOURCES})
|
||||||
# message(STATUS "${SOURCES}")
|
# message(STATUS "${SOURCES}")
|
||||||
target_link_libraries(sysy antlr4_static)
|
target_link_libraries(sysy antlr4_static)
|
||||||
1201
docs/LLVM-promoteAlloca.cpp
Normal file
1201
docs/LLVM-promoteAlloca.cpp
Normal file
File diff suppressed because it is too large
Load Diff
11
include/algos.h
Normal file
11
include/algos.h
Normal 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
|
||||||
@ -16,6 +16,10 @@
|
|||||||
if (!(cond)) throw GrammarException(__FILE__, __LINE__, #cond); \
|
if (!(cond)) throw GrammarException(__FILE__, __LINE__, #cond); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define DEF_PTR_T(type) \
|
||||||
|
class type; \
|
||||||
|
typedef std::shared_ptr<type> type##Ptr_t
|
||||||
|
|
||||||
namespace antlrSysY {
|
namespace antlrSysY {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@ -7,6 +7,18 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace antlrSysY {
|
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 {
|
enum class InstTag {
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
@ -41,6 +53,7 @@ public:
|
|||||||
int ir_seqno = -1;
|
int ir_seqno = -1;
|
||||||
InstTag tag;
|
InstTag tag;
|
||||||
BasicBlockPtr_t parent_bb;
|
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)
|
Instruction(InstTag inst_tag, TypePtr_t type, BasicBlockPtr_t parent_bb)
|
||||||
: User("", type), tag(inst_tag), parent_bb(parent_bb) {}
|
: User("", type), tag(inst_tag), parent_bb(parent_bb) {}
|
||||||
virtual std::string to_string() override {
|
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
|
} // namespace antlrSysY
|
||||||
@ -4,10 +4,17 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace antlrSysY {
|
namespace antlrSysY {
|
||||||
|
|
||||||
class Type;
|
DEF_PTR_T(Type);
|
||||||
typedef std::shared_ptr<Type> TypePtr_t;
|
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 {
|
class Type {
|
||||||
public:
|
public:
|
||||||
@ -139,6 +146,12 @@ public:
|
|||||||
virtual std::string to_IR_string() override {
|
virtual std::string to_IR_string() override {
|
||||||
return pointed_type->to_IR_string() + "*";
|
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 {
|
class FunctionType : public Type {
|
||||||
|
|||||||
@ -8,29 +8,33 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace antlrSysY {
|
namespace antlrSysY {
|
||||||
|
|
||||||
class Value;
|
DEF_PTR_T(Value);
|
||||||
class BasicBlock;
|
DEF_PTR_T(BasicBlock);
|
||||||
class User;
|
DEF_PTR_T(User);
|
||||||
class Function;
|
DEF_PTR_T(Function);
|
||||||
class Instruction;
|
DEF_PTR_T(Instruction);
|
||||||
typedef std::shared_ptr<Value> ValuePtr_t;
|
DEF_PTR_T(Constant);
|
||||||
typedef std::shared_ptr<BasicBlock> BasicBlockPtr_t;
|
DEF_PTR_T(ConstantInt);
|
||||||
typedef std::shared_ptr<Function> FunctionPtr_t;
|
|
||||||
typedef std::shared_ptr<User> UserPtr_t;
|
// typedef std::tuple<ValuePtr_t, UserPtr_t, int> UseEdge_t;
|
||||||
typedef std::shared_ptr<Instruction> InstructionPtr_t;
|
struct Use {
|
||||||
typedef std::tuple<ValuePtr_t, UserPtr_t, int> UseEdge_t;
|
ValuePtr_t value;
|
||||||
|
User* user;
|
||||||
|
unsigned op_index;
|
||||||
|
};
|
||||||
// Define, User, operand-index
|
// Define, User, operand-index
|
||||||
|
// for Instruction, inst `uses` op, so inst is the user
|
||||||
|
|
||||||
class Value {
|
class Value {
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
TypePtr_t type;
|
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) {}
|
Value(const std::string &name, TypePtr_t type) : name(name), type(type) {}
|
||||||
virtual ~Value() = default;
|
virtual ~Value() = default;
|
||||||
@ -60,8 +64,24 @@ public:
|
|||||||
virtual std::string to_IR_string() {
|
virtual std::string to_IR_string() {
|
||||||
panic("No applicable for IR gen");
|
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 {
|
class User : public Value {
|
||||||
public:
|
public:
|
||||||
@ -69,14 +89,34 @@ public:
|
|||||||
|
|
||||||
User(const std::string &name, TypePtr_t type) : Value(name, type) {}
|
User(const std::string &name, TypePtr_t type) : Value(name, type) {}
|
||||||
void Add_Operand(ValuePtr_t op) {
|
void Add_Operand(ValuePtr_t op) {
|
||||||
|
op->use_list.push_back({op, this, (unsigned)operand_list.size()});
|
||||||
operand_list.push_back(op);
|
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 {
|
class FParam : public Value {
|
||||||
public:
|
public:
|
||||||
int ir_seqno = -1;
|
int ir_seqno = -1;
|
||||||
@ -115,18 +155,20 @@ public:
|
|||||||
class BasicBlock : public Value {
|
class BasicBlock : public Value {
|
||||||
public:
|
public:
|
||||||
int ir_seqno = -1;
|
int ir_seqno = -1;
|
||||||
std::vector<std::shared_ptr<Instruction>> inst_list;
|
std::list<InstructionPtr_t> inst_list;
|
||||||
std::shared_ptr<Function> parent;
|
std::shared_ptr<Function> parent;
|
||||||
BasicBlockListNode_t itr;
|
BasicBlockListNode_t itr;
|
||||||
std::list<std::shared_ptr<BasicBlock>> successors;
|
std::list<BasicBlockPtr_t> successors;
|
||||||
std::list<std::shared_ptr<BasicBlock>> predecessors;
|
std::list<BasicBlockPtr_t> predecessors;
|
||||||
|
|
||||||
BasicBlockPtr_t idomer;
|
BasicBlockPtr_t idomer; // dominating node
|
||||||
std::list<BasicBlockPtr_t> idomee_list;
|
std::list<BasicBlockPtr_t> idom_list; // immediate dominated nodes
|
||||||
std::list<BasicBlockPtr_t> domer_list;
|
std::list<BasicBlockPtr_t> dom_list; // dominated nodes
|
||||||
std::list<BasicBlockPtr_t> dom_frontier;
|
std::list<BasicBlockPtr_t> dom_frontier;
|
||||||
int dom_level;
|
int dom_level;
|
||||||
int _dom_helper_index;
|
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) {
|
BasicBlock(const std::string &name, std::shared_ptr<Function> parent) : Value(name, TypeHelper::TYPE_LABEL) {
|
||||||
this->parent = parent;
|
this->parent = parent;
|
||||||
|
|||||||
@ -81,6 +81,8 @@ std::shared_ptr<InstGEP> build_InstGEP(
|
|||||||
BasicBlockPtr_t parent_bb
|
BasicBlockPtr_t parent_bb
|
||||||
);
|
);
|
||||||
|
|
||||||
|
InstPhiPtr_t build_InstPhi(TypePtr_t type, const decltype(Function::bb_list) &incoming_vals, BasicBlockPtr_t parent_bb);
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
class Visitor : public antlrSysY::SysyBaseVisitor {
|
class Visitor : public antlrSysY::SysyBaseVisitor {
|
||||||
|
|||||||
137
src/algo_dominance.cpp
Normal file
137
src/algo_dominance.cpp
Normal 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
|
||||||
@ -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:
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
17
src/main.cpp
17
src/main.cpp
@ -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::Warning, el::ConfigurationType::Format, "%level %loc %msg");
|
||||||
defaultConf.set(el::Level::Error, 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::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::addFlag(el::LoggingFlag::ColoredTerminalOutput);
|
||||||
el::Loggers::reconfigureLogger("default", defaultConf);
|
el::Loggers::reconfigureLogger("default", defaultConf);
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
@ -90,6 +91,16 @@ int main(int argc, const char **argv) {
|
|||||||
auto tree = parser.program();
|
auto tree = parser.program();
|
||||||
Visitor visitor(lexer);
|
Visitor visitor(lexer);
|
||||||
visitor.visitProgram(tree);
|
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) {
|
if (emit_llvm) {
|
||||||
auto llir_file = output_file.substr(0, output_file.rfind(".")) + ".ll";
|
auto llir_file = output_file.substr(0, output_file.rfind(".")) + ".ll";
|
||||||
std::ofstream ofs_llir_file(llir_file);
|
std::ofstream ofs_llir_file(llir_file);
|
||||||
@ -100,12 +111,6 @@ int main(int argc, const char **argv) {
|
|||||||
visitor.llir_gen(ofs_llir_file);
|
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;
|
// std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -1,14 +1,293 @@
|
|||||||
#include "passes.h"
|
#include "3rdparty/easylogging++.h"
|
||||||
#include "llir.h"
|
#include "algos.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "llir.h"
|
||||||
|
#include "passes.h"
|
||||||
|
#include "visitor.h"
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace antlrSysY {
|
namespace antlrSysY {
|
||||||
|
|
||||||
void PassMem2Reg::run(const Module& module) {
|
static bool is_alloca_promotable(InstAllocaPtr_t inst) {
|
||||||
for (auto func : module.function_list) {
|
for (const auto use : inst->use_list) {
|
||||||
if (func->is_libfunc()) continue;
|
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
|
||||||
@ -139,4 +139,14 @@ std::shared_ptr<InstGEP> build_InstGEP(
|
|||||||
return inst;
|
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
|
} // namespace antlrSysY
|
||||||
@ -107,8 +107,7 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
|
|||||||
auto block = *block_itr;
|
auto block = *block_itr;
|
||||||
sysy_assert(block->ir_seqno == -1); // multi-alloc is error
|
sysy_assert(block->ir_seqno == -1); // multi-alloc is error
|
||||||
block->ir_seqno = reg_count++;
|
block->ir_seqno = reg_count++;
|
||||||
for (int j = 0; j < block->inst_list.size(); ++j) {
|
for (auto inst : block->inst_list) {
|
||||||
auto inst = block->inst_list[j];
|
|
||||||
sysy_assert(inst->ir_seqno == -1); // multi-alloc is error
|
sysy_assert(inst->ir_seqno == -1); // multi-alloc is error
|
||||||
switch (inst->tag) {
|
switch (inst->tag) {
|
||||||
// These are not to get a seqno
|
// 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::Load:
|
||||||
case InstTag::GEP:
|
case InstTag::GEP:
|
||||||
case InstTag::Alloca:
|
case InstTag::Alloca:
|
||||||
|
case InstTag::Phi:
|
||||||
case InstTag::Zext: inst->ir_seqno = reg_count++; break;
|
case InstTag::Zext: inst->ir_seqno = reg_count++; break;
|
||||||
// These should not be generated in frontend stage
|
// These should not be generated in frontend stage
|
||||||
default: panic("Unexpected instruction");
|
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()) {
|
if (block_itr != block_list.begin()) {
|
||||||
ostr << block->ir_seqno << ":" << std::endl;
|
ostr << block->ir_seqno << ":" << std::endl;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < block->inst_list.size(); ++j) {
|
for (auto _inst : block->inst_list) {
|
||||||
ostr << " ";
|
ostr << " ";
|
||||||
auto _inst = block->inst_list[j];
|
|
||||||
VLOG(5) << "Build inst" << _inst->ir_seqno << ": " << _inst->to_string();
|
VLOG(5) << "Build inst" << _inst->ir_seqno << ": " << _inst->to_string();
|
||||||
switch (_inst->tag) {
|
switch (_inst->tag) {
|
||||||
case InstTag::Br: {
|
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));
|
assert(Type::isType<PointerType>(inst->operand_list[0]->type));
|
||||||
ostr << "%" << inst->ir_seqno << " = load " << inst->type->to_IR_string() << ", ";
|
ostr << "%" << inst->ir_seqno << " = load " << inst->type->to_IR_string() << ", ";
|
||||||
if (Value::is<GlobalVar>(inst->operand_list[0])) {
|
if (Value::is<GlobalVar>(inst->operand_list[0])) {
|
||||||
auto op1 = Value::as<GlobalVar>(inst->operand_list[0]);
|
auto op = Value::as<GlobalVar>(inst->operand_list[0]);
|
||||||
ostr << op1->type->to_IR_string() << " @" << op1->name;
|
ostr << op->type->to_IR_string() << " @" << op->name;
|
||||||
}
|
}
|
||||||
else if (Value::is<Instruction>(inst->operand_list[0])) {
|
else if (Value::is<Instruction>(inst->operand_list[0])) {
|
||||||
auto op1 = Value::as<Instruction>(inst->operand_list[0]);
|
auto op = Value::as<Instruction>(inst->operand_list[0]);
|
||||||
assert(op1->ir_seqno >= 0);
|
assert(op->ir_seqno >= 0);
|
||||||
ostr << op1->type->to_IR_string() << " %" << op1->ir_seqno;
|
ostr << op->type->to_IR_string() << " %" << op->ir_seqno;
|
||||||
}
|
}
|
||||||
else if (Value::is<FParam>(inst->operand_list[0])) {
|
else if (Value::is<FParam>(inst->operand_list[0])) {
|
||||||
auto op0 = Value::as<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";
|
ostr << "i32";
|
||||||
break;
|
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
|
// These should not be generated in frontend stage
|
||||||
default: panic("Unexpected instruction");
|
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) {
|
void Visitor::llir_gen(std::ostream &ostr) {
|
||||||
#pragma region GenLibFuncDecl
|
#pragma region GenLibFuncDecl
|
||||||
for (auto &lib_func_name : libfunc_list) {
|
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 = _func_tab.get_name(lib_func_name).value();
|
||||||
auto lib_func_type = std::dynamic_pointer_cast<FunctionType>(lib_func->type);
|
auto lib_func_type = std::dynamic_pointer_cast<FunctionType>(lib_func->type);
|
||||||
ostr << "declare"
|
ostr << "declare"
|
||||||
@ -458,7 +493,7 @@ void Visitor::llir_gen(std::ostream &ostr) {
|
|||||||
#pragma region GenGlobDecl
|
#pragma region GenGlobDecl
|
||||||
for (auto &global_var : module.global_var_list) {
|
for (auto &global_var : module.global_var_list) {
|
||||||
// both int and arr have the same leading part
|
// 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 << " = "
|
ostr << "@" << global_var->name << " = "
|
||||||
<< "dso_local"
|
<< "dso_local"
|
||||||
<< " " << (global_var->is_const ? "constant" : "global") << " ";
|
<< " " << (global_var->is_const ? "constant" : "global") << " ";
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user