Commit 83f09476 authored by lxq's avatar lxq

should pass the functional test

parent 33502fa9
...@@ -43,18 +43,17 @@ class CodeGen { ...@@ -43,18 +43,17 @@ class CodeGen {
void IR2assem(GetElementPtrInst *); void IR2assem(GetElementPtrInst *);
void IR2assem(CallInst *); void IR2assem(CallInst *);
void IR2assem(BranchInst *); void IR2assem(BranchInst *);
void IR2assem(BinaryInst *);
void IR2assem(FpToSiInst *);
void IR2assem(SiToFpInst *);
// The Instructions below will do nothing // The Instructions below will do nothing
void IR2assem(AllocaInst *) {} void IR2assem(AllocaInst *) {}
// integration with BranchInst // integration with BranchInst
void IR2assem(CmpInst *) {} void IR2assem(CmpInst *) {}
void IR2assem(FCmpInst *) {}
void IR2assem(ZextInst *) {} void IR2assem(ZextInst *) {}
void IR2assem(BinaryInst *);
void IR2assem(PhiInst *) {} void IR2assem(PhiInst *) {}
void IR2assem(FCmpInst *) {}
void IR2assem(FpToSiInst *) {}
void IR2assem(SiToFpInst *) {}
void stackMemAlloc(); void stackMemAlloc();
void stackMemDealloc(); void stackMemDealloc();
...@@ -63,7 +62,7 @@ class CodeGen { ...@@ -63,7 +62,7 @@ class CodeGen {
// - for global variables and pointers from alloca and GEP, read through // - for global variables and pointers from alloca and GEP, read through
// address // address
// only use register a_id and t_ // only use register a_id and t_
void value2reg(Value *, int id = 0, bool is_float = false); 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_ // only use register a_id and t_
void ptrContent2reg(Value *, int id = 0); void ptrContent2reg(Value *, int id = 0);
...@@ -92,21 +91,27 @@ class CodeGen { ...@@ -92,21 +91,27 @@ class CodeGen {
} }
} }
void back2stack(Instruction *instr, string reg = "$a0") { // assert the value needed to store back is in $a0 or $f0, according to the
// value type
void back2stack(Instruction *instr) {
// std::cerr << instr->print() << std::endl; // std::cerr << instr->print() << std::endl;
string suff = suffix(typeLen(instr->get_type())); auto type = instr->get_type();
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[instr]); string addr = "$fp, -" + std::to_string(off[instr]);
output.push_back("st" + suff + " " + reg + " " + addr); output.push_back(instr_ir + suff + " " + reg + ", " + addr);
} }
string suffix(int len) { string suffix(Type *type) {
int len = typeLen(type);
switch (len) { switch (len) {
case 1: case 1:
return ".b"; return ".b";
case 2: case 2:
return ".h"; return ".h";
case 4: case 4:
return ".w"; return type->is_float_type() ? ".s" : ".w";
case 8: case 8:
return ".d"; return ".d";
} }
...@@ -116,16 +121,16 @@ class CodeGen { ...@@ -116,16 +121,16 @@ class CodeGen {
bool no_stack_alloca(Instruction *instr) { bool no_stack_alloca(Instruction *instr) {
if (instr->is_void()) if (instr->is_void())
return true; return true;
if (instr->is_cmp() or instr->is_zext()) if (instr->is_fcmp() or instr->is_cmp() or instr->is_zext())
return true; return true;
return false; return false;
} }
std::map<Value *, unsigned int> off; // to $fp std::map<Value *, unsigned int> off; // stack offset to $fp
std::map<Function *, std::map<int, int>> func_arg_off; // to $sp std::map<Function *, std::map<int, int>> func_arg_off; // to $sp
std::map<Function *, int> func_arg_N; std::map<Function *, int> func_arg_N; // total space for args
unsigned int stackN; unsigned int stackN; // function local vars and so on
Function *cur_func; Function *cur_func;
......
...@@ -17,13 +17,16 @@ ...@@ -17,13 +17,16 @@
using namespace std::literals::string_literals; using namespace std::literals::string_literals;
void print_help(std::string exe_name) { void
print_help(std::string exe_name) {
std::cout << "Usage: " << exe_name std::cout << "Usage: " << exe_name
<< " [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] [-mem2reg] [-gvn] [-dump-json] <input-file>" << " [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] "
"[-mem2reg] [-gvn] [-dump-json] <input-file>"
<< std::endl; << std::endl;
} }
int main(int argc, char **argv) { int
main(int argc, char **argv) {
std::string target_path; std::string target_path;
std::string input_path; std::string input_path;
...@@ -36,9 +39,11 @@ int main(int argc, char **argv) { ...@@ -36,9 +39,11 @@ int main(int argc, char **argv) {
if (argv[i] == "-h"s || argv[i] == "--help"s) { if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help(argv[0]); print_help(argv[0]);
return 0; return 0;
} else if (argv[i] == "-o"s) { } else if (argv[i] == "-o"s || argv[i] == "-S"s) {
if (target_path.empty() && i + 1 < argc) { if (target_path.empty() && i + 1 < argc) {
target_path = argv[i + 1]; target_path = argv[i + 1];
if (target_path.rfind(".") != std::string::npos)
target_path = target_path.substr(0, target_path.rfind("."));
i += 1; i += 1;
} else { } else {
print_help(argv[0]); print_help(argv[0]);
...@@ -71,12 +76,13 @@ int main(int argc, char **argv) { ...@@ -71,12 +76,13 @@ int main(int argc, char **argv) {
if (target_path.empty()) { if (target_path.empty()) {
auto pos = input_path.rfind('.'); auto pos = input_path.rfind('.');
if (pos == std::string::npos) { if (pos == std::string::npos) {
std::cerr << argv[0] << ": input file " << input_path << " has unknown filetype!" << std::endl; std::cerr << argv[0] << ": input file " << input_path
<< " has unknown filetype!" << std::endl;
return -1; return -1;
} else { } else {
// if (input_path.substr(pos) != ".cminus") { // if (input_path.substr(pos) != ".cminus") {
// std::cerr << argv[0] << ": input file " << input_path << " has unknown filetype!" << std::endl; // std::cerr << argv[0] << ": input file " << input_path << "
// return -1; // has unknown filetype!" << std::endl; return -1;
// } // }
target_path = input_path.substr(0, pos); target_path = input_path.substr(0, pos);
} }
...@@ -89,7 +95,8 @@ int main(int argc, char **argv) { ...@@ -89,7 +95,8 @@ int main(int argc, char **argv) {
a.run_visitor(builder); a.run_visitor(builder);
} catch (std::exception e) { } catch (std::exception e) {
std::cout << "Exception catched:\n\t" << e.what() << std::endl; std::cout << "Exception catched:\n\t" << e.what() << std::endl;
std::cout << "Already generated IR code:\n" << builder.getModule()->print(); std::cout << "Already generated IR code:\n"
<< builder.getModule()->print();
return -1; return -1;
} }
...@@ -104,7 +111,8 @@ int main(int argc, char **argv) { ...@@ -104,7 +111,8 @@ int main(int argc, char **argv) {
if (gvn) { if (gvn) {
PM.add_pass<DeadCode>(false); // remove some undef PM.add_pass<DeadCode>(false); // remove some undef
PM.add_pass<GVN>(emit, dump_json); PM.add_pass<GVN>(emit, dump_json);
PM.add_pass<DeadCode>(false); // delete unused instructions created by GVN PM.add_pass<DeadCode>(
false); // delete unused instructions created by GVN
} }
PM.run(); PM.run();
...@@ -132,7 +140,8 @@ int main(int argc, char **argv) { ...@@ -132,7 +140,8 @@ int main(int argc, char **argv) {
lib_path.erase(lib_path.rfind('/')); lib_path.erase(lib_path.rfind('/'));
else else
lib_path.clear(); lib_path.clear();
auto cmd_str = "clang -O0 -w -no-pie "s + target_path + ".ll -o " + target_path + lib_path + " -lcminus_io"; auto cmd_str = "clang -O0 -w -no-pie "s + target_path + ".ll -o " +
target_path + lib_path + " -lcminus_io";
int re_code0 = std::system(cmd_str.c_str()); int re_code0 = std::system(cmd_str.c_str());
cmd_str = "rm "s + target_path + ".ll"; cmd_str = "rm "s + target_path + ".ll";
int re_code1 = std::system(cmd_str.c_str()); int re_code1 = std::system(cmd_str.c_str());
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "Type.h" #include "Type.h"
#include "Value.h" #include "Value.h"
#include <cstdint>
#include <cstring>
#include <string> #include <string>
// $r0 $zero constant 0 // $r0 $zero constant 0
...@@ -98,50 +100,67 @@ CodeGen::run() { ...@@ -98,50 +100,67 @@ CodeGen::run() {
void void
CodeGen::ptrContent2reg(Value *ptr, int id) { CodeGen::ptrContent2reg(Value *ptr, int id) {
auto reg_name = "$a" + to_string(id); 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 reg_name = (is_float ? "$fa" : "$a") + to_string(id);
string suff = suffix(ele_tp);
if (dynamic_cast<GlobalVariable *>(ptr)) { if (dynamic_cast<GlobalVariable *>(ptr)) {
auto type = static_cast<GlobalVariable *>(ptr)
->get_type()
->get_pointer_element_type();
auto suff = suffix(typeLen(type));
output.push_back("la.local " + reg_name + ", " + ptr->get_name()); output.push_back("la.local " + reg_name + ", " + ptr->get_name());
output.push_back("ldx" + suff + " " + reg_name + ", " + reg_name + output.push_back(instr_ir + suff + " " + reg_name + ", " + reg_name +
", $r0"); ", 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(typeLen(alloc_instr->get_alloca_type())); * string suff = suffix(alloc_instr->get_alloca_type()); */
output.push_back("ld" + suff + " " + reg_name + ", $fp, -" + output.push_back(instr_ir + suff + " " + reg_name + ", $fp, -" +
to_string(off[ptr])); to_string(off[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);
auto suff = suffix(typeLen(GEP_instr->get_element_type()));
output.push_back("ld.d " + reg_name + ", $fp, -" + to_string(off[ptr])); output.push_back("ld.d " + reg_name + ", $fp, -" + to_string(off[ptr]));
output.push_back("ldx" + suff + " " + reg_name + ", " + reg_name + output.push_back(instr_ir + suff + " " + reg_name + ", " + reg_name +
", $r0"); ", 0");
} else } else
assert(false && "unknown type"); assert(false && "unknown type");
} }
void void
CodeGen::value2reg(Value *v, int id, bool is_float) { CodeGen::value2reg(Value *v, int id) {
auto reg_name = (is_float ? "$f" : "$a") + to_string(id); bool is_float = v->get_type()->is_float_type();
auto reg_name = (is_float ? "$fa" : "$a") + to_string(id);
if (dynamic_cast<Constant *>(v)) { if (dynamic_cast<Constant *>(v)) {
auto constant = static_cast<Constant *>(v); auto constant = static_cast<Constant *>(v);
if (dynamic_cast<ConstantInt *>(constant)) { if (dynamic_cast<ConstantInt *>(constant)) {
int k = static_cast<ConstantInt *>(constant)->get_value(); int k = static_cast<ConstantInt *>(constant)->get_value();
if ((k & 0xfff) != k) { if ((k & 0xfff) != k) {
output.push_back("lui.w " + reg_name + ", " + output.push_back("lu12i.w " + reg_name + ", " +
to_string(k >> 12)); to_string(k >> 12));
output.push_back("ori " + reg_name + ", " + reg_name + ", " + output.push_back("ori " + reg_name + ", " + reg_name + ", " +
to_string(k & 0xfff)); to_string(k & 0xfff));
} else } else
output.push_back("ori " + reg_name + ", $r0, " + to_string(k)); output.push_back("ori " + reg_name + ", $r0, " + to_string(k));
} else if (dynamic_cast<ConstantFP *>(constant)) {
// move the binary code to int-reg, then use movgr2fr to move the
// value to float-reg
string tmp_ireg = "$t0";
float k = static_cast<ConstantFP *>(constant)->get_value();
int hex_int = *(uint32_t *)&k;
if ((hex_int & 0xfff) != hex_int)
output.push_back("lu12i.w " + tmp_ireg + ", " +
to_string(hex_int >> 12));
if (hex_int & 0xfff)
output.push_back("ori " + tmp_ireg + ", " + tmp_ireg + ", " +
to_string(hex_int & 0xfff));
output.push_back("movgr2fr.w " + reg_name + ", " + tmp_ireg);
// output.push_back("ffint.s.w " + reg_name + ", " + reg_name);
} else } else
assert(false && "wait for completion"); assert(false && "wait for completion");
} else if (dynamic_cast<GlobalVariable *>(v)) { } else if (dynamic_cast<GlobalVariable *>(v)) {
output.push_back("la.local " + reg_name + ", " + v->get_name()); output.push_back("la.local " + reg_name + ", " + v->get_name());
} 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
output.push_back("addi.d " + reg_name + ", $fp, -" + to_string(off[v])); output.push_back("addi.d " + reg_name + ", $fp, -" + to_string(off[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();
...@@ -149,12 +168,13 @@ CodeGen::value2reg(Value *v, int id, bool is_float) { ...@@ -149,12 +168,13 @@ CodeGen::value2reg(Value *v, int id, bool is_float) {
for (auto iter = args.begin(); id <= args.size(); ++iter, ++id) for (auto iter = args.begin(); id <= args.size(); ++iter, ++id)
if (*iter == v) if (*iter == v)
break; break;
output.push_back("ld" + suffix(typeLen(v->get_type())) + " " + string instr_ir = is_float ? "fld" : "ld";
reg_name + ", $fp, " + output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
to_string(func_arg_off[cur_func][id])); ", $fp, " + to_string(func_arg_off[cur_func][id]));
} else { } else {
output.push_back("ld" + suffix(typeLen(v->get_type())) + " " + string instr_ir = is_float ? "fld" : "ld";
reg_name + ", $fp, -" + to_string(off[v])); output.push_back(instr_ir + suffix(v->get_type()) + " " + reg_name +
", $fp, -" + to_string(off[v]));
} }
} }
...@@ -215,55 +235,98 @@ CodeGen::stackMemAlloc() { ...@@ -215,55 +235,98 @@ CodeGen::stackMemAlloc() {
output.push_back("addi.d $fp, $sp, " + to_string(stackN)); output.push_back("addi.d $fp, $sp, " + to_string(stackN));
output.push_back("st.d $ra, $fp, -8"); output.push_back("st.d $ra, $fp, -8");
} }
void
CodeGen::IR2assem(FpToSiInst *instr) {
assert(instr->get_operand(0)->get_type() == m->get_float_type());
assert(instr->get_dest_type() == m->get_int32_type());
value2reg(instr->get_operand(0));
output.push_back("ftint.w.s $fa0, $fa0");
output.push_back("movfr2gr.s $a0, $fa0");
}
void
CodeGen::IR2assem(SiToFpInst *instr) {
assert(instr->get_operand(0)->get_type() == m->get_int32_type());
assert(instr->get_dest_type() == m->get_float_type());
output.push_back("movgr2fr.w $fa0, $a0");
output.push_back("ffint.s.w $fa0, $fa0");
}
string string
CodeGen::bool2branch(Instruction *instr) { CodeGen::bool2branch(Instruction *instr) {
assert(instr->get_type() == instr->get_module()->get_int1_type()); assert(instr->get_type() == m->get_int1_type());
auto cmp_instr = dynamic_cast<CmpInst *>(instr); auto icmp_instr = dynamic_cast<CmpInst *>(instr);
assert(cmp_instr); auto fcmp_instr = dynamic_cast<FCmpInst *>(instr);
assert(icmp_instr or fcmp_instr);
string instr_ir; string instr_ir;
bool reverse = false; bool reverse = false;
switch (cmp_instr->get_cmp_op()) { if (icmp_instr) {
case CmpInst::EQ: switch (icmp_instr->get_cmp_op()) {
instr_ir = "beq"; case CmpInst::EQ:
break; instr_ir = "beq";
case CmpInst::NE: { break;
instr_ir = "bne"; case CmpInst::NE: {
if (instr->get_operand(1) == instr_ir = "bne";
ConstantInt::get(0, instr->get_module()) and if (instr->get_operand(1) == ConstantInt::get(0, m) and
dynamic_cast<Instruction *>(instr->get_operand(0))->is_zext()) { dynamic_cast<Instruction *>(instr->get_operand(0))
// something like: ->is_zext()) {
// %op0 = icmp slt i32 1, 2 # deepest // something like:
// %op1 = zext i1 %op0 to i32 // %op0 = icmp slt i32 1, 2 # deepest
// %op2 = icmp ne i32 %op1, 0 // %op1 = zext i1 %op0 to i32
// br i1 %op2, label %label3, label %label5 // %op2 = icmp ne i32 %op1, 0
auto deepest = static_cast<Instruction *>( // br i1 %op2, label %label3, label %label5
static_cast<Instruction *>(instr->get_operand(0)) auto deepest = static_cast<Instruction *>(
->get_operand(0)); static_cast<Instruction *>(instr->get_operand(0))
return bool2branch(deepest); ->get_operand(0));
} return bool2branch(deepest);
}
} break;
case CmpInst::GT:
instr_ir = "blt";
reverse = true;
break;
case CmpInst::GE:
instr_ir = "bge";
break;
case CmpInst::LT:
instr_ir = "blt";
break;
case CmpInst::LE:
instr_ir = "bge";
reverse = true;
break;
} }
value2reg(instr->get_operand(0), 0);
break; value2reg(instr->get_operand(1), 1);
case CmpInst::GT: return instr_ir + (reverse ? " $a1, $a0," : " $a0, $a1,");
instr_ir = "blt"; } else {
reverse = true; switch (fcmp_instr->get_cmp_op()) {
break; case FCmpInst::EQ:
case CmpInst::GE: instr_ir = "fcmp.ceq.s $fcc0";
instr_ir = "bge"; break;
break; case FCmpInst::NE:
case CmpInst::LT: instr_ir = "fcmp.cun.s $fcc0";
instr_ir = "blt"; break;
break; case FCmpInst::GT:
case CmpInst::LE: instr_ir = "fcmp.cle.s $fcc0";
instr_ir = "bge"; reverse = true;
reverse = true; break;
break; case FCmpInst::GE:
instr_ir = "fcmp.clt.s $fcc0";
reverse = true;
break;
case FCmpInst::LT:
instr_ir = "fcmp.clt.s $fcc0";
break;
case FCmpInst::LE:
instr_ir = "fcmp.cle.s $fcc0";
break;
}
value2reg(instr->get_operand(0), 0);
value2reg(instr->get_operand(1), 1);
output.push_back(instr_ir + ", " + "$fa0, $fa1");
return (reverse ? "bceqz $fcc0," : "bcnez $fcc0,");
} }
value2reg(instr->get_operand(0), 0);
value2reg(instr->get_operand(1), 1);
return instr_ir + (reverse ? " $a1, $a0 " : " $a0, $a1 ");
} }
void void
...@@ -287,85 +350,33 @@ CodeGen::IR2assem(CallInst *instr) { ...@@ -287,85 +350,33 @@ CodeGen::IR2assem(CallInst *instr) {
auto func = static_cast<Function *>(instr->get_operand(0)); auto func = static_cast<Function *>(instr->get_operand(0));
// 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(func_arg_N[func]));
string instr_ir, suff, reg;
// 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());
string suff = suffix(tplen); instr_ir = (arg->get_type()->is_float_type() ? "fst" : "st");
suff = suffix(arg->get_type());
reg = (arg->get_type()->is_float_type() ? "$fa0" : "$a0");
value2reg(arg); value2reg(arg);
output.push_back("st" + suff + " $a0, $sp, " + output.push_back(instr_ir + suff + " " + reg + ", $sp, " +
to_string(func_arg_off[func][i])); to_string(func_arg_off[func][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])); output.push_back("addi.d $sp, $sp, " + to_string(func_arg_N[func]));
output.push_back("addi.d $fp, $sp, " + to_string(stackN)); output.push_back("addi.d $fp, $sp, " + to_string(stackN));
if (not instr->is_void())
back2stack(instr);
} }
/* void
* CodeGen::IR2assem(CmpInst *instr) {
* value2reg(instr->get_operand(0), 0);
* value2reg(instr->get_operand(1), 1);
* string instr_ir;
* switch (instr->get_cmp_op()) {
* case CmpInst::EQ:
* break;
* case CmpInst::NE:
* // output.push_back("xor $a0, $a0, $a1");
* break;
* case CmpInst::GT:
* output.push_back("slt $a0, $a1, $a0");
* break;
* case CmpInst::GE:
* break;
* case CmpInst::LT:
* output.push_back("slt $a0, $a0, $a1");
* break;
* case CmpInst::LE:
* break;
* }
* output.push_back(instr_ir + " $a0, $a0, $a1");
* back2stack(instr);
* } */
void void
CodeGen::IR2assem(BinaryInst *instr) { CodeGen::IR2assem(BinaryInst *instr) {
auto is_float = instr->get_type()->is_float_type();
value2reg(instr->get_operand(0), 0); value2reg(instr->get_operand(0), 0);
value2reg(instr->get_operand(1), 1); value2reg(instr->get_operand(1), 1);
string suff = suffix(typeLen(instr->get_type())); string instr_ir = instr->get_instr_op_name();
string instr_ir; string suff = suffix(instr->get_type());
switch (instr->get_instr_type()) { output.push_back(instr_ir + suff +
case Instruction::add: (is_float ? " $fa0, $fa0, $fa1" : " $a0, $a0, $a1"));
instr_ir = "add";
break;
case Instruction::sub:
instr_ir = "sub";
break;
case Instruction::mul:
instr_ir = "mulw.d.w";
suff = "";
break;
case Instruction::sdiv:
instr_ir = "div";
break;
/* case Instruction::fadd:
* instr_ir = "fadd";
* break;
* case Instruction::fsub:
* instr_ir = "fsub";
* break;
* case Instruction::fmul:
* instr_ir = "fmul";
* break;
* case Instruction::fdiv:
* instr_ir = "fdiv";
* break; */
default:
assert(false && "instruction type");
}
output.push_back(instr_ir + suff + " $a0, $a0, $a1");
back2stack(instr);
} }
void void
...@@ -383,10 +394,10 @@ CodeGen::IR2assem(GetElementPtrInst *instr) { ...@@ -383,10 +394,10 @@ CodeGen::IR2assem(GetElementPtrInst *instr) {
} else } else
assert(false && "GEP translation error"); assert(false && "GEP translation error");
value2reg(instr->get_operand(i), 1); value2reg(instr->get_operand(i), 1);
output.push_back("mul.w $a1, $a1, " + to_string(size)); value2reg(ConstantInt::get(size, m), 2);
output.push_back("mul.w $a1, $a1, $a2");
output.push_back("add.d $a0, $a0, $a1"); output.push_back("add.d $a0, $a0, $a1");
} }
back2stack(instr);
} }
void void
...@@ -395,18 +406,17 @@ CodeGen::IR2assem(LoadInst *instr) { ...@@ -395,18 +406,17 @@ CodeGen::IR2assem(LoadInst *instr) {
ptrContent2reg(instr->get_lval()); ptrContent2reg(instr->get_lval());
assert(instr->get_type() == instr->get_load_type()); assert(instr->get_type() == instr->get_load_type());
back2stack(instr);
/* string suff = suffix(typeLen(instr->get_load_type()));
* string addr = "$fp, -" + to_string(off[instr]);
* output.push_back("st" + suff + " $a0, " + addr); */
} }
void void
CodeGen::IR2assem(StoreInst *instr) { CodeGen::IR2assem(StoreInst *instr) {
value2reg(instr->get_rval()); value2reg(instr->get_rval(), 0);
value2reg(instr->get_lval(), 1); value2reg(instr->get_lval(), 1);
string suff = suffix(typeLen(instr->get_rval()->get_type())); bool is_float = instr->get_rval()->get_type()->is_float_type();
output.push_back("st" + suff + " $a0, $a1, 0"); string instr_ir = (is_float ? "fst" : "st");
string suff = suffix(instr->get_rval()->get_type());
string reg = (is_float ? "$fa0" : "$a0");
output.push_back(instr_ir + suff + " " + reg + ", $a1, 0");
} }
void void
...@@ -424,59 +434,60 @@ CodeGen::IR2assem(Instruction &instr) { ...@@ -424,59 +434,60 @@ CodeGen::IR2assem(Instruction &instr) {
switch (instr.get_instr_type()) { switch (instr.get_instr_type()) {
case Instruction::ret: case Instruction::ret:
IR2assem(static_cast<ReturnInst *>(&instr)); IR2assem(static_cast<ReturnInst *>(&instr));
return; break;
case Instruction::br: case Instruction::br:
IR2assem(static_cast<BranchInst *>(&instr)); IR2assem(static_cast<BranchInst *>(&instr));
return; break;
// Standard binary operators // Standard binary operators
case Instruction::add: case Instruction::add:
case Instruction::sub: case Instruction::sub:
case Instruction::mul: case Instruction::mul:
case Instruction::sdiv: case Instruction::sdiv:
IR2assem(static_cast<BinaryInst *>(&instr));
return;
// float binary operators // float binary operators
case Instruction::fadd: case Instruction::fadd:
break;
case Instruction::fsub: case Instruction::fsub:
break;
case Instruction::fmul: case Instruction::fmul:
break;
case Instruction::fdiv: case Instruction::fdiv:
IR2assem(static_cast<BinaryInst *>(&instr));
break; break;
// Memory operators // Memory operators
case Instruction::alloca: case Instruction::alloca:
IR2assem(static_cast<AllocaInst *>(&instr)); IR2assem(static_cast<AllocaInst *>(&instr));
return; break;
case Instruction::load: case Instruction::load:
IR2assem(static_cast<LoadInst *>(&instr)); IR2assem(static_cast<LoadInst *>(&instr));
return; break;
case Instruction::store: case Instruction::store:
IR2assem(static_cast<StoreInst *>(&instr)); IR2assem(static_cast<StoreInst *>(&instr));
return; break;
// Other operators // Other operators
case Instruction::cmp: case Instruction::cmp:
IR2assem(static_cast<CmpInst *>(&instr));
break; break;
case Instruction::fcmp: case Instruction::fcmp:
IR2assem(static_cast<FCmpInst *>(&instr));
break; break;
case Instruction::phi: case Instruction::phi:
IR2assem(static_cast<PhiInst *>(&instr)); IR2assem(static_cast<PhiInst *>(&instr));
return; break;
case Instruction::call: case Instruction::call:
IR2assem(static_cast<CallInst *>(&instr)); IR2assem(static_cast<CallInst *>(&instr));
return; break;
case Instruction::getelementptr: case Instruction::getelementptr:
IR2assem(static_cast<GetElementPtrInst *>(&instr)); IR2assem(static_cast<GetElementPtrInst *>(&instr));
return; break;
case Instruction::zext: case Instruction::zext:
IR2assem(static_cast<ZextInst *>(&instr)); IR2assem(static_cast<ZextInst *>(&instr));
return; break;
case Instruction::fptosi: case Instruction::fptosi:
IR2assem(static_cast<FpToSiInst *>(&instr)); IR2assem(static_cast<FpToSiInst *>(&instr));
return; break;
case Instruction::sitofp: case Instruction::sitofp:
IR2assem(static_cast<SiToFpInst *>(&instr)); IR2assem(static_cast<SiToFpInst *>(&instr));
return; break;
} }
// assert(false && "This ") // assert(false && "This ")
if (not instr.is_void() and not no_stack_alloca(&instr) and
not instr.is_alloca())
back2stack(&instr);
} }
...@@ -6,7 +6,7 @@ import argparse ...@@ -6,7 +6,7 @@ import argparse
import subprocess import subprocess
test_dir = os.path.dirname(os.path.abspath(__file__)) # 当前文件夹路径 tests/5-bonus test_dir = os.path.dirname(os.path.abspath(__file__)) # 当前文件夹路径 tests/5-bonus
cminus = os.path.join(test_dir, '../../build/cminus') # ===可修改=== cminus = os.path.join(test_dir, '../../build/cminusfc') # ===可修改===
testfile_dir = os.path.join(test_dir, './testcases') testfile_dir = os.path.join(test_dir, './testcases')
output_file_name = os.path.join(test_dir, './test_result') output_file_name = os.path.join(test_dir, './test_result')
io = os.path.join(test_dir, '../../src/io/io.c') io = os.path.join(test_dir, '../../src/io/io.c')
...@@ -56,7 +56,8 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False): ...@@ -56,7 +56,8 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
# 超时,跳过 # 超时,跳过
if start_time - total_start > 30 * 60 or start_time - single_begin > 30 * 60: if start_time - total_start > 30 * 60 or start_time - single_begin > 30 * 60:
output_file.write(f"[{count+1}/{test_count}] " + file_name + ': skipped due to exceeded total time limit\n') output_file.write(f"[{count+1}/{test_count}] " + file_name +
': skipped due to exceeded total time limit\n')
continue continue
# 未超时 # 未超时
output_file.write(f"[{count+1}/{test_count}] " + file_name + ': ') output_file.write(f"[{count+1}/{test_count}] " + file_name + ': ')
...@@ -75,8 +76,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False): ...@@ -75,8 +76,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file.write('compile-1 timeout\n') output_file.write('compile-1 timeout\n')
failed_count += 1 failed_count += 1
continue continue
except Exception: except Exception as e:
output_file.write("compile-1 failed with an unexcept error\n") output_file.write("compile-1 failed with an unexcept error\n")
output_file.write(str(e))
failed_count += 1 failed_count += 1
continue continue
...@@ -107,8 +109,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False): ...@@ -107,8 +109,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file.write('compile timeout\n') output_file.write('compile timeout\n')
failed_count += 1 failed_count += 1
continue continue
except Exception: except Exception as e:
output_file.write("compile failed with an unexcept error\n") output_file.write("compile failed with an unexcept error\n")
output_file.write(e)
failed_count += 1 failed_count += 1
continue continue
...@@ -135,8 +138,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False): ...@@ -135,8 +138,9 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file.write("executable time limit exceeded\n") output_file.write("executable time limit exceeded\n")
failed_count += 1 failed_count += 1
continue continue
except Exception as _: except Exception as e:
output_file.write('executable runtime error\n') output_file.write('executable runtime error\n')
output_file.write(str(e))
failed_count += 1 failed_count += 1
continue continue
...@@ -159,8 +163,11 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False): ...@@ -159,8 +163,11 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
succ_count += 1 succ_count += 1
testtime[count] = time testtime[count] = time
else: else:
output_file.write('output is different from standard answer, this may be caused by wrong return code\n' # 因为退出码也会作为输出的一部分,因此输出和答案不同可能是程序崩溃造成的
) # 因为退出码也会作为输出的一部分,因此输出和答案不同可能是程序崩溃造成的 output_file.write(
'output is different from standard answer, this may be caused by wrong return code\n')
output_file.write(f"\t{ref=}")
output_file.write(f"\t{actual=}")
failed_count += 1 failed_count += 1
output_file.write(f"{failed_count} tests failed\n") output_file.write(f"{failed_count} tests failed\n")
...@@ -172,9 +179,11 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False): ...@@ -172,9 +179,11 @@ def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file.write('\t\t\tyour_cminus') output_file.write('\t\t\tyour_cminus')
for count, file_name in enumerate(testfiles): for count, file_name in enumerate(testfiles):
output_file.write('{:<20}'.format(file_name)) output_file.write('{:<20}'.format(file_name))
output_file.write('\t\t %.6f' % testtime[count] if testtime[count] != -1 else '\t\t None ') output_file.write(
'\t\t %.6f' % testtime[count] if testtime[count] != -1 else '\t\t None ')
output_file.write("===================================================================\n") output_file.write(
"===================================================================\n")
if __name__ == "__main__": if __name__ == "__main__":
...@@ -182,8 +191,10 @@ if __name__ == "__main__": ...@@ -182,8 +191,10 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser(description="functional test") parser = argparse.ArgumentParser(description="functional test")
parser.add_argument("--console", action="store_true", help="specify whether to output the result to console") parser.add_argument("--console", action="store_true",
parser.add_argument("--clang", action="store_true", help="estimate runtime when compile with clang") help="specify whether to output the result to console")
parser.add_argument("--clang", action="store_true",
help="estimate runtime when compile with clang")
args = parser.parse_args() args = parser.parse_args()
eval(args.console, testfile_dir, use_clang=args.clang) eval(args.console, testfile_dir, use_clang=args.clang)
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