Commit 5b9b463e authored by zygzagZ's avatar zygzagZ

SSA+CFG, quadruple code working

parent 9234e433
......@@ -73,6 +73,10 @@ void Compiler::compileFunction(FunctionInfoPtr f) {
flushBasicBlock();
block = nullptr;
for (auto b : blocks) {
b->finishQuads();
}
int label = 1;
for (auto b : blocks) {
for (auto q : b->quads) {
......@@ -96,6 +100,9 @@ void Compiler::compileFunction(FunctionInfoPtr f) {
v->info->loc = nullptr;
}
vars.clear();
blocks.clear();
scope->currentFunction = nullptr;
}
......@@ -132,10 +139,6 @@ implementacja detektora:
*/
BasicBlockPtr Compiler::flushBasicBlock() {
for (const auto& v : vars) {
if (v->info) v->info->loc = nullptr;
}
auto ret = block;
if (block) {
blocks.emplace_back(block);
......@@ -397,7 +400,7 @@ void Compiler::assign(Expr* lval, VariablePtr val) {
auto quad = dynamic_pointer_cast<QAccess>(lastQuad);
assert(quad);
auto loc = quad->access;
block->quads.pop_back();
lastQuad = nullptr;
addQuad<QWrite>(loc, val);
} else {
// local variable - only assign
......@@ -438,44 +441,70 @@ void Compiler::visitVRet(VRet *p) {
}
void Compiler::visitCond(Cond *p) {
auto var = evalExpr(p->expr_);
auto after = make_shared<QLabel>("end_if");
addQuad<QJumpCond>(after, Op::Not, var);
auto beforeBlock = flushBasicBlock(); // possible jump -> after
p->stmt_->accept(this);
auto innerBlock = flushBasicBlock(); // possible jump <- cond
addQuad(after);
beforeBlock->append(innerBlock);
beforeBlock->append(block);
innerBlock->append(block);
compileCond(p->expr_, p->stmt_, nullptr);
}
void Compiler::visitCondElse(CondElse *p) {
compileCond(p->expr_, p->stmt_1, p->stmt_2);
}
void Compiler::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
auto elseBranch = make_shared<QLabel>("else");
auto after = make_shared<QLabel>("end_else");
auto var = evalExpr(p->expr_);
auto var = evalExpr(expr_);
addQuad<QJumpCond>(elseBranch, Op::Not, var);
auto beforeBlock = flushBasicBlock(); // possible jump -> else
auto env1 = captureEnv(), env2 = env1;
p->stmt_1->accept(this);
stmt_1->accept(this);
addQuad<QJump>(after);
auto stmt1Block = flushBasicBlock(); // jump -> after
env1.capture();
env1.revert();
addQuad(elseBranch);
p->stmt_2->accept(this);
if (stmt_2) {
stmt_2->accept(this);
}
auto stmt2Block = flushBasicBlock(); // jump <- cond
env2.capture();
addQuad(after);
beforeBlock->append(stmt1Block);
beforeBlock->append(stmt2Block);
stmt1Block->append(block);
stmt2Block->append(block);
merge2Envs(&env1, stmt1Block, &env2, stmt2Block);
}
void Compiler::merge2Envs(VariableLayout *env1, BasicBlockPtr b1, VariableLayout *env2, BasicBlockPtr b2) {
for (int i = 0; i < 2; i++) {
for (const auto& p1 : env1->changes) {
if (p1.second.first == p1.second.second) continue;
auto info = p1.first;
auto it = env2->changes.find(info);
if (it != env2->changes.end()) {
auto p2 = *it;
// variables have been already merged
if (p1.second.first == p2.second.second) continue;
info->loc = nullptr;
auto merged = alloc(info);
// assign both versions to merged variable location
b1->addJumpInitQuad(make_shared<QAssign>(merged, Op::Copy, p1.second.second));
b2->addJumpInitQuad(make_shared<QAssign>(merged, Op::Copy, p2.second.second));
} else {
// copy changes to another block that did not touch var
b2->addJumpInitQuad(make_shared<QAssign>(p1.second.second, Op::Copy, p1.second.first));
}
}
swap(env1, env2);
swap(b1, b2);
}
}
void Compiler::visitWhile(While *p) {
......@@ -483,21 +512,56 @@ void Compiler::visitWhile(While *p) {
addQuad<QJump>(cond);
auto beforeBlock = flushBasicBlock(); // jump <- loop -> cond
// jump <- loop
auto loop = make_shared<QLabel>("loop");
addQuad(loop);
addQuad(loop); // jump <- loop
// hook env
auto env1 = captureEnv();
// produce all variables hooks
for (const auto& change : env1.changes) {
auto info = change.first;
info->loc = nullptr;
alloc(info);
}
// save hooks for later
env1.capture();
// env2 starts with hooked variables
auto env2 = captureEnv();
p->stmt_->accept(this);
auto stmtsBlock = flushBasicBlock(); // jump <- cond
auto loopBlock = flushBasicBlock(); // jump <- cond
addQuad(cond);
// env2 contains changed hooks
env2.capture();
// restore env1 pre-hook variables
env1.revert();
for (auto p : env2.changes) {
auto info = p.first;
auto x1 = p.second.first;
auto x2 = p.second.second;
// save hooks if used
info->loc = x1;
// transition from pre-hook to hooked var [before -> cond]
beforeBlock->addJumpInitQuad(make_shared<QAssign>(x1, Op::Copy, env1.changes[info].first));
// transition from loop var to hooked var [loop -> cond]
loopBlock->addJumpInitQuad(make_shared<QAssign>(x1, Op::Copy, x2));
}
// expr uses pre-hook variables iff unused in loop
auto var = evalExpr(p->expr_);
addQuad<QJumpCond>(loop, Op::Copy, var);
auto condBlock = flushBasicBlock(); // jump -> loop
// next block is ready to use updated variables
beforeBlock->append(condBlock);
condBlock->append(stmtsBlock);
condBlock->append(loopBlock);
condBlock->append(block);
}
......
......@@ -113,6 +113,8 @@ private:
VariableLayout captureEnv();
void merge2Envs(VariableLayout *env1, BasicBlockPtr b1, VariableLayout *env2, BasicBlockPtr b2);
void compileCond(Expr *cond, Stmt *stmt1, Stmt *stmt2);
void visitEVar(EVar *p) override;
void visitEIndexAcc(EIndexAcc *p) override;
......
......@@ -239,7 +239,7 @@ void TypeCheck::visitForEach(ForEach *for_each)
{
BindingPtr binding = make_shared<Binding>(scope->currentBinding);
for_each->type_->accept(this);
Array expect(for_each->type_);
Array expect(for_each->type_->clone());
auto arrType = evalExpr<Array>(for_each->expr_);
if (!expect.isEqual(&*arrType, true)) {
throw InvalidTypeError(expect, {arrType}, for_each->expr_);
......
......@@ -3,3 +3,18 @@
//
#include "BasicBlock.h"
#include "Quadruple.h"
void BasicBlock::finishQuads() {
while (!quads.empty() && quads.back()->isFinal()) {
auto final = quads.back();
quads.pop_back();
afterInit.emplace_back(final);
}
for (const auto& q : afterInit) {
quads.push_back(q);
}
afterInit.clear();
}
......@@ -12,13 +12,21 @@ using namespace std;
class BasicBlock : public std::enable_shared_from_this<BasicBlock> {
public:
BasicBlock() = default;;
vector<QuadruplePtr> quads;
vector<QuadruplePtr> afterInit;
vector<BasicBlockPtr> in, out;
set<VarInfoPtr> modifications;
void append(const BasicBlockPtr& after) {
out.push_back(after);
after->in.push_back(shared_from_this());
}
void addJumpInitQuad(const QuadruplePtr& q) {
afterInit.push_back(q);
}
void finishQuads();
};
......
......@@ -11,7 +11,7 @@ static const std::string opNames[] = { "_U", "-", "!", "", "_UE",
"_B", "+", "-", "*", "/", "%", "&", "|", "^", "_BE",
"_C", "<", "<=", "==", "!=", ">=", ">", "_CE"};
class Quadruple : std::enable_shared_from_this<Quadruple> {
class Quadruple {
public:
class Op {
public:
......@@ -42,6 +42,7 @@ public:
virtual ~Quadruple() {};
virtual std::string toString() const { return to_string(lineno) + "\t"; };
virtual bool isFinal() const { return false; }
};
class QWriteVar : public Quadruple {
......@@ -84,6 +85,8 @@ public:
std::string toString() const override {
return Quadruple::toString() + "jump " + target->label;
}
virtual bool isFinal() const { return true; }
};
class QJumpCond : public QJump {
......@@ -103,6 +106,8 @@ public:
else
return Quadruple::toString() + "jump \"" + target->label + "\" if " + left->name + " " + Op::name(op) + " " + right->name;
}
virtual bool isFinal() const { return true; }
};
class QParam : public Quadruple {
......@@ -150,6 +155,8 @@ public:
return Quadruple::toString() + "\treturn";
}
}
virtual bool isFinal() const { return true; }
};
class QAccess : public QWriteVar {
......
......@@ -50,23 +50,28 @@ public:
class VariableLayout {
map<VarInfoPtr, pair<VariablePtr, VariablePtr>> changes;
public:
map<VarInfoPtr, pair<VariablePtr, VariablePtr>> changes;
void add(const VarInfoPtr& info) {
if (!changes.count(info)) {
if (!changes.count(info) && info->loc) {
changes[info] = {info->loc, nullptr};
}
}
void update() {
for (auto p : changes) {
void capture() {
for (auto &p : changes) {
p.second.second = p.first->loc;
}
for (auto it = changes.begin(); it != changes.end(); ) {
auto pit = it;
it++;
if (pit->second.first == pit->second.second)
changes.erase(pit);
}
}
void revert() {
for (auto p : changes) {
for (const auto& p : changes) {
VarInfoPtr info = p.first;
info->loc = p.second.first;
}
......
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