Commit bb0ba170 authored by zygzagZ's avatar zygzagZ

Register Allocation fixed & working

parent ec3a8925
......@@ -39,7 +39,7 @@ Info.o : src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h
ParseError.o : src/ParseError.cpp src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h
${CC} ${CCFLAGS} -c src/ParseError.cpp
Quadruple.o : src/codeGen/Quadruple.cpp src/Info.h src/InfoList.h src/Absyn.h src/codeGen/Variable.h
Quadruple.o : src/codeGen/Quadruple.cpp src/codeGen/Quadruple.h src/Info.h src/InfoList.h src/Absyn.h src/codeGen/Variable.h
${CC} ${CCFLAGS} -c src/codeGen/Quadruple.cpp
Variable.o : src/codeGen/Variable.cpp src/codeGen/Quadruple.h src/Info.h src/InfoList.h src/Absyn.h
......
......@@ -8,6 +8,7 @@
extern std::filesystem::path binaryPath;
const std::string Compiler::extension = "s";
void Compiler::externalCommand(std::filesystem::path lat) {
return;
auto obj = lat;
obj.replace_extension("o");
auto cmd = std::string("as --32 '") + lat.string() + "' -o '" + obj.string() + "'";
......@@ -126,3 +127,79 @@ void Compiler::printFunction(QuadrupleGenerator::Result quadEnv) {
blkNo++;
}
}
Compiler::regs = {"eax", "ebx", "ecx", "edx", "esi", "edi"};
string Compiler::getRef(VariablePtr &v) {
if (v->registerColor == -1) {
if (!v->localOffset) {
temps.emplace(v);
v->localOffset = 4 * temps.size();
}
return to_string(v->localOffset) + "(ebp)";
} else {
return regs[v->registerColor+1];
}
}
void Compiler::generateQJumpCond(QJumpCond &q) {
// return QJump::generateAsm();
}
void Compiler::generateQAlloc(QAlloc &q) {
}
void Compiler::generateQWrite(QWrite &q) {
// return Quadruple::generateAsm();
}
void Compiler::generateQAccess(QAccess &q) {
// return Quadruple::generateAsm();
}
void Compiler::generateQReturn(QReturn &q) {
// return Quadruple::generateAsm();
}
void Compiler::generateQCall(QCall &q) {
// return Quadruple::generateAsm();
}
void Compiler::generateQParam(QParam &q) {
// return Quadruple::generateAsm();
}
void Compiler::generateQJump(QJump &q) {
// return Quadruple::generateAsm();
}
void Compiler::generateQAssign(QAssign &q) {
string tg = regs[q.loc->registerColor + 1];
if (q.args.size() == 1) {
switch (q.op.op) {
case Op::Not: {
buf << ""
return;
}
}
} else {
buf << "movl %" << tg << " ";
auto &i = q.args[0], &j = q.args[1];
buf << getRef(i) << endl;
buf << getOpName(q.op) << " %" << tg << " " << getRef(i) << endl;
}
}
void Compiler::generateQLabel(QLabel &q) {
// return Quadruple::generateAsm();
}
\ No newline at end of file
......@@ -12,6 +12,7 @@
#include "codeGen/Quadruple.h"
#include "codeGen/BasicBlock.h"
#include "codeGen/QuadrupleGenerator.h"
#include <unordered_set>
using Op = Quadruple::Op;
class Compiler {
......@@ -26,12 +27,26 @@ public:
static std::string getVirtName(const ClassInfoPtr& c) {
return c->name + ":virt_table";
}
void generateQJumpCond(QJumpCond &q);
void generateQAlloc(QAlloc &q);
void generateQWrite(QWrite &q);
void generateQAccess(QAccess &q);
void generateQReturn(QReturn &q);
void generateQCall(QCall &q);
void generateQParam(QParam &q);
void generateQJump(QJump &q);
void generateQAssign(QAssign &q);
void generateQLabel(QLabel &q);
private:
std::filesystem::path file;
std::stringstream buf;
shared_ptr<Scope> scope;
QuadrupleGenerator quadGen;
unordered_set<VariablePtr> temps;
unordered_set<VarInfoPtr> localInfos;
void compileFunction(const FunctionInfoPtr& f);
void printFunction(QuadrupleGenerator::Result quadEnv);
......@@ -41,6 +56,28 @@ private:
}
return f->name;
}
string getRef(VariablePtr &v);
static const char** regs;
static string getOpName(Quadruple::Op op) {
switch(op.op) {
case Op::Plus: return "addl";
case Op::Minus: return "subl";
case Op::Mul: return "mull";
case Op::Div: return "divl";
case Op::Mod: return "divl";
default: return "";
}
}
string moveToAnyRegister(VariablePtr &v) {
if (v->registerColor == -1) {
buf << "movl %eax " << getRef(v) << endl;
return "eax";
} else return regs[v->registerColor+1];
}
};
#endif
......@@ -26,7 +26,7 @@ public:
string name;
TypePtr type;
int lineLocation;
size_t offset = 0;
size_t offset = 0, localOffset = 0;
bool isInstanceVariable() const { return offset; };
VariablePtr loc;
......
#ifndef ZAD2_GRAPH_H
#define ZAD2_GRAPH_H
#include <unordered_set>
#include <queue>
using namespace std;
class FindUnion {
uint n{0};
vector<uint> t;
public:
void resize(uint num) {
n = num;
t.resize(n);
for (uint i = 0; i < n; i++)
t[i] = i;
}
uint get(uint c) {
if (t[c] == c) return c;
return t[c] = get(t[c]);
}
void add(uint a, uint b) {
t[get(a)] = get(b);
}
};
template<typename T>
class Graph {
public:
Graph() { };
struct Result {
int color;
bool spilled;
};
void add(T &i, T &j) {
if (evaluated) throw runtime_error("Add to evaluated graph");
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;
void addAssign(T &i, T &j) {
if (evaluated) throw runtime_error("Add to evaluated graph");
assignsSet.emplace(i, j);
vertices[i];
vertices[j];
}
auto getEdges() const {
const auto& getEdges() const {
return edgesSet;
}
vector<T> getOrder() const {
vector<T> ret;
for (auto i : order)
ret.emplace_back(reverseVertices[i]);
const auto& getAssigns() const {
return assignsSet;
}
map<T, int> getAllocation() const {
if (!evaluated) throw runtime_error("Query of unevaluated graph");
map<T, int> ret;
for (const auto &i : vertices)
ret[i.first] = color[i.second];
return ret;
}
int getColor(T x) {
if (!evaluated) throw runtime_error("Query of unevaluated graph");
if (!vertices.count(x)) throw runtime_error("Query of non-graph vertex");
int c = vertices[x];
return color[c];
}
Result get(T x) {
if (!evaluated) throw runtime_error("Query of unevaluated graph");
if (!vertices.count(x)) throw runtime_error("Query of non-graph vertex");
int c = vertices[x];
return Result(color[c], spilled(c));
}
void eval(int colors) {
if (evaluated) throw runtime_error("Try of re-evaluating graph");
evaluated = true;
if (vertices.empty()) return;
maxColors = colors;
buildGraph();
initOrder();
initChordal();
initColoring(vertices.size());
if (!chordal) return;
if (maxColors < 1) {
throw std::runtime_error("Spill to no colors!");
}
spillToColors(maxColors);
coalesce();
remapColors();
checkAllocation();
}
bool isChordal() const {
if (!evaluated) throw runtime_error("Query of unevaluated graph");
return chordal;
}
private:
bool evaluated = false;
set<pair<T, T>> edgesSet;
map<T, int> vertices;
vector<T> reverseVertices;
vector<unordered_set<int>> edges;
FindUnion alias;
vector<int> order;
vector<int> color;
bool chordal = true;
int maxColors = 0;
set<pair<T, T>> assignsSet;
void buildGraph() {
int n = 0;
reverseVertices.reserve(vertices.size());
......@@ -39,6 +121,7 @@ public:
reverseVertices.emplace_back(i.first);
}
alias.resize(vertices.size());
edges.resize(vertices.size());
for (auto e : edgesSet) {
auto a = vertices[e.first], b = vertices[e.second];
......@@ -69,7 +152,7 @@ public:
if (c >= 0) {
lambda[c].erase(x);
c++;
if (lambda.size() <= c)
if ((int)lambda.size() <= c)
lambda.emplace_back();
lambda[c].emplace(x);
}
......@@ -103,49 +186,187 @@ public:
}
vector<int> spilledVertices;
int highestColor;
map<int, int> colorUses;
int highestColor = -1;
vector<unordered_set<int>> colorUses;
vector<int> colorCount;
vector<int> spilledColor;
vector<uint> nonSpilledColors;
vector<int> coalescedNodes;
void initColoring(int maxC) {
highestColor = -1;
color.resize(vertices.size());
colorUses.resize(vertices.size());
colorCount.resize(vertices.size());
vector<char> used;
used.resize(maxC);
for (auto &i : color) i = -1;
for (auto c : order) {
bool used[maxC];
// calc used
for (auto x : edges[c]) {
if (color[x] == -1) continue;
used[color[x]] = true;
}
// calc self color
for (int col = 0; col < maxC; col++) {
if (!used[col]) {
color[c] = col;
break;
}
}
// clear used table for next use
for (auto x : edges[c]) {
if (color[x] == -1) continue;
used[color[x]] = false;
}
// spill or apply color
if (color[c] == -1) {
disconnectNode(c);
spilledVertices.emplace_back(c);
markSpilled(c);
} else {
highestColor = max(highestColor, color[c]);
colorUses[color[c]].emplace(c);
colorCount[color[c]]++;
}
}
chordal = true;
while (!colorCount.empty() && colorCount.back() == 0) {
colorUses.pop_back();
colorCount.pop_back();
}
}
void disconnectNode(int node) {
for (auto x : edges[node]) {
edges[x].erase(node);
bool spilled(int c) const {
return color[c] == -1;
}
void markSpilled(int c) {
spilledVertices.emplace_back(c);
color[c] = -1;
// edges won't contain already spilled nodes
for (auto x : edges[c]) {
edges[x].erase(c);
}
}
void setup() {
if (vertices.empty()) {
throw std::runtime_error("ayy lmao empty vertices");
void spillToColors(uint maxC) {
// heuristic: least used
priority_queue<pair<uint, uint>> Q; // { number of uses, color id }
spilledColor.resize(colorCount.size());
nonSpilledColors.clear();
for (uint i = 0; i < colorCount.size(); i++) {
Q.emplace(colorCount[i], i);
}
for (uint i = 0; i < maxC && !Q.empty(); i++) {
// pop first most used maxC colors
auto col = Q.top().second;
spilledColor[col] = false;
nonSpilledColors.emplace_back(col);
Q.pop();
}
while (!Q.empty()) {
auto col = Q.top().second;
spilledColor[col] = true;
Q.pop();
for (auto i : colorUses[col]) {
if (!spilled(i)) {
markSpilled(i);
}
}
colorUses[col].clear();
}
// reconnect spilled nodes;
for (auto c : spilledVertices) {
for (auto it = edges[c].begin(); it != edges[c].end();) {
auto n = *it;
if (spilled(n)) {
edges[n].emplace(c);
++it;
} else {
it = edges[c].erase(it);
}
}
}
}
void setColor(int x, int col) {
if (color[x] == col) return;
if (color[x] != -1) {
colorUses[color[x]].erase(x);
colorCount[color[x]]--;
}
color[x] = col;
if (col != -1) {
colorCount[col]++;
colorUses[col].emplace(x);
}
}
void coalesceNode(int x, int y, int col) {
for (auto e : edges[y]) {
edges[x].emplace(e);
edges[e].emplace(x);
edges[e].erase(y);
}
edges[y].clear();
setColor(x, col);
coalescedNodes.emplace_back(y);
alias.add(y, x);
}
void coalesce() {
vector<char> used;
used.resize(highestColor + 1);
for (auto it : assignsSet) {
for (auto &c : used) c = false;
auto x = vertices[it.first], y = vertices[it.second];
x = alias.get(x); y = alias.get(y);
if (x == y) continue;
if (spilled(x) || spilled(y)) continue;
if (edges[x].count(y) || edges[y].count(x)) continue;
for (auto z : edges[x]) if (color[z] >= 0) used[color[z]] = true;
for (auto z : edges[y]) if (color[z] >= 0) used[color[z]] = true;
for (int c : nonSpilledColors) {
if (used[c]) continue;
coalesceNode(x, y, c);
break;
}
}
for (uint i = 0; i < color.size(); i++) {
setColor(i, color[alias.get(i)]);
}
}
void remapColors() {
sort(nonSpilledColors.begin(), nonSpilledColors.end());
for (uint i = 0; i < nonSpilledColors.size(); i++) {
if (nonSpilledColors[i] != i) {
auto &col = nonSpilledColors[i];
for (auto v : colorUses[col])
color[v] = i;
swap(colorCount[i], colorCount[col]);
swap(colorUses[i], colorUses[col]);
}
}
}
void checkAllocation() {
if (vertices.size() != color.size()) throw runtime_error("Invalid allocation, vertices size mismatches color size");
uint size = spilledVertices.size() + coalescedNodes.size();
for (uint i = 0; i < vertices.size(); i++) if (!spilled(i)) if (alias.get(i) == i) size++;
if (size != vertices.size()) throw runtime_error("Invalid allocation, original size mismatches current size");
for (auto v : edgesSet) {
int x = alias.get(vertices[v.first]);
int y = alias.get(vertices[v.second]);
if (!spilled(x) && color[x] == color[y])
throw runtime_error("Invalid allocation, same color assigned to colliding variables");
if (color[x] >= maxColors || color[y] >= maxColors)
throw runtime_error("Invalid allocation, more colors used than allowed");
}
buildGraph();
initOrder();
initChordal();
}
};
......
#include "Quadruple.h"
#include "../Compiler.h"
void QJumpCond::generateAsm(Compiler &c) {
c.generateQJumpCond(*this);
}
void QAlloc::generateAsm(Compiler &c) {
c.generateQAlloc(*this);
}
void QWrite::generateAsm(Compiler &c) {
c.generateQWrite(*this);
}
void QAccess::generateAsm(Compiler &c) {
c.generateQAccess(*this);
}
void QReturn::generateAsm(Compiler &c) {
c.generateQReturn(*this);
}
void QCall::generateAsm(Compiler &c) {
c.generateQCall(*this);
}
void QParam::generateAsm(Compiler &c) {
c.generateQParam(*this);
}
void QJump::generateAsm(Compiler &c) {
c.generateQJump(*this);
}
void QAssign::generateAsm(Compiler &c) {
c.generateQAssign(*this);
}
void QLabel::generateAsm(Compiler &c) {
c.generateQLabel(*this);
}
......@@ -7,6 +7,7 @@
#include "Variable.h"
#include "setOverloads.h"
using namespace std;
class Compiler;
static const std::string opNames[] = { "_U", "-", "!", "", "_UE",
"_B", "+", "-", "*", "/", "%", "&", "|", "^", "_BE",
......@@ -59,6 +60,7 @@ public:
};
virtual vector<VariablePtr> vars() const { return {}; };
virtual vector<VariablePtr> definitions() const { return {}; };
virtual void generateAsm(Compiler &c) { };
};
class QWriteVar : public Quadruple {
......@@ -79,6 +81,7 @@ public:
string label;
std::string toString() const override { return Quadruple::toString() + "\"" + label + "\":"; }
explicit QLabel(std::string comment) : label(std::move(comment)) {}
void generateAsm(Compiler &c) override;
};
class QAssign : public QWriteVar {
......@@ -100,6 +103,7 @@ public:
vector<VariablePtr> vars() const override {
return args;
}
void generateAsm(Compiler &c) override;
};
class QJump : public Quadruple {
......@@ -108,10 +112,11 @@ public:
explicit QJump(shared_ptr<QLabel> target) : target(std::move(target)) {};
std::string toString() const override {
return Quadruple::toString() + "jump " + target->label;
return Quadruple::toString() + "jump \"" + target->label + "\"";
}
virtual bool isFinal() const { return true; }
bool isFinal() const override { return true; }
void generateAsm(Compiler &c) override;
};
class QJumpCond : public QJump {
......@@ -127,9 +132,9 @@ public:
std::string toString() const override {
if (!left)
return Quadruple::toString() + "jump \"" + target->label + "\" if " + Op::name(op) + " " + right->name;
return QJump::toString() + " if " + Op::name(op) + " " + right->name;
else
return Quadruple::toString() + "jump \"" + target->label + "\" if " + left->name + " " + Op::name(op) + " " + right->name;
return QJump::toString() + " if " + left->name + " " + Op::name(op) + " " + right->name;
}
bool isFinal() const override { return true; }
......@@ -140,6 +145,7 @@ public:
if (right) ret.emplace_back(right);
return ret;
}
void generateAsm(Compiler &c) override;
};
class QParam : public Quadruple {
......@@ -170,6 +176,7 @@ public:
if (param && num < 0) ret.emplace_back(param);
return ret;
};
void generateAsm(Compiler &c) override;
};
class QCall : public QWriteVar {
......@@ -193,6 +200,7 @@ public:
if (self) ret.emplace_back(self);
return ret;
}
void generateAsm(Compiler &c) override;
};
class QReturn : public Quadruple {
......@@ -215,6 +223,7 @@ public:
if (val) ret.emplace_back(val);
return ret;
}
void generateAsm(Compiler &c) override;
};
class QAccess : public QWriteVar {
......@@ -237,6 +246,7 @@ public:
if (access.index) ret.emplace_back(access.index);
return ret;
}
void generateAsm(Compiler &c) override;
};
class QWrite : public Quadruple {
......@@ -256,6 +266,7 @@ public:
if (val) ret.emplace_back(val);
return ret;
}
void generateAsm(Compiler &c) override;
};
class QAlloc : public QWriteVar {
......@@ -278,6 +289,7 @@ public:
if (count) ret.emplace_back(count);
return ret;
}
void generateAsm(Compiler &c) override;
};
class QPhi : public Quadruple {
......
......@@ -317,6 +317,12 @@ void QuadrupleGenerator::visitInit(Init *p) {
addQuad<QAssign>(alloc(info), Op::Copy, var);
}
void QuadrupleGenerator::visitNoInit(Init *p) {
auto info = p->pident_->var.lock();
assert(info);
addQuad<QAssign>(alloc(info), Op::Copy, alloc(0));
}
void QuadrupleGenerator::assign(Expr* lval, VariablePtr val) {
auto dest = evalLVal(lval);
if (dest->info && dest->info->isInstanceVariable()) {
......
......@@ -161,6 +161,8 @@ private:
void visitInit(Init *p) override;
void visitNoInit(Init *p) override;
void assign(Expr* lval, VariablePtr val);
void visitAss(Ass *p) override;
......
......@@ -68,6 +68,12 @@ void RegisterAllocator::buildGraph() {
for (const auto& b : blocks) {
set<VariablePtr> alive = b->flow.in;
for (const auto& q : b->quads) {
if (auto assign = dynamic_pointer_cast<QAssign>(q)) {
if (assign->op == Quadruple::Op::Copy) {
graph.addAssign(assign->loc, assign->args[0]);
g2.addAssign(assign->loc->name, assign->args[0]->name);
}
}
alive += to_set(q->definitions());
vector<VariablePtr> dead;
for (const auto& var : alive) {
......@@ -78,7 +84,7 @@ void RegisterAllocator::buildGraph() {
}
alive -= to_set(dead);
q->aliveAfter = alive;
anyAlive |= alive.size() >= 2;
anyAlive |= alive.size() >= 1;
for (auto i : alive) {
for (auto j : alive) {
if (i != j) {
......@@ -90,13 +96,33 @@ void RegisterAllocator::buildGraph() {
}
}
if (!anyAlive) return;
graph.setup();
g2.setup();
assert(graph.chordal == g2.chordal);
if (!g2.chordal) {
graph.eval(5);
g2.eval(5);
int gNumSpill = 0, g2NumSpill = 0;
for (auto &v : graph.getAllocation()) {
v.first->registerColor = v.second;
if (v.second == -1) {
gNumSpill++;
} else {
v.first->name += "-r" + to_string(v.second);
}
}
for (auto &v : g2.getAllocation()) {
if (v.second == -1)
g2NumSpill++;
}
cout << "allocation: VPtr eval spills: " << gNumSpill << " vs strings spills: " << g2NumSpill << endl;
if (!g2.isChordal()) {
printGraph(graph, "./mygraph");
printGraph(g2, "./myg2");
throw ParseError("graph not chordal!");
if (graph.isChordal()) {
throw ParseError("allocation: g2 not chordal, tho g1 is chordal!");
}
throw ParseError("allocation: none graph chordal!");
} else {
if (!graph.isChordal()) {
throw ParseError("allocation: g1 not chordal, tho g2 is chordal!");
}
}
}
......
......@@ -18,24 +18,16 @@ public:
bool constExpr{false};
int val{0};
std::string name;
int registerColor = -1;
vector<QuadruplePtr> uses;
vector<QuadruplePtr> writes;
int localOffset = 0;
void clear(const QuadruplePtr& q) {
uses.erase(std::remove(uses.begin(), uses.end(), q), uses.end());
writes.erase(std::remove(writes.begin(), writes.end(), q), writes.end());
//
// for (auto it = uses.begin(); it != uses.end();) {
// if (*it == q)
// it = uses.erase(it);
// else it++;
// }
// for (auto it = writes.begin(); it != writes.end();) {
// if (*it == q)
// it = writes.erase(it);
// else it++;
// }
}
};
......
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