Files
BlitzNext/compiler/node.cpp
T
Michael Fabian Dirks 581c640149 Uh, Updates?
2016-10-03 17:11:15 +02:00

285 lines
6.8 KiB
C++

#include "std.h"
#include "nodes.h"
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 );
}