codegen_x86.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. #include "../std.h"
  2. #include "codegen_x86.h"
  3. #include "tile.h"
  4. //#define NOOPTS
  5. Codegen_x86::Codegen_x86( ostream &out,bool debug ):Codegen( out,debug ),inCode(false){
  6. }
  7. static string itoa_sgn(int n){
  8. return n ? (n>0 ? "+"+itoa(n) : itoa(n)) : "";
  9. }
  10. static bool isRelop( int op ){
  11. return op==IR_SETEQ||op==IR_SETNE||op==IR_SETLT||op==IR_SETGT||op==IR_SETLE||op==IR_SETGE;
  12. }
  13. static bool nodesEqual( TNode *t1,TNode *t2 ){
  14. if( t1->op!=t2->op ||
  15. t1->iconst!=t2->iconst ||
  16. t1->sconst!=t2->sconst ) return false;
  17. if( t1->l ){
  18. if( !t2->l || !nodesEqual( t1->l,t2->l ) ) return false;
  19. }else if( t2->l ) return false;
  20. if( t1->r ){
  21. if( !t2->r || !nodesEqual( t1->r,t2->r ) ) return false;
  22. }else if( t2->r ) return false;
  23. return true;
  24. }
  25. static bool getShift( int n,int &shift ){
  26. #ifdef NOOPTS
  27. return false;
  28. #endif
  29. for( shift=0;shift<32;++shift ){
  30. if( (1<<shift)==n ) return true;
  31. }
  32. return false;
  33. }
  34. static bool matchMEM( TNode *t,string &s ){
  35. #ifdef NOOPTS
  36. return false;
  37. #endif
  38. if( t->op!=IR_MEM ) return false;
  39. t=t->l;
  40. switch( t->op ){
  41. case IR_GLOBAL:s="["+t->sconst+"]";return true;
  42. case IR_LOCAL:s="[ebp"+itoa_sgn(t->iconst)+"]";return true;
  43. case IR_ARG:s="[esp"+itoa_sgn(t->iconst)+"]";return true;
  44. }
  45. return false;
  46. }
  47. static bool matchCONST( TNode *t,string &s ){
  48. #ifdef NOOPTS
  49. return false;
  50. #endif
  51. switch( t->op ){
  52. case IR_CONST:s=itoa( t->iconst );return true;
  53. case IR_GLOBAL:s=t->sconst;return true;
  54. }
  55. return false;
  56. }
  57. static bool matchMEMCONST( TNode *t,string &s ){
  58. #ifdef NOOPTS
  59. return false;
  60. #endif
  61. return matchMEM( t,s ) || matchCONST( t,s );
  62. }
  63. Tile *Codegen_x86::genCompare( TNode *t,string &func,bool negate ){
  64. switch( t->op ){
  65. case IR_SETEQ:func=negate ? "nz" : "z";break;
  66. case IR_SETNE:func=negate ? "z" : "nz";break;
  67. case IR_SETLT:func=negate ? "ge" : "l";break;
  68. case IR_SETGT:func=negate ? "le" : "g";break;
  69. case IR_SETLE:func=negate ? "g" : "le";break;
  70. case IR_SETGE:func=negate ? "l" : "ge";break;
  71. default:return 0;
  72. }
  73. string q,m,c;
  74. TNode *ql=0,*qr=0;
  75. if( matchMEM( t->l,m ) ){
  76. if( matchCONST( t->r,c ) ){
  77. q="\tcmp\t"+m+","+c+"\n";
  78. }else{
  79. q="\tcmp\t"+m+",%l\n";ql=t->r;
  80. }
  81. }else{
  82. if( matchMEMCONST( t->r,m ) ){
  83. q="\tcmp\t%l,"+m+"\n";ql=t->l;
  84. }else{
  85. q="\tcmp\t%l,%r\n";ql=t->l;qr=t->r;
  86. }
  87. }
  88. return d_new Tile( q,ql ? munchReg( ql ) : 0,qr ? munchReg( qr ) : 0 );
  89. }
  90. ////////////////////////////////////////////////
  91. // Integer expressions returned in a register //
  92. ////////////////////////////////////////////////
  93. Tile *Codegen_x86::munchUnary( TNode *t ){
  94. string s;
  95. switch( t->op ){
  96. case IR_NEG:s="\tneg\t%l\n";break;
  97. default:return 0;
  98. }
  99. return d_new Tile( s,munchReg( t->l ) );
  100. }
  101. Tile *Codegen_x86::munchLogical( TNode *t ){
  102. string s;
  103. switch( t->op ){
  104. case IR_AND:s="\tand\t%l,%r\n";break;
  105. case IR_OR:s="\tor\t%l,%r\n";break;
  106. case IR_XOR:s="\txor\t%l,%r\n";break;
  107. default:return 0;
  108. }
  109. return d_new Tile( s,munchReg( t->l ),munchReg( t->r ) );
  110. }
  111. Tile *Codegen_x86::munchArith( TNode *t ){
  112. if( t->op==IR_DIV ){
  113. int shift;
  114. if( t->r->op==IR_CONST ){
  115. if( getShift( t->r->iconst,shift ) ){
  116. return d_new Tile( "\tsar\t%l,byte "+itoa(shift)+"\n",munchReg( t->l ) );
  117. }
  118. }
  119. Tile *q=d_new Tile( "\tcdq\n\tidiv\tecx\n",munchReg( t->l ),munchReg( t->r ) );
  120. q->want_l=EAX;q->want_r=ECX;q->hits=1<<EDX;
  121. return q;
  122. }
  123. if( t->op==IR_MUL ){
  124. int shift;
  125. if( t->r->op==IR_CONST ){
  126. if( getShift( t->r->iconst,shift ) ){
  127. return d_new Tile( "\tshl\t%l,byte "+itoa(shift)+"\n",munchReg( t->l ) );
  128. }
  129. }else if( t->l->op==IR_CONST ){
  130. if( getShift( t->l->iconst,shift ) ){
  131. return d_new Tile( "\tshl\t%l,byte "+itoa(shift)+"\n",munchReg( t->r ) );
  132. }
  133. }
  134. }
  135. string s,op;
  136. switch( t->op ){
  137. case IR_ADD:op="\tadd\t";break;
  138. case IR_SUB:op="\tsub\t";break;
  139. case IR_MUL:op="\timul\t";break;
  140. default:return 0;
  141. }
  142. if( matchMEMCONST( t->r,s ) ){
  143. return d_new Tile( op+"%l,"+s+"\n",munchReg( t->l ) );
  144. }
  145. if( t->op!=IR_SUB && matchMEMCONST( t->l,s ) ){
  146. return d_new Tile( op+"%l,"+s+"\n",munchReg( t->r ) );
  147. }
  148. return d_new Tile( op+"%l,%r\n",munchReg( t->l ),munchReg( t->r ) );
  149. }
  150. Tile *Codegen_x86::munchShift( TNode *t ){
  151. string s,op;
  152. switch( t->op ){
  153. case IR_SHL:op="\tshl\t";break;
  154. case IR_SHR:op="\tshr\t";break;
  155. case IR_SAR:op="\tsar\t";break;
  156. default:return 0;
  157. }
  158. if( matchCONST( t->r,s ) ){
  159. return d_new Tile( op+"%l,byte "+s+"\n",munchReg( t->l ) );
  160. }
  161. Tile *q=d_new Tile( op+"%l,cl\n",munchReg( t->l ),munchReg( t->r ) );
  162. q->want_r=ECX;return q;
  163. }
  164. Tile *Codegen_x86::munchRelop( TNode *t ){
  165. string func;
  166. Tile *q=genCompare( t,func,false );
  167. q=d_new Tile( "\tset"+func+"\tal\n\tmovzx\teax,al\n",q );
  168. q->want_l=EAX;
  169. return q;
  170. }
  171. ////////////////////////////////////////////////
  172. // Float expressions returned on the FP stack //
  173. ////////////////////////////////////////////////
  174. Tile *Codegen_x86::munchFPUnary( TNode *t ){
  175. string s;
  176. switch( t->op ){
  177. case IR_FNEG:s="\tfchs\n";break;
  178. default:return 0;
  179. }
  180. return d_new Tile( s,munchFP( t->l ) );
  181. }
  182. Tile *Codegen_x86::munchFPArith( TNode *t ){
  183. string s,s2;
  184. switch( t->op ){
  185. case IR_FADD:s="\tfaddp\tst(1)\n";break;
  186. case IR_FMUL:s="\tfmulp\tst(1)\n";break;
  187. case IR_FSUB:s="\tfsubrp\tst(1)\n";s2="\tfsubp\tst(1)\n";break;
  188. case IR_FDIV:s="\tfdivrp\tst(1)\n";s2="\tfdivp\tst(1)\n";break;
  189. default:return 0;
  190. }
  191. return d_new Tile( s,s2,munchFP( t->l ),munchFP( t->r ) );
  192. }
  193. Tile *Codegen_x86::munchFPRelop( TNode *t ){
  194. string s,s2;
  195. switch( t->op ){
  196. case IR_FSETEQ:s="z";s2="z";break;
  197. case IR_FSETNE:s="nz";s2="nz";break;
  198. case IR_FSETLT:s="b";s2="a";break;
  199. case IR_FSETGT:s="a";s2="b";break;
  200. case IR_FSETLE:s="be";s2="ae";break;
  201. case IR_FSETGE:s="ae";s2="be";break;
  202. default:return 0;
  203. }
  204. s="\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset"+s+"\tal\n\tmovzx\t%l,al\n";
  205. s2="\tfucompp\n\tfnstsw\tax\n\tsahf\n\tset"+s2+"\tal\n\tmovzx\t%l,al\n";
  206. Tile *q=d_new Tile( s,s2,munchFP( t->l ),munchFP( t->r ) );
  207. q->want_l=EAX;
  208. return q;
  209. }
  210. ///////////////////////////
  211. // Generic Call handling //
  212. ///////////////////////////
  213. Tile *Codegen_x86::munchCall( TNode *t ){
  214. Tile *q;
  215. if( t->l->op==IR_GLOBAL ){
  216. q=d_new Tile( "\tcall\t"+t->l->sconst+"\n",t->r ? munchReg( t->r ) : 0 );
  217. }else{
  218. q=d_new Tile( "\tcall\t%l\n",munchReg( t->l ),t->r ? munchReg( t->r ) : 0 );
  219. }
  220. q->argFrame=t->iconst;
  221. q->want_l=EAX;
  222. q->hits=(1<<EAX)|(1<<ECX)|(1<<EDX);
  223. return q;
  224. }
  225. /////////////////////////////
  226. // munch and dicard result //
  227. /////////////////////////////
  228. Tile *Codegen_x86::munch( TNode *t ){
  229. if( !t ) return 0;
  230. Tile *q=0;
  231. string s;
  232. switch( t->op ){
  233. case IR_JSR:
  234. q=d_new Tile( "\tcall\t"+t->sconst+'\n' );
  235. break;
  236. case IR_RET:
  237. q=d_new Tile( "\tret\n" );
  238. break;
  239. case IR_RETURN:
  240. q=munchReg( t->l );q->want_l=EAX;
  241. s="\tjmp\t"+t->sconst+'\n';
  242. q=d_new Tile( s,q );
  243. break;
  244. case IR_FRETURN:
  245. q=munchFP( t->l );
  246. s="\tjmp\t"+t->sconst+'\n';
  247. q=d_new Tile( s,q );
  248. break;
  249. case IR_CALL:
  250. q=munchCall( t );
  251. break;
  252. case IR_JUMP:
  253. q=d_new Tile( "\tjmp\t"+t->sconst+'\n' );
  254. break;
  255. case IR_JUMPT:
  256. if( TNode *p=t->l ){
  257. bool neg=false;
  258. if( isRelop( p->op ) ){
  259. string func;
  260. q=genCompare( p,func,neg );
  261. q=d_new Tile( "\tj"+func+"\t"+t->sconst+"\n",q );
  262. }
  263. }
  264. break;
  265. case IR_JUMPF:
  266. if( TNode *p=t->l ){
  267. bool neg=true;
  268. if( isRelop( p->op ) ){
  269. string func;
  270. q=genCompare( p,func,neg );
  271. q=d_new Tile( "\tj"+func+"\t"+t->sconst+"\n",q );
  272. }
  273. }
  274. break;
  275. case IR_MOVE:
  276. if( matchMEM( t->r,s ) ){
  277. string c;
  278. if( matchCONST( t->l,c ) ){
  279. q=d_new Tile( "\tmov\t"+s+","+c+"\n" );
  280. }else if( t->l->op==IR_ADD || t->l->op==IR_SUB ){
  281. TNode *p=0;
  282. if( nodesEqual( t->l->l,t->r ) ) p=t->l->r;
  283. else if( t->l->op==IR_ADD && nodesEqual( t->l->r,t->r ) ) p=t->l->l;
  284. if( p ){
  285. string c,op;
  286. switch( t->l->op ){
  287. case IR_ADD:op="\tadd\t";break;
  288. case IR_SUB:op="\tsub\t";break;
  289. }
  290. if( matchCONST( p,c ) ){
  291. q=d_new Tile( op+s+","+c+"\n" );
  292. }else{
  293. q=d_new Tile( op+s+",%l\n",munchReg( p ) );
  294. }
  295. }
  296. }
  297. if( !q ) q=d_new Tile( "\tmov\t"+s+",%l\n",munchReg( t->l ) );
  298. }
  299. break;
  300. }
  301. if( !q ) q=munchReg( t );
  302. return q;
  303. }
  304. ///////////////////////////////////////////
  305. // munch and return result in a register //
  306. ///////////////////////////////////////////
  307. Tile *Codegen_x86::munchReg( TNode *t ){
  308. if( !t ) return 0;
  309. string s;
  310. Tile *q=0;
  311. switch( t->op ){
  312. case IR_JUMPT:
  313. q=d_new Tile( "\tand\t%l,%l\n\tjnz\t"+t->sconst+'\n',munchReg( t->l ) );
  314. break;
  315. case IR_JUMPF:
  316. q=d_new Tile( "\tand\t%l,%l\n\tjz\t"+t->sconst+'\n',munchReg( t->l ) );
  317. break;
  318. case IR_JUMPGE:
  319. q=d_new Tile( "\tcmp\t%l,%r\n\tjnc\t"+t->sconst+'\n',munchReg( t->l ),munchReg( t->r ) );
  320. break;
  321. case IR_CALL:
  322. q=munchCall( t );
  323. break;
  324. case IR_MOVE:
  325. //MUST BE MOVE TO MEM!
  326. if( matchMEM( t->r,s ) ){
  327. q=d_new Tile( "\tmov\t"+s+",%l\n",munchReg( t->l ) );
  328. }else if( t->r->op==IR_MEM ){
  329. q=d_new Tile( "\tmov\t[%r],%l\n",munchReg( t->l ),munchReg( t->r->l ) );
  330. }
  331. break;
  332. case IR_MEM:
  333. if( matchMEM( t,s ) ){
  334. q=d_new Tile( "\tmov\t%l,"+s+"\n" );
  335. }else{
  336. q=d_new Tile( "\tmov\t%l,[%l]\n",munchReg( t->l ) );
  337. }
  338. break;
  339. case IR_SEQ:
  340. q=d_new Tile( "",munch(t->l),munch(t->r) );
  341. break;
  342. case IR_ARG:
  343. q=d_new Tile( "\tlea\t%l,[esp"+itoa_sgn(t->iconst)+"]\n" );
  344. break;
  345. case IR_LOCAL:
  346. q=d_new Tile( "\tlea\t%l,[ebp"+itoa_sgn(t->iconst)+"]\n" );
  347. break;
  348. case IR_GLOBAL:
  349. q=d_new Tile( string( "\tmov\t%l," )+t->sconst+'\n' );
  350. break;
  351. case IR_CAST:
  352. q=munchFP( t->l );
  353. s="\tpush\t%l\n\tfistp\t[esp]\n\tpop\t%l\n";
  354. q=d_new Tile( s,q );
  355. break;
  356. case IR_CONST:
  357. q=d_new Tile( "\tmov\t%l,"+itoa(t->iconst)+"\n" );
  358. break;
  359. case IR_NEG:
  360. q=munchUnary( t );
  361. break;
  362. case IR_AND:case IR_OR:case IR_XOR:
  363. q=munchLogical( t );
  364. break;
  365. case IR_ADD:case IR_SUB:case IR_MUL:case IR_DIV:
  366. q=munchArith( t );
  367. break;
  368. case IR_SHL:case IR_SHR:case IR_SAR:
  369. q=munchShift( t );
  370. break;
  371. case IR_SETEQ:case IR_SETNE:case IR_SETLT:case IR_SETGT:case IR_SETLE:case IR_SETGE:
  372. q=munchRelop( t );
  373. break;
  374. case IR_FSETEQ:case IR_FSETNE:case IR_FSETLT:case IR_FSETGT:case IR_FSETLE:case IR_FSETGE:
  375. q=munchFPRelop( t );
  376. break;
  377. default:
  378. q=munchFP( t );if( !q ) return 0;
  379. s="\tpush\t%l\n\tfstp\t[esp]\n\tpop\t%l\n";
  380. q=d_new Tile( s,q );
  381. }
  382. return q;
  383. }
  384. /////////////////////////////////////////
  385. // munch and return result on FP stack //
  386. /////////////////////////////////////////
  387. Tile *Codegen_x86::munchFP( TNode *t ){
  388. if( !t ) return 0;
  389. string s;
  390. Tile *q=0;
  391. switch( t->op ){
  392. case IR_FCALL:
  393. q=munchCall( t );
  394. break;
  395. case IR_FCAST:
  396. s="\tpush\t%l\n\tfild\t[esp]\n\tpop\t%l\n";
  397. q=d_new Tile( s,munchReg( t->l ) );
  398. break;
  399. case IR_FNEG:
  400. q=munchFPUnary( t );
  401. break;
  402. case IR_FADD:case IR_FSUB:case IR_FMUL:case IR_FDIV:
  403. q=munchFPArith( t );
  404. break;
  405. default:
  406. q=munchReg( t );if( !q ) return 0;
  407. s="\tpush\t%l\n\tfld\t[esp]\n\tpop\t%l\n";
  408. q=d_new Tile( s,q );
  409. }
  410. return q;
  411. }