Commit b4870a73 authored by lxq's avatar lxq

have too many bugs now, use lab3 testcases to debug

parent 0454682c
......@@ -113,7 +113,7 @@ op6: <8, 8>
程序有`$a`系列寄存器8个,`$t`系列9个,拿出`$t0``$t1`做IR生成汇编过程中的临时寄存器(这个方案仅在cminus下成立),所以可以自由分配的寄存器一共15个。
首先完成对于局部变量的寄存器分配,即全局变量、传参依旧通过栈进行
首先完成对于局部变量和参数的整形寄存器分配
程序分配寄存器时会对部分指令做特殊处理,具体如下:
......@@ -135,4 +135,28 @@ op6: <8, 8>
- `call`指令:使用栈传参,caller保存自己用到的寄存器,被保存的寄存器的活跃区间覆盖`call`指令的程序点。
参数传递:固定为前8个参数分配`$a0`\~`$a7`,超过8个使用栈传递。
#### 4. 局部优化
- 基于跳转的bool变量翻译。
- GEP取值的优化:两个0的情况
- 常量取值的优化
-
#### 5. 测试样例
功能正确性由以下几部分测试样例作为证明:
- `/tests/5-bonus/testcases`
- `tests/3-ir-gen/testcases`
而性能主要向gcc看齐,主要测试样例为
- `tests/4-ir-opt/testcases/GVN/performance`
-
......@@ -11,9 +11,13 @@
#include "liverange.hpp"
#include "regalloc.hpp"
#include <string>
#define __PRINT_ORI__
#define __RO_PART__
// #a = 8, #t = 9, reserve $t0, $t1 for temporary
#define R_USABLE 17 - 2
#define ARG_R 8
#include <map>
#include <ostream>
......@@ -29,7 +33,7 @@ using std::vector;
class CodeGen {
public:
CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE) {}
CodeGen(Module *m_) : m(m_), LRA(m_, phi_map), RA(R_USABLE, ARG_R) {}
string print() {
string result;
......@@ -74,9 +78,8 @@ class CodeGen {
void stackMemDealloc();
// In the case of register allocation, this function will return the
// allocated register for that value, if the value possesses no register,
// choose from from $t0 or $t1 based on id
__attribute__((warn_unused_result)) string value2reg(Value *, int i = 0);
// choose from from $t0 or $t1 based on id, or the input string(not "")
__attribute__((warn_unused_result)) string value2reg(Value *, int i = 0, string = "");
// load the content in ptr to specified register.
void ptrContent2reg(Value *, string);
void compute_arg_info(Function *);
......@@ -104,13 +107,16 @@ class CodeGen {
return false;
}
auto is_float = lhs->get_type()->is_float_type();
gencopy(lhs_reg, rhs_reg, is_float);
return true;
}
void gencopy(string lhs_reg, string rhs_reg, bool is_float = false) {
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 {
......@@ -186,6 +192,8 @@ class CodeGen {
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);
}
return name;
}
......
......@@ -49,7 +49,7 @@ class LiveRangeAnalyzer {
// void run();
void run(Function *);
void clear();
void print(Function *func, bool printSet = true) const;
void print(Function *func, bool printSet = false, bool printInt = false) const;
string print_liveSet(const LiveSet &ls) const {
string s = "[ ";
for (auto k : ls)
......
#ifndef REGALLOCA_HPP
#define REGALLOCA_HPP
#include "Function.h"
#include "Value.h"
#include "liverange.hpp"
......@@ -6,16 +9,12 @@
using std::cout;
using std::endl;
using std::to_string;
using namespace LRA;
namespace RA {
#define MAXR 32
bool no_reg_alloca(Value *v);
struct ActiveCMP {
bool operator()(LiveInterval const &lhs, LiveInterval const &rhs) const {
if (lhs.first.j != rhs.first.j)
......@@ -27,11 +26,14 @@ struct ActiveCMP {
class RegAllocator {
public:
RegAllocator(const uint R_) : R(R_), used{false} { assert(R <= MAXR); }
RegAllocator(const uint R_, const uint ARG_R_)
: R(R_), ARG_MAX_R(ARG_R_), used{false} {
assert(R <= MAXR);
}
RegAllocator() = delete;
bool no_reg_alloca(Value *v) const;
// input set is sorted by increasing start point
void LinearScan(const LVITS &liveints);
void reset();
void LinearScan(const LVITS &, Function *);
const map<Value *, int> &get() const { return regmap; }
void print(string (*regname)(int)) {
for (auto [op, reg] : regmap)
......@@ -39,13 +41,19 @@ class RegAllocator {
}
private:
Function *cur_func;
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
set<LiveInterval, ActiveCMP> active;
void reset(Function * = nullptr);
int ReserveForArg(const LVITS &);
void ExpireOldIntervals(LiveInterval);
void SpillAtInterval(LiveInterval);
};
} // namespace RA
#endif
......@@ -12,6 +12,7 @@
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <ostream>
#include <sstream>
#include <string>
#include <sys/types.h>
......@@ -19,6 +20,8 @@
#include <utility>
#include <vector>
#define CONST_0 ConstantInt::get(0, m)
// $r0 $zero constant 0
// $r1 $ra return address
// $r2 $tp thread pointer
......@@ -31,6 +34,7 @@
// $r23 - $r31 $s0 - $s8 static
using std::to_string;
using std::operator""s;
pair<string, bool>
CodeGen::getRegName(Value *v, int i) const {
......@@ -89,7 +93,7 @@ CodeGen::run() {
for (auto &func : m->get_functions()) {
if (not func.is_declaration()) {
LRA.run(&func);
RA.LinearScan(LRA.get());
RA.LinearScan(LRA.get(), &func);
std::cout << "register map for function: " << func.get_name()
<< std::endl;
......@@ -149,8 +153,8 @@ CodeGen::ptrContent2reg(Value *ptr, string reg_name) {
string suff = suffix(ele_tp);
auto [addr_reg, find] = getRegName(ptr, 1);
if (not find)
addr_reg = "$t1";
/* if (not find)
* addr_reg = "$t1"; */
if (dynamic_cast<GlobalVariable *>(ptr)) {
output.push_back("la.local " + addr_reg + ", " + ptr->get_name());
......@@ -174,15 +178,17 @@ CodeGen::ptrContent2reg(Value *ptr, string reg_name) {
}
string
CodeGen::value2reg(Value *v, int i) {
CodeGen::value2reg(Value *v, int i, string recommend) {
bool is_float = v->get_type()->is_float_type();
string tmp_ireg = "$t" + to_string(i);
auto [reg_name, find] = getRegName(v, i);
if (find)
return reg_name;
else if (recommend != "")
reg_name = recommend;
// now is the stack allocation case
if (dynamic_cast<Constant *>(v)) {
if (v == ConstantInt::get(0, m))
if (v == CONST_0)
return "$zero";
auto constant = static_cast<Constant *>(v);
#ifdef __RO_PART__
......@@ -239,10 +245,14 @@ CodeGen::value2reg(Value *v, int i) {
for (auto iter = args.begin(); id <= args.size(); ++iter, ++id)
if (*iter == v)
break;
string instr_ir = is_float ? "fld" : "ld";
output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
", $fp, " +
to_string(func_arg_off.at(cur_func).at(id)));
if (id <= ARG_R)
return regname(ARG_R);
else {
string instr_ir = is_float ? "fld" : "ld";
output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
", $fp, " +
to_string(func_arg_off.at(cur_func).at(id)));
}
} else {
string instr_ir = is_float ? "fld" : "ld";
output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
......@@ -258,15 +268,19 @@ CodeGen::compute_arg_info(Function *func) {
auto func_tp = func->get_function_type();
auto &arg_off = func_arg_off[func];
int argN = 0, arg_id = func->get_num_of_args();
// only alloca stack memory for argk, k >= 8;
auto rend = func_tp->param_begin();
for (int i = 0; i < ARG_R and rend != func_tp->param_end(); ++i, ++rend)
;
// reserve space
for (auto iter = func_tp->param_end(); iter != func_tp->param_begin();) {
for (auto iter = func_tp->param_end(); iter != rend;) {
--iter;
auto tplen = typeLen(*iter);
argN = ALIGN(argN, tplen) + tplen;
arg_off[arg_id--] = argN;
}
for (arg_id = 1; arg_id <= func->get_num_of_args(); ++arg_id)
arg_off[arg_id] = argN - arg_off[arg_id];
for (arg_id = ARG_R + 1; arg_id <= func->get_num_of_args(); ++arg_id)
arg_off.at(arg_id) = argN - arg_off.at(arg_id);
func_arg_N[func] = argN;
}
......@@ -349,7 +363,7 @@ CodeGen::bool2branch(Instruction *instr) {
break;
case CmpInst::NE: {
instr_ir = "bne";
if (instr->get_operand(1) == ConstantInt::get(0, m) and
if (instr->get_operand(1) == CONST_0 and
dynamic_cast<Instruction *>(instr->get_operand(0))
->is_zext()) {
// something like:
......@@ -440,7 +454,7 @@ CodeGen::IR2assem(CallInst *instr) {
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))
if (RA.no_reg_alloca(op) or regmap.at(op) == 1)
continue;
if (interval.i <= cur_i and cur_i <= interval.j) {
int tplen = typeLen(op->get_type());
......@@ -452,8 +466,9 @@ CodeGen::IR2assem(CallInst *instr) {
int totalN = STACK_ALIGN(ALIGN(storeN, 8) + func_argN);
// cout << "debug: " << STACK_ALIGN(12) << endl;
// stack space allocation
output.push_back("addi.d $sp, $sp, -" + to_string(totalN));
string instr_ir, suff, reg;
if (totalN)
output.push_back("addi.d $sp, $sp, -" + to_string(totalN));
string instr_ir, suff, v_reg;
// place the reserved regs
for (auto [op, reg, off] : store_record) {
instr_ir = (op->get_type()->is_float_type() ? "fst" : "st");
......@@ -461,15 +476,18 @@ CodeGen::IR2assem(CallInst *instr) {
output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(totalN - off));
}
// place the arguments
for (int i = 1; i < instr->get_num_operand(); i++) {
auto arg = instr->get_operand(i);
// auto tplen = typeLen(arg->get_type());
instr_ir = (arg->get_type()->is_float_type() ? "fst" : "st");
suff = suffix(arg->get_type());
reg = value2reg(arg);
output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(func_arg_off.at(func).at(i)));
// pass arguments
for (int arg_i = 1; arg_i < instr->get_num_operand(); arg_i++) {
auto arg_value = instr->get_operand(arg_i);
v_reg = value2reg(arg_value);
if (arg_i <= ARG_R) { // pass by register
gencopy(regname(arg_i), v_reg);
} else { // pass by stack
instr_ir = (arg_value->get_type()->is_float_type() ? "fst" : "st");
suff = suffix(arg_value->get_type());
output.push_back(instr_ir + suff + " " + v_reg + ", $sp, " +
to_string(func_arg_off.at(func).at(arg_i)));
}
}
output.push_back("bl " + func->get_name());
// bug here: maybe
......@@ -481,8 +499,8 @@ CodeGen::IR2assem(CallInst *instr) {
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));
if (totalN)
output.push_back("addi.d $sp, $sp, " + to_string(totalN));
}
void
......@@ -502,34 +520,27 @@ CodeGen::IR2assem(BinaryInst *instr) {
void
CodeGen::IR2assem(GetElementPtrInst *instr) {
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();
for (int i = 1; i < instr->get_num_operand(); i++) {
int size;
if (type->is_array_type()) {
size = type->get_array_element_type()->get_size();
type = type->get_array_element_type();
} else if (type->is_pointer_type()) {
size = type->get_size();
type = type->get_pointer_element_type();
} else
assert(false && "GEP translation error");
if (size != 4) {
// getelementptr [5 x i32], [5 x i32]* @w, i32 0, i32 4
assert(instr->get_operand(i) == ConstantInt::get(0, m) &&
"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);
auto [dest_reg, _] = getRegName(instr);
auto off = instr->get_operand(instr->get_num_operand() == 3 ? 2 : 1);
if (off == CONST_0) {
auto final_reg = value2reg(instr->get_operand(0), 0, dest_reg);
gencopy(instr, final_reg);
return;
}
if (instr->get_num_operand() == 3) {
// %op54 = getelementptr [66 x i32], [66 x i32]* @dp, i32 0, i32 %op41
assert(instr->get_operand(1) == CONST_0);
} else { // %op38 = getelementptr i32, i32* %arg1, i32 %op34
}
gencopy(instr, addr_reg);
auto addr_reg = value2reg(instr->get_operand(0), 0);
auto off_reg = value2reg(off, 1);
auto tmp_reg = "$t1"s;
output.push_back("slli.d " + tmp_reg + ", " + off_reg + ", 2");
output.push_back("add.d " + dest_reg + ", " + addr_reg + ", " + tmp_reg);
gencopy(instr, dest_reg);
}
void
......@@ -559,7 +570,7 @@ CodeGen::IR2assem(ReturnInst *instr) {
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("or $a0, $zero, " + reg);
}
output.push_back("b " + cur_func->get_name() + "_end");
......@@ -569,7 +580,9 @@ void
CodeGen::IR2assem(Instruction &instr, BasicBlock &bb) {
if (instr.is_br() or instr.is_ret())
copystmt(&bb);
#ifdef __PRINT_ORI__
output.push_back("# " + instr.print());
#endif
switch (instr.get_instr_type()) {
case Instruction::ret:
IR2assem(static_cast<ReturnInst *>(&instr));
......
#include "liverange.hpp"
#include "Function.h"
using std::cout;
using std::endl;
using namespace LRA;
......@@ -58,9 +60,6 @@ void
LiveRangeAnalyzer::run(Function *func) {
clear();
make_id(func);
#ifdef __LRA_PRINT__
print(func, false);
#endif
bool cont = true;
while (cont) {
cont = false;
......@@ -128,7 +127,7 @@ LiveRangeAnalyzer::run(Function *func) {
make_interval(func);
#ifdef __LRA_PRINT__
print(func);
print(func, false, true);
#endif
}
......@@ -166,12 +165,15 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) {
// - function
// - Constant
// - instruction
// - argument
// - argument*
// - BasicBlock
auto ins = dynamic_cast<Instruction *>(op);
auto arg = dynamic_cast<Argument *>(op);
if (ins) {
assert(not ins->is_void() && "instr as op should not be void");
use.insert(op);
} else if (arg) {
use.insert(op);
}
}
// in = use + (out - def)
......@@ -188,7 +190,9 @@ LiveRangeAnalyzer::transferFunction(Instruction *instr) {
}
void
LiveRangeAnalyzer::print(Function *func, bool printSet) const { // for debug
LiveRangeAnalyzer::print(Function *func,
bool printSet,
bool printInt) const { // for debug
cout << "Function " << func->get_name() << endl;
for (auto &bb : func->get_basic_blocks()) {
for (auto &instr : bb.get_instructions()) {
......@@ -225,7 +229,7 @@ LiveRangeAnalyzer::print(Function *func, bool printSet) const { // for debug
}
}
if (printSet) {
if (printInt) {
for (auto [interval, op] : liveIntervals)
cout << op->get_name() << ": " << print_interval(interval) << endl;
}
......
#include "regalloc.hpp"
#include "Function.h"
#include "Instruction.h"
#include "liverange.hpp"
......@@ -9,25 +10,67 @@ using std::for_each;
using namespace RA;
int
get_arg_id(Argument *arg) {
auto args = arg->get_parent()->get_args();
int id = 1;
for (auto a : args) {
if (a == arg)
break;
++id;
}
return id;
}
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();
RegAllocator::no_reg_alloca(Value *v) const {
auto instr = dynamic_cast<Instruction *>(v);
auto arg = dynamic_cast<Argument *>(v);
if (instr)
return instr->is_alloca() or instr->is_cmp() or instr->is_fcmp() or
instr->is_zext();
if (arg) {
return get_arg_id(arg) > ARG_MAX_R;
} else
assert(false && "only instruction and argument's LiveInterval exits");
}
void
RegAllocator::reset() {
RegAllocator::reset(Function *func) {
cur_func = func;
regmap.clear();
active.clear();
for_each(used, used + R + 1, [](bool &u) { u = false; });
}
int
RegAllocator::ReserveForArg(const LVITS &Liveints) {
auto args = cur_func->get_args();
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;
auto liveint = *it_int;
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;
}
void
RegAllocator::LinearScan(const LVITS &liveints) {
reset();
RegAllocator::LinearScan(const LVITS &liveints, Function *func) {
reset(func);
ReserveForArg(liveints);
int reg;
for (auto liveint : liveints) {
if (dynamic_cast<Argument *>(liveint.second)) {
continue;
}
if (no_reg_alloca(liveint.second))
continue;
ExpireOldIntervals(liveint);
......@@ -54,6 +97,8 @@ RegAllocator::ExpireOldIntervals(LiveInterval liveint) {
void
RegAllocator::SpillAtInterval(LiveInterval liveint) {
auto spill = *active.rbegin();
if (dynamic_cast<Argument *>(spill.second))
return;
if (spill.first.j > liveint.first.j) {
// cancel reg allocation for spill
regmap[liveint.second] = regmap.at(spill.second);
......
int getarg(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j)
{
output(a);
output(b);
output(c);
output(d);
output(e);
output(f);
output(g);
output(h);
output(i);
output(j);
}
int main(void)
{
int arr[100];
arr[0] = input();
arr[1] = input();
arr[2] = input();
arr[3] = input();
arr[4] = input();
arr[5] = input();
arr[6] = input();
arr[7] = input();
arr[8] = input();
arr[9] = input();
getarg(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7], arr[8], arr[9]);
return 0;
}
826
-652
-395
146
704
859
728
556
609
-822
826
-652
-395
146
704
859
728
556
609
-822
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