n386add.pas 107 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338
  1. {
  2. $Id$
  3. Copyright (c) 2000 by Florian Klaempfl
  4. Code generation for add nodes on the i386
  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 n386add;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. nadd,cpubase;
  23. type
  24. ti386addnode = class(taddnode)
  25. procedure pass_2;override;
  26. function getresflags(unsigned : boolean) : tresflags;
  27. procedure SetResultLocation(cmpop,unsigned : boolean);
  28. procedure addstring;
  29. procedure addset;
  30. end;
  31. implementation
  32. uses
  33. globtype,systems,
  34. cutils,cobjects,verbose,globals,
  35. symconst,symdef,aasm,types,
  36. hcodegen,temp_gen,pass_2,
  37. cpuasm,
  38. node,ncon,nset,
  39. cgai386,n386util,tgcpu;
  40. function ti386addnode.getresflags(unsigned : boolean) : tresflags;
  41. begin
  42. if not(unsigned) then
  43. begin
  44. if nf_swaped in flags then
  45. case nodetype of
  46. equaln : getresflags:=F_E;
  47. unequaln : getresflags:=F_NE;
  48. ltn : getresflags:=F_G;
  49. lten : getresflags:=F_GE;
  50. gtn : getresflags:=F_L;
  51. gten : getresflags:=F_LE;
  52. end
  53. else
  54. case nodetype of
  55. equaln : getresflags:=F_E;
  56. unequaln : getresflags:=F_NE;
  57. ltn : getresflags:=F_L;
  58. lten : getresflags:=F_LE;
  59. gtn : getresflags:=F_G;
  60. gten : getresflags:=F_GE;
  61. end;
  62. end
  63. else
  64. begin
  65. if nf_swaped in flags then
  66. case nodetype of
  67. equaln : getresflags:=F_E;
  68. unequaln : getresflags:=F_NE;
  69. ltn : getresflags:=F_A;
  70. lten : getresflags:=F_AE;
  71. gtn : getresflags:=F_B;
  72. gten : getresflags:=F_BE;
  73. end
  74. else
  75. case nodetype of
  76. equaln : getresflags:=F_E;
  77. unequaln : getresflags:=F_NE;
  78. ltn : getresflags:=F_B;
  79. lten : getresflags:=F_BE;
  80. gtn : getresflags:=F_A;
  81. gten : getresflags:=F_AE;
  82. end;
  83. end;
  84. end;
  85. procedure ti386addnode.SetResultLocation(cmpop,unsigned : boolean);
  86. begin
  87. { remove temporary location if not a set or string }
  88. { that's a bad hack (FK) who did this ? }
  89. if (left.resulttype^.deftype<>stringdef) and
  90. ((left.resulttype^.deftype<>setdef) or (psetdef(left.resulttype)^.settype=smallset)) and
  91. (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  92. ungetiftemp(left.location.reference);
  93. if (right.resulttype^.deftype<>stringdef) and
  94. ((right.resulttype^.deftype<>setdef) or (psetdef(right.resulttype)^.settype=smallset)) and
  95. (right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  96. ungetiftemp(right.location.reference);
  97. { in case of comparison operation the put result in the flags }
  98. if cmpop then
  99. begin
  100. clear_location(location);
  101. location.loc:=LOC_FLAGS;
  102. location.resflags:=getresflags(unsigned);
  103. end;
  104. end;
  105. {*****************************************************************************
  106. Addstring
  107. *****************************************************************************}
  108. procedure ti386addnode.addstring;
  109. var
  110. {$ifdef newoptimizations2}
  111. l: pasmlabel;
  112. hreg: tregister;
  113. href2: preference;
  114. oldregisterdef: boolean;
  115. {$endif newoptimizations2}
  116. pushedregs : tpushed;
  117. href : treference;
  118. pushed,
  119. cmpop : boolean;
  120. regstopush : byte;
  121. begin
  122. { string operations are not commutative }
  123. if nf_swaped in flags then
  124. swapleftright;
  125. case pstringdef(left.resulttype)^.string_typ of
  126. st_ansistring:
  127. begin
  128. case nodetype of
  129. addn:
  130. begin
  131. cmpop:=false;
  132. secondpass(left);
  133. { to avoid problem with maybe_push and restore }
  134. set_location(location,left.location);
  135. pushed:=maybe_push(right.registers32,self,false);
  136. secondpass(right);
  137. if pushed then
  138. begin
  139. restore(self,false);
  140. set_location(left.location,location);
  141. end;
  142. { get the temp location, must be done before regs are
  143. released/pushed because after the release the regs are
  144. still used for the push (PFV) }
  145. clear_location(location);
  146. location.loc:=LOC_MEM;
  147. gettempansistringreference(location.reference);
  148. decrstringref(cansistringdef,location.reference);
  149. { release used registers }
  150. del_location(right.location);
  151. del_location(left.location);
  152. { push the still used registers }
  153. pushusedregisters(pushedregs,$ff);
  154. { push data }
  155. emitpushreferenceaddr(location.reference);
  156. emit_push_loc(right.location);
  157. emit_push_loc(left.location);
  158. saveregvars($ff);
  159. emitcall('FPC_ANSISTR_CONCAT');
  160. popusedregisters(pushedregs);
  161. maybe_loadesi;
  162. ungetiftempansi(left.location.reference);
  163. ungetiftempansi(right.location.reference);
  164. end;
  165. ltn,lten,gtn,gten,
  166. equaln,unequaln:
  167. begin
  168. cmpop:=true;
  169. if (nodetype in [equaln,unequaln]) and
  170. (left.nodetype=stringconstn) and
  171. (tstringconstnode(left).len=0) then
  172. begin
  173. secondpass(right);
  174. { release used registers }
  175. del_location(right.location);
  176. del_location(left.location);
  177. case right.location.loc of
  178. LOC_REFERENCE,LOC_MEM:
  179. emit_const_ref(A_CMP,S_L,0,newreference(right.location.reference));
  180. LOC_REGISTER,LOC_CREGISTER:
  181. emit_const_reg(A_CMP,S_L,0,right.location.register);
  182. end;
  183. ungetiftempansi(left.location.reference);
  184. ungetiftempansi(right.location.reference);
  185. end
  186. else if (nodetype in [equaln,unequaln]) and
  187. (right.nodetype=stringconstn) and
  188. (tstringconstnode(right).len=0) then
  189. begin
  190. secondpass(left);
  191. { release used registers }
  192. del_location(right.location);
  193. del_location(left.location);
  194. case right.location.loc of
  195. LOC_REFERENCE,LOC_MEM:
  196. emit_const_ref(A_CMP,S_L,0,newreference(left.location.reference));
  197. LOC_REGISTER,LOC_CREGISTER:
  198. emit_const_reg(A_CMP,S_L,0,left.location.register);
  199. end;
  200. ungetiftempansi(left.location.reference);
  201. ungetiftempansi(right.location.reference);
  202. end
  203. else
  204. begin
  205. secondpass(left);
  206. pushed:=maybe_push(right.registers32,left,false);
  207. secondpass(right);
  208. if pushed then
  209. restore(left,false);
  210. { release used registers }
  211. del_location(right.location);
  212. del_location(left.location);
  213. { push the still used registers }
  214. pushusedregisters(pushedregs,$ff);
  215. { push data }
  216. case right.location.loc of
  217. LOC_REFERENCE,LOC_MEM:
  218. emit_push_mem(right.location.reference);
  219. LOC_REGISTER,LOC_CREGISTER:
  220. emit_reg(A_PUSH,S_L,right.location.register);
  221. end;
  222. case left.location.loc of
  223. LOC_REFERENCE,LOC_MEM:
  224. emit_push_mem(left.location.reference);
  225. LOC_REGISTER,LOC_CREGISTER:
  226. emit_reg(A_PUSH,S_L,left.location.register);
  227. end;
  228. saveregvars($ff);
  229. emitcall('FPC_ANSISTR_COMPARE');
  230. emit_reg_reg(A_OR,S_L,R_EAX,R_EAX);
  231. popusedregisters(pushedregs);
  232. maybe_loadesi;
  233. ungetiftempansi(left.location.reference);
  234. ungetiftempansi(right.location.reference);
  235. end;
  236. end;
  237. end;
  238. { the result of ansicompare is signed }
  239. SetResultLocation(cmpop,false);
  240. end;
  241. st_shortstring:
  242. begin
  243. case nodetype of
  244. addn:
  245. begin
  246. cmpop:=false;
  247. secondpass(left);
  248. { if str_concat is set in expr
  249. s:=s+ ... no need to create a temp string (PM) }
  250. if (left.nodetype<>addn) and not(nf_use_strconcat in flags) then
  251. begin
  252. { can only reference be }
  253. { string in register would be funny }
  254. { therefore produce a temporary string }
  255. gettempofsizereference(256,href);
  256. copyshortstring(href,left.location.reference,255,false,true);
  257. { release the registers }
  258. { done by copyshortstring now (JM) }
  259. { del_reference(left.location.reference); }
  260. ungetiftemp(left.location.reference);
  261. { does not hurt: }
  262. clear_location(left.location);
  263. left.location.loc:=LOC_MEM;
  264. left.location.reference:=href;
  265. {$ifdef newoptimizations2}
  266. { length of temp string = 255 (JM) }
  267. { *** redefining a type is not allowed!! (thanks, Pierre) }
  268. { also problem with constant string! }
  269. pstringdef(left.resulttype)^.len := 255;
  270. {$endif newoptimizations2}
  271. end;
  272. secondpass(right);
  273. {$ifdef newoptimizations2}
  274. { special case for string := string + char (JM) }
  275. { needs string length stuff from above! }
  276. hreg := R_NO;
  277. if is_shortstring(left.resulttype) and
  278. is_char(right.resulttype) then
  279. begin
  280. getlabel(l);
  281. getexplicitregister32(R_EDI);
  282. { load the current string length }
  283. emit_ref_reg(A_MOVZX,S_BL,
  284. newreference(left.location.reference),R_EDI);
  285. { is it already maximal? }
  286. emit_const_reg(A_CMP,S_L,
  287. pstringdef(left.resulttype)^.len,R_EDI);
  288. emitjmp(C_E,l);
  289. { no, so add the new character }
  290. { is it a constant char? }
  291. if (right.nodetype <> ordconstn) then
  292. { no, make sure it is in a register }
  293. if right.location.loc in [LOC_REFERENCE,LOC_MEM] then
  294. begin
  295. { free the registers of right }
  296. del_reference(right.location.reference);
  297. { get register for the char }
  298. hreg := reg32toreg8(getregister32);
  299. emit_ref_reg(A_MOV,S_B,
  300. newreference(right.location.reference),
  301. hreg);
  302. { I don't think a temp char exists, but it won't hurt (JM)Ê}
  303. ungetiftemp(right.location.reference);
  304. end
  305. else hreg := right.location.register;
  306. href2 := newreference(left.location.reference);
  307. { we need a new reference to store the character }
  308. { at the end of the string. Check if the base or }
  309. { index register is still free }
  310. if (left.location.reference.base <> R_NO) and
  311. (left.location.reference.index <> R_NO) then
  312. begin
  313. { they're not free, so add the base reg to }
  314. { the string length (since the index can }
  315. { have a scalefactor) and use EDI as base }
  316. emit_reg_reg(A_ADD,S_L,
  317. left.location.reference.base,R_EDI);
  318. href2^.base := R_EDI;
  319. end
  320. else
  321. { at least one is still free, so put EDI there }
  322. if href2^.base = R_NO then
  323. href2^.base := R_EDI
  324. else
  325. begin
  326. href2^.index := R_EDI;
  327. href2^.scalefactor := 1;
  328. end;
  329. { we need to be one position after the last char }
  330. inc(href2^.offset);
  331. { increase the string length }
  332. emit_ref(A_INC,S_B,newreference(left.location.reference));
  333. { and store the character at the end of the string }
  334. if (right.nodetype <> ordconstn) then
  335. begin
  336. { no new_reference(href2) because it's only }
  337. { used once (JM) }
  338. emit_reg_ref(A_MOV,S_B,hreg,href2);
  339. ungetregister(hreg);
  340. end
  341. else
  342. emit_const_ref(A_MOV,S_B,right.value,href2);
  343. emitlab(l);
  344. ungetregister32(R_EDI);
  345. end
  346. else
  347. begin
  348. {$endif newoptimizations2}
  349. { on the right we do not need the register anymore too }
  350. { Instead of releasing them already, simply do not }
  351. { push them (so the release is in the right place, }
  352. { because emitpushreferenceaddr doesn't need extra }
  353. { registers) (JM) }
  354. regstopush := $ff;
  355. remove_non_regvars_from_loc(right.location,
  356. regstopush);
  357. pushusedregisters(pushedregs,regstopush);
  358. { push the maximum possible length of the result }
  359. {$ifdef newoptimizations2}
  360. { string (could be < 255 chars now) (JM) }
  361. emit_const(A_PUSH,S_L,
  362. pstringdef(left.resulttype)^.len);
  363. {$endif newoptimizations2}
  364. emitpushreferenceaddr(left.location.reference);
  365. { the optimizer can more easily put the }
  366. { deallocations in the right place if it happens }
  367. { too early than when it happens too late (if }
  368. { the pushref needs a "lea (..),edi; push edi") }
  369. del_reference(right.location.reference);
  370. emitpushreferenceaddr(right.location.reference);
  371. saveregvars(regstopush);
  372. {$ifdef newoptimizations2}
  373. emitcall('FPC_SHORTSTR_CONCAT_LEN');
  374. {$else newoptimizations2}
  375. emitcall('FPC_SHORTSTR_CONCAT');
  376. {$endif newoptimizations2}
  377. ungetiftemp(right.location.reference);
  378. maybe_loadesi;
  379. popusedregisters(pushedregs);
  380. {$ifdef newoptimizations2}
  381. end;
  382. {$endif newoptimizations2}
  383. set_location(location,left.location);
  384. end;
  385. ltn,lten,gtn,gten,
  386. equaln,unequaln :
  387. begin
  388. cmpop:=true;
  389. { generate better code for s='' and s<>'' }
  390. if (nodetype in [equaln,unequaln]) and
  391. (((left.nodetype=stringconstn) and (str_length(left)=0)) or
  392. ((right.nodetype=stringconstn) and (str_length(right)=0))) then
  393. begin
  394. secondpass(left);
  395. { are too few registers free? }
  396. pushed:=maybe_push(right.registers32,left,false);
  397. secondpass(right);
  398. if pushed then
  399. restore(left,false);
  400. { only one node can be stringconstn }
  401. { else pass 1 would have evaluted }
  402. { this node }
  403. if left.nodetype=stringconstn then
  404. emit_const_ref(
  405. A_CMP,S_B,0,newreference(right.location.reference))
  406. else
  407. emit_const_ref(
  408. A_CMP,S_B,0,newreference(left.location.reference));
  409. del_reference(right.location.reference);
  410. del_reference(left.location.reference);
  411. end
  412. else
  413. begin
  414. pushusedregisters(pushedregs,$ff);
  415. secondpass(left);
  416. emitpushreferenceaddr(left.location.reference);
  417. del_reference(left.location.reference);
  418. secondpass(right);
  419. emitpushreferenceaddr(right.location.reference);
  420. del_reference(right.location.reference);
  421. saveregvars($ff);
  422. emitcall('FPC_SHORTSTR_COMPARE');
  423. maybe_loadesi;
  424. popusedregisters(pushedregs);
  425. end;
  426. ungetiftemp(left.location.reference);
  427. ungetiftemp(right.location.reference);
  428. end;
  429. else CGMessage(type_e_mismatch);
  430. end;
  431. SetResultLocation(cmpop,true);
  432. end;
  433. end;
  434. end;
  435. {*****************************************************************************
  436. Addset
  437. *****************************************************************************}
  438. procedure ti386addnode.addset;
  439. var
  440. createset,
  441. cmpop,
  442. pushed : boolean;
  443. href : treference;
  444. pushedregs : tpushed;
  445. regstopush: byte;
  446. begin
  447. cmpop:=false;
  448. { not commutative }
  449. if nf_swaped in flags then
  450. swapleftright;
  451. { optimize first loading of a set }
  452. {$ifdef usecreateset}
  453. if (right.nodetype=setelementn) and
  454. not(assigned(right.right)) and
  455. is_emptyset(left) then
  456. createset:=true
  457. else
  458. {$endif}
  459. begin
  460. createset:=false;
  461. secondpass(left);
  462. end;
  463. { are too few registers free? }
  464. pushed:=maybe_push(right.registers32,left,false);
  465. secondpass(right);
  466. if codegenerror then
  467. exit;
  468. if pushed then
  469. restore(left,false);
  470. set_location(location,left.location);
  471. { handle operations }
  472. case nodetype of
  473. equaln,
  474. unequaln
  475. {$IfNDef NoSetInclusion}
  476. ,lten, gten
  477. {$EndIf NoSetInclusion}
  478. : begin
  479. cmpop:=true;
  480. del_location(left.location);
  481. del_location(right.location);
  482. pushusedregisters(pushedregs,$ff);
  483. {$IfNDef NoSetInclusion}
  484. If (nodetype in [equaln, unequaln, lten]) Then
  485. Begin
  486. {$EndIf NoSetInclusion}
  487. emitpushreferenceaddr(right.location.reference);
  488. emitpushreferenceaddr(left.location.reference);
  489. {$IfNDef NoSetInclusion}
  490. End
  491. Else {gten = lten, if the arguments are reversed}
  492. Begin
  493. emitpushreferenceaddr(left.location.reference);
  494. emitpushreferenceaddr(right.location.reference);
  495. End;
  496. saveregvars($ff);
  497. Case nodetype of
  498. equaln, unequaln:
  499. {$EndIf NoSetInclusion}
  500. emitcall('FPC_SET_COMP_SETS');
  501. {$IfNDef NoSetInclusion}
  502. lten, gten:
  503. Begin
  504. emitcall('FPC_SET_CONTAINS_SETS');
  505. { we need a jne afterwards, not a jnbe/jnae }
  506. nodetype := equaln;
  507. End;
  508. End;
  509. {$EndIf NoSetInclusion}
  510. maybe_loadesi;
  511. popusedregisters(pushedregs);
  512. ungetiftemp(left.location.reference);
  513. ungetiftemp(right.location.reference);
  514. end;
  515. addn : begin
  516. { add can be an other SET or Range or Element ! }
  517. { del_location(right.location);
  518. done in pushsetelement below PM
  519. And someone added it again because those registers must
  520. not be pushed by the pushusedregisters, however this
  521. breaks the optimizer (JM)
  522. del_location(right.location);
  523. pushusedregisters(pushedregs,$ff);}
  524. regstopush := $ff;
  525. remove_non_regvars_from_loc(right.location,regstopush);
  526. remove_non_regvars_from_loc(left.location,regstopush);
  527. pushusedregisters(pushedregs,regstopush);
  528. { this is still right before the instruction that uses }
  529. { left.location, but that can be fixed by the }
  530. { optimizer. There must never be an additional }
  531. { between the release and the use, because that is not }
  532. { detected/fixed. As Pierre said above, right.loc }
  533. { will be released in pushsetelement (JM) }
  534. del_location(left.location);
  535. href.symbol:=nil;
  536. gettempofsizereference(32,href);
  537. if createset then
  538. begin
  539. pushsetelement(tunarynode(right).left);
  540. emitpushreferenceaddr(href);
  541. saveregvars(regstopush);
  542. emitcall('FPC_SET_CREATE_ELEMENT');
  543. end
  544. else
  545. begin
  546. { add a range or a single element? }
  547. if right.nodetype=setelementn then
  548. begin
  549. {$IfNDef regallocfix}
  550. concatcopy(left.location.reference,href,32,false,false);
  551. {$Else regallocfix}
  552. concatcopy(left.location.reference,href,32,true,false);
  553. {$EndIf regallocfix}
  554. if assigned(tbinarynode(right).right) then
  555. begin
  556. pushsetelement(tbinarynode(right).right);
  557. pushsetelement(tunarynode(right).left);
  558. emitpushreferenceaddr(href);
  559. saveregvars(regstopush);
  560. emitcall('FPC_SET_SET_RANGE');
  561. end
  562. else
  563. begin
  564. pushsetelement(tunarynode(right).left);
  565. emitpushreferenceaddr(href);
  566. saveregvars(regstopush);
  567. emitcall('FPC_SET_SET_BYTE');
  568. end;
  569. end
  570. else
  571. begin
  572. { must be an other set }
  573. emitpushreferenceaddr(href);
  574. emitpushreferenceaddr(right.location.reference);
  575. {$IfDef regallocfix}
  576. del_location(right.location);
  577. {$EndIf regallocfix}
  578. emitpushreferenceaddr(left.location.reference);
  579. {$IfDef regallocfix}
  580. del_location(left.location);
  581. {$EndIf regallocfix}
  582. saveregvars(regstopush);
  583. emitcall('FPC_SET_ADD_SETS');
  584. end;
  585. end;
  586. maybe_loadesi;
  587. popusedregisters(pushedregs);
  588. ungetiftemp(left.location.reference);
  589. ungetiftemp(right.location.reference);
  590. location.loc:=LOC_MEM;
  591. location.reference:=href;
  592. end;
  593. subn,
  594. symdifn,
  595. muln : begin
  596. { Find out which registers have to pushed (JM) }
  597. regstopush := $ff;
  598. remove_non_regvars_from_loc(left.location,regstopush);
  599. remove_non_regvars_from_loc(right.location,regstopush);
  600. { Push them (JM) }
  601. pushusedregisters(pushedregs,regstopush);
  602. href.symbol:=nil;
  603. gettempofsizereference(32,href);
  604. emitpushreferenceaddr(href);
  605. { Release the registers right before they're used, }
  606. { see explanation in cgai386.pas:loadansistring for }
  607. { info why this is done right before the push (JM) }
  608. del_location(right.location);
  609. emitpushreferenceaddr(right.location.reference);
  610. { The same here }
  611. del_location(left.location);
  612. emitpushreferenceaddr(left.location.reference);
  613. saveregvars(regstopush);
  614. case nodetype of
  615. subn : emitcall('FPC_SET_SUB_SETS');
  616. symdifn : emitcall('FPC_SET_SYMDIF_SETS');
  617. muln : emitcall('FPC_SET_MUL_SETS');
  618. end;
  619. maybe_loadesi;
  620. popusedregisters(pushedregs);
  621. ungetiftemp(left.location.reference);
  622. ungetiftemp(right.location.reference);
  623. location.loc:=LOC_MEM;
  624. location.reference:=href;
  625. end;
  626. else
  627. CGMessage(type_e_mismatch);
  628. end;
  629. SetResultLocation(cmpop,true);
  630. end;
  631. {*****************************************************************************
  632. pass_2
  633. *****************************************************************************}
  634. procedure ti386addnode.pass_2;
  635. { is also being used for xor, and "mul", "sub, or and comparative }
  636. { operators }
  637. label do_normal;
  638. var
  639. hregister,hregister2 : tregister;
  640. noswap,popeax,popedx,
  641. pushed,mboverflow,cmpop : boolean;
  642. op,op2 : tasmop;
  643. resflags : tresflags;
  644. otl,ofl : pasmlabel;
  645. power : longint;
  646. opsize : topsize;
  647. hl4: pasmlabel;
  648. hr : preference;
  649. { true, if unsigned types are compared }
  650. unsigned : boolean;
  651. { true, if a small set is handled with the longint code }
  652. is_set : boolean;
  653. { is_in_dest if the result is put directly into }
  654. { the resulting refernce or varregister }
  655. is_in_dest : boolean;
  656. { true, if for sets subtractions the extra not should generated }
  657. extra_not : boolean;
  658. {$ifdef SUPPORT_MMX}
  659. mmxbase : tmmxtype;
  660. {$endif SUPPORT_MMX}
  661. pushedreg : tpushed;
  662. hloc : tlocation;
  663. regstopush: byte;
  664. procedure firstjmp64bitcmp;
  665. var
  666. oldnodetype : tnodetype;
  667. begin
  668. { the jump the sequence is a little bit hairy }
  669. case nodetype of
  670. ltn,gtn:
  671. begin
  672. emitjmp(flag_2_cond[getresflags(unsigned)],truelabel);
  673. { cheat a little bit for the negative test }
  674. toggleflag(nf_swaped);
  675. emitjmp(flag_2_cond[getresflags(unsigned)],falselabel);
  676. toggleflag(nf_swaped);
  677. end;
  678. lten,gten:
  679. begin
  680. oldnodetype:=nodetype;
  681. if nodetype=lten then
  682. nodetype:=ltn
  683. else
  684. nodetype:=gtn;
  685. emitjmp(flag_2_cond[getresflags(unsigned)],truelabel);
  686. { cheat for the negative test }
  687. if nodetype=ltn then
  688. nodetype:=gtn
  689. else
  690. nodetype:=ltn;
  691. emitjmp(flag_2_cond[getresflags(unsigned)],falselabel);
  692. nodetype:=oldnodetype;
  693. end;
  694. equaln:
  695. emitjmp(C_NE,falselabel);
  696. unequaln:
  697. emitjmp(C_NE,truelabel);
  698. end;
  699. end;
  700. procedure secondjmp64bitcmp;
  701. begin
  702. { the jump the sequence is a little bit hairy }
  703. case nodetype of
  704. ltn,gtn,lten,gten:
  705. begin
  706. { the comparisaion of the low dword have to be }
  707. { always unsigned! }
  708. emitjmp(flag_2_cond[getresflags(true)],truelabel);
  709. emitjmp(C_None,falselabel);
  710. end;
  711. equaln:
  712. begin
  713. emitjmp(C_NE,falselabel);
  714. emitjmp(C_None,truelabel);
  715. end;
  716. unequaln:
  717. begin
  718. emitjmp(C_NE,truelabel);
  719. emitjmp(C_None,falselabel);
  720. end;
  721. end;
  722. end;
  723. begin
  724. { to make it more readable, string and set (not smallset!) have their
  725. own procedures }
  726. case left.resulttype^.deftype of
  727. stringdef : begin
  728. addstring;
  729. exit;
  730. end;
  731. setdef : begin
  732. { normalsets are handled separate }
  733. if not(psetdef(left.resulttype)^.settype=smallset) then
  734. begin
  735. addset;
  736. exit;
  737. end;
  738. end;
  739. end;
  740. { defaults }
  741. unsigned:=false;
  742. is_in_dest:=false;
  743. extra_not:=false;
  744. noswap:=false;
  745. opsize:=S_L;
  746. { are we a (small)set, must be set here because the side can be
  747. swapped ! (PFV) }
  748. is_set:=(left.resulttype^.deftype=setdef);
  749. { calculate the operator which is more difficult }
  750. firstcomplex(self);
  751. { handling boolean expressions extra: }
  752. if is_boolean(left.resulttype) and
  753. is_boolean(right.resulttype) then
  754. begin
  755. if (porddef(left.resulttype)^.typ=bool8bit) or
  756. (porddef(right.resulttype)^.typ=bool8bit) then
  757. opsize:=S_B
  758. else
  759. if (porddef(left.resulttype)^.typ=bool16bit) or
  760. (porddef(right.resulttype)^.typ=bool16bit) then
  761. opsize:=S_W
  762. else
  763. opsize:=S_L;
  764. if (cs_full_boolean_eval in aktlocalswitches) or
  765. (nodetype in
  766. [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  767. begin
  768. if left.nodetype=ordconstn then
  769. swapleftright;
  770. if left.location.loc=LOC_JUMP then
  771. begin
  772. otl:=truelabel;
  773. getlabel(truelabel);
  774. ofl:=falselabel;
  775. getlabel(falselabel);
  776. end;
  777. secondpass(left);
  778. { if in flags then copy first to register, because the
  779. flags can be destroyed }
  780. case left.location.loc of
  781. LOC_FLAGS:
  782. locflags2reg(left.location,opsize);
  783. LOC_JUMP:
  784. locjump2reg(left.location,opsize, otl, ofl);
  785. end;
  786. set_location(location,left.location);
  787. pushed:=maybe_push(right.registers32,self,false);
  788. if right.location.loc=LOC_JUMP then
  789. begin
  790. otl:=truelabel;
  791. getlabel(truelabel);
  792. ofl:=falselabel;
  793. getlabel(falselabel);
  794. end;
  795. secondpass(right);
  796. if pushed then
  797. begin
  798. restore(self,false);
  799. set_location(left.location,location);
  800. end;
  801. case right.location.loc of
  802. LOC_FLAGS:
  803. locflags2reg(right.location,opsize);
  804. LOC_JUMP:
  805. locjump2reg(right.location,opsize,otl,ofl);
  806. end;
  807. goto do_normal;
  808. end;
  809. case nodetype of
  810. andn,
  811. orn : begin
  812. clear_location(location);
  813. location.loc:=LOC_JUMP;
  814. cmpop:=false;
  815. case nodetype of
  816. andn : begin
  817. otl:=truelabel;
  818. getlabel(truelabel);
  819. secondpass(left);
  820. maketojumpbool(left);
  821. emitlab(truelabel);
  822. truelabel:=otl;
  823. end;
  824. orn : begin
  825. ofl:=falselabel;
  826. getlabel(falselabel);
  827. secondpass(left);
  828. maketojumpbool(left);
  829. emitlab(falselabel);
  830. falselabel:=ofl;
  831. end;
  832. else
  833. CGMessage(type_e_mismatch);
  834. end;
  835. secondpass(right);
  836. maketojumpbool(right);
  837. end;
  838. else
  839. CGMessage(type_e_mismatch);
  840. end
  841. end
  842. else
  843. begin
  844. { in case of constant put it to the left }
  845. if (left.nodetype=ordconstn) then
  846. swapleftright;
  847. secondpass(left);
  848. { this will be complicated as
  849. a lot of code below assumes that
  850. location and left.location are the same }
  851. {$ifdef test_dest_loc}
  852. if dest_loc_known and (dest_loc_tree=p) and
  853. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  854. begin
  855. set_location(location,dest_loc);
  856. in_dest_loc:=true;
  857. is_in_dest:=true;
  858. end
  859. else
  860. {$endif test_dest_loc}
  861. set_location(location,left.location);
  862. { are too few registers free? }
  863. pushed:=maybe_push(right.registers32,self,is_64bitint(left.resulttype));
  864. secondpass(right);
  865. if pushed then
  866. begin
  867. restore(self,is_64bitint(left.resulttype));
  868. set_location(left.location,location);
  869. end;
  870. if (left.resulttype^.deftype=pointerdef) or
  871. (right.resulttype^.deftype=pointerdef) or
  872. (is_class_or_interface(right.resulttype) and is_class_or_interface(left.resulttype)) or
  873. (left.resulttype^.deftype=classrefdef) or
  874. (left.resulttype^.deftype=procvardef) or
  875. ((left.resulttype^.deftype=enumdef) and
  876. (left.resulttype^.size=4)) or
  877. ((left.resulttype^.deftype=orddef) and
  878. (porddef(left.resulttype)^.typ=s32bit)) or
  879. ((right.resulttype^.deftype=orddef) and
  880. (porddef(right.resulttype)^.typ=s32bit)) or
  881. ((left.resulttype^.deftype=orddef) and
  882. (porddef(left.resulttype)^.typ=u32bit)) or
  883. ((right.resulttype^.deftype=orddef) and
  884. (porddef(right.resulttype)^.typ=u32bit)) or
  885. { as well as small sets }
  886. is_set then
  887. begin
  888. do_normal:
  889. mboverflow:=false;
  890. cmpop:=false;
  891. unsigned := not(is_signed(left.resulttype)) or
  892. not(is_signed(right.resulttype));
  893. case nodetype of
  894. addn : begin
  895. { this is a really ugly hack!!!!!!!!!! }
  896. { this could be done later using EDI }
  897. { as it is done for subn }
  898. { instead of two registers!!!! }
  899. if is_set then
  900. begin
  901. { adding elements is not commutative }
  902. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  903. swapleftright;
  904. { are we adding set elements ? }
  905. if right.nodetype=setelementn then
  906. begin
  907. { no range support for smallsets! }
  908. if assigned(tsetelementnode(right).right) then
  909. internalerror(43244);
  910. { bts requires both elements to be registers }
  911. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  912. begin
  913. ungetiftemp(left.location.reference);
  914. del_location(left.location);
  915. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  916. hregister:=getregister32;
  917. emit_ref_reg(A_MOV,opsize,
  918. newreference(left.location.reference),hregister);
  919. clear_location(left.location);
  920. left.location.loc:=LOC_REGISTER;
  921. left.location.register:=hregister;
  922. set_location(location,left.location);
  923. end;
  924. if right.location.loc in [LOC_MEM,LOC_REFERENCE] then
  925. begin
  926. ungetiftemp(right.location.reference);
  927. del_location(right.location);
  928. hregister:=getregister32;
  929. emit_ref_reg(A_MOV,opsize,
  930. newreference(right.location.reference),hregister);
  931. clear_location(right.location);
  932. right.location.loc:=LOC_REGISTER;
  933. right.location.register:=hregister;
  934. end;
  935. op:=A_BTS;
  936. noswap:=true;
  937. end
  938. else
  939. op:=A_OR;
  940. mboverflow:=false;
  941. unsigned:=false;
  942. end
  943. else
  944. begin
  945. op:=A_ADD;
  946. mboverflow:=true;
  947. end;
  948. end;
  949. symdifn : begin
  950. { the symetric diff is only for sets }
  951. if is_set then
  952. begin
  953. op:=A_XOR;
  954. mboverflow:=false;
  955. unsigned:=false;
  956. end
  957. else
  958. CGMessage(type_e_mismatch);
  959. end;
  960. muln : begin
  961. if is_set then
  962. begin
  963. op:=A_AND;
  964. mboverflow:=false;
  965. unsigned:=false;
  966. end
  967. else
  968. begin
  969. if unsigned then
  970. op:=A_MUL
  971. else
  972. op:=A_IMUL;
  973. mboverflow:=true;
  974. end;
  975. end;
  976. subn : begin
  977. if is_set then
  978. begin
  979. op:=A_AND;
  980. mboverflow:=false;
  981. unsigned:=false;
  982. {$IfNDef NoSetConstNot}
  983. If (right.nodetype = setconstn) then
  984. right.location.reference.offset := not(right.location.reference.offset)
  985. Else
  986. {$EndIf NoNosetConstNot}
  987. extra_not:=true;
  988. end
  989. else
  990. begin
  991. op:=A_SUB;
  992. mboverflow:=true;
  993. end;
  994. end;
  995. ltn,lten,
  996. gtn,gten,
  997. equaln,unequaln : begin
  998. {$IfNDef NoSetInclusion}
  999. If is_set Then
  1000. Case nodetype of
  1001. lten,gten:
  1002. Begin
  1003. If nodetype = lten then
  1004. swapleftright;
  1005. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  1006. begin
  1007. ungetiftemp(left.location.reference);
  1008. del_reference(left.location.reference);
  1009. hregister:=getregister32;
  1010. emit_ref_reg(A_MOV,opsize,
  1011. newreference(left.location.reference),hregister);
  1012. clear_location(left.location);
  1013. left.location.loc:=LOC_REGISTER;
  1014. left.location.register:=hregister;
  1015. set_location(location,left.location);
  1016. end
  1017. else
  1018. if left.location.loc = LOC_CREGISTER Then
  1019. {save the register var in a temp register, because
  1020. its value is going to be modified}
  1021. begin
  1022. hregister := getregister32;
  1023. emit_reg_reg(A_MOV,opsize,
  1024. left.location.register,hregister);
  1025. clear_location(left.location);
  1026. left.location.loc:=LOC_REGISTER;
  1027. left.location.register:=hregister;
  1028. set_location(location,left.location);
  1029. end;
  1030. {here, left.location should be LOC_REGISTER}
  1031. If right.location.loc in [LOC_MEM,LOC_REFERENCE] Then
  1032. emit_ref_reg(A_AND,opsize,
  1033. newreference(right.location.reference),left.location.register)
  1034. Else
  1035. emit_reg_reg(A_AND,opsize,
  1036. right.location.register,left.location.register);
  1037. {warning: ugly hack ahead: we need a "jne" after the cmp, so
  1038. change the nodetype from lten/gten to equaln}
  1039. nodetype := equaln
  1040. End;
  1041. {no < or > support for sets}
  1042. ltn,gtn: CGMessage(type_e_mismatch);
  1043. End;
  1044. {$EndIf NoSetInclusion}
  1045. op:=A_CMP;
  1046. cmpop:=true;
  1047. end;
  1048. xorn : op:=A_XOR;
  1049. orn : op:=A_OR;
  1050. andn : op:=A_AND;
  1051. else
  1052. CGMessage(type_e_mismatch);
  1053. end;
  1054. { filter MUL, which requires special handling }
  1055. if op=A_MUL then
  1056. begin
  1057. popeax:=false;
  1058. popedx:=false;
  1059. { here you need to free the symbol first }
  1060. { left.location and right.location must }
  1061. { only be freed when they are really released, }
  1062. { because the optimizer NEEDS correct regalloc }
  1063. { info!!! (JM) }
  1064. clear_location(location);
  1065. { the location.register will be filled in later (JM) }
  1066. location.loc:=LOC_REGISTER;
  1067. {$IfNDef NoShlMul}
  1068. if right.nodetype=ordconstn then
  1069. swapleftright;
  1070. If (left.nodetype = ordconstn) and
  1071. ispowerof2(tordconstnode(left).value, power) and
  1072. not(cs_check_overflow in aktlocalswitches) then
  1073. Begin
  1074. { This release will be moved after the next }
  1075. { instruction by the optimizer. No need to }
  1076. { release left.location, since it's a }
  1077. { constant (JM) }
  1078. release_loc(right.location);
  1079. location.register := getregister32;
  1080. emitloadord2reg(right.location,u32bitdef,location.register,false);
  1081. emit_const_reg(A_SHL,S_L,power,location.register)
  1082. End
  1083. Else
  1084. Begin
  1085. {$EndIf NoShlMul}
  1086. regstopush := $ff;
  1087. remove_non_regvars_from_loc(right.location,regstopush);
  1088. remove_non_regvars_from_loc(left.location,regstopush);
  1089. { now, regstopush does NOT contain EAX and/or EDX if they are }
  1090. { used in either the left or the right location, excepts if }
  1091. {they are regvars. It DOES contain them if they are used in }
  1092. { another location (JM) }
  1093. if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
  1094. begin
  1095. emit_reg(A_PUSH,S_L,R_EAX);
  1096. popeax:=true;
  1097. end;
  1098. if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
  1099. begin
  1100. emit_reg(A_PUSH,S_L,R_EDX);
  1101. popedx:=true;
  1102. end;
  1103. { left.location can be R_EAX !!! }
  1104. getexplicitregister32(R_EDI);
  1105. { load the left value }
  1106. emitloadord2reg(left.location,u32bitdef,R_EDI,true);
  1107. release_loc(left.location);
  1108. { allocate EAX }
  1109. if R_EAX in unused then
  1110. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1111. { load he right value }
  1112. emitloadord2reg(right.location,u32bitdef,R_EAX,true);
  1113. release_loc(right.location);
  1114. { allocate EAX if it isn't yet allocated (JM) }
  1115. if (R_EAX in unused) then
  1116. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  1117. { also allocate EDX, since it is also modified by }
  1118. { a mul (JM) }
  1119. if R_EDX in unused then
  1120. exprasmList.concat(Tairegalloc.Alloc(R_EDX));
  1121. emit_reg(A_MUL,S_L,R_EDI);
  1122. ungetregister32(R_EDI);
  1123. if R_EDX in unused then
  1124. exprasmList.concat(Tairegalloc.DeAlloc(R_EDX));
  1125. if R_EAX in unused then
  1126. exprasmList.concat(Tairegalloc.DeAlloc(R_EAX));
  1127. location.register := getregister32;
  1128. emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
  1129. if popedx then
  1130. emit_reg(A_POP,S_L,R_EDX);
  1131. if popeax then
  1132. emit_reg(A_POP,S_L,R_EAX);
  1133. {$IfNDef NoShlMul}
  1134. End;
  1135. {$endif NoShlMul}
  1136. SetResultLocation(false,true);
  1137. exit;
  1138. end;
  1139. { Convert flags to register first }
  1140. if (left.location.loc=LOC_FLAGS) then
  1141. locflags2reg(left.location,opsize);
  1142. if (right.location.loc=LOC_FLAGS) then
  1143. locflags2reg(right.location,opsize);
  1144. { left and right no register? }
  1145. { then one must be demanded }
  1146. if (left.location.loc<>LOC_REGISTER) and
  1147. (right.location.loc<>LOC_REGISTER) then
  1148. begin
  1149. { register variable ? }
  1150. if (left.location.loc=LOC_CREGISTER) then
  1151. begin
  1152. { it is OK if this is the destination }
  1153. if is_in_dest then
  1154. begin
  1155. hregister:=location.register;
  1156. emit_reg_reg(A_MOV,opsize,left.location.register,
  1157. hregister);
  1158. end
  1159. else
  1160. if cmpop then
  1161. begin
  1162. { do not disturb the register }
  1163. hregister:=location.register;
  1164. end
  1165. else
  1166. begin
  1167. case opsize of
  1168. S_L : hregister:=getregister32;
  1169. S_B : hregister:=reg32toreg8(getregister32);
  1170. end;
  1171. emit_reg_reg(A_MOV,opsize,left.location.register,
  1172. hregister);
  1173. end
  1174. end
  1175. else
  1176. begin
  1177. ungetiftemp(left.location.reference);
  1178. del_reference(left.location.reference);
  1179. if is_in_dest then
  1180. begin
  1181. hregister:=location.register;
  1182. emit_ref_reg(A_MOV,opsize,
  1183. newreference(left.location.reference),hregister);
  1184. end
  1185. else
  1186. begin
  1187. { first give free, then demand new register }
  1188. case opsize of
  1189. S_L : hregister:=getregister32;
  1190. S_W : hregister:=reg32toreg16(getregister32);
  1191. S_B : hregister:=reg32toreg8(getregister32);
  1192. end;
  1193. emit_ref_reg(A_MOV,opsize,
  1194. newreference(left.location.reference),hregister);
  1195. end;
  1196. end;
  1197. clear_location(location);
  1198. location.loc:=LOC_REGISTER;
  1199. location.register:=hregister;
  1200. end
  1201. else
  1202. { if on the right the register then swap }
  1203. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1204. begin
  1205. swap_location(location,right.location);
  1206. { newly swapped also set swapped flag }
  1207. toggleflag(nf_swaped);
  1208. end;
  1209. { at this point, location.loc should be LOC_REGISTER }
  1210. { and location.register should be a valid register }
  1211. { containing the left result }
  1212. if right.location.loc<>LOC_REGISTER then
  1213. begin
  1214. if (nodetype=subn) and (nf_swaped in flags) then
  1215. begin
  1216. if right.location.loc=LOC_CREGISTER then
  1217. begin
  1218. if extra_not then
  1219. emit_reg(A_NOT,opsize,location.register);
  1220. getexplicitregister32(R_EDI);
  1221. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1222. emit_reg_reg(op,opsize,location.register,R_EDI);
  1223. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1224. ungetregister32(R_EDI);
  1225. end
  1226. else
  1227. begin
  1228. if extra_not then
  1229. emit_reg(A_NOT,opsize,location.register);
  1230. getexplicitregister32(R_EDI);
  1231. emit_ref_reg(A_MOV,opsize,
  1232. newreference(right.location.reference),R_EDI);
  1233. emit_reg_reg(op,opsize,location.register,R_EDI);
  1234. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1235. ungetregister32(R_EDI);
  1236. ungetiftemp(right.location.reference);
  1237. del_reference(right.location.reference);
  1238. end;
  1239. end
  1240. else
  1241. begin
  1242. if (right.nodetype=ordconstn) and
  1243. (op=A_CMP) and
  1244. (tordconstnode(right).value=0) then
  1245. begin
  1246. emit_reg_reg(A_TEST,opsize,location.register,
  1247. location.register);
  1248. end
  1249. else if (right.nodetype=ordconstn) and
  1250. (op=A_ADD) and
  1251. (tordconstnode(right).value=1) and
  1252. not(cs_check_overflow in aktlocalswitches) then
  1253. begin
  1254. emit_reg(A_INC,opsize,
  1255. location.register);
  1256. end
  1257. else if (right.nodetype=ordconstn) and
  1258. (op=A_SUB) and
  1259. (tordconstnode(right).value=1) and
  1260. not(cs_check_overflow in aktlocalswitches) then
  1261. begin
  1262. emit_reg(A_DEC,opsize,
  1263. location.register);
  1264. end
  1265. else if (right.nodetype=ordconstn) and
  1266. (op=A_IMUL) and
  1267. (ispowerof2(tordconstnode(right).value,power)) and
  1268. not(cs_check_overflow in aktlocalswitches) then
  1269. begin
  1270. emit_const_reg(A_SHL,opsize,power,
  1271. location.register);
  1272. end
  1273. else
  1274. begin
  1275. if (right.location.loc=LOC_CREGISTER) then
  1276. begin
  1277. if extra_not then
  1278. begin
  1279. getexplicitregister32(R_EDI);
  1280. emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
  1281. emit_reg(A_NOT,S_L,R_EDI);
  1282. emit_reg_reg(A_AND,S_L,R_EDI,
  1283. location.register);
  1284. ungetregister32(R_EDI);
  1285. end
  1286. else
  1287. begin
  1288. emit_reg_reg(op,opsize,right.location.register,
  1289. location.register);
  1290. end;
  1291. end
  1292. else
  1293. begin
  1294. if extra_not then
  1295. begin
  1296. getexplicitregister32(R_EDI);
  1297. emit_ref_reg(A_MOV,S_L,newreference(
  1298. right.location.reference),R_EDI);
  1299. emit_reg(A_NOT,S_L,R_EDI);
  1300. emit_reg_reg(A_AND,S_L,R_EDI,
  1301. location.register);
  1302. ungetregister32(R_EDI);
  1303. end
  1304. else
  1305. begin
  1306. emit_ref_reg(op,opsize,newreference(
  1307. right.location.reference),location.register);
  1308. end;
  1309. ungetiftemp(right.location.reference);
  1310. del_reference(right.location.reference);
  1311. end;
  1312. end;
  1313. end;
  1314. end
  1315. else
  1316. begin
  1317. { when swapped another result register }
  1318. if (nodetype=subn) and (nf_swaped in flags) then
  1319. begin
  1320. if extra_not then
  1321. emit_reg(A_NOT,S_L,location.register);
  1322. emit_reg_reg(op,opsize,
  1323. location.register,right.location.register);
  1324. swap_location(location,right.location);
  1325. { newly swapped also set swapped flag }
  1326. { just to maintain ordering }
  1327. toggleflag(nf_swaped);
  1328. end
  1329. else
  1330. begin
  1331. if extra_not then
  1332. emit_reg(A_NOT,S_L,right.location.register);
  1333. emit_reg_reg(op,opsize,
  1334. right.location.register,
  1335. location.register);
  1336. end;
  1337. case opsize of
  1338. S_L : ungetregister32(right.location.register);
  1339. S_B : ungetregister32(reg8toreg32(right.location.register));
  1340. end;
  1341. end;
  1342. if cmpop then
  1343. case opsize of
  1344. S_L : ungetregister32(location.register);
  1345. S_B : ungetregister32(reg8toreg32(location.register));
  1346. end;
  1347. { only in case of overflow operations }
  1348. { produce overflow code }
  1349. { we must put it here directly, because sign of operation }
  1350. { is in unsigned VAR!! }
  1351. if mboverflow then
  1352. begin
  1353. if cs_check_overflow in aktlocalswitches then
  1354. begin
  1355. getlabel(hl4);
  1356. if unsigned then
  1357. emitjmp(C_NB,hl4)
  1358. else
  1359. emitjmp(C_NO,hl4);
  1360. emitcall('FPC_OVERFLOW');
  1361. emitlab(hl4);
  1362. end;
  1363. end;
  1364. end
  1365. else
  1366. { Char type }
  1367. if ((left.resulttype^.deftype=orddef) and
  1368. (porddef(left.resulttype)^.typ=uchar)) or
  1369. { enumeration type 16 bit }
  1370. ((left.resulttype^.deftype=enumdef) and
  1371. (left.resulttype^.size=1)) then
  1372. begin
  1373. case nodetype of
  1374. ltn,lten,gtn,gten,
  1375. equaln,unequaln :
  1376. cmpop:=true;
  1377. else CGMessage(type_e_mismatch);
  1378. end;
  1379. unsigned:=true;
  1380. { left and right no register? }
  1381. { the one must be demanded }
  1382. if (location.loc<>LOC_REGISTER) and
  1383. (right.location.loc<>LOC_REGISTER) then
  1384. begin
  1385. if location.loc=LOC_CREGISTER then
  1386. begin
  1387. if cmpop then
  1388. { do not disturb register }
  1389. hregister:=location.register
  1390. else
  1391. begin
  1392. hregister:=reg32toreg8(getregister32);
  1393. emit_reg_reg(A_MOV,S_B,location.register,
  1394. hregister);
  1395. end;
  1396. end
  1397. else
  1398. begin
  1399. del_reference(location.reference);
  1400. { first give free then demand new register }
  1401. hregister:=reg32toreg8(getregister32);
  1402. emit_ref_reg(A_MOV,S_B,newreference(location.reference),
  1403. hregister);
  1404. end;
  1405. clear_location(location);
  1406. location.loc:=LOC_REGISTER;
  1407. location.register:=hregister;
  1408. end;
  1409. { now p always a register }
  1410. if (right.location.loc=LOC_REGISTER) and
  1411. (location.loc<>LOC_REGISTER) then
  1412. begin
  1413. swap_location(location,right.location);
  1414. { newly swapped also set swapped flag }
  1415. toggleflag(nf_swaped);
  1416. end;
  1417. if right.location.loc<>LOC_REGISTER then
  1418. begin
  1419. if right.location.loc=LOC_CREGISTER then
  1420. begin
  1421. emit_reg_reg(A_CMP,S_B,
  1422. right.location.register,location.register);
  1423. end
  1424. else
  1425. begin
  1426. emit_ref_reg(A_CMP,S_B,newreference(
  1427. right.location.reference),location.register);
  1428. del_reference(right.location.reference);
  1429. end;
  1430. end
  1431. else
  1432. begin
  1433. emit_reg_reg(A_CMP,S_B,right.location.register,
  1434. location.register);
  1435. ungetregister32(reg8toreg32(right.location.register));
  1436. end;
  1437. ungetregister32(reg8toreg32(location.register));
  1438. end
  1439. else
  1440. { 16 bit enumeration type }
  1441. if ((left.resulttype^.deftype=enumdef) and
  1442. (left.resulttype^.size=2)) then
  1443. begin
  1444. case nodetype of
  1445. ltn,lten,gtn,gten,
  1446. equaln,unequaln :
  1447. cmpop:=true;
  1448. else CGMessage(type_e_mismatch);
  1449. end;
  1450. unsigned:=true;
  1451. { left and right no register? }
  1452. { the one must be demanded }
  1453. if (location.loc<>LOC_REGISTER) and
  1454. (right.location.loc<>LOC_REGISTER) then
  1455. begin
  1456. if location.loc=LOC_CREGISTER then
  1457. begin
  1458. if cmpop then
  1459. { do not disturb register }
  1460. hregister:=location.register
  1461. else
  1462. begin
  1463. hregister:=reg32toreg16(getregister32);
  1464. emit_reg_reg(A_MOV,S_W,location.register,
  1465. hregister);
  1466. end;
  1467. end
  1468. else
  1469. begin
  1470. del_reference(location.reference);
  1471. { first give free then demand new register }
  1472. hregister:=reg32toreg16(getregister32);
  1473. emit_ref_reg(A_MOV,S_W,newreference(location.reference),
  1474. hregister);
  1475. end;
  1476. clear_location(location);
  1477. location.loc:=LOC_REGISTER;
  1478. location.register:=hregister;
  1479. end;
  1480. { now p always a register }
  1481. if (right.location.loc=LOC_REGISTER) and
  1482. (location.loc<>LOC_REGISTER) then
  1483. begin
  1484. swap_location(location,right.location);
  1485. { newly swapped also set swapped flag }
  1486. toggleflag(nf_swaped);
  1487. end;
  1488. if right.location.loc<>LOC_REGISTER then
  1489. begin
  1490. if right.location.loc=LOC_CREGISTER then
  1491. begin
  1492. emit_reg_reg(A_CMP,S_W,
  1493. right.location.register,location.register);
  1494. end
  1495. else
  1496. begin
  1497. emit_ref_reg(A_CMP,S_W,newreference(
  1498. right.location.reference),location.register);
  1499. del_reference(right.location.reference);
  1500. end;
  1501. end
  1502. else
  1503. begin
  1504. emit_reg_reg(A_CMP,S_W,right.location.register,
  1505. location.register);
  1506. ungetregister32(reg16toreg32(right.location.register));
  1507. end;
  1508. ungetregister32(reg16toreg32(location.register));
  1509. end
  1510. else
  1511. { 64 bit types }
  1512. if is_64bitint(left.resulttype) then
  1513. begin
  1514. mboverflow:=false;
  1515. cmpop:=false;
  1516. unsigned:=((left.resulttype^.deftype=orddef) and
  1517. (porddef(left.resulttype)^.typ=u64bit)) or
  1518. ((right.resulttype^.deftype=orddef) and
  1519. (porddef(right.resulttype)^.typ=u64bit));
  1520. case nodetype of
  1521. addn : begin
  1522. begin
  1523. op:=A_ADD;
  1524. op2:=A_ADC;
  1525. mboverflow:=true;
  1526. end;
  1527. end;
  1528. subn : begin
  1529. op:=A_SUB;
  1530. op2:=A_SBB;
  1531. mboverflow:=true;
  1532. end;
  1533. ltn,lten,
  1534. gtn,gten,
  1535. equaln,unequaln:
  1536. begin
  1537. op:=A_CMP;
  1538. op2:=A_CMP;
  1539. cmpop:=true;
  1540. end;
  1541. xorn:
  1542. begin
  1543. op:=A_XOR;
  1544. op2:=A_XOR;
  1545. end;
  1546. orn:
  1547. begin
  1548. op:=A_OR;
  1549. op2:=A_OR;
  1550. end;
  1551. andn:
  1552. begin
  1553. op:=A_AND;
  1554. op2:=A_AND;
  1555. end;
  1556. muln:
  1557. ;
  1558. else
  1559. CGMessage(type_e_mismatch);
  1560. end;
  1561. if nodetype=muln then
  1562. begin
  1563. { save lcoation, because we change it now }
  1564. set_location(hloc,location);
  1565. release_qword_loc(location);
  1566. release_qword_loc(right.location);
  1567. location.registerlow:=getexplicitregister32(R_EAX);
  1568. location.registerhigh:=getexplicitregister32(R_EDX);
  1569. pushusedregisters(pushedreg,$ff
  1570. and not($80 shr byte(location.registerlow))
  1571. and not($80 shr byte(location.registerhigh)));
  1572. if cs_check_overflow in aktlocalswitches then
  1573. push_int(1)
  1574. else
  1575. push_int(0);
  1576. { the left operand is in hloc, because the
  1577. location of left is location but location
  1578. is already destroyed
  1579. }
  1580. emit_pushq_loc(hloc);
  1581. clear_location(hloc);
  1582. emit_pushq_loc(right.location);
  1583. saveregvars($ff);
  1584. if porddef(resulttype)^.typ=u64bit then
  1585. emitcall('FPC_MUL_QWORD')
  1586. else
  1587. emitcall('FPC_MUL_INT64');
  1588. emit_reg_reg(A_MOV,S_L,R_EAX,location.registerlow);
  1589. emit_reg_reg(A_MOV,S_L,R_EDX,location.registerhigh);
  1590. popusedregisters(pushedreg);
  1591. location.loc:=LOC_REGISTER;
  1592. end
  1593. else
  1594. begin
  1595. { left and right no register? }
  1596. { then one must be demanded }
  1597. if (left.location.loc<>LOC_REGISTER) and
  1598. (right.location.loc<>LOC_REGISTER) then
  1599. begin
  1600. { register variable ? }
  1601. if (left.location.loc=LOC_CREGISTER) then
  1602. begin
  1603. { it is OK if this is the destination }
  1604. if is_in_dest then
  1605. begin
  1606. hregister:=location.registerlow;
  1607. hregister2:=location.registerhigh;
  1608. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1609. hregister);
  1610. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1611. hregister2);
  1612. end
  1613. else
  1614. if cmpop then
  1615. begin
  1616. { do not disturb the register }
  1617. hregister:=location.registerlow;
  1618. hregister2:=location.registerhigh;
  1619. end
  1620. else
  1621. begin
  1622. hregister:=getregister32;
  1623. hregister2:=getregister32;
  1624. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1625. hregister);
  1626. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
  1627. hregister2);
  1628. end
  1629. end
  1630. else
  1631. begin
  1632. ungetiftemp(left.location.reference);
  1633. del_reference(left.location.reference);
  1634. if is_in_dest then
  1635. begin
  1636. hregister:=location.registerlow;
  1637. hregister2:=location.registerhigh;
  1638. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1639. end
  1640. else
  1641. begin
  1642. hregister:=getregister32;
  1643. hregister2:=getregister32;
  1644. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1645. end;
  1646. end;
  1647. clear_location(location);
  1648. location.loc:=LOC_REGISTER;
  1649. location.registerlow:=hregister;
  1650. location.registerhigh:=hregister2;
  1651. end
  1652. else
  1653. { if on the right the register then swap }
  1654. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1655. begin
  1656. swap_location(location,right.location);
  1657. { newly swapped also set swapped flag }
  1658. toggleflag(nf_swaped);
  1659. end;
  1660. { at this point, location.loc should be LOC_REGISTER }
  1661. { and location.register should be a valid register }
  1662. { containing the left result }
  1663. if right.location.loc<>LOC_REGISTER then
  1664. begin
  1665. if (nodetype=subn) and (nf_swaped in flags) then
  1666. begin
  1667. if right.location.loc=LOC_CREGISTER then
  1668. begin
  1669. getexplicitregister32(R_EDI);
  1670. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1671. emit_reg_reg(op,opsize,location.register,R_EDI);
  1672. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1673. ungetregister32(R_EDI);
  1674. getexplicitregister32(R_EDI);
  1675. emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
  1676. { the carry flag is still ok }
  1677. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1678. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
  1679. ungetregister32(R_EDI);
  1680. end
  1681. else
  1682. begin
  1683. getexplicitregister32(R_EDI);
  1684. emit_ref_reg(A_MOV,opsize,
  1685. newreference(right.location.reference),R_EDI);
  1686. emit_reg_reg(op,opsize,location.registerlow,R_EDI);
  1687. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
  1688. ungetregister32(R_EDI);
  1689. getexplicitregister32(R_EDI);
  1690. hr:=newreference(right.location.reference);
  1691. inc(hr^.offset,4);
  1692. emit_ref_reg(A_MOV,opsize,
  1693. hr,R_EDI);
  1694. { here the carry flag is still preserved }
  1695. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1696. emit_reg_reg(A_MOV,opsize,R_EDI,
  1697. location.registerhigh);
  1698. ungetregister32(R_EDI);
  1699. ungetiftemp(right.location.reference);
  1700. del_reference(right.location.reference);
  1701. end;
  1702. end
  1703. else if cmpop then
  1704. begin
  1705. if (right.location.loc=LOC_CREGISTER) then
  1706. begin
  1707. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,
  1708. location.registerhigh);
  1709. firstjmp64bitcmp;
  1710. emit_reg_reg(A_CMP,S_L,right.location.registerlow,
  1711. location.registerlow);
  1712. secondjmp64bitcmp;
  1713. end
  1714. else
  1715. begin
  1716. hr:=newreference(right.location.reference);
  1717. inc(hr^.offset,4);
  1718. emit_ref_reg(A_CMP,S_L,
  1719. hr,location.registerhigh);
  1720. firstjmp64bitcmp;
  1721. emit_ref_reg(A_CMP,S_L,newreference(
  1722. right.location.reference),location.registerlow);
  1723. secondjmp64bitcmp;
  1724. emitjmp(C_None,falselabel);
  1725. ungetiftemp(right.location.reference);
  1726. del_reference(right.location.reference);
  1727. end;
  1728. end
  1729. else
  1730. begin
  1731. {
  1732. if (right.nodetype=ordconstn) and
  1733. (op=A_CMP) and
  1734. (right.value=0) then
  1735. begin
  1736. emit_reg_reg(A_TEST,opsize,location.register,
  1737. location.register);
  1738. end
  1739. else if (right.nodetype=ordconstn) and
  1740. (op=A_IMUL) and
  1741. (ispowerof2(right.value,power)) then
  1742. begin
  1743. emit_const_reg(A_SHL,opsize,power,
  1744. location.register);
  1745. end
  1746. else
  1747. }
  1748. begin
  1749. if (right.location.loc=LOC_CREGISTER) then
  1750. begin
  1751. emit_reg_reg(op,S_L,right.location.registerlow,
  1752. location.registerlow);
  1753. emit_reg_reg(op2,S_L,right.location.registerhigh,
  1754. location.registerhigh);
  1755. end
  1756. else
  1757. begin
  1758. emit_ref_reg(op,S_L,newreference(
  1759. right.location.reference),location.registerlow);
  1760. hr:=newreference(right.location.reference);
  1761. inc(hr^.offset,4);
  1762. emit_ref_reg(op2,S_L,
  1763. hr,location.registerhigh);
  1764. ungetiftemp(right.location.reference);
  1765. del_reference(right.location.reference);
  1766. end;
  1767. end;
  1768. end;
  1769. end
  1770. else
  1771. begin
  1772. { when swapped another result register }
  1773. if (nodetype=subn) and (nf_swaped in flags) then
  1774. begin
  1775. emit_reg_reg(op,S_L,
  1776. location.registerlow,
  1777. right.location.registerlow);
  1778. emit_reg_reg(op2,S_L,
  1779. location.registerhigh,
  1780. right.location.registerhigh);
  1781. swap_location(location,right.location);
  1782. { newly swapped also set swapped flag }
  1783. { just to maintain ordering }
  1784. toggleflag(nf_swaped);
  1785. end
  1786. else if cmpop then
  1787. begin
  1788. emit_reg_reg(A_CMP,S_L,
  1789. right.location.registerhigh,
  1790. location.registerhigh);
  1791. firstjmp64bitcmp;
  1792. emit_reg_reg(A_CMP,S_L,
  1793. right.location.registerlow,
  1794. location.registerlow);
  1795. secondjmp64bitcmp;
  1796. end
  1797. else
  1798. begin
  1799. emit_reg_reg(op,S_L,
  1800. right.location.registerlow,
  1801. location.registerlow);
  1802. emit_reg_reg(op2,S_L,
  1803. right.location.registerhigh,
  1804. location.registerhigh);
  1805. end;
  1806. ungetregister32(right.location.registerlow);
  1807. ungetregister32(right.location.registerhigh);
  1808. end;
  1809. if cmpop then
  1810. begin
  1811. ungetregister32(location.registerlow);
  1812. ungetregister32(location.registerhigh);
  1813. end;
  1814. { only in case of overflow operations }
  1815. { produce overflow code }
  1816. { we must put it here directly, because sign of operation }
  1817. { is in unsigned VAR!! }
  1818. if mboverflow then
  1819. begin
  1820. if cs_check_overflow in aktlocalswitches then
  1821. begin
  1822. getlabel(hl4);
  1823. if unsigned then
  1824. emitjmp(C_NB,hl4)
  1825. else
  1826. emitjmp(C_NO,hl4);
  1827. emitcall('FPC_OVERFLOW');
  1828. emitlab(hl4);
  1829. end;
  1830. end;
  1831. { we have LOC_JUMP as result }
  1832. if cmpop then
  1833. begin
  1834. clear_location(location);
  1835. location.loc:=LOC_JUMP;
  1836. cmpop:=false;
  1837. end;
  1838. end;
  1839. end
  1840. else
  1841. { Floating point }
  1842. if (left.resulttype^.deftype=floatdef) and
  1843. (pfloatdef(left.resulttype)^.typ<>f32bit) then
  1844. begin
  1845. { real constants to the right, but only if it
  1846. isn't on the FPU stack, i.e. 1.0 or 0.0! }
  1847. if (left.nodetype=realconstn) and
  1848. (left.location.loc<>LOC_FPU) then
  1849. swapleftright;
  1850. cmpop:=false;
  1851. case nodetype of
  1852. addn : op:=A_FADDP;
  1853. muln : op:=A_FMULP;
  1854. subn : op:=A_FSUBP;
  1855. slashn : op:=A_FDIVP;
  1856. ltn,lten,gtn,gten,
  1857. equaln,unequaln : begin
  1858. op:=A_FCOMPP;
  1859. cmpop:=true;
  1860. end;
  1861. else CGMessage(type_e_mismatch);
  1862. end;
  1863. if (right.location.loc<>LOC_FPU) then
  1864. begin
  1865. if right.location.loc=LOC_CFPUREGISTER then
  1866. begin
  1867. emit_reg( A_FLD,S_NO,
  1868. correct_fpuregister(right.location.register,fpuvaroffset));
  1869. inc(fpuvaroffset);
  1870. end
  1871. else
  1872. floatload(pfloatdef(right.resulttype)^.typ,right.location.reference);
  1873. if (left.location.loc<>LOC_FPU) then
  1874. begin
  1875. if left.location.loc=LOC_CFPUREGISTER then
  1876. begin
  1877. emit_reg( A_FLD,S_NO,
  1878. correct_fpuregister(left.location.register,fpuvaroffset));
  1879. inc(fpuvaroffset);
  1880. end
  1881. else
  1882. floatload(pfloatdef(left.resulttype)^.typ,left.location.reference)
  1883. end
  1884. { left was on the stack => swap }
  1885. else
  1886. toggleflag(nf_swaped);
  1887. { releases the right reference }
  1888. del_reference(right.location.reference);
  1889. end
  1890. { the nominator in st0 }
  1891. else if (left.location.loc<>LOC_FPU) then
  1892. begin
  1893. if left.location.loc=LOC_CFPUREGISTER then
  1894. begin
  1895. emit_reg( A_FLD,S_NO,
  1896. correct_fpuregister(left.location.register,fpuvaroffset));
  1897. inc(fpuvaroffset);
  1898. end
  1899. else
  1900. floatload(pfloatdef(left.resulttype)^.typ,left.location.reference)
  1901. end
  1902. { fpu operands are always in the wrong order on the stack }
  1903. else
  1904. toggleflag(nf_swaped);
  1905. { releases the left reference }
  1906. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1907. del_reference(left.location.reference);
  1908. { if we swaped the tree nodes, then use the reverse operator }
  1909. if nf_swaped in flags then
  1910. begin
  1911. if (nodetype=slashn) then
  1912. op:=A_FDIVRP
  1913. else if (nodetype=subn) then
  1914. op:=A_FSUBRP;
  1915. end;
  1916. { to avoid the pentium bug
  1917. if (op=FDIVP) and (opt_processors=pentium) then
  1918. emitcall('EMUL_FDIVP')
  1919. else
  1920. }
  1921. { the Intel assemblers want operands }
  1922. if op<>A_FCOMPP then
  1923. begin
  1924. emit_reg_reg(op,S_NO,R_ST,R_ST1);
  1925. dec(fpuvaroffset);
  1926. end
  1927. else
  1928. begin
  1929. emit_none(op,S_NO);
  1930. dec(fpuvaroffset,2);
  1931. end;
  1932. { on comparison load flags }
  1933. if cmpop then
  1934. begin
  1935. if not(R_EAX in unused) then
  1936. begin
  1937. getexplicitregister32(R_EDI);
  1938. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1939. end;
  1940. emit_reg(A_FNSTSW,S_NO,R_AX);
  1941. emit_none(A_SAHF,S_NO);
  1942. if not(R_EAX in unused) then
  1943. begin
  1944. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1945. ungetregister32(R_EDI);
  1946. end;
  1947. if nf_swaped in flags then
  1948. begin
  1949. case nodetype of
  1950. equaln : resflags:=F_E;
  1951. unequaln : resflags:=F_NE;
  1952. ltn : resflags:=F_A;
  1953. lten : resflags:=F_AE;
  1954. gtn : resflags:=F_B;
  1955. gten : resflags:=F_BE;
  1956. end;
  1957. end
  1958. else
  1959. begin
  1960. case nodetype of
  1961. equaln : resflags:=F_E;
  1962. unequaln : resflags:=F_NE;
  1963. ltn : resflags:=F_B;
  1964. lten : resflags:=F_BE;
  1965. gtn : resflags:=F_A;
  1966. gten : resflags:=F_AE;
  1967. end;
  1968. end;
  1969. clear_location(location);
  1970. location.loc:=LOC_FLAGS;
  1971. location.resflags:=resflags;
  1972. cmpop:=false;
  1973. end
  1974. else
  1975. begin
  1976. clear_location(location);
  1977. location.loc:=LOC_FPU;
  1978. end;
  1979. end
  1980. {$ifdef SUPPORT_MMX}
  1981. else
  1982. { MMX Arrays }
  1983. if is_mmx_able_array(left.resulttype) then
  1984. begin
  1985. cmpop:=false;
  1986. mmxbase:=mmx_type(left.resulttype);
  1987. case nodetype of
  1988. addn : begin
  1989. if (cs_mmx_saturation in aktlocalswitches) then
  1990. begin
  1991. case mmxbase of
  1992. mmxs8bit:
  1993. op:=A_PADDSB;
  1994. mmxu8bit:
  1995. op:=A_PADDUSB;
  1996. mmxs16bit,mmxfixed16:
  1997. op:=A_PADDSB;
  1998. mmxu16bit:
  1999. op:=A_PADDUSW;
  2000. end;
  2001. end
  2002. else
  2003. begin
  2004. case mmxbase of
  2005. mmxs8bit,mmxu8bit:
  2006. op:=A_PADDB;
  2007. mmxs16bit,mmxu16bit,mmxfixed16:
  2008. op:=A_PADDW;
  2009. mmxs32bit,mmxu32bit:
  2010. op:=A_PADDD;
  2011. end;
  2012. end;
  2013. end;
  2014. muln : begin
  2015. case mmxbase of
  2016. mmxs16bit,mmxu16bit:
  2017. op:=A_PMULLW;
  2018. mmxfixed16:
  2019. op:=A_PMULHW;
  2020. end;
  2021. end;
  2022. subn : begin
  2023. if (cs_mmx_saturation in aktlocalswitches) then
  2024. begin
  2025. case mmxbase of
  2026. mmxs8bit:
  2027. op:=A_PSUBSB;
  2028. mmxu8bit:
  2029. op:=A_PSUBUSB;
  2030. mmxs16bit,mmxfixed16:
  2031. op:=A_PSUBSB;
  2032. mmxu16bit:
  2033. op:=A_PSUBUSW;
  2034. end;
  2035. end
  2036. else
  2037. begin
  2038. case mmxbase of
  2039. mmxs8bit,mmxu8bit:
  2040. op:=A_PSUBB;
  2041. mmxs16bit,mmxu16bit,mmxfixed16:
  2042. op:=A_PSUBW;
  2043. mmxs32bit,mmxu32bit:
  2044. op:=A_PSUBD;
  2045. end;
  2046. end;
  2047. end;
  2048. {
  2049. ltn,lten,gtn,gten,
  2050. equaln,unequaln :
  2051. begin
  2052. op:=A_CMP;
  2053. cmpop:=true;
  2054. end;
  2055. }
  2056. xorn:
  2057. op:=A_PXOR;
  2058. orn:
  2059. op:=A_POR;
  2060. andn:
  2061. op:=A_PAND;
  2062. else CGMessage(type_e_mismatch);
  2063. end;
  2064. { left and right no register? }
  2065. { then one must be demanded }
  2066. if (left.location.loc<>LOC_MMXREGISTER) and
  2067. (right.location.loc<>LOC_MMXREGISTER) then
  2068. begin
  2069. { register variable ? }
  2070. if (left.location.loc=LOC_CMMXREGISTER) then
  2071. begin
  2072. { it is OK if this is the destination }
  2073. if is_in_dest then
  2074. begin
  2075. hregister:=location.register;
  2076. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2077. hregister);
  2078. end
  2079. else
  2080. begin
  2081. hregister:=getregistermmx;
  2082. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2083. hregister);
  2084. end
  2085. end
  2086. else
  2087. begin
  2088. del_reference(left.location.reference);
  2089. if is_in_dest then
  2090. begin
  2091. hregister:=location.register;
  2092. emit_ref_reg(A_MOVQ,S_NO,
  2093. newreference(left.location.reference),hregister);
  2094. end
  2095. else
  2096. begin
  2097. hregister:=getregistermmx;
  2098. emit_ref_reg(A_MOVQ,S_NO,
  2099. newreference(left.location.reference),hregister);
  2100. end;
  2101. end;
  2102. clear_location(location);
  2103. location.loc:=LOC_MMXREGISTER;
  2104. location.register:=hregister;
  2105. end
  2106. else
  2107. { if on the right the register then swap }
  2108. if (right.location.loc=LOC_MMXREGISTER) then
  2109. begin
  2110. swap_location(location,right.location);
  2111. { newly swapped also set swapped flag }
  2112. toggleflag(nf_swaped);
  2113. end;
  2114. { at this point, location.loc should be LOC_MMXREGISTER }
  2115. { and location.register should be a valid register }
  2116. { containing the left result }
  2117. if right.location.loc<>LOC_MMXREGISTER then
  2118. begin
  2119. if (nodetype=subn) and (nf_swaped in flags) then
  2120. begin
  2121. if right.location.loc=LOC_CMMXREGISTER then
  2122. begin
  2123. emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
  2124. emit_reg_reg(op,S_NO,location.register,R_MM0);
  2125. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  2126. end
  2127. else
  2128. begin
  2129. emit_ref_reg(A_MOVQ,S_NO,
  2130. newreference(right.location.reference),R_MM7);
  2131. emit_reg_reg(op,S_NO,location.register,
  2132. R_MM7);
  2133. emit_reg_reg(A_MOVQ,S_NO,
  2134. R_MM7,location.register);
  2135. del_reference(right.location.reference);
  2136. end;
  2137. end
  2138. else
  2139. begin
  2140. if (right.location.loc=LOC_CREGISTER) then
  2141. begin
  2142. emit_reg_reg(op,S_NO,right.location.register,
  2143. location.register);
  2144. end
  2145. else
  2146. begin
  2147. emit_ref_reg(op,S_NO,newreference(
  2148. right.location.reference),location.register);
  2149. del_reference(right.location.reference);
  2150. end;
  2151. end;
  2152. end
  2153. else
  2154. begin
  2155. { when swapped another result register }
  2156. if (nodetype=subn) and (nf_swaped in flags) then
  2157. begin
  2158. emit_reg_reg(op,S_NO,
  2159. location.register,right.location.register);
  2160. swap_location(location,right.location);
  2161. { newly swapped also set swapped flag }
  2162. { just to maintain ordering }
  2163. toggleflag(nf_swaped);
  2164. end
  2165. else
  2166. begin
  2167. emit_reg_reg(op,S_NO,
  2168. right.location.register,
  2169. location.register);
  2170. end;
  2171. ungetregistermmx(right.location.register);
  2172. end;
  2173. end
  2174. {$endif SUPPORT_MMX}
  2175. else CGMessage(type_e_mismatch);
  2176. end;
  2177. SetResultLocation(cmpop,unsigned);
  2178. end;
  2179. begin
  2180. caddnode:=ti386addnode;
  2181. end.
  2182. {
  2183. $Log$
  2184. Revision 1.8 2000-12-25 00:07:32 peter
  2185. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  2186. tlinkedlist objects)
  2187. Revision 1.7 2000/12/16 15:56:18 jonas
  2188. - removed all ifdef cardinalmulfix code
  2189. Revision 1.6 2000/12/05 11:44:32 jonas
  2190. + new integer regvar handling, should be much more efficient
  2191. Revision 1.5 2000/11/29 00:30:45 florian
  2192. * unused units removed from uses clause
  2193. * some changes for widestrings
  2194. Revision 1.4 2000/11/13 11:30:56 florian
  2195. * some bugs with interfaces and NIL fixed
  2196. Revision 1.3 2000/11/04 14:25:23 florian
  2197. + merged Attila's changes for interfaces, not tested yet
  2198. Revision 1.2 2000/10/31 22:02:56 peter
  2199. * symtable splitted, no real code changes
  2200. Revision 1.1 2000/10/15 09:33:31 peter
  2201. * moved n386*.pas to i386/ cpu_target dir
  2202. Revision 1.6 2000/10/14 10:14:47 peter
  2203. * moehrendorf oct 2000 rewrite
  2204. Revision 1.5 2000/09/30 16:08:45 peter
  2205. * more cg11 updates
  2206. Revision 1.4 2000/09/24 15:06:18 peter
  2207. * use defines.inc
  2208. Revision 1.3 2000/09/22 22:42:52 florian
  2209. * more fixes
  2210. Revision 1.2 2000/09/21 12:24:22 jonas
  2211. * small fix to my changes for full boolean evaluation support (moved
  2212. opsize determination for boolean operations back in boolean
  2213. processing block)
  2214. + full boolean evaluation support (from cg386add)
  2215. Revision 1.1 2000/09/20 21:23:32 florian
  2216. * initial revision
  2217. }