#include "../std.h" #include "codegen_x86.h" #include "tile.h" //reduce to 3 for stress test static const int NUM_REGS=6; static const string regs[]= {"???","eax","ecx","edx","edi","esi","ebx"}; //array of 'used' flags static bool regUsed[NUM_REGS+1]; //size of locals in function static int frameSize,maxFrameSize; //code fragments static vector codeFrags,dataFrags; //name of function static string funcLabel; static void resetRegs(){ for( int n=1;n<=NUM_REGS;++n ) regUsed[n]=false; } static int allocReg( int n ){ if( !n || regUsed[n] ){ for( n=NUM_REGS;n>=1 && regUsed[n];--n ){} if( !n ) return 0; } regUsed[n]=true; return n; } static void freeReg( int n ){ regUsed[n]=false; } static void pushReg( int n ){ frameSize+=4; if( frameSize>maxFrameSize ) maxFrameSize=frameSize; char buff[32];itoa( frameSize,buff,10 ); string s="\tmov\t[ebp-";s+=buff;s+="],";s+=regs[n];s+='\n'; codeFrags.push_back( s ); } static void popReg( int n ){ char buff[32];itoa( frameSize,buff,10 ); string s="\tmov\t";s+=regs[n];s+=",[ebp-";s+=buff;s+="]\n"; codeFrags.push_back( s ); frameSize-=4; } static void moveReg( int d,int s ){ string t="\tmov\t"+regs[d]+','+regs[s]+'\n'; codeFrags.push_back( t ); } static void swapRegs( int d,int s ){ string t="\txchg\t"+regs[d]+','+regs[s]+'\n'; codeFrags.push_back( t ); } Tile::Tile( const string &a,Tile *l,Tile *r ) :assem(a),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){ } Tile::Tile( const string &a,const string &a2,Tile *l,Tile *r ) :assem(a),assem2(a2),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){ } Tile::~Tile(){ delete l;delete r; } void Tile::label(){ if( !l ){ need=1; }else if( !r ){ l->label(); need=l->need; }else{ l->label();r->label(); if( l->need==r->need ) need=l->need+1; else if( l->need>r->need ) need=l->need; else need=r->need; } } int Tile::eval( int want ){ //save any hit registers int spill=hits; if( want_l ) spill|=1<eval( want ); }else{ if( l->need>=NUM_REGS && r->need>=NUM_REGS ){ got_r=r->eval( 0 ); pushReg( got_r );freeReg( got_r ); got_l=l->eval( want ); got_r=allocReg( want_r );popReg( got_r ); }else if( r->need>l->need ){ got_r=r->eval( want_r ); got_l=l->eval( want ); }else{ got_l=l->eval( want ); got_r=r->eval( want_r ); if( assem2.size() ) as=&assem2; } if( want_l==got_r || want_r==got_l ){ swapRegs( got_l,got_r ); int t=got_l;got_l=got_r;got_r=t; } } if( !want_l ) want_l=got_l; else if( want_l!=got_l ) moveReg( want_l,got_l ); if( !want_r ) want_r=got_r; else if( want_r!=got_r ) moveReg( want_r,got_r ); int i; while( (i=as->find( "%l" ))!=string::npos ) as->replace( i,2,regs[want_l] ); while( (i=as->find( "%r" ))!=string::npos ) as->replace( i,2,regs[want_r] ); codeFrags.push_back( *as ); freeReg( got_r ); if( want_l!=got_l ) moveReg( got_l,want_l ); //cleanup argFrame if( argFrame ){ //***** Not needed for STDCALL ***** // codeFrags.push_back( "+"+itoa(argFrame) ); } //restore spilled regs if( spill ){ for( int n=NUM_REGS;n>=1;--n ){ if( spill&(1<::iterator it; for( it=dataFrags.begin();it!=dataFrags.end();++it ) out<<*it; dataFrags.clear(); } void Codegen_x86::enter( const string &l,int frameSize ){ inCode=true; ::frameSize=maxFrameSize=frameSize; codeFrags.clear();funcLabel=l; } void Codegen_x86::code( TNode *stmt ){ resetRegs(); Tile *q=munch( stmt ); q->label(); q->eval( 0 ); delete q; delete stmt; } static string fixEsp( int esp_off ){ if( esp_off<0 ) return "\tsub\tesp,"+itoa(-esp_off)+"\n"; return "\tadd\tesp,"+itoa(esp_off)+"\n"; } void Codegen_x86::leave( TNode *cleanup,int pop_sz ){ if( cleanup ){ resetRegs(); allocReg( EAX ); Tile *q=munch( cleanup ); q->label(); q->eval( 0 ); delete q; } out<<"\t.align\t16\n"; if( funcLabel.size() ) out<::iterator it=codeFrags.begin(); for( it=codeFrags.begin();it!=codeFrags.end();++it ){ const string &t=*it; if( t[0]=='+' ){ esp_off+=atoi(t.substr(1)); }else if( t[0]=='-' ){ //***** Still needed for STDCALL ***** esp_off-=atoi(t.substr(1)); }else{ if( esp_off ){ out<