Commit 1bed5bf5 authored by zygzagZ's avatar zygzagZ

Refactor arrays

parent 75ea8c19
......@@ -6,6 +6,11 @@
#include <string.h>
#include <stdint.h>
void error() {
puts("runtime error");
exit(1);
}
int printInt(int a) {
printf("%d\n", a);
}
......@@ -47,28 +52,18 @@ int readInt () {
return result;
}
void error() {
puts("runtime error");
exit(1);
}
char* __latte_mem_init(size_t size, void* virtTab) {
char *buf = calloc(1, size);
if (!buf) error();
*((void**)buf) = virtTab;
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 > (SIZE_MAX-4)/size) error();
char *buf = calloc(1, 4 + len * size);
if (!buf) error();
*((int*)buf) = len; // store length
if (virtTab) {
for (size_t i = 0; i < len; i++) {
*((void**)(buf + 4 + i * size)) = virtTab;
}
}
return buf;
}
......
......@@ -2909,7 +2909,7 @@ bool Fun::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)) {
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 true;
if (!sub) return false;
......@@ -2922,5 +2922,5 @@ bool ClassT::isEqual(Type const *other, bool sub) 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
{
public:
String string_;
std::weak_ptr<VarInfo> var;
shared_ptr<VarInfo> var;
shared_ptr<VarInfo> getVar() { return var; }
PIdent(const PIdent &);
PIdent &operator=(const PIdent &);
......
......@@ -78,8 +78,7 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
RegisterAllocator regGen((quadEnv));
regGen.allocate();
} catch(const ParseError &e) {
printFunction(quadEnv, f);
throw ParseError(buf.str() + e.what());
std::cerr << "Register Allocator error: " << e.what() << endl;
}
printFunction(quadEnv, f);
......@@ -251,19 +250,16 @@ void Compiler::generateQAlloc(QAlloc &q) {
if (r != Register(q.loc))
append("PUSHL", r);
}
assert(q.virtSymbol.empty() || !q.count);
if (q.virtSymbol.empty()) {
append("PUSHL", "$0");
if (q.count) {
append("PUSHL", getRef(q.count));
} else {
append("PUSHL", "$" + quote(q.virtSymbol));
}
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("ADDL", "$" + to_string(q.count ? 12 : 8), "%esp");
......@@ -319,7 +315,7 @@ void Compiler::generateQCall(QCall &q) {
} else {
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");
}
auto popRegs = registersToSave(q);
......@@ -335,7 +331,7 @@ void Compiler::generateQCall(QCall &q) {
void Compiler::generateQParam(QParam &q) {
if (q.call) {
assert(q.num >= 0);
if (q.num == 1) {
if (q.num == (q.call->params ? 1 : 0)) {
// first argument, need to save registers
for (auto r : registersToSave(*q.call)) {
if (r != Register(q.call->loc))
......@@ -438,12 +434,13 @@ Op Compiler::generateCmp(const VariablePtr& l, Op op, const VariablePtr &r) {
void Compiler::generateQJumpCond(QJumpCond &q) {
auto thisBlock = q.block;
auto tgBlock = q.target->block;
assert(thisBlock && tgBlock);
const auto &map = tgBlock->getPhiMapping(thisBlock);
for (const auto &phiVars : map) {
if ((phiVars.first->info && phiVars.second->info && phiVars.first->info != phiVars.second->info) ||
(phiVars.first->localOffset && phiVars.second->localOffset && phiVars.first->localOffset != phiVars.second->localOffset) ||
(phiVars.first->registerColor && phiVars.second->registerColor && phiVars.first->registerColor != phiVars.second->registerColor)
) {
(phiVars.first->localOffset && phiVars.second->localOffset && phiVars.first->localOffset != phiVars.second->localOffset) ||
(phiVars.first->registerColor && phiVars.second->registerColor && phiVars.first->registerColor != phiVars.second->registerColor)
) {
buf << ("// Unimplemented phi CondJump register XCHG\n");
}
}
......
......@@ -85,10 +85,7 @@ public:
}
auto unused(const QuadruplePtr &q) const {
auto ret = to_set(::aliveAfter(q, Register::assignable));
ret.emplace(0);
ret -= to_set(locks);
return ret;
return available() - to_set(::aliveAfter(q, Register::assignable));
}
void lock(Register i) {
......@@ -220,10 +217,6 @@ protected:
}
void moveTo(VariablePtr &v, Register tg) {
if (v->constExpr) {
append("MOVL", "$"+to_string(v->val), tg);
return;
}
auto reg = Register(v);
if (reg == 0) {
append("MOVL", getRef(v), tg);
......
......@@ -31,7 +31,7 @@ void TypeCheck::visitPIdent(PIdent *p_ident)
p_ident->var = var;
lastType = var->type;
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");
}
}
......@@ -247,6 +247,7 @@ void TypeCheck::visitForEach(ForEach *for_each)
VarInfoPtr var = make_shared<VarInfo>(for_each->pident_, for_each->type_->clone());
binding->variables << var;
for_each->pident_->var = var;
scope->currentBinding = binding;
for_each->stmt_->accept(this);
......@@ -319,7 +320,7 @@ void TypeCheck::visitEClsMmbr(EClsMmbr *e_cls_mmbr)
throw ParseError("Class expected", e_cls_mmbr->expr_);
}
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_];
if (!var || var == scope->variables.local(e_cls_mmbr->pident_->string_)) {
throw UndefinedError(e_cls_mmbr->pident_);
......@@ -662,6 +663,7 @@ void TypeCheck::checkFunction(FunctionInfoPtr f)
f->binding = binding;
if (scope->currentClass) {
f->self = make_shared<VarInfo>("self", scope->currentClass->type);
f->self->lineLocation = f->lineLocation;
binding->variables << f->self;
}
......
......@@ -73,6 +73,7 @@ public:
[[nodiscard]] set<VariablePtr> inForBlock(const BasicBlockPtr& q) const {
set<VariablePtr> ret;
for (const auto& var : b->findPhi(q)) {
if (var.second->constExpr) continue;
ret.emplace(var.second);
}
return in + ret;
......
......@@ -107,7 +107,7 @@ VariableLayout QuadrupleGenerator::captureEnv() {
/// expressions
void QuadrupleGenerator::visitEVar(EVar *p) {
auto var = p->pident_->var.lock();
auto var = p->pident_->getVar();
lastVar = alloc(var);
if (var->isInstanceVariable()) {
auto fn = scope->currentFunction;
......@@ -281,13 +281,14 @@ void QuadrupleGenerator::visitEOr(EOr *p) {
leftValBlock->append(block);
auto r = evalJump(p->expr_2, labelTrue, labelFalse);
if (!r) return;
if (r->constExpr) {
if (!r || r->constExpr) {
assert(leftValBlock->quads.back() == llq);
leftValBlock->quads.pop_back();
// could merge basic blocks now, but why bother
lastVar = r->val ? r : l;
if (r) {
lastVar = r->val ? r : l;
}
} else {
auto rightValBlock = block;
flushBasicBlock();
......@@ -321,17 +322,8 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
}
lastVar = alloc(type->type_->clone());
lastVar->memory = true;
if (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
}
assert(type->type_->size() <= 4);
addQuad<QAccess>(lastVar, lhs, index, type->type_->size(), 4); // 4 accounts for table length entry
Bool b;
if (type->type_->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar);
......@@ -340,23 +332,13 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) {
auto l = evalJump(p->expr_, labelTrue, labelFalse);
auto var = p->pident_->var.lock();
auto var = p->pident_->getVar();
assert(var);
// it cannot be function, as function might only be used in EApp and are handled directly there
assert(!var->toFunction());
// 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);
auto quad = make_shared<QAccess>(lastVar, l, nullptr, 0, offset);
addQuad(quad);
}
lastVar = alloc(var);
addQuad<QAccess>(lastVar, l, nullptr, 0, var->offset);
Bool b;
if (var->type->isEqual(&b)) {
addLastVarCondJump(nullptr, Op::Copy, lastVar);
......@@ -371,10 +353,10 @@ void QuadrupleGenerator::visitEApp(EApp *p) {
// call tab[i].fun()
// call obj.fun()
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_)) {
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();
if (otherClass) {
// call fun() = self.fun()
......@@ -416,20 +398,14 @@ void QuadrupleGenerator::visitENewArray(ENewArray *p) {
// allocate enough memory with calloc, if it is class then init each entry...
auto type = p->type_;
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_);
lastVar = alloc(new Array(type->clone()));
addQuad<QAlloc>(lastVar, size, virtSymbol, count);
addQuad<QAlloc>(lastVar, size, "", count);
}
void QuadrupleGenerator::visitENewClass(ENewClass *p) {
// 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;
string virtSymbol = Compiler::getVirtName(info);
lastVar = alloc();
......@@ -439,7 +415,7 @@ void QuadrupleGenerator::visitENewClass(ENewClass *p) {
/// statements
void QuadrupleGenerator::visitInit(Init *p) {
auto info = p->pident_->var.lock();
auto info = p->pident_->getVar();
assert(info);
auto var = evalExpr(p->expr_);
auto loc = alloc(info);
......@@ -449,7 +425,7 @@ void QuadrupleGenerator::visitInit(Init *p) {
}
void QuadrupleGenerator::visitNoInit(Init *p) {
auto info = p->pident_->var.lock();
auto info = p->pident_->getVar();
assert(info);
auto loc = alloc(info);
addQuad<QAssign>(loc, Op::Copy, alloc(0));
......@@ -531,8 +507,10 @@ void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
if (condVar->constExpr) {
assert(!dynamic_pointer_cast<QJump>(lastQuad));
if (condVar->val) {
addQuad(ifBranch);
stmt_1->accept(this);
} else if (stmt_2) {
addQuad(elseBranch);
stmt_2->accept(this);
}
return;
......@@ -647,8 +625,83 @@ void QuadrupleGenerator::visitSExp(SExp *p) {
evalExpr(p->expr_);
}
void QuadrupleGenerator::visitForEach(ForEach *p) {
auto tab = evalExpr(p->expr_);
// throw ParseError("ForEach is yet unimplemented!", p);
// TODO: implement
void QuadrupleGenerator::visitForEach(ForEach *expr) {
auto cond = make_shared<QLabel>("for_cond");
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