Commit a83f92b3 authored by zygzagZ's avatar zygzagZ

Works: Using function parameters, strict-SSA, analysis: liveness, flow

parent 726a943e
...@@ -62,8 +62,25 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) { ...@@ -62,8 +62,25 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
regGen.allocate(); regGen.allocate();
for (const auto& b : quadEnv.blocks) { for (const auto& b : quadEnv.blocks) {
buf << "------------------------------\n";
if (!b->flow.in.empty()) {
buf << "in: ";
for (const auto& v : b->flow.in) {
buf << v->name << ", ";
}
buf << "\n----------\n";
}
for (const auto& q : b->quads) { for (const auto& q : b->quads) {
buf << q->toString() << endl; auto ret = q->toString();
if (!ret.empty())
buf << ret << endl;
}
if (!b->flow.out.empty()) {
buf << "----------\nout: ";
for (const auto &v : b->flow.out) {
buf << v->name << ", ";
}
buf << "\n";
} }
} }
} }
...@@ -14,9 +14,9 @@ void BasicBlock::finishQuads() { ...@@ -14,9 +14,9 @@ void BasicBlock::finishQuads() {
afterInit.clear(); afterInit.clear();
auto self = shared_from_this(); auto self = this->shared_from_this();
for (const auto& q : quads) { for (const auto& q : quads) {
q->useVariables();
q->block = self; q->block = self;
q->useVariables();
} }
} }
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <map> #include <map>
#include <cassert> #include <cassert>
#include "Variable.h" #include "Variable.h"
#include "Quadruple.h"
#include "setOverloads.h"
using namespace std; using namespace std;
...@@ -13,30 +15,56 @@ class BasicBlock : public std::enable_shared_from_this<BasicBlock> { ...@@ -13,30 +15,56 @@ class BasicBlock : public std::enable_shared_from_this<BasicBlock> {
public: public:
struct FlowAnalysisData { struct FlowAnalysisData {
set<VariablePtr> in, out, def, use; set<VariablePtr> in, out, def, use;
BasicBlock *b {};
void addUse(const VariablePtr& v) {
if (!def.contains(v)) use.emplace(v);
}
void addDef(const VariablePtr &v) {
def.emplace(v);
use.erase(v);
}
[[nodiscard]] set<VariablePtr> inForBlock(const BasicBlockPtr& q) const {
set<VariablePtr> ret;
for (const auto& var : b->findPhi(q)) {
ret.emplace(var.second);
}
return in + ret;
}
};
BasicBlock() {
phi = make_shared<QPhi>();
flow.b = this;
quads.emplace_back(phi);
}; };
BasicBlock() = default;
vector<QuadruplePtr> quads; vector<QuadruplePtr> quads;
vector<QuadruplePtr> afterInit; vector<QuadruplePtr> afterInit;
vector<BasicBlockPtr> in, out; vector<BasicBlockPtr> in, out;
vector<map<VariablePtr, VariablePtr>> phi; shared_ptr<QPhi> phi;
FlowAnalysisData flow; FlowAnalysisData flow;
void append(const BasicBlockPtr& after) { void append(const BasicBlockPtr& after) {
out.push_back(after); out.push_back(after);
after->in.push_back(shared_from_this()); after->in.push_back(shared_from_this());
after->phi.emplace_back(); after->phi->phi.emplace_back();
} }
void addJumpInitQuad(const QuadruplePtr& q) { void addJumpInitQuad(const QuadruplePtr& q) {
afterInit.push_back(q); afterInit.push_back(q);
} }
map<VariablePtr, VariablePtr> &findPhi(const BasicBlockPtr& blk) {
auto it = find(in.begin(), in.end(), blk);
if (it == in.end()) throw runtime_error("blk not found in incoming blocks");
auto mit = phi->phi.begin() + (it - in.begin());
return *mit;
}
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 it = find(in.begin(), in.end(), blk); auto &phiMap = findPhi(blk);
if (it == in.end()) throw runtime_error("blk not found in incoming blocks"); phiMap[local] = std::move(remote);
auto mit = phi.begin() + (it - in.begin());
(*mit)[local] = std::move(remote);
} }
void finishQuads(); void finishQuads();
......
...@@ -154,10 +154,14 @@ public: ...@@ -154,10 +154,14 @@ public:
vector<VariablePtr> vars() const override { vector<VariablePtr> vars() const override {
auto ret = Quadruple::vars(); auto ret = Quadruple::vars();
if (param) ret.emplace_back(param); if (param && num >= 0) ret.emplace_back(param);
return ret; return ret;
} }
};
void useVariables() override {
Quadruple::useVariables();
if (param && num < 0) param->writes.emplace_back(shared_from_this());
}};
class QCall : public QWriteVar { class QCall : public QWriteVar {
public: public:
...@@ -267,5 +271,54 @@ public: ...@@ -267,5 +271,54 @@ public:
} }
}; };
class QPhi : public Quadruple {
public:
vector<map<VariablePtr, VariablePtr>> phi;
vector<VariablePtr> vars() const override {
auto ret = Quadruple::vars();
for (const auto& b : phi) {
for (const auto& v : b) {
ret.emplace_back(v.second);
}
}
return ret;
}
void useVariables() override {
set<VariablePtr> written;
auto self = shared_from_this();
for (const auto& b : phi) {
for (const auto &v : b) {
if (!written.contains(v.first)) {
v.first->writes.emplace_back(self);
written.emplace(v.first);
}
// QPhi does not place uses here, it is handled in RegisterAllocator
}
}
}
std::string toString() const override {
if (phi.size() < 2) return "";
std::string ret = Quadruple::toString() + "phi ";
for (const auto& left : *phi.begin()) {
auto &tg = left.first;
ret += tg->name + " = [";
bool f = true;
for (auto b : phi) {
if (!b.count(tg)) continue;
if (f) f=false;
else ret += ", ";
ret += b[tg]->name;
}
ret += "] ";
}
return ret;
}
};
#endif //ZAD2_QUAD_H #endif //ZAD2_QUAD_H
...@@ -9,7 +9,15 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f ...@@ -9,7 +9,15 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f
if (!f->block) return {}; if (!f->block) return {};
scope->currentFunction = f; scope->currentFunction = f;
block = make_shared<BasicBlock>(); newBlock();
{
int param = 1;
for (const auto& arg : f->arguments) {
auto var = alloc(arg);
addQuad(make_shared<QParam>(var, -param));
param++;
}
}
f->block->accept(this); f->block->accept(this);
int id = 1; int id = 1;
...@@ -49,11 +57,12 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f ...@@ -49,11 +57,12 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f
for (const auto& v : vars) { for (const auto& v : vars) {
if (v->info) if (v->info)
v->info->loc = nullptr; v->info->loc = nullptr;
cout << "\nvar " << v->name << endl; // TODO: wypisywanie zmiennych
/*cout << "\nvar " << v->name << endl;
for (const auto& q : v->writes) for (const auto& q : v->writes)
cout << q->toString() << endl; cout << q->toString() << endl;
for (const auto& q : v->uses) for (const auto& q : v->uses)
cout << q->toString() << endl; cout << q->toString() << endl;*/
} }
QuadrupleGenerator::Result ret; QuadrupleGenerator::Result ret;
vars.swap(ret.vars); vars.swap(ret.vars);
...@@ -70,7 +79,7 @@ BasicBlockPtr QuadrupleGenerator::flushBasicBlock() { ...@@ -70,7 +79,7 @@ BasicBlockPtr QuadrupleGenerator::flushBasicBlock() {
flushLastQuad(); flushLastQuad();
} }
block = make_shared<BasicBlock>(); newBlock();
return ret; return ret;
} }
...@@ -431,6 +440,7 @@ void QuadrupleGenerator::visitWhile(While *expr) { ...@@ -431,6 +440,7 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// produce all variables hooks // produce all variables hooks
for (const auto& change : env1.changes) { for (const auto& change : env1.changes) {
if (!change.second.first) continue;
auto info = change.first; auto info = change.first;
info->loc = nullptr; info->loc = nullptr;
alloc(info); alloc(info);
...@@ -445,6 +455,7 @@ void QuadrupleGenerator::visitWhile(While *expr) { ...@@ -445,6 +455,7 @@ void QuadrupleGenerator::visitWhile(While *expr) {
expr->stmt_->accept(this); expr->stmt_->accept(this);
auto loopBlock = flushBasicBlock(); // jump <- cond auto loopBlock = flushBasicBlock(); // jump <- cond
auto condBlock = block;
addQuad(cond); addQuad(cond);
// env2 contains changed hooks // env2 contains changed hooks
...@@ -452,26 +463,30 @@ void QuadrupleGenerator::visitWhile(While *expr) { ...@@ -452,26 +463,30 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// restore env1 pre-hook variables // restore env1 pre-hook variables
env1.revert(); env1.revert();
beforeBlock->append(block); beforeBlock->append(condBlock);
block->append(loopBlock); condBlock->append(loopBlock);
loopBlock->append(condBlock);
for (const auto& p : env2.changes) { for (const auto& p : env2.changes) {
auto info = p.first; auto info = p.first;
auto x1 = p.second.first; auto hooked = p.second.first;
auto x2 = p.second.second; auto looped = p.second.second;
if (!hooked || hooked == looped) continue;
// save hooks if used // save hooks if used
info->loc = x1; info->loc = hooked;
// transition from pre-hook to hooked var [before -> cond] // transition from pre-hook to hooked var [before -> cond]
block->addPhi(beforeBlock, x1, env1.changes[info].first); auto orig = env1.changes[info].first;
// transition from loop var to hooked var [loop -> cond] condBlock->addPhi(beforeBlock, hooked, orig);
loopBlock->addPhi(block, x1, x2); condBlock->addPhi(loopBlock, hooked, looped);
// loopBlock doesn't need phi, it has only one incoming block
} }
// expr uses pre-hook variables iff unused in loop // expr uses pre-hook variables iff unused in loop
auto var = evalExpr(expr->expr_); auto var = evalExpr(expr->expr_);
addQuad<QJumpCond>(loop, Op::Copy, var); addQuad<QJumpCond>(loop, Op::Copy, var);
auto condBlock = flushBasicBlock(); // jump -> loop flushBasicBlock(); // jump -> loop
// next block is ready to use updated variables // next block is ready to use updated variables
......
...@@ -86,6 +86,10 @@ private: ...@@ -86,6 +86,10 @@ private:
QuadruplePtr lastQuad; QuadruplePtr lastQuad;
BasicBlockPtr newBlock() {
return block = make_shared<BasicBlock>();
}
void flushLastQuad() { void flushLastQuad() {
if (lastQuad) { if (lastQuad) {
block->quads.emplace_back(lastQuad); block->quads.emplace_back(lastQuad);
......
...@@ -4,19 +4,19 @@ ...@@ -4,19 +4,19 @@
void RegisterAllocator::analyseLive() { void RegisterAllocator::analyseLive() {
for (const auto& v : vars) { for (const auto& v : vars) {
for (const auto& q : v->uses) { if (!v->info) continue;
q->block->flow.use.emplace(v);
}
for (const auto& q : v->writes) { for (const auto& q : v->writes) {
q->block->flow.def.emplace(v); q->block->flow.addDef(v);
}
for (const auto& q : v->uses) {
q->block->flow.addUse(v);
} }
} }
for (const auto& b : blocks) { for (const auto& b : blocks) {
for (const auto& phiMap : b->phi) { for (const auto& phiMap : b->phi->phi) {
for (const auto& phiRow : phiMap) { for (const auto& phiRow : phiMap) {
b->flow.def.emplace(phiRow.first); b->flow.def.emplace(phiRow.first);
b->flow.use.emplace(phiRow.second);
} }
} }
} }
...@@ -30,12 +30,14 @@ void RegisterAllocator::analyseLive() { ...@@ -30,12 +30,14 @@ void RegisterAllocator::analyseLive() {
pOut.swap(f.out); pOut.swap(f.out);
f.in = f.use + (pOut - f.def); f.in = f.use + (pOut - f.def);
for (const auto& succ : b->out) { for (const auto& succ : b->out) {
f.out += succ->flow.in; f.out += succ->flow.inForBlock(b);
} }
if (f.in != pIn || f.out != pOut) changed = true; if (f.in != pIn || f.out != pOut) changed = true;
} }
if (!changed) break; if (!changed) break;
} }
assert(blocks.empty() || blocks[0]->flow.in.empty());
} }
void RegisterAllocator::allocate() { void RegisterAllocator::allocate() {
......
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