cg386add.pas 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate i386 assembler for in add node
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit cg386add;
  19. interface
  20. uses
  21. tree;
  22. procedure secondadd(var p : ptree);
  23. implementation
  24. uses
  25. cobjects,verbose,globals,
  26. symtable,aasm,i386,types,
  27. cgi386,cgai386,temp_gen,tgeni386,hcodegen;
  28. {*****************************************************************************
  29. SecondAdd
  30. *****************************************************************************}
  31. procedure setaddresult(cmpop,unsigned : boolean;var p :ptree);
  32. var
  33. flags : tresflags;
  34. begin
  35. if (p^.left^.resulttype^.deftype<>stringdef) and
  36. ((p^.left^.resulttype^.deftype<>setdef) or
  37. (psetdef(p^.left^.resulttype)^.settype=smallset)) then
  38. if (p^.left^.location.loc=LOC_REFERENCE) or
  39. (p^.left^.location.loc=LOC_MEM) then
  40. ungetiftemp(p^.left^.location.reference);
  41. if (p^.right^.resulttype^.deftype<>stringdef) and
  42. ((p^.right^.resulttype^.deftype<>setdef) or
  43. (psetdef(p^.right^.resulttype)^.settype=smallset)) then
  44. { this can be useful if for instance length(string) is called }
  45. if (p^.right^.location.loc=LOC_REFERENCE) or
  46. (p^.right^.location.loc=LOC_MEM) then
  47. ungetiftemp(p^.right^.location.reference);
  48. { in case of comparison operation the put result in the flags }
  49. if cmpop then
  50. begin
  51. if not(unsigned) then
  52. begin
  53. if p^.swaped then
  54. case p^.treetype of
  55. equaln : flags:=F_E;
  56. unequaln : flags:=F_NE;
  57. ltn : flags:=F_G;
  58. lten : flags:=F_GE;
  59. gtn : flags:=F_L;
  60. gten : flags:=F_LE;
  61. end
  62. else
  63. case p^.treetype of
  64. equaln : flags:=F_E;
  65. unequaln : flags:=F_NE;
  66. ltn : flags:=F_L;
  67. lten : flags:=F_LE;
  68. gtn : flags:=F_G;
  69. gten : flags:=F_GE;
  70. end;
  71. end
  72. else
  73. begin
  74. if p^.swaped then
  75. case p^.treetype of
  76. equaln : flags:=F_E;
  77. unequaln : flags:=F_NE;
  78. ltn : flags:=F_A;
  79. lten : flags:=F_AE;
  80. gtn : flags:=F_B;
  81. gten : flags:=F_BE;
  82. end
  83. else
  84. case p^.treetype of
  85. equaln : flags:=F_E;
  86. unequaln : flags:=F_NE;
  87. ltn : flags:=F_B;
  88. lten : flags:=F_BE;
  89. gtn : flags:=F_A;
  90. gten : flags:=F_AE;
  91. end;
  92. end;
  93. p^.location.loc:=LOC_FLAGS;
  94. p^.location.resflags:=flags;
  95. end;
  96. end;
  97. procedure addstring(var p : ptree);
  98. var
  99. swapp : ptree;
  100. pushedregs : tpushed;
  101. href : treference;
  102. pushed,cmpop : boolean;
  103. begin
  104. { string operations are not commutative }
  105. if p^.swaped then
  106. begin
  107. swapp:=p^.left;
  108. p^.left:=p^.right;
  109. p^.right:=swapp;
  110. { because of jump being produced at comparison below: }
  111. p^.swaped:=not(p^.swaped);
  112. end;
  113. {$ifdef UseAnsiString}
  114. if is_ansistring(p^.left^.resulttype) then
  115. begin
  116. case p^.treetype of
  117. addn :
  118. begin
  119. { we do not need destination anymore }
  120. del_reference(p^.left^.location.reference);
  121. del_reference(p^.right^.location.reference);
  122. { concatansistring(p); }
  123. end;
  124. ltn,lten,gtn,gten,
  125. equaln,unequaln :
  126. begin
  127. pushusedregisters(pushedregs,$ff);
  128. secondpass(p^.left);
  129. del_reference(p^.left^.location.reference);
  130. emitpushreferenceaddr(p^.left^.location.reference);
  131. secondpass(p^.right);
  132. del_reference(p^.right^.location.reference);
  133. emitpushreferenceaddr(p^.right^.location.reference);
  134. emitcall('ANSISTRCMP',true);
  135. maybe_loadesi;
  136. popusedregisters(pushedregs);
  137. end;
  138. end;
  139. end
  140. else
  141. {$endif UseAnsiString}
  142. case p^.treetype of
  143. addn :
  144. begin
  145. cmpop:=false;
  146. secondpass(p^.left);
  147. { if str_concat is set in expr
  148. s:=s+ ... no need to create a temp string (PM) }
  149. if (p^.left^.treetype<>addn) and not (p^.use_strconcat) then
  150. begin
  151. { can only reference be }
  152. { string in register would be funny }
  153. { therefore produce a temporary string }
  154. { release the registers }
  155. del_reference(p^.left^.location.reference);
  156. gettempofsizereference(256,href);
  157. copystring(href,p^.left^.location.reference,255);
  158. ungetiftemp(p^.left^.location.reference);
  159. { does not hurt: }
  160. p^.left^.location.loc:=LOC_MEM;
  161. p^.left^.location.reference:=href;
  162. end;
  163. secondpass(p^.right);
  164. { on the right we do not need the register anymore too }
  165. del_reference(p^.right^.location.reference);
  166. { if p^.right^.resulttype^.deftype=orddef then
  167. begin
  168. pushusedregisters(pushedregs,$ff);
  169. exprasmlist^.concat(new(pai386,op_ref_reg(
  170. A_LEA,S_L,newreference(p^.left^.location.reference),R_EDI)));
  171. exprasmlist^.concat(new(pai386,op_reg_reg(
  172. A_XOR,S_L,R_EBX,R_EBX)));
  173. reset_reference(href);
  174. href.base:=R_EDI;
  175. exprasmlist^.concat(new(pai386,op_ref_reg(
  176. A_MOV,S_B,newreference(href),R_BL)));
  177. exprasmlist^.concat(new(pai386,op_reg(
  178. A_INC,S_L,R_EBX)));
  179. exprasmlist^.concat(new(pai386,op_reg_ref(
  180. A_MOV,S_B,R_BL,newreference(href))));
  181. href.index:=R_EBX;
  182. if p^.right^.treetype=ordconstn then
  183. exprasmlist^.concat(new(pai386,op_const_ref(
  184. A_MOV,S_L,p^.right^.value,newreference(href))))
  185. else
  186. begin
  187. if p^.right^.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  188. exprasmlist^.concat(new(pai386,op_reg_ref(
  189. A_MOV,S_B,p^.right^.location.register,newreference(href))))
  190. else
  191. begin
  192. exprasmlist^.concat(new(pai386,op_ref_reg(
  193. A_MOV,S_L,newreference(p^.right^.location.reference),R_EAX)));
  194. exprasmlist^.concat(new(pai386,op_reg_ref(
  195. A_MOV,S_B,R_AL,newreference(href))));
  196. end;
  197. end;
  198. popusedregisters(pushedregs);
  199. end
  200. else }
  201. begin
  202. if p^.use_strconcat then
  203. pushusedregisters(pushedregs,pstringdef(p^.left^.resulttype)^.len)
  204. else
  205. pushusedregisters(pushedregs,$ff);
  206. emitpushreferenceaddr(p^.left^.location.reference);
  207. emitpushreferenceaddr(p^.right^.location.reference);
  208. emitcall('STRCONCAT',true);
  209. maybe_loadesi;
  210. popusedregisters(pushedregs);
  211. end;
  212. set_location(p^.location,p^.left^.location);
  213. ungetiftemp(p^.right^.location.reference);
  214. end;
  215. ltn,lten,gtn,gten,
  216. equaln,unequaln :
  217. begin
  218. cmpop:=true;
  219. { generate better code for s='' and s<>'' }
  220. if (p^.treetype in [equaln,unequaln]) and
  221. (((p^.left^.treetype=stringconstn) and (p^.left^.values^='')) or
  222. ((p^.right^.treetype=stringconstn) and (p^.right^.values^=''))) then
  223. begin
  224. secondpass(p^.left);
  225. { are too few registers free? }
  226. pushed:=maybe_push(p^.right^.registers32,p);
  227. secondpass(p^.right);
  228. if pushed then restore(p);
  229. del_reference(p^.right^.location.reference);
  230. del_reference(p^.left^.location.reference);
  231. { only one node can be stringconstn }
  232. { else pass 1 would have evaluted }
  233. { this node }
  234. if p^.left^.treetype=stringconstn then
  235. exprasmlist^.concat(new(pai386,op_const_ref(
  236. A_CMP,S_B,0,newreference(p^.right^.location.reference))))
  237. else
  238. exprasmlist^.concat(new(pai386,op_const_ref(
  239. A_CMP,S_B,0,newreference(p^.left^.location.reference))));
  240. end
  241. else
  242. begin
  243. pushusedregisters(pushedregs,$ff);
  244. secondpass(p^.left);
  245. del_reference(p^.left^.location.reference);
  246. emitpushreferenceaddr(p^.left^.location.reference);
  247. secondpass(p^.right);
  248. del_reference(p^.right^.location.reference);
  249. emitpushreferenceaddr(p^.right^.location.reference);
  250. emitcall('STRCMP',true);
  251. maybe_loadesi;
  252. popusedregisters(pushedregs);
  253. end;
  254. ungetiftemp(p^.left^.location.reference);
  255. ungetiftemp(p^.right^.location.reference);
  256. end;
  257. else Message(sym_e_type_mismatch);
  258. end;
  259. setaddresult(cmpop,true,p);
  260. end;
  261. procedure secondadd(var p : ptree);
  262. { is also being used for xor, and "mul", "sub, or and comparative }
  263. { operators }
  264. label do_normal;
  265. var
  266. swapp : ptree;
  267. hregister : tregister;
  268. pushed,mboverflow,cmpop : boolean;
  269. op : tasmop;
  270. pushedregs : tpushed;
  271. flags : tresflags;
  272. otl,ofl : plabel;
  273. power : longint;
  274. href : treference;
  275. opsize : topsize;
  276. hl4: plabel;
  277. { true, if unsigned types are compared }
  278. unsigned : boolean;
  279. { is_in_dest if the result is put directly into }
  280. { the resulting refernce or varregister }
  281. { true, if a small set is handled with the longint code }
  282. is_set : boolean;
  283. is_in_dest : boolean;
  284. { true, if for sets subtractions the extra not should generated }
  285. extra_not : boolean;
  286. {$ifdef SUPPORT_MMX}
  287. mmxbase : tmmxtype;
  288. {$endif SUPPORT_MMX}
  289. begin
  290. if (p^.left^.resulttype^.deftype=stringdef) then
  291. begin
  292. addstring(p);
  293. exit;
  294. end;
  295. unsigned:=false;
  296. is_in_dest:=false;
  297. extra_not:=false;
  298. opsize:=S_L;
  299. { calculate the operator which is more difficult }
  300. firstcomplex(p);
  301. { handling boolean expressions extra: }
  302. if ((p^.left^.resulttype^.deftype=orddef) and
  303. (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) or
  304. ((p^.right^.resulttype^.deftype=orddef) and
  305. (porddef(p^.right^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) then
  306. begin
  307. if (porddef(p^.left^.resulttype)^.typ=bool8bit) or
  308. (porddef(p^.right^.resulttype)^.typ=bool8bit) then
  309. opsize:=S_B
  310. else
  311. if (porddef(p^.left^.resulttype)^.typ=bool16bit) or
  312. (porddef(p^.right^.resulttype)^.typ=bool16bit) then
  313. opsize:=S_W
  314. else
  315. opsize:=S_L;
  316. case p^.treetype of
  317. andn,
  318. orn : begin
  319. p^.location.loc:=LOC_JUMP;
  320. cmpop:=false;
  321. case p^.treetype of
  322. andn : begin
  323. otl:=truelabel;
  324. getlabel(truelabel);
  325. secondpass(p^.left);
  326. maketojumpbool(p^.left);
  327. emitl(A_LABEL,truelabel);
  328. truelabel:=otl;
  329. end;
  330. orn : begin
  331. ofl:=falselabel;
  332. getlabel(falselabel);
  333. secondpass(p^.left);
  334. maketojumpbool(p^.left);
  335. emitl(A_LABEL,falselabel);
  336. falselabel:=ofl;
  337. end;
  338. else
  339. Message(sym_e_type_mismatch);
  340. end;
  341. secondpass(p^.right);
  342. maketojumpbool(p^.right);
  343. end;
  344. unequaln,
  345. equaln,xorn : begin
  346. if p^.left^.treetype=ordconstn then
  347. begin
  348. swapp:=p^.right;
  349. p^.right:=p^.left;
  350. p^.left:=swapp;
  351. p^.swaped:=not(p^.swaped);
  352. end;
  353. secondpass(p^.left);
  354. p^.location:=p^.left^.location;
  355. { are enough registers free ? }
  356. pushed:=maybe_push(p^.right^.registers32,p);
  357. secondpass(p^.right);
  358. if pushed then restore(p);
  359. goto do_normal;
  360. end
  361. else
  362. Message(sym_e_type_mismatch);
  363. end
  364. end
  365. else if (p^.left^.resulttype^.deftype=setdef) and
  366. not(psetdef(p^.left^.resulttype)^.settype=smallset) then
  367. begin
  368. mboverflow:=false;
  369. secondpass(p^.left);
  370. set_location(p^.location,p^.left^.location);
  371. { are too few registers free? }
  372. pushed:=maybe_push(p^.right^.registers32,p);
  373. secondpass(p^.right);
  374. if pushed then restore(p);
  375. { not commutative }
  376. if p^.swaped then
  377. begin
  378. swapp:=p^.left;
  379. p^.left:=p^.right;
  380. p^.right:=swapp;
  381. { because of jump being produced by comparison }
  382. p^.swaped:=not(p^.swaped);
  383. end;
  384. case p^.treetype of
  385. equaln,unequaln:
  386. begin
  387. cmpop:=true;
  388. del_reference(p^.left^.location.reference);
  389. del_reference(p^.right^.location.reference);
  390. pushusedregisters(pushedregs,$ff);
  391. emitpushreferenceaddr(p^.right^.location.reference);
  392. emitpushreferenceaddr(p^.left^.location.reference);
  393. emitcall('SET_COMP_SETS',true);
  394. maybe_loadesi;
  395. popusedregisters(pushedregs);
  396. ungetiftemp(p^.left^.location.reference);
  397. ungetiftemp(p^.right^.location.reference);
  398. end;
  399. addn,symdifn,subn,muln:
  400. begin
  401. cmpop:=false;
  402. del_reference(p^.left^.location.reference);
  403. del_reference(p^.right^.location.reference);
  404. href.symbol:=nil;
  405. pushusedregisters(pushedregs,$ff);
  406. gettempofsizereference(32,href);
  407. emitpushreferenceaddr(href);
  408. { wrong place !! was hard to find out
  409. pushusedregisters(pushedregs,$ff);}
  410. emitpushreferenceaddr(p^.right^.location.reference);
  411. emitpushreferenceaddr(p^.left^.location.reference);
  412. case p^.treetype of
  413. subn:
  414. emitcall('SET_SUB_SETS',true);
  415. addn:
  416. emitcall('SET_ADD_SETS',true);
  417. symdifn:
  418. emitcall('SET_SYMDIF_SETS',true);
  419. muln:
  420. emitcall('SET_MUL_SETS',true);
  421. end;
  422. maybe_loadesi;
  423. popusedregisters(pushedregs);
  424. ungetiftemp(p^.left^.location.reference);
  425. ungetiftemp(p^.right^.location.reference);
  426. p^.location.loc:=LOC_MEM;
  427. stringdispose(p^.location.reference.symbol);
  428. p^.location.reference:=href;
  429. end;
  430. else Message(sym_e_type_mismatch);
  431. end;
  432. end
  433. else
  434. begin
  435. { in case of constant put it to the left }
  436. if p^.left^.treetype=ordconstn then
  437. begin
  438. swapp:=p^.right;
  439. p^.right:=p^.left;
  440. p^.left:=swapp;
  441. p^.swaped:=not(p^.swaped);
  442. end;
  443. secondpass(p^.left);
  444. { this will be complicated as
  445. a lot of code below assumes that
  446. p^.location and p^.left^.location are the same }
  447. {$ifdef test_dest_loc}
  448. if dest_loc_known and (dest_loc_tree=p) and
  449. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  450. begin
  451. set_location(p^.location,dest_loc);
  452. in_dest_loc:=true;
  453. is_in_dest:=true;
  454. end
  455. else
  456. {$endif test_dest_loc}
  457. set_location(p^.location,p^.left^.location);
  458. { are too few registers free? }
  459. pushed:=maybe_push(p^.right^.registers32,p);
  460. secondpass(p^.right);
  461. if pushed then restore(p);
  462. if (p^.left^.resulttype^.deftype=pointerdef) or
  463. (p^.right^.resulttype^.deftype=pointerdef) or
  464. ((p^.right^.resulttype^.deftype=objectdef) and
  465. pobjectdef(p^.right^.resulttype)^.isclass and
  466. (p^.left^.resulttype^.deftype=objectdef) and
  467. pobjectdef(p^.left^.resulttype)^.isclass
  468. ) or
  469. (p^.left^.resulttype^.deftype=classrefdef) or
  470. (p^.left^.resulttype^.deftype=procvardef) or
  471. (p^.left^.resulttype^.deftype=enumdef) or
  472. ((p^.left^.resulttype^.deftype=orddef) and
  473. (porddef(p^.left^.resulttype)^.typ=s32bit)) or
  474. ((p^.right^.resulttype^.deftype=orddef) and
  475. (porddef(p^.right^.resulttype)^.typ=s32bit)) or
  476. ((p^.left^.resulttype^.deftype=orddef) and
  477. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  478. ((p^.right^.resulttype^.deftype=orddef) and
  479. (porddef(p^.right^.resulttype)^.typ=u32bit)) or
  480. { as well as small sets }
  481. ((p^.left^.resulttype^.deftype=setdef) and
  482. (psetdef(p^.left^.resulttype)^.settype=smallset)
  483. ) then
  484. begin
  485. do_normal:
  486. mboverflow:=false;
  487. cmpop:=false;
  488. if (p^.left^.resulttype^.deftype=pointerdef) or
  489. (p^.right^.resulttype^.deftype=pointerdef) or
  490. ((p^.left^.resulttype^.deftype=orddef) and
  491. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  492. ((p^.right^.resulttype^.deftype=orddef) and
  493. (porddef(p^.right^.resulttype)^.typ=u32bit)) then
  494. unsigned:=true;
  495. is_set:=p^.resulttype^.deftype=setdef;
  496. case p^.treetype of
  497. addn : begin
  498. if is_set then
  499. begin
  500. op:=A_OR;
  501. mboverflow:=false;
  502. unsigned:=false;
  503. end
  504. else
  505. begin
  506. op:=A_ADD;
  507. mboverflow:=true;
  508. end;
  509. end;
  510. symdifn : begin
  511. { the symetric diff is only for sets }
  512. if is_set then
  513. begin
  514. op:=A_XOR;
  515. mboverflow:=false;
  516. unsigned:=false;
  517. end
  518. else
  519. begin
  520. Message(sym_e_type_mismatch);
  521. end;
  522. end;
  523. muln : begin
  524. if is_set then
  525. begin
  526. op:=A_AND;
  527. mboverflow:=false;
  528. unsigned:=false;
  529. end
  530. else
  531. begin
  532. if unsigned then
  533. op:=A_MUL
  534. else
  535. op:=A_IMUL;
  536. mboverflow:=true;
  537. end;
  538. end;
  539. subn : begin
  540. if is_set then
  541. begin
  542. op:=A_AND;
  543. mboverflow:=false;
  544. unsigned:=false;
  545. extra_not:=true;
  546. end
  547. else
  548. begin
  549. op:=A_SUB;
  550. mboverflow:=true;
  551. end;
  552. end;
  553. ltn,lten,gtn,gten,
  554. equaln,unequaln :
  555. begin
  556. op:=A_CMP;
  557. cmpop:=true;
  558. end;
  559. xorn : op:=A_XOR;
  560. orn : op:=A_OR;
  561. andn : op:=A_AND;
  562. else Message(sym_e_type_mismatch);
  563. end;
  564. { left and right no register? }
  565. { then one must be demanded }
  566. if (p^.left^.location.loc<>LOC_REGISTER) and
  567. (p^.right^.location.loc<>LOC_REGISTER) then
  568. begin
  569. { register variable ? }
  570. if (p^.left^.location.loc=LOC_CREGISTER) then
  571. begin
  572. { it is OK if this is the destination }
  573. if is_in_dest then
  574. begin
  575. hregister:=p^.location.register;
  576. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  577. hregister);
  578. end
  579. else
  580. if cmpop then
  581. begin
  582. { do not disturb the register }
  583. hregister:=p^.location.register;
  584. end
  585. else
  586. begin
  587. case opsize of
  588. S_L : hregister:=getregister32;
  589. S_B : hregister:=reg32toreg8(getregister32);
  590. end;
  591. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  592. hregister);
  593. end
  594. end
  595. else
  596. begin
  597. del_reference(p^.left^.location.reference);
  598. if is_in_dest then
  599. begin
  600. hregister:=p^.location.register;
  601. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  602. newreference(p^.left^.location.reference),hregister)));
  603. end
  604. else
  605. begin
  606. { first give free, then demand new register }
  607. case opsize of
  608. S_L : hregister:=getregister32;
  609. S_W : hregister:=reg32toreg16(getregister32);
  610. S_B : hregister:=reg32toreg8(getregister32);
  611. end;
  612. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  613. newreference(p^.left^.location.reference),hregister)));
  614. end;
  615. end;
  616. p^.location.loc:=LOC_REGISTER;
  617. p^.location.register:=hregister;
  618. end
  619. else
  620. { if on the right the register then swap }
  621. if (p^.right^.location.loc=LOC_REGISTER) then
  622. begin
  623. swap_location(p^.location,p^.right^.location);
  624. { newly swapped also set swapped flag }
  625. p^.swaped:=not(p^.swaped);
  626. end;
  627. { at this point, p^.location.loc should be LOC_REGISTER }
  628. { and p^.location.register should be a valid register }
  629. { containing the left result }
  630. if p^.right^.location.loc<>LOC_REGISTER then
  631. begin
  632. if (p^.treetype=subn) and p^.swaped then
  633. begin
  634. if p^.right^.location.loc=LOC_CREGISTER then
  635. begin
  636. if extra_not then
  637. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  638. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  639. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  640. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  641. end
  642. else
  643. begin
  644. if extra_not then
  645. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  646. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  647. newreference(p^.right^.location.reference),R_EDI)));
  648. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,p^.location.register,R_EDI)));
  649. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,opsize,R_EDI,p^.location.register)));
  650. del_reference(p^.right^.location.reference);
  651. end;
  652. end
  653. else
  654. begin
  655. if (p^.right^.treetype=ordconstn) and
  656. (op=A_CMP) and
  657. (p^.right^.value=0) then
  658. begin
  659. exprasmlist^.concat(new(pai386,op_reg_reg(A_TEST,opsize,p^.location.register,
  660. p^.location.register)));
  661. end
  662. else if (p^.right^.treetype=ordconstn) and
  663. (op=A_ADD) and
  664. (p^.right^.value=1) then
  665. begin
  666. exprasmlist^.concat(new(pai386,op_reg(A_INC,opsize,
  667. p^.location.register)));
  668. end
  669. else if (p^.right^.treetype=ordconstn) and
  670. (op=A_SUB) and
  671. (p^.right^.value=1) then
  672. begin
  673. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,
  674. p^.location.register)));
  675. end
  676. else if (p^.right^.treetype=ordconstn) and
  677. (op=A_IMUL) and
  678. (ispowerof2(p^.right^.value,power)) then
  679. begin
  680. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,opsize,power,
  681. p^.location.register)));
  682. end
  683. else
  684. begin
  685. if (p^.right^.location.loc=LOC_CREGISTER) then
  686. begin
  687. if extra_not then
  688. begin
  689. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,R_EDI);
  690. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  691. emit_reg_reg(A_AND,S_L,R_EDI,
  692. p^.location.register);
  693. end
  694. else
  695. begin
  696. emit_reg_reg(op,opsize,p^.right^.location.register,
  697. p^.location.register);
  698. end;
  699. end
  700. else
  701. begin
  702. if extra_not then
  703. begin
  704. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(
  705. p^.right^.location.reference),R_EDI)));
  706. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  707. emit_reg_reg(A_AND,S_L,R_EDI,
  708. p^.location.register);
  709. end
  710. else
  711. begin
  712. exprasmlist^.concat(new(pai386,op_ref_reg(op,opsize,newreference(
  713. p^.right^.location.reference),p^.location.register)));
  714. end;
  715. del_reference(p^.right^.location.reference);
  716. end;
  717. end;
  718. end;
  719. end
  720. else
  721. begin
  722. { when swapped another result register }
  723. if (p^.treetype=subn) and p^.swaped then
  724. begin
  725. if extra_not then
  726. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  727. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  728. p^.location.register,p^.right^.location.register)));
  729. swap_location(p^.location,p^.right^.location);
  730. { newly swapped also set swapped flag }
  731. { just to maintain ordering }
  732. p^.swaped:=not(p^.swaped);
  733. end
  734. else
  735. begin
  736. if extra_not then
  737. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.right^.location.register)));
  738. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  739. p^.right^.location.register,
  740. p^.location.register)));
  741. end;
  742. case opsize of
  743. S_L : ungetregister32(p^.right^.location.register);
  744. S_B : ungetregister32(reg8toreg32(p^.right^.location.register));
  745. end;
  746. end;
  747. if cmpop then
  748. case opsize of
  749. S_L : ungetregister32(p^.location.register);
  750. S_B : ungetregister32(reg8toreg32(p^.location.register));
  751. end;
  752. { only in case of overflow operations }
  753. { produce overflow code }
  754. if mboverflow then
  755. { we must put it here directly, because sign of operation }
  756. { is in unsigned VAR!! }
  757. begin
  758. if cs_check_overflow in aktswitches then
  759. begin
  760. getlabel(hl4);
  761. if unsigned then
  762. emitl(A_JNB,hl4)
  763. else
  764. emitl(A_JNO,hl4);
  765. emitcall('RE_OVERFLOW',true);
  766. emitl(A_LABEL,hl4);
  767. end;
  768. end;
  769. end
  770. else if ((p^.left^.resulttype^.deftype=orddef) and
  771. (porddef(p^.left^.resulttype)^.typ=uchar)) then
  772. begin
  773. case p^.treetype of
  774. ltn,lten,gtn,gten,
  775. equaln,unequaln :
  776. cmpop:=true;
  777. else Message(sym_e_type_mismatch);
  778. end;
  779. unsigned:=true;
  780. { left and right no register? }
  781. { the one must be demanded }
  782. if (p^.location.loc<>LOC_REGISTER) and
  783. (p^.right^.location.loc<>LOC_REGISTER) then
  784. begin
  785. if p^.location.loc=LOC_CREGISTER then
  786. begin
  787. if cmpop then
  788. { do not disturb register }
  789. hregister:=p^.location.register
  790. else
  791. begin
  792. hregister:=reg32toreg8(getregister32);
  793. emit_reg_reg(A_MOV,S_B,p^.location.register,
  794. hregister);
  795. end;
  796. end
  797. else
  798. begin
  799. del_reference(p^.location.reference);
  800. { first give free then demand new register }
  801. hregister:=reg32toreg8(getregister32);
  802. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_B,newreference(p^.location.reference),
  803. hregister)));
  804. end;
  805. p^.location.loc:=LOC_REGISTER;
  806. p^.location.register:=hregister;
  807. end;
  808. { now p always a register }
  809. if (p^.right^.location.loc=LOC_REGISTER) and
  810. (p^.location.loc<>LOC_REGISTER) then
  811. begin
  812. swap_location(p^.location,p^.right^.location);
  813. { newly swapped also set swapped flag }
  814. p^.swaped:=not(p^.swaped);
  815. end;
  816. if p^.right^.location.loc<>LOC_REGISTER then
  817. begin
  818. if p^.right^.location.loc=LOC_CREGISTER then
  819. begin
  820. emit_reg_reg(A_CMP,S_B,
  821. p^.right^.location.register,p^.location.register);
  822. end
  823. else
  824. begin
  825. exprasmlist^.concat(new(pai386,op_ref_reg(A_CMP,S_B,newreference(
  826. p^.right^.location.reference),p^.location.register)));
  827. del_reference(p^.right^.location.reference);
  828. end;
  829. end
  830. else
  831. begin
  832. emit_reg_reg(A_CMP,S_B,p^.right^.location.register,
  833. p^.location.register);
  834. ungetregister32(reg8toreg32(p^.right^.location.register));
  835. end;
  836. ungetregister32(reg8toreg32(p^.location.register));
  837. end
  838. else if (p^.left^.resulttype^.deftype=floatdef) and
  839. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  840. begin
  841. { real constants to the left }
  842. if p^.left^.treetype=realconstn then
  843. begin
  844. swapp:=p^.right;
  845. p^.right:=p^.left;
  846. p^.left:=swapp;
  847. p^.swaped:=not(p^.swaped);
  848. end;
  849. cmpop:=false;
  850. case p^.treetype of
  851. addn : op:=A_FADDP;
  852. muln : op:=A_FMULP;
  853. subn : op:=A_FSUBP;
  854. slashn : op:=A_FDIVP;
  855. ltn,lten,gtn,gten,
  856. equaln,unequaln : begin
  857. op:=A_FCOMPP;
  858. cmpop:=true;
  859. end;
  860. else Message(sym_e_type_mismatch);
  861. end;
  862. if (p^.right^.location.loc<>LOC_FPU) then
  863. begin
  864. floatload(pfloatdef(p^.right^.resulttype)^.typ,p^.right^.location.reference);
  865. if (p^.left^.location.loc<>LOC_FPU) then
  866. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  867. { left was on the stack => swap }
  868. else
  869. p^.swaped:=not(p^.swaped);
  870. { releases the right reference }
  871. del_reference(p^.right^.location.reference);
  872. end
  873. { the nominator in st0 }
  874. else if (p^.left^.location.loc<>LOC_FPU) then
  875. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  876. { fpu operands are always in the wrong order on the stack }
  877. else
  878. p^.swaped:=not(p^.swaped);
  879. { releases the left reference }
  880. if (p^.left^.location.loc<>LOC_FPU) then
  881. del_reference(p^.left^.location.reference);
  882. { if we swaped the tree nodes, then use the reverse operator }
  883. if p^.swaped then
  884. begin
  885. if (p^.treetype=slashn) then
  886. op:=A_FDIVRP
  887. else if (p^.treetype=subn) then
  888. op:=A_FSUBRP;
  889. end;
  890. { to avoid the pentium bug
  891. if (op=FDIVP) and (opt_processors=pentium) then
  892. exprasmlist^.concat(new(pai386,op_CALL,S_NO,'EMUL_FDIVP')
  893. else
  894. }
  895. { the Intel assemblers want operands }
  896. if op<>A_FCOMPP then
  897. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,R_ST,R_ST1)))
  898. else
  899. exprasmlist^.concat(new(pai386,op_none(op,S_NO)));
  900. { on comparison load flags }
  901. if cmpop then
  902. begin
  903. if not(R_EAX in unused) then
  904. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  905. exprasmlist^.concat(new(pai386,op_reg(A_FNSTSW,S_NO,R_AX)));
  906. exprasmlist^.concat(new(pai386,op_none(A_SAHF,S_NO)));
  907. if not(R_EAX in unused) then
  908. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  909. if p^.swaped then
  910. case p^.treetype of
  911. equaln : flags:=F_E;
  912. unequaln : flags:=F_NE;
  913. ltn : flags:=F_A;
  914. lten : flags:=F_AE;
  915. gtn : flags:=F_B;
  916. gten : flags:=F_BE;
  917. end
  918. else
  919. case p^.treetype of
  920. equaln : flags:=F_E;
  921. unequaln : flags:=F_NE;
  922. ltn : flags:=F_B;
  923. lten : flags:=F_BE;
  924. gtn : flags:=F_A;
  925. gten : flags:=F_AE;
  926. end;
  927. p^.location.loc:=LOC_FLAGS;
  928. p^.location.resflags:=flags;
  929. cmpop:=false;
  930. end
  931. else
  932. p^.location.loc:=LOC_FPU;
  933. end
  934. {$ifdef SUPPORT_MMX}
  935. else if is_mmx_able_array(p^.left^.resulttype) then
  936. begin
  937. cmpop:=false;
  938. mmxbase:=mmx_type(p^.left^.resulttype);
  939. case p^.treetype of
  940. addn : begin
  941. if (cs_mmx_saturation in aktswitches) then
  942. begin
  943. case mmxbase of
  944. mmxs8bit:
  945. op:=A_PADDSB;
  946. mmxu8bit:
  947. op:=A_PADDUSB;
  948. mmxs16bit,mmxfixed16:
  949. op:=A_PADDSB;
  950. mmxu16bit:
  951. op:=A_PADDUSW;
  952. end;
  953. end
  954. else
  955. begin
  956. case mmxbase of
  957. mmxs8bit,mmxu8bit:
  958. op:=A_PADDB;
  959. mmxs16bit,mmxu16bit,mmxfixed16:
  960. op:=A_PADDW;
  961. mmxs32bit,mmxu32bit:
  962. op:=A_PADDD;
  963. end;
  964. end;
  965. end;
  966. muln : begin
  967. case mmxbase of
  968. mmxs16bit,mmxu16bit:
  969. op:=A_PMULLW;
  970. mmxfixed16:
  971. op:=A_PMULHW;
  972. end;
  973. end;
  974. subn : begin
  975. if (cs_mmx_saturation in aktswitches) then
  976. begin
  977. case mmxbase of
  978. mmxs8bit:
  979. op:=A_PSUBSB;
  980. mmxu8bit:
  981. op:=A_PSUBUSB;
  982. mmxs16bit,mmxfixed16:
  983. op:=A_PSUBSB;
  984. mmxu16bit:
  985. op:=A_PSUBUSW;
  986. end;
  987. end
  988. else
  989. begin
  990. case mmxbase of
  991. mmxs8bit,mmxu8bit:
  992. op:=A_PSUBB;
  993. mmxs16bit,mmxu16bit,mmxfixed16:
  994. op:=A_PSUBW;
  995. mmxs32bit,mmxu32bit:
  996. op:=A_PSUBD;
  997. end;
  998. end;
  999. end;
  1000. {
  1001. ltn,lten,gtn,gten,
  1002. equaln,unequaln :
  1003. begin
  1004. op:=A_CMP;
  1005. cmpop:=true;
  1006. end;
  1007. }
  1008. xorn:
  1009. op:=A_PXOR;
  1010. orn:
  1011. op:=A_POR;
  1012. andn:
  1013. op:=A_PAND;
  1014. else Message(sym_e_type_mismatch);
  1015. end;
  1016. { left and right no register? }
  1017. { then one must be demanded }
  1018. if (p^.left^.location.loc<>LOC_MMXREGISTER) and
  1019. (p^.right^.location.loc<>LOC_MMXREGISTER) then
  1020. begin
  1021. { register variable ? }
  1022. if (p^.left^.location.loc=LOC_CMMXREGISTER) then
  1023. begin
  1024. { it is OK if this is the destination }
  1025. if is_in_dest then
  1026. begin
  1027. hregister:=p^.location.register;
  1028. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1029. hregister);
  1030. end
  1031. else
  1032. begin
  1033. hregister:=getregistermmx;
  1034. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1035. hregister);
  1036. end
  1037. end
  1038. else
  1039. begin
  1040. del_reference(p^.left^.location.reference);
  1041. if is_in_dest then
  1042. begin
  1043. hregister:=p^.location.register;
  1044. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1045. newreference(p^.left^.location.reference),hregister)));
  1046. end
  1047. else
  1048. begin
  1049. hregister:=getregistermmx;
  1050. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1051. newreference(p^.left^.location.reference),hregister)));
  1052. end;
  1053. end;
  1054. p^.location.loc:=LOC_MMXREGISTER;
  1055. p^.location.register:=hregister;
  1056. end
  1057. else
  1058. { if on the right the register then swap }
  1059. if (p^.right^.location.loc=LOC_MMXREGISTER) then
  1060. begin
  1061. swap_location(p^.location,p^.right^.location);
  1062. { newly swapped also set swapped flag }
  1063. p^.swaped:=not(p^.swaped);
  1064. end;
  1065. { at this point, p^.location.loc should be LOC_MMXREGISTER }
  1066. { and p^.location.register should be a valid register }
  1067. { containing the left result }
  1068. if p^.right^.location.loc<>LOC_MMXREGISTER then
  1069. begin
  1070. if (p^.treetype=subn) and p^.swaped then
  1071. begin
  1072. if p^.right^.location.loc=LOC_CMMXREGISTER then
  1073. begin
  1074. emit_reg_reg(A_MOVQ,S_NO,p^.right^.location.register,R_MM7);
  1075. emit_reg_reg(op,S_NO,p^.location.register,R_EDI);
  1076. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  1077. end
  1078. else
  1079. begin
  1080. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1081. newreference(p^.right^.location.reference),R_MM7)));
  1082. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,p^.location.register,
  1083. R_MM7)));
  1084. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOVQ,S_NO,
  1085. R_MM7,p^.location.register)));
  1086. del_reference(p^.right^.location.reference);
  1087. end;
  1088. end
  1089. else
  1090. begin
  1091. if (p^.right^.location.loc=LOC_CREGISTER) then
  1092. begin
  1093. emit_reg_reg(op,S_NO,p^.right^.location.register,
  1094. p^.location.register);
  1095. end
  1096. else
  1097. begin
  1098. exprasmlist^.concat(new(pai386,op_ref_reg(op,S_NO,newreference(
  1099. p^.right^.location.reference),p^.location.register)));
  1100. del_reference(p^.right^.location.reference);
  1101. end;
  1102. end;
  1103. end
  1104. else
  1105. begin
  1106. { when swapped another result register }
  1107. if (p^.treetype=subn) and p^.swaped then
  1108. begin
  1109. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1110. p^.location.register,p^.right^.location.register)));
  1111. swap_location(p^.location,p^.right^.location);
  1112. { newly swapped also set swapped flag }
  1113. { just to maintain ordering }
  1114. p^.swaped:=not(p^.swaped);
  1115. end
  1116. else
  1117. begin
  1118. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1119. p^.right^.location.register,
  1120. p^.location.register)));
  1121. end;
  1122. ungetregistermmx(p^.right^.location.register);
  1123. end;
  1124. end
  1125. {$endif SUPPORT_MMX}
  1126. else Message(sym_e_type_mismatch);
  1127. end;
  1128. setaddresult(cmpop,unsigned,p);
  1129. end;
  1130. end.
  1131. {
  1132. $Log$
  1133. Revision 1.2 1998-06-08 13:13:28 pierre
  1134. + temporary variables now in temp_gen.pas unit
  1135. because it is processor independent
  1136. * mppc68k.bat modified to undefine i386 and support_mmx
  1137. (which are defaults for i386)
  1138. Revision 1.1 1998/06/05 17:44:10 peter
  1139. * splitted cgi386
  1140. }