This commit is contained in:
ridethepig 2023-06-15 22:14:00 +08:00
parent 3b5cd82206
commit 40ac8b9d65
11 changed files with 464 additions and 104 deletions

2
.vscode/launch.json vendored
View File

@ -10,7 +10,7 @@
"name": "Debug", "name": "Debug",
"program": "${workspaceFolder}/build/sysy", "program": "${workspaceFolder}/build/sysy",
// "args": ["../sysytests/functional_2021/069_greatest_common_divisor.sy", "-S", "-o", "build/my.s", "-O1", "-emit-llvm"], // "args": ["../sysytests/functional_2021/069_greatest_common_divisor.sy", "-S", "-o", "build/my.s", "-O1", "-emit-llvm"],
"args" : ["-S", "../sysytests/functional_2022/88_many_params2.sy", "-o", "build/my.s", "-emit-llvm", "-O1"], "args" : ["-S", "../sysytests/functional_2022/21_if_test2.sy", "-o", "build/my.s", "-emit-llvm", "-O1",],
"cwd": "${workspaceFolder}" "cwd": "${workspaceFolder}"
}, },
] ]

View File

@ -34,6 +34,7 @@ inline sptr(DST) strict_shared_cast(SRC src) {
} }
#define STD_FIND(container, val) std::find(container.begin(), container.end(), val) #define STD_FIND(container, val) std::find(container.begin(), container.end(), val)
#define GETINDEX(container, val) std::distance(container.begin(), STD_FIND(container, val))
#define STD_FOUND(container, val) (STD_FIND(container, val) != container.end()) #define STD_FOUND(container, val) (STD_FIND(container, val) != container.end())
#define INSET(cont, val) (cont.find(val) != cont.end()) #define INSET(cont, val) (cont.find(val) != cont.end())
#define BEGINEND(cont) cont.begin(), cont.end() #define BEGINEND(cont) cont.begin(), cont.end()

View File

@ -41,10 +41,10 @@ enum class InstTag {
GEP, GEP,
Zext, Zext,
Phi, Phi,
MemPhi, // MemPhi,
LoadDep, // LoadDep,
InsertEle, // InsertEle,
ExtractEle // ExtractEle
}; };
class Instruction : public User { class Instruction : public User {
@ -78,11 +78,12 @@ public:
case InstTag::Store: return "store"; case InstTag::Store: return "store";
case InstTag::GEP: return "GEP"; case InstTag::GEP: return "GEP";
case InstTag::Zext: return "zext"; case InstTag::Zext: return "zext";
case InstTag::Phi: return "Phi"; case InstTag::Phi:
case InstTag::MemPhi: return "MemPhi"; return "Phi";
case InstTag::LoadDep: return "LoadDep"; // case InstTag::MemPhi: return "MemPhi";
case InstTag::InsertEle: return "InsertEle"; // case InstTag::LoadDep: return "LoadDep";
case InstTag::ExtractEle: return "ExtractEle"; // case InstTag::InsertEle: return "InsertEle";
// case InstTag::ExtractEle: return "ExtractEle";
} }
} }
virtual std::string to_string() override { virtual std::string to_string() override {
@ -101,7 +102,7 @@ public:
static sptr(InstAlloca) New(const std::string &name, TypePtr_t type, sptr(BasicBlock) parent_bb) { static sptr(InstAlloca) New(const std::string &name, TypePtr_t type, sptr(BasicBlock) parent_bb) {
auto inst = std::make_shared<InstAlloca>(type, parent_bb); auto inst = std::make_shared<InstAlloca>(type, parent_bb);
inst->name = name; inst->name = name;
auto func_head_bb = parent_bb->parent->bb_list.front(); auto func_head_bb = parent_bb->parent_func->bb_list.front();
// put all alloca in the head of each basic block // put all alloca in the head of each basic block
inst->inst_itr = func_head_bb->inst_list.insert(func_head_bb->inst_list.begin(), inst); inst->inst_itr = func_head_bb->inst_list.insert(func_head_bb->inst_list.begin(), inst);
return inst; return inst;
@ -113,8 +114,8 @@ public:
InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, std::shared_ptr<BasicBlock> parent_bb) InstStore(std::shared_ptr<Value> value, std::shared_ptr<Value> pointer, std::shared_ptr<BasicBlock> parent_bb)
: Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) { : Instruction(InstTag::Store, TypeHelper::TYPE_VOID, parent_bb) {
assert(value); assert(value);
Add_Operand(value); add_operand(value);
Add_Operand(pointer); add_operand(pointer);
} }
static sptr(InstStore) New(sptr(Value) value, sptr(Value) pointer, sptr(BasicBlock) parent_bb) { static sptr(InstStore) New(sptr(Value) value, sptr(Value) pointer, sptr(BasicBlock) parent_bb) {
auto inst = std::make_shared<InstStore>(value, pointer, parent_bb); auto inst = std::make_shared<InstStore>(value, pointer, parent_bb);
@ -127,7 +128,7 @@ class InstLoad : public Instruction {
public: public:
InstLoad(std::shared_ptr<Value> value, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb) InstLoad(std::shared_ptr<Value> value, TypePtr_t type, std::shared_ptr<BasicBlock> parent_bb)
: Instruction(InstTag::Load, type, parent_bb) { : Instruction(InstTag::Load, type, parent_bb) {
Add_Operand(value); add_operand(value);
} }
virtual std::string to_IR_string() override { virtual std::string to_IR_string() override {
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
@ -150,8 +151,8 @@ public:
std::shared_ptr<BasicBlock> parent_bb std::shared_ptr<BasicBlock> parent_bb
) )
: Instruction(inst_tag, val_type, parent_bb) { : Instruction(inst_tag, val_type, parent_bb) {
Add_Operand(op1); add_operand(op1);
Add_Operand(op2); add_operand(op2);
} }
virtual std::string to_IR_string() override { virtual std::string to_IR_string() override {
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
@ -193,7 +194,7 @@ class InstZext : public Instruction {
public: public:
InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb) InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb)
: Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) { : Instruction(InstTag::Zext, TypeHelper::TYPE_I32, parent_bb) {
Add_Operand(op); add_operand(op);
} }
virtual std::string to_IR_string() override { virtual std::string to_IR_string() override {
std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno); std::string str = type->to_IR_string() + " %" + std::to_string(ir_seqno);
@ -206,14 +207,15 @@ public:
} }
}; };
// Operands: 0:cond, 1:true, 2:false | 0:target
class InstBranch : public Instruction { class InstBranch : public Instruction {
public: public:
// conditional branch // conditional branch
InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb) InstBranch(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) { : Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
this->Add_Operand(cond); this->add_operand(cond);
this->Add_Operand(true_block); this->add_operand(true_block);
this->Add_Operand(false_block); this->add_operand(false_block);
} }
static sptr(InstBranch) static sptr(InstBranch)
New(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb) { New(ValuePtr_t cond, BasicBlockPtr_t true_block, BasicBlockPtr_t false_block, BasicBlockPtr_t parent_bb) {
@ -224,7 +226,7 @@ public:
// unconditional branch // unconditional branch
InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb) InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) { : Instruction(InstTag::Br, TypeHelper::TYPE_VOID, parent_bb) {
this->Add_Operand(target_block); this->add_operand(target_block);
} }
static sptr(InstBranch) New(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb) { static sptr(InstBranch) New(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb) {
auto inst = std::make_shared<InstBranch>(target_block, parent_bb); auto inst = std::make_shared<InstBranch>(target_block, parent_bb);
@ -237,7 +239,7 @@ class InstReturn : public Instruction {
public: public:
InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb) InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) { : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {
this->Add_Operand(ret_val); this->add_operand(ret_val);
} }
InstReturn(BasicBlockPtr_t parent_bb) : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {} InstReturn(BasicBlockPtr_t parent_bb) : Instruction(InstTag::Ret, TypeHelper::TYPE_VOID, parent_bb) {}
static sptr(InstReturn) New(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb) { static sptr(InstReturn) New(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb) {
@ -257,9 +259,9 @@ class InstCall : public Instruction {
public: public:
InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, BasicBlockPtr_t parent_bb) InstCall(FunctionPtr_t func, const std::vector<ValuePtr_t> &args, BasicBlockPtr_t parent_bb)
: Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) { : Instruction(InstTag::Call, func->get_type()->return_type, parent_bb) {
Add_Operand(func); add_operand(func);
for (auto arg : args) { for (auto arg : args) {
Add_Operand(arg); add_operand(arg);
} }
} }
virtual std::string to_IR_string() override { virtual std::string to_IR_string() override {
@ -305,9 +307,9 @@ public:
} }
assert(indices.size() <= 2); assert(indices.size() <= 2);
element_type = extract_type(pointer, indices); element_type = extract_type(pointer, indices);
Add_Operand(pointer); add_operand(pointer);
for (auto index : indices) { for (auto index : indices) {
Add_Operand(index); add_operand(index);
} }
} }

View File

@ -71,28 +71,28 @@ public:
std::vector<ValuePtr_t> operand_list; std::vector<ValuePtr_t> operand_list;
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) { /*
Value加入到operands里面,use信息
*/
void add_operand(ValuePtr_t op) {
// value, use, op_index // value, use, op_index
op->use_list.push_back({/*op.get(),*/ this, (unsigned)operand_list.size()}); op->use_list.push_back({/*op.get(),*/ this, (unsigned)operand_list.size()});
operand_list.push_back(op); operand_list.push_back(op);
} }
// make anything that use this value use the new value /*
this的use给换掉,this就没人用了
this拥有一个use_list,使this的指令
*/
void u_replace_users(ValuePtr_t 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) { for (auto use : use_list) {
auto user = use.user;
auto index = use.op_index;
user->operand_list[index] = value;
assert(value); assert(value);
value->use_list.push_back({/*value.get(),*/ user, index}); use.user->operand_list[use.op_index] = value;
value->use_list.push_back({/*value.get(),*/ use.user, use.op_index});
} }
// all original uses are gone // all original uses are gone
use_list.clear(); use_list.clear();
} }
// remove this user from its operands // 更新所有被use到的指令,因为this不再使用它,也就是从每个operands的use_list里面把自己删掉
void u_remove_from_usees() { void u_remove_from_usees() {
for (auto op : operand_list) { for (auto op : operand_list) {
assert(op); assert(op);
@ -140,7 +140,7 @@ class BasicBlock : public Value {
public: public:
int ir_seqno = -1; int ir_seqno = -1;
std::list<InstructionPtr_t> inst_list; std::list<InstructionPtr_t> inst_list;
std::shared_ptr<Function> parent; std::shared_ptr<Function> parent_func;
BasicBlockListNode_t itr; BasicBlockListNode_t itr;
std::list<BasicBlockPtr_t> succ_list; std::list<BasicBlockPtr_t> succ_list;
std::list<BasicBlockPtr_t> pred_list; std::list<BasicBlockPtr_t> pred_list;
@ -155,7 +155,7 @@ public:
int dom_dfs_out; 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_func = parent;
} }
static sptr(BasicBlock) static sptr(BasicBlock)
@ -175,9 +175,9 @@ public:
class ConstantInt : public Constant { class ConstantInt : public Constant {
public: public:
int value; int value;
ConstantInt(const std::string &name, int value) : Constant(name, TypeHelper::TYPE_I32), value(value) {} ConstantInt(const std::string &name, int value, TypePtr_t type) : Constant(name, type), value(value) {}
static std::shared_ptr<ConstantInt> New(int value) { static std::shared_ptr<ConstantInt> New(int value, TypePtr_t type = TypeHelper::TYPE_I32) {
return std::make_shared<ConstantInt>("", value); return std::make_shared<ConstantInt>("", value, type);
} }
virtual std::string to_string() override { virtual std::string to_string() override {
std::string str = type->to_string() + " " + std::to_string(value); std::string str = type->to_string() + " " + std::to_string(value);

View File

@ -11,20 +11,68 @@ class Pass {
public: public:
std::string pass_name; std::string pass_name;
Pass(const std::string &name) : pass_name(name) {} Pass(const std::string &name) : pass_name(name) {}
virtual ~Pass() = default;
virtual void run(const Module &module) = 0; virtual void run(const Module &module) = 0;
}; };
class PassSCCP final : public Pass {
public:
PassSCCP() : Pass("const fold") {}
void run(const Module &module) override;
enum class ConstLatTag { Top = 0, Const, Bottom };
struct ConstLat {
ConstLatTag tag = ConstLatTag::Top;
int value = ~0;
bool is_top() const {
return tag == ConstLatTag::Top;
}
bool is_bot() const {
return tag == ConstLatTag::Bottom;
}
bool is_const() const {
return tag == ConstLatTag::Const;
}
bool operator==(const ConstLat &op2) const {
return tag == op2.tag && value == op2.value;
}
bool operator!=(const ConstLat &op2) const {
return !(tag == op2.tag && value == op2.value);
}
static ConstLat get_bot() {
return {ConstLatTag::Bottom, ~0};
}
};
private:
typedef std::pair<int, int> edge_type;
std::set<edge_type> FLowWL;
std::set<edge_type> SSAWL;
std::map<edge_type, bool> ExecFlag;
std::map<Value *, ConstLat> LatCell;
std::unordered_map<Instruction *, int> inst_id;
std::unordered_map<int, Instruction *> id_inst;
std::set<std::pair<int, int>> edge_set;
std::unordered_map<int, std::unordered_set<int>> edge_list;
void build_single_inst_block(Function *func);
void Initialize(Function *);
void SCCP(Function *);
void Visit_Phi(InstPhi *);
void Visit_Inst(Instruction *);
ConstLat Lat_Eval(Instruction *inst);
void post_sccp();
};
class PassMem2Reg final : public Pass { class PassMem2Reg final : public Pass {
public: public:
PassMem2Reg() : Pass("mem2reg") {} PassMem2Reg() : Pass("mem2reg") {}
virtual void run(const Module &module) override; void run(const Module &module) override;
}; };
class PassBuildCFG final : public Pass { class PassBuildCFG final : public Pass {
public: public:
PassBuildCFG() : Pass("build_cfg") {} PassBuildCFG() : Pass("build_cfg") {}
virtual void run(const Module &module) override; void run(const Module &module) override;
}; };
class MCPass { class MCPass {

View File

@ -43,7 +43,7 @@ private:
ScopeTable<std::shared_ptr<Value>> _scope_tab; ScopeTable<std::shared_ptr<Value>> _scope_tab;
ScopeTable<std::shared_ptr<Function>> _func_tab; // var can have same name as func ScopeTable<std::shared_ptr<Function>> _func_tab; // var can have same name as func
VisitorState _state = {}; VisitorState _state = {};
inline static std::shared_ptr<ConstantInt> CONST0 = std::make_shared<ConstantInt>("CONST0", 0); inline static std::shared_ptr<ConstantInt> CONST0 = ConstantInt::New(0);
public: public:
Module module = {}; Module module = {};

View File

@ -52,11 +52,11 @@ class Compiler:
log = self.compile_log.format(testcase=testcase) log = self.compile_log.format(testcase=testcase)
log_file = open(log, "a+") log_file = open(log, "a+")
Print_C.print_procedure(f"Generating {ir} from {sy}") Print_C.print_procedure(f"Gen {ir} from {sy}")
completed = subprocess.run(frontend_instr.format(sy=sy, ir=ir).split(), stdout=log_file, stderr=log_file, bufsize=1) completed = subprocess.run(frontend_instr.format(sy=sy, ir=ir).split(), stdout=log_file, stderr=log_file, bufsize=1)
log_file.close() log_file.close()
if completed.returncode != 0: if completed.returncode != 0:
Print_C.print_error(f"Generate {ir} failed! See {log}") Print_C.print_error(f"Gen {ir} failed! See {log}")
self.count_error += 1 self.count_error += 1
return False return False
return True return True
@ -68,11 +68,11 @@ class Compiler:
log = self.compile_log.format(testcase=testcase) log = self.compile_log.format(testcase=testcase)
log_file = open(log, "a+") log_file = open(log, "a+")
Print_C.print_procedure(f"Generating {asm} from {ir}") Print_C.print_procedure(f"Gen {asm} from {ir}")
completed = subprocess.run(ir_asm_instr.format(ir=ir, asm=asm).split(), stdout=log_file, stderr=log_file, bufsize=1) completed = subprocess.run(ir_asm_instr.format(ir=ir, asm=asm).split(), stdout=log_file, stderr=log_file, bufsize=1)
log_file.close() log_file.close()
if completed.returncode != 0: if completed.returncode != 0:
Print_C.print_error(f"Generate {asm} failed! See {log}") Print_C.print_error(f"Gen {asm} failed! See {log}")
self.count_error += 1 self.count_error += 1
return False return False
return True return True
@ -84,11 +84,11 @@ class Compiler:
log = self.compile_log.format(testcase=testcase) log = self.compile_log.format(testcase=testcase)
log_file = open(log, "a+") log_file = open(log, "a+")
Print_C.print_procedure(f"Generating {obj} from {asm}") Print_C.print_procedure(f"Gen {obj} from {asm}")
completed = subprocess.run(asm_obj_instr.format(asm=asm,obj=obj).split(), stdout=log_file, stderr=log_file, bufsize=1) completed = subprocess.run(asm_obj_instr.format(asm=asm,obj=obj).split(), stdout=log_file, stderr=log_file, bufsize=1)
log_file.close() log_file.close()
if completed.returncode != 0: if completed.returncode != 0:
Print_C.print_error(f"Generate {obj} failed! See {log}") Print_C.print_error(f"Gen {obj} failed! See {log}")
self.count_error += 1 self.count_error += 1
return False return False
return True return True
@ -100,11 +100,11 @@ class Compiler:
log = self.compile_log.format(testcase=testcase) log = self.compile_log.format(testcase=testcase)
log_file = open(log, "a+") log_file = open(log, "a+")
Print_C.print_procedure(f"Generating {bin}") Print_C.print_procedure(f"Gen {bin}")
completed = subprocess.run(obj_bin_instr.format(obj=obj,bin=bin).split(), stdout=log_file, stderr=log_file, bufsize=1) completed = subprocess.run(obj_bin_instr.format(obj=obj,bin=bin).split(), stdout=log_file, stderr=log_file, bufsize=1)
log_file.close() log_file.close()
if completed.returncode != 0: if completed.returncode != 0:
Print_C.print_error(f"Generate {bin} failed! See {log}") Print_C.print_error(f"Gen {bin} failed! See {log}")
self.count_error += 1 self.count_error += 1
return False return False
return True return True
@ -116,12 +116,12 @@ class Compiler:
log = self.compile_log.format(testcase=testcase) log = self.compile_log.format(testcase=testcase)
log_file = open(log, "a+") log_file = open(log, "a+")
Print_C.print_procedure(f"Generating {asm}") Print_C.print_procedure(f"Gen {asm} from {sy}")
completed = subprocess.run(sy_asm_instr.format(asm=asm, sy=sy).split(), stdout=log_file, stderr=log_file, bufsize=1) completed = subprocess.run(sy_asm_instr.format(asm=asm, sy=sy).split(), stdout=log_file, stderr=log_file, bufsize=1)
# print(sy_asm_instr.format(asm=asm, sy=sy)) # print(sy_asm_instr.format(asm=asm, sy=sy))
log_file.close() log_file.close()
if completed.returncode != 0: if completed.returncode != 0:
Print_C.print_error(f"Generate {bin} failed! See {log}") Print_C.print_error(f"Gen {bin} failed! See {log}")
self.count_error += 1 self.count_error += 1
return False return False
return True return True

View File

@ -113,7 +113,10 @@ int main(int argc, const char **argv) {
} }
} }
std::vector<sptr(Pass)> optpasses = {}; std::vector<sptr(Pass)> optpasses = {
std::make_shared<PassSCCP>(),
};
if (flg_O1) { if (flg_O1) {
for (auto pass : optpasses) { for (auto pass : optpasses) {
pass->run(visitor.module); pass->run(visitor.module);

313
src/pass_const_prop.cpp Normal file
View File

@ -0,0 +1,313 @@
#include "pass.h"
namespace CompSysY {
using ConstLat = PassSCCP::ConstLat;
using ConstLatTag = PassSCCP::ConstLatTag;
static InstBranch *is_cond_br(Instruction *inst) {
auto inst_br = dynamic_cast<InstBranch *>(inst);
if (inst_br && inst_br->operand_list.size() == 3) {
return inst_br;
}
return nullptr;
}
static bool Has_Left(Instruction *inst) {
return inst->type->type_tag != Type::TypeTag::VoidType || is_cond_br(inst);
}
void PassSCCP::build_single_inst_block(Function *func) {
int id_cnt = 1;
inst_id.clear();
id_inst.clear();
edge_list.clear();
edge_set.clear();
// dummy entry node
edge_set.insert({0, 1});
edge_list[0].insert(1);
std::vector<BasicBlock *> stk = {func->bb_list.front().get()};
std::unordered_map<BasicBlock *, bool> visit;
while (stk.size()) {
auto bb = stk.back();
stk.pop_back();
if (visit[bb]) continue;
visit[bb] = true;
for (auto inst : bb->inst_list) {
inst_id[inst.get()] = id_cnt;
id_inst[id_cnt] = inst.get();
++id_cnt;
}
for (auto succ : bb->succ_list) {
stk.push_back(succ.get());
}
}
stk.push_back(func->bb_list.front().get());
visit.clear();
while (stk.size()) {
auto bb = stk.back();
stk.pop_back();
if (visit[bb]) continue;
visit[bb] = true;
int begin_id = inst_id[bb->inst_list.front().get()];
int end_id = inst_id[bb->inst_list.back().get()];
for (int i = begin_id; i < end_id; ++i) {
edge_set.insert({i, i + 1});
edge_list[i].insert(i + 1);
}
for (auto succ : bb->succ_list) {
stk.push_back(succ.get());
edge_set.insert({end_id, inst_id.at(succ->inst_list.front().get())});
edge_list[end_id].insert(inst_id.at(succ->inst_list.front().get()));
}
}
}
void PassSCCP::Initialize(Function *func) {
build_single_inst_block(func);
SSAWL.clear();
FLowWL.clear();
ExecFlag.clear();
for (auto e : edge_set) {
ExecFlag[e] = false;
}
LatCell.clear();
for (auto [a, inst] : id_inst) {
if (Has_Left(inst)) {
LatCell[inst] = ConstLat();
}
}
// for ExecFlag, LatCell, [] operator gives default value on first use
auto entry_bb = func->bb_list.front();
auto entry_inst = inst_id[entry_bb->inst_list.front().get()];
// dummy entry node, anyways, it won't get used
FLowWL.insert({0, entry_inst});
}
/*
According to Wegman,Zadeck's paper, the rules for \union:
1. any \union Top = any
2. any \union Bot = Bot
3. v1 \union v2 = v1, if v1==v2
4. v1 \union v2 = Bot, if v1!=v2
*/
static ConstLat lattice_meet(const ConstLat &op1, const ConstLat &op2) {
// 1.
if (op1.is_top()) return op2;
if (op2.is_top()) return op1;
// 2.
if (op1.is_bot() || op2.is_bot()) return ConstLat::get_bot();
// 3.
if (op1 == op2) return op1;
// 4.
return ConstLat::get_bot();
}
/*
expression ebaluation rules: the value of the operands of an expression corresponds to
the value of the variables at the entrance to the node,
and the result corresponds to the value of variables that
change during the execution of the node.
Usually,
1. if the node is an assignment and any of the variables used in its expression portion has a value of \bot, the value
exiting the assignment statement for that variable is \bot.
2. If all values used in its expression portion are constant,the value of the assigned variable is the value of the
expression when evaluated with those constant values.
3. Otherwise, the value assigned is \bot
*/
ConstLat PassSCCP::Lat_Eval(Instruction *inst) {
bool evaluatable = false;
if (InstTag::Add <= inst->tag && inst->tag <= InstTag::Ne || inst->tag == InstTag::Zext) evaluatable = true;
if (is_cond_br(inst)) {
// directly use its cond's value as its result
return LatCell[inst->operand_list[0].get()];
}
if (!evaluatable) {
return ConstLat::get_bot();
}
for (auto op : inst->operand_list) {
if (dynamic_cast<ConstantInt *>(op.get()) || LatCell[op.get()].is_const()) continue;
return ConstLat::get_bot();
}
auto val = [&](int op) {
if (auto const_op = dynamic_cast<ConstantInt *>(inst->operand_list[op].get())) {
return const_op->value;
}
else {
return LatCell[inst->operand_list[op].get()].value;
}
};
int result = 0;
switch (inst->tag) {
case InstTag::Add: result = val(0) + val(1); break;
case InstTag::Sub: result = val(0) - val(1); break;
case InstTag::Mod: result = val(0) % val(1); break;
case InstTag::Mul: result = val(0) * val(1); break;
case InstTag::Div: result = val(0) / val(1); break;
case InstTag::Lt: result = val(0) < val(1); break;
case InstTag::Le: result = val(0) <= val(1); break;
case InstTag::Ge: result = val(0) >= val(1); break;
case InstTag::Gt: result = val(0) > val(1); break;
case InstTag::Eq: result = val(0) == val(1); break;
case InstTag::Ne: result = val(0) != val(1); break;
case InstTag::Zext: result = val(0); break;
default: break;
}
return {ConstLatTag::Const, result};
}
void PassSCCP::SCCP(Function *func) {
Initialize(func);
auto Edge_Count = [&](int b) {
int cnt = 0;
for (int i = 0; i < inst_id.size(); ++i) {
auto e = std::make_pair(i, b);
if (INSET(edge_set, e) && ExecFlag[e]) {
cnt++;
}
}
return cnt;
};
while (!FLowWL.empty() || !SSAWL.empty()) {
// propagate along CFG edges
if (!FLowWL.empty()) {
int a = FLowWL.begin()->first;
int b = FLowWL.begin()->second;
FLowWL.erase(FLowWL.begin());
if (!ExecFlag[{a, b}]) {
ExecFlag[{a, b}] = true;
auto inst = id_inst[b];
if (auto inst_phi = dynamic_cast<InstPhi *>(inst)) {
Visit_Phi(inst_phi);
}
else if (Edge_Count(b) == 1) {
Visit_Inst(inst);
}
}
}
// propagate along SSA edges(def-use)
if (!SSAWL.empty()) {
int a = SSAWL.begin()->first;
int b = SSAWL.begin()->second;
SSAWL.erase(SSAWL.begin());
auto inst = id_inst[b];
if (auto inst_phi = dynamic_cast<InstPhi *>(inst)) {
Visit_Phi(inst_phi);
}
else if (Edge_Count(b) >= 1) {
Visit_Inst(inst);
}
}
}
}
void PassSCCP::Visit_Phi(InstPhi *inst_phi) {
for (int i = 0; i < inst_phi->operand_list.size(); ++i) {
auto inst_vars = inst_phi->operand_list[i].get();
LatCell[inst_phi] = lattice_meet(LatCell[inst_phi], LatCell[inst_vars]);
}
}
void PassSCCP::Visit_Inst(Instruction *inst) {
auto EL = [&](int v) -> bool {
auto inst_br = dynamic_cast<InstBranch *>(inst);
assert(inst_br && inst_br->operand_list.size() == 3);
auto true_bb = dynamic_cast<BasicBlock *>(inst_br->operand_list[1].get());
if (id_inst[v] == true_bb->inst_list.front().get()) {
return true;
}
return false;
};
auto val = Lat_Eval(inst);
if (Has_Left(inst)) {
if (val != LatCell[inst]) {
LatCell[inst] = lattice_meet(LatCell[inst], val);
// SSAWL UNION SSASucc(inst)
for (auto &use : inst->use_list) {
auto user = dynamic_cast<Instruction *>(use.user);
SSAWL.insert({inst_id[inst], inst_id[user]});
}
}
}
if (InstTag::Add <= inst->tag && inst->tag <= InstTag::Ne || inst->tag == InstTag::Zext || is_cond_br(inst)) {
int k = inst_id[inst];
if (val.is_top()) {
for (auto i : edge_list[k]) {
FLowWL.insert({k, i});
}
}
else if (!val.is_bot()) {
// imply: val is const
assert(edge_list[k].size() <= 2);
if (edge_list[k].size() == 2) {
for (auto i : edge_list[k]) {
// val & EL(k,i)=Y OR !val & EL(k,i)=N
if ((val.value && EL(i)) || (!val.value && !EL(i))) {
FLowWL.insert({k, i});
}
}
}
else if (edge_list[k].size() == 1) {
// FlowWL UNION k->Succ(k)
FLowWL.insert({k, *edge_list[k].begin()});
}
}
}
}
/*
pred is no more bb's pred, so maintain cfg and rewrite bb's phi nodes
*/
static void rewrite_bb(sptr(BasicBlock) bb, sptr(BasicBlock) pred) {
pred->succ_list.remove(bb);
auto pred_index = GETINDEX(bb->pred_list, pred);
bb->pred_list.remove(pred);
for (auto itr = bb->inst_list.begin(); itr != bb->inst_list.end();) {
auto inst = *itr++;
if (!shared_cast<InstPhi>(inst)) break;
auto inst_phi = shared_cast<InstPhi>(inst);
assert(inst_phi->operand_list.size() > pred_index);
inst_phi->operand_list.erase(inst_phi->operand_list.begin() + pred_index);
}
}
void PassSCCP::post_sccp() {
for (auto lat_pair : LatCell) {
if (lat_pair.second.is_const()) {
auto inst = dynamic_cast<Instruction *>(lat_pair.first);
inst->u_replace_users(ConstantInt::New(lat_pair.second.value, inst->type));
inst->u_remove_from_usees();
VLOG(6) << fmt::format("[SCCP] Replace vreg ${} with const {}", inst_id[inst], lat_pair.second.value);
// Though it should be removed here... leave this work to dce part
}
}
// rewrite branches
for (const auto &_p : inst_id) {
auto inst = _p.first;
if (auto inst_br = is_cond_br(inst)) {
if (auto const_cond = dynamic_cast<ConstantInt *>(inst_br->operand_list[0].get())) {
auto cond = const_cond->value;
VLOG(6) << fmt::format("[SCCP] Replace branch cond ${} with const {}", inst_id[inst], const_cond->value);
inst_br->u_remove_from_usees();
auto target = shared_cast<BasicBlock>(cond ? inst->operand_list[1] : inst->operand_list[2]);
auto dead_target = shared_cast<BasicBlock>(!cond ? inst->operand_list[1] : inst->operand_list[2]);
assert(target && dead_target);
inst_br->operand_list.clear();
inst_br->add_operand(target);
// maintain cfg
rewrite_bb(dead_target, inst_br->parent_bb);
}
}
}
}
void PassSCCP::run(const Module &module) {
LOG(INFO) << "Run pass " << pass_name;
for (auto func : module.function_list) {
if (func->is_libfunc()) continue;
SCCP(func.get());
post_sccp();
}
}
} // namespace CompSysY

View File

@ -234,70 +234,58 @@ static void _mem_2_reg(FunctionPtr_t func) {
if (alloca_list.empty()) return; if (alloca_list.empty()) return;
VLOG(6) << "[mem2reg] Variable renaming"; VLOG(6) << "[mem2reg] Variable renaming";
/*
From LLVM, , ()
dfs,entry开始沿着succ往后走,alloca的值,
*/
std::vector<ValuePtr_t> _init_values; std::vector<ValuePtr_t> _init_values;
for (int i = 0; i < alloca_list.size(); ++i) _init_values.push_back(ConstantInt::New(0)); for (int i = 0; i < alloca_list.size(); ++i) _init_values.push_back(ConstantInt::New(0));
std::vector<RenameInfo> rename_list = {{func->bb_list.front(), nullptr, _init_values}}; std::vector<RenameInfo> rename_list;
rename_list.push_back({func->bb_list.front(), nullptr, _init_values});
std::vector<bool> visited(bb_to_id.size(), 0); std::vector<bool> visited(bb_to_id.size(), 0);
while (!rename_list.empty()) { while (!rename_list.empty()) {
auto rename_info = rename_list.back(); auto rename_info = rename_list.back();
rename_list.pop_back(); rename_list.pop_back();
// replace block with more specific alloca // 将phi指令中对应pred的值更新,因为它在处理pred的时候已经被重新定值
for (auto inst : rename_info.bb->inst_list) { for (auto inst : rename_info.bb->inst_list) {
// phi only appear at block head // phi only appear at block head
if (!shared_cast<InstPhi>(inst)) break; if (!shared_cast<InstPhi>(inst)) break;
auto phi = shared_cast<InstPhi>(inst); auto phi = shared_cast<InstPhi>(inst);
auto alloca_index = phi_to_allocaid.at(phi); int pred_index = GETINDEX(rename_info.bb->pred_list, rename_info.pred);
int pred_index = -1; phi->set_incoming_val(pred_index, rename_info.value_list[phi_to_allocaid.at(phi)]);
for (auto pred : rename_info.bb->pred_list) {
pred_index++;
if (pred == rename_info.pred) break;
}
phi->set_incoming_val(pred_index, rename_info.value_list[alloca_index]);
} }
// already processed, skip // already processed, skip
if (visited[bb_to_id.at(rename_info.bb)]) continue; if (visited[bb_to_id.at(rename_info.bb)]) continue;
visited[bb_to_id.at(rename_info.bb)] = true; visited[bb_to_id.at(rename_info.bb)] = true;
// process instruction // process instruction
// 这里其实十分的清楚,就是把所有load alloca的load指令删掉,把这条load的use换成alloca的值(而不是alloca地址)
// 然后把store alloca的store也删掉,同时更新当前的alloca的值
// 遇到phi指令要更新alloca的值为phi
// 如果是alloca,记得直接删掉(当然只删掉前面处理过的int类型的)
for (auto itr = rename_info.bb->inst_list.begin(); itr != rename_info.bb->inst_list.end();) { for (auto itr = rename_info.bb->inst_list.begin(); itr != rename_info.bb->inst_list.end();) {
auto inst = *itr++; auto inst = *itr++; // increase itr first, it will get invalidated by remove
// we skip non-integer alloca, they are not in our alloca_list // we skip non-integer alloca, they are not in our alloca_list
if (shared_cast<InstAlloca>(inst) && alloca_to_id.count(shared_cast<InstAlloca>(inst))) { if (shared_cast<InstAlloca>(inst)) {
rename_info.bb->inst_list.remove(inst); if (alloca_to_id.count(shared_cast<InstAlloca>(inst))) rename_info.bb->inst_list.remove(inst);
} }
else if (shared_cast<InstLoad>(inst)) { else if (auto inst_ld = shared_cast<InstLoad>(inst)) {
auto li = shared_cast<InstLoad>(inst); if (!(shared_cast<InstAlloca>(inst_ld->operand_list[0]))) continue;
if (!(shared_cast<InstAlloca>(li->operand_list[0]))) { auto ai = shared_cast<InstAlloca>(inst_ld->operand_list[0]);
continue; if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) continue;
} rename_info.bb->inst_list.remove(inst_ld);
auto ai = shared_cast<InstAlloca>(li->operand_list[0]); inst_ld->u_replace_users(rename_info.value_list[alloca_to_id.at(ai)]);
if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) { inst_ld->u_remove_from_usees();
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 (shared_cast<InstStore>(inst)) { else if (auto inst_st = shared_cast<InstStore>(inst)) {
auto si = shared_cast<InstStore>(inst); if (!(shared_cast<InstAlloca>(inst_st->operand_list[1]))) continue;
if (!(shared_cast<InstAlloca>(si->operand_list[1]))) { auto ai = shared_cast<InstAlloca>(inst_st->operand_list[1]);
continue; if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) continue;
} rename_info.value_list[alloca_to_id.at(ai)] = inst_st->operand_list[0];
auto ai = shared_cast<InstAlloca>(si->operand_list[1]); inst_st->u_remove_from_usees();
if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) { rename_info.bb->inst_list.remove(inst_st);
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 (shared_cast<InstPhi>(inst)) { else if (auto phi = shared_cast<InstPhi>(inst)) {
auto phi = shared_cast<InstPhi>(inst); rename_info.value_list[phi_to_allocaid.at(phi)] = phi;
int alloca_index = phi_to_allocaid.at(phi);
rename_info.value_list[alloca_index] = phi;
} }
} }
for (auto succ : rename_info.bb->succ_list) { for (auto succ : rename_info.bb->succ_list) {

View File

@ -168,6 +168,11 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
assert(bb_dest->ir_seqno >= 0); assert(bb_dest->ir_seqno >= 0);
ostr << "label %" << bb_dest->ir_seqno; ostr << "label %" << bb_dest->ir_seqno;
} }
else if (auto const_cond = shared_cast<ConstantInt>(inst->operand_list[0])) {
//! temporary patch after sccp, but it is often incorrect for phi
auto target_bb = const_cond->value ? inst->operand_list[1] : inst->operand_list[2];
ostr << "label %" << shared_cast<BasicBlock>(target_bb)->ir_seqno;
}
else { else {
assert(shared_cast<Instruction>(inst->operand_list[0])); assert(shared_cast<Instruction>(inst->operand_list[0]));
assert(Type::isType<IntegerType>(inst->operand_list[0]->type)); assert(Type::isType<IntegerType>(inst->operand_list[0]->type));
@ -416,11 +421,11 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
} }
else if (shared_cast<ConstantInt>(inst->operand_list[0])) { else if (shared_cast<ConstantInt>(inst->operand_list[0])) {
auto op0 = shared_cast<ConstantInt>(inst->operand_list[0]); auto op0 = shared_cast<ConstantInt>(inst->operand_list[0]);
ostr << op0->to_IR_string() << "to "; ostr << op0->to_IR_string() << " to ";
} }
else if (shared_cast<FParam>(inst->operand_list[0])) { else if (shared_cast<FParam>(inst->operand_list[0])) {
auto op0 = shared_cast<FParam>(inst->operand_list[0]); auto op0 = shared_cast<FParam>(inst->operand_list[0]);
ostr << op0->to_IR_string() << "to "; ostr << op0->to_IR_string() << " to ";
} }
else { else {
LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string(); LOG(ERROR) << "Unexpected type of op0: " << inst->operand_list[0]->to_string();