Files
BlitzNext/compiler/codegen_x86/tile.cpp
T
blitz-research 08a613ed0e Initial commit.
2014-01-31 08:23:00 +13:00

274 lines
5.8 KiB
C++

#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' );
}