Commit 1bed5bf5 authored by zygzagZ's avatar zygzagZ

Refactor arrays

parent 75ea8c19
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
void error() {
puts("runtime error");
exit(1);
}
int printInt(int a) { int printInt(int a) {
printf("%d\n", a); printf("%d\n", a);
} }
...@@ -47,28 +52,18 @@ int readInt () { ...@@ -47,28 +52,18 @@ int readInt () {
return result; return result;
} }
void error() {
puts("runtime error");
exit(1);
}
char* __latte_mem_init(size_t size, void* virtTab) { char* __latte_mem_init(size_t size, void* virtTab) {
char *buf = calloc(1, size); char *buf = calloc(1, size);
if (!buf) error(); if (!buf) error();
*((void**)buf) = virtTab; *((void**)buf) = virtTab;
return buf; return buf;
} }
char* __latte_mem_init_array(int len, size_t size, void* virtTab) { char* __latte_mem_init_array(size_t size, int len) {
if (len < 0) error(); if (len < 0) error();
if (len > (SIZE_MAX-4)/size) error(); if (len > (SIZE_MAX-4)/size) error();
char *buf = calloc(1, 4 + len * size); char *buf = calloc(1, 4 + len * size);
if (!buf) error(); if (!buf) error();
*((int*)buf) = len; // store length *((int*)buf) = len; // store length
if (virtTab) {
for (size_t i = 0; i < len; i++) {
*((void**)(buf + 4 + i * size)) = virtTab;
}
}
return buf; return buf;
} }
......
...@@ -2909,7 +2909,7 @@ bool Fun::isEqual(Type const *other, bool sub) const { ...@@ -2909,7 +2909,7 @@ bool Fun::isEqual(Type const *other, bool sub) const {
bool ClassT::isEqual(Type const *other, bool sub) const { bool ClassT::isEqual(Type const *other, bool sub) const {
if (const ClassT* casted = dynamic_cast<const ClassT*>(other)) { if (const ClassT* casted = dynamic_cast<const ClassT*>(other)) {
auto v1 = pident_->var.lock(), v2 = casted->pident_->var.lock(); auto v1 = pident_->getVar(), v2 = casted->pident_->getVar();
if (!v1 || !v2) return false; if (!v1 || !v2) return false;
if (v1 == v2) return true; if (v1 == v2) return true;
if (!sub) return false; if (!sub) return false;
...@@ -2922,5 +2922,5 @@ bool ClassT::isEqual(Type const *other, bool sub) const { ...@@ -2922,5 +2922,5 @@ bool ClassT::isEqual(Type const *other, bool sub) const {
} }
ClassInfoPtr ClassT::getClass() const { ClassInfoPtr ClassT::getClass() const {
return dynamic_pointer_cast<ClassInfo>(pident_->var.lock()); return dynamic_pointer_cast<ClassInfo>(pident_->getVar());
} }
\ No newline at end of file
...@@ -273,7 +273,9 @@ class PIdent : public Visitable ...@@ -273,7 +273,9 @@ class PIdent : public Visitable
{ {
public: public:
String string_; String string_;
std::weak_ptr<VarInfo> var; shared_ptr<VarInfo> var;
shared_ptr<VarInfo> getVar() { return var; }
PIdent(const PIdent &); PIdent(const PIdent &);
PIdent &operator=(const PIdent &); PIdent &operator=(const PIdent &);
......
...@@ -78,8 +78,7 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) { ...@@ -78,8 +78,7 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
RegisterAllocator regGen((quadEnv)); RegisterAllocator regGen((quadEnv));
regGen.allocate(); regGen.allocate();
} catch(const ParseError &e) { } catch(const ParseError &e) {
printFunction(quadEnv, f); std::cerr << "Register Allocator error: " << e.what() << endl;
throw ParseError(buf.str() + e.what());
} }
printFunction(quadEnv, f); printFunction(quadEnv, f);
...@@ -251,19 +250,16 @@ void Compiler::generateQAlloc(QAlloc &q) { ...@@ -251,19 +250,16 @@ void Compiler::generateQAlloc(QAlloc &q) {
if (r != Register(q.loc)) if (r != Register(q.loc))
append("PUSHL", r); append("PUSHL", r);
} }
assert(q.virtSymbol.empty() || !q.count);
if (q.virtSymbol.empty()) { if (q.count) {
append("PUSHL", "$0"); append("PUSHL", getRef(q.count));
} else { } else {
append("PUSHL", "$" + quote(q.virtSymbol)); append("PUSHL", "$" + quote(q.virtSymbol));
} }
append("PUSHL", "$" + to_string(q.size)); append("PUSHL", "$" + to_string(q.size));
if (q.count) {
append("PUSHL", getRef(q.count));
}
append("CALL", q.count ? "__latte_mem_init_array" : "__latte_mem_init"); append("CALL", q.count ? "__latte_mem_init_array" : "__latte_mem_init");
append("ADDL", "$" + to_string(q.count ? 12 : 8), "%esp"); append("ADDL", "$" + to_string(q.count ? 12 : 8), "%esp");
...@@ -319,7 +315,7 @@ void Compiler::generateQCall(QCall &q) { ...@@ -319,7 +315,7 @@ void Compiler::generateQCall(QCall &q) {
} else { } else {
append("CALL", quote(mangleFunctionName(q.fn))); append("CALL", quote(mangleFunctionName(q.fn)));
} }
if (q.params) { if (q.params || q.self) {
append("ADDL", "$" + to_string(q.params*4 + (q.self ? 4 : 0)), "%esp"); append("ADDL", "$" + to_string(q.params*4 + (q.self ? 4 : 0)), "%esp");
} }
auto popRegs = registersToSave(q); auto popRegs = registersToSave(q);
...@@ -335,7 +331,7 @@ void Compiler::generateQCall(QCall &q) { ...@@ -335,7 +331,7 @@ void Compiler::generateQCall(QCall &q) {
void Compiler::generateQParam(QParam &q) { void Compiler::generateQParam(QParam &q) {
if (q.call) { if (q.call) {
assert(q.num >= 0); assert(q.num >= 0);
if (q.num == 1) { if (q.num == (q.call->params ? 1 : 0)) {
// first argument, need to save registers // first argument, need to save registers
for (auto r : registersToSave(*q.call)) { for (auto r : registersToSave(*q.call)) {
if (r != Register(q.call->loc)) if (r != Register(q.call->loc))
...@@ -438,6 +434,7 @@ Op Compiler::generateCmp(const VariablePtr& l, Op op, const VariablePtr &r) { ...@@ -438,6 +434,7 @@ Op Compiler::generateCmp(const VariablePtr& l, Op op, const VariablePtr &r) {
void Compiler::generateQJumpCond(QJumpCond &q) { void Compiler::generateQJumpCond(QJumpCond &q) {
auto thisBlock = q.block; auto thisBlock = q.block;
auto tgBlock = q.target->block; auto tgBlock = q.target->block;
assert(thisBlock && tgBlock);
const auto &map = tgBlock->getPhiMapping(thisBlock); const auto &map = tgBlock->getPhiMapping(thisBlock);
for (const auto &phiVars : map) { for (const auto &phiVars : map) {
if ((phiVars.first->info && phiVars.second->info && phiVars.first->info != phiVars.second->info) || if ((phiVars.first->info && phiVars.second->info && phiVars.first->info != phiVars.second->info) ||
......
...@@ -85,10 +85,7 @@ public: ...@@ -85,10 +85,7 @@ public:
} }
auto unused(const QuadruplePtr &q) const { auto unused(const QuadruplePtr &q) const {
auto ret = to_set(::aliveAfter(q, Register::assignable)); return available() - to_set(::aliveAfter(q, Register::assignable));
ret.emplace(0);
ret -= to_set(locks);
return ret;
} }
void lock(Register i) { void lock(Register i) {
...@@ -220,10 +217,6 @@ protected: ...@@ -220,10 +217,6 @@ protected:
} }
void moveTo(VariablePtr &v, Register tg) { void moveTo(VariablePtr &v, Register tg) {
if (v->constExpr) {
append("MOVL", "$"+to_string(v->val), tg);
return;
}
auto reg = Register(v); auto reg = Register(v);
if (reg == 0) { if (reg == 0) {
append("MOVL", getRef(v), tg); append("MOVL", getRef(v), tg);
......
...@@ -31,7 +31,7 @@ void TypeCheck::visitPIdent(PIdent *p_ident) ...@@ -31,7 +31,7 @@ void TypeCheck::visitPIdent(PIdent *p_ident)
p_ident->var = var; p_ident->var = var;
lastType = var->type; lastType = var->type;
if (auto ptr = dynamic_pointer_cast<ClassT>(lastType)) { if (auto ptr = dynamic_pointer_cast<ClassT>(lastType)) {
if (!ptr->pident_ || !ptr->pident_->var.lock()) if (!ptr->pident_ || !ptr->pident_->getVar())
throw runtime_error("either no pident or no var assigned found"); throw runtime_error("either no pident or no var assigned found");
} }
} }
...@@ -247,6 +247,7 @@ void TypeCheck::visitForEach(ForEach *for_each) ...@@ -247,6 +247,7 @@ void TypeCheck::visitForEach(ForEach *for_each)
VarInfoPtr var = make_shared<VarInfo>(for_each->pident_, for_each->type_->clone()); VarInfoPtr var = make_shared<VarInfo>(for_each->pident_, for_each->type_->clone());
binding->variables << var; binding->variables << var;
for_each->pident_->var = var;
scope->currentBinding = binding; scope->currentBinding = binding;
for_each->stmt_->accept(this); for_each->stmt_->accept(this);
...@@ -319,7 +320,7 @@ void TypeCheck::visitEClsMmbr(EClsMmbr *e_cls_mmbr) ...@@ -319,7 +320,7 @@ void TypeCheck::visitEClsMmbr(EClsMmbr *e_cls_mmbr)
throw ParseError("Class expected", e_cls_mmbr->expr_); throw ParseError("Class expected", e_cls_mmbr->expr_);
} }
ClassInfoPtr klass = scope->classes[type->pident_]; ClassInfoPtr klass = scope->classes[type->pident_];
assert(klass == type->pident_->var.lock()); assert(klass == type->pident_->getVar());
VarInfoPtr var = klass->variables[e_cls_mmbr->pident_]; VarInfoPtr var = klass->variables[e_cls_mmbr->pident_];
if (!var || var == scope->variables.local(e_cls_mmbr->pident_->string_)) { if (!var || var == scope->variables.local(e_cls_mmbr->pident_->string_)) {
throw UndefinedError(e_cls_mmbr->pident_); throw UndefinedError(e_cls_mmbr->pident_);
...@@ -662,6 +663,7 @@ void TypeCheck::checkFunction(FunctionInfoPtr f) ...@@ -662,6 +663,7 @@ void TypeCheck::checkFunction(FunctionInfoPtr f)
f->binding = binding; f->binding = binding;
if (scope->currentClass) { if (scope->currentClass) {
f->self = make_shared<VarInfo>("self", scope->currentClass->type); f->self = make_shared<VarInfo>("self", scope->currentClass->type);
f->self->lineLocation = f->lineLocation;
binding->variables << f->self; binding->variables << f->self;
} }
......
...@@ -73,6 +73,7 @@ public: ...@@ -73,6 +73,7 @@ public:
[[nodiscard]] set<VariablePtr> inForBlock(const BasicBlockPtr& q) const { [[nodiscard]] set<VariablePtr> inForBlock(const BasicBlockPtr& q) const {
set<VariablePtr> ret; set<VariablePtr> ret;
for (const auto& var : b->findPhi(q)) { for (const auto& var : b->findPhi(q)) {
if (var.second->constExpr) continue;
ret.emplace(var.second); ret.emplace(var.second);
} }
return in + ret; return in + ret;
......
...@@ -107,7 +107,7 @@ VariableLayout QuadrupleGenerator::captureEnv() { ...@@ -107,7 +107,7 @@ VariableLayout QuadrupleGenerator::captureEnv() {
/// expressions /// expressions
void QuadrupleGenerator::visitEVar(EVar *p) { void QuadrupleGenerator::visitEVar(EVar *p) {
auto var = p->pident_->var.lock(); auto var = p->pident_->getVar();
lastVar = alloc(var); lastVar = alloc(var);
if (var->isInstanceVariable()) { if (var->isInstanceVariable()) {
auto fn = scope->currentFunction; auto fn = scope->currentFunction;
...@@ -281,13 +281,14 @@ void QuadrupleGenerator::visitEOr(EOr *p) { ...@@ -281,13 +281,14 @@ void QuadrupleGenerator::visitEOr(EOr *p) {
leftValBlock->append(block); leftValBlock->append(block);
auto r = evalJump(p->expr_2, labelTrue, labelFalse); auto r = evalJump(p->expr_2, labelTrue, labelFalse);
if (!r) return;
if (r->constExpr) { if (!r || r->constExpr) {
assert(leftValBlock->quads.back() == llq); assert(leftValBlock->quads.back() == llq);
leftValBlock->quads.pop_back(); leftValBlock->quads.pop_back();
// could merge basic blocks now, but why bother // could merge basic blocks now, but why bother
if (r) {
lastVar = r->val ? r : l; lastVar = r->val ? r : l;
}
} else { } else {
auto rightValBlock = block; auto rightValBlock = block;
flushBasicBlock(); flushBasicBlock();
...@@ -321,17 +322,8 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) { ...@@ -321,17 +322,8 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
} }
lastVar = alloc(type->type_->clone()); lastVar = alloc(type->type_->clone());
lastVar->memory = true; lastVar->memory = true;
if (type->type_->size() > 4) { assert(type->type_->size() <= 4);
// calculate quantifier, we multiply index because size is larger than 4
auto q = alloc(type->type_->size());
auto newIndex = alloc();
// calculate var = index * quantifier
addQuad<QAssign>(newIndex, index, Op::Mul, q);
addQuad<QAccess>(lastVar, lhs, newIndex, 1, 4); // 4 accounts for table length entry
} else {
addQuad<QAccess>(lastVar, lhs, index, type->type_->size(), 4); // 4 accounts for table length entry addQuad<QAccess>(lastVar, lhs, index, type->type_->size(), 4); // 4 accounts for table length entry
}
Bool b; Bool b;
if (type->type_->isEqual(&b)) { if (type->type_->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar); addLastVarCondJump(nullptr, Op::Copy, lastVar);
...@@ -340,23 +332,13 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) { ...@@ -340,23 +332,13 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) { void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) {
auto l = evalJump(p->expr_, labelTrue, labelFalse); auto l = evalJump(p->expr_, labelTrue, labelFalse);
auto var = p->pident_->var.lock(); auto var = p->pident_->getVar();
assert(var); assert(var);
// it cannot be function, as function might only be used in EApp and are handled directly there // it cannot be function, as function might only be used in EApp and are handled directly there
assert(!var->toFunction()); assert(!var->toFunction());
// Array length calculation works because of arrayLengthVar that has offset 0 // Array length calculation works because of arrayLengthVar that has offset 0
size_t offset = var->offset;
if (dynamic_cast<EIndexAcc*>(p->expr_)) {
// opt if EIndexAcc is used inside visitEClsMmbr
auto access = dynamic_pointer_cast<QAccess>(lastQuad);
access->access.offset += offset;
l->info = var;
lastVar = l;
} else {
lastVar = alloc(var); lastVar = alloc(var);
auto quad = make_shared<QAccess>(lastVar, l, nullptr, 0, offset); addQuad<QAccess>(lastVar, l, nullptr, 0, var->offset);
addQuad(quad);
}
Bool b; Bool b;
if (var->type->isEqual(&b)) { if (var->type->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar); addLastVarCondJump(nullptr, Op::Copy, lastVar);
...@@ -371,10 +353,10 @@ void QuadrupleGenerator::visitEApp(EApp *p) { ...@@ -371,10 +353,10 @@ void QuadrupleGenerator::visitEApp(EApp *p) {
// call tab[i].fun() // call tab[i].fun()
// call obj.fun() // call obj.fun()
self = evalExpr(mem->expr_); self = evalExpr(mem->expr_);
info = static_pointer_cast<FunctionInfo>(mem->pident_->var.lock()); info = static_pointer_cast<FunctionInfo>(mem->pident_->getVar());
} else if (auto ident = dynamic_cast<EVar*>(p->expr_)) { } else if (auto ident = dynamic_cast<EVar*>(p->expr_)) {
auto klass = scope->currentFunction->klass.lock(); auto klass = scope->currentFunction->klass.lock();
info = static_pointer_cast<FunctionInfo>(ident->pident_->var.lock()); info = static_pointer_cast<FunctionInfo>(ident->pident_->getVar());
auto otherClass = info->klass.lock(); auto otherClass = info->klass.lock();
if (otherClass) { if (otherClass) {
// call fun() = self.fun() // call fun() = self.fun()
...@@ -416,20 +398,14 @@ void QuadrupleGenerator::visitENewArray(ENewArray *p) { ...@@ -416,20 +398,14 @@ void QuadrupleGenerator::visitENewArray(ENewArray *p) {
// allocate enough memory with calloc, if it is class then init each entry... // allocate enough memory with calloc, if it is class then init each entry...
auto type = p->type_; auto type = p->type_;
size_t size = type->size(); size_t size = type->size();
string virtSymbol;
if (auto klass = dynamic_cast<ClassT*>(type)) {
auto info = klass->pident_->var.lock()->toClass();
size = info->size;
virtSymbol = Compiler::getVirtName(info);
}
auto count = evalExpr(p->expr_); auto count = evalExpr(p->expr_);
lastVar = alloc(new Array(type->clone())); lastVar = alloc(new Array(type->clone()));
addQuad<QAlloc>(lastVar, size, virtSymbol, count); addQuad<QAlloc>(lastVar, size, "", count);
} }
void QuadrupleGenerator::visitENewClass(ENewClass *p) { void QuadrupleGenerator::visitENewClass(ENewClass *p) {
// allocate enough memory with calloc, setup virt table pointer. // allocate enough memory with calloc, setup virt table pointer.
auto info = p->pident_->var.lock()->toClass(); auto info = p->pident_->getVar()->toClass();
size_t size = info->size; size_t size = info->size;
string virtSymbol = Compiler::getVirtName(info); string virtSymbol = Compiler::getVirtName(info);
lastVar = alloc(); lastVar = alloc();
...@@ -439,7 +415,7 @@ void QuadrupleGenerator::visitENewClass(ENewClass *p) { ...@@ -439,7 +415,7 @@ void QuadrupleGenerator::visitENewClass(ENewClass *p) {
/// statements /// statements
void QuadrupleGenerator::visitInit(Init *p) { void QuadrupleGenerator::visitInit(Init *p) {
auto info = p->pident_->var.lock(); auto info = p->pident_->getVar();
assert(info); assert(info);
auto var = evalExpr(p->expr_); auto var = evalExpr(p->expr_);
auto loc = alloc(info); auto loc = alloc(info);
...@@ -449,7 +425,7 @@ void QuadrupleGenerator::visitInit(Init *p) { ...@@ -449,7 +425,7 @@ void QuadrupleGenerator::visitInit(Init *p) {
} }
void QuadrupleGenerator::visitNoInit(Init *p) { void QuadrupleGenerator::visitNoInit(Init *p) {
auto info = p->pident_->var.lock(); auto info = p->pident_->getVar();
assert(info); assert(info);
auto loc = alloc(info); auto loc = alloc(info);
addQuad<QAssign>(loc, Op::Copy, alloc(0)); addQuad<QAssign>(loc, Op::Copy, alloc(0));
...@@ -531,8 +507,10 @@ void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) { ...@@ -531,8 +507,10 @@ void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
if (condVar->constExpr) { if (condVar->constExpr) {
assert(!dynamic_pointer_cast<QJump>(lastQuad)); assert(!dynamic_pointer_cast<QJump>(lastQuad));
if (condVar->val) { if (condVar->val) {
addQuad(ifBranch);
stmt_1->accept(this); stmt_1->accept(this);
} else if (stmt_2) { } else if (stmt_2) {
addQuad(elseBranch);
stmt_2->accept(this); stmt_2->accept(this);
} }
return; return;
...@@ -647,8 +625,83 @@ void QuadrupleGenerator::visitSExp(SExp *p) { ...@@ -647,8 +625,83 @@ void QuadrupleGenerator::visitSExp(SExp *p) {
evalExpr(p->expr_); evalExpr(p->expr_);
} }
void QuadrupleGenerator::visitForEach(ForEach *p) { void QuadrupleGenerator::visitForEach(ForEach *expr) {
auto tab = evalExpr(p->expr_); auto cond = make_shared<QLabel>("for_cond");
// throw ParseError("ForEach is yet unimplemented!", p);
// TODO: implement auto arr = evalExpr(expr->expr_);
addQuad<QJump>(cond);
auto beforeBlock = flushBasicBlock(); // jump <- loop -> cond
auto loop = make_shared<QLabel>("for_loop");
addQuad(loop); // jump <- loop
// hook env
auto env1 = captureEnv();
// produce all variables hooks
for (const auto& change : env1.changes) {
if (!change.second.first) continue;
auto info = change.first;
info->loc = nullptr;
alloc(info);
}
VarInfoPtr iter = make_shared<VarInfo>("_it", make_shared<Int>());
auto iter1 = alloc(iter);
// save hooks for later
env1.capture();
// env2 starts with hooked variables
auto env2 = captureEnv();
auto loopFirstBlock = block;
auto iterInfo = expr->pident_->getVar();
assert(iterInfo);
auto iterVar = alloc(iterInfo);
addQuad<QAccess>(iterVar, arr, iter1, 4, 4);
expr->stmt_->accept(this);
iter->loc = nullptr;
auto iter2 = alloc(iter);
addQuad<QAssign>(iter2, iter1, Op::Plus, alloc(1));
auto loopLastBlock = flushBasicBlock(true); // jump <- cond
auto condFirstBlock = block;
addQuad(cond);
// env2 contains changed hooks
env2.capture();
// restore env1 pre-hook variables
env1.revert();
beforeBlock->append(condFirstBlock);
for (const auto& p : env2.changes) {
auto info = p.first;
auto hooked = p.second.first;
auto looped = p.second.second;
if (!hooked) continue;
auto orig = env1.changes[info].first;
// save hooks if used
info->loc = hooked;
// transition from pre-hook to hooked var [before -> cond]
condFirstBlock->addPhi(beforeBlock, hooked, orig);
// transition from hooked var
condFirstBlock->addPhi(loopLastBlock, hooked, looped);
// loopLastBlock doesn't need phi, it has only one incoming block
}
condFirstBlock->addPhi(beforeBlock, iter1, alloc(0));
condFirstBlock->addPhi(loopLastBlock, iter1, iter2);
auto len = alloc();
addQuad<QAccess>(len, arr, nullptr, 0, 0);
addQuad<QJumpCond>(loop, iter1, Op::LT, len);
auto condLastBlock = flushBasicBlock(true); // jump -> loop
condLastBlock->append(loopFirstBlock);
// next block is ready to use updated variables
} }
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