n386add.pas 106 KB

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