tile.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. #include "../std.h"
  2. #include "codegen_x86.h"
  3. #include "tile.h"
  4. //reduce to 3 for stress test
  5. static const int NUM_REGS=6;
  6. static const string regs[]=
  7. {"???","eax","ecx","edx","edi","esi","ebx"};
  8. //array of 'used' flags
  9. static bool regUsed[NUM_REGS+1];
  10. //size of locals in function
  11. static int frameSize,maxFrameSize;
  12. //code fragments
  13. static vector<string> codeFrags,dataFrags;
  14. //name of function
  15. static string funcLabel;
  16. static void resetRegs(){
  17. for( int n=1;n<=NUM_REGS;++n ) regUsed[n]=false;
  18. }
  19. static int allocReg( int n ){
  20. if( !n || regUsed[n] ){
  21. for( n=NUM_REGS;n>=1 && regUsed[n];--n ){}
  22. if( !n ) return 0;
  23. }
  24. regUsed[n]=true;
  25. return n;
  26. }
  27. static void freeReg( int n ){
  28. regUsed[n]=false;
  29. }
  30. static void pushReg( int n ){
  31. frameSize+=4;
  32. if( frameSize>maxFrameSize ) maxFrameSize=frameSize;
  33. char buff[32];itoa( frameSize,buff,10 );
  34. string s="\tmov\t[ebp-";s+=buff;s+="],";s+=regs[n];s+='\n';
  35. codeFrags.push_back( s );
  36. }
  37. static void popReg( int n ){
  38. char buff[32];itoa( frameSize,buff,10 );
  39. string s="\tmov\t";s+=regs[n];s+=",[ebp-";s+=buff;s+="]\n";
  40. codeFrags.push_back( s );
  41. frameSize-=4;
  42. }
  43. static void moveReg( int d,int s ){
  44. string t="\tmov\t"+regs[d]+','+regs[s]+'\n';
  45. codeFrags.push_back( t );
  46. }
  47. static void swapRegs( int d,int s ){
  48. string t="\txchg\t"+regs[d]+','+regs[s]+'\n';
  49. codeFrags.push_back( t );
  50. }
  51. Tile::Tile( const string &a,Tile *l,Tile *r )
  52. :assem(a),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){
  53. }
  54. Tile::Tile( const string &a,const string &a2,Tile *l,Tile *r )
  55. :assem(a),assem2(a2),l(l),r(r),want_l(0),want_r(0),hits(0),need(0),argFrame(0){
  56. }
  57. Tile::~Tile(){
  58. delete l;delete r;
  59. }
  60. void Tile::label(){
  61. if( !l ){
  62. need=1;
  63. }else if( !r ){
  64. l->label();
  65. need=l->need;
  66. }else{
  67. l->label();r->label();
  68. if( l->need==r->need ) need=l->need+1;
  69. else if( l->need>r->need ) need=l->need;
  70. else need=r->need;
  71. }
  72. }
  73. int Tile::eval( int want ){
  74. //save any hit registers
  75. int spill=hits;
  76. if( want_l ) spill|=1<<want_l;
  77. if( want_r ) spill|=1<<want_r;
  78. if( spill ){
  79. for( int n=1;n<=NUM_REGS;++n ){
  80. if( spill&(1<<n) ){
  81. if( regUsed[n] ) pushReg( n );
  82. else spill&=~(1<<n);
  83. }
  84. }
  85. }
  86. //if tile needs an argFrame...
  87. if( argFrame ){
  88. codeFrags.push_back( "-"+itoa(argFrame) );
  89. }
  90. int got_l=0,got_r=0;
  91. if( want_l ) want=want_l;
  92. string *as=&assem;
  93. if( !l ){
  94. got_l=allocReg( want );
  95. }else if( !r ){
  96. got_l=l->eval( want );
  97. }else{
  98. if( l->need>=NUM_REGS && r->need>=NUM_REGS ){
  99. got_r=r->eval( 0 );
  100. pushReg( got_r );freeReg( got_r );
  101. got_l=l->eval( want );
  102. got_r=allocReg( want_r );popReg( got_r );
  103. }else if( r->need>l->need ){
  104. got_r=r->eval( want_r );
  105. got_l=l->eval( want );
  106. }else{
  107. got_l=l->eval( want );
  108. got_r=r->eval( want_r );
  109. if( assem2.size() ) as=&assem2;
  110. }
  111. if( want_l==got_r || want_r==got_l ){
  112. swapRegs( got_l,got_r );
  113. int t=got_l;got_l=got_r;got_r=t;
  114. }
  115. }
  116. if( !want_l ) want_l=got_l;
  117. else if( want_l!=got_l ) moveReg( want_l,got_l );
  118. if( !want_r ) want_r=got_r;
  119. else if( want_r!=got_r ) moveReg( want_r,got_r );
  120. int i;
  121. while( (i=as->find( "%l" ))!=string::npos ) as->replace( i,2,regs[want_l] );
  122. while( (i=as->find( "%r" ))!=string::npos ) as->replace( i,2,regs[want_r] );
  123. codeFrags.push_back( *as );
  124. freeReg( got_r );
  125. if( want_l!=got_l ) moveReg( got_l,want_l );
  126. //cleanup argFrame
  127. if( argFrame ){
  128. //***** Not needed for STDCALL *****
  129. // codeFrags.push_back( "+"+itoa(argFrame) );
  130. }
  131. //restore spilled regs
  132. if( spill ){
  133. for( int n=NUM_REGS;n>=1;--n ){
  134. if( spill&(1<<n) ) popReg( n );
  135. }
  136. }
  137. return got_l;
  138. }
  139. void Codegen_x86::flush(){
  140. vector<string>::iterator it;
  141. for( it=dataFrags.begin();it!=dataFrags.end();++it ) out<<*it;
  142. dataFrags.clear();
  143. }
  144. void Codegen_x86::enter( const string &l,int frameSize ){
  145. inCode=true;
  146. ::frameSize=maxFrameSize=frameSize;
  147. codeFrags.clear();funcLabel=l;
  148. }
  149. void Codegen_x86::code( TNode *stmt ){
  150. resetRegs();
  151. Tile *q=munch( stmt );
  152. q->label();
  153. q->eval( 0 );
  154. delete q;
  155. delete stmt;
  156. }
  157. static string fixEsp( int esp_off ){
  158. if( esp_off<0 ) return "\tsub\tesp,"+itoa(-esp_off)+"\n";
  159. return "\tadd\tesp,"+itoa(esp_off)+"\n";
  160. }
  161. void Codegen_x86::leave( TNode *cleanup,int pop_sz ){
  162. if( cleanup ){
  163. resetRegs();
  164. allocReg( EAX );
  165. Tile *q=munch( cleanup );
  166. q->label();
  167. q->eval( 0 );
  168. delete q;
  169. }
  170. out<<"\t.align\t16\n";
  171. if( funcLabel.size() ) out<<funcLabel<<'\n';
  172. out<<"\tpush\tebx\n";
  173. out<<"\tpush\tesi\n";
  174. out<<"\tpush\tedi\n";
  175. out<<"\tpush\tebp\n";
  176. out<<"\tmov\tebp,esp\n";
  177. if( maxFrameSize ) out<<"\tsub\tesp,"<<maxFrameSize<<'\n';
  178. int esp_off=0;
  179. vector<string>::iterator it=codeFrags.begin();
  180. for( it=codeFrags.begin();it!=codeFrags.end();++it ){
  181. const string &t=*it;
  182. if( t[0]=='+' ){
  183. esp_off+=atoi(t.substr(1));
  184. }else if( t[0]=='-' ){
  185. //***** Still needed for STDCALL *****
  186. esp_off-=atoi(t.substr(1));
  187. }else{
  188. if( esp_off ){
  189. out<<fixEsp( esp_off );
  190. esp_off=0;
  191. }
  192. out<<*it;
  193. }
  194. }
  195. if( esp_off ) out<<fixEsp( esp_off );
  196. out<<"\tmov\tesp,ebp\n";
  197. out<<"\tpop\tebp\n";
  198. out<<"\tpop\tedi\n";
  199. out<<"\tpop\tesi\n";
  200. out<<"\tpop\tebx\n";
  201. out<<"\tret\tword "<<pop_sz<<"\n";
  202. delete cleanup;
  203. inCode=false;
  204. }
  205. void Codegen_x86::label( const string &l ){
  206. string t=l+'\n';
  207. if( inCode ) codeFrags.push_back( t );
  208. else dataFrags.push_back( t );
  209. }
  210. void Codegen_x86::align_data( int n ){
  211. char buff[32];itoa( n,buff,10 );
  212. dataFrags.push_back( string( "\t.align\t" )+buff+'\n' );
  213. }
  214. void Codegen_x86::i_data( int i,const string &l ){
  215. if( l.size() ) dataFrags.push_back( l );
  216. char buff[32];itoa( i,buff,10 );
  217. dataFrags.push_back( string( "\t.dd\t" )+buff+'\n' );
  218. }
  219. void Codegen_x86::s_data( const string &s,const string &l ){
  220. if( l.size() ) dataFrags.push_back( l );
  221. dataFrags.push_back( string( "\t.db\t\"" )+s+"\",0\n" );
  222. }
  223. void Codegen_x86::p_data( const string &p,const string &l ){
  224. if( l.size() ) dataFrags.push_back( l );
  225. dataFrags.push_back( string( "\t.dd\t" )+p+'\n' );
  226. }