Commit 0454682c authored by lxq's avatar lxq

write reg-alloca for int values

parent 3d814ba8
...@@ -111,4 +111,28 @@ op6: <8, 8> ...@@ -111,4 +111,28 @@ op6: <8, 8>
- [Documentations/5-bonus/寄存器分配.md · master · compiler_staff / 2022fall-Compiler_CMinus · GitLab](https://cscourse.ustc.edu.cn/vdir/Gitlab/compiler_staff/2022fall-compiler_cminus/-/blob/master/Documentations/5-bonus/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D.md#poletto) - [Documentations/5-bonus/寄存器分配.md · master · compiler_staff / 2022fall-Compiler_CMinus · GitLab](https://cscourse.ustc.edu.cn/vdir/Gitlab/compiler_staff/2022fall-compiler_cminus/-/blob/master/Documentations/5-bonus/%E5%AF%84%E5%AD%98%E5%99%A8%E5%88%86%E9%85%8D.md#poletto)
i 程序有`$a`系列寄存器8个,`$t`系列9个,拿出`$t0``$t1`做IR生成汇编过程中的临时寄存器(这个方案仅在cminus下成立),所以可以自由分配的寄存器一共15个。
首先完成对于局部变量的寄存器分配,即全局变量、传参依旧通过栈进行。
程序分配寄存器时会对部分指令做特殊处理,具体如下:
- `phi`指令:还原为`copy-stmt`,所以寄存器照样分配,如果没分到使用栈内存
- `alloca`指令:这里忽略对于`alloca`指令的寄存器分配,`alloca`仍然使用栈存储,原因如下:
- 对于int|float的`alloca`,使用寄存器可以正常进行,只需将相关指令`load``store`分别成赋值即可。
- 但是对于数组的`alloca`,使用寄存器就很难模拟了。
即寄存器不能完成`alloca`的内存逻辑,同时经过`mem2reg`优化过后,不再有局部变量的声明,所以忽略对于`alloca`指令的寄存器分配。
- `cmp``fcmp``zext`指令:不做寄存器分配,也不做栈分配。
这实际是指令选择部分的内容:
因为在cminus中并没有bool变量,这些IR指令用到的i1类型都是临时的:只为分支指令服务,所以直接将这些指令集成到分支跳转的判断中。
- `call`指令:使用栈传参,caller保存自己用到的寄存器,被保存的寄存器的活跃区间覆盖`call`指令的程序点。
...@@ -9,15 +9,17 @@ ...@@ -9,15 +9,17 @@
#include "Module.h" #include "Module.h"
#include "Value.h" #include "Value.h"
#include "liverange.hpp" #include "liverange.hpp"
#include "logging.hpp" #include "regalloc.hpp"
#define __RO_PART__ #define __RO_PART__
// #a = 8, #t = 9, reserve $t0, $t1 for temporary
#define R_USABLE 17 - 2
#include <map> #include <map>
#include <ostream> #include <ostream>
#include <vector> #include <vector>
#define ALIGN(x, align) (((x / align) + (x % align ? 1 : 0)) * align) #define ALIGN(x, align) ((((x) / align) + (((x) % align) ? 1 : 0)) * align)
// #define STACK_ALIGN(x) (((x / 16) + (x % 16 ? 1 : 0)) * 16) // #define STACK_ALIGN(x) (((x / 16) + (x % 16 ? 1 : 0)) * 16)
#define STACK_ALIGN(x) ALIGN(x, 16) #define STACK_ALIGN(x) ALIGN(x, 16)
...@@ -27,7 +29,7 @@ using std::vector; ...@@ -27,7 +29,7 @@ using std::vector;
class CodeGen { class CodeGen {
public: public:
CodeGen(Module *m_) : m(m_), LRA(m_, phi_map) {} CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE) {}
string print() { string print() {
string result; string result;
...@@ -42,35 +44,41 @@ class CodeGen { ...@@ -42,35 +44,41 @@ class CodeGen {
void run(); void run();
private: private:
void IR2assem(Instruction &, BasicBlock &); //
void IR2assem(LoadInst *); // data member
void IR2assem(StoreInst *); //
void IR2assem(ReturnInst *); std::map<Value *, unsigned int> off; // stack offset to $fp
void IR2assem(GetElementPtrInst *); std::map<Function *, std::map<int, int>> func_arg_off; // to $sp
void IR2assem(CallInst *); // total space for args, NOTE: not aligned
void IR2assem(BranchInst *); std::map<Function *, int> func_arg_N;
void IR2assem(BinaryInst *); std::map<BasicBlock *, std::vector<std::pair<Value *, Value *>>> phi_map;
void IR2assem(FpToSiInst *); std::map<Constant *, std::string> ROdata;
void IR2assem(SiToFpInst *); unsigned int stackN; // function local vars and so on
void IR2assem(PhiInst *) {}
// The Instructions below will do nothing
void IR2assem(AllocaInst *) {}
// integration with BranchInst
void IR2assem(CmpInst *) {}
void IR2assem(FCmpInst *) {}
void IR2assem(ZextInst *) {}
Function *cur_func;
Module *m;
vector<string> output;
// register allocation
LRA::LiveRangeAnalyzer LRA;
RA::RegAllocator RA;
// some instruction has lvalue, but is stack-allocated,
// we need this variable to track the reg name which has rvalue.
// this variable is maintain by gencopy() and LoadInst.
string last_reg;
//
// function member
//
void stackMemAlloc(); void stackMemAlloc();
void stackMemDealloc(); void stackMemDealloc();
// load value `opk` to the specified register // In the case of register allocation, this function will return the
// - for constant number, just load into reg // allocated register for that value, if the value possesses no register,
// - for global variables and pointers from alloca and GEP, read through // choose from from $t0 or $t1 based on id
// address
// only use register a_id and t_ __attribute__((warn_unused_result)) string value2reg(Value *, int i = 0);
void value2reg(Value *, int id = 0);
// load the content in ptr to specified register. // load the content in ptr to specified register.
// only use register a_id and t_ void ptrContent2reg(Value *, string);
void ptrContent2reg(Value *, int id = 0);
void compute_arg_info(Function *); void compute_arg_info(Function *);
string bool2branch(Instruction *); string bool2branch(Instruction *);
void getPhiMap(); void getPhiMap();
...@@ -80,15 +88,35 @@ class CodeGen { ...@@ -80,15 +88,35 @@ class CodeGen {
output.push_back("# " + print_as_op(copy.first, false) + " = " + output.push_back("# " + print_as_op(copy.first, false) + " = " +
print_as_op(copy.second, false)); print_as_op(copy.second, false));
auto lvalue = static_cast<Instruction *>(copy.first); auto lvalue = static_cast<Instruction *>(copy.first);
value2reg(copy.second); auto src_reg = value2reg(copy.second);
if (gencopy(lvalue, src_reg) == false)
back2stack(lvalue); back2stack(lvalue);
} }
} }
string label_in_assem(BasicBlock *bb) { // if reg-allocation, store to the specific register
// or is stack-allocation, set last_reg for back2stack()
bool gencopy(Value *lhs, string rhs_reg) {
auto [lhs_reg, find] = getRegName(lhs);
if (not find) {
// wait for back2stack() to store back
last_reg = rhs_reg;
return false;
}
auto is_float = lhs->get_type()->is_float_type();
if (rhs_reg != lhs_reg) {
if (is_float)
output.push_back("fmov.s " + lhs_reg + ", " + rhs_reg);
else
output.push_back("or " + lhs_reg + ", $zero, " + rhs_reg);
}
return true;
}
string label_in_assem(BasicBlock *bb) const {
return cur_func->get_name() + bb->get_name().substr(5); return cur_func->get_name() + bb->get_name().substr(5);
} }
int typeLen(Type *type) { int typeLen(Type *type) const {
if (type->is_float_type()) if (type->is_float_type())
return 4; return 4;
else if (type->is_integer_type()) { else if (type->is_integer_type()) {
...@@ -107,19 +135,19 @@ class CodeGen { ...@@ -107,19 +135,19 @@ class CodeGen {
} }
} }
// assert the value needed to store back is in $a0 or $f0, according to the // assert the value needed to store back is in `last_reg`, according to the
// value type // value type
void back2stack(Instruction *instr) { void back2stack(Instruction *instr) {
// std::cerr << instr->print() << std::endl; // std::cerr << instr->print() << std::endl;
auto type = instr->get_type(); auto type = instr->get_type();
string instr_ir = type->is_float_type() ? "fst" : "st"; string instr_ir = type->is_float_type() ? "fst" : "st";
string suff = suffix(type); string suff = suffix(type);
string reg = type->is_float_type() ? "$fa0" : "$a0"; // string reg = type->is_float_type() ? "$fa0" : "$a0";
string addr = "$fp, -" + std::to_string(off[instr]); string addr = "$fp, -" + std::to_string(off.at(instr));
output.push_back(instr_ir + suff + " " + reg + ", " + addr); output.push_back(instr_ir + suff + " " + last_reg + ", " + addr);
} }
string suffix(Type *type) { string suffix(Type *type) const {
int len = typeLen(type); int len = typeLen(type);
switch (len) { switch (len) {
case 1: case 1:
...@@ -134,29 +162,53 @@ class CodeGen { ...@@ -134,29 +162,53 @@ class CodeGen {
assert(false && "no such suffix"); assert(false && "no such suffix");
} }
bool no_stack_alloca(Instruction *instr) { bool no_stack_alloca(Instruction *instr) const {
if (instr->is_void()) if (instr->is_void())
return true; return true;
if (instr->is_fcmp() or instr->is_cmp() or instr->is_zext()) if (instr->is_fcmp() or instr->is_cmp() or instr->is_zext())
return true; return true;
if (RA.get().find(instr) != RA.get().end())
return true;
return false; return false;
} }
string tmpregname(int i, bool is_float) const {
assert(i == 0 or i == 1);
return (is_float ? "$ft" : "$t") + to_string(i);
}
std::map<Value *, unsigned int> off; // stack offset to $fp static string regname(int i, bool is_float = false) {
std::map<Function *, std::map<int, int>> func_arg_off; // to $sp string name;
std::map<Function *, int> func_arg_N; // total space for args if (is_float) {
std::map<BasicBlock *, std::vector<std::pair<Value *, Value *>>> phi_map; assert(false && "not implemented!");
std::map<Constant *, std::string> ROdata; } else {
unsigned int stackN; // function local vars and so on if (1 <= i and i <= 8)
name = "$a" + to_string(i - 1);
Function *cur_func; else if (9 <= i and i <= R_USABLE)
name = "$t" + to_string(i - 9 + 2);
}
return name;
}
Module *m; pair<string, bool> getRegName(Value *, int = 0) const;
vector<string> output;
// register allocation void IR2assem(Instruction &, BasicBlock &);
LRA::LiveRangeAnalyzer LRA; void IR2assem(LoadInst *);
void IR2assem(StoreInst *);
void IR2assem(ReturnInst *);
void IR2assem(GetElementPtrInst *);
void IR2assem(CallInst *);
void IR2assem(BranchInst *);
void IR2assem(BinaryInst *);
void IR2assem(FpToSiInst *);
void IR2assem(SiToFpInst *);
void IR2assem(PhiInst *) {}
// The Instructions below will do nothing
void IR2assem(AllocaInst *) {}
// integration with BranchInst
void IR2assem(CmpInst *) {}
void IR2assem(FCmpInst *) {}
void IR2assem(ZextInst *) {}
}; };
#endif #endif
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define LIVERANGE_HPP #define LIVERANGE_HPP
#include "Module.h" #include "Module.h"
#include "Value.h"
#include <iostream> #include <iostream>
#include <map> #include <map>
...@@ -27,7 +28,6 @@ struct Interval { ...@@ -27,7 +28,6 @@ struct Interval {
using LiveSet = set<Value *>; using LiveSet = set<Value *>;
using PhiMap = map<BasicBlock *, vector<pair<Value *, Value *>>>; using PhiMap = map<BasicBlock *, vector<pair<Value *, Value *>>>;
using LiveInterval = pair<Interval, Value *>; using LiveInterval = pair<Interval, Value *>;
struct LiveIntervalCMP { struct LiveIntervalCMP {
bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const { bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const {
if (lhs.first.i != rhs.first.i) if (lhs.first.i != rhs.first.i)
...@@ -36,29 +36,31 @@ struct LiveIntervalCMP { ...@@ -36,29 +36,31 @@ struct LiveIntervalCMP {
return lhs.second < rhs.second; return lhs.second < rhs.second;
} }
}; };
using LVITS = set<LiveInterval, LiveIntervalCMP>;
class LiveRangeAnalyzer { class LiveRangeAnalyzer {
public:
friend class CodeGen; friend class CodeGen;
public:
LiveRangeAnalyzer(Module *m_, PhiMap &phi_map_) LiveRangeAnalyzer(Module *m_, PhiMap &phi_map_)
: m(m_), phi_map(phi_map_) {} : m(m_), phi_map(phi_map_) {}
LiveRangeAnalyzer() = delete; LiveRangeAnalyzer() = delete;
void run(); // void run();
void run(Function *); void run(Function *);
void clear(); void clear();
void print(Function *func, bool printSet = true); void print(Function *func, bool printSet = true) const;
string print_liveSet(const LiveSet &ls) { string print_liveSet(const LiveSet &ls) const {
string s = "[ "; string s = "[ ";
for (auto k : ls) for (auto k : ls)
s += k->get_name() + " "; s += k->get_name() + " ";
s += "]"; s += "]";
return s; return s;
} }
string print_interval(Interval &i) { string print_interval(Interval &i) const {
return "<" + to_string(i.i) + ", " + to_string(i.j) + ">"; return "<" + to_string(i.i) + ", " + to_string(i.j) + ">";
} }
const LVITS &get() { return liveIntervals; }
private: private:
Module *m; Module *m;
...@@ -68,7 +70,8 @@ class LiveRangeAnalyzer { ...@@ -68,7 +70,8 @@ class LiveRangeAnalyzer {
map<Value *, int> instr_id; map<Value *, int> instr_id;
map<pair<Value *, Value *>, int> cpstmt_id; map<pair<Value *, Value *>, int> cpstmt_id;
const PhiMap &phi_map; const PhiMap &phi_map;
set<LiveInterval, LiveIntervalCMP> liveIntervals; LVITS liveIntervals;
map<Value *, Interval> intervalmap;
void make_id(Function *); void make_id(Function *);
void make_interval(Function *); void make_interval(Function *);
...@@ -86,6 +89,10 @@ class LiveRangeAnalyzer { ...@@ -86,6 +89,10 @@ class LiveRangeAnalyzer {
// Require: out-set is already set // Require: out-set is already set
// Return: the in-set(will not set IN-map) // Return: the in-set(will not set IN-map)
LiveSet transferFunction(Instruction *); LiveSet transferFunction(Instruction *);
public:
const decltype(instr_id) &get_instr_id() { return instr_id; }
const decltype(intervalmap) &get_interval_map() { return intervalmap; }
}; };
} // namespace LRA } // namespace LRA
#endif #endif
#include "Value.h"
#include "liverange.hpp" #include "liverange.hpp"
// using std::transform; #include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::to_string;
using namespace LRA; using namespace LRA;
namespace RA { namespace RA {
#define MAXR 32 #define MAXR 32
bool no_reg_alloca(Value *v);
struct ActiveCMP { struct ActiveCMP {
bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const { bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const {
if (lhs.first.j != rhs.first.j) if (lhs.first.j != rhs.first.j)
...@@ -18,15 +27,20 @@ struct ActiveCMP { ...@@ -18,15 +27,20 @@ struct ActiveCMP {
class RegAllocator { class RegAllocator {
public: public:
RegAllocator(const uint R_) : R(R_), used{false} {} RegAllocator(const uint R_) : R(R_), used{false} { assert(R <= MAXR); }
RegAllocator() = delete; RegAllocator() = delete;
// input set is sorted by increasing start point // input set is sorted by increasing start point
void LinearScan(set<LiveInterval> &liveints); void LinearScan(const LVITS &liveints);
void reset(); void reset();
const map<Value *, int> &get() const { return regmap; }
void print(string (*regname)(int)) {
for (auto [op, reg] : regmap)
cout << op->get_name() << " ~ " << regname(reg) << endl;
}
private: private:
const uint R; const uint R;
bool used[MAXR]; bool used[MAXR + 1]; // index range: 1 ~ R
map<Value *, int> regmap; map<Value *, int> regmap;
// sorted by increasing end point // sorted by increasing end point
set<LiveInterval, ActiveCMP> active; set<LiveInterval, ActiveCMP> active;
......
// 局部变量究竟保存在哪里?
// alloca会返回一个指针,这个指针指向一块可用的内存区域
// 这个该如何体现在assemb上?
// NOTE: 参数类型需要额外考虑!
#include "codegen.hpp" #include "codegen.hpp"
#include "BasicBlock.h" #include "BasicBlock.h"
...@@ -21,6 +15,7 @@ ...@@ -21,6 +15,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <sys/types.h> #include <sys/types.h>
#include <tuple>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -37,30 +32,23 @@ ...@@ -37,30 +32,23 @@
using std::to_string; using std::to_string;
class Reg { pair<string, bool>
public: CodeGen::getRegName(Value *v, int i) const {
Reg(int index) : id(index) {} assert(i == 0 or i == 1);
bool find;
int id; string name;
bool is_float = v->get_type()->is_float_type();
string print() { auto regmap = RA.get();
if (id == 0) if (regmap.find(v) == regmap.end()) {
return "$zero"; name = tmpregname(i, is_float);
if (id == 1) find = false;
return "$ra"; } else {
if (id == 2) auto regid = regmap.find(v)->second;
return "$tp"; name = regname(regid, is_float);
if (id == 3) find = true;
return "$sp";
if (4 <= id and id <= 11)
return "$a" + to_string(id - 4);
if (12 <= id and id <= 20)
return "$t" + to_string(id - 12);
if (id == 22)
return "$fp";
assert(false);
} }
}; return {name, find};
}
void void
CodeGen::getPhiMap() { CodeGen::getPhiMap() {
...@@ -95,12 +83,25 @@ CodeGen::run() { ...@@ -95,12 +83,25 @@ CodeGen::run() {
} }
// arguments: stack transfer // arguments: stack transfer
for (auto &func : m->get_functions()) for (auto &func : m->get_functions())
if (not func.is_declaration()) // if (not func.is_declaration())
compute_arg_info(&func); compute_arg_info(&func);
// funtions // funtions
for (auto &func : m->get_functions()) { for (auto &func : m->get_functions()) {
if (not func.is_declaration()) { if (not func.is_declaration()) {
LRA.run(&func); LRA.run(&func);
RA.LinearScan(LRA.get());
std::cout << "register map for function: " << func.get_name()
<< std::endl;
RA.print([](int i) { return regname(i); });
auto regmap = RA.get();
for (auto [_, op] : LRA.get()) {
if (regmap.find(op) == regmap.end())
std::cout << "no reg belongs to " << op->get_name()
<< std::endl;
}
cur_func = &func; cur_func = &func;
output.push_back(""); output.push_back("");
output.push_back(".globl " + func.get_name()); output.push_back(".globl " + func.get_name());
...@@ -140,37 +141,49 @@ CodeGen::run() { ...@@ -140,37 +141,49 @@ CodeGen::run() {
} }
void void
CodeGen::ptrContent2reg(Value *ptr, int id) { CodeGen::ptrContent2reg(Value *ptr, string reg_name) {
auto ele_tp = ptr->get_type()->get_pointer_element_type(); auto ele_tp = ptr->get_type()->get_pointer_element_type();
assert(ele_tp); assert(ele_tp);
bool is_float = ele_tp->is_float_type(); bool is_float = ele_tp->is_float_type();
string instr_ir = (is_float ? "fld" : "ld"); string instr_ir = (is_float ? "fld" : "ld");
string reg_name = (is_float ? "$fa" : "$a") + to_string(id);
string suff = suffix(ele_tp); string suff = suffix(ele_tp);
auto [addr_reg, find] = getRegName(ptr, 1);
if (not find)
addr_reg = "$t1";
if (dynamic_cast<GlobalVariable *>(ptr)) { if (dynamic_cast<GlobalVariable *>(ptr)) {
output.push_back("la.local " + reg_name + ", " + ptr->get_name()); output.push_back("la.local " + addr_reg + ", " + ptr->get_name());
output.push_back(instr_ir + suff + " " + reg_name + ", " + reg_name + output.push_back(instr_ir + suff + " " + reg_name + ", " + addr_reg +
", 0"); ", 0");
} else if (dynamic_cast<AllocaInst *>(ptr)) { } else if (dynamic_cast<AllocaInst *>(ptr)) {
/* auto alloc_instr = static_cast<AllocaInst *>(ptr); /* auto alloc_instr = static_cast<AllocaInst *>(ptr);
* string suff = suffix(alloc_instr->get_alloca_type()); */ * string suff = suffix(alloc_instr->get_alloca_type()); */
output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" + output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" +
to_string(off[ptr])); to_string(off.at(ptr)));
} else if (dynamic_cast<GetElementPtrInst *>(ptr)) { } else if (dynamic_cast<GetElementPtrInst *>(ptr)) {
// auto GEP_instr = static_cast<GetElementPtrInst *>(ptr); // auto GEP_instr = static_cast<GetElementPtrInst *>(ptr);
output.push_back("ld.d " + reg_name + ", $fp, -" + to_string(off[ptr])); if (not find) {
output.push_back(instr_ir + suff + " " + reg_name + ", " + reg_name + output.push_back("ld.d " + addr_reg + ", $fp, -" +
to_string(off.at(ptr)));
}
output.push_back(instr_ir + suff + " " + reg_name + ", " + addr_reg +
", 0"); ", 0");
} else } else
assert(false && "unknown type"); assert(false && "unknown type");
} }
void string
CodeGen::value2reg(Value *v, int id) { CodeGen::value2reg(Value *v, int i) {
bool is_float = v->get_type()->is_float_type(); bool is_float = v->get_type()->is_float_type();
auto reg_name = (is_float ? "$fa" : "$a") + to_string(id); string tmp_ireg = "$t" + to_string(i);
string tmp_ireg = "$t0"; auto [reg_name, find] = getRegName(v, i);
if (find)
return reg_name;
// now is the stack allocation case
if (dynamic_cast<Constant *>(v)) { if (dynamic_cast<Constant *>(v)) {
if (v == ConstantInt::get(0, m))
return "$zero";
auto constant = static_cast<Constant *>(v); auto constant = static_cast<Constant *>(v);
#ifdef __RO_PART__ #ifdef __RO_PART__
if (ROdata.find(constant) == ROdata.end()) if (ROdata.find(constant) == ROdata.end())
...@@ -182,6 +195,7 @@ CodeGen::value2reg(Value *v, int id) { ...@@ -182,6 +195,7 @@ CodeGen::value2reg(Value *v, int id) {
instr_ir = "fld.s"; instr_ir = "fld.s";
else else
assert(false && "wait for completion"); assert(false && "wait for completion");
// bug here: maybe
output.push_back("la.local " + tmp_ireg + ", " + addr); output.push_back("la.local " + tmp_ireg + ", " + addr);
output.push_back(instr_ir + " " + reg_name + ", " + tmp_ireg + ", 0"); output.push_back(instr_ir + " " + reg_name + ", " + tmp_ireg + ", 0");
#else #else
...@@ -217,7 +231,8 @@ CodeGen::value2reg(Value *v, int id) { ...@@ -217,7 +231,8 @@ CodeGen::value2reg(Value *v, int id) {
} else if (dynamic_cast<AllocaInst *>(v)) { } else if (dynamic_cast<AllocaInst *>(v)) {
// auto alloc_instr = dynamic_cast<AllocaInst *>(v); // auto alloc_instr = dynamic_cast<AllocaInst *>(v);
// give the stack address // give the stack address
output.push_back("addi.d " + reg_name + ", $fp, -" + to_string(off[v])); output.push_back("addi.d " + reg_name + ", $fp, -" +
to_string(off.at(v)));
} else if (dynamic_cast<Argument *>(v)) { } else if (dynamic_cast<Argument *>(v)) {
auto args = cur_func->get_args(); auto args = cur_func->get_args();
int id = 1; int id = 1;
...@@ -226,12 +241,14 @@ CodeGen::value2reg(Value *v, int id) { ...@@ -226,12 +241,14 @@ CodeGen::value2reg(Value *v, int id) {
break; break;
string instr_ir = is_float ? "fld" : "ld"; string instr_ir = is_float ? "fld" : "ld";
output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name + output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
", $fp, " + to_string(func_arg_off[cur_func][id])); ", $fp, " +
to_string(func_arg_off.at(cur_func).at(id)));
} else { } else {
string instr_ir = is_float ? "fld" : "ld"; string instr_ir = is_float ? "fld" : "ld";
output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name + output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
", $fp, -" + to_string(off[v])); ", $fp, -" + to_string(off.at(v)));
} }
return reg_name;
} }
void void
...@@ -250,20 +267,7 @@ CodeGen::compute_arg_info(Function *func) { ...@@ -250,20 +267,7 @@ CodeGen::compute_arg_info(Function *func) {
} }
for (arg_id = 1; arg_id <= func->get_num_of_args(); ++arg_id) for (arg_id = 1; arg_id <= func->get_num_of_args(); ++arg_id)
arg_off[arg_id] = argN - arg_off[arg_id]; arg_off[arg_id] = argN - arg_off[arg_id];
func_arg_N[func] = STACK_ALIGN(argN); func_arg_N[func] = argN;
}
void
CodeGen::stackMemDealloc() {
// 7: return value should be determined already!
output.push_back(cur_func->get_name() + "_end:");
output.push_back("# epilog");
output.push_back("ld.d $ra, $sp, " + to_string(stackN - 8));
output.push_back("ld.d $fp, $sp, " + to_string(stackN - 16));
/* output.push_back("ld.d $ra, $fp, -8");
* output.push_back("ld.d $fp, $fp, -16"); */
output.push_back("addi.d $sp, $sp, " + to_string(stackN));
output.push_back("jr $ra");
} }
// the addr for opk is: fp - off[opk] // the addr for opk is: fp - off[opk]
...@@ -294,20 +298,39 @@ CodeGen::stackMemAlloc() { ...@@ -294,20 +298,39 @@ CodeGen::stackMemAlloc() {
output.push_back("st.d $fp, $sp, " + to_string(stackN - 16)); output.push_back("st.d $fp, $sp, " + to_string(stackN - 16));
output.push_back("addi.d $fp, $sp, " + to_string(stackN)); output.push_back("addi.d $fp, $sp, " + to_string(stackN));
} }
void
CodeGen::stackMemDealloc() {
// 7: return value should be determined already!
output.push_back(cur_func->get_name() + "_end:");
output.push_back("# epilog");
output.push_back("ld.d $ra, $sp, " + to_string(stackN - 8));
output.push_back("ld.d $fp, $sp, " + to_string(stackN - 16));
/* output.push_back("ld.d $ra, $fp, -8");
* output.push_back("ld.d $fp, $fp, -16"); */
output.push_back("addi.d $sp, $sp, " + to_string(stackN));
output.push_back("jr $ra");
}
void void
CodeGen::IR2assem(FpToSiInst *instr) { CodeGen::IR2assem(FpToSiInst *instr) {
assert(instr->get_operand(0)->get_type() == m->get_float_type()); assert(instr->get_operand(0)->get_type() == m->get_float_type());
assert(instr->get_dest_type() == m->get_int32_type()); assert(instr->get_dest_type() == m->get_int32_type());
value2reg(instr->get_operand(0)); string f_reg = value2reg(instr->get_operand(0));
output.push_back("ftintrz.w.s $fa0, $fa0"); auto [i_reg, _] = getRegName(instr);
output.push_back("movfr2gr.s $a0, $fa0"); output.push_back("ftintrz.w.s " + f_reg + ", " + f_reg);
output.push_back("movfr2gr.s " + i_reg + ", " + f_reg);
gencopy(instr, i_reg);
} }
void void
CodeGen::IR2assem(SiToFpInst *instr) { CodeGen::IR2assem(SiToFpInst *instr) {
assert(instr->get_operand(0)->get_type() == m->get_int32_type()); assert(instr->get_operand(0)->get_type() == m->get_int32_type());
assert(instr->get_dest_type() == m->get_float_type()); assert(instr->get_dest_type() == m->get_float_type());
output.push_back("movgr2fr.w $fa0, $a0"); string i_reg = value2reg(instr->get_operand(0));
output.push_back("ffint.s.w $fa0, $fa0"); auto [f_reg, _] = getRegName(instr);
output.push_back("movgr2fr.w " + f_reg + ", " + i_reg);
output.push_back("ffint.s.w " + f_reg + ", " + f_reg);
gencopy(instr, f_reg);
} }
string string
...@@ -355,10 +378,12 @@ CodeGen::bool2branch(Instruction *instr) { ...@@ -355,10 +378,12 @@ CodeGen::bool2branch(Instruction *instr) {
reverse = true; reverse = true;
break; break;
} }
value2reg(instr->get_operand(0), 0); auto reg1 = value2reg(instr->get_operand(0), 0);
value2reg(instr->get_operand(1), 1); auto reg2 = value2reg(instr->get_operand(1), 1);
return instr_ir + (reverse ? " $a1, $a0," : " $a0, $a1,"); return instr_ir + " " +
(reverse ? (reg2 + ", " + reg1) : (reg1 + ", " + reg2)) + ",";
} else { } else {
assert(false && "not implemented");
switch (fcmp_instr->get_cmp_op()) { switch (fcmp_instr->get_cmp_op()) {
case FCmpInst::EQ: case FCmpInst::EQ:
instr_ir = "fcmp.ceq.s $fcc0"; instr_ir = "fcmp.ceq.s $fcc0";
...@@ -381,9 +406,9 @@ CodeGen::bool2branch(Instruction *instr) { ...@@ -381,9 +406,9 @@ CodeGen::bool2branch(Instruction *instr) {
instr_ir = "fcmp.cle.s $fcc0"; instr_ir = "fcmp.cle.s $fcc0";
break; break;
} }
value2reg(instr->get_operand(0), 0); auto reg1 = value2reg(instr->get_operand(0), 0);
value2reg(instr->get_operand(1), 1); auto reg2 = value2reg(instr->get_operand(1), 1);
output.push_back(instr_ir + ", " + "$fa0, $fa1"); output.push_back(instr_ir + ", " + reg1 + ", " + reg2);
return (reverse ? "bceqz $fcc0," : "bcnez $fcc0,"); return (reverse ? "bceqz $fcc0," : "bcnez $fcc0,");
} }
} }
...@@ -407,42 +432,79 @@ CodeGen::IR2assem(BranchInst *instr) { ...@@ -407,42 +432,79 @@ CodeGen::IR2assem(BranchInst *instr) {
void void
CodeGen::IR2assem(CallInst *instr) { CodeGen::IR2assem(CallInst *instr) {
auto func = static_cast<Function *>(instr->get_operand(0)); auto func = static_cast<Function *>(instr->get_operand(0));
auto func_argN = func_arg_N.at(func);
// analyze the registers that need to be stored
int cur_i = LRA.get_instr_id().at(instr);
auto regmap = RA.get();
//
int storeN = 0;
vector<std::tuple<Value *, string, int>> store_record;
for (auto [op, interval] : LRA.get_interval_map()) {
if (RA::no_reg_alloca(op))
continue;
if (interval.i <= cur_i and cur_i <= interval.j) {
int tplen = typeLen(op->get_type());
storeN = ALIGN(storeN, tplen) + tplen;
auto name = regname(regmap.at(op), op->get_type()->is_float_type());
store_record.push_back({op, name, storeN});
}
}
int totalN = STACK_ALIGN(ALIGN(storeN, 8) + func_argN);
// cout << "debug: " << STACK_ALIGN(12) << endl;
// stack space allocation // stack space allocation
output.push_back("addi.d $sp, $sp, -" + to_string(func_arg_N[func])); output.push_back("addi.d $sp, $sp, -" + to_string(totalN));
string instr_ir, suff, reg; string instr_ir, suff, reg;
// place the reserved regs
for (auto [op, reg, off] : store_record) {
instr_ir = (op->get_type()->is_float_type() ? "fst" : "st");
suff = suffix(op->get_type());
output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(totalN - off));
}
// place the arguments // place the arguments
for (int i = 1; i < instr->get_num_operand(); i++) { for (int i = 1; i < instr->get_num_operand(); i++) {
auto arg = instr->get_operand(i); auto arg = instr->get_operand(i);
// auto tplen = typeLen(arg->get_type()); // auto tplen = typeLen(arg->get_type());
instr_ir = (arg->get_type()->is_float_type() ? "fst" : "st"); instr_ir = (arg->get_type()->is_float_type() ? "fst" : "st");
suff = suffix(arg->get_type()); suff = suffix(arg->get_type());
reg = (arg->get_type()->is_float_type() ? "$fa0" : "$a0"); reg = value2reg(arg);
value2reg(arg);
output.push_back(instr_ir + suff + " " + reg + ", $sp, " + output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(func_arg_off[func][i])); to_string(func_arg_off.at(func).at(i)));
} }
output.push_back("bl " + func->get_name()); output.push_back("bl " + func->get_name());
output.push_back("addi.d $sp, $sp, " + to_string(func_arg_N[func])); // bug here: maybe
gencopy(instr, instr->get_type()->is_float_type() ? "$fa0" : "$a0");
// restore the reserved regs
for (auto [op, reg, off] : store_record) {
instr_ir = (op->get_type()->is_float_type() ? "fld" : "ld");
suff = suffix(op->get_type());
output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(totalN - off));
}
output.push_back("addi.d $sp, $sp, " + to_string(totalN));
// output.push_back("addi.d $fp, $sp, " + to_string(stackN)); // output.push_back("addi.d $fp, $sp, " + to_string(stackN));
} }
void void
CodeGen::IR2assem(BinaryInst *instr) { CodeGen::IR2assem(BinaryInst *instr) {
auto is_float = instr->get_type()->is_float_type(); auto reg1 = value2reg(instr->get_operand(0), 0);
value2reg(instr->get_operand(0), 0); auto reg2 = value2reg(instr->get_operand(1), 1);
value2reg(instr->get_operand(1), 1); auto [reg, _] = getRegName(instr);
string instr_ir = instr->get_instr_op_name(); string instr_ir = instr->get_instr_op_name();
if (instr_ir == "sdiv") if (instr_ir == "sdiv")
instr_ir = "div"; instr_ir = "div";
string suff = suffix(instr->get_type()); string suff = suffix(instr->get_type());
output.push_back(instr_ir + suff + output.push_back(instr_ir + suff + " " + reg + ", " + reg1 + ", " + reg2);
(is_float ? " $fa0, $fa0, $fa1" : " $a0, $a0, $a1")); gencopy(instr, reg);
} }
void void
CodeGen::IR2assem(GetElementPtrInst *instr) { CodeGen::IR2assem(GetElementPtrInst *instr) {
value2reg(instr->get_operand(0), 0); assert(instr->get_num_operand() <= 3);
auto addr_reg = value2reg(instr->get_operand(0), 0);
assert(addr_reg == "$t0");
Type *type = instr->get_operand(0)->get_type(); Type *type = instr->get_operand(0)->get_type();
for (int i = 1; i < instr->get_num_operand(); i++) { for (int i = 1; i < instr->get_num_operand(); i++) {
int size; int size;
...@@ -454,38 +516,52 @@ CodeGen::IR2assem(GetElementPtrInst *instr) { ...@@ -454,38 +516,52 @@ CodeGen::IR2assem(GetElementPtrInst *instr) {
type = type->get_pointer_element_type(); type = type->get_pointer_element_type();
} else } else
assert(false && "GEP translation error"); assert(false && "GEP translation error");
value2reg(instr->get_operand(i), 1); if (size != 4) {
value2reg(ConstantInt::get(size, m), 2); // getelementptr [5 x i32], [5 x i32]* @w, i32 0, i32 4
output.push_back("mul.w $a1, $a1, $a2"); assert(instr->get_operand(i) == ConstantInt::get(0, m) &&
output.push_back("add.d $a0, $a0, $a1"); "cminus support only 1 dimension array, so first offset is "
"must 0");
continue;
} }
auto off_reg = value2reg(instr->get_operand(i), 1);
// value2reg(ConstantInt::get(size, m), 2);
output.push_back("slli.d " + off_reg + ", " + off_reg + ", 2");
output.push_back("add.d " + addr_reg + ", " + addr_reg + ", " +
off_reg);
}
gencopy(instr, addr_reg);
} }
void void
CodeGen::IR2assem(LoadInst *instr) { CodeGen::IR2assem(LoadInst *instr) {
// move the address to a0 auto [reg, find] = getRegName(instr);
ptrContent2reg(instr->get_lval()); ptrContent2reg(instr->get_lval(), reg);
if (not find) // this if is just for logically clear
assert(instr->get_type() == instr->get_load_type()); last_reg = reg;
} }
void void
CodeGen::IR2assem(StoreInst *instr) { CodeGen::IR2assem(StoreInst *instr) {
value2reg(instr->get_rval(), 0); auto reg1 = value2reg(instr->get_rval(), 0);
value2reg(instr->get_lval(), 1); auto reg2 = value2reg(instr->get_lval(), 1);
bool is_float = instr->get_rval()->get_type()->is_float_type(); bool is_float = instr->get_rval()->get_type()->is_float_type();
string instr_ir = (is_float ? "fst" : "st"); string instr_ir = (is_float ? "fst" : "st");
string suff = suffix(instr->get_rval()->get_type()); string suff = suffix(instr->get_rval()->get_type());
string reg = (is_float ? "$fa0" : "$a0"); output.push_back(instr_ir + suff + " " + reg1 + ", " + reg2 + ", 0");
output.push_back(instr_ir + suff + " " + reg + ", $a1, 0");
} }
void void
CodeGen::IR2assem(ReturnInst *instr) { CodeGen::IR2assem(ReturnInst *instr) {
if (not instr->is_void_ret()) { if (not instr->is_void_ret()) {
auto value = instr->get_operand(0); auto value = instr->get_operand(0);
value2reg(value); auto is_float = value->get_type()->is_float_type();
auto reg = value2reg(value);
if (is_float and reg != "$fa0")
output.push_back("fmov.s $fa0, " + reg);
else if (not is_float and reg != "$a0")
output.push_back("or $a0, $zero " + reg);
} }
output.push_back("b " + cur_func->get_name() + "_end"); output.push_back("b " + cur_func->get_name() + "_end");
} }
......
...@@ -11,6 +11,7 @@ LiveRangeAnalyzer::clear() { ...@@ -11,6 +11,7 @@ LiveRangeAnalyzer::clear() {
OUT.clear(); OUT.clear();
instr_id.clear(); instr_id.clear();
cpstmt_id.clear(); cpstmt_id.clear();
intervalmap.clear();
liveIntervals.clear(); liveIntervals.clear();
} }
...@@ -133,24 +134,23 @@ LiveRangeAnalyzer::run(Function *func) { ...@@ -133,24 +134,23 @@ LiveRangeAnalyzer::run(Function *func) {
void void
LiveRangeAnalyzer::make_interval(Function *) { LiveRangeAnalyzer::make_interval(Function *) {
map<Value *, Interval> liverange;
for (int time = 1; time <= ir_cnt; ++time) { for (int time = 1; time <= ir_cnt; ++time) {
for (auto op : IN.at(time)) { for (auto op : IN.at(time)) {
auto &interval = liverange[op]; auto &interval = intervalmap[op];
if (interval.i == 0) // uninitialized if (interval.i == 0) // uninitialized
interval.i = time - 1; interval.i = time - 1;
else else
interval.j = time - 1; interval.j = time - 1;
} }
for (auto op : OUT.at(time)) { for (auto op : OUT.at(time)) {
auto &interval = liverange[op]; auto &interval = intervalmap[op];
if (interval.i == 0) // uninitialized if (interval.i == 0) // uninitialized
interval.i = time; interval.i = time;
else else
interval.j = time; interval.j = time;
} }
} }
for (auto [op, interval] : liverange) for (auto [op, interval] : intervalmap)
liveIntervals.insert({interval, op}); liveIntervals.insert({interval, op});
} }
...@@ -188,7 +188,7 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) { ...@@ -188,7 +188,7 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) {
} }
void void
LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug LiveRangeAnalyzer::print(Function *func, bool printSet) const { // for debug
cout << "Function " << func->get_name() << endl; cout << "Function " << func->get_name() << endl;
for (auto &bb : func->get_basic_blocks()) { for (auto &bb : func->get_basic_blocks()) {
for (auto &instr : bb.get_instructions()) { for (auto &instr : bb.get_instructions()) {
...@@ -200,7 +200,7 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug ...@@ -200,7 +200,7 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug
for (auto pr : phi_map.find(&bb)->second) { for (auto pr : phi_map.find(&bb)->second) {
auto [lv, rv] = pr; auto [lv, rv] = pr;
auto idx = cpstmt_id.at(pr); auto idx = cpstmt_id.at(pr);
cout << cpstmt_id[pr] << ". " << lv->get_name() << " = " cout << cpstmt_id.at(pr) << ". " << lv->get_name() << " = "
<< (rv->get_name() == "" ? rv->print() << (rv->get_name() == "" ? rv->print()
: rv->get_name()) : rv->get_name())
<< endl; << endl;
...@@ -213,8 +213,8 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug ...@@ -213,8 +213,8 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug
} }
} }
// normal ir // normal ir
cout << instr_id[&instr] << ". " << instr.print() << " # " << &instr cout << instr_id.at(&instr) << ". " << instr.print() << " # "
<< endl; << &instr << endl;
if (not printSet) if (not printSet)
continue; continue;
auto idx = instr_id.at(&instr); auto idx = instr_id.at(&instr);
......
#include "regalloc.hpp" #include "regalloc.hpp"
#include "Instruction.h"
#include "liverange.hpp"
#include <algorithm> #include <algorithm>
using std::for_each; using std::for_each;
using namespace RA; using namespace RA;
bool
RA::no_reg_alloca(Value *v) {
auto instr = static_cast<Instruction *>(v);
return instr->is_alloca() or instr->is_cmp() or instr->is_fcmp() or
instr->is_zext();
}
void void
RegAllocator::reset() { RegAllocator::reset() {
regmap.clear(); regmap.clear();
active.clear(); active.clear();
for_each(used, used + R, [](bool &u) { u = false; }); for_each(used, used + R + 1, [](bool &u) { u = false; });
} }
void void
RegAllocator::LinearScan(set<LiveInterval> &liveints) { RegAllocator::LinearScan(const LVITS &liveints) {
reset(); reset();
int reg; int reg;
for (auto liveint : liveints) { for (auto liveint : liveints) {
if (no_reg_alloca(liveint.second))
continue;
ExpireOldIntervals(liveint); ExpireOldIntervals(liveint);
if (active.size() == R) if (active.size() == R)
SpillAtInterval(liveint); SpillAtInterval(liveint);
......
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