n386add.pas 108 KB

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