cg386add.pas 84 KB

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