| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- #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<string> 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<<want_l;
- if( want_r ) spill|=1<<want_r;
- if( spill ){
- for( int n=1;n<=NUM_REGS;++n ){
- if( spill&(1<<n) ){
- if( regUsed[n] ) pushReg( n );
- else spill&=~(1<<n);
- }
- }
- }
- //if tile needs an argFrame...
- if( argFrame ){
- codeFrags.push_back( "-"+itoa(argFrame) );
- }
- int got_l=0,got_r=0;
- if( want_l ) want=want_l;
- string *as=&assem;
- if( !l ){
- got_l=allocReg( want );
- }else if( !r ){
- got_l=l->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<<n) ) popReg( n );
- }
- }
- return got_l;
- }
- void Codegen_x86::flush(){
- vector<string>::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<<funcLabel<<'\n';
- out<<"\tpush\tebx\n";
- out<<"\tpush\tesi\n";
- out<<"\tpush\tedi\n";
- out<<"\tpush\tebp\n";
- out<<"\tmov\tebp,esp\n";
- if( maxFrameSize ) out<<"\tsub\tesp,"<<maxFrameSize<<'\n';
- int esp_off=0;
- vector<string>::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<<fixEsp( esp_off );
- esp_off=0;
- }
- out<<*it;
- }
- }
- if( esp_off ) out<<fixEsp( esp_off );
- out<<"\tmov\tesp,ebp\n";
- out<<"\tpop\tebp\n";
- out<<"\tpop\tedi\n";
- out<<"\tpop\tesi\n";
- out<<"\tpop\tebx\n";
- out<<"\tret\tword "<<pop_sz<<"\n";
- delete cleanup;
- inCode=false;
- }
- void Codegen_x86::label( const string &l ){
- string t=l+'\n';
- if( inCode ) codeFrags.push_back( t );
- else dataFrags.push_back( t );
- }
- void Codegen_x86::align_data( int n ){
- char buff[32];itoa( n,buff,10 );
- dataFrags.push_back( string( "\t.align\t" )+buff+'\n' );
- }
- void Codegen_x86::i_data( int i,const string &l ){
- if( l.size() ) dataFrags.push_back( l );
- char buff[32];itoa( i,buff,10 );
- dataFrags.push_back( string( "\t.dd\t" )+buff+'\n' );
- }
- void Codegen_x86::s_data( const string &s,const string &l ){
- if( l.size() ) dataFrags.push_back( l );
- dataFrags.push_back( string( "\t.db\t\"" )+s+"\",0\n" );
- }
- void Codegen_x86::p_data( const string &p,const string &l ){
- if( l.size() ) dataFrags.push_back( l );
- dataFrags.push_back( string( "\t.dd\t" )+p+'\n' );
- }
|