From: blitz-research Date: Wed, 22 Jan 2014 23:11:01 +0000 (+1300) Subject: Added compiler src. X-Git-Tag: v150~21 X-Git-Url: https://jcornell.net/gitweb/gitweb.cgi?a=commitdiff_plain;h=ef5d0cfcaa923d2cc8c8a0a6b979f310e0c538ff;p=blitzmax.git Added compiler src. --- diff --git a/_src/.gitignore b/_src/.gitignore new file mode 100644 index 0000000..aa21a79 --- /dev/null +++ b/_src/.gitignore @@ -0,0 +1,2 @@ +/old/* +/setup/* diff --git a/_src/codegen/cgallocregs.cpp b/_src/codegen/cgallocregs.cpp new file mode 100644 index 0000000..baf1c50 --- /dev/null +++ b/_src/codegen/cgallocregs.cpp @@ -0,0 +1,596 @@ + +#include "cgstd.h" + +#include "cgallocregs.h" +#include "cgdebug.h" +#include "cgutil.h" + +#include + +//quick debug +//#define _DEBUG_ALLOCREGS + +//BIG debug! +//#define _DEBUG_REGALLOC + +using namespace CG; +using namespace std; + +static CGFlow *flow; +static CGFrame *frame; + +struct Node; +typedef set NodeSet; +typedef NodeSet::iterator NodeIter; + +static int reg_colors[4]; + +static int n_passes,n_spills,max_spill_id; + +struct Node{ + Node *succ,*pred,*_list; + + CGReg *reg; + Node *alias; + int bank,color,degree; + float usage; + int block_count; + NodeSet edges,moves; + + bool cant_spill; + + Node():reg(0),alias(0),bank(-1),color(-1),degree(0),usage(0),block_count(1),cant_spill(false){ + clear(); + } + + void setReg( CGReg *r ){ + reg=r; + color=reg->color; + bank=frame->reg_banks[reg->type]; + } + + Node *unAlias(){ + return alias ? alias->unAlias() : this; + } + + void clear(){ + _list=0; + succ=pred=this; + } + + bool empty(){ + return succ==this; + } + + void insert( Node *t_list ){ + if( _list==t_list ) return; + pred->succ=succ; + succ->pred=pred; + succ=t_list; + pred=succ->pred; + succ->pred=pred->succ=this; + _list=t_list; + } + + int colors(){ + return reg_colors[bank]; + } + + bool sigDegree(){ + return degree>=colors(); + } + + bool colored(){ + return color!=-1; + } + + bool moveRelated(){ + return moves.size()>0; + } +}; + +//node per enumerated tmp +static vector nodes; + +//nodes not yet removed from graph +static Node *_simplify,*_coalesce,*_freeze,*_spill; + +//nodes removed from graph +static Node *_selected,*_coalesced,*_spilled,*_colored; + +static void freezeNode( Node *node ); + +static void createNodes(){ + + nodes.clear(); + nodes.resize( frame->regs.size() ); + + int k; + for( k=0;kregs.size();++k ){ + CGReg *r=frame->regs[k]; + nodes[k].setReg( r ); + if( r->id!=k ) nodes[k].alias=&nodes[r->id]; + } + for( k=0;kreg; + assert( frame->regs[r->id]->id==r->id ); + } + } +} + +static void createGraph(){ + + CGAsm *as; + CGBlockCIter blk_it; + + //build interference edges + for( blk_it=flow->blocks.begin();blk_it!=flow->blocks.end();++blk_it ){ + CGBlock *blk=*blk_it; + + float use_cost=pow((double)10,(double)blk->loop_level); + + //Increase usage for regs that are live_in and live_out + CGIntCIter int_it; + for( int_it=blk->live_in.begin();int_it!=blk->live_in.end();++int_it ){ + if( blk->live_out.count(*int_it) ) nodes[*int_it].block_count+=1; + } + + CGIntSet live=blk->live_out; + + CGAsm *as=blk->end; + + while( as!=blk->begin ){ + as=as->pred; + + Node *copy_src=0; + if( CGMov *t=as->stm->mov() ){ + if( CGReg *lhs=t->lhs->reg() ){ + if( CGReg *rhs=t->rhs->reg() ){ + copy_src=&nodes[rhs->id]; + } + } + } + + CGIntCIter def_it; + for( def_it=as->def.begin();def_it!=as->def.end();++def_it ){ + Node *x=&nodes[*def_it]; + x->usage+=use_cost; + + CGIntCIter live_it; + for( live_it=live.begin();live_it!=live.end();++live_it ){ + Node *y=&nodes[*live_it]; + if( (x!=y) && (y!=copy_src) && (x->bank==y->bank) ){ + x->edges.insert( y ); + y->edges.insert( x ); + } + } + } + + CGIntCIter use_it; + for( use_it=as->use.begin();use_it!=as->use.end();++use_it ){ + Node *y=&nodes[*use_it]; + y->usage+=use_cost; + } + + live.erase( as->def ); + live.insert( as->use ); + } + } + + //build 'move' edges + for( as=flow->assem.begin;as!=flow->assem.end;as=as->succ ){ + if( CGMov *t=as->stm->mov() ){ + if( CGReg *lhs=t->lhs->reg() ){ + if( CGReg *rhs=t->rhs->reg() ){ + Node *x=&nodes[lhs->id]; + Node *y=&nodes[rhs->id]; + if( x!=y && !x->edges.count(y) ){ + x->moves.insert(y); + y->moves.insert(x); + } + } + } + } + } + + //initial node degrees + int k; + for( k=0;kdegree=node->colored() ? 0x7fffffff : node->edges.size(); + } + +#ifdef _DEBUG_REGALLOC + cout<reg->id<<' '; + cout<<"(usage="<usage; + cout<<" moves="<moves.size(); + cout<<" degree="<degree; + if( node->degree ) cout<<" spill="<<(float)node->usage/(float)node->degree; + cout<<"):"; + NodeIter it; + for( it=node->edges.begin();it!=node->edges.end();++it ){ + cout<<' '<<(*it)->reg->id; + } + cout<clear(); + _coalesce->clear(); + _freeze->clear(); + _spill->clear(); + + _selected->clear(); + _coalesced->clear(); + _spilled->clear(); + _colored->clear(); + + for( int k=0;kalias ) node->insert( _coalesced ); + else if( node->moveRelated() ) node->insert( _coalesce ); + else freezeNode( node ); + } +} + +//decrement degree of a node. +static void decDegree( Node *node ){ + //dec degree + if( --node->degree!=node->colors()-1 ) return; + + //OK node transitioned from sig to insig... + + //move frozen neighbors to coalesce + NodeIter it; + for( it=node->edges.begin();it!=node->edges.end();++it ){ + Node *t=(*it); + if( t->_list==_freeze ) t->insert( _coalesce ); + } + + //simplify if in spill + if( node->_list==_spill ) node->insert( _simplify ); +} + +//node has become non-move related +//(node in coalesce or frozen) +static void freezeNode( Node *node ){ + assert( !node->moveRelated() ); + if( node->colored() ) node->insert( _colored ); + else if( node->sigDegree() ) node->insert( _spill ); + else node->insert( _simplify ); +} + +//move node to select stack +//decrement degree of neighboring nodes +//(node is insig degree ) +static void selectNode( Node *node ){ + assert( node->_list==_simplify || node->_list==_spill ); + node->degree=0; + node->insert( _selected ); + NodeIter it; + for( it=node->edges.begin();it!=node->edges.end();++it ){ + Node *t=(*it); + decDegree( t ); + } +} + +//combine nodes a,b to node a +//(a in coalesce, b in coalesce or frozen) +static void combine( Node *a,Node *b ){ + assert( a->_list==_coalesce && (b->_list==_coalesce||b->_list==_freeze) ); + + a->cant_spill=true; + + b->alias=a; + b->insert( _coalesced ); + + NodeIter it; + + //fix moves + for( it=b->moves.begin();it!=b->moves.end();++it ){ + Node *t=*it; + + t->moves.erase(b); + if( t==a ) continue; + + if( !a->edges.count(t) ){ + t->moves.insert(a); + a->moves.insert(t); + }else if( !t->moveRelated() ){ + freezeNode(t); + } + } + + //fix edges + for( it=b->edges.begin();it!=b->edges.end();++it ){ + Node *t=(*it); + + t->edges.erase(b); + + if( a->edges.count(t) ){ + decDegree(t); + continue; + } + + t->edges.insert(a); + a->edges.insert(t); + if( t->_list==_selected ) continue; + + if( !a->colored() ) ++a->degree; + if( !t->moves.count(a) ) continue; + + t->moves.erase(a); + a->moves.erase(t); + if( !t->moveRelated() ) freezeNode(t); + } + + a->usage+=b->usage; + if( !a->moveRelated() ) freezeNode( a ); +} + +//Briggs: +//can we coalesce these 2 nodes? +//(a in coalesce, b in coalesce or frozen) +static bool canCoalesce( Node *a,Node *b ){ + assert( a->_list==_coalesce && (b->_list==_coalesce||b->_list==_freeze||b->_list==_colored) ); + + if( b->colored() ) return false; + + NodeIter it; + + bool briggs; + + //Briggs... + int n=0; + for( it=a->edges.begin();it!=a->edges.end();++it ){ + Node *t=(*it); + if( t->sigDegree() ) ++n; + } + for( it=b->edges.begin();it!=b->edges.end();++it ){ + Node *t=(*it); + if( t->sigDegree() && !t->edges.count(a) ) ++n; + } + briggs=ncolors(); + + return briggs; +} + +static void simplify(){ + + Node *node=_simplify->succ; + +#ifdef _DEBUG_REGALLOC + cout<<"Simplifying:\t"<reg->id<succ; + + NodeIter it; + for( it=node->moves.begin();it!=node->moves.end();++it ){ + Node *t=*it; + + if( !canCoalesce(node,t) ) continue; + +#ifdef _DEBUG_REGALLOC + cout<<"Coalescing:\t"<reg->id<<"->"<reg->id<colored() ) node->insert( _colored ); + else node->insert( _freeze ); +} + +//freeze heuristic: +//pick non-sig degree node with lowest move count +// +static void freeze(){ + + int min=0x7fffffff; + Node *node=0; + for( Node *t=_freeze->succ;t!=_freeze;t=t->succ ){ + if( t->degreedegree; + } + } + +#ifdef _DEBUG_REGALLOC + cout<<"Freezing:\t"<reg->id<moves.begin();it!=node->moves.end();++it ){ + Node *t=*it; + t->moves.erase(node); + if( !t->moveRelated() ) freezeNode( t ); + } + + node->moves.clear(); + freezeNode( node ); +} + +static void spill(){ + + Node *node=0; + float min=FLT_MAX; + for( int pass=0;pass<2;++pass ){ + for( Node *t=_spill->succ;t!=_spill;t=t->succ ){ + + if( t->cant_spill ) cout<<"Shouldn't spill:"<reg->id<reg->id>=max_spill_id ) continue; + + //No idea...! +// if( !pass && t->reg->owner ) continue; + +// float cost=(float)t->usage/(float)t->degree; + + //***** Munged cost *****// + float cost=(float)t->usage/((float)t->degree*(float)t->block_count); + + if( costreg->id<empty() ){ + + Node *node=_selected->pred; + + //find color; + NodeIter it; + + unsigned avail=frame->reg_masks[node->bank]; + + for( it=node->edges.begin();it!=node->edges.end();++it ){ + Node *t=(*it); + if( t->color>=0 ) avail&=~(1<color); + } + + if( avail ){ + int color=0; + for( ;!(avail&1);avail>>=1 ) ++color; + node->color=color; + node->insert( _colored ); +#ifdef _DEBUG_REGALLOC + cout<<"Colored:\t"<reg->id<<"->"<insert( _spilled ); +#ifdef _DEBUG_REGALLOC + cout<<"Spilled:\t"<reg->id<empty() ){ + int k; + for( k=0;kunAlias(); + assert( y->color>=0 ); + x->reg->color=y->color; + } + return true; + } + +// max_spill_id=nodes.size(); + + for( Node *node=_spilled->succ;node!=_spilled;node=node->succ ){ + frame->spillReg( node->reg,0 ); + ++n_spills; + } + + flow->liveness(); + return false; +} + +static int countBits( unsigned n ){ + int c=0; + for( ;n;n>>=1 ) c+=(n&1); + return c; +} + +static bool allocRegs(){ + + createNodes(); + createGraph(); + createLists(); + + if( !max_spill_id ) max_spill_id=nodes.size(); + + for(;;){ + if( !_simplify->empty() ){ + simplify(); + }else if( !_coalesce->empty() ){ + coalesce(); + }else if( !_freeze->empty() ){ + freeze(); + }else if( !_spill->empty() ){ + spill(); + }else{ + break; + } + } + + return selectRegs(); +} + +void cgAllocRegs( CGFrame *t_frame ){ + + frame=t_frame; + flow=frame->flow; + + for( int k=0;k<4;++k ){ + reg_colors[k]=countBits( frame->reg_masks[k] ); + } + + nodes.clear(); + max_spill_id=0;//0x7fffffff; + + n_passes=0; + n_spills=0; + + for(;;){ + if( ++n_passes==100 ){ + cout<<"INTERNAL ERROR! Register allocator terminally confused!"<fun->sym->value<<" passes="<reg(); + while( r ){ + as->use.insert(r->id); + r=r->owner; + } + return e; + } +}; + +CGAsm::CGAsm( CGStm *t,const char *s ):succ(0),pred(0),stm(t),assem(strdup(s)){ + assert(stm); + assert(assem); + genUseDef(); +} + +void CGAsm::genUseDef(){ + + use.clear(); + def.clear(); + UseFinder uf(this); + + if( CGXop *t=stm->xop() ){ + if( CGReg *r=t->def ){ + def.insert( r->id ); + } + if( t->exp ) t->exp->visit( uf ); + return; + } + + if( CGMov *t=stm->mov() ){ + if( CGReg *r=t->lhs->reg() ){ + def.insert( r->id ); + t->rhs->visit( uf ); + return; + } + } + + stm->visit( uf ); +} + +CGAsmSeq::CGAsmSeq():begin(0),end(0){ + clear(); +} + +void CGAsmSeq::clear(){ + begin=end=new CGAsm(CG::nop(),""); +} + +CGAsm *CGAsmSeq::erase( CGAsm *as ){ + CGAsm *succ=as->succ; + if( as->pred ) as->pred->succ=succ; + else begin=succ; + succ->pred=as->pred; + return succ; +} + +CGAsm *CGAsmSeq::insert( CGAsm *as,CGAsm *succ ){ + as->succ=succ; + if( as->pred=succ->pred ) as->pred->succ=as; + else begin=as; + succ->pred=as; + return as; +} diff --git a/_src/codegen/cgasm.h b/_src/codegen/cgasm.h new file mode 100644 index 0000000..455a425 --- /dev/null +++ b/_src/codegen/cgasm.h @@ -0,0 +1,31 @@ + +#ifndef CGASM_H +#define CGASM_H + +#include "cgcode.h" +#include "cgintset.h" + +struct CGAsm{ + CGAsm *succ,*pred; + + CGStm *stm; + char *assem; + CGIntSet use,def; + + CGAsm( CGStm *t,const char *s ); + + void genUseDef(); +}; + +struct CGAsmSeq{ + CGAsm *begin,*end; + + CGAsmSeq(); + + void clear(); + + CGAsm* erase( CGAsm *as ); + CGAsm* insert( CGAsm *as,CGAsm *succ ); +}; + +#endif \ No newline at end of file diff --git a/_src/codegen/cgblock.cpp b/_src/codegen/cgblock.cpp new file mode 100644 index 0000000..f92bf46 --- /dev/null +++ b/_src/codegen/cgblock.cpp @@ -0,0 +1,24 @@ + +#include "cgstd.h" + +#include "cgblock.h" + +void CGBlock::removeSucc( CGBlock *blk ){ + CGBlockIter it; + for( it=succ.begin();it!=succ.end();++it ){ + if( *it==blk ){ + succ.erase(it); + return; + } + } +} + +void CGBlock::removePred( CGBlock *blk ){ + CGBlockIter it; + for( it=pred.begin();it!=pred.end();++it ){ + if( *it==blk ){ + pred.erase(it); + return; + } + } +} diff --git a/_src/codegen/cgblock.h b/_src/codegen/cgblock.h new file mode 100644 index 0000000..38357d0 --- /dev/null +++ b/_src/codegen/cgblock.h @@ -0,0 +1,26 @@ + +#ifndef CGBLOCK_H +#define CGBLOCK_H + +#include "cgasm.h" + +struct CGBlock; + +typedef std::vector CGBlockSeq; +typedef CGBlockSeq::iterator CGBlockIter; +typedef CGBlockSeq::const_iterator CGBlockCIter; + +struct CGBlock{ + CGAsm *begin,*end; + CGBlockSeq succ,pred; + CGIntSet use,def,live_in,live_out; + std::set dom,loops; + int loop_level; + + CGBlock():begin(0),end(0),loop_level(0){} + + void removeSucc( CGBlock *blk ); + void removePred( CGBlock *blk ); +}; + +#endif \ No newline at end of file diff --git a/_src/codegen/cgcode.cpp b/_src/codegen/cgcode.cpp new file mode 100644 index 0000000..bcd377f --- /dev/null +++ b/_src/codegen/cgcode.cpp @@ -0,0 +1,525 @@ + +#include "cgstd.h" + +#include "cgcode.h" +#include "cgutil.h" + +CGStm *CGVisitor::visit( CGStm *t ){ + return t; +} + +CGExp *CGVisitor::visit( CGExp *e ){ + return e; +} + +CGNop *CGStm::nop(){ return 0; } +CGXop *CGStm::xop(){ return 0; } +CGRem *CGStm::rem(){ return 0; } +CGAti *CGStm::ati(){ return 0; } +CGAtd *CGStm::atd(){ return 0; } +CGMov *CGStm::mov(){ return 0; } +CGLab *CGStm::lab(){ return 0; } +CGBra *CGStm::bra(){ return 0; } +CGBcc *CGStm::bcc(){ return 0; } +CGEva *CGStm::eva(){ return 0; } +CGRet *CGStm::ret(){ return 0; } +CGSeq *CGStm::seq(){ return 0; } + +CGMem *CGExp::mem(){ return 0; } +CGLea *CGExp::lea(){ return 0; } +CGCvt *CGExp::cvt(){ return 0; } +CGUop *CGExp::uop(){ return 0; } +CGBop *CGExp::bop(){ return 0; } +CGJsr *CGExp::jsr(){ return 0; } +CGVfn *CGExp::vfn(){ return 0; } +CGScc *CGExp::scc(){ return 0; } +CGEsq *CGExp::esq(){ return 0; } +CGFrm *CGExp::frm(){ return 0; } +CGTmp *CGExp::tmp(){ return 0; } +CGLit *CGExp::lit(){ return 0; } +CGSym *CGExp::sym(){ return 0; } +CGDat *CGExp::dat(){ return 0; } +CGReg *CGExp::reg(){ return 0; } + +CGStm::~CGStm(){ +} + +CGStm *CGStm::visit( CGVisitor &vis ){ + assert(0); + return 0; +} + +CGExp *CGExp::nonEsq(){ + return this; +} + +CGExp *CGExp::visit( CGVisitor &vis ){ + assert(0); + return 0; +} + +CGExp::~CGExp(){ +} + +bool CGExp::sideEffects(){ + return false; +} + +bool CGExp::equals( CGExp *exp ){ + return false; +} + +//***** CGNop ***** +CGNop *CGNop::nop(){ + return this; +} + +CGStm *CGNop::visit( CGVisitor &vis ){ + return vis.visit( this ); +} + +//***** CGXop ***** +CGXop *CGXop::xop(){ + return this; +} + +CGStm *CGXop::visit( CGVisitor &vis ){ + CGReg *r=def ? vis.visit(def)->reg() : 0; + CGExp *e=exp ? exp->visit(vis) : 0; + return vis.visit( r==def && e==exp ? this : CG::xop(op,r,e) ); +} + +//***** CGRem ***** +CGRem *CGRem::rem(){ + return this; +} + +CGStm *CGRem::visit( CGVisitor &vis ){ + return vis.visit( this ); +} + +//***** CGAti ***** +CGAti *CGAti::ati(){ + return this; +} + +CGStm *CGAti::visit( CGVisitor &vis ){ + CGMem *e=mem->visit(vis)->mem(); + return vis.visit( e==mem ? this : CG::ati(e) ); +} + +//***** CGAtd ***** +CGAtd *CGAtd::atd(){ + return this; +} + +CGStm *CGAtd::visit( CGVisitor &vis ){ + CGMem *a=mem->visit(vis)->mem(); + CGSym *b=sym->visit(vis)->sym(); + return vis.visit( a==mem && b==sym ? this : CG::atd(a,b) ); +} + +//***** CGMov ***** +CGMov *CGMov::mov(){ + return this; +} + +CGStm *CGMov::visit( CGVisitor &vis ){ + CGExp *b=rhs->visit(vis); + CGExp *a=lhs->visit(vis); + return vis.visit( a==lhs && b==rhs ? this : CG::mov(a,b) ); +} + +//***** CGLab ***** +CGLab *CGLab::lab(){ + return this; +} + +CGStm *CGLab::visit( CGVisitor &vis ){ + CGSym *e=vis.visit(sym)->sym(); + return vis.visit( e==sym ? this : CG::lab(e) ); +} + +//***** CGBra ***** +CGBra *CGBra::bra(){ + return this; +} + +CGStm *CGBra::visit( CGVisitor &vis ){ + CGSym *e=vis.visit(sym)->sym(); + return vis.visit( e==sym ? this : CG::bra(e) ); +} + +//***** CGBcc ***** +CGBcc *CGBcc::bcc(){ + return this; +} + +CGStm *CGBcc::visit( CGVisitor &vis ){ + CGExp *a=lhs->visit(vis); + CGExp *b=rhs->visit(vis); + CGSym *c=vis.visit(sym)->sym(); + return vis.visit( a==lhs && b==rhs && c==sym ? this : CG::bcc(cc,a,b,c) ); +} + +//***** CGEva ***** +CGEva *CGEva::eva(){ + return this; +} + +CGStm *CGEva::visit( CGVisitor &vis ){ + CGExp *e=exp->visit(vis); + return vis.visit( e==exp ? this : CG::eva(e) ); +} + +//***** CGRet ***** +CGRet *CGRet::ret(){ + return this; +} + +CGStm *CGRet::visit( CGVisitor &vis ){ + CGExp *e=exp ? exp->visit(vis) : 0; + return vis.visit( e==exp ? this : CG::ret(e) ); +} + +//***** CGSeq ***** +CGSeq *CGSeq::seq(){ + return this; +} + +CGStm *CGSeq::visit( CGVisitor &vis ){ + bool dup=false; + vector t_stms; + int i; + for( i=0;ivisit(vis); + if( t!=stms[i] ) dup=true; + t_stms.push_back( t ); + } + return vis.visit( dup ? CG::seq( t_stms ) : this ); +} + +void CGSeq::push_back( CGStm *stm ){ + stms.push_back( stm ); +} + +void CGSeq::push_front( CGStm *stm ){ + stms.insert( stms.begin(),stm ); +} + +//***** CGMem ***** +CGMem *CGMem::mem(){ + return this; +} + +bool CGMem::sideEffects(){ + return exp->sideEffects(); +} + +bool CGMem::equals( CGExp *e ){ + CGMem *t=e->mem(); + if( !t || type!=t->type || offset!=t->offset || flags!=t->flags ) return false; + return exp->equals(t->exp); +} + +CGExp *CGMem::visit( CGVisitor &vis ){ + CGExp *e=exp->visit(vis); + return vis.visit( e==exp ? this : CG::mem(type,e,offset) ); +} + +//***** CGLea ***** +CGLea *CGLea::lea(){ + return this; +} + +bool CGLea::sideEffects(){ + return exp->sideEffects(); +} + +bool CGLea::equals( CGExp *e ){ + CGLea *t=e->lea(); + if( !t || type!=t->type ) return false; + return exp->equals(t->exp); +} + +CGExp *CGLea::visit( CGVisitor &vis ){ + CGExp *e=exp->visit(vis); + return vis.visit( e==exp ? this : CG::lea(e) ); +} + +//***** CGCvt ***** +CGCvt *CGCvt::cvt(){ + return this; +} + +bool CGCvt::sideEffects(){ + return exp->sideEffects(); +} + +bool CGCvt::equals( CGExp *e ){ + CGCvt *t=e->cvt(); + if( !t || type!=t->type ) return false; + return exp->equals(t->exp); +} + +CGExp *CGCvt::visit( CGVisitor &vis ){ + CGExp *e=exp->visit(vis); + return vis.visit( e==exp ? this : CG::cvt(type,e) ); +} + +//***** CGUop ***** +CGUop *CGUop::uop(){ + return this; +} + +bool CGUop::sideEffects(){ + return exp->sideEffects(); +} + +bool CGUop::equals( CGExp *e ){ + CGUop *t=e->uop(); + return t && type==t->type && exp->equals(t->exp); +} + +CGExp *CGUop::visit( CGVisitor &vis ){ + CGExp *e=exp->visit(vis); + return vis.visit( e==exp ? this : CG::uop(op,e) ); +} + +//***** CGBop ***** +CGBop *CGBop::bop(){ + return this; +} + +bool CGBop::commutes(){ + switch(op){ + case CG_ADD:case CG_MUL:case CG_AND:case CG_ORL:case CG_XOR: + return true; + } + return false; +} + +bool CGBop::sideEffects(){ + return lhs->sideEffects() || rhs->sideEffects(); +} + +bool CGBop::equals( CGExp *e ){ + CGBop *t=e->bop(); + if( !t || type!=t->type || op!=t->op ) return false; + if( lhs->equals(t->lhs) && rhs->equals(t->rhs) ) return true; + switch(op){ + case CG_ADD:case CG_MUL:break; + default:return false; + } + return lhs->equals(t->rhs) && rhs->equals(t->lhs); +} + +CGExp *CGBop::visit( CGVisitor &vis ){ + CGExp *a=lhs->visit(vis); + CGExp *b=rhs->visit(vis); + return vis.visit( a==lhs && b==rhs ? this : CG::bop(op,a,b) ); +} + +//***** CGJsr ***** +CGJsr *CGJsr::jsr(){ + return this; +} + +bool CGJsr::sideEffects(){ + return true; +} + +bool CGJsr::equals( CGExp *e ){ + CGJsr *t=e->jsr(); + if( !t || type!=t->type || args.size()!=t->args.size() ) return false; + if( exp->equals(t->exp) ) return false; + for( int k=0;kequals(t->args[k]) ) return false; + } + return true; +} + +CGExp *CGJsr::visit( CGVisitor &vis ){ + CGExp *t_exp=exp->visit(vis); + bool copy=t_exp!=exp; + vector t_args; + t_args.resize(args.size()); + for( int k=0;kvisit(vis); + if( t_args[k]!=args[k] ) copy=true; + } + if( !copy ) return vis.visit( this ); + CGJsr *t=CG::jsr(type,call_conv,t_exp,t_args ); + return vis.visit( t ); +} + +//***** CGVfn ***** +CGVfn *CGVfn::vfn(){ + return this; +} + +bool CGVfn::sideEffects(){ + return exp->sideEffects() || self->sideEffects(); +} + +bool CGVfn::equals( CGExp *e ){ + CGVfn *t=e->vfn(); + if( !t || type!=t->type ) return false; + return exp->equals(t->exp) && self->equals(t->self); +} + +CGExp *CGVfn::visit( CGVisitor &vis ){ + CGExp *a=exp->visit(vis); + CGExp *b=self->visit(vis); + return vis.visit( a==exp && b==self ? this : CG::vfn(a,b) ); +} + +//***** CGScc ***** +CGScc *CGScc::scc(){ + return this; +} + +bool CGScc::sideEffects(){ + return lhs->sideEffects() || rhs->sideEffects(); +} + +bool CGScc::equals( CGExp *e ){ + CGScc *t=e->scc(); + if( !t || type!=t->type || cc!=t->cc ) return false; + return lhs->equals(t->lhs) && rhs->equals(t->rhs); +} + +CGExp *CGScc::visit( CGVisitor &vis ){ + CGExp *a=lhs->visit(vis); + CGExp *b=rhs->visit(vis); + return vis.visit( a==lhs && b==rhs ? this : CG::scc(cc,a,b) ); +} + +//***** CGEsq ***** +CGEsq *CGEsq::esq(){ + return this; +} + +CGExp *CGEsq::nonEsq(){ + return rhs->nonEsq(); +} + +bool CGEsq::sideEffects(){ + return true; +} + +bool CGEsq::equals( CGExp *e ){ + CGEsq *t=e->esq(); + if( !t || type!=t->type ) return false; + return rhs->equals(t->rhs); +} + +CGExp *CGEsq::visit( CGVisitor &vis ){ + CGStm *a=lhs->visit(vis); + CGExp *b=rhs->visit(vis); + return vis.visit( a==lhs && b==rhs ? this : CG::esq(a,b) ); +} + +//***** CGFrm ***** +CGFrm *CGFrm::frm(){ + return this; +} + +bool CGFrm::equals( CGExp *e ){ + return e->frm() ? true : false; +} + +CGExp *CGFrm::visit( CGVisitor &vis ){ + return vis.visit(this); +} + +//***** CGTmp ***** +CGTmp *CGTmp::tmp(){ + return this; +} + +bool CGTmp::equals( CGExp *e ){ + CGTmp *t=e->tmp(); + if( !t || type!=t->type ) return false; + return ident==t->ident; +} + +CGExp *CGTmp::visit( CGVisitor &vis ){ + return vis.visit(this); +} + +//***** CGReg ***** +CGReg *CGReg::reg(){ + return this; +} + +bool CGReg::equals( CGExp *e ){ + CGReg *t=e->reg(); + return t ? id==t->id : false; +} + +CGExp *CGReg::visit( CGVisitor &vis ){ + return vis.visit(this); +} + +//***** CGLit ***** +CGLit *CGLit::lit(){ + return this; +} + +bool CGLit::equals( CGExp *e ){ + CGLit *t=e->lit(); + if( !t || type!=t->type ) return false; + if( isfloat() ) return float_value==t->float_value; + return int_value==t->int_value; +} + +CGExp *CGLit::visit( CGVisitor &vis ){ + return vis.visit(this); +} + +//***** CGSym ***** +CGSym *CGSym::sym(){ + return this; +} + +bool CGSym::equals( CGExp *e ){ + CGSym *t=e->sym(); + return t && value==t->value && linkage==t->linkage; +} + +CGExp *CGSym::visit( CGVisitor &vis ){ + return vis.visit(this); +} + +//***** CGDat ***** +CGDat *CGDat::dat(){ + return this; +} + +bool CGDat::equals( CGExp *e ){ + CGDat *t=e->dat(); + if( !t || value!=t->value || linkage!=t->linkage || exps.size()!=t->exps.size() ) return false; + for( int k=0;kexps.size();++k ){ + if( !exps[k]->equals(t->exps[k]) ) return false; + } + return true; +} + +CGExp *CGDat::visit( CGVisitor &vis ){ + bool copy=false; + vector t_exps; + t_exps.resize( exps.size() ); + for( int k=0;kvisit(vis); + if( t_exps[k]!=exps[k] ) copy=true; + } + if( !copy ) return vis.visit(this); + CGDat *t=new CGDat; + t->type=type;t->value=value;t->linkage=linkage;t->exps=t_exps; + return vis.visit( t ); +} + +void CGDat::push_back( CGExp *exp ){ + exps.push_back(exp); +} diff --git a/_src/codegen/cgcode.h b/_src/codegen/cgcode.h new file mode 100644 index 0000000..3dcded0 --- /dev/null +++ b/_src/codegen/cgcode.h @@ -0,0 +1,408 @@ + +#ifndef CGCODE_H +#define CGCODE_H + +//calling conventions +enum{ + CG_CDECL=1, + CG_STDCALL=2 +}; + +//data types +enum{ + CG_VOID=-1, + CG_PTR, + CG_INT8,CG_INT16, + CG_INT32,CG_INT64, + CG_FLOAT32,CG_FLOAT64, + CG_CSTRING,CG_BSTRING,CG_BINFILE,CG_LABEL +}; + +//condition codes +enum{ + CG_EQ,CG_NE, + CG_LT,CG_GT,CG_LE,CG_GE, + CG_LTU,CG_GTU,CG_LEU,CG_GEU +}; + +//unary operators for cguop +enum{ + CG_NEG,CG_NOT,CG_ABS,CG_SGN +}; + +//binary operators for cgbop +enum{ + CG_ADD,CG_SUB,CG_MUL,CG_DIV,CG_MOD, + CG_AND,CG_ORL,CG_XOR,CG_SHL,CG_SHR,CG_SAR, + CG_MIN,CG_MAX +}; + +//linkage flags +enum{ + CG_INTERNAL,CG_IMPORT,CG_EXPORT +}; + +//statements +struct CGStm; +struct CGNop; +struct CGXop; +struct CGRem; +struct CGAti; +struct CGAtd; +struct CGMov; +struct CGLab; +struct CGBra; +struct CGBcc; +struct CGEva; +struct CGRet; +struct CGSeq; + +//expressions +struct CGExp; +struct CGMem; +struct CGLea; +struct CGCvt; +struct CGUop; +struct CGBop; +struct CGJsr; +struct CGVfn; +struct CGScc; +struct CGEsq; +//leaf expressions +struct CGFrm; +struct CGTmp; +struct CGLit; +struct CGSym; +struct CGDat; +//private! +struct CGReg; + +struct CGVisitor{ + virtual CGStm *visit( CGStm *stm ); + virtual CGExp *visit( CGExp *exp ); +}; + +struct CGStm{ + virtual ~CGStm()=0; + + virtual CGNop *nop(); + virtual CGXop *xop(); + virtual CGRem *rem(); + virtual CGAti *ati(); + virtual CGAtd *atd(); + virtual CGMov *mov(); + virtual CGLab *lab(); + virtual CGBra *bra(); + virtual CGBcc *bcc(); + virtual CGEva *eva(); + virtual CGRet *ret(); + virtual CGSeq *seq(); + + virtual CGStm *visit( CGVisitor &vis ); +}; + +typedef std::vector CGStmSeq; + +struct CGExp{ + int type; + + virtual ~CGExp()=0; + + virtual CGMem *mem(); + virtual CGLea *lea(); + virtual CGCvt *cvt(); + virtual CGUop *uop(); + virtual CGBop *bop(); + virtual CGJsr *jsr(); + virtual CGVfn *vfn(); + virtual CGScc *scc(); + virtual CGEsq *esq(); + virtual CGFrm *frm(); + virtual CGTmp *tmp(); + virtual CGLit *lit(); + virtual CGSym *sym(); + virtual CGDat *dat(); + virtual CGReg *reg(); + + virtual CGExp *nonEsq(); + + virtual bool sideEffects(); + virtual bool equals( CGExp *exp ); + virtual CGExp *visit( CGVisitor &vis ); + + bool isint(){ return !isfloat(); } + bool isfloat(){ return type==CG_FLOAT32||type==CG_FLOAT64; } +}; + +struct CGNop : public CGStm{ + + CGNop *nop(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGXop : public CGStm{ + int op; + CGReg *def; + CGExp *exp; + + CGXop *xop(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGRem : public CGStm{ + string comment; + + CGRem *rem(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGAti : public CGStm{ + CGMem *mem; + + CGAti *ati(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGAtd : public CGStm{ + CGMem *mem; + CGSym *sym; + + CGAtd *atd(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGMov : public CGStm{ + CGExp *lhs,*rhs; + + CGMov *mov(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGLab : public CGStm{ + CGSym *sym; + + CGLab *lab(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGBra : public CGStm{ + CGSym *sym; + + CGBra *bra(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGBcc : public CGStm{ + int cc; + CGExp *lhs,*rhs; + CGSym *sym; + + CGBcc *bcc(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGEva : public CGStm{ + CGExp *exp; + + CGEva *eva(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGRet : public CGStm{ + CGExp *exp; + + CGRet *ret(); + + CGStm *visit( CGVisitor &vis ); +}; + +struct CGSeq : public CGStm{ + vector stms; + + CGSeq *seq(); + + CGStm *visit( CGVisitor &vis ); + + void push_back( CGStm *stm ); + void push_front( CGStm *stm ); +}; + +struct CGMem : public CGExp{ + CGExp *exp; + int offset,flags; + + CGMem *mem(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGLea : public CGExp{ + CGExp *exp; + + CGLea *lea(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGCvt : public CGExp{ + CGExp *exp; + + CGCvt *cvt(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGUop : public CGExp{ + int op; + CGExp *exp; + + CGUop *uop(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGBop : public CGExp{ + int op; + CGExp *lhs,*rhs; + + CGBop *bop(); + + bool commutes(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGJsr : public CGExp{ + int call_conv; + CGExp *exp; + std::vector args; + + CGJsr *jsr(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGVfn : public CGExp{ + CGExp *exp,*self; + + CGVfn *vfn(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGScc : public CGExp{ + int cc; + CGExp *lhs,*rhs; + + CGScc *scc(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGEsq : public CGExp{ + CGStm *lhs; + CGExp *rhs; + + CGEsq *esq(); + + CGExp *nonEsq(); + + bool sideEffects(); + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGFrm : public CGExp{ + CGFrm *frm(); + + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGTmp : public CGExp{ + string ident; + CGTmp *owner; + + CGTmp *tmp(); + + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGReg : public CGExp{ + int id,color; + CGReg *owner; + + CGReg *reg(); + + bool equals( CGExp *e ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGLit : public CGExp{ + int64 int_value; + double float_value; + bstring string_value; + + CGLit *lit(); + + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGSym : public CGExp{ + string value; + int linkage; + + CGSym *sym(); + + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); +}; + +struct CGDat : public CGSym{ + std::vector exps; + + CGDat *dat(); + + bool equals( CGExp *exp ); + CGExp *visit( CGVisitor &vis ); + + void push_back( CGExp *exp ); +}; + +struct CGFun : public CGExp{ + int call_conv; + CGSym *sym; + CGExp *self; + std::vector args; + std::vector stms; +}; + +#endif diff --git a/_src/codegen/cgdebug.cpp b/_src/codegen/cgdebug.cpp new file mode 100644 index 0000000..f430dcd --- /dev/null +++ b/_src/codegen/cgdebug.cpp @@ -0,0 +1,247 @@ + +#include "cgstd.h" + +#include "cgdebug.h" + +#include + +static const char *ccSym( int cc ){ + switch( cc ){ + case CG_EQ:return "EQ"; + case CG_NE:return "NE"; + case CG_LT:return "LT"; + case CG_GT:return "GT"; + case CG_LE:return "LE"; + case CG_GE:return "GE"; + case CG_LTU:return "LTU"; + case CG_GTU:return "GTU"; + case CG_LEU:return "LEU"; + case CG_GEU:return "GEU"; + } + assert(0); + return 0; +} + +static const char *uopSym( int op ){ + return "UOP"; +} + +static const char *bopSym( int op ){ + switch( op ){ + case CG_ADD:return "add"; + case CG_SUB:return "sub"; + case CG_MUL:return "mul"; + case CG_DIV:return "div"; + case CG_MOD:return "mod"; + case CG_AND:return "and"; + case CG_ORL:return "orl"; + case CG_XOR:return "xor"; + case CG_SHL:return "shl"; + case CG_SHR:return "shr"; + case CG_SAR:return "sar"; + } + assert(0); + return 0; +} + +static const char *typeSym( int ty ){ + switch( ty ){ + case CG_PTR:return "PTR"; + case CG_VOID:return "VOID"; + case CG_INT8:return "INT8"; + case CG_INT16:return "INT16"; + case CG_INT32:return "INT32"; + case CG_INT64:return "INT64"; + case CG_FLOAT32:return "FLOAT32"; + case CG_FLOAT64:return "FLOAT64"; + case CG_CSTRING:return "CSTRING"; + case CG_BSTRING:return "BSTRING"; + } + assert(0); + return 0; +} + +ostream &operator<<( ostream &o,CGStm *stm ){ + + if( !stm ) return o; + + if( CGNop *t=stm->nop() ){ + o<<"nop"; + }else if( CGMov *t=stm->mov() ){ + o<<"mov "<lhs<<','<rhs; + }else if( CGLab *t=stm->lab() ){ + o<<"lab "<sym; + }else if( CGBra *t=stm->bra() ){ + o<<"bra "<sym; + }else if( CGBcc *t=stm->bcc() ){ + o<<"bcc "<cc)<<','<lhs<<','<rhs<<","<sym; + }else if( CGRet *t=stm->ret() ){ + o<<"ret ";if( t->exp ) o<exp; + }else if( CGSeq *t=stm->seq() ){ + int i; + o<<"seq "; + for( i=0;istms.size();++i ){ + if( i ) o<<','; + o<stms[i]; + } + }else if( CGXop *t=stm->xop() ){ + o<<"xop "<op<<','<exp; + }else if( CGRem *t=stm->rem() ){ + o<<"rem "<comment; + }else if( CGEva *t=stm->eva() ){ + o<<"eva "<exp; + }else if( CGAti *t=stm->ati() ){ + o<<"ati "<mem; + }else if( CGAtd *t=stm->atd() ){ + o<<"atd "<mem<<","<sym; + }else{ + o<<"STM: "<type); + + if( CGMem *t=exp->mem() ){ + o<<"mem("<exp<<','<offset<<')'; + }else if( CGLea *t=exp->lea() ){ + o<<"lea("<exp<<')'; + }else if( CGCvt *t=exp->cvt() ){ + o<<"cvt("<exp<<')'; + }else if( CGUop *t=exp->uop() ){ + o<op)<<'('<exp<<')'; + }else if( CGBop *t=exp->bop() ){ + o<op)<<'('<lhs<<','<rhs<<')'; + }else if( CGJsr *t=exp->jsr() ){ + o<<"jsr("<exp; + for( int k=0;kargs.size();++k ) o<<','<args[k]; + o<<')'; + }else if( CGVfn *t=exp->vfn() ){ + o<<"vfn("<exp<<','<self<<')'; + }else if( CGScc *t=exp->scc() ){ + o<<"scc("<lhs<<','<rhs<<')'; + }else if( CGEsq *t=exp->esq() ){ + o<<"esq("<lhs<<','<rhs<<')'; + }else if( CGReg *t=exp->reg() ){ + o<<"reg("<id<<')'; + }else if( CGTmp *t=exp->tmp() ){ + o<<"tmp("<ident<<')'; + }else if( CGLit *t=exp->lit() ){ + if( t->isfloat() ) o<float_value; + else o<int_value); + }else if( CGSym *t=exp->sym() ){ + o<<"sym("<value<<")"; + }else if( CGFrm *t=exp->frm() ){ + o<<"frm"; + }else{ + assert(0); + } + return o; +} + +ostream &operator<<( ostream &o,const CGStmSeq &seq ){ + for( int k=0;ksucc ){ + if( as->stm ) o<<"\t;"<stm<assem ) o<assem; + } + return o; +} + +ostream &operator<<( ostream &o,const CGIntSet &t ){ + CGIntSet::const_iterator it; + for( it=t.begin();it!=t.end();++it ) o<<' '<<*it; + return o; +} + +ostream &operator<<( ostream &o,CGFlow *flow ){ + + CGBlockSeq &seq=flow->blocks; + + CGBlockCIter it; + + //enumerate blocks + map blk_map; + for( it=seq.begin();it!=seq.end();++it ){ + blk_map[*it]=blk_map.size(); + } + + for( it=seq.begin();it!=seq.end();++it ){ + CGBlock *blk=*it; + CGBlockCIter t_it; + o<<"\t;---block "<use<def<live_in<live_out<succ.begin();t_it!=blk->succ.end();++t_it ) o<<' '<pred.begin();t_it!=blk->pred.end();++t_it ) o<<' '<::iterator d_it; + + o<<"\t;dom:"; + for( d_it=blk->dom.begin();d_it!=blk->dom.end();++d_it ){ + o<<' '<loops.begin();d_it!=blk->loops.end();++d_it ){ + o<<' '<loop_level<begin; + while( as!=blk->end ){ + if( as->stm ) o<<"\t;"<stm<def.size() ) o<<"\t;def="<def<use.size() ) o<<"\t;use="<use<assem ) o<assem; + as=as->succ; + } + + o<stms.size();++k ){ + o<stms[k]< BlockSet; +typedef map StackMap; + +static BlockSet blocks_todo; +static StackMap stack_map; + +static void emit( const char *fmt,... ){ + va_list args; + va_start( args,fmt ); + vsprintf( out,fmt,args ); + out+=strlen(out); +} + +struct FPStack{ + + int regs[8],stack[8],sp; + + FPStack( int live ):sp(8){ + memset( regs,-1,sizeof(regs) ); + memset( stack,0,sizeof(stack) ); + for( int k=0;k<8;++k ){ + if( live & (1<sp){ + memcpy( regs,st->regs,sizeof(regs) ); + memcpy( stack,st->stack,sizeof(stack) ); + } + + int liveMask(){ + int n=0; + for( int k=sp;k<8;++k ) n|=1<sp ) return false; + for( int k=sp;k<8;++k ){ + if( stack[k]!=st->stack[k] ) return false; + } + return true; + } + + int top(){ + return stack[sp]; + } + + void pop(){ + int r=stack[sp]; + regs[r]=-1; + ++sp; + } + + void push( int r ){ + --sp; + regs[r]=sp; + stack[sp]=r; + } + + void swap( int rd,int rs ){ + assert(regs[rs]>=0 && regs[rd]>=0); + std::swap( stack[regs[rs]],stack[regs[rd]] ); + std::swap( regs[rs],regs[rd] ); + } + + int stoff( int r ){ + return regs[r]-sp; + } + + void fpop(){ + emit( "\tfstp\tst0\n" ); + pop(); + } + + void fxch( int r ){ + if( r==top() ) return; + emit( "\tfxch\tst%i\n",stoff(r) ); + swap( r,top() ); + } + + void fpop( int r ){ + if( regs[r]<0 ) return; + fxch(r); + fpop(); + } + + void debug(){ + for( int k=0;k<8;++k ){ + if( k=st->sp;--t_sp ){ + + int t=top(); + + for( ;st->regs[t]==-1;t=top() ) fpop(); + + int rs=stack[t_sp]; + int rd=st->stack[t_sp]; + + if( rs==rd ){ + + }else if( st->regs[rs]==-1 ){ + fxch( rd ); + emit( "\tfstp\tst%i\n",t_sp-sp ); + stack[regs[rd]=t_sp]=rd; + pop(); + }else{ + fxch( rd ); + fxch( rs ); + } + } + while( spsp ) fpop(); + } + + void fcopy( int rd,int rs,int live ){ + + if( rd==rs || !(live&(1<=0 ){ + fxch(rs); + emit( "\tfst\tst%i\n",stoff(rd) ); + }else{ + emit( "\tfld\tst%i\n",stoff(rs) ); + push(rd); + } + }else{ + if( regs[rd]>=0 ){ + fxch(rs); + emit( "\tfstp\tst%i\n",stoff(rd) ); + pop(); + }else{ + stack[regs[rs]]=rd; + regs[rd]=regs[rs]; + regs[rs]=-1; + } + } + } + + + void fload( int rd,double val,int live ){ + + if( !(live&(1<=0 ){ + emit( "\tfstp\tst%i\n",stoff(rd)+1 ); + }else{ + push(rd); + } + } + + void fload( int rd,const char *ea,const char *op,int live ){ + if( live&(1<=0 ){ + emit( "\tfstp\tst%i\n",stoff(rd)+1 ); + }else{ + push(rd); + } + }else{ + fpop(rd); + } + } + + void fstore( int rs,const char *ea,const char *op,int live ){ + fxch( rs ); + if( live&(1<regs[*it]; + if( r->isfloat() ){ + assert(r->color>=0); + live|=(1<color); + } + } + return live; +} + +static void adjustStack( FPStack *st,CGBlock *blk ){ + StackMap::iterator it=stack_map.find(blk); + + if( it!=stack_map.end() ){ + st->fadjust( it->second ); + return; + } + + st->fadjust( liveMask(blk->live_in) ); + stack_map.insert( make_pair(blk,new FPStack(st)) ); + blocks_todo.insert( blk ); +} + +static const char *op1( CGAsm *as ){ + static char buf[256]; + + const char *b=strchr( as->assem+1,'\t' ); + assert(b); + ++b; + + const char *e=strchr( as->assem,',' ); + if( !e ) e=b+strlen(b); + + int sz=e-b; + memcpy(buf,b,sz); + buf[sz]=0; + return buf; +} + +static const char *op2( CGAsm *as ){ + static char buf[256]; + + const char *b=strchr( as->assem,',' ); + assert(b); + ++b; + + const char *e=strchr( b,'\n' ); + assert(e); + + int sz=e-b; + memcpy(buf,b,sz); + buf[sz]=0; + return buf; +} + +static void allocTmp32(){ + if( tmpbuf32[0] ) return; + CGMem *m=frame->allocLocal(CG_INT32); + sprintf( tmpbuf8,"byte [ebp+%i]",m->offset ); + sprintf( tmpbuf16,"word [ebp+%i]",m->offset ); + sprintf( tmpbuf32,"dword [ebp+%i]",m->offset ); +} + +static bool fixXop( CGAsm *as,CGXop *op,FPStack *st,int live ){ + + CGExp *exp=op->exp; + + if( op->op==CGFrame_X86::XOP_PUSH4 ){ + //push dword + if( exp->isint() || exp->mem() ) return false; + int rs=exp->reg()->color; + emit( "\tsub\tesp,4\n" ); + st->fstore( rs,"dword [esp]","fst",live ); + return true; + } + if( op->op==CGFrame_X86::XOP_PUSH8 ){ + //push qword + if( exp->isint() ) return false; + assert( !exp->mem() ); + int rs=exp->reg()->color; + emit( "\tsub\tesp,8\n" ); + st->fstore( rs,"qword [esp]","fst",live ); + return true; + } + return false; +} + +static bool fixEva( CGAsm *as,CGEva *ev,FPStack *st,int live ){ + + CGExp *exp=ev->exp; + + if( CGJsr *t=exp->jsr() ){ + if( !exp->isfloat() ) return false; + if( !live ){ + emit(as->assem); + emit("\tfstp\tst0\n"); + return true; + }else if( live==1 ){ + if( st->regs[0]<0 ) st->push(0); + return false; + } + cout<<"Invalid FP stack state after FP jsr"<lhs; + CGExp *rhs=mv->rhs; + + if( CGCvt *t=rhs->cvt() ){ + if( lhs->isfloat() ){ + if( t->exp->isfloat() ){ + //float to float + st->fcopy( lhs->reg()->color,t->exp->reg()->color,live ); + return true; + } + //int to float + allocTmp32(); + int rd=lhs->reg()->color; + emit( "\tmov\t%s,%s\n",tmpbuf32,op2(as) ); + st->fload( rd,tmpbuf32,"fild",live ); + return true; + }else if( t->exp->isfloat() ){ + //float to int + allocTmp32(); + int rs=t->exp->reg()->color; + st->fstore( rs,tmpbuf32,"fist",live ); + if( lhs->type==CG_INT8 ){ + emit( "\tmovzx\t%s,%s\n",op1(as),tmpbuf8 ); + }else if( lhs->type==CG_INT16 ){ + emit( "\tmovzx\t%s,%s\n",op1(as),tmpbuf16 ); + }else{ + emit( "\tmov\t%s,%s\n",op1(as),tmpbuf32 ); + } + return true; + } + return false; + }else if( CGScc *t=rhs->scc() ){ + if( !t->lhs->isfloat() ) return false; + int rd=t->lhs->reg()->color; + int rs=t->rhs->reg()->color; + st->fcomp( rd,rs,live ); + const char *op; + switch( t->cc ){ + case CG_EQ:op="z";break; + case CG_NE:op="nz";break; + case CG_LT:op="b";break; + case CG_GT:op="a";break; + case CG_LE:op="be";break; + case CG_GE:op="ae";break; + } + emit( "\tset%s\tal\n",op ); + emit( "\tmovzx\teax,al\n" ); + return true; + } + + if( lhs->isint() && rhs->isint() ) return false; + assert( lhs->isfloat() && rhs->isfloat() ); + + if( lhs->reg() && rhs->reg() ){ + st->fcopy( lhs->reg()->color,rhs->reg()->color,live ); + return true; + } + if( CGJsr *t=rhs->jsr() ){ + if( !live ){ + emit(as->assem); + emit("\tfstp\tst0\n"); + return true; + }else if( live==1 ){ + if( st->regs[0]<0 ) st->push(0); + return false; + } + cout<<"Invalid FP stack state after FP jsr"<assem); + if( live&1 ){ + if( st->regs[0]<0 ) st->push(0); + }else if( st->regs[0]>=0 ){ + st->fpop(); + } + return true; + */ + } + if( CGMem *t=rhs->mem() ){ + int rd=lhs->reg()->color; + st->fload( rd,op2(as),"fld",live ); + return true; + } + if( CGMem *t=lhs->mem() ){ + int rs=rhs->reg()->color; + st->fstore( rs,op1(as),"fst",live ); + return true; + } + if( CGUop *t=rhs->uop() ){ + int rd=lhs->reg()->color; + const char *op; + switch( t->op ){ + case CG_NEG:op="fchs";break; + default:assert(0); + } + st->funiop( rd,op,live ); + return true; + } + if( CGBop *t=rhs->bop() ){ + int rd=lhs->reg()->color; + const char *op; + switch( t->op ){ + case CG_ADD:op="fadd";break; + case CG_SUB:op="fsub";break; + case CG_MUL:op="fmul";break; + case CG_DIV:op="fdiv";break; + default:assert(0); + } + if( CGReg *r=t->rhs->reg() ){ + st->fbinop( rd,r->color,op,live ); + }else{ + st->fbinop( rd,op2(as),op,live ); + } + return true; + } + if( CGLit *t=rhs->lit() ){ + int rd=lhs->reg()->color; + st->fload( rd,t->float_value,live ); + return true; + } + assert(0); + return false; +} + +static void fix( CGBlock *blk ){ + + if( blk->begin==blk->end ) return; + + vector live_stack; + int live=liveMask( blk->live_out ); + + CGAsm *as=blk->end; + while( as!=blk->begin ){ + as=as->pred; + + live_stack.push_back( live ); + + live&=~liveMask(as->def); + live|=liveMask(as->use); + } + + assert( stack_map.count(blk) ); + FPStack *st=new FPStack( stack_map[blk] ); + assert( st->liveMask()==live ); + + for( as=blk->begin;as!=blk->end;as=as->succ ){ + + live=live_stack.back(); + live_stack.pop_back(); + + *(out=buf)=0; + + bool fix=false; + + if( CGMov *t=as->stm->mov() ){ + fix=fixMov( as,t,st,live ); + }else if( CGXop *t=as->stm->xop() ){ + fix=fixXop( as,t,st,live ); + }else if( CGEva *t=as->stm->eva() ){ + fix=fixEva( as,t,st,live ); + } + + if( fix ) as->assem=strdup(buf); + } + + as=as->pred; + + buf_a[0]=0; + CGBlock *blk_a=blk->succ.size()>0 ? blk->succ[0] : 0; + if( blk_a ){ + out=buf_a; + adjustStack( new FPStack(st),blk_a ); + } + + buf_b[0]=0; + CGBlock *blk_b=blk->succ.size()>1 ? blk->succ[1] : 0; + if( blk_b ){ + assert( as->stm->bcc() ); + out=buf_b; + adjustStack( new FPStack(st),blk_b ); + } + + if( !buf_a[0] && !buf_b[0] ) return; + + *(out=buf)=0; + + assert( blk_a ); + + if( !blk_b ){ + + if( as->stm->bra() ){ + emit( buf_a ); + emit( as->assem ); + }else{ + emit( as->assem ); + emit( buf_a ); + } + + }else if( !buf_b[0] ){ + + emit( as->assem ); + emit( buf_a ); + + }else{ + + CGBcc *t=as->stm->bcc(); + + CGSym *skip=CG::sym(); + + const char *cc=CGFrame_X86::x86cc( CG::swapcc(t->cc) ); + + //find the jmp + char *p=strstr( as->assem,"\tj" );assert(p); + + //cmp... + memcpy( out,as->assem,p-as->assem );out+=p-as->assem; + + //new jmp + emit( "\tj%s\t%s\n",cc,skip->value.c_str() ); + + //normalize bra block + emit( buf_b ); + + //bra to block + emit( "\tjmp\t%s\n",t->sym->value.c_str() ); + + //our new symbol! + emit( "%s:\n",skip->value.c_str() ); + + emit( buf_a ); + } + + as->assem=strdup(buf); +} + +void CGFrame_X86::fixFp(){ + + if( !flow->blocks.size() ) return; + + ::frame=this; + + tmpbuf32[0]=0; + buf=new char[1024]; + buf_a=new char[1024]; + buf_b=new char[1024]; + + CGBlock *blk=*flow->blocks.begin(); + + stack_map.clear(); + stack_map.insert( make_pair(blk,new FPStack(0)) ); + + blocks_todo.clear(); + blocks_todo.insert( blk ); + + while( blocks_todo.size() ){ + BlockSet::iterator it=blocks_todo.begin(); + CGBlock *blk=*it; + blocks_todo.erase(it); + fix(blk); + } + + blocks_todo.clear(); + stack_map.clear(); + + delete[] buf_b; + delete[] buf_a; + delete[] buf; +} diff --git a/_src/codegen/cgfixfp_x86.h b/_src/codegen/cgfixfp_x86.h new file mode 100644 index 0000000..6de7a79 --- /dev/null +++ b/_src/codegen/cgfixfp_x86.h @@ -0,0 +1,6 @@ + +#ifndef CGFIXFP_X86_H +#define CGFIXFP_X86_H + +#endif + diff --git a/_src/codegen/cgflow.cpp b/_src/codegen/cgflow.cpp new file mode 100644 index 0000000..7c59b1e --- /dev/null +++ b/_src/codegen/cgflow.cpp @@ -0,0 +1,257 @@ + +#include "cgstd.h" + +#include "cgflow.h" +#include "cgutil.h" +#include "cgdebug.h" + +//#define _DEBUG_FLOW + +static set reachable; + +static void findReachable( CGBlock *blk ){ + if( !reachable.insert(blk).second ) return; + CGBlockIter it; + for( it=blk->succ.begin();it!=blk->succ.end();++it ){ + findReachable(*it); + } +} + +//******************* Build flow ****************** +CGBlock *CGFlow::block( CGAsm *as,CGBlock *p ){ + CGBlock *b=new CGBlock; + b->begin=b->end=as; + blocks.push_back(b); + if( !p ) return b; + p->succ.push_back(b); + b->pred.push_back(p); + return b; +} + +void CGFlow::buildFlow(){ + + CGAsm *as; + blocks.clear(); + map lab_map; + map bra_map; + +#ifdef _DEBUG_FLOW + cout<<"CGFlow::buildFlow()"<stm->lab() ){ + assem.insert( new CGAsm(CG::lab(),""),assem.begin ); + } + + //ensure there's a LAB after each BRA/BCC/RET + for( as=assem.begin;as!=assem.end;as=as->succ ){ + CGStm *st=as->stm; + if( !st->bra() && !st->bcc() && !st->ret() ) continue; + if( as->succ->stm->lab() ) continue; + as=assem.insert( new CGAsm(CG::lab(),""),as->succ ); + } + + as=assem.begin; + CGBlock *b=block(as,0); + while( as!=assem.end ){ + + CGStm *st=as->stm; + + if( CGLab *t=st->lab() ){ + if( as!=b->begin ){ + b->end=as; + b=block(as,b); + } + lab_map[t->sym]=b; + as=as->succ; + }else if( CGBra *t=st->bra() ){ + bra_map[b]=t->sym; + as=as->succ; + b->end=as; + b=block(as,0); + }else if( CGBcc *t=st->bcc() ){ + bra_map[b]=t->sym; + as=as->succ; + b->end=as; + b=block(as,b); + }else if( CGRet *t=st->ret() ){ + as=as->succ; + b->end=as; + b=block(as,0); + }else{ + as=as->succ; + } + } + b->end=as; + + //patch bras + map::iterator it; + for( it=bra_map.begin();it!=bra_map.end();++it ){ + CGBlock *src=it->first; + if( !lab_map.count(it->second) ) continue; + CGBlock *dst=lab_map[it->second]; + src->succ.push_back( dst ); + dst->pred.push_back( src ); + } + + //find reachable blocks + reachable.clear(); + findReachable( *blocks.begin() ); + + CGBlockIter blk_it=blocks.begin(); + for( ++blk_it;blk_it!=blocks.end(); ){ + + //reachable? + CGBlock *blk=*blk_it; + if( reachable.count(blk) ){ + ++blk_it; + continue; + } + + //erase assem + CGAsm *as=blk->begin; + while( as!=blk->end ) as=assem.erase(as); + (*(blk_it-1))->end=as; + + //erase block + blk_it=blocks.erase( blk_it ); + } +} + +//***************** Loop detection **************** + +static void eraseDom( CGBlock *blk,CGBlock *dom ){ + + if( blk==dom ) return; + + if( !blk->dom.insert(dom).second ) return; + + CGBlockIter it; + for( it=blk->succ.begin();it!=blk->succ.end();++it ){ + eraseDom( *it,dom ); + } +} + +static void insertLoop( CGBlock *blk,CGBlock *head ){ + + if( !head->loops.insert( blk ).second ) return; + + CGBlockIter it; + for( it=blk->pred.begin();it!=blk->pred.end();++it ){ + insertLoop( *it,head ); + } +} + +void CGFlow::findLoops(){ + +#ifdef _DEBUG_FLOW + cout<<"CGFlow::findLoops() - blocks="<succ.begin();it!=blk->succ.end();++it ){ + CGBlock *head=*it; + if( blk->dom.count(head) ) continue; + head->loops.insert( head ); + insertLoop( blk,head ); + } + } + +// cout<<"Creating loop_level"<::iterator it; + for( it=blk->loops.begin();it!=blk->loops.end();++it ){ + ++(*it)->loop_level; + } + } +} + +//*************** liveness analysis *************** +static void liveIn( CGBlock *blk,int n ){ + + if( !blk->live_in.insert( n ) ) return; + + CGBlockIter it; + for( it=blk->pred.begin();it!=blk->pred.end();++it ){ + CGBlock *t=*it; + + if( t->live_out.insert(n) && !t->def.count(n) ) liveIn( t,n ); + } +} + +void CGFlow::liveness(){ + +#ifdef _DEBUG_FLOW + cout<<"CGFlow::liveness()"<use.clear(); + blk->def.clear(); + blk->live_in.clear(); + blk->live_out.clear(); + + CGAsm *as; + + for( as=blk->begin;as!=blk->end;as=as->succ ){ + + blk->use.xinsert( as->use,blk->def ); + blk->def.xinsert( as->def,blk->use ); + } + } + + for( blk_it=blocks.begin();blk_it!=blocks.end();++blk_it ){ + CGBlock *blk=*blk_it; + + CGIntCIter it; + for( it=blk->use.begin();it!=blk->use.end();++it ){ + liveIn( blk,*it ); + } + } +} + +//***************** Constructor ******************* +static vector _flows; + +CGFlow::CGFlow( CGAsmSeq &t_assem ):assem(t_assem){ + buildFlow(); + findLoops(); + _flows.push_back( this ); +} + +CGFlow::~CGFlow(){ + for( int k=0;k IdExpMap; + +CGFrame::CGFrame( CGFun *_fun ):fun(_fun),flow(0),int64ret(0){ + asm_it=assem.end; + big_endian=!(little_endian=env_config.count("x86")?true:false); +} + +CGFrame::~CGFrame(){ + deleteFlow(); +} + +CGMem *CGFrame::int64el( CGMem *i64,int n ){ + CGMem *m=CG::mem(CG_INT32,i64->exp,i64->offset+n); + m->flags=i64->flags; + return m; +} + +CGMem *CGFrame::int64lo( CGMem *i64 ){ + return int64el( i64,big_endian ? 4 : 0 ); +} + +CGMem *CGFrame::int64hi( CGMem *i64 ){ + return int64el( i64,big_endian ? 0 : 4 ); +} + +//****************** Linearize ******************** +struct CGLinearizer : public CGVisitor{ + CGFrame *frame; + + CGLinearizer( CGFrame *f ):frame(f){} + + CGStm *visit( CGStm *stm ){ + if( stm->nop() || stm->seq() ) return stm; + frame->fun->stms.push_back(stm); + return stm; + } + + CGExp *visit( CGExp *exp ){ + + if( CGEsq *t=exp->esq() ) return t->rhs; + + if( exp->type==CG_INT64 ) return exp; + + if( CGCvt *t=exp->cvt() ){ + if( t->isint() && t->exp->isfloat() ){ + if( env_config.count("x86") ){ + exp=CG::cvt(t->type,CG::jsr(CG_INT32,"bbFloatToInt",CG::cvt(CG_FLOAT64,t->exp))); + } + } + }else if( CGUop *t=exp->uop() ){ + string iop,fop; + switch( t->op ){ + case CG_ABS:iop="bbIntAbs";fop="bbFloatAbs";break; + case CG_SGN:iop="bbIntSgn";fop="bbFloatSgn";break; + } + if( t->isint() && iop.size() ){ + exp=CG::cvt(t->type,CG::jsr(CG_INT32,iop,CG::cvt(CG_INT32,t->exp))); + }else if( t->isfloat() && fop.size() ){ + exp=CG::cvt(t->type,CG::jsr(CG_FLOAT64,fop,CG::cvt(CG_FLOAT64,t->exp))); + } + }else if( CGBop *t=exp->bop() ){ + string iop,fop; + switch( t->op ){ + case CG_MOD:fop="bbFloatMod";break; + case CG_MIN:iop="bbIntMin";fop="bbFloatMin";break; + case CG_MAX:iop="bbIntMax";fop="bbFloatMax";break; + } + if( t->isint() && iop.size() ){ + exp=CG::cvt(t->type,CG::jsr(CG_INT32,iop,CG::cvt(CG_INT32,t->lhs),CG::cvt(CG_INT32,t->rhs))); + }else if( t->isfloat() && fop.size() ){ + exp=CG::cvt(t->type,CG::jsr(CG_FLOAT64,fop,CG::cvt(CG_FLOAT64,t->lhs),CG::cvt(CG_FLOAT64,t->rhs))); + } + } + return exp; + } +}; + +void CGFrame::linearize(){ + + CGFun *in=fun; + fun=CG::fun( in->type,in->call_conv,in->sym,in->self ); + + if( int64ret ) fun->args.push_back( int64ret ); + + int k; + for( k=0;kargs.size();++k ){ + CGExp *arg=in->args[k]; + if( arg->type!=CG_INT64 ){ + fun->args.push_back( arg ); + continue; + } + assert( arg->mem() ); + fun->args.push_back( int64el(arg->mem(),0) ); + fun->args.push_back( int64el(arg->mem(),4) ); + } + + CGLinearizer vis( this ); + + for( k=0;kstms.size();++k ) in->stms[k]->visit( vis ); +} + +//**************** Fix Symbols ******************** +struct CGSymFixer : public CGVisitor{ + CGFrame *frame; + + map done; + + CGSymFixer( CGFrame *f ):frame(f){} + + CGExp *visit( CGExp *exp ){ + + CGSym *t=exp->sym(); + if( !t || t->linkage==CG_INTERNAL ) return exp; + + map::iterator it=done.find(t); + if( it!=done.end() ) return it->second; + + string id=frame->fixSym( t->value ); + + if( id==t->value ){ + exp=t; + }else if( CGDat *d=exp->dat() ){ + CGDat *t; + if( d->linkage==CG_INTERNAL ) t=CG::dat(); + else t=CG::dat(id); + t->exps=d->exps; + exp=t; + }else{ + exp=CG::sym(id,t->linkage); + } + + done.insert( make_pair(t,exp) ); + return exp; + } +}; + +void CGFrame::fixSymbols(){ + + CGSymFixer vis( this ); + + fun=CG::visitFun( fun,vis ); +} + +//************* Find Escaping Tmps **************** +struct CGEscFinder : public CGVisitor{ + CGFrame *frame; + + CGEscFinder( CGFrame *f ):frame(f){} + + CGExp *visit( CGExp *exp ){ + if( CGLea *p=exp->lea() ){ + CGTmp *t=p->exp->tmp(); + if( !t ) return exp; + if( frame->tmps.find(t->ident)==frame->tmps.end() ){ + frame->tmps.insert( make_pair(t->ident,frame->allocLocal(t->type)) ); + } + }else if( CGTmp *t=exp->tmp() ){ + //always spill bytes, shorts, longs... + if( t->type==CG_INT8 || t->type==CG_INT16 || t->type==CG_INT64 ){ + if( frame->tmps.find(t->ident)==frame->tmps.end() ){ + frame->tmps.insert( make_pair(t->ident,frame->allocLocal(t->type)) ); + } + } + } + return exp; + } +}; + +void CGFrame::findEscapes(){ + + if( fun->type==CG_INT64 ) int64ret=reg(CG_PTR); + + CGEscFinder vis( this ); + + fun=CG::visitFun( fun,vis ); +} + +//**************** Rename tmps ******************** +struct CGTmpRenamer : public CGVisitor{ + CGFrame *frame; + + CGTmpRenamer( CGFrame *f ):frame(f){} + + CGExp *visit( CGExp *exp ){ + if( CGTmp *t=exp->tmp() ){ + return tmpReg( t ); + } + return exp; + } + + CGExp *tmpReg( CGTmp *t ){ + IdExpMap::iterator it=frame->tmps.find(t->ident); + + if( it==frame->tmps.end() ){ + + CGReg *owner=0; + if( t->owner ) owner=tmpReg( t->owner )->reg(); + + it=frame->tmps.insert( make_pair(t->ident,frame->reg(t->type,owner)) ).first; + } + return it->second; + } +}; + +void CGFrame::renameTmps(){ + + CGTmpRenamer vis( this ); + + fun=CG::visitFun( fun,vis ); +} + +//**************** PreOptimize ******************** +static int shifter( int n ){ + int k; + for( k=0;k<32;++k ) if( n==(1<bcc() ){ + if( CGScc *p=t->lhs->scc() ){ + if( CGLit *q=t->rhs->lit() ){ + if( !q->int_value ){ + if( t->cc==CG_NE ){ + //bcc NE,scc,0,sym + return CG::bcc( p->cc,p->lhs,p->rhs,t->sym ); + }else if( t->cc==CG_EQ ){ + //bcc EQ,scc,0,sym + return CG::bcc( CG::swapcc(p->cc),p->lhs,p->rhs,t->sym ); + } + } + } + } + return stm; + } + return stm; + } + + + CGExp *visit( CGExp *exp ){ + + if( CGCvt *t=exp->cvt() ){ + //remove cvt between same types + CGExp *e=t->exp; + if( t->type==e->type ) exp=e; + return exp; + } + + if( CGMem *t=exp->mem() ){ + //remove mem(lea(mem),0)... + CGExp *e=t->exp; + CGLea *p=e->lea(); + assert( !p || p->exp->mem() ); + if( p && !t->offset && t->type==p->exp->mem()->type ) exp=p->exp; + return exp; + } + + if( CGUop *t=exp->uop() ){ + //const precalc unary op + if( t->isfloat() ) return exp; + if( CGLit *p=t->exp->lit() ){ + int n=p->int_value; + switch( t->op ){ + case CG_NOT:exp=CG::lit(~n);break; + case CG_NEG:exp=CG::lit(-n);break; + } + } + return exp; + } + + if( CGBop *t=exp->bop() ){ + if( t->isfloat() ) return exp; + + //const precalc binary op + CGLit *p=t->lhs->lit(),*q=t->rhs->lit(); + + if( p && !q && t->commutes() ){ + //put const on RHS in commuting const,non-const BOPs. + std::swap(p,q); + exp=t=CG::bop(t->op,t->rhs,q); + } + + if( p && q ){ + //const,const + int x=p->int_value,y=q->int_value; + switch( t->op ){ + case CG_ADD:exp=CG::lit(x+y);break; + case CG_SUB:exp=CG::lit(x-y);break; + case CG_MUL:exp=CG::lit(x*y);break; + case CG_DIV:assert(y);exp=CG::lit(x/y);break; + case CG_MOD:assert(y);exp=CG::lit(x%y);break; + case CG_AND:exp=CG::lit(x&y);break; + case CG_ORL:exp=CG::lit(x|y);break; + case CG_XOR:exp=CG::lit(x^y);break; + case CG_SHL:exp=CG::lit(x<>(unsigned)y));break; + case CG_SAR:exp=CG::lit(x>>y);break; + } + }else if( p ){ + //const,non-const (ie: non-commuting) + switch( p->int_value ){ + case 0: + switch( t->op ){ + case CG_DIV:case CG_MOD: + case CG_SHL:case CG_SHR:case CG_SAR: + exp=CG::lit0;break; + } + break; + } + }else if( q ){ + //non-const,const + switch( q->int_value ){ + case 0: + switch( t->op ){ + case CG_ADD:case CG_SUB: + case CG_ORL:case CG_XOR: + case CG_SHL:case CG_SHR:case CG_SAR: + exp=t->lhs;break; + case CG_MUL:case CG_AND: + exp=CG::lit0;break; + } + break; + case 1: + switch( t->op ){ + case CG_MUL:case CG_DIV: + exp=t->lhs;break; + } + break; + } + } + return exp; + } + return exp; + } +}; + +void CGFrame::preOptimize(){ + + CGPreOpter vis( this ); + + fun=CG::visitFun( fun,vis ); +} + +//****************** GenAssem ********************* +void CGFrame::genAssem(){ + assem.clear(); + asm_it=assem.end; + genFun(); +} + +//**************** Create flow ******************** +void CGFrame::createFlow(){ + deleteFlow(); + flow=new CGFlow(assem); + flow->liveness(); +} + +//**************** Create a reg ******************* +CGReg *CGFrame::reg( int type,CGReg *owner,int color ){ + assert( type!=CG_INT64 ); + CGReg *r=new CGReg; + r->type=type; + r->id=regs.size(); + r->owner=owner; + r->color=color; + regs.push_back(r); + return r; +} + +//*************** Generate assem ****************** +static CGIntSet *genUse; + +CGAsm *CGFrame::gen( CGStm *stm,const char *fmt,... ){ + CGAsm *as; + if( fmt ){ + char buf[256]; + buf[255]=0; + + va_list args; + va_start( args,fmt ); + vsprintf( buf,fmt,args ); + assert( !buf[255] ); + + as=new CGAsm( stm,buf ); + + }else{ + as=new CGAsm( stm,"" ); + } + + if( genUse ) as->use.insert( *genUse ); + + asm_it=assem.insert(as,asm_it)->succ; + return as; +} + +//*************** Elim dead code ****************** +void CGFrame::optDeadCode(){ + for(;;){ + bool changed=false; + CGBlockIter blk_it; + for( blk_it=flow->blocks.begin();blk_it!=flow->blocks.end();++blk_it ){ + CGBlock *blk=*blk_it; + + CGAsm *as=blk->end; + + CGIntSet live=blk->live_out; + + while( as!=blk->begin ){ + as=as->pred; + + bool elim=false; + + CGMov *t=as->stm->mov(); + + if( t ){ + CGReg *lhs=t->lhs->reg(); + CGReg *rhs=t->rhs->reg(); + if( lhs && rhs && lhs==rhs ){ + elim=true; + }else if( lhs && !t->rhs->sideEffects() && !live.count(lhs->id) ){ + elim=true; + } + } + + if( elim ){ + as=assem.erase(as); + changed=true; + }else{ + live.erase( as->def ); + live.insert( as->use ); + } + } + } + if( !changed ) break; + flow->liveness(); + } +} + +//*************** Optimize loads ****************** +/* +This is dodgy and probably not worth it... +CGMov to reg should eliminate any loads which depend on reg - this doesn't. +*/ +void CGFrame::optDupLoads(){ + /* + vector loads; + + bool changed=false; + + for( asm_it=assem.begin;asm_it!=assem.end;asm_it=asm_it->succ ){ + + CGMov *t=asm_it->stm->mov(); + if( !t || t->lhs->mem() || t->rhs->sideEffects() ){ + loads.clear(); + continue; + } + + if( !t->rhs->mem() ){ + continue; + } + + int k; + for( k=0;krhs->equals(loads[k]->rhs) ) continue; + //found a load! + cout<<"Eliminating load!"<lhs,loads[k]->lhs) ); + asm_it=asm_it->pred; + changed=true; + break; + } + if( k==loads.size() ) loads.push_back( t ); + } + if( changed ) flow->liveness(); + */ +} + +//*************** Allocate regs ******************* +struct Spiller : public CGVisitor{ + + CGReg *reg; + CGExp *exp; + CGIntSet owners; + + Spiller( CGReg *r,CGExp *e ):reg(r),exp(e){} + + CGExp *visit( CGExp *e ){ + CGReg *t=e->reg(); + if( t!=reg ) return e; + + while( t=t->owner ){ + owners.insert( t->id ); + } + + return exp; + /* + if( t==reg ) return exp; + CGReg *r=reg; + while( r=r->owner ){ + if( r==t ) owned.insert( r->id ); + } + return e; + */ + } +}; + +void CGFrame::spillReg( CGReg *reg,CGExp *exp ){ + + if( !exp ) exp=allocSpill(reg); + + int i; + for( i=0;iowner==reg ) regs[i]->owner=0; + } + + Spiller spiller( reg,exp ); + + asm_it=assem.begin; + while( asm_it!=assem.end ){ + spiller.owners.clear(); + CGStm *stm=asm_it->stm->visit( spiller ); + if( stm==asm_it->stm ){ + asm_it->use.erase( reg->id ); + asm_it=asm_it->succ; + continue; + } + asm_it=assem.erase( asm_it ); + genUse=&spiller.owners; + genStm( stm ); + genUse=0; + /* + asm_it=assem.erase( asm_it ); + genStm( stm ); + asm_it->pred->use.insert( spiller.owned ); + */ + } +} + +void CGFrame::allocRegs(){ + + cgAllocRegs( this ); + + CGAsm *as=assem.begin; + + while( as!=assem.end ){ + + if( CGMov *t=as->stm->mov() ){ + CGReg *lhs=t->lhs->reg(),*rhs=t->rhs->reg(); + if( lhs && rhs && lhs->color==rhs->color ){ + as=assem.erase(as); + continue; + } + } + + char buf[256],*q=buf; + const char *p=as->assem; + + while( const char *t=strchr(p,'\'') ){ + + memcpy(q,p,t-p); + q+=t-p; + + int n=0,c; + while( isdigit(c=*++t) ) n=n*10+(c-'0'); + + CGReg *r=regs[n]; + + int bank=reg_banks[r->type]; + const char *name=reg_names[bank][r->color]; + + strcpy( q,name ); + q+=strlen(q); + + p=t; + } + + if( q!=buf ){ + strcpy(q,p); + as->assem=strdup(buf); + } + + as=as->succ; + } +} + +void CGFrame::deleteFlow(){ + if( flow ){ + delete flow; + flow=0; + } +} + +void CGFrame::peepOpt(){ + CGAsm *as; + for( as=assem.begin;as!=assem.end;as=as->succ ){ + if( CGBra *p=as->stm->bra() ){ + if( CGLab *q=as->succ->stm->lab() ){ + if( p->sym->value==q->sym->value ){ + cout<<"Erasing:"<assem<banks + int reg_masks[4]; //usable regs per bank + vector reg_names[4]; //reg names per bank + + vector regs; + map tmps; + + CGFrame( CGFun *fun ); + virtual ~CGFrame(); + + //before ASM is generated + void findEscapes(); //local escaping tmps + void renameTmps(); //rename tmps->regs + void fixInt64(); + void linearize(); //remove SEQ and ESQ nodes + void fixSymbols(); //fix symbols depending on platform + void preOptimize(); //do some opts before asm gen + + //generate ASM + void genAssem(); //create assem from fun + void createFlow(); //create flowgraph + + //optimize FlowGraph + void optDeadCode(); //eliminate dead code + void optDupLoads(); //eliminate extra 'loads' + + //assign regs/rewrite src + void allocRegs(); //alloc registers + void spillReg( CGReg *r,CGExp *e ); + + void deleteFlow(); + void peepOpt(); + + CGMem* int64el( CGMem *i64,int n ); + CGMem* int64lo( CGMem *i64 ); + CGMem* int64hi( CGMem *i64 ); + + CGReg* reg( int type,CGReg *owner=0,int color=-1 ); + CGAsm* gen( CGStm *stm,const char *fmt,... ); + + virtual string fixSym( string id )=0; + virtual void genFun()=0; + virtual void genStm( CGStm *stm )=0; + virtual CGMem* allocLocal( int type )=0; + virtual CGExp* allocSpill( CGReg *r )=0; + virtual void finish()=0; +}; + +#endif \ No newline at end of file diff --git a/_src/codegen/cgframe_ppc.cpp b/_src/codegen/cgframe_ppc.cpp new file mode 100644 index 0000000..3af2f58 --- /dev/null +++ b/_src/codegen/cgframe_ppc.cpp @@ -0,0 +1,733 @@ + +#include "cgstd.h" + +#include "cgframe_ppc.h" +#include "cgmodule_ppc.h" + +#include "cgutil.h" +#include "cgdebug.h" + +using namespace CG; + +enum{ + MEM_PARAM=1, + MEM_LOCAL=2 +}; + +CGMem *CGFrame_PPC::genMem( CGMem *m,char *buf ){ + CGReg *r=genExp(m->exp); + const char *q=""; + switch( m->flags ){ + case MEM_PARAM:q="__FRAME+";break; + case MEM_LOCAL:q="__LOCAL+";break; + } + sprintf( buf,"%s%i('%i)",q,m->offset,r->id ); + CGMem *t=mem(m->type,r,m->offset); + t->flags=m->flags; + return t; +} + +CGReg *CGFrame_PPC::genLoad( CGMem *m ){ + + CGReg *r=reg(m->type); + + const char *op=0; + switch( m->type ){ + case CG_INT8:op="lbz";break; + case CG_INT16:op="lhz";break; + case CG_FLOAT32:op="lfs";break; + case CG_FLOAT64:op="lfd";break; + default:op="lwz"; + } + char buf[256]; + m=genMem(m,buf); + gen( mov(r,m), + "\t%s\t'%i,%s\n",op,r->id,buf ); + return r; +} + +void CGFrame_PPC::genStore( CGMem *m,CGExp *e ){ + + CGReg *r=genExp(e); + + const char *op=0; + switch( m->type ){ + case CG_INT8:op="stb";break; + case CG_INT16:op="sth";break; + case CG_FLOAT32:op="stfs";break; + case CG_FLOAT64:op="stfd";break; + default:op="stw"; + } + char buf[256]; + m=genMem(m,buf); + gen( mov( m,r ),"\t%s\t'%i,%s\n",op,r->id,buf ); +} + +void CGFrame_PPC::genCopy( CGReg *d,CGReg *r ){ + const char *op=d->isint() ? "mr" : "fmr"; + gen( mov(d,r),"\t%s\t'%i,'%i\n",op,d->id,r->id ); +} + +void CGFrame_PPC::genMov( CGExp *lhs,CGExp *rhs ){ + if( lhs->equals(rhs) ) return; + if( CGMem *t=lhs->mem() ){ + genStore( t,rhs ); + }else if( CGReg *t=lhs->reg() ){ + genCopy( t,genExp( rhs ) ); + }else{ + assert(0); + } +} + +CGReg *CGFrame_PPC::genExp( CGExp *e ){ + if( CGReg *t=e->reg() ){ + return t; + }else if( CGMem *t=e->mem() ){ + return genLoad( t ); + }else if( CGLea *t=e->lea() ){ + return genLea( t ); + }else if( CGCvt *t=e->cvt() ){ + return genCvt( t ); + }else if( CGUop *t=e->uop() ){ + return genUop( t ); + }else if( CGBop *t=e->bop() ){ + return genBop( t ); + }else if( CGScc *t=e->scc() ){ + return genScc( t ); + }else if( CGJsr *t=e->jsr() ){ + return genJsr( t ); + }else if( CGLit *t=e->lit() ){ + return genLit( t ); + }else if( CGSym *t=e->sym() ){ + return genSym( t ); + }else if( CGFrm *t=e->frm() ){ + return genFrm( t ); + } + cout<lit() ){ + if( t->isint() ){ + int n=t->int_value; + if( (mask & EA_SIMM) && n>=-32768 && n<32768 ){ + sprintf( buf,"%i",n ); + mask=EA_SIMM; + return e; + } + if( (mask & EA_UIMM) && n>=0 && n<65536 ){ + sprintf( buf,"%i",n ); + mask=EA_UIMM; + return e; + } + } + } + } + CGReg *r=genExp( e ); + sprintf( buf,"'%i",r->id ); + mask=0; + return r; +} + +CGReg *CGFrame_PPC::genLea( CGLea *e ){ + + CGReg *r=reg(e->type); + CGMem *m=e->exp->mem(); + + assert( m ); + + char buf[256]; + m=genMem(m,buf); + gen( mov(r,lea(m)),"\tla\t'%i,%s\n",r->id,buf ); + return r; +} + +CGReg *CGFrame_PPC::genCvt( CGCvt *e ){ + + CGReg *r=reg(e->type); + + if( r->isint() && e->exp->isint() ){ + //int to int + CGReg *t=genExp(e->exp); + if( r->type==CG_INT8 && e->exp->type!=CG_INT8 ){ + gen( mov(r,cvt(r->type,t)), + "\tandi.\t'%i,'%i,0xff\n", + r->id,t->id ); + }else if( r->type==CG_INT16 && e->exp->type==CG_INT32 ){ + gen( mov(r,cvt(r->type,t)), + "\tandi.\t'%i,'%i,0xffff\n", + r->id,t->id ); + }else{ + gen( mov(r,cvt(r->type,t)), + "\tmr\t'%i,'%i\n", + r->id,t->id ); + } + }else if( r->isfloat() && e->exp->isfloat() ){ + //float to float + CGReg *t=genExp(e->exp); + gen( mov(r,cvt(r->type,t)), + "\tfmr\t'%i,'%i\n", + r->id,t->id ); + }else if( r->isint() && e->exp->isfloat() ){ + //float to int + if( tmp_disp8<0 ){ + tmp_disp8=local_sz; + local_sz+=8; + } + int off; + const char *op; + switch( r->type ){ + case CG_INT8:off=7;op="lbz";break; + case CG_INT16:off=6;op="lhz";break; + case CG_INT32:case CG_PTR:off=4;op="lwz";break; + default:assert(0); + } + CGReg *t=genExp(e->exp),*f=F[0]; + + CGAsm *as=gen( mov(r,cvt(e->type,t)), + "\tfctiwz\t'%i,'%i\n" + "\tstfd\t'%i,__LOCAL+%i(r1)\n" + "\t%s\t'%i,__LOCAL+%i+%i(r1)\n", + f->id,t->id, + f->id,tmp_disp8, + op,r->id,tmp_disp8,off ); + as->def.insert(f->id); + + }else if( r->isfloat() && e->exp->isint() ){ + //int to float + if( tmp_disp8<0 ){ + tmp_disp8=local_sz; + local_sz+=8; + } + if( !mod_ppc->fp_const ){ + mod_ppc->fp_const=sym(); + } + CGReg *t=reg(CG_INT32),*f=F[0]; + + string p=mod_ppc->fp_const->value; + + genMov( t,genExp(e->exp) ); + + CGAsm *as=gen( mov(r,cvt(e->type,t)), + "\tlis\tr0,0x4330\n" + "\tstw\tr0,__LOCAL+%i(r1)\n" + "\txoris\t'%i,'%i,0x8000\n" + "\tstw\t'%i,__LOCAL+%i+4(r1)\n" + "\tlis\t'%i,ha16(%s)\n" + "\tlfd\t'%i,lo16(%s)('%i)\n" + "\tlfd\t'%i,__LOCAL+%i(r1)\n" + "\tfsub\t'%i,'%i,'%i\n", + tmp_disp8, + t->id,t->id, + t->id,tmp_disp8, + t->id,p.c_str(), + f->id,p.c_str(),t->id, + r->id,tmp_disp8, + r->id,r->id,f->id ); + as->use.insert(t->id); + as->def.insert(t->id); + as->def.insert(f->id); + + }else{ + assert(0); + } + + return r; + + /* int r3 to float f1 + addis R0,R0,0x4330 # R0 = 0x43300000 + stw R0,disp(R1) # store upper half + xoris R3,R3,0x8000 # flip sign bit + stw R3,disp+4(R1) # store lower half + lfd FR1,disp(R1) # float load double of value + fsub FR1,FR1,FR2 # subtract 0x4330000080000000 + */ + + /* float f1 to int r3 + fctiw[z] FR2,FR1 # convert to integer + stfd FR2,disp(R1) # copy unmodified to memory + lwz R3,disp+4(R1) # load the low-order 32 bits + */ +} + +CGReg *CGFrame_PPC::genUop( CGUop *e ){ + + const char *op=0; + + switch( e->op ){ + case CG_NOT:assert(e->isint());op="not";break; + case CG_NEG:op=e->isfloat() ? "fneg" : "neg";break; + default:assert(0); + } + + CGReg *r=reg(e->type); + CGReg *s=genExp(e->exp); + gen( mov(r,uop(e->op,s)),"\t%s\t'%i,'%i\n",op,r->id,s->id ); + return r; +} + +static int shifter( int n ){ + int k; + for( k=0;k<32;++k ) if( (1<isint() && (e->op==CG_MUL || e->op==CG_DIV) ){ + if( CGLit *c=e->rhs->lit() ){ + int i=c->int_value; + if( e->op==CG_MUL ){ + int n=shifter(i); + if( n!=-1 ){ + CGReg *r=reg(e->type); + CGReg *t=genExp(e->lhs); + gen( mov(r,bop(e->op,t,c)), + "\tslwi\t'%i,'%i,%i\n", + r->id,t->id,n ); + return r; + } + }else if( e->op==CG_DIV ){ + int n=shifter(i); + if( n!=-1 ){ + CGReg *r=reg(e->type); + CGReg *t=genExp(e->lhs); + gen( mov(r,bop(e->op,t,c)), + "\tsrawi\t'%i,'%i,%i\n" + "\taddze\t'%i,'%i\n", + r->id,t->id,n,r->id,r->id ); + return r; + } + } + } + } + + CGReg *r=reg(e->type); + + const char *op=0; + + int mask=0; + + if( e->isfloat() ){ + switch( e->op ){ + case CG_ADD:op="fadd";break; + case CG_SUB:op="fsub";break; + case CG_MUL:op="fmul";break; + case CG_DIV:op="fdiv";break; + } + }else{ + switch( e->op ){ + case CG_ADD:op="add";mask=EA_SIMM;break; + case CG_SUB:op="sub";mask=EA_SIMM;break; + case CG_MUL:op="mullw";mask=EA_SIMM;break; + case CG_DIV:op="divw";break; + case CG_AND:op="and";mask=EA_UIMM;break; + case CG_ORL:op="or";mask=EA_UIMM;break; + case CG_XOR:op="xor";mask=EA_UIMM;break; + case CG_SHL:op="slw";break; + case CG_SHR:op="srw";break; + case CG_SAR:op="sraw";break; + } + } + + if( op ){ + + char buf[256]; + CGReg *lhs=genExp(e->lhs); + CGExp *rhs=genExp(e->rhs,buf,mask); + const char *ext=""; + if( mask ){ + ext="i"; + switch( e->op ){ + case CG_AND:ext="i.";break; + case CG_MUL:op="mull";break; + } + } + + gen( mov(r,bop(e->op,lhs,rhs)), + "\t%s%s\t'%i,'%i,%s\n",op,ext,r->id,lhs->id,buf ); + + return r; + } + + if( e->op==CG_MOD && e->isint() ){ + CGReg *lhs=genExp(e->lhs); + CGReg *rhs=genExp(e->rhs); + //divw Rt,Ra,Rb # quotient = (int)(Ra / Rb) + //mullw Rt,Rt,Rb # quotient * Rb + //subf Rt,Rt,Ra # remainder = Ra - quotient * Rb + gen( mov(r,bop(e->op,lhs,rhs)), + "\tdivw\tr0,'%i,'%i\n" + "\tmullw\tr0,r0,'%i\n" + "\tsubf\t'%i,r0,'%i\n", + lhs->id,rhs->id,rhs->id,r->id,lhs->id ); + return r; + } + assert(0); + return 0; +} + +CGReg *CGFrame_PPC::genScc( CGScc *e ){ + + CGReg *r=reg(CG_INT32); + + CGReg *lhs=genExp(e->lhs); + CGReg *rhs=genExp(e->rhs); + + int bit=0; + char cror[256];cror[0]=0; + char exor[256];exor[0]=0; + + const char *op=lhs->isfloat() ? "fcmpu" : "cmpw"; + + switch( e->cc ){ + case CG_LT:bit=29;break; + case CG_GT:bit=30;break; + case CG_EQ:bit=31;break; + case CG_LE:bit=0;sprintf(cror,"\tcror\t31,30,28\n");break; + case CG_GE:bit=0;sprintf(cror,"\tcror\t31,30,29\n");break; + case CG_NE:bit=31;sprintf(exor,"\txori\t'%i,'%i,1\n",r->id,r->id);break; + case CG_LTU:bit=29;op="cmplw";break; + + default:assert(0); + } + + gen( mov(r,scc(e->cc,lhs,rhs)), + "\t%s\tcr7,'%i,'%i\n%s" + "\tmfcr\t'%i\n" + "\trlwinm\t'%i,'%i,%i,31,31\n%s", + op,lhs->id,rhs->id,cror,r->id,r->id,r->id,bit,exor ); + + return r; +} + +CGReg *CGFrame_PPC::genJsr( CGJsr *e ){ + + vector args; + + int k; + for( k=e->args.size()-1;k>=0;--k ){ + CGExp *arg=e->args[k]; + args.push_back( genExp(e->args[k]) ); + } + CGExp *ea=e->exp; + if( CGVfn *t=ea->vfn() ){ + args.push_back( genExp(t->self) ); + ea=t->exp; + } + ea=genExp(ea); + + int arg_sz=0,fp_id=1; + for( k=args.size()-1;k>=0;--k ){ + CGExp *t=args[k],*p; + if( t->isfloat() && fp_id<14 ){ + p=F[fp_id++]; + }else if( t->isfloat() || arg_sz>=32 ){ + p=mem(t->type,R[1],arg_sz+24 ); + }else{ + p=R[arg_sz/4+3]; + } + arg_sz+=(t->type==CG_FLOAT64) ? 8 : 4; + genMov( p,t ); + args[k]=p; + } + if( arg_sz>param_sz ) param_sz=arg_sz; + + CGExp *dst=e->isfloat() ? F[1] : R[3]; + + CGAsm *as=gen( mov(dst,jsr(e->type,e->call_conv,ea,args)), + "\tmtctr\t'%i\n" + "\tbctrl\n",ea->reg()->id ); + + for( k=3;k<13;++k ) as->def.insert( R[k]->id ); + for( k=1;k<14;++k ) as->def.insert( F[k]->id ); + + CGReg *r=reg( e->type ); + genMov( r,dst ); + return r; +} + +CGReg *CGFrame_PPC::genLit( CGLit *e ){ + + CGReg *r=reg(e->type); + + if( e->isfloat() ){ + CGDat *d=dat(); + d->push_back(e); + genMov( r,mem(e->type,d,0) ); + return r; + } + CGStm *m=mov(r,e); + int n=e->int_value; + if( n>=-32768 && n<32768 ){ + //16 bit signed + gen( m, + "\tli\t'%i,%i\n",r->id,n ); + }else if( !(n&65535) ){ + //32 bit - 0 low word + gen( m, + "\tlis\t'%i,%i\n",r->id,(n>>16) ); + }else{ + //32 bit + gen( m, + "\tlis\t'%i,%i\n" + "\tori\t'%i,'%i,%i\n",r->id,(n>>16),r->id,r->id,(n&65535) ); + } + return r; +} + +CGReg *CGFrame_PPC::genSym( CGSym *e ){ + CGReg *r=reg(e->type); + if( e->linkage==CG_IMPORT ){ + string t=""+e->value+"$non_lazy_ptr"; + gen( mov(r,e), + "\tlis\t'%i,ha16(%s)\n" + "\tlwz\t'%i,lo16(%s)('%i)\n",r->id,t.c_str(),r->id,t.c_str(),r->id ); + }else{ + gen( mov(r,e), + "\tlis\t'%i,hi16(%s)\n" + "\tori\t'%i,'%i,lo16(%s)\n",r->id,e->value.c_str(),r->id,r->id,e->value.c_str() ); + } + return r; +} + +CGReg *CGFrame_PPC::genFrm( CGFrm *e ){ + CGReg *r=reg(CG_PTR); + gen( mov(r,e), + "\tla\t'%i,__LOCAL(r1)\n",r->id ); + return r; +} + +void CGFrame_PPC::genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ){ + + if( cc==CG_LTU ){ + genBcc( CG_NE,scc(cc,lhs,rhs),lit0,sym ); + return; + } + + int tcc=cc; + if( bigFun ) cc=CG::swapcc(cc); + + const char *p; + switch( cc ){ + case CG_LT:p="lt";break; + case CG_GT:p="gt";break; + case CG_EQ:p="eq";break; + case CG_LE:p="le";break; + case CG_GE:p="ge";break; + case CG_NE:p="ne";break; + default:assert(0); + } + + if( lhs->isfloat() ){ + CGReg *x=genExp(lhs); + CGReg *y=genExp(rhs); + if( bigFun ){ + CGSym *t=CG::sym(); + gen( bcc(tcc,x,y,sym), + "\tfcmpu\tcr0,'%i,'%i\n" + "\tb%s\t%s\n\tb\t%s\n%s:\n",x->id,y->id,p,t->value.c_str(),sym->value.c_str(),t->value.c_str() ); + }else{ + gen( bcc(cc,x,y,sym), + "\tfcmpu\tcr0,'%i,'%i\n" + "\tb%s\t%s\n",x->id,y->id,p,sym->value.c_str() ); + } + return; + } + + char buf[256]; + int mask=EA_SIMM; + CGReg *x=genExp(lhs); + CGExp *y=genExp(rhs,buf,mask); + const char *ext=mask ? "i" : ""; + if( bigFun ){ + CGSym *t=CG::sym(); + gen( bcc(tcc,x,y,sym), + "\tcmpw%s\t'%i,%s\n" + "\tb%s\t%s\n\tb\t%s\n%s:\n",ext,x->id,buf,p,t->value.c_str(),sym->value.c_str(),t->value.c_str() ); + }else{ + gen( bcc(cc,x,y,sym), + "\tcmpw%s\t'%i,%s\n" + "\tb%s\t%s\n",ext,x->id,buf,p,sym->value.c_str() ); + } +} + +void CGFrame_PPC::genRet( CGExp *e ){ + CGReg *r=0; + if( e ){ + r=e->isfloat() ? F[1] : R[3]; + genMov(r,e); + } + CGAsm *as=gen( ret(r),"\tblr\n" ); + as->use.insert( R[1]->id ); +} + +string CGFrame_PPC::fixSym( string id ){ + return "_"+id; +} + +void CGFrame_PPC::genStm( CGStm *s ){ + + if( CGAti *t=s->ati() ){ + char buf[256]; + CGMem *m=genMem( t->mem,buf ); + CGAsm *as=gen( ati(m), + "\tlwz\tr2,%s\n" + "\taddi\tr2,r2,1\n" + "\tstw\tr2,%s\n", + buf,buf ); + /* + CGReg *r=genLea( lea(t->mem) ); + CGAsm *as=gen( ati(mem(CG_INT32,r,0)), + "1:\n" + "\tlwarx\tr2,0,'%i\n" + "\taddi\tr2,r2,1\n" + "\tstwcx.\tr2,0,'%i\n" + "\tbne\t1b\n", + r->id,r->id ); + */ + }else if( CGAtd *t=s->atd() ){ + char buf[256]; + CGMem *m=genMem( t->mem,buf ); + CGAsm *as=gen( atd(m,t->sym), + "\tlwz\tr2,%s\n" + "\taddi\tr2,r2,-1\n" + "\tstw\tr2,%s\n" + "\tcmpwi\tr2,0\n" + "\tbne\t%s\n", + buf,buf,t->sym->value.c_str() ); + /* + CGReg *r=genLea( lea(t->mem) ); + CGAsm *as=gen( atd(mem(CG_INT32,r,0),t->sym), + "1:\n" + "\tlwarx\tr2,0,'%i\n" + "\taddi\tr2,r2,-1\n" + "\tstwcx.\tr2,0,'%i\n" + "\tbne\t1b\n" + "\tor.\tr2,r2,r2\n" + "\tbne\t%s\n", + r->id,r->id,t->sym->value.c_str() ); + */ + }else if( CGMov *t=s->mov() ){ + genMov( t->lhs,t->rhs ); + }else if( CGLab *t=s->lab() ){ + gen( t,"%s:\n",t->sym->value.c_str() ); + }else if( CGBra *t=s->bra() ){ + gen( t,"\tb\t%s\n",t->sym->value.c_str() ); + }else if( CGBcc *t=s->bcc() ){ + genBcc( t->cc,t->lhs,t->rhs,t->sym ); + }else if( CGEva *t=s->eva() ){ + if( t->exp->dat() ){ + gen( t,"" ); + }else{ + genExp( t->exp ); + } + }else if( CGRem *t=s->rem() ){ + gen( t,"\t;%s\n",t->comment.c_str() ); + }else if( CGRet *t=s->ret() ){ + genRet( t->exp ); + }else if( CGXop *t=s->xop() ){ + assert(0); + }else{ + assert(0); + } +} + +void CGFrame_PPC::genFun(){ + + param_sz=32; + tmp_disp8=-1; + + int k,arg_sz=0,fp_id=1; + + //move self to tmp + if( CGExp *t=fun->self ){ + //get 'this' from stack + genMov( t,R[3] ); + arg_sz+=4; + } + + //move args to tmps + for( k=0;kargs.size();++k ){ + CGExp *t=fun->args[k],*p; + if( t->isfloat() && fp_id<14 ){ + p=F[fp_id++]; + }else if( t->isfloat() || arg_sz>=32 ){ + CGMem *m=mem(t->type,R[1],arg_sz+24 ); + m->flags=MEM_PARAM; + p=m; + }else{ + p=R[arg_sz/4+3]; + } + arg_sz+=(t->type==CG_FLOAT64) ? 8 : 4; + genMov( t,p ); + } + + //genAsm for statements + for( k=0;kstms.size();++k ){ + genStm( fun->stms[k] ); + } +} + +CGMem *CGFrame_PPC::allocLocal( int type ){ + CGMem *m=mem(type,R[1],local_sz); + m->flags=MEM_LOCAL; + int sz=(type==CG_INT64 || type==CG_FLOAT64) ? 8 : 4; + local_sz+=sz; + return m; +} + +CGExp *CGFrame_PPC::allocSpill( CGReg *r ){ + return allocLocal( r->type ); +} + +void CGFrame_PPC::finish(){ +} + +CGFrame_PPC::CGFrame_PPC( CGFun *fun,CGModule_PPC *mod ):CGFrame(fun), +mod_ppc(mod),local_sz(0){ + + bigFun=fun->stms.size()>300; +/* + if( bigFun ){ + printf( "Big function:%i stms\n",fun->stms.size() ); + fflush( stdout ); + }else{ + printf( "Small function:%i stms\n",fun->stms.size() ); + fflush( stdout ); + } +*/ + + //int types map to reg bank 0 + reg_banks[CG_INT8]=0; + reg_banks[CG_INT16]=0; + reg_banks[CG_INT32]=0; + reg_banks[CG_PTR]=0; + + //float types map to bank 1 + reg_banks[CG_FLOAT32]=1; + reg_banks[CG_FLOAT64]=1; + + //available reg masks + reg_masks[0]=0xfffffff8; //R0/R1/R2 unavailable! + reg_masks[1]=0xfffffffe; //F0 unavailable! + + char *buf; + + for( int k=0;k<32;++k ){ + + R[k]=reg( CG_INT32,0,k ); + F[k]=reg( CG_FLOAT64,0,k ); + + buf=new char[4]; + sprintf( buf,"r%i",k<13 ? k : 31+13-k ); + reg_names[0].push_back( buf ); + + buf=new char[4]; + sprintf( buf,"f%i",k ); + reg_names[1].push_back( buf ); + } +} diff --git a/_src/codegen/cgframe_ppc.h b/_src/codegen/cgframe_ppc.h new file mode 100644 index 0000000..0bdc8f0 --- /dev/null +++ b/_src/codegen/cgframe_ppc.h @@ -0,0 +1,60 @@ + +#ifndef CGFRAME_PPC_H +#define CGFRAME_PPC_H + +#include "cgframe.h" + +struct CGModule_PPC; + +struct CGFrame_PPC : public CGFrame{ + + CGModule_PPC *mod_ppc; + + int param_sz,local_sz,tmp_disp8,bigFun; + + CGReg* R[32]; + CGReg* F[32]; + + enum{ + EA_SIMM=1, + EA_UIMM=2, + EA_SHIFTED=4 + }; + enum{ + XOP_LWARX, + XOP_STWCX + }; + + CGMem* genMem( CGMem *exp,char *buf ); + + CGReg* genExp( CGExp *exp ); + CGReg* genLea( CGLea *exp ); + CGReg* genCvt( CGCvt *exp ); + CGReg* genUop( CGUop *exp ); + CGReg* genBop( CGBop *exp ); + CGReg* genScc( CGScc *exp ); + CGReg* genJsr( CGJsr *exp ); + CGReg* genLit( CGLit *exp ); + CGReg* genSym( CGSym *exp ); + CGReg* genFrm( CGFrm *exp ); + + CGExp* genExp( CGExp *exp,char *buf,int &ea_mask ); + + CGReg* genLoad( CGMem *mem ); + void genStore( CGMem *mem,CGExp *exp ); + void genCopy( CGReg *dst,CGReg *src ); + void genMov( CGExp *lhs,CGExp *rhs ); + void genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ); + void genRet( CGExp *exp ); + + CGFrame_PPC( CGFun *fun,CGModule_PPC *mod ); + + virtual string fixSym( string id ); + virtual void genFun(); + virtual void genStm( CGStm *stm ); + virtual CGMem* allocLocal( int type ); + virtual CGExp* allocSpill( CGReg *r ); + virtual void finish(); +}; + +#endif diff --git a/_src/codegen/cgframe_x86.cpp b/_src/codegen/cgframe_x86.cpp new file mode 100644 index 0000000..20d9ff6 --- /dev/null +++ b/_src/codegen/cgframe_x86.cpp @@ -0,0 +1,983 @@ + +#include "cgstd.h" + +#include "cgutil.h" +#include "cgframe_x86.h" +#include "cgmodule_x86.h" +#include "cgdebug.h" + +using namespace CG; + +//Can't use %lld 'coz it doesn't work on mingw! +//#define FMTI64 "%lld" + +const char *CGFrame_X86::x86cc( int cc ){ + switch( cc ){ + case CG_EQ:return "e"; + case CG_NE:return "ne"; + case CG_LT:return "l"; + case CG_GT:return "g"; + case CG_LE:return "le"; + case CG_GE:return "ge"; + case CG_LTU:return "b"; + case CG_GTU:return "a"; + case CG_LEU:return "be"; + case CG_GEU:return "ae"; + } + assert(0); + return 0; +} + +const char *CGFrame_X86::x86size( int type ){ + switch(type){ + case CG_PTR:return "dword"; + case CG_INT8:return "byte"; + case CG_INT16:return "word"; + case CG_INT32:return "dword"; + case CG_INT64:return "dword"; + case CG_FLOAT32:return "dword"; + case CG_FLOAT64:return "qword"; + } + cout<<"Unrcognized type:"<exp->bop(); + + if( !t ) return 0; + + if( t->op!=CG_ADD && t->op!=CG_SUB ) return 0; + + char c=t->op==CG_ADD ? '+' : '-'; + + CGBop *q=t->rhs->bop(); + if( q && q->op==CG_MUL ){ + if( CGLit *n=q->rhs->lit() ){ + int f=n->int_value; + if( f==2 || f==4 || f==8 ){ + char x_buf[256]; + CGExp *x=genExp( t->lhs,x_buf,EA_IMM ); + CGReg *y=genExp( q->lhs ); + //x+y*v + const char *tm=e->offset ? "%s [%s%c'%i*%i+%i]" : "%s [%s%c'%i*%i]"; + sprintf( buf,tm,x86size(e->type),x_buf,c,y->id,f,e->offset ); + + return mem(e->type,bop(t->op,x,bop(CG_MUL,y,n)),e->offset); + } + } + } + + char x_buf[256],y_buf[256]; + + CGExp *x=genExp( t->lhs,x_buf,EA_IMM ); + CGExp *y=genExp( t->rhs,y_buf,EA_IMM ); + + const char *tm=e->offset ? "%s [%s%c%s+%i]" : "%s [%s%c%s]"; + + sprintf( buf,tm,x86size(e->type),x_buf,c,y_buf,e->offset ); + + return mem(e->type,bop(t->op,x,y),e->offset); +} + +bool CGFrame_X86::optMov( CGExp *lhs,CGExp *rhs ){ + + if( !lhs->mem() ) return false; + + if( lhs->isfloat() ) return false; + + CGBop *t=rhs->bop(); + if( !t ) return false; + + const char *op; + switch( t->op ){ + case CG_ADD:op="add";break; + case CG_SUB:op="sub";break; + case CG_ORL:op="or";break; + case CG_AND:op="and";break; + case CG_XOR:op="xor";break; + default:return false; + } + + if( !lhs->equals(t->lhs) ) return false; + + char x_buf[256]; + CGExp *x=genExp( lhs,x_buf,EA_MEM ); + + if( CGLit *y=t->rhs->lit() ){ + int n=y->int_value; + const char *q=0; + if( t->op==CG_ADD ){ + if( n==1 ) q="inc"; + else if( n==-1 ) q="dec"; + }else if( t->op==CG_SUB ){ + if( n==1 ) q="dec"; + else if( n==-1 ) q="inc"; + } + if( q ){ + gen( mov(x,bop(t->op,x,y)),"\t%s\t%s\n",q,x_buf ); + return true; + } + } + + char y_buf[256]; + CGExp *y=genExp( t->rhs,y_buf,x->reg() ? EA_MEM|EA_IMM : EA_IMM ); + + gen( mov(x,bop(t->op,x,y)),"\t%s\t%s,%s\n",op,x_buf,y_buf ); + + return true; +} + +CGReg *CGFrame_X86::genExp( CGExp *e ){ + if( CGReg *t=e->reg() ){ + return t; + }else if( CGMem *t=e->mem() ){ + return genLoad( t ); + }else if( CGLea *t=e->lea() ){ + return genLea( t ); + }else if( CGCvt *t=e->cvt() ){ + return genCvt( t ); + }else if( CGUop *t=e->uop() ){ + return genUop( t ); + }else if( CGBop *t=e->bop() ){ + return genBop( t ); + }else if( CGScc *t=e->scc() ){ + return genScc( t ); + }else if( CGJsr *t=e->jsr() ){ + return genJsr( t ); + }else if( CGLit *t=e->lit() ){ + return genLit( t ); + }else if( CGSym *t=e->sym() ){ + return genSym( t ); + }else if( CGFrm *t=e->frm() ){ + return genFrm( t ); + } + assert(0); + return 0; +} + +CGMem *CGFrame_X86::genMem( CGMem *e,char *buf ){ + if( CGMem *t=optMem(e,buf) ) return t; + char t_buf[256]; + CGExp *t=genExp(e->exp,t_buf,EA_IMM ); + const char *tm=e->offset ? "%s [%s%+i]" : "%s [%s]"; + sprintf( buf,tm,x86size(e->type),t_buf,e->offset ); + return mem( e->type,t,e->offset ); +} + +CGExp *CGFrame_X86::genExp( CGExp *e,char *buf,int mask ){ + + if( mask & EA_IMM ){ + if( CGLit *t=e->lit() ){ + if( t->isint() ){ +// sprintf( buf,FMTI64,t->int_value ); + strcpy( buf,fromint( t->int_value ).c_str() ); + return e; + } + } + if( CGSym *t=e->sym() ){ + sprintf( buf,"%s",t->value.c_str() ); + return e; + } + } + if( mask & EA_MEM ){ + if( CGLit *t=e->lit() ){ + if( t->type==CG_FLOAT32 ){ + CGDat *d=dat(); + d->push_back(t); + return genMem( mem(CG_FLOAT32,d,0),buf ); + } + } + if( CGMem *t=e->mem() ){ + if( t->type!=CG_INT8 && t->type!=CG_INT16 ){ + return genMem( t,buf ); + } + } + } + CGReg *r=genExp(e); + sprintf( buf,"'%i",r->id ); + return r; +} + +CGReg *CGFrame_X86::genLoad( CGMem *e ){ + + char buf[256]; + e=genMem( e,buf ); + const char *zx=(e->type==CG_INT8 || e->type==CG_INT16) ? "zx" : ""; + + CGReg *r=reg(e->type); + gen( mov(r,e), + "\tmov%s\t'%i,%s\n",zx,r->id,buf ); + + return r; +} + +void CGFrame_X86::genCopy( CGReg *r,CGReg *t ){ + if( r->id==t->id ) return; + + gen( mov(r,t),"\tmov\t'%i,'%i\n",r->id,t->id ); +} + +void CGFrame_X86::genMov( CGExp *lhs,CGExp *rhs ){ + if( lhs->equals(rhs) ) return; + + char lhs_buf[256]; + CGMem *lhs_mem=lhs->mem(); + CGReg *lhs_reg=lhs->reg(); + + if( lhs_reg ){ + sprintf( lhs_buf,"'%i",lhs_reg->id ); + }else{ + lhs=lhs_mem=genMem( lhs_mem,lhs_buf ); + } + + if( CGBop *t=rhs->bop() ){ + if( t->lhs->equals(lhs) ){ + if( t->isint() ){ + const char *op=0; + switch( t->op ){ + case CG_ADD:op="add";break; + case CG_SUB:op="sub";break; + case CG_ORL:op="or";break; + case CG_AND:op="and";break; + case CG_XOR:op="xor";break; + } + if( op ){ + char rhs_buf[256]; + int rhs_ea=EA_IMM; + if( lhs_reg ) rhs_ea|=EA_MEM; + rhs=genExp( t->rhs,rhs_buf,rhs_ea ); + gen( mov(lhs,bop(t->op,lhs,rhs)), + "\t%s\t%s,%s\n",op,lhs_buf,rhs_buf ); + return; + } + switch( t->op ){ + case CG_SHL:op="shl";break; + case CG_SHR:op="shr";break; + case CG_SAR:op="sar";break; + } + if( op ){ + char rhs_buf[256]; + rhs=genExp( t->rhs,rhs_buf,EA_IMM ); + if( CGReg *r=rhs->reg() ){ + if( r->id!=ECX ){ + genMov( ecx,r ); + rhs=ecx; + } + strcpy( rhs_buf,"cl" ); + } + gen( mov(lhs,bop(t->op,lhs,rhs)), + "\t%s\t%s,%s\n",op,lhs_buf,rhs_buf ); + return; + } + }else if( lhs_reg && t->isfloat() ){ + const char *op=0; + switch( t->op ){ + case CG_ADD:op="fadd";break; + case CG_SUB:op="fsub";break; + case CG_MUL:op="fmul";break; + case CG_DIV:op="fdiv";break; + } + if( op ){ + int rhs_ea=0; + char rhs_buf[256]; + if( lhs_reg ) rhs_ea|=EA_MEM; + rhs=genExp( t->rhs,rhs_buf,rhs_ea ); + gen( mov(lhs,bop(t->op,lhs,rhs)), + "\t%s\t%s,%s\n",op,lhs_buf,rhs_buf ); + return; + } + } + } + } + + char rhs_buf[256]; + int rhs_ea=EA_IMM; + if( lhs_reg ) rhs_ea|=EA_MEM; + rhs=genExp( rhs,rhs_buf,rhs_ea ); + + if( lhs_mem && (lhs->type==CG_INT8 || lhs->type==CG_INT16) ){ + if( CGReg *r=rhs->reg() ){ + if( r->id!=EAX ){ + genMov( eax,cvt(CG_INT32,rhs) ); + rhs=cvt(lhs->type,eax); + } + strcpy( rhs_buf,lhs->type==CG_INT8 ? "al" : "ax" ); + } + } + + gen( mov(lhs,rhs), + "\tmov\t%s,%s\n",lhs_buf,rhs_buf ); +} + +CGReg *CGFrame_X86::genLea( CGLea *t ){ + + CGReg *r=reg(t->type); + CGMem *m=t->exp->mem(); + + assert( m ); + + char buf[256]; + m=genMem( m,buf ); + gen( mov(r,lea(m)),"\tlea\t'%i,%s\n",r->id,buf ); + return r; +} + +CGReg *CGFrame_X86::genCvt( CGCvt *t ){ + CGReg *r; + if( t->isint() && t->exp->isint() ){ + //int to int + r=reg(t->type); + char buf[256]; + CGExp *exp=genExp(t->exp,buf,EA_IMM|EA_MEM); + if( r->type==CG_INT8 && t->exp->type!=CG_INT8 ){ + gen( mov(r,cvt(r->type,exp)), + "\tmov\t'%i,%s\n" + "\tand\t'%i,0xff\n", + r->id,buf,r->id ); + }else if( t->type==CG_INT16 && (t->exp->type==CG_INT32 || t->exp->type==CG_PTR) ){ + gen( mov(r,cvt(r->type,exp)), + "\tmov\t'%i,%s\n" + "\tand\t'%i,0xffff\n", + r->id,buf,r->id ); + }else{ + gen( mov(r,cvt(r->type,exp)), + "\tmov\t'%i,%s\n", + r->id,buf ); + } + }else{ + r=reg(t->type); + CGReg *exp=genExp(t->exp); + gen( mov(r,cvt(r->type,exp)), + "\tmov\t'%i,'%i\n",r->id,exp->id ); + } + return r; +} + +CGReg *CGFrame_X86::genUop( CGUop *t ){ + + const char *op=0; + + switch( t->op ){ + case CG_NEG:op="neg";break; + case CG_NOT:assert(t->isint());op="not";break; + default:assert(0); + } + + CGReg *r=reg(t->type); + genMov( r,t->exp ); + gen( mov(r,uop(t->op,r)),"\t%s\t'%i\n",op,r->id ); + return r; +} + +static int shifter( int n ){ + int k; + for( k=0;k<32;++k ) if( (1<isint() && (t->op==CG_MUL || t->op==CG_DIV) ){ + if( CGLit *c=t->rhs->lit() ){ + int i=c->int_value; + if( t->op==CG_MUL ){ + int n=shifter(i); + if( n!=-1 ){ + return genBop( bop(CG_SHL,t->lhs,lit(n)) ); + } + }else if( t->op==CG_DIV ){ + int n=shifter(i); + if( n!=-1 ){ + genMov( eax,t->lhs ); + gen( xop(XOP_CDQ,edx,eax),"\tcdq\n" ); + CGExp *e=edx; + e=bop(CG_AND,edx,lit(i-1)); + e=bop(CG_ADD,eax,e); + e=bop(CG_SAR,e,lit(n)); + return genExp(e); + } + } + } + } + + CGReg *r=reg(t->type); + + const char *op=0; + + if( t->isfloat() ){ + switch( t->op ){ + case CG_ADD:op="fadd";break; + case CG_SUB:op="fsub";break; + case CG_MUL:op="fmul";break; + case CG_DIV:op="fdiv";break; + } + }else{ + switch( t->op ){ + case CG_ADD:op="add";break; + case CG_SUB:op="sub";break; + case CG_MUL:op="imul";break; + case CG_AND:op="and";break; + case CG_ORL:op="or";break; + case CG_XOR:op="xor";break; + } + } + + if( op ){ + genMov( r,t->lhs ); + + char buf[256]; + CGExp *rhs=genExp( t->rhs,buf,EA_MEM|EA_IMM ); + + gen( mov(r,bop(t->op,r,rhs)), + "\t%s\t'%i,%s\n",op,r->id,buf ); + return r; + } + + assert( t->isint() ); + + switch( t->op ){ + case CG_SHL:op="shl";break; + case CG_SHR:op="shr";break; + case CG_SAR:op="sar";break; + } + if( op ){ + genMov(r,t->lhs); + + if( CGLit *rhs=t->rhs->lit() ){ +// gen( mov(r,bop(t->op,r,rhs)), +// "\t%s\t'%i," FMTI64 "\n",op,r->id,rhs->int_value ); + char buf[64]; + strcpy( buf,fromint( rhs->int_value ).c_str() ); + gen( mov(r,bop(t->op,r,rhs)), + "\t%s\t'%i,%s\n",op,r->id,buf ); + }else{ + genMov( ecx,t->rhs ); + gen( mov(r,bop(t->op,r,ecx)), + "\t%s\t'%i,cl\n",op,r->id ); + } + return r; + } + switch( t->op ){ + case CG_MOD:case CG_DIV:break; + default:assert(0); + } + + char buf[256]; + CGExp *rhs=genExp( t->rhs,buf,EA_MEM ); + + CGAsm *as; + if( t->op==CG_MOD ){ + genMov( eax,t->lhs ); + gen( xop(XOP_CDQ,edx,eax),"\tcdq\n" ); + as=gen( mov(edx,bop(CG_MOD,eax,rhs)),"\tidiv\t%s\n",buf ); + as->use.insert( EDX ); + as->def.insert( EAX ); + genMov( r,edx ); + +// genMov( eax,t->lhs ); +// as=gen( mov(edx,bop(CG_MOD,eax,rhs)),"\tcdq\n\tidiv\t%s\n",buf ); +// as->def.insert( EAX ); +// genMov( r,edx ); + }else{ + genMov( eax,t->lhs ); + gen( xop(XOP_CDQ,edx,eax),"\tcdq\n" ); + as=gen( mov(eax,bop(CG_DIV,eax,rhs)),"\tidiv\t%s\n",buf ); + as->use.insert( EDX ); + as->def.insert( EDX ); + genMov( r,eax ); + +// genMov( eax,t->lhs ); +// as=gen( mov(eax,bop(CG_DIV,eax,rhs)),"\tcdq\n\tidiv\t%s\n",buf ); +// as->def.insert( EDX ); +// genMov( r,eax ); + } + return r; +} + +CGReg *CGFrame_X86::genScc( CGScc *t ){ + + CGReg *lhs=genExp( t->lhs ); + + if( lhs->isfloat() ){ + CGReg *rhs=genExp( t->rhs ); + gen( mov(eax,scc(t->cc,lhs,rhs)),"" ); + }else{ + char rhs_buf[256]; + CGExp *rhs=genExp( t->rhs,rhs_buf,EA_MEM|EA_IMM ); + + gen( mov(eax,scc(t->cc,lhs,rhs)), + "\tcmp\t'%i,%s\n" + "\tset%s\tal\n" + "\tmovzx\teax,al\n",lhs->id,rhs_buf,x86cc(t->cc) ); + } + + CGReg *r=reg(CG_INT32); + genMov( r,eax ); + return r; +} + +CGReg *CGFrame_X86::genJsr( CGJsr *t ){ + + if( env_platform=="macos" ){ + return genMacJsr( t ); + } + + int k,arg_sz=0; + + CGExp *ea=t->exp; + + for( k=0;kargs.size();++k ){ + arg_sz+=t->args[k]->type==CG_FLOAT64 ? 8 : 4; + } + if( CGVfn *p=ea->vfn() ){ + arg_sz+=p->self->type==CG_FLOAT64 ? 8 : 4; + } + + for( k=t->args.size()-1;k>=0;--k ){ + genPush( t->args[k] ); + } + if( CGVfn *p=ea->vfn() ){ + //put 'this' on stack + genPush( p->self ); + ea=p->exp; + } + + char buf[256]; + ea=genExp( ea,buf,EA_MEM|EA_IMM ); + + CGReg *dst=t->isfloat() ? fp0 : eax; + + CGAsm *as=gen( mov(dst,jsr(t->type,t->call_conv,ea)),"\tcall\t%s\n",buf ); + + as->def.insert(EAX);as->def.insert(EDX);as->def.insert(ECX); + as->def.insert(FP0);as->def.insert(FP1);as->def.insert(FP2); + as->def.insert(FP3);as->def.insert(FP4);as->def.insert(FP5); + as->def.insert(FP6); + + if( t->call_conv==CG_CDECL ){ + genPop( lit(arg_sz) ); + }else{ + ++extern_jsrs; + + } + + CGReg *r=reg(t->type); + genMov( r,dst ); + return r; +} + +static int argSize( CGExp *e ){ + return e->type==CG_FLOAT64 ? 8 : 4; +} + +static int paramSize( CGJsr *t ){ + int i,sz=0; + if( CGVfn *p=t->exp->vfn() ) sz+=argSize( p->self ); + for( i=0;iargs.size();++i ) sz+=argSize( t->args[i] ); + return sz; +} + +struct MaxParamSizeVisitor : public CGVisitor{ + int size; + + MaxParamSizeVisitor():size(0){} + + CGExp *visit( CGExp *e ){ + CGJsr *t=e->jsr(); + if( !t ) return e; + int sz=paramSize( t ); + if( sz>size ) size=sz; + return e; + } +}; + +static int maxParamSize( CGExp *e,int sz ){ + MaxParamSizeVisitor v; + e->visit(v); + return v.size>sz ? v.size : sz; +} + +CGReg *CGFrame_X86::genMacJsr( CGJsr *t ){ + +///* + int i; + vector maxszs; + vector args; + vector movs; + + CGExp *ea=t->exp,*self=0; + if( CGVfn *p=ea->vfn() ){ + ea=p->exp; + self=p->self; + } + + args.push_back( ea ); + if( self ) args.push_back( self ); + for( i=0;iargs.size();++i ){ + args.push_back( t->args[i] ); + } + + int maxsz=0; + for( i=0;iparam_sz ) param_sz=offset; + + for( i=args.size()-1;i>=0;--i ){ + if( i ){ + CGExp *arg=args[i]; + offset-=argSize( arg ); + CGExp *lhs=mem( arg->type,esp,offset ); + CGExp *rhs=genExp( args[i],buf,EA_IMM ); + movs.push_back( mov(lhs,rhs) ); + }else{ + ea=genExp( ea,buf,EA_MEM|EA_IMM ); + } + bool again=true; + vector::iterator it; + while( again ){ + again=false; + for( it=movs.begin();it!=movs.end();++it ){ + CGMov *t=*it; + if( t->lhs->mem()->offset>=maxszs[i] ){ + genMov( t->lhs,t->rhs ); + movs.erase( it ); + again=true; + break; + } + } + } + } +//*/ +/* + vector args; + + int k,arg_sz=0; + + for( k=t->args.size()-1;k>=0;--k ){ + CGExp *arg=t->args[k]; + args.push_back( genExp(t->args[k]) ); + } + + CGExp *ea=t->exp; + + if( CGVfn *t=ea->vfn() ){ + args.push_back( genExp(t->self) ); + ea=t->exp; + } + + char buf[256]; + ea=genExp( ea,buf,EA_MEM|EA_IMM ); + + for( k=args.size()-1;k>=0;--k ){ + CGExp *arg=args[k],*p; + p=mem( arg->type,esp,arg_sz ); + arg_sz+=(arg->type==CG_FLOAT64) ? 8 : 4; + genMov( p,arg ); + args[k]=p; + } + + if( arg_sz>param_sz ) param_sz=arg_sz; +*/ + + CGReg *dst=t->isfloat() ? fp0 : eax; + + CGAsm *as=gen( mov(dst,jsr(t->type,t->call_conv,ea)),"\tcall\t%s\n",buf ); + + as->def.insert(EAX);as->def.insert(EDX);as->def.insert(ECX); + as->def.insert(FP0);as->def.insert(FP1);as->def.insert(FP2); + as->def.insert(FP3);as->def.insert(FP4);as->def.insert(FP5); + as->def.insert(FP6); + + CGReg *r=reg( t->type ); + genMov( r,dst ); + return r; +} + +CGReg *CGFrame_X86::genLit( CGLit *t ){ + + CGReg *r=reg(t->type); + + if( t->isfloat() ){ + double val=t->float_value; + if( val==0.0 || val==1.0 ){ + gen( mov(r,t),"\tmov\t'%i,%f\n",r->id,t->float_value ); + }else{ + CGDat *d=dat(); + d->push_back(t); + genMov( r,mem(t->type,d,0) ); + } + }else if( t->int_value==0 ){ + gen( mov(r,t),"\txor\t'%i,'%i\n",r->id,r->id ); + }else{ +// gen( mov(r,t),"\tmov\t'%i," FMTI64 "\n",r->id,t->int_value ); + char buf[64]; + strcpy( buf,fromint( t->int_value ).c_str() ); + gen( mov(r,t),"\tmov\t'%i,%s\n",r->id,buf ); + } + return r; +} + +CGReg *CGFrame_X86::genSym( CGSym *t ){ + CGReg *r=reg(t->type); + gen( mov(r,t),"\tmov\t'%i,%s\n",r->id,t->value.c_str() ); + return r; +} + +CGReg *CGFrame_X86::genFrm( CGFrm *t ){ + CGReg *r=reg(CG_PTR); + genMov( r,ebp ); + return r; +} + +void CGFrame_X86::genPush( CGExp *e ){ + if( e->type==CG_FLOAT32 ){ + if( CGLit *t=e->lit() ){ + float n=t->float_value; + e=lit( *(int*)&n ); + } + genPush4(e); + }else if( e->type==CG_FLOAT64 ){ + genPush8(e); + }else if( e->type==CG_INT8 || e->type==CG_INT16 ){ + if( e->mem() ) e=genExp(e); + genPush4(e); + }else{ + genPush4(e); + } +} + +void CGFrame_X86::genPush4( CGExp *e ){ + int ea=(e->type==CG_FLOAT64) ? 0 : EA_MEM|EA_IMM; + char buf[256]; + e=genExp( e,buf,ea ); + gen( xop(XOP_PUSH4,0,e),"\tpush\t%s\n",buf ); +} + +void CGFrame_X86::genPush8( CGExp *e ){ + CGReg *r=genExp( e ); + gen( xop(XOP_PUSH8,0,r),"\tpush\t'%i\n",r->id ); +} + +void CGFrame_X86::genPop( CGExp *e ){ + + if( CGLit *t=e->lit() ){ + if( !t->int_value ) return; + } + + char buf[256]; + e=genExp( e,buf,EA_MEM|EA_IMM ); + + if( buf[0]=='-' ){ + gen( xop(XOP_POP,0,e),"\tsub\tesp,%s\n",buf+1 ); + }else{ + gen( xop(XOP_POP,0,e),"\tadd\tesp,%s\n",buf ); + } +} + +void CGFrame_X86::genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *tgt ){ + + //use scc for FP + if( lhs->isfloat() ){ + lhs=genExp(lhs); + rhs=genExp(rhs); + gen( mov(eax,scc(cc,lhs,rhs)),"" ); + cc=CG_NE; + lhs=eax; + rhs=lit0; + } + + char lhs_buf[256],rhs_buf[256]; + lhs=genExp(lhs,lhs_buf,EA_MEM); + rhs=genExp(rhs,rhs_buf,lhs->mem() ? EA_IMM : EA_MEM|EA_IMM); + gen( + bcc(cc,lhs,rhs,tgt), + "\tcmp\t%s,%s\n" + "\tj%s\t%s\n", + lhs_buf,rhs_buf,x86cc(cc),tgt->value.c_str() ); +} + +void CGFrame_X86::genRet( CGExp *e ){ + CGReg *r=0; + if( e ){ + r=e->isfloat() ? fp0 : eax; + genMov(r,e); + } + CGAsm *as; + if( fun->call_conv==CG_CDECL ){ + as=gen( ret(r),"\tret\n" ); + }else{ + as=gen( ret(r),"\tret\t%i\n",arg_sz ); + } + as->use.insert( EBP ); +} + +string CGFrame_X86::fixSym( string id ){ + if( env_platform=="linux" ) return id; + return "_"+id; +} + +void CGFrame_X86::genStm( CGStm *s ){ + + if( CGAti *t=s->ati() ){ + char buf[256]; + CGMem *mem=genMem( t->mem,buf ); + gen( ati(mem),"\tinc\t%s\n",buf ); + }else if( CGAtd *t=s->atd() ){ + char buf[256]; + CGMem *mem=genMem( t->mem,buf ); + gen( atd(mem,t->sym),"\tdec\t%s\n\tjnz\t%s\n",buf,t->sym->value.c_str() ); + }else if( CGMov *t=s->mov() ){ + genMov( t->lhs,t->rhs ); + }else if( CGLab *t=s->lab() ){ + gen( t,"%s:\n",t->sym->value.c_str() ); + }else if( CGBra *t=s->bra() ){ + gen( t,"\tjmp\t%s\n",t->sym->value.c_str() ); + }else if( CGBcc *t=s->bcc() ){ + genBcc( t->cc,t->lhs,t->rhs,t->sym ); + }else if( CGEva *t=s->eva() ){ + if( t->exp->dat() ){ + gen( t,"" ); + }else{ + genExp( t->exp ); + } + }else if( CGRem *t=s->rem() ){ + gen( t,"\t;%s\n",t->comment.c_str() ); + }else if( CGRet *t=s->ret() ){ + genRet( t->exp ); + }else if( CGXop *t=s->xop() ){ + switch( t->op ){ + case XOP_PUSH4:genPush4(t->exp);break; + case XOP_PUSH8:genPush8(t->exp);break; + case XOP_POP:genPop(t->exp);break; + case XOP_CDQ:break; + default:assert(0); + } + }else{ + assert(0); + } +} + +void CGFrame_X86::genFun(){ + + if( CGExp *t=fun->self ){ + //get 'this' from stack + genMov( t,mem(CG_PTR,ebp,arg_sz+8) ); + arg_sz+=4; + } + + int k; + for( k=0;kargs.size();++k ){ + //get args from stack + CGExp *t=fun->args[k]; + int n=t->type==CG_FLOAT64 ? 8 :4; + genMov(t,mem(t->type,ebp,arg_sz+8)); + arg_sz+=n; + } + + for( k=0;kstms.size();++k ){ + genStm( fun->stms[k] ); + } +} + +CGMem *CGFrame_X86::allocLocal( int type ){ + int n=(type==CG_FLOAT64 || type==CG_INT64) ? 8 : 4; + local_sz+=n; + return mem(type,ebp,-local_sz); +} + +CGExp *CGFrame_X86::allocSpill( CGReg *r ){ + int sz=8; + if( fun->self ){ + if( r->equals(fun->self) ) return mem(CG_PTR,ebp,sz); + sz+=4; + } + int k; + for( k=0;kargs.size();++k ){ + CGExp *t=fun->args[k]; + if( r->equals(t) ) return mem(t->type,ebp,sz); + sz+=(t->type==CG_FLOAT64) ? 8 : 4; + } + return allocLocal( r->type ); +} + +void CGFrame_X86::finish(){ + fixFp(); +} + +CGFrame_X86::CGFrame_X86( CGFun *f,CGModule_X86 *m ):CGFrame(f),mod_x86(m){ + + arg_sz=0; + tmp_mem=0; + param_sz=0; + local_sz=0; + extern_jsrs=0; + + //int types map to reg bank 0 + reg_banks[CG_PTR]=0; + reg_banks[CG_INT8]=0; + reg_banks[CG_INT16]=0; + reg_banks[CG_INT32]=0; + reg_banks[CG_INT64]=-1; //no int64 regs! + + //int regs + eax=reg( CG_INT32,0,0 ); + edx=reg( CG_INT32,0,1 ); + ecx=reg( CG_INT32,0,2 ); + ebx=reg( CG_INT32,0,3 ); + esi=reg( CG_INT32,0,4 ); + edi=reg( CG_INT32,0,5 ); + ebp=reg( CG_INT32,0,6 ); + esp=reg( CG_INT32,0,7 ); + + reg_masks[0]=0x3f; //no ebp or esp! + + //int reg names + reg_names[0].push_back( "eax" ); + reg_names[0].push_back( "edx" ); + reg_names[0].push_back( "ecx" ); + reg_names[0].push_back( "ebx" ); + reg_names[0].push_back( "esi" ); + reg_names[0].push_back( "edi" ); + reg_names[0].push_back( "ebp" ); + reg_names[0].push_back( "esp" ); + + //float types map to bank 1 + reg_banks[CG_FLOAT32]=1; + reg_banks[CG_FLOAT64]=1; + + //float regs + fp0=reg( CG_FLOAT64,0,0 ); + fp1=reg( CG_FLOAT64,0,1 ); + fp2=reg( CG_FLOAT64,0,2 ); + fp3=reg( CG_FLOAT64,0,3 ); + fp4=reg( CG_FLOAT64,0,4 ); + fp5=reg( CG_FLOAT64,0,5 ); + fp6=reg( CG_FLOAT64,0,6 ); + + reg_masks[1]=0x7f; //no f7! + + //float reg names + reg_names[1].push_back( "fp0" ); + reg_names[1].push_back( "fp1" ); + reg_names[1].push_back( "fp2" ); + reg_names[1].push_back( "fp3" ); + reg_names[1].push_back( "fp4" ); + reg_names[1].push_back( "fp5" ); + reg_names[1].push_back( "fp6" ); +} diff --git a/_src/codegen/cgframe_x86.h b/_src/codegen/cgframe_x86.h new file mode 100644 index 0000000..87584f1 --- /dev/null +++ b/_src/codegen/cgframe_x86.h @@ -0,0 +1,78 @@ + +#ifndef CGFRAME_X86_H +#define CGFRAME_X86_H + +#include "cgframe.h" + +struct CGModule_X86; + +struct CGFrame_X86 : public CGFrame{ + + CGModule_X86 *mod_x86; + + int arg_sz,param_sz,local_sz,tmp_mem,extern_jsrs; + + enum{ + EA_IMM=1,EA_MEM=2 + }; + enum{ + XOP_CDQ=1,XOP_DIV, + XOP_PUSH4,XOP_PUSH8,XOP_POP + }; + enum{ + EAX,EDX,ECX,EBX,ESI,EDI,EBP,ESP, + FP0,FP1,FP2,FP3,FP4,FP5,FP6 + }; + + CGReg *eax,*edx,*ecx,*ebx,*esi,*edi,*ebp,*esp; + CGReg *fp0,*fp1,*fp2,*fp3,*fp4,*fp5,*fp6; + + CGMem* tmpMem( int type ); + + CGMem* optMem( CGMem *exp,char *buf ); + bool optMov( CGExp *lhs,CGExp *rhs ); + + CGMem* genMem( CGMem *exp,char *buf ); + CGExp* genExp( CGExp *exp,char *buf,int mask ); + + CGReg* genExp( CGExp *exp ); + CGReg* genLea( CGLea *exp ); + CGReg* genCvt( CGCvt *exp ); + CGReg* genUop( CGUop *exp ); + CGReg* genBop( CGBop *exp ); + CGReg* genScc( CGScc *exp ); + CGReg* genJsr( CGJsr *exp ); + CGReg* genMacJsr( CGJsr *exp ); + CGReg* genLit( CGLit *exp ); + CGReg* genSym( CGSym *exp ); + CGReg* genFrm( CGFrm *exp ); + + CGReg* genLoad( CGMem *exp ); + void genStore( CGMem *mem,CGExp *exp ); + void genCopy( CGReg *res,CGReg *exp ); + void genMov( CGExp *lhs,CGExp *rhs ); + + void genPush( CGExp *exp ); + void genPush4( CGExp *exp ); + void genPush8( CGExp *exp ); + void genPop( CGExp *exp ); + + void genBcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ); + void genRet( CGExp *exp ); + + void fixFp(); + + CGFrame_X86( CGFun *fun,CGModule_X86 *mod ); + + virtual string fixSym( string id ); + virtual void genFun(); + virtual void genStm( CGStm *stm ); + virtual CGMem *allocLocal( int type ); + virtual CGExp *allocSpill( CGReg *r ); + virtual void finish(); + + static const char *x86cc( int cg_cc ); + static const char *x86size( int cg_sz ); +}; + +#endif diff --git a/_src/codegen/cgint64.cpp b/_src/codegen/cgint64.cpp new file mode 100644 index 0000000..b3a78af --- /dev/null +++ b/_src/codegen/cgint64.cpp @@ -0,0 +1,266 @@ + +#include "cgstd.h" + +#include "cgframe.h" +#include "cgallocregs.h" +#include "cgutil.h" +#include "cgdebug.h" + +using namespace CG; + +static CGFun *func; +static CGFrame *frame; +static CGMem *i64_dummy; + +static void int32ToInt64( CGMem *m,CGExp *exp ){ + func->stms.push_back( mov(frame->int64lo(m),exp) ); + func->stms.push_back( mov(frame->int64hi(m),lit0) ); +} + +static CGExp *int64ToInt32( CGExp *exp ){ + if( CGLit *t=exp->lit() ){ + return lit((int)(t->int_value)); + }else if( CGMem *t=exp->mem() ){ + return frame->int64lo(t); + } + assert(0); + return 0; +} + +static void genInt64Stms( CGMem *m,CGExp *exp ){ + if( CGLit *t=exp->lit() ){ + //mov i64,lit + CGLit *lo=lit( (int)(t->int_value) ); + CGLit *hi=lit( (int)(t->int_value>>int64(32)) ); + func->stms.push_back( mov(frame->int64lo(m),lo) ); + func->stms.push_back( mov(frame->int64hi(m),hi) ); + }else if( CGMem *t=exp->mem() ){ + func->stms.push_back( mov(frame->int64lo(m),frame->int64lo(t)) ); + func->stms.push_back( mov(frame->int64hi(m),frame->int64hi(t)) ); + }else if( CGJsr *t=exp->jsr() ){ + CGJsr *e=jsr(CG_INT32,t->call_conv,t->exp ); + e->args.push_back( lea(m) ); + for( int k=0;kargs.size();++k ) e->args.push_back( t->args[k] ); + func->stms.push_back( eva(e) ); + }else if( CGUop *t=exp->uop() ){ + string f; + switch( t->op ){ + case CG_NEG:f="bbLongNeg";break; + case CG_NOT:f="bbLongNot";break; + case CG_ABS:f="bbLongAbs";break; + case CG_SGN:f="bbLongSgn";break; + default:assert(0); + } + CGJsr *e=jsr(CG_INT32,f); + e->args.push_back( lea(m) ); + e->args.push_back( t->exp ); + func->stms.push_back( eva(e) ); + }else if( CGBop *t=exp->bop() ){ + string f; + switch( t->op ){ + case CG_ADD:f="bbLongAdd";break; + case CG_SUB:f="bbLongSub";break; + case CG_MUL:f="bbLongMul";break; + case CG_DIV:f="bbLongDiv";break; + case CG_MOD:f="bbLongMod";break; + case CG_AND:f="bbLongAnd";break; + case CG_ORL:f="bbLongOrl";break; + case CG_XOR:f="bbLongXor";break; + case CG_SHL:f="bbLongShl";break; + case CG_SHR:f="bbLongShr";break; + case CG_SAR:f="bbLongSar";break; + case CG_MIN:f="bbLongMin";break; + case CG_MAX:f="bbLongMax";break; + default:assert(0); + } + CGJsr *e=jsr(CG_INT32,f); + e->args.push_back( lea(m) ); + e->args.push_back( t->lhs ); + e->args.push_back( t->rhs ); + func->stms.push_back( eva(e) ); + }else if( CGCvt *t=exp->cvt() ){ + CGExp *e=t->exp; + switch( e->type ){ + case CG_INT8: //int8 to int64 + int32ToInt64(m,cvt(CG_INT32,e)); + break; + case CG_INT16: //int16 to int64 + int32ToInt64(m,cvt(CG_INT32,e)); + break; + case CG_PTR: //ptr to int64 + int32ToInt64(m,e); + break; + case CG_INT32: //int32 to int64 + func->stms.push_back( eva(jsr(CG_INT32,"bbIntToLong",lea(m),e)) ); + break; + case CG_INT64: + break; + case CG_FLOAT32://float32 to int64 + func->stms.push_back( eva(jsr(CG_INT32,"bbFloatToLong",lea(m),cvt(CG_FLOAT64,e))) ); + break; + case CG_FLOAT64://float64 to int64 + func->stms.push_back( eva(jsr(CG_INT32,"bbFloatToLong",lea(m),e)) ); + break; + default: + assert(0); + } + }else{ + cout<mov() ){ + if( t->lhs->type==CG_INT64 ){ + CGMem *lhs=t->lhs->mem(); + assert( lhs ); + genInt64Stms( lhs,t->rhs ); + return stm; + } + }else if( CGEva *t=stm->eva() ){ + if( t->exp->type==CG_INT64 ){ + if( !i64_dummy ) i64_dummy=frame->allocLocal( CG_INT64 ); + genInt64Stms( i64_dummy,t->exp ); + return stm; + } + }else if( CGRet *t=stm->ret() ){ + if( frame->int64ret ){ + CGMem *lhs=mem(CG_INT64,frame->int64ret,0); + genInt64Stms( lhs,t->exp ); + func->stms.push_back( ret(0) ); + return stm; + } + }else if( CGBcc *t=stm->bcc() ){ + if( t->lhs->type==CG_INT64 ){ + func->stms.push_back( bcc(CG_NE,scc(t->cc,t->lhs,t->rhs),lit0,t->sym) ); + return stm; + } + } + func->stms.push_back( stm ); + return stm; + } +}; + +struct CGInt64ExpFixer : public CGVisitor{ + CGFrame *frame; + CGFun *fun; + + CGInt64ExpFixer( CGFrame *f ):frame(f),fun(frame->fun){} + + CGStm *visit( CGStm *stm ){ + func->stms.push_back( stm ); + return stm; + } + + CGExp *visit( CGExp *exp ){ + if( CGScc *t=exp->scc() ){ + if( t->lhs->type!=CG_INT64 ) return exp; + string f; + switch( t->cc ){ + case CG_LT:f="bbLongSlt";break; + case CG_GT:f="bbLongSgt";break; + case CG_LE:f="bbLongSle";break; + case CG_GE:f="bbLongSge";break; + case CG_EQ:f="bbLongSeq";break; + case CG_NE:f="bbLongSne";break; + default:assert(0); + } + CGJsr *e=jsr(CG_INT32,f,t->lhs,t->rhs); + return e; + }else if( CGCvt *t=exp->cvt() ){ + CGExp *e=t->exp; + if( e->type==CG_INT64 ){ + switch( t->type ){ + case CG_INT8: //int64 to int8 + return cvt(CG_INT8,int64ToInt32(e)); + case CG_INT16: //int64 to int16 + return cvt(CG_INT16,int64ToInt32(e)); + case CG_INT32: //int64 to int32 + return int64ToInt32(e); + case CG_INT64: + return e; + case CG_FLOAT32://int64 to float32 + return cvt(CG_FLOAT32,jsr(CG_FLOAT64,"bbLongToFloat",e)); + case CG_FLOAT64://int64 to float64 + return jsr(CG_FLOAT64,"bbLongToFloat",e); + } + assert(0); + } + } + if( exp->type!=CG_INT64 ) return exp; + if( exp->uop() || exp->bop() || exp->jsr() || exp->cvt() ){ + CGMem *m=frame->allocLocal( CG_INT64 ); + genInt64Stms( m,exp ); + return m; + } + return exp; + } +}; + +struct CGInt64ArgFixer : public CGVisitor{ + CGFrame *frame; + + CGInt64ArgFixer( CGFrame *f ):frame(f){} + + CGExp *visit( CGExp *exp ){ + if( CGJsr *t=exp->jsr() ){ + int k; + for( k=0;kargs.size();++k ){ + if( t->args[k]->type==CG_INT64 ) break; + } + if( k==t->args.size() ) return exp; + CGJsr *e=jsr( t->type,t->call_conv,t->exp ); + for( k=0;kargs.size();++k ){ + CGExp *arg=t->args[k]; + if( arg->type!=CG_INT64 ){ + e->args.push_back( arg ); + continue; + } + if( CGMem *t=arg->mem() ){ + e->args.push_back( frame->int64el(t,0) ); + e->args.push_back( frame->int64el(t,4) ); + }else if( CGLit *t=arg->lit() ){ + assert( t->type==CG_INT64 ); + int *p=(int*)&t->int_value; + e->args.push_back( lit(p[0]) ); + e->args.push_back( lit(p[1]) ); + }else{ + cout< stms; + + stms.clear(); + stms.swap( func->stms ); + CGInt64StmFixer stm_vis( this ); + for( k=0;kvisit( stm_vis ); + + stms.clear(); + stms.swap( func->stms ); + CGInt64ExpFixer exp_vis( this ); + for( k=0;kvisit( exp_vis ); + + CGInt64ArgFixer arg_vis( this ); + func=visitFun( func,arg_vis ); + + fun=func; +} diff --git a/_src/codegen/cgint64.h b/_src/codegen/cgint64.h new file mode 100644 index 0000000..3eb6a94 --- /dev/null +++ b/_src/codegen/cgint64.h @@ -0,0 +1,9 @@ + +#ifndef CGINT64_H +#define CGINT64_H + +#include "cgframe.h" + +#endif + + diff --git a/_src/codegen/cgintset.cpp b/_src/codegen/cgintset.cpp new file mode 100644 index 0000000..6efc60c --- /dev/null +++ b/_src/codegen/cgintset.cpp @@ -0,0 +1,59 @@ + +#include "cgstd.h" + +#include "cgintset.h" + +using namespace std; + +int CGIntSet::insert( int n ){ + int sz=size(); + set::insert(n); + return size()-sz; +} + +int CGIntSet::insert( const CGIntSet &t ){ + int sz=size(); + const_iterator it; + for( it=t.begin();it!=t.end();++it ){ + set::insert( *it ); + } + return size()-sz; +} + +int CGIntSet::xinsert( const CGIntSet &t,const CGIntSet &p ){ //insert elements in t NOT in p + int sz=size(); + const_iterator it; + for( it=t.begin();it!=t.end();++it ){ + int n=*it; + if( !p.count(n) ) set::insert(n); + } + return size()-sz; +} + +int CGIntSet::erase( int n ){ + return set::erase(n); +} + +int CGIntSet::erase( const CGIntSet &t ){ + int sz=size(); + const_iterator it; + for( it=t.begin();it!=t.end();++it ){ + set::erase( *it ); + } + return sz-size(); +} +int CGIntSet::xerase( const CGIntSet &t,const CGIntSet &p ){ //erase elements in t NOT in p + int sz=size(); + const_iterator it; + for( it=t.begin();it!=t.end();++it ){ + int n=*it; + if( !p.count(n) ) set::erase(n); + } + return sz-size(); +} + +CGIntSet::iterator CGIntSet::erase( iterator it ){ + iterator t=it++; + set::erase(t); + return it; +} diff --git a/_src/codegen/cgintset.h b/_src/codegen/cgintset.h new file mode 100644 index 0000000..e60b1c0 --- /dev/null +++ b/_src/codegen/cgintset.h @@ -0,0 +1,21 @@ + +#ifndef CGINTSET_H +#define CGINTSET_H + +struct CGIntSet : std::set{ + + int insert( int n ); + int insert( const CGIntSet &t ); + int xinsert( const CGIntSet &t,const CGIntSet &p ); + + int erase( int n ); + int erase( const CGIntSet &t ); + int xerase( const CGIntSet &t,const CGIntSet &p ); + + iterator erase( iterator it ); +}; + +typedef CGIntSet::iterator CGIntIter; +typedef CGIntSet::const_iterator CGIntCIter; + +#endif \ No newline at end of file diff --git a/_src/codegen/cgmodule.cpp b/_src/codegen/cgmodule.cpp new file mode 100644 index 0000000..613ce76 --- /dev/null +++ b/_src/codegen/cgmodule.cpp @@ -0,0 +1,86 @@ + +#include "cgstd.h" + +#include "cgmodule.h" + +CGModule::CGModule( ostream &o ):out(o){ +} + +CGModule::~CGModule(){ +} + +CGFrame *CGModule::createFrame( CGFun *fun ){ + CGFrame *f=frame(fun); + frames.push_back(f); + return f; +} + +struct CGSymFinder : public CGVisitor{ + + CGModule *module; + + CGSymFinder( CGModule *m ):module(m){} + + CGExp *visit( CGExp *exp ){ + if( CGSym *t=exp->sym() ){ + if( CGDat *d=t->dat() ){ + if( !module->dataSyms.count(d->value) ){ + module->datas.push_back(d); + module->dataSyms.insert( d->value ); + } + } + if( t->linkage==CG_IMPORT ) module->importSyms.insert( t->value ); + else if( t->linkage==CG_EXPORT ) module->exportSyms.insert( t->value ); + + } + return exp; + } +}; + +void CGModule::emitModule(){ + + CGSymFinder vis(this); + + int k; + for( k=0;kfun->sym; + if( sym->linkage==CG_EXPORT ) exportSyms.insert( sym->value ); + CGAsm *as; + for( as=f->assem.begin;as!=f->assem.end;as=as->succ ){ + CGStm *t=as->stm; + if( !t ) continue; + t->visit( vis ); + } + } + + set::iterator sym_it; + + //header + emitHeader(); + + //imports + for( sym_it=importSyms.begin();sym_it!=importSyms.end();++sym_it ){ + emitImport( *sym_it ); + } + + //exports + for( sym_it=exportSyms.begin();sym_it!=exportSyms.end();++sym_it ){ + emitExport( *sym_it ); + } + + //frames + for( k=0;k frames; + vector datas; + + set importSyms,exportSyms,dataSyms; + + CGModule( ostream &out ); + virtual ~CGModule(); + + CGFrame* createFrame( CGFun *f ); + void emitModule(); + + virtual CGFrame*frame( CGFun *fun )=0; + virtual void emitHeader()=0; + virtual void emitImport( string t )=0; + virtual void emitExport( string t )=0; + virtual void emitFrame( CGFrame *frame )=0; + virtual void emitData( CGDat *dat )=0; + virtual void emitFooter()=0; +}; + +/* +struct CGModule{ + + IdentSet externs; + IdentSet exports; + IdentSet imports; + + std::set datas; + + virtual ~CGModule(); + + virtual void emit(); + + virtual CGFrame* createFrame( CGFun *fun )=0; + virtual void flush()=0; +}; +*/ + +#endif \ No newline at end of file diff --git a/_src/codegen/cgmodule_ppc.cpp b/_src/codegen/cgmodule_ppc.cpp new file mode 100644 index 0000000..eda924c --- /dev/null +++ b/_src/codegen/cgmodule_ppc.cpp @@ -0,0 +1,207 @@ + +#include "cgstd.h" +#include "cgdebug.h" + +#include "cgmodule_ppc.h" + +CGModule_PPC::CGModule_PPC( ostream &o ):CGModule(o),fp_const(0){ +} + +void CGModule_PPC::setSeg( string t ){ + if( t==seg ) return; + seg=t; + out<<"\t."<(f); + assert(frame); + + setSeg( "text" ); + + //find callee-save regs + int k,max_int=12,max_flt=13; + + for( k=64;kregs.size();++k ){ + CGReg *r=frame->regs[k]; + if( r->isfloat() ){ + if( r->color>=14 && r->color<=31 && r->color>max_flt ) max_flt=r->color; + }else{ + if( r->color>=13 && r->color<=31 && r->color>max_int ) max_int=r->color; + } + } + + int int_save=max_int-12; + int flt_save=max_flt-13; + int save_sz=int_save*4+flt_save*8; + + int stack_sz=24+frame->param_sz+frame->local_sz+save_sz; + stack_sz=(stack_sz+15)&~15; + + //emit label + out<fun->sym->value<<":\n"; + + //setup frames + out<<"__LOCAL="<<(24+frame->param_sz)<<'\n'; + out<<"__FRAME="<assem.begin;as!=frame->assem.end;as=as->succ ){ + if( as->stm->ret() ){ + out<<"\tlwz\tr1,0(r1)\n"; + out<<"\tlwz\tr0,8(r1)\n"; + out<<"\tmtlr\tr0\n"; + //restore int regs + if( int_save ){ + out<<"\tlmw\tr"<<(32-int_save)<<","<<(-save_sz)<<"(r1)\n"; + } + //restore float regs + for( int k=flt_save-1;k>=0;--k ){ + out<<"\tlfd\tf"<<(k+14)<<","<<(-save_sz+int_save*4+k*8)<<"(r1)\n"; + } + } + + const char *p=as->assem; + if( !p ) continue; + + out<value<<":\n"; + + for( int k=0;kexps.size();++k ){ + + CGExp *e=d->exps[k]; + + if( CGLit *t=e->lit() ){ + if( t->type==CG_INT8 ){ + out<<"\t.byte\t"<int_value)<<'\n'; + }else if( t->type==CG_INT16 ){ + out<<"\t.short\t"<int_value)<<'\n'; + }else if( t->type==CG_INT32 ){ + out<<"\t.long\t"<int_value)<<'\n'; + }else if( t->type==CG_INT64 ){ + out<<"\t.long\t"<int_value>>int64(32))<<','<int_value)<<'\n'; + }else if( t->type==CG_FLOAT32 ){ + float f=t->float_value; + out<<"\t.long\t0x"<type==CG_FLOAT64 ){ + double f=t->float_value; + out<<"\t.long\t0x"<type==CG_CSTRING ){ + bstring s=t->string_value; + out<<"\t.asciz\t\""; + for( int k=0;ktype==CG_BSTRING ){ + bstring s=t->string_value; + out<<"\t.long\t"<type==CG_BINFILE ){ + string file=tostring(t->string_value); + ifstream is( file.c_str() ); + if( !is.good() ) fail( "Unable to read from file '%s'",file.c_str() ); + for(;;){ + char buf[16]; + is.read( buf,16 ); + int n=is.gcount(); + if( !n ) break; + out<<"\t.byte\t"; + for( int k=0;ktype==CG_LABEL ){ + out<string_value)<<":\n"; + }else{ + assert(0); + } + }else if( CGSym *t=e->sym() ){ + out<<"\t.long\t"<value<<'\n'; + }else if( CGLea *t=e->lea() ){ + CGMem *m=t->exp->mem(); + assert(m); + if( m->flags==1 ){ //PARAM + }else if( m->flags==2 ){ //LOCAL + out<<"\t.long\t"<offset<<'\n'; + }else if( CGSym *t=m->exp->sym() ){ + assert(t); + if( m->offset ){ + out<<"\t.long\t"<value<<'+'<offset<<'\n'; + }else{ + out<<"\t.long\t"<value<<'\n'; + } + }else{ + assert(0); + } + }else{ + cout<value<<":\n"; + out<<"\t.double\t0r4.50360177485414400000e15\n"; + } +} diff --git a/_src/codegen/cgmodule_ppc.h b/_src/codegen/cgmodule_ppc.h new file mode 100644 index 0000000..ec50528 --- /dev/null +++ b/_src/codegen/cgmodule_ppc.h @@ -0,0 +1,25 @@ + +#ifndef CGMODULE_PPC_H +#define CGMODULE_PPC_H + +#include "cgmodule.h" +#include "cgframe_ppc.h" + +struct CGModule_PPC : public CGModule{ + string seg; + CGSym* fp_const; + + CGModule_PPC( std::ostream &out ); + + void setSeg( string t ); + + CGFrame* frame( CGFun *fun ); + void emitHeader(); + void emitImport( string t ); + void emitExport( string t ); + void emitFrame( CGFrame *f ); + void emitData( CGDat *d ); + void emitFooter(); +}; + +#endif diff --git a/_src/codegen/cgmodule_x86.cpp b/_src/codegen/cgmodule_x86.cpp new file mode 100644 index 0000000..f611455 --- /dev/null +++ b/_src/codegen/cgmodule_x86.cpp @@ -0,0 +1,301 @@ + +#include "cgstd.h" + +#include "cgmodule_x86.h" +#include "cgfixfp_x86.h" + +static bool USE_NASM=false; //NASM doesn't seem to work at all + +CGModule_X86::CGModule_X86( ostream &o ):CGModule(o){ +} + +void CGModule_X86::setSeg( string t ){ + if( seg==t ) return; + seg=t; + if( USE_NASM ){ + out<<"\tsection\t."<(f); + assert( frame ); + + int k,n_use[7]={0}; + + for( k=0;kregs.size();++k ){ + CGReg *r=frame->regs[k]; + if( r->isint() && r->id>=14 && r->color>=0 && r->color<7 ) ++n_use[r->color]; + } + + if( frame->extern_jsrs ){ + n_use[3]=n_use[4]=n_use[5]=-1; + } + + int local_sz=frame->local_sz; + + //create frame + out<fun->sym->value<<":\n"; + + out<<"\tpush\tebp\n"; + out<<"\tmov\tebp,esp\n"; + emitSubEsp( local_sz ); + //push callee save + if( n_use[3] ) out<<"\tpush\tebx\n"; + if( n_use[4] ) out<<"\tpush\tesi\n"; + if( n_use[5] ) out<<"\tpush\tedi\n"; + + CGAsm *as; + + for( as=frame->assem.begin;as!=frame->assem.end;as=as->succ ){ + if( as->stm && as->stm->ret() ){ + //pop callee save + if( n_use[5] ) out<<"\tpop\tedi\n"; + if( n_use[4] ) out<<"\tpop\tesi\n"; + if( n_use[3] ) out<<"\tpop\tebx\n"; + out<<"\tmov\tesp,ebp\n"; + out<<"\tpop\tebp\n"; + } + + const char *p=as->assem; + if( !p ) continue; + + out<4096 ){ + out<<"\tsub\tesp,4092\n\tpush\teax\n"; + sz-=4096; + } + if( sz ) out<<"\tsub\tesp,"<(f); + assert( frame ); + + int k,n_use[7]={0}; + + for( k=0;kregs.size();++k ){ + CGReg *r=frame->regs[k]; + if( r->isint() && r->id>=14 && r->color>=0 && r->color<7 ) ++n_use[r->color]; + } + + int save_sz=8; //ret address+ebp + if( n_use[3] ) save_sz+=4; //ebx + if( n_use[4] ) save_sz+=4; //esi + if( n_use[5] ) save_sz+=4; //edi + + int local_sz=frame->local_sz; + int param_sz=frame->param_sz; + + int frame_sz=param_sz+local_sz+save_sz; + + frame_sz=(frame_sz+15)&~15; + + param_sz=frame_sz-(local_sz+save_sz); + + //create frame + out<fun->sym->value<<":\n"; + + //push ebp + out<<"\tpush\tebp\n"; + out<<"\tmov\tebp,esp\n"; + + if( save_sz>8 ){ + emitSubEsp( local_sz ); + if( n_use[3] ) out<<"\tpush\tebx\n"; + if( n_use[4] ) out<<"\tpush\tesi\n"; + if( n_use[5] ) out<<"\tpush\tedi\n"; + emitSubEsp( param_sz ); + }else{ + emitSubEsp( local_sz+param_sz ); + } + + CGAsm *as; + + for( as=frame->assem.begin;as!=frame->assem.end;as=as->succ ){ + if( as->stm && as->stm->ret() ){ + //pop callee save + if( save_sz>8 ){ + if( param_sz ) out<<"\tadd\tesp,"<assem; + if( !p ) continue; + + out<exps.size()==1 ){ + switch( d->exps[0]->type ){ + case CG_INT8: + case CG_CSTRING: + align=1; + break; + case CG_INT16: + align=2; + break; + case CG_INT64:case CG_FLOAT64: + align=8; + break; + } + } + if( align!=1 ){ + out<<"\talign\t"<value<<":\n"; + + for( int k=0;kexps.size();++k ){ + + CGExp *e=d->exps[k]; + + if( CGLit *t=e->lit() ){ + if( t->type==CG_INT8 ){ + out<<"\tdb\t"<int_value)<<'\n'; + }else if( t->type==CG_INT16 ){ + out<<"\tdw\t"<int_value)<<'\n'; + }else if( t->type==CG_INT32 ){ + out<<"\tdd\t"<int_value)<<'\n'; + }else if( t->type==CG_INT64 ){ + out<<"\tdd\t"<int_value)<<','<int_value>>int64(32))<<'\n'; + }else if( t->type==CG_FLOAT32 ){ + float f=t->float_value; + int n=*(int*)&f; + out<<"\tdd\t0x"<float_value; +// out<<"\tdd\t0x"<type==CG_FLOAT64 ){ + double f=t->float_value; + int64 n=*(int64*)&f; + out<<"\tdd\t0x"<>int64(32))<float_value; +//#if __APPLE__ && __BIG_ENDIAN__ +// out<<"\tdd\t0x"<type==CG_CSTRING ){ + bstring s=t->string_value; + out<<"\tdb\t\""; + for( int k=0;ktype==CG_BSTRING ){ + bstring s=t->string_value; + out<<"\tdd\t"<type==CG_BINFILE ){ + string file=tostring(t->string_value); + out<<"\tfile\t\""+file+"\"\n"; + }else if( t->type==CG_LABEL ){ + out<string_value)<<":\n"; + }else{ + assert(0); + } + }else if( CGSym *t=e->sym() ){ + out<<"\tdd\t"<value<<'\n'; + }else if( CGLea *t=e->lea() ){ + CGMem *m=t->exp->mem(); + assert(m); + if( CGReg *t=m->exp->reg() ){ + out<<"\tdd\t"<offset<<'\n'; + }else if( CGSym *t=m->exp->sym() ){ + assert(t); + if( m->offset ){ + out<<"\tdd\t"<value<<'+'<offset<<'\n'; + }else{ + out<<"\tdd\t"<value<<'\n'; + } + }else{ + assert(0); + } + }else{ + fail( "cgmodule_x86::emitData - unrecognized data format" ); + } + } +} + +void CGModule_X86::emitFooter(){ +} diff --git a/_src/codegen/cgmodule_x86.h b/_src/codegen/cgmodule_x86.h new file mode 100644 index 0000000..b970fbd --- /dev/null +++ b/_src/codegen/cgmodule_x86.h @@ -0,0 +1,26 @@ + +#ifndef CGMODULE_X86_H +#define CGMODULE_X86_H + +#include "cgmodule.h" +#include "cgframe_x86.h" + +struct CGModule_X86 : public CGModule{ + string seg; + + CGModule_X86( ostream &out ); + + void setSeg( string t ); + + CGFrame* frame( CGFun *fun ); + void emitHeader(); + void emitImport( string t ); + void emitExport( string t ); + void emitFrame( CGFrame *f ); + void emitMacFrame( CGFrame *f ); + void emitData( CGDat *d ); + void emitFooter(); + void emitSubEsp( int sz ); +}; + +#endif \ No newline at end of file diff --git a/_src/codegen/cgstd.h b/_src/codegen/cgstd.h new file mode 100644 index 0000000..40c424e --- /dev/null +++ b/_src/codegen/cgstd.h @@ -0,0 +1,2 @@ + +#include "../compiler/stdutil.h" diff --git a/_src/codegen/cgutil.cpp b/_src/codegen/cgutil.cpp new file mode 100644 index 0000000..d05c693 --- /dev/null +++ b/_src/codegen/cgutil.cpp @@ -0,0 +1,310 @@ + +#include "cgstd.h" + +#include "cgutil.h" + +static string _id(){ + char buf[32]; + static int n_id; + sprintf( buf,"_%i",++n_id ); + return buf; +} + +CGNop *CG::nop(){ + return new CGNop; +} + +CGXop *CG::xop( int op,CGReg *r,CGExp *exp ){ + CGXop *t=new CGXop; + t->op=op;t->def=r;t->exp=exp; + return t; +} + +CGRem *CG::rem( string comment ){ + CGRem *t=new CGRem; + t->comment=comment; + return t; +} + +CGAti *CG::ati( CGMem *mem ){ + CGAti *t=new CGAti; + t->mem=mem; + return t; +} + +CGAtd *CG::atd( CGMem *mem,CGSym *sym ){ + CGAtd *t=new CGAtd; + t->mem=mem;t->sym=sym; + return t; +} + +CGMov *CG::mov( CGExp *lhs,CGExp *rhs ){ + CGMov *t=new CGMov; + t->lhs=lhs;t->rhs=rhs; + return t; +} + +CGLab *CG::lab( CGSym *sym ){ + CGLab *t=new CGLab; + t->sym=sym ? sym : CG::sym(); + return t; +} + +CGBra *CG::bra( CGSym *sym ){ + CGBra *t=new CGBra; + t->sym=sym; + return t; +} + +CGBcc *CG::bcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ){ + CGBcc *t=new CGBcc; + t->cc=cc;t->lhs=lhs;t->rhs=rhs;t->sym=sym; + return t; +} + +CGRet *CG::ret( CGExp *exp ){ + CGRet *t=new CGRet; + t->exp=exp; + return t; +} + +CGEva *CG::eva( CGExp *exp ){ + CGEva *t=new CGEva; + t->exp=exp; + return t; +} + +CGSeq *CG::seq( const std::vector &stms ){ + CGSeq *t=new CGSeq; + t->stms=stms; + return t; +} + +CGSeq *CG::seq( CGStm *stm0,... ){ + CGSeq *t=new CGSeq; + if( !stm0 ) return t; + t->stms.push_back( stm0 ); + va_list args; + va_start( args,stm0 ); + while( CGStm *p=va_arg(args,CGStm*) ) t->stms.push_back(p); + return t; +} + +CGMem *CG::mem( int type,CGExp *exp,int offset ){ + CGMem *t=new CGMem; + t->type=type;t->exp=exp;t->offset=offset;t->flags=0; + return t; +} + +CGLea *CG::lea( CGExp *exp ){ + CGLea *t=new CGLea; + t->type=CG_INT32;t->exp=exp; + return t; +} + +CGCvt *CG::cvt( int type,CGExp *exp ){ + CGCvt *t=new CGCvt; + t->type=type;t->exp=exp; + return t; +} + +CGUop *CG::uop( int op,CGExp *exp ){ + CGUop *t=new CGUop; + t->type=exp->type;t->op=op;t->exp=exp; + return t; +} + +CGBop *CG::bop( int op,CGExp *lhs,CGExp *rhs ){ + CGBop *t=new CGBop; + t->type=lhs->type;t->op=op;t->lhs=lhs;t->rhs=rhs; + return t; +} + +CGJsr *CG::jsr( int type,int call_conv,CGExp *exp,const vector &args ){ + CGJsr *t=new CGJsr; + t->type=type;t->call_conv=call_conv;t->exp=exp;t->args=args; + return t; +} + +CGJsr *CG::jsr( int type,int call_conv,CGExp *exp,CGExp *a0,CGExp *a1,CGExp *a2,CGExp *a3 ){ + vector args; + if( a0 ) args.push_back(a0); + if( a1 ) args.push_back(a1); + if( a2 ) args.push_back(a2); + if( a3 ) args.push_back(a3); + return jsr( type,call_conv,exp,args ); +} + +CGJsr *CG::jsr( int type,string t_sym,const vector &args ){ + return jsr( type,CG_CDECL,sym(t_sym,CG_IMPORT),args ); +} + +CGJsr *CG::jsr( int type,string t_sym,CGExp *a0,CGExp *a1,CGExp *a2,CGExp *a3 ){ + vector args; + if( a0 ) args.push_back(a0); + if( a1 ) args.push_back(a1); + if( a2 ) args.push_back(a2); + if( a3 ) args.push_back(a3); + return jsr( type,t_sym,args ); +} + +CGVfn *CG::vfn( CGExp *exp,CGExp *self ){ + CGVfn *t=new CGVfn; + t->type=exp->type;t->exp=exp;t->self=self; + return t; +} + +CGScc *CG::scc( int cc,CGExp *lhs,CGExp *rhs ){ + CGScc *t=new CGScc; + t->type=CG_INT32;t->cc=cc;t->lhs=lhs;t->rhs=rhs; + return t; +} + +CGEsq *CG::esq( CGStm *lhs,CGExp *rhs ){ + CGEsq *t=new CGEsq; + t->type=rhs->type;t->lhs=lhs;t->rhs=rhs; + return t; +} + +CGFrm *CG::frm(){ + CGFrm *t=new CGFrm; + t->type=CG_PTR; + return t; +} + +CGLit *CG::lit( int val ){ + CGLit *t=new CGLit; + t->type=CG_INT32;t->int_value=val; + return t; +} + +CGLit *CG::lit( int64 val ){ + CGLit *t=new CGLit; + t->type=CG_INT64;t->int_value=val; + return t; +} + +CGLit *CG::lit( float val ){ + CGLit *t=new CGLit; + t->type=CG_FLOAT32;t->float_value=val; + return t; +} + +CGLit *CG::lit( double val ){ + CGLit *t=new CGLit; + t->type=CG_FLOAT64;t->float_value=val; + return t; +} + +CGLit *CG::lit( bstring val,int type ){ + CGLit *t=new CGLit; + t->type=type;t->string_value=val; + return t; +} + +CGTmp *CG::tmp( int type,string id ){ + CGTmp *t=new CGTmp; + t->type=type;t->ident=id.size() ? id : _id();t->owner=0; + return t; +} + +CGSym *CG::sym(){ + CGSym *t=new CGSym; + t->type=CG_INT32; + t->value=_id(); + t->linkage=CG_INTERNAL; + return t; +} + +CGSym *CG::sym( string id,int linkage ){ + CGSym *t=new CGSym; + t->type=CG_INT32; + t->value=id; + t->linkage=linkage; + return t; +} + +CGDat *CG::dat(){ + CGDat *t=new CGDat; + t->type=CG_INT32; + t->value=_id(); + t->linkage=CG_INTERNAL; + return t; +} + +CGDat *CG::dat( string id ){ + CGDat *t=new CGDat; + t->type=CG_INT32; + t->value=id; + t->linkage=CG_EXPORT; + return t; +} + +CGFun *CG::fun( int type,int call_conv,CGSym *sym,CGExp *self ){ + CGFun *t=new CGFun; + t->type=type;t->call_conv=call_conv;t->sym=sym;t->self=self; + return t; +} + +CGFun *CG::visitFun( CGFun *fun,CGVisitor &vis ){ + + int k; + CGFun *out=0; + bool copy=false; + vector args; + + CGSym *sym=fun->sym->visit( vis )->sym(); + CGExp *self=fun->self ? fun->self->visit( vis ) : 0; + if( sym!=fun->sym || self!=fun->self ) copy=true; + + for( k=0;kargs.size();++k ){ + args.push_back( fun->args[k]->visit( vis ) ); + if( args.back()!=fun->args[k] ) copy=true; + } + + CGStm *stm=0; + + for( k=0;;++k ){ + + if( copy ){ + out=CG::fun( fun->type,fun->call_conv,sym,self ); + out->args=args; + out->stms.reserve( fun->stms.size() ); + for( int j=0;jstms.push_back( fun->stms[j] ); + if( stm ) out->stms[out->stms.size()-1]=stm; + copy=false; + } + + if( k==fun->stms.size() ) break; + + stm=fun->stms[k]->visit( vis ); + + if( out ){ + out->stms.push_back( stm ); + }else{ + if( stm!=fun->stms[k] ) copy=true; + } + } + + return out ? out : fun; +} + +int CG::swapcc( int cg_cc ){ + switch( cg_cc ){ + case CG_EQ:return CG_NE; + case CG_NE:return CG_EQ; + case CG_LT:return CG_GE; + case CG_GT:return CG_LE; + case CG_LE:return CG_GT; + case CG_GE:return CG_LT; + case CG_LTU:return CG_GEU; + case CG_GTU:return CG_LEU; + case CG_LEU:return CG_GTU; + case CG_GEU:return CG_LTU; + } + assert(0); + return 0; +} + +CGLit *CG::lit0=CG::lit(0); +CGLit *CG::lit1=CG::lit(1); diff --git a/_src/codegen/cgutil.h b/_src/codegen/cgutil.h new file mode 100644 index 0000000..0ec4150 --- /dev/null +++ b/_src/codegen/cgutil.h @@ -0,0 +1,57 @@ + +#ifndef CGUTIL_H +#define CGUTIL_H + +#include "cgcode.h" + +namespace CG{ + CGNop* nop(); + CGXop* xop( int op,CGReg *def,CGExp *exp ); + CGRem* rem( string comment ); + CGAti* ati( CGMem *mem ); + CGAtd* atd( CGMem *mem,CGSym *sym ); + CGMov* mov( CGExp *lhs,CGExp *rhs ); + CGLab* lab( CGSym *sym=0 ); + CGBra* bra( CGSym *sym ); + CGBcc* bcc( int cc,CGExp *lhs,CGExp *rhs,CGSym *sym ); + CGRet* ret( CGExp *exp ); + CGEva* eva( CGExp *exp ); + CGSeq* seq( const std::vector &stms ); + CGSeq* seq( CGStm *stm0,... ); + + CGCvt* cvt( int type,CGExp *exp ); + CGMem* mem( int type,CGExp *exp,int offset=0 ); + CGUop* uop( int op,CGExp *exp ); + CGBop* bop( int op,CGExp *lhs,CGExp *rhs ); + CGScc* scc( int cc,CGExp *lhs,CGExp *rhs ); + CGJsr* jsr( int type,int call_conv,CGExp *exp,const std::vector &args ); + CGJsr* jsr( int type,int call_conv,CGExp *exp,CGExp *a0=0,CGExp *a1=0,CGExp *a2=0,CGExp *a3=0 ); + CGJsr* jsr( int type,string exp,const std::vector &args ); + CGJsr* jsr( int type,string exp,CGExp *a0=0,CGExp *a1=0,CGExp *a2=0,CGExp *a3=0 ); + CGVfn* vfn( CGExp *exp,CGExp *self ); + CGEsq* esq( CGStm *lhs,CGExp *rhs ); + CGLea* lea( CGExp *exp ); + + CGLit* lit( int val ); + CGLit* lit( int64 val ); + CGLit* lit( float val ); + CGLit* lit( double val ); + CGLit* lit( bstring val,int type=CG_BSTRING ); + + CGFrm* frm(); + CGSym* sym(); + CGSym* sym( string ident,int linkage ); + CGDat* dat(); + CGDat* dat( string ident ); + CGTmp* tmp( int type,string ident="" ); + + CGFun* fun( int type,int call_conv,CGSym *sym,CGExp *self ); + + CGFun* visitFun( CGFun *fun,CGVisitor &vis ); + + int swapcc( int cg_cc ); + + extern CGLit *lit0,*lit1; +} + +#endif \ No newline at end of file diff --git a/_src/codegen/codegen.cpp b/_src/codegen/codegen.cpp new file mode 100644 index 0000000..df23bf0 --- /dev/null +++ b/_src/codegen/codegen.cpp @@ -0,0 +1,77 @@ + +#include "cgstd.h" + +#include "codegen.h" +#include "cgdebug.h" +#include "cgallocregs.h" + +#include "cgmodule_x86.h" +#include "cgmodule_ppc.h" + +void cgGenCode( ostream &o,const vector &funs ){ + + CGModule *mod; + + if( opt_arch=="x86" ) mod=new CGModule_X86(o); + else if( opt_arch=="ppc" ) mod=new CGModule_PPC(o); + else fail( "No backend available" ); + + for( int k=0;ksym->value<createFrame( fun ); + +// cout<fun; + +// cout<<"FindEscapes"<findEscapes(); //local escaping tmps + + //cout<<"RenameTmps"<renameTmps(); //rename tmps->regs + + //cout<<"Linearize"<linearize(); //remove SEQ and ESQ nodes + + //cout<<"fixInt64"<fixInt64(); //rewrite int_64 code + + //cout<<"fixSymbols"<fixSymbols(); //fix symbols depending on platform + + //cout<<"preOptimize"<preOptimize(); //do some opts before asm gen + + //cout<<"genAssem"<genAssem(); + + //cout<<"createFlow"<createFlow(); + +// cout<assem; + + //cout<<"optDeadCode"<optDeadCode(); + + //cout<<"optDupLoads"<optDupLoads(); + +// cout<fun; +// cout<assem; + + //cout<<"allocRegs"<allocRegs(); + + frame->finish(); + + frame->deleteFlow(); + +// frame->peepOpt(); //BROKEN!!!!! + + //cout<assem; + } + + mod->emitModule(); +} diff --git a/_src/codegen/codegen.h b/_src/codegen/codegen.h new file mode 100644 index 0000000..fb37092 --- /dev/null +++ b/_src/codegen/codegen.h @@ -0,0 +1,10 @@ + +#ifndef CODEGEN_H +#define CODEGEN_H + +#include "cgcode.h" +#include "cgutil.h" + +void cgGenCode( ostream &o,const vector &funcs ); + +#endif \ No newline at end of file diff --git a/_src/compiler/bcc.cpp b/_src/compiler/bcc.cpp new file mode 100644 index 0000000..af371b0 --- /dev/null +++ b/_src/compiler/bcc.cpp @@ -0,0 +1,62 @@ + +#include "std.h" +#include "parser.h" +#include "output.h" +#include "config.h" + +using namespace CG; + +int main( int argc,char *argv[] ){ + + stdutil_init( argc,argv ); + + int demo_days=demoDays(); + + if( !opt_infile.size() ){ + if( demo_days<0 ){ + cout<<"BlitzMax Release Version "<=30 ){ + cout<<"BlitzMax demo has expired. Please visit www.blitzbasic.com to buy the full version of BlitzMax."< _funBlocks; +static vector _classBlocks; + +//******************** Block ********************** +Block::Block( Block *o ):outer(o),cg_debug(0){ + fun_block=outer ? outer->fun_block : 0; + cg_enter=CG::seq(0); + cg_leave=CG::seq(0); + debug_on=outer ? outer->debug_on : opt_debug; +} + +CGDat *Block::debugScope(){ + + if( cg_debug ) return cg_debug; + + int kind=0; + string name; + DeclSeq *scope=&decls; + + if( FunBlock *fun=dynamic_cast(this) ){ + kind=1; + name=fun->fun_decl ? fun->fun_decl->ident : stripall( opt_infile ); + }else if( ClassBlock *clas=dynamic_cast(this) ){ + kind=2; + scope=&clas->type->decls; + name=clas->class_decl->ident; + string meta=clas->class_decl->meta; + if( meta.size() ) name+="{"+meta+"}"; + }else{ + kind=3; + } + + CGDat *d=CG::dat(); + + d->push_back( lit(kind) ); //kind + if( name.size() ) d->push_back( genCString(name) ); //name + else d->push_back( lit0 ); + + if( FunBlock *fun=dynamic_cast(this) ){ + ClassBlock *clas=dynamic_cast(outer); + if( clas && fun->type->method() ){ + assert( fun->fun_scope->cg_exp->tmp() ); + d->push_back( CG::lit(2) ); + d->push_back( genCString("Self") ); + d->push_back( genCString(":"+clas->class_decl->ident) ); + d->push_back( lea(fun->fun_scope->cg_exp) ); + } + } + + for( int k=0;ksize();++k ){ + (*scope)[k]->debugDecl( d,kind ); + } + + d->push_back( lit0 ); + + return cg_debug=d; +} + +void Block::emit( Stm *t ){ + stms.push_back(t); +} + +void Block::emit( CGStm *t ){ + if( t ) fun_block->cg_fun->stms.push_back(t); +} + +void Block::decl( Decl *d ){ + decls.push_back(d); +} + +void Block::declLocal( Decl *d ){ + decls.push_back(d); + locals.push_back(d); +} + +Val *Block::linearizeRef( Val *v ){ + CGExp *e=v->cg_exp; + + if( !e->sideEffects() ) return v; + + while( CGEsq *t=e->esq() ){ + emit( t->lhs ); + e=t->rhs; + } + + if( e->tmp() ) return new Val( v->type,e ); + + CGMem *t=e->mem(); + if( !t ) fail( "Internal error: Can't linearize reference" ); + CGTmp *p=tmp(CG_PTR); + emit( mov(p,t->exp) ); + return new Val( v->type,mem(v->type->cgType(),p,t->offset) ); +} + +void Block::initRef( Val *lhs,Val *rhs ){ + if( !lhs->type->refType() ) fail( "initRef expecting ref type" ); + + if( !lhs->cg_exp->tmp() && !lhs->cg_exp->mem() ){ + cout<cg_exp<refCounted() ){ + rhs=rhs->retain(); + } + + emit( mov(lhs->cg_exp,rhs->cg_exp) ); +} + +void Block::assignRef( Val *lhs,Val *rhs ){ + + RefType *ref=lhs->type->refType(); + + if( !ref ) fail( "assignRef expecting ref type" ); + + if( !lhs->cg_exp->tmp() && !lhs->cg_exp->mem() ){ + cout<cg_exp<refCounted() ){ + emit( mov( lhs->cg_exp,rhs->cg_exp ) ); + return; + } + + //Release LHS AFTER evaluating and incing RHS + CGTmp *t=tmp(CG_PTR); + emit( mov( t,rhs->retain()->cg_exp ) ); + emit( lhs->release() ); + emit( mov( lhs->cg_exp,t ) ); +} + +void Block::initGlobalRef( Val *lhs,Val *rhs ){ + if( !lhs->type->refType() ) fail( "initGlobalRef expecting ref type" ); + if( !lhs->cg_exp->mem() ) fail( "initGlobalRef expecting mem exp" ); + + if( lhs->refCounted() ){ + rhs=rhs->retain(); + } + + static int init_bit; + static CGExp *init_var; + + init_bit<<=1; + if( !init_bit ){ + init_bit=1; + CGDat *d=dat(); + d->push_back(lit0); + init_var=mem(CG_INT32,d); + } + CGLit *init_lit=lit(init_bit); + + CGSym *t=sym(); + + emit( bcc(CG_NE,bop(CG_AND,init_var,init_lit),lit0,t) ); + emit( mov(lhs->cg_exp,rhs->cg_exp) ); + emit( mov(init_var,bop(CG_ORL,init_var,init_lit)) ); + emit( lab(t) ); +} + +Val *Block::find( string id ){ + Val *v; + Block *t; + for( t=this;t;t=t->outer ){ + if( v=t->_find( id,this ) ) return v; + } + return findGlobal( id ); +} + +Val *Block::_find( string id,Block *from ){ + Val *v=decls.find(id); + if( !v || !locals.find(id) ) return v; + return from && fun_block==from->fun_block ? v : 0; +} + +void Block::eval(){ + ClassBlock *clas=dynamic_cast(this); + + bool t_debug=opt_debug; + opt_debug=debug_on; + + emit( cg_enter ); + for( int k=0;ksource_info; + st->eval( this ); + } + emit( cg_leave ); + + opt_debug=t_debug; + + if( debug_on && !clas ){ + if( strictMode || dynamic_cast(this) ){ + cg_enter->push_back( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugEnterScope",CG_IMPORT),0),debugScope(),frm())) ); + cg_leave->push_front( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugLeaveScope",CG_IMPORT),0))) ); + } + } +} + +void Block::resolveBlocks(){ + int k; + for( k=0;k<_classBlocks.size();++k ) _classBlocks[k]->resolve(); + for( k=0;k<_funBlocks.size();++k ) _funBlocks[k]->resolve(); +} + +void Block::evalFunBlocks(){ + int k; + for( k=0;k<_funBlocks.size();++k ) _funBlocks[k]->eval(); +} + +void Block::evalClassBlocks(){ + int k; + for( k=0;k<_classBlocks.size();++k ) _classBlocks[k]->eval(); +} + +//****************** Loop Block ******************* +LoopBlock::LoopBlock( Block *o,string lab ):Block(o),label(lab){ + cont_sym=sym(); + exit_sym=sym(); + loop_sym=sym(); +} + +//**************** Function Block ***************** +FunBlock::FunBlock():Block(0), +fun_decl(0),fun_scope(0),ret_tmp(0),ret_sym(0),data_ptr(0),data_stms(0){ + fun_block=this; + sourceinfo=source_info; + _funBlocks.push_back( this ); + + type=new FunType( Type::int32,FunType::VOIDFUN ); + + string entry; + + if( opt_apptype.size() ){ + entry="_bb_main"; + }else if( opt_module.size() && (moduleIdent(opt_module)==stripall(opt_infile)) ){ + entry=mungModuleEntry( opt_module ); + }else{ + entry=mungObjectEntry( opt_infile ); + } + + CGSym *cg_sym=sym( entry,CG_EXPORT ); + + cg_fun=fun( CG_INT32,CG_CDECL,cg_sym,0 ); +} + +FunBlock::FunBlock( Block *o,string id,FunType *ty,bool pub,ExpSeq *defs ):Block(o), +type(ty),cg_fun(0),fun_scope(0),ret_tmp(0),ret_sym(0),data_ptr(0),data_stms(0){ + fun_block=this; + sourceinfo=source_info; + _funBlocks.push_back( this ); + + ClassBlock *class_blk=dynamic_cast(outer); + ClassType *class_ty=class_blk ? class_blk->type : 0; + + CGSym *cg_sym; + + if( pub ){ + if( class_blk ) cg_sym=sym( mungMember(class_blk->class_decl->ident,id),CG_EXPORT ); + else cg_sym=sym( mungGlobal(id),CG_EXPORT ); + }else{ + cg_sym=sym(); + } + + fun_decl=new FunDecl(id,type,cg_sym,outer,defs); + + if( class_ty ){ + class_ty->methods.push_back(fun_decl); + }else if( outer ){ + outer->decl(fun_decl); + if( pub ) publish( fun_decl ); + } +} + +void FunBlock::resolve(){ + source_info=sourceinfo; + + ClassBlock *class_blk=dynamic_cast(outer); + ClassType *class_ty=class_blk ? class_blk->type : 0; + + CGTmp *cg_self=0; + + if( class_ty ){ + if( type->method() ){ + cg_self=tmp(CG_PTR); + Val *class_val=new Val(class_ty,class_blk->class_decl->val->cg_exp); + fun_scope=new Val( new ObjectType(class_val),cg_self ); + }else{ + fun_scope=class_blk->class_decl->val; + } + } + + if( !cg_fun ){ + //create cg_fun + CGSym *cg_sym=fun_decl->val->cg_exp->sym(); + cg_fun=fun( type->return_type->cgType(),type->call_conv,cg_sym,cg_self ); + for( int k=0;kargs.size();++k ){ + cg_fun->args.push_back( tmp(type->args[k]->val->type->cgType()) ); + } + } + + //copy args to locals + for( int k=0;kargs.size();++k ){ + Decl *d=type->args[k]; + Type *ty=d->val->type; + CGExp *cg=cg_fun->args[k]; + int attrs=0; + if( VarType *t=ty->varType() ){ + ty=t->val_type; + cg=mem(ty->cgType(),cg,0); + } + Val *v=new Val( new RefType(ty,attrs),cg ); + declLocal( new Decl(d->ident,v) ); + } + + ret_sym=sym(); + ret_tmp=tmp( type->return_type->cgType() ); + + emit( new ReturnStm( (type->attrs&FunType::VOIDFUN) ? 0 : new NullExp() ) ); +} + +void FunBlock::eval(){ + + Block::eval(); + + //data statements? + if( data_ptr ){ + data_stms->push_back( lit0 ); + cg_enter->push_back( mov( mem(CG_PTR,data_ptr,0),data_stms ) ); + } + + //if main, prevent recursive startup + if( !outer ){ + CGDat *d=dat(); + d->push_back( lit0 ); + CGMem *m=mem(CG_INT32,d); + CGSym *t=sym(); + CGStm *s=seq( + bcc(CG_EQ,m,lit0,t), + ret(lit0), + lab(t), + mov(m,lit1), + 0 ); + cg_enter->push_front(s); + } + + cg_leave->push_front( lab(ret_sym) ); + emit( ret(ret_tmp) ); +} + +Val *FunBlock::_find( string id,Block *from ){ + + Val *v; + if( v=Block::_find( id,from ) ) return v; + if( !fun_scope ) return 0; + + //bit naughty! turn off debug for members of 'Self' + bool t_debug=debug_on; + debug_on=false; + v=fun_scope->find(id); + debug_on=t_debug; + return v; +} + +void FunBlock::genAssem(){ + vector cgfuns; + int k; + for( k=0;k<_funBlocks.size();++k ) cgfuns.push_back( _funBlocks[k]->cg_fun ); + string file=getdir(opt_infile)+"/.bmx/"+stripdir(opt_infile); + if( opt_apptype.size() ) file+="."+opt_apptype; + file+=config_mung+".s"; + ofstream out(file.c_str()); + cgGenCode( out,cgfuns ); + out.close(); +} + +void FunBlock::genInterface(){ + if( opt_apptype.size() ) return; + if( moduleIdent(opt_module)==stripall(opt_infile) ){ + string file=modulePath(opt_module,true)+"/"+moduleIdent(opt_module)+config_mung+".i"; + ofstream out(file.c_str()); + int k; + for( k=0;kpush_back( lit0 ); + + return data_ptr; +} + +CGDat *FunBlock::dataStms(){ + dataPtr(); + return data_stms; +} + +//******************* Type Block ****************** +ClassBlock::ClassBlock( Block *o,string id,ClassType *ty ):Block(o),type(ty){ + sourceinfo=source_info; + _classBlocks.push_back( this ); + + bool pub=(ty->attrs & ClassType::PRIVATE) ? false : true; + + CGDat *d; + if( pub ) d=dat( mungGlobal(id) ); + else d=dat(); + + class_decl=new Decl(id,type,d); + + FunType *ctor_ty=new FunType( Type::int32,FunType::METHOD|FunType::VOIDFUN ); + ctor=new FunBlock( this,"New",ctor_ty,true ); + ctor_new=new Block( ctor ); + field_ctors=new Block( ctor ); + field_ctors->debug_on=false; + ctor->emit( new CtorStm( this,ctor_new ) ); + + dtor=0; + dtor_delete=0; + + if( !opt_threaded ){ + makeDtor(); + } + + outer->decl( class_decl ); + + if( pub ){ + publish( class_decl ); + } +} + +void ClassBlock::makeDtor(){ + if( !dtor ){ + FunType *dtor_ty=new FunType( Type::int32,FunType::METHOD|FunType::VOIDFUN ); + dtor=new FunBlock( this,"Delete",dtor_ty,true ); + dtor->debug_on=false; + + dtor_delete=new Block(dtor); + dtor->emit( new DtorStm( this,dtor_delete ) ); + } +} + +void ClassBlock::resolve(){ + source_info=sourceinfo; + + CGDat *vtbl=class_decl->val->cg_exp->dat(); + + Val *super_val=type->superVal(); + CGExp *exts=super_val ? super_val->cg_exp : lit0; + + //construct vtable methods + vector stk; + for( ClassType *t=type;t;t=t->superClass() ) stk.push_back(t); + + vector vtbl_methods; + for( ;stk.size();stk.pop_back() ){ + ClassType *t=stk.back(); + for( int k=0;kmethods.size();++k ){ + Decl *d=t->methods[k]; + string id=tolower(d->ident); + + for( int j=0;jident) ) continue; + vtbl_methods[j]=d; + d=0;break; + } + if( d ) vtbl_methods.push_back(d); + } + } + + CGExp *db=debugScope(); + + vtbl->push_back( exts ); //super + vtbl->push_back( sym("bbObjectFree",CG_IMPORT) ); //free method! + vtbl->push_back( db ); //debug scope + vtbl->push_back( lit(type->sizeof_fields) ); //sizeof_fields + for( int k=0;kval; + vtbl->push_back( v->cg_exp ); + if( v->type->funType()->attrs & FunType::ABSTRACT ){ + if( type->attrs & ClassType::FINAL ){ + fail( "Abstract method '%s' in final type '%s'", + vtbl_methods[k]->ident.c_str(),class_decl->ident.c_str() ); + } + type->attrs|=ClassType::ABSTRACT; + } + } +} + +void ClassBlock::eval(){ + bool t_debug=opt_debug; + opt_debug=debug_on; + for( int k=0;ksource_info; + st->eval( this ); + } + //globals initialized: register type + //CGDat *name=genCString(class_decl->ident); + CGDat *vtbl=class_decl->val->cg_exp->dat(); + + emit( eva( jsr( CG_INT32,"bbObjectRegisterType",vtbl ) ) ); + + opt_debug=t_debug; +} + +void ClassBlock::decl( Decl *d ){ + decls.push_back(d); + type->decls.push_back(d); +} diff --git a/_src/compiler/block.h b/_src/compiler/block.h new file mode 100644 index 0000000..be16a26 --- /dev/null +++ b/_src/compiler/block.h @@ -0,0 +1,109 @@ + +#ifndef BLOCK_H +#define BLOCK_H + +#include "decl.h" + +struct Stm; +struct Block; +struct FunBlock; +struct LabelStm; + +struct Block : public Scope{ + Block *outer; + DeclSeq decls; + DeclSeq locals; + vector stms; + FunBlock *fun_block; + CGSeq *cg_enter,*cg_leave; + CGDat *cg_debug; + bool debug_on; + + Block( Block *outer ); + + CGDat* debugScope(); + + void emit( Stm *t ); + void emit( CGStm *t ); + void declLocal( Decl *d ); + + Val* linearizeRef( Val *v ); + void initRef( Val *lhs,Val *rhs ); + void assignRef( Val *lhs,Val *rhs ); + void initGlobalRef( Val *lhs,Val *rhs ); + + virtual void decl( Decl *d ); + + virtual Val* find( string id ); + virtual Val* _find( string id,Block *from ); + + virtual void eval(); + + static void resolveBlocks(); + static void evalFunBlocks(); + static void evalClassBlocks(); +}; + +struct LoopBlock : public Block{ + CGSym *cont_sym,*exit_sym,*loop_sym; + string label; + + LoopBlock( Block *outer,string lab ); +}; + +struct FunBlock : public Block{ + FunType* type; + Decl* fun_decl; + Val* fun_scope; + + map labels; + + CGDat* data_ptr; + CGDat* data_stms; + + CGFun* cg_fun; + CGTmp* ret_tmp; + CGSym* ret_sym; + + string sourceinfo; + + FunBlock(); + FunBlock( Block *outer,string id,FunType *ty,bool pub,ExpSeq *defs=0 ); + + virtual Val *_find( string id,Block *from ); + + void resolve(); + + virtual void eval(); + + CGTmp* gcTmp(); + + static void genAssem(); + static void genInterface(); + + CGDat* dataPtr(); + CGDat* dataStms(); +}; + +struct ClassBlock : public Block{ + ClassType *type; + Decl *class_decl; + FunBlock *ctor,*dtor; + Block *ctor_new; + Block *dtor_delete; + Block *field_ctors; + + string sourceinfo; + + ClassBlock( Block *outer,string id,ClassType *ty ); + + void makeDtor(); + + void resolve(); + + virtual void eval(); + + virtual void decl( Decl *d ); +}; + +#endif diff --git a/_src/compiler/config.cpp b/_src/compiler/config.cpp new file mode 100644 index 0000000..d3b326b --- /dev/null +++ b/_src/compiler/config.cpp @@ -0,0 +1,138 @@ + +#include "config.h" + +#include "std.h" + +#ifdef DEMO_VERSION + +#define BAD_DEMO 10000 + +//#define DEMO_SECS_PER_DAY 1 //(60*60*24) +#define DEMO_SECS_PER_DAY (60*60*24) + +#if _WIN32 + +int demoDays(){ + + static const char *key_path="SOFTWARE\\Blitz Research\\BlitzMax\\CurrentVersion\\Setup"; + + HKEY key; + char name[32]; + sprintf( name,"DriverKey%s",DEMO_VERSION ); + + string p=getenv( "COMSPEC" ); + int i=p.rfind( '\\' ); + if( i==string::npos ) return BAD_DEMO; + + p=p.substr( 0,i )+"\\PROTOC0L.IN"+DEMO_VERSION; + + if( RegOpenKeyEx( HKEY_LOCAL_MACHINE,key_path,0,KEY_READ|KEY_WRITE,&key )==ERROR_SUCCESS ){ + + if( FILE *f=fopen( p.c_str(),"rb" ) ){ + + char value[MAX_PATH]; + + fgets( value,MAX_PATH,f ); + fclose( f ); + string a=value; + + DWORD type,size=MAX_PATH; + LONG res=RegQueryValueEx( key,name,0,&type,(unsigned char*)value,&size ); + RegCloseKey( key ); + string b=value; + + if( res==ERROR_SUCCESS && a==b ){ + int64 then=toint( string(value) ); + double secs=difftime( time(0),time_t(then) ); + if( secs>=0 ) return (int)(secs/DEMO_SECS_PER_DAY); + } + } + + }else if( RegCreateKeyEx( HKEY_LOCAL_MACHINE,key_path,0,0,0,KEY_READ|KEY_WRITE,0,&key,0 )==ERROR_SUCCESS ){ + + if( FILE *f=fopen( p.c_str(),"rb" ) ){ + + fclose( f ); + + }else if( FILE *f=fopen( p.c_str(),"wb" ) ){ + + string t=fromint(int64(time(0))); + + int r=fputs( t.c_str(),f ); + fclose( f ); + + if( r>=0 ){ + LONG r=RegSetValueEx( key,name,0,REG_SZ,(unsigned char*)t.c_str(),t.size()+1 ); + RegCloseKey( key ); + if( r==ERROR_SUCCESS ) return 0; + } + } + + } + return BAD_DEMO; +} + +#elif __APPLE__ + +int demoDays(){ + + FILE *f; + FSRef fsref; + CFNumberRef num; + CFAbsoluteTime now,time1,time2; + char home[1024],as_dir[1024],sup_dir[1024],sup_file[1024],tmp[32]; + + sprintf( tmp,".version%s",DEMO_VERSION ); + + CFStringRef key=CFStringCreateWithCString( 0,tmp,kCFStringEncodingASCII ); + CFStringRef app=CFStringCreateWithCString( 0,"com.brl.bmx",kCFStringEncodingASCII ); + + FSFindFolder( kUserDomain,kVolumeRootFolderType,false,&fsref ); + FSRefMakePath( &fsref,(unsigned char *)home,1024 ); + + sprintf( as_dir,"%s/Library/Application Support",home ); + sprintf( sup_dir,"%s/Library/Application Support/Blitz Research",home ); + sprintf( sup_file,"%s/Library/Application Support/Blitz Research/%s",home,tmp ); + + time1=0; + if( num=(CFNumberRef)CFPreferencesCopyAppValue( key,app ) ){ + if( !CFNumberGetValue( num,kCFNumberFloat64Type,&time1 ) ) time1=0; + } + + time2=0; + if( f=fopen( sup_file,"rb") ){ + if( fread( &time2,8,1,f) !=1 ) time2=0; + fclose(f); + } + + now=CFAbsoluteTimeGetCurrent(); + + if( time1 && time2 ){ + if( fabs(time1-time2)<1 ){ + CFTimeInterval secs=now-time1; + if( secs>=0 ) return (int)(secs/DEMO_SECS_PER_DAY); + } + }else if( !time1 && !time2 ){ + mkdir( as_dir,0777 ); + mkdir( sup_dir,0777 ); + if( f=fopen( sup_file,"wb" ) ){ + if( fwrite( &now,8,1,f )==1 ){ + fclose( f ); + num=CFNumberCreate(0,kCFNumberFloat64Type,&now); + CFPreferencesSetAppValue( key,num,app ); + if( CFPreferencesAppSynchronize( app ) ) return 0; + } + fclose( f ); + } + } + return BAD_DEMO; +} +#endif + +#else + +int demoDays(){ + return -1; +} + +#endif diff --git a/_src/compiler/config.h b/_src/compiler/config.h new file mode 100644 index 0000000..02e3b23 --- /dev/null +++ b/_src/compiler/config.h @@ -0,0 +1,14 @@ + +#ifndef CONFIG_H +#define CONFIG_H + +//compiler version +#define BCC_VERSION "1.50" + +//identifier for demo - bump for fresh demo, disable for release +//#define DEMO_VERSION "5" + +//days demo has been going, returns -1 for not a demo +int demoDays(); + +#endif diff --git a/_src/compiler/config.h.bak b/_src/compiler/config.h.bak new file mode 100644 index 0000000..e5fdf77 --- /dev/null +++ b/_src/compiler/config.h.bak @@ -0,0 +1,14 @@ + +#ifndef CONFIG_H +#define CONFIG_H + +//compiler version +#define BCC_VERSION "1.49" + +//identifier for demo - bump for fresh demo, disable for release +//#define DEMO_VERSION "5" + +//days demo has been going, returns -1 for not a demo +int demoDays(); + +#endif diff --git a/_src/compiler/decl.cpp b/_src/compiler/decl.cpp new file mode 100644 index 0000000..def12c3 --- /dev/null +++ b/_src/compiler/decl.cpp @@ -0,0 +1,190 @@ + +#include "std.h" +#include "decl.h" +#include "exp.h" + +#include "../codegen/cgdebug.h" + +static vector _constDecls; +static vector _funDecls; + +//********************* Decl ********************** +Decl::Decl( string id,Val *v ):ident(id),val(v){ +} + +Decl::Decl( string id,Type *ty,CGExp *cg ):ident(id),val(new Val(ty,cg)){ +} + +void Decl::setMetaData( string meta ){ + this->meta=meta; +} + +string Decl::debugEncoding(){ + Type *t=val->type; + string e=t->encoding(); + if( e.size() && e[0]==':' && t->exObjectType() ) e='?'+e.substr(1); + if( meta.size() ){ + e+="{"+meta+"}"; + } + return e; +} + +void Decl::resolveDecls(){ + int k; + if( opt_verbose ) cout<<"Resolving const decls..."<resolve(); + if( opt_verbose ) cout<<"Resolving fun decls..."<resolve(); +} + +void Decl::debugDecl( CGDat *d,int blockKind ){ + + CGExp *e=val->cg_exp; + if( !e ) return; + + if( val->constant() ){ + if( val->type->numericType() || val->type->stringType() ){ + bstring t=val->stringValue(); + + d->push_back( CG::lit(1) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( genBBString2( t ) ); + + /* + CGDat *dt=CG::dat(); + dt->push_back( CG::sym("bbStringClass",CG_IMPORT) ); + dt->push_back( CG::lit(0x7ffffffe) ); //normally 0x7fffffff - 0x..fe indicates 'ignore for GC'. + dt->push_back( CG::lit(t,CG_BSTRING) ); + d->push_back( dt ); + */ + + /* + d->push_back( CG::lit(1) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( val->cast(Type::stringObject)->cg_exp ); + */ + + return; + } + } + + if( !val->type->refType() ){ + if( blockKind==2 && val->type->funType() ){ + //type method/function + int dt=7; + if( CGVfn *t=e->vfn() ){ + e=t->exp; + dt=6; + } + if( CGMem *t=e->mem() ){ + d->push_back( CG::lit( dt ) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( CG::lit( t->offset ) ); + }else if( CGSym *t=e->sym() ){ + d->push_back( CG::lit( dt ) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( t ); + } + } + return; + } + + if( CGTmp *t=e->tmp() ){ + d->push_back( CG::lit(2) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( CG::lea(t) ); + return; + } + + if( CGMem *t=e->mem() ){ + if( t->exp->tmp() ){ + if( blockKind==2 ){ + //field + d->push_back( CG::lit(3) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( CG::lit(t->offset) ); + }else{ + d->push_back( CG::lit(5) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( CG::lea(t->exp->tmp()) ); + } + return; + }else if( t->exp->sym() && !t->offset ){ + d->push_back( CG::lit(4) ); + d->push_back( genCString(ident) ); + d->push_back( genCString(debugEncoding()) ); + d->push_back( t->exp ); + return; + } + } + return; +} + +//***************** fun Decl ******************** +FunDecl::FunDecl( string id,FunType *ty,CGExp *cg,Scope *sc,ExpSeq *defs ):Decl( id,ty,cg ),scope(sc),defaults(defs){ + sourceinfo=source_info; + _funDecls.push_back( this ); +} + +void FunDecl::resolve(){ + + source_info=sourceinfo; + FunType *fun=val->type->funType(); + + ClassBlock *class_block=dynamic_cast(scope); + + if( class_block ){ + if( Val *v=class_block->type->findSuperMethod( ident ) ){ + FunType *t=v->type->funType(); + if( t->attrs & FunType::FINAL ){ + fail( "Final methods cannot be overridden" ); + } + if( !fun->extends(t) ){ + fail( "Overriding method differs by type" ); + } + } + } + + if( defaults ){ + int k; + for( k=0;ksize();++k ){ + Exp *e=(*defaults)[k]; + if( !e ) continue; + Val *v=e->eval(scope,fun->args[k]->val->type); + if( !v->constant() ) fail( "Function defaults must be constant" ); + fun->args[k]->val->cg_exp=v->cg_exp; + } + } + if( !val->cg_exp ){ + string id=ident; + if( fun->call_conv==CG_STDCALL ){ + int sz=0; + for( int k=0;kargs.size();++k ){ + int n=fun->args[k]->val->type->size(); + sz+=n>4 ? n : 4; + } + id+="@"+fromint(sz); + } + val->cg_exp=CG::sym( id,CG_IMPORT ); + } +} + +//****************** ConstDecl ********************* +ConstDecl::ConstDecl( string id,Type *ty,Scope *sc,Exp *e ):Decl(id,ty,0),scope(sc),exp(e){ + sourceinfo=source_info; + _constDecls.push_back(this); +} + +void ConstDecl::resolve(){ + source_info=sourceinfo; + Val *v=exp->eval(scope,val->type); + if( !v->constant() ) fail( "Constant initializers must be constant" ); + val->cg_exp=v->cg_exp; +} diff --git a/_src/compiler/decl.h b/_src/compiler/decl.h new file mode 100644 index 0000000..9e132de --- /dev/null +++ b/_src/compiler/decl.h @@ -0,0 +1,47 @@ + +#ifndef DECL_H +#define DECL_H + +#include "val.h" + +struct Exp; +struct ExpSeq; + +struct Decl{ + string ident; //real ident + Val* val; //value of decl + string meta; //meta data + + Decl( string id,Val *v ); + Decl( string id,Type *ty,CGExp *cg ); + + void debugDecl( CGDat *d,int blockKind ); + + void setMetaData( string meta ); + + string debugEncoding(); + + static void resolveDecls(); +}; + +struct FunDecl : public Decl{ + string sourceinfo; + Scope *scope; + ExpSeq *defaults; + + FunDecl( string id,FunType *ty,CGExp *cg,Scope *sc,ExpSeq *defs ); + + void resolve(); +}; + +struct ConstDecl : public Decl{ + string sourceinfo; + Scope *scope; + Exp *exp; + + ConstDecl( string id,Type *ty,Scope *sc,Exp *e ); + + void resolve(); +}; + +#endif \ No newline at end of file diff --git a/_src/compiler/declseq.cpp b/_src/compiler/declseq.cpp new file mode 100644 index 0000000..4def231 --- /dev/null +++ b/_src/compiler/declseq.cpp @@ -0,0 +1,19 @@ + +#include "std.h" +#include "declseq.h" +#include "decl.h" + +void DeclSeq::push_back( Decl *d ){ + if( !_map.insert( make_pair(tolower(d->ident),d->val) ).second ) dupid( d->ident ); + _vec.push_back(d); +} + +Val *DeclSeq::find( string id ){ + map::const_iterator it=_map.find(tolower(id)); + return it==_map.end() ? 0 : it->second; +} + +void DeclSeq::update( int i,Decl *d ){ + _vec[i]=d; + _map.find(tolower(d->ident))->second=d->val; +} diff --git a/_src/compiler/declseq.h b/_src/compiler/declseq.h new file mode 100644 index 0000000..99b2163 --- /dev/null +++ b/_src/compiler/declseq.h @@ -0,0 +1,21 @@ + +#ifndef DECLSEQ_H +#define DECLSEQ_H + +#include "scope.h" + +struct Val; +struct Decl; + +struct DeclSeq : public Scope{ + vector _vec; + map _map; + + void push_back( Decl *d ); + Val* find( string id ); + int size()const{ return _vec.size(); } + Decl* operator[]( int n )const{ return _vec[n]; } + void update( int i,Decl *d ); +}; + +#endif \ No newline at end of file diff --git a/_src/compiler/exp.cpp b/_src/compiler/exp.cpp new file mode 100644 index 0000000..40527da --- /dev/null +++ b/_src/compiler/exp.cpp @@ -0,0 +1,940 @@ + +#include "std.h" +#include "exp.h" +#include "toker.h" + +using namespace CG; + +//**************** Expression ********************* +Exp::~Exp(){ +} + +//internal eval +Val *Exp::_eval( Scope *sc ){ + fail( "TODO!" ); + return 0; +} + +Val *Exp::eval( Scope *sc ){ + return _eval(sc); +} + +Val *Exp::eval( Scope *sc,Type *ty ){ + Val *v=_eval(sc); + return v->cast(ty); +} + +Val *Exp::evalRef( Block *b ){ + Val *v=_eval(b); + if( !v->type->refType() ) fail( "Expression must be a variable" ); + v=b->linearizeRef(v); + return v; +} + +Val *Exp::evalInit( Scope *sc,Type *ty ){ + return _eval( sc )->initCast( ty ); +} + +//************ Expression sequence **************** +ExpSeq::ExpSeq(){ +} + +ExpSeq::~ExpSeq(){ +} + +//************** Cast Expression ****************** +Val *CastExp::_eval( Scope *sc ){ + Val *v=exp->eval(sc); + v=v->explicitCast( type ); + return v; +} + +//*************** Val Expression ****************** +Val *ValExp::_eval( Scope *sc ){ + return val; +} + +//************ Local Decl Expression ************** +Val *LocalDeclExp::_eval( Scope *sc ){ + + Block *b=dynamic_cast(sc); + assert(b); + + Val *v=new Val(type,tmp(type->cgType())); + Decl *d=new Decl( ident,v ); + + Val *i=Val::null(type); + FunBlock *func=b->fun_block; + + if( strictMode ){ + b->initRef( v,i ); + block->declLocal( d ); + }else{ + b->assignRef( v,i ); + func->declLocal( d ); + } + + if( !strictMode || opt_debug ){ + func->cg_enter->push_back( mov(v->cg_exp,i->cg_exp) ); + } + + return v; +} + +//************* Global Expression ***************** +Val *GlobalExp::_eval( Scope *sc ){ + Val *v=mainFun->find(ident); + if( !v ) badid( ident ); + return v; +} + +//************** Ident Expression ***************** +Val *IdentExp::_eval( Scope *sc ){ + Val *v=sc->find(ident); + + if( !v ){ + if( !strictMode ){ + if( Block *b=dynamic_cast(sc) ){ + FunBlock *f=b->fun_block; + Type *ty=new RefType(type ? type : Type::int32); + v=new Val(ty,tmp(ty->cgType())); + f->cg_enter->push_back( mov(v->cg_exp,(new Val(Type::null,0))->cast(ty)->cg_exp) ); + f->declLocal(new Decl(ident,v)); + return v; + } + } + badid(ident); + } + + if( !v->cg_exp ) fail( "Identifier '%s' is not a legal expression",ident.c_str() ); + + if( type ){ + Type *ty=v->type; + if( FunType *t=ty->funType() ) ty=t->return_type; + else if( ArrayType *t=ty->arrayType() ) ty=t->element_type; + if( !type->equals(ty) ) fail( "Identifier type does not match declared type" ); + } + + return v; +} + +//************** Member Expression **************** +Val *MemberExp::_eval( Scope *sc ){ + return rhs->eval( lhs->eval( sc ) ); +} + +//*************** Null Expression ***************** +Val *NullExp::_eval( Scope *sc ){ + return new Val( Type::null,0 ); +} + +//*************** Self Expression ***************** +Val *SelfExp::_eval( Scope *sc ){ + Block *b=dynamic_cast(sc); + Val *v=b ? b->fun_block->fun_scope : 0; + if( !v ) fail( "'Self' can only be used within methods" ); + return v; +} + +//************** Super Expression ***************** +Val *SuperExp::_eval( Scope *sc ){ + Block *b=dynamic_cast(sc); + Val *v=b ? b->fun_block->fun_scope : 0; + if( !v ) fail( "'Super' can only be used within methods" ); + return new SuperVal( v ); +} + +//*************** New Expression ****************** +Val *NewExp::_eval( Scope *sc ){ + + Val *v=exp->eval(sc); + + ClassType *t=v->type->classType(); + + if( !t ){ + ObjectType *o=v->type->objectType(); + if( !o ) fail( "Subexpression for 'New' must be a user defined type or object" ); + t=o->class_val->type->classType(); + assert(t); + v=new Val( t,mem(CG_PTR,v->cg_exp,0) ); + }else if( t->attrs & ClassType::ABSTRACT ){ + string tyname="?"; + if( IdentExp *ie=dynamic_cast(exp) ) tyname=ie->ident; + set ids; + while( t ){ + int k; + for( k=0;kmethods.size();++k ){ + Decl *d=t->methods[k]; + if( ids.count(d->ident) ) continue; + if( FunType *f=d->val->type->funType() ){ + if( f->attrs & FunType::ABSTRACT ){ + fail( "Unable to create new object of abstract type '%s' due to abstract method '%s'",tyname.c_str(),d->ident.c_str() ); + } + } + ids.insert(d->ident); + } + t=t->superClass(); + } + fail( "Unable to create new object of abstract type '%s'",tyname.c_str() ); + }else if( t->attrs & ClassType::EXTERN ){ + fail( "'New' can not be used to create extern objects" ); + } + + Type *type=new ObjectType(v); + v=new Val(type,jsr(CG_PTR,"bbObjectNew",v->cg_exp)); + return v; +} + +//************** Array Expression ***************** +Val *ArrayExp::_eval( Scope *sc ){ + + if( !type ){ + Val *v=exp->eval(sc); + type=v->type; + if( !type->classType() ) fail( "Subexpression for 'New array' must be a Type" ); + type=new ObjectType(v); + } + + ArrayType *arr=new ArrayType( type,dims.size() ); + + string e=type->encoding(); + if( e.size() && e[0]==':' && type->exObjectType() ) e='?'+e.substr(1); + + CGDat *d=dat(); + d->push_back( lit(tobstring(e),CG_CSTRING) ); + + CGJsr *cg; + if( dims.size()==1 ){ + cg=jsr(CG_PTR,"bbArrayNew1D",d,dims[0]->eval(sc,Type::int32)->cg_exp); + }else{ + cg=jsr(CG_PTR,"bbArrayNew",d,lit((int)dims.size()) ); + for( int k=0;kargs.push_back( dims[k]->eval(sc,Type::int32)->cg_exp ); + } + } + + Val *v=new Val(arr,cg); + return v; +} + +//************ AutoArray Expression *************** +Val *ArrayDataExp::_eval( Scope *sc ){ + if( !exps.size() ) return new Val( Type::null,0 ); + + int k; + Type *ty=0; + vector vals; + + for( k=0;keval(sc); + if( !v->type || v->type->nullType() ){ + fail( "Auto array element has no type" ); + } + if( !ty ){ + ty=v->type; + }else{ + if( !ty->equals(v->type) ) fail( "Auto array elements must have identical types" ); + } + vals.push_back( v ); + } + + vector stms; + + CGTmp *t=tmp(CG_PTR); + stms.push_back( mov(t,jsr(CG_PTR,"bbArrayNew1D",genCString(ty->encoding()),lit((int)vals.size()))) ); + + for( k=0;kcast( ty ); + if( ty->objectType() && !opt_threaded ){ + v=v->retain(); + } + stms.push_back( mov(mem(ty->cgType(),t,k*ty->size()+24),v->cg_exp) ); + } + + return new Val( new ArrayType(ty,1),esq( seq(stms),t ) ); +} + +//************ Intrinsic Expression *************** +Val *IntrinsicExp::_eval( Scope *sc ){ + if( toke==T_VARPTR ){ + if( type ) fail( "No return type permitted for 'Varptr'" ); + + Val *v=exp->eval(sc); + RefType *t=v->type->refType(); + if( !t ) fail( "Subexpression for 'Ptr' must be a variable" ); + + Type *type=new PtrType(t->val_type); + + return new Val(type,lea(v->cg_exp)); + + }else if( toke==T_LEN ){ + if( type && type->encoding()!="i" ) fail( "Return type for 'Len' must be Int" ); + + Val *v=exp->eval(sc); + if( v->type->stringType() ){ + if( v->constant() ) return new Val((int)v->stringValue().size()); + return new Val(Type::int32,mem(CG_INT32,v->cg_exp,8)); + }else if( v->type->arrayType() ){ + return new Val(Type::int32,mem(CG_INT32,v->cg_exp,20)); + } + return new Val(Type::int32,lit1); + + }else if( toke==T_SIZEOF ){ + if( type && type->encoding()!="i" ) fail( "Return type for 'SizeOf' must be Int" ); + + Val *v=exp->eval(sc); + if( v->type->stringType() ){ + if( v->constant() ) return new Val((int)v->stringValue().size()*2); + return new Val(Type::int32,bop(CG_MUL,mem(CG_INT32,v->cg_exp,8),lit(2))); + }else if( v->type->arrayType() ){ + return new Val(Type::int32,mem(CG_INT32,v->cg_exp,16)); + }else if( ObjectType *t=v->type->objectType() ){ + return new Val(Type::int32,lit(t->objectClass()->sizeof_fields-8)); + }else if( ClassType *t=v->type->classType() ){ + if( t->attrs & ClassType::EXTERN ){ + }else{ + return new Val(Type::int32,lit(t->sizeof_fields-8)); + } + } + return new Val(Type::int32,lit(v->type->size())); + + }else if( toke==T_CHR ){ + if( type && type->encoding()!="$" ) fail( "Return type for 'Chr' must be String" ); + + Val *v=exp->eval(sc,Type::int32); + if( v->constant() ){ + return new Val( bstring(1,(bchar_t)v->intValue()) ); + } + return new Val( Type::stringObject,jsr(CG_PTR,"bbStringFromChar",v->cg_exp) ); + + }else if( toke==T_ASC ){ + if( type && type->encoding()!="i" ) fail( "Return type for 'Asc' must be Int" ); + + Val *v=exp->eval(sc,Type::stringObject); + if( v->constant() ){ + if( v->stringValue().size() ) return new Val( (int)v->stringValue()[0] ); + return new Val(-1); + } + return new Val( Type::int32,jsr(CG_INT32,"bbStringAsc",v->cg_exp) ); + + }else if( toke==T_INCBINPTR ){ + if( type && type->encoding()!="*b" ) fail( "Return type for 'IncbinPtr' must be Byte Ptr" ); + + Val *v=exp->eval(sc,Type::stringObject); + return new Val( Type::bytePtr,jsr(CG_PTR,"bbIncbinPtr",v->cg_exp) ); + + }else if( toke==T_INCBINLEN ){ + if( type && type->encoding()!="i" ) fail( "Return type for 'IncbinLen' must be Int" ); + + Val *v=exp->eval(sc,Type::stringObject); + return new Val( Type::int32,jsr(CG_INT32,"bbIncbinLen",v->cg_exp) ); + + }else{ + + fail( "Internal error" ); + } + return 0; +} + +//************* ExpSeq Expression ***************** +Val *ExpSeqExp::_eval( Scope *sc ){ + assert(0); + return 0; +} + +Val *ExpSeqExp::invokeFun( Val *v,FunType *fun,Scope *sc ){ + + if( seq.size()>fun->args.size() ) fail( "Too many function parameters" ); + + vector args; + vector cg_args; + CGSeq *cleanup=CG::seq(0); + + int k; + for( k=0;kargs.size();++k ){ + Decl *d=fun->args[k]; + Type *ty=d->val->type; + if( keval(sc)->funArgCast(ty,cleanup); + args.push_back(t); + }else if( CGExp *e=d->val->cg_exp ){ + args.push_back( new Val(d->val->type,e) ); + }else{ + fail( "Missing function parameter '%s'",d->ident.c_str() ); + } + cg_args.push_back( args.back()->cg_exp ); + } + + Type *ty=fun->return_type; + CGExp *e=jsr( ty->cgType(),fun->call_conv,v->cg_exp,cg_args ); + + if( ty->cstringType() ){ + ty=Type::stringObject; + e=jsr( CG_PTR,"bbStringFromCString",e ); + }else if( ty->wstringType() ){ + ty=Type::stringObject; + e=jsr( CG_PTR,"bbStringFromWString",e ); + } + + if( cleanup->stms.size() ){ + CGTmp *t=tmp( ty->cgType() ); + CGSeq *tseq=CG::seq(0); + tseq->push_back( mov(t,e) ); + tseq->push_back( cleanup ); + e=esq( tseq,t ); + } + + return new Val( ty,e ); +} + +Val *ExpSeqExp::performCast( Val *lhs,Scope *sc ){ + + if( seq.size()!=1 ) fail( "Illegal subexpression for object cast" ); + + Val *rhs=seq[0]->eval(sc); + + return rhs->explicitCast( new ObjectType(lhs) ); +} + +Val *ExpSeqExp::indexString( Val *v,Scope *sc ){ + if( seq.size()!=1 ) fail( "Illegal subexpression for string index" ); + + CGExp *p=v->cg_exp; + + CGExp *e=seq[0]->eval( sc,Type::int32 )->cg_exp; + + if( opt_debug ){ + p=tmp(CG_PTR); + CGTmp *t=tmp(CG_INT32); + CGSym *q=sym(); + CGStm *stms=CG::seq( + mov(p,v->cg_exp), + mov(t,e), + bcc(CG_LTU,t,mem(CG_INT32,p,8),q), + eva(jsr(CG_INT32,"brl_blitz_ArrayBoundsError")), + lab(q), + 0 ); + e=esq(stms,t); + } + + e=cvt( CG_INT32,mem( CG_INT16,bop(CG_ADD,p,bop(CG_MUL,e,lit(2))),12 ) ); + return new Val(Type::int32,e); + +// Val *i=seq[0]->eval( sc,Type::int32 ); +// CGExp *e=cvt( CG_INT32,mem( CG_INT16,bop(CG_ADD,v->cg_exp,bop(CG_MUL,i->cg_exp,lit(2))),12 ) ); +// return new Val(Type::int32,e); +} + +Val *ExpSeqExp::indexArray( Val *v,ArrayType *arr,Scope *sc ){ + + if( arr->dims!=seq.size() ) fail( "Incorrect number of array dimensions" ); + + CGExp *cg_exp=v->cg_exp,*p=0; + + bool sidefx=cg_exp->sideEffects(); + if( sidefx ) cg_exp=tmp(CG_PTR); + + for( int k=0;keval(sc)->cast( Type::int32 ); + + CGExp *e=v->cg_exp; + + if( kelement_type; + + p=bop(CG_ADD,cg_exp,bop(CG_MUL,p,lit(ty->size()))); + + if( sidefx ) p=esq( mov(cg_exp,v->cg_exp),p ); + + p=mem(ty->cgType(),p,seq.size()*4+20); + + return new Val(ty,p); +} + +Val *ExpSeqExp::indexPointer( Val *v,Type *t,Scope *sc ){ + if( seq.size()!=1 ) fail( "Illegal subexpression for pointer index" ); + + Val *i=seq[0]->eval( sc,Type::int32 ); + CGExp *e=mem( t->cgType(), + bop(CG_ADD,v->cg_exp, + bop(CG_MUL,i->cg_exp,lit(t->size()))),0); + Type *type=new RefType(t); + return new Val(type,e); +} + +//************* Invoke Expression ***************** +Val *InvokeExp::_eval( Scope *sc ){ + Val *v=exp->eval(sc); + Type *type=v->type; + + if( FunType *t=type->funType() ){ + return invokeFun( v,t,sc ); + }else if( ClassType *t=type->classType() ){ + return performCast( v,sc ); + }else if( ArrayType *t=type->arrayType() ){ + if( !strictMode ) return indexArray( v,t,sc ); + } + if( !strictMode ){ + if( IdentExp *ie=dynamic_cast(exp) ){ + fail( "Identifier '%s' not found",ie->ident.c_str() ); + } + } + fail( "Expression of type '%s' cannot be invoked",type->toString().c_str() ); + return 0; +} + +//************** Index Expression ***************** +Val *IndexExp::_eval( Scope *sc ){ + + Val *v=exp->eval(sc); + Type *type=v->type; + + if( ArrayType *t=type->arrayType() ){ + return indexArray( v,t,sc ); + }else if( PtrType *t=type->ptrType() ){ + return indexPointer( v,t->val_type,sc ); + }else if( type->stringType() ){ + return indexString( v,sc ); + } + fail( "Expression of type '%s' cannot be indexed",type->toString().c_str() ); + return 0; +} + +//************** Slice Expression ***************** +Val *SliceExp::_eval( Scope *sc ){ + + Val *v=exp->eval(sc); + + ArrayType *arr=v->type->arrayType(); + StringType *str=v->type->stringType(); + + if( (!arr && !str) || (arr && arr->dims!=1) ) fail( "Slices can only be used with strings or one dimensional arrays" ); + + CGExp *e=v->cg_exp,*t=0; + if( !rhs && v->cg_exp->sideEffects() ){ + t=e; + e=tmp(CG_PTR); + } + + CGExp *l=lhs ? lhs->eval(sc,Type::int32)->cg_exp : lit0; + CGExp *r=rhs ? rhs->eval(sc,Type::int32)->cg_exp : mem(CG_INT32,e,arr ? 20 : 8); + + if( str ){ + l=jsr(CG_PTR,"bbStringSlice",e,l,r); + }else{ + CGExp *ty=genCString( arr->element_type->encoding() ); + l=jsr(CG_PTR,"bbArraySlice",ty,e,l,r); + } + + Type *ty=v->type; + if( RefType *r=ty->refType() ) ty=r->val_type; + + if( !t ) return new Val( ty,l ); + + return new Val( ty,esq(mov(e,t),l) ); +} + +//************* Compare Expression **************** +Val *CmpExp::_eval( Scope *sc ){ + + Val *l=lhs->eval(sc); + Val *r=rhs->eval(sc); + + if( l->type->ptrType() && r->type->nullType() ) r=r->cast(l->type); + else if( r->type->ptrType() && l->type->nullType() ) l=l->cast(r->type); + + if( PtrType *px=l->type->ptrType() ){ + if( PtrType *py=r->type->ptrType() ){ + if( px->val_type->equals( py->val_type ) ){ + int cgop; + switch( op ){ + case T_LT:cgop=CG_LT;break; + case T_EQ:cgop=CG_EQ;break; + case T_GT:cgop=CG_GT;break; + case T_LE:cgop=CG_LE;break; + case T_GE:cgop=CG_GE;break; + case T_NE:cgop=CG_NE;break; + } + return new Val(Type::int32,scc(cgop,l->cg_exp,r->cg_exp)); + } + } + } + + if( l->type->ptrType() || r->type->ptrType() ){ + fail( "Pointer type mismatch" ); + } + + Type *ty=l->balance(r); + + if( ty->numericType() ){ + }else if( ty->stringType() ){ + }else if( ObjectType *obj=ty->objectType() ){ + if( op!=T_EQ && op!=T_NE ) fail( "Operator '%s' cannot be applied to objects",Toker::toString(op).c_str() ); + }else if( ObjectType *obj=ty->exObjectType() ){ + if( op!=T_EQ && op!=T_NE ) fail( "Operator '%s' cannot be applied to extern objects",Toker::toString(op).c_str() ); + }else if( FunType *fun=ty->funType() ){ + if( (op!=T_EQ && op!=T_NE) || (fun->attrs & FunType::METHOD) ){ + const char *p=(fun->attrs & FunType::METHOD) ? "methods" : "functions"; + fail( "Operator '%s' cannot be applied to %s",Toker::toString(op).c_str(),p ); + } + }else if( ty->nullType() ){ + if( op!=T_EQ && op!=T_NE ) fail( "Operator '%s' cannot be applied to 'Null'",Toker::toString(op).c_str() ); + return new Val( op==T_EQ ? 1 : 0); + }else{ + fail( "Operands cannot be compared" ); + } + + l=l->cast(ty); + r=r->cast(ty); + + if( l->constant() && r->constant() ){ + int z; + if( ty->intType() ){ + int64 x=l->intValue(),y=r->intValue(); + switch(op){ + case T_LT:z=xy;break; + case T_LE:z=x<=y;break; + case T_GE:z=x>=y;break; + case T_NE:z=x!=y;break; + } + }else if( ty->floatType() ){ + double x=l->floatValue(),y=r->floatValue(); + switch(op){ + case T_LT:z=xy;break; + case T_LE:z=x<=y;break; + case T_GE:z=x>=y;break; + case T_NE:z=x!=y;break; + } + }else if( ty->stringType() ){ + bstring x=l->stringValue(),y=r->stringValue(); + switch(op){ + case T_LT:z=xy;break; + case T_LE:z=x<=y;break; + case T_GE:z=x>=y;break; + case T_NE:z=x!=y;break; + } + }else{ + fail( "Operands cannot be compared" ); + } + return new Val(z); + } + + int cgop; + switch( op ){ + case T_LT:cgop=CG_LT;break; + case T_EQ:cgop=CG_EQ;break; + case T_GT:cgop=CG_GT;break; + case T_LE:cgop=CG_LE;break; + case T_GE:cgop=CG_GE;break; + case T_NE:cgop=CG_NE;break; + } + + Val *t; + if( ty->stringType() ){ + t=new Val(Type::int32,scc(cgop,jsr(CG_INT32,"bbStringCompare",l->cg_exp,r->cg_exp),lit0)); + }else{ + t=new Val(Type::int32,scc(cgop,l->cg_exp,r->cg_exp)); + } + return t; +} + +//************ Short Circuit Expression *********** +Val *ShortCircExp::_eval( Scope *sc ){ + + Val *lv=lhs->eval(sc)->cond(); + Val *rv=rhs->eval(sc)->cond(); + + int cg_op=op==T_AND ? CG_EQ : CG_NE; + + //result reg + CGSym *e=sym(); + CGTmp *r=tmp(CG_INT32); + + CGStm *stms=seq( + mov(r,lv->cg_exp), + bcc(cg_op,r,lit0,e), + mov(r,rv->cg_exp), + lab(e), + 0 ); + + return new Val(Type::int32,esq(stms,r)); +} + +//***************** Not Expression **************** +Val *NotExp::_eval( Scope *sc ){ + + Val *v=exp->eval(sc)->cond(); + + if( v->constant() ) return new Val( !v->intValue() ); + + return new Val(Type::int32,scc(CG_EQ,v->cg_exp,lit0)); +} + +//**************** Unary Expression *************** +Val *UnaryExp::_eval( Scope *sc ){ + Val *v=exp->eval(sc); + Type *ty=v->type; + + if( !ty->numericType() ){ + fail( "Subexpression for '%s' must be of numeric type",Toker::toString(op).c_str() ); + } + + switch( op ){ + case '+': + return v; + case '~': + if( !v->type->intType() ) fail( "Bitwise complement can only be used with integers" ); + if( v->type->cgType()!=CG_INT64 ) v=v->cast( Type::int32 ); + break; + } + + ty=v->type; + + if( v->constant() ){ + if( ty->intType() ){ + int64 n=v->intValue(); + switch( op ){ + case '-':n=-n;break; + case '~':n=~n;break; + case T_ABS:n=(n>=0) ? n : -n;break; + case T_SGN:n=(n==0) ? 0 : (n>0 ? 1 : -1);break; + default:assert(0); + } + return new Val(n,ty); + }else{ + double n=v->floatValue(); + switch( op ){ + case '-':n=-n;break; + case T_ABS:n=fabs(n);break; + case T_SGN:n=(n==0) ? 0 : (n>0 ? 1 : -1);break; + default:assert(0); + } + return new Val(n,ty); + } + assert(0); + } + + int cgop; + switch( op ){ + case '-':cgop=CG_NEG;break; + case '~':cgop=CG_NOT;break; + case T_ABS:cgop=CG_ABS;break; + case T_SGN:cgop=CG_SGN;break; + default:assert(0); + } + + return new Val(ty,uop(cgop,v->cg_exp)); +} + +//**************** Arith Expression *************** +Val *ArithExp::pointerArith( Val *lv,Val *rv ){ + + PtrType *lp=lv->type->ptrType(); + PtrType *rp=rv->type->ptrType(); + PtrType *ty=lp ? lp : rp; + + CGLit *sz=lit( ty->val_type->size() ); + + if( lp && rp ){ + if( op!='-' ) fail( "Illegal pointer arithmetic operator" ); + if( !lp->equals(rp) ) fail( "Pointer types are not equivalent" ); + CGExp *e=bop(CG_DIV,bop(CG_SUB,lv->cg_exp,rv->cg_exp),sz); + return new Val(Type::int32,e); + } + CGExp *e=0; + if( lp ){ + rv=rv->cast(Type::int32); + if( op=='+' ) e=bop(CG_ADD,lv->cg_exp,bop(CG_MUL,rv->cg_exp,sz)); + else if( op=='-' ) e=bop(CG_SUB,lv->cg_exp,bop(CG_MUL,rv->cg_exp,sz)); + }else{ + lv=lv->cast(Type::int32); + if( op=='+' ) e=bop(CG_ADD,rv->cg_exp,bop(CG_MUL,lv->cg_exp,sz)); + } + if( !e ) fail( "Illegal pointer arithmetic operator" ); + return new Val( ty,e ); +} + +Val *ArithExp::_eval( Scope *sc ){ + Val *l=lhs ? lhs->eval(sc) : lhs_val; + Val *r=rhs ? rhs->eval(sc) : rhs_val; + + if( l->type->ptrType() || r->type->ptrType() ) return pointerArith(l,r); + + Type *ty=0; + + if( op=='^' ){ + ty=Type::float64; + }else if( ArrayType *p=l->type->arrayType() ){ + if( ArrayType *q=r->type->arrayType() ){ + if( p->dims==q->dims ){ + if( p->element_type->equals( q->element_type ) ){ + ty=p; + }else if( ObjectType *pt=p->element_type->objectType() ){ + if( ObjectType *qt=q->element_type->objectType() ){ + if( pt->extends(qt) ){ + ty=q; + }else if( qt->extends(pt) ){ + ty=p; + }else{ + ty=new ArrayType( Type::objectObject,p->dims ); + } + } + } + } + } + } + + if( !ty ) ty=l->balance(r); + + if( ty->nullType() ){ + fail( "Operator '%s' cannot be used with null",Toker::toString(op).c_str() ); + }else if( ty->arrayType() ){ + if( op!='+' ) fail( "Operator '%s' can not be used with arrays",Toker::toString(op).c_str() ); + }else if( ty->stringType() ){ + if( op!='+' ) fail( "Operator '%s' can not be used with strings",Toker::toString(op).c_str() ); + + }else if( !ty->numericType() ){ + fail( "Operator '%s' can only be used with numeric types",Toker::toString(op).c_str() ); + } + + l=l->cast(ty); + r=r->cast(ty); + + if( l->constant() && r->constant() ){ + if( ty->intType() ){ + int64 x=l->intValue(),y=r->intValue(); + switch( op ){ + case '+':x+=y;break; + case '-':x-=y;break; + case '*':x*=y;break; + case '/':if( !y ) fail( "Integer division by zero" );x/=y;break; + case '^':x=(int)pow((double)x,(double)y);break; + case T_MOD:if( !y ) fail( "Integer division by zero" );x%=y;break; + case T_MIN:x=xy ? x : y;break; + default:assert(0); + } + return new Val(x,ty); + }else if( ty->floatType() ){ + double x=l->floatValue(),y=r->floatValue(); + switch( op ){ + case '+':x+=y;break; + case '-':x-=y;break; + case '*':x*=y;break; + case '/':x/=y;break; + case '^':x=pow(x,y);break; + case T_MOD:x=fmod(x,y);break; + case T_MIN:x=xy ? x : y;break; + default:assert(0); + } + return new Val(x,ty); + }else if( ty->stringType() ){ + bstring x=l->stringValue(),y=r->stringValue(); + switch( op ){ + case '+':x+=y;break; + default:assert(0); + } + return new Val(x); + } + assert(0); + } + + if( ArrayType *t=ty->arrayType() ){ + if( l->type->arrayType()->dims!=1 || r->type->arrayType()->dims!=1 ){ + fail( "Multi-dimensional arrays can not be concatenated" ); + } + CGExp *e=jsr(CG_PTR,"bbArrayConcat",genCString(t->element_type->encoding()),l->cg_exp,r->cg_exp ); + return new Val(ty,e); + } + + if( ty->stringType() ){ + CGExp *e=jsr(CG_PTR,"bbStringConcat",l->cg_exp,r->cg_exp ); + return new Val(ty,e); + } + + if( op=='^' ){ + CGExp *e=jsr(CG_FLOAT64,"bbFloatPow",l->cg_exp,r->cg_exp ); + return new Val(ty,e); + } + + int cgop; + switch( op ){ + case '+':cgop=CG_ADD;break; + case '-':cgop=CG_SUB;break; + case '*':cgop=CG_MUL;break; + case '/':cgop=CG_DIV;break; + case T_MOD:cgop=CG_MOD;break; + case T_MIN:cgop=CG_MIN;break; + case T_MAX:cgop=CG_MAX;break; + default:assert(0); + } + + return new Val(ty,bop(cgop,l->cg_exp,r->cg_exp)); +} + +//*************** Bitwise Expression ************** +Val *BitwiseExp::_eval( Scope *sc ){ + + Val *l=lhs ? lhs->eval(sc) : lhs_val; + Val *r=rhs ? rhs->eval(sc) : rhs_val; + + if( !l->type->intType() || !r->type->intType() ) fail( "Bitwise operators can only be used with integers" ); + + Type *ty=Type::int32; + if( l->type->cgType()==CG_INT64 || r->type->cgType()==CG_INT64) ty=Type::int64; + + l=l->cast(ty); + r=r->cast(ty); + + if( l->constant() && r->constant() ){ + int64 x=l->intValue(),y=r->intValue(); + switch( op ){ + case '&':x&=y;break; + case '|':x|=y;break; + case '~':x^=y;break; + case T_SHL:x<<=y;break; + case T_SAR:x>>=y;break; + case T_SHR:x=(unsigned)x>>(unsigned)y;break; + default:assert(0); + } + return new Val(x,ty); + } + + int cgop; + switch( op ){ + case '&':cgop=CG_AND;break; + case '|':cgop=CG_ORL;break; + case '~':cgop=CG_XOR;break; + case T_SHL:cgop=CG_SHL;break; + case T_SHR:cgop=CG_SHR;break; + case T_SAR:cgop=CG_SAR;break; + default:assert(0); + } + + return new Val(ty,bop(cgop,l->cg_exp,r->cg_exp)); +} diff --git a/_src/compiler/exp.h b/_src/compiler/exp.h new file mode 100644 index 0000000..2b5169a --- /dev/null +++ b/_src/compiler/exp.h @@ -0,0 +1,229 @@ + +#ifndef EXP_H +#define EXP_H + +#include "block.h" + +struct Exp{ + + virtual ~Exp(); + + Val *evalRef( Block *block ); + + Val *eval( Scope *scope ); + Val *eval( Scope *scope,Type *type ); + Val *evalInit( Scope *scope,Type *type ); + +protected: + virtual Val *_eval( Scope *scope ); +}; + +struct ExpSeq : public vector{ + ExpSeq(); + virtual ~ExpSeq(); +}; + +struct ValExp : public Exp{ + Val *val; + + ValExp( Val *v ):val(v){} + + Val *_eval( Scope *scope ); +}; + +struct CastExp : public Exp{ + Type *type; + Exp *exp; + + CastExp( Type *t,Exp *e ):type(t),exp(e){} + + Val *_eval( Scope *scope ); +}; + +struct NullExp : public Exp{ + Val *_eval( Scope *scope ); +}; + +struct LocalDeclExp : public Exp{ + string ident; + Type *type; + Block *block; + + LocalDeclExp( string id,Type *ty,Block *b ):ident(id),type(ty),block(b){} + + Val *_eval( Scope *scope ); +}; + +struct GlobalExp : public Exp{ + string ident; + + GlobalExp( string id ):ident(id){} + + Val *_eval( Scope *scope ); +}; + +struct IdentExp : public Exp{ + string ident; + Type *type; + + IdentExp( string id,Type *ty ):ident(id),type(ty){} + + Val *_eval( Scope *scope ); +}; + +struct MemberExp : public Exp{ + Exp *lhs,*rhs; + + MemberExp( Exp *l,Exp *r ):lhs(l),rhs(r){} + + Val *_eval( Scope *scope ); +}; + +struct SelfExp : public Exp{ + Val *_eval( Scope *scope ); +}; + +struct SuperExp : public Exp{ + Val *_eval( Scope *scope ); +}; + +struct NewExp : public Exp{ + Exp *exp; + + NewExp( Exp *e ):exp(e){} + + Val *_eval( Scope *scope ); +}; + +struct ArrayExp : public Exp{ + Exp *exp; + Type *type; + + ExpSeq dims; + + ArrayExp( Exp *e ):exp(e),type(0){} + ArrayExp( Type *t ):exp(0),type(t){} + + Val *_eval( Scope *scope ); +}; + +struct ArrayDataExp : public Exp{ + ExpSeq exps; + + Val *_eval( Scope *scope ); +}; + +struct IntrinsicExp : public Exp{ + int toke; + Type *type; + Exp *exp; + + IntrinsicExp( int t,Type *ty,Exp *e ):toke(t),type(ty),exp(e){} + + Val *_eval( Scope *scope ); +}; + +struct ExpSeqExp : public Exp{ + Exp *exp; + ExpSeq seq; + + ExpSeqExp( Exp *e ):exp(e){} + + Val *_eval( Scope *scope ); + + Val *invokeFun( Val *v,FunType *t,Scope *sc ); + Val *performCast( Val *v,Scope *sc ); + + Val *indexString( Val *v,Scope *sc ); + Val *indexArray( Val *v,ArrayType *t,Scope *sc ); + Val *indexPointer( Val *v,Type *t,Scope *sc ); +}; + +struct InvokeExp : public ExpSeqExp{ + + InvokeExp( Exp *e ):ExpSeqExp(e){} + + Val *_eval( Scope *scope ); +}; + +struct IndexExp : public ExpSeqExp{ + + IndexExp( Exp *e ):ExpSeqExp(e){} + + Val *_eval( Scope *scope ); +}; + +struct SliceExp : public Exp{ + int toke; + Exp *exp; + Exp *lhs,*rhs; + + SliceExp( int t,Exp *e,Exp *l,Exp *r ):toke(t),exp(e),lhs(l),rhs(r){} + + Val *_eval( Scope *scope ); +}; + +//<, =, >, <=, >=, <> +struct CmpExp : public Exp{ + int op; + Exp *lhs,*rhs; + + CmpExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r){} + + Val *_eval( Scope *scope ); +}; + +struct ShortCircExp : public Exp{ + int op; + Exp *lhs,*rhs; + + ShortCircExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r){} + + Val *_eval( Scope *scope ); +}; + +struct NotExp : public Exp{ + Exp *exp; + + NotExp( Exp *e ):exp(e){} + + Val *_eval( Scope *scope ); +}; + +//-, Abs +struct UnaryExp : public Exp{ + int op; + Exp *exp; + + UnaryExp( int o,Exp *e ):op(o),exp(e){} + + Val *_eval( Scope *scope ); +}; + +//+, -, *, /, Mod, Min, Max +struct ArithExp : public Exp{ + int op; + Exp *lhs,*rhs; + Val *lhs_val,*rhs_val; + + ArithExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r),lhs_val(0),rhs_val(0){} + ArithExp( int o,Val *l,Exp *r ):op(o),lhs(0),rhs(r),lhs_val(l),rhs_val(0){} + + Val *pointerArith( Val *pv,Val *iv ); + + Val *_eval( Scope *scope ); +}; + +//And, Or, Xor, Shl, Shr, Sar +struct BitwiseExp : public Exp{ + int op; + Exp *lhs,*rhs; + Val *lhs_val,*rhs_val; + + BitwiseExp( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r),lhs_val(0),rhs_val(0){} + BitwiseExp( int o,Val *l,Exp *r ):op(o),lhs(0),rhs(r),lhs_val(l),rhs_val(0){} + + Val *_eval( Scope *scope ); +}; + +#endif diff --git a/_src/compiler/make.bat b/_src/compiler/make.bat new file mode 100644 index 0000000..d99c3cf --- /dev/null +++ b/_src/compiler/make.bat @@ -0,0 +1 @@ +bmk0 -a -r -z -o ~/blitzmax/bin/bcc bcc.cpp diff --git a/_src/compiler/module.cpp b/_src/compiler/module.cpp new file mode 100644 index 0000000..52b9c32 --- /dev/null +++ b/_src/compiler/module.cpp @@ -0,0 +1,3 @@ + +#include "std.h" +#include "module.h" diff --git a/_src/compiler/module.h b/_src/compiler/module.h new file mode 100644 index 0000000..acb9709 --- /dev/null +++ b/_src/compiler/module.h @@ -0,0 +1,5 @@ + +#ifndef MODULE_H +#define MODULE_H + +#endif diff --git a/_src/compiler/output.cpp b/_src/compiler/output.cpp new file mode 100644 index 0000000..ad59e9b --- /dev/null +++ b/_src/compiler/output.cpp @@ -0,0 +1,149 @@ + +#include "std.h" +#include "output.h" +#include "decl.h" +#include "val.h" + +ostream &out::operator<<( ostream &out,CGExp *exp ){ + + if( CGLit *t=exp->lit() ){ + if( t->isint() ){ + out<int_value); + if( t->type==CG_INT64 ) out<<":Long"; + }else if( t->isfloat() ){ + if( isnan( t->float_value ) ){ + out<<"nan"; + }else if( isinf( t->float_value ) ){ + out<<( t->float_value>0 ? "inf" : "-inf" ); + }else{ + out<float_value; + } + out<<( t->type==CG_FLOAT32 ? '#' : '!' ); + }else{ + assert(0); + } + }else if( CGSym *t=exp->sym() ){ + out<<"\""<value<<"\""; + }else{ + const char *ty=""; + switch( exp->type ){ + case CG_INT8:ty=":b";break; + case CG_INT16:ty=":s";break; + case CG_INT32:break; + case CG_INT64:ty=":l";break; + case CG_PTR:ty=":p";break; + case CG_FLOAT32:ty=":f";break; + case CG_FLOAT64:ty=":d";break; + default: + cout<<"type error:"<type<mem() ){ + out<<"mem"<exp; + if( t->offset ) out<<","<offset; + out<<")"; + }else{ + fail( "Unrecognized intermediate code expression - !*#%" ); + } + } + return out; +} + +ostream &out::operator<<( ostream &out,Type *ty ){ + if( RefType *t=ty->refType() ){ + out<val_type<<'&'; + }else if( VarType *t=ty->varType() ){ + out<val_type<<" Var"; + }else if( PtrType *t=ty->ptrType() ){ + out<val_type<<'*'; + }else if( IntType *t=ty->intType() ){ + switch( t->size() ){ + case 1:out<<"@";break; + case 2:out<<"@@";break; + case 4:out<<"%";break; + case 8:out<<"%%";break; + default:assert(0); + } + }else if( FloatType *t=ty->floatType() ){ + switch( t->size() ){ + case 4:out<<"#";break; + case 8:out<<"!";break; + default:assert(0); + } + }else if( CStringType *t=ty->cstringType() ){ + out<<"$z"; + }else if( WStringType *t=ty->wstringType() ){ + out<<"$w"; + }else if( StringType *t=ty->stringType() ){ + out<<"$"; + }else if( ArrayType *t=ty->arrayType() ){ + out<element_type<<'['<dims-1,',')<<']'; + }else if( ObjectType *t=ty->objectType() ){ + if( t->ident=="" ) fail( "export of unknown type" ); + string id=t->ident; + ClassType *ty=t->objectClass(); + while( ty->attrs & ClassType::PRIVATE ){ + id=ty->super_name; + ty=ty->superClass(); + } + out<<':'<exObjectType() ){ + if( t->ident=="" ) fail( "export of unknown type" ); + out<<':'<ident; + }else if( FunType *t=ty->funType() ){ + out<return_type<<'('; + for( int k=0;kargs.size();++k ){ + if( k ) out<<','; + out<args[k]; + } + out<<')'; + if( t->attrs & FunType::ABSTRACT ) out<<'A'; + if( t->attrs & FunType::FINAL ) out<<'F'; + if( t->call_conv==CG_STDCALL ) out<<'S'; + }else if( ClassType *t=ty->classType() ){ + out<<'^'; + if( t->super_name.size() ) out<super_name; else out<<"Null"; + out<<"{\n"; + int k; + for( k=0;kdecls.size();++k ){ + Decl *d=t->decls[k]; + if( t->methods.find(d->ident) || t->fields.find(d->ident) ) continue; + out<fields.size();++k ){ + out<<'.'<fields[k]<<'\n'; + } + for( k=0;kmethods.size();++k ){ + FunType *ty=t->methods[k]->val->type->funType(); + out<<(ty->method() ? '-' : '+')<methods[k]<<'\n'; + } + out<<"}"; + if( t->attrs & ClassType::ABSTRACT ) out<<'A'; + if( t->attrs & ClassType::FINAL ) out<<'F'; + if( t->attrs & ClassType::EXTERN ) out<<'E'; + }else{ + fail( "Export Type '%s' failed",ty->toString().c_str() ); + } + return out; +} + +ostream &out::operator<<( ostream &out,Decl *d ){ + Val *v=d->val; + out<ident<type; + if( v->cg_exp ){ + if( v->type->stringType() && v->constant() ){ + out<<"=$\""<stringValue() ) )<<'\"'; + }else{ + out<<'='<cg_exp; + } + } + return out; +} + +ostream &out::operator<<( ostream &out,const DeclSeq &seq ){ + int k; + for( k=0;ksourceInfo(); + ::fail( buf ); +} + +int Parser::curr(){ + return toker->curr(); +} + +int Parser::next(){ + return toker->next(); +} + +string Parser::text(){ + return toker->text(); +} + +bstring Parser::wtext(){ + if( toker->curr()==T_STRINGCONST ) return unescapeString( toker->wtext() ); + return toker->wtext(); +} + +void Parser::exp( int n ){ + fail( "Expecting %s but encountered %s",Toker::toString(n).c_str(),Toker::toString(curr()).c_str() ); +} + +void Parser::exp( string t ){ + fail( "Expecting %s but encountered %s",t.c_str(),Toker::toString(curr()).c_str() ); +} + +string Parser::parse( int n ){ + if( curr()!=n ) exp(n); + string t=text(); + next();return t; +} + +bool Parser::cparse( int n ){ + if( curr()!=n ) return false; + next();return true; +} + +bool Parser::pub(){ + return pub_ && block==mainFun; +} + +void Parser::emitDebugInfo(){ + if( !block->debug_on ) return; + DebugInfoStm *t=new DebugInfoStm; + t->source_info=source_info; + block->emit(t); +} + +void Parser::emit( Stm *t,bool debugInfo ){ + if( debugInfo ) emitDebugInfo(); + t->source_info=source_info; + block->emit(t); +} + +void Parser::decl( Decl *d ){ + block->decl(d); + if( pub() ) publish( d ); +} + +Type *Parser::parseLitType( Type *ty ){ + switch( curr() ){ + case '%':next();return cparse('%') ? Type::int64 : Type::int32; + case '#':next();return cparse('#') ? Type::float64 : Type::float32; + case '!':next();return Type::float64; + case ':':next();break; + default:return ty; + } + switch( curr() ){ + case T_BYTE:next();return Type::int8; + case T_SHORT:next();return Type::int16; + case T_INT:next();return Type::int32; + case T_LONG:next();return Type::int64; + case T_FLOAT:next();return Type::float32; + case T_DOUBLE:next();return Type::float64; + } + fail( "Expecting literal type" ); + return 0; +} + +Val *Parser::parseLitVal(){ + Val *v; + Type *ty; + switch( curr() ){ + case T_INTCONST: + v=new Val( toint(text()) ); + ty=Type::int32; + break; + case T_FLOATCONST: + v=new Val( tofloat(text()) ); + ty=Type::float32; + break; + default: + exp( "integer or floating point literal value" ); + } + next(); + ty=parseLitType( ty ); + return v->cast( ty ); +} + +CGExp *Parser::parseLitExp( Type *ty ){ + int sign=0; + for(;;){ + if( cparse('+') ){ + }else if( cparse('-') ){ + sign=sign ? -sign : -1; + }else{ + break; + } + } + Val *v; + switch( curr() ){ + case T_INTCONST:{ + int64 n=toint(text()); + if( sign<0 ) n=-n; + v=new Val( n ); + next(); + break; + } + case T_FLOATCONST:{ + double n=tofloat(text()); + if( sign<0 ) n=-n; + v=new Val( n ); + next(); + break; + } + case T_STRINGCONST:{ + if( sign ) exp( "Numeric or string literal value" ); + v=new Val( parseBString() ); + break; + } + default: + exp( "Numeric or string literal value" ); + } + ty=parseLitType( ty ); + v=v->cast( ty ); + return v->cg_exp; +} + +string Parser::parseString(){ + string t=parse(T_STRINGCONST); + return t.substr(1,t.size()-2); +} + +bstring Parser::parseBString(){ + if( curr()!=T_STRINGCONST ) exp(T_STRINGCONST); + bstring t=wtext();next(); + return t.substr(1,t.size()-2); +} + +string Parser::parseIdent(){ + if( !import_nest ) return parse(T_IDENT); + switch( curr() ){ + case T_OBJECT:case T_STRING:case T_NEW:case T_DELETE:case T_IDENT: + break; + default: + fail( "Invalid import identifier: %s",Toker::toString(curr()).c_str() ); + } + string id=text(); + next(); + return id; +} + +string Parser::parseClassName(){ + string id=parseIdent(); + while( cparse('.') ) id+='.'+parseIdent(); + return id; +} + +string Parser::parseModuleName(){ + string id=parseIdent(); + while( cparse('.') ) id+='.'+parseIdent(); + return tolower(id); +} + +static void ass( bool t ){ + if( !t ) fail( "Error in import file" ); +} + +CGExp *Parser::parseCGExp(){ + + int sgn=1; + if( cparse('-') ) sgn=-1; + + if( curr()==T_INTCONST || curr()==T_FLOATCONST ){ + Val *v=parseLitVal(); + CGLit *t=v->cg_exp->lit(); + if( t->type==CG_INT64 ) return lit( sgn * t->int_value ); + if( t->type==CG_FLOAT64 ) return lit( sgn * t->float_value ); + if( t->type==CG_INT32 ) return lit( sgn * int(t->int_value ) ); + if( t->type==CG_FLOAT32 ) return lit( sgn * float(t->float_value) ); + assert(0); + }else if( curr()==T_STRINGCONST ){ + return sym(parseString(),CG_IMPORT); + }else if( cparse('$') ){ + return (new Val(parseBString()))->cg_exp; + } + + string id=parseIdent(); + + if( id=="nan" ){ + double zero=0.0; + if( cparse('#') ) return lit( float(0.0/zero) ); + if( cparse('!') ) return lit( double(0.0/zero) ); + fail( "Nan error" ); + } + if( id=="inf" ){ + double zero=0.0; + if( cparse('#') ) return lit( float(sgn/zero) ); + if( cparse('!') ) return lit( double(sgn/zero) ); + fail( "Inf error" ); + } + + int ty=CG_INT32; + if( cparse(':') ){ + string t=parseIdent(); + switch(t[0]){ + case 'b':ty=CG_INT8;break; + case 's':ty=CG_INT16;break; + case 'i':ty=CG_INT32;break; + case 'l':ty=CG_INT64;break; + case 'p':ty=CG_PTR;break; + case 'f':ty=CG_FLOAT32;break; + case 'd':ty=CG_FLOAT64;break; + default:fail( "Unrecognized intermediate code data type" ); + } + } + + parse('('); + CGExp *exp=0; + + if( id=="mem" ){ + exp=parseCGExp(); + int n=0; + if( curr()!=')' ){ + parse(','); + n=parseLitVal()->cg_exp->lit()->int_value; + } + exp=CG::mem(ty,exp,n); + }else{ + fail( "Unrecognized intermediate code expression" ); + } + + parse(')'); + return exp; +} + +Decl *Parser::parseImportDecl(){ + string id=parseIdent(); + Type *ty=parseType(); + CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0; + return new Decl( id,ty,cg ); +} + +int Parser::parseCallConv(){ + + if( curr()!=T_STRINGCONST ) return default_call_conv; + + string t=tolower(parseString()); + + if( t=="c" ) return CG_CDECL; + if( t=="blitz" ) return CG_CDECL; + if( t=="os" ) t=env_platform; + if( t=="macos" ) return CG_CDECL; + if( t=="linux" ) return CG_CDECL; + if( t=="win32" ) return CG_STDCALL; + + fail( "Unrecognized calling convention '%s'",t.c_str() ); + return 0; +} + +void Parser::parseExtern(){ + next(); + + ++extern_nest; + + int call_conv=default_call_conv; + default_call_conv=parseCallConv(); + + while( !cparse(T_ENDEXTERN) ){ + source_info=toker->sourceInfo(); + if( cparse('\n') ){ + }else if( curr()==T_CONST ){ + parseConstDecls(); + }else if( cparse(T_GLOBAL) ){ + do{ + string id=parseIdent(); + Type *ty=parseRefType(); + CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0; + emit( new ExternDeclStm(T_GLOBAL,id,ty,cg,pub()),false ); + }while( cparse(',') ); + }else if( cparse(T_FUNCTION) ){ + do{ + string id=parseIdent(); + ExpSeq *defs=new ExpSeq(); + fun_defaults=defs; + FunType *ty=parseType()->funType(); + fun_defaults=0; + if( !ty ) exp( "function type" ); + CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0; + Decl *d=new FunDecl( id,ty,cg,block,defs ); + decl(d); + }while( cparse(',') ); + }else if( cparse(T_TYPE) ){ + string id=parseIdent(),super_id; + if( cparse(T_EXTENDS) ) super_id=parseIdent(); + ClassType *class_ty=new ClassType( super_id,block,ClassType::EXTERN ); + while( !cparse(T_ENDTYPE) ){ + if( cparse('\n') ){ + }else if( cparse(T_FIELD) ){ + do{ + string id=parseIdent(); + Type *ty=parseRefType(); + class_ty->fields.push_back( new Decl(id,ty,0) ); + }while( cparse(',') ); + }else if( cparse(T_METHOD) ){ + string id=parseIdent(); + ExpSeq *defs=new ExpSeq(); + fun_defaults=defs; + FunType *ty=parseType()->funType(); + fun_defaults=0; + if( !ty ) exp( "method type" ); + ty->attrs|=FunType::METHOD; + CGExp *cg=cparse(T_EQ) ? parseCGExp() : 0; + Decl *d=new FunDecl( id,ty,cg,block,defs ); + class_ty->methods.push_back( d ); +/* + string id=parseIdent(); + FunType *ty=parseType()->funType(); + if( !ty ) exp( "method type" ); + ty->attrs|=FunType::METHOD; + class_ty->methods.push_back( new Decl(id,ty,0) ); +*/ + }else{ + exp( "field or method declaration" ); + } + } + decl( new Decl(id,class_ty,lit0) ); + }else{ + fail( "Syntax error in extern block - expecting Const, Global, Function or Type declaration" ); + } + } + default_call_conv=call_conv; + + --extern_nest; +} + +Type *Parser::parseBaseType(){ + Scope *scope=block; + + if( import_module ) scope=import_module; + + switch( curr() ){ + case '!':next();return Type::float64; + case '$':next();return Type::stringObject; + case '@':if( next()!='@' ) return Type::int8; + next();return Type::int16; + case '%':if( next()!='%' ) return Type::int32; + next();return Type::int64; + case '#':if( next()!='#' ) return Type::float32; + next();return Type::float64; + case T_CSTRING: + next();return Type::c_string; + case T_WSTRING: + next();return Type::w_string; + case ':': + switch( next() ){ + case T_BYTE:next();return Type::int8; + case T_SHORT:next();return Type::int16; + case T_INT:next();return Type::int32; + case T_LONG:next();return Type::int64; + case T_FLOAT:next();return Type::float32; + case T_DOUBLE:next();return Type::float64; + case T_OBJECT:next();return Type::objectObject; + case T_STRING:next();return Type::stringObject; + case T_IDENT:return new ObjectType( parseClassName(),scope ); + } + exp(T_IDENT); + case '^': + if( import_nest ){ + next(); + string super_name=cparse(T_NULL) ? "" : parseClassName(); + parse('{'); + + ClassType *ty=new ClassType( super_name,scope ); + + while( !cparse('}') ){ + if( cparse('\n') ){ + }else if( curr()=='+' || curr()=='-' ){ + int tok=curr();next(); + Decl *d=parseImportDecl(); + FunType *f=d->val->type->funType();ass( !!f ); + if( tok=='-' ) f->attrs|=FunType::METHOD; + ty->methods.push_back(d); + }else if( cparse('.') ){ + Decl *d=parseImportDecl(); + ass( !d->val->cg_exp ); + ty->fields.push_back(d); + }else{ + Decl *d=parseImportDecl(); + ass( !!d->val->cg_exp ); + ty->decls.push_back(d); + } + } + if( curr()==T_IDENT ){ + string id=tolower(parseIdent()); + if( id.find('a')!=string::npos ) ty->attrs|=ClassType::ABSTRACT; + if( id.find('f')!=string::npos ) ty->attrs|=ClassType::FINAL; + if( id.find('e')!=string::npos ) ty->attrs|=ClassType::EXTERN; + } + return ty; + } + break; + } + return Type::int32; +} + +FunType *Parser::parseFunType( Type *ty ){ + + parse('('); + + FunType *fun=new FunType(ty); + fun->call_conv=default_call_conv; + + if( !cparse(')') ){ + do{ + CGExp *cg=0; + + string id=parseIdent(); + + ExpSeq *tmp_defaults=fun_defaults; + fun_defaults=0; + Type *ty=parseType(); + fun_defaults=tmp_defaults; + + if( cparse(T_VAR) ) ty=new VarType(ty); + + if( fun_defaults ){ + if( cparse(T_EQ) ) fun_defaults->push_back( parseExp() ); + else fun_defaults->push_back(0); + }else if( cparse(T_EQ) ){ + if( !import_nest ){ + fail( "Function argument defaults can only be specified in function declaration" ); +// cg=parseLitExp( ty ); + }else{ + cg=parseCGExp(); + } + } + fun->args.push_back( new Decl(id,ty,cg) ); + }while( cparse(',') ); + parse(')'); + } + if( import_nest ){ + if( curr()==T_IDENT ){ + string id=tolower(parseIdent()); + if( id.find('a')!=string::npos ) fun->attrs|=FunType::ABSTRACT; + if( id.find('f')!=string::npos ) fun->attrs|=FunType::FINAL; + if( id.find('s')!=string::npos ) fun->call_conv=CG_STDCALL; + } + }else if( curr()==T_STRINGCONST ){ + fun->call_conv=parseCallConv(); + } + return fun; +} + +int Parser::arrayDeclDims( string t ){ + assert( t.size()>1 && t[0]=='[' && t[t.size()-1]==']' ); + int n=1; + for( int i=1;i1 && !import_nest ){ + FunType *fun; + switch( curr() ){ + case '(': + fun=parseFunType( Type::int32 ); + fun->attrs|=FunType::VOIDFUN; + ty=fun; + break; + case '%':case ':': + ty=parseBaseType(); + break; + default: + ty=parseBaseType(); + if( ty==Type::int32 ) fail( "Missing type specifier" ); + } + }else{ + ty=parseBaseType(); + } + + for(;;){ + if( curr()=='(' ){ + if( fun_defaults ){ + for( int i=0;isize();++i ){ + if( (*fun_defaults)[i] ){ + fail( "Illegal default function parameter" ); + } + } + fun_defaults->clear(); + } + ty=parseFunType(ty); + continue; + } + + if( ty->cstringType() || ty->wstringType() ) break; + + if( curr()==T_ARRAYDECL ){ + if( !import_nest ) ty=new RefType(ty); + ArrayType *arr=new ArrayType( ty,arrayDeclDims( text() ) );//text().size()-1 ); + next(); + ty=arr; + }else if( import_nest && cparse('&') ){ + ty=new RefType(ty); + }else if( import_nest && cparse('*') ){ + ty=new PtrType(ty); + }else if( cparse(T_PTR) ){ + ty=new PtrType( ty ); + }else{ + break; + } + } + return ty; +} + +RefType *Parser::parseRefType(){ + Type *ty=parseType(); + if( ty->cstringType() || ty->wstringType() ) fail( "Illegal variable type" ); + return new RefType( ty ); +} + +Exp *Parser::parseCastExp( Type *ty ){ + for(;;){ + if( curr()==T_ARRAYDECL ){ + ty=new ArrayType( new RefType( ty ),arrayDeclDims( text() ) ); + next(); + }else if( cparse(T_PTR) ){ + ty=new PtrType(ty); + }else{ + break; + } + } + if( curr()=='(' ){ + return parsePostExp( new CastExp( ty,parsePriExp() ) ); + } + return new CastExp( ty,parsePreExp() ); +} + +Exp *Parser::parseIdentExp(){ + string id=parseIdent(); + Type *ty=0; + switch( curr() ){ + case '@':case '%':case '#':case '!':case '$':case ':':ty=parseBaseType();break; + } + return new IdentExp(id,ty); +} + +ArrayExp *Parser::parseArrayExp( Type *ty ){ + parse('['); + ArrayExp *exp=new ArrayExp(ty); + do{ + exp->dims.push_back( parseExp() ); + }while(cparse(',')); + parse(']'); + return exp; +} + +Exp *Parser::parseArrayDataExp(){ + parse('['); + if( cparse(']') ) return new NullExp(); + ArrayDataExp *e=new ArrayDataExp(); + do{ + e->exps.push_back( parseExp() ); + }while( cparse(',') ); + parse(']'); + return e; +} + +Exp *Parser::parseNewExp(){ + Type *t=0; + switch( curr() ){ + case T_BYTE:t=Type::int8;break; + case T_SHORT:t=Type::int16;break; + case T_INT:t=Type::int32;break; + case T_LONG:t=Type::int64;break; + case T_FLOAT:t=Type::float32;break; + case T_DOUBLE:t=Type::float64;break; + case T_STRING:t=Type::stringObject;break; + case T_OBJECT:t=Type::objectObject;break; + } + if( t ){ + next(); + }else{ + Exp *e=parsePriExp(); + if( curr()!=T_ARRAYDECL && curr()!=T_PTR && curr()!='[' ){ + return new NewExp(e); + } + IdentExp *id=dynamic_cast(e); + if( !id ) fail( "Expecting element type" ); + t=new ObjectType( id->ident,block ); + } + for(;;){ + if( curr()==T_ARRAYDECL ){ + t=new ArrayType( t,arrayDeclDims( text() ) ); + next(); + }else if( cparse(T_PTR) ){ + t=new PtrType( t ); + }else{ + break; + } + } + parse('['); + ArrayExp *exp=new ArrayExp(t); + do{ + exp->dims.push_back( parseExp() ); + }while(cparse(',')); + parse(']'); + return exp; +} + +Exp *Parser::parsePriExp(){ + + int t; + Type *ty; + Exp *e=0,*lhs,*rhs; + + //Yuck! This extremely nasty hack allows for 'bracketless' fun invocation by statements... + if( primary ){ + e=primary; + primary=0; + return e; + } + + switch( int op=curr() ){ + case '(': + next(); + e=parseExp(); + parse(')'); + return e; + case '[': + return parseArrayDataExp(); + case T_IDENT: + return parseIdentExp(); + case T_INTCONST:case T_FLOATCONST: + return new ValExp( parseLitVal() ); + case T_STRINGCONST: + return new ValExp( new Val(parseBString()) ); + case T_TRUE: + next();return new ValExp( new Val(1) ); + case T_FALSE: + next();return new ValExp( new Val(0) ); + case T_PI: + next();return new ValExp( new Val((double)PI) ); + case T_NULL: + next();return new NullExp(); + case T_SELF: + next();return new SelfExp(); + case T_SUPER: + next();return new SuperExp(); + case T_NEW: + next();return parseNewExp(); + case T_LEN: + case T_CHR: + case T_ASC: + case T_INCBINPTR: + case T_INCBINLEN: + ty=0; + switch( next() ){ + case '@':case '%':case '#':case '!':case '$':case ':': + if( op!=T_VARPTR ) ty=parseBaseType(); + break; + } + return new IntrinsicExp( op,ty,parsePriExp() ); + case '.': + next();return new GlobalExp( parseIdent() ); + case T_MIN:case T_MAX: + t=curr();next(); + parse('(');lhs=parseExp();parse(',');rhs=parseExp();parse(')'); + return new ArithExp( t,lhs,rhs ); + } + exp( "expression" ); + return 0; +} + +Exp *Parser::parsePostExp( Exp *t ){ + if( !t ) t=parsePriExp(); + for(;;){ + if( cparse('.') ){ + t=new MemberExp( t,parsePriExp() ); + }else if( cparse('(') ){ + InvokeExp *i=new InvokeExp(t); + if( !cparse(')') ){ + do{ + if( curr()==',' ) i->seq.push_back(0); + else i->seq.push_back(parseExp()); + }while( cparse(',') ); + parse(')'); + } + t=i; + }else if( cparse('[') ){ + int c=curr(); + if( c==T_DOTDOT ){ + if( next()==']' ) t=new SliceExp(c,t,0,0); + else t=new SliceExp(c,t,0,parseExp()); + }else{ + Exp *e=parseExp(); + int c=curr(); + if( c==T_DOTDOT ){ + if( next()==']' ) t=new SliceExp(c,t,e,0); + else t=new SliceExp(c,t,e,parseExp()); + }else{ + IndexExp *i=new IndexExp(t); + i->seq.push_back(e); + while( cparse(',') ) i->seq.push_back(parseExp()); + t=i; + } + } + parse(']'); + }else if( curr()==T_ARRAYDECL || curr()==T_PTR ){ + IdentExp *e=dynamic_cast(t); + if( !e ) fail( "Expecting identifier" ); + ObjectType *ty=new ObjectType( e->ident,block ); + t=parseCastExp(ty); + }else{ + return t; + } + } +} + +Exp *Parser::parsePreExp(){ + Type *ty; + if( primary ) return parsePostExp(); + switch( int op=curr() ){ + case T_NOT: + next();return new NotExp( parsePreExp() ); + case '-':case '+':case '~':case T_ABS:case T_SGN: + next();return new UnaryExp( op,parsePreExp() ); + case T_SIZEOF: + case T_VARPTR: + ty=0; + switch( next() ){ + case '@':case '%':case '#':case '!':case '$':case ':': + if( op!=T_VARPTR ) ty=parseBaseType(); + break; + } + return new IntrinsicExp( op,ty,parsePostExp() ); + case T_BYTE: + next();return parseCastExp( Type::int8 ); + case T_SHORT: + next();return parseCastExp( Type::int16 ); + case T_INT: + next();return parseCastExp( Type::int32 ); + case T_LONG: + next();return parseCastExp( Type::int64 ); + case T_FLOAT: + next();return parseCastExp( Type::float32 ); + case T_DOUBLE: + next();return parseCastExp( Type::float64 ); + case T_STRING: + if( next()=='.' ) return parsePostExp( new ValExp(Type::stringClass) ); + return parseCastExp( Type::stringObject ); + case T_OBJECT: + if( next()=='.' ) return parsePostExp( new ValExp(Type::objectClass) ); + return parseCastExp( Type::objectObject ); + } + + return parsePostExp(); +} + +Exp *Parser::parsePowExp(){ + Exp *t=parsePreExp(); + for(;;){ + switch( int op=curr() ){ + case '^': + next(); + t=new ArithExp( op,t,parsePreExp() ); + break; + default: + return t; + } + } +} + +Exp *Parser::parseFactExp(){ + Exp *t=parsePowExp(); + for(;;){ + switch( int op=curr() ){ + case '*':case '/':case T_MOD: + next(); + t=new ArithExp( op,t,parsePowExp() ); + break; + case T_SHL:case T_SHR:case T_SAR: + next(); + t=new BitwiseExp( op,t,parsePowExp() ); + break; + default: + return t; + } + } +} + +Exp *Parser::parseTermExp(){ + Exp *t=parseFactExp(); + for(;;){ + switch( int op=curr() ){ + case '+':case '-': + next(); + t=new ArithExp( op,t,parseFactExp() ); + break; + default: + return t; + } + } +} + +Exp *Parser::parseBitwiseExp(){ + Exp *t=parseTermExp(); + for(;;){ + switch( int op=curr() ){ + case '&':case '|':case '~': + next(); + t=new BitwiseExp( op,t,parseTermExp() ); + break; + default: + return t; + } + } +} + +Exp *Parser::parseCmpExp(){ + Exp *t=parseBitwiseExp(); + for(;;){ + switch( int op=curr() ){ + case T_LT:case T_EQ:case T_GT:case T_LE:case T_GE:case T_NE: + next(); + t=new CmpExp( op,t,parseBitwiseExp() ); + break; + default: + return t; + } + } +} + +Exp *Parser::parseShortCircExp(){ + Exp *t=parseCmpExp(); + for(;;){ + switch( int op=curr() ){ + case T_AND:case T_OR: + next(); + t=new ShortCircExp( op,t,parseCmpExp() ); + break; + default: + return t; + } + } +} + +Exp *Parser::parseExp(){ + Exp *e=parseShortCircExp(); + return e; +} + +string Parser::parseMetaData(){ + if( !cparse('{') ) return ""; + + string meta; + + while( curr()==T_IDENT ){ + string id=parseIdent(),t; + if( cparse( T_EQ ) ){ + switch( curr() ){ + case T_INTCONST: + case T_FLOATCONST: + case T_STRINGCONST: + t=text(); + next(); + break; + default: + fail( "Meta data must be literal constant" ); + } + }else{ + t="1"; + } + if( meta.size() ) meta+=" "; + meta+=id+"="+t; + } + + parse( '}' ); + return meta; +} + +void Parser::addMetaData( const vector &decls ){ + string meta=parseMetaData(); + for( vector::const_iterator it=decls.begin();it!=decls.end();++it ){ + (*it)->setMetaData( meta ); + } +} + +Decl *Parser::parseInitDecl( Exp **init ){ + string id=parseIdent(); + Type *ty=parseRefType(); + Exp *_init=0; + if( cparse(T_EQ) ){ + _init=parseExp(); + }else if( cparse('[') ){ + ArrayExp *exp=new ArrayExp(ty); + do{ + exp->dims.push_back( parseExp() ); + }while( cparse(',') ); + parse(']'); + ty=new RefType( new ArrayType(ty,exp->dims.size()) ); + _init=exp; + }else{ + _init=new NullExp(); + } + *init=_init; + return new Decl( id,ty,0 ); +} + +void Parser::parseLocalDecls(){ + next(); + emitDebugInfo(); + + vector decls; + + do{ + Exp *e; + Decl *d=parseInitDecl( &e ); + decls.push_back( d ); + emit( new LocalDeclStm(d->ident,d->val->type,e),false ); + }while( cparse(',') ); + + addMetaData( decls ); +} + +void Parser::parseGlobalDecls(){ + next(); + emitDebugInfo(); + + vector decls; + + do{ + Exp *e; + Decl *d=parseInitDecl( &e ); + decls.push_back( d ); + emit( new GlobalDeclStm(d->ident,d->val->type,e,pub()),false ); + }while( cparse(',') ); + + addMetaData( decls ); +} + +void Parser::parseConstDecls(){ + next(); + + vector decls; + + do{ + string id=parseIdent(); + Type *ty=parseType(); + if( !cparse(T_EQ) ) fail( "Constants must be initialized" ); + Decl *d=new ConstDecl( id,ty,block,parseExp() ); + decls.push_back( d ); + decl( d ); + }while( cparse(',') ); + + addMetaData( decls ); +} + +void Parser::parseTypeDecl(){ + next(); + + string id=parseIdent(); + string super_name=cparse(T_EXTENDS) ? parseClassName() : "Object"; + + int attrs=0; + if( cparse(T_FINAL) ){ + attrs=ClassType::FINAL; + }else if( cparse(T_ABSTRACT) ){ + attrs=ClassType::ABSTRACT; + } + + string meta=parseMetaData(); + + if( !pub() ) attrs|=ClassType::PRIVATE; + + ClassType *class_type=new ClassType( super_name,block,attrs ); + + ClassBlock *class_block=new ClassBlock( block,id,class_type ); + + class_block->class_decl->setMetaData( meta ); + + block=class_block; + while( !cparse(T_ENDTYPE) ){ + source_info=toker->sourceInfo(); + switch( curr() ){ + case '\n':case ';':next();break; + case T_FIELD:parseFieldDecls();break; + case T_CONST:parseConstDecls();break; + case T_GLOBAL:parseGlobalDecls();break; + case T_METHOD:parseFunDecl( FunType::METHOD );break; + case T_FUNCTION:parseFunDecl( 0 );break; + default:fail( "Syntax error in user defined type declaration" ); + } + } + block=block->outer; + +} + +void Parser::parseFieldDecls(){ + next(); + + ClassBlock *class_block=dynamic_cast(block); + if( !class_block ) fail( "Field declarations must appear within a Type declaration" ); + ClassType *class_type=class_block->type; + + Block *t_block=block; + block=class_block->field_ctors; + + emitDebugInfo(); + + vector decls; + + do{ + Exp *e; + Decl *d=parseInitDecl( &e ); + emit( new FieldDeclStm(d->ident,d->val->type,e),false ); + class_type->fields.push_back( d ); + decls.push_back( d ); + }while( cparse(',') ); + + addMetaData( decls ); + + block=t_block; +} + +void Parser::parseFunDecl( int attrs ){ + next(); + + bool method=!!(attrs & FunType::METHOD); + + ClassBlock *class_block=dynamic_cast(block); + ClassType *class_type=class_block ? class_block->type : 0; + + if( method && !class_block ) fail( "Methods must appear within a type" ); + + string id; + Block *fun_block=0; + + if( cparse(T_NEW) ){ + id="New"; + if( !method ) fail( "New must be a method" ); + + fun_block=class_block->ctor_new; + if( !fun_block ) fail( "New method already defined" ); + + class_block->ctor_new=0; + }else if( cparse(T_DELETE) ){ + id="Delete"; + if( !method ) fail( "Delete must be a method" ); + + class_block->makeDtor(); + + fun_block=class_block->dtor_delete; + if( !fun_block ) fail( "Delete method already defined" ); + + class_block->dtor_delete=0; + }else{ + id=parseIdent(); + } + + ExpSeq *defs=new ExpSeq(); + fun_defaults=defs; + FunType *ty=parseType()->funType(); + fun_defaults=0; + + if( !ty ) fail( "Expecting function type" ); + + if( ty->return_type->cstringType() || ty->return_type->wstringType() ) fail( "Illegal function return type" ); + + int i; + for( i=0;iargs.size();++i ){ + Type *t=ty->args[i]->val->type; + if( t->cstringType() || t->wstringType() ) fail( "Illegal function parameter type" ); + } + + bool noDebug=false; + + if( cparse( T_NODEBUG ) ) noDebug=true; + + if( cparse( T_FINAL ) ){ + if( !class_block ){ + fail( "Final cannot be used with global functions" ); + } + attrs|=FunType::FINAL; + }else if( cparse( T_ABSTRACT ) ){ + if( !class_block ){ + fail( "Abstract cannot be used with global functions" ); + } + if( class_type->attrs & ClassType::FINAL ){ + fail( "Abstract methods cannot appear in final types" ); + } + attrs|=FunType::ABSTRACT; + }else if( method && (class_type->attrs & ClassType::FINAL) ){ + attrs|=FunType::FINAL; + } + + if( cparse( T_NODEBUG ) ) noDebug=true; + + ty->attrs|=attrs; + + string meta=parseMetaData(); + + if( attrs & FunType::ABSTRACT ){ + FunDecl *decl=new FunDecl(id,ty,sym("brl_blitz_NullMethodError",CG_IMPORT),block,defs); + class_type->methods.push_back( decl ); + decl->setMetaData( meta ); + return; + } + + if( !fun_block ){ + bool pub=method || class_block || this->pub(); + FunBlock *t=new FunBlock( block,id,ty,pub,defs ); + t->fun_decl->setMetaData( meta ); + fun_block=t; + } + + if( noDebug ) fun_block->debug_on=false; + + parseStms( fun_block,method ? T_ENDMETHOD : T_ENDFUNCTION ); +} + +static bool isExpOp( int t ){ + switch( t ){ + case '&':case '|':case '~': + case '+':case '-':case '*':case '/':case T_MOD:case '^': + case T_LT:case T_GT:case T_LE:case T_GE:case T_EQ:case T_NE: + case T_AND:case T_OR:case T_SHL:case T_SHR:case T_SAR: + return true; + } + return false; +} + +void Parser::parseExpStm(){ + + Exp *e=parsePreExp(); + + if( cparse(T_EQ) ){ + emit( new AssignStm(e,parseExp()),true ); + return; + } + + int op=0; + switch( curr() ){ + case T_ADDASSIGN:case T_SUBASSIGN:case T_MULASSIGN:case T_DIVASSIGN:case T_MODASSIGN: + case T_ORASSIGN:case T_ANDASSIGN:case T_XORASSIGN:case T_SHLASSIGN:case T_SHRASSIGN:case T_SARASSIGN: + op=curr();next();break; + } + if( op ){ + emit( new OpAssignStm(op,e,parseExp()),true ); + return; + } + + if( dynamic_cast(e) ){ + emit( new EvalStm(e),true ); + return; + } + + InvokeExp *t=dynamic_cast(e); + bool more=false; + + if( !t ){ + t=new InvokeExp(e); + more=curr()!=';' && curr()!='\n' && curr()!=EOF; + }else if( t->seq.size()==1 ){ + if( isExpOp(curr()) ){ + primary=t->seq[0]; + t->seq[0]=parseExp(); + } + more=cparse(','); + } + if( more ){ + do{ + if( curr()==',' ) t->seq.push_back(0); + else t->seq.push_back( parseExp() ); + }while( cparse(',') ); + } + emit( new EvalStm(t),true ); +} + +void Parser::parseIfStm( int t_term ){ + source_info=toker->sourceInfo(); + next(); + + Exp *e=parseExp(); + cparse( T_THEN ); + + int term=t_term ? t_term : (curr()=='\n' ? T_ENDIF : '\n'); + + IfStm *stm=new IfStm( e,0,0 ); + emit( stm,true ); + + int t; + block=stm->then_block=new Block( block ); + for(;;){ + t=curr(); + if( t==term || t==T_ELSE || t==T_ELSEIF ) break; + parseStm(); + } + block=block->outer; + + if( t!=term ){ + block=stm->else_block=new Block( block ); + if( t==T_ELSE ){ + if( next()==T_IF ){ + parseIfStm( term ); + }else{ + while( curr()!=term ) parseStm(); + } + }else{ + //t==T_ELSEIF + parseIfStm( term ); + } + block=block->outer; + } + + if( !t_term && term==T_ENDIF ) next(); +} + +void Parser::parseLoopCtrlStm(){ + int toke=curr(); + string lab; + if( next()==T_IDENT ) lab=parseIdent(); + emit( new LoopCtrlStm( toke,lab ),true ); +} + +void Parser::parseForStm(){ + next(); + + LoopBlock *loop_block=new LoopBlock( block,loopLabel ); + loopLabel=""; + + Exp *var; + if( cparse(T_LOCAL) ){ + string id=parseIdent(); + Type *ty=parseRefType(); + var=new LocalDeclExp( id,ty,loop_block ); + }else{ + var=parsePostExp(); + } + if( !cparse(T_EQ) ) exp( "assignment" ); + + if( cparse(T_EACHIN) ){ + Exp *coll=parseExp(); + emit( new ForEachStm( var,coll,loop_block ),true ); + parseStms( loop_block,T_NEXT ); + return; + } + + Exp *init=parseExp(); + bool until; + if( cparse(T_TO) ) until=false; + else if( cparse(T_UNTIL) ) until=true; + else fail( "Expecting 'To' or 'Until'" ); + Exp *to=parseExp(); + Exp *step=cparse(T_STEP) ? parseExp() : 0; + emit( new ForStm( var,init,to,step,loop_block,until ),true ); + parseStms( loop_block,T_NEXT ); +} + +void Parser::parseWhileStm(){ + next(); + + LoopBlock *loop_block=new LoopBlock( block,loopLabel ); + loopLabel=""; + + emit( new WhileStm( parseExp(),loop_block),true ); + + parseStms( loop_block,T_WEND ); +} + +void Parser::parseRepeatStm(){ + next(); + + LoopBlock *loop_block=new LoopBlock( block,loopLabel ); + loopLabel=""; + + block=loop_block; + while( curr()!=T_UNTIL && curr()!=T_FOREVER ){ + parseStm(); + } + source_info=toker->sourceInfo(); + int c=curr();next(); + block=block->outer; + + Exp *e=(c==T_UNTIL) ? parseExp() : 0; + + emit( new RepeatStm(e,loop_block),true ); +} + +void Parser::parseTryStm(){ + next(); + + TryStm *try_stm=new TryStm( new Block(block) ); + emit( try_stm,true ); + + block=try_stm->block; + while( curr()!=T_CATCH && curr()!=T_ENDTRY ){ + parseStm(); + } + block=block->outer; + + while( cparse(T_CATCH) ){ + TryCatch *t=new TryCatch( new Block(block) ); + try_stm->catches.push_back( t ); + + t->ident=parseIdent(); + t->type=parseType(); + + block=t->block; + while( curr()!=T_CATCH && curr()!=T_ENDTRY ){ + parseStm(); + } + block=block->outer; + } + parse( T_ENDTRY ); +} + +void Parser::parseThrowStm(){ + next(); + emit( new ThrowStm(parseExp()),true ); +} + +void Parser::parseSelectStm(){ + next(); + + SelectStm *sel=new SelectStm( parseExp() ); + emit( sel,true ); + + while( cparse('\n') ){} + + source_info=toker->sourceInfo(); + while( cparse(T_CASE) ){ + SelCase *t_case=new SelCase( new Block( block ) ); + t_case->source_info=source_info; + sel->cases.push_back( t_case ); + + do{ + t_case->exps.push_back( parseExp() ); + }while( cparse(',') ); + + block=t_case->block; + while( curr()!=T_CASE && curr()!=T__DEFAULT && curr()!=T_ENDSELECT ){ + parseStm(); + } + source_info=toker->sourceInfo(); + block=block->outer; + } + + if( cparse(T__DEFAULT) ){ + sel->_default=new Block( block ); + + block=sel->_default; + while( curr()!=T_ENDSELECT ){ + parseStm(); + } + block=block->outer; + } + + parse( T_ENDSELECT ); +} + +void Parser::parseReturnStm(){ + next(); + Exp *exp=0; + if( curr()!=';' && curr()!='\n' && curr()!=EOF ) exp=parseExp(); + emit( new ReturnStm(exp),true ); +} + +void Parser::parseDeleteStm(){ + next(); + Exp *exp=parseExp(); + emit( new DeleteStm(exp),true ); +} + +void Parser::parseAccess(){ + switch( curr() ){ + case T_PUBLIC:pub_=true;break; + case T_PRIVATE:pub_=false;break; + default:assert(0); + } + next(); +} + +void Parser::parseLabelStm(){ + next(); + string id=parseIdent(); + if( strictMode ){ + while( cparse('\n') ){} + switch( curr() ){ + case T_FOR:case T_WHILE:case T_REPEAT:case T_DEFDATA: + break; + default: + fail( "Labels must appear before a loop or DefData statement" ); + } + if( curr()!=T_DEFDATA ){ + loopLabel=id; + return; + } + } + if( block->fun_block->labels.count(id) ) fail( "Duplicate label '%s'",id.c_str() ); + CGSym *goto_sym=CG::sym(); + CGSym *restore_sym=CG::sym(); + LabelStm *stm=new LabelStm(goto_sym,restore_sym); + block->fun_block->labels.insert( make_pair(tolower(id),stm) ); + emit( stm,true ); +} + +void Parser::parseGotoStm(){ + next(); + emit( new GotoStm( parseIdent() ),true ); +} + +void Parser::parseAssertStm(){ + next(); + Exp *e=parseExp(),*m; + if( cparse(',') || cparse(T_ELSE) ) m=parseExp(); + else m=new ValExp( new Val(tobstring("Assert failed")) ); + emit( new AssertStm(e,m),true ); +} + +void Parser::includeFile( string file ){ + + file=realpath(file); + + Toker *t=toker; + toker=new Toker( file ); + + string cd=getcwd(); + setcwd( getdir(file) ); + + while( curr()!=EOF ){ + parseStm(); + } + setcwd( cd ); + toker=t; +} + +void Parser::parseDataStm(){ + next(); + DataStm *t=new DataStm(); + emit( t,false ); + do{ + t->exps.push_back( parseExp() ); + }while( cparse(',') ); +} + +void Parser::parseReadStm(){ + next(); + ReadStm *t=new ReadStm(); + emit( t,true ); + do{ + t->exps.push_back( parseExp() ); + }while( cparse(',') ); +} + +void Parser::parseRestoreStm(){ + next(); + emit( new RestoreStm( parseIdent() ),true ); +} + +void Parser::parseStm(){ + source_info=toker->sourceInfo(); + + switch( curr() ){ + case ';': + case '\n': + next(); + break; + case '#': + parseLabelStm(); + break; + case T_DEFDATA: + parseDataStm(); + break; + case T_READDATA: + parseReadStm(); + break; + case T_RESTOREDATA: + parseRestoreStm(); + break; + case T_GOTO: + parseGotoStm(); + break; + case T_TRY: + parseTryStm(); + break; + case T_THROW: + parseThrowStm(); + break; + case T_IF: + //case T_ELSEIF: + parseIfStm(0); + break; + case T_GLOBAL: + parseGlobalDecls(); + break; + case T_FUNCTION: + parseFunDecl( 0 ); + break; + case T_EXIT:case T_CONTINUE: + parseLoopCtrlStm(); + break; + case T_FOR: + parseForStm(); + break; + case T_WHILE: + parseWhileStm(); + break; + case T_REPEAT: + parseRepeatStm(); + break; + case T_SELECT: + parseSelectStm(); + break; + case T_RETURN: + parseReturnStm(); + break; + case T_ASSERT: + parseAssertStm(); + break; + case T_END: + next();emit( new EndStm(),true ); + break; + case T_RELEASE: + next();emit( new ReleaseStm( parseExp() ),true ); + break; + case T_LOCAL: + parseLocalDecls(); + break; + case T_CONST: + parseConstDecls(); + break; + case T_TYPE: + parseTypeDecl(); + break; + case T_INCLUDE: + next();includeFile( parseString() ); + break; + case T_INCBIN: + next();emit( new IncbinStm( parseString() ),false ); + break; + case T_EXTERN: + parseExtern(); + break; + case T_PUBLIC:case T_PRIVATE: + parseAccess(); + break; + case T_MODULE:case T_MODULEINFO:case T_IMPORT:case T_STRICT: + fail( "'%s' must appear at top of file",toker->text().c_str() ); + case T_FIELD: + fail( "Field declaration outside of user defined type" ); + case T_METHOD: + fail( "Method declaration outside of user defined type" ); + case T_ELSE: + fail( "'Else' without matching 'If'" ); + case T_ENDIF: + fail( "'%s' without matching 'If'",toker->text().c_str() ); + case T_NEXT: + fail( "'Next' without matching 'For'" ); + case T_WEND: + fail( "'%s' without matching 'While'",toker->text().c_str() ); + case T_UNTIL: + fail( "'Until' without matching 'Repeat'" ); + case T_FOREVER: + fail( "'Forever' without matching 'Repeat'" ); + case T_CASE: + fail( "'Case' without matching 'Select'" ); + case T__DEFAULT: + fail( "'Default' without matching 'Select'" ); + case T_CATCH: + fail( "'Catch' without matching 'Try'" ); + case T_ENDTRY: + fail( "'%s' without matching 'Try'",toker->text().c_str() ); + case T_ENDTYPE: + fail( "'%s' without matching 'Type'",toker->text().c_str() ); + case T_ENDEXTERN: + fail( "'%s' without matching 'Extern'",toker->text().c_str() ); + case T_ENDMETHOD: + fail( "'%s' without matching 'Method'",toker->text().c_str() ); + case T_ENDFUNCTION: + fail( "'%s' without matching 'Function'",toker->text().c_str() ); + case T_ENDSELECT: + fail( "'%s' without matching 'Select'",toker->text().c_str() ); + default: + parseExpStm(); + } +} + +void Parser::parseStms( Block *t,int term ){ + + Block *t_block=block; + block=t; + + while( curr()!=term ){ + parseStm(); + } + + next(); + block=t_block; +} + +void Parser::importFile( string file,ModuleType *mod ){ + + Toker *t=toker; + toker=new Toker( file ); + ModuleType *m=import_module; + import_module=mod; + + ++import_nest; + + while( curr()!=EOF ){ + source_info=toker->sourceInfo(); + if( cparse(';') ){ + }else if( cparse('\n') ){ + }else if( cparse( T_IMPORT ) ){ + parseImport(); + }else if( cparse( T_MODULEINFO ) ){ + parseString(); + }else{ + Decl *d=parseImportDecl(); + if( import_module ){ + import_module->decls.push_back(d); + }else{ + mainFun->decl(d); + moduleExports.push_back(d); + } + } + } + + --import_nest; + + toker->close(); + import_module=m; + toker=t; +} + +void Parser::importModule( string mod ){ + + string mung="@"+mod; + if( rootScope.find(mung) ) return; + + vector ids; + splitModule( mod,ids ); + + ModuleType *mod_ty; + DeclSeq *decls=&mainFun->decls; + + int k; + for( k=0;kfind(id) ){ + mod_ty=v->type->moduleType(); + if( !mod_ty ) fail( "Unable to import module '%s'",mod.c_str() ); + }else{ + mod_ty=new ModuleType(); + decls->push_back( new Decl(id,mod_ty,lit0) ); + } + decls=&mod_ty->decls; + } + + rootScope.push_back( new Decl(mung,mod_ty,lit0) ); + + importFile( moduleInterface(mod),mod_ty ); + + if( !import_module ){ + string t="import "+mod; + if( !import_nest ){ + objectImports.push_back(t); + emit( new ImportStm(sym(mungModuleEntry(mod),CG_IMPORT)),false ); + } + moduleImports.push_back(t); + } +} + +void Parser::importSource( string file ){ + + string ext=tolower(getext(file)),path=realpath(file); + + if( ext=="bmx" ){ + if( !importedSources.insert( tolower(path) ).second ) return; + + if( !ftime(path) ) fail( "File '%s' not found",path.c_str() ); + + string cd=getcwd(); + setcwd( getdir(path) ); + + importFile( ".bmx/"+stripdir(path)+config_mung+".i",0 ); + + setcwd( cd ); + + if( !import_nest ){ + string t="import \""+file+'\"'; + objectImports.push_back( t ); + emit( new ImportStm( sym(mungObjectEntry(file),CG_IMPORT) ),false ); + } + }else if( ext=="o" || ext=="a" || ext=="lib" ){ + + if( !import_module ){ + + if( !ftime(path) ) fail( "File '%s' not found",path.c_str() ); + + string t="import \""+file+'\"'; + if( !import_nest ) objectImports.push_back( t ); + moduleImports.push_back(t); + } + }else if( ext=="c" || ext=="m" || ext=="cpp" || ext=="cxx" || ext=="cc" || ext=="mm" || ext=="s" || ext=="asm" ){ + + if( !ftime(path) ) fail( "File '%s' not found",path.c_str() ); + + }else{ + + fail( "Unrecognized import file type for import '%s'",path.c_str() ); + } +} + +void Parser::parseImport(){ + if( curr()==T_IDENT ){ + importModule( parseModuleName() ); + }else if( curr()==T_STRINGCONST ){ + string file=parseString(); + if( stripall(file)=="*" ){ + }else if( file[0]=='-' ){ + if( !import_module ){ + string t="import \""+file+'\"'; + if( !import_nest ) objectImports.push_back( t ); + moduleImports.push_back(t); + } + return; + }else{ + importSource( file ); + } + }else{ + fail( "Expecting module name or import file" ); + } +} + +Parser::Parser(){ +} + +void Parser::parse(){ + + pub_=true; + primary=0; + fun_defaults=0; + default_call_conv=CG_CDECL; + import_nest=0; + extern_nest=0; + import_module=0; + + Type::createTypes(); + + setcwd( getdir(opt_infile) ); + toker=new Toker( opt_infile ); + mainFun=new FunBlock(); + block=mainFun; + + ModuleType *mod_ty=new ModuleType(); + mainFun->decls.push_back( new Decl("brl",mod_ty,lit0) ); + mod_ty->decls.push_back( new Decl("blitz",Type::blitzModule,lit0) ); + + importFile( env_blitzpath+"/mod/brl.mod/blitz.mod/blitz_classes.i",Type::blitzModule ); + + *Type::objectClass=*Type::blitzModule->find("Object"); + *Type::stringClass=*Type::blitzModule->find("String"); + *Type::arrayClass=*Type::blitzModule->find("Array"); + + if( opt_module=="brl.blitz" ){ + if( stripall(opt_infile)=="blitz" ){ + rootScope.push_back( new Decl("@brl.blitz",Type::blitzModule,lit0) ); + } + }else{ + importModule( "brl.blitz" ); + } + + //if( stripall(opt_infile)!="blitz" ) importModule( "brl.blitz" ); + //else rootScope.push_back( new Decl("@brl.blitz",Type::blitzModule,lit0) ); + + while( curr()!=EOF ){ + source_info=toker->sourceInfo(); + if( cparse('\n') ){ + }else if( cparse( T_STRICT ) ){ + if( strictMode ) fail( "Strict or SuperStrict already specified" ); + strictMode=1; + }else if( cparse( T_SUPERSTRICT ) ){ + if( strictMode ) fail( "Strict or SuperStrict already specified" ); + strictMode=2; + }else if( cparse( T_NODEBUG ) ){ + opt_debug=false; + opt_release=true; + block->debug_on=false; + }else if( cparse( T_MODULE ) ){ + string name=parseModuleName(); + if( name!=opt_module ) fail( "Module does not match commandline module" ); + if( opt_apptype.size() ) fail( "Modules cannot be built as applications" ); + }else if( cparse( T_MODULEINFO ) ){ + if( !opt_module.size() ) fail( "ModuleInfo can only be used with modules" ); + moduleInfos.push_back( parseString() ); + }else if( cparse( T_FRAMEWORK ) ){ + string framework=parseModuleName(); + if( opt_framework.size() && opt_framework!=framework ) fail( "Framework does not match commandline framework" ); + opt_framework=framework; + }else if( cparse( T_IMPORT ) ){ + parseImport(); + }else{ + break; + } + } + + if( opt_module.size() ){ + }else if( opt_framework.size() ){ + importModule( opt_framework ); + }else{ + vector mods; + enumModules( "",mods ); + for( int k=0;kclose(); +} diff --git a/_src/compiler/parser.h b/_src/compiler/parser.h new file mode 100644 index 0000000..790f73a --- /dev/null +++ b/_src/compiler/parser.h @@ -0,0 +1,135 @@ + +#ifndef PARSER_H +#define PARSER_H + +#include "stm.h" +#include "toker.h" + +class Parser{ + + Toker* toker; + Block* block; + + bool pub_; + Exp* primary; + ExpSeq* fun_defaults; + int default_call_conv; + string loopLabel; + int import_nest; + int extern_nest; + ModuleType *import_module; + + void fail( const char *fmt,... ); + int curr(); + int next(); + string text(); + bstring wtext(); + string parse( int n ); + bool cparse( int n ); + void exp( int n ); + void exp( string t ); + + bool pub(); + int linkage(); + + void emitDebugInfo(); + void emit( Stm *t,bool debugInfo ); + void decl( Decl *d ); + + Type* parseLitType( Type *ty ); + Val* parseLitVal(); + CGExp *parseLitExp( Type *ty ); + string parseString(); + bstring parseBString(); + string parseIdent(); + string parseClassName(); + string parseModuleName(); + + int parseCGType(); + CGLit* parseCGLit(); + CGExp* parseCGExp(); + Decl* parseImportDecl(); + + void importFile( string file,ModuleType *mod ); + void importModule( string mod ); + void importSource( string src ); + + void parseImport(); + int parseCallConv(); + void parseExtern(); + + int arrayDeclDims( string t ); + + Type* parseBaseType(); + FunType*parseFunType( Type *baseType ); + Type* parseType(); + RefType*parseRefType(); + + Exp* parseCastExp( Type *base_ty ); + ArrayExp*parseArrayExp( Type *ty ); + Exp* parsePeekExp(); + Exp* parseIdentExp(); + + Exp* parseArrayDataExp(); + Exp* parseNewExp(); + + Exp* parsePriExp(); //Ident, Constant, Self, Super, New(?) + Exp* parsePostExp( Exp *lhs=0 ); //Member, Extends, Invoke + Exp* parsePreExp(); //Cast, Varptr, Peek, First, Last, Before, After + Exp* parsePowExp(); //^ + Exp* parseFactExp(); //*, /, Mod, Shl, Shr, Sar + Exp* parseTermExp(); //+, - + Exp* parseCmpExp(); //<, =, >, <=, >=, <> + Exp* parseShortCircExp(); //AndIf, OrIf + Exp* parseBitwiseExp(); //And, Or, Xor + Exp* parseExp(); + + string parseMetaData(); + void addMetaData( const vector &decls ); + + Decl* parseInitDecl( Exp **init ); + + void parseLocalDecls(); + void parseGlobalDecls(); + void parseConstDecls(); + void parseFieldDecls(); + + void parseTypeDecl(); + void parseFunDecl( int attr ); + + void parseAccess(); + void parseModule(); + + void parseLabelStm(); + void parseGotoStm(); + void parseFlushMemStm(); + void parseDataStm(); + void parseReadStm(); + void parseRestoreStm(); + + void parseStm(); + void parseEndStm(); + void parseExpStm(); + void parseIfStm( int term ); + void parseLoopCtrlStm(); + void parseForStm(); + void parseWhileStm(); + void parseRepeatStm(); + void parseSelectStm(); + void parseReturnStm(); + void parseDeleteStm(); + void parsePokeStm(); + void parseAssertStm(); + void parseTryStm(); + void parseThrowStm(); + void includeFile( string file ); + + void parseStms( Block *block,int term ); + +public: + Parser(); + + void parse(); +}; + +#endif \ No newline at end of file diff --git a/_src/compiler/scope.cpp b/_src/compiler/scope.cpp new file mode 100644 index 0000000..5a2ff0b --- /dev/null +++ b/_src/compiler/scope.cpp @@ -0,0 +1,33 @@ + +#include "std.h" +#include "block.h" +#include "val.h" + +//******************** Scope ********************** +Scope::~Scope(){ +} + +Val *Scope::find( string id ){ + return 0; +} + +Val *Scope::findTypeIdent( string id ){ + + int i=id.find('.'); + if( i==string::npos ){ + globalIdent=""; + Val *v=find( id ); + if( !v ) v=findGlobal( id ); + if( v && globalIdent.size() ) id=globalIdent; + return v; + } + + Scope *sc=mainFun; + while( (i=id.find('.'))!=string::npos ){ + Val *v=sc->find(id.substr(0,i)); + if( !v ) return 0; + id=id.substr(i+1); + sc=v; + } + return sc->find(id); +} diff --git a/_src/compiler/scope.h b/_src/compiler/scope.h new file mode 100644 index 0000000..9218713 --- /dev/null +++ b/_src/compiler/scope.h @@ -0,0 +1,15 @@ + +#ifndef SCOPE_H +#define SCOPE_H + +struct Val; + +struct Scope{ + virtual ~Scope(); + + virtual Val* find( string id ); + + Val* findTypeIdent( string id ); +}; + +#endif diff --git a/_src/compiler/std.cpp b/_src/compiler/std.cpp new file mode 100644 index 0000000..f9cc304 --- /dev/null +++ b/_src/compiler/std.cpp @@ -0,0 +1,234 @@ + +#include "std.h" +#include "block.h" + +int strictMode; +FunBlock *mainFun; //main function + +DeclSeq rootScope; +DeclSeq objectExports; //exports from this object file +DeclSeq moduleExports; //exports from this and imported object files +vector objectImports; //imports to this object file +vector moduleImports; //imports to this object file +vector moduleInfos; + +string globalIdent; + +set importedSources; //source files already imported + +string fixIdent( string id ){ + int k; + for( k=0;k=0;--k ){ + if( Val *t=rootScope[k]->val->find(id) ){ + if( v ){ + fail( "Duplicate identifier '%s' in modules '%s' and '%s'",id.c_str(),mod.substr(1).c_str(),rootScope[k]->ident.substr(1).c_str() ); + dupid( id ); + } + mod=rootScope[k]->ident; + v=t; + } + } + if( v ) globalIdent=mod.substr(1)+"."+id; + return v; +} + +CGDat *genDebugStm( string t ){ + CGDat *d=CG::dat(); + int i1=t.find(';'); + if( i1!=string::npos ){ + int i2=t.find(';',i1+1); + if( i2!=string::npos ){ + string f=t.substr(0,i1); + string l=t.substr(i1+1,i2-i1-1); + string c=t.substr(i2+1); + fixpath( f ); + if( !f.find(env_blitzpath+"/") ) f="$BMXPATH"+f.substr(env_blitzpath.size()); + d->push_back( genCString(f) ); + d->push_back( CG::lit(int(toint(l))) ); + d->push_back( CG::lit(int(toint(c))) ); + return d; + } + } + return 0; +} + +CGDat *genCString( string t ){ + static map c_strings; + map::iterator it=c_strings.find(t); + if( it!=c_strings.end() ) return it->second; + CGDat *d=CG::dat(); + d->push_back( CG::lit(tobstring(t),CG_CSTRING) ); + c_strings.insert( make_pair(t,d) ); + return d; +} + +CGDat *genBBString( bstring t ){ + static map bb_strings; + map::iterator it=bb_strings.find(t); + if( it!=bb_strings.end() ) return it->second; + CGDat *d=CG::dat(); + d->push_back( CG::sym("bbStringClass",CG_IMPORT) ); + d->push_back( CG::lit(0x7fffffff) ); + d->push_back( CG::lit(t,CG_BSTRING) ); + bb_strings.insert( make_pair(t,d) ); + return d; +} + +CGDat *genBBString2( bstring t ){ + static map bb_strings2; + map::iterator it=bb_strings2.find(t); + if( it!=bb_strings2.end() ) return it->second; + CGDat *d=CG::dat(); + d->push_back( CG::sym("bbStringClass",CG_IMPORT) ); + d->push_back( CG::lit(0x7ffffffe) ); + d->push_back( CG::lit(t,CG_BSTRING) ); + bb_strings2.insert( make_pair(t,d) ); + return d; +} + +string mungGlobal( string decl_id ){ + return global_mung+decl_id; +} + +string mungMember( string class_id,string decl_id ){ + return "_"+global_mung+class_id+"_"+decl_id; +} + +string mungObjectEntry( string path ){ + path=tolower(realpath(path)); + string dir=stripall(getdir(path)); + return "__bb_"+fixIdent(dir)+"_"+fixIdent(stripall(path)); +} + +string mungModuleEntry( string mod ){ + string id=moduleIdent(mod); +//#if DEMO_VERSION +// if( id!="appstub" ) return "__bb_"+id+"_"+id+"_"; +//#endif + return "__bb_"+id+"_"+id; +} + +void dupid( string id,const char *fmt ){ + fail( fmt,id.c_str() ); +} + +void badid( string id,const char *fmt ){ + fail( fmt,id.c_str() ); +} + +void badty( string id,const char *fmt ){ + fail( fmt,id.c_str() ); +} + +void badmod( string id,const char *fmt ){ + fail( fmt,id.c_str() ); +} + +static void escErr(){ + fail( "Bad escape sequence in string" ); +} + +bstring escapeString( bstring t ){ + bstring r; + r.reserve( t.size() ); + int i=0; + while( i=32 && c<127 ){ + r+=bchar_t(c); + }else{ + char buf[32]; + sprintf( buf,"~%i~",c ); + r+=tobstring(buf); + } + continue; + } + r+=bchar_t('~'); + r+=bchar_t(esc); + } + return r; +} + +bstring unescapeString( bstring t ){ + bstring r; + r.reserve( t.size() ); + int i=0; + while( i='1' && c<='9' ){ + int n=0; + while( c>='0' && c<='9' ){ + n=n*10+(c-'0'); + if( i==t.size() ) escErr(); + c=t[i++]; + } + if( c!='~' ) escErr(); + r+=bchar_t(n); + }else{ + escErr(); + } + } + } + return r; +} diff --git a/_src/compiler/std.h b/_src/compiler/std.h new file mode 100644 index 0000000..73bcf0c --- /dev/null +++ b/_src/compiler/std.h @@ -0,0 +1,51 @@ + +#ifndef STD_H +#define STD_H + +#include "stdutil.h" +#include "declseq.h" +#include "../codegen/codegen.h" + +struct Decl; +struct FunBlock; +struct ClassBlock; +struct ModuleType; + +extern int strictMode; //strict option : 1=strict, 2=superstrict! +extern FunBlock* mainFun; //main function + +extern DeclSeq rootScope; //root scope - moduletype decls +extern DeclSeq objectExports; //exports from this object file +extern DeclSeq moduleExports; //exports from this and imported object files +extern vector objectImports; //'import' directives for object +extern vector moduleImports; //'import' directives for module +extern vector moduleInfos; //'ModuleInfo' directives + +extern set importedSources; //source files already imported + +extern string globalIdent; + +string fixIdent( string id ); + +void publish( Decl *d ); +Val* findGlobal( string id ); + +CGDat* genCString( string t ); +CGDat* genBBString( bstring t ); +CGDat* genBBString2( bstring t ); +CGDat* genDebugStm( string t ); + +string mungGlobal( string decl_id ); +string mungMember( string class_id,string decl_id ); +string mungObjectEntry( string path ); +string mungModuleEntry( string modname ); + +bstring escapeString( bstring t ); +bstring unescapeString( bstring t ); + +void dupid( string id,const char *fmt="Duplicate identifier '%s'" ); +void badid( string id,const char *fmt="Identifier '%s' not found" ); +void badty( string id,const char *fmt="Type '%s' not found" ); +void badmod( string id,const char *fmt="Module '%s' not found" ); + +#endif diff --git a/_src/compiler/stdutil.cpp b/_src/compiler/stdutil.cpp new file mode 100644 index 0000000..2ab5758 --- /dev/null +++ b/_src/compiler/stdutil.cpp @@ -0,0 +1,544 @@ + +#include "stdutil.h" + +#include +#include + +bool opt_trace; //-z BMK0: trace dependancies +string opt_outfile; //-o BMK0: output exe + +bool opt_quiet; //-q +bool opt_verbose; //-v +bool opt_makeall; //-a +bool opt_debug; //-d +bool opt_release; //-r +bool opt_threaded; +string opt_arch; //-g x86/ppc +string opt_apptype; //-t apptype +string opt_module; //-m 'modname' +string opt_framework; //-f 'modname' or "*" +string opt_infile; + +set env_config; +string env_blitzpath,env_platform,env_binpath,env_libpath,config_mung,global_mung; + +#if _WIN32 + +static void init_env(){ + char path[1024]={0}; + GetModuleFileName( GetModuleHandle(0),path,1024 ); + string t=path; + int n=t.rfind( "\\bin\\" ); + if( n==string::npos ) n=t.rfind( "\\BIN\\" ); + if( n==string::npos ) abort(); + env_blitzpath=t.substr(0,n); + + env_platform="win32"; +} + +#elif __APPLE__ + +static void init_env(){ + + CFURLRef url; + char path[1024],*p; + + url=CFBundleCopyExecutableURL( CFBundleGetMainBundle() ); + CFURLGetFileSystemRepresentation( url,true,(UInt8*)path,1024 ); + + string t=path; + int n=t.rfind( "/bin/" ); + if( n==string::npos ) abort(); + env_blitzpath=t.substr(0,n); + + env_platform="macos"; +} + +#elif __linux + +static void init_env(){ + + char linkname[256]; // /proc//exe + char path[1024]={0}; + pid_t pid; + int ret; + + pid=getpid(); + sprintf(linkname, "/proc/%i/exe", pid); + ret=readlink(linkname, path,1024); + if (ret<1 || ret>1022) abort(); + path[ret]=0; + + string t=path; + int n=t.rfind( "/bin/" ); + if( n==string::npos ) abort(); + env_blitzpath=t.substr(0,n); + + env_platform="linux"; +} + +#else + +#error "Unsuppported build platform" + +#endif + +void stdutil_init( int argc,char *argv[] ){ + + init_env(); + + fixpath( env_blitzpath ); + + env_binpath=env_blitzpath+"/bin"; + env_libpath=env_blitzpath+"/lib"; + +#if __APPLE__ +#if __ppc__ + if( is_pid_native(0) ) opt_arch="ppc"; else opt_arch="x86"; +#elif __i386__ + if( is_pid_native(0) ) opt_arch="x86"; else opt_arch="ppc"; +#endif +#else + opt_arch="x86"; +#endif + opt_debug=true; + opt_release=false; + + for( int k=1;k ids; + splitModule( opt_module,ids ); + int k; + for( k=0;k &ids ){ + if( !mod.size() ) return; + int i; + while( (i=mod.find('.'))!=string::npos ){ + ids.push_back(mod.substr(0,i)); + mod=mod.substr(i+1); + } + ids.push_back(mod); +} + +string moduleIdent( string mod ){ + int i=mod.rfind('.'); + return i==string::npos ? mod : mod.substr(i+1); +} + +string moduleInterface( string mod ){ + string path=modulePath( mod,false )+"/"+moduleIdent(mod)+config_mung+".i"; + if( ftime( path ) ) return path; + fail( "Can't find interface for module '%s'",mod.c_str() ); + return ""; +/* + string path=modulePath( mod,false ); + + string d_ext=".debug."+env_platform+"."+opt_arch+".i"; + string r_ext=".release."+env_platform+"."+opt_arch+".i"; + + string f1=path+"/"+moduleIdent(mod)+r_ext; + string f2=path+"/"+moduleIdent(mod)+d_ext; + if( opt_debug ) std::swap(f1,f2); + if( ftime(f1) ) return f1; + if( ftime(f2) ) return f2; + + fail( "Can't find interface for module '%s'",mod.c_str() ); + return ""; +*/ +} + +void enumModules( string mod,vector &mods ){ + string path=modulePath( mod,false ); + + DIR *d=opendir( path.c_str() ); + if( !d ) return; + + string d_ext=".debug."+env_platform+"."+opt_arch+".i"; + string r_ext=".release."+env_platform+"."+opt_arch+".i"; + + while( dirent *e=readdir( d ) ){ + string f=e->d_name; + if( getext(f)!="mod" ) continue; + string id=stripall(f); + string tmod=mod.size() ? mod+"."+id : id; + enumModules( tmod,mods ); + string path=modulePath( tmod,false )+"/"+id; + if( ftime(path+d_ext) || ftime(path+r_ext) ){ + mods.push_back( tmod ); + } + } + closedir(d); +} + +time_t ftime( string path ){ + struct stat st; + fixpath(path); + if( !stat( path.c_str(),&st ) ) return st.st_mtime; + return 0; +} + +string getcwd(){ + char buf[256]; + if( !getcwd( buf,255 ) ) fail( "getcwd failed" ); + string path=string(buf); + fixpath(path); + return buf; +} + +void setcwd( string path ){ + fixpath(path); + chdir( path.c_str() ); +} + +string getdir( string path ){ + fixpath(path); + int n=path.rfind( '/' ); + if( n==string::npos ) return ""; + return path.substr(0,n); +} + +string getext( string path ){ + fixpath(path); + int n=path.rfind( '.' ); + if( n==string::npos ) return ""; + if( path.find( '/',n+1 )!=string::npos ) return ""; + return path.substr(n+1); +} + +string stripdir( string path ){ + fixpath(path); + int n=path.rfind( '/' ); + if( n==string::npos ) n=path.rfind( '\\' ); + if( n==string::npos ) return path; + return path.substr(n+1); +} + +string stripext( string path ){ + fixpath(path); + int n=path.rfind( '.' ); + if( n==string::npos ) return path; + if( path.find( '/',n+1 )!=string::npos ) return path; + if( path.find( '\\',n+1 )!=string::npos ) return path; + return path.substr(0,n); +} + +string stripall( string path ){ + return stripext(stripdir(path)); +} + +string realpath( string path ){ + fixpath(path); + string dir=getdir(path); + string file=stripdir(path); + static char buf[MAX_PATH+8]; + if( dir.size() ){ +// printf( "Calling realpath( %s ), MAX_PATH=%i PATH_MAX=%i\n",dir.c_str(),MAX_PATH,PATH_MAX );fflush( stdout ); + if( !_realpath( dir.c_str(),buf ) ){ + fail( "realpath failed for %s",path.c_str() ); + } + dir=buf; + }else{ + dir=getcwd(); + } + fixpath( dir ); + return dir+"/"+file; +} + +string tolower( string t ){ + for( int k=0;k='A' ) c-=('A'-'0'-10); + n=n*16+(c-'0'); + } + }else{ + for( ;i0 ? n : -n; +} + +double tofloat( string t ){ + double zero=0.0; + string q=tolower(t); + if( q=="nan#" ){ + return 0.0/zero; + }else if( q=="inf#" || q=="+inf#" ){ + return 1.0/zero; + }else if( q=="-inf#" ){ + return -1.0/zero; + } + return atof(t.c_str()); +} + +string fromint( int64 n ){ +// Can't use %lld 'coz it doesn't work on mingw! +// char buf[64]; +// sprintf( buf,"%lld",n ); +// return buf; + char buf[64],*p=buf+64; + int neg=n<0; + if( neg ){ + n=-n; + if( n<0 ) return "-9223372036854775808"; + } + *--p=0; + do{ + *--p=n%10+'0'; + }while(n/=10); + if( neg ) *--p='-'; + return p; +} + +string fromfloat( float n ){ + char buf[64]; + if( isnan(n) ){ + sprintf( buf,"nan" ); + }else if( isinf(n) ){ + if( n>0 ) sprintf( buf,"inf" ); + else sprintf( buf,"-inf" ); + }else{ + sprintf( buf,"%#.9g",n ); + } + return buf; +} + +string fromdouble( double n ){ + char buf[64]; + if( isnan(n) ){ + sprintf( buf,"nan" ); + }else if( isinf(n) ){ + if( n>0 ) sprintf( buf,"inf" ); + else sprintf( buf,"-inf" ); + }else{ + sprintf( buf,"%#.17lg",n ); + } + return buf; +} + +string tostring( bstring w ){ + string t; + t.resize(w.size()); + for( int k=0;k + +static int sysctlbyname_with_pid (const char *name, pid_t pid, + void *oldp, size_t *oldlenp, + void *newp, size_t newlen) +{ + if (pid == 0) { + if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) { + return -1; + } + }else{ + int mib[CTL_MAXNAME]; + size_t len = CTL_MAXNAME; + if (sysctlnametomib(name, mib, &len) == -1) { + return -1; + } + mib[len] = pid; + len++; + if (sysctl(mib, len, oldp, oldlenp, newp, newlen) == -1) { + return -1; + } + } + return 0; +} + +int is_pid_native (pid_t pid) +{ + int ret = 0; + size_t sz = sizeof(ret); + + if (sysctlbyname_with_pid("sysctl.proc_native", pid, &ret, &sz, NULL, 0) == -1) { + if (errno == ENOENT) { + // sysctl doesn't exist, which means that this version of Mac OS + // pre-dates Rosetta, so the application must be native. + return 1; + } + return -1; + } + return ret; +} +#endif diff --git a/_src/compiler/stdutil.h b/_src/compiler/stdutil.h new file mode 100644 index 0000000..bd6aa49 --- /dev/null +++ b/_src/compiler/stdutil.h @@ -0,0 +1,173 @@ + +#ifndef STDUTIL_H +#define STDUTIL_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if _WIN32 + +#include +#include +#define mkdir(X,Y) mkdir(X) +#define _realpath(X,Y) _fullpath(Y,X,MAX_PATH) + +#elif __APPLE__ + +#include +#define _realpath realpath +#include +#include +int is_pid_native (pid_t pid); + +//only need these with gcc-3.3 : error with gcc4 +#ifndef isnan +extern "C"{ +int isnan( double n ); +int isinf( double n ); +} +#endif + +#elif __linux + +#include +#define _realpath realpath + +#endif + +#include + +#ifndef MAX_PATH +#if PATH_MAX +#define MAX_PATH PATH_MAX +#else +#define MAX_PATH 4096 +#endif +#endif + +#ifdef NDEBUG +#undef NDEBUG +#include +#define NDEBUG +#else +#include +#endif + +typedef long long int64; + +//wchar_t and wstring a total nightmare to get going - roll our own for now! + +typedef unsigned short bchar_t; + +namespace std{ + template<> struct char_traits{ + typedef bchar_t char_type; + typedef int int_type; + static void assign( char_type &c,char_type a ){ + c=a; + } + static size_t length( const char_type *s ){ + int n=0; + while( *s++ ) ++n; + return n; + } + static char_type *assign( char_type *s,size_t n,char_type a ){ + for( size_t k=0;k( memcpy(s1,s2,n*sizeof(char_type)) ); + } + static char_type *move( char_type *s1,const char_type *s2,size_t n ){ + return static_cast( memmove(s1,s2,n*sizeof(char_type)) ); + } + static const char_type *find( const char_type *s,size_t n,char_type c ){ + for( size_t k=0;k bstring; + +extern bool opt_trace; //-z BMK0: trace dependancies +extern string opt_outfile; //-o BMK0: output exe + +extern bool opt_quiet; //-q +extern bool opt_verbose; //-v +extern bool opt_makeall; //-a +extern bool opt_debug; //-d +extern bool opt_release; //-r +extern bool opt_threaded; //-h +extern string opt_arch; //-g x86/ppc +extern string opt_apptype; //-t apptype +extern string opt_module; //-m 'modname' +extern string opt_framework;//-f 'modname' or "*" +extern string opt_infile; + +extern set env_config; +extern string env_blitzpath,env_platform,env_binpath,env_libpath,config_mung,global_mung; + +void stdutil_init( int argc,char *argv[] ); + +//convert a dotted mod name to a path +string modulePath( string mod,bool create ); + +//split module components +void splitModule( string mod,vector &idents ); + +//extract last component of a dotted mod name +string moduleIdent( string mod ); + +//return interface (.i) file for a module +string moduleInterface( string mod ); + +//enumerate modules starting with 'mod' +void enumModules( string mod,vector &mods ); + +void sys( string cmd ); +string getcwd(); +void setcwd( string dir ); +time_t ftime( string path ); +string getdir( string path ); +string getext( string path ); +void fixpath( string &path ); +string stripdir( string path ); +string stripext( string path ); +string stripall( string path ); +string realpath( string path ); + +int64 toint( string t ); +double tofloat( string t ); +string fromint( int64 n ); +string fromfloat( float n ); +string fromdouble( double n ); +string tolower( string str ); +string tostring( bstring w ); +bstring tobstring( string t ); +bstring tobstring( const char *p ); + +extern string source_info; + +void fail( const char *fmt,... ); + +#endif diff --git a/_src/compiler/stm.cpp b/_src/compiler/stm.cpp new file mode 100644 index 0000000..0837f2e --- /dev/null +++ b/_src/compiler/stm.cpp @@ -0,0 +1,807 @@ + +#include "std.h" +#include "stm.h" +#include "toker.h" + +using namespace CG; + +//******************** Stm ************************ +Stm::~Stm(){ +} + +//***************** SourceInfo ******************** +void DebugInfoStm::eval( Block *b ){ + CGDat *d=genDebugStm( source_info ); + if( d ) b->emit( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugEnterStm",CG_IMPORT),0),d)) ); +} + +//******************** Rem ************************ +void RemStm::eval( Block *b ){ + if( comment.size() ) b->emit( rem(comment) ); +} + +//******************* StmStm ********************** +void StmStm::eval( Block *b ){ + b->emit( stm ); +} + +//***************** ClassInits ******************** +void EvalClassBlocksStm::eval( Block *b ){ + b->evalClassBlocks(); +} + +//******************* Label *********************** +void LabelStm::eval( Block *b ){ + b->emit( CG::lab(goto_sym) ); + b->fun_block->dataStms()->push_back( lit(tobstring(restore_sym->value),CG_LABEL) ); +} + +//******************** Goto *********************** +void GotoStm::eval( Block *b ){ + if( strictMode ) fail( "Goto cannot be used in strict mode" ); + FunBlock *f=b->fun_block; + map::iterator it=f->labels.find( tolower(ident) ); + if( it==f->labels.end() ) fail( "Label '%s' not found",ident.c_str() ); + b->emit( CG::bra( it->second->goto_sym ) ); +} + +//******************** Eval *********************** +void EvalStm::eval( Block *b ){ + Val *v=exp->eval(b); + b->emit(eva(v->cg_exp)); +} + +//******************** Ctor *********************** +void CtorStm::eval( Block *b ){ + CGExp *self=b->fun_block->fun_scope->cg_exp; + CGDat *vtbl=block->class_decl->val->cg_exp->dat(); + + ClassType *class_ty=block->type; + Val *super_val=class_ty->superVal(); + ClassType *super_ty=class_ty->superClass(); + + //invoke super ctor + if( super_ty ){ + if( Val *super_ctor=super_ty->methods.find( "New" ) ){ + b->emit( eva( jsr( CG_PTR,CG_CDECL,vfn(super_ctor->cg_exp,self) ) ) ); + } + } + + //install vtbl + b->emit( mov( mem(CG_PTR,self,0),vtbl ) ); + + //initialize fields + block->field_ctors->eval(); + + ctor_new->eval(); +} + +//******************** Dtor *********************** +void DtorStm::eval( Block *b ){ + + CGExp *self=b->fun_block->fun_scope->cg_exp; + CGDat *vtbl=block->class_decl->val->cg_exp->dat(); + + ClassType *class_ty=block->type; + + dtor_delete->eval(); + + //return sym hack - dtor return jumps here... + b->emit(lab(b->fun_block->ret_sym)); + b->fun_block->ret_sym=sym(); + + //destroy fields + for( int k=class_ty->fields.size()-1;k>=0;--k ){ + Val *v=class_ty->decls.find( class_ty->fields[k]->ident ); + v=v->renameTmps("@self",self); + if( v->refCounted() ){ + b->emit( v->release() ); + } + } + + Val *super_val=class_ty->superVal(); + ClassType *super_ty=class_ty->superClass(); + + //invoke super dtor + while( super_ty ){ + if( Val *super_dtor=super_ty->methods.find( "Delete" ) ){ + + //Don't bother calling root object dtor + if( !super_ty->superClass() ) return; + + //install super vtbl + b->emit( mov( mem(CG_PTR,self,0),super_val->cg_exp ) ); + + //invoke super dtor + b->emit( eva( jsr( CG_PTR,CG_CDECL,vfn(super_dtor->cg_exp,self) ) ) ); + + return; + } + super_val=super_ty->superVal(); + super_ty=super_ty->superClass(); + } + + /* + //invoke super dtor + if( super_ty ){ + //install super vtbl + b->emit( mov( mem(CG_PTR,self,0),super_val->cg_exp ) ); + if( Val *super_dtor=super_ty->methods.find( "Delete" ) ){ + b->emit( eva( jsr( CG_PTR,CG_CDECL,vfn(super_dtor->cg_exp,self) ) ) ); + } + }else{ + b->emit( mov( mem(CG_PTR,self,0),lit0 ) ); + } + */ +} + +//***************** Local Decl ******************** +void LocalDeclStm::eval( Block *b ){ + + Val *i=init->evalInit( b,type ); + + Val *v=new Val(type,tmp(type->cgType())); + Decl *d=new Decl( ident,v ); + + FunBlock *f=b->fun_block; + + if( strictMode ){ + b->declLocal( d ); + b->initRef( v,i ); + }else{ + f->declLocal( d ); + b->assignRef( v,i ); + } + + if( !strictMode || opt_debug ){ + f->cg_enter->push_back( mov(v->cg_exp,Val::null(type)->cg_exp) ); + } +} + +//***************** Field Decl ******************** +void FieldDeclStm::eval( Block *b ){ + + Val *i=init->evalInit( b,type ); + + Val *v=b->fun_block->fun_scope->find( ident ); + v=b->linearizeRef(v); + + b->initRef( v,i ); +} + +//***************** Global Decl ******************* +void GlobalDeclStm::eval( Block *b ){ + + Val *i=init->evalInit( b,type ); + + ClassBlock *cb=dynamic_cast(b); + + CGDat *e; + if( cb ){ + e=dat(mungMember(cb->class_decl->ident,ident)); + }else if( pub ){ + e=dat(mungGlobal(ident)); + }else{ + e=dat(); + } + + Val *v=new Val(type,mem(type->cgType(),e,0)); + Decl *d=new Decl( ident,v ); + + if( i->constant() ){ + CGExp *t=i->cg_exp; + if( i->type->cgType()==CG_INT8 || i->type->cgType()==CG_INT16 ){ + t=lit(t->lit()->int_value); + t->type=i->type->cgType(); + } + e->push_back( t ); + b->emit(eva(e)); + }else{ + e->push_back( (new Val(Type::null,0))->cast(type)->cg_exp ); + b->initGlobalRef( v,i ); + } + b->decl(d); + if( pub ) publish( d ); +} + +//***************** Extern Decl ****************** +void ExternDeclStm::eval( Block *b ){ + + if( !cg ) cg=sym(ident,CG_IMPORT); + + switch( toke ){ + case T_GLOBAL:cg=mem(type->cgType(),cg,0);break; + default:assert(0); + } + Decl *d=new Decl(ident,type,cg); + b->decl(d); + if( pub ) publish( d ); +} + +//****************** Import *********************** +void ImportStm::eval( Block *b ){ + b->emit( eva(jsr(CG_INT32,CG_CDECL,entry)) ); +} + +//****************** Incbin *********************** +IncbinStm::IncbinStm( string n ):name(n),path(realpath(n)){ +} + +void IncbinStm::eval( Block *b ){ + + if( b!=mainFun ) fail( "Incbin can only be used in main program block" ); + + Val *v=new Val( tobstring(name) ); + + CGDat *d=dat(); + CGSym *q=sym(); + + d->push_back(lit(tobstring(path),CG_BINFILE)); + d->push_back(lit(tobstring(q->value),CG_LABEL)); + + b->cg_enter->push_back( eva(jsr(CG_INT32,"bbIncbinAdd",v->cg_exp,d,bop(CG_SUB,q,d))) ); +} + +//****************** Assign *********************** +void AssignStm::eval( Block *b ){ + + Val *v=lhs->evalRef(b); + + b->assignRef( v,rhs->evalInit(b,v->type) ); +} + +//****************** OpAssign ********************* +void OpAssignStm::eval( Block *b ){ + + Val *v=lhs->evalRef(b); + + switch( op ){ + case T_ADDASSIGN:rhs=new ArithExp('+',v,rhs);break; + case T_SUBASSIGN:rhs=new ArithExp('-',v,rhs);break; + case T_MULASSIGN:rhs=new ArithExp('*',v,rhs);break; + case T_DIVASSIGN:rhs=new ArithExp('/',v,rhs);break; + case T_MODASSIGN:rhs=new ArithExp(T_MOD,v,rhs);break; + case T_ORASSIGN:rhs=new BitwiseExp('|',v,rhs);break; + case T_ANDASSIGN:rhs=new BitwiseExp('&',v,rhs);break; + case T_XORASSIGN:rhs=new BitwiseExp('~',v,rhs);break; + case T_SHLASSIGN:rhs=new BitwiseExp(T_SHL,v,rhs);break; + case T_SHRASSIGN:rhs=new BitwiseExp(T_SHR,v,rhs);break; + case T_SARASSIGN:rhs=new BitwiseExp(T_SAR,v,rhs);break; + default:assert(0); + } + + b->assignRef( v,rhs->eval(b,v->type) ); +} + +//***************** If Then Else ****************** +void IfStm::eval( Block *b ){ + + Val *v=exp->eval(b)->cond(); + + CGSym *t_sym=sym(); + + b->emit( bcc(CG_EQ,v->cg_exp,lit0,t_sym) ); + + then_block->eval(); + + if( else_block ){ + + CGSym *t_sym2=sym(); + b->emit( bra(t_sym2) ); + b->emit( lab(t_sym) ); + t_sym=t_sym2; + + else_block->eval(); + } + + b->emit(lab(t_sym)); +} + +//***************** Loop control ****************** +void LoopCtrlStm::eval( Block *b ){ + + LoopBlock *loop=0; + FunBlock *f=b->fun_block; + + Block *p=b; + while( p!=f ){ + b->emit( p->cg_leave ); + if( loop=dynamic_cast(p) ){ + if( !label.size() || label==loop->label ) break; + } + p=p->outer; + } + if( p==f ){ + if( !loop ){ + fail( "Continue/Exit must appear inside a loop" ); + }else{ + fail( "Continue/Exit label '%s' not found",label.c_str() ); + } + } + + if( toke==T_CONTINUE ){ + b->emit( bra(loop->cont_sym) ); + }else{ + b->emit( bra(loop->exit_sym) ); + } +} + +//****************** For/Next ********************* +void ForStm::eval( Block *b ){ + + Val *v=var->evalRef(b); + Type *ty=v->type; + if( !ty->numericType() ) fail( "Loop index variable must be of numeric type" ); + + Val *init_val=init->eval(b)->cast(ty); + Val *to_val=to->eval(b)->cast(ty); + Val *step_val; + if( step ){ + step_val=step->eval(b)->cast(ty); + if( !step_val->constant() ) fail( "Step expression must be constant" ); + }else{ + step_val=(new Val(1))->cast(ty); + } + + int bcc_cc=CG_LE; + if( ty->intType() && step_val->intValue()<0 ) bcc_cc=CG_GE; + if( ty->floatType() && step_val->floatValue()<0 ) bcc_cc=CG_GE; + if( until ) bcc_cc=(bcc_cc==CG_LE) ? CG_LT : CG_GT; + + CGSym *t_sym=sym(); + + b->assignRef( v,init_val ); + + CGExp *var_exp=v->cg_exp; + + if( !to_val->constant() ){ + CGTmp *t=tmp(ty->cgType()); + b->emit(mov(t,to_val->cg_exp)); + to_val=new Val(ty,t); + } + + b->emit(bra(t_sym)); + + b->emit(lab(block->loop_sym)); + + block->eval(); + + b->emit(lab(block->cont_sym)); + + b->emit(mov(var_exp,bop(CG_ADD,var_exp,step_val->cg_exp))); + b->emit(lab(t_sym)); + b->emit(bcc(bcc_cc,var_exp,to_val->cg_exp,block->loop_sym)); + + b->emit(lab(block->exit_sym)); +} + +//****************** For Each ********************* +void ForEachStm::checkInt32Method( Val *v ){ + if( v ){ + if( FunType *ty=v->type->funType() ){ + if( ty->method() ){ + if( !ty->args.size() ){ + if( ty->return_type->intType() && ty->size()==4 ) return; + } + } + } + } + fail( "Illegal EachIn expression" ); +} + +ObjectType *ForEachStm::checkObjMethod( Val *v ){ + if( v ){ + if( FunType *ty=v->type->funType() ){ + if( ty->method() ){ + if( !ty->args.size() ){ + if( ObjectType *t=ty->return_type->objectType() ) return t; + } + } + } + } + fail( "Illegal EachIn expression" ); + return 0; +} + +void ForEachStm::eval( Block *b ){ + + Val *v=var->evalRef(b); + Val *t=coll->eval(b); + + if( !t->type->arrayType() && !t->type->objectType() ){ + fail( "EachIn must be used with a string, array, or appropriate object" ); + } + + Val *c=new Val( t->type,tmp(CG_PTR) ); + + b->emit( mov(c->cg_exp,t->cg_exp) ); + + if( c->type->arrayType() ){ + evalArray( b,v,c ); + }else{ + evalCollection( b,v,c ); + } +} + +void ForEachStm::evalArray( Block *b,Val *var,Val *coll ){ + + Type *var_ty=var->type; + ArrayType *arr_ty=coll->type->arrayType(); + Type *elem_ty=arr_ty->element_type; + + Val *arr=new Val( arr_ty,tmp(CG_PTR) ); + + CGTmp *beg=tmp(CG_PTR); + beg->owner=coll->cg_exp->tmp(); + + CGTmp *end=tmp(CG_PTR); + end->owner=coll->cg_exp->tmp(); + + Val *next=new Val(elem_ty,mem(elem_ty->cgType(),beg,0)); + + b->emit( mov(beg,bop(CG_ADD,coll->cg_exp,lit(20+arr_ty->dims*4))) ); + b->emit( mov(end,bop(CG_ADD,beg,mem(CG_INT32,coll->cg_exp,16))) ); + b->emit( bra(block->cont_sym) ); + + //loop + b->emit( lab(block->loop_sym) ); + b->assignRef( var,next->forEachCast(var_ty) ); + b->emit( mov(beg,bop(CG_ADD,beg,lit(elem_ty->size()))) ); + if( var_ty->objectType() ) b->emit( bcc(CG_EQ,var->cg_exp,sym("bbNullObject",CG_IMPORT),block->cont_sym) ); + + //statements! + block->eval(); + + //continue + b->emit( lab(block->cont_sym) ); + b->emit( bcc(CG_NE,beg,end,block->loop_sym) ); + + //exit + b->emit( lab(block->exit_sym) ); +} + +void ForEachStm::evalCollection( Block *b,Val *var,Val *coll ){ + + ObjectType *var_ty=var->type->objectType(); + if( !var_ty ) fail( "EachIn index variable must be an object" ); + + ObjectType *coll_ty=coll->type->objectType(); + + Val *enumer=coll->find( "ObjectEnumerator" ); + ObjectType *enumer_ty=checkObjMethod( enumer ); + + Val *enumer_tmp=new Val( enumer_ty,tmp(CG_PTR) ); + enumer_tmp->cg_exp->tmp()->owner=coll->cg_exp->tmp(); + + Val *enumer_jsr=new Val( enumer_ty,jsr(CG_PTR,CG_CDECL,enumer->cg_exp) ); + + Val *hasnext=enumer_tmp->find( "HasNext" ); + checkInt32Method( hasnext ); + + Val *nextobj=enumer_tmp->find( "NextObject" ); + ObjectType *nextobj_ty=checkObjMethod( nextobj ); + + Val *hasnext_jsr=new Val( Type::int32,jsr(CG_INT32,CG_CDECL,hasnext->cg_exp) ); + Val *nextobj_jsr=new Val( nextobj_ty,jsr(CG_PTR,CG_CDECL,nextobj->cg_exp) ); + + //invoke 'ObjectEnumerator' + b->emit( mov(enumer_tmp->cg_exp,enumer_jsr->cg_exp) ); + b->emit( bra(block->cont_sym) ); + + //loop + b->emit( lab(block->loop_sym) ); + b->assignRef( var,nextobj_jsr->forEachCast(var_ty) ); + b->emit( bcc(CG_EQ,var->cg_exp,sym("bbNullObject",CG_IMPORT),block->cont_sym) ); + + //statements! + block->eval(); + + //continue + b->emit( lab(block->cont_sym) ); + //invoke 'HasNext' + b->emit( bcc(CG_NE,hasnext_jsr->cg_exp,lit0,block->loop_sym) ); + + //exit + b->emit( lab(block->exit_sym) ); +} + +//******************* While *********************** +void WhileStm::eval( Block *b ){ + + Val *v=exp->eval(b)->cond(); + + b->emit(bra(block->cont_sym)); + b->emit(lab(block->loop_sym)); + + block->eval(); + + b->emit(lab(block->cont_sym)); + b->emit(bcc(CG_NE,v->cg_exp,lit0,block->loop_sym)); + b->emit(lab(block->exit_sym)); +} + +//****************** Repeat *********************** +void RepeatStm::eval( Block *b ){ + + b->emit(lab(block->loop_sym)); + if( !exp ) b->emit(lab(block->cont_sym)); + + block->eval(); + + ::source_info=source_info; + + if( exp ){ + Val *v=exp->eval(b)->cond(); + b->emit(lab(block->cont_sym)); + b->emit(bcc(CG_EQ,v->cg_exp,lit0,block->loop_sym)); + }else{ + b->emit(bra(block->loop_sym)); + } + + b->emit(lab(block->exit_sym)); +} + +//****************** Return *********************** +void ReturnStm::eval( Block *b ){ + + FunBlock *f=b->fun_block; + Type *ty=f->type->return_type; + + if( exp ){ + if( strictMode>1 && (f->type->attrs & FunType::VOIDFUN) ) fail( "Function can not return a value" ); + }else{ + if( strictMode>1 && !(f->type->attrs & FunType::VOIDFUN) ) fail( "Function must return a value" ); + exp=new NullExp(); + } + + Val *v=exp->eval(b,ty); + b->emit( mov(f->ret_tmp,v->cg_exp) ); + + Block *t=b; + while( t!=f ){ + b->emit(t->cg_leave); + t=t->outer; + } + + b->emit( bra(f->ret_sym) ); +} + +//****************** Release ********************** +void ReleaseStm::eval( Block *b ){ + Val *v=exp->evalRef(b); + Type *ty=v->type; + + if( ty->cgType()==CG_INT32 ){ + b->emit( eva(jsr(CG_INT32,"bbHandleRelease",v->cg_exp)) ); + b->emit( mov(v->cg_exp,cvt(v->type->cgType(),lit0)) ); + }else{ + fail( "Subexpression for release must be an integer variable" ); + } +} + +//****************** delete *********************** +void DeleteStm::eval( Block *b ){ + + Val *v=exp->eval(b); + + ObjectType *ty=v->type->objectType(); + + if( !ty ) fail( "'Delete' expression does not evaluate to an object" ); + + b->emit( eva(jsr(CG_INT32,"bbObjectDelete",v->cg_exp)) ); +} + +//****************** assert *********************** +void AssertStm::eval( Block *b ){ + + Val *e=exp->eval(b)->cond(); + Val *m=msg->eval(b)->cast( Type::stringObject ); + + if( !opt_debug ) return; + + CGSym *q=sym(); + b->emit( bcc(CG_NE,e->cg_exp,lit0,q) ); + b->emit( eva(jsr(CG_INT32,"brl_blitz_RuntimeError",m->cg_exp)) ); + b->emit( lab(q) ); +} + +//******************** end ************************ +void EndStm::eval( Block *b ){ + + b->emit( eva(jsr(CG_INT32,"bbEnd")) ); +} + +//***************** select/case ******************* +void SelectStm::eval( Block *b ){ + + Val *tv=exp->eval(b); + Type *ty=tv->type; + + Val *t_val=new Val(ty,tmp(ty->cgType())); + b->emit( mov(t_val->cg_exp,tv->cg_exp) ); + + CGSym *end=sym(); + + vector case_syms; + + int k; + for( k=0;ksource_info; + + case_syms.push_back( sym() ); + + for( int j=0;jexps.size();++j ){ + + Val *r=t->exps[j]->eval( b,ty ); + + if( ty->stringType() ){ + b->emit( + bcc(CG_EQ, + jsr(CG_INT32,"bbStringCompare",t_val->cg_exp,r->cg_exp), + lit0,case_syms.back()) ); + }else{ + b->emit( + bcc(CG_EQ,t_val->cg_exp,r->cg_exp,case_syms.back()) ); + } + } + } + + if( _default ) _default->eval(); + + b->emit( bra(end) ); + + for( k=0;kemit( lab(case_syms[k]) ); + + Block *block=cases[k]->block; + block->eval(); + b->emit( bra(end) ); + } + + b->emit( lab(end) ); +} + +//********************** Try ************************* +void TryStm::eval( Block *b ){ + + block->cg_leave->push_back(eva(jsr(CG_INT32,"bbExLeave"))); + + CGTmp *ex_tmp=tmp(CG_PTR); + CGSym *catch_sym=sym(),*exit_sym=sym(); + + if( opt_debug ) b->emit( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugPushExState",CG_IMPORT),0))) ); + + b->emit( mov(ex_tmp,jsr(CG_PTR,"bbExEnter")) ); + b->emit( mov(ex_tmp,jsr(CG_PTR,"_bbExEnter",ex_tmp)) ); + b->emit( bcc(CG_NE,ex_tmp,lit0,catch_sym) ); + + if( opt_debug ) block->cg_leave->push_back( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugPopExState",CG_IMPORT),0))) ); + + block->eval(); + + b->emit( bra(exit_sym) ); + + b->emit( lab(catch_sym) ); + + if( opt_debug ) b->emit( eva(jsr(CG_INT32,CG_CDECL,mem(CG_PTR,sym("bbOnDebugPopExState",CG_IMPORT),0))) ); + + //exception thrown! + vector catch_syms; + + int k; + for( k=0;ktype->objectType(); + if( !type ) fail( "'Catch' variables must be objects" ); + + CGTmp *catch_tmp=tmp(CG_PTR); + t->block->declLocal( new Decl(t->ident,type,catch_tmp) ); + + b->emit( mov(catch_tmp,jsr(CG_PTR,"bbObjectDowncast",ex_tmp,type->class_val->cg_exp)) ); + b->emit( bcc(CG_NE,catch_tmp,sym("bbNullObject",CG_IMPORT),catch_syms.back()) ); + } + b->emit( eva(jsr(CG_INT32,"bbExThrow",ex_tmp)) ); + for( k=0;kemit( lab(catch_syms[k]) ); + + t->block->eval(); + + b->emit( bra(exit_sym) ); + } + + b->emit( lab(exit_sym) ); +} + +//******************** Throw ************************* +void ThrowStm::eval( Block *b ){ + Val *val=exp->eval( b ); + if( !val->type->objectType() ) fail( "'Throw' expression must be an object" ); + b->emit( eva(jsr(CG_INT32,"bbExThrow",val->cg_exp)) ); +} + +//********************* Data ************************* +void DataStm::eval( Block *b ){ + int k; + if( b!=mainFun ) fail( "Data can only be declared in main program" ); + FunBlock *f=mainFun; + CGDat *d=f->dataStms(); + for( k=0;keval( b ); + if( v->type->nullType() ) fail( "Data items can not be 'Null'" ); + if( !v->constant() ) fail( "Data items must be constant" ); + if( v->type->intType() ) v=v->cast(Type::int32); + string t; + switch( v->type->encoding()[0] ){ + case 'i':t="bbIntTypeTag";break; + case 'f':t="bbFloatTypeTag";break; + case 'd':t="bbDoubleTypeTag";break; + case '$':t="bbStringTypeTag";break; + default:fail( "Data items must be numeric or strings" ); + } + d->push_back( sym(t,CG_IMPORT) ); + d->push_back( v->cg_exp ); + } +} + +//******************** Restore *********************** +void RestoreStm::eval( Block *b ){ + FunBlock *f=mainFun; + map::iterator it=f->labels.find( tolower(ident) ); + if( it==f->labels.end() ) fail( "Label '%s' not found",ident.c_str() ); + b->emit( mov(mem(CG_PTR,f->dataPtr(),0),it->second->restore_sym) ); +} + +//********************* Read ************************* +void ReadStm::eval( Block *b ){ + int k; + FunBlock *f=mainFun; + CGDat *d=f->dataPtr(); + CGTmp *p=tmp(CG_PTR); + CGTmp *q=tmp(CG_PTR); + b->emit( mov(p,mem(CG_PTR,d,0)) ); + for( k=0;kevalRef( b ); + Type *ty=v->type; + if( !ty->refType() ) fail( "Read may only be used with variables" ); + if( !ty->numericType() && !ty->stringType() ) fail( "Read may only be used with numeric or string variables" ); + string f; + int cg_ty; + if( ty->intType() ){ + f="bbConvertToInt"; + cg_ty=CG_INT32; + }else if( ty->floatType() ){ + f="bbConvertToFloat"; + cg_ty=CG_FLOAT64; + }else if( ty->stringType() ){ + f="bbConvertToString"; + cg_ty=CG_PTR; + }else{ + fail( "Read may only be used with numeric or string variables" ); + } + b->emit( mov(q,mem(CG_PTR,p,0)) ); + if( opt_debug ){ + CGSym *skip=sym(); + b->emit( bcc(CG_NE,q,lit0,skip) ); + b->emit( eva(jsr(CG_INT32,"brl_blitz_OutOfDataError")) ); + b->emit( lab(skip) ); + } + b->emit( mov(q,mem(CG_PTR,q,0)) ); + b->emit( mov(p,bop(CG_ADD,p,lit(4))) ); + CGExp *e=cvt(ty->cgType(),jsr(cg_ty,f,p,q)); + b->assignRef( v,new Val(ty,e) ); + b->emit( mov(p,bop(CG_ADD,p,lit(4))) ); + CGSym *skip=sym(); + b->emit( bcc(CG_NE,mem(CG_INT8,q,0),lit('d'),skip) ); + b->emit( mov(p,bop(CG_ADD,p,lit(4))) ); + b->emit( lab(skip) ); + } + b->emit( mov(mem(CG_PTR,d,0),p) ); +} diff --git a/_src/compiler/stm.h b/_src/compiler/stm.h new file mode 100644 index 0000000..a86c62a --- /dev/null +++ b/_src/compiler/stm.h @@ -0,0 +1,327 @@ + +#ifndef STM_H +#define STM_H + +#include "exp.h" + +struct Decl; + +struct Stm{ + string source_info; + + virtual ~Stm(); + virtual void eval( Block *b )=0; +}; + +struct DebugInfoStm : public Stm{ + void eval( Block *b ); +}; + +struct RemStm : public Stm{ + string comment; + + void eval( Block *b ); +}; + +struct StmStm : public Stm{ + CGStm *stm; + + StmStm( CGStm *s ):stm(s){} + + void eval( Block *b ); +}; + +struct EvalClassBlocksStm : public Stm{ + + void eval( Block *b ); +}; + +struct LabelStm : public Stm{ + CGSym *goto_sym,*restore_sym; + + LabelStm( CGSym *x,CGSym *y ):goto_sym(x),restore_sym(y){} + + void eval( Block *b ); +}; + +struct GotoStm : public Stm{ + string ident; + + GotoStm( string id ):ident(id){} + + void eval( Block *b ); +}; + +struct EvalStm : public Stm{ + Exp *exp; + + EvalStm( Exp *e ):exp(e){} + + void eval( Block *b ); +}; + +struct CtorStm : public Stm{ + ClassBlock *block; + Block *ctor_new; + + CtorStm( ClassBlock *b,Block *n ):block(b),ctor_new(n){} + + void eval( Block *b ); +}; + +struct DtorStm : public Stm{ + ClassBlock *block; + Block *dtor_delete; + + DtorStm( ClassBlock *b,Block *d ):block(b),dtor_delete(d){} + + void eval( Block *b ); +}; + +struct LocalDeclStm : public Stm{ + string ident; + Type *type; + Exp *init; + + LocalDeclStm( string id,Type *ty,Exp *e ):ident(id),type(ty),init(e){} + + void eval( Block *b ); +}; + +struct FieldDeclStm : public Stm{ + string ident; + Type *type; + Exp *init; + + FieldDeclStm( string id,Type *ty,Exp *e ):ident(id),type(ty),init(e){} + + void eval( Block *b ); +}; + +struct GlobalDeclStm : public Stm{ + string ident; + Type *type; + Exp *init; + bool pub; + + GlobalDeclStm( string id,Type *ty,Exp *e,bool p ):ident(id),type(ty),init(e),pub(p){} + + void eval( Block *b ); +}; + +struct ExternDeclStm : public Stm{ + int toke; + string ident; + Type* type; + CGExp* cg; + bool pub; + + ExternDeclStm( int t,string id,Type *ty,CGExp *e,bool p ):toke(t),ident(id),type(ty),cg(e),pub(p){} + + void eval( Block *b ); +}; + +struct ImportStm : public Stm{ + CGExp *entry; + + ImportStm( CGExp *e ):entry(e){} + + void eval( Block *b ); +}; + +struct IncbinStm : public Stm{ + string name,path; + + IncbinStm( string n ); + + void eval( Block *b ); +}; + +struct AssignStm : public Stm{ + Exp *lhs,*rhs; + + AssignStm( Exp *l,Exp *r ):lhs(l),rhs(r){} + + void eval( Block *b ); +}; + +struct OpAssignStm : public Stm{ + int op; + Exp *lhs,*rhs; + + OpAssignStm( int o,Exp *l,Exp *r ):op(o),lhs(l),rhs(r){} + + void eval( Block *b ); +}; + +struct IfStm : public Stm{ + Exp *exp; + Block *then_block,*else_block; + + IfStm( Exp *e,Block *t,Block *l ):exp(e),then_block(t),else_block(l){} + + void eval( Block *b ); +}; + +struct LoopCtrlStm : public Stm{ + int toke; + string label; + + LoopCtrlStm( int t,string l ):toke(t),label(l){} + + void eval( Block *b ); +}; + +struct ForStm : public Stm{ + Exp *var; + Exp *init; + Exp *to; + Exp *step; + bool until; + + LoopBlock *block; + + ForStm( Exp *v,Exp *i,Exp *t,Exp *s,LoopBlock *b,bool u ):var(v),init(i),to(t),step(s),block(b),until(u){} + + void eval( Block *b ); +}; + +struct ForEachStm : public Stm{ + + Exp *var; + Exp *coll; + + LoopBlock *block; + + ForEachStm( Exp *v,Exp *c,LoopBlock *b ):var(v),coll(c),block(b){} + + void eval( Block *b ); + + void evalArray( Block *b,Val *var,Val *arr ); + void evalString( Block *b,Val *var,Val *str ); + void evalCollection( Block *b,Val *var,Val *coll ); + + ObjectType *checkObjMethod( Val *v ); + void checkInt32Method( Val *v ); +}; + +struct WhileStm : public Stm{ + Exp *exp; + LoopBlock *block; + + WhileStm( Exp *e,LoopBlock *b ):exp(e),block(b){} + + void eval( Block *b ); +}; + +struct RepeatStm : public Stm{ + Exp *exp; + LoopBlock *block; + + RepeatStm( Exp *e,LoopBlock *b ):exp(e),block(b){} + + void eval( Block *b ); +}; + +struct ReturnStm : public Stm{ + Exp *exp; + + ReturnStm( Exp *e ):exp(e){} + + void eval( Block *b ); +}; + +struct ReleaseStm : public Stm{ + Exp *exp; + + ReleaseStm( Exp *e ):exp(e){} + + void eval( Block *b ); +}; + +struct DeleteStm : public Stm{ + Exp *exp; + + DeleteStm( Exp *e ):exp(e){} + + void eval( Block *b ); +}; + +struct SelCase{ + ExpSeq exps; + Block *block; + string source_info; + + SelCase( Block *b ):block(b){} +}; + +struct SelectStm : public Stm{ + Exp *exp; + vector cases; + Block *_default; + + SelectStm( Exp *e ):exp(e),_default(0){} + + void eval( Block *b ); +}; + +struct AssertStm : public Stm{ + Exp *exp,*msg; + + AssertStm( Exp *e,Exp *m ):exp(e),msg(m){} + + void eval( Block *b ); +}; + +struct EndStm : public Stm{ + + void eval( Block *b ); +}; + +struct TryCatch{ + string ident; + Type *type; + Block *block; + string source_info; + + TryCatch( Block *b ):block(b){} +}; + +struct TryStm : public Stm{ + Block *block; + vector catches; + + TryStm( Block *b ):block(b){} + + void eval( Block *b ); +}; + +struct ThrowStm : public Stm{ + Exp *exp; + + ThrowStm( Exp *e ):exp(e){} + + void eval( Block *b ); +}; + +struct DataStm : public Stm{ + ExpSeq exps; + + void eval( Block *b ); +}; + +struct ReadStm : public Stm{ + ExpSeq exps; + + void eval( Block *b ); +}; + +struct RestoreStm : public Stm{ + string ident; + + RestoreStm( string id ):ident(id){} + + void eval( Block *b ); +}; + +#endif \ No newline at end of file diff --git a/_src/compiler/toker.cpp b/_src/compiler/toker.cpp new file mode 100644 index 0000000..3da61b6 --- /dev/null +++ b/_src/compiler/toker.cpp @@ -0,0 +1,482 @@ + +#include "std.h" +#include "toker.h" + +struct Stricmp{ + bool operator()( const char *x,const char *y )const{ + while( tolower(*x)==tolower(*y) && *x ){++x;++y;} + return tolower(*x)-tolower(*y)<0; + } +}; + +typedef map TokeMap; + +static TokeMap _tokes; + +static void initTokes(){ + if( _tokes.size() ) return; + + _tokes["Strict"]=T_STRICT; + _tokes["SuperStrict"]=T_SUPERSTRICT; + _tokes["Module"]=T_MODULE; + _tokes["Framework"]=T_FRAMEWORK; + _tokes["Import"]=T_IMPORT; + _tokes["ModuleInfo"]=T_MODULEINFO; + + _tokes["DefData"]=T_DEFDATA; + _tokes["ReadData"]=T_READDATA; + _tokes["RestoreData"]=T_RESTOREDATA; + + _tokes["Rem"]=T_REM; + _tokes["EndRem"]=T_ENDREM; + + _tokes["Try"]=T_TRY; + _tokes["Catch"]=T_CATCH; + _tokes["EndTry"]=T_ENDTRY; + _tokes["Throw"]=T_THROW; + _tokes["Goto"]=T_GOTO; + + _tokes["True"]=T_TRUE; + _tokes["False"]=T_FALSE; + _tokes["Pi"]=T_PI; + + _tokes["Byte"]=T_BYTE; + _tokes["Short"]=T_SHORT; + _tokes["Int"]=T_INT; + _tokes["Long"]=T_LONG; + _tokes["Float"]=T_FLOAT; + _tokes["Double"]=T_DOUBLE; + _tokes["Object"]=T_OBJECT; + _tokes["String"]=T_STRING; + + _tokes["Var"]=T_VAR; + _tokes["Ptr"]=T_PTR; + _tokes["VarPtr"]=T_VARPTR; + + _tokes["Chr"]=T_CHR; + _tokes["Len"]=T_LEN; + _tokes["Asc"]=T_ASC; + _tokes["SizeOf"]=T_SIZEOF; + + _tokes["Sgn"]=T_SGN; + + _tokes["Abs"]=T_ABS; + _tokes["Min"]=T_MIN; + _tokes["Max"]=T_MAX; + _tokes["Mod"]=T_MOD; + + _tokes["Shl"]=T_SHL; + _tokes["Shr"]=T_SHR; + _tokes["Sar"]=T_SAR; + + _tokes["Not"]=T_NOT; + _tokes["And"]=T_AND; + _tokes["Or"]=T_OR; + + _tokes["Return"]=T_RETURN; + + _tokes["Local"]=T_LOCAL; + _tokes["Global"]=T_GLOBAL; + _tokes["Const"]=T_CONST; + _tokes["Field"]=T_FIELD; + _tokes["Alias"]=T_ALIAS; + _tokes["End"]=T_END; + + _tokes["Type"]=T_TYPE; + _tokes["EndType"]=T_ENDTYPE; + _tokes["Extends"]=T_EXTENDS; + + _tokes["Method"]=T_METHOD; + _tokes["EndMethod"]=T_ENDMETHOD; + _tokes["Abstract"]=T_ABSTRACT; + _tokes["Final"]=T_FINAL; + + _tokes["Function"]=T_FUNCTION; + _tokes["EndFunction"]=T_ENDFUNCTION; + + _tokes["New"]=T_NEW; + _tokes["Release"]=T_RELEASE; + _tokes["Delete"]=T_DELETE; + + _tokes["Null"]=T_NULL; + _tokes["Self"]=T_SELF; + _tokes["Super"]=T_SUPER; + + _tokes["Incbin"]=T_INCBIN; + _tokes["IncbinPtr"]=T_INCBINPTR; + _tokes["IncbinLen"]=T_INCBINLEN; + + _tokes["Include"]=T_INCLUDE; + _tokes["Extern"]=T_EXTERN; + _tokes["EndExtern"]=T_ENDEXTERN; + + _tokes["Public"]=T_PUBLIC; + _tokes["Private"]=T_PRIVATE; + + _tokes["If"]=T_IF; + _tokes["Then"]=T_THEN; + _tokes["Else"]=T_ELSE; + _tokes["ElseIf"]=T_ELSEIF; + _tokes["EndIf"]=T_ENDIF; + + _tokes["For"]=T_FOR; + _tokes["To"]=T_TO; + _tokes["Step"]=T_STEP; + _tokes["Next"]=T_NEXT; + _tokes["EachIn"]=T_EACHIN; + + _tokes["While"]=T_WHILE; + _tokes["EndWhile"]=T_WEND; + _tokes["Wend"]=T_WEND; + + _tokes["Repeat"]=T_REPEAT; + _tokes["Until"]=T_UNTIL; + _tokes["Forever"]=T_FOREVER; + + _tokes["Select"]=T_SELECT; + _tokes["Case"]=T_CASE; + _tokes["Default"]=T__DEFAULT; + _tokes["EndSelect"]=T_ENDSELECT; + + _tokes["Continue"]=T_CONTINUE; + _tokes["Exit"]=T_EXIT; + + _tokes["Assert"]=T_ASSERT; + + _tokes["NoDebug"]=T_NODEBUG; +} + +static Toke nextToke( const vector &line,int &p ){ + + int b=p; + int c=line[p++]; + int cur=c; + + if( isalpha(c) || c=='_' ){ + while( isalnum( c=line[p] ) || c=='_' ) ++p; + cur=T_IDENT; + string t( &line[b],p-b ); + TokeMap::iterator it=_tokes.find(t.c_str()); + if( it!=_tokes.end() ){ + cur=it->second; + if( cur==T_END && line[p]==' ' && isalpha(line[p+1]) ){ + int st=p+1,en=p+2; + while( isalpha(line[en]) ) ++en; + string t="end"+string( &line[st],en-st ); + it=_tokes.find(t.c_str()); + if( it!=_tokes.end() ){ + cur=it->second; + p=en; + } + } + } + }else if( isdigit(c) || (c=='.' && isdigit(line[p])) ){ + cur=T_INTCONST; + if( c=='.' ){ + ++p;cur=T_FLOATCONST; + } + while( isdigit(line[p]) ) ++p; + if( cur==T_INTCONST && line[p]=='.' && isdigit(line[p+1]) ){ + p+=2;cur=T_FLOATCONST; + while( isdigit(line[p]) ) ++p; + } + if( tolower(line[p])=='e' && (line[p+1]=='+'||line[p+1]=='-'||isdigit(line[p+1])) ){ + ++p;cur=T_FLOATCONST; + if( !isdigit(line[p]) ) ++p; + while( isdigit(line[p]) ) ++p; + } + }else if( c=='$' && isxdigit(line[p]) ){ + ++p;cur=T_INTCONST; + while( isxdigit(line[p]) ) ++p; + }else if( c=='%' && (line[p]=='0'||line[p]=='1') ){ + ++p;cur=T_INTCONST; + while( line[p]=='0' || line[p]=='1' ) ++p; + }else if( c=='$' && tolower(line[p])=='z' ){ + ++p;cur=T_CSTRING; + }else if( c=='$' && tolower(line[p])=='w' ){ + ++p;cur=T_WSTRING; + }else if( c=='\"' ){ //string const + while( line[p]!='\"' && line[p]!='\n' ) ++p; + if( line[p]=='\"' ){ + cur=T_STRINGCONST; + ++p; + }else{ + cur=T_BADSTRINGCONST; + } + /* + cur=T_STRINGCONST; + while( line[p]!='\"' && line[p]!='\n' ) ++p; + if( line[p++]!='\"' ) cur=T_BADSTRINGCONST; + */ + + }else if( c=='<' ){ //comparison + switch( line[p++] ){ + case '=':cur=T_LE;break; + case '>':cur=T_NE;break; + default:cur=T_LT;--p; + } + }else if( c=='=' ){ //comparison + switch( line[p++] ){ + case '>':cur=T_GE;break; + case '<':cur=T_LE;break; + default:cur=T_EQ;--p; + } + }else if( c=='>' ){ //comparison + switch( line[p++] ){ + case '=':cur=T_GE;break; + case '<':cur=T_NE;break; + default:cur=T_GT;--p; + } + }else if( c==':' ){ + Toke t=nextToke( line,p ); + switch( t.toke ){ + case '+':cur=T_ADDASSIGN;break; + case '-':cur=T_SUBASSIGN;break; + case '*':cur=T_MULASSIGN;break; + case '/':cur=T_DIVASSIGN;break; + case '|':cur=T_ORASSIGN;break; + case '&':cur=T_ANDASSIGN;break; + case '~':cur=T_XORASSIGN;break; + case T_MOD:cur=T_MODASSIGN;break; + case T_SHL:cur=T_SHLASSIGN;break; + case T_SHR:cur=T_SHRASSIGN;break; + case T_SAR:cur=T_SARASSIGN;break; + default:p=b+1; + } + }else if( c=='.' && line[p]=='.' ){ + ++p;cur=T_DOTDOT; + }else if( c=='[' ){ //allow spaces in [,] type tokes + while( line[p]==' ' || line[p]==',' ) ++p; + if( line[p]==']' ){ + ++p;cur=T_ARRAYDECL; + }else{ + p=b+1; + } + } + return Toke( cur,b,p ); +} + +Toker::Toker( string f ):fh(0),toke_index(0),line_num(0),file_name(f){ + initTokes(); + + fh=fopen( file_name.c_str(),"rb" ); + if( !fh ) fail( "Unable to open file '%s'",file_name.c_str() ); + + encoding=UNK; + + next(); +} + +void Toker::close(){ + if( fh ){ + fclose( fh ); + fh=0; + } +} + +string Toker::sourceFile(){ + return file_name; +} + +string Toker::sourceInfo(){ + return file_name+";"+fromint(line_num)+";"+fromint(curr_toke.begin+1); +} + +int Toker::curr(){ + return curr_toke.toke; +} + +string Toker::text(){ + return string( &line[curr_toke.begin],curr_toke.end-curr_toke.begin ); +} + +bstring Toker::wtext(){ + return bstring( &wline[curr_toke.begin],curr_toke.end-curr_toke.begin ); +} + +int Toker::peek( int n ){ + assert( toke_index+n32 && c<127) ? c : ' ' ); + wline.push_back(c); + } + + int p=0; + for(;;){ + int c=line[p]; + if( c=='\'' || c=='\n' ){ + if( tokes.size() && tokes.back().toke==T_DOTDOT ){ + tokes.pop_back(); + break; + } + tokes.push_back( Toke('\n',p,line.size()) ); + break; + }else if( isgraph(c) ){ + tokes.push_back( nextToke(line,p) ); + }else{ + ++p; + } + } +} + +int Toker::next(){ + + if( curr()==EOF ) return EOF; + + while( toke_index==tokes.size() ){ + + nextLine(); + toke_index=0; + + for(;;){ + if( !tokes.size() ){ + nextLine(); + }else if( tokes[0].toke=='?' ){ + ++toke_index; + bool cc=true,cNot=false; + if( toke_index'"; + case T_LE:return "'<='"; + case T_GE:return "'>='"; + case T_EQ:return "'='"; + case T_NE:return "'<>'"; + case T_DOTDOT:return "'..'"; + case T_IDENT:return "identifier"; + case T_INTCONST:return "integer literal"; + case T_FLOATCONST:return "floating point literal"; + case T_STRINGCONST:return "string literal"; + case T_CSTRING:return "cstring tag"; + case T_WSTRING:return "wstring tag"; + case T_ARRAYDECL:return "array declaration"; + case T_BADSTRINGCONST:return "malformed string literal"; + case T_ADDASSIGN:return "add assign"; + case T_SUBASSIGN:return "subtract assign"; + case T_MULASSIGN:return "multiply assign"; + case T_DIVASSIGN:return "divide assign"; + case T_MODASSIGN:return "remainder assign"; + case T_ORASSIGN:return "or assign"; + case T_ANDASSIGN:return "and assign"; + case T_XORASSIGN:return "exclusive or assign"; + case T_SHLASSIGN:return "shift left assign"; + case T_SHRASSIGN:return "shift right assign"; + case T_SARASSIGN:return "Shift arithmetic right assign"; + } + TokeMap::iterator it; + for( it=_tokes.begin();it!=_tokes.end();++it ){ + if( n==it->second ) return it->first; + } + if( isgraph(n) ){ + char c=n; + return "'"+string(&c,1)+"'"; + } + char buf[8]; + sprintf( buf,"%i",n ); + return ""; +} diff --git a/_src/compiler/toker.cpp.bak b/_src/compiler/toker.cpp.bak new file mode 100644 index 0000000..9d17eef --- /dev/null +++ b/_src/compiler/toker.cpp.bak @@ -0,0 +1,472 @@ + +#include "std.h" +#include "toker.h" + +struct Stricmp{ + bool operator()( const char *x,const char *y )const{ + while( tolower(*x)==tolower(*y) && *x ){++x;++y;} + return tolower(*x)-tolower(*y)<0; + } +}; + +typedef map TokeMap; + +static TokeMap _tokes; + +static void initTokes(){ + if( _tokes.size() ) return; + + _tokes["Strict"]=T_STRICT; + _tokes["SuperStrict"]=T_SUPERSTRICT; + _tokes["Module"]=T_MODULE; + _tokes["Framework"]=T_FRAMEWORK; + _tokes["Import"]=T_IMPORT; + _tokes["ModuleInfo"]=T_MODULEINFO; + + _tokes["DefData"]=T_DEFDATA; + _tokes["ReadData"]=T_READDATA; + _tokes["RestoreData"]=T_RESTOREDATA; + + _tokes["Rem"]=T_REM; + _tokes["EndRem"]=T_ENDREM; + + _tokes["Try"]=T_TRY; + _tokes["Catch"]=T_CATCH; + _tokes["EndTry"]=T_ENDTRY; + _tokes["Throw"]=T_THROW; + _tokes["Goto"]=T_GOTO; + + _tokes["True"]=T_TRUE; + _tokes["False"]=T_FALSE; + _tokes["Pi"]=T_PI; + + _tokes["Byte"]=T_BYTE; + _tokes["Short"]=T_SHORT; + _tokes["Int"]=T_INT; + _tokes["Long"]=T_LONG; + _tokes["Float"]=T_FLOAT; + _tokes["Double"]=T_DOUBLE; + _tokes["Object"]=T_OBJECT; + _tokes["String"]=T_STRING; + + _tokes["Var"]=T_VAR; + _tokes["Ptr"]=T_PTR; + _tokes["VarPtr"]=T_VARPTR; + + _tokes["Chr"]=T_CHR; + _tokes["Len"]=T_LEN; + _tokes["Asc"]=T_ASC; + _tokes["SizeOf"]=T_SIZEOF; + + _tokes["Sgn"]=T_SGN; + + _tokes["Abs"]=T_ABS; + _tokes["Min"]=T_MIN; + _tokes["Max"]=T_MAX; + _tokes["Mod"]=T_MOD; + + _tokes["Shl"]=T_SHL; + _tokes["Shr"]=T_SHR; + _tokes["Sar"]=T_SAR; + + _tokes["Not"]=T_NOT; + _tokes["And"]=T_AND; + _tokes["Or"]=T_OR; + + _tokes["Return"]=T_RETURN; + + _tokes["Local"]=T_LOCAL; + _tokes["Global"]=T_GLOBAL; + _tokes["Const"]=T_CONST; + _tokes["Field"]=T_FIELD; + _tokes["Alias"]=T_ALIAS; + _tokes["End"]=T_END; + + _tokes["Type"]=T_TYPE; + _tokes["EndType"]=T_ENDTYPE; + _tokes["Extends"]=T_EXTENDS; + + _tokes["Method"]=T_METHOD; + _tokes["EndMethod"]=T_ENDMETHOD; + _tokes["Abstract"]=T_ABSTRACT; + _tokes["Final"]=T_FINAL; + + _tokes["Function"]=T_FUNCTION; + _tokes["EndFunction"]=T_ENDFUNCTION; + + _tokes["New"]=T_NEW; + _tokes["Release"]=T_RELEASE; + _tokes["Delete"]=T_DELETE; + + _tokes["Null"]=T_NULL; + _tokes["Self"]=T_SELF; + _tokes["Super"]=T_SUPER; + + _tokes["Incbin"]=T_INCBIN; + _tokes["IncbinPtr"]=T_INCBINPTR; + _tokes["IncbinLen"]=T_INCBINLEN; + + _tokes["Include"]=T_INCLUDE; + _tokes["Extern"]=T_EXTERN; + _tokes["EndExtern"]=T_ENDEXTERN; + + _tokes["Public"]=T_PUBLIC; + _tokes["Private"]=T_PRIVATE; + + _tokes["If"]=T_IF; + _tokes["Then"]=T_THEN; + _tokes["Else"]=T_ELSE; + _tokes["ElseIf"]=T_ELSEIF; + _tokes["EndIf"]=T_ENDIF; + + _tokes["For"]=T_FOR; + _tokes["To"]=T_TO; + _tokes["Step"]=T_STEP; + _tokes["Next"]=T_NEXT; + _tokes["EachIn"]=T_EACHIN; + + _tokes["While"]=T_WHILE; + _tokes["EndWhile"]=T_WEND; + _tokes["Wend"]=T_WEND; + + _tokes["Repeat"]=T_REPEAT; + _tokes["Until"]=T_UNTIL; + _tokes["Forever"]=T_FOREVER; + + _tokes["Select"]=T_SELECT; + _tokes["Case"]=T_CASE; + _tokes["Default"]=T__DEFAULT; + _tokes["EndSelect"]=T_ENDSELECT; + + _tokes["Continue"]=T_CONTINUE; + _tokes["Exit"]=T_EXIT; + + _tokes["Assert"]=T_ASSERT; + + _tokes["NoDebug"]=T_NODEBUG; +} + +static Toke nextToke( const vector &line,int &p ){ + + int b=p; + int c=line[p++]; + int cur=c; + + if( isalpha(c) || c=='_' ){ + while( isalnum( c=line[p] ) || c=='_' ) ++p; + cur=T_IDENT; + string t( &line[b],p-b ); + TokeMap::iterator it=_tokes.find(t.c_str()); + if( it!=_tokes.end() ){ + cur=it->second; + if( cur==T_END && line[p]==' ' && isalpha(line[p+1]) ){ + int st=p+1,en=p+2; + while( isalpha(line[en]) ) ++en; + string t="end"+string( &line[st],en-st ); + it=_tokes.find(t.c_str()); + if( it!=_tokes.end() ){ + cur=it->second; + p=en; + } + } + } + }else if( isdigit(c) || (c=='.' && isdigit(line[p])) ){ + cur=T_INTCONST; + if( c=='.' ){ + ++p;cur=T_FLOATCONST; + } + while( isdigit(line[p]) ) ++p; + if( cur==T_INTCONST && line[p]=='.' && isdigit(line[p+1]) ){ + p+=2;cur=T_FLOATCONST; + while( isdigit(line[p]) ) ++p; + } + if( tolower(line[p])=='e' && (line[p+1]=='+'||line[p+1]=='-'||isdigit(line[p+1])) ){ + ++p;cur=T_FLOATCONST; + if( !isdigit(line[p]) ) ++p; + while( isdigit(line[p]) ) ++p; + } + }else if( c=='$' && isxdigit(line[p]) ){ + ++p;cur=T_INTCONST; + while( isxdigit(line[p]) ) ++p; + }else if( c=='%' && (line[p]=='0'||line[p]=='1') ){ + ++p;cur=T_INTCONST; + while( line[p]=='0' || line[p]=='1' ) ++p; + }else if( c=='$' && tolower(line[p])=='z' ){ + ++p;cur=T_CSTRING; + }else if( c=='$' && tolower(line[p])=='w' ){ + ++p;cur=T_WSTRING; + }else if( c=='\"' ){ //string const + cur=T_STRINGCONST; + while( line[p]!='\"' && line[p]!='\n' ) ++p; + if( line[p++]!='\"' ) cur=T_BADSTRINGCONST; + }else if( c=='<' ){ //comparison + switch( line[p++] ){ + case '=':cur=T_LE;break; + case '>':cur=T_NE;break; + default:cur=T_LT;--p; + } + }else if( c=='=' ){ //comparison + switch( line[p++] ){ + case '>':cur=T_GE;break; + case '<':cur=T_LE;break; + default:cur=T_EQ;--p; + } + }else if( c=='>' ){ //comparison + switch( line[p++] ){ + case '=':cur=T_GE;break; + case '<':cur=T_NE;break; + default:cur=T_GT;--p; + } + }else if( c==':' ){ + Toke t=nextToke( line,p ); + switch( t.toke ){ + case '+':cur=T_ADDASSIGN;break; + case '-':cur=T_SUBASSIGN;break; + case '*':cur=T_MULASSIGN;break; + case '/':cur=T_DIVASSIGN;break; + case '|':cur=T_ORASSIGN;break; + case '&':cur=T_ANDASSIGN;break; + case '~':cur=T_XORASSIGN;break; + case T_MOD:cur=T_MODASSIGN;break; + case T_SHL:cur=T_SHLASSIGN;break; + case T_SHR:cur=T_SHRASSIGN;break; + case T_SAR:cur=T_SARASSIGN;break; + default:p=b+1; + } + }else if( c=='.' && line[p]=='.' ){ + ++p;cur=T_DOTDOT; + }else if( c=='[' ){ //allow spaces in [,] type tokes + while( line[p]==' ' || line[p]==',' ) ++p; + if( line[p]==']' ){ + ++p;cur=T_ARRAYDECL; + }else{ + p=b+1; + } + } + return Toke( cur,b,p ); +} + +Toker::Toker( string f ):fh(0),toke_index(0),line_num(0),file_name(f){ + initTokes(); + + fh=fopen( file_name.c_str(),"rb" ); + if( !fh ) fail( "Unable to open file '%s'",file_name.c_str() ); + + encoding=UNK; + + next(); +} + +void Toker::close(){ + if( fh ){ + fclose( fh ); + fh=0; + } +} + +string Toker::sourceFile(){ + return file_name; +} + +string Toker::sourceInfo(){ + return file_name+";"+fromint(line_num)+";"+fromint(curr_toke.begin+1); +} + +int Toker::curr(){ + return curr_toke.toke; +} + +string Toker::text(){ + return string( &line[curr_toke.begin],curr_toke.end-curr_toke.begin ); +} + +bstring Toker::wtext(){ + return bstring( &wline[curr_toke.begin],curr_toke.end-curr_toke.begin ); +} + +int Toker::peek( int n ){ + assert( toke_index+n32 && c<127) ? c : ' ' ); + wline.push_back(c); + } + + int p=0; + for(;;){ + int c=line[p]; + if( c=='\'' || c=='\n' ){ + if( tokes.size() && tokes.back().toke==T_DOTDOT ){ + tokes.pop_back(); + break; + } + tokes.push_back( Toke('\n',p,line.size()) ); + break; + }else if( isgraph(c) ){ + tokes.push_back( nextToke(line,p) ); + }else{ + ++p; + } + } +} + +int Toker::next(){ + + if( curr()==EOF ) return EOF; + + while( toke_index==tokes.size() ){ + + nextLine(); + toke_index=0; + + for(;;){ + if( !tokes.size() ){ + nextLine(); + }else if( tokes[0].toke=='?' ){ + ++toke_index; + bool cc=true,cNot=false; + if( toke_index'"; + case T_LE:return "'<='"; + case T_GE:return "'>='"; + case T_EQ:return "'='"; + case T_NE:return "'<>'"; + case T_DOTDOT:return "'..'"; + case T_IDENT:return "identifier"; + case T_INTCONST:return "integer literal"; + case T_FLOATCONST:return "floating point literal"; + case T_STRINGCONST:return "string literal"; + case T_CSTRING:return "cstring tag"; + case T_WSTRING:return "wstring tag"; + case T_ARRAYDECL:return "array declaration"; + case T_BADSTRINGCONST:return "malformed string literal"; + case T_ADDASSIGN:return "add assign"; + case T_SUBASSIGN:return "subtract assign"; + case T_MULASSIGN:return "multiply assign"; + case T_DIVASSIGN:return "divide assign"; + case T_MODASSIGN:return "remainder assign"; + case T_ORASSIGN:return "or assign"; + case T_ANDASSIGN:return "and assign"; + case T_XORASSIGN:return "exclusive or assign"; + case T_SHLASSIGN:return "shift left assign"; + case T_SHRASSIGN:return "shift right assign"; + case T_SARASSIGN:return "Shift arithmetic right assign"; + } + TokeMap::iterator it; + for( it=_tokes.begin();it!=_tokes.end();++it ){ + if( n==it->second ) return it->first; + } + if( isgraph(n) ){ + char c=n; + return "'"+string(&c,1)+"'"; + } + char buf[8]; + sprintf( buf,"%i",n ); + return ""; +} diff --git a/_src/compiler/toker.h b/_src/compiler/toker.h new file mode 100644 index 0000000..41a4cc0 --- /dev/null +++ b/_src/compiler/toker.h @@ -0,0 +1,119 @@ + +#ifndef TOKER_H +#define TOKER_H + +struct Toke{ + int toke; + int begin,end; + + Toke():toke(0),begin(0),end(0){} + Toke( int n,int b,int e ):toke(n),begin(b),end(e){} +}; + +struct Toker{ + FILE* fh; + + enum{ + UNK=0,LATIN1=1,UTF8=2,UTF16BE=3,UTF16LE=4 + }; + Toke curr_toke; + int toke_index; + int encoding; + vector line; + vector wline; + vector tokes; + + int line_num; + string file_name; + + Toker( string file ); + void close(); + + int curr(); + int next(); + string text(); + bstring wtext(); + int peek( int n ); + void nextLine(); + int tgetc(); + + string sourceFile(); + string sourceInfo(); + + static string toString( int n ); +}; + +enum{ + T_NOP=0x80000000, + + //non-ident + T_DOTDOT, + + T_ARRAYDECL, + + T_LT,T_EQ,T_GT,T_LE,T_GE,T_NE, + + T_IDENT,T_INTCONST,T_FLOATCONST,T_STRINGCONST,T_BADSTRINGCONST,T_CSTRING,T_WSTRING, + + //ident + T_STRICT,T_SUPERSTRICT,T_MODULE,T_FRAMEWORK,T_IMPORT,T_MODULEINFO, + + T_DEFDATA,T_READDATA,T_RESTOREDATA, + + T_REM,T_ENDREM, + + T_TRY,T_CATCH,T_ENDTRY,T_THROW,T_GOTO, + + T_TRUE,T_FALSE,T_PI, + + T_BYTE,T_SHORT,T_INT,T_LONG,T_FLOAT,T_DOUBLE,T_OBJECT,T_STRING, + + T_VAR,T_PTR,T_VARPTR, + + T_CHR, + T_LEN,T_ASC,T_SIZEOF, + + T_SGN, + T_ABS,T_MIN,T_MAX,T_MOD, + T_SHL,T_SHR,T_SAR, + T_NOT,T_AND,T_OR, + + T_ADDASSIGN,T_SUBASSIGN,T_MULASSIGN,T_DIVASSIGN,T_MODASSIGN, + T_ORASSIGN,T_ANDASSIGN,T_XORASSIGN,T_SHLASSIGN,T_SHRASSIGN,T_SARASSIGN, + + T_RETURN,T_LOCAL,T_GLOBAL,T_CONST,T_FIELD,T_ALIAS,T_END, + + T_TYPE,T_ENDTYPE,T_EXTENDS, + + T_METHOD,T_ENDMETHOD,T_ABSTRACT,T_FINAL, + + T_FUNCTION,T_ENDFUNCTION, + + T_NEW,T_RELEASE,T_DELETE, + + T_NULL,T_SELF,T_SUPER, + + T_INCBIN,T_INCBINPTR,T_INCBINLEN, + + T_INCLUDE,T_EXTERN,T_ENDEXTERN, + + T_PUBLIC,T_PRIVATE, + + T_IF,T_THEN,T_ELSE,T_ELSEIF,T_ENDIF, + + T_FOR,T_TO,T_STEP,T_NEXT,T_EACHIN, + + T_WHILE,T_WEND, + + T_REPEAT,T_UNTIL,T_FOREVER, + + T_SELECT,T_CASE,T__DEFAULT,T_ENDSELECT, + + T_EXIT,T_CONTINUE, + + T_ASSERT, + + T_NODEBUG +}; + +#endif diff --git a/_src/compiler/type.cpp b/_src/compiler/type.cpp new file mode 100644 index 0000000..74c9641 --- /dev/null +++ b/_src/compiler/type.cpp @@ -0,0 +1,693 @@ + +#include "std.h" +#include "decl.h" + +using namespace CG; + +static vector _classTypes; +static vector _objectTypes; +static vector _ptrTypes; + +IntType *Type::int8; +IntType *Type::int16; +IntType *Type::int32; +IntType *Type::int64; +FloatType *Type::float32; +FloatType *Type::float64; +CStringType *Type::c_string; +WStringType *Type::w_string; +PtrType *Type::bytePtr; +NullType *Type::null; +ModuleType *Type::blitzModule; +ObjectType *Type::objectObject; +StringType *Type::stringObject; +Val *Type::objectClass,*Type::stringClass,*Type::arrayClass; + +void Type::createTypes(){ + + int8=new IntType(1); + int16=new IntType(2); + int32=new IntType(4); + int64=new IntType(8); + float32=new FloatType(4); + float64=new FloatType(8); + c_string=new CStringType(); + w_string=new WStringType(); + bytePtr=new PtrType(new IntType(1)); + null=new NullType(); + + objectClass=new Val((Type*)0,(CGExp*)0); + objectObject=new ObjectType(0); + objectObject->ident="Object"; + objectObject->class_val=objectClass; + + stringClass=new Val((Type*)0,(CGExp*)0); + stringObject=new StringType(0); + stringObject->ident="String"; + stringObject->class_val=stringClass; + + arrayClass=new Val((Type*)0,(CGExp*)0); + + blitzModule=new ModuleType(); +} + +void Type::resolveTypes(){ + int k; + for( k=0;k<_classTypes.size();++k ) _classTypes[k]->resolve(); + for( k=0;k<_objectTypes.size();++k ) _objectTypes[k]->resolve(); + for( k=0;k<_ptrTypes.size();++k ) _ptrTypes[k]->resolve(); +} + +//********************* Type ********************** +Type::~Type(){ +} +NumericType *Type::numericType(){ + return 0; +} +IntType *Type::intType(){ + return 0; +} +FloatType *Type::floatType(){ + return 0; +} +StringType *Type::stringType(){ + return 0; +} +CStringType *Type::cstringType(){ + return 0; +} +WStringType *Type::wstringType(){ + return 0; +} +ArrayType *Type::arrayType(){ + return 0; +} +ClassType *Type::classType(){ + return 0; +} +ObjectType *Type::objectType(){ + return 0; +} +ObjectType *Type::exObjectType(){ + return 0; +} +FunType *Type::funType(){ + return 0; +} +PtrType *Type::ptrType(){ + return 0; +} +VarType *Type::varType(){ + return 0; +} +RefType *Type::refType(){ + return 0; +} +NullType *Type::nullType(){ + return 0; +} +ModuleType *Type::moduleType(){ + return 0; +} +string Type::encoding(){ + return "?"; +} +string Type::toString(){ + return ""; +} +bool Type::equals( Type *ty ){ + return false; +} +bool Type::extends( Type *ty ){ + return equals(ty); +} +int Type::size(){ + switch( cgType() ){ + case CG_VOID:return 0; + case CG_INT8:return 1; + case CG_INT16:return 2; + case CG_INT32:return 4; + case CG_INT64:return 8; + case CG_FLOAT32:return 4; + case CG_FLOAT64:return 8; + case CG_PTR:return 4; + } + assert(0); + return 0; +} +int Type::cgType(){ + switch( encoding()[0] ){ + case '?':return CG_VOID; + case 'b':return CG_INT8; + case 's':return CG_INT16; + case 'i':return CG_INT32; + case 'l':return CG_INT64; + case 'f':return CG_FLOAT32; + case 'd':return CG_FLOAT64; + } + return CG_PTR; +} +PtrType *Type::ptrType( string valEncoding ){ + PtrType *p=ptrType(); + return (p && p->val_type->encoding()==valEncoding) ? p : 0; +} + +//****************** NumericType ****************** +NumericType::NumericType( int sz,bool fp ){ + switch( sz ){ + case 1:assert(!fp);_encoding="b";break; + case 2:assert(!fp);_encoding="s";break; + case 4:_encoding=fp ? "f" : "i";break; + case 8:_encoding=fp ? "d" : "l";break; + default:assert(0); + } +} + +NumericType *NumericType::numericType(){ + return this; +} + +string NumericType::encoding(){ + return _encoding; +} + +string NumericType::toString(){ + switch( encoding()[0] ){ + case 'b':return "Byte"; + case 's':return "Short"; + case 'i':return "Int"; + case 'l':return "Long"; + case 'f':return "Float"; + case 'd':return "Double"; + default:assert(0); + } + return ""; +} + +bool NumericType::equals( Type *ty ){ + NumericType *t=ty->numericType(); + return t && encoding()==t->encoding(); +} + +//******************** IntType ******************** +IntType *IntType::intType(){ + return this; +} + +//******************* FloatType ******************* +FloatType *FloatType::floatType(){ + return this; +} + +//***************** CStringType ******************* +CStringType *CStringType::cstringType(){ + return this; +} + +string CStringType::encoding(){ + return "z"; +} + +string CStringType::toString(){ + return "CString"; +} + +bool CStringType::equals( Type *ty ){ + return ty->cstringType() ? true : false; +} + +//***************** WStringType ******************* +WStringType *WStringType::wstringType(){ + return this; +} + +string WStringType::encoding(){ + return "w"; +} + +string WStringType::toString(){ + return "WString"; +} + +bool WStringType::equals( Type *ty ){ + return ty->wstringType() ? true : false; +} + +//******************* StringType ****************** +StringType::StringType( Val *clas ):ObjectType(clas){ +} + +StringType *StringType::stringType(){ + return this; +} + +string StringType::encoding(){ + return "$"; +} + +string StringType::toString(){ + return "String"; +} + +bool StringType::equals( Type *ty ){ + return ty->stringType() ? true : false; +} + +//****************** ArrayType ******************** +ArrayType::ArrayType( Type *ty,int n ):ObjectType(arrayClass),element_type(ty),dims(n){ +} + +ArrayType *ArrayType::arrayType(){ + return this; +} + +string ArrayType::encoding(){ + return "["+string(dims-1,',')+"]"+element_type->encoding(); +} + +string ArrayType::toString(){ + return element_type->toString()+" Array"; +} + +bool ArrayType::equals( Type *ty ){ + ArrayType *t=ty->arrayType(); + return t && dims==t->dims && element_type->equals(t->element_type); +} + +bool ArrayType::extends( Type *ty ){ + ArrayType *t=ty->arrayType(); + if( !t ) return ObjectType::extends( ty ); + return t && dims==t->dims && element_type->extends(t->element_type); +} + +//****************** ClassType ******************** +ClassType::ClassType( string supername,Scope *sc,int attrs ): +super_name(supername),scope(sc),attrs(attrs), +sizeof_fields(0),sizeof_vtable(0),super_val(0),super_class(0),resolved(0){ + sourceinfo=source_info; + _classTypes.push_back(this); +} + +void ClassType::resolve(){ + if( resolved==1 ) return; + source_info=sourceinfo; + if( resolved==-1 ) fail( "Cyclic type dependancy" ); + resolved=-1; + + //resolve super + if( super_name.size() ){ + if( super_val=scope->findTypeIdent( super_name ) ){ + super_class=super_val->type->classType(); + } + if( !super_class ) badty( super_name ); + super_class->resolve(); + if( super_class->attrs & ClassType::FINAL ) fail( "Final types cannot be extended" ); + if( (attrs & ClassType::EXTERN) && !(super_class->attrs & ClassType::EXTERN) ) fail( "Extern types can only extends other extern types" ); + if( (super_class->attrs & ClassType::EXTERN) && !(attrs & ClassType::EXTERN) ) fail( "Extern types can only be extended by other extern types" ); + sizeof_fields=super_class->sizeof_fields; + sizeof_vtable=super_class->sizeof_vtable; + }else if( attrs & EXTERN ){ + sizeof_fields=4; + sizeof_vtable=0; + }else{ + sizeof_fields=8; + sizeof_vtable=16; + } + + //resolve fields + int k; + for( k=0;kval->type; + + int sz=type->size(); + sizeof_fields=(sizeof_fields+sz-1)/sz*sz; + + CGExp *e=mem( type->cgType(),tmp(CG_PTR,"@self"),sizeof_fields ); + + Decl *t=new Decl( d->ident,type,e ); + t->setMetaData( d->meta ); + + decls.push_back( t ); + sizeof_fields+=sz; + } + + //resolve methods + for( k=0;kval->type->funType(); + + CGExp *e; + Val *v=findSuperMethod(d->ident); + + if( (attrs & FINAL) || (type->attrs & FunType::FINAL) ){ + e=d->val->cg_exp; + if( type->method() ) e=vfn( e,tmp(CG_PTR,"@self") ); + if( !v ) sizeof_vtable+=4; + }else if( v ){ + e=v->cg_exp; + }else{ + e=mem( CG_PTR,tmp(CG_PTR,"@type"),sizeof_vtable ); + if( type->method() ) e=vfn( e,tmp(CG_PTR,"@self") ); + sizeof_vtable+=4; + } + + Decl *t=new Decl( d->ident,type,e ); + t->setMetaData( d->meta ); + + decls.push_back( t ); + } + + resolved=1; +} + +ClassType *ClassType::classType(){ + return this; +} + +Val *ClassType::superVal(){ + return super_val; +} + +ClassType *ClassType::superClass(){ + return super_class; +} + +string ClassType::encoding(){ + return "^"; +} + +string ClassType::toString(){ + return "Type"; +} + +bool ClassType::equals( Type *ty ){ + return this==ty->classType(); +} + +bool ClassType::extends( Type *ty ){ + ClassType *c=ty->classType(); + if( !c ) return false; + ClassType *t; + for( t=this;t;t=t->super_class ){ + if( t==ty ) return true; + } + return false; +} + +Val *ClassType::find( string id ){ + ClassType *t; + for( t=this;t;t=t->superClass() ){ + Val *v=t->decls.find(id); + if( v && !v->countTmps( "@self" ) ) return v; + } + return 0; +} + +Val *ClassType::findMethod( string id ){ + ClassType *t; + for( t=this;t;t=t->super_class ){ + if( t->methods.find(id) ) return t->decls.find(id); + } + return 0; +} + +Val *ClassType::findSuperMethod( string id ){ + return super_class ? super_class->findMethod( id ) : 0; +} + +//****************** ObjectType ******************* +ObjectType::ObjectType( Val *clas ):ident(""),scope(0),class_val(clas){ +} + +ObjectType::ObjectType( string id,Scope *sc ):ident(id),scope(sc),class_val(0){ + sourceinfo=source_info; + _objectTypes.push_back( this ); +} + +ObjectType *ObjectType::objectType(){ + if( objectClass()->attrs & ClassType::EXTERN ) return 0; + return this; +} + +ObjectType *ObjectType::exObjectType(){ + if( objectClass()->attrs & ClassType::EXTERN ) return this; + return 0; +} + +void ObjectType::resolve(){ + if( class_val ) return; + + source_info=sourceinfo; + + class_val=scope->findTypeIdent( ident ); + + if( !class_val ) badid( ident ); + + if( !class_val->type->classType() ) fail( "expecting type name" ); +} + +string ObjectType::encoding(){ +// if( objectClass()->attrs & ClassType::EXTERN ) return "?"+ident; + return ":"+ident; +} + +string ObjectType::toString(){ + return ident; +} + +bool ObjectType::equals( Type *ty ){ + ObjectType *o=objectType() ? ty->objectType() : ty->exObjectType(); + return o ? objectClass()==o->objectClass() : false; +} + +bool ObjectType::extends( Type *ty ){ + ObjectType *o=objectType() ? ty->objectType() : ty->exObjectType(); + return o && objectClass()->extends(o->objectClass()); +} + +Val *ObjectType::find( string id ){ + ClassType *t; + for( t=objectClass();t;t=t->superClass() ){ + if( Val *v=t->decls.find(id) ) return v; + } + return 0; +} + +ClassType *ObjectType::objectClass(){ + return class_val->type->classType(); +} + +//******************** FunType ******************** +FunType::FunType( Type *ty,int attrs ):return_type(ty),attrs(attrs),call_conv(CG_CDECL){ +} + +FunType *FunType::funType(){ + return this; +} + +string FunType::encoding(){ + string t="("; + for( int k=0;kval->type->encoding(); + } + return t+")"+return_type->encoding(); +} + +string FunType::toString(){ + string t=return_type->toString()+"("; + for( int k=0;kval->type->toString(); + } + return t+")"; +} + +bool FunType::equals( Type *ty ){ + FunType *f=ty->funType(); + if( !f ) return false; + + if( method()!=f->method() || args.size()!=f->args.size() ) return false; + + if( !return_type->equals(f->return_type) ) return false; + + for( int k=0;kval->type->equals(f->args[k]->val->type) ) return false; + } + + return true; +} + +bool FunType::extends( Type *ty ){ + FunType *f=ty->funType(); + if( !f) return false; + + if( method()!=f->method() || args.size()!=f->args.size() ) return false; + + if( ObjectType *t=return_type->objectType() ){ + ObjectType *p=f->return_type->objectType(); + if( !p || !t->objectClass()->extends(p->objectClass()) ) return false; + }else{ + if( !return_type->equals(f->return_type) ) return false; + } + + for( int k=0;kval->type->equals(f->args[k]->val->type) ) return false; + } + return true; +} + +bool FunType::method(){ + return !!(attrs & METHOD); +} + +//******************** PtrType ******************** +PtrType::PtrType( Type *ty ):val_type(ty){ + _ptrTypes.push_back( this ); + sourceinfo=source_info; +} + +PtrType *PtrType::ptrType(){ + return this; +} + +void PtrType::resolve(){ + source_info=sourceinfo; + if( val_type->ptrType() || val_type->numericType() || val_type->exObjectType() ) return; + fail( "Illegal pointer type" ); +} + +string PtrType::encoding(){ + return "*"+val_type->encoding(); +} + +string PtrType::toString(){ + return val_type->toString()+ " Ptr"; +} + +bool PtrType::equals( Type *ty ){ + PtrType *t=ty->ptrType(); + return t && val_type->equals(t->val_type); +} + +//******************** VarType ******************** +VarType *VarType::varType(){ + return this; +} + +string VarType::encoding(){ + return "*"+val_type->encoding(); +} + +string VarType::toString(){ + return val_type->toString()+" Var"; +} + +bool VarType::equals( Type *ty ){ + VarType *t=ty->varType(); + return t && val_type->equals(t->val_type); +} + +//******************** AliasType ******************** +AliasType::AliasType( Type *ty ):val_type(ty){ +} + +NumericType *AliasType::numericType(){ + return val_type->numericType(); +} + +IntType *AliasType::intType(){ + return val_type->intType(); +} + +FloatType *AliasType::floatType(){ + return val_type->floatType(); +} + +ClassType *AliasType::classType(){ + return val_type->classType(); +} + +ObjectType *AliasType::objectType(){ + return val_type->objectType(); +} + +ObjectType *AliasType::exObjectType(){ + return val_type->exObjectType(); +} + +StringType *AliasType::stringType(){ + return val_type->stringType(); +} + +ArrayType *AliasType::arrayType(){ + return val_type->arrayType(); +} + +FunType *AliasType::funType(){ + return val_type->funType(); +} + +PtrType *AliasType::ptrType(){ + return val_type->ptrType(); +} + +ModuleType *AliasType::moduleType(){ + return val_type->moduleType(); +} + +string AliasType::encoding(){ + return val_type->encoding(); +} + +string AliasType::toString(){ + return val_type->toString(); +} + +bool AliasType::equals( Type *ty ){ + return val_type->equals(ty); +} + +bool AliasType::extends( Type *ty ){ + return val_type->extends(ty); +} + +Val *AliasType::find( string id ){ + return val_type->find(id); +} + +//***************** Reference Type **************** +RefType *RefType::refType(){ + return this; +} + +//***************** Null Type ********************* +NullType *NullType::nullType(){ + return this; +} + +string NullType::toString(){ + return "null"; +} + +bool NullType::equals( Type *ty ){ + return !!ty->nullType(); +} + +//***************** Module Type ******************* +ModuleType *ModuleType::moduleType(){ + return this; +} + +string ModuleType::toString(){ + return "module"; +} + +bool ModuleType::equals( Type *ty ){ + return this==ty; +} + +Val *ModuleType::find( string id ){ + return decls.find(id); +} diff --git a/_src/compiler/type.h b/_src/compiler/type.h new file mode 100644 index 0000000..46c4136 --- /dev/null +++ b/_src/compiler/type.h @@ -0,0 +1,313 @@ + +#ifndef TYPE_H +#define TYPE_H + +#include "scope.h" +#include "declseq.h" + +struct Val; + +/* + +Runtime type Encoding: + +b=byte +s=short +i=int +f=float +d=double +z=cstring +$=string +[]=array +^.=class +:.=object +(,...)=function +*=pointer + +*/ + +struct NumericType; +struct IntType; +struct FloatType; +struct StringType; +struct CStringType; +struct WStringType; +struct ArrayType; +struct ClassType; +struct ObjectType; +struct FunType; +struct PtrType; +struct VarType; +struct RefType; +struct NullType; +struct ModuleType; + +struct Type : public Scope{ + virtual ~Type(); + + virtual NumericType*numericType(); + virtual IntType* intType(); + virtual FloatType* floatType(); + virtual StringType* stringType(); + virtual CStringType*cstringType(); + virtual WStringType*wstringType(); + virtual ClassType* classType(); + virtual ObjectType* objectType(); + virtual ObjectType* exObjectType(); + virtual ArrayType* arrayType(); + virtual FunType* funType(); + + virtual PtrType* ptrType(); + virtual VarType* varType(); + virtual RefType* refType(); + virtual NullType* nullType(); + virtual ModuleType* moduleType(); + + virtual string encoding(); + virtual string toString(); + virtual bool equals( Type *ty ); + virtual bool extends( Type *ty ); + + int size(); + int cgType(); + PtrType* ptrType( string valEncoding ); + + static void createTypes(); + static void resolveTypes(); + + static IntType *int8,*int16,*int32,*int64; + static FloatType *float32,*float64; + static CStringType *c_string; + static WStringType *w_string; + static PtrType *bytePtr; + static NullType *null; + static ModuleType *blitzModule; + static ObjectType *objectObject; + static StringType *stringObject; + static Val *objectClass,*stringClass,*arrayClass; +}; + +struct NumericType : public Type{ + string _encoding; + + NumericType( int sz,bool fp ); + + NumericType *numericType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); +}; + +struct IntType : public NumericType{ + IntType( int sz ):NumericType( sz,false ){} + + IntType *intType(); +}; + +struct FloatType : public NumericType{ + FloatType( int sz ):NumericType( sz,true ){} + + FloatType *floatType(); +}; + +struct CStringType : public Type{ + CStringType *cstringType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); +}; + +struct WStringType : public Type{ + WStringType *wstringType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); +}; + +struct ClassType : public Type{ + enum{ + ABSTRACT=1,FINAL=2,EXTERN=4,PRIVATE=8 + }; + + string super_name; + Scope* scope; + DeclSeq decls,fields,methods; + int attrs,sizeof_fields,sizeof_vtable; + + ClassType( string supername,Scope *sc,int attrs=0 ); + + ClassType*classType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); + bool extends( Type *ty ); + Val* find( string id ); + + Val* findMethod( string id ); + Val* findSuperMethod( string id ); + + void resolve(); + + Val* superVal(); + + ClassType*superClass(); + +private: + int resolved; + Val* super_val; + ClassType*super_class; + string sourceinfo; +}; + +struct ObjectType : public Type{ + string ident; + Scope *scope; + Val *class_val; + string sourceinfo; + + ObjectType( Val *clas ); + ObjectType( string id,Scope *sc ); + + ObjectType *objectType(); + ObjectType *exObjectType(); + + void resolve(); + string encoding(); + string toString(); + bool equals( Type *ty ); + bool extends( Type *ty ); + Val* find( string id ); + + Val* classVal(); + ClassType *objectClass(); +}; + +struct StringType : public ObjectType{ + + StringType( Val *clas ); + + StringType *stringType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); +}; + +struct ArrayType : public ObjectType{ + Type *element_type; + int dims; + + ArrayType( Type *ty,int n ); + + ArrayType *arrayType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); + bool extends( Type *ty ); +}; + +struct FunType : public Type{ + enum{ + ABSTRACT=1,FINAL=2,METHOD=4,VOIDFUN=8 + }; + DeclSeq args; + Type *return_type; + int attrs,call_conv; + + FunType( Type *ty,int at=0 ); + + FunType *funType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); + bool extends( Type *ty ); + bool method(); +}; + +struct PtrType : public Type{ + Type *val_type; + string sourceinfo; + + PtrType( Type *ty ); + + PtrType *ptrType(); + + void resolve(); + + string encoding(); + string toString(); + bool equals( Type *ty ); +}; + +struct VarType : public Type{ + Type *val_type; + + VarType( Type *ty ):val_type(ty){} + + VarType *varType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); +}; + +struct AliasType : public Type{ + Type *val_type; + + AliasType( Type *ty ); + + NumericType*numericType(); + IntType* intType(); + FloatType* floatType(); + StringType* stringType(); + ClassType* classType(); + ObjectType* objectType(); + ObjectType* exObjectType(); + ArrayType* arrayType(); + FunType* funType(); + PtrType* ptrType(); + ModuleType* moduleType(); + + string encoding(); + string toString(); + bool equals( Type *ty ); + bool extends( Type *ty ); + Val* find( string id ); +}; + +struct RefType : public AliasType{ + enum{ + VARPARAM=1 + }; + int attrs; + + RefType( Type *ty,int at=0 ):AliasType(ty),attrs(at){} + + RefType* refType(); +}; + +struct NullType : public Type{ + + NullType *nullType(); + + string toString(); + bool equals( Type *ty ); +}; + +struct ModuleType : public Type{ + DeclSeq decls; + + ModuleType* moduleType(); + + string toString(); + bool equals( Type *ty ); + Val* find( string id ); +}; + +#endif diff --git a/_src/compiler/val.cpp b/_src/compiler/val.cpp new file mode 100644 index 0000000..c103789 --- /dev/null +++ b/_src/compiler/val.cpp @@ -0,0 +1,662 @@ + +#include "std.h" +#include "val.h" +#include "block.h" + +using namespace CG; + +static CGLit *literal( CGExp *e ){ + if( CGLit *t=e->lit() ) return t; + if( CGDat *t=e->dat() ){ + if( t->exps.size()==3 ) return t->exps[2]->lit(); + } + if( CGSym *t=e->sym() ){ + if( t->value=="bbEmptyString" ) return lit(bstring()); + } + return 0; +} + +//********************* Val *********************** +Val::Val( int n,Type *ty ):type(ty){ + assert( ty->intType() ); + switch( ty->cgType() ){ + case CG_INT8:n&=0xff;break; + case CG_INT16:n&=0xffff;break; + } + cg_exp=ty->cgType()==CG_INT64 ? lit( int64(n) ) : lit( int(n) ); +} + +Val::Val( int64 n,Type *ty ):type(ty){ + assert( ty->intType() ); + switch( ty->cgType() ){ + case CG_INT8 :n&=int64(0xff);break; + case CG_INT16:n&=int64(0xffff);break; + case CG_INT32:n&=int64(0xffffffff);break; + } + cg_exp=ty->cgType()==CG_INT64 ? lit( int64(n) ) : lit( int(n) ); +} + +Val::Val( float n,Type *ty ):type(ty){ + assert( ty->floatType() ); + cg_exp=ty->cgType()==CG_FLOAT64 ? lit( double(n) ) : lit( float(n) ); +} + +Val::Val( double n,Type *ty ):type(ty){ + assert( ty->floatType() ); + cg_exp=ty->cgType()==CG_FLOAT64 ? lit( double(n) ) : lit( float(n) ); +} + +Val::Val( bstring t ):type(Type::stringObject){ + cg_exp=genBBString(t); +} + +Val::Val( const char *t ):type(Type::c_string){ + cg_exp=genCString(t); +} + +Val::Val( Type *t,CGExp *e ):type(t),cg_exp(e){ +} + +Val::~Val(){ +} + +CGExp *Val::constant(){ + return cg_exp->lit() || cg_exp->sym() ? cg_exp : 0; +} + +int64 Val::intValue(){ + CGLit *t=literal( cg_exp ); + assert(t); + switch( t->type ){ + case CG_INT8:case CG_INT16:return t->int_value; + case CG_INT32:case CG_INT64:return t->int_value; + case CG_FLOAT32:case CG_FLOAT64:return (int64)t->float_value; + case CG_BSTRING:return toint(tostring(t->string_value)); + } + assert(0); + return 0; +} + +double Val::floatValue(){ + CGLit *t=literal( cg_exp ); + assert(t); + switch( t->type ){ + case CG_INT8:case CG_INT16:return t->int_value; + case CG_INT32:case CG_INT64:return t->int_value; + case CG_FLOAT32:case CG_FLOAT64:return t->float_value; + case CG_BSTRING:return tofloat(tostring(t->string_value)); + } + assert(0); + return 0; +} + +bstring Val::stringValue(){ + CGLit *t=literal( cg_exp ); + assert(t); + switch( t->type ){ + case CG_INT8:return tobstring(fromint(t->int_value)); + case CG_INT16:return tobstring(fromint(t->int_value)); + case CG_INT32:return tobstring(fromint(t->int_value)); + case CG_INT64:return tobstring(fromint(t->int_value)); + case CG_FLOAT32:return tobstring(fromfloat(t->float_value)); + case CG_FLOAT64:return tobstring(fromdouble(t->float_value)); + case CG_BSTRING:return t->string_value; + } + assert(0); + return tobstring(""); +} + +Val *Val::cond(){ + CGExp *e=0; + + if( type->nullType() ){ + e=lit0; + }else if( type->intType() ){ + if( type->cgType()!=CG_INT64 ) return this; + e=scc(CG_NE,cg_exp,lit(int64(0))); + }else if( type->floatType() ){ + if( constant() ) e=floatValue() ? lit1 : lit0; + else e=scc(CG_NE,cg_exp,type->size()==8 ? lit(0.0) : lit(0.0f)); + }else if( type->stringType() ){ + if( constant() ) e=stringValue().size() ? lit1 : lit0; + else e=mem(CG_INT32,cg_exp,8); //len of string + }else if( type->arrayType() ){ + e=mem(CG_INT32,cg_exp,16); //len of array + }else if( type->objectType() ){ + e=scc(CG_NE,cg_exp,sym("bbNullObject",CG_IMPORT));//cmp with null object + }else if( type->exObjectType() ){ + e=scc(CG_NE,cg_exp,lit0); //cmp with 0 + }else if( type->ptrType() ){ + e=scc(CG_NE,cg_exp,lit0); //cmp with 0 + }else if( FunType *f=type->funType() ){ + if( !f->method() ){ + e=scc(CG_NE,cg_exp,sym("brl_blitz_NullFunctionError",CG_IMPORT)); + } + } + + if( !e ) fail( "Unable to convert expression to conditional value" ); + + return new Val(Type::int32,e); +} + +Type *Val::balance( Val *t ){ + return balance( t->type ); +} + +Type *Val::balance( Type *y ){ + + Type *x=type; + + if( x->intType() ){ + if( y->intType() ) return (x->cgType()==CG_INT64 || y->cgType()==CG_INT64) ? Type::int64 : Type::int32; + if( y->floatType() ) return y; + if( y->stringType() ) return y; + if( y->objectType() ) return y; + if( y->classType() ) return y; + }else if( x->floatType() ){ + if( y->intType() ) return x; + if( y->floatType() ) return (x->cgType()==CG_FLOAT64 || y->cgType()==CG_FLOAT64) ? Type::float64 : Type::float32; + if( y->stringType() ) return y; + if( y->classType() ) return y; + if( y->objectType() ) return y; + }else if( x->stringType() ){ + if( y->intType() ) return x; + if( y->floatType() ) return x; + if( y->stringType() ) return x; + if( y->objectType() ) return y; + if( y->classType() ) return y; + }else if( FunType *p=x->funType() ){ + if( FunType *q=y->funType() ){ + if( p->extends(q) ) return y; + if( q->extends(p) ) return x; + } + }else if( ObjectType *p=x->objectType() ){ + if( ObjectType *q=y->objectType() ){ + if( p->extends(q) ) return y; + if( q->extends(p) ) return x; + } + }else if( ObjectType *p=x->exObjectType() ){ + if( ObjectType *q=y->exObjectType() ){ + if( p->extends(q) ) return y; + if( q->extends(p) ) return x; + } + } + + if( x->nullType() ) return y; + if( y->nullType() ) return x; + + fail( "Types '%s' and '%s' are unrelated",x->toString().c_str(),y->toString().c_str() ); + return 0; +} + +Val *Val::cast( Type *dst ){ + + //nop? + if( type->equals(dst) ) return this; + if( type->extends(dst) ) return new Val(dst,cg_exp); + + //null casts... + if( type->nullType() ){ + if( dst->intType() ) return new Val(0,dst); + if( dst->floatType() ) return new Val(0.0,dst); + if( dst->ptrType() ) return new Val(dst,lit0); + if( dst->cstringType() ) return new Val(dst,lit0); + if( dst->wstringType() ) return new Val(dst,lit0); + if( dst->stringType() ) return new Val(dst,sym("bbEmptyString",CG_IMPORT)); + if( dst->arrayType() ) return new Val(dst,sym("bbEmptyArray",CG_IMPORT)); + if( dst->objectType() ) return new Val(dst,sym("bbNullObject",CG_IMPORT)); + if( dst->exObjectType() ) return new Val(dst,lit0); + if( dst->funType() ) return new Val(dst,sym("brl_blitz_NullFunctionError",CG_IMPORT)); + fail( "Unable to cast 'Null' to '%s'",(dst->toString()).c_str() ); + return 0; + } + + int cg_ty=dst->cgType(); + + //literal conversions + if( constant() && type->numericType() ){ + switch( cg_ty ){ + case CG_INT8:return new Val( intValue(),Type::int8 ); + case CG_INT16:return new Val( intValue(),Type::int16 ); + case CG_INT32:return new Val( intValue(),Type::int32 ); + case CG_INT64:return new Val( intValue(),Type::int64 ); + case CG_FLOAT32:return new Val( floatValue(),Type::float32 ); + case CG_FLOAT64:return new Val( floatValue(),Type::float64 ); + default:if( dst->stringType() ) return new Val( stringValue() ); + } + } + + CGExp *e=0; + + //standard type conversions + if( type->intType() ){ + if( dst->intType() ){ + e=cvt(cg_ty,cg_exp); + }else if( dst->floatType() ){ + e=cvt(cg_ty,cg_exp); + }else if( dst->stringType() ){ + if( type->cgType()==CG_INT64 ){ + e=jsr(cg_ty,"bbStringFromLong",cg_exp); + }else{ + e=jsr(cg_ty,"bbStringFromInt",cvt(CG_INT32,cg_exp)); + } + } + }else if( type->floatType() ){ + if( dst->intType() ){ + e=cvt(cg_ty,cg_exp); + }else if( dst->floatType() ){ + e=cvt(cg_ty,cg_exp); + }else if( dst->stringType() ){ + if( type->cgType()==CG_FLOAT64 ){ + e=jsr(cg_ty,"bbStringFromDouble",cg_exp ); + }else{ + e=jsr(cg_ty,"bbStringFromFloat",cg_exp ); + } + } + }else if( type->stringType() ){ + /* + if( dst->cstringType() ){ + e=jsr(CG_PTR,"bbStringToCString",cg_exp); + }else if( dst->wstringType() ){ + e=jsr(CG_PTR,"bbStringToWString",cg_exp); + } + */ + }else if( type->cstringType() ){ + /* + if( dst->stringType() ){ + e=jsr(cg_ty,"bbStringFromCString",cg_exp); + }else if( dst->cstringType() ){ + e=cg_exp; + } + */ + }else if( type->wstringType() ){ + /* + if( dst->stringType() ){ + e=jsr(cg_ty,"bbStringFromWString",cg_exp); + }else if( dst->wstringType() ){ + e=cg_exp; + } + */ + }else if( ArrayType *src_ty=type->arrayType() ){ + if( PtrType *dst_ty=dst->ptrType() ){ + Type *val_ty=dst_ty->val_type; + if( val_ty->encoding()=="b" || val_ty->equals(src_ty->element_type) ){ + e=cg_exp; + if( e->tmp() ){ + e=mem(CG_PTR,lea(e),0); + }else if( !e->mem() ){ + CGTmp *t=tmp(CG_PTR); + e=esq(mov(t,e),mem(CG_PTR,lea(t),0)); + } + e=lea(mem(val_ty->cgType(),e,src_ty->dims*4+20)); + } + } + }else if( ObjectType *src_ty=type->objectType() ){ + if( PtrType *dst_ty=dst->ptrType() ){ + if( dst_ty->val_type->encoding()=="b" ){ + e=cg_exp; + if( e->tmp() ){ + e=mem(CG_PTR,lea(e),0); + }else if( !e->mem() ){ + CGTmp *t=tmp(CG_PTR); + e=esq(mov(t,e),mem(CG_PTR,lea(t),0)); + } + e=lea(mem(CG_PTR,e,8)); + } + } + }else if( ObjectType *src_ty=type->exObjectType() ){ + if( PtrType *dst_ty=dst->ptrType() ){ + if( dst_ty->val_type->encoding()=="b" ){ + e=cg_exp; + } + } + }else if( PtrType *src_ty=type->ptrType() ){ + if( PtrType *dst_ty=dst->ptrType() ){ + if( dst_ty->val_type->equals(src_ty->val_type) || dst_ty->val_type->encoding()=="b" ){ + e=cg_exp; + } + }else if( FunType *dst_ty=dst->funType() ){ + if( src_ty->val_type->encoding()=="b" ){ + //check for '0' func! + CGTmp *t=tmp(CG_PTR); + CGSym *p=sym(); + CGStm *s=CG::seq( + mov(t,cg_exp), + bcc(CG_NE,t,lit0,p), + mov(t,sym("brl_blitz_NullFunctionError",CG_IMPORT)), + lab(p), + 0 ); + e=esq(s,t); + } + } + }else if( FunType *src_ty=type->funType() ){ + if( PtrType *dst_ty=dst->ptrType() ){ + if( !src_ty->method() && dst_ty->val_type->encoding()=="b" ) e=cg_exp; + } + } + + if( !e ) fail( "Unable to convert from '%s' to '%s'",type->toString().c_str(),dst->toString().c_str() ); + + return new Val(dst,e); +} + +Val *Val::initCast( Type *dst ){ + if( !strictMode && dst->cgType()==CG_INT32 ){ + if( type->objectType() && !type->stringType() && !type->arrayType() ){ + return new Val( dst,jsr(CG_INT32,"bbHandleFromObject",cg_exp) ); + } + } + return cast( dst ); +} + +Val *Val::funArgCast( Type *dst,CGSeq *cleanup ){ + //convert reference to var + if( VarType *var=dst->varType() ){ + RefType *ref=type->refType(); + if( !ref ) fail( "Expression for 'Var' parameter must be a variable" ); + if( !ref->val_type->extends(var->val_type) ) fail( "Variable for 'Var' parameter is not of matching type" ); + CGExp *e=lea(cg_exp); + if( !opt_threaded && var->val_type->objectType() && cg_exp->tmp() ){ + CGMem *m=mem(CG_INT32,cg_exp,4); + e=esq(ati(m),e); + CGSym *l=sym(); + cleanup->push_back( CG::seq( + atd(m,l), + eva(jsr(CG_INT32,"bbGCFree",cg_exp)), + lab(l), + 0) ); + } + return new Val( dst,e ); + } + + //convert int32 to object + if( !strictMode && type->cgType()==CG_INT32 ){ + if( dst->objectType() && !dst->stringType() && !dst->arrayType() ){ + Val *v=new Val( Type::objectObject,jsr(CG_PTR,"bbHandleToObject",cg_exp) ); + return v->explicitCast(dst); + } + } + + //convert string to cstring/wstring + if( type->stringType() ){ + CGExp *e=0; + if( dst->cstringType() || dst->ptrType("b") ){ + e=jsr(CG_PTR,"bbStringToCString",cg_exp); + }else if( dst->wstringType() || dst->ptrType("s") ){ + e=jsr(CG_PTR,"bbStringToWString",cg_exp); + } + if( e ){ + CGTmp *t=tmp(CG_PTR); + e=esq(mov(t,e),t); + cleanup->push_back( eva(jsr(CG_INT32,"bbMemFree",t)) ); + return new Val( dst,e ); + } + } + + return cast(dst); +} + +Val *Val::explicitCast( Type *dst ){ + + if( type->nullType() ) return cast(dst); + + if( type->equals(dst) ) return this; + + int cg_ty=dst->cgType(); + + //literal conversions + if( constant() && type->stringType() ){ + switch( cg_ty ){ + case CG_INT8:return new Val( intValue(),Type::int8 ); + case CG_INT16:return new Val( intValue(),Type::int16 ); + case CG_INT32:return new Val( intValue(),Type::int32 ); + case CG_INT64:return new Val( intValue(),Type::int64 ); + case CG_FLOAT32:return new Val( floatValue(),Type::float32 ); + case CG_FLOAT64:return new Val( floatValue(),Type::float64 ); + } + } + + CGExp *e=0; + + if( type->ptrType() ){ + if( dst->intType() ){ + //ptr to int + e=cvt(cg_ty,cg_exp); + }else if( dst->ptrType() ){ + //ptr to ptr + e=cg_exp; + } + }else if( type->intType() ){ + if( dst->ptrType() ){ + //int to ptr + e=cvt(cg_ty,cg_exp); + } + }else if( type->stringType() ){ + if( dst->intType() ){ + //string to int + if( cg_ty==CG_INT64 ){ + e=jsr(cg_ty,CG_CDECL,vfn(sym("bbStringToLong",CG_IMPORT),cg_exp) ); + }else{ + e=cvt(cg_ty,jsr(CG_INT32,"bbStringToInt",cg_exp)); + } + }else if( dst->floatType() ){ + //string to float + if( cg_ty==CG_FLOAT64 ){ + e=jsr(cg_ty,"bbStringToDouble",cg_exp ); + }else{ + e=jsr(cg_ty,"bbStringToFloat",cg_exp ); + } + } + }else if( ObjectType *src_ty=type->objectType() ){ + if( ObjectType *dst_ty=dst->objectType() ){ + if( dst_ty->extends(src_ty) ){ + if( ArrayType *arr_ty=dst->arrayType() ){ + e=jsr(CG_PTR,"bbArrayCastFromObject",cg_exp,genCString(arr_ty->element_type->encoding()) ); + }else{ + e=jsr(CG_PTR,"bbObjectDowncast",cg_exp,dst_ty->class_val->cg_exp); + } + if( dst->stringType() || dst->arrayType() ){ + CGSym *t=sym( (dst->stringType() ? "bbEmptyString" : "bbEmptyArray"),CG_IMPORT ); + CGTmp *r=tmp(CG_PTR); + CGSym *l=sym(); + CGStm *s=CG::seq( + mov(r,e), + bcc(CG_NE,r,sym("bbNullObject",CG_IMPORT),l), + mov(r,t), + lab(l), + 0 ); + e=esq(s,r); + } + } + } + }else if( ObjectType *src_ty=type->exObjectType() ){ + if( ObjectType *dst_ty=dst->exObjectType() ){ + if( dst_ty->extends(src_ty) ){ + e=cg_exp; + } + } + } + + if( e ) return new Val( dst,e ); + + return cast(dst); +} + +Val *Val::forEachCast( Type *dst ){ + + if( type->nullType() ) return cast(dst); + + if( type->equals(dst) ) return this; + + CGExp *e=0; + int cg_ty=dst->cgType(); + + if( ObjectType *src_ty=type->objectType() ){ + if( ObjectType *dst_ty=dst->objectType() ){ + if( dst_ty->extends(src_ty) ){ + if( dst_ty->objectClass()->attrs & ClassType::EXTERN ){ + e=cg_exp; + }else if( ArrayType *arr_ty=dst->arrayType() ){ + e=jsr(CG_PTR,"bbArrayCastFromObject",cg_exp,genCString(arr_ty->element_type->encoding()) ); + }else{ + e=jsr(CG_PTR,"bbObjectDowncast",cg_exp,dst_ty->class_val->cg_exp); + } + } + } + } + + if( e ) return new Val( dst,e ); + + return explicitCast( dst ); +} + +Val *Val::find( string id ){ + Val *v=type->find(id); + if( !v ) return 0; + + int n_self=v->countTmps("@self"); + int n_type=v->countTmps("@type"); + if( !n_self && !n_type ) return v; + + CGExp *cg=cg_exp; + + if( n_self && opt_debug && !type->stringType() && !type->arrayType() ){ + cg=tmp(CG_PTR); + + CGSym *q=sym(); + CGStm *stms=CG::seq( + mov(cg,cg_exp), + bcc(CG_NE,cg,sym("bbNullObject",CG_IMPORT),q), + eva(jsr(CG_INT32,"brl_blitz_NullObjectError")), + lab(q), + 0 ); + v=new Val(v->type,esq(stms,v->cg_exp)); + }else if( n_self+n_type>1 ){ + cg=tmp(CG_PTR); + v=new Val(v->type,esq(mov(cg,cg_exp),v->cg_exp)); + } + + if( type->objectType() || type->exObjectType() ){ + if( n_self ) v=v->renameTmps( "@self",cg ); + if( n_type ) v=v->renameTmps( "@type",mem(CG_PTR,cg,0) ); + }else if( type->classType() ){ + assert( !n_self ); + if( n_type ) v=v->renameTmps( "@type",cg ); + }else{ + assert(0); + } + + return v; +} + +bool Val::refCounted(){ + if( opt_threaded ) return false; + RefType *t=type->refType(); + return t && t->objectType() && cg_exp->mem(); +} + +Val *Val::retain(){ + if( opt_threaded ){ + fail( "Internal error: Val::retain() invoked in threaded mode." ); + } + CGTmp *p=tmp(CG_PTR); + CGMem *m=mem(CG_INT32,p,4); + CGStm *t=seq( + mov(p,cg_exp), + ati(m), + 0); + return new Val(type,esq(t,p)); +} + +CGStm *Val::release(){ + if( opt_threaded ){ + fail( "Internal error: Val::release() invoked in threaded mode." ); + } + CGTmp *p=tmp(CG_PTR); + CGMem *m=mem(CG_INT32,p,4); + CGSym *q=sym(); + CGStm *t=seq( + mov(p,cg_exp), + atd(m,q), + eva(jsr(CG_INT32,"bbGCFree",p)), + lab(q), + 0); + return t; +} + +struct TmpCounter : public CGVisitor{ + int n; + string ident; + + TmpCounter( string id ):n(0),ident(id){ + } + + CGExp *visit( CGExp *e ){ + if( CGTmp *t=e->tmp() ){ + if( ident==t->ident ) ++n; + } + return e; + } +}; + +int Val::countTmps( string id ){ + if( !cg_exp ) return 0; + TmpCounter cnt( id ); + cg_exp->visit( cnt ); + return cnt.n; +} + +struct TmpRenamer : public CGVisitor{ + string ident; + CGExp *cg_exp; + + TmpRenamer( string id,CGExp *e ):ident(id),cg_exp(e){ + } + + CGExp *visit( CGExp *e ){ + if( CGTmp *t=e->tmp() ){ + if( ident==t->ident ) return cg_exp; + } + return e; + } +}; + +Val *Val::renameTmps( string id,CGExp *e ){ + if( !cg_exp ) return this; + TmpRenamer ren( id,e ); + CGExp *t=cg_exp->visit( ren ); + return t==cg_exp ? this : new Val(type,t); +} + +Val *Val::null( Type *ty ){ + return (new Val(Type::null,0))->cast(ty); +} + +//*********************** SuperVal ************************* +SuperVal::SuperVal( Val *v ):Val(v->type,v->cg_exp){ +} + +Val *SuperVal::find( string id ){ + + ObjectType *o=type->objectType(); + ClassType *t=o ? o->objectClass() : type->classType(); + + assert(t); + + Val *v=0; + bool method=false; + + for( t=t->superClass();t;t=t->superClass() ){ + v=t->methods.find(id); + if( !v ) continue; + method=v->type->funType()->method(); + if( o || !method ) break; + v=0; + } + + if( !v ) badid(id); + + if( method ) v=new Val( v->type,vfn(v->cg_exp,cg_exp) ); + + return v; +} diff --git a/_src/compiler/val.h b/_src/compiler/val.h new file mode 100644 index 0000000..c3af93a --- /dev/null +++ b/_src/compiler/val.h @@ -0,0 +1,55 @@ + +#ifndef VAL_H +#define VAL_H + +#include "type.h" +#include "scope.h" + +struct Val : public Scope{ + Type *type; + CGExp *cg_exp; + + Val( int n,Type *ty=Type::int32 ); + Val( int64 n,Type *ty=Type::int64 ); + Val( float n,Type *ty=Type::float32 ); + Val( double n,Type *ty=Type::float64 ); + + Val( bstring t ); + Val( const char *t ); + Val( Type *t,CGExp *e ); + virtual ~Val(); + + CGExp* constant(); + + int64 intValue(); + double floatValue(); + bstring stringValue(); + + Val* cond(); + Val* cast( Type *ty ); + Val* initCast( Type *ty ); + Val* funArgCast( Type *ty,CGSeq *cleanup ); + Val* forEachCast( Type *ty ); + Val* explicitCast( Type *ty ); + Val* find( string id ); + + Type* balance( Val *t ); + Type* balance( Type *t ); + + Val* retain(); + CGStm* release(); + + bool refCounted(); + int countTmps( string id ); + Val* renameTmps( string id,CGExp *e ); + + static Val* null( Type *ty ); +}; + +struct SuperVal : public Val{ + SuperVal( Val *v ); + + Val* find( string id ); +}; + +#endif \ No newline at end of file