Commit f40efe88 authored by Yang's avatar Yang

publish lab4

parent 93702b62
......@@ -63,4 +63,4 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR})
add_subdirectory(src)
# add_subdirectory(tests)
add_subdirectory(tests)
......@@ -67,15 +67,10 @@ class CminusfBuilder : public ASTVisitor {
auto *output_float_fun =
Function::create(output_float_type, "outputFloat", module);
auto *neg_idx_except_type = FunctionType::get(TyVoid, {});
auto *neg_idx_except_fun = Function::create(
neg_idx_except_type, "neg_idx_except", module);
scope.enter();
scope.push("input", input_fun);
scope.push("output", output_fun);
scope.push("outputFloat", output_float_fun);
scope.push("neg_idx_except", neg_idx_except_fun);
}
Module* getModule() const { return module; }
......
......@@ -64,18 +64,6 @@ class CodeGen {
void gen_fptosi();
void gen_epilogue();
static std::string label_name(BasicBlock *bb) {
return "." + bb->get_parent()->get_name() + "_" + bb->get_name();
}
static std::string func_exit_label_name(Function *func) {
return func->get_name() + "_exit";
}
static std::string fcmp_label_name(BasicBlock *bb, unsigned cnt) {
return label_name(bb) + "_fcmp_" + std::to_string(cnt);
}
struct {
/* 随着ir遍历设置 */
Function *func{nullptr}; // 当前函数
......@@ -84,14 +72,12 @@ class CodeGen {
/* 在allocate()中设置 */
unsigned frame_size{0}; // 当前函数的栈帧大小
std::unordered_map<Value *, int> offset_map{}; // 指针相对 fp 的偏移
unsigned fcmp_cnt{0}; // fcmp 的计数器, 用于创建 fcmp 需要的 label
void clear() {
func = nullptr;
bb = nullptr;
inst = nullptr;
frame_size = 0;
fcmp_cnt = 0;
offset_map.clear();
}
......
......@@ -20,8 +20,7 @@ class BasicBlock : public Value {
~BasicBlock() override;
static BasicBlock *create(Module *m, const std::string &name,
Function *parent) {
auto prefix = name.empty() ? "" : "label_";
return new BasicBlock(m, prefix + name, parent);
return new BasicBlock(m, name, parent);
}
/****************api about cfg****************/
......
......@@ -214,6 +214,8 @@ public:
Value *get_condition() const { return get_operand(0); }
void replace_all_bb_match(BasicBlock* need_replace, BasicBlock* replace_to);
std::string print() override;
};
......@@ -251,8 +253,8 @@ class StoreInst : public Instruction {
public:
static StoreInst *create_store(Value *val, Value *ptr, BasicBlock *bb);
Value *get_rval() const { return this->get_operand(0); }
Value *get_lval() const { return this->get_operand(1); }
Value *get_val() const { return this->get_operand(0); }
Value *get_ptr() const { return this->get_operand(1); }
std::string print() override;
};
......@@ -264,7 +266,7 @@ class LoadInst : public Instruction {
public:
static LoadInst *create_load(Value *ptr, BasicBlock *bb, const std::string& name = "");
Value *get_lval() const { return this->get_operand(0); }
Value *get_ptr() const { return this->get_operand(0); }
Type *get_load_type() const { return get_type(); }
std::string print() override;
......
......@@ -20,11 +20,11 @@ class Dominators : public FunctionAnalysisPass {
void run() override;
// 获取基本块的直接支配节点
BasicBlock *get_idom(const BasicBlock *bb) const { return idom_.at(bb); }
const std::set<BasicBlock*> &get_dominance_frontier(const BasicBlock *bb) {
BasicBlock *get_idom(BasicBlock *bb) const { return idom_.at(bb); }
const std::set<BasicBlock*> &get_dominance_frontier(BasicBlock *bb) {
return dom_frontier_.at(bb);
}
const std::set<BasicBlock*> &get_dom_tree_succ_blocks(const BasicBlock *bb) {
const std::set<BasicBlock*> &get_dom_tree_succ_blocks(BasicBlock *bb) {
return dom_tree_succ_blocks_.at(bb);
}
......@@ -33,7 +33,7 @@ class Dominators : public FunctionAnalysisPass {
void dump_dominator_tree();
// functions for dominance tree
bool is_dominate(const BasicBlock *bb1, const BasicBlock *bb2) const {
bool is_dominate(BasicBlock *bb1, BasicBlock *bb2) const {
return dom_tree_L_.at(bb1) <= dom_tree_L_.at(bb2) &&
dom_tree_R_.at(bb1) >= dom_tree_L_.at(bb2);
}
......@@ -54,33 +54,33 @@ class Dominators : public FunctionAnalysisPass {
void create_dom_tree_succ();
void create_dom_dfs_order();
BasicBlock * intersect(BasicBlock *b1, const BasicBlock *b2) const;
BasicBlock * intersect(BasicBlock *b1, BasicBlock *b2) const;
void create_reverse_post_order();
void set_idom(const BasicBlock *bb, BasicBlock *idom) { idom_[bb] = idom; }
void set_dominance_frontier(const BasicBlock *bb, std::set<BasicBlock*>&df) {
void set_idom(BasicBlock *bb, BasicBlock *idom) { idom_[bb] = idom; }
void set_dominance_frontier(BasicBlock *bb, std::set<BasicBlock*>&df) {
dom_frontier_[bb].clear();
dom_frontier_[bb].insert(df.begin(), df.end());
}
void add_dom_tree_succ_block(const BasicBlock *bb, BasicBlock *dom_tree_succ_bb) {
void add_dom_tree_succ_block(BasicBlock *bb, BasicBlock *dom_tree_succ_bb) {
dom_tree_succ_blocks_[bb].insert(dom_tree_succ_bb);
}
unsigned int get_post_order(const BasicBlock *bb) const {
return post_order_.at(bb);
unsigned int get_reversed_post_order(BasicBlock *bb) const {
return reversed_post_order_.at(bb);
}
// for debug
void print_idom() const;
void print_dominance_frontier();
std::vector<BasicBlock *> post_order_vec_{}; // 逆后序
std::map<const BasicBlock *, unsigned int> post_order_{}; // 逆后序
std::map<const BasicBlock *, BasicBlock *> idom_{}; // 直接支配
std::map<const BasicBlock *, std::set<BasicBlock*>> dom_frontier_{}; // 支配边界集合
std::map<const BasicBlock *, std::set<BasicBlock*>> dom_tree_succ_blocks_{}; // 支配树中的后继节点
std::vector<BasicBlock *> reversed_post_order_vec_{}; // 逆后序
std::map<BasicBlock *, unsigned int> reversed_post_order_{}; // 逆后序索引
std::map<BasicBlock *, BasicBlock *> idom_{}; // 直接支配
std::map<BasicBlock *, std::set<BasicBlock*>> dom_frontier_{}; // 支配边界集合
std::map<BasicBlock *, std::set<BasicBlock*>> dom_tree_succ_blocks_{}; // 支配树中的后继节点
// 支配树上的dfs序L,R
std::map<const BasicBlock *, unsigned int> dom_tree_L_;
std::map<const BasicBlock *, unsigned int> dom_tree_R_;
std::map<BasicBlock *, unsigned int> dom_tree_L_;
std::map<BasicBlock *, unsigned int> dom_tree_R_;
std::vector<BasicBlock *> dom_dfs_order_;
std::vector<BasicBlock *> dom_post_order_;
......
......@@ -27,13 +27,17 @@ class FuncInfo : public ModuleAnalysisPass {
void run() override;
// 函数是否是纯函数
bool is_pure(Function *func) { return !func->is_declaration() && !use_libs.count(func) && loads[func].empty() && stores[func].empty(); }
bool is_pure(Function *func) { return !func->is_declaration() && !use_libs[func] && loads[func].empty() && stores[func].empty(); }
// 函数是否使用了 io
bool use_io(Function* func) { return func->is_declaration() || use_libs[func]; }
// 返回 StoreInst 存入的变量(全局/局部变量或函数参数)
static Value* store_ptr(const StoreInst* st);
// 返回 LoadInst 加载的变量(全局/局部变量或函数参数)
static Value* load_ptr(const LoadInst* ld);
// 返回 CallInst 代表的函数调用间接存入的变量(全局/局部变量或函数参数)
std::unordered_set<Value*> get_stores(const CallInst* call);
// 返回 CallInst 代表的函数调用间接加载的变量(全局/局部变量或函数参数)
std::unordered_set<Value*> get_loads(const CallInst* call);
private:
// 函数存储的值
std::unordered_map<Function*, UseMessage> stores;
......
......@@ -18,8 +18,4 @@ class LoopInvariantCodeMotion : public TransformPass {
std::vector<Instruction*> collect_insts(Loop* loop);
void traverse_loop(Loop* loop);
void run_on_loop(Loop* loop);
void collect_loop_info(Loop* loop,
std::set<Value *> &loop_instructions,
std::set<Value *> &updated_global,
bool &contains_impure_call);
};
\ No newline at end of file
......@@ -40,6 +40,7 @@ class Loop {
const std::vector<Loop*>& get_sub_loops() { return sub_loops_; }
const std::unordered_set<BasicBlock *>& get_latches() { return latches_; }
void add_latch(BasicBlock *bb) { latches_.insert(bb); }
std::string safe_print() const;
};
class LoopDetection : public FunctionAnalysisPass {
......
......@@ -25,7 +25,8 @@ def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
, "BasicBlock"
, "GlobalVariable"
, "Instruction", "IBinaryInst", "FBinaryInst", "ICmpInst", "FCmpInst", "CallInst", "BranchInst", "ReturnInst", "GetElementPtrInst", "StoreInst", "LoadInst", "AllocaInst", "ZextInst", "FpToSiInst", "SiToFpInst", "PhiInst"
, "ASMInstruction", "Reg", "FReg", "CFReg" ]
, "ASMInstruction", "Reg", "FReg", "CFReg"
, "Loop" ]
for i in types:
debugger.HandleCommand(
f"type summary add -F lldb_formatters.SafePrintSummary {i} -w my"
......
......@@ -329,27 +329,10 @@ Value* CminusfBuilder::visit(ASTVar &node) {
}
} else {
auto *val = node.expression->accept(*this);
auto *exceptBB = BasicBlock::create(module, "", context.func);
auto *contBB = BasicBlock::create(module, "", context.func);
if (val->get_type()->is_float_type()) {
val = builder->create_fptosi(val, INT32_T);
}
Value* is_neg = builder->create_icmp_lt(val, CONST_INT(0));
builder->create_cond_br(is_neg, exceptBB, contBB);
builder->set_insert_point(exceptBB);
auto *neg_idx_except_fun = scope.find("neg_idx_except");
builder->create_call(dynamic_cast<Function *>(neg_idx_except_fun), {});
if (context.func->get_return_type()->is_void_type()) {
builder->create_void_ret();
} else if (context.func->get_return_type()->is_float_type()) {
builder->create_ret(CONST_FP(0.));
} else {
builder->create_ret(CONST_INT(0));
}
builder->set_insert_point(contBB);
Value *tmp_ptr;
if (is_int || is_float) {
tmp_ptr = builder->create_gep(var, {val});
......
......@@ -23,30 +23,30 @@ struct Config {
std::filesystem::path input_file;
std::filesystem::path output_file;
bool emitast{false};
bool emitasm{false};
bool emitllvm{false};
bool emitast{ false };
bool emitasm{ false };
bool emitllvm{ false };
// optization conifg
bool mem2reg{false};
bool licm{false};
bool mem2reg{ false };
bool licm{ false };
Config(int argc, char **argv) : argc(argc), argv(argv) {
Config(int argc, char** argv) : argc(argc), argv(argv) {
parse_cmd_line();
check();
}
private:
int argc{-1};
char **argv{nullptr};
private:
int argc{ -1 };
char** argv{ nullptr };
void parse_cmd_line();
void check();
// print helper infomation and exit
void print_help() const;
void print_err(const string &msg) const;
void print_err(const string& msg) const;
};
int main(int argc, char **argv) {
int main(int argc, char** argv) {
Config config(argc, argv);
auto syntax_tree = parse(config.input_file.c_str());
......@@ -55,7 +55,8 @@ int main(int argc, char **argv) {
if (config.emitast) { // if emit ast (lab1), print ast and return
ASTPrinter printer;
ast.run_visitor(printer);
} else {
}
else {
Module* m;
CminusfBuilder builder;
ast.run_visitor(builder);
......@@ -63,11 +64,12 @@ int main(int argc, char **argv) {
PassManager PM(m);
// optimization
if(config.mem2reg) {
if (config.mem2reg) {
PM.add_pass<DeadCode>(true);
PM.add_pass<Mem2Reg>();
PM.add_pass<DeadCode>(false);
}
if(config.licm) {
if (config.licm) {
PM.add_pass<LoopInvariantCodeMotion>();
PM.add_pass<DeadCode>(false);
}
......@@ -79,7 +81,14 @@ int main(int argc, char **argv) {
output_stream << "; ModuleID = 'cminus'\n";
output_stream << "source_filename = " << abs_path << "\n\n";
output_stream << m->print();
} else if (config.emitasm) {
}
else if (config.emitasm) {
auto abs_path = std::filesystem::canonical(config.input_file);
config.output_file.replace_extension("ll");
std::ofstream output_stream2(config.output_file);
output_stream2 << "; ModuleID = 'cminus'\n";
output_stream2 << "source_filename = " << abs_path << "\n\n";
output_stream2 << m->print();
CodeGen codegen(m);
codegen.run();
output_stream << codegen.print();
......@@ -96,27 +105,36 @@ void Config::parse_cmd_line() {
for (int i = 1; i < argc; ++i) {
if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help();
} else if (argv[i] == "-o"s) {
}
else if (argv[i] == "-o"s) {
if (output_file.empty() && i + 1 < argc) {
output_file = argv[i + 1];
i += 1;
} else {
}
else {
print_err("bad output file");
}
} else if (argv[i] == "-emit-ast"s) {
}
else if (argv[i] == "-emit-ast"s) {
emitast = true;
} else if (argv[i] == "-S"s) {
}
else if (argv[i] == "-S"s) {
emitasm = true;
} else if (argv[i] == "-emit-llvm"s) {
}
else if (argv[i] == "-emit-llvm"s) {
emitllvm = true;
} else if (argv[i] == "-mem2reg"s) {
}
else if (argv[i] == "-mem2reg"s) {
mem2reg = true;
} else if (argv[i] == "-licm"s) {
}
else if (argv[i] == "-licm"s) {
licm = true;
}else {
}
else {
if (input_file.empty()) {
input_file = argv[i];
} else {
}
else {
string err =
"unrecognized command-line option \'"s + argv[i] + "\'"s;
print_err(err);
......@@ -143,11 +161,12 @@ void Config::check() {
}
if (output_file.empty()) {
output_file = input_file.stem();
}
if (emitllvm) {
output_file.replace_extension(".ll");
} else if (emitasm) {
output_file.replace_extension(".s");
}
else if (emitasm) {
output_file.replace_extension(".s");
}
}
......@@ -160,7 +179,7 @@ void Config::print_help() const {
exit(0);
}
void Config::print_err(const string &msg) const {
void Config::print_err(const string& msg) const {
std::cout << exe_name << ": " << msg << std::endl;
exit(-1);
}
This diff is collapsed.
#include <stdio.h>
#include <stdlib.h>
int input() {
#include <sys/time.h>
struct timeval time_start, time_end;
int end_set;
int flags[2];
int input(void)
{
int a;
scanf("%d", &a);
gettimeofday(&time_start, NULL);
end_set = 0;
return a;
}
void output(int a) { printf("%d\n", a); }
void output(int a)
{
if (end_set == 0)
{
gettimeofday(&time_end, NULL);
end_set = 1;
}
printf("%d\n", a);
}
void outputFloat(float a)
{
if (end_set == 0)
{
gettimeofday(&time_end, NULL);
end_set = 1;
}
printf("%f\n", a);
}
void add_lab4_flag(int idx, int val)
{
flags[idx] += val;
}
void outputFloat(float a) { printf("%f\n", a); }
__attribute((constructor)) void before_main(void)
{
flags[0] = 0;
flags[1] = 0;
end_set = 0;
gettimeofday(&time_start, NULL);
}
void neg_idx_except() {
printf("negative index exception\n");
exit(0);
__attribute((destructor)) void after_main(void)
{
long time_us = 0;
fprintf(stderr, "Allocate Size (bytes):\n%d\n", flags[0]);
fprintf(stderr, "Execute Cost:\n%d\n", flags[1]);
if (end_set == 0)
{
gettimeofday(&time_end, NULL);
}
time_us += 1000000L * (time_end.tv_sec - time_start.tv_sec) +
time_end.tv_usec - time_start.tv_usec;
fprintf(stderr, "Take Times (us):\n%ld\n", time_us);
}
int input();
int input(void);
void output(int a);
void outputFloat(float a);
void neg_idx_except();
void add_lab4_flag(int idx, int val);
\ No newline at end of file
......@@ -12,13 +12,13 @@
BasicBlock::BasicBlock(const Module* m, const std::string& name = "",
Function* parent = nullptr)
: Value(m->get_label_type(),
parent == nullptr ? GLOBAL_BASICBLOCK_NAMES_.get_name(name) : parent->names4blocks_.get_name(name))
, parent_(parent) {
parent == nullptr ? GLOBAL_BASICBLOCK_NAMES_.get_name(name) : parent->names4blocks_.get_name(name))
, parent_(parent) {
assert(parent && "currently parent should not be nullptr");
parent_->add_basic_block(this);
}
Module *BasicBlock::get_module() const { return get_parent()->get_parent(); }
Module* BasicBlock::get_module() const { return get_parent()->get_parent(); }
void BasicBlock::erase_from_parent() { this->get_parent()->remove(this); }
bool BasicBlock::is_terminated() const {
......@@ -34,18 +34,18 @@ bool BasicBlock::is_terminated() const {
}
}
Instruction *BasicBlock::get_terminator() const
Instruction* BasicBlock::get_terminator() const
{
assert(is_terminated() &&
"Trying to get terminator from an bb which is not terminated");
return instr_list_.back();
}
void BasicBlock::add_instruction(Instruction *instr) {
void BasicBlock::add_instruction(Instruction* instr) {
if (instr->is_alloca() || instr->is_phi())
{
auto it = instr_list_.begin();
for (; it != instr_list_.end() && ((*it)->is_alloca() || (*it)->is_phi()); ++it){}
for (; it != instr_list_.end() && ((*it)->is_alloca() || (*it)->is_phi()); ++it) {}
instr_list_.emplace(it, instr);
return;
}
......@@ -146,4 +146,4 @@ BasicBlock* BasicBlock::get_entry_block_of_same_function() const
return parent_->get_entry_block();
}
Names GLOBAL_BASICBLOCK_NAMES_{"label", "_"};
\ No newline at end of file
Names GLOBAL_BASICBLOCK_NAMES_{ "label", "_" };
\ No newline at end of file
......@@ -7,17 +7,8 @@
#include <unordered_set>
#include <queue>
namespace
{
std::string chopName(std::string name)
{
if (name.size() > 3) return { name.begin(), name.begin() + 3 };
return name;
}
}
Function::Function(FunctionType* ty, const std::string& name, Module* parent)
: Value(ty, name), names4blocks_("label", chopName(name) + "_"), names4insts_("op", ""), parent_(parent), seq_cnt_(0) {
: Value(ty, name), names4blocks_("", name + "_"), names4insts_("op", ""), parent_(parent), seq_cnt_(0) {
// num_args_ = ty->getNumParams();
parent->add_function(this);
// build args
......
......@@ -382,7 +382,7 @@ std::string Instruction::safe_print() const
}
else
{
if (auto fty = dynamic_cast<FunctionType*>(ty))
if (auto fty = dynamic_cast<FunctionType*>(op0->get_type()))
{
auto ty3 = fty->get_return_type();
if (ty3 == nullptr)
......
......@@ -197,6 +197,23 @@ BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *bb) {
return new BranchInst(nullptr, if_true, nullptr, bb);
}
void BranchInst::replace_all_bb_match(BasicBlock* need_replace, BasicBlock* replace_to)
{
if (need_replace == nullptr || replace_to == nullptr || need_replace == replace_to) return;
int size = static_cast<int>(get_operands().size());
for (int i = 0; i < size; i ++)
{
auto op = get_operand(i);
if (op == need_replace) set_operand(i, replace_to);
}
auto parent = get_parent();
if (parent == nullptr) return;
parent->remove_succ_basic_block(need_replace);
need_replace->remove_pre_basic_block(parent);
parent->add_succ_basic_block(replace_to);
replace_to->add_pre_basic_block(parent);
}
ReturnInst::ReturnInst(Value *val, BasicBlock *bb)
: Instruction(bb->get_module()->get_void_type(), ret, "", bb) {
if (val == nullptr) {
......@@ -352,14 +369,13 @@ SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb, const std::str
PhiInst::PhiInst(Type *ty, const std::vector<Value *>& vals,
const std::vector<BasicBlock *>& val_bbs, BasicBlock *bb, const std::string& name)
: Instruction(ty, phi, name) {
: Instruction(ty, phi, name, bb) {
assert(vals.size() == val_bbs.size() && "Unmatched vals and bbs");
for (unsigned i = 0; i < vals.size(); i++) {
assert(ty == vals[i]->get_type() && "Bad type for phi");
add_operand(vals[i]);
add_operand(val_bbs[i]);
}
this->set_parent(bb);
}
PhiInst *PhiInst::create_phi(Type *ty, BasicBlock *bb,
......
......@@ -27,48 +27,48 @@ Module::~Module()
for (auto i : global_list_) delete i;
}
Type *Module::get_void_type() const { return void_ty_; }
Type *Module::get_label_type() const { return label_ty_; }
IntegerType *Module::get_int1_type() const { return int1_ty_; }
IntegerType *Module::get_int32_type() const { return int32_ty_; }
FloatType *Module::get_float_type() const { return float32_ty_; }
PointerType *Module::get_int32_ptr_type() {
Type* Module::get_void_type() const { return void_ty_; }
Type* Module::get_label_type() const { return label_ty_; }
IntegerType* Module::get_int1_type() const { return int1_ty_; }
IntegerType* Module::get_int32_type() const { return int32_ty_; }
FloatType* Module::get_float_type() const { return float32_ty_; }
PointerType* Module::get_int32_ptr_type() {
return get_pointer_type(int32_ty_);
}
PointerType *Module::get_float_ptr_type() {
PointerType* Module::get_float_ptr_type() {
return get_pointer_type(float32_ty_);
}
PointerType *Module::get_pointer_type(Type *contained) {
PointerType* Module::get_pointer_type(Type* contained) {
if (pointer_map_.find(contained) == pointer_map_.end()) {
pointer_map_[contained] = new PointerType(contained);
}
return pointer_map_[contained];
}
ArrayType *Module::get_array_type(Type *contained, unsigned num_elements) {
if (array_map_.find({contained, num_elements}) == array_map_.end()) {
ArrayType* Module::get_array_type(Type* contained, unsigned num_elements) {
if (array_map_.find({ contained, num_elements }) == array_map_.end()) {
array_map_[{contained, num_elements}] =
new ArrayType(contained, num_elements);
}
return array_map_[{contained, num_elements}];
}
FunctionType *Module::get_function_type(Type *retty,
std::vector<Type *> &args) {
if (not function_map_.count({retty, args})) {
FunctionType* Module::get_function_type(Type* retty,
std::vector<Type*>& args) {
if (not function_map_.count({ retty, args })) {
function_map_[{retty, args}] =
new FunctionType(retty, args);
}
return function_map_[{retty, args}];
}
void Module::add_function(Function *f) { function_list_.push_back(f); }
std::list<Function*> &Module::get_functions() { return function_list_; }
void Module::add_global_variable(GlobalVariable *g) {
void Module::add_function(Function* f) { function_list_.push_back(f); }
std::list<Function*>& Module::get_functions() { return function_list_; }
void Module::add_global_variable(GlobalVariable* g) {
global_list_.push_back(g);
}
std::list<GlobalVariable*> &Module::get_global_variable() {
std::list<GlobalVariable*>& Module::get_global_variable() {
return global_list_;
}
......
......@@ -15,6 +15,7 @@ void DeadCode::run() {
do {
changed = false;
for (auto func : m_->get_functions()) {
if (func->is_declaration()) continue;
if (remove_bb_) changed |= clear_basic_blocks(func);
mark(func);
changed |= sweep(func);
......
......@@ -62,13 +62,13 @@ void Dominators::run() {
* 该函数使用后序号来查找两个节点的最近公共支配者。
* 通过在支配树上向上遍历直到找到交点。
*/
BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const
BasicBlock *Dominators::intersect(BasicBlock *b1, BasicBlock *b2) const
{
while (b1 != b2) {
while (get_post_order(b1) < get_post_order(b2)) {
while (get_reversed_post_order(b1) > get_reversed_post_order(b2)) {
b1 = get_idom(b1);
}
while (get_post_order(b2) < get_post_order(b1)) {
while (get_reversed_post_order(b2) > get_reversed_post_order(b1)) {
b2 = get_idom(b2);
}
}
......@@ -84,6 +84,12 @@ BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const
void Dominators::create_reverse_post_order() {
std::set<BasicBlock*> visited;
dfs(f_->get_entry_block(), visited);
int size = static_cast<int>(reversed_post_order_vec_.size()) - 1;
for (auto& it : reversed_post_order_)
{
it.second = size - it.second;
reversed_post_order_vec_[it.second] = it.first;
}
}
/**
......@@ -100,8 +106,8 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
dfs(succ, visited);
}
}
post_order_vec_.push_back(bb);
post_order_.insert({bb, post_order_.size()});
reversed_post_order_vec_.push_back(bb);
reversed_post_order_.insert({bb, reversed_post_order_.size()});
}
/**
......@@ -111,38 +117,28 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
*/
void Dominators::create_idom() {
// 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
// post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 post_order_vec_ 中的索引
// reversed_post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
// reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_post_order_vec_ 中的索引
// 可能有用的函数
// intersect(BasicBlock *, BasicBlock *) 寻找两个基本块在支配树上的最近祖先
// 需要填写
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a (或者 idom_[a] = a 代表 a 没有直接支配者)
// 代表基本块的直接支配者是否已经确定, 不会在迭代中改变 (默认初始化为 false)
bool* already_determined = new bool[post_order_vec_.size()]{};
int bb_count = static_cast<int>(reversed_post_order_vec_.size());
int bb_count = static_cast<int>(post_order_vec_.size());
for (int i = 0; i < bb_count; i++)
{
auto bb = post_order_vec_[i];
// TODO 填写可以直接确定直接支配者, 无需参与迭代的基本块的 idom_ 和 already_determined
throw "Unimplemented create_idom";
}
idom_[reversed_post_order_vec_[0]] = reversed_post_order_vec_[0];
bool changed;
do
{
changed = false;
for (int i = 0; i < bb_count; i++)
for (int i = 1; i < bb_count; i++)
{
if (already_determined[i]) continue;
auto bb = post_order_vec_[i];
auto bb = reversed_post_order_vec_[i];
// TODO 更新基本块 bb 的 idom_, 设置 changed(如果 idom_ 有变化)
throw "Unimplemented create_idom";
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
} while (changed);
delete[] already_determined;
}
/**
......@@ -154,19 +150,19 @@ void Dominators::create_idom() {
*/
void Dominators::create_dominance_frontier() {
// 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
// post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 post_order_vec_ 中的索引
// reversed_post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
// reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_post_order_vec_ 中的索引
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// (或者 idom_[a] = a 代表 a 没有直接支配者)
// 需要填写
// dom_frontier_ map<BasicBlock*, set<BasicBlock*>> 支配边界
int bb_count = static_cast<int>(post_order_vec_.size());
int bb_count = static_cast<int>(reversed_post_order_vec_.size());
for (int i = 0; i < bb_count; i++)
{
auto bb = post_order_vec_[i];
auto bb = reversed_post_order_vec_[i];
// TODO 计算 bb 的支配边界集合, 填入 dom_frontier_
throw "Unimplemented create_dominance_frontier";
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
}
......@@ -183,7 +179,8 @@ void Dominators::create_dom_tree_succ() {
// dom_tree_succ_blocks_ map<BasicBlock*, set<BasicBlock*>> 支配树中后继(孩子)节点
// TODO 分析得到 f_ 中各个基本块的支配树后继
throw "Unimplemented create_dom_tree_succ";
// 注意如果 idom_[n] = n, 这意味着 n 没有直接支配者,因此 n 的后继中没有 n
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
/**
......
......@@ -174,6 +174,21 @@ std::unordered_set<Value*> FuncInfo::get_stores(const CallInst* call)
return ret;
}
std::unordered_set<Value*> FuncInfo::get_loads(const CallInst* call)
{
auto func = call->get_operand(0)->as<Function>();
if (func->is_declaration()) return {};
std::unordered_set<Value*> ret;
for (auto i : loads[func].globals_) ret.emplace(i);
for (auto arg : loads[func].arguments_)
{
int arg_no = static_cast<int>(arg->get_arg_no());
auto in = call->get_operand(arg_no + 1);
ret.emplace(trace_ptr(in));
}
return ret;
}
void FuncInfo::log() const
{
for (auto it : use_libs)
......
......@@ -67,21 +67,6 @@ std::vector<Instruction*> LoopInvariantCodeMotion::collect_insts(Loop* loop)
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
// TODO: 实现collect_loop_info函数
// 1. 遍历当前循环及其子循环的所有指令
// 2. 收集所有指令到loop_instructions中
// 3. 检查store指令是否修改了全局变量,如果是则添加到updated_global中
// 4. 检查是否包含非纯函数调用,如果有则设置contains_impure_call为true
void LoopInvariantCodeMotion::collect_loop_info(
Loop* loop,
std::set<Value*>& loop_instructions,
std::set<Value*>& updated_global,
bool& contains_impure_call)
{
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
enum InstructionType: std::uint8_t
{
UNKNOWN, VARIANT, INVARIANT
......@@ -99,19 +84,9 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
// 循环中的所有指令
std::vector<Instruction*> instructions = collect_insts(loop);
int insts_count = static_cast<int>(instructions.size());
// 循环的所有基本块
std::unordered_set<BasicBlock*> bbs;
for (auto i : loop->get_blocks()) bbs.emplace(i);
// val 是否在循环内定义,可以当成函数进行调用
auto is_val_in_loop = [&bbs](Value* val)->bool
{
auto inst = dynamic_cast<Instruction*>(val);
if (inst == nullptr) return true;
return bbs.count(inst->get_parent());
};
// inst_type[i] 代表 instructions[i] 是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
std::vector<InstructionType> inst_type;
inst_type.resize(insts_count);
// Value* 在 map 内说明它是循环内的指令,InstructionType 指示它是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
std::unordered_map<Value*, InstructionType> inst_type;
for (auto i : instructions) inst_type[i] = UNKNOWN;
// 遍历后是不是还有指令不知道 InstructionType
bool have_inst_can_not_decide;
......@@ -123,10 +98,10 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
for (int i = 0; i < insts_count; i++)
{
Instruction* inst = instructions[i];
InstructionType type = inst_type[i];
InstructionType type = inst_type[inst];
if (type != UNKNOWN) continue;
// 可能有用的函数
// FuncInfo::load_ptr
// FuncInfo::load_ptr, FuncInfo::get_stores, FuncInfo::use_io
// TODO: 识别循环不变式指令
// - 将 store、ret、br、phi 等指令与非纯函数调用标记为 VARIANT
......@@ -134,6 +109,10 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
// - 如果指令有 VARIANT 操作数,标记为 VARIANT
// - 如果指令所有操作数都是 INVARIANT (或者不在循环内),标记为 INVARIANT, 设置 have_invariant
// - 否则设置 have_inst_can_not_decide
// TODO: 外提循环不变的非纯函数调用
// 注意: 你不应该外提使用了 io 的函数调用
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
}
......@@ -152,20 +131,26 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
for (auto phi : loop->get_header()->get_instructions())
{
if (phi->get_instr_type() != Instruction::phi) break;
// 可能有用的函数
// PhiInst::create_phi
// TODO: 分裂 phi 指令
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
}
// 可能有用的函数
// BranchInst::replace_all_bb_match
// TODO: 维护 bb, header, 与 header 前驱块的基本块关系
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
bb->add_instruction(BranchInst::create_br(header, bb));
BranchInst::create_br(header, bb);
// 若你想维护 LoopDetection 在 LICM 后保持正确
// auto loop2 = loop->get_parent();
// while (loop2 != nullptr)
// {
// loop2->get_parent()->add_block(bb);
// loop2->add_block(bb);
// loop2 = loop2->get_parent();
// }
}
......@@ -177,8 +162,12 @@ void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
auto terminator = preheader->get_instructions().back();
preheader->get_instructions().pop_back();
// 可以使用 Function::check_for_block_relation_error 检查基本块间的关系是否正确维护
// TODO: 外提循环不变指令
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
preheader->add_instruction(terminator);
std::cerr << "licm done\n";
}
......@@ -54,6 +54,21 @@ void LoopDetection::run() {
delete dominators_;
}
std::string Loop::safe_print() const
{
std::string ret;
if (header_ == nullptr) ret += "b<null>";
else ret += header_->get_name();
ret += " ";
ret += std::to_string(blocks_.size());
ret += "b ";
ret += std::to_string(latches_.size());
ret += "latch ";
ret += std::to_string(sub_loops_.size());
ret += "sub";
return ret;
}
/**
* @brief 发现循环及其子循环
* @param bb 循环的header块
......@@ -69,10 +84,12 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
// 5. 建立正确的循环嵌套关系
std::vector<BasicBlock*> work_list = {latches.begin(), latches.end()}; // 初始化工作表
std::unordered_set<BasicBlock*> already_in_work_list = { latches.begin(), latches.end() }; // 已经在工作表,防止重复加入
while (!work_list.empty()) { // 当工作表非空时继续处理
auto bb2 = work_list.back();
work_list.pop_back();
already_in_work_list.erase(bb2);
// TODO-1: 处理未分配给任何循环的节点
if (bb_to_loop_.find(bb2) == bb_to_loop_.end()) {
......
......@@ -4,11 +4,12 @@
#include "Value.hpp"
// l_val 是否是非数组 alloca 变量
static bool is_not_array_alloca(Value* l_val)
// ptr 是否是非数组 alloca 变量(是则转换为 AllocaInst)
static AllocaInst* is_not_array_alloca(Value* ptr)
{
auto alloca = dynamic_cast<AllocaInst*>(l_val);
return alloca != nullptr && !alloca->get_alloca_type()->is_array_type();
auto alloca = dynamic_cast<AllocaInst*>(ptr);
if (alloca != nullptr && !alloca->get_alloca_type()->is_array_type()) return alloca;
return nullptr;
}
/**
......@@ -43,7 +44,7 @@ void Mem2Reg::run() {
generate_phi();
// 确保每个局部变量的栈都有初始值
for (auto var : allocas_)
var_val_stack[var].emplace_back(ConstantZero::get(var->get_alloca_type(), m_));
var_val_stack[var].emplace_back(var->get_alloca_type()->is_float_type() ? static_cast<Value*>(ConstantFP::get(0, m_)) : static_cast<Value*>(ConstantInt::get(0, m_)));
// 对应伪代码中重命名阶段
rename(func_->get_entry_block());
}
......@@ -80,11 +81,13 @@ void Mem2Reg::generate_phi() {
if (instr->is_store()) {
// store i32 a, i32 *b
// a is r_val, b is l_val
auto l_val = dynamic_cast<StoreInst *>(instr)->get_lval();
if (is_not_array_alloca(l_val)) {
auto lalloca = dynamic_cast<AllocaInst*>(instr);
auto l_val = dynamic_cast<StoreInst*>(instr)->get_ptr();
if (auto lalloca = is_not_array_alloca(l_val)) {
if (!not_array_allocas.count(lalloca))
{
not_array_allocas.insert(lalloca);
allocas_.emplace_back(lalloca);
}
allocas_stored_bbs[lalloca].emplace_back(bb);
}
}
......@@ -115,7 +118,6 @@ void Mem2Reg::generate_phi() {
bb_dominance_frontier_bb);
phi_to_alloca_.emplace(phi, var);
bb_to_phi_[bb_dominance_frontier_bb].emplace_back(phi);
bb_dominance_frontier_bb->add_instr_begin(phi);
work_list.push_back(bb_dominance_frontier_bb);
bb_has_var_phi.emplace(bb_dominance_frontier_bb, var);
}
......@@ -128,20 +130,23 @@ void Mem2Reg::rename(BasicBlock *bb) {
// 可能用到的数据结构
// list<AllocaInst*> allocas_ 所有 Mem2Reg 需要消除的局部变量,用于遍历
// map<AllocaInst*,vector<Value *>> var_val_stack 每个局部变量的存储值栈,还未进行任何操作时已经存进去了 0,不会为空
// map<PhiInst *, AllocaInst*>; Phi 对应的局部变量
// map<BasicBlock*, list<PhiInst*>>; 在某个基本块的 Phi
// map<PhiInst *, AllocaInst*> phi_to_alloca_; Phi 对应的局部变量
// map<BasicBlock*, list<PhiInst*>> bb_to_phi_; 在某个基本块的 Phi
// 可能用到的函数
// Value::replace_all_use_with(Value* a) 将所有用到 this 的指令对应 this 的操作数都替换为 a
// BasicBlock::erase_instrs(set<Instruction*>) 移除并 delete 列表中的指令
// StoreInst / LoadInst get_ptr 这些 Inst 所操作的变量
// is_not_array_alloca(Value* ptr) 一个变量是不是 Mem2Reg 所关心的非数组局部变量
// TODO
// 步骤一:对每个 alloca 非数组变量(局部变量), 在其存储值栈存入其当前的最新值(也就是目前的栈顶值)
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令(注意: 并非所有 load/store/alloca 都是 Mem2Reg 需要处理的)
// - 步骤三: 将 store 指令存储的值,作为其对应局部变量的最新值(更新栈顶)
// - 步骤四: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// 步骤五:为所有后继块的 phi 添加参数
// 步骤六:对 bb 在支配树上的所有后继节点,递归执行 rename 操作
// 步骤七:pop 出所有局部变量的最新值
// 步骤八:删除需要删除的冗余指令
// - 步骤四: 将 phi 指令的所有使用替换为其对应的局部变量的最新值
// - 步骤五: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// 步骤六:为所有后继块的 phi 添加参数
// 步骤七:对 bb 在支配树上的所有后继节点,递归执行 rename 操作
// 步骤八:pop 出所有局部变量的最新值
// 步骤九:删除需要删除的冗余指令
}
add_executable(
eval_lab4
eval_lab4.cpp
)
install(
TARGETS eval_lab4
)
\ No newline at end of file
This diff is collapsed.
add_subdirectory("2-ir-gen/warmup")
add_subdirectory("3-codegen/warmup")
\ No newline at end of file
# add_subdirectory("2-ir-gen/warmup")
# add_subdirectory("3-codegen/warmup")
add_subdirectory("4-opt")
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment