Commit ec3a8925 authored by zygzagZ's avatar zygzagZ

Fixed quad BB generation, start implementation of optimal graph-coloring

register allocation
parent bc58b2c2
......@@ -30,7 +30,7 @@ Skeleton.o : src/Skeleton.cpp src/Skeleton.h src/Absyn.h
TypeCheck.o : src/TypeCheck.cpp src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h
${CC} ${CCFLAGS} -c src/TypeCheck.cpp
Compiler.o : src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h src/codeGen/QuadrupleGenerator.h
Compiler.o : src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h src/codeGen/QuadrupleGenerator.h src/codeGen/RegisterAllocator.h src/codeGen/Graph.h
${CC} ${CCFLAGS} -c src/Compiler.cpp
Info.o : src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h
......@@ -51,10 +51,10 @@ BasicBlock.o : src/codeGen/BasicBlock.cpp src/codeGen/Quadruple.h src/codeGen/Ba
QuadrupleGenerator.o : src/codeGen/QuadrupleGenerator.cpp src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/Info.h src/InfoList.h src/Absyn.h src/codeGen/Variable.h src/Compiler.h src/codeGen/QuadrupleGenerator.h
${CC} ${CCFLAGS} -c src/codeGen/QuadrupleGenerator.cpp
RegisterAllocator.o : src/codeGen/RegisterAllocator.cpp src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/Info.h src/InfoList.h src/Absyn.h src/codeGen/Variable.h src/codeGen/RegisterAllocator.h
RegisterAllocator.o : src/codeGen/RegisterAllocator.cpp src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/Info.h src/InfoList.h src/Absyn.h src/codeGen/Variable.h src/codeGen/RegisterAllocator.h src/codeGen/Graph.h
${CC} ${CCFLAGS} -c src/codeGen/RegisterAllocator.cpp
Latte.o : src/Latte.cpp src/Parser.h src/Printer.h src/Absyn.h src/ParseError.h src/TypeCheck.h src/Compiler.h src/Info.h src/InfoList.h src/codeGen/QuadrupleGenerator.h
Latte.o : src/Latte.cpp src/Parser.h src/Printer.h src/Absyn.h src/ParseError.h src/TypeCheck.h src/Compiler.h src/Info.h src/InfoList.h src/codeGen/QuadrupleGenerator.h src/codeGen/RegisterAllocator.h src/codeGen/Graph.h
${CC} ${CCFLAGS} -c src/Latte.cpp
lib/runtime.o : lib/runtime.c Makefile
......
......@@ -54,16 +54,22 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
// c++ thiscall ecx, stack right-to-left (push c, push b, push a)
buf << "\"" << name << "\":\n";
QuadrupleGenerator::Result quadEnv = quadGen.compileFunction(f);
try {
RegisterAllocator regGen((quadEnv));
regGen.allocate();
} catch(const ParseError &e) {
printFunction(quadEnv);
throw ParseError(buf.str() + e.what());
}
auto quadEnv = quadGen.compileFunction(f);
RegisterAllocator regGen = RegisterAllocator(quadEnv);
regGen.allocate();
printFunction(quadEnv);
}
void Compiler::printFunction(QuadrupleGenerator::Result quadEnv) {
int blkNo = 0;
for (const auto& b : quadEnv.blocks) {
buf << "------------------------------\n";
buf << "----------------------------------------------------------------------------\n";
buf << "blok " << blkNo << " " << b->getName() << endl;
/*buf << "in: ";
for (auto in : b->in) {
......@@ -91,6 +97,12 @@ void Compiler::compileFunction(const FunctionInfoPtr& f) {
for (const auto& q : b->quads) {
auto ret = q->toString();
if (!ret.empty()) {
auto len = 0;
for (const auto &c : ret) {
len++;
if (c == '\t') len += 8 - (len % 8);
}
for (; len < 70; len++) ret += ' ';
buf << ret << " alive: ";
for (auto var : q->aliveAfter)
buf << var->name << " ";
......
......@@ -33,6 +33,7 @@ private:
QuadrupleGenerator quadGen;
void compileFunction(const FunctionInfoPtr& f);
void printFunction(QuadrupleGenerator::Result quadEnv);
static std::string mangleFunctionName(const FunctionInfoPtr& f) {
if (auto c = f->klass.lock()) {
......
......@@ -2,18 +2,19 @@
#include "Quadruple.h"
void BasicBlock::finishQuads() {
while (!quads.empty() && quads.back()->isFinal()) {
auto final = quads.back();
quads.pop_back();
afterInit.emplace_back(final);
}
if (!afterInit.empty()) {
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);
for (const auto& q : afterInit) {
quads.push_back(q);
}
afterInit.clear();
}
afterInit.clear();
auto self = this->shared_from_this();
for (const auto& q : quads) {
q->block = self;
......
#ifndef ZAD2_GRAPH_H
#define ZAD2_GRAPH_H
#include <unordered_set>
template<typename T>
class Graph {
public:
Graph() { };
void add(T &i, T &j) {
vertices[i];
vertices[j];
edgesSet.emplace(i, j);
edgesSet.emplace(j, i);
}
set<pair<T, T>> edgesSet;
map<T, int> vertices;
vector<T> reverseVertices;
vector<unordered_set<int>> edges;
vector<int> order;
vector<int> color;
bool chordal = false;
auto getEdges() const {
return edgesSet;
}
vector<T> getOrder() const {
vector<T> ret;
for (auto i : order)
ret.emplace_back(reverseVertices[i]);
return ret;
}
void buildGraph() {
int n = 0;
reverseVertices.reserve(vertices.size());
for (auto &i : vertices) {
i.second = n++;
reverseVertices.emplace_back(i.first);
}
edges.resize(vertices.size());
for (auto e : edgesSet) {
auto a = vertices[e.first], b = vertices[e.second];
edges[a].emplace(b);
}
}
void initOrder() {
if (vertices.empty()) return;
vector<int> card;
vector<unordered_set<int>> lambda;
int n = vertices.size();
card.resize(n);
lambda.resize(n);
for (int i = 0; i < n; i++) {
lambda[0].emplace(i);
}
while (!lambda.empty()) {
if (lambda.back().empty()) {
lambda.pop_back();
continue;
}
auto v = *lambda.back().begin();
order.push_back(v);
for (auto x : edges[v]) {
auto &c = card[x];
if (c >= 0) {
lambda[c].erase(x);
c++;
if (lambda.size() <= c)
lambda.emplace_back();
lambda[c].emplace(x);
}
}
lambda[card[v]].erase(v);
card[v] = -1;
}
}
void initChordal() {
unordered_set<int> visited;
for (auto i : order) {
unordered_set<int> neighbors;
for (auto x : edges[i]) {
if (visited.count(x)) {
neighbors.emplace(x);
}
}
for (auto x : neighbors) {
for (auto y : neighbors) {
if (x == y) continue;
if (!edges[x].count(y) || !edges[y].count(x)) {
chordal = false;
return;
}
}
}
visited.emplace(i);
}
chordal = true;
}
vector<int> spilledVertices;
int highestColor;
map<int, int> colorUses;
vector<int> colorCount;
void initColoring(int maxC) {
highestColor = -1;
color.resize(vertices.size());
for (auto &i : color) i = -1;
for (auto c : order) {
bool used[maxC];
for (auto x : edges[c]) {
if (color[x] == -1) continue;
used[color[x]] = true;
}
for (int col = 0; col < maxC; col++) {
if (!used[col]) {
color[c] = col;
break;
}
}
if (color[c] == -1) {
disconnectNode(c);
spilledVertices.emplace_back(c);
} else {
highestColor = max(highestColor, color[c]);
}
}
chordal = true;
}
void disconnectNode(int node) {
for (auto x : edges[node]) {
edges[x].erase(node);
}
}
void setup() {
if (vertices.empty()) {
throw std::runtime_error("ayy lmao empty vertices");
}
buildGraph();
initOrder();
initChordal();
}
};
#endif //ZAD2_GRAPH_H
......@@ -5,6 +5,7 @@
#include "../Info.h"
#include "Variable.h"
#include "setOverloads.h"
using namespace std;
static const std::string opNames[] = { "_U", "-", "!", "", "_UE",
......@@ -52,6 +53,9 @@ public:
for (const auto& v : vars()) {
if (v) v->uses.emplace_back(self);
}
for (const auto& v : definitions()) {
if (v) v->writes.emplace_back(self);
}
};
virtual vector<VariablePtr> vars() const { return {}; };
virtual vector<VariablePtr> definitions() const { return {}; };
......@@ -63,10 +67,6 @@ public:
explicit QWriteVar(VariablePtr loc) : Quadruple(), loc(std::move(loc)) {};
std::string toString() const override { return Quadruple::toString() + "\t" + (loc ? (loc->name + " := ") : ""); }
void useVariables() override {
Quadruple::useVariables();
if (loc) loc->writes.emplace_back(shared_from_this());
}
vector<VariablePtr> definitions() const override {
auto ret = Quadruple::definitions();
if (loc) ret.emplace_back(loc);
......@@ -165,11 +165,6 @@ public:
return ret;
}
void useVariables() override {
Quadruple::useVariables();
if (param && num < 0) param->writes.emplace_back(shared_from_this());
}
vector<VariablePtr> definitions() const override {
auto ret = Quadruple::definitions();
if (param && num < 0) ret.emplace_back(param);
......
......@@ -382,36 +382,38 @@ void QuadrupleGenerator::visitCondElse(CondElse *p) {
void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
// TODO: stmty nie składają się z jednego bloku tylko z wielu
auto elseBranch = make_shared<QLabel>("else");
auto elseBranch = make_shared<QLabel>("if_else");
auto after = make_shared<QLabel>("end_else");
auto var = evalExpr(expr_);
addQuad<QJumpCond>(elseBranch, Op::Not, var);
auto beforeBlock = flushBasicBlock(); // possible jump -> else
auto env1 = captureEnv(), env2 = env1;
auto envIf = captureEnv(), envElse = envIf;
auto stmtIfFirstBlock = block;
addQuad<QLabel>("if_true");
stmt_1->accept(this);
addQuad<QJump>(after);
auto stmt1Block = flushBasicBlock(); // jump -> after
env1.capture();
env1.revert();
auto stmtIfLastBlock = flushBasicBlock(); // jump -> after
envIf.capture();
envIf.revert();
addQuad(elseBranch);
auto stmtElseFirstBlock = block;
if (stmt_2) {
stmt_2->accept(this);
}
auto stmt2Block = flushBasicBlock(); // jump <- cond
env2.capture();
auto stmtElseLastBlock = flushBasicBlock(); // jump <- cond
envElse.capture();
addQuad(after);
beforeBlock->append(stmt1Block);
beforeBlock->append(stmt2Block);
stmt1Block->append(block);
stmt2Block->append(block);
beforeBlock->append(stmtIfFirstBlock);
beforeBlock->append(stmtElseFirstBlock);
stmtIfLastBlock->append(block);
stmtElseLastBlock->append(block);
merge2Envs(&env1, stmt1Block, &env2, stmt2Block);
merge2Envs(&envIf, stmtIfLastBlock, &envElse, stmtElseLastBlock);
}
void QuadrupleGenerator::merge2Envs(VariableLayout *env1, const BasicBlockPtr& b1, VariableLayout *env2, const BasicBlockPtr& b2) {
......@@ -473,12 +475,13 @@ void QuadrupleGenerator::visitWhile(While *expr) {
auto info = p.first;
auto hooked = p.second.first;
auto looped = p.second.second;
if (!hooked || hooked == looped) continue;
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]
auto orig = env1.changes[info].first;
condBlock->addPhi(beforeBlock, hooked, orig);
// transition from hooked var
condBlock->addPhi(loopLastBlock, hooked, looped);
// loopLastBlock doesn't need phi, it has only one incoming block
......@@ -501,6 +504,6 @@ void QuadrupleGenerator::visitSExp(SExp *p) {
void QuadrupleGenerator::visitForEach(ForEach *p) {
auto tab = evalExpr(p->expr_);
throw ParseError("ForEach is yet unimplemented!", p);
// throw ParseError("ForEach is yet unimplemented!", p);
// TODO: implement
}
\ No newline at end of file
#include "RegisterAllocator.h"
#include "BasicBlock.h"
#include "setOverloads.h"
#include <fstream>
void RegisterAllocator::analyseLive() {
for (const auto& v : vars) {
......@@ -37,7 +38,8 @@ void RegisterAllocator::analyseLive() {
if (!changed) break;
}
assert(blocks.empty() || blocks[0]->flow.in.empty());
if (!blocks.empty() && !blocks[0]->flow.in.empty())
throw ParseError("Variable definition not found - first block expects input");
}
void RegisterAllocator::allocate() {
......@@ -45,7 +47,24 @@ void RegisterAllocator::allocate() {
buildGraph();
}
void printGraph(const Graph<VariablePtr> &graph, const std::string& filename) {
ofstream f(filename);
for (const auto &v : graph.getEdges()) {
f << v.first->name << " " << v.second->name << endl;
}
f.close();
}
void printGraph(const Graph<std::string> &graph, const std::string& filename) {
ofstream f(filename);
for (const auto &v : graph.getEdges()) {
f << v.first << " " << v.second << endl;
}
f.close();
}
void RegisterAllocator::buildGraph() {
bool anyAlive = false;
for (const auto& b : blocks) {
set<VariablePtr> alive = b->flow.in;
for (const auto& q : b->quads) {
......@@ -59,18 +78,26 @@ void RegisterAllocator::buildGraph() {
}
alive -= to_set(dead);
q->aliveAfter = alive;
anyAlive |= alive.size() >= 2;
for (auto i : alive) {
for (auto j : alive) {
if (i != j) {
if (i.get() > j.get()) {
swap(i, j);
}
graphEdges.insert(make_pair(i, j));
graph.add(i, j);
g2.add(i->name, j->name);
}
}
}
}
}
if (!anyAlive) return;
graph.setup();
g2.setup();
assert(graph.chordal == g2.chordal);
if (!g2.chordal) {
printGraph(graph, "./mygraph");
printGraph(g2, "./myg2");
throw ParseError("graph not chordal!");
}
}
......@@ -5,6 +5,7 @@
#include "Quadruple.h"
#include "QuadrupleGenerator.h"
#include "Graph.h"
class Register : public std::enable_shared_from_this<Register> {
bool available;
......@@ -14,7 +15,7 @@ class Register : public std::enable_shared_from_this<Register> {
class RegisterAllocator {
public:
explicit RegisterAllocator(const QuadrupleGenerator::Result &r) : blocks(r.blocks), vars(r.vars) {}
RegisterAllocator(const QuadrupleGenerator::Result &r) : blocks(r.blocks), vars(r.vars) {}
void processQJump(shared_ptr<QJump> q);
void processQJumpCond(shared_ptr<QJumpCond> q);
void processQLabel(shared_ptr<QLabel> q);
......@@ -29,10 +30,11 @@ public:
void allocate();
void buildGraph();
private:
Graph<VariablePtr> graph;
Graph<std::string> g2;
void analyseLive();
vector<BasicBlockPtr> blocks;
vector<VariablePtr> vars;
set<pair<VariablePtr, VariablePtr>> graphEdges;
};
......
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