Commit f40efe88 authored by Yang's avatar Yang

publish lab4

parent 93702b62
...@@ -63,4 +63,4 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) ...@@ -63,4 +63,4 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_BINARY_DIR})
add_subdirectory(src) add_subdirectory(src)
# add_subdirectory(tests) add_subdirectory(tests)
...@@ -67,15 +67,10 @@ class CminusfBuilder : public ASTVisitor { ...@@ -67,15 +67,10 @@ class CminusfBuilder : public ASTVisitor {
auto *output_float_fun = auto *output_float_fun =
Function::create(output_float_type, "outputFloat", module); 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.enter();
scope.push("input", input_fun); scope.push("input", input_fun);
scope.push("output", output_fun); scope.push("output", output_fun);
scope.push("outputFloat", output_float_fun); scope.push("outputFloat", output_float_fun);
scope.push("neg_idx_except", neg_idx_except_fun);
} }
Module* getModule() const { return module; } Module* getModule() const { return module; }
......
...@@ -64,18 +64,6 @@ class CodeGen { ...@@ -64,18 +64,6 @@ class CodeGen {
void gen_fptosi(); void gen_fptosi();
void gen_epilogue(); 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 { struct {
/* 随着ir遍历设置 */ /* 随着ir遍历设置 */
Function *func{nullptr}; // 当前函数 Function *func{nullptr}; // 当前函数
...@@ -84,14 +72,12 @@ class CodeGen { ...@@ -84,14 +72,12 @@ class CodeGen {
/* 在allocate()中设置 */ /* 在allocate()中设置 */
unsigned frame_size{0}; // 当前函数的栈帧大小 unsigned frame_size{0}; // 当前函数的栈帧大小
std::unordered_map<Value *, int> offset_map{}; // 指针相对 fp 的偏移 std::unordered_map<Value *, int> offset_map{}; // 指针相对 fp 的偏移
unsigned fcmp_cnt{0}; // fcmp 的计数器, 用于创建 fcmp 需要的 label
void clear() { void clear() {
func = nullptr; func = nullptr;
bb = nullptr; bb = nullptr;
inst = nullptr; inst = nullptr;
frame_size = 0; frame_size = 0;
fcmp_cnt = 0;
offset_map.clear(); offset_map.clear();
} }
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* $r23 - $r31 $s0 - $s8 static * $r23 - $r31 $s0 - $s8 static
* *
* Floating-point Register Convention * Floating-point Register Convention
* Name Alias Meaning * Name Alias Meaning
* $f0-$f1 $fa0-$fa1 argument/return value * $f0-$f1 $fa0-$fa1 argument/return value
* $f2-$f7 $fa2-$fa7 argument * $f2-$f7 $fa2-$fa7 argument
* $f8-$f23 $ft0-$ft15 temporary * $f8-$f23 $ft0-$ft15 temporary
......
...@@ -20,8 +20,7 @@ class BasicBlock : public Value { ...@@ -20,8 +20,7 @@ class BasicBlock : public Value {
~BasicBlock() override; ~BasicBlock() override;
static BasicBlock *create(Module *m, const std::string &name, static BasicBlock *create(Module *m, const std::string &name,
Function *parent) { Function *parent) {
auto prefix = name.empty() ? "" : "label_"; return new BasicBlock(m, name, parent);
return new BasicBlock(m, prefix + name, parent);
} }
/****************api about cfg****************/ /****************api about cfg****************/
......
...@@ -214,6 +214,8 @@ public: ...@@ -214,6 +214,8 @@ public:
Value *get_condition() const { return get_operand(0); } Value *get_condition() const { return get_operand(0); }
void replace_all_bb_match(BasicBlock* need_replace, BasicBlock* replace_to);
std::string print() override; std::string print() override;
}; };
...@@ -251,8 +253,8 @@ class StoreInst : public Instruction { ...@@ -251,8 +253,8 @@ class StoreInst : public Instruction {
public: public:
static StoreInst *create_store(Value *val, Value *ptr, BasicBlock *bb); static StoreInst *create_store(Value *val, Value *ptr, BasicBlock *bb);
Value *get_rval() const { return this->get_operand(0); } Value *get_val() const { return this->get_operand(0); }
Value *get_lval() const { return this->get_operand(1); } Value *get_ptr() const { return this->get_operand(1); }
std::string print() override; std::string print() override;
}; };
...@@ -264,7 +266,7 @@ class LoadInst : public Instruction { ...@@ -264,7 +266,7 @@ class LoadInst : public Instruction {
public: public:
static LoadInst *create_load(Value *ptr, BasicBlock *bb, const std::string& name = ""); 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(); } Type *get_load_type() const { return get_type(); }
std::string print() override; std::string print() override;
......
...@@ -15,7 +15,7 @@ class FuncInfo; ...@@ -15,7 +15,7 @@ class FuncInfo;
class DeadCode : public TransformPass { class DeadCode : public TransformPass {
public: public:
/** /**
* *
* @param m 所属 Module * @param m 所属 Module
* @param remove_unreachable_bb 是否需要删除不可达的 BasicBlocks * @param remove_unreachable_bb 是否需要删除不可达的 BasicBlocks
......
...@@ -20,11 +20,11 @@ class Dominators : public FunctionAnalysisPass { ...@@ -20,11 +20,11 @@ class Dominators : public FunctionAnalysisPass {
void run() override; void run() override;
// 获取基本块的直接支配节点 // 获取基本块的直接支配节点
BasicBlock *get_idom(const BasicBlock *bb) const { return idom_.at(bb); } BasicBlock *get_idom(BasicBlock *bb) const { return idom_.at(bb); }
const std::set<BasicBlock*> &get_dominance_frontier(const BasicBlock *bb) { const std::set<BasicBlock*> &get_dominance_frontier(BasicBlock *bb) {
return dom_frontier_.at(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); return dom_tree_succ_blocks_.at(bb);
} }
...@@ -33,7 +33,7 @@ class Dominators : public FunctionAnalysisPass { ...@@ -33,7 +33,7 @@ class Dominators : public FunctionAnalysisPass {
void dump_dominator_tree(); void dump_dominator_tree();
// functions for dominance 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) && return dom_tree_L_.at(bb1) <= dom_tree_L_.at(bb2) &&
dom_tree_R_.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 { ...@@ -54,33 +54,33 @@ class Dominators : public FunctionAnalysisPass {
void create_dom_tree_succ(); void create_dom_tree_succ();
void create_dom_dfs_order(); 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 create_reverse_post_order();
void set_idom(const BasicBlock *bb, BasicBlock *idom) { idom_[bb] = idom; } void set_idom(BasicBlock *bb, BasicBlock *idom) { idom_[bb] = idom; }
void set_dominance_frontier(const BasicBlock *bb, std::set<BasicBlock*>&df) { void set_dominance_frontier(BasicBlock *bb, std::set<BasicBlock*>&df) {
dom_frontier_[bb].clear(); dom_frontier_[bb].clear();
dom_frontier_[bb].insert(df.begin(), df.end()); 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); dom_tree_succ_blocks_[bb].insert(dom_tree_succ_bb);
} }
unsigned int get_post_order(const BasicBlock *bb) const { unsigned int get_reversed_post_order(BasicBlock *bb) const {
return post_order_.at(bb); return reversed_post_order_.at(bb);
} }
// for debug // for debug
void print_idom() const; void print_idom() const;
void print_dominance_frontier(); void print_dominance_frontier();
std::vector<BasicBlock *> post_order_vec_{}; // 逆后序 std::vector<BasicBlock *> reversed_post_order_vec_{}; // 逆后序
std::map<const BasicBlock *, unsigned int> post_order_{}; // 逆后序 std::map<BasicBlock *, unsigned int> reversed_post_order_{}; // 逆后序索引
std::map<const BasicBlock *, BasicBlock *> idom_{}; // 直接支配 std::map<BasicBlock *, BasicBlock *> idom_{}; // 直接支配
std::map<const BasicBlock *, std::set<BasicBlock*>> dom_frontier_{}; // 支配边界集合 std::map<BasicBlock *, std::set<BasicBlock*>> dom_frontier_{}; // 支配边界集合
std::map<const BasicBlock *, std::set<BasicBlock*>> dom_tree_succ_blocks_{}; // 支配树中的后继节点 std::map<BasicBlock *, std::set<BasicBlock*>> dom_tree_succ_blocks_{}; // 支配树中的后继节点
// 支配树上的dfs序L,R // 支配树上的dfs序L,R
std::map<const BasicBlock *, unsigned int> dom_tree_L_; std::map<BasicBlock *, unsigned int> dom_tree_L_;
std::map<const BasicBlock *, unsigned int> dom_tree_R_; std::map<BasicBlock *, unsigned int> dom_tree_R_;
std::vector<BasicBlock *> dom_dfs_order_; std::vector<BasicBlock *> dom_dfs_order_;
std::vector<BasicBlock *> dom_post_order_; std::vector<BasicBlock *> dom_post_order_;
......
...@@ -27,13 +27,17 @@ class FuncInfo : public ModuleAnalysisPass { ...@@ -27,13 +27,17 @@ class FuncInfo : public ModuleAnalysisPass {
void run() override; 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 存入的变量(全局/局部变量或函数参数) // 返回 StoreInst 存入的变量(全局/局部变量或函数参数)
static Value* store_ptr(const StoreInst* st); static Value* store_ptr(const StoreInst* st);
// 返回 LoadInst 加载的变量(全局/局部变量或函数参数) // 返回 LoadInst 加载的变量(全局/局部变量或函数参数)
static Value* load_ptr(const LoadInst* ld); static Value* load_ptr(const LoadInst* ld);
// 返回 CallInst 代表的函数调用间接存入的变量(全局/局部变量或函数参数) // 返回 CallInst 代表的函数调用间接存入的变量(全局/局部变量或函数参数)
std::unordered_set<Value*> get_stores(const CallInst* call); std::unordered_set<Value*> get_stores(const CallInst* call);
// 返回 CallInst 代表的函数调用间接加载的变量(全局/局部变量或函数参数)
std::unordered_set<Value*> get_loads(const CallInst* call);
private: private:
// 函数存储的值 // 函数存储的值
std::unordered_map<Function*, UseMessage> stores; std::unordered_map<Function*, UseMessage> stores;
......
...@@ -18,8 +18,4 @@ class LoopInvariantCodeMotion : public TransformPass { ...@@ -18,8 +18,4 @@ class LoopInvariantCodeMotion : public TransformPass {
std::vector<Instruction*> collect_insts(Loop* loop); std::vector<Instruction*> collect_insts(Loop* loop);
void traverse_loop(Loop* loop); void traverse_loop(Loop* loop);
void run_on_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 { ...@@ -40,6 +40,7 @@ class Loop {
const std::vector<Loop*>& get_sub_loops() { return sub_loops_; } const std::vector<Loop*>& get_sub_loops() { return sub_loops_; }
const std::unordered_set<BasicBlock *>& get_latches() { return latches_; } const std::unordered_set<BasicBlock *>& get_latches() { return latches_; }
void add_latch(BasicBlock *bb) { latches_.insert(bb); } void add_latch(BasicBlock *bb) { latches_.insert(bb); }
std::string safe_print() const;
}; };
class LoopDetection : public FunctionAnalysisPass { class LoopDetection : public FunctionAnalysisPass {
......
...@@ -25,7 +25,8 @@ def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict): ...@@ -25,7 +25,8 @@ def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
, "BasicBlock" , "BasicBlock"
, "GlobalVariable" , "GlobalVariable"
, "Instruction", "IBinaryInst", "FBinaryInst", "ICmpInst", "FCmpInst", "CallInst", "BranchInst", "ReturnInst", "GetElementPtrInst", "StoreInst", "LoadInst", "AllocaInst", "ZextInst", "FpToSiInst", "SiToFpInst", "PhiInst" , "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: for i in types:
debugger.HandleCommand( debugger.HandleCommand(
f"type summary add -F lldb_formatters.SafePrintSummary {i} -w my" f"type summary add -F lldb_formatters.SafePrintSummary {i} -w my"
......
...@@ -329,27 +329,10 @@ Value* CminusfBuilder::visit(ASTVar &node) { ...@@ -329,27 +329,10 @@ Value* CminusfBuilder::visit(ASTVar &node) {
} }
} else { } else {
auto *val = node.expression->accept(*this); 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()) { if (val->get_type()->is_float_type()) {
val = builder->create_fptosi(val, INT32_T); 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; Value *tmp_ptr;
if (is_int || is_float) { if (is_int || is_float) {
tmp_ptr = builder->create_gep(var, {val}); tmp_ptr = builder->create_gep(var, {val});
......
...@@ -23,30 +23,30 @@ struct Config { ...@@ -23,30 +23,30 @@ struct Config {
std::filesystem::path input_file; std::filesystem::path input_file;
std::filesystem::path output_file; std::filesystem::path output_file;
bool emitast{false}; bool emitast{ false };
bool emitasm{false}; bool emitasm{ false };
bool emitllvm{false}; bool emitllvm{ false };
// optization conifg // optization conifg
bool mem2reg{false}; bool mem2reg{ false };
bool licm{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(); parse_cmd_line();
check(); check();
} }
private: private:
int argc{-1}; int argc{ -1 };
char **argv{nullptr}; char** argv{ nullptr };
void parse_cmd_line(); void parse_cmd_line();
void check(); void check();
// print helper infomation and exit // print helper infomation and exit
void print_help() const; 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); Config config(argc, argv);
auto syntax_tree = parse(config.input_file.c_str()); auto syntax_tree = parse(config.input_file.c_str());
...@@ -55,7 +55,8 @@ int main(int argc, char **argv) { ...@@ -55,7 +55,8 @@ int main(int argc, char **argv) {
if (config.emitast) { // if emit ast (lab1), print ast and return if (config.emitast) { // if emit ast (lab1), print ast and return
ASTPrinter printer; ASTPrinter printer;
ast.run_visitor(printer); ast.run_visitor(printer);
} else { }
else {
Module* m; Module* m;
CminusfBuilder builder; CminusfBuilder builder;
ast.run_visitor(builder); ast.run_visitor(builder);
...@@ -63,11 +64,12 @@ int main(int argc, char **argv) { ...@@ -63,11 +64,12 @@ int main(int argc, char **argv) {
PassManager PM(m); PassManager PM(m);
// optimization // optimization
if(config.mem2reg) { if (config.mem2reg) {
PM.add_pass<DeadCode>(true);
PM.add_pass<Mem2Reg>(); PM.add_pass<Mem2Reg>();
PM.add_pass<DeadCode>(false); PM.add_pass<DeadCode>(false);
} }
if(config.licm) { if (config.licm) {
PM.add_pass<LoopInvariantCodeMotion>(); PM.add_pass<LoopInvariantCodeMotion>();
PM.add_pass<DeadCode>(false); PM.add_pass<DeadCode>(false);
} }
...@@ -79,13 +81,20 @@ int main(int argc, char **argv) { ...@@ -79,13 +81,20 @@ int main(int argc, char **argv) {
output_stream << "; ModuleID = 'cminus'\n"; output_stream << "; ModuleID = 'cminus'\n";
output_stream << "source_filename = " << abs_path << "\n\n"; output_stream << "source_filename = " << abs_path << "\n\n";
output_stream << m->print(); 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 codegen(m);
codegen.run(); codegen.run();
output_stream << codegen.print(); output_stream << codegen.print();
} }
delete m; delete m;
} }
return 0; return 0;
...@@ -96,27 +105,36 @@ void Config::parse_cmd_line() { ...@@ -96,27 +105,36 @@ void Config::parse_cmd_line() {
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (argv[i] == "-h"s || argv[i] == "--help"s) { if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help(); print_help();
} else if (argv[i] == "-o"s) { }
else if (argv[i] == "-o"s) {
if (output_file.empty() && i + 1 < argc) { if (output_file.empty() && i + 1 < argc) {
output_file = argv[i + 1]; output_file = argv[i + 1];
i += 1; i += 1;
} else { }
else {
print_err("bad output file"); print_err("bad output file");
} }
} else if (argv[i] == "-emit-ast"s) { }
else if (argv[i] == "-emit-ast"s) {
emitast = true; emitast = true;
} else if (argv[i] == "-S"s) { }
else if (argv[i] == "-S"s) {
emitasm = true; emitasm = true;
} else if (argv[i] == "-emit-llvm"s) { }
else if (argv[i] == "-emit-llvm"s) {
emitllvm = true; emitllvm = true;
} else if (argv[i] == "-mem2reg"s) { }
else if (argv[i] == "-mem2reg"s) {
mem2reg = true; mem2reg = true;
} else if (argv[i] == "-licm"s) { }
else if (argv[i] == "-licm"s) {
licm = true; licm = true;
}else { }
else {
if (input_file.empty()) { if (input_file.empty()) {
input_file = argv[i]; input_file = argv[i];
} else { }
else {
string err = string err =
"unrecognized command-line option \'"s + argv[i] + "\'"s; "unrecognized command-line option \'"s + argv[i] + "\'"s;
print_err(err); print_err(err);
...@@ -143,24 +161,25 @@ void Config::check() { ...@@ -143,24 +161,25 @@ void Config::check() {
} }
if (output_file.empty()) { if (output_file.empty()) {
output_file = input_file.stem(); output_file = input_file.stem();
if (emitllvm) { }
output_file.replace_extension(".ll"); if (emitllvm) {
} else if (emitasm) { output_file.replace_extension(".ll");
output_file.replace_extension(".s"); }
} else if (emitasm) {
output_file.replace_extension(".s");
} }
} }
void Config::print_help() const { void Config::print_help() const {
std::cout << "Usage: " << exe_name std::cout << "Usage: " << exe_name
<< " [-h|--help] [-o <target-file>] [-emit-llvm] [-S] [-dump-json]" << " [-h|--help] [-o <target-file>] [-emit-llvm] [-S] [-dump-json]"
"[-mem2reg] [-licm]" "[-mem2reg] [-licm]"
"<input-file>" "<input-file>"
<< std::endl; << std::endl;
exit(0); 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; std::cout << exe_name << ": " << msg << std::endl;
exit(-1); exit(-1);
} }
#include "CodeGen.hpp" #include "CodeGen.hpp"
#include <cstring>
#include "ASMInstruction.hpp" #include "ASMInstruction.hpp"
#include "BasicBlock.hpp"
#include "CodeGenUtil.hpp" #include "CodeGenUtil.hpp"
#include "Function.hpp"
#include "Instruction.hpp"
#include "Register.hpp" #include "Register.hpp"
#include "Type.hpp"
#include <string>
std::string ASMInstruction::safe_print() const void CodeGen::allocate()
{ {
switch (type) {
case Instruction:
case Attribute:
return content;
case Label:
return content + ":";
case Comment:
return "# " + content;
}
return "<error>";
}
void CodeGen::allocate() {
// 备份 $ra $fp
unsigned offset = PROLOGUE_OFFSET_BASE; unsigned offset = PROLOGUE_OFFSET_BASE;
for (auto& arg : context.func->get_args())
// 为每个参数分配栈空间 {
for (auto &arg : context.func->get_args()) {
auto size = arg->get_type()->get_size(); auto size = arg->get_type()->get_size();
offset = offset + size; offset = ALIGN(offset + size, size);
context.offset_map[arg] = -static_cast<int>(offset); context.offset_map[arg] = -static_cast<int>(offset);
} }
for (auto& bb : context.func->get_basic_blocks())
// 为指令结果分配栈空间 {
for (auto bb : context.func->get_basic_blocks()) { for (auto& instr : bb->get_instructions())
for (auto instr : bb->get_instructions()) { {
// 每个非 void 的定值都分配栈空间 if (not instr->is_void())
if (not instr->is_void()) { {
auto size = instr->get_type()->get_size(); auto size = instr->get_type()->get_size();
offset = offset + size; offset = ALIGN(offset + size, size > 8 ? 8 : size);
context.offset_map[instr] = -static_cast<int>(offset); context.offset_map[instr] = -static_cast<int>(offset);
} }
// alloca 的副作用:分配额外空间 if (instr->is_alloca())
if (instr->is_alloca()) { {
auto *alloca_inst = dynamic_cast<AllocaInst *>(instr); auto* alloca_inst = dynamic_cast<AllocaInst*>(instr);
auto alloc_size = alloca_inst->get_alloca_type()->get_size(); auto alloc_size = alloca_inst->get_alloca_type()->get_size();
offset += alloc_size; offset = ALIGN(offset + alloc_size, alloc_size > 8 ? 8 : alloc_size);
} }
} }
} }
// 分配栈空间,需要是 16 的整数倍
context.frame_size = ALIGN(offset, PROLOGUE_ALIGN); context.frame_size = ALIGN(offset, PROLOGUE_ALIGN);
} }
void CodeGen::copy_stmt() { void CodeGen::copy_stmt()
for (auto succ : context.bb->get_succ_basic_blocks()) { {
for (auto inst : succ->get_instructions()) { for (auto& succ : context.bb->get_succ_basic_blocks())
if (inst->is_phi()) { {
// 遍历后继块中 phi 的定值 bb for (auto& inst : succ->get_instructions())
for (unsigned i = 1; i < inst->get_operands().size(); i += 2) { {
// phi 的定值 bb 是当前翻译块 if (inst->is_phi())
if (inst->get_operand(i) == context.bb) { {
auto *lvalue = inst->get_operand(i - 1); for (unsigned i = 1; i < inst->get_operands().size(); i += 2)
if (lvalue->get_type()->is_float_type()) { {
if (inst->get_operand(i) == context.bb)
{
auto* lvalue = inst->get_operand(i - 1);
if (lvalue->get_type()->is_float_type())
{
load_to_freg(lvalue, FReg::fa(0)); load_to_freg(lvalue, FReg::fa(0));
store_from_freg(inst, FReg::fa(0)); store_from_freg(inst, FReg::fa(0));
} else { }
else
{
load_to_greg(lvalue, Reg::a(0)); load_to_greg(lvalue, Reg::a(0));
store_from_greg(inst, Reg::a(0)); store_from_greg(inst, Reg::a(0));
} }
break; break;
} }
// 如果没有找到当前翻译块,说明是 undef,无事可做
} }
} else { }
else
{
break; break;
} }
} }
} }
} }
void CodeGen::load_to_greg(Value *val, const Reg &reg) { void CodeGen::load_to_greg(Value* val, const Reg& reg)
{
assert(val->get_type()->is_integer_type() || assert(val->get_type()->is_integer_type() ||
val->get_type()->is_pointer_type()); val->get_type()->is_pointer_type());
if (auto *constant = dynamic_cast<ConstantInt *>(val)) { if (auto* constant = dynamic_cast<ConstantInt*>(val))
int32_t val = constant->get_value(); {
if (IS_IMM_12(val)) { int32_t val1 = constant->get_value();
append_inst(ADDI WORD, {reg.print(), "$zero", std::to_string(val)}); if (IS_IMM_12(val1))
} else { {
load_large_int32(val, reg); append_inst(ADDI WORD, {reg.print(), "$zero", std::to_string(val1)});
} }
} else if (auto *global = dynamic_cast<GlobalVariable *>(val)) { else
{
load_large_int32(val1, reg);
}
}
else if (auto* global = dynamic_cast<GlobalVariable*>(val))
{
append_inst(LOAD_ADDR, {reg.print(), global->get_name()}); append_inst(LOAD_ADDR, {reg.print(), global->get_name()});
} else { }
else
{
load_from_stack_to_greg(val, reg); load_from_stack_to_greg(val, reg);
} }
} }
void CodeGen::load_large_int32(int32_t val, const Reg &reg) { void CodeGen::load_large_int32(int32_t val, const Reg& reg)
int32_t high_20 = val >> 12; // si20 {
int32_t high_20 = val >> 12;
uint32_t low_12 = val & LOW_12_MASK; uint32_t low_12 = val & LOW_12_MASK;
append_inst(LU12I_W, {reg.print(), std::to_string(high_20)}); append_inst(LU12I_W, {reg.print(), std::to_string(high_20)});
append_inst(ORI, {reg.print(), reg.print(), std::to_string(low_12)}); append_inst(ORI, {reg.print(), reg.print(), std::to_string(low_12)});
} }
void CodeGen::load_large_int64(int64_t val, const Reg &reg) { void CodeGen::load_large_int64(int64_t val, const Reg& reg)
{
auto low_32 = static_cast<int32_t>(val & LOW_32_MASK); auto low_32 = static_cast<int32_t>(val & LOW_32_MASK);
load_large_int32(low_32, reg); load_large_int32(low_32, reg);
auto high_32 = static_cast<int32_t>(val >> 32); auto high_32 = static_cast<int32_t>(val >> 32);
int32_t high_32_low_20 = (high_32 << 12) >> 12; // si20 int32_t high_32_low_20 = (high_32 << 12) >> 12;
int32_t high_32_high_12 = high_32 >> 20; // si12 int32_t high_32_high_12 = high_32 >> 20;
append_inst(LU32I_D, {reg.print(), std::to_string(high_32_low_20)}); append_inst(LU32I_D, {reg.print(), std::to_string(high_32_low_20)});
append_inst(LU52I_D, append_inst(LU52I_D,
{reg.print(), reg.print(), std::to_string(high_32_high_12)}); {reg.print(), reg.print(), std::to_string(high_32_high_12)});
} }
void CodeGen::load_from_stack_to_greg(Value *val, const Reg &reg) { void CodeGen::load_from_stack_to_greg(Value* val, const Reg& reg)
{
auto offset = context.offset_map.at(val); auto offset = context.offset_map.at(val);
auto offset_str = std::to_string(offset); auto offset_str = std::to_string(offset);
auto *type = val->get_type(); auto* type = val->get_type();
if (IS_IMM_12(offset)) { if (IS_IMM_12(offset))
if (type->is_int1_type()) { {
if (type->is_int1_type())
{
append_inst(LOAD BYTE, {reg.print(), "$fp", offset_str}); append_inst(LOAD BYTE, {reg.print(), "$fp", offset_str});
} else if (type->is_int32_type()) { }
else if (type->is_int32_type())
{
append_inst(LOAD WORD, {reg.print(), "$fp", offset_str}); append_inst(LOAD WORD, {reg.print(), "$fp", offset_str});
} else { // Pointer }
else
{
append_inst(LOAD DOUBLE, {reg.print(), "$fp", offset_str}); append_inst(LOAD DOUBLE, {reg.print(), "$fp", offset_str});
} }
} else { }
else
{
load_large_int64(offset, reg); load_large_int64(offset, reg);
append_inst(ADD DOUBLE, {reg.print(), "$fp", reg.print()}); append_inst(ADD DOUBLE, {reg.print(), "$fp", reg.print()});
if (type->is_int1_type()) { if (type->is_int1_type())
{
append_inst(LOAD BYTE, {reg.print(), reg.print(), "0"}); append_inst(LOAD BYTE, {reg.print(), reg.print(), "0"});
} else if (type->is_int32_type()) { }
else if (type->is_int32_type())
{
append_inst(LOAD WORD, {reg.print(), reg.print(), "0"}); append_inst(LOAD WORD, {reg.print(), reg.print(), "0"});
} else { // Pointer }
else
{
append_inst(LOAD DOUBLE, {reg.print(), reg.print(), "0"}); append_inst(LOAD DOUBLE, {reg.print(), reg.print(), "0"});
} }
} }
} }
void CodeGen::store_from_greg(Value *val, const Reg &reg) { void CodeGen::store_from_greg(Value* val, const Reg& reg)
{
auto offset = context.offset_map.at(val); auto offset = context.offset_map.at(val);
auto offset_str = std::to_string(offset); auto offset_str = std::to_string(offset);
auto *type = val->get_type(); auto* type = val->get_type();
if (IS_IMM_12(offset)) { if (IS_IMM_12(offset))
if (type->is_int1_type()) { {
if (type->is_int1_type())
{
append_inst(STORE BYTE, {reg.print(), "$fp", offset_str}); append_inst(STORE BYTE, {reg.print(), "$fp", offset_str});
} else if (type->is_int32_type()) { }
else if (type->is_int32_type())
{
append_inst(STORE WORD, {reg.print(), "$fp", offset_str}); append_inst(STORE WORD, {reg.print(), "$fp", offset_str});
} else { // Pointer }
else
{
append_inst(STORE DOUBLE, {reg.print(), "$fp", offset_str}); append_inst(STORE DOUBLE, {reg.print(), "$fp", offset_str});
} }
} else { }
else
{
auto addr = Reg::t(8); auto addr = Reg::t(8);
load_large_int64(offset, addr); load_large_int64(offset, addr);
append_inst(ADD DOUBLE, {addr.print(), "$fp", addr.print()}); append_inst(ADD DOUBLE, {addr.print(), "$fp", addr.print()});
if (type->is_int1_type()) { if (type->is_int1_type())
{
append_inst(STORE BYTE, {reg.print(), addr.print(), "0"}); append_inst(STORE BYTE, {reg.print(), addr.print(), "0"});
} else if (type->is_int32_type()) { }
else if (type->is_int32_type())
{
append_inst(STORE WORD, {reg.print(), addr.print(), "0"}); append_inst(STORE WORD, {reg.print(), addr.print(), "0"});
} else { // Pointer }
else
{
append_inst(STORE DOUBLE, {reg.print(), addr.print(), "0"}); append_inst(STORE DOUBLE, {reg.print(), addr.print(), "0"});
} }
} }
} }
void CodeGen::load_to_freg(Value *val, const FReg &freg) { void CodeGen::load_to_freg(Value* val, const FReg& freg)
{
assert(val->get_type()->is_float_type()); assert(val->get_type()->is_float_type());
if (auto *constant = dynamic_cast<ConstantFP *>(val)) { if (auto* constant = dynamic_cast<ConstantFP*>(val))
float val = constant->get_value(); {
load_float_imm(val, freg); float val1 = constant->get_value();
} else { load_float_imm(val1, freg);
}
else
{
auto offset = context.offset_map.at(val); auto offset = context.offset_map.at(val);
auto offset_str = std::to_string(offset); auto offset_str = std::to_string(offset);
if (IS_IMM_12(offset)) { if (IS_IMM_12(offset))
{
append_inst(FLOAD SINGLE, {freg.print(), "$fp", offset_str}); append_inst(FLOAD SINGLE, {freg.print(), "$fp", offset_str});
} else { }
else
{
auto addr = Reg::t(8); auto addr = Reg::t(8);
load_large_int64(offset, addr); load_large_int64(offset, addr);
append_inst(ADD DOUBLE, {addr.print(), "$fp", addr.print()}); append_inst(ADD DOUBLE, {addr.print(), "$fp", addr.print()});
...@@ -185,18 +229,24 @@ void CodeGen::load_to_freg(Value *val, const FReg &freg) { ...@@ -185,18 +229,24 @@ void CodeGen::load_to_freg(Value *val, const FReg &freg) {
} }
} }
void CodeGen::load_float_imm(float val, const FReg &r) { void CodeGen::load_float_imm(float val, const FReg& r)
int32_t bytes = *reinterpret_cast<int32_t *>(&val); {
int32_t bytes = 0;
memcpy(&bytes, &val, sizeof(float));
load_large_int32(bytes, Reg::t(8)); load_large_int32(bytes, Reg::t(8));
append_inst(GR2FR WORD, {r.print(), Reg::t(8).print()}); append_inst(GR2FR WORD, {r.print(), Reg::t(8).print()});
} }
void CodeGen::store_from_freg(Value *val, const FReg &r) { void CodeGen::store_from_freg(Value* val, const FReg& r)
{
auto offset = context.offset_map.at(val); auto offset = context.offset_map.at(val);
if (IS_IMM_12(offset)) { if (IS_IMM_12(offset))
{
auto offset_str = std::to_string(offset); auto offset_str = std::to_string(offset);
append_inst(FSTORE SINGLE, {r.print(), "$fp", offset_str}); append_inst(FSTORE SINGLE, {r.print(), "$fp", offset_str});
} else { }
else
{
auto addr = Reg::t(8); auto addr = Reg::t(8);
load_large_int64(offset, addr); load_large_int64(offset, addr);
append_inst(ADD DOUBLE, {addr.print(), "$fp", addr.print()}); append_inst(ADD DOUBLE, {addr.print(), "$fp", addr.print()});
...@@ -204,14 +254,18 @@ void CodeGen::store_from_freg(Value *val, const FReg &r) { ...@@ -204,14 +254,18 @@ void CodeGen::store_from_freg(Value *val, const FReg &r) {
} }
} }
void CodeGen::gen_prologue() { void CodeGen::gen_prologue()
if (IS_IMM_12(-static_cast<int>(context.frame_size))) { {
if (IS_IMM_12(-static_cast<int>(context.frame_size)))
{
append_inst("st.d $ra, $sp, -8"); append_inst("st.d $ra, $sp, -8");
append_inst("st.d $fp, $sp, -16"); append_inst("st.d $fp, $sp, -16");
append_inst("addi.d $fp, $sp, 0"); append_inst("addi.d $fp, $sp, 0");
append_inst("addi.d $sp, $sp, " + append_inst("addi.d $sp, $sp, " +
std::to_string(-static_cast<int>(context.frame_size))); std::to_string(-static_cast<int>(context.frame_size)));
} else { }
else
{
load_large_int64(context.frame_size, Reg::t(0)); load_large_int64(context.frame_size, Reg::t(0));
append_inst("st.d $ra, $sp, -8"); append_inst("st.d $ra, $sp, -8");
append_inst("st.d $fp, $sp, -16"); append_inst("st.d $fp, $sp, -16");
...@@ -221,177 +275,405 @@ void CodeGen::gen_prologue() { ...@@ -221,177 +275,405 @@ void CodeGen::gen_prologue() {
int garg_cnt = 0; int garg_cnt = 0;
int farg_cnt = 0; int farg_cnt = 0;
for (auto arg : context.func->get_args()) { for (auto arg : context.func->get_args())
if (arg->get_type()->is_float_type()) { {
if (arg->get_type()->is_float_type())
{
store_from_freg(arg, FReg::fa(farg_cnt++)); store_from_freg(arg, FReg::fa(farg_cnt++));
} else { // int or pointer }
else
{
store_from_greg(arg, Reg::a(garg_cnt++)); store_from_greg(arg, Reg::a(garg_cnt++));
} }
} }
} }
void CodeGen::gen_epilogue() { void CodeGen::gen_epilogue()
// TODO 根据你的理解设定函数的 epilogue {
throw not_implemented_error{__FUNCTION__}; append_inst(context.func->get_name() + "_exit", ASMInstruction::Label);
if (IS_IMM_12(-static_cast<int>(context.frame_size)))
{
append_inst("addi.d $sp, $sp, " + std::to_string(static_cast<int>(context.frame_size)));
append_inst("ld.d $ra, $sp, -8");
append_inst("ld.d $fp, $sp, -16");
append_inst("jr $ra");
}
else
{
load_large_int64(context.frame_size, Reg::t(0));
append_inst("add.d $sp, $sp, $t0");
append_inst("ld.d $ra, $sp, -8");
append_inst("ld.d $fp, $sp, -16");
append_inst("jr $ra");
}
} }
void CodeGen::gen_ret() { void CodeGen::gen_ret()
// TODO 函数返回,思考如何处理返回值、寄存器备份,如何返回调用者地址 {
throw not_implemented_error{__FUNCTION__}; auto* retInst = dynamic_cast<ReturnInst*>(context.inst);
auto* retType = context.func->get_return_type();
if (retType->is_void_type())
{
append_inst("addi.w $a0, $zero, 0");
}
else if (retType->is_float_type())
{
load_to_freg(retInst->get_operand(0), FReg::fa(0));
}
else
{
load_to_greg(retInst->get_operand(0), Reg::a(0));
}
std::string label = context.func->get_name() + "_exit";
append_inst("b " + label);
} }
void CodeGen::gen_br() { void CodeGen::gen_br()
auto *branchInst = static_cast<BranchInst *>(context.inst); {
if (branchInst->is_cond_br()) { auto* branchInst = dynamic_cast<BranchInst*>(context.inst);
// TODO 补全条件跳转的情况 if (branchInst->is_cond_br())
throw not_implemented_error{__FUNCTION__}; {
} else { load_to_greg(branchInst->get_operand(0), Reg::t(0));
auto *branchbb = static_cast<BasicBlock *>(branchInst->get_operand(0)); auto* trueBB = dynamic_cast<BasicBlock*>(branchInst->get_operand(1));
append_inst("b " + label_name(branchbb)); auto* falseBB = dynamic_cast<BasicBlock*>(branchInst->get_operand(2));
append_inst("bnez", {Reg::t(0).print(), trueBB->get_name()});
append_inst("b", {falseBB->get_name()});
}
else
{
auto* branchbb = dynamic_cast<BasicBlock*>(branchInst->get_operand(0));
append_inst("b " + branchbb->get_name());
} }
} }
void CodeGen::gen_binary() { void CodeGen::gen_binary()
{
load_to_greg(context.inst->get_operand(0), Reg::t(0)); load_to_greg(context.inst->get_operand(0), Reg::t(0));
load_to_greg(context.inst->get_operand(1), Reg::t(1)); load_to_greg(context.inst->get_operand(1), Reg::t(1));
switch (context.inst->get_instr_type()) { switch (context.inst->get_instr_type())
case Instruction::add: {
append_inst("add.w $t2, $t0, $t1"); case Instruction::add:
break; output.emplace_back("add.w $t2, $t0, $t1");
case Instruction::sub: break;
append_inst("sub.w $t2, $t0, $t1"); case Instruction::sub:
break; output.emplace_back("sub.w $t2, $t0, $t1");
case Instruction::mul: break;
append_inst("mul.w $t2, $t0, $t1"); case Instruction::mul:
break; output.emplace_back("mul.w $t2, $t0, $t1");
case Instruction::sdiv: break;
append_inst("div.w $t2, $t0, $t1"); case Instruction::sdiv:
break; output.emplace_back("div.w $t2, $t0, $t1");
default: break;
assert(false); default:
assert(false);
} }
store_from_greg(context.inst, Reg::t(2)); store_from_greg(context.inst, Reg::t(2));
if (context.inst->get_instr_type() == Instruction::mul)
{
load_to_greg(ConstantInt::get(1, m), Reg::a(0));
load_to_greg(ConstantInt::get(1, m), Reg::a(1));
append_inst("bl add_lab4_flag");
}
if (context.inst->get_instr_type() == Instruction::sdiv)
{
load_to_greg(ConstantInt::get(1, m), Reg::a(0));
load_to_greg(ConstantInt::get(4, m), Reg::a(1));
append_inst("bl add_lab4_flag");
}
} }
void CodeGen::gen_float_binary() { void CodeGen::gen_float_binary()
// TODO 浮点类型的二元指令 {
throw not_implemented_error{__FUNCTION__}; auto* floatInst = dynamic_cast<FBinaryInst*>(context.inst);
auto op = floatInst->get_instr_type();
auto firstNum = floatInst->get_operand(0);
load_to_freg(firstNum, FReg::ft(1));
auto secondNum = floatInst->get_operand(1);
load_to_freg(secondNum, FReg::ft(2));
switch (op)
{
case Instruction::fadd:
append_inst("fadd.s", {FReg::ft(0).print(), FReg::ft(1).print(), FReg::ft(2).print()});
break;
case Instruction::fsub:
append_inst("fsub.s", {FReg::ft(0).print(), FReg::ft(1).print(), FReg::ft(2).print()});
break;
case Instruction::fmul:
append_inst("fmul.s", {FReg::ft(0).print(), FReg::ft(1).print(), FReg::ft(2).print()});
break;
case Instruction::fdiv:
append_inst("fdiv.s", {FReg::ft(0).print(), FReg::ft(1).print(), FReg::ft(2).print()});
break;
default:
std::cout << "wrong gen_float_binary\n";
break;
}
store_from_freg(context.inst, FReg::ft(0));
if (context.inst->get_instr_type() == Instruction::fmul)
{
load_to_greg(ConstantInt::get(1, m), Reg::a(0));
load_to_greg(ConstantInt::get(1, m), Reg::a(1));
append_inst("bl add_lab4_flag");
}
if (context.inst->get_instr_type() == Instruction::fdiv)
{
load_to_greg(ConstantInt::get(1, m), Reg::a(0));
load_to_greg(ConstantInt::get(4, m), Reg::a(1));
append_inst("bl add_lab4_flag");
}
} }
void CodeGen::gen_alloca() { void CodeGen::gen_alloca()
/* 我们已经为 alloca 的内容分配空间,在此我们还需保存 alloca {
* 指令自身产生的定值,即指向 alloca 空间起始地址的指针 auto* allocaInst = dynamic_cast<AllocaInst*>(context.inst);
*/ auto offset = context.offset_map[allocaInst];
// TODO 将 alloca 出空间的起始地址保存在栈帧上 auto trueOffset = offset - static_cast<int>(allocaInst->get_alloca_type()->get_size());
throw not_implemented_error{__FUNCTION__}; if (IS_IMM_12(trueOffset))
append_inst("addi.d", {Reg::t(0).print(), "$fp", std::to_string(trueOffset)});
else
{
load_to_greg(ConstantInt::get(trueOffset, m), Reg::t(1));
append_inst("add.d", {Reg::t(0).print(), "$fp", Reg::t(1).print()});
}
store_from_greg(allocaInst, Reg::t(0));
load_to_greg(ConstantInt::get(0, m), Reg::a(0));
load_to_greg(ConstantInt::get(static_cast<int>(allocaInst->get_alloca_type()->get_size()), m), Reg::a(1));
append_inst("bl add_lab4_flag");
} }
void CodeGen::gen_load() { void CodeGen::gen_load()
auto *ptr = context.inst->get_operand(0); {
auto *type = context.inst->get_type(); auto* ptr = context.inst->get_operand(0);
auto* type = context.inst->get_type();
load_to_greg(ptr, Reg::t(0)); load_to_greg(ptr, Reg::t(0));
if (type->is_float_type()) { if (type->is_float_type())
{
append_inst("fld.s $ft0, $t0, 0"); append_inst("fld.s $ft0, $t0, 0");
store_from_freg(context.inst, FReg::ft(0)); store_from_freg(context.inst, FReg::ft(0));
} else {
// TODO load 整数类型的数据
throw not_implemented_error{__FUNCTION__};
} }
else if (type->is_int32_type())
{
append_inst("ld.w $t0, $t0, 0");
store_from_greg(context.inst, Reg::t(0));
}
else if (type->is_int1_type())
{
append_inst("ld.b $t0, $t0, 0");
store_from_greg(context.inst, Reg::t(0));
}
else
{
append_inst("ld.d $t0, $t0, 0");
store_from_greg(context.inst, Reg::t(0));
}
if (ptr->is<AllocaInst>() && !((ptr->as<AllocaInst>())->get_alloca_type()->is_array_type())) return;
load_to_greg(ConstantInt::get(1, m), Reg::a(0));
load_to_greg(ConstantInt::get(3, m), Reg::a(1));
append_inst("bl add_lab4_flag");
} }
void CodeGen::gen_store() { void CodeGen::gen_store()
// TODO 翻译 store 指令 {
throw not_implemented_error{__FUNCTION__}; auto* storeInst = dynamic_cast<StoreInst*>(context.inst);
auto addr = storeInst->get_operand(1);
auto value = storeInst->get_operand(0);
load_to_greg(addr, Reg::t(0));
if (value->get_type()->is_float_type())
{
load_to_freg(value, FReg::ft(0));
append_inst("fst.s $ft0, $t0, 0");
}
else if (value->get_type()->is_int32_type())
{
load_to_greg(value, Reg::t(1));
append_inst("st.w $t1, $t0, 0");
}
else if (value->get_type()->is_int1_type())
{
load_to_greg(value, Reg::t(1));
append_inst("st.b $t1, $t0, 0");
}
else
{
load_to_greg(value, Reg::t(1));
append_inst("st.d $t1, $t0, 0");
}
} }
void CodeGen::gen_icmp() { void CodeGen::gen_icmp()
// TODO 处理各种整数比较的情况 {
throw not_implemented_error{__FUNCTION__}; auto* icmpInst = dynamic_cast<ICmpInst*>(context.inst);
auto op = icmpInst->get_instr_type();
load_to_greg(icmpInst->get_operand(0), Reg::t(0));
load_to_greg(icmpInst->get_operand(1), Reg::t(1));
switch (op)
{
case Instruction::ge:
append_inst("slt $t0, $t0, $t1");
append_inst("addi.d $t1, $zero, 1");
append_inst("xor $t0, $t0, $t1");
break;
case Instruction::gt:
append_inst("slt $t0, $t1, $t0");
break;
case Instruction::le:
append_inst("slt $t0, $t1, $t0");
append_inst("addi.d $t1, $zero, 1");
append_inst("xor $t0, $t0, $t1");
break;
case Instruction::lt:
append_inst("slt $t0, $t0, $t1");
break;
case Instruction::eq:
append_inst("xor $t0, $t0, $t1");
append_inst("sltu $t0, $zero, $t0");
append_inst("addi.d $t1, $zero, 1");
append_inst("xor $t0, $t0, $t1");
break;
case Instruction::ne:
append_inst("xor $t0, $t0, $t1");
append_inst("sltu $t0, $zero, $t0");
break;
default:
std::cout << "wrong icmp\n";
break;
}
store_from_greg(icmpInst, Reg::t(0));
} }
void CodeGen::gen_fcmp() { void CodeGen::gen_fcmp()
// TODO 处理各种浮点数比较的情况 {
throw not_implemented_error{__FUNCTION__}; auto* fcmpInst = dynamic_cast<FCmpInst*>(context.inst);
auto op = fcmpInst->get_instr_type();
load_to_freg(fcmpInst->get_operand(0), FReg::ft(0));
load_to_freg(fcmpInst->get_operand(1), FReg::ft(1));
switch (op)
{
case Instruction::fge:
append_inst("fcmp.sle.s $fcc0, $ft1, $ft0");
break;
case Instruction::fgt:
append_inst("fcmp.slt.s $fcc0, $ft1, $ft0");
break;
case Instruction::fle:
append_inst("fcmp.sle.s $fcc0, $ft0, $ft1");
break;
case Instruction::flt:
append_inst("fcmp.slt.s $fcc0, $ft0, $ft1");
break;
case Instruction::feq:
append_inst("fcmp.seq.s $fcc0, $ft0, $ft1");
break;
case Instruction::fne:
append_inst("fcmp.sne.s $fcc0, $ft0, $ft1");
break;
default:
break;
}
append_inst("bceqz", {"$fcc0", "0XC"});
append_inst("addi.w $t0, $zero, 1");
append_inst("b 0x8");
append_inst("addi.w $t0, $zero, 0");
store_from_greg(context.inst, Reg::t(0));
} }
void CodeGen::gen_zext() { void CodeGen::gen_zext()
// TODO 将窄位宽的整数数据进行零扩展 {
throw not_implemented_error{__FUNCTION__}; auto* zextInst = dynamic_cast<ZextInst*>(context.inst);
load_to_greg(zextInst->get_operand(0), Reg::t(0));
append_inst("bstrpick.w $t0, $t0, 7, 0");
store_from_greg(context.inst, Reg::t(0));
} }
void CodeGen::gen_call() { void CodeGen::gen_call()
// TODO 函数调用,注意我们只需要通过寄存器传递参数,即不需考虑栈上传参的情况 {
throw not_implemented_error{__FUNCTION__}; auto* callInst = dynamic_cast<CallInst*>(context.inst);
auto* functionType = static_cast<FunctionType*>(callInst->get_function_type());
auto argsNum = functionType->get_num_of_args();
unsigned int j = 0;
unsigned int k = 0;
for (unsigned int i = 0; i < argsNum; i++)
{
if (functionType->get_param_type(i)->is_float_type())
{
load_to_freg(callInst->get_operand(i + 1), FReg::fa(k));
k++;
}
else
{
load_to_greg(callInst->get_operand(i + 1), Reg::a(j));
j++;
}
}
auto* func = dynamic_cast<Function*>(callInst->get_operand(0));
append_inst("bl", {func->get_name()});
auto retType = functionType->get_return_type();
if (retType->is_integer_type())
{
store_from_greg(context.inst, Reg::a(0));
}
else if (retType->is_float_type())
{
store_from_freg(context.inst, FReg::fa(0));
}
} }
/* void CodeGen::gen_gep()
* %op = getelementptr [10 x i32], [10 x i32]* %op, i32 0, i32 %op {
* %op = getelementptr i32, i32* %op, i32 %op auto* getElementPtrInst = dynamic_cast<GetElementPtrInst*>(context.inst);
* unsigned int num = getElementPtrInst->get_num_operand();
* Memory layout load_to_greg(getElementPtrInst->get_operand(0), Reg::t(0));
* - ^ load_to_greg(getElementPtrInst->get_operand(num - 1), Reg::t(1));
* +-----------+ | Smaller address auto elementType = getElementPtrInst->get_element_type();
* | arg ptr |---+ | append_inst("addi.d $t2, $zero, 4");
* +-----------+ | | if (elementType->is_float_type() || elementType->is_int32_type())
* | | | | {
* +-----------+ / | append_inst("mul.d $t1, $t1, $t2");
* | |<-- | }
* | | \ | else
* | | | | {
* | Array | | | append_inst("addi.d $t2, $zero, 8");
* | | | | append_inst("mul.d $t1, $t1, $t2");
* | | | | }
* | | | | append_inst("add.d $t2, $t1, $t0");
* +-----------+ | | store_from_greg(context.inst, Reg::t(2));
* | Pointer |---+ | load_to_greg(ConstantInt::get(1, m), Reg::a(0));
* +-----------+ | load_to_greg(ConstantInt::get(1, m), Reg::a(1));
* | | | append_inst("bl add_lab4_flag");
* +-----------+ |
* | | |
* +-----------+ |
* | | |
* +-----------+ | Larger address
* +
*/
void CodeGen::gen_gep() {
// TODO 计算内存地址
throw not_implemented_error{__FUNCTION__};
} }
void CodeGen::gen_sitofp() { void CodeGen::gen_sitofp()
// TODO 整数转向浮点数 {
throw not_implemented_error{__FUNCTION__}; auto* sitofpInst = dynamic_cast<SiToFpInst*>(context.inst);
load_to_greg(sitofpInst->get_operand(0), Reg::t(0));
append_inst("movgr2fr.w $ft0, $t0");
append_inst("ffint.s.w $ft1, $ft0");
store_from_freg(context.inst, FReg::ft(1));
} }
void CodeGen::gen_fptosi() { void CodeGen::gen_fptosi()
// TODO 浮点数转向整数,注意向下取整(round to zero) {
throw not_implemented_error{__FUNCTION__}; auto* fptosiInst = dynamic_cast<FpToSiInst*>(context.inst);
load_to_freg(fptosiInst->get_operand(0), FReg::ft(0));
append_inst("ftintrz.w.s $ft1, $ft0");
append_inst("movfr2gr.s $t0, $ft1");
store_from_greg(context.inst, Reg::t(0));
} }
void CodeGen::run() { void CodeGen::run()
// 确保每个函数中基本块的名字都被设置好 {
m->set_print_name(); m->set_print_name();
if (!m->get_global_variable().empty())
/* 使用 GNU 伪指令为全局变量分配空间 {
* 你可以使用 `la.local` 指令将标签 (全局变量) 的地址载入寄存器中, 比如
* 要将 `a` 的地址载入 $t0, 只需要 `la.local $t0, a`
*/
if (!m->get_global_variable().empty()) {
append_inst("Global variables", ASMInstruction::Comment); append_inst("Global variables", ASMInstruction::Comment);
/* 虽然下面两条伪指令可以简化为一条 `.bss` 伪指令, 但是我们还是选择使用
* `.section` 将全局变量放到可执行文件的 BSS 段, 原因如下:
* - 尽可能对齐交叉编译器 loongarch64-unknown-linux-gnu-gcc 的行为
* - 支持更旧版本的 GNU 汇编器, 因为 `.bss` 伪指令是应该相对较新的指令,
* GNU 汇编器在 2023 年 2 月的 2.37 版本才将其引入
*/
append_inst(".text", ASMInstruction::Attribute); append_inst(".text", ASMInstruction::Attribute);
append_inst(".section", {".bss", "\"aw\"", "@nobits"}, append_inst(".section", {".bss", "\"aw\"", "@nobits"},
ASMInstruction::Attribute); ASMInstruction::Attribute);
for (auto global : m->get_global_variable()) { for (auto global : m->get_global_variable())
auto size = {
global->get_type()->get_pointer_element_type()->get_size(); auto size = global->get_type()->get_pointer_element_type()->get_size();
append_inst(".globl", {global->get_name()}, append_inst(".globl", {global->get_name()},
ASMInstruction::Attribute); ASMInstruction::Attribute);
append_inst(".type", {global->get_name(), "@object"}, append_inst(".type", {global->get_name(), "@object"},
...@@ -404,114 +686,106 @@ void CodeGen::run() { ...@@ -404,114 +686,106 @@ void CodeGen::run() {
} }
} }
// 函数代码段
output.emplace_back(".text", ASMInstruction::Attribute); output.emplace_back(".text", ASMInstruction::Attribute);
for (auto func : m->get_functions()) { for (auto func : m->get_functions())
if (not func->is_declaration()) { {
// 更新 context if (not func->is_declaration())
{
context.clear(); context.clear();
context.func = func; context.func = func;
// 函数信息
append_inst(".globl", {func->get_name()}, ASMInstruction::Attribute); append_inst(".globl", {func->get_name()}, ASMInstruction::Attribute);
append_inst(".type", {func->get_name(), "@function"}, append_inst(".type", {func->get_name(), "@function"},
ASMInstruction::Attribute); ASMInstruction::Attribute);
append_inst(func->get_name(), ASMInstruction::Label); append_inst(func->get_name(), ASMInstruction::Label);
// 分配函数栈帧
allocate(); allocate();
// 生成 prologue
gen_prologue(); gen_prologue();
for (auto bb : func->get_basic_blocks()) { for (auto& bb : func->get_basic_blocks())
{
context.bb = bb; context.bb = bb;
append_inst(label_name(context.bb), ASMInstruction::Label); append_inst(context.bb->get_name(), ASMInstruction::Label);
for (auto instr : bb->get_instructions()) { for (auto& instr : bb->get_instructions())
// For debug {
append_inst(instr->print(), ASMInstruction::Comment); append_inst(instr->print(), ASMInstruction::Comment);
context.inst = instr; // 更新 context context.inst = instr;
switch (instr->get_instr_type()) { switch (instr->get_instr_type())
case Instruction::ret: {
gen_ret(); case Instruction::ret:
break; gen_ret();
case Instruction::br: break;
copy_stmt(); case Instruction::br:
gen_br(); copy_stmt();
break; gen_br();
case Instruction::add: break;
case Instruction::sub: case Instruction::add:
case Instruction::mul: case Instruction::sub:
case Instruction::sdiv: case Instruction::mul:
gen_binary(); case Instruction::sdiv:
break; gen_binary();
case Instruction::fadd: break;
case Instruction::fsub: case Instruction::fadd:
case Instruction::fmul: case Instruction::fsub:
case Instruction::fdiv: case Instruction::fmul:
gen_float_binary(); case Instruction::fdiv:
break; gen_float_binary();
case Instruction::alloca: break;
/* 对于 alloca 指令,我们已经为 alloca case Instruction::alloca:
* 的内容分配空间,在此我们还需保存 alloca gen_alloca();
* 指令自身产生的定值,即指向 alloca 空间起始地址的指针 break;
*/ case Instruction::load:
gen_alloca(); gen_load();
break; break;
case Instruction::load: case Instruction::store:
gen_load(); gen_store();
break; break;
case Instruction::store: case Instruction::ge:
gen_store(); case Instruction::gt:
break; case Instruction::le:
case Instruction::ge: case Instruction::lt:
case Instruction::gt: case Instruction::eq:
case Instruction::le: case Instruction::ne:
case Instruction::lt: gen_icmp();
case Instruction::eq: break;
case Instruction::ne: case Instruction::fge:
gen_icmp(); case Instruction::fgt:
break; case Instruction::fle:
case Instruction::fge: case Instruction::flt:
case Instruction::fgt: case Instruction::feq:
case Instruction::fle: case Instruction::fne:
case Instruction::flt: gen_fcmp();
case Instruction::feq: break;
case Instruction::fne: case Instruction::phi:
gen_fcmp(); break;
break; case Instruction::call:
case Instruction::phi: gen_call();
/* for phi, just convert to a series of break;
* copy-stmts */ case Instruction::getelementptr:
/* we can collect all phi and deal them at gen_gep();
* the end */ break;
break; case Instruction::zext:
case Instruction::call: gen_zext();
gen_call(); break;
break; case Instruction::fptosi:
case Instruction::getelementptr: gen_fptosi();
gen_gep(); break;
break; case Instruction::sitofp:
case Instruction::zext: gen_sitofp();
gen_zext(); break;
break;
case Instruction::fptosi:
gen_fptosi();
break;
case Instruction::sitofp:
gen_sitofp();
break;
} }
} }
} }
// 生成 epilogue
gen_epilogue(); gen_epilogue();
} }
} }
} }
std::string CodeGen::print() const { std::string CodeGen::print() const
{
std::string result; std::string result;
for (const auto& inst : output) { for (const auto& inst : output)
{
result += inst.format(); result += inst.format();
} }
return result; return result;
......
#include <stdio.h> #include <stdio.h>
#include <stdlib.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; int a;
scanf("%d", &a); scanf("%d", &a);
gettimeofday(&time_start, NULL);
end_set = 0;
return a; 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() { __attribute((destructor)) void after_main(void)
printf("negative index exception\n"); {
exit(0); 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 output(int a);
void outputFloat(float a); void outputFloat(float a);
void neg_idx_except(); void add_lab4_flag(int idx, int val);
\ No newline at end of file
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
BasicBlock::BasicBlock(const Module* m, const std::string& name = "", BasicBlock::BasicBlock(const Module* m, const std::string& name = "",
Function* parent = nullptr) Function* parent = nullptr)
: Value(m->get_label_type(), : Value(m->get_label_type(),
parent == nullptr ? GLOBAL_BASICBLOCK_NAMES_.get_name(name) : parent->names4blocks_.get_name(name)) parent == nullptr ? GLOBAL_BASICBLOCK_NAMES_.get_name(name) : parent->names4blocks_.get_name(name))
, parent_(parent) { , parent_(parent) {
assert(parent && "currently parent should not be nullptr"); assert(parent && "currently parent should not be nullptr");
parent_->add_basic_block(this); 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); } void BasicBlock::erase_from_parent() { this->get_parent()->remove(this); }
bool BasicBlock::is_terminated() const { bool BasicBlock::is_terminated() const {
...@@ -34,18 +34,18 @@ 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() && assert(is_terminated() &&
"Trying to get terminator from an bb which is not terminated"); "Trying to get terminator from an bb which is not terminated");
return instr_list_.back(); return instr_list_.back();
} }
void BasicBlock::add_instruction(Instruction *instr) { void BasicBlock::add_instruction(Instruction* instr) {
if (instr->is_alloca() || instr->is_phi()) if (instr->is_alloca() || instr->is_phi())
{ {
auto it = instr_list_.begin(); 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); instr_list_.emplace(it, instr);
return; return;
} }
...@@ -146,4 +146,4 @@ BasicBlock* BasicBlock::get_entry_block_of_same_function() const ...@@ -146,4 +146,4 @@ BasicBlock* BasicBlock::get_entry_block_of_same_function() const
return parent_->get_entry_block(); return parent_->get_entry_block();
} }
Names GLOBAL_BASICBLOCK_NAMES_{"label", "_"}; Names GLOBAL_BASICBLOCK_NAMES_{ "label", "_" };
\ No newline at end of file \ No newline at end of file
...@@ -7,17 +7,8 @@ ...@@ -7,17 +7,8 @@
#include <unordered_set> #include <unordered_set>
#include <queue> #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) 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(); // num_args_ = ty->getNumParams();
parent->add_function(this); parent->add_function(this);
// build args // build args
......
...@@ -382,7 +382,7 @@ std::string Instruction::safe_print() const ...@@ -382,7 +382,7 @@ std::string Instruction::safe_print() const
} }
else else
{ {
if (auto fty = dynamic_cast<FunctionType*>(ty)) if (auto fty = dynamic_cast<FunctionType*>(op0->get_type()))
{ {
auto ty3 = fty->get_return_type(); auto ty3 = fty->get_return_type();
if (ty3 == nullptr) if (ty3 == nullptr)
......
...@@ -197,6 +197,23 @@ BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *bb) { ...@@ -197,6 +197,23 @@ BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *bb) {
return new BranchInst(nullptr, if_true, nullptr, 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) ReturnInst::ReturnInst(Value *val, BasicBlock *bb)
: Instruction(bb->get_module()->get_void_type(), ret, "", bb) { : Instruction(bb->get_module()->get_void_type(), ret, "", bb) {
if (val == nullptr) { if (val == nullptr) {
...@@ -352,14 +369,13 @@ SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb, const std::str ...@@ -352,14 +369,13 @@ SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb, const std::str
PhiInst::PhiInst(Type *ty, const std::vector<Value *>& vals, PhiInst::PhiInst(Type *ty, const std::vector<Value *>& vals,
const std::vector<BasicBlock *>& val_bbs, BasicBlock *bb, const std::string& name) 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"); assert(vals.size() == val_bbs.size() && "Unmatched vals and bbs");
for (unsigned i = 0; i < vals.size(); i++) { for (unsigned i = 0; i < vals.size(); i++) {
assert(ty == vals[i]->get_type() && "Bad type for phi"); assert(ty == vals[i]->get_type() && "Bad type for phi");
add_operand(vals[i]); add_operand(vals[i]);
add_operand(val_bbs[i]); add_operand(val_bbs[i]);
} }
this->set_parent(bb);
} }
PhiInst *PhiInst::create_phi(Type *ty, BasicBlock *bb, PhiInst *PhiInst::create_phi(Type *ty, BasicBlock *bb,
......
...@@ -27,48 +27,48 @@ Module::~Module() ...@@ -27,48 +27,48 @@ Module::~Module()
for (auto i : global_list_) delete i; for (auto i : global_list_) delete i;
} }
Type *Module::get_void_type() const { return void_ty_; } Type* Module::get_void_type() const { return void_ty_; }
Type *Module::get_label_type() const { return label_ty_; } Type* Module::get_label_type() const { return label_ty_; }
IntegerType *Module::get_int1_type() const { return int1_ty_; } IntegerType* Module::get_int1_type() const { return int1_ty_; }
IntegerType *Module::get_int32_type() const { return int32_ty_; } IntegerType* Module::get_int32_type() const { return int32_ty_; }
FloatType *Module::get_float_type() const { return float32_ty_; } FloatType* Module::get_float_type() const { return float32_ty_; }
PointerType *Module::get_int32_ptr_type() { PointerType* Module::get_int32_ptr_type() {
return get_pointer_type(int32_ty_); return get_pointer_type(int32_ty_);
} }
PointerType *Module::get_float_ptr_type() { PointerType* Module::get_float_ptr_type() {
return get_pointer_type(float32_ty_); 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()) { if (pointer_map_.find(contained) == pointer_map_.end()) {
pointer_map_[contained] = new PointerType(contained); pointer_map_[contained] = new PointerType(contained);
} }
return pointer_map_[contained]; return pointer_map_[contained];
} }
ArrayType *Module::get_array_type(Type *contained, unsigned num_elements) { ArrayType* Module::get_array_type(Type* contained, unsigned num_elements) {
if (array_map_.find({contained, num_elements}) == array_map_.end()) { if (array_map_.find({ contained, num_elements }) == array_map_.end()) {
array_map_[{contained, num_elements}] = array_map_[{contained, num_elements}] =
new ArrayType(contained, num_elements); new ArrayType(contained, num_elements);
} }
return array_map_[{contained, num_elements}]; return array_map_[{contained, num_elements}];
} }
FunctionType *Module::get_function_type(Type *retty, FunctionType* Module::get_function_type(Type* retty,
std::vector<Type *> &args) { std::vector<Type*>& args) {
if (not function_map_.count({retty, args})) { if (not function_map_.count({ retty, args })) {
function_map_[{retty, args}] = function_map_[{retty, args}] =
new FunctionType(retty, args); new FunctionType(retty, args);
} }
return function_map_[{retty, args}]; return function_map_[{retty, args}];
} }
void Module::add_function(Function *f) { function_list_.push_back(f); } void Module::add_function(Function* f) { function_list_.push_back(f); }
std::list<Function*> &Module::get_functions() { return function_list_; } std::list<Function*>& Module::get_functions() { return function_list_; }
void Module::add_global_variable(GlobalVariable *g) { void Module::add_global_variable(GlobalVariable* g) {
global_list_.push_back(g); global_list_.push_back(g);
} }
std::list<GlobalVariable*> &Module::get_global_variable() { std::list<GlobalVariable*>& Module::get_global_variable() {
return global_list_; return global_list_;
} }
......
...@@ -42,6 +42,6 @@ void User::remove_operand(unsigned idx) { ...@@ -42,6 +42,6 @@ void User::remove_operand(unsigned idx) {
} }
// remove the designated operand // remove the designated operand
if (operands_[idx]) if (operands_[idx])
operands_[idx]->remove_use(this, idx); operands_[idx]->remove_use(this, idx);
operands_.erase(operands_.begin() + idx); operands_.erase(operands_.begin() + idx);
} }
...@@ -10,11 +10,12 @@ ...@@ -10,11 +10,12 @@
// 处理流程:两趟处理,mark 标记有用变量,sweep 删除无用指令 // 处理流程:两趟处理,mark 标记有用变量,sweep 删除无用指令
void DeadCode::run() { void DeadCode::run() {
bool changed; bool changed;
func_info = new FuncInfo(m_); func_info = new FuncInfo(m_);
func_info->run(); func_info->run();
do { do {
changed = false; changed = false;
for (auto func : m_->get_functions()) { for (auto func : m_->get_functions()) {
if (func->is_declaration()) continue;
if (remove_bb_) changed |= clear_basic_blocks(func); if (remove_bb_) changed |= clear_basic_blocks(func);
mark(func); mark(func);
changed |= sweep(func); changed |= sweep(func);
...@@ -133,7 +134,7 @@ bool DeadCode::sweep(Function *func) { ...@@ -133,7 +134,7 @@ bool DeadCode::sweep(Function *func) {
for (auto bb : func->get_basic_blocks()) { for (auto bb : func->get_basic_blocks()) {
for (auto inst : bb->get_instructions()) { for (auto inst : bb->get_instructions()) {
if (marked[inst]) continue; if (marked[inst]) continue;
wait_del.emplace(inst); wait_del.emplace(inst);
} }
bb->get_instructions().remove_if([&wait_del](Instruction* i) -> bool {return wait_del.count(i); }); bb->get_instructions().remove_if([&wait_del](Instruction* i) -> bool {return wait_del.count(i); });
if (!wait_del.empty()) rm = true; if (!wait_del.empty()) rm = true;
...@@ -172,12 +173,12 @@ void DeadCode::sweep_globally() const { ...@@ -172,12 +173,12 @@ void DeadCode::sweep_globally() const {
// changed |= unused_funcs.size() or unused_globals.size(); // changed |= unused_funcs.size() or unused_globals.size();
for (auto func : unused_funcs) for (auto func : unused_funcs)
{ {
m_->get_functions().remove(func); m_->get_functions().remove(func);
delete func; delete func;
} }
for (auto glob : unused_globals) for (auto glob : unused_globals)
{ {
m_->get_global_variable().remove(glob); m_->get_global_variable().remove(glob);
delete glob; delete glob;
} }
} }
...@@ -62,13 +62,13 @@ void Dominators::run() { ...@@ -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 (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); 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); b2 = get_idom(b2);
} }
} }
...@@ -84,6 +84,12 @@ BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const ...@@ -84,6 +84,12 @@ BasicBlock *Dominators::intersect(BasicBlock *b1, const BasicBlock *b2) const
void Dominators::create_reverse_post_order() { void Dominators::create_reverse_post_order() {
std::set<BasicBlock*> visited; std::set<BasicBlock*> visited;
dfs(f_->get_entry_block(), 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) { ...@@ -100,8 +106,8 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
dfs(succ, visited); dfs(succ, visited);
} }
} }
post_order_vec_.push_back(bb); reversed_post_order_vec_.push_back(bb);
post_order_.insert({bb, post_order_.size()}); reversed_post_order_.insert({bb, reversed_post_order_.size()});
} }
/** /**
...@@ -111,38 +117,28 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) { ...@@ -111,38 +117,28 @@ void Dominators::dfs(BasicBlock *bb, std::set<BasicBlock *> &visited) {
*/ */
void Dominators::create_idom() { void Dominators::create_idom() {
// 可能有用的数据结构 // 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列 // reversed_post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
// post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 post_order_vec_ 中的索引 // reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_post_order_vec_ 中的索引
// 可能有用的函数 // 可能有用的函数
// intersect(BasicBlock *, BasicBlock *) 寻找两个基本块在支配树上的最近祖先 // intersect(BasicBlock *, BasicBlock *) 寻找两个基本块在支配树上的最近祖先
// 需要填写 // 需要填写
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a (或者 idom_[a] = a 代表 a 没有直接支配者) // idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a (或者 idom_[a] = a 代表 a 没有直接支配者)
// 代表基本块的直接支配者是否已经确定, 不会在迭代中改变 (默认初始化为 false) int bb_count = static_cast<int>(reversed_post_order_vec_.size());
bool* already_determined = new bool[post_order_vec_.size()]{};
int bb_count = static_cast<int>(post_order_vec_.size()); idom_[reversed_post_order_vec_[0]] = reversed_post_order_vec_[0];
for (int i = 0; i < bb_count; i++)
{
auto bb = post_order_vec_[i];
// TODO 填写可以直接确定直接支配者, 无需参与迭代的基本块的 idom_ 和 already_determined
throw "Unimplemented create_idom";
}
bool changed; bool changed;
do do
{ {
changed = false; 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 = reversed_post_order_vec_[i];
auto bb = post_order_vec_[i];
// TODO 更新基本块 bb 的 idom_, 设置 changed(如果 idom_ 有变化) // TODO 更新基本块 bb 的 idom_, 设置 changed(如果 idom_ 有变化)
throw "Unimplemented create_idom"; throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
} }
} while (changed); } while (changed);
delete[] already_determined;
} }
/** /**
...@@ -154,19 +150,19 @@ void Dominators::create_idom() { ...@@ -154,19 +150,19 @@ void Dominators::create_idom() {
*/ */
void Dominators::create_dominance_frontier() { void Dominators::create_dominance_frontier() {
// 可能有用的数据结构 // 可能有用的数据结构
// post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列 // reversed_post_order_vec_ vector<BasicBlock*>, 其中基本块按照逆后续排列
// post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 post_order_vec_ 中的索引 // reversed_post_order_ map<BasicBlock*, unsigned int>, 每个基本块在 reversed_post_order_vec_ 中的索引
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent // idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// (或者 idom_[a] = a 代表 a 没有直接支配者) // (或者 idom_[a] = a 代表 a 没有直接支配者)
// 需要填写 // 需要填写
// dom_frontier_ map<BasicBlock*, set<BasicBlock*>> 支配边界 // 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++) 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_ // TODO 计算 bb 的支配边界集合, 填入 dom_frontier_
throw "Unimplemented create_dominance_frontier"; throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
} }
} }
...@@ -178,12 +174,13 @@ void Dominators::create_dominance_frontier() { ...@@ -178,12 +174,13 @@ void Dominators::create_dominance_frontier() {
*/ */
void Dominators::create_dom_tree_succ() { void Dominators::create_dom_tree_succ() {
// 可能有用的数据结构 // 可能有用的数据结构
// idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent // idom_ map<BasicBlock *, BasicBlock *> 直接支配者, idom_[a] = b 代表 b 直接支配 a, 支配树中 b 是 a 的 parent
// 需要填写 // 需要填写
// dom_tree_succ_blocks_ map<BasicBlock*, set<BasicBlock*>> 支配树中后继(孩子)节点 // dom_tree_succ_blocks_ map<BasicBlock*, set<BasicBlock*>> 支配树中后继(孩子)节点
// TODO 分析得到 f_ 中各个基本块的支配树后继 // TODO 分析得到 f_ 中各个基本块的支配树后继
throw "Unimplemented create_dom_tree_succ"; // 注意如果 idom_[n] = n, 这意味着 n 没有直接支配者,因此 n 的后继中没有 n
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
} }
/** /**
......
...@@ -8,251 +8,266 @@ ...@@ -8,251 +8,266 @@
void FuncInfo::UseMessage::add(Value* val) void FuncInfo::UseMessage::add(Value* val)
{ {
auto g = dynamic_cast<GlobalVariable*>(val); auto g = dynamic_cast<GlobalVariable*>(val);
if (g != nullptr) if (g != nullptr)
{ {
globals_.emplace(g); globals_.emplace(g);
return; return;
} }
auto arg = dynamic_cast<Argument*>(val); auto arg = dynamic_cast<Argument*>(val);
arguments_.emplace(arg); arguments_.emplace(arg);
} }
bool FuncInfo::UseMessage::have(Value* val) const bool FuncInfo::UseMessage::have(Value* val) const
{ {
auto g = dynamic_cast<GlobalVariable*>(val); auto g = dynamic_cast<GlobalVariable*>(val);
if (g != nullptr) return globals_.count(g); if (g != nullptr) return globals_.count(g);
return arguments_.count(dynamic_cast<Argument*>(val)); return arguments_.count(dynamic_cast<Argument*>(val));
} }
bool FuncInfo::UseMessage::empty() const bool FuncInfo::UseMessage::empty() const
{ {
return globals_.empty() && arguments_.empty(); return globals_.empty() && arguments_.empty();
} }
void FuncInfo::run() void FuncInfo::run()
{ {
std::unordered_map<Value*, Value*> val_to_var; std::unordered_map<Value*, Value*> val_to_var;
// 计算对全局变量的 load/store // 计算对全局变量的 load/store
for (auto glob : m_->get_global_variable()) for (auto glob : m_->get_global_variable())
cal_val_2_var(glob, val_to_var); cal_val_2_var(glob, val_to_var);
std::queue<Function*> worklist; std::queue<Function*> worklist;
std::unordered_set<Function*> in_worklist; std::unordered_set<Function*> in_worklist;
// 计算对函数参数的 load/store // 计算对函数参数的 load/store
// 本质上来说,对局部变量的 load/store 不会在函数外产生副作用,它也不会被用作 func_info 的信息 // 本质上来说,对局部变量的 load/store 不会在函数外产生副作用,它也不会被用作 func_info 的信息
for (auto func : m_->get_functions()) for (auto func : m_->get_functions())
{ {
if (func->is_declaration()) continue; if (func->is_declaration()) continue;
use_libs[func] = false; use_libs[func] = false;
worklist.emplace(func); worklist.emplace(func);
in_worklist.emplace(func); in_worklist.emplace(func);
for (auto arg : func->get_args()) for (auto arg : func->get_args())
{ {
if (arg->get_type()->is_pointer_type()) if (arg->get_type()->is_pointer_type())
{ {
cal_val_2_var(arg, val_to_var); cal_val_2_var(arg, val_to_var);
} }
} }
} }
// 处理函数相互调用导致的隐式 load/store // 处理函数相互调用导致的隐式 load/store
while (!worklist.empty()) while (!worklist.empty())
{ {
// 被调用的函数 // 被调用的函数
auto calleeF = worklist.front(); auto calleeF = worklist.front();
worklist.pop(); worklist.pop();
in_worklist.erase(calleeF); in_worklist.erase(calleeF);
for (auto& use : calleeF->get_use_list()) for (auto& use : calleeF->get_use_list())
{ {
// 函数调用指令 // 函数调用指令
auto inst = dynamic_cast<CallInst*>(use.val_); auto inst = dynamic_cast<CallInst*>(use.val_);
// 调用 f 的函数 // 调用 f 的函数
auto callerF = inst->get_parent()->get_parent(); auto callerF = inst->get_parent()->get_parent();
auto& callerLoads = loads[callerF]; auto& callerLoads = loads[callerF];
auto& calleeLoads = loads[calleeF]; auto& calleeLoads = loads[calleeF];
auto& callerStores = stores[callerF]; auto& callerStores = stores[callerF];
auto& calleeStores = stores[calleeF]; auto& calleeStores = stores[calleeF];
// caller 的 load store 数量 // caller 的 load store 数量
auto caller_old_load_store_count = callerLoads.globals_.size() + callerLoads.arguments_.size() + auto caller_old_load_store_count = callerLoads.globals_.size() + callerLoads.arguments_.size() +
callerStores.globals_.size() + callerStores.arguments_.size(); callerStores.globals_.size() + callerStores.arguments_.size();
// caller 同时 load 了 callee load 的全局变量 // caller 同时 load 了 callee load 的全局变量
for (auto i : calleeLoads.globals_) callerLoads.globals_.emplace(i); for (auto i : calleeLoads.globals_) callerLoads.globals_.emplace(i);
// caller 同时 store 了 callee store 的全局变量 // caller 同时 store 了 callee store 的全局变量
for (auto i : calleeStores.globals_) callerStores.globals_.emplace(i); for (auto i : calleeStores.globals_) callerStores.globals_.emplace(i);
auto& ops = inst->get_operands(); auto& ops = inst->get_operands();
// 形式参数 // 形式参数
for (auto calleArg : calleeF->get_args()) for (auto calleArg : calleeF->get_args())
{ {
if (calleArg->get_type()->is_pointer_type()) if (calleArg->get_type()->is_pointer_type())
{ {
// 传入的实参 // 传入的实参
auto trueArg = ops[calleArg->get_arg_no() + 1]; auto trueArg = ops[calleArg->get_arg_no() + 1];
// 实参来自哪个临时变量 // 实参来自哪个临时变量
auto trueArgVar = val_to_var.find(trueArg); auto trueArgVar = val_to_var.find(trueArg);
// 来自局部变量,跳过,因为对局部变量的 load/store 不会在函数外产生副作用 // 来自局部变量,跳过,因为对局部变量的 load/store 不会在函数外产生副作用
if (trueArgVar == val_to_var.end()) continue; if (trueArgVar == val_to_var.end()) continue;
auto trace = trueArgVar->second; auto trace = trueArgVar->second;
// 添加 load // 添加 load
if (calleeLoads.have(calleArg)) callerLoads.add(trace); if (calleeLoads.have(calleArg)) callerLoads.add(trace);
// 添加 store // 添加 store
if (calleeStores.have(calleArg)) callerStores.add(trace); if (calleeStores.have(calleArg)) callerStores.add(trace);
} }
} }
// caller f 的 load/store 产生了变化,可能会影响其它调用 f 的函数的 load/store // caller f 的 load/store 产生了变化,可能会影响其它调用 f 的函数的 load/store
if (callerLoads.globals_.size() + callerLoads.arguments_.size() + callerStores.globals_.size() + if (callerLoads.globals_.size() + callerLoads.arguments_.size() + callerStores.globals_.size() +
callerStores.arguments_.size() != caller_old_load_store_count) callerStores.arguments_.size() != caller_old_load_store_count)
{ {
if (!in_worklist.count(callerF)) if (!in_worklist.count(callerF))
{ {
in_worklist.emplace(callerF); in_worklist.emplace(callerF);
worklist.emplace(callerF); worklist.emplace(callerF);
} }
} }
} }
} }
// 没有 load/store,但是调用了库函数的函数是非纯函数(因为库函数是 IO) // 没有 load/store,但是调用了库函数的函数是非纯函数(因为库函数是 IO)
for (auto& func : m_->get_functions()) for (auto& func : m_->get_functions())
{ {
if (func->is_declaration()) if (func->is_declaration())
{ {
for (auto& use : func->get_use_list()) for (auto& use : func->get_use_list())
{ {
auto call = dynamic_cast<CallInst*>(use.val_); auto call = dynamic_cast<CallInst*>(use.val_);
use_libs[call->get_parent()->get_parent()] = true; use_libs[call->get_parent()->get_parent()] = true;
} }
} }
worklist.emplace(func); worklist.emplace(func);
in_worklist.emplace(func); in_worklist.emplace(func);
} }
while (!worklist.empty()) while (!worklist.empty())
{ {
auto f = worklist.front(); auto f = worklist.front();
worklist.pop(); worklist.pop();
in_worklist.erase(f); in_worklist.erase(f);
if (use_libs[f]) if (use_libs[f])
for (auto& use : f->get_use_list()) for (auto& use : f->get_use_list())
{ {
auto inst = dynamic_cast<CallInst*>(use.val_); auto inst = dynamic_cast<CallInst*>(use.val_);
auto cf = inst->get_parent()->get_parent(); auto cf = inst->get_parent()->get_parent();
if (!use_libs[cf]) if (!use_libs[cf])
{ {
use_libs[cf] = true; use_libs[cf] = true;
if (!in_worklist.count(cf)) if (!in_worklist.count(cf))
{ {
in_worklist.emplace(cf); in_worklist.emplace(cf);
worklist.emplace(cf); worklist.emplace(cf);
} }
} }
} }
} }
log(); log();
} }
Value* FuncInfo::store_ptr(const StoreInst* st) Value* FuncInfo::store_ptr(const StoreInst* st)
{ {
return trace_ptr(st->get_operand(1)); return trace_ptr(st->get_operand(1));
} }
Value* FuncInfo::load_ptr(const LoadInst* ld) Value* FuncInfo::load_ptr(const LoadInst* ld)
{ {
return trace_ptr(ld->get_operand(0)); return trace_ptr(ld->get_operand(0));
} }
std::unordered_set<Value*> FuncInfo::get_stores(const CallInst* call) std::unordered_set<Value*> FuncInfo::get_stores(const CallInst* call)
{ {
auto func = call->get_operand(0)->as<Function>(); auto func = call->get_operand(0)->as<Function>();
if (func->is_declaration()) return {}; if (func->is_declaration()) return {};
std::unordered_set<Value*> ret; std::unordered_set<Value*> ret;
for (auto i : stores[func].globals_) ret.emplace(i); for (auto i : stores[func].globals_) ret.emplace(i);
for (auto arg : stores[func].arguments_) for (auto arg : stores[func].arguments_)
{ {
int arg_no = static_cast<int>(arg->get_arg_no()); int arg_no = static_cast<int>(arg->get_arg_no());
auto in = call->get_operand(arg_no + 1); auto in = call->get_operand(arg_no + 1);
ret.emplace(trace_ptr(in)); ret.emplace(trace_ptr(in));
} }
return ret; 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 void FuncInfo::log() const
{ {
for (auto it : use_libs) for (auto it : use_libs)
{ {
LOG_INFO << it.first->get_name() << " is pure? " << it.second; LOG_INFO << it.first->get_name() << " is pure? " << it.second;
} }
} }
void FuncInfo::cal_val_2_var(Value* var, std::unordered_map<Value*, Value*>& val_2_var) void FuncInfo::cal_val_2_var(Value* var, std::unordered_map<Value*, Value*>& val_2_var)
{ {
auto global = dynamic_cast<GlobalVariable*>(var); auto global = dynamic_cast<GlobalVariable*>(var);
if (global != nullptr && global->is_const()) return; if (global != nullptr && global->is_const()) return;
std::unordered_set<Value*> handled; std::unordered_set<Value*> handled;
std::queue<Value*> wait_to_handle; std::queue<Value*> wait_to_handle;
handled.emplace(var); handled.emplace(var);
val_2_var[var] = var; val_2_var[var] = var;
wait_to_handle.emplace(var); wait_to_handle.emplace(var);
while (!wait_to_handle.empty()) while (!wait_to_handle.empty())
{ {
Value* v = wait_to_handle.front(); Value* v = wait_to_handle.front();
wait_to_handle.pop(); wait_to_handle.pop();
for (auto& use : v->get_use_list()) for (auto& use : v->get_use_list())
{ {
auto inst = dynamic_cast<Instruction*>(use.val_); auto inst = dynamic_cast<Instruction*>(use.val_);
auto f = inst->get_parent()->get_parent(); auto f = inst->get_parent()->get_parent();
switch (inst->get_instr_type()) switch (inst->get_instr_type())
{ {
case Instruction::load: case Instruction::load:
{ {
loads[f].add(var); loads[f].add(var);
break; break;
} }
case Instruction::store: case Instruction::store:
{ {
stores[f].add(var); stores[f].add(var);
break; break;
} }
case Instruction::getelementptr: case Instruction::getelementptr:
case Instruction::phi: case Instruction::phi:
{ {
if (!handled.count(inst)) if (!handled.count(inst))
{ {
handled.emplace(inst); handled.emplace(inst);
val_2_var[inst] = var; val_2_var[inst] = var;
wait_to_handle.emplace(inst); wait_to_handle.emplace(inst);
} }
break; break;
} }
// case Instruction::call: // case Instruction::call:
// { // {
// 如果遇到不能确定行为的库函数,需要指定其其对参数同时进行了读写,目前这里遇不到 // 如果遇到不能确定行为的库函数,需要指定其其对参数同时进行了读写,目前这里遇不到
// auto callF = dynamic_cast<Function*>(inst->get_operand(0)); // auto callF = dynamic_cast<Function*>(inst->get_operand(0));
// if (callF->is_declaration()) // if (callF->is_declaration())
// { // {
// stores[f].add(var); // stores[f].add(var);
// loads[f].add(var); // loads[f].add(var);
// } // }
// break; // break;
// } // }
default: default:
break; break;
} }
} }
} }
} }
Value* FuncInfo::trace_ptr(Value* val) Value* FuncInfo::trace_ptr(Value* val)
{ {
assert(val != nullptr); assert(val != nullptr);
if (dynamic_cast<GlobalVariable*>(val) != nullptr if (dynamic_cast<GlobalVariable*>(val) != nullptr
|| dynamic_cast<Argument*>(val) != nullptr || dynamic_cast<Argument*>(val) != nullptr
|| dynamic_cast<AllocaInst*>(val) != nullptr || dynamic_cast<AllocaInst*>(val) != nullptr
) )
return val; return val;
auto inst = dynamic_cast<Instruction*>(val); auto inst = dynamic_cast<Instruction*>(val);
assert(inst != nullptr); assert(inst != nullptr);
if (inst->is_gep()) return trace_ptr(inst->get_operand(0)); if (inst->is_gep()) return trace_ptr(inst->get_operand(0));
// 这意味着栈里面存在指针,你需要运行 Mem2Reg;或者你给 trace_ptr 传入了非指针参数 // 这意味着栈里面存在指针,你需要运行 Mem2Reg;或者你给 trace_ptr 传入了非指针参数
assert(!inst->is_load()); assert(!inst->is_load());
assert(inst->is_alloca()); assert(inst->is_alloca());
return inst; return inst;
} }
...@@ -14,23 +14,23 @@ ...@@ -14,23 +14,23 @@
*/ */
void LoopInvariantCodeMotion::run() void LoopInvariantCodeMotion::run()
{ {
func_info_ = new FuncInfo(m_); func_info_ = new FuncInfo(m_);
func_info_->run(); func_info_->run();
for (auto func : m_->get_functions()) for (auto func : m_->get_functions())
{ {
if (func->is_declaration()) continue; if (func->is_declaration()) continue;
loop_detection_ = new LoopDetection(func); loop_detection_ = new LoopDetection(func);
loop_detection_->run(); loop_detection_->run();
for (auto loop : loop_detection_->get_loops()) for (auto loop : loop_detection_->get_loops())
{ {
// 遍历处理顶层循环 // 遍历处理顶层循环
if (loop->get_parent() == nullptr) traverse_loop(loop); if (loop->get_parent() == nullptr) traverse_loop(loop);
} }
delete loop_detection_; delete loop_detection_;
loop_detection_ = nullptr; loop_detection_ = nullptr;
} }
delete func_info_; delete func_info_;
func_info_ = nullptr; func_info_ = nullptr;
} }
/** /**
...@@ -40,12 +40,12 @@ void LoopInvariantCodeMotion::run() ...@@ -40,12 +40,12 @@ void LoopInvariantCodeMotion::run()
*/ */
void LoopInvariantCodeMotion::traverse_loop(Loop* loop) void LoopInvariantCodeMotion::traverse_loop(Loop* loop)
{ {
// 先外层再内层,这样不用在插入 preheader 后更改循环 // 先外层再内层,这样不用在插入 preheader 后更改循环
run_on_loop(loop); run_on_loop(loop);
for (auto sub_loop : loop->get_sub_loops()) for (auto sub_loop : loop->get_sub_loops())
{ {
traverse_loop(sub_loop); traverse_loop(sub_loop);
} }
} }
// TODO: 收集并返回循环 store 过的变量 // TODO: 收集并返回循环 store 过的变量
...@@ -56,35 +56,20 @@ void LoopInvariantCodeMotion::traverse_loop(Loop* loop) ...@@ -56,35 +56,20 @@ void LoopInvariantCodeMotion::traverse_loop(Loop* loop)
// 则你应该返回 %a 而非 %b // 则你应该返回 %a 而非 %b
std::unordered_set<Value*> LoopInvariantCodeMotion::collect_loop_store_vars(Loop* loop) std::unordered_set<Value*> LoopInvariantCodeMotion::collect_loop_store_vars(Loop* loop)
{ {
// 可能用到 // 可能用到
// FuncInfo::store_ptr, FuncInfo::get_stores // FuncInfo::store_ptr, FuncInfo::get_stores
throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
} }
// TODO: 收集并返回循环中的所有指令 // TODO: 收集并返回循环中的所有指令
std::vector<Instruction*> LoopInvariantCodeMotion::collect_insts(Loop* loop) std::vector<Instruction*> LoopInvariantCodeMotion::collect_insts(Loop* loop)
{ {
throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); 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 enum InstructionType: std::uint8_t
{ {
UNKNOWN, VARIANT, INVARIANT UNKNOWN, VARIANT, INVARIANT
}; };
/** /**
...@@ -94,91 +79,95 @@ enum InstructionType: std::uint8_t ...@@ -94,91 +79,95 @@ enum InstructionType: std::uint8_t
*/ */
void LoopInvariantCodeMotion::run_on_loop(Loop* loop) void LoopInvariantCodeMotion::run_on_loop(Loop* loop)
{ {
// 循环 store 过的变量 // 循环 store 过的变量
std::unordered_set<Value*> loop_stores_var = collect_loop_store_vars(loop); std::unordered_set<Value*> loop_stores_var = collect_loop_store_vars(loop);
// 循环中的所有指令 // 循环中的所有指令
std::vector<Instruction*> instructions = collect_insts(loop); std::vector<Instruction*> instructions = collect_insts(loop);
int insts_count = static_cast<int>(instructions.size()); int insts_count = static_cast<int>(instructions.size());
// 循环的所有基本块 // Value* 在 map 内说明它是循环内的指令,InstructionType 指示它是循环变量(每次循环都会变)/ 循环不变量 还是 不知道
std::unordered_set<BasicBlock*> bbs; std::unordered_map<Value*, InstructionType> inst_type;
for (auto i : loop->get_blocks()) bbs.emplace(i); for (auto i : instructions) inst_type[i] = UNKNOWN;
// val 是否在循环内定义,可以当成函数进行调用
auto is_val_in_loop = [&bbs](Value* val)->bool // 遍历后是不是还有指令不知道 InstructionType
{ bool have_inst_can_not_decide;
auto inst = dynamic_cast<Instruction*>(val); // 是否存在 invariant
if (inst == nullptr) return true; bool have_invariant = false;
return bbs.count(inst->get_parent()); do
}; {
// inst_type[i] 代表 instructions[i] 是循环变量(每次循环都会变)/ 循环不变量 还是 不知道 have_inst_can_not_decide = false;
std::vector<InstructionType> inst_type; for (int i = 0; i < insts_count; i++)
inst_type.resize(insts_count); {
Instruction* inst = instructions[i];
// 遍历后是不是还有指令不知道 InstructionType InstructionType type = inst_type[inst];
bool have_inst_can_not_decide; if (type != UNKNOWN) continue;
// 是否存在 invariant // 可能有用的函数
bool have_invariant = false; // FuncInfo::load_ptr, FuncInfo::get_stores, FuncInfo::use_io
do
{ // TODO: 识别循环不变式指令
have_inst_can_not_decide = false; // - 将 store、ret、br、phi 等指令与非纯函数调用标记为 VARIANT
for (int i = 0; i < insts_count; i++) // - 如果 load 指令加载的变量是循环 store 过的变量,标记为 VARIANT
{ // - 如果指令有 VARIANT 操作数,标记为 VARIANT
Instruction* inst = instructions[i]; // - 如果指令所有操作数都是 INVARIANT (或者不在循环内),标记为 INVARIANT, 设置 have_invariant
InstructionType type = inst_type[i]; // - 否则设置 have_inst_can_not_decide
if (type != UNKNOWN) continue;
// 可能有用的函数 // TODO: 外提循环不变的非纯函数调用
// FuncInfo::load_ptr // 注意: 你不应该外提使用了 io 的函数调用
// TODO: 识别循环不变式指令 throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
// - 将 store、ret、br、phi 等指令与非纯函数调用标记为 VARIANT }
// - 如果 load 指令加载的变量是循环 store 过的变量,标记为 VARIANT }
// - 如果指令有 VARIANT 操作数,标记为 VARIANT while (have_inst_can_not_decide);
// - 如果指令所有操作数都是 INVARIANT (或者不在循环内),标记为 INVARIANT, 设置 have_invariant
// - 否则设置 have_inst_can_not_decide if (!have_invariant) return;
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
} auto header = loop->get_header();
}
while (have_inst_can_not_decide); if (header->get_pre_basic_blocks().size() > 1 || header->get_pre_basic_blocks().front()->get_succ_basic_blocks().size() > 1)
{
if (!have_invariant) return; // 插入 preheader
auto bb = BasicBlock::create(m_, "", loop->get_header()->get_parent());
auto header = loop->get_header(); loop->set_preheader(bb);
if (header->get_pre_basic_blocks().size() > 1 || header->get_pre_basic_blocks().front()->get_succ_basic_blocks().size() > 1) for (auto phi : loop->get_header()->get_instructions())
{ {
// 插入 preheader if (phi->get_instr_type() != Instruction::phi) break;
auto bb = BasicBlock::create(m_, "", loop->get_header()->get_parent()); // 可能有用的函数
loop->set_preheader(bb); // PhiInst::create_phi
for (auto phi : loop->get_header()->get_instructions()) // TODO: 分裂 phi 指令
{ throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
if (phi->get_instr_type() != Instruction::phi) break; }
// TODO: 分裂 phi 指令
throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); // 可能有用的函数
} // BranchInst::replace_all_bb_match
// TODO: 维护 bb, header, 与 header 前驱块的基本块关系 // TODO: 维护 bb, header, 与 header 前驱块的基本块关系
throw std::runtime_error("Lab4: 你有一个TODO需要完成!"); throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
bb->add_instruction(BranchInst::create_br(header, bb)); BranchInst::create_br(header, bb);
// 若你想维护 LoopDetection 在 LICM 后保持正确 // 若你想维护 LoopDetection 在 LICM 后保持正确
// auto loop2 = loop->get_parent(); // auto loop2 = loop->get_parent();
// while (loop2 != nullptr) // while (loop2 != nullptr)
// { // {
// loop2->get_parent()->add_block(bb); // loop2->add_block(bb);
// loop2 = loop2->get_parent(); // loop2 = loop2->get_parent();
// } // }
} }
else loop->set_preheader(header->get_pre_basic_blocks().front()); else loop->set_preheader(header->get_pre_basic_blocks().front());
// insert preheader // insert preheader
auto preheader = loop->get_preheader(); auto preheader = loop->get_preheader();
auto terminator = preheader->get_instructions().back(); auto terminator = preheader->get_instructions().back();
preheader->get_instructions().pop_back(); preheader->get_instructions().pop_back();
// TODO: 外提循环不变指令 // 可以使用 Function::check_for_block_relation_error 检查基本块间的关系是否正确维护
throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
// TODO: 外提循环不变指令
preheader->add_instruction(terminator); throw std::runtime_error("Lab4: 你有一个TODO需要完成!");
preheader->add_instruction(terminator);
std::cerr << "licm done\n";
} }
...@@ -54,6 +54,21 @@ void LoopDetection::run() { ...@@ -54,6 +54,21 @@ void LoopDetection::run() {
delete dominators_; 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 发现循环及其子循环 * @brief 发现循环及其子循环
* @param bb 循环的header块 * @param bb 循环的header块
...@@ -69,10 +84,12 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl ...@@ -69,10 +84,12 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
// 5. 建立正确的循环嵌套关系 // 5. 建立正确的循环嵌套关系
std::vector<BasicBlock*> work_list = {latches.begin(), latches.end()}; // 初始化工作表 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()) { // 当工作表非空时继续处理 while (!work_list.empty()) { // 当工作表非空时继续处理
auto bb2 = work_list.back(); auto bb2 = work_list.back();
work_list.pop_back(); work_list.pop_back();
already_in_work_list.erase(bb2);
// TODO-1: 处理未分配给任何循环的节点 // TODO-1: 处理未分配给任何循环的节点
if (bb_to_loop_.find(bb2) == bb_to_loop_.end()) { if (bb_to_loop_.find(bb2) == bb_to_loop_.end()) {
...@@ -85,7 +102,7 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl ...@@ -85,7 +102,7 @@ void LoopDetection::discover_loop_and_sub_loops(BasicBlock *bb, std::set<BasicBl
} }
// TODO-2: 处理已属于其他循环的节点 // TODO-2: 处理已属于其他循环的节点
if (bb_to_loop_[bb2] != loop) { if (bb_to_loop_[bb2] != loop) {
/* 在此添加代码: /* 在此添加代码:
* 1. 获取bb当前所属的循环sub_loop * 1. 获取bb当前所属的循环sub_loop
* 2. 找到sub_loop的最顶层父循环 * 2. 找到sub_loop的最顶层父循环
......
...@@ -4,16 +4,17 @@ ...@@ -4,16 +4,17 @@
#include "Value.hpp" #include "Value.hpp"
// l_val 是否是非数组 alloca 变量 // ptr 是否是非数组 alloca 变量(是则转换为 AllocaInst)
static bool is_not_array_alloca(Value* l_val) static AllocaInst* is_not_array_alloca(Value* ptr)
{ {
auto alloca = dynamic_cast<AllocaInst*>(l_val); auto alloca = dynamic_cast<AllocaInst*>(ptr);
return alloca != nullptr && !alloca->get_alloca_type()->is_array_type(); if (alloca != nullptr && !alloca->get_alloca_type()->is_array_type()) return alloca;
return nullptr;
} }
/** /**
* @brief Mem2Reg Pass的主入口函数 * @brief Mem2Reg Pass的主入口函数
* *
* 该函数执行内存到寄存器的提升过程,将栈上的局部变量提升到SSA格式。 * 该函数执行内存到寄存器的提升过程,将栈上的局部变量提升到SSA格式。
* 主要步骤: * 主要步骤:
* 1. 创建并运行支配树分析 * 1. 创建并运行支配树分析
...@@ -21,7 +22,7 @@ static bool is_not_array_alloca(Value* l_val) ...@@ -21,7 +22,7 @@ static bool is_not_array_alloca(Value* l_val)
* - 清空相关数据结构 * - 清空相关数据结构
* - 插入必要的phi指令 * - 插入必要的phi指令
* - 执行变量重命名 * - 执行变量重命名
* *
* 注意:函数执行后,冗余的局部变量分配指令将由后续的死代码删除Pass处理 * 注意:函数执行后,冗余的局部变量分配指令将由后续的死代码删除Pass处理
*/ */
void Mem2Reg::run() { void Mem2Reg::run() {
...@@ -43,7 +44,7 @@ void Mem2Reg::run() { ...@@ -43,7 +44,7 @@ void Mem2Reg::run() {
generate_phi(); generate_phi();
// 确保每个局部变量的栈都有初始值 // 确保每个局部变量的栈都有初始值
for (auto var : allocas_) 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()); rename(func_->get_entry_block());
} }
...@@ -55,17 +56,17 @@ void Mem2Reg::run() { ...@@ -55,17 +56,17 @@ void Mem2Reg::run() {
/** /**
* @brief 在必要的位置插入phi指令 * @brief 在必要的位置插入phi指令
* *
* 该函数实现了经典的phi节点插入算法: * 该函数实现了经典的phi节点插入算法:
* 1. 收集全局活跃变量: * 1. 收集全局活跃变量:
* - 扫描所有store指令 * - 扫描所有store指令
* - 识别在多个基本块中被赋值的变量 * - 识别在多个基本块中被赋值的变量
* *
* 2. 插入phi指令: * 2. 插入phi指令:
* - 对每个全局活跃变量 * - 对每个全局活跃变量
* - 在其定值点的支配边界处插入phi指令 * - 在其定值点的支配边界处插入phi指令
* - 使用工作表法处理迭代式的phi插入 * - 使用工作表法处理迭代式的phi插入
* *
* phi指令的插入遵循最小化原则,只在必要的位置插入phi节点 * phi指令的插入遵循最小化原则,只在必要的位置插入phi节点
*/ */
void Mem2Reg::generate_phi() { void Mem2Reg::generate_phi() {
...@@ -80,11 +81,13 @@ void Mem2Reg::generate_phi() { ...@@ -80,11 +81,13 @@ void Mem2Reg::generate_phi() {
if (instr->is_store()) { if (instr->is_store()) {
// store i32 a, i32 *b // store i32 a, i32 *b
// a is r_val, b is l_val // a is r_val, b is l_val
auto l_val = dynamic_cast<StoreInst *>(instr)->get_lval(); auto l_val = dynamic_cast<StoreInst*>(instr)->get_ptr();
if (is_not_array_alloca(l_val)) { if (auto lalloca = is_not_array_alloca(l_val)) {
auto lalloca = dynamic_cast<AllocaInst*>(instr); if (!not_array_allocas.count(lalloca))
not_array_allocas.insert(lalloca); {
allocas_.emplace_back(lalloca); not_array_allocas.insert(lalloca);
allocas_.emplace_back(lalloca);
}
allocas_stored_bbs[lalloca].emplace_back(bb); allocas_stored_bbs[lalloca].emplace_back(bb);
} }
} }
...@@ -105,7 +108,7 @@ void Mem2Reg::generate_phi() { ...@@ -105,7 +108,7 @@ void Mem2Reg::generate_phi() {
if (already_handled.count(bb)) continue; if (already_handled.count(bb)) continue;
already_handled.emplace(bb); already_handled.emplace(bb);
for (auto bb_dominance_frontier_bb : for (auto bb_dominance_frontier_bb :
dominators_->get_dominance_frontier(bb)) { dominators_->get_dominance_frontier(bb)) {
if (bb_has_var_phi.find({bb_dominance_frontier_bb, var}) == if (bb_has_var_phi.find({bb_dominance_frontier_bb, var}) ==
bb_has_var_phi.end()) { bb_has_var_phi.end()) {
// generate phi for bb_dominance_frontier_bb & add // generate phi for bb_dominance_frontier_bb & add
...@@ -115,7 +118,6 @@ void Mem2Reg::generate_phi() { ...@@ -115,7 +118,6 @@ void Mem2Reg::generate_phi() {
bb_dominance_frontier_bb); bb_dominance_frontier_bb);
phi_to_alloca_.emplace(phi, var); phi_to_alloca_.emplace(phi, var);
bb_to_phi_[bb_dominance_frontier_bb].emplace_back(phi); 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); work_list.push_back(bb_dominance_frontier_bb);
bb_has_var_phi.emplace(bb_dominance_frontier_bb, var); bb_has_var_phi.emplace(bb_dominance_frontier_bb, var);
} }
...@@ -128,20 +130,23 @@ void Mem2Reg::rename(BasicBlock *bb) { ...@@ -128,20 +130,23 @@ void Mem2Reg::rename(BasicBlock *bb) {
// 可能用到的数据结构 // 可能用到的数据结构
// list<AllocaInst*> allocas_ 所有 Mem2Reg 需要消除的局部变量,用于遍历 // list<AllocaInst*> allocas_ 所有 Mem2Reg 需要消除的局部变量,用于遍历
// map<AllocaInst*,vector<Value *>> var_val_stack 每个局部变量的存储值栈,还未进行任何操作时已经存进去了 0,不会为空 // map<AllocaInst*,vector<Value *>> var_val_stack 每个局部变量的存储值栈,还未进行任何操作时已经存进去了 0,不会为空
// map<PhiInst *, AllocaInst*>; Phi 对应的局部变量 // map<PhiInst *, AllocaInst*> phi_to_alloca_; Phi 对应的局部变量
// map<BasicBlock*, list<PhiInst*>>; 在某个基本块的 Phi // map<BasicBlock*, list<PhiInst*>> bb_to_phi_; 在某个基本块的 Phi
// 可能用到的函数 // 可能用到的函数
// Value::replace_all_use_with(Value* a) 将所有用到 this 的指令对应 this 的操作数都替换为 a // Value::replace_all_use_with(Value* a) 将所有用到 this 的指令对应 this 的操作数都替换为 a
// BasicBlock::erase_instrs(set<Instruction*>) 移除并 delete 列表中的指令 // BasicBlock::erase_instrs(set<Instruction*>) 移除并 delete 列表中的指令
// StoreInst / LoadInst get_ptr 这些 Inst 所操作的变量
// is_not_array_alloca(Value* ptr) 一个变量是不是 Mem2Reg 所关心的非数组局部变量
// TODO // TODO
// 步骤一:对每个 alloca 非数组变量(局部变量), 在其存储值栈存入其当前的最新值(也就是目前的栈顶值) // 步骤一:对每个 alloca 非数组变量(局部变量), 在其存储值栈存入其当前的最新值(也就是目前的栈顶值)
// 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令 // 步骤二:遍历基本块所有指令,执行操作并记录需要删除的 load/store/alloca 指令(注意: 并非所有 load/store/alloca 都是 Mem2Reg 需要处理的)
// - 步骤三: 将 store 指令存储的值,作为其对应局部变量的最新值(更新栈顶) // - 步骤三: 将 store 指令存储的值,作为其对应局部变量的最新值(更新栈顶)
// - 步骤四: 将 load 指令的所有使用替换为其读取的局部变量的最新值 // - 步骤四: 将 phi 指令的所有使用替换为其对应的局部变量的最新值
// 步骤五:为所有后继块的 phi 添加参数 // - 步骤五: 将 load 指令的所有使用替换为其读取的局部变量的最新值
// 步骤六:对 bb 在支配树上的所有后继节点,递归执行 rename 操作 // 步骤六:为所有后继块的 phi 添加参数
// 步骤七:pop 出所有局部变量的最新值 // 步骤七:对 bb 在支配树上的所有后继节点,递归执行 rename 操作
// 步骤八:删除需要删除的冗余指令 // 步骤八:pop 出所有局部变量的最新值
// 步骤九:删除需要删除的冗余指令
} }
add_executable(
eval_lab4
eval_lab4.cpp
)
install(
TARGETS eval_lab4
)
\ No newline at end of file
// ReSharper disable CppClangTidyPerformanceInefficientStringConcatenation
#include <climits>
#include <complex>
#include <cstdint>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <iterator>
#include <list>
#include <optional>
#include <regex>
#include <string>
#include <unistd.h>
#include <sys/select.h>
#include <sys/wait.h>
using namespace std;
enum evaluate_result : uint8_t { SUCCESS, FAIL, PASS };
static enum stage : uint8_t
{
raw, mem2reg, licm, all
} STAGE;
static string TEST_PATH;
static enum test_type : uint8_t
{
debug, test
} TYPE;
struct cmd_result
{
string out_str;
string err_str;
int ret_val;
bool have_err_message() const
{
return !err_str.empty();
}
};
struct cmd_result_mix
{
string str;
int ret_val;
};
static string red(const string& str) { return "\033[31;1m" + str + "\033[0m"; }
static string green(const string& str) { return "\033[32;1m" + str + "\033[0m"; }
static ofstream ost;
static void ext(int flag)
{
ost.close();
exit(flag);
}
static void out(const string& str, bool to_std)
{
if (to_std) cout << str;
else ost << str;
}
static void out2(const string& str)
{
cout << str;
ost << str;
}
static void out2e(const string& str)
{
cout << red(str);
ost << str;
}
static std::pair<std::string, std::string> readPipeLine(int outpipe[], int errpipe[], int limit)
{
fd_set readfds;
int maxFd = std::max(outpipe[0], errpipe[0]);
char buffer[1024];
std::string stdout_result;
std::string stderr_result;
int totalRead = 0;
bool have_stdout = true;
bool have_stderr = true;
while (true)
{
FD_ZERO(&readfds);
if (have_stdout)
FD_SET(outpipe[0], &readfds);
if (have_stderr)
FD_SET(errpipe[0], &readfds);
int ret = select(maxFd + 1, &readfds, nullptr, nullptr, nullptr);
if (ret == -1)
{
out("select() 调用失败!\n", true);
out("select() 调用失败!\n", false);
ext(-1);
}
if (ret == 0)
continue;
if (FD_ISSET(outpipe[0], &readfds))
{
int bytes = static_cast<int>(read(outpipe[0], buffer, sizeof(buffer) - 1));
if (bytes > 0)
{
int writeLen = std::min(bytes, limit - totalRead);
buffer[writeLen] = '\0';
stdout_result += buffer;
totalRead += writeLen;
if (totalRead >= limit)
break;
}
else
{
FD_CLR(outpipe[0], &readfds);
close(outpipe[0]);
have_stdout = false;
maxFd = have_stderr ? errpipe[0] : -1;
}
}
if (FD_ISSET(errpipe[0], &readfds))
{
int bytes = static_cast<int>(read(errpipe[0], buffer, sizeof(buffer) - 1));
if (bytes > 0)
{
int writeLen = std::min(bytes, limit - totalRead);
buffer[writeLen] = '\0';
stderr_result += buffer;
totalRead += writeLen;
if (totalRead >= limit)
break;
}
else
{
FD_CLR(errpipe[0], &readfds);
close(errpipe[0]);
have_stderr = false;
maxFd = have_stdout ? outpipe[0] : -1;
}
}
if (!FD_ISSET(outpipe[0], &readfds) && !FD_ISSET(errpipe[0], &readfds))
break;
}
if (!stdout_result.empty() && stdout_result.back() != '\n') stdout_result += '\n';
if (!stderr_result.empty() && stderr_result.back() != '\n') stderr_result += '\n';
return {stdout_result, stderr_result};
}
static std::string readPipeLineMix(int outpipe[], int errpipe[], int limit)
{
fd_set readfds;
int maxFd = std::max(outpipe[0], errpipe[0]);
char buffer[1024];
std::string result;
int totalRead = 0;
bool have_stdout = true;
bool have_stderr = true;
while (true)
{
FD_ZERO(&readfds);
if (have_stdout)
FD_SET(outpipe[0], &readfds);
if (have_stderr)
FD_SET(errpipe[0], &readfds);
int ret = select(maxFd + 1, &readfds, nullptr, nullptr, nullptr);
if (ret == -1)
{
out("select() 调用失败!\n", true);
out("select() 调用失败!\n", false);
ext(-1);
}
if (ret == 0)
continue;
if (FD_ISSET(outpipe[0], &readfds))
{
int bytes = static_cast<int>(read(outpipe[0], buffer, sizeof(buffer) - 1));
if (bytes > 0)
{
int writeLen = std::min(bytes, limit - totalRead);
buffer[writeLen] = '\0';
result += buffer;
totalRead += writeLen;
if (totalRead >= limit)
break;
}
else
{
FD_CLR(outpipe[0], &readfds);
close(outpipe[0]);
have_stdout = false;
maxFd = have_stderr ? errpipe[0] : -1;
}
}
if (FD_ISSET(errpipe[0], &readfds))
{
int bytes = static_cast<int>(read(errpipe[0], buffer, sizeof(buffer) - 1));
if (bytes > 0)
{
int writeLen = std::min(bytes, limit - totalRead);
buffer[writeLen] = '\0';
result += buffer;
totalRead += writeLen;
if (totalRead >= limit)
break;
}
else
{
FD_CLR(errpipe[0], &readfds);
close(errpipe[0]);
have_stderr = false;
maxFd = have_stdout ? outpipe[0] : -1;
}
}
if (!FD_ISSET(outpipe[0], &readfds) && !FD_ISSET(errpipe[0], &readfds))
break;
}
if (!result.empty() && result.back() != '\n') result += '\n';
return result;
}
static cmd_result runCommand(const std::string& command, int limit = INT_MAX)
{
int outpipe[2];
int errpipe[2];
if (pipe(outpipe) != 0 || pipe(errpipe) != 0)
{
out2("pipe() 调用失败!\n");
ext(-1);
}
pid_t pid = fork();
if (pid == -1)
{
out2("fork() 调用失败!\n");
ext(-1);
}
if (pid == 0)
{
close(outpipe[0]);
close(errpipe[0]);
dup2(outpipe[1], STDOUT_FILENO);
dup2(errpipe[1], STDERR_FILENO);
execlp("sh", "sh", "-c", command.c_str(), static_cast<char*>(nullptr));
perror("execlp");
ext(127);
}
close(outpipe[1]);
close(errpipe[1]);
auto res = readPipeLine(outpipe, errpipe, limit);
int status;
waitpid(pid, &status, 0);
cmd_result ret;
ret.out_str = res.first;
ret.err_str = res.second;
ret.ret_val = WEXITSTATUS(status);
return ret;
}
static cmd_result_mix runCommandMix(const std::string& command, int limit = INT_MAX)
{
int outpipe[2];
int errpipe[2];
if (pipe(outpipe) != 0 || pipe(errpipe) != 0)
{
out2("pipe() 调用失败!\n");
ext(-1);
}
pid_t pid = fork();
if (pid == -1)
{
out2("fork() 调用失败!\n");
ext(-1);
}
if (pid == 0)
{
close(outpipe[0]);
close(errpipe[0]);
dup2(outpipe[1], STDOUT_FILENO);
dup2(errpipe[1], STDERR_FILENO);
execlp("sh", "sh", "-c", command.c_str(), static_cast<char*>(nullptr));
perror("execlp");
ext(127);
}
close(outpipe[1]);
close(errpipe[1]);
auto res = readPipeLineMix(outpipe, errpipe, limit);
int status;
waitpid(pid, &status, 0);
cmd_result_mix ret;
ret.str = res;
ret.ret_val = WEXITSTATUS(status);
return ret;
}
static list<string> splitString(const string& str)
{
list<string> lines;
std::istringstream stream(str);
std::string line;
while (std::getline(stream, line))
{
if (!line.empty()) lines.push_back(line);
}
return lines;
}
static std::string readFile(const std::string& filename)
{
std::ifstream file(filename);
if (!file.is_open())
{
cerr << "无法打开文件 " + filename << '\n';
ext(-1);
}
std::string content((std::istreambuf_iterator(file)),
std::istreambuf_iterator<char>());
file.close();
return content;
}
static void writeFile(const std::string& content, const std::string& filename)
{
std::ofstream file(filename);
if (!file.is_open())
{
cerr << "无法打开文件 " + filename << '\n';
ext(-1);
}
file << content;
file.close();
}
static string lastDotLeft(const string& str)
{
size_t lastDotPos = str.find_last_of('.');
if (lastDotPos == string::npos)
{
return str;
}
return str.substr(0, lastDotPos);
}
static string lastLineRight(const string& str)
{
size_t lastSlashPos = str.find_last_of('/');
if (lastSlashPos == string::npos)
{
return str;
}
return str.substr(lastSlashPos + 1);
}
static void makeDir(const string& dirPath)
{
if (filesystem::exists(dirPath))
return;
if (!filesystem::create_directories(dirPath))
{
out2("目录 " + dirPath + " 创建失败!\n");
ext(-1);
}
}
static const char* ERR_LOG = R"(Usage: ./eval_lab4.sh [test-stage] [path-to-testcases] [type]
test-stage: 'raw' or 'licm' or 'mem2reg' or 'all'
path-to-testcases: './testcases/functional-cases' or '../testcases_general' or 'self made cases'
type: 'debug' or 'test', debug will output .ll file
)";
static int parseCmd(int argc, char* argv[])
{
if (argc != 4)
{
out(ERR_LOG, true);
return -1;
}
if (std::strcmp(argv[1], "licm") == 0)
{
STAGE = licm;
ost.open("licm_log.txt", ios::out);
}
else if (std::strcmp(argv[1], "mem2reg") == 0)
{
STAGE = mem2reg;
ost.open("mem2reg_log.txt", ios::out);
}
else if (std::strcmp(argv[1], "raw") == 0)
{
STAGE = raw;
ost.open("raw_log.txt", ios::out);
}
else if (std::strcmp(argv[1], "all") == 0)
{
STAGE = all;
ost.open("all_log.txt", ios::out);
}
else
{
out(ERR_LOG, true);
return -1;
}
TEST_PATH = argv[2];
if (TEST_PATH.empty() || TEST_PATH.back() != '/') TEST_PATH += '/';
if (!std::filesystem::exists(TEST_PATH))
{
out2("测评路径 " + TEST_PATH + " 不存在\n");
return -1;
}
if (!std::filesystem::is_directory(TEST_PATH))
{
out2("测评路径 " + TEST_PATH + " 不是文件夹\n");
return -1;
}
if (std::strcmp(argv[3], "debug") == 0)
TYPE = debug;
else if (std::strcmp(argv[3], "test") == 0)
TYPE = test;
else
{
out2(ERR_LOG);
return -1;
}
return 0;
}
static string pad(int count)
{
return count > 0 ? std::string(count, ' ') : std::string();
}
static string pad(int count, char target)
{
return count > 0 ? std::string(count, target) : std::string();
}
static int allmain(int argc, char* argv[])
{
auto cmd = R"(ls )" + TEST_PATH + R"(*.cminus | sort -V)";
auto result = runCommand(cmd);
string flags[3] = {"", "-mem2reg ", "-mem2reg -licm "};
string tys[3] = {"raw", "mem2reg", "licm"};
if (result.have_err_message()) out2e(result.err_str);
auto io_c = runCommand("realpath ../../").out_str;
io_c.pop_back();
io_c += "/src/io/io.c";
auto io_h = io_c;
io_h.back() = 'h';
auto tests = splitString(result.out_str);
string out_path = "./output/";
out2("[info] Start testing, using testcase dir: " + TEST_PATH + "\n");
int maxLen = 0;
for (const auto& line : tests) maxLen = std::max(maxLen, static_cast<int>(line.size()));
for (const auto& line : tests)
{
auto no_path_have_suffix = lastLineRight(line);
auto no_path_no_suffix = lastDotLeft(no_path_have_suffix);
makeDir(out_path + no_path_no_suffix);
auto in_file = TEST_PATH + no_path_no_suffix + ".in";
auto std_out_file = TEST_PATH + no_path_no_suffix + ".out";
out2("==========" + no_path_have_suffix + pad(maxLen - static_cast<int>(line.length()), '=') + "==========\n");
int sz[2] = {};
for (int i = 0; i < 3; i++)
{
const auto& arg = flags[i];
const auto& ty = tys[i];
auto ll_file = out_path + no_path_no_suffix + "/" + ty + ".ll";
auto asm_file = out_path + no_path_no_suffix + "/" + ty + ".s";
auto exe_file = out_path + no_path_no_suffix + "/" + ty + "o";
auto out_file = out_path + no_path_no_suffix + "/" + ty + ".out";
auto eval_file = out_path + no_path_no_suffix + "/eval_" + ty + ".txt";
out(ty + pad(7 - static_cast<int>(ty.length())) + " ", true);
out("==========" + ty + pad(7 - static_cast<int>(ty.length()), '=') + "==========\n",
false);
cout.flush();
ost.flush();
auto cmd2 = runCommandMix("cminusfc -S " + arg + line + " -o " + asm_file);
out(cmd2.str, false);
if (cmd2.ret_val)
{
out2e("CE: cminusfc compiler .cminus error\n");
continue;
}
if (TYPE == debug)
{
cmd2 = runCommandMix(
"loongarch64-unknown-linux-gnu-gcc -g -static " + asm_file + " " + io_c + " -o " + exe_file);
out(cmd2.str, false);
if (cmd2.ret_val)
{
out2e("CE: gcc compiler .s error\n");
continue;
}
}
else
{
cmd2 = runCommandMix(
"loongarch64-unknown-linux-gnu-gcc -static " + asm_file + " " + io_c + " -o " + exe_file);
out(cmd2.str, false);
if (cmd2.ret_val)
{
out2e("CE: gcc compiler .s error\n");
continue;
}
}
cmd_result ret;
if (filesystem::exists(in_file))
ret = runCommand("qemu-loongarch64 " + exe_file + " >" + out_file + " <" + in_file);
else ret = runCommand("qemu-loongarch64 " + exe_file + " >" + out_file);
auto o = readFile(out_file);
writeFile(o + to_string(ret.ret_val) + "\n", out_file);
writeFile(ret.err_str, eval_file);
cmd2 = runCommandMix("diff --strip-trailing-cr " + std_out_file + " " + out_file + " -y");
out(cmd2.str, false);
if (cmd2.ret_val != 0)
{
out2e("WA: output differ, check " + std_out_file + " and " + out_file + "\n");
continue;
}
out(green(" OK"), true);
out("OK\n", false);
auto strs = splitString(ret.err_str);
if (strs.size() >= 6)
{
out(" Take Time (us): " + green(strs.back()) + pad(
sz[0] == 0 ? 1 : (sz[0] - static_cast<int>(strs.back().size()))), true);
out(" Take Time (us): " + strs.back() + pad(
sz[0] == 0 ? 1 : (sz[0] - static_cast<int>(strs.back().size()))), false);
if (sz[0] == 0) sz[0] = static_cast<int>(strs.back().size()) + 1;
strs.pop_back();
strs.pop_back();
out(" Inst Execute Cost: " + green(strs.back()) + pad(sz[1] - static_cast<int>(strs.back().size())),
true);
out(" Inst Execute Cost: " + strs.back() + pad(sz[1] - static_cast<int>(strs.back().size())), false);
if (sz[1] == 0) sz[1] = static_cast<int>(strs.back().size());
strs.pop_back();
strs.pop_back();
out(" Allocate Size (bytes): " + green(strs.back()) + "\n", true);
out(" Allocate Size (bytes): " + strs.back() + "\n", false);
}
else cout << "\n";
filesystem::remove(exe_file);
filesystem::remove(out_file);
filesystem::remove(asm_file);
}
}
return 0;
}
int main(int argc, char* argv[])
{
if (parseCmd(argc, argv)) ext(-1);
if (STAGE == all)
{
return allmain(argc, argv);
}
auto cmd = R"(ls )" + TEST_PATH + R"(*.cminus | sort -V)";
auto result = runCommand(cmd);
string flags = (STAGE == mem2reg ? "-mem2reg " : (STAGE == raw ? "" : "-mem2reg -licm "));
if (result.have_err_message()) out2e(result.err_str);
auto io_c = runCommand("realpath ../../").out_str;
io_c.pop_back();
io_c += "/src/io/io.c";
auto io_h = io_c;
io_h.back() = 'h';
auto tests = splitString(result.out_str);
string out_path = "./output/";
out2("[info] Start testing, using testcase dir: " + TEST_PATH + "\n");
int maxLen = 0;
for (const auto& line : tests) maxLen = std::max(maxLen, static_cast<int>(line.size()));
for (const auto& line : tests)
{
auto no_path_have_suffix = lastLineRight(line);
auto no_path_no_suffix = lastDotLeft(no_path_have_suffix);
makeDir(out_path + no_path_no_suffix);
auto ll_file = out_path + no_path_no_suffix + "/" + argv[1] + ".ll";
auto asm_file = out_path + no_path_no_suffix + "/" + argv[1] + ".s";
auto exe_file = out_path + no_path_no_suffix + "/" + argv[1] + "o";
auto out_file = out_path + no_path_no_suffix + "/" + argv[1] + ".out";
auto eval_file = out_path + no_path_no_suffix + "/eval_" + argv[1] + ".txt";
auto in_file = TEST_PATH + no_path_no_suffix + ".in";
auto std_out_file = TEST_PATH + no_path_no_suffix + ".out";
out(no_path_have_suffix + pad(maxLen - static_cast<int>(line.length())) + " ", true);
out("==========" + no_path_have_suffix + pad(maxLen - static_cast<int>(line.length()), '=') + "==========\n",
false);
cout.flush();
ost.flush();
auto cmd2 = runCommandMix("cminusfc -S " + flags + line + " -o " + asm_file);
out(cmd2.str, false);
if (cmd2.ret_val)
{
out2e("CE: cminusfc compiler .cminus error\n");
continue;
}
if (TYPE == debug)
{
cmd2 = runCommandMix(
"loongarch64-unknown-linux-gnu-gcc -g -static " + asm_file + " " + io_c + " -o " + exe_file);
out(cmd2.str, false);
if (cmd2.ret_val)
{
out2e("CE: gcc compiler .s error\n");
continue;
}
}
else
{
cmd2 = runCommandMix(
"loongarch64-unknown-linux-gnu-gcc -static " + asm_file + " " + io_c + " -o " + exe_file);
out(cmd2.str, false);
if (cmd2.ret_val)
{
out2e("CE: gcc compiler .s error\n");
continue;
}
}
cmd_result ret;
if (filesystem::exists(in_file))
ret = runCommand("qemu-loongarch64 " + exe_file + " >" + out_file + " <" + in_file);
else ret = runCommand("qemu-loongarch64 " + exe_file + " >" + out_file);
auto o = readFile(out_file);
writeFile(o + to_string(ret.ret_val) + "\n", out_file);
writeFile(ret.err_str, eval_file);
cmd2 = runCommandMix("diff --strip-trailing-cr " + std_out_file + " " + out_file + " -y");
out(cmd2.str, false);
if (cmd2.ret_val != 0)
{
out2e("WA: output differ, check " + std_out_file + " and " + out_file + "\n");
continue;
}
out(green(" OK"), true);
out("OK\n", false);
auto strs = splitString(ret.err_str);
if (strs.size() >= 6)
{
out(" Take Time (us): " + green(strs.back()), true);
out(" Take Time (us): " + strs.back(), false);
strs.pop_back();
strs.pop_back();
out(" Inst Execute Cost: " + green(strs.back()), true);
out(" Inst Execute Cost: " + strs.back(), false);
strs.pop_back();
strs.pop_back();
out(" Allocate Size (bytes): " + green(strs.back()) + "\n", true);
out(" Allocate Size (bytes): " + strs.back() + "\n", false);
}
else cout << "\n";
filesystem::remove(exe_file);
filesystem::remove(out_file);
filesystem::remove(asm_file);
}
}
add_subdirectory("2-ir-gen/warmup") # add_subdirectory("2-ir-gen/warmup")
add_subdirectory("3-codegen/warmup") # add_subdirectory("3-codegen/warmup")
\ No newline at end of file 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