Files
BlitzNext/compiler/lib/codegen_x86/tile.cpp
T

223 lines
3.9 KiB
C++
Raw Normal View History

2019-01-19 18:28:07 +01:00
#include "tile.hpp"
#include <string>
#include <vector>
#include "codegen_x86.hpp"
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
#include <stdutil.hpp>
2014-01-31 08:23:00 +13:00
//reduce to 3 for stress test
2019-01-19 18:28:07 +01:00
const std::string regs[] = {"???", "eax", "ecx", "edx", "edi", "esi", "ebx"};
2014-01-31 08:23:00 +13:00
//array of 'used' flags
2019-01-19 18:28:07 +01:00
bool regUsed[NUM_REGS + 1];
2014-01-31 08:23:00 +13:00
//size of locals in function
2019-01-19 18:28:07 +01:00
int frameSize, maxFrameSize;
2014-01-31 08:23:00 +13:00
//code fragments
2019-01-19 18:28:07 +01:00
std::vector<std::string> codeFrags, dataFrags;
2014-01-31 08:23:00 +13:00
//name of function
2019-01-19 18:28:07 +01:00
std::string funcLabel;
2014-01-31 08:23:00 +13:00
2019-01-19 18:28:07 +01:00
void resetRegs()
2019-01-18 17:04:57 +01:00
{
for (int n = 1; n <= NUM_REGS; ++n)
regUsed[n] = false;
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
int allocReg(int n)
2019-01-18 17:04:57 +01:00
{
if (!n || regUsed[n]) {
2019-01-18 17:04:57 +01:00
for (n = NUM_REGS; n >= 1 && regUsed[n]; --n) {
}
if (!n)
return 0;
2014-01-31 08:23:00 +13:00
}
regUsed[n] = true;
2014-01-31 08:23:00 +13:00
return n;
}
2019-01-18 17:04:57 +01:00
static void freeReg(int n)
{
regUsed[n] = false;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
static void pushReg(int n)
{
frameSize += 4;
2019-01-18 17:04:57 +01:00
if (frameSize > maxFrameSize)
maxFrameSize = frameSize;
char buff[32];
_itoa(frameSize, buff, 10);
2019-01-19 18:28:07 +01:00
std::string s = "\tmov\t[ebp-";
2019-01-18 17:04:57 +01:00
s += buff;
s += "],";
s += regs[n];
s += '\n';
codeFrags.push_back(s);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
static void popReg(int n)
{
char buff[32];
_itoa(frameSize, buff, 10);
2019-01-19 18:28:07 +01:00
std::string s = "\tmov\t";
2019-01-18 17:04:57 +01:00
s += regs[n];
s += ",[ebp-";
s += buff;
s += "]\n";
codeFrags.push_back(s);
frameSize -= 4;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
static void moveReg(int d, int s)
{
2019-01-19 18:28:07 +01:00
std::string t = "\tmov\t" + regs[d] + ',' + regs[s] + '\n';
codeFrags.push_back(t);
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
static void swapRegs(int d, int s)
{
2019-01-19 18:28:07 +01:00
std::string t = "\txchg\t" + regs[d] + ',' + regs[s] + '\n';
codeFrags.push_back(t);
2014-01-31 08:23:00 +13:00
}
2019-01-19 18:28:07 +01:00
Tile::Tile(const std::string& a, Tile* l, Tile* r)
2019-01-18 17:04:57 +01:00
: 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
2019-01-19 18:28:07 +01:00
Tile::Tile(const std::string& a, const std::string& a2, Tile* l, Tile* r)
2019-01-18 17:04:57 +01:00
: 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
2019-01-18 17:04:57 +01:00
Tile::~Tile()
{
delete l;
delete r;
2014-01-31 08:23:00 +13:00
}
2019-01-18 17:04:57 +01:00
void Tile::label()
{
if (!l) {
need = 1;
} else if (!r) {
2014-01-31 08:23:00 +13:00
l->label();
need = l->need;
} else {
2019-01-18 17:04:57 +01:00
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
}
}
2019-01-18 17:04:57 +01:00
int Tile::eval(int want)
{
2014-01-31 08:23:00 +13:00
//save any hit registers
int spill = hits;
2019-01-18 17:04:57 +01:00
if (want_l)
spill |= 1 << want_l;
if (want_r)
spill |= 1 << want_r;
if (spill) {
for (int n = 1; n <= NUM_REGS; ++n) {
2019-01-18 17:04:57 +01:00
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...
if (argFrame) {
codeFrags.push_back("-" + itoa(argFrame));
2014-01-31 08:23:00 +13:00
}
int got_l = 0, got_r = 0;
2019-01-18 17:04:57 +01:00
if (want_l)
want = want_l;
2019-01-19 18:28:07 +01:00
std::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);
2019-01-18 17:04:57 +01:00
pushReg(got_r);
freeReg(got_r);
got_l = l->eval(want);
2019-01-18 17:04:57 +01:00
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);
2019-01-18 17:04:57 +01:00
if (assem2.size())
as = &assem2;
2014-01-31 08:23:00 +13:00
}
if (want_l == got_r || want_r == got_l) {
swapRegs(got_l, got_r);
2019-01-18 17:04:57 +01:00
int t = got_l;
got_l = got_r;
got_r = t;
2014-01-31 08:23:00 +13:00
}
}
2019-01-18 17:04:57 +01: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
2019-01-18 17:04:57 +01: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;
2019-01-19 18:28:07 +01:00
while ((i = as->find("%l")) != std::string::npos)
2019-01-18 17:04:57 +01:00
as->replace(i, 2, regs[want_l]);
2019-01-19 18:28:07 +01:00
while ((i = as->find("%r")) != std::string::npos)
2019-01-18 17:04:57 +01:00
as->replace(i, 2, regs[want_r]);
2014-01-31 08:23:00 +13:00
codeFrags.push_back(*as);
2014-01-31 08:23:00 +13:00
freeReg(got_r);
2019-01-18 17:04:57 +01:00
if (want_l != got_l)
moveReg(got_l, want_l);
2014-01-31 08:23:00 +13:00
//cleanup argFrame
if (argFrame) {
2014-01-31 08:23:00 +13:00
//***** Not needed for STDCALL *****
2019-01-18 17:04:57 +01:00
// codeFrags.push_back( "+"+itoa(argFrame) );
2014-01-31 08:23:00 +13:00
}
//restore spilled regs
if (spill) {
for (int n = NUM_REGS; n >= 1; --n) {
2019-01-18 17:04:57 +01:00
if (spill & (1 << n))
popReg(n);
2014-01-31 08:23:00 +13:00
}
}
return got_l;
}
2019-01-19 18:28:07 +01:00
std::string fixEsp(int esp_off)
2019-01-18 17:04:57 +01:00
{
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
}