c4947bd12a
compiler is blitzcc, what I previously called compiler is now compiler_lib
724 lines
14 KiB
C++
724 lines
14 KiB
C++
#include "codegen_x86.hpp"
|
|
#include "tile.hpp"
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <stdutil.hpp>
|
|
|
|
//#define NOOPTS
|
|
|
|
Codegen_x86::Codegen_x86(std::ostream& out, bool debug) : Codegen(out, debug), inCode(false) {}
|
|
|
|
void Codegen_x86::enter(const std::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;
|
|
}
|
|
|
|
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;
|
|
std::vector<std::string>::iterator it = codeFrags.begin();
|
|
for (it = codeFrags.begin(); it != codeFrags.end(); ++it) {
|
|
const std::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 std::string& l)
|
|
{
|
|
std::string t = l + '\n';
|
|
if (inCode)
|
|
codeFrags.push_back(t);
|
|
else
|
|
dataFrags.push_back(t);
|
|
}
|
|
|
|
void Codegen_x86::i_data(int i, const std::string& l)
|
|
{
|
|
if (l.size())
|
|
dataFrags.push_back(l);
|
|
char buff[32];
|
|
_itoa(i, buff, 10);
|
|
dataFrags.push_back(std::string("\t.dd\t") + buff + '\n');
|
|
}
|
|
|
|
void Codegen_x86::s_data(const std::string& s, const std::string& l)
|
|
{
|
|
if (l.size())
|
|
dataFrags.push_back(l);
|
|
dataFrags.push_back(std::string("\t.db\t\"") + s + "\",0\n");
|
|
}
|
|
|
|
void Codegen_x86::p_data(const std::string& p, const std::string& l)
|
|
{
|
|
if (l.size())
|
|
dataFrags.push_back(l);
|
|
dataFrags.push_back(std::string("\t.dd\t") + p + '\n');
|
|
}
|
|
|
|
void Codegen_x86::align_data(int n)
|
|
{
|
|
char buff[32];
|
|
_itoa(n, buff, 10);
|
|
dataFrags.push_back(std::string("\t.align\t") + buff + '\n');
|
|
}
|
|
|
|
void Codegen_x86::flush()
|
|
{
|
|
std::vector<std::string>::iterator it;
|
|
for (it = dataFrags.begin(); it != dataFrags.end(); ++it)
|
|
out << *it;
|
|
dataFrags.clear();
|
|
}
|
|
|
|
static std::string itoa_sgn(int n)
|
|
{
|
|
return n ? (n > 0 ? "+" + itoa(n) : itoa(n)) : "";
|
|
}
|
|
|
|
static bool isRelop(int op)
|
|
{
|
|
return op == IR_SETEQ || op == IR_SETNE || op == IR_SETLT || op == IR_SETGT || op == IR_SETLE || op == IR_SETGE;
|
|
}
|
|
|
|
static bool nodesEqual(TNode* t1, TNode* t2)
|
|
{
|
|
if (t1->op != t2->op || t1->iconst != t2->iconst || t1->sconst != t2->sconst)
|
|
return false;
|
|
|
|
if (t1->l) {
|
|
if (!t2->l || !nodesEqual(t1->l, t2->l))
|
|
return false;
|
|
} else if (t2->l)
|
|
return false;
|
|
|
|
if (t1->r) {
|
|
if (!t2->r || !nodesEqual(t1->r, t2->r))
|
|
return false;
|
|
} else if (t2->r)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool getShift(int n, int& shift)
|
|
{
|
|
#ifdef NOOPTS
|
|
return false;
|
|
#endif
|
|
|
|
for (shift = 0; shift < 32; ++shift) {
|
|
if ((1 << shift) == n)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool matchMEM(TNode* t, std::string& s)
|
|
{
|
|
#ifdef NOOPTS
|
|
return false;
|
|
#endif
|
|
|
|
if (t->op != IR_MEM)
|
|
return false;
|
|
t = t->l;
|
|
switch (t->op) {
|
|
case IR_GLOBAL:
|
|
s = "[" + t->sconst + "]";
|
|
return true;
|
|
case IR_LOCAL:
|
|
s = "[ebp" + itoa_sgn(t->iconst) + "]";
|
|
return true;
|
|
case IR_ARG:
|
|
s = "[esp" + itoa_sgn(t->iconst) + "]";
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool matchCONST(TNode* t, std::string& s)
|
|
{
|
|
#ifdef NOOPTS
|
|
return false;
|
|
#endif
|
|
|
|
switch (t->op) {
|
|
case IR_CONST:
|
|
s = itoa(t->iconst);
|
|
return true;
|
|
case IR_GLOBAL:
|
|
s = t->sconst;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool matchMEMCONST(TNode* t, std::string& s)
|
|
{
|
|
#ifdef NOOPTS
|
|
return false;
|
|
#endif
|
|
|
|
return matchMEM(t, s) || matchCONST(t, s);
|
|
}
|
|
|
|
Tile* Codegen_x86::genCompare(TNode* t, std::string& func, bool negate)
|
|
{
|
|
switch (t->op) {
|
|
case IR_SETEQ:
|
|
func = negate ? "nz" : "z";
|
|
break;
|
|
case IR_SETNE:
|
|
func = negate ? "z" : "nz";
|
|
break;
|
|
case IR_SETLT:
|
|
func = negate ? "ge" : "l";
|
|
break;
|
|
case IR_SETGT:
|
|
func = negate ? "le" : "g";
|
|
break;
|
|
case IR_SETLE:
|
|
func = negate ? "g" : "le";
|
|
break;
|
|
case IR_SETGE:
|
|
func = negate ? "l" : "ge";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
std::string q, m, c;
|
|
TNode *ql = 0, *qr = 0;
|
|
|
|
if (matchMEM(t->l, m)) {
|
|
if (matchCONST(t->r, c)) {
|
|
q = "\tcmp\t" + m + "," + c + "\n";
|
|
} else {
|
|
q = "\tcmp\t" + m + ",%l\n";
|
|
ql = t->r;
|
|
}
|
|
} else {
|
|
if (matchMEMCONST(t->r, m)) {
|
|
q = "\tcmp\t%l," + m + "\n";
|
|
ql = t->l;
|
|
} else {
|
|
q = "\tcmp\t%l,%r\n";
|
|
ql = t->l;
|
|
qr = t->r;
|
|
}
|
|
}
|
|
|
|
return new Tile(q, ql ? munchReg(ql) : 0, qr ? munchReg(qr) : 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////
|
|
// Integer expressions returned in a register //
|
|
////////////////////////////////////////////////
|
|
Tile* Codegen_x86::munchUnary(TNode* t)
|
|
{
|
|
std::string s;
|
|
switch (t->op) {
|
|
case IR_NEG:
|
|
s = "\tneg\t%l\n";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return new Tile(s, munchReg(t->l));
|
|
}
|
|
|
|
Tile* Codegen_x86::munchLogical(TNode* t)
|
|
{
|
|
std::string s;
|
|
switch (t->op) {
|
|
case IR_AND:
|
|
s = "\tand\t%l,%r\n";
|
|
break;
|
|
case IR_OR:
|
|
s = "\tor\t%l,%r\n";
|
|
break;
|
|
case IR_XOR:
|
|
s = "\txor\t%l,%r\n";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return new Tile(s, munchReg(t->l), munchReg(t->r));
|
|
}
|
|
|
|
Tile* Codegen_x86::munchArith(TNode* t)
|
|
{
|
|
if (t->op == IR_DIV) {
|
|
int shift;
|
|
if (t->r->op == IR_CONST) {
|
|
if (getShift(t->r->iconst, shift)) {
|
|
return new Tile("\tsar\t%l,byte " + itoa(shift) + "\n", munchReg(t->l));
|
|
}
|
|
}
|
|
Tile* q = new Tile("\tcdq\n\tidiv\tecx\n", munchReg(t->l), munchReg(t->r));
|
|
q->want_l = EAX;
|
|
q->want_r = ECX;
|
|
q->hits = 1 << EDX;
|
|
return q;
|
|
}
|
|
|
|
if (t->op == IR_MUL) {
|
|
int shift;
|
|
if (t->r->op == IR_CONST) {
|
|
if (getShift(t->r->iconst, shift)) {
|
|
return new Tile("\tshl\t%l,byte " + itoa(shift) + "\n", munchReg(t->l));
|
|
}
|
|
} else if (t->l->op == IR_CONST) {
|
|
if (getShift(t->l->iconst, shift)) {
|
|
return new Tile("\tshl\t%l,byte " + itoa(shift) + "\n", munchReg(t->r));
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string s, op;
|
|
switch (t->op) {
|
|
case IR_ADD:
|
|
op = "\tadd\t";
|
|
break;
|
|
case IR_SUB:
|
|
op = "\tsub\t";
|
|
break;
|
|
case IR_MUL:
|
|
op = "\timul\t";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
if (matchMEMCONST(t->r, s)) {
|
|
return new Tile(op + "%l," + s + "\n", munchReg(t->l));
|
|
}
|
|
if (t->op != IR_SUB && matchMEMCONST(t->l, s)) {
|
|
return new Tile(op + "%l," + s + "\n", munchReg(t->r));
|
|
}
|
|
return new Tile(op + "%l,%r\n", munchReg(t->l), munchReg(t->r));
|
|
}
|
|
|
|
Tile* Codegen_x86::munchShift(TNode* t)
|
|
{
|
|
std::string s, op;
|
|
switch (t->op) {
|
|
case IR_SHL:
|
|
op = "\tshl\t";
|
|
break;
|
|
case IR_SHR:
|
|
op = "\tshr\t";
|
|
break;
|
|
case IR_SAR:
|
|
op = "\tsar\t";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
if (matchCONST(t->r, s)) {
|
|
return new Tile(op + "%l,byte " + s + "\n", munchReg(t->l));
|
|
}
|
|
|
|
Tile* q = new Tile(op + "%l,cl\n", munchReg(t->l), munchReg(t->r));
|
|
q->want_r = ECX;
|
|
return q;
|
|
}
|
|
|
|
Tile* Codegen_x86::munchRelop(TNode* t)
|
|
{
|
|
std::string func;
|
|
Tile* q = genCompare(t, func, false);
|
|
|
|
q = new Tile("\tset" + func + "\tal\n\tmovzx\teax,al\n", q);
|
|
q->want_l = EAX;
|
|
return q;
|
|
}
|
|
|
|
////////////////////////////////////////////////
|
|
// Float expressions returned on the FP stack //
|
|
////////////////////////////////////////////////
|
|
Tile* Codegen_x86::munchFPUnary(TNode* t)
|
|
{
|
|
std::string s;
|
|
switch (t->op) {
|
|
case IR_FNEG:
|
|
s = "\tfchs\n";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return new Tile(s, munchFP(t->l));
|
|
}
|
|
|
|
Tile* Codegen_x86::munchFPArith(TNode* t)
|
|
{
|
|
std::string s, s2;
|
|
switch (t->op) {
|
|
case IR_FADD:
|
|
s = "\tfaddp\tst(1)\n";
|
|
break;
|
|
case IR_FMUL:
|
|
s = "\tfmulp\tst(1)\n";
|
|
break;
|
|
case IR_FSUB:
|
|
s = "\tfsubrp\tst(1)\n";
|
|
s2 = "\tfsubp\tst(1)\n";
|
|
break;
|
|
case IR_FDIV:
|
|
s = "\tfdivrp\tst(1)\n";
|
|
s2 = "\tfdivp\tst(1)\n";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return new Tile(s, s2, munchFP(t->l), munchFP(t->r));
|
|
}
|
|
|
|
Tile* Codegen_x86::munchFPRelop(TNode* t)
|
|
{
|
|
std::string s, s2;
|
|
switch (t->op) {
|
|
case IR_FSETEQ:
|
|
s = "z";
|
|
s2 = "z";
|
|
break;
|
|
case IR_FSETNE:
|
|
s = "nz";
|
|
s2 = "nz";
|
|
break;
|
|
case IR_FSETLT:
|
|
s = "b";
|
|
s2 = "a";
|
|
break;
|
|
case IR_FSETGT:
|
|
s = "a";
|
|
s2 = "b";
|
|
break;
|
|
case IR_FSETLE:
|
|
s = "be";
|
|
s2 = "ae";
|
|
break;
|
|
case IR_FSETGE:
|
|
s = "ae";
|
|
s2 = "be";
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
s = "\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset" + s + "\tal\n\tmovzx\t%l,al\n";
|
|
s2 = "\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset" + s2 + "\tal\n\tmovzx\t%l,al\n";
|
|
Tile* q = new Tile(s, s2, munchFP(t->l), munchFP(t->r));
|
|
q->want_l = EAX;
|
|
return q;
|
|
}
|
|
|
|
///////////////////////////
|
|
// Generic Call handling //
|
|
///////////////////////////
|
|
Tile* Codegen_x86::munchCall(TNode* t)
|
|
{
|
|
Tile* q;
|
|
if (t->l->op == IR_GLOBAL) {
|
|
q = new Tile("\tcall\t" + t->l->sconst + "\n", t->r ? munchReg(t->r) : 0);
|
|
} else {
|
|
q = new Tile("\tcall\t%l\n", munchReg(t->l), t->r ? munchReg(t->r) : 0);
|
|
}
|
|
q->argFrame = t->iconst;
|
|
q->want_l = EAX;
|
|
q->hits = (1 << EAX) | (1 << ECX) | (1 << EDX);
|
|
return q;
|
|
}
|
|
|
|
/////////////////////////////
|
|
// munch and dicard result //
|
|
/////////////////////////////
|
|
Tile* Codegen_x86::munch(TNode* t)
|
|
{
|
|
if (!t)
|
|
return 0;
|
|
Tile* q = 0;
|
|
std::string s;
|
|
switch (t->op) {
|
|
case IR_JSR:
|
|
q = new Tile("\tcall\t" + t->sconst + '\n');
|
|
break;
|
|
case IR_RET:
|
|
q = new Tile("\tret\n");
|
|
break;
|
|
case IR_RETURN:
|
|
q = munchReg(t->l);
|
|
q->want_l = EAX;
|
|
s = "\tjmp\t" + t->sconst + '\n';
|
|
q = new Tile(s, q);
|
|
break;
|
|
case IR_FRETURN:
|
|
q = munchFP(t->l);
|
|
s = "\tjmp\t" + t->sconst + '\n';
|
|
q = new Tile(s, q);
|
|
break;
|
|
case IR_CALL:
|
|
q = munchCall(t);
|
|
break;
|
|
case IR_JUMP:
|
|
q = new Tile("\tjmp\t" + t->sconst + '\n');
|
|
break;
|
|
case IR_JUMPT:
|
|
if (TNode* p = t->l) {
|
|
bool neg = false;
|
|
if (isRelop(p->op)) {
|
|
std::string func;
|
|
q = genCompare(p, func, neg);
|
|
q = new Tile("\tj" + func + "\t" + t->sconst + "\n", q);
|
|
}
|
|
}
|
|
break;
|
|
case IR_JUMPF:
|
|
if (TNode* p = t->l) {
|
|
bool neg = true;
|
|
if (isRelop(p->op)) {
|
|
std::string func;
|
|
q = genCompare(p, func, neg);
|
|
q = new Tile("\tj" + func + "\t" + t->sconst + "\n", q);
|
|
}
|
|
}
|
|
break;
|
|
case IR_MOVE:
|
|
if (matchMEM(t->r, s)) {
|
|
std::string c;
|
|
if (matchCONST(t->l, c)) {
|
|
q = new Tile("\tmov\t" + s + "," + c + "\n");
|
|
} else if (t->l->op == IR_ADD || t->l->op == IR_SUB) {
|
|
TNode* p = 0;
|
|
if (nodesEqual(t->l->l, t->r))
|
|
p = t->l->r;
|
|
else if (t->l->op == IR_ADD && nodesEqual(t->l->r, t->r))
|
|
p = t->l->l;
|
|
if (p) {
|
|
std::string c, op;
|
|
switch (t->l->op) {
|
|
case IR_ADD:
|
|
op = "\tadd\t";
|
|
break;
|
|
case IR_SUB:
|
|
op = "\tsub\t";
|
|
break;
|
|
}
|
|
if (matchCONST(p, c)) {
|
|
q = new Tile(op + s + "," + c + "\n");
|
|
} else {
|
|
q = new Tile(op + s + ",%l\n", munchReg(p));
|
|
}
|
|
}
|
|
}
|
|
if (!q)
|
|
q = new Tile("\tmov\t" + s + ",%l\n", munchReg(t->l));
|
|
}
|
|
break;
|
|
}
|
|
if (!q)
|
|
q = munchReg(t);
|
|
return q;
|
|
}
|
|
|
|
///////////////////////////////////////////
|
|
// munch and return result in a register //
|
|
///////////////////////////////////////////
|
|
Tile* Codegen_x86::munchReg(TNode* t)
|
|
{
|
|
if (!t)
|
|
return 0;
|
|
|
|
std::string s;
|
|
Tile* q = 0;
|
|
|
|
switch (t->op) {
|
|
case IR_JUMPT:
|
|
q = new Tile("\tand\t%l,%l\n\tjnz\t" + t->sconst + '\n', munchReg(t->l));
|
|
break;
|
|
case IR_JUMPF:
|
|
q = new Tile("\tand\t%l,%l\n\tjz\t" + t->sconst + '\n', munchReg(t->l));
|
|
break;
|
|
case IR_JUMPGE:
|
|
q = new Tile("\tcmp\t%l,%r\n\tjnc\t" + t->sconst + '\n', munchReg(t->l), munchReg(t->r));
|
|
break;
|
|
case IR_CALL:
|
|
q = munchCall(t);
|
|
break;
|
|
case IR_MOVE:
|
|
//MUST BE MOVE TO MEM!
|
|
if (matchMEM(t->r, s)) {
|
|
q = new Tile("\tmov\t" + s + ",%l\n", munchReg(t->l));
|
|
} else if (t->r->op == IR_MEM) {
|
|
q = new Tile("\tmov\t[%r],%l\n", munchReg(t->l), munchReg(t->r->l));
|
|
}
|
|
break;
|
|
case IR_MEM:
|
|
if (matchMEM(t, s)) {
|
|
q = new Tile("\tmov\t%l," + s + "\n");
|
|
} else {
|
|
q = new Tile("\tmov\t%l,[%l]\n", munchReg(t->l));
|
|
}
|
|
break;
|
|
case IR_SEQ:
|
|
q = new Tile("", munch(t->l), munch(t->r));
|
|
break;
|
|
case IR_ARG:
|
|
q = new Tile("\tlea\t%l,[esp" + itoa_sgn(t->iconst) + "]\n");
|
|
break;
|
|
case IR_LOCAL:
|
|
q = new Tile("\tlea\t%l,[ebp" + itoa_sgn(t->iconst) + "]\n");
|
|
break;
|
|
case IR_GLOBAL:
|
|
q = new Tile(std::string("\tmov\t%l,") + t->sconst + '\n');
|
|
break;
|
|
case IR_CAST:
|
|
q = munchFP(t->l);
|
|
s = "\tpush\t%l\n\tfistp\t[esp]\n\tpop\t%l\n";
|
|
q = new Tile(s, q);
|
|
break;
|
|
case IR_CONST:
|
|
q = new Tile("\tmov\t%l," + itoa(t->iconst) + "\n");
|
|
break;
|
|
case IR_NEG:
|
|
q = munchUnary(t);
|
|
break;
|
|
case IR_AND:
|
|
case IR_OR:
|
|
case IR_XOR:
|
|
q = munchLogical(t);
|
|
break;
|
|
case IR_ADD:
|
|
case IR_SUB:
|
|
case IR_MUL:
|
|
case IR_DIV:
|
|
q = munchArith(t);
|
|
break;
|
|
case IR_SHL:
|
|
case IR_SHR:
|
|
case IR_SAR:
|
|
q = munchShift(t);
|
|
break;
|
|
case IR_SETEQ:
|
|
case IR_SETNE:
|
|
case IR_SETLT:
|
|
case IR_SETGT:
|
|
case IR_SETLE:
|
|
case IR_SETGE:
|
|
q = munchRelop(t);
|
|
break;
|
|
case IR_FSETEQ:
|
|
case IR_FSETNE:
|
|
case IR_FSETLT:
|
|
case IR_FSETGT:
|
|
case IR_FSETLE:
|
|
case IR_FSETGE:
|
|
q = munchFPRelop(t);
|
|
break;
|
|
default:
|
|
q = munchFP(t);
|
|
if (!q)
|
|
return 0;
|
|
s = "\tpush\t%l\n\tfstp\t[esp]\n\tpop\t%l\n";
|
|
q = new Tile(s, q);
|
|
}
|
|
return q;
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
// munch and return result on FP stack //
|
|
/////////////////////////////////////////
|
|
Tile* Codegen_x86::munchFP(TNode* t)
|
|
{
|
|
if (!t)
|
|
return 0;
|
|
|
|
std::string s;
|
|
Tile* q = 0;
|
|
|
|
switch (t->op) {
|
|
case IR_FCALL:
|
|
q = munchCall(t);
|
|
break;
|
|
case IR_FCAST:
|
|
s = "\tpush\t%l\n\tfild\t[esp]\n\tpop\t%l\n";
|
|
q = new Tile(s, munchReg(t->l));
|
|
break;
|
|
case IR_FNEG:
|
|
q = munchFPUnary(t);
|
|
break;
|
|
case IR_FADD:
|
|
case IR_FSUB:
|
|
case IR_FMUL:
|
|
case IR_FDIV:
|
|
q = munchFPArith(t);
|
|
break;
|
|
default:
|
|
q = munchReg(t);
|
|
if (!q)
|
|
return 0;
|
|
s = "\tpush\t%l\n\tfld\t[esp]\n\tpop\t%l\n";
|
|
q = new Tile(s, q);
|
|
}
|
|
return q;
|
|
}
|