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

356 lines
7.2 KiB
C++

#include "nodes.hpp"
#include "std.hpp"
set<string> Node::usedfuncs;
///////////////////////////////
// generic exception thrower //
///////////////////////////////
void Node::ex()
{
ex("INTERNAL COMPILER ERROR");
}
void Node::ex(const string& e)
{
throw Ex(e, -1, "");
}
void Node::ex(const string& e, int pos)
{
throw Ex(e, pos, "");
}
void Node::ex(const string& e, int pos, const string& f)
{
throw Ex(e, pos, f);
}
///////////////////////////////
// Generate a local variable //
///////////////////////////////
VarNode* Node::genLocal(Environ* e, Type* ty)
{
string t = genLabel();
Decl* d = e->decls->insertDecl(t, ty, DECL_LOCAL);
return new DeclVarNode(d);
}
/////////////////////////////////////////////////
// if type is const, return const value else 0 //
/////////////////////////////////////////////////
ConstNode* Node::constValue(Type* ty)
{
ConstType* c = ty->constType();
if (!c)
return 0;
ty = c->valueType;
if (ty == Type::int_type)
return new IntConstNode(c->intValue);
if (ty == Type::float_type)
return new FloatConstNode(c->floatValue);
return new StringConstNode(c->stringValue);
}
///////////////////////////////////////////////////////
// work out var offsets - return size of local frame //
///////////////////////////////////////////////////////
int Node::enumVars(Environ* e)
{
//calc offsets
int p_size = 0, l_size = 0;
for (int k = 0; k < e->decls->size(); ++k) {
Decl* d = e->decls->decls[k];
if (d->kind & DECL_PARAM) {
d->offset = p_size + 20;
p_size += 4;
} else if (d->kind & DECL_LOCAL) {
d->offset = -4 - l_size;
l_size += 4;
}
}
return l_size;
}
//////////////////////////////
// initialize all vars to 0 //
//////////////////////////////
TNode* Node::createVars(Environ* e)
{
int k;
TNode* t = 0;
//initialize locals
for (k = 0; k < e->decls->size(); ++k) {
Decl* d = e->decls->decls[k];
if (d->kind != DECL_LOCAL)
continue;
if (d->type->vectorType())
continue;
if (!t)
t = new TNode(IR_CONST, 0, 0, 0);
TNode* p = new TNode(IR_LOCAL, 0, 0, d->offset);
p = new TNode(IR_MEM, p, 0);
t = new TNode(IR_MOVE, t, p);
}
//initialize vectors
for (k = 0; k < e->decls->size(); ++k) {
Decl* d = e->decls->decls[k];
if (d->kind == DECL_PARAM)
continue;
VectorType* v = d->type->vectorType();
if (!v)
continue;
TNode* p = call("__bbVecAlloc", global(v->label));
TNode* m = d->kind == DECL_GLOBAL ? global("_v" + d->name) : local(d->offset);
p = move(p, mem(m));
if (t)
t = seq(t, p);
else
t = p;
}
return t;
}
////////////////////////
// release local vars //
////////////////////////
TNode* Node::deleteVars(Environ* e)
{
TNode *t = 0, *l = 0, *p, *p1 = nullptr, *p2 = nullptr;
for (int k = 0; k < e->decls->size(); ++k) {
Decl* d = e->decls->decls[k];
Type* type = d->type;
string func;
if (type == Type::string_type) {
if (d->kind == DECL_LOCAL || d->kind == DECL_PARAM) {
func = "__bbStrRelease";
p1 = mem(local(d->offset));
p2 = 0;
}
} else if (type->structType()) {
if (d->kind == DECL_LOCAL) {
func = "__bbObjRelease";
p1 = mem(local(d->offset));
p2 = 0;
}
} else if (VectorType* v = type->vectorType()) {
if (d->kind == DECL_LOCAL) {
func = "__bbVecFree";
p1 = mem(local(d->offset));
p2 = global(v->label);
}
}
if (!func.size())
continue;
p = new TNode(IR_SEQ, call(func, p1, p2), 0);
(l ? l->r : t) = p;
l = p;
}
return t;
}
//////////////////////////////////////////////////////////////
// compare 2 translated operands - return 1 if true, else 0 //
//////////////////////////////////////////////////////////////
TNode* Node::compare(int op, TNode* l, TNode* r, Type* ty)
{
int n = 0;
if (ty == Type::float_type) {
switch (op) {
case '=':
n = IR_FSETEQ;
break;
case NE:
n = IR_FSETNE;
break;
case '<':
n = IR_FSETLT;
break;
case '>':
n = IR_FSETGT;
break;
case LE:
n = IR_FSETLE;
break;
case GE:
n = IR_FSETGE;
break;
}
} else {
switch (op) {
case '=':
n = IR_SETEQ;
break;
case NE:
n = IR_SETNE;
break;
case '<':
n = IR_SETLT;
break;
case '>':
n = IR_SETGT;
break;
case LE:
n = IR_SETLE;
break;
case GE:
n = IR_SETGE;
break;
}
}
if (ty == Type::string_type) {
l = call("__bbStrCompare", l, r);
r = new TNode(IR_CONST, 0, 0, 0);
} else if (ty->structType()) {
l = call("__bbObjCompare", l, r);
r = new TNode(IR_CONST, 0, 0, 0);
}
return new TNode(n, l, r);
}
/////////////////////////////////
// calculate the type of a tag //
/////////////////////////////////
Type* Node::tagType(const string& tag, Environ* e)
{
Type* t;
if (tag.size()) {
t = e->findType(tag);
if (!t)
ex("Type \"" + tag + "\" not found");
} else
t = 0;
return t;
}
////////////////////////////////
// Generate a fresh ASM label //
////////////////////////////////
string Node::genLabel()
{
static int cnt;
return "_" + itoa(++cnt & 0x7fffffff);
}
//////////////////////////////////////////////////////
// create a stmt-type function call with int result //
//////////////////////////////////////////////////////
TNode* Node::call(const string& func, TNode* a0, TNode* a1, TNode* a2)
{
int size = 0;
TNode* t = 0;
if (a0) {
t = move(a0, mem(arg(0)));
size += 4;
if (a1) {
t = seq(t, move(a1, mem(arg(4))));
size += 4;
if (a2) {
t = seq(t, move(a2, mem(arg(8))));
size += 4;
}
}
}
TNode* l = new TNode(IR_GLOBAL, 0, 0, func);
return new TNode(IR_CALL, l, t, size);
}
////////////////////////////////////////////////////////
// create a stmt-type function call with float result //
////////////////////////////////////////////////////////
TNode* Node::fcall(const string& func, TNode* a0, TNode* a1, TNode* a2)
{
int size = 0;
TNode* t = 0;
if (a0) {
t = move(a0, mem(arg(0)));
size += 4;
if (a1) {
t = seq(t, move(a1, mem(arg(4))));
size += 4;
if (a2) {
t = seq(t, move(a2, mem(arg(8))));
size += 4;
}
}
}
TNode* l = new TNode(IR_GLOBAL, 0, 0, func);
return new TNode(IR_FCALL, l, t, size);
}
TNode* Node::seq(TNode* l, TNode* r)
{
return new TNode(IR_SEQ, l, r);
}
TNode* Node::move(TNode* src, TNode* dest)
{
return new TNode(IR_MOVE, src, dest);
}
TNode* Node::global(const string& s)
{
return new TNode(IR_GLOBAL, 0, 0, s);
}
TNode* Node::local(int offset)
{
return new TNode(IR_LOCAL, 0, 0, offset);
}
TNode* Node::arg(int offset)
{
return new TNode(IR_ARG, 0, 0, offset);
}
TNode* Node::mem(TNode* ref)
{
return new TNode(IR_MEM, ref, 0);
}
TNode* Node::add(TNode* l, TNode* r)
{
return new TNode(IR_ADD, l, r);
}
TNode* Node::mul(TNode* l, TNode* r)
{
return new TNode(IR_MUL, l, r);
}
TNode* Node::iconst(int n)
{
return new TNode(IR_CONST, 0, 0, n);
}
TNode* Node::ret()
{
return new TNode(IR_RET, 0, 0);
}
TNode* Node::jsr(const string& s)
{
return new TNode(IR_JSR, 0, 0, s);
}
TNode* Node::jump(const string& s)
{
return new TNode(IR_JUMP, 0, 0, s);
}
TNode* Node::jumpt(TNode* expr, const string& s)
{
return new TNode(IR_JUMPT, expr, 0, s);
}
TNode* Node::jumpf(TNode* expr, const string& s)
{
return new TNode(IR_JUMPF, expr, 0, s);
}
TNode* Node::jumpge(TNode* l, TNode* r, const string& s)
{
return new TNode(IR_JUMPGE, l, r, s);
}