Commit 805d36ad authored by lxq's avatar lxq

ready to finish all the functional test!

parent e23c2e2e
......@@ -161,4 +161,10 @@ op6: <8, 8>
- `tests/4-ir-opt/testcases/GVN/performance`
## 局限性
- GEP的取巧设计
- 未考虑指令寻址的立即数
-
......@@ -15,10 +15,12 @@
#include <string>
#define __PRINT_ORI__
#define __RO_PART__
// #define __RO_PART__
#define __PRINT_COMMENT__
// #a = 8, #t = 9, reserve $t0, $t1 for temporary
#define R_USABLE 17 - 2
#define R_USABLE (17 - 2)
// #fa = 8, #ft=16, reserve $ft0, $ft1 for temporary
#define FR_USABLE (24 - 2)
#define ARG_R 8
#include <map>
......@@ -40,7 +42,12 @@ using std::vector;
class CodeGen {
public:
CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE, ARG_R) {}
CodeGen(Module *m_)
: cmp_zext_cnt(0)
, m(m_)
, LRA(m_, phi_map)
, RA_int(R_USABLE, false)
, RA_float(FR_USABLE, true) {}
string print() {
string result;
......@@ -77,7 +84,8 @@ class CodeGen {
vector<string> output;
// register allocation
LRA::LiveRangeAnalyzer LRA;
RA::RegAllocator RA;
LRA::LVITS LVITS_int, LVITS_float;
RA::RegAllocator RA_int, RA_float;
// 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.
......@@ -147,7 +155,7 @@ class CodeGen {
gencopy(lhs_reg, rhs_reg, is_float);
return true;
}
void gencopy(string lhs_reg, string rhs_reg, bool is_float = false) {
void gencopy(string lhs_reg, string rhs_reg, bool is_float) {
if (rhs_reg != lhs_reg) {
if (is_float)
output.push_back("fmov.s " + lhs_reg + ", " + rhs_reg);
......@@ -215,7 +223,9 @@ class CodeGen {
return true;
if (instr->is_fcmp() or instr->is_cmp() or instr->is_zext())
return true;
if (RA.get().find(instr) != RA.get().end())
auto regmap = (instr->get_type()->is_float_type() ? RA_float.get()
: RA_int.get());
if (regmap.find(instr) != regmap.end())
return true;
return false;
......@@ -225,17 +235,23 @@ class CodeGen {
return (is_float ? "$ft" : "$t") + to_string(i);
}
static string regname(int i, bool is_float = false) {
static string regname(uint i, bool is_float) {
string name;
if (is_float) {
assert(false && "not implemented!");
// assert(false && "not implemented!");
if (1 <= i and i <= 8)
name = "$fa" + to_string(i - 1);
else if (9 <= i and i <= FR_USABLE)
name = "$ft" + to_string(i - 9 + 2);
else
name = "WRONG_REG_" + to_string(i);
} else {
if (1 <= i and i <= 8)
name = "$a" + to_string(i - 1);
else if (9 <= i and i <= R_USABLE)
name = "$t" + to_string(i - 9 + 2);
else
name = "WRONG_REG" + to_string(i);
name = "WRONG_REG_" + to_string(i);
}
return name;
}
......
......@@ -15,12 +15,14 @@ using std::string;
using std::to_string;
using std::vector;
#define UNINITIAL -1
#define __LRA_PRINT__
namespace LRA {
struct Interval {
Interval(int a = -1, int b = -1) : i(a), j(b) {}
Interval(int a = UNINITIAL, int b = UNINITIAL) : i(a), j(b) {}
int i; // 0 means uninitialized
int j;
};
......@@ -49,15 +51,17 @@ class LiveRangeAnalyzer {
// void run();
void run(Function *);
void clear();
void print(Function *func, bool printSet = false, bool printInt = false) const;
string print_liveSet(const LiveSet &ls) const {
void print(Function *func,
bool printSet = false,
bool printInt = false) const;
static string print_liveSet(const LiveSet &ls) {
string s = "[ ";
for (auto k : ls)
s += k->get_name() + " ";
s += "]";
return s;
}
string print_interval(Interval &i) const {
static string print_interval(const Interval &i) {
return "<" + to_string(i.i) + ", " + to_string(i.j) + ">";
}
const LVITS &get() { return liveIntervals; }
......@@ -91,8 +95,12 @@ class LiveRangeAnalyzer {
LiveSet transferFunction(Instruction *);
public:
const decltype(instr_id) &get_instr_id() { return instr_id; }
const decltype(intervalmap) &get_interval_map() { return intervalmap; }
const decltype(instr_id) &get_instr_id() const { return instr_id; }
const decltype(intervalmap) &get_interval_map() const {
return intervalmap;
}
const decltype(IN) &get_in_set() const { return IN; }
const decltype(OUT) &get_out_set() const { return OUT; }
};
} // namespace LRA
#endif
......@@ -14,24 +14,27 @@ using namespace LRA;
namespace RA {
#define MAXR 32
#define ARG_MAX_R 8
struct ActiveCMP {
bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const {
if (lhs.first.j != rhs.first.j)
return lhs.first.j < rhs.first.j;
else
else if (lhs.first.i != rhs.first.i)
return lhs.first.i < rhs.first.i;
else
return lhs.second < rhs.second;
}
};
class RegAllocator {
public:
RegAllocator(const uint R_, const uint ARG_R_)
: R(R_), ARG_MAX_R(ARG_R_), used{false} {
RegAllocator(const uint R_, bool fl) : FLOAT(fl), R(R_), used{false} {
cout << "RegAllocator initialize: R=" << R << endl;
assert(R <= MAXR);
}
RegAllocator() = delete;
bool no_reg_alloca(Value *v) const;
static bool no_reg_alloca(Value *v);
// input set is sorted by increasing start point
void LinearScan(const LVITS &, Function *);
const map<Value *, int> &get() const { return regmap; }
......@@ -42,8 +45,8 @@ class RegAllocator {
private:
Function *cur_func;
const bool FLOAT;
const uint R;
const uint ARG_MAX_R;
bool used[MAXR + 1]; // index range: 1 ~ R
map<Value *, int> regmap;
// sorted by increasing end point
......
This diff is collapsed.
......@@ -125,31 +125,34 @@ LiveRangeAnalyzer::run(Function *func) {
}
}
// argument should be in the IN-set of Entry
assert(IN.find(0) == IN.end() and OUT.find(0) == OUT.end() &&
"no instr_id will be mapped to 0");
IN[0] = OUT[0] = {};
for (auto arg : func->get_args())
IN[1].insert(arg);
IN[0].insert(arg);
make_interval(func);
#ifdef __LRA_PRINT__
print(func, true, true);
print(func, false, true);
#endif
}
void
LiveRangeAnalyzer::make_interval(Function *) {
for (int time = 1; time <= ir_cnt; ++time) {
for (int time = 0; time <= ir_cnt; ++time) {
for (auto op : IN.at(time)) {
auto &interval = intervalmap[op];
if (interval.i == -1) // uninitialized
interval.i = time - 1;
if (interval.i == UNINITIAL) // uninitialized
interval.i = interval.j = time;
else
interval.j = time - 1;
interval.j = time;
}
for (auto op : OUT.at(time)) {
auto &interval = intervalmap[op];
if (interval.i == -1) // uninitialized
interval.i = time;
if (interval.i == UNINITIAL) // uninitialized
interval.i = interval.j = time + 1;
else
interval.j = time;
interval.j = time + 1;
}
}
for (auto &[op, interval] : intervalmap)
......@@ -197,6 +200,11 @@ LiveRangeAnalyzer::print(Function *func,
bool printSet,
bool printInt) const { // for debug
cout << "Function " << func->get_name() << endl;
cout << "0. Entry" << endl;
if (printSet) {
cout << "\tin-set: " + print_liveSet(IN.at(0)) << "\n";
cout << "\tout-set: " + print_liveSet(OUT.at(0)) << "\n";
}
for (auto &bb : func->get_basic_blocks()) {
for (auto &instr : bb.get_instructions()) {
if (instr.is_phi()) // ignore phi
......@@ -220,8 +228,7 @@ LiveRangeAnalyzer::print(Function *func,
}
}
// normal ir
cout << instr_id.at(&instr) << ". " << instr.print() << " # "
<< &instr << endl;
cout << instr_id.at(&instr) << ". " << instr.print() << endl;
if (not printSet)
continue;
auto idx = instr_id.at(&instr);
......
......@@ -10,6 +10,9 @@ using std::for_each;
using namespace RA;
#define ASSERT_CMPINST_USED_ONCE(cmpinst) \
(assert(cmpinst->get_use_list().size() == 1))
int
get_arg_id(Argument *arg) {
auto args = arg->get_parent()->get_args();
......@@ -23,7 +26,7 @@ get_arg_id(Argument *arg) {
}
bool
RegAllocator::no_reg_alloca(Value *v) const {
RegAllocator::no_reg_alloca(Value *v) {
auto instr = dynamic_cast<Instruction *>(v);
auto arg = dynamic_cast<Argument *>(v);
if (instr) {
......@@ -31,21 +34,26 @@ RegAllocator::no_reg_alloca(Value *v) const {
if (instr->is_alloca() or instr->is_cmp() or instr->is_fcmp())
return true;
else if (instr->is_zext()) { // only alloca for true use
for (auto use : instr->get_use_list())
if (not dynamic_cast<Instruction *>(use.val_)->is_br()) {
auto instr = static_cast<Instruction *>(use.val_);
if (instr->is_cmp()) { // special case for cmp again
auto cmp = static_cast<CmpInst *>(instr);
assert(cmp->get_cmp_op() == CmpInst::NE);
auto uses = instr->get_use_list();
assert(uses.size() == 1 and
dynamic_cast<Instruction *>(uses.begin()->val_)
->is_br());
bool alloc;
ASSERT_CMPINST_USED_ONCE(instr);
auto use_ins = dynamic_cast<Instruction *>(
instr->get_use_list().begin()->val_);
// assert(use_ins != nullptr && "should only be instruction?");
if (use_ins->is_cmp() and
static_cast<CmpInst *>(use_ins)->get_cmp_op() == CmpInst::NE) {
// this case:
// %op0 = icmp slt i32 1, 2
// %op1 = zext i1 %op0 to i32
// %op2 = icmp ne i32 %op1, 0 # <- if judges to here
// br i1 %op2, label %label3, label %label5
ASSERT_CMPINST_USED_ONCE(use_ins);
auto use2_ins = dynamic_cast<Instruction *>(
use_ins->get_use_list().begin()->val_);
alloc = not(use2_ins->is_br());
} else
return false;
}
return true;
alloc = true;
return not(alloc);
} else // then always allocate
return false;
}
......@@ -64,19 +72,22 @@ RegAllocator::reset(Function *func) {
}
int
RegAllocator::ReserveForArg(const LVITS &Liveints) {
RegAllocator::ReserveForArg(const LVITS &liveints) {
auto args = cur_func->get_args();
auto it_int = Liveints.begin();
auto it_int = liveints.begin();
auto it_arg = args.begin();
int reg;
for (reg = 1; reg <= args.size() and reg <= ARG_MAX_R; ++reg) {
auto arg = *it_arg;
if (not(FLOAT ^ arg->get_type()->is_float_type())) {
auto liveint = *it_int;
assert(arg == liveint.second && "arg should be in order in liveints");
assert(arg == liveint.second &&
"arg should be in order in liveints");
used[reg] = true;
regmap[arg] = reg;
active.insert(liveint);
}
++it_arg, ++it_int;
}
return reg;
......@@ -88,6 +99,8 @@ RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
ReserveForArg(liveints);
int reg;
for (auto liveint : liveints) {
if (FLOAT ^ liveint.second->get_type()->is_float_type())
continue;
if (dynamic_cast<Argument *>(liveint.second)) {
continue;
}
......@@ -99,6 +112,13 @@ RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
else {
for (reg = 1; reg <= R and used[reg]; ++reg)
;
if (reg == 16) {
for (auto [interval, v] : active) {
cout << "already allocated: " << v->get_name() << " ~ "
<< regmap.at(v) << endl;
}
assert(false);
}
used[reg] = true;
regmap[liveint.second] = reg;
active.insert(liveint);
......@@ -108,10 +128,12 @@ RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
void
RegAllocator::ExpireOldIntervals(LiveInterval liveint) {
auto it = active.begin();
for (; it != active.end() and it->first.j < liveint.first.i; ++it)
used[regmap.at(it->second)] = false;
active.erase(active.begin(), it);
}
void
......@@ -122,6 +144,7 @@ RegAllocator::SpillAtInterval(LiveInterval liveint) {
if (spill.first.j > liveint.first.j) {
// cancel reg allocation for spill
regmap[liveint.second] = regmap.at(spill.second);
active.insert(liveint);
active.erase(spill);
regmap.erase(spill.second);
......
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