n386add.pas 109 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375
  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,verbose,globals,widestr,
  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.def.deftype<>stringdef) and
  90. ((left.resulttype.def.deftype<>setdef) or (tsetdef(left.resulttype.def).settype=smallset)) and
  91. (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  92. ungetiftemp(left.location.reference);
  93. if (right.resulttype.def.deftype<>stringdef) and
  94. ((right.resulttype.def.deftype<>setdef) or (tsetdef(right.resulttype.def).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: tasmlabel;
  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 tstringdef(left.resulttype.def).string_typ of
  126. st_widestring,
  127. st_ansistring:
  128. begin
  129. case nodetype of
  130. addn:
  131. begin
  132. cmpop:=false;
  133. secondpass(left);
  134. { to avoid problem with maybe_push and restore }
  135. set_location(location,left.location);
  136. pushed:=maybe_push(right.registers32,self,false);
  137. secondpass(right);
  138. if pushed then
  139. begin
  140. restore(self,false);
  141. set_location(left.location,location);
  142. end;
  143. { get the temp location, must be done before regs are
  144. released/pushed because after the release the regs are
  145. still used for the push (PFV) }
  146. clear_location(location);
  147. location.loc:=LOC_MEM;
  148. if (tstringdef(left.resulttype.def).string_typ=st_widestring) then
  149. begin
  150. gettempwidestringreference(location.reference);
  151. decrstringref(cwidestringtype.def,location.reference);
  152. end
  153. else
  154. begin
  155. gettempansistringreference(location.reference);
  156. decrstringref(cansistringtype.def,location.reference);
  157. end;
  158. { release used registers }
  159. del_location(right.location);
  160. del_location(left.location);
  161. { push the still used registers }
  162. pushusedregisters(pushedregs,$ff);
  163. { push data }
  164. emitpushreferenceaddr(location.reference);
  165. emit_push_loc(right.location);
  166. emit_push_loc(left.location);
  167. saveregvars($ff);
  168. if tstringdef(left.resulttype.def).string_typ=st_widestring then
  169. emitcall('FPC_WIDESTR_CONCAT')
  170. else
  171. emitcall('FPC_ANSISTR_CONCAT');
  172. popusedregisters(pushedregs);
  173. maybe_loadself;
  174. end;
  175. ltn,lten,gtn,gten,
  176. equaln,unequaln:
  177. begin
  178. cmpop:=true;
  179. if (nodetype in [equaln,unequaln]) and
  180. (left.nodetype=stringconstn) and
  181. (tstringconstnode(left).len=0) then
  182. begin
  183. secondpass(right);
  184. { release used registers }
  185. del_location(right.location);
  186. del_location(left.location);
  187. case right.location.loc of
  188. LOC_REFERENCE,LOC_MEM:
  189. emit_const_ref(A_CMP,S_L,0,newreference(right.location.reference));
  190. LOC_REGISTER,LOC_CREGISTER:
  191. emit_const_reg(A_CMP,S_L,0,right.location.register);
  192. end;
  193. end
  194. else if (nodetype in [equaln,unequaln]) and
  195. (right.nodetype=stringconstn) and
  196. (tstringconstnode(right).len=0) then
  197. begin
  198. secondpass(left);
  199. { release used registers }
  200. del_location(right.location);
  201. del_location(left.location);
  202. case right.location.loc of
  203. LOC_REFERENCE,LOC_MEM:
  204. emit_const_ref(A_CMP,S_L,0,newreference(left.location.reference));
  205. LOC_REGISTER,LOC_CREGISTER:
  206. emit_const_reg(A_CMP,S_L,0,left.location.register);
  207. end;
  208. end
  209. else
  210. begin
  211. secondpass(left);
  212. pushed:=maybe_push(right.registers32,left,false);
  213. secondpass(right);
  214. if pushed then
  215. restore(left,false);
  216. { release used registers }
  217. del_location(right.location);
  218. del_location(left.location);
  219. { push the still used registers }
  220. pushusedregisters(pushedregs,$ff);
  221. { push data }
  222. case right.location.loc of
  223. LOC_REFERENCE,LOC_MEM:
  224. emit_push_mem(right.location.reference);
  225. LOC_REGISTER,LOC_CREGISTER:
  226. emit_reg(A_PUSH,S_L,right.location.register);
  227. end;
  228. case left.location.loc of
  229. LOC_REFERENCE,LOC_MEM:
  230. emit_push_mem(left.location.reference);
  231. LOC_REGISTER,LOC_CREGISTER:
  232. emit_reg(A_PUSH,S_L,left.location.register);
  233. end;
  234. saveregvars($ff);
  235. if tstringdef(left.resulttype.def).string_typ=st_widestring then
  236. emitcall('FPC_WIDESTR_COMPARE')
  237. else
  238. emitcall('FPC_ANSISTR_COMPARE');
  239. emit_reg_reg(A_OR,S_L,R_EAX,R_EAX);
  240. popusedregisters(pushedregs);
  241. maybe_loadself;
  242. end;
  243. end;
  244. end;
  245. if tstringdef(left.resulttype.def).string_typ=st_widestring then
  246. begin
  247. ungetiftempwidestr(left.location.reference);
  248. ungetiftempwidestr(right.location.reference);
  249. end
  250. else
  251. begin
  252. ungetiftempansi(left.location.reference);
  253. ungetiftempansi(right.location.reference);
  254. end;
  255. { the result of wide/ansicompare is signed :/ }
  256. SetResultLocation(cmpop,false);
  257. end;
  258. st_shortstring:
  259. begin
  260. case nodetype of
  261. addn:
  262. begin
  263. cmpop:=false;
  264. secondpass(left);
  265. { if str_concat is set in expr
  266. s:=s+ ... no need to create a temp string (PM) }
  267. { the tempstring can also come from a typeconversion }
  268. { or a function result, so simply check for a }
  269. { temp of 256 bytes(JM) }
  270. if not(istemp(left.location.reference) and
  271. (getsizeoftemp(left.location.reference) = 256)) and
  272. not(nf_use_strconcat in flags) then
  273. begin
  274. { can only reference be }
  275. { string in register would be funny }
  276. { therefore produce a temporary string }
  277. gettempofsizereference(256,href);
  278. copyshortstring(href,left.location.reference,255,false,true);
  279. { release the registers }
  280. { done by copyshortstring now (JM) }
  281. { del_reference(left.location.reference); }
  282. ungetiftemp(left.location.reference);
  283. { does not hurt: }
  284. clear_location(left.location);
  285. left.location.loc:=LOC_MEM;
  286. left.location.reference:=href;
  287. {$ifdef newoptimizations2}
  288. { length of temp string = 255 (JM) }
  289. { *** redefining a type is not allowed!! (thanks, Pierre) }
  290. { also problem with constant string! }
  291. tstringdef(left.resulttype.def).len := 255;
  292. {$endif newoptimizations2}
  293. end;
  294. secondpass(right);
  295. {$ifdef newoptimizations2}
  296. { special case for string := string + char (JM) }
  297. { needs string length stuff from above! }
  298. hreg := R_NO;
  299. if is_shortstring(left.resulttype.def) and
  300. is_char(right.resulttype.def) then
  301. begin
  302. getlabel(l);
  303. getexplicitregister32(R_EDI);
  304. { load the current string length }
  305. emit_ref_reg(A_MOVZX,S_BL,
  306. newreference(left.location.reference),R_EDI);
  307. { is it already maximal? }
  308. emit_const_reg(A_CMP,S_L,
  309. tstringdef(left.resulttype.def).len,R_EDI);
  310. emitjmp(C_E,l);
  311. { no, so add the new character }
  312. { is it a constant char? }
  313. if (right.nodetype <> ordconstn) then
  314. { no, make sure it is in a register }
  315. if right.location.loc in [LOC_REFERENCE,LOC_MEM] then
  316. begin
  317. { free the registers of right }
  318. del_reference(right.location.reference);
  319. { get register for the char }
  320. hreg := reg32toreg8(getregister32);
  321. emit_ref_reg(A_MOV,S_B,
  322. newreference(right.location.reference),
  323. hreg);
  324. { I don't think a temp char exists, but it won't hurt (JM) }
  325. ungetiftemp(right.location.reference);
  326. end
  327. else hreg := right.location.register;
  328. href2 := newreference(left.location.reference);
  329. { we need a new reference to store the character }
  330. { at the end of the string. Check if the base or }
  331. { index register is still free }
  332. if (left.location.reference.base <> R_NO) and
  333. (left.location.reference.index <> R_NO) then
  334. begin
  335. { they're not free, so add the base reg to }
  336. { the string length (since the index can }
  337. { have a scalefactor) and use EDI as base }
  338. emit_reg_reg(A_ADD,S_L,
  339. left.location.reference.base,R_EDI);
  340. href2^.base := R_EDI;
  341. end
  342. else
  343. { at least one is still free, so put EDI there }
  344. if href2^.base = R_NO then
  345. href2^.base := R_EDI
  346. else
  347. begin
  348. href2^.index := R_EDI;
  349. href2^.scalefactor := 1;
  350. end;
  351. { we need to be one position after the last char }
  352. inc(href2^.offset);
  353. { increase the string length }
  354. emit_ref(A_INC,S_B,newreference(left.location.reference));
  355. { and store the character at the end of the string }
  356. if (right.nodetype <> ordconstn) then
  357. begin
  358. { no new_reference(href2) because it's only }
  359. { used once (JM) }
  360. emit_reg_ref(A_MOV,S_B,hreg,href2);
  361. ungetregister(hreg);
  362. end
  363. else
  364. emit_const_ref(A_MOV,S_B,right.value,href2);
  365. emitlab(l);
  366. ungetregister32(R_EDI);
  367. end
  368. else
  369. begin
  370. {$endif newoptimizations2}
  371. { on the right we do not need the register anymore too }
  372. { Instead of releasing them already, simply do not }
  373. { push them (so the release is in the right place, }
  374. { because emitpushreferenceaddr doesn't need extra }
  375. { registers) (JM) }
  376. regstopush := $ff;
  377. remove_non_regvars_from_loc(right.location,
  378. regstopush);
  379. pushusedregisters(pushedregs,regstopush);
  380. { push the maximum possible length of the result }
  381. {$ifdef newoptimizations2}
  382. { string (could be < 255 chars now) (JM) }
  383. emit_const(A_PUSH,S_L,
  384. tstringdef(left.resulttype.def).len);
  385. {$endif newoptimizations2}
  386. emitpushreferenceaddr(left.location.reference);
  387. { the optimizer can more easily put the }
  388. { deallocations in the right place if it happens }
  389. { too early than when it happens too late (if }
  390. { the pushref needs a "lea (..),edi; push edi") }
  391. del_reference(right.location.reference);
  392. emitpushreferenceaddr(right.location.reference);
  393. saveregvars(regstopush);
  394. {$ifdef newoptimizations2}
  395. emitcall('FPC_SHORTSTR_CONCAT_LEN');
  396. {$else newoptimizations2}
  397. emitcall('FPC_SHORTSTR_CONCAT');
  398. {$endif newoptimizations2}
  399. ungetiftemp(right.location.reference);
  400. maybe_loadself;
  401. popusedregisters(pushedregs);
  402. {$ifdef newoptimizations2}
  403. end;
  404. {$endif newoptimizations2}
  405. set_location(location,left.location);
  406. end;
  407. ltn,lten,gtn,gten,
  408. equaln,unequaln :
  409. begin
  410. cmpop:=true;
  411. { generate better code for s='' and s<>'' }
  412. if (nodetype in [equaln,unequaln]) and
  413. (((left.nodetype=stringconstn) and (str_length(left)=0)) or
  414. ((right.nodetype=stringconstn) and (str_length(right)=0))) then
  415. begin
  416. secondpass(left);
  417. { are too few registers free? }
  418. pushed:=maybe_push(right.registers32,left,false);
  419. secondpass(right);
  420. if pushed then
  421. restore(left,false);
  422. { only one node can be stringconstn }
  423. { else pass 1 would have evaluted }
  424. { this node }
  425. if left.nodetype=stringconstn then
  426. emit_const_ref(
  427. A_CMP,S_B,0,newreference(right.location.reference))
  428. else
  429. emit_const_ref(
  430. A_CMP,S_B,0,newreference(left.location.reference));
  431. del_reference(right.location.reference);
  432. del_reference(left.location.reference);
  433. end
  434. else
  435. begin
  436. pushusedregisters(pushedregs,$ff);
  437. secondpass(left);
  438. emitpushreferenceaddr(left.location.reference);
  439. del_reference(left.location.reference);
  440. secondpass(right);
  441. emitpushreferenceaddr(right.location.reference);
  442. del_reference(right.location.reference);
  443. saveregvars($ff);
  444. emitcall('FPC_SHORTSTR_COMPARE');
  445. maybe_loadself;
  446. popusedregisters(pushedregs);
  447. end;
  448. ungetiftemp(left.location.reference);
  449. ungetiftemp(right.location.reference);
  450. end;
  451. else CGMessage(type_e_mismatch);
  452. end;
  453. SetResultLocation(cmpop,true);
  454. end;
  455. end;
  456. end;
  457. {*****************************************************************************
  458. Addset
  459. *****************************************************************************}
  460. procedure ti386addnode.addset;
  461. var
  462. createset,
  463. cmpop,
  464. pushed : boolean;
  465. href : treference;
  466. pushedregs : tpushed;
  467. regstopush: byte;
  468. begin
  469. cmpop:=false;
  470. { not commutative }
  471. if nf_swaped in flags then
  472. swapleftright;
  473. { optimize first loading of a set }
  474. if (right.nodetype=setelementn) and
  475. not(assigned(tsetelementnode(right).right)) and
  476. is_emptyset(left) then
  477. createset:=true
  478. else
  479. begin
  480. createset:=false;
  481. secondpass(left);
  482. end;
  483. { are too few registers free? }
  484. pushed:=maybe_push(right.registers32,left,false);
  485. secondpass(right);
  486. if codegenerror then
  487. exit;
  488. if pushed then
  489. restore(left,false);
  490. set_location(location,left.location);
  491. { handle operations }
  492. case nodetype of
  493. equaln,
  494. unequaln
  495. ,lten, gten
  496. : begin
  497. cmpop:=true;
  498. del_location(left.location);
  499. del_location(right.location);
  500. pushusedregisters(pushedregs,$ff);
  501. If (nodetype in [equaln, unequaln, lten]) Then
  502. Begin
  503. emitpushreferenceaddr(right.location.reference);
  504. emitpushreferenceaddr(left.location.reference);
  505. End
  506. Else {gten = lten, if the arguments are reversed}
  507. Begin
  508. emitpushreferenceaddr(left.location.reference);
  509. emitpushreferenceaddr(right.location.reference);
  510. End;
  511. saveregvars($ff);
  512. Case nodetype of
  513. equaln, unequaln:
  514. emitcall('FPC_SET_COMP_SETS');
  515. lten, gten:
  516. Begin
  517. emitcall('FPC_SET_CONTAINS_SETS');
  518. { we need a jne afterwards, not a jnbe/jnae }
  519. nodetype := equaln;
  520. End;
  521. End;
  522. maybe_loadself;
  523. popusedregisters(pushedregs);
  524. ungetiftemp(left.location.reference);
  525. ungetiftemp(right.location.reference);
  526. end;
  527. addn : begin
  528. { add can be an other SET or Range or Element ! }
  529. { del_location(right.location);
  530. done in pushsetelement below PM
  531. And someone added it again because those registers must
  532. not be pushed by the pushusedregisters, however this
  533. breaks the optimizer (JM)
  534. del_location(right.location);
  535. pushusedregisters(pushedregs,$ff);}
  536. regstopush := $ff;
  537. remove_non_regvars_from_loc(right.location,regstopush);
  538. if (right.nodetype = setelementn) and
  539. assigned(tsetelementnode(right).right) then
  540. remove_non_regvars_from_loc(tsetelementnode(right).right.location,regstopush);
  541. remove_non_regvars_from_loc(left.location,regstopush);
  542. pushusedregisters(pushedregs,regstopush);
  543. { this is still right before the instruction that uses }
  544. { left.location, but that can be fixed by the }
  545. { optimizer. There must never be an additional }
  546. { between the release and the use, because that is not }
  547. { detected/fixed. As Pierre said above, right.loc }
  548. { will be released in pushsetelement (JM) }
  549. del_location(left.location);
  550. href.symbol:=nil;
  551. gettempofsizereference(32,href);
  552. if createset then
  553. begin
  554. pushsetelement(tunarynode(right).left);
  555. emitpushreferenceaddr(href);
  556. saveregvars(regstopush);
  557. emitcall('FPC_SET_CREATE_ELEMENT');
  558. end
  559. else
  560. begin
  561. { add a range or a single element? }
  562. if right.nodetype=setelementn then
  563. begin
  564. concatcopy(left.location.reference,href,32,false,false);
  565. if assigned(tbinarynode(right).right) then
  566. begin
  567. pushsetelement(tbinarynode(right).right);
  568. pushsetelement(tunarynode(right).left);
  569. emitpushreferenceaddr(href);
  570. saveregvars(regstopush);
  571. emitcall('FPC_SET_SET_RANGE');
  572. end
  573. else
  574. begin
  575. pushsetelement(tunarynode(right).left);
  576. emitpushreferenceaddr(href);
  577. saveregvars(regstopush);
  578. emitcall('FPC_SET_SET_BYTE');
  579. end;
  580. end
  581. else
  582. begin
  583. { must be an other set }
  584. emitpushreferenceaddr(href);
  585. emitpushreferenceaddr(right.location.reference);
  586. emitpushreferenceaddr(left.location.reference);
  587. saveregvars(regstopush);
  588. emitcall('FPC_SET_ADD_SETS');
  589. end;
  590. end;
  591. maybe_loadself;
  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_loadself;
  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 : tasmlabel;
  650. power : longint;
  651. opsize : topsize;
  652. hl4: tasmlabel;
  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.def.deftype of
  732. stringdef : begin
  733. addstring;
  734. exit;
  735. end;
  736. setdef : begin
  737. { normalsets are handled separate }
  738. if not(tsetdef(left.resulttype.def).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.def.deftype=setdef);
  754. { calculate the operator which is more difficult }
  755. firstcomplex(self);
  756. { handling boolean expressions extra: }
  757. if is_boolean(left.resulttype.def) and
  758. is_boolean(right.resulttype.def) then
  759. begin
  760. if (torddef(left.resulttype.def).typ=bool8bit) or
  761. (torddef(right.resulttype.def).typ=bool8bit) then
  762. opsize:=S_B
  763. else
  764. if (torddef(left.resulttype.def).typ=bool16bit) or
  765. (torddef(right.resulttype.def).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.def));
  869. secondpass(right);
  870. if pushed then
  871. begin
  872. restore(self,is_64bitint(left.resulttype.def));
  873. set_location(left.location,location);
  874. end;
  875. if (left.resulttype.def.deftype=pointerdef) or
  876. (right.resulttype.def.deftype=pointerdef) or
  877. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  878. (left.resulttype.def.deftype=classrefdef) or
  879. (left.resulttype.def.deftype=procvardef) or
  880. ((left.resulttype.def.deftype=enumdef) and
  881. (left.resulttype.def.size=4)) or
  882. ((left.resulttype.def.deftype=orddef) and
  883. (torddef(left.resulttype.def).typ=s32bit)) or
  884. ((right.resulttype.def.deftype=orddef) and
  885. (torddef(right.resulttype.def).typ=s32bit)) or
  886. ((left.resulttype.def.deftype=orddef) and
  887. (torddef(left.resulttype.def).typ=u32bit)) or
  888. ((right.resulttype.def.deftype=orddef) and
  889. (torddef(right.resulttype.def).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.def)) or
  897. not(is_signed(right.resulttype.def));
  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. If (not (nf_swaped in flags)) and
  988. (right.nodetype = setconstn) then
  989. right.location.reference.offset := not(right.location.reference.offset)
  990. Else If (nf_swaped in flags) and
  991. (left.nodetype = setconstn) then
  992. left.location.reference.offset := not(left.location.reference.offset)
  993. Else
  994. extra_not:=true;
  995. end
  996. else
  997. begin
  998. op:=A_SUB;
  999. mboverflow:=true;
  1000. end;
  1001. end;
  1002. ltn,lten,
  1003. gtn,gten,
  1004. equaln,unequaln : begin
  1005. If is_set Then
  1006. Case nodetype of
  1007. lten,gten:
  1008. Begin
  1009. If nodetype = lten then
  1010. swapleftright;
  1011. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  1012. begin
  1013. ungetiftemp(left.location.reference);
  1014. del_reference(left.location.reference);
  1015. hregister:=getregister32;
  1016. emit_ref_reg(A_MOV,opsize,
  1017. newreference(left.location.reference),hregister);
  1018. clear_location(left.location);
  1019. left.location.loc:=LOC_REGISTER;
  1020. left.location.register:=hregister;
  1021. set_location(location,left.location);
  1022. end
  1023. else
  1024. if left.location.loc = LOC_CREGISTER Then
  1025. {save the register var in a temp register, because
  1026. its value is going to be modified}
  1027. begin
  1028. hregister := getregister32;
  1029. emit_reg_reg(A_MOV,opsize,
  1030. left.location.register,hregister);
  1031. clear_location(left.location);
  1032. left.location.loc:=LOC_REGISTER;
  1033. left.location.register:=hregister;
  1034. set_location(location,left.location);
  1035. end;
  1036. {here, left.location should be LOC_REGISTER}
  1037. If right.location.loc in [LOC_MEM,LOC_REFERENCE] Then
  1038. emit_ref_reg(A_AND,opsize,
  1039. newreference(right.location.reference),left.location.register)
  1040. Else
  1041. emit_reg_reg(A_AND,opsize,
  1042. right.location.register,left.location.register);
  1043. {warning: ugly hack ahead: we need a "jne" after the cmp, so
  1044. change the nodetype from lten/gten to equaln}
  1045. nodetype := equaln
  1046. End;
  1047. {no < or > support for sets}
  1048. ltn,gtn: CGMessage(type_e_mismatch);
  1049. End;
  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,torddef(u32bittype.def),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,torddef(u32bittype.def),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,torddef(u32bittype.def),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.def.deftype=orddef) and
  1373. (torddef(left.resulttype.def).typ=uchar)) or
  1374. { enumeration type 16 bit }
  1375. ((left.resulttype.def.deftype=enumdef) and
  1376. (left.resulttype.def.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.def.deftype=enumdef) and
  1447. (left.resulttype.def.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.def) then
  1518. begin
  1519. mboverflow:=false;
  1520. cmpop:=false;
  1521. unsigned:=((left.resulttype.def.deftype=orddef) and
  1522. (torddef(left.resulttype.def).typ=u64bit)) or
  1523. ((right.resulttype.def.deftype=orddef) and
  1524. (torddef(right.resulttype.def).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 torddef(resulttype.def).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.def.deftype=floatdef) then
  1848. begin
  1849. { real constants to the right, but only if it
  1850. isn't on the FPU stack, i.e. 1.0 or 0.0! }
  1851. if (left.nodetype=realconstn) and
  1852. (left.location.loc<>LOC_FPU) then
  1853. swapleftright;
  1854. cmpop:=false;
  1855. case nodetype of
  1856. addn : op:=A_FADDP;
  1857. muln : op:=A_FMULP;
  1858. subn : op:=A_FSUBP;
  1859. slashn : op:=A_FDIVP;
  1860. ltn,lten,gtn,gten,
  1861. equaln,unequaln : begin
  1862. op:=A_FCOMPP;
  1863. cmpop:=true;
  1864. end;
  1865. else CGMessage(type_e_mismatch);
  1866. end;
  1867. if (right.location.loc<>LOC_FPU) then
  1868. begin
  1869. if right.location.loc=LOC_CFPUREGISTER then
  1870. begin
  1871. emit_reg( A_FLD,S_NO,
  1872. correct_fpuregister(right.location.register,fpuvaroffset));
  1873. inc(fpuvaroffset);
  1874. end
  1875. else
  1876. floatload(tfloatdef(right.resulttype.def).typ,right.location.reference);
  1877. if (left.location.loc<>LOC_FPU) then
  1878. begin
  1879. if left.location.loc=LOC_CFPUREGISTER then
  1880. begin
  1881. emit_reg( A_FLD,S_NO,
  1882. correct_fpuregister(left.location.register,fpuvaroffset));
  1883. inc(fpuvaroffset);
  1884. end
  1885. else
  1886. floatload(tfloatdef(left.resulttype.def).typ,left.location.reference)
  1887. end
  1888. { left was on the stack => swap }
  1889. else
  1890. toggleflag(nf_swaped);
  1891. { releases the right reference }
  1892. del_reference(right.location.reference);
  1893. end
  1894. { the nominator in st0 }
  1895. else if (left.location.loc<>LOC_FPU) then
  1896. begin
  1897. if left.location.loc=LOC_CFPUREGISTER then
  1898. begin
  1899. emit_reg( A_FLD,S_NO,
  1900. correct_fpuregister(left.location.register,fpuvaroffset));
  1901. inc(fpuvaroffset);
  1902. end
  1903. else
  1904. floatload(tfloatdef(left.resulttype.def).typ,left.location.reference)
  1905. end
  1906. { fpu operands are always in the wrong order on the stack }
  1907. else
  1908. toggleflag(nf_swaped);
  1909. { releases the left reference }
  1910. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1911. del_reference(left.location.reference);
  1912. { if we swaped the tree nodes, then use the reverse operator }
  1913. if nf_swaped in flags then
  1914. begin
  1915. if (nodetype=slashn) then
  1916. op:=A_FDIVRP
  1917. else if (nodetype=subn) then
  1918. op:=A_FSUBRP;
  1919. end;
  1920. { to avoid the pentium bug
  1921. if (op=FDIVP) and (opt_processors=pentium) then
  1922. emitcall('EMUL_FDIVP')
  1923. else
  1924. }
  1925. { the Intel assemblers want operands }
  1926. if op<>A_FCOMPP then
  1927. begin
  1928. emit_reg_reg(op,S_NO,R_ST,R_ST1);
  1929. dec(fpuvaroffset);
  1930. end
  1931. else
  1932. begin
  1933. emit_none(op,S_NO);
  1934. dec(fpuvaroffset,2);
  1935. end;
  1936. { on comparison load flags }
  1937. if cmpop then
  1938. begin
  1939. if not(R_EAX in unused) then
  1940. begin
  1941. getexplicitregister32(R_EDI);
  1942. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1943. end;
  1944. emit_reg(A_FNSTSW,S_NO,R_AX);
  1945. emit_none(A_SAHF,S_NO);
  1946. if not(R_EAX in unused) then
  1947. begin
  1948. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1949. ungetregister32(R_EDI);
  1950. end;
  1951. if nf_swaped in flags then
  1952. begin
  1953. case nodetype of
  1954. equaln : resflags:=F_E;
  1955. unequaln : resflags:=F_NE;
  1956. ltn : resflags:=F_A;
  1957. lten : resflags:=F_AE;
  1958. gtn : resflags:=F_B;
  1959. gten : resflags:=F_BE;
  1960. end;
  1961. end
  1962. else
  1963. begin
  1964. case nodetype of
  1965. equaln : resflags:=F_E;
  1966. unequaln : resflags:=F_NE;
  1967. ltn : resflags:=F_B;
  1968. lten : resflags:=F_BE;
  1969. gtn : resflags:=F_A;
  1970. gten : resflags:=F_AE;
  1971. end;
  1972. end;
  1973. clear_location(location);
  1974. location.loc:=LOC_FLAGS;
  1975. location.resflags:=resflags;
  1976. cmpop:=false;
  1977. end
  1978. else
  1979. begin
  1980. clear_location(location);
  1981. location.loc:=LOC_FPU;
  1982. end;
  1983. end
  1984. {$ifdef SUPPORT_MMX}
  1985. else
  1986. { MMX Arrays }
  1987. if is_mmx_able_array(left.resulttype.def) then
  1988. begin
  1989. cmpop:=false;
  1990. mmxbase:=mmx_type(left.resulttype.def);
  1991. case nodetype of
  1992. addn : begin
  1993. if (cs_mmx_saturation in aktlocalswitches) then
  1994. begin
  1995. case mmxbase of
  1996. mmxs8bit:
  1997. op:=A_PADDSB;
  1998. mmxu8bit:
  1999. op:=A_PADDUSB;
  2000. mmxs16bit,mmxfixed16:
  2001. op:=A_PADDSB;
  2002. mmxu16bit:
  2003. op:=A_PADDUSW;
  2004. end;
  2005. end
  2006. else
  2007. begin
  2008. case mmxbase of
  2009. mmxs8bit,mmxu8bit:
  2010. op:=A_PADDB;
  2011. mmxs16bit,mmxu16bit,mmxfixed16:
  2012. op:=A_PADDW;
  2013. mmxs32bit,mmxu32bit:
  2014. op:=A_PADDD;
  2015. end;
  2016. end;
  2017. end;
  2018. muln : begin
  2019. case mmxbase of
  2020. mmxs16bit,mmxu16bit:
  2021. op:=A_PMULLW;
  2022. mmxfixed16:
  2023. op:=A_PMULHW;
  2024. end;
  2025. end;
  2026. subn : begin
  2027. if (cs_mmx_saturation in aktlocalswitches) then
  2028. begin
  2029. case mmxbase of
  2030. mmxs8bit:
  2031. op:=A_PSUBSB;
  2032. mmxu8bit:
  2033. op:=A_PSUBUSB;
  2034. mmxs16bit,mmxfixed16:
  2035. op:=A_PSUBSB;
  2036. mmxu16bit:
  2037. op:=A_PSUBUSW;
  2038. end;
  2039. end
  2040. else
  2041. begin
  2042. case mmxbase of
  2043. mmxs8bit,mmxu8bit:
  2044. op:=A_PSUBB;
  2045. mmxs16bit,mmxu16bit,mmxfixed16:
  2046. op:=A_PSUBW;
  2047. mmxs32bit,mmxu32bit:
  2048. op:=A_PSUBD;
  2049. end;
  2050. end;
  2051. end;
  2052. {
  2053. ltn,lten,gtn,gten,
  2054. equaln,unequaln :
  2055. begin
  2056. op:=A_CMP;
  2057. cmpop:=true;
  2058. end;
  2059. }
  2060. xorn:
  2061. op:=A_PXOR;
  2062. orn:
  2063. op:=A_POR;
  2064. andn:
  2065. op:=A_PAND;
  2066. else CGMessage(type_e_mismatch);
  2067. end;
  2068. { left and right no register? }
  2069. { then one must be demanded }
  2070. if (left.location.loc<>LOC_MMXREGISTER) and
  2071. (right.location.loc<>LOC_MMXREGISTER) then
  2072. begin
  2073. { register variable ? }
  2074. if (left.location.loc=LOC_CMMXREGISTER) then
  2075. begin
  2076. { it is OK if this is the destination }
  2077. if is_in_dest then
  2078. begin
  2079. hregister:=location.register;
  2080. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2081. hregister);
  2082. end
  2083. else
  2084. begin
  2085. hregister:=getregistermmx;
  2086. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  2087. hregister);
  2088. end
  2089. end
  2090. else
  2091. begin
  2092. del_reference(left.location.reference);
  2093. if is_in_dest then
  2094. begin
  2095. hregister:=location.register;
  2096. emit_ref_reg(A_MOVQ,S_NO,
  2097. newreference(left.location.reference),hregister);
  2098. end
  2099. else
  2100. begin
  2101. hregister:=getregistermmx;
  2102. emit_ref_reg(A_MOVQ,S_NO,
  2103. newreference(left.location.reference),hregister);
  2104. end;
  2105. end;
  2106. clear_location(location);
  2107. location.loc:=LOC_MMXREGISTER;
  2108. location.register:=hregister;
  2109. end
  2110. else
  2111. { if on the right the register then swap }
  2112. if (right.location.loc=LOC_MMXREGISTER) then
  2113. begin
  2114. swap_location(location,right.location);
  2115. { newly swapped also set swapped flag }
  2116. toggleflag(nf_swaped);
  2117. end;
  2118. { at this point, location.loc should be LOC_MMXREGISTER }
  2119. { and location.register should be a valid register }
  2120. { containing the left result }
  2121. if right.location.loc<>LOC_MMXREGISTER then
  2122. begin
  2123. if (nodetype=subn) and (nf_swaped in flags) then
  2124. begin
  2125. if right.location.loc=LOC_CMMXREGISTER then
  2126. begin
  2127. emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
  2128. emit_reg_reg(op,S_NO,location.register,R_MM0);
  2129. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  2130. end
  2131. else
  2132. begin
  2133. emit_ref_reg(A_MOVQ,S_NO,
  2134. newreference(right.location.reference),R_MM7);
  2135. emit_reg_reg(op,S_NO,location.register,
  2136. R_MM7);
  2137. emit_reg_reg(A_MOVQ,S_NO,
  2138. R_MM7,location.register);
  2139. del_reference(right.location.reference);
  2140. end;
  2141. end
  2142. else
  2143. begin
  2144. if (right.location.loc=LOC_CREGISTER) then
  2145. begin
  2146. emit_reg_reg(op,S_NO,right.location.register,
  2147. location.register);
  2148. end
  2149. else
  2150. begin
  2151. emit_ref_reg(op,S_NO,newreference(
  2152. right.location.reference),location.register);
  2153. del_reference(right.location.reference);
  2154. end;
  2155. end;
  2156. end
  2157. else
  2158. begin
  2159. { when swapped another result register }
  2160. if (nodetype=subn) and (nf_swaped in flags) then
  2161. begin
  2162. emit_reg_reg(op,S_NO,
  2163. location.register,right.location.register);
  2164. swap_location(location,right.location);
  2165. { newly swapped also set swapped flag }
  2166. { just to maintain ordering }
  2167. toggleflag(nf_swaped);
  2168. end
  2169. else
  2170. begin
  2171. emit_reg_reg(op,S_NO,
  2172. right.location.register,
  2173. location.register);
  2174. end;
  2175. ungetregistermmx(right.location.register);
  2176. end;
  2177. end
  2178. {$endif SUPPORT_MMX}
  2179. else CGMessage(type_e_mismatch);
  2180. end;
  2181. SetResultLocation(cmpop,unsigned);
  2182. end;
  2183. begin
  2184. caddnode:=ti386addnode;
  2185. end.
  2186. {
  2187. $Log$
  2188. Revision 1.16 2001-07-08 21:00:16 peter
  2189. * various widestring updates, it works now mostly without charset
  2190. mapping supported
  2191. Revision 1.15 2001/06/25 14:11:37 jonas
  2192. * fixed set bug discovered by Carl (merged)
  2193. Revision 1.14 2001/06/18 20:36:25 peter
  2194. * -Ur switch (merged)
  2195. * masm fixes (merged)
  2196. * quoted filenames for go32v2 and win32
  2197. Revision 1.13 2001/05/27 14:30:56 florian
  2198. + some widestring stuff added
  2199. Revision 1.12 2001/05/06 17:12:14 jonas
  2200. * fixed an IE10 and another bug with [var1..var2] construct
  2201. Revision 1.11 2001/04/13 01:22:18 peter
  2202. * symtable change to classes
  2203. * range check generation and errors fixed, make cycle DEBUG=1 works
  2204. * memory leaks fixed
  2205. Revision 1.10 2001/04/02 21:20:36 peter
  2206. * resulttype rewrite
  2207. Revision 1.9 2000/12/31 11:14:11 jonas
  2208. + implemented/fixed docompare() mathods for all nodes (not tested)
  2209. + nopt.pas, nadd.pas, i386/n386opt.pas: optimized nodes for adding strings
  2210. and constant strings/chars together
  2211. * n386add.pas: don't copy temp strings (of size 256) to another temp string
  2212. when adding
  2213. Revision 1.8 2000/12/25 00:07:32 peter
  2214. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  2215. tlinkedlist objects)
  2216. Revision 1.7 2000/12/16 15:56:18 jonas
  2217. - removed all ifdef cardinalmulfix code
  2218. Revision 1.6 2000/12/05 11:44:32 jonas
  2219. + new integer regvar handling, should be much more efficient
  2220. Revision 1.5 2000/11/29 00:30:45 florian
  2221. * unused units removed from uses clause
  2222. * some changes for widestrings
  2223. Revision 1.4 2000/11/13 11:30:56 florian
  2224. * some bugs with interfaces and NIL fixed
  2225. Revision 1.3 2000/11/04 14:25:23 florian
  2226. + merged Attila's changes for interfaces, not tested yet
  2227. Revision 1.2 2000/10/31 22:02:56 peter
  2228. * symtable splitted, no real code changes
  2229. Revision 1.1 2000/10/15 09:33:31 peter
  2230. * moved n386*.pas to i386/ cpu_target dir
  2231. Revision 1.6 2000/10/14 10:14:47 peter
  2232. * moehrendorf oct 2000 rewrite
  2233. Revision 1.5 2000/09/30 16:08:45 peter
  2234. * more cg11 updates
  2235. Revision 1.4 2000/09/24 15:06:18 peter
  2236. * use defines.inc
  2237. Revision 1.3 2000/09/22 22:42:52 florian
  2238. * more fixes
  2239. Revision 1.2 2000/09/21 12:24:22 jonas
  2240. * small fix to my changes for full boolean evaluation support (moved
  2241. opsize determination for boolean operations back in boolean
  2242. processing block)
  2243. + full boolean evaluation support (from cg386add)
  2244. Revision 1.1 2000/09/20 21:23:32 florian
  2245. * initial revision
  2246. }