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) {
regGen.allocate();
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) {
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() {
afterInit.clear();
auto self = shared_from_this();
auto self = this->shared_from_this();
for (const auto& q : quads) {
q->useVariables();
q->block = self;
q->useVariables();
}
}
......@@ -6,6 +6,8 @@
#include <map>
#include <cassert>
#include "Variable.h"
#include "Quadruple.h"
#include "setOverloads.h"
using namespace std;
......@@ -13,30 +15,56 @@ class BasicBlock : public std::enable_shared_from_this<BasicBlock> {
public:
struct FlowAnalysisData {
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> afterInit;
vector<BasicBlockPtr> in, out;
vector<map<VariablePtr, VariablePtr>> phi;
shared_ptr<QPhi> phi;
FlowAnalysisData flow;
void append(const BasicBlockPtr& after) {
out.push_back(after);
after->in.push_back(shared_from_this());
after->phi.emplace_back();
after->phi->phi.emplace_back();
}
void addJumpInitQuad(const QuadruplePtr& 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) {
assert(blk && local && remote);
assert(local->info && !local->info->isInstanceVariable());
auto it = find(in.begin(), in.end(), blk);
if (it == in.end()) throw runtime_error("blk not found in incoming blocks");
auto mit = phi.begin() + (it - in.begin());
(*mit)[local] = std::move(remote);
auto &phiMap = findPhi(blk);
phiMap[local] = std::move(remote);
}
void finishQuads();
......
......@@ -154,10 +154,14 @@ public:
vector<VariablePtr> vars() const override {
auto ret = Quadruple::vars();
if (param) ret.emplace_back(param);
if (param && num >= 0) ret.emplace_back(param);
return ret;
}
};
void useVariables() override {
Quadruple::useVariables();
if (param && num < 0) param->writes.emplace_back(shared_from_this());
}};
class QCall : public QWriteVar {
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
......@@ -9,7 +9,15 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f
if (!f->block) return {};
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);
int id = 1;
......@@ -49,11 +57,12 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f
for (const auto& v : vars) {
if (v->info)
v->info->loc = nullptr;
cout << "\nvar " << v->name << endl;
// TODO: wypisywanie zmiennych
/*cout << "\nvar " << v->name << endl;
for (const auto& q : v->writes)
cout << q->toString() << endl;
for (const auto& q : v->uses)
cout << q->toString() << endl;
cout << q->toString() << endl;*/
}
QuadrupleGenerator::Result ret;
vars.swap(ret.vars);
......@@ -70,7 +79,7 @@ BasicBlockPtr QuadrupleGenerator::flushBasicBlock() {
flushLastQuad();
}
block = make_shared<BasicBlock>();
newBlock();
return ret;
}
......@@ -431,6 +440,7 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// produce all variables hooks
for (const auto& change : env1.changes) {
if (!change.second.first) continue;
auto info = change.first;
info->loc = nullptr;
alloc(info);
......@@ -445,6 +455,7 @@ void QuadrupleGenerator::visitWhile(While *expr) {
expr->stmt_->accept(this);
auto loopBlock = flushBasicBlock(); // jump <- cond
auto condBlock = block;
addQuad(cond);
// env2 contains changed hooks
......@@ -452,26 +463,30 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// restore env1 pre-hook variables
env1.revert();
beforeBlock->append(block);
block->append(loopBlock);
beforeBlock->append(condBlock);
condBlock->append(loopBlock);
loopBlock->append(condBlock);
for (const auto& p : env2.changes) {
auto info = p.first;
auto x1 = p.second.first;
auto x2 = p.second.second;
auto hooked = p.second.first;
auto looped = p.second.second;
if (!hooked || hooked == looped) continue;
// save hooks if used
info->loc = x1;
info->loc = hooked;
// transition from pre-hook to hooked var [before -> cond]
block->addPhi(beforeBlock, x1, env1.changes[info].first);
// transition from loop var to hooked var [loop -> cond]
loopBlock->addPhi(block, x1, x2);
auto orig = env1.changes[info].first;
condBlock->addPhi(beforeBlock, hooked, orig);
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
auto var = evalExpr(expr->expr_);
addQuad<QJumpCond>(loop, Op::Copy, var);
auto condBlock = flushBasicBlock(); // jump -> loop
flushBasicBlock(); // jump -> loop
// next block is ready to use updated variables
......
......@@ -86,6 +86,10 @@ private:
QuadruplePtr lastQuad;
BasicBlockPtr newBlock() {
return block = make_shared<BasicBlock>();
}
void flushLastQuad() {
if (lastQuad) {
block->quads.emplace_back(lastQuad);
......
......@@ -4,19 +4,19 @@
void RegisterAllocator::analyseLive() {
for (const auto& v : vars) {
for (const auto& q : v->uses) {
q->block->flow.use.emplace(v);
}
if (!v->info) continue;
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& phiMap : b->phi) {
for (const auto& phiMap : b->phi->phi) {
for (const auto& phiRow : phiMap) {
b->flow.def.emplace(phiRow.first);
b->flow.use.emplace(phiRow.second);
}
}
}
......@@ -30,14 +30,16 @@ void RegisterAllocator::analyseLive() {
pOut.swap(f.out);
f.in = f.use + (pOut - f.def);
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 (!changed) break;
}
assert(blocks.empty() || blocks[0]->flow.in.empty());
}
void RegisterAllocator::allocate() {
analyseLive();
}
\ No newline at end of file
}
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