Commit 459ffddf authored by zygzagZ's avatar zygzagZ

Dopychanie kolanem

parent e694f348
...@@ -3,14 +3,14 @@ CCFLAGS=-g -W -Wall -O0 -std=c++2a -Wno-unused-parameter ...@@ -3,14 +3,14 @@ CCFLAGS=-g -W -Wall -O0 -std=c++2a -Wno-unused-parameter
.PHONY : clean distclean .PHONY : clean distclean
all : latc all : latc_x86
clean : clean :
rm -f *.o latc Grammar.aux Grammar.log Grammar.pdf Grammar.dvi Grammar.ps Grammar rm -f *.o latc_x86 Grammar.aux Grammar.log Grammar.pdf Grammar.dvi Grammar.ps Grammar
latc : Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o QuadrupleGenerator.o RegisterAllocator.o Latte.o latc_x86 : Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o QuadrupleGenerator.o RegisterAllocator.o Latte.o
@echo "Linking latc..." @echo "Linking latc_x86..."
${CC} ${CCFLAGS} $^ -lstdc++fs -o latc ${CC} ${CCFLAGS} $^ -lstdc++fs -o latc_x86
Absyn.o : src/Absyn.cpp src/Absyn.h Absyn.o : src/Absyn.cpp src/Absyn.h
${CC} ${CCFLAGS} -c src/Absyn.cpp ${CC} ${CCFLAGS} -c src/Absyn.cpp
...@@ -30,7 +30,7 @@ Skeleton.o : src/Skeleton.cpp src/Skeleton.h src/Absyn.h ...@@ -30,7 +30,7 @@ Skeleton.o : src/Skeleton.cpp src/Skeleton.h src/Absyn.h
TypeCheck.o : src/TypeCheck.cpp src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h TypeCheck.o : src/TypeCheck.cpp src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h
${CC} ${CCFLAGS} -c src/TypeCheck.cpp ${CC} ${CCFLAGS} -c src/TypeCheck.cpp
Compiler.o : src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h src/codeGen/QuadrupleGenerator.h src/codeGen/RegisterAllocator.h src/codeGen/Graph.h Compiler.o : src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h src/codeGen/QuadrupleGenerator.h src/codeGen/RegisterAllocator.h src/codeGen/Graph.h src/codeGen/BasicBlock.h
${CC} ${CCFLAGS} -c src/Compiler.cpp ${CC} ${CCFLAGS} -c src/Compiler.cpp
Info.o : src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h Info.o : src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
extern std::filesystem::path binaryPath; extern std::filesystem::path binaryPath;
const std::string Compiler::extension = "s"; const std::string Compiler::extension = "s";
void Compiler::externalCommand(std::filesystem::path lat) { void Compiler::externalCommand(std::filesystem::path lat) {
return;
auto obj = lat; auto obj = lat;
obj.replace_extension("o"); obj.replace_extension("o");
auto cmd = std::string("as --32 '") + lat.string() + "' -o '" + obj.string() + "'"; auto cmd = std::string("as --32 '") + lat.string() + "' -o '" + obj.string() + "'";
...@@ -16,9 +15,10 @@ void Compiler::externalCommand(std::filesystem::path lat) { ...@@ -16,9 +15,10 @@ void Compiler::externalCommand(std::filesystem::path lat) {
system(cmd.data()); system(cmd.data());
auto lib = binaryPath.parent_path() / "lib"; auto lib = binaryPath.parent_path() / "lib";
auto runtime = lib / "runtime.o"; auto runtime = lib / "runtime.o";
auto libc = lib / "libc.a";
auto result = obj; auto result = obj;
result.replace_extension(""); result.replace_extension("");
cmd = std::string("ld -m elf_i386 -L'") + lib.string() + "' '" + runtime.string() + "' '" + obj.string() + "' -o '" + result.string() + "'"; cmd = std::string("ld -m elf_i386 -L'") + lib.string() + "' '" + runtime.string() + "' '" + libc.string() + "' '" + obj.string() + "' -o '" + result.string() + "'";
cerr << cmd << endl; cerr << cmd << endl;
system(cmd.data()); system(cmd.data());
} }
...@@ -55,6 +55,9 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) { ...@@ -55,6 +55,9 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
// c++ thiscall ecx, stack right-to-left (push c, push b, push a) // c++ thiscall ecx, stack right-to-left (push c, push b, push a)
buf << "\"" << name << "\":\n"; buf << "\"" << name << "\":\n";
stringstream asmGen;
swap(buf, asmGen);
exitLabel = make_shared<QLabel>("." + name + "_exit");
QuadrupleGenerator::Result quadEnv = quadGen.compileFunction(f); QuadrupleGenerator::Result quadEnv = quadGen.compileFunction(f);
try { try {
RegisterAllocator regGen((quadEnv)); RegisterAllocator regGen((quadEnv));
...@@ -65,12 +68,28 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) { ...@@ -65,12 +68,28 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
} }
printFunction(quadEnv); printFunction(quadEnv);
swap(buf, asmGen);
// for (auto &b : quadEnv.blocks) { // for (auto &b : quadEnv.blocks) {
// for (auto &q : b->quads) { // for (auto &q : b->quads) {
// q->generateAsm(*this); // q->generateAsm(*this);
// } // }
// } // }
uint localsCount = temps.size() + localInfos.size();
for (auto i : calleeSavedRegisters)
append("PUSH", Register(i));
buf <<
"\tpush %ebp\n"
"\tmov %esp, %ebp\n";
if (localsCount) {
buf << "\tsub $" + to_string(localsCount * 4) << ",%esp\n";
}
buf << asmGen.str();
buf << "\"" << exitLabel->label << "\":\n" <<
"MOVL %ebp, %esp\n"
"POP %ebp\n";
for (auto i : calleeSavedRegisters)
append("POP", Register(i));
buf << "RET\n";
for (auto &t : temps) t->localOffset = 0; for (auto &t : temps) t->localOffset = 0;
for (auto &v : localInfos) v->localOffset = 0; for (auto &v : localInfos) v->localOffset = 0;
...@@ -81,30 +100,30 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) { ...@@ -81,30 +100,30 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
void Compiler::printFunction(QuadrupleGenerator::Result quadEnv) { void Compiler::printFunction(QuadrupleGenerator::Result quadEnv) {
int blkNo = 0; int blkNo = 0;
for (const auto& b : quadEnv.blocks) { for (const auto& b : quadEnv.blocks) {
buf << "----------------------------------------------------------------------------\n"; cout << "----------------------------------------------------------------------------\n";
buf << "blok " << blkNo << " " << b->getName() << endl; cout << "blok " << blkNo << " " << b->getName() << endl;
/*buf << "in: "; /*cout << "in: ";
for (auto in : b->in) { for (auto in : b->in) {
buf << in->getName() << " "; cout << in->getName() << " ";
} }
buf << "\nouts: "; cout << "\nouts: ";
for (auto out : b->out) { for (auto out : b->out) {
buf << out->getName() << " "; cout << out->getName() << " ";
} }
buf << "\n";*/ cout << "\n";*/
if (!b->flow.in.empty()) { if (!b->flow.in.empty()) {
buf << "in: "; cout << "in: ";
for (const auto& v : b->flow.in) { for (const auto& v : b->flow.in) {
buf << v->name << ", "; cout << v->name << ", ";
} }
buf << "\n----------\n"; cout << "\n----------\n";
} }
if (!b->flow.def.empty()) { if (!b->flow.def.empty()) {
buf << "def: "; cout << "def: ";
for (const auto& v : b->flow.def) { for (const auto& v : b->flow.def) {
buf << v->name << ", "; cout << v->name << ", ";
} }
buf << "\n----------\n"; cout << "\n----------\n";
} }
for (const auto& q : b->quads) { for (const auto& q : b->quads) {
auto ret = q->toString(); auto ret = q->toString();
...@@ -115,35 +134,49 @@ void Compiler::printFunction(QuadrupleGenerator::Result quadEnv) { ...@@ -115,35 +134,49 @@ void Compiler::printFunction(QuadrupleGenerator::Result quadEnv) {
if (c == '\t') len += 8 - (len % 8); if (c == '\t') len += 8 - (len % 8);
} }
for (; len < 70; len++) ret += ' '; for (; len < 70; len++) ret += ' ';
buf << ret << " alive: "; cout << ret << " alive: ";
for (auto var : q->aliveAfter) for (auto var : q->aliveAfter)
buf << var->name << " "; cout << var->name << " ";
buf << endl; cout << endl;
cout << "\x1b[37;1m";
stringstream asmStr;
swap(asmStr, buf);
q->generateAsm(*this); q->generateAsm(*this);
swap(asmStr, buf);
buf << asmStr.str();
cout << asmStr.str();
cout << "\x1b[0m";
} }
} }
if (!b->flow.use.empty()) { if (!b->flow.use.empty()) {
buf << "----------\nuse: "; cout << "----------\nuse: ";
for (const auto &v : b->flow.use) { for (const auto &v : b->flow.use) {
buf << v->name << ", "; cout << v->name << ", ";
} }
buf << "\n"; cout << "\n";
} }
if (!b->flow.out.empty()) { if (!b->flow.out.empty()) {
buf << "----------\nout: "; cout << "----------\nout: ";
for (const auto &v : b->flow.out) { for (const auto &v : b->flow.out) {
buf << v->name << ", "; cout << v->name << ", ";
} }
buf << "\n"; cout << "\n";
} }
blkNo++; blkNo++;
} }
generateStandardReturn();
} }
const char* const Compiler::regs[6] = {"eax", "ebx", "ecx", "edx", "esi", "edi"}; const char* const Compiler::regs[6] = {"eax", "ebx", "ecx", "edx", "edi", "esi"};
const int Compiler::callerSavedRegisters[2] = {2, 3};
const int Compiler::calleeSavedRegisters[3] = {1, 4, 5};
string Compiler::getRef(VariablePtr &v) { string Compiler::getRef(VariablePtr &v) {
if (v->registerColor == -1) { if (v->registerColor == -1) {
if (v->constExpr) {
return "$" + to_string(v->val);
}
if (!v->localOffset) { if (!v->localOffset) {
if (v->info) { if (v->info) {
if (!v->info->localOffset) { if (!v->info->localOffset) {
...@@ -156,40 +189,50 @@ string Compiler::getRef(VariablePtr &v) { ...@@ -156,40 +189,50 @@ string Compiler::getRef(VariablePtr &v) {
v->localOffset = 4 * (temps.size() + localInfos.size()); v->localOffset = 4 * (temps.size() + localInfos.size());
} }
} }
return to_string(v->localOffset) + "(%ebp)"; return to_string(-v->localOffset) + "(%ebp)";
} else { } else {
return Register(v); return Register(v);
} }
} }
void Compiler::generateQJumpCond(QJumpCond &q) {
// return QJump::generateAsm();
}
void Compiler::generateQAlloc(QAlloc &q) { void Compiler::generateQAlloc(QAlloc &q) {
// memory = extension
throw runtime_error("Memory alloc unimplemented!");
} }
void Compiler::generateQWrite(QWrite &q) { void Compiler::generateQWrite(QWrite &q) {
// return Quadruple::generateAsm(); // memory = extension
throw runtime_error("Memory write unimplemented!");
} }
void Compiler::generateQAccess(QAccess &q) { void Compiler::generateQAccess(QAccess &q) {
// return Quadruple::generateAsm(); // memory = extension
throw runtime_error("Memory access unimplemented!");
} }
void Compiler::generateQReturn(QReturn &q) { void Compiler::generateQReturn(QReturn &q) {
// return Quadruple::generateAsm(); if (q.val)
moveTo(q.val, 0);
append("JMP", "\"" + exitLabel->label + "\"");
} }
void Compiler::generateQCall(QCall &q) { void Compiler::generateQCall(QCall &q) {
// return Quadruple::generateAsm(); // return Quadruple::generateAsm();
if (q.self) {
throw runtime_error("Class call unimplemented!");
}
append("CALL", "\"" + mangleFunctionName(q.fn) + "\"");
if (q.params) {
append("ADDL", "$" + to_string(q.params*4), "%esp");
}
auto popRegs = registersToSave(q);
for (auto r = popRegs.rbegin(); r != popRegs.rend(); r++) {
append("POPL", *r);
}
if (q.aliveAfter.count(q.loc)) {
moveTo(0, q.loc);
}
} }
void Compiler::generateQParam(QParam &q) { void Compiler::generateQParam(QParam &q) {
...@@ -200,20 +243,66 @@ void Compiler::generateQParam(QParam &q) { ...@@ -200,20 +243,66 @@ void Compiler::generateQParam(QParam &q) {
if (reg == 0) { if (reg == 0) {
q.param->localOffset = offset; q.param->localOffset = offset;
} else { } else {
append("MOVL", to_string(offset)+"(%ebp)"); append("MOVL", to_string(-offset)+"(%ebp)", reg);
} }
} else { } else {
if (q.num == 1 && q.call) {
// first argument, need to save registers
for (auto r : registersToSave(*q.call)) {
append("PUSHL", r);
}
}
append("PUSHL", getRef(q.param)); append("PUSHL", getRef(q.param));
} }
} }
void Compiler::generateQJump(QJump &q) { void Compiler::generateQJump(QJump &q) {
// return Quadruple::generateAsm(); // return Quadruple::generateAsm();
// append("JMP", q.block.la) append("JMP", getBlockLabelText(q.target));
}
void Compiler::generateQJumpCond(QJumpCond &q) {
auto op = q.op;
if (q.left) {
assert(!q.left->constExpr || !q.right->constExpr);
auto regL = Register(q.left), regR = Register(q.right);
auto locL = getRef(q.left);
auto locR = getRef(q.right);
if (regL == 0 && regR == 0) {
append("MOVL", locR, regR);
locR = regR;
} else if (regL != 0 && regR == 0) {
// left is in register but right is not - swap operands
// as right needs to be a register
swap(locL, locR);
if (op.kind() == Op::CMP && op != Op::EQ && op != Op::NEQ)
op = op.neg();
}
append("CMP", locL, locR);
} else {
if (q.right->constExpr) {
if ((op == Op::Not) ^ q.right->val) {
generateQJump(q);
}
return;
}
auto tg = moveToAnyRegister(q.right);
append("CMP", tg, tg);
}
if (op.kind() != Op::CMP && op.kind() != Op::UNARY) throw runtime_error("Unexpected operator in compare");
string operand = getOpName(op);
// getOpName returns SETZ, SETNE, SET*, replace it to JMP
operand.replace(0,3, "J");
// if (operand == "SETZ" || operand == "SETNZ") {
//
// } else {
// operand.replace(0,3, "JMP");
// }
append(operand, getBlockLabelText(q.target));
} }
void Compiler::generateQAssign(QAssign &q) { void Compiler::generateQAssign(QAssign &q) {
if (!q.aliveAfter.count(q.loc)) return;
Register tg(q.loc); Register tg(q.loc);
if (q.args.size() == 1) { if (q.args.size() == 1) {
auto &arg = q.args[0]; auto &arg = q.args[0];
...@@ -231,7 +320,8 @@ void Compiler::generateQAssign(QAssign &q) { ...@@ -231,7 +320,8 @@ void Compiler::generateQAssign(QAssign &q) {
} }
case Op::Copy: { case Op::Copy: {
if (arg->constExpr) { if (arg->constExpr) {
// TODO append("MOVL", "$"+to_string(arg->val), getRef(q.loc));
return;
} else { } else {
moveTo(arg, tg); moveTo(arg, tg);
} }
...@@ -248,20 +338,23 @@ void Compiler::generateQAssign(QAssign &q) { ...@@ -248,20 +338,23 @@ void Compiler::generateQAssign(QAssign &q) {
auto &i = q.args[0], &j = q.args[1]; auto &i = q.args[0], &j = q.args[1];
if (q.op == Op::Div || q.op == Op::Mod) { if (q.op == Op::Div || q.op == Op::Mod) {
auto edx = Register("edx"); auto edx = Register("edx");
bool backupEdx = edx != tg && edx != Register(i); bool edxAlive = false;
if (backupEdx) append("MOVL", edx, "4(%esp)"); for (auto &alive : q.aliveAfter)
auto jLoc = edx != Register(j) ? getRef(j) : "4(%esp)"; if (Register(alive) == edx) {
edxAlive = true;
}
bool backupEdx = edx != tg && edx != Register(i) && (edx == Register(j) || edxAlive);
if (backupEdx) append("MOVL", edx, "-4(%esp)");
auto jLoc = edx != Register(j) ? getRef(j) : "-4(%esp)";
moveTo(i, 0); moveTo(i, 0);
append("CLTD"); // edx lost append("CLTD"); // edx lost
append("IDIVL", jLoc); append("IDIVL", jLoc);
moveTo(q.op == Op::Mod ? edx : 0, getRef(q.loc)); append("MOVL", q.op == Op::Mod ? edx : 0, getRef(q.loc));
// restore unnecessary if j was in edx and becomes dead and was NOT coalesced // restore unnecessary if j was in edx and becomes dead and was NOT coalesced
if (backupEdx) append("MOVL", "4(%esp)", edx); // not easy to check if not coalesced, so move anyway
if (backupEdx && edxAlive) append("MOVL", "-4(%esp)", edx);
return; return;
} else if (q.op < Op::CMP) { } else if (q.op.kind() == Op::CMP) {
moveTo(i, tg);
append(q.op, getRef(i), tg);
} else {
auto loc = getRef(i); auto loc = getRef(i);
if (Register(i) == 0 && Register(j) == 0) { if (Register(i) == 0 && Register(j) == 0) {
moveTo(i, 0); moveTo(i, 0);
...@@ -270,6 +363,19 @@ void Compiler::generateQAssign(QAssign &q) { ...@@ -270,6 +363,19 @@ void Compiler::generateQAssign(QAssign &q) {
append("CMPL", loc, getRef(j)); append("CMPL", loc, getRef(j));
append(q.op, tg); append(q.op, tg);
} else {
assert(q.op.kind() == Op::BINARY);
bool swapped = false;
if (Register(j) == tg && tg != 0) {
swapped = true;
swap(i, j);
}
moveTo(i, tg);
append(q.op, getRef(j), tg);
if (swapped) {
if (q.op == Op::Minus)
append("NEG", tg);
}
} }
} }
if (tg == 0) { if (tg == 0) {
...@@ -278,6 +384,5 @@ void Compiler::generateQAssign(QAssign &q) { ...@@ -278,6 +384,5 @@ void Compiler::generateQAssign(QAssign &q) {
} }
void Compiler::generateQLabel(QLabel &q) { void Compiler::generateQLabel(QLabel &q) {
// return Quadruple::generateAsm(); buf << "\"" << q.label << "\":" << endl;
} }
...@@ -38,6 +38,13 @@ public: ...@@ -38,6 +38,13 @@ public:
void generateQJump(QJump &q); void generateQJump(QJump &q);
void generateQAssign(QAssign &q); void generateQAssign(QAssign &q);
void generateQLabel(QLabel &q); void generateQLabel(QLabel &q);
static std::string mangleFunctionName(const FunctionInfoPtr& f) {
if (auto c = f->klass.lock()) {
return c->name + "::" + f->name;
}
return f->name;
}
private: private:
std::filesystem::path file; std::filesystem::path file;
std::stringstream buf; std::stringstream buf;
...@@ -52,7 +59,14 @@ private: ...@@ -52,7 +59,14 @@ private:
class Register { class Register {
public: public:
Register(string n) : name(std::move(n)) {}; Register(string n) : name(n) {
for (auto reg : Compiler::regs) {
if (name == reg) {
return;
}
}
throw runtime_error("Invalid register name");
};
Register(int n) { name = Compiler::regs[n]; } Register(int n) { name = Compiler::regs[n]; }
Register(const VariablePtr &v) { name = Compiler::regs[v->registerColor + 1]; } Register(const VariablePtr &v) { name = Compiler::regs[v->registerColor + 1]; }
string name; string name;
...@@ -61,16 +75,12 @@ private: ...@@ -61,16 +75,12 @@ private:
bool operator!=(const Register &other) const { return name != other.name; } bool operator!=(const Register &other) const { return name != other.name; }
}; };
static std::string mangleFunctionName(const FunctionInfoPtr& f) {
if (auto c = f->klass.lock()) {
return c->name + "::" + f->name;
}
return f->name;
}
string getRef(VariablePtr &v); string getRef(VariablePtr &v);
static const char* const regs[6]; static const char* const regs[6];
static const int callerSavedRegisters[2];
static const int calleeSavedRegisters[3];
static string getOpName(Quadruple::Op op) { static string getOpName(Quadruple::Op op) {
switch(op.op) { switch(op.op) {
...@@ -79,10 +89,12 @@ private: ...@@ -79,10 +89,12 @@ private:
case Op::Mul: return "IMULL"; case Op::Mul: return "IMULL";
case Op::Div: case Op::Div:
case Op::Mod: throw runtime_error("Impossible to handle division with default"); case Op::Mod: throw runtime_error("Impossible to handle division with default");
case Op::Not: return "SETZ";
case Op::Copy: return "SETNZ";
case Op::LT: return "SETL"; case Op::LT: return "SETL";
case Op::LE: return "SETLE"; case Op::LE: return "SETLE";
case Op::EQ: return "SETE"; case Op::EQ: return "SETZ";
case Op::NEQ: return "SETNE"; case Op::NEQ: return "SETNZ";
case Op::GE: return "SETGE"; case Op::GE: return "SETGE";
case Op::GT: return "SETG"; case Op::GT: return "SETG";
default: return "Op" + to_string(op.op) + "?"; default: return "Op" + to_string(op.op) + "?";
...@@ -121,7 +133,57 @@ private: ...@@ -121,7 +133,57 @@ private:
} }
void append(string cmd, string op1 = "", string op2 = "", string op3 = "") { void append(string cmd, string op1 = "", string op2 = "", string op3 = "") {
buf << "\t" << cmd << " " << op1 << " " << op2 << " " << op3 << endl; append({cmd, op1, op2, op3});
}
void append(vector<string> ops) {
static const char* const delimiters = "\t ,,,,";
assert(ops.size() < 6);
while (ops.size() && ops.back().empty())
ops.pop_back();
buf << "\t";
for (uint i = 0; i < ops.size(); i++) {
buf << delimiters[i] << ops[i];
}
buf << endl;
}
string getBlockLabelText(const QuadruplePtr &q) {
return getBlockLabelText(q->block);
}
string getBlockLabelText(BasicBlockPtr &b) {
auto n = b->getName();
if (n.empty()) throw runtime_error("Attempt to get label text of unlabeled block");
return "\"" + n + "\"";
}
shared_ptr<QLabel> exitLabel;
void generateStandardReturn() {
append("JMP", "\"" + exitLabel->label + "\"");
}
vector<Register> registersToSave(QCall &q) {
const int noRegs = sizeof(callerSavedRegisters) / sizeof(*callerSavedRegisters);
bool saved[noRegs];
int notSaved = noRegs;
for (auto &i : saved) i = false;
for (auto &live : q.aliveAfter) {
for (int i = 0; i < noRegs; i++) {
int r = callerSavedRegisters[i];
if (!saved[i] && Register(live) == Register(r)) {
saved[i] = true;
--notSaved;
}
}
if (notSaved == 0) break;
}
vector<Register> ret;
for (int i = 0; i < noRegs; i++) {
if (saved[i]) ret.emplace_back(callerSavedRegisters[i]);
}
return ret;
} }
}; };
......
...@@ -50,7 +50,7 @@ public: ...@@ -50,7 +50,7 @@ public:
void addPhi(const BasicBlockPtr& blk, const VariablePtr& local, VariablePtr remote) { void addPhi(const BasicBlockPtr& blk, const VariablePtr& local, VariablePtr remote) {
assert(blk && local && remote); assert(blk && local && remote);
assert(local->info && !local->info->isInstanceVariable()); assert(!local->info || !local->info->isInstanceVariable());
auto &phiMap = findPhi(blk); auto &phiMap = findPhi(blk);
phiMap[local] = std::move(remote); phiMap[local] = std::move(remote);
} }
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
using namespace std; using namespace std;
class Compiler; class Compiler;
static const std::string opNames[] = { "_U", "-", "!", "", "_UE", static const std::string opNames[] = { "_U", "!", "", "-", "_UE",
"_B", "+", "-", "*", "/", "%", "&", "|", "^", "_BE", "_B", "+", "-", "*", "/", "%", "&", "|", "^", "_BE",
"_C", "<", "<=", "==", "!=", ">=", ">", "_CE"}; "_C", "<", ">=", "<=", ">", "==", "!=", "_CE"};
class Quadruple : public enable_shared_from_this<Quadruple> { class Quadruple : public enable_shared_from_this<Quadruple> {
public: public:
...@@ -19,22 +19,35 @@ public: ...@@ -19,22 +19,35 @@ public:
public: public:
enum OpType { enum OpType {
UNARY, UNARY,
Neg, Not, Copy, UNARY_END, Not, Copy, Neg, UNARY_END,
BINARY, BINARY,
Plus, Minus, Mul, Div, Mod, And, Or, Xor, BINARY_END, Plus, Minus, Mul, Div, Mod, And, Or, Xor, BINARY_END,
CMP, CMP,
LT, LE, EQ, NEQ, GE, GT, CMP_END LT, GE, LE, GT, EQ, NEQ, CMP_END
}; };
OpType op; OpType op;
Op(OpType op = UNARY) : op(op) {}; Op(OpType op = UNARY) : op(op) {};
operator OpType() const { return op; }; operator OpType() const { return op; };
Op neg() const {
if (op <= Op::Copy)
return OpType(UNARY + 1 + ((int)(op - UNARY - 1)^1));
if (op > Op::CMP)
return OpType(CMP + 1 + ((int)(op - CMP - 1)^1));
throw runtime_error("Invalid argument to Op::neg()");
};
static OpType kind(OpType op) { static OpType kind(OpType op) {
if (op <= UNARY_END) return UNARY; if (op <= UNARY_END) return UNARY;
if (op <= BINARY_END) return BINARY; if (op <= BINARY_END) return BINARY;
return CMP; return CMP;
}; };
OpType kind() const {
return Op::kind(*this);
};
static const std::string& name(OpType op) { static const std::string& name(OpType op) {
return opNames[op]; return opNames[op];
} }
...@@ -71,7 +84,7 @@ public: ...@@ -71,7 +84,7 @@ public:
std::string toString() const override { return Quadruple::toString() + "\t" + (loc ? (loc->name + " := ") : ""); } std::string toString() const override { return Quadruple::toString() + "\t" + (loc ? (loc->name + " := ") : ""); }
vector<VariablePtr> definitions() const override { vector<VariablePtr> definitions() const override {
auto ret = Quadruple::definitions(); auto ret = Quadruple::definitions();
if (loc) ret.emplace_back(loc); if (loc && !loc->constExpr) ret.emplace_back(loc);
return ret; return ret;
}; };
}; };
...@@ -147,13 +160,16 @@ public: ...@@ -147,13 +160,16 @@ public:
} }
void generateAsm(Compiler &c) override; void generateAsm(Compiler &c) override;
}; };
class QCall;
class QParam : public Quadruple { class QParam : public Quadruple {
public: public:
VariablePtr param; VariablePtr param;
int num; int num;
QParam(VariablePtr param, int num) : param(std::move(param)), num(num) {}; shared_ptr<QCall> call;
QParam(VariablePtr param, int num, shared_ptr<QCall> call = nullptr) : param(std::move(param)), num(num), call(std::move(call)) {};
std::string toString() const override { std::string toString() const override {
if (num < 0) { if (num < 0) {
......
...@@ -46,10 +46,10 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f ...@@ -46,10 +46,10 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f
for (const auto& q : b->quads) { for (const auto& q : b->quads) {
q->index = index++; q->index = index++;
if (auto l = dynamic_pointer_cast<QLabel>(q)) { if (auto l = dynamic_pointer_cast<QLabel>(q)) {
if (!l->label.empty()) auto old = l->label;
l->label = to_string(label++) + "_" + l->label; l->label = "." + to_string(label++) + "_" + Compiler::mangleFunctionName(f);
else if (!old.empty())
l->label = to_string(label++); l->label += "_" + old;
} }
} }
} }
...@@ -109,10 +109,12 @@ void QuadrupleGenerator::visitELitInt(ELitInt *p) { ...@@ -109,10 +109,12 @@ void QuadrupleGenerator::visitELitInt(ELitInt *p) {
void QuadrupleGenerator::visitELitTrue(ELitTrue *p) { void QuadrupleGenerator::visitELitTrue(ELitTrue *p) {
lastVar = alloc(1); lastVar = alloc(1);
if (labelTrue) addQuad<QJump>(labelTrue);
} }
void QuadrupleGenerator::visitELitFalse(ELitFalse *p) { void QuadrupleGenerator::visitELitFalse(ELitFalse *p) {
lastVar = alloc(0); lastVar = alloc(0);
if (labelFalse) addQuad<QJump>(labelFalse);
} }
void QuadrupleGenerator::visitEString(EString *p) { void QuadrupleGenerator::visitEString(EString *p) {
...@@ -128,12 +130,20 @@ void QuadrupleGenerator::visitNeg(Neg *p) { ...@@ -128,12 +130,20 @@ void QuadrupleGenerator::visitNeg(Neg *p) {
auto var = evalExpr(p->expr_); auto var = evalExpr(p->expr_);
lastVar = alloc(); lastVar = alloc();
addQuad<QAssign>(lastVar, Op::Neg, var); addQuad<QAssign>(lastVar, Op::Neg, var);
if ((lastVar->constExpr = var->constExpr)) {
lastVar->val = -var->val;
}
} }
void QuadrupleGenerator::visitNot(Not *p) { void QuadrupleGenerator::visitNot(Not *p) {
swap(labelTrue, labelFalse);
auto var = evalExpr(p->expr_); auto var = evalExpr(p->expr_);
swap(labelTrue, labelFalse);
lastVar = alloc(); lastVar = alloc();
addQuad<QAssign>(lastVar, Op::Not, var); addQuad<QAssign>(lastVar, Op::Not, var);
if ((lastVar->constExpr = var->constExpr)) {
lastVar->val = !var->val;
}
} }
void QuadrupleGenerator::visitEMul(EMul *p) { void QuadrupleGenerator::visitEMul(EMul *p) {
...@@ -142,6 +152,16 @@ void QuadrupleGenerator::visitEMul(EMul *p) { ...@@ -142,6 +152,16 @@ void QuadrupleGenerator::visitEMul(EMul *p) {
lastVar = alloc(); lastVar = alloc();
p->mulop_->accept(this); p->mulop_->accept(this);
addQuad<QAssign>(lastVar, l, op, r); addQuad<QAssign>(lastVar, l, op, r);
if ((lastVar->constExpr = l->constExpr && r->constExpr)) {
if (op == Op::Mul)
lastVar->val = l->val * r->val;
else if (r->val == 0)
throw ParseError("Division by 0", p);
else if (op == Op::Div)
lastVar->val = l->val / r->val;
else if (op == Op::Mod)
lastVar->val = l->val % r->val;
}
} }
void QuadrupleGenerator::visitEAdd(EAdd *p) { void QuadrupleGenerator::visitEAdd(EAdd *p) {
...@@ -150,48 +170,120 @@ void QuadrupleGenerator::visitEAdd(EAdd *p) { ...@@ -150,48 +170,120 @@ void QuadrupleGenerator::visitEAdd(EAdd *p) {
lastVar = alloc(); lastVar = alloc();
p->addop_->accept(this); p->addop_->accept(this);
addQuad<QAssign>(lastVar, l, op, r); addQuad<QAssign>(lastVar, l, op, r);
if ((lastVar->constExpr = l->constExpr && r->constExpr)) {
if (op == Op::Minus)
lastVar->val = l->val - r->val;
else if (op == Op::Plus)
lastVar->val = l->val + r->val;
}
} }
void QuadrupleGenerator::visitERel(ERel *p) { void QuadrupleGenerator::visitERel(ERel *p) {
auto l = evalExpr(p->expr_1); auto l = evalJump(p->expr_1, nullptr, nullptr);
auto r = evalExpr(p->expr_2); auto r = evalJump(p->expr_2, nullptr, nullptr);
lastVar = alloc(); lastVar = alloc();
p->relop_->accept(this); p->relop_->accept(this);
if ((lastVar->constExpr = l->constExpr && r->constExpr)) {
if (op == Op::LT)
lastVar->val = l->val < r->val;
else if (op == Op::LE)
lastVar->val = l->val <= r->val;
else if (op == Op::EQ)
lastVar->val = l->val == r->val;
else if (op == Op::NEQ)
lastVar->val = l->val != r->val;
else if (op == Op::GE)
lastVar->val = l->val >= r->val;
else if (op == Op::GT)
lastVar->val = l->val > r->val;
addQuad<QAssign>(lastVar, l, op, r); addQuad<QAssign>(lastVar, l, op, r);
}
addLastVarCondJump(l, op, r);
} }
void QuadrupleGenerator::visitEAnd(EAnd *p) { void QuadrupleGenerator::visitEAnd(EAnd *p) {
auto l = evalExpr(p->expr_1); auto labelAfter = make_shared<QLabel>("and_else");
auto labelLeft = make_shared<QLabel>("use_left"); auto l = evalJump(p->expr_1, nullptr, labelFalse);
auto labelAfter = make_shared<QLabel>("end_and"); if (!l) return;
if (l->constExpr) {
lastVar = l->val ? evalJump(p->expr_2, labelTrue, labelFalse) : l;
// jest git skoczymy pozniej bo to constexpr
return;
} else {
auto leftValBlock = block;
auto llq = make_shared<QJumpCond>(labelFalse ? labelFalse : labelAfter, Op::Not, l);
addQuad(llq);
flushBasicBlock();
leftValBlock->append(block);
addQuad<QJumpCond>(labelLeft, Op::Not, l); auto r = evalJump(p->expr_2, labelTrue, labelFalse);
auto r = evalExpr(p->expr_2);
lastVar = alloc();
addQuad<QAssign>(lastVar, Op::Copy, r); if (!r || r->constExpr) {
addQuad<QJump>(labelAfter); assert(leftValBlock->quads.back() == llq);
addQuad(labelLeft); leftValBlock->quads.pop_back();
addQuad<QAssign>(lastVar, Op::Copy, alloc(0)); // could merge basic blocks now, but why bother
if (r) {
lastVar = r->val ? l : r;
}
} else {
auto rightValBlock = block;
flushBasicBlock();
addQuad(labelAfter); addQuad(labelAfter);
rightValBlock->append(block);
leftValBlock->append(block);
if (!labelTrue || !labelFalse) {
lastVar = alloc();
block->addPhi(rightValBlock, lastVar, r);
block->addPhi(leftValBlock, lastVar, l);
} else {
lastVar = nullptr;
}
}
}
} }
void QuadrupleGenerator::visitEOr(EOr *p) { void QuadrupleGenerator::visitEOr(EOr *p) {
auto l = evalExpr(p->expr_1); auto labelAfter = make_shared<QLabel>("or_else");
auto labelLeft = make_shared<QLabel>("use_left"); auto l = evalJump(p->expr_1, labelTrue, nullptr);
auto labelAfter = make_shared<QLabel>("end_or"); if (!l) return;
if (l->constExpr) {
addQuad<QJumpCond>(labelLeft, Op::Copy, l); lastVar = l->val ? l : evalJump(p->expr_2, labelTrue, labelFalse);
// jest git skoczymy pozniej bo to constexpr
return;
} else {
auto leftValBlock = block;
auto llq = make_shared<QJumpCond>(labelTrue ? labelTrue : labelAfter, Op::Copy, l);
addQuad(llq);
flushBasicBlock();
leftValBlock->append(block);
auto r = evalExpr(p->expr_2); auto r = evalExpr(p->expr_2);
lastVar = alloc(); if (!r) return;
addQuad<QAssign>(lastVar, Op::Copy, r); if (r->constExpr) {
addQuad<QJump>(labelAfter); assert(leftValBlock->quads.back() == llq);
addQuad(labelLeft); leftValBlock->quads.pop_back();
addQuad<QAssign>(lastVar, Op::Copy, alloc(1)); // could merge basic blocks now, but why bother
lastVar = r->val ? r : l;
} else {
auto rightValBlock = block;
flushBasicBlock();
addQuad(labelAfter); addQuad(labelAfter);
rightValBlock->append(block);
leftValBlock->append(block);
if (!labelTrue || !labelFalse) {
lastVar = alloc();
block->addPhi(rightValBlock, lastVar, r);
block->addPhi(leftValBlock, lastVar, l);
} else {
lastVar = nullptr;
}
}
}
} }
/// complex extensions /// complex extensions
...@@ -219,6 +311,10 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) { ...@@ -219,6 +311,10 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
} }
auto quad = make_shared<QAccess>(lastVar, lhs, index, 4, 0); auto quad = make_shared<QAccess>(lastVar, lhs, index, 4, 0);
addQuad(quad); addQuad(quad);
Bool b;
if (type->type_->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar);
}
} }
void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) { void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) {
...@@ -240,6 +336,10 @@ void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) { ...@@ -240,6 +336,10 @@ void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) {
auto quad = make_shared<QAccess>(lastVar, l, nullptr, 0, offset); auto quad = make_shared<QAccess>(lastVar, l, nullptr, 0, offset);
addQuad(quad); addQuad(quad);
} }
Bool b;
if (var->type->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar);
}
} }
void QuadrupleGenerator::visitEApp(EApp *p) { void QuadrupleGenerator::visitEApp(EApp *p) {
...@@ -270,18 +370,24 @@ void QuadrupleGenerator::visitEApp(EApp *p) { ...@@ -270,18 +370,24 @@ void QuadrupleGenerator::visitEApp(EApp *p) {
throw ParseError("Unimplemented EApp instantiation (neither EClsMmbr nor EVar", p); throw ParseError("Unimplemented EApp instantiation (neither EClsMmbr nor EVar", p);
} }
int i = 1; auto call = make_shared<QCall>(lastVar, info, p->listexpr_->size(), self);
int i = 0;
for (auto param : *p->listexpr_) { for (auto param : *p->listexpr_) {
auto var = evalExpr(param); auto var = evalExpr(param);
addQuad<QParam>(var, i++); addQuad<QParam>(var, ++i, call);
} }
if (self) { if (self) {
addQuad<QParam>(self, 0); addQuad<QParam>(self, 0, call);
} }
lastVar = alloc(); lastVar = alloc();
addQuad<QCall>(lastVar, info, i, self); addQuad(call);
Bool b;
if (info->type->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar);
}
} }
void QuadrupleGenerator::visitENewArray(ENewArray *p) { void QuadrupleGenerator::visitENewArray(ENewArray *p) {
...@@ -387,17 +493,16 @@ void QuadrupleGenerator::visitCondElse(CondElse *p) { ...@@ -387,17 +493,16 @@ void QuadrupleGenerator::visitCondElse(CondElse *p) {
} }
void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) { void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
// TODO: stmty nie składają się z jednego bloku tylko z wielu
auto elseBranch = make_shared<QLabel>("if_else"); auto elseBranch = make_shared<QLabel>("if_else");
auto after = make_shared<QLabel>("end_else"); auto after = make_shared<QLabel>("end_else");
auto ifBranch = make_shared<QLabel>("if_true");
auto var = evalExpr(expr_); evalJump(expr_, ifBranch, elseBranch);
addQuad<QJumpCond>(elseBranch, Op::Not, var);
auto beforeBlock = flushBasicBlock(); // possible jump -> else auto beforeBlock = flushBasicBlock(); // possible jump -> else
auto envIf = captureEnv(), envElse = envIf; auto envIf = captureEnv(), envElse = envIf;
auto stmtIfFirstBlock = block; auto stmtIfFirstBlock = block;
addQuad<QLabel>("if_true"); addQuad(ifBranch);
stmt_1->accept(this); stmt_1->accept(this);
addQuad<QJump>(after); addQuad<QJump>(after);
auto stmtIfLastBlock = flushBasicBlock(); // jump -> after auto stmtIfLastBlock = flushBasicBlock(); // jump -> after
......
...@@ -30,6 +30,7 @@ private: ...@@ -30,6 +30,7 @@ private:
VariablePtr lastVar; VariablePtr lastVar;
int lineno; int lineno;
shared_ptr<Scope> scope; shared_ptr<Scope> scope;
shared_ptr<QLabel> labelTrue, labelFalse;
VariablePtr evalLVal(Visitable *expr) { VariablePtr evalLVal(Visitable *expr) {
auto info = evalExpr(expr)->info; auto info = evalExpr(expr)->info;
...@@ -55,6 +56,17 @@ private: ...@@ -55,6 +56,17 @@ private:
return ret; return ret;
} }
VariablePtr evalJump(Visitable *expr, shared_ptr<QLabel> tLabel, shared_ptr<QLabel> fLabel) {
if (!expr) throw runtime_error("No expr to eval");
lineno = expr->lineno;
swap(labelTrue, tLabel);
swap(labelFalse ,fLabel);
auto ret = evalExpr(expr);
swap(labelTrue, tLabel);
swap(labelFalse ,fLabel);
return ret;
}
VariablePtr alloc(const VarInfoPtr& info) { VariablePtr alloc(const VarInfoPtr& info) {
if (info->loc) { if (info->loc) {
return info->loc; return info->loc;
...@@ -84,6 +96,22 @@ private: ...@@ -84,6 +96,22 @@ private:
return quad; return quad;
} }
void addLastVarCondJump(const VariablePtr& l, Quadruple::Op op, const VariablePtr& r) {
if (labelTrue && labelFalse) {
addQuad<QJumpCond>(labelTrue, l, op, r);
addQuad<QAssign>(lastVar, l, op, r);
addQuad<QJump>(labelFalse);
return;
} else if (labelTrue) {
addQuad<QJumpCond>(labelTrue, l, op, r);
lastVar = alloc(0);
} else if (labelFalse) {
addQuad<QJumpCond>(labelFalse, l, op.neg(), r);
lastVar = alloc(1);
} else return;
addQuad<QAssign>(lastVar, l, op, r);
}
QuadruplePtr lastQuad; QuadruplePtr lastQuad;
BasicBlockPtr newBlock() { BasicBlockPtr newBlock() {
......
...@@ -104,7 +104,7 @@ void RegisterAllocator::buildGraph() { ...@@ -104,7 +104,7 @@ void RegisterAllocator::buildGraph() {
if (v.second == -1) { if (v.second == -1) {
gNumSpill++; gNumSpill++;
} else { } else {
v.first->name += "-r" + to_string(v.second); v.first->name += "-r" + to_string(v.second + 2);
} }
} }
for (auto &v : g2.getAllocation()) { for (auto &v : g2.getAllocation()) {
......
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