Files
BlitzNext/compiler/codegen_x86/tile.cpp
T
Michael Fabian 'Xaymar' Dirks c9ff5b8ca4 compiler: Formatting
2019-01-18 17:04:57 +01:00

342 lines
6.2 KiB
C++

#include "tile.h"
#include "../std.h"
#include "codegen_x86.h"
//reduce to 3 for stress test
static const int NUM_REGS = 6;
static const string regs[] = {"???", "eax", "ecx", "edx", "edi", "esi", "ebx"};
//array of 'used' flags
static bool regUsed[NUM_REGS + 1];
//size of locals in function
static int frameSize, maxFrameSize;
//code fragments
static vector<string> codeFrags, dataFrags;
//name of function
static string funcLabel;
static void resetRegs()
{
for (int n = 1; n <= NUM_REGS; ++n)
regUsed[n] = false;
}
static int allocReg(int n)
{
if (!n || regUsed[n]) {
for (n = NUM_REGS; n >= 1 && regUsed[n]; --n) {
}
if (!n)
return 0;
}
regUsed[n] = true;
return n;
}
static void freeReg(int n)
{
regUsed[n] = false;
}
static void pushReg(int n)
{
frameSize += 4;
if (frameSize > maxFrameSize)
maxFrameSize = frameSize;
char buff[32];
_itoa(frameSize, buff, 10);
string s = "\tmov\t[ebp-";
s += buff;
s += "],";
s += regs[n];
s += '\n';
codeFrags.push_back(s);
}
static void popReg(int n)
{
char buff[32];
_itoa(frameSize, buff, 10);
string s = "\tmov\t";
s += regs[n];
s += ",[ebp-";
s += buff;
s += "]\n";
codeFrags.push_back(s);
frameSize -= 4;
}
static void moveReg(int d, int s)
{
string t = "\tmov\t" + regs[d] + ',' + regs[s] + '\n';
codeFrags.push_back(t);
}
static void swapRegs(int d, int s)
{
string t = "\txchg\t" + regs[d] + ',' + regs[s] + '\n';
codeFrags.push_back(t);
}
Tile::Tile(const string& a, Tile* l, Tile* r)
: assem(a), l(l), r(r), want_l(0), want_r(0), hits(0), need(0), argFrame(0)
{}
Tile::Tile(const string& a, const string& a2, Tile* l, Tile* r)
: assem(a), assem2(a2), l(l), r(r), want_l(0), want_r(0), hits(0), need(0), argFrame(0)
{}
Tile::~Tile()
{
delete l;
delete r;
}
void Tile::label()
{
if (!l) {
need = 1;
} else if (!r) {
l->label();
need = l->need;
} else {
l->label();
r->label();
if (l->need == r->need)
need = l->need + 1;
else if (l->need > r->need)
need = l->need;
else
need = r->need;
}
}
int Tile::eval(int want)
{
//save any hit registers
int spill = hits;
if (want_l)
spill |= 1 << want_l;
if (want_r)
spill |= 1 << want_r;
if (spill) {
for (int n = 1; n <= NUM_REGS; ++n) {
if (spill & (1 << n)) {
if (regUsed[n])
pushReg(n);
else
spill &= ~(1 << n);
}
}
}
//if tile needs an argFrame...
if (argFrame) {
codeFrags.push_back("-" + itoa(argFrame));
}
int got_l = 0, got_r = 0;
if (want_l)
want = want_l;
string* as = &assem;
if (!l) {
got_l = allocReg(want);
} else if (!r) {
got_l = l->eval(want);
} else {
if (l->need >= NUM_REGS && r->need >= NUM_REGS) {
got_r = r->eval(0);
pushReg(got_r);
freeReg(got_r);
got_l = l->eval(want);
got_r = allocReg(want_r);
popReg(got_r);
} else if (r->need > l->need) {
got_r = r->eval(want_r);
got_l = l->eval(want);
} else {
got_l = l->eval(want);
got_r = r->eval(want_r);
if (assem2.size())
as = &assem2;
}
if (want_l == got_r || want_r == got_l) {
swapRegs(got_l, got_r);
int t = got_l;
got_l = got_r;
got_r = t;
}
}
if (!want_l)
want_l = got_l;
else if (want_l != got_l)
moveReg(want_l, got_l);
if (!want_r)
want_r = got_r;
else if (want_r != got_r)
moveReg(want_r, got_r);
int i;
while ((i = as->find("%l")) != string::npos)
as->replace(i, 2, regs[want_l]);
while ((i = as->find("%r")) != string::npos)
as->replace(i, 2, regs[want_r]);
codeFrags.push_back(*as);
freeReg(got_r);
if (want_l != got_l)
moveReg(got_l, want_l);
//cleanup argFrame
if (argFrame) {
//***** Not needed for STDCALL *****
// codeFrags.push_back( "+"+itoa(argFrame) );
}
//restore spilled regs
if (spill) {
for (int n = NUM_REGS; n >= 1; --n) {
if (spill & (1 << n))
popReg(n);
}
}
return got_l;
}
void Codegen_x86::flush()
{
vector<string>::iterator it;
for (it = dataFrags.begin(); it != dataFrags.end(); ++it)
out << *it;
dataFrags.clear();
}
void Codegen_x86::enter(const string& l, int frameSize)
{
inCode = true;
::frameSize = maxFrameSize = frameSize;
codeFrags.clear();
funcLabel = l;
}
void Codegen_x86::code(TNode* stmt)
{
resetRegs();
Tile* q = munch(stmt);
q->label();
q->eval(0);
delete q;
delete stmt;
}
static string fixEsp(int esp_off)
{
if (esp_off < 0)
return "\tsub\tesp," + itoa(-esp_off) + "\n";
return "\tadd\tesp," + itoa(esp_off) + "\n";
}
void Codegen_x86::leave(TNode* cleanup, int pop_sz)
{
if (cleanup) {
resetRegs();
allocReg(EAX);
Tile* q = munch(cleanup);
q->label();
q->eval(0);
delete q;
}
out << "\t.align\t16\n";
if (funcLabel.size())
out << funcLabel << '\n';
out << "\tpush\tebx\n";
out << "\tpush\tesi\n";
out << "\tpush\tedi\n";
out << "\tpush\tebp\n";
out << "\tmov\tebp,esp\n";
if (maxFrameSize)
out << "\tsub\tesp," << maxFrameSize << '\n';
int esp_off = 0;
vector<string>::iterator it = codeFrags.begin();
for (it = codeFrags.begin(); it != codeFrags.end(); ++it) {
const string& t = *it;
if (t[0] == '+') {
esp_off += atoi(t.substr(1));
} else if (t[0] == '-') {
//***** Still needed for STDCALL *****
esp_off -= atoi(t.substr(1));
} else {
if (esp_off) {
out << fixEsp(esp_off);
esp_off = 0;
}
out << *it;
}
}
if (esp_off)
out << fixEsp(esp_off);
out << "\tmov\tesp,ebp\n";
out << "\tpop\tebp\n";
out << "\tpop\tedi\n";
out << "\tpop\tesi\n";
out << "\tpop\tebx\n";
out << "\tret\tword " << pop_sz << "\n";
delete cleanup;
inCode = false;
}
void Codegen_x86::label(const string& l)
{
string t = l + '\n';
if (inCode)
codeFrags.push_back(t);
else
dataFrags.push_back(t);
}
void Codegen_x86::align_data(int n)
{
char buff[32];
_itoa(n, buff, 10);
dataFrags.push_back(string("\t.align\t") + buff + '\n');
}
void Codegen_x86::i_data(int i, const string& l)
{
if (l.size())
dataFrags.push_back(l);
char buff[32];
_itoa(i, buff, 10);
dataFrags.push_back(string("\t.dd\t") + buff + '\n');
}
void Codegen_x86::s_data(const string& s, const string& l)
{
if (l.size())
dataFrags.push_back(l);
dataFrags.push_back(string("\t.db\t\"") + s + "\",0\n");
}
void Codegen_x86::p_data(const string& p, const string& l)
{
if (l.size())
dataFrags.push_back(l);
dataFrags.push_back(string("\t.dd\t") + p + '\n');
}