2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
#include "../std.h"
|
|
|
|
|
#include "codegen_x86.h"
|
|
|
|
|
#include "tile.h"
|
|
|
|
|
|
|
|
|
|
//reduce to 3 for stress test
|
2016-05-07 22:49:54 +02:00
|
|
|
static const int NUM_REGS = 6;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static const string regs[] =
|
|
|
|
|
{ "???","eax","ecx","edx","edi","esi","ebx" };
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//array of 'used' flags
|
2016-05-07 22:49:54 +02:00
|
|
|
static bool regUsed[NUM_REGS + 1];
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//size of locals in function
|
2016-05-07 22:49:54 +02:00
|
|
|
static int frameSize, maxFrameSize;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//code fragments
|
2016-05-07 22:49:54 +02:00
|
|
|
static vector<string> codeFrags, dataFrags;
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//name of function
|
|
|
|
|
static string funcLabel;
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static void resetRegs() {
|
|
|
|
|
for (int n = 1; n <= NUM_REGS; ++n) regUsed[n] = false;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static int allocReg(int n) {
|
|
|
|
|
if (!n || regUsed[n]) {
|
|
|
|
|
for (n = NUM_REGS; n >= 1 && regUsed[n]; --n) {}
|
|
|
|
|
if (!n) return 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2016-05-07 22:49:54 +02:00
|
|
|
regUsed[n] = true;
|
2014-01-31 08:23:00 +13:00
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static void freeReg(int n) {
|
|
|
|
|
regUsed[n] = false;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static void moveReg(int d, int s) {
|
|
|
|
|
string t = "\tmov\t" + regs[d] + ',' + regs[s] + '\n';
|
|
|
|
|
codeFrags.push_back(t);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static void swapRegs(int d, int s) {
|
|
|
|
|
string t = "\txchg\t" + regs[d] + ',' + regs[s] + '\n';
|
|
|
|
|
codeFrags.push_back(t);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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) {
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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) {
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
Tile::~Tile() {
|
|
|
|
|
delete l; delete r;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Tile::label() {
|
|
|
|
|
if (!l) {
|
|
|
|
|
need = 1;
|
|
|
|
|
} else if (!r) {
|
2014-01-31 08:23:00 +13:00
|
|
|
l->label();
|
2016-05-07 22:49:54 +02:00
|
|
|
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;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
int Tile::eval(int want) {
|
2014-01-31 08:23:00 +13:00
|
|
|
//save any hit registers
|
2016-05-07 22:49:54 +02:00
|
|
|
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);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//if tile needs an argFrame...
|
2016-05-07 22:49:54 +02:00
|
|
|
if (argFrame) {
|
|
|
|
|
codeFrags.push_back("-" + itoa(argFrame));
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2016-05-07 22:49:54 +02:00
|
|
|
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;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
if (!want_l) want_l = got_l;
|
|
|
|
|
else if (want_l != got_l) moveReg(want_l, got_l);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
if (!want_r) want_r = got_r;
|
|
|
|
|
else if (want_r != got_r) moveReg(want_r, got_r);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
int i;
|
2016-05-07 22:49:54 +02:00
|
|
|
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]);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
codeFrags.push_back(*as);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
freeReg(got_r);
|
|
|
|
|
if (want_l != got_l) moveReg(got_l, want_l);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
//cleanup argFrame
|
2016-05-07 22:49:54 +02:00
|
|
|
if (argFrame) {
|
2014-01-31 08:23:00 +13:00
|
|
|
//***** Not needed for STDCALL *****
|
|
|
|
|
// codeFrags.push_back( "+"+itoa(argFrame) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//restore spilled regs
|
2016-05-07 22:49:54 +02:00
|
|
|
if (spill) {
|
|
|
|
|
for (int n = NUM_REGS; n >= 1; --n) {
|
|
|
|
|
if (spill&(1 << n)) popReg(n);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return got_l;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Codegen_x86::flush() {
|
2014-01-31 08:23:00 +13:00
|
|
|
vector<string>::iterator it;
|
2016-05-07 22:49:54 +02:00
|
|
|
for (it = dataFrags.begin(); it != dataFrags.end(); ++it) out << *it;
|
2014-01-31 08:23:00 +13:00
|
|
|
dataFrags.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Codegen_x86::enter(const string &l, int frameSize) {
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
inCode = true;
|
|
|
|
|
::frameSize = maxFrameSize = frameSize;
|
|
|
|
|
codeFrags.clear(); funcLabel = l;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Codegen_x86::code(TNode *stmt) {
|
2014-01-31 08:23:00 +13:00
|
|
|
resetRegs();
|
2016-05-07 22:49:54 +02:00
|
|
|
Tile *q = munch(stmt);
|
2014-01-31 08:23:00 +13:00
|
|
|
q->label();
|
2016-05-07 22:49:54 +02:00
|
|
|
q->eval(0);
|
2014-01-31 08:23:00 +13:00
|
|
|
delete q;
|
|
|
|
|
delete stmt;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
static string fixEsp(int esp_off) {
|
|
|
|
|
if (esp_off < 0) return "\tsub\tesp," + itoa(-esp_off) + "\n";
|
|
|
|
|
return "\tadd\tesp," + itoa(esp_off) + "\n";
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Codegen_x86::leave(TNode *cleanup, int pop_sz) {
|
|
|
|
|
if (cleanup) {
|
2014-01-31 08:23:00 +13:00
|
|
|
resetRegs();
|
2016-05-07 22:49:54 +02:00
|
|
|
allocReg(EAX);
|
|
|
|
|
Tile *q = munch(cleanup);
|
2014-01-31 08:23:00 +13:00
|
|
|
q->label();
|
2016-05-07 22:49:54 +02:00
|
|
|
q->eval(0);
|
2014-01-31 08:23:00 +13:00
|
|
|
delete q;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
out << "\t.align\t16\n";
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
if (funcLabel.size()) out << funcLabel << '\n';
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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';
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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] == '-') {
|
2014-01-31 08:23:00 +13:00
|
|
|
//***** Still needed for STDCALL *****
|
2016-05-07 22:49:54 +02:00
|
|
|
esp_off -= atoi(t.substr(1));
|
|
|
|
|
} else {
|
|
|
|
|
if (esp_off) {
|
|
|
|
|
out << fixEsp(esp_off);
|
|
|
|
|
esp_off = 0;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
2016-05-07 22:49:54 +02:00
|
|
|
out << *it;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-07 22:49:54 +02:00
|
|
|
if (esp_off) out << fixEsp(esp_off);
|
2014-01-31 08:23:00 +13:00
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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";
|
2014-01-31 08:23:00 +13:00
|
|
|
|
|
|
|
|
delete cleanup;
|
2016-05-07 22:49:54 +02:00
|
|
|
inCode = false;
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Codegen_x86::label(const string &l) {
|
|
|
|
|
string t = l + '\n';
|
|
|
|
|
if (inCode) codeFrags.push_back(t);
|
|
|
|
|
else dataFrags.push_back(t);
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
void Codegen_x86::align_data(int n) {
|
|
|
|
|
char buff[32]; _itoa(n, buff, 10);
|
|
|
|
|
dataFrags.push_back(string("\t.align\t") + buff + '\n');
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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');
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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");
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|
|
|
|
|
|
2016-05-07 22:49:54 +02:00
|
|
|
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');
|
2014-01-31 08:23:00 +13:00
|
|
|
}
|