cg386add.pas 56 KB

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