cg386add.pas 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780
  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. {$define usecreateset}
  21. uses
  22. tree;
  23. procedure secondadd(var p : ptree);
  24. implementation
  25. uses
  26. globtype,systems,
  27. cobjects,verbose,globals,
  28. symtable,aasm,types,
  29. hcodegen,temp_gen,pass_2,
  30. i386,cgai386,tgeni386;
  31. {*****************************************************************************
  32. Helpers
  33. *****************************************************************************}
  34. procedure SetResultLocation(cmpop,unsigned:boolean;var p :ptree);
  35. var
  36. flags : tresflags;
  37. begin
  38. { remove temporary location if not a set or string }
  39. { that's a bad hack (FK) who did this ? }
  40. if (p^.left^.resulttype^.deftype<>stringdef) and
  41. ((p^.left^.resulttype^.deftype<>setdef) or (psetdef(p^.left^.resulttype)^.settype=smallset)) and
  42. (p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  43. ungetiftemp(p^.left^.location.reference);
  44. if (p^.right^.resulttype^.deftype<>stringdef) and
  45. ((p^.right^.resulttype^.deftype<>setdef) or (psetdef(p^.right^.resulttype)^.settype=smallset)) and
  46. (p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE]) 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. clear_location(p^.location);
  94. p^.location.loc:=LOC_FLAGS;
  95. p^.location.resflags:=flags;
  96. end;
  97. end;
  98. {*****************************************************************************
  99. Addstring
  100. *****************************************************************************}
  101. procedure addstring(var p : ptree);
  102. var
  103. pushedregs : tpushed;
  104. href : treference;
  105. pushed,
  106. cmpop : boolean;
  107. savedunused : tregisterset;
  108. hr : treference;
  109. begin
  110. { string operations are not commutative }
  111. if p^.swaped then
  112. swaptree(p);
  113. case pstringdef(p^.left^.resulttype)^.string_typ of
  114. st_ansistring:
  115. begin
  116. case p^.treetype of
  117. addn:
  118. begin
  119. cmpop:=false;
  120. secondpass(p^.left);
  121. pushed:=maybe_push(p^.right^.registers32,p);
  122. secondpass(p^.right);
  123. if pushed then restore(p);
  124. { release used registers }
  125. case p^.right^.location.loc of
  126. LOC_REFERENCE,LOC_MEM:
  127. del_reference(p^.right^.location.reference);
  128. LOC_REGISTER,LOC_CREGISTER:
  129. ungetregister32(p^.right^.location.register);
  130. end;
  131. case p^.left^.location.loc of
  132. LOC_REFERENCE,LOC_MEM:
  133. del_reference(p^.left^.location.reference);
  134. LOC_REGISTER,LOC_CREGISTER:
  135. ungetregister32(p^.left^.location.register);
  136. end;
  137. savedunused:=unused;
  138. { push the still used registers }
  139. pushusedregisters(pushedregs,$ff);
  140. { push data }
  141. emit_push_loc(p^.right^.location);
  142. emit_push_loc(p^.left^.location);
  143. emitcall('FPC_ANSISTR_CONCAT',true);
  144. unused:=savedunused;
  145. clear_location(p^.location);
  146. p^.location.register:=getexplicitregister32(R_EAX);
  147. p^.location.loc:=LOC_REGISTER;
  148. emit_reg_reg(A_MOV,S_L,R_EAX,p^.location.register);
  149. popusedregisters(pushedregs);
  150. maybe_loadesi;
  151. ungetiftemp(p^.left^.location.reference);
  152. ungetiftemp(p^.right^.location.reference);
  153. reset_reference(hr);
  154. gettempansistringreference(hr);
  155. {temptoremove^.concat(new(ptemptodestroy,init(hr,p^.resulttype)));}
  156. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,p^.location.register,
  157. newreference(hr))));
  158. end;
  159. ltn,lten,gtn,gten,
  160. equaln,unequaln:
  161. begin
  162. secondpass(p^.left);
  163. pushed:=maybe_push(p^.right^.registers32,p);
  164. secondpass(p^.right);
  165. if pushed then restore(p);
  166. { release used registers }
  167. case p^.right^.location.loc of
  168. LOC_REFERENCE,LOC_MEM:
  169. del_reference(p^.right^.location.reference);
  170. LOC_REGISTER,LOC_CREGISTER:
  171. ungetregister32(p^.right^.location.register);
  172. end;
  173. case p^.left^.location.loc of
  174. LOC_REFERENCE,LOC_MEM:
  175. del_reference(p^.left^.location.reference);
  176. LOC_REGISTER,LOC_CREGISTER:
  177. ungetregister32(p^.left^.location.register);
  178. end;
  179. { push the still used registers }
  180. pushusedregisters(pushedregs,$ff);
  181. { push data }
  182. case p^.right^.location.loc of
  183. LOC_REFERENCE,LOC_MEM:
  184. emit_push_mem(p^.right^.location.reference);
  185. LOC_REGISTER,LOC_CREGISTER:
  186. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.right^.location.register)));
  187. end;
  188. case p^.left^.location.loc of
  189. LOC_REFERENCE,LOC_MEM:
  190. emit_push_mem(p^.left^.location.reference);
  191. LOC_REGISTER,LOC_CREGISTER:
  192. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.left^.location.register)));
  193. end;
  194. emitcall('FPC_ANSISTR_COMPARE',true);
  195. emit_reg_reg(A_OR,S_L,R_EAX,R_EAX);
  196. popusedregisters(pushedregs);
  197. maybe_loadesi;
  198. ungetiftemp(p^.left^.location.reference);
  199. ungetiftemp(p^.right^.location.reference);
  200. end;
  201. end;
  202. { the result of ansicompare is signed }
  203. SetResultLocation(cmpop,false,p);
  204. end;
  205. st_shortstring:
  206. begin
  207. case p^.treetype of
  208. addn:
  209. begin
  210. cmpop:=false;
  211. secondpass(p^.left);
  212. { if str_concat is set in expr
  213. s:=s+ ... no need to create a temp string (PM) }
  214. if (p^.left^.treetype<>addn) and not (p^.use_strconcat) then
  215. begin
  216. { can only reference be }
  217. { string in register would be funny }
  218. { therefore produce a temporary string }
  219. { release the registers }
  220. del_reference(p^.left^.location.reference);
  221. gettempofsizereference(256,href);
  222. copyshortstring(href,p^.left^.location.reference,255,false);
  223. ungetiftemp(p^.left^.location.reference);
  224. { does not hurt: }
  225. clear_location(p^.left^.location);
  226. p^.left^.location.loc:=LOC_MEM;
  227. p^.left^.location.reference:=href;
  228. end;
  229. secondpass(p^.right);
  230. { on the right we do not need the register anymore too }
  231. del_reference(p^.right^.location.reference);
  232. pushusedregisters(pushedregs,$ff);
  233. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  234. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  235. emitcall('FPC_SHORTSTR_CONCAT',true);
  236. maybe_loadesi;
  237. popusedregisters(pushedregs);
  238. set_location(p^.location,p^.left^.location);
  239. ungetiftemp(p^.right^.location.reference);
  240. end;
  241. ltn,lten,gtn,gten,
  242. equaln,unequaln :
  243. begin
  244. cmpop:=true;
  245. { generate better code for s='' and s<>'' }
  246. if (p^.treetype in [equaln,unequaln]) and
  247. (((p^.left^.treetype=stringconstn) and (str_length(p^.left)=0)) or
  248. ((p^.right^.treetype=stringconstn) and (str_length(p^.right)=0))) then
  249. begin
  250. secondpass(p^.left);
  251. { are too few registers free? }
  252. pushed:=maybe_push(p^.right^.registers32,p);
  253. secondpass(p^.right);
  254. if pushed then restore(p);
  255. del_reference(p^.right^.location.reference);
  256. del_reference(p^.left^.location.reference);
  257. { only one node can be stringconstn }
  258. { else pass 1 would have evaluted }
  259. { this node }
  260. if p^.left^.treetype=stringconstn then
  261. exprasmlist^.concat(new(pai386,op_const_ref(
  262. A_CMP,S_B,0,newreference(p^.right^.location.reference))))
  263. else
  264. exprasmlist^.concat(new(pai386,op_const_ref(
  265. A_CMP,S_B,0,newreference(p^.left^.location.reference))));
  266. end
  267. else
  268. begin
  269. pushusedregisters(pushedregs,$ff);
  270. secondpass(p^.left);
  271. del_reference(p^.left^.location.reference);
  272. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  273. secondpass(p^.right);
  274. del_reference(p^.right^.location.reference);
  275. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  276. emitcall('FPC_SHORTSTR_COMPARE',true);
  277. maybe_loadesi;
  278. popusedregisters(pushedregs);
  279. end;
  280. ungetiftemp(p^.left^.location.reference);
  281. ungetiftemp(p^.right^.location.reference);
  282. end;
  283. else CGMessage(type_e_mismatch);
  284. end;
  285. SetResultLocation(cmpop,true,p);
  286. end;
  287. end;
  288. end;
  289. {*****************************************************************************
  290. Addset
  291. *****************************************************************************}
  292. procedure addset(var p : ptree);
  293. var
  294. createset,
  295. cmpop,
  296. pushed : boolean;
  297. href : treference;
  298. pushedregs : tpushed;
  299. begin
  300. cmpop:=false;
  301. { not commutative }
  302. if p^.swaped then
  303. swaptree(p);
  304. { optimize first loading of a set }
  305. {$ifdef usecreateset}
  306. if (p^.right^.treetype=setelementn) and
  307. is_emptyset(p^.left) then
  308. createset:=true
  309. else
  310. {$endif}
  311. begin
  312. createset:=false;
  313. secondpass(p^.left);
  314. end;
  315. { are too few registers free? }
  316. pushed:=maybe_push(p^.right^.registers32,p);
  317. secondpass(p^.right);
  318. if codegenerror then
  319. exit;
  320. if pushed then
  321. restore(p);
  322. set_location(p^.location,p^.left^.location);
  323. { handle operations }
  324. case p^.treetype of
  325. equaln,
  326. unequaln : begin
  327. cmpop:=true;
  328. del_reference(p^.left^.location.reference);
  329. del_reference(p^.right^.location.reference);
  330. pushusedregisters(pushedregs,$ff);
  331. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  332. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  333. emitcall('FPC_SET_COMP_SETS',true);
  334. maybe_loadesi;
  335. popusedregisters(pushedregs);
  336. ungetiftemp(p^.left^.location.reference);
  337. ungetiftemp(p^.right^.location.reference);
  338. end;
  339. addn : begin
  340. { add can be an other SET or Range or Element ! }
  341. del_reference(p^.left^.location.reference);
  342. del_reference(p^.right^.location.reference);
  343. pushusedregisters(pushedregs,$ff);
  344. href.symbol:=nil;
  345. gettempofsizereference(32,href);
  346. if createset then
  347. begin
  348. pushsetelement(p^.right^.left);
  349. emitpushreferenceaddr(exprasmlist,href);
  350. emitcall('FPC_SET_CREATE_ELEMENT',true);
  351. end
  352. else
  353. begin
  354. { add a range or a single element? }
  355. if p^.right^.treetype=setelementn then
  356. begin
  357. concatcopy(p^.left^.location.reference,href,32,false,false);
  358. if assigned(p^.right^.right) then
  359. begin
  360. pushsetelement(p^.right^.right);
  361. pushsetelement(p^.right^.left);
  362. emitpushreferenceaddr(exprasmlist,href);
  363. emitcall('FPC_SET_SET_RANGE',true);
  364. end
  365. else
  366. begin
  367. pushsetelement(p^.right^.left);
  368. emitpushreferenceaddr(exprasmlist,href);
  369. emitcall('FPC_SET_SET_BYTE',true);
  370. end;
  371. end
  372. else
  373. begin
  374. { must be an other set }
  375. emitpushreferenceaddr(exprasmlist,href);
  376. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  377. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  378. emitcall('FPC_SET_ADD_SETS',true);
  379. end;
  380. end;
  381. maybe_loadesi;
  382. popusedregisters(pushedregs);
  383. ungetiftemp(p^.left^.location.reference);
  384. ungetiftemp(p^.right^.location.reference);
  385. p^.location.loc:=LOC_MEM;
  386. stringdispose(p^.location.reference.symbol);
  387. p^.location.reference:=href;
  388. end;
  389. subn,
  390. symdifn,
  391. muln : begin
  392. del_reference(p^.left^.location.reference);
  393. del_reference(p^.right^.location.reference);
  394. href.symbol:=nil;
  395. pushusedregisters(pushedregs,$ff);
  396. gettempofsizereference(32,href);
  397. emitpushreferenceaddr(exprasmlist,href);
  398. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  399. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  400. case p^.treetype of
  401. subn : emitcall('FPC_SET_SUB_SETS',true);
  402. symdifn : emitcall('FPC_SET_SYMDIF_SETS',true);
  403. muln : emitcall('FPC_SET_MUL_SETS',true);
  404. end;
  405. maybe_loadesi;
  406. popusedregisters(pushedregs);
  407. ungetiftemp(p^.left^.location.reference);
  408. ungetiftemp(p^.right^.location.reference);
  409. p^.location.loc:=LOC_MEM;
  410. stringdispose(p^.location.reference.symbol);
  411. p^.location.reference:=href;
  412. end;
  413. else
  414. CGMessage(type_e_mismatch);
  415. end;
  416. SetResultLocation(cmpop,true,p);
  417. end;
  418. {*****************************************************************************
  419. SecondAdd
  420. *****************************************************************************}
  421. procedure secondadd(var p : ptree);
  422. { is also being used for xor, and "mul", "sub, or and comparative }
  423. { operators }
  424. label do_normal;
  425. var
  426. hregister,hregister2 : tregister;
  427. noswap,popeax,popedx,
  428. pushed,mboverflow,cmpop : boolean;
  429. op,op2 : tasmop;
  430. flags : tresflags;
  431. otl,ofl : plabel;
  432. power : longint;
  433. opsize : topsize;
  434. hl4: plabel;
  435. hr : preference;
  436. { true, if unsigned types are compared }
  437. unsigned : boolean;
  438. { true, if a small set is handled with the longint code }
  439. is_set : boolean;
  440. { is_in_dest if the result is put directly into }
  441. { the resulting refernce or varregister }
  442. is_in_dest : boolean;
  443. { true, if for sets subtractions the extra not should generated }
  444. extra_not : boolean;
  445. {$ifdef SUPPORT_MMX}
  446. mmxbase : tmmxtype;
  447. {$endif SUPPORT_MMX}
  448. begin
  449. { to make it more readable, string and set (not smallset!) have their
  450. own procedures }
  451. case p^.left^.resulttype^.deftype of
  452. stringdef : begin
  453. addstring(p);
  454. exit;
  455. end;
  456. setdef : begin
  457. { normalsets are handled separate }
  458. if not(psetdef(p^.left^.resulttype)^.settype=smallset) then
  459. begin
  460. addset(p);
  461. exit;
  462. end;
  463. end;
  464. end;
  465. { defaults }
  466. unsigned:=false;
  467. is_in_dest:=false;
  468. extra_not:=false;
  469. noswap:=false;
  470. opsize:=S_L;
  471. { are we a (small)set, must be set here because the side can be
  472. swapped ! (PFV) }
  473. is_set:=(p^.left^.resulttype^.deftype=setdef);
  474. { calculate the operator which is more difficult }
  475. firstcomplex(p);
  476. { handling boolean expressions extra: }
  477. if ((p^.left^.resulttype^.deftype=orddef) and
  478. (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) or
  479. ((p^.right^.resulttype^.deftype=orddef) and
  480. (porddef(p^.right^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) then
  481. begin
  482. if (porddef(p^.left^.resulttype)^.typ=bool8bit) or
  483. (porddef(p^.right^.resulttype)^.typ=bool8bit) then
  484. opsize:=S_B
  485. else
  486. if (porddef(p^.left^.resulttype)^.typ=bool16bit) or
  487. (porddef(p^.right^.resulttype)^.typ=bool16bit) then
  488. opsize:=S_W
  489. else
  490. opsize:=S_L;
  491. case p^.treetype of
  492. andn,
  493. orn : begin
  494. clear_location(p^.location);
  495. p^.location.loc:=LOC_JUMP;
  496. cmpop:=false;
  497. case p^.treetype of
  498. andn : begin
  499. otl:=truelabel;
  500. getlabel(truelabel);
  501. secondpass(p^.left);
  502. maketojumpbool(p^.left);
  503. emitl(A_LABEL,truelabel);
  504. truelabel:=otl;
  505. end;
  506. orn : begin
  507. ofl:=falselabel;
  508. getlabel(falselabel);
  509. secondpass(p^.left);
  510. maketojumpbool(p^.left);
  511. emitl(A_LABEL,falselabel);
  512. falselabel:=ofl;
  513. end;
  514. else
  515. CGMessage(type_e_mismatch);
  516. end;
  517. secondpass(p^.right);
  518. maketojumpbool(p^.right);
  519. end;
  520. unequaln,
  521. equaln,xorn : begin
  522. if p^.left^.treetype=ordconstn then
  523. swaptree(p);
  524. secondpass(p^.left);
  525. set_location(p^.location,p^.left^.location);
  526. {p^.location:=p^.left^.location;
  527. created a bug !!! PM
  528. because symbol was used twice }
  529. { are enough registers free ? }
  530. pushed:=maybe_push(p^.right^.registers32,p);
  531. secondpass(p^.right);
  532. if pushed then restore(p);
  533. goto do_normal;
  534. end
  535. else
  536. CGMessage(type_e_mismatch);
  537. end
  538. end
  539. else
  540. begin
  541. { in case of constant put it to the left }
  542. if (p^.left^.treetype=ordconstn) then
  543. swaptree(p);
  544. secondpass(p^.left);
  545. { this will be complicated as
  546. a lot of code below assumes that
  547. p^.location and p^.left^.location are the same }
  548. {$ifdef test_dest_loc}
  549. if dest_loc_known and (dest_loc_tree=p) and
  550. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  551. begin
  552. set_location(p^.location,dest_loc);
  553. in_dest_loc:=true;
  554. is_in_dest:=true;
  555. end
  556. else
  557. {$endif test_dest_loc}
  558. set_location(p^.location,p^.left^.location);
  559. { are too few registers free? }
  560. pushed:=maybe_push(p^.right^.registers32,p);
  561. secondpass(p^.right);
  562. if pushed then
  563. restore(p);
  564. if (p^.left^.resulttype^.deftype=pointerdef) or
  565. (p^.right^.resulttype^.deftype=pointerdef) or
  566. ((p^.right^.resulttype^.deftype=objectdef) and
  567. pobjectdef(p^.right^.resulttype)^.isclass and
  568. (p^.left^.resulttype^.deftype=objectdef) and
  569. pobjectdef(p^.left^.resulttype)^.isclass
  570. ) or
  571. (p^.left^.resulttype^.deftype=classrefdef) or
  572. (p^.left^.resulttype^.deftype=procvardef) or
  573. (p^.left^.resulttype^.deftype=enumdef) or
  574. ((p^.left^.resulttype^.deftype=orddef) and
  575. (porddef(p^.left^.resulttype)^.typ=s32bit)) or
  576. ((p^.right^.resulttype^.deftype=orddef) and
  577. (porddef(p^.right^.resulttype)^.typ=s32bit)) or
  578. ((p^.left^.resulttype^.deftype=orddef) and
  579. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  580. ((p^.right^.resulttype^.deftype=orddef) and
  581. (porddef(p^.right^.resulttype)^.typ=u32bit)) or
  582. { as well as small sets }
  583. is_set then
  584. begin
  585. do_normal:
  586. mboverflow:=false;
  587. cmpop:=false;
  588. if (p^.left^.resulttype^.deftype=pointerdef) or
  589. (p^.right^.resulttype^.deftype=pointerdef) or
  590. ((p^.left^.resulttype^.deftype=orddef) and
  591. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  592. ((p^.right^.resulttype^.deftype=orddef) and
  593. (porddef(p^.right^.resulttype)^.typ=u32bit)) then
  594. unsigned:=true;
  595. case p^.treetype of
  596. addn : begin
  597. if is_set then
  598. begin
  599. { adding elements is not commutative }
  600. if p^.swaped and (p^.left^.treetype=setelementn) then
  601. swaptree(p);
  602. { are we adding set elements ? }
  603. if p^.right^.treetype=setelementn then
  604. begin
  605. { no range support for smallsets! }
  606. if assigned(p^.right^.right) then
  607. internalerror(43244);
  608. { bts requires both elements to be registers }
  609. if p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  610. begin
  611. ungetiftemp(p^.left^.location.reference);
  612. del_reference(p^.left^.location.reference);
  613. hregister:=getregister32;
  614. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  615. newreference(p^.left^.location.reference),hregister)));
  616. clear_location(p^.left^.location);
  617. p^.left^.location.loc:=LOC_REGISTER;
  618. p^.left^.location.register:=hregister;
  619. set_location(p^.location,p^.left^.location);
  620. end;
  621. if p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  622. begin
  623. ungetiftemp(p^.right^.location.reference);
  624. del_reference(p^.right^.location.reference);
  625. hregister:=getregister32;
  626. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  627. newreference(p^.right^.location.reference),hregister)));
  628. clear_location(p^.right^.location);
  629. p^.right^.location.loc:=LOC_REGISTER;
  630. p^.right^.location.register:=hregister;
  631. end;
  632. op:=A_BTS;
  633. noswap:=true;
  634. end
  635. else
  636. op:=A_OR;
  637. mboverflow:=false;
  638. unsigned:=false;
  639. end
  640. else
  641. begin
  642. op:=A_ADD;
  643. mboverflow:=true;
  644. end;
  645. end;
  646. symdifn : begin
  647. { the symetric diff is only for sets }
  648. if is_set then
  649. begin
  650. op:=A_XOR;
  651. mboverflow:=false;
  652. unsigned:=false;
  653. end
  654. else
  655. CGMessage(type_e_mismatch);
  656. end;
  657. muln : begin
  658. if is_set then
  659. begin
  660. op:=A_AND;
  661. mboverflow:=false;
  662. unsigned:=false;
  663. end
  664. else
  665. begin
  666. if unsigned then
  667. op:=A_MUL
  668. else
  669. op:=A_IMUL;
  670. mboverflow:=true;
  671. end;
  672. end;
  673. subn : begin
  674. if is_set then
  675. begin
  676. op:=A_AND;
  677. mboverflow:=false;
  678. unsigned:=false;
  679. extra_not:=true;
  680. end
  681. else
  682. begin
  683. op:=A_SUB;
  684. mboverflow:=true;
  685. end;
  686. end;
  687. ltn,lten,
  688. gtn,gten,
  689. equaln,unequaln : begin
  690. op:=A_CMP;
  691. cmpop:=true;
  692. end;
  693. xorn : op:=A_XOR;
  694. orn : op:=A_OR;
  695. andn : op:=A_AND;
  696. else
  697. CGMessage(type_e_mismatch);
  698. end;
  699. { filter MUL, which requires special handling }
  700. if op=A_MUL then
  701. begin
  702. popeax:=false;
  703. popedx:=false;
  704. { here you need to free the symbol first }
  705. clear_location(p^.location);
  706. p^.location.register:=getregister32;
  707. p^.location.loc:=LOC_REGISTER;
  708. if not(R_EAX in unused) and (p^.location.register<>R_EAX) then
  709. begin
  710. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EAX)));
  711. popeax:=true;
  712. end;
  713. if not(R_EDX in unused) and (p^.location.register<>R_EDX) then
  714. begin
  715. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_EDX)));
  716. popedx:=true;
  717. end;
  718. emitloadord2reg(p^.left^.location,u32bitdef,R_EDI,true);
  719. emitloadord2reg(p^.right^.location,u32bitdef,R_EAX,true);
  720. exprasmlist^.concat(new(pai386,op_reg(A_MUL,S_L,R_EDI)));
  721. emit_reg_reg(A_MOV,S_L,R_EAX,p^.location.register);
  722. if popeax then
  723. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EAX)));
  724. if popedx then
  725. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDX)));
  726. SetResultLocation(false,true,p);
  727. exit;
  728. end;
  729. { left and right no register? }
  730. { then one must be demanded }
  731. if (p^.left^.location.loc<>LOC_REGISTER) and
  732. (p^.right^.location.loc<>LOC_REGISTER) then
  733. begin
  734. { register variable ? }
  735. if (p^.left^.location.loc=LOC_CREGISTER) then
  736. begin
  737. { it is OK if this is the destination }
  738. if is_in_dest then
  739. begin
  740. hregister:=p^.location.register;
  741. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  742. hregister);
  743. end
  744. else
  745. if cmpop then
  746. begin
  747. { do not disturb the register }
  748. hregister:=p^.location.register;
  749. end
  750. else
  751. begin
  752. case opsize of
  753. S_L : hregister:=getregister32;
  754. S_B : hregister:=reg32toreg8(getregister32);
  755. end;
  756. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  757. hregister);
  758. end
  759. end
  760. else
  761. begin
  762. ungetiftemp(p^.left^.location.reference);
  763. del_reference(p^.left^.location.reference);
  764. if is_in_dest then
  765. begin
  766. hregister:=p^.location.register;
  767. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  768. newreference(p^.left^.location.reference),hregister)));
  769. end
  770. else
  771. begin
  772. { first give free, then demand new register }
  773. case opsize of
  774. S_L : hregister:=getregister32;
  775. S_W : hregister:=reg32toreg16(getregister32);
  776. S_B : hregister:=reg32toreg8(getregister32);
  777. end;
  778. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  779. newreference(p^.left^.location.reference),hregister)));
  780. end;
  781. end;
  782. clear_location(p^.location);
  783. p^.location.loc:=LOC_REGISTER;
  784. p^.location.register:=hregister;
  785. end
  786. else
  787. { if on the right the register then swap }
  788. if not(noswap) and (p^.right^.location.loc=LOC_REGISTER) then
  789. begin
  790. swap_location(p^.location,p^.right^.location);
  791. { newly swapped also set swapped flag }
  792. p^.swaped:=not(p^.swaped);
  793. end;
  794. { at this point, p^.location.loc should be LOC_REGISTER }
  795. { and p^.location.register should be a valid register }
  796. { containing the left result }
  797. if p^.right^.location.loc<>LOC_REGISTER then
  798. begin
  799. if (p^.treetype=subn) and p^.swaped then
  800. begin
  801. if p^.right^.location.loc=LOC_CREGISTER then
  802. begin
  803. if extra_not then
  804. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  805. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  806. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  807. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  808. end
  809. else
  810. begin
  811. if extra_not then
  812. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  813. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  814. newreference(p^.right^.location.reference),R_EDI)));
  815. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,p^.location.register,R_EDI)));
  816. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,opsize,R_EDI,p^.location.register)));
  817. ungetiftemp(p^.right^.location.reference);
  818. del_reference(p^.right^.location.reference);
  819. end;
  820. end
  821. else
  822. begin
  823. if (p^.right^.treetype=ordconstn) and
  824. (op=A_CMP) and
  825. (p^.right^.value=0) then
  826. begin
  827. exprasmlist^.concat(new(pai386,op_reg_reg(A_TEST,opsize,p^.location.register,
  828. p^.location.register)));
  829. end
  830. else if (p^.right^.treetype=ordconstn) and
  831. (op=A_ADD) and
  832. (p^.right^.value=1) then
  833. begin
  834. exprasmlist^.concat(new(pai386,op_reg(A_INC,opsize,
  835. p^.location.register)));
  836. end
  837. else if (p^.right^.treetype=ordconstn) and
  838. (op=A_SUB) and
  839. (p^.right^.value=1) then
  840. begin
  841. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,
  842. p^.location.register)));
  843. end
  844. else if (p^.right^.treetype=ordconstn) and
  845. (op=A_IMUL) and
  846. (ispowerof2(p^.right^.value,power)) then
  847. begin
  848. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,opsize,power,
  849. p^.location.register)));
  850. end
  851. else
  852. begin
  853. if (p^.right^.location.loc=LOC_CREGISTER) then
  854. begin
  855. if extra_not then
  856. begin
  857. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,R_EDI);
  858. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  859. emit_reg_reg(A_AND,S_L,R_EDI,
  860. p^.location.register);
  861. end
  862. else
  863. begin
  864. emit_reg_reg(op,opsize,p^.right^.location.register,
  865. p^.location.register);
  866. end;
  867. end
  868. else
  869. begin
  870. if extra_not then
  871. begin
  872. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(
  873. p^.right^.location.reference),R_EDI)));
  874. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  875. emit_reg_reg(A_AND,S_L,R_EDI,
  876. p^.location.register);
  877. end
  878. else
  879. begin
  880. exprasmlist^.concat(new(pai386,op_ref_reg(op,opsize,newreference(
  881. p^.right^.location.reference),p^.location.register)));
  882. end;
  883. ungetiftemp(p^.right^.location.reference);
  884. del_reference(p^.right^.location.reference);
  885. end;
  886. end;
  887. end;
  888. end
  889. else
  890. begin
  891. { when swapped another result register }
  892. if (p^.treetype=subn) and p^.swaped then
  893. begin
  894. if extra_not then
  895. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  896. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  897. p^.location.register,p^.right^.location.register)));
  898. swap_location(p^.location,p^.right^.location);
  899. { newly swapped also set swapped flag }
  900. { just to maintain ordering }
  901. p^.swaped:=not(p^.swaped);
  902. end
  903. else
  904. begin
  905. if extra_not then
  906. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.right^.location.register)));
  907. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  908. p^.right^.location.register,
  909. p^.location.register)));
  910. end;
  911. case opsize of
  912. S_L : ungetregister32(p^.right^.location.register);
  913. S_B : ungetregister32(reg8toreg32(p^.right^.location.register));
  914. end;
  915. end;
  916. if cmpop then
  917. case opsize of
  918. S_L : ungetregister32(p^.location.register);
  919. S_B : ungetregister32(reg8toreg32(p^.location.register));
  920. end;
  921. { only in case of overflow operations }
  922. { produce overflow code }
  923. { we must put it here directly, because sign of operation }
  924. { is in unsigned VAR!! }
  925. if mboverflow then
  926. begin
  927. if cs_check_overflow in aktlocalswitches then
  928. begin
  929. getlabel(hl4);
  930. if unsigned then
  931. emitl(A_JNB,hl4)
  932. else
  933. emitl(A_JNO,hl4);
  934. emitcall('FPC_OVERFLOW',true);
  935. emitl(A_LABEL,hl4);
  936. end;
  937. end;
  938. end
  939. else
  940. { Char type }
  941. if ((p^.left^.resulttype^.deftype=orddef) and
  942. (porddef(p^.left^.resulttype)^.typ=uchar)) then
  943. begin
  944. case p^.treetype of
  945. ltn,lten,gtn,gten,
  946. equaln,unequaln :
  947. cmpop:=true;
  948. else CGMessage(type_e_mismatch);
  949. end;
  950. unsigned:=true;
  951. { left and right no register? }
  952. { the one must be demanded }
  953. if (p^.location.loc<>LOC_REGISTER) and
  954. (p^.right^.location.loc<>LOC_REGISTER) then
  955. begin
  956. if p^.location.loc=LOC_CREGISTER then
  957. begin
  958. if cmpop then
  959. { do not disturb register }
  960. hregister:=p^.location.register
  961. else
  962. begin
  963. hregister:=reg32toreg8(getregister32);
  964. emit_reg_reg(A_MOV,S_B,p^.location.register,
  965. hregister);
  966. end;
  967. end
  968. else
  969. begin
  970. del_reference(p^.location.reference);
  971. { first give free then demand new register }
  972. hregister:=reg32toreg8(getregister32);
  973. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_B,newreference(p^.location.reference),
  974. hregister)));
  975. end;
  976. clear_location(p^.location);
  977. p^.location.loc:=LOC_REGISTER;
  978. p^.location.register:=hregister;
  979. end;
  980. { now p always a register }
  981. if (p^.right^.location.loc=LOC_REGISTER) and
  982. (p^.location.loc<>LOC_REGISTER) then
  983. begin
  984. swap_location(p^.location,p^.right^.location);
  985. { newly swapped also set swapped flag }
  986. p^.swaped:=not(p^.swaped);
  987. end;
  988. if p^.right^.location.loc<>LOC_REGISTER then
  989. begin
  990. if p^.right^.location.loc=LOC_CREGISTER then
  991. begin
  992. emit_reg_reg(A_CMP,S_B,
  993. p^.right^.location.register,p^.location.register);
  994. end
  995. else
  996. begin
  997. exprasmlist^.concat(new(pai386,op_ref_reg(A_CMP,S_B,newreference(
  998. p^.right^.location.reference),p^.location.register)));
  999. del_reference(p^.right^.location.reference);
  1000. end;
  1001. end
  1002. else
  1003. begin
  1004. emit_reg_reg(A_CMP,S_B,p^.right^.location.register,
  1005. p^.location.register);
  1006. ungetregister32(reg8toreg32(p^.right^.location.register));
  1007. end;
  1008. ungetregister32(reg8toreg32(p^.location.register));
  1009. end
  1010. else
  1011. { 64 bit types }
  1012. if is_64bitint(p^.left^.resulttype) then
  1013. begin
  1014. mboverflow:=false;
  1015. cmpop:=false;
  1016. unsigned:=((p^.left^.resulttype^.deftype=orddef) and
  1017. (porddef(p^.left^.resulttype)^.typ=u64bit)) or
  1018. ((p^.right^.resulttype^.deftype=orddef) and
  1019. (porddef(p^.right^.resulttype)^.typ=u64bit));
  1020. case p^.treetype of
  1021. addn : begin
  1022. begin
  1023. op:=A_ADD;
  1024. op2:=A_ADC;
  1025. mboverflow:=true;
  1026. end;
  1027. end;
  1028. muln : begin
  1029. begin
  1030. if unsigned then
  1031. op:=A_MUL
  1032. else
  1033. op:=A_IMUL;
  1034. mboverflow:=true;
  1035. end;
  1036. end;
  1037. subn : begin
  1038. op:=A_SUB;
  1039. op2:=A_SBB;
  1040. mboverflow:=true;
  1041. end;
  1042. ltn,lten,
  1043. gtn,gten,
  1044. equaln,unequaln:
  1045. begin
  1046. op:=A_CMP;
  1047. op2:=A_CMP;
  1048. { cmpop is set later, if necessary }
  1049. end;
  1050. xorn:
  1051. begin
  1052. op:=A_XOR;
  1053. op2:=A_XOR;
  1054. end;
  1055. orn:
  1056. begin
  1057. op:=A_OR;
  1058. op2:=A_OR;
  1059. end;
  1060. andn:
  1061. begin
  1062. op:=A_AND;
  1063. op2:=A_AND;
  1064. end;
  1065. else
  1066. CGMessage(type_e_mismatch);
  1067. end;
  1068. { left and right no register? }
  1069. { then one must be demanded }
  1070. if (p^.left^.location.loc<>LOC_REGISTER) and
  1071. (p^.right^.location.loc<>LOC_REGISTER) then
  1072. begin
  1073. { register variable ? }
  1074. if (p^.left^.location.loc=LOC_CREGISTER) then
  1075. begin
  1076. { it is OK if this is the destination }
  1077. if is_in_dest then
  1078. begin
  1079. hregister:=p^.location.registerlow;
  1080. hregister2:=p^.location.registerhigh;
  1081. emit_reg_reg(A_MOV,opsize,p^.left^.location.registerlow,
  1082. hregister);
  1083. emit_reg_reg(A_MOV,opsize,p^.left^.location.registerlow,
  1084. hregister2);
  1085. end
  1086. else
  1087. if cmpop then
  1088. begin
  1089. { do not disturb the register }
  1090. hregister:=p^.location.registerlow;
  1091. hregister2:=p^.location.registerhigh;
  1092. end
  1093. else
  1094. begin
  1095. hregister:=getregister32;
  1096. hregister2:=getregister32;
  1097. emit_reg_reg(A_MOV,opsize,p^.left^.location.registerlow,
  1098. hregister);
  1099. emit_reg_reg(A_MOV,opsize,p^.left^.location.registerhigh,
  1100. hregister2);
  1101. end
  1102. end
  1103. else
  1104. begin
  1105. ungetiftemp(p^.left^.location.reference);
  1106. del_reference(p^.left^.location.reference);
  1107. if is_in_dest then
  1108. begin
  1109. hregister:=p^.location.registerlow;
  1110. hregister2:=p^.location.registerhigh;
  1111. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  1112. newreference(p^.left^.location.reference),hregister)));
  1113. hr:=newreference(p^.left^.location.reference);
  1114. inc(hr^.offset,4);
  1115. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  1116. hr,hregister2)));
  1117. end
  1118. else
  1119. begin
  1120. hregister:=getregister32;
  1121. hregister2:=getregister32;
  1122. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  1123. newreference(p^.left^.location.reference),hregister)));
  1124. hr:=newreference(p^.left^.location.reference);
  1125. inc(hr^.offset,4);
  1126. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  1127. newreference(p^.left^.location.reference),hregister2)));
  1128. end;
  1129. end;
  1130. clear_location(p^.location);
  1131. p^.location.loc:=LOC_REGISTER;
  1132. p^.location.registerlow:=hregister;
  1133. p^.location.registerhigh:=hregister2;
  1134. end
  1135. else
  1136. { if on the right the register then swap }
  1137. if not(noswap) and (p^.right^.location.loc=LOC_REGISTER) then
  1138. begin
  1139. swap_location(p^.location,p^.right^.location);
  1140. { newly swapped also set swapped flag }
  1141. p^.swaped:=not(p^.swaped);
  1142. end;
  1143. { at this point, p^.location.loc should be LOC_REGISTER }
  1144. { and p^.location.register should be a valid register }
  1145. { containing the left result }
  1146. if p^.right^.location.loc<>LOC_REGISTER then
  1147. begin
  1148. if (p^.treetype=subn) and p^.swaped then
  1149. begin
  1150. if p^.right^.location.loc=LOC_CREGISTER then
  1151. begin
  1152. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  1153. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  1154. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  1155. end
  1156. else
  1157. begin
  1158. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  1159. newreference(p^.right^.location.reference),R_EDI)));
  1160. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,p^.location.register,R_EDI)));
  1161. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,opsize,R_EDI,p^.location.register)));
  1162. ungetiftemp(p^.right^.location.reference);
  1163. del_reference(p^.right^.location.reference);
  1164. end;
  1165. end
  1166. else
  1167. begin
  1168. {
  1169. if (p^.right^.treetype=ordconstn) and
  1170. (op=A_CMP) and
  1171. (p^.right^.value=0) then
  1172. begin
  1173. exprasmlist^.concat(new(pai386,op_reg_reg(A_TEST,opsize,p^.location.register,
  1174. p^.location.register)));
  1175. end
  1176. else if (p^.right^.treetype=ordconstn) and
  1177. (op=A_IMUL) and
  1178. (ispowerof2(p^.right^.value,power)) then
  1179. begin
  1180. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,opsize,power,
  1181. p^.location.register)));
  1182. end
  1183. else
  1184. }
  1185. begin
  1186. if (p^.right^.location.loc=LOC_CREGISTER) then
  1187. begin
  1188. emit_reg_reg(op,opsize,p^.right^.location.register,
  1189. p^.location.register);
  1190. end
  1191. else
  1192. begin
  1193. exprasmlist^.concat(new(pai386,op_ref_reg(op,opsize,newreference(
  1194. p^.right^.location.reference),p^.location.registerlow)));
  1195. hr:=newreference(p^.right^.location.reference);
  1196. inc(hr^.offset,4);
  1197. exprasmlist^.concat(new(pai386,op_ref_reg(op2,opsize,
  1198. hr,p^.location.registerhigh)));
  1199. ungetiftemp(p^.right^.location.reference);
  1200. del_reference(p^.right^.location.reference);
  1201. end;
  1202. end;
  1203. end;
  1204. end
  1205. else
  1206. begin
  1207. { when swapped another result register }
  1208. if (p^.treetype=subn) and p^.swaped then
  1209. begin
  1210. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  1211. p^.location.register,p^.right^.location.register)));
  1212. swap_location(p^.location,p^.right^.location);
  1213. { newly swapped also set swapped flag }
  1214. { just to maintain ordering }
  1215. p^.swaped:=not(p^.swaped);
  1216. end
  1217. else
  1218. begin
  1219. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  1220. p^.right^.location.register,
  1221. p^.location.register)));
  1222. exprasmlist^.concat(new(pai386,op_reg_reg(op2,opsize,
  1223. p^.right^.location.registerhigh,
  1224. p^.location.registerhigh)));
  1225. end;
  1226. ungetregister32(p^.right^.location.registerlow);
  1227. ungetregister32(p^.right^.location.registerhigh);
  1228. end;
  1229. if cmpop then
  1230. case opsize of
  1231. S_L : ungetregister32(p^.location.register);
  1232. S_B : ungetregister32(reg8toreg32(p^.location.register));
  1233. end;
  1234. { only in case of overflow operations }
  1235. { produce overflow code }
  1236. { we must put it here directly, because sign of operation }
  1237. { is in unsigned VAR!! }
  1238. if mboverflow then
  1239. begin
  1240. if cs_check_overflow in aktlocalswitches then
  1241. begin
  1242. getlabel(hl4);
  1243. if unsigned then
  1244. emitl(A_JNB,hl4)
  1245. else
  1246. emitl(A_JNO,hl4);
  1247. emitcall('FPC_OVERFLOW',true);
  1248. emitl(A_LABEL,hl4);
  1249. end;
  1250. end;
  1251. end
  1252. else
  1253. { Floating point }
  1254. if (p^.left^.resulttype^.deftype=floatdef) and
  1255. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  1256. begin
  1257. { real constants to the left }
  1258. if p^.left^.treetype=realconstn then
  1259. swaptree(p);
  1260. cmpop:=false;
  1261. case p^.treetype of
  1262. addn : op:=A_FADDP;
  1263. muln : op:=A_FMULP;
  1264. subn : op:=A_FSUBP;
  1265. slashn : op:=A_FDIVP;
  1266. ltn,lten,gtn,gten,
  1267. equaln,unequaln : begin
  1268. op:=A_FCOMPP;
  1269. cmpop:=true;
  1270. end;
  1271. else CGMessage(type_e_mismatch);
  1272. end;
  1273. if (p^.right^.location.loc<>LOC_FPU) then
  1274. begin
  1275. floatload(pfloatdef(p^.right^.resulttype)^.typ,p^.right^.location.reference);
  1276. if (p^.left^.location.loc<>LOC_FPU) then
  1277. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  1278. { left was on the stack => swap }
  1279. else
  1280. p^.swaped:=not(p^.swaped);
  1281. { releases the right reference }
  1282. del_reference(p^.right^.location.reference);
  1283. end
  1284. { the nominator in st0 }
  1285. else if (p^.left^.location.loc<>LOC_FPU) then
  1286. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  1287. { fpu operands are always in the wrong order on the stack }
  1288. else
  1289. p^.swaped:=not(p^.swaped);
  1290. { releases the left reference }
  1291. if (p^.left^.location.loc<>LOC_FPU) then
  1292. del_reference(p^.left^.location.reference);
  1293. { if we swaped the tree nodes, then use the reverse operator }
  1294. if p^.swaped then
  1295. begin
  1296. if (p^.treetype=slashn) then
  1297. op:=A_FDIVRP
  1298. else if (p^.treetype=subn) then
  1299. op:=A_FSUBRP;
  1300. end;
  1301. { to avoid the pentium bug
  1302. if (op=FDIVP) and (opt_processors=pentium) then
  1303. exprasmlist^.concat(new(pai386,op_CALL,S_NO,'EMUL_FDIVP')
  1304. else
  1305. }
  1306. { the Intel assemblers want operands }
  1307. if op<>A_FCOMPP then
  1308. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,R_ST,R_ST1)))
  1309. else
  1310. exprasmlist^.concat(new(pai386,op_none(op,S_NO)));
  1311. { on comparison load flags }
  1312. if cmpop then
  1313. begin
  1314. if not(R_EAX in unused) then
  1315. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1316. exprasmlist^.concat(new(pai386,op_reg(A_FNSTSW,S_NO,R_AX)));
  1317. exprasmlist^.concat(new(pai386,op_none(A_SAHF,S_NO)));
  1318. if not(R_EAX in unused) then
  1319. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1320. if p^.swaped then
  1321. begin
  1322. case p^.treetype of
  1323. equaln : flags:=F_E;
  1324. unequaln : flags:=F_NE;
  1325. ltn : flags:=F_A;
  1326. lten : flags:=F_AE;
  1327. gtn : flags:=F_B;
  1328. gten : flags:=F_BE;
  1329. end;
  1330. end
  1331. else
  1332. begin
  1333. case p^.treetype of
  1334. equaln : flags:=F_E;
  1335. unequaln : flags:=F_NE;
  1336. ltn : flags:=F_B;
  1337. lten : flags:=F_BE;
  1338. gtn : flags:=F_A;
  1339. gten : flags:=F_AE;
  1340. end;
  1341. end;
  1342. clear_location(p^.location);
  1343. p^.location.loc:=LOC_FLAGS;
  1344. p^.location.resflags:=flags;
  1345. cmpop:=false;
  1346. end
  1347. else
  1348. begin
  1349. clear_location(p^.location);
  1350. p^.location.loc:=LOC_FPU;
  1351. end;
  1352. end
  1353. {$ifdef SUPPORT_MMX}
  1354. else
  1355. { MMX Arrays }
  1356. if is_mmx_able_array(p^.left^.resulttype) then
  1357. begin
  1358. cmpop:=false;
  1359. mmxbase:=mmx_type(p^.left^.resulttype);
  1360. case p^.treetype of
  1361. addn : begin
  1362. if (cs_mmx_saturation in aktlocalswitches) then
  1363. begin
  1364. case mmxbase of
  1365. mmxs8bit:
  1366. op:=A_PADDSB;
  1367. mmxu8bit:
  1368. op:=A_PADDUSB;
  1369. mmxs16bit,mmxfixed16:
  1370. op:=A_PADDSB;
  1371. mmxu16bit:
  1372. op:=A_PADDUSW;
  1373. end;
  1374. end
  1375. else
  1376. begin
  1377. case mmxbase of
  1378. mmxs8bit,mmxu8bit:
  1379. op:=A_PADDB;
  1380. mmxs16bit,mmxu16bit,mmxfixed16:
  1381. op:=A_PADDW;
  1382. mmxs32bit,mmxu32bit:
  1383. op:=A_PADDD;
  1384. end;
  1385. end;
  1386. end;
  1387. muln : begin
  1388. case mmxbase of
  1389. mmxs16bit,mmxu16bit:
  1390. op:=A_PMULLW;
  1391. mmxfixed16:
  1392. op:=A_PMULHW;
  1393. end;
  1394. end;
  1395. subn : begin
  1396. if (cs_mmx_saturation in aktlocalswitches) then
  1397. begin
  1398. case mmxbase of
  1399. mmxs8bit:
  1400. op:=A_PSUBSB;
  1401. mmxu8bit:
  1402. op:=A_PSUBUSB;
  1403. mmxs16bit,mmxfixed16:
  1404. op:=A_PSUBSB;
  1405. mmxu16bit:
  1406. op:=A_PSUBUSW;
  1407. end;
  1408. end
  1409. else
  1410. begin
  1411. case mmxbase of
  1412. mmxs8bit,mmxu8bit:
  1413. op:=A_PSUBB;
  1414. mmxs16bit,mmxu16bit,mmxfixed16:
  1415. op:=A_PSUBW;
  1416. mmxs32bit,mmxu32bit:
  1417. op:=A_PSUBD;
  1418. end;
  1419. end;
  1420. end;
  1421. {
  1422. ltn,lten,gtn,gten,
  1423. equaln,unequaln :
  1424. begin
  1425. op:=A_CMP;
  1426. cmpop:=true;
  1427. end;
  1428. }
  1429. xorn:
  1430. op:=A_PXOR;
  1431. orn:
  1432. op:=A_POR;
  1433. andn:
  1434. op:=A_PAND;
  1435. else CGMessage(type_e_mismatch);
  1436. end;
  1437. { left and right no register? }
  1438. { then one must be demanded }
  1439. if (p^.left^.location.loc<>LOC_MMXREGISTER) and
  1440. (p^.right^.location.loc<>LOC_MMXREGISTER) then
  1441. begin
  1442. { register variable ? }
  1443. if (p^.left^.location.loc=LOC_CMMXREGISTER) then
  1444. begin
  1445. { it is OK if this is the destination }
  1446. if is_in_dest then
  1447. begin
  1448. hregister:=p^.location.register;
  1449. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1450. hregister);
  1451. end
  1452. else
  1453. begin
  1454. hregister:=getregistermmx;
  1455. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1456. hregister);
  1457. end
  1458. end
  1459. else
  1460. begin
  1461. del_reference(p^.left^.location.reference);
  1462. if is_in_dest then
  1463. begin
  1464. hregister:=p^.location.register;
  1465. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1466. newreference(p^.left^.location.reference),hregister)));
  1467. end
  1468. else
  1469. begin
  1470. hregister:=getregistermmx;
  1471. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1472. newreference(p^.left^.location.reference),hregister)));
  1473. end;
  1474. end;
  1475. clear_location(p^.location);
  1476. p^.location.loc:=LOC_MMXREGISTER;
  1477. p^.location.register:=hregister;
  1478. end
  1479. else
  1480. { if on the right the register then swap }
  1481. if (p^.right^.location.loc=LOC_MMXREGISTER) then
  1482. begin
  1483. swap_location(p^.location,p^.right^.location);
  1484. { newly swapped also set swapped flag }
  1485. p^.swaped:=not(p^.swaped);
  1486. end;
  1487. { at this point, p^.location.loc should be LOC_MMXREGISTER }
  1488. { and p^.location.register should be a valid register }
  1489. { containing the left result }
  1490. if p^.right^.location.loc<>LOC_MMXREGISTER then
  1491. begin
  1492. if (p^.treetype=subn) and p^.swaped then
  1493. begin
  1494. if p^.right^.location.loc=LOC_CMMXREGISTER then
  1495. begin
  1496. emit_reg_reg(A_MOVQ,S_NO,p^.right^.location.register,R_MM7);
  1497. emit_reg_reg(op,S_NO,p^.location.register,R_EDI);
  1498. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  1499. end
  1500. else
  1501. begin
  1502. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1503. newreference(p^.right^.location.reference),R_MM7)));
  1504. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,p^.location.register,
  1505. R_MM7)));
  1506. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOVQ,S_NO,
  1507. R_MM7,p^.location.register)));
  1508. del_reference(p^.right^.location.reference);
  1509. end;
  1510. end
  1511. else
  1512. begin
  1513. if (p^.right^.location.loc=LOC_CREGISTER) then
  1514. begin
  1515. emit_reg_reg(op,S_NO,p^.right^.location.register,
  1516. p^.location.register);
  1517. end
  1518. else
  1519. begin
  1520. exprasmlist^.concat(new(pai386,op_ref_reg(op,S_NO,newreference(
  1521. p^.right^.location.reference),p^.location.register)));
  1522. del_reference(p^.right^.location.reference);
  1523. end;
  1524. end;
  1525. end
  1526. else
  1527. begin
  1528. { when swapped another result register }
  1529. if (p^.treetype=subn) and p^.swaped then
  1530. begin
  1531. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1532. p^.location.register,p^.right^.location.register)));
  1533. swap_location(p^.location,p^.right^.location);
  1534. { newly swapped also set swapped flag }
  1535. { just to maintain ordering }
  1536. p^.swaped:=not(p^.swaped);
  1537. end
  1538. else
  1539. begin
  1540. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1541. p^.right^.location.register,
  1542. p^.location.register)));
  1543. end;
  1544. ungetregistermmx(p^.right^.location.register);
  1545. end;
  1546. end
  1547. {$endif SUPPORT_MMX}
  1548. else CGMessage(type_e_mismatch);
  1549. end;
  1550. SetResultLocation(cmpop,unsigned,p);
  1551. end;
  1552. end.
  1553. {
  1554. $Log$
  1555. Revision 1.34 1998-12-11 00:02:46 peter
  1556. + globtype,tokens,version unit splitted from globals
  1557. Revision 1.33 1998/12/10 11:16:00 florian
  1558. + some basic operations with qwords and int64 added: +, xor, and, or;
  1559. the register allocation works fine
  1560. Revision 1.32 1998/12/10 09:47:13 florian
  1561. + basic operations with int64/qord (compiler with -dint64)
  1562. + rtti of enumerations extended: names are now written
  1563. Revision 1.31 1998/11/30 09:42:59 pierre
  1564. * some range check bugs fixed (still not working !)
  1565. + added DLL writing support for win32 (also accepts variables)
  1566. + TempAnsi for code that could be used for Temporary ansi strings
  1567. handling
  1568. Revision 1.30 1998/11/24 12:52:40 peter
  1569. * sets are not written twice anymore
  1570. * optimize for emptyset+single element which uses a new routine from
  1571. set.inc FPC_SET_CREATE_ELEMENT
  1572. Revision 1.29 1998/11/18 15:44:05 peter
  1573. * VALUEPARA for tp7 compatible value parameters
  1574. Revision 1.28 1998/11/18 09:18:01 pierre
  1575. + automatic loading of profile unit with -pg option
  1576. in go32v2 mode (also defines FPC_PROFILE)
  1577. * some memory leaks removed
  1578. * unreleased temp problem with sets solved
  1579. Revision 1.27 1998/11/17 00:36:38 peter
  1580. * more ansistring fixes
  1581. Revision 1.26 1998/11/16 16:17:16 peter
  1582. * fixed ansistring temp which forgot a reset
  1583. Revision 1.25 1998/11/16 15:35:35 peter
  1584. * rename laod/copystring -> load/copyshortstring
  1585. * fixed int-bool cnv bug
  1586. + char-ansistring conversion
  1587. Revision 1.24 1998/11/07 12:49:30 peter
  1588. * fixed ansicompare which returns signed
  1589. Revision 1.23 1998/10/29 15:42:43 florian
  1590. + partial disposing of temp. ansistrings
  1591. Revision 1.22 1998/10/28 18:26:12 pierre
  1592. * removed some erros after other errors (introduced by useexcept)
  1593. * stabs works again correctly (for how long !)
  1594. Revision 1.21 1998/10/25 23:32:48 peter
  1595. * fixed unsigned mul
  1596. Revision 1.20 1998/10/21 08:39:56 florian
  1597. + ansistring operator +
  1598. + $h and string[n] for n>255 added
  1599. * small problem with TP fixed
  1600. Revision 1.19 1998/10/20 15:09:21 florian
  1601. + binary operators for ansi strings
  1602. Revision 1.18 1998/10/20 08:06:38 pierre
  1603. * several memory corruptions due to double freemem solved
  1604. => never use p^.loc.location:=p^.left^.loc.location;
  1605. + finally I added now by default
  1606. that ra386dir translates global and unit symbols
  1607. + added a first field in tsymtable and
  1608. a nextsym field in tsym
  1609. (this allows to obtain ordered type info for
  1610. records and objects in gdb !)
  1611. Revision 1.17 1998/10/09 11:47:45 pierre
  1612. * still more memory leaks fixes !!
  1613. Revision 1.16 1998/10/09 08:56:21 pierre
  1614. * several memory leaks fixed
  1615. Revision 1.15 1998/10/08 17:17:10 pierre
  1616. * current_module old scanner tagged as invalid if unit is recompiled
  1617. + added ppheap for better info on tracegetmem of heaptrc
  1618. (adds line column and file index)
  1619. * several memory leaks removed ith help of heaptrc !!
  1620. Revision 1.14 1998/09/28 16:57:13 pierre
  1621. * changed all length(p^.value_str^) into str_length(p)
  1622. to get it work with and without ansistrings
  1623. * changed sourcefiles field of tmodule to a pointer
  1624. Revision 1.13 1998/09/17 09:42:09 peter
  1625. + pass_2 for cg386
  1626. * Message() -> CGMessage() for pass_1/pass_2
  1627. Revision 1.12 1998/09/14 10:43:44 peter
  1628. * all internal RTL functions start with FPC_
  1629. Revision 1.11 1998/09/07 18:45:52 peter
  1630. * update smartlinking, uses getdatalabel
  1631. * renamed ptree.value vars to value_str,value_real,value_set
  1632. Revision 1.10 1998/09/04 10:05:04 florian
  1633. * ugly fix for STRCAT, nevertheless it needs more fixing !!!!!!!
  1634. we need an new version of STRCAT which takes a length parameter
  1635. Revision 1.9 1998/09/04 08:41:36 peter
  1636. * updated some error CGMessages
  1637. Revision 1.8 1998/08/28 10:54:18 peter
  1638. * fixed smallset generation from elements, it has never worked before!
  1639. Revision 1.7 1998/08/19 14:56:59 peter
  1640. * forgot to removed some unused code in addset for set<>set
  1641. Revision 1.6 1998/08/18 09:24:35 pierre
  1642. * small warning position bug fixed
  1643. * support_mmx switches splitting was missing
  1644. * rhide error and warning output corrected
  1645. Revision 1.5 1998/08/14 18:18:37 peter
  1646. + dynamic set contruction
  1647. * smallsets are now working (always longint size)
  1648. Revision 1.4 1998/08/10 14:49:42 peter
  1649. + localswitches, moduleswitches, globalswitches splitting
  1650. Revision 1.3 1998/06/25 08:48:04 florian
  1651. * first version of rtti support
  1652. Revision 1.2 1998/06/08 13:13:28 pierre
  1653. + temporary variables now in temp_gen.pas unit
  1654. because it is processor independent
  1655. * mppc68k.bat modified to undefine i386 and support_mmx
  1656. (which are defaults for i386)
  1657. Revision 1.1 1998/06/05 17:44:10 peter
  1658. * splitted cgi386
  1659. }