Commit e4d71bee authored by zygzagZ's avatar zygzagZ

WIP better memory access

parent aafb3bcc
......@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
int printInt(int a) {
printf("%d\n", a);
......@@ -59,11 +60,13 @@ char* __latte_mem_init(size_t size, void* virtTab) {
}
char* __latte_mem_init_array(int len, size_t size, void* virtTab) {
if (len < 0) error();
char *buf = calloc(len, size);
if (len > (SIZE_MAX-4)/size) error();
char *buf = calloc(1, 4 + len * size);
if (!buf) error();
*((int*)buf) = len; // store length
if (virtTab) {
for (size_t i = 0; i < len; i++) {
*((void**)(buf + i * size)) = virtTab;
*((void**)(buf + 4 + i * size)) = virtTab;
}
}
return buf;
......
......@@ -137,6 +137,7 @@ void Compiler::printFunction(const QuadrupleGenerator::Result& quadEnv, const Fu
buf << "\n" COMMENT "----------\n";
}
for (const auto& q : b->quads) {
currentQuad = q;
auto ret = q->toString();
if (!ret.empty()) {
auto len = 0;
......@@ -162,6 +163,7 @@ void Compiler::printFunction(const QuadrupleGenerator::Result& quadEnv, const Fu
}
}
}
currentQuad = nullptr;
if (!b->flow.use.empty()) {
buf << COMMENT "----------\n" COMMENT "use: ";
for (const auto &v : b->flow.use) {
......@@ -209,7 +211,7 @@ const char* const Register::names[9] = {"eax", "ebx", "ecx", "edx", "edi", "esi"
const vector<Register> Register::all = {0, 1, 2, 3, 4, 5, 6, 7, 8};
const vector<Register> Register::callerSaved = {2, 3};
const vector<Register> Register::calleeSaved = {1, 4, 5};
const vector<Register> Register::assignable = {1,4,5,2,3}; // ecx and edx least used
const vector<Register> Register::assignable = {1,5,4,2,3}; // ecx and edx least used
string Compiler::getRef(const VariablePtr &v) {
if (v->constExpr) {
......@@ -274,13 +276,28 @@ void Compiler::generateQAlloc(QAlloc &q) {
}
void Compiler::generateQWrite(QWrite &q) {
// memory = extension
append("MOVL", getRef(q.val), getRef(q.loc));
Register rl = lock(q.val, true);
// out of all registers
// now i want to choose some that are free
// or temporarily push some not used in calculation of q.access nor q.loc
append("MOVL", rl, loadLoc(q.loc));
// and, if pushed, pop them back later
regMap.unlock();
}
void Compiler::generateQAccess(QAccess &q) {
// memory = extension
append("MOVL", getRef(q.access), getRef(q.loc));
// get register for q.loc, spilling one if necessary
Register rl = lock(q.loc, false);
// out of all registers
// now i want to choose some that are free
// or temporarily push some not used in calculation of q.access nor q.loc
append("MOVL", loadLoc(q.access), rl);
if (Register(q.loc) == 0) {
append("MOVL", rl, getRef(q.loc));
}
// and, if pushed, pop them back later
regMap.unlock();
}
void Compiler::generateQReturn(QReturn &q) {
......@@ -568,3 +585,35 @@ void Compiler::generateQBlockEnd(QBlockEnd &q) {
const auto &map = tgBlock->getPhiMapping(thisBlock);
generatePhiXCHG(map);
}
string Compiler::loadLoc(const VariableLocation &loc) {
int offset = loc.offset;
Register rb = lock(loc.base, true);
if (loc.index) {
if (loc.index->constExpr) {
offset += loc.index->val * loc.multiplier;
} else {
Register ri = lock(loc.index, true);
auto ret = to_string(offset) + "(" + (string)rb + "," + (string)ri;
if (loc.multiplier != 1) ret += "," + to_string(loc.multiplier);
return ret + ")";
}
}
return to_string(offset) + "(" + (string)rb + ")";
}
void RegisterMap::backup(Register i) {
chk(i);
backups.emplace_back(i);
c->append("MOVL", i, "-" + to_string(backups.size()*4) + "(%esp)");
lock(i);
}
void RegisterMap::unlock() {
locks.clear();
for (size_t i = 0; i < backups.size(); i++) {
c->append("MOVL", "-" + to_string(i*4+4) + "(%esp)", backups[i]);
}
backups.clear();
}
......@@ -42,10 +42,85 @@ public:
static const vector<Register> assignable;
};
namespace {
vector<Register> aliveAfter(const Quadruple &q, const vector<Register> &vec) {
const uint noRegs = vec.size();
bool used[noRegs];
int notUsed = noRegs;
for (auto &i : used) i = false;
for (auto &live : q.aliveAfter) {
for (uint i = 0; i < noRegs; i++) {
const Register &r = vec[i];
if (!used[i] && Register(live) == r) {
used[i] = true;
--notUsed;
}
}
if (notUsed == 0) break;
}
vector<Register> ret;
for (uint i = 0; i < noRegs; i++) {
if (used[i]) ret.emplace_back(vec[i]);
}
return ret;
}
vector<Register> aliveAfter(const QuadruplePtr &q, const vector<Register> &vec) {
return aliveAfter(*q, vec);
}
}
class RegisterMap {
public:
RegisterMap(Compiler *c) : c(c) {};
Compiler *c;
set<Register> locks;
vector<Register> backups;
set<Register> available() const {
auto ret = to_set(Register::assignable);
ret.emplace(0);
ret -= to_set(locks);
return ret;
}
auto unused(const QuadruplePtr &q) const {
auto ret = to_set(::aliveAfter(q, Register::assignable));
ret.emplace(0);
ret -= to_set(locks);
return ret;
}
void lock(Register i) {
if (!locks.count(i))
locks.emplace(i);
}
Register borrow(const QuadruplePtr &q) {
for (auto i : unused(q)) {
lock(i);
return i;
}
for (auto i : available()) {
backup(i);
return i;
}
throw runtime_error("Unable to borrow register!");
}
void backup(Register i);
void unlock();
private:
void chk(Register i) const {
if (locks.count(i))
throw runtime_error("Register already locked!");
}
};
using Op = Quadruple::Op;
class Compiler {
public:
Compiler(const std::string& f, shared_ptr<Scope> s) : file(f), buf(), scope(s), quadGen(std::move(s)) {};
Compiler(const std::string& f, shared_ptr<Scope> s) : file(f), buf(), scope(s), quadGen(std::move(s)), regMap(this) {};
static const std::string extension;
static void externalCommand(std::filesystem::path file);
......@@ -82,6 +157,8 @@ private:
std::stringstream buf;
shared_ptr<Scope> scope;
QuadrupleGenerator quadGen;
RegisterMap regMap;
QuadruplePtr currentQuad;
unordered_set<VariablePtr> temps;
unordered_set<VarInfoPtr> localInfos;
......@@ -91,21 +168,38 @@ private:
void genVirtTables();
string getRef(const VariablePtr &v);
string getRef(const VariableLocation &loc) {
int offset = loc.offset;
if (loc.index) {
if (loc.index->constExpr) {
offset += loc.index->val * loc.multiplier;
} else {
auto ret = to_string(offset) + "(" + getRef(loc.base) + "," + getRef(loc.index);
if (loc.multiplier != 1) ret += "," + to_string(loc.multiplier);
return ret + ")";
string loadLoc(const VariableLocation &loc);
void generatePhiXCHG(const map<VariablePtr, VariablePtr> &varMap);
string getBlockLabelText(const QuadruplePtr &q) {
return getBlockLabelText(q->block);
}
string getBlockLabelText(BasicBlockPtr &b) {
auto n = b->getName();
if (n.empty()) throw runtime_error("Attempt to get label text of unlabeled block");
return quote(n);
}
shared_ptr<QLabel> exitLabel;
void generateStandardReturn() {
append("JMP", quote(exitLabel->label));
}
Register lock(const VariablePtr &v, bool move = false) {
auto reg = Register(v);
if (reg == 0) {
reg = regMap.borrow(currentQuad);
if (move) {
append("MOVL", getRef(v), reg);
}
} else {
regMap.lock(reg);
}
return to_string(offset) + "(" + getRef(loc.base) + ")";
return reg;
}
void generatePhiXCHG(const map<VariablePtr, VariablePtr> &varMap);
protected:
static string getOpName(Quadruple::Op op) {
switch(op.op) {
case Op::Plus: return "ADDL";
......@@ -172,46 +266,16 @@ private:
buf << endl;
}
string getBlockLabelText(const QuadruplePtr &q) {
return getBlockLabelText(q->block);
public:
static vector<Register> aliveAfter(Quadruple &q, const vector<Register> &vec) {
return ::aliveAfter(q, vec);
}
string getBlockLabelText(BasicBlockPtr &b) {
auto n = b->getName();
if (n.empty()) throw runtime_error("Attempt to get label text of unlabeled block");
return quote(n);
}
shared_ptr<QLabel> exitLabel;
void generateStandardReturn() {
append("JMP", quote(exitLabel->label));
}
static vector<Register> aliveAfter(Quadruple &q, const vector<Register> &vec) {
const uint noRegs = vec.size();
bool used[noRegs];
int notUsed = noRegs;
for (auto &i : used) i = false;
for (auto &live : q.aliveAfter) {
for (uint i = 0; i < noRegs; i++) {
const Register &r = vec[i];
if (!used[i] && Register(live) == r) {
used[i] = true;
--notUsed;
}
}
if (notUsed == 0) break;
}
vector<Register> ret;
for (uint i = 0; i < noRegs; i++) {
if (used[i]) ret.emplace_back(vec[i]);
}
return ret;
}
static vector<Register> registersToSave(Quadruple &q) {
return aliveAfter(q, Register::callerSaved);
}
friend class RegisterMap;
};
#endif
......@@ -12,14 +12,15 @@ QuadrupleGenerator::Result QuadrupleGenerator::compileFunction(FunctionInfoPtr f
newBlock();
{
int param = 1;
for (const auto& arg : f->arguments) {
auto var = alloc(arg);
if (VarInfoPtr self = f->self){
auto var = alloc(self);
addQuad(make_shared<QParam>(var, -param));
param++;
}
if (VarInfoPtr self = f->self){
auto var = alloc(self);
for (const auto& arg : f->arguments) {
auto var = alloc(arg);
addQuad(make_shared<QParam>(var, -param));
param++;
}
}
f->block->accept(this);
......@@ -327,9 +328,9 @@ void QuadrupleGenerator::visitEIndexAcc(EIndexAcc *p) {
auto newIndex = alloc();
// calculate var = index * quantifier
addQuad<QAssign>(newIndex, index, Op::Mul, q);
addQuad<QAccess>(lastVar, lhs, newIndex, 1, 0);
addQuad<QAccess>(lastVar, lhs, newIndex, 1, 4); // 4 accounts for table length entry
} else {
addQuad<QAccess>(lastVar, lhs, index, type->type_->size(), 0);
addQuad<QAccess>(lastVar, lhs, index, type->type_->size(), 4); // 4 accounts for table length entry
}
Bool b;
if (type->type_->isEqual(&b)) {
......
......@@ -38,11 +38,17 @@ private:
shared_ptr<QLabel> labelTrue, labelFalse;
VariablePtr evalLVal(Visitable *expr) {
auto info = evalExpr(expr)->info;
auto ret = evalExpr(expr);
auto info = ret->info;
if (!info) {
throw ParseError("LValue expected", expr);
if (!lastQuad || !dynamic_pointer_cast<QAccess>(lastQuad))
throw ParseError("LValue expected", expr);
else
return ret;
} else {
info->loc = nullptr;
}
info->loc = nullptr;
return alloc(info);
}
......
......@@ -85,7 +85,8 @@ done && green "OK: $t bad+ tests passed!" && for ext in `ls lat/lattests/extensi
if ! diff <( $VALGRIND timeout 2 ${i%.*} < "$inp" ) "${i%.*}.output"; then
red "ERROR $i"
exit 1
ok=0
break
fi
done
if [ $ok -eq 1 ]; then
......
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