Commit 5ee30f7d authored by zygzagZ's avatar zygzagZ

WIP live variables, flow analysis and register allocation

parent 093e7cbe
CC=g++
CCFLAGS=-g -W -Wall -O0 -std=c++2a -Wno-unused-parameter
OBJS=Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o QuadrupleGenerator.o
OBJS=Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o QuadrupleGenerator.o RegisterAllocator.o
.PHONY : clean distclean
......@@ -53,6 +53,9 @@ BasicBlock.o : src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/codeGen/Basi
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
${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
${CC} ${CCFLAGS} -c src/Latte.cpp
......
......@@ -2914,7 +2914,7 @@ bool ClassT::isEqual(Type const *other, bool sub) const {
if (v1 == v2) return true;
if (!sub) return false;
auto klass = static_pointer_cast<ClassInfo>(v2);
if (auto parent = klass->getParent()) {
if (auto parent = klass->getClassParent()) {
return isEqual(&*parent->type, sub);
}
}
......
......@@ -37,7 +37,7 @@ size_t ClassInfo::calculateSize() {
if (size) return size;
size = 4; // pointer to virtual methods table
if (auto p = getParent()) { // parent already has virt pointer included
if (auto p = getClassParent()) { // parent already has virt pointer included
p->calculateSize();
size = p->size;
functionCount = p->functionCount;
......
......@@ -72,7 +72,7 @@ public:
ClassInfo(PIdent *ident, BindingPtr parent = nullptr);
virtual string kind() const { return "class"; }
ClassInfoPtr getParent() { return dynamic_pointer_cast<ClassInfo>(parent.lock()); };
ClassInfoPtr getClassParent() { return dynamic_pointer_cast<ClassInfo>(parent.lock()); };
size_t calculateSize();
size_t size, functionCount;
};
......
#ifndef INFOLIST_HEADER
#define INFOLIST_HEADER
#include "Info.h"
#include "ParseError.h"
#include "TypeDefs.h"
#include <iostream>
......
//
// Created by zygzagz on 03.01.2021.
//
#include "BasicBlock.h"
#include "Quadruple.h"
......@@ -17,4 +13,8 @@ void BasicBlock::finishQuads() {
}
afterInit.clear();
for (auto q : quads) {
q->useVariables();
}
}
//
// Created by zygzagz on 03.01.2021.
//
#ifndef ZAD2_BASICBLOCK_H
#define ZAD2_BASICBLOCK_H
#include "../TypeDefs.h"
#include <utility>
#include <vector>
#include <set>
#include <map>
#include <cassert>
#include "Variable.h"
using namespace std;
class BasicBlock : public std::enable_shared_from_this<BasicBlock> {
public:
BasicBlock() = default;;
BasicBlock() = default;
vector<QuadruplePtr> quads;
vector<QuadruplePtr> afterInit;
vector<BasicBlockPtr> in, out;
vector<map<VariablePtr, VariablePtr>> phi;
void append(const BasicBlockPtr& after) {
out.push_back(after);
after->in.push_back(shared_from_this());
after->phi.emplace_back();
}
void addJumpInitQuad(const QuadruplePtr& q) {
afterInit.push_back(q);
}
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);
}
void finishQuads();
};
......
......@@ -11,7 +11,7 @@ static const std::string opNames[] = { "_U", "-", "!", "", "_UE",
"_B", "+", "-", "*", "/", "%", "&", "|", "^", "_BE",
"_C", "<", "<=", "==", "!=", ">=", ">", "_CE"};
class Quadruple {
class Quadruple : public enable_shared_from_this<Quadruple> {
public:
class Op {
public:
......@@ -39,10 +39,13 @@ public:
};
int lineno;
int index;
virtual ~Quadruple() {};
virtual ~Quadruple() = default;
virtual std::string toString() const { return to_string(lineno) + "\t"; };
virtual bool isFinal() const { return false; }
virtual void useVariables() {};
};
class QWriteVar : public Quadruple {
......@@ -51,13 +54,16 @@ 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 {
if (loc) loc->writes.emplace_back(shared_from_this());
}
};
class QLabel : public Quadruple {
public:
string label;
std::string toString() const override { return Quadruple::toString() + "\"" + label + "\":"; }
QLabel(std::string comment) : label(comment) {}
explicit QLabel(std::string comment) : label(std::move(comment)) {}
};
class QAssign : public QWriteVar {
......@@ -75,6 +81,11 @@ public:
else
return QWriteVar::toString() + args[0]->name + " " + Op::name(op) + " " + args[1]->name;
}
void useVariables() override {
QWriteVar::useVariables();
auto self = shared_from_this();
for (const auto& a : args) if (a) a->uses.emplace_back(self);
}
};
class QJump : public Quadruple {
......@@ -107,7 +118,12 @@ public:
return Quadruple::toString() + "jump \"" + target->label + "\" if " + left->name + " " + Op::name(op) + " " + right->name;
}
virtual bool isFinal() const { return true; }
bool isFinal() const override { return true; }
void useVariables() override {
if (left) left->uses.emplace_back(shared_from_this());
if (right) right->uses.emplace_back(shared_from_this());
}
};
class QParam : public Quadruple {
......@@ -118,12 +134,18 @@ public:
QParam(VariablePtr param, int num) : param(std::move(param)), num(num) {};
std::string toString() const override {
if (num == 0) {
if (num < 0) {
return Quadruple::toString() + "\t" + param->name + " := param #" + to_string(-num);
} else if (num == 0) {
return Quadruple::toString() + "\tparam self " + param->name;
} else {
return Quadruple::toString() + "\tparam #" + to_string(num) + " <- " + param->name;
}
}
void useVariables() override {
if (param) param->uses.emplace_back(shared_from_this());
}
};
class QCall : public QWriteVar {
......@@ -141,6 +163,11 @@ public:
return QWriteVar::toString() + "call " + fn->name + " with " + to_string(params) + " params";
}
}
void useVariables() override {
QWriteVar::useVariables();
if (self) self->uses.emplace_back(shared_from_this());
}
};
class QReturn : public Quadruple {
......@@ -156,7 +183,11 @@ public:
}
}
virtual bool isFinal() const { return true; }
bool isFinal() const override { return true; }
void useVariables() override {
if (ret) ret->uses.emplace_back(shared_from_this());
}
};
class QAccess : public QWriteVar {
......@@ -167,13 +198,17 @@ public:
// leal 8(,%eax,4), %eax # Arithmetic: multiply eax by 4 and add 8
// leal (%edx,%eax,2), %eax # Arithmetic: multiply eax by 2 and add edx
VariableLocation access;
bool lea = false;
std::string toString() const override {
auto ret = QWriteVar::toString();
if (lea) ret += "&";
return ret + access.toString();
}
void useVariables() override {
QWriteVar::useVariables();
if (access.base) access.base->uses.emplace_back(shared_from_this());
if (access.index) access.index->uses.emplace_back(shared_from_this());
}
};
class QWrite : public Quadruple {
......@@ -185,6 +220,12 @@ public:
VariablePtr val;
std::string toString() const override { return Quadruple::toString() + "\t" + loc.toString() + " := " + val->name; }
void useVariables() override {
if (loc.base) loc.base->uses.emplace_back(shared_from_this());
if (loc.index) loc.index->uses.emplace_back(shared_from_this());
if (val) val->uses.emplace_back(shared_from_this());
}
};
class QAlloc : public QWriteVar {
......@@ -201,6 +242,11 @@ public:
if (!virtSymbol.empty()) { ret += " " + virtSymbol; }
return ret;
}
void useVariables() override {
QWriteVar::useVariables();
if (count) count->uses.emplace_back(shared_from_this());
}
};
......
......@@ -33,8 +33,10 @@ vector<BasicBlockPtr> QuadrupleGenerator::compileFunction(FunctionInfoPtr f) {
}
int label = 1;
int index = 1;
for (const auto& b : blocks) {
for (const auto& q : b->quads) {
q->index = index++;
if (auto l = dynamic_pointer_cast<QLabel>(q)) {
if (!l->label.empty())
l->label = to_string(label++) + "_" + l->label;
......@@ -47,6 +49,11 @@ vector<BasicBlockPtr> QuadrupleGenerator::compileFunction(FunctionInfoPtr f) {
for (const auto& v : vars) {
if (v->info)
v->info->loc = nullptr;
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;
}
vars.clear();
......@@ -75,10 +82,8 @@ VariableLayout QuadrupleGenerator::captureEnv() {
while (b) {
for (const auto& info : b->variables) {
if (info->isInstanceVariable()) continue;
if (info->loc) {
ret.add(info);
}
}
b = b->getParent();
}
return ret;
......@@ -224,7 +229,7 @@ void QuadrupleGenerator::visitEClsMmbr(EClsMmbr *p) {
lastVar = l;
} else {
lastVar = alloc(var);
auto quad = make_shared<QAccess>(lastVar, l, alloc(0), 0, offset);
auto quad = make_shared<QAccess>(lastVar, l, nullptr, 0, offset);
addQuad(quad);
}
}
......@@ -400,29 +405,17 @@ void QuadrupleGenerator::compileCond(Expr *expr_, Stmt *stmt_1, Stmt *stmt_2) {
merge2Envs(&env1, stmt1Block, &env2, stmt2Block);
}
void QuadrupleGenerator::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;
void QuadrupleGenerator::merge2Envs(VariableLayout *env1, const BasicBlockPtr& b1, VariableLayout *env2, const BasicBlockPtr& b2) {
assert(env1->changes.size() == env2->changes.size());
for (auto it = env1->changes.begin(), itt = env2->changes.begin(); it != env1->changes.end(); it++, itt++) {
assert(it->first == itt->first);
assert(it->second.first == itt->second.first);
if (it->second.second == itt->second.second) continue;
auto info = it->first;
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);
block->addPhi(b1, merged, it->second.second);
block->addPhi(b2, merged, itt->second.second);
}
}
......@@ -446,6 +439,7 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// save hooks for later
env1.capture();
// env2 starts with hooked variables
auto env2 = captureEnv();
......@@ -459,6 +453,9 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// restore env1 pre-hook variables
env1.revert();
beforeBlock->append(block);
block->append(loopBlock);
for (const auto& p : env2.changes) {
auto info = p.first;
auto x1 = p.second.first;
......@@ -466,9 +463,9 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// 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));
block->addPhi(beforeBlock, x1, env1.changes[info].first);
// transition from loop var to hooked var [loop -> cond]
loopBlock->addJumpInitQuad(make_shared<QAssign>(x1, Op::Copy, x2));
loopBlock->addPhi(block, x1, x2);
}
// expr uses pre-hook variables iff unused in loop
......@@ -479,8 +476,6 @@ void QuadrupleGenerator::visitWhile(While *expr) {
// next block is ready to use updated variables
beforeBlock->append(condBlock);
condBlock->append(loopBlock);
condBlock->append(block);
}
......
......@@ -170,7 +170,7 @@ private:
void compileCond(Expr *cond, Stmt *stmt1, Stmt *stmt2);
void merge2Envs(VariableLayout *env1, BasicBlockPtr b1, VariableLayout *env2, BasicBlockPtr b2);
void merge2Envs(VariableLayout *env1, const BasicBlockPtr& b1, VariableLayout *env2, const BasicBlockPtr& b2);
void visitWhile(While *expr) override;
......
#include "RegisterAllocator.h"
void RegisterAllocator::analyseLive() {
}
\ No newline at end of file
#ifndef ZAD2_REGISTERALLOCATOR_H
#define ZAD2_REGISTERALLOCATOR_H
#include "Quadruple.h"
class Register : public std::enable_shared_from_this<Register> {
bool available;
set<VariablePtr> contains;
std::string name;
};
class RegisterAllocator {
public:
RegisterAllocator(vector<BasicBlockPtr> v) : blocks(v) {}
void processQJump(shared_ptr<QJump> q) {};
void processQJumpCond(shared_ptr<QJumpCond> q) {};
void processQLabel(shared_ptr<QLabel> q) {};
void processQParam(shared_ptr<QParam> q) {};
void processQReturn(shared_ptr<QReturn> q) {};
void processQWrite(shared_ptr<QWrite> q) {};
void processQAccess(shared_ptr<QAccess> q) {};
void processQAlloc(shared_ptr<QAlloc> q) {};
void processQAssign(shared_ptr<QAssign> q) {};
void processQCall(shared_ptr<QCall> q) {};
void analyseLive();
private:
vector<BasicBlockPtr> blocks;
};
#endif //ZAD2_REGISTERALLOCATOR_H
//
// Created by zygzagz on 02.01.2021.
//
#include "Variable.h"
//
// Created by zygzagz on 02.01.2021.
//
#ifndef ZAD2_VARIABLE_H
#define ZAD2_VARIABLE_H
......@@ -14,19 +10,33 @@
class Variable : std::enable_shared_from_this<Variable> {
public:
Variable() = default;
explicit Variable(VarInfoPtr info) : info(std::move(info)), constExpr(false), val(0) {};
explicit Variable(VarInfoPtr info) : info(std::move(info)) {};
explicit Variable(int constVal) : type(new Int), constExpr(true), val(constVal) {};
explicit Variable(std::string symbolName) {};
explicit Variable(std::string symbolName) : name(std::move(symbolName)) {};
VarInfoPtr info;
TypePtr type;
bool constExpr;
int val;
bool constExpr{false};
int val{0};
std::string name;
// chcemy znać lokalizację w pamięci gdzie zapisać z powrotem i gdzie leży ogólnie
// lok. może nie być, jeśli to tymczasowa
// registers
// is mem?
// where in mem - id or offset
vector<QuadruplePtr> uses;
vector<QuadruplePtr> writes;
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++;
// }
}
};
class VariableLocation {
......@@ -37,12 +47,12 @@ public:
{}
VariablePtr base;
VariablePtr index;
int multiplier;
int offset;
int multiplier{};
int offset{};
string toString() const {
std::string ret = "[" + base->name;
if (multiplier || !(index->constExpr || !index->val)) ret += " + " + to_string(multiplier) + "*" + index->name;
if (index) if (multiplier || !(index->constExpr || !index->val)) ret += " + " + to_string(multiplier) + "*" + index->name;
if (offset) ret += " + " + to_string(offset);
return ret + "]";
}
......@@ -53,7 +63,7 @@ class VariableLayout {
public:
map<VarInfoPtr, pair<VariablePtr, VariablePtr>> changes;
void add(const VarInfoPtr& info) {
if (!changes.count(info) && info->loc) {
if (!changes.count(info)) {
changes[info] = {info->loc, nullptr};
}
}
......@@ -62,12 +72,6 @@ public:
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() {
......
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