Commit e23c2e2e authored by lxq's avatar lxq

finish argument pass, need to do float part

parent b4870a73
......@@ -132,6 +132,8 @@ op6: <8, 8>
这实际是指令选择部分的内容:
因为在cminus中并没有bool变量,这些IR指令用到的i1类型都是临时的:只为分支指令服务,所以直接将这些指令集成到分支跳转的判断中。
一个例外是隐式的类型转化,将比较的结果`i1`隐式转换为`i32`,此时是`zext`指令与`cmp`捆绑,特殊为`zext`指令分配寄存器。
- `call`指令:使用栈传参,caller保存自己用到的寄存器,被保存的寄存器的活跃区间覆盖`call`指令的程序点。
......
......@@ -11,10 +11,12 @@
#include "liverange.hpp"
#include "regalloc.hpp"
#include <functional>
#include <string>
#define __PRINT_ORI__
#define __RO_PART__
#define __PRINT_COMMENT__
// #a = 8, #t = 9, reserve $t0, $t1 for temporary
#define R_USABLE 17 - 2
#define ARG_R 8
......@@ -27,6 +29,11 @@
// #define STACK_ALIGN(x) (((x / 16) + (x % 16 ? 1 : 0)) * 16)
#define STACK_ALIGN(x) ALIGN(x, 16)
#define CONST_0 ConstantInt::get(0, m)
#define FP "$fp"
#define SP "$sp"
#define RA_reg "$ra"
using std::map;
using std::string;
using std::vector;
......@@ -38,6 +45,10 @@ class CodeGen {
string print() {
string result;
for (auto line : output) {
#ifndef __PRINT_COMMENT__
if (line.find("#") != string::npos)
continue;
#endif
if (line.find(":") == string::npos and line != "")
result += "\t"; // 添加缩进
result += line + "\n";
......@@ -58,6 +69,7 @@ class CodeGen {
std::map<BasicBlock *, std::vector<std::pair<Value *, Value *>>> phi_map;
std::map<Constant *, std::string> ROdata;
unsigned int stackN; // function local vars and so on
uint cmp_zext_cnt;
Function *cur_func;
......@@ -79,11 +91,16 @@ class CodeGen {
// 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, or the input string(not "")
__attribute__((warn_unused_result)) string value2reg(Value *, int i = 0, string = "");
__attribute__((warn_unused_result)) string value2reg(Value *,
int i = 0,
string = "");
// load the content in ptr to specified register.
void ptrContent2reg(Value *, string);
void pass_arguments(CallInst *);
void compute_arg_info(Function *);
string bool2branch(Instruction *);
void getPhiMap();
void copystmt(BasicBlock *bb) {
// all the phi instruction is transformed to copy-stmt
......@@ -97,6 +114,26 @@ class CodeGen {
}
}
// this is a decorated version of push_back, it checks intermediat number in
// the instruction, make sure imm will not overflow
void makeSureInRange(string instr_ir,
string reg1,
string reg2,
int imm,
string tinstr,
int bits = 12,
string treg = "$t0",
bool u = false) {
auto [l, h] = immRange(bits, u);
if (l <= imm and imm <= h)
output.push_back(instr_ir + " " + reg1 + ", " + reg2 + ", " +
to_string(imm));
else {
assert(value2reg(ConstantInt::get(imm, m), 0, treg) == treg);
output.push_back(tinstr + " " + reg1 + ", " + reg2 + ", " + treg);
}
}
// if reg-allocation, store to the specific register
// or is stack-allocation, set last_reg for back2stack()
bool gencopy(Value *lhs, string rhs_reg) {
......@@ -122,7 +159,7 @@ class CodeGen {
string label_in_assem(BasicBlock *bb) const {
return cur_func->get_name() + bb->get_name().substr(5);
}
int typeLen(Type *type) const {
static int typeLen(Type *type) {
if (type->is_float_type())
return 4;
else if (type->is_integer_type()) {
......@@ -149,11 +186,16 @@ class CodeGen {
string instr_ir = type->is_float_type() ? "fst" : "st";
string suff = suffix(type);
// string reg = type->is_float_type() ? "$fa0" : "$a0";
string addr = "$fp, -" + std::to_string(off.at(instr));
output.push_back(instr_ir + suff + " " + last_reg + ", " + addr);
makeSureInRange(instr_ir + suff,
last_reg,
FP,
-off.at(instr),
instr_ir + "x" + suff);
// string addr = "$fp, -" + std::to_string(off.at(instr));
// output.push_back(instr_ir + suff + " " + last_reg + ", " + addr);
}
string suffix(Type *type) const {
static string suffix(Type *type) {
int len = typeLen(type);
switch (len) {
case 1:
......@@ -198,6 +240,20 @@ class CodeGen {
return name;
}
static pair<int, int> immRange(int bit, bool u) {
pair<int, int> res;
if (u) {
res.first = 0;
res.second = (1 << bit) - 1;
} else {
bit--;
res.first = -(1 << bit);
res.second = (1 << bit) - 1;
}
return res;
};
pair<string, bool> getRegName(Value *, int = 0) const;
void IR2assem(Instruction &, BasicBlock &);
......@@ -211,12 +267,12 @@ class CodeGen {
void IR2assem(FpToSiInst *);
void IR2assem(SiToFpInst *);
void IR2assem(PhiInst *) {}
void IR2assem(ZextInst *);
// The Instructions below will do nothing
void IR2assem(AllocaInst *) {}
// integration with BranchInst
// integration with BranchInst and ZextInst
void IR2assem(CmpInst *) {}
void IR2assem(FCmpInst *) {}
void IR2assem(ZextInst *) {}
};
#endif
......@@ -20,7 +20,7 @@ using std::vector;
namespace LRA {
struct Interval {
Interval(int a = 0, int b = 0) : i(a), j(b) {}
Interval(int a = -1, int b = -1) : i(a), j(b) {}
int i; // 0 means uninitialized
int j;
};
......
......@@ -34,13 +34,15 @@ main(int argc, char **argv) {
bool gvn = false;
bool dump_json = false;
bool emit = false;
bool assembly = true;
bool assembly = false;
for (int i = 1; i < argc; ++i) {
if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help(argv[0]);
return 0;
} else if (argv[i] == "-o"s || argv[i] == "-S"s) {
if (argv[i] == "-S"s)
assembly = true;
if (target_path.empty() && i + 1 < argc) {
target_path = argv[i + 1];
if (target_path.rfind(".") != std::string::npos)
......@@ -54,8 +56,6 @@ main(int argc, char **argv) {
emit = true;
} else if (argv[i] == "-mem2reg"s) {
mem2reg = true;
} else if (argv[i] == "-S"s) {
assembly = true;
} else if (argv[i] == "-gvn"s) {
gvn = true;
} else if (argv[i] == "-dump-json"s) {
......@@ -123,6 +123,7 @@ main(int argc, char **argv) {
auto IR = m->print();
if (assembly) {
CodeGen codegen(m.get());
codegen.run();
std::ofstream target_file(target_path + ".s");
......
......@@ -12,16 +12,16 @@
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <deque>
#include <ostream>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#define CONST_0 ConstantInt::get(0, m)
// $r0 $zero constant 0
// $r1 $ra return address
// $r2 $tp thread pointer
......@@ -33,6 +33,7 @@
// $r22 $fp frame pointer
// $r23 - $r31 $s0 - $s8 static
using std::deque;
using std::to_string;
using std::operator""s;
......@@ -145,38 +146,39 @@ CodeGen::run() {
}
void
CodeGen::ptrContent2reg(Value *ptr, string reg_name) {
CodeGen::ptrContent2reg(Value *ptr, string dest_reg) {
auto ele_tp = ptr->get_type()->get_pointer_element_type();
assert(ele_tp);
bool is_float = ele_tp->is_float_type();
string instr_ir = (is_float ? "fld" : "ld");
string suff = suffix(ele_tp);
auto [addr_reg, find] = getRegName(ptr, 1);
/* if (not find)
* addr_reg = "$t1"; */
auto [addr_reg, find] = getRegName(ptr, 0);
if (dynamic_cast<GlobalVariable *>(ptr)) {
output.push_back("la.local " + addr_reg + ", " + ptr->get_name());
output.push_back(instr_ir + suff + " " + reg_name + ", " + addr_reg +
output.push_back(instr_ir + suff + " " + dest_reg + ", " + addr_reg +
", 0");
} else if (dynamic_cast<AllocaInst *>(ptr)) {
/* auto alloc_instr = static_cast<AllocaInst *>(ptr);
* string suff = suffix(alloc_instr->get_alloca_type()); */
output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" +
to_string(off.at(ptr)));
makeSureInRange(
instr_ir + suff, dest_reg, FP, -off.at(ptr), instr_ir + "x" + suff);
/* output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" +
* to_string(off.at(ptr))); */
} else if (dynamic_cast<GetElementPtrInst *>(ptr)) {
// auto GEP_instr = static_cast<GetElementPtrInst *>(ptr);
if (not find) {
output.push_back("ld.d " + addr_reg + ", $fp, -" +
to_string(off.at(ptr)));
makeSureInRange("ld.d", addr_reg, FP, -off.at(ptr), "ldx.d");
/* output.push_back("ld.d " + addr_reg + ", $fp, -" +
* to_string(off.at(ptr))); */
}
output.push_back(instr_ir + suff + " " + reg_name + ", " + addr_reg +
output.push_back(instr_ir + suff + " " + dest_reg + ", " + addr_reg +
", 0");
} else
assert(false && "unknown type");
}
void IR2assem(ZextInst *);
string
CodeGen::value2reg(Value *v, int i, string recommend) {
bool is_float = v->get_type()->is_float_type();
......@@ -237,8 +239,10 @@ CodeGen::value2reg(Value *v, int i, string recommend) {
} else if (dynamic_cast<AllocaInst *>(v)) {
// auto alloc_instr = dynamic_cast<AllocaInst *>(v);
// give the stack address
output.push_back("addi.d " + reg_name + ", $fp, -" +
to_string(off.at(v)));
makeSureInRange(
"addi.d", reg_name, FP, -off.at(v), "add.d", 12, reg_name);
/* output.push_back("addi.d " + reg_name + ", $fp, -" +
* to_string(off.at(v))); */
} else if (dynamic_cast<Argument *>(v)) {
auto args = cur_func->get_args();
int id = 1;
......@@ -249,14 +253,29 @@ CodeGen::value2reg(Value *v, int i, string recommend) {
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)));
auto suff = suffix(v->get_type());
makeSureInRange(instr_ir + suff,
reg_name,
FP,
func_arg_off.at(cur_func).at(id),
instr_ir + "x" + suff,
12,
reg_name);
/* output.push_back(instr_ir + suff + " " + 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 +
", $fp, -" + to_string(off.at(v)));
auto suff = suffix(v->get_type());
makeSureInRange(instr_ir + suff,
reg_name,
FP,
off.at(v),
instr_ir + "x" + suff,
12,
reg_name);
/* output.push_back(instr_ir + suff + " " + reg_name +
* ", $fp, -" + to_string(off.at(v))); */
}
return reg_name;
}
......@@ -307,10 +326,14 @@ CodeGen::stackMemAlloc() {
}
stackN = STACK_ALIGN(stackN);
output.push_back("# prolog");
output.push_back("addi.d $sp, $sp, -" + to_string(stackN));
output.push_back("st.d $ra, $sp," + to_string(stackN - 8));
output.push_back("st.d $fp, $sp, " + to_string(stackN - 16));
output.push_back("addi.d $fp, $sp, " + to_string(stackN));
makeSureInRange("addi.d", SP, SP, -stackN, "add.d");
makeSureInRange("st.d", RA_reg, SP, stackN - 8, "stx.d");
makeSureInRange("st.d", FP, SP, stackN - 16, "stx.d");
makeSureInRange("addi.d", FP, SP, stackN, "add.d");
/* output.push_back("addi.d $sp, $sp, -" + to_string(stackN));
* output.push_back("st.d $ra, $sp," + to_string(stackN - 8));
* output.push_back("st.d $fp, $sp, " + to_string(stackN - 16));
* output.push_back("addi.d $fp, $sp, " + to_string(stackN)); */
}
void
......@@ -318,11 +341,13 @@ 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));
makeSureInRange("ld.d", RA_reg, SP, stackN - 8, "ldx.d");
makeSureInRange("ld.d", FP, SP, stackN - 16, "ldx.d");
makeSureInRange("addi.d", SP, SP, stackN, "add.d");
/* 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("addi.d $sp, $sp, " + to_string(stackN)); */
output.push_back("jr $ra");
}
......@@ -364,6 +389,7 @@ CodeGen::bool2branch(Instruction *instr) {
case CmpInst::NE: {
instr_ir = "bne";
if (instr->get_operand(1) == CONST_0 and
dynamic_cast<Instruction *>(instr->get_operand(0)) and
dynamic_cast<Instruction *>(instr->get_operand(0))
->is_zext()) {
// something like:
......@@ -397,7 +423,6 @@ CodeGen::bool2branch(Instruction *instr) {
return instr_ir + " " +
(reverse ? (reg2 + ", " + reg1) : (reg1 + ", " + reg2)) + ",";
} else {
assert(false && "not implemented");
switch (fcmp_instr->get_cmp_op()) {
case FCmpInst::EQ:
instr_ir = "fcmp.ceq.s $fcc0";
......@@ -443,6 +468,117 @@ CodeGen::IR2assem(BranchInst *instr) {
}
}
void
CodeGen::pass_arguments(CallInst *instr) {
/* cannot use the arg order simply, example leading to error:
* a0<-..., a1<-a0
* so we need an suitable order and use at most 1 tmp reg to pass arguments
*/
// ASSERT: use index start from 1
const int N = 8;
auto func = static_cast<Function *>(instr->get_operand(0));
string v_reg, instr_ir, suff;
// 1. get rely graph for $a regs
// for example, $a1 is need by needby[1], which is a set
vector<int> needby[N + 1];
for (int arg_id = 1; arg_id < instr->get_num_operand(); arg_id++) {
auto arg_value = instr->get_operand(arg_id);
v_reg = getRegName(arg_value).first;
if (v_reg.substr(0, 2) != "$a")
continue;
else {
int v_id = std::stoi(to_string(v_reg[2])) - 47;
if (v_id != arg_id)
needby[v_id].push_back(arg_id);
}
}
// 2. get traverse order: an enhanced topological order
// key: if there is a cycle, should give out an order rather than endless
// loop, and the order should statisfy:
vector<int> order;
deque<int> queue;
bool vis[N + 1]{false};
map<int, bool> backup;
for (int arg_id = 1; arg_id < instr->get_num_operand(); arg_id++)
queue.push_back(arg_id); // initialize
while (not queue.empty()) {
int i = queue.front();
queue.pop_front();
if (find(order.begin(), order.end(), i) != order.end())
continue; // already has order
bool assign;
if (needby[i].size() == 0) {
// there is no argument relying on $a_i or is self rely
assign = true;
} else if (vis[i]) { // cycle detected
backup[i] = true;
assign = true;
} else
assign = false;
if (assign) {
order.push_back(i);
for (int j = 1; j <= N; ++j) { // remove $a_i 's rely
auto &need_vec = needby[j];
auto iter = find(need_vec.begin(), need_vec.end(), i);
if (iter !=
need_vec.end()) { // $a_i has at most one rely on $a_
need_vec.erase(iter);
if (needby[j].size() == 0) {
queue.push_front(j);
}
break;
}
}
} else
queue.push_back(i);
vis[i] = true;
}
order.clear();
for (int arg_id = 1; arg_id < instr->get_num_operand(); arg_id++)
order.push_back(arg_id); // initialize
// 3. pass arguments' value
assert(order.size() == func->get_num_of_args());
map<string, bool> wroten;
// bool assigned[8] = {false};
string t0_contained;
for (auto arg_id : order) {
auto arg_value = instr->get_operand(arg_id);
auto t_reg = arg_value->get_type()->is_float_type() ? "$ft0" : "$t0";
v_reg = value2reg(arg_value, 1);
if (backup[arg_id]) { // still relied by some argument due to cycle
auto a_id = regname(arg_id);
assert(not wroten[a_id]);
gencopy(t_reg, a_id);
t0_contained = a_id;
}
// in case that the src register has been wroten
if (wroten[v_reg]) {
assert(t0_contained == v_reg);
v_reg = arg_value->get_type()->is_float_type() ? "$ft0" : "$t0";
}
if (arg_id <= ARG_R) { // pass by register
gencopy(regname(arg_id), v_reg);
} else { // pass by stack
instr_ir = (arg_value->get_type()->is_float_type() ? "fst" : "st");
suff = suffix(arg_value->get_type());
makeSureInRange(instr_ir + suff,
v_reg,
SP,
func_arg_off.at(func).at(arg_id),
instr_ir + "x" + suff);
/* output.push_back(instr_ir + suff + " " + v_reg + ",
* $sp, " + to_string(func_arg_off.at(func).at(arg_id)));
*/
}
wroten[regname(arg_id)] = true;
}
}
void
CodeGen::IR2assem(CallInst *instr) {
auto func = static_cast<Function *>(instr->get_operand(0));
......@@ -454,9 +590,16 @@ 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) or regmap.at(op) == 1)
if (RA.no_reg_alloca(op))
continue;
if (not instr->get_function_type()
->get_return_type()
->is_void_type() and
regmap.find(instr) != regmap.end() and regmap.at(instr) == 1)
continue;
if (interval.i <= cur_i and cur_i <= interval.j) {
if (interval.i < cur_i and cur_i <= interval.j) {
cout << "At point " << cur_i << ", restore for " << op->get_name()
<< ", interval " << LRA.print_interval(interval) << endl;
int tplen = typeLen(op->get_type());
storeN = ALIGN(storeN, tplen) + tplen;
auto name = regname(regmap.at(op), op->get_type()->is_float_type());
......@@ -464,31 +607,23 @@ CodeGen::IR2assem(CallInst *instr) {
}
}
int totalN = STACK_ALIGN(ALIGN(storeN, 8) + func_argN);
// cout << "debug: " << STACK_ALIGN(12) << endl;
// stack space allocation
if (totalN)
output.push_back("addi.d $sp, $sp, -" + to_string(totalN));
if (totalN) {
makeSureInRange("addi.d", SP, SP, -totalN, "add.d");
// 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");
suff = suffix(op->get_type());
output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(totalN - off));
makeSureInRange(
instr_ir + suff, reg, SP, totalN - off, instr_ir + "x" + suff);
/* output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
* to_string(totalN - off)); */
}
// 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)));
}
}
pass_arguments(instr);
output.push_back("bl " + func->get_name());
// bug here: maybe
gencopy(instr, instr->get_type()->is_float_type() ? "$fa0" : "$a0");
......@@ -496,11 +631,15 @@ CodeGen::IR2assem(CallInst *instr) {
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));
makeSureInRange(
instr_ir + suff, reg, SP, totalN - off, instr_ir + "x" + suff);
/* output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
* to_string(totalN - off)); */
}
if (totalN) {
makeSureInRange("addi.d", SP, SP, totalN, "add.d");
// output.push_back("addi.d $sp, $sp, " + to_string(totalN));
}
if (totalN)
output.push_back("addi.d $sp, $sp, " + to_string(totalN));
}
void
......@@ -529,7 +668,8 @@ CodeGen::IR2assem(GetElementPtrInst *instr) {
return;
}
if (instr->get_num_operand() == 3) {
// %op54 = getelementptr [66 x i32], [66 x i32]* @dp, i32 0, i32 %op41
// %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
}
......@@ -547,8 +687,7 @@ void
CodeGen::IR2assem(LoadInst *instr) {
auto [reg, find] = getRegName(instr);
ptrContent2reg(instr->get_lval(), reg);
if (not find) // this if is just for logically clear
last_reg = reg;
gencopy(instr, reg);
}
void
......@@ -576,6 +715,95 @@ CodeGen::IR2assem(ReturnInst *instr) {
output.push_back("b " + cur_func->get_name() + "_end");
}
void
CodeGen::IR2assem(ZextInst *instr) {
if (RA.no_reg_alloca(instr))
return;
assert(instr->get_num_operand() == 1);
auto cmp_instr = instr->get_operand(0);
auto icmp_instr = dynamic_cast<CmpInst *>(cmp_instr);
auto fcmp_instr = dynamic_cast<FCmpInst *>(cmp_instr);
assert(icmp_instr or fcmp_instr);
auto [dest_reg, _] = getRegName(instr);
auto reg1 = value2reg(icmp_instr->get_operand(0), 0);
auto reg2 = value2reg(icmp_instr->get_operand(1), 1);
string instr_ir;
bool reverse = false, flip = false, check = false;
if (icmp_instr) {
switch (icmp_instr->get_cmp_op()) {
case CmpInst::EQ:
instr_ir = "xor";
check = flip = true;
break;
case CmpInst::NE:
instr_ir = "xor";
check = true;
break;
case CmpInst::GT:
instr_ir = "slt";
reverse = true;
break;
case CmpInst::GE:
instr_ir = "slt";
flip = true;
break;
case CmpInst::LT:
instr_ir = "slt";
break;
case CmpInst::LE:
instr_ir = "slt";
reverse = true;
flip = true;
break;
}
output.push_back(
instr_ir + " " + dest_reg + ", " +
(reverse ? (reg2 + ", " + reg1) : (reg1 + ", " + reg2)));
if (check) {
if (flip)
output.push_back("sltui " + dest_reg + ", " + dest_reg + ", 1");
else
output.push_back("sltu " + dest_reg + ", $zero, " + dest_reg);
} else if (flip) // check && flip can be solved in a single
// instruction
output.push_back("sltui " + dest_reg + ", " + dest_reg + ", 1");
} else {
switch (fcmp_instr->get_cmp_op()) {
case FCmpInst::EQ:
instr_ir = "fcmp.ceq.s";
break;
case FCmpInst::NE:
instr_ir = "fcmp.cun.s";
break;
case FCmpInst::GT:
instr_ir = "fcmp.cle.s";
reverse = true;
break;
case FCmpInst::GE:
instr_ir = "fcmp.clt.s";
reverse = true;
break;
case FCmpInst::LT:
instr_ir = "fcmp.clt.s";
break;
case FCmpInst::LE:
instr_ir = "fcmp.cle.s";
break;
}
string cmp_reg = "$fcc0";
auto label = "cmp_zext_" + to_string(++cmp_zext_cnt) + ":";
output.push_back(instr_ir + " " + cmp_reg + ", " + reg1 + ", " + reg2);
output.push_back("or " + dest_reg + ", $zero, $zero");
output.push_back("bceqz " + cmp_reg + ", " + label);
output.push_back("addi.w " + dest_reg + ", $zero, 1");
output.push_back(label + ":");
}
gencopy(instr, dest_reg);
}
void
CodeGen::IR2assem(Instruction &instr, BasicBlock &bb) {
if (instr.is_br() or instr.is_ret())
......
......@@ -124,10 +124,13 @@ LiveRangeAnalyzer::run(Function *func) {
}
}
}
// argument should be in the IN-set of Entry
for (auto arg : func->get_args())
IN[1].insert(arg);
make_interval(func);
#ifdef __LRA_PRINT__
print(func, false, true);
print(func, true, true);
#endif
}
......@@ -136,20 +139,20 @@ LiveRangeAnalyzer::make_interval(Function *) {
for (int time = 1; time <= ir_cnt; ++time) {
for (auto op : IN.at(time)) {
auto &interval = intervalmap[op];
if (interval.i == 0) // uninitialized
if (interval.i == -1) // uninitialized
interval.i = time - 1;
else
interval.j = time - 1;
}
for (auto op : OUT.at(time)) {
auto &interval = intervalmap[op];
if (interval.i == 0) // uninitialized
if (interval.i == -1) // uninitialized
interval.i = time;
else
interval.j = time;
}
}
for (auto [op, interval] : intervalmap)
for (auto &[op, interval] : intervalmap)
liveIntervals.insert({interval, op});
}
......
......@@ -26,10 +26,30 @@ bool
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) {
if (instr) {
// never allocate register
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());
} else
return false;
}
return true;
} else // then always allocate
return false;
}
if (arg) { // only allocate for the first 8 args
return get_arg_id(arg) > ARG_MAX_R;
} else
assert(false && "only instruction and argument's LiveInterval exits");
......
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