n386add.pas 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994
  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. node,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. protected
  29. function first_addstring : tnode; override;
  30. private
  31. procedure second_addstring;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. cutils,verbose,globals,widestr,
  37. symconst,symdef,aasm,types,
  38. cgbase,temp_gen,pass_2,
  39. cpuasm,
  40. ncon,nset,
  41. cga,n386util,tgcpu;
  42. function ti386addnode.getresflags(unsigned : boolean) : tresflags;
  43. begin
  44. if not(unsigned) then
  45. begin
  46. if nf_swaped in flags then
  47. case nodetype of
  48. equaln : getresflags:=F_E;
  49. unequaln : getresflags:=F_NE;
  50. ltn : getresflags:=F_G;
  51. lten : getresflags:=F_GE;
  52. gtn : getresflags:=F_L;
  53. gten : getresflags:=F_LE;
  54. end
  55. else
  56. case nodetype of
  57. equaln : getresflags:=F_E;
  58. unequaln : getresflags:=F_NE;
  59. ltn : getresflags:=F_L;
  60. lten : getresflags:=F_LE;
  61. gtn : getresflags:=F_G;
  62. gten : getresflags:=F_GE;
  63. end;
  64. end
  65. else
  66. begin
  67. if nf_swaped in flags then
  68. case nodetype of
  69. equaln : getresflags:=F_E;
  70. unequaln : getresflags:=F_NE;
  71. ltn : getresflags:=F_A;
  72. lten : getresflags:=F_AE;
  73. gtn : getresflags:=F_B;
  74. gten : getresflags:=F_BE;
  75. end
  76. else
  77. case nodetype of
  78. equaln : getresflags:=F_E;
  79. unequaln : getresflags:=F_NE;
  80. ltn : getresflags:=F_B;
  81. lten : getresflags:=F_BE;
  82. gtn : getresflags:=F_A;
  83. gten : getresflags:=F_AE;
  84. end;
  85. end;
  86. end;
  87. procedure ti386addnode.SetResultLocation(cmpop,unsigned : boolean);
  88. begin
  89. { remove temporary location if not a set or string }
  90. { that's a bad hack (FK) who did this ? }
  91. if (left.resulttype.def.deftype<>stringdef) and
  92. ((left.resulttype.def.deftype<>setdef) or (tsetdef(left.resulttype.def).settype=smallset)) and
  93. (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  94. ungetiftemp(left.location.reference);
  95. if (right.resulttype.def.deftype<>stringdef) and
  96. ((right.resulttype.def.deftype<>setdef) or (tsetdef(right.resulttype.def).settype=smallset)) and
  97. (right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  98. ungetiftemp(right.location.reference);
  99. { in case of comparison operation the put result in the flags }
  100. if cmpop then
  101. begin
  102. clear_location(location);
  103. location.loc:=LOC_FLAGS;
  104. location.resflags:=getresflags(unsigned);
  105. end;
  106. end;
  107. {*****************************************************************************
  108. Addstring
  109. *****************************************************************************}
  110. { note: if you implemented an fpc_shortstr_concat similar to the }
  111. { one in i386.inc, you have to override first_addstring like in }
  112. { ti386addnode.first_string and implement the shortstring concat }
  113. { manually! The generic routine is different from the i386 one (JM) }
  114. function ti386addnode.first_addstring : tnode;
  115. begin
  116. { special cases for shortstrings, handled in pass_2 (JM) }
  117. { can't handle fpc_shortstr_compare with compilerproc either because it }
  118. { returns its results in the flags instead of in eax }
  119. if ((nodetype = addn) and
  120. is_shortstring(resulttype.def)) or
  121. ((nodetype in [ltn,lten,gtn,gten,equaln,unequaln]) and
  122. not(((left.nodetype=stringconstn) and (str_length(left)=0)) or
  123. ((right.nodetype=stringconstn) and (str_length(right)=0))) and
  124. is_shortstring(left.resulttype.def)) then
  125. begin
  126. result := nil;
  127. exit;
  128. end;
  129. { otherwise, use the generic code }
  130. result := inherited first_addstring;
  131. end;
  132. procedure ti386addnode.second_addstring;
  133. var
  134. pushedregs : tpushed;
  135. href : treference;
  136. pushed,
  137. cmpop : boolean;
  138. regstopush : byte;
  139. begin
  140. { string operations are not commutative }
  141. if nf_swaped in flags then
  142. swapleftright;
  143. case tstringdef(left.resulttype.def).string_typ of
  144. st_shortstring:
  145. begin
  146. case nodetype of
  147. addn:
  148. begin
  149. cmpop:=false;
  150. secondpass(left);
  151. { if str_concat is set in expr
  152. s:=s+ ... no need to create a temp string (PM) }
  153. { the tempstring can also come from a typeconversion }
  154. { or a function result, so simply check for a }
  155. { temp of 256 bytes(JM) }
  156. if not(istemp(left.location.reference) and
  157. (getsizeoftemp(left.location.reference) = 256)) and
  158. not(nf_use_strconcat in flags) then
  159. begin
  160. { can only reference be }
  161. { string in register would be funny }
  162. { therefore produce a temporary string }
  163. gettempofsizereference(256,href);
  164. copyshortstring(href,left.location.reference,255,false,true);
  165. { release the registers }
  166. { done by copyshortstring now (JM) }
  167. { del_reference(left.location.reference); }
  168. ungetiftemp(left.location.reference);
  169. { does not hurt: }
  170. clear_location(left.location);
  171. left.location.loc:=LOC_MEM;
  172. left.location.reference:=href;
  173. end;
  174. secondpass(right);
  175. { on the right we do not need the register anymore too }
  176. { Instead of releasing them already, simply do not }
  177. { push them (so the release is in the right place, }
  178. { because emitpushreferenceaddr doesn't need extra }
  179. { registers) (JM) }
  180. regstopush := $ff;
  181. remove_non_regvars_from_loc(right.location,
  182. regstopush);
  183. pushusedregisters(pushedregs,regstopush);
  184. { push the maximum possible length of the result }
  185. emitpushreferenceaddr(left.location.reference);
  186. { the optimizer can more easily put the }
  187. { deallocations in the right place if it happens }
  188. { too early than when it happens too late (if }
  189. { the pushref needs a "lea (..),edi; push edi") }
  190. del_reference(right.location.reference);
  191. emitpushreferenceaddr(right.location.reference);
  192. saveregvars(regstopush);
  193. emitcall('FPC_SHORTSTR_CONCAT');
  194. ungetiftemp(right.location.reference);
  195. maybe_loadself;
  196. popusedregisters(pushedregs);
  197. set_location(location,left.location);
  198. end;
  199. ltn,lten,gtn,gten,equaln,unequaln :
  200. begin
  201. cmpop := true;
  202. pushusedregisters(pushedregs,$ff);
  203. secondpass(left);
  204. emitpushreferenceaddr(left.location.reference);
  205. del_reference(left.location.reference);
  206. secondpass(right);
  207. emitpushreferenceaddr(right.location.reference);
  208. del_reference(right.location.reference);
  209. saveregvars($ff);
  210. emitcall('FPC_SHORTSTR_COMPARE');
  211. maybe_loadself;
  212. popusedregisters(pushedregs);
  213. ungetiftemp(left.location.reference);
  214. ungetiftemp(right.location.reference);
  215. end;
  216. end;
  217. SetResultLocation(cmpop,true);
  218. end;
  219. else
  220. { rest should be handled in first pass (JM) }
  221. internalerror(200108303);
  222. end;
  223. end;
  224. {*****************************************************************************
  225. pass_2
  226. *****************************************************************************}
  227. procedure ti386addnode.pass_2;
  228. { is also being used for xor, and "mul", "sub, or and comparative }
  229. { operators }
  230. label do_normal;
  231. var
  232. unusedregisters : tregisterset;
  233. usablecount : byte;
  234. hregister,hregister2 : tregister;
  235. noswap,popeax,popedx,
  236. pushed,pushedfpu,
  237. mboverflow,cmpop : boolean;
  238. op,op2 : tasmop;
  239. resflags : tresflags;
  240. otl,ofl : tasmlabel;
  241. power : longint;
  242. opsize : topsize;
  243. hl4: tasmlabel;
  244. hr : preference;
  245. { true, if unsigned types are compared }
  246. unsigned : boolean;
  247. { true, if a small set is handled with the longint code }
  248. is_set : boolean;
  249. { is_in_dest if the result is put directly into }
  250. { the resulting refernce or varregister }
  251. is_in_dest : boolean;
  252. { true, if for sets subtractions the extra not should generated }
  253. extra_not : boolean;
  254. {$ifdef SUPPORT_MMX}
  255. mmxbase : tmmxtype;
  256. {$endif SUPPORT_MMX}
  257. pushedreg : tpushed;
  258. regstopush: byte;
  259. procedure firstjmp64bitcmp;
  260. var
  261. oldnodetype : tnodetype;
  262. begin
  263. { the jump the sequence is a little bit hairy }
  264. case nodetype of
  265. ltn,gtn:
  266. begin
  267. emitjmp(flag_2_cond[getresflags(unsigned)],truelabel);
  268. { cheat a little bit for the negative test }
  269. toggleflag(nf_swaped);
  270. emitjmp(flag_2_cond[getresflags(unsigned)],falselabel);
  271. toggleflag(nf_swaped);
  272. end;
  273. lten,gten:
  274. begin
  275. oldnodetype:=nodetype;
  276. if nodetype=lten then
  277. nodetype:=ltn
  278. else
  279. nodetype:=gtn;
  280. emitjmp(flag_2_cond[getresflags(unsigned)],truelabel);
  281. { cheat for the negative test }
  282. if nodetype=ltn then
  283. nodetype:=gtn
  284. else
  285. nodetype:=ltn;
  286. emitjmp(flag_2_cond[getresflags(unsigned)],falselabel);
  287. nodetype:=oldnodetype;
  288. end;
  289. equaln:
  290. emitjmp(C_NE,falselabel);
  291. unequaln:
  292. emitjmp(C_NE,truelabel);
  293. end;
  294. end;
  295. procedure secondjmp64bitcmp;
  296. begin
  297. { the jump the sequence is a little bit hairy }
  298. case nodetype of
  299. ltn,gtn,lten,gten:
  300. begin
  301. { the comparisaion of the low dword have to be }
  302. { always unsigned! }
  303. emitjmp(flag_2_cond[getresflags(true)],truelabel);
  304. emitjmp(C_None,falselabel);
  305. end;
  306. equaln:
  307. begin
  308. emitjmp(C_NE,falselabel);
  309. emitjmp(C_None,truelabel);
  310. end;
  311. unequaln:
  312. begin
  313. emitjmp(C_NE,truelabel);
  314. emitjmp(C_None,falselabel);
  315. end;
  316. end;
  317. end;
  318. begin
  319. { to make it more readable, string and set (not smallset!) have their
  320. own procedures }
  321. case left.resulttype.def.deftype of
  322. stringdef : begin
  323. second_addstring;
  324. exit;
  325. end;
  326. setdef : begin
  327. { normalsets are handled separate }
  328. if not(tsetdef(left.resulttype.def).settype=smallset) then
  329. begin
  330. { should be handled in pass 1 (JM) }
  331. internalerror(200109041);
  332. end;
  333. end;
  334. end;
  335. { defaults }
  336. unsigned:=false;
  337. is_in_dest:=false;
  338. extra_not:=false;
  339. noswap:=false;
  340. opsize:=S_L;
  341. { are we a (small)set, must be set here because the side can be
  342. swapped ! (PFV) }
  343. is_set:=(left.resulttype.def.deftype=setdef);
  344. { calculate the operator which is more difficult }
  345. firstcomplex(self);
  346. { handling boolean expressions extra: }
  347. if is_boolean(left.resulttype.def) and
  348. is_boolean(right.resulttype.def) then
  349. begin
  350. if (torddef(left.resulttype.def).typ=bool8bit) or
  351. (torddef(right.resulttype.def).typ=bool8bit) then
  352. opsize:=S_B
  353. else
  354. if (torddef(left.resulttype.def).typ=bool16bit) or
  355. (torddef(right.resulttype.def).typ=bool16bit) then
  356. opsize:=S_W
  357. else
  358. opsize:=S_L;
  359. if (cs_full_boolean_eval in aktlocalswitches) or
  360. (nodetype in
  361. [unequaln,ltn,lten,gtn,gten,equaln,xorn]) then
  362. begin
  363. if left.nodetype in [ordconstn,realconstn] then
  364. swapleftright;
  365. if left.location.loc=LOC_JUMP then
  366. begin
  367. otl:=truelabel;
  368. getlabel(truelabel);
  369. ofl:=falselabel;
  370. getlabel(falselabel);
  371. end;
  372. secondpass(left);
  373. { if in flags then copy first to register, because the
  374. flags can be destroyed }
  375. case left.location.loc of
  376. LOC_FLAGS:
  377. locflags2reg(left.location,opsize);
  378. LOC_JUMP:
  379. locjump2reg(left.location,opsize, otl, ofl);
  380. end;
  381. set_location(location,left.location);
  382. pushed:=maybe_push(right.registers32,self,false);
  383. if right.location.loc=LOC_JUMP then
  384. begin
  385. otl:=truelabel;
  386. getlabel(truelabel);
  387. ofl:=falselabel;
  388. getlabel(falselabel);
  389. end;
  390. secondpass(right);
  391. if pushed then
  392. begin
  393. restore(self,false);
  394. set_location(left.location,location);
  395. end;
  396. case right.location.loc of
  397. LOC_FLAGS:
  398. locflags2reg(right.location,opsize);
  399. LOC_JUMP:
  400. locjump2reg(right.location,opsize,otl,ofl);
  401. end;
  402. goto do_normal;
  403. end;
  404. case nodetype of
  405. andn,
  406. orn : begin
  407. clear_location(location);
  408. location.loc:=LOC_JUMP;
  409. cmpop:=false;
  410. case nodetype of
  411. andn : begin
  412. otl:=truelabel;
  413. getlabel(truelabel);
  414. secondpass(left);
  415. maketojumpbool(left);
  416. emitlab(truelabel);
  417. truelabel:=otl;
  418. end;
  419. orn : begin
  420. ofl:=falselabel;
  421. getlabel(falselabel);
  422. secondpass(left);
  423. maketojumpbool(left);
  424. emitlab(falselabel);
  425. falselabel:=ofl;
  426. end;
  427. else
  428. CGMessage(type_e_mismatch);
  429. end;
  430. secondpass(right);
  431. maketojumpbool(right);
  432. end;
  433. else
  434. CGMessage(type_e_mismatch);
  435. end
  436. end
  437. else
  438. begin
  439. { in case of constant put it to the left }
  440. if (left.nodetype=ordconstn) then
  441. swapleftright;
  442. secondpass(left);
  443. { this will be complicated as
  444. a lot of code below assumes that
  445. location and left.location are the same }
  446. {$ifdef test_dest_loc}
  447. if dest_loc_known and (dest_loc_tree=p) and
  448. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  449. begin
  450. set_location(location,dest_loc);
  451. in_dest_loc:=true;
  452. is_in_dest:=true;
  453. end
  454. else
  455. {$endif test_dest_loc}
  456. set_location(location,left.location);
  457. { are too few registers free? }
  458. pushed:=maybe_push(right.registers32,self,is_64bitint(left.resulttype.def));
  459. if location.loc=LOC_FPU then
  460. pushedfpu:=maybe_pushfpu(right.registersfpu,self)
  461. else
  462. pushedfpu:=false;
  463. secondpass(right);
  464. if pushed then
  465. begin
  466. restore(self,is_64bitint(left.resulttype.def));
  467. set_location(left.location,location);
  468. end;
  469. if (left.resulttype.def.deftype=pointerdef) or
  470. (right.resulttype.def.deftype=pointerdef) or
  471. (is_class_or_interface(right.resulttype.def) and is_class_or_interface(left.resulttype.def)) or
  472. (left.resulttype.def.deftype=classrefdef) or
  473. (left.resulttype.def.deftype=procvardef) or
  474. ((left.resulttype.def.deftype=enumdef) and
  475. (left.resulttype.def.size=4)) or
  476. ((left.resulttype.def.deftype=orddef) and
  477. (torddef(left.resulttype.def).typ=s32bit)) or
  478. ((right.resulttype.def.deftype=orddef) and
  479. (torddef(right.resulttype.def).typ=s32bit)) or
  480. ((left.resulttype.def.deftype=orddef) and
  481. (torddef(left.resulttype.def).typ=u32bit)) or
  482. ((right.resulttype.def.deftype=orddef) and
  483. (torddef(right.resulttype.def).typ=u32bit)) or
  484. { as well as small sets }
  485. is_set then
  486. begin
  487. do_normal:
  488. mboverflow:=false;
  489. cmpop:=false;
  490. unsigned := not(is_signed(left.resulttype.def)) or
  491. not(is_signed(right.resulttype.def));
  492. case nodetype of
  493. addn : begin
  494. { this is a really ugly hack!!!!!!!!!! }
  495. { this could be done later using EDI }
  496. { as it is done for subn }
  497. { instead of two registers!!!! }
  498. if is_set then
  499. begin
  500. { adding elements is not commutative }
  501. if (nf_swaped in flags) and (left.nodetype=setelementn) then
  502. swapleftright;
  503. { are we adding set elements ? }
  504. if right.nodetype=setelementn then
  505. begin
  506. { no range support for smallsets! }
  507. if assigned(tsetelementnode(right).right) then
  508. internalerror(43244);
  509. { bts requires both elements to be registers }
  510. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  511. begin
  512. ungetiftemp(left.location.reference);
  513. del_location(left.location);
  514. {!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
  515. hregister:=getregister32;
  516. emit_ref_reg(A_MOV,opsize,
  517. newreference(left.location.reference),hregister);
  518. clear_location(left.location);
  519. left.location.loc:=LOC_REGISTER;
  520. left.location.register:=hregister;
  521. set_location(location,left.location);
  522. end;
  523. if right.location.loc in [LOC_MEM,LOC_REFERENCE] then
  524. begin
  525. ungetiftemp(right.location.reference);
  526. del_location(right.location);
  527. hregister:=getregister32;
  528. emit_ref_reg(A_MOV,opsize,
  529. newreference(right.location.reference),hregister);
  530. clear_location(right.location);
  531. right.location.loc:=LOC_REGISTER;
  532. right.location.register:=hregister;
  533. end;
  534. op:=A_BTS;
  535. noswap:=true;
  536. end
  537. else
  538. op:=A_OR;
  539. mboverflow:=false;
  540. unsigned:=false;
  541. end
  542. else
  543. begin
  544. op:=A_ADD;
  545. mboverflow:=true;
  546. end;
  547. end;
  548. symdifn : begin
  549. { the symetric diff is only for sets }
  550. if is_set then
  551. begin
  552. op:=A_XOR;
  553. mboverflow:=false;
  554. unsigned:=false;
  555. end
  556. else
  557. CGMessage(type_e_mismatch);
  558. end;
  559. muln : begin
  560. if is_set then
  561. begin
  562. op:=A_AND;
  563. mboverflow:=false;
  564. unsigned:=false;
  565. end
  566. else
  567. begin
  568. if unsigned then
  569. op:=A_MUL
  570. else
  571. op:=A_IMUL;
  572. mboverflow:=true;
  573. end;
  574. end;
  575. subn : begin
  576. if is_set then
  577. begin
  578. op:=A_AND;
  579. mboverflow:=false;
  580. unsigned:=false;
  581. If (not (nf_swaped in flags)) and
  582. (right.nodetype = setconstn) then
  583. right.location.reference.offset := not(right.location.reference.offset)
  584. Else If (nf_swaped in flags) and
  585. (left.nodetype = setconstn) then
  586. left.location.reference.offset := not(left.location.reference.offset)
  587. Else
  588. extra_not:=true;
  589. end
  590. else
  591. begin
  592. op:=A_SUB;
  593. mboverflow:=true;
  594. end;
  595. end;
  596. ltn,lten,
  597. gtn,gten,
  598. equaln,unequaln : begin
  599. If is_set Then
  600. Case nodetype of
  601. lten,gten:
  602. Begin
  603. If nodetype = lten then
  604. swapleftright;
  605. if left.location.loc in [LOC_MEM,LOC_REFERENCE] then
  606. begin
  607. ungetiftemp(left.location.reference);
  608. del_reference(left.location.reference);
  609. hregister:=getregister32;
  610. emit_ref_reg(A_MOV,opsize,
  611. newreference(left.location.reference),hregister);
  612. clear_location(left.location);
  613. left.location.loc:=LOC_REGISTER;
  614. left.location.register:=hregister;
  615. set_location(location,left.location);
  616. end
  617. else
  618. if left.location.loc = LOC_CREGISTER Then
  619. {save the register var in a temp register, because
  620. its value is going to be modified}
  621. begin
  622. hregister := getregister32;
  623. emit_reg_reg(A_MOV,opsize,
  624. left.location.register,hregister);
  625. clear_location(left.location);
  626. left.location.loc:=LOC_REGISTER;
  627. left.location.register:=hregister;
  628. set_location(location,left.location);
  629. end;
  630. {here, left.location should be LOC_REGISTER}
  631. If right.location.loc in [LOC_MEM,LOC_REFERENCE] Then
  632. emit_ref_reg(A_AND,opsize,
  633. newreference(right.location.reference),left.location.register)
  634. Else
  635. emit_reg_reg(A_AND,opsize,
  636. right.location.register,left.location.register);
  637. {warning: ugly hack ahead: we need a "jne" after the cmp, so
  638. change the nodetype from lten/gten to equaln}
  639. nodetype := equaln
  640. End;
  641. {no < or > support for sets}
  642. ltn,gtn: CGMessage(type_e_mismatch);
  643. End;
  644. op:=A_CMP;
  645. cmpop:=true;
  646. end;
  647. xorn : op:=A_XOR;
  648. orn : op:=A_OR;
  649. andn : op:=A_AND;
  650. else
  651. CGMessage(type_e_mismatch);
  652. end;
  653. { filter MUL, which requires special handling }
  654. if op=A_MUL then
  655. begin
  656. popeax:=false;
  657. popedx:=false;
  658. { here you need to free the symbol first }
  659. { left.location and right.location must }
  660. { only be freed when they are really released, }
  661. { because the optimizer NEEDS correct regalloc }
  662. { info!!! (JM) }
  663. clear_location(location);
  664. { the location.register will be filled in later (JM) }
  665. location.loc:=LOC_REGISTER;
  666. {$IfNDef NoShlMul}
  667. if right.nodetype=ordconstn then
  668. swapleftright;
  669. If (left.nodetype = ordconstn) and
  670. ispowerof2(tordconstnode(left).value, power) and
  671. not(cs_check_overflow in aktlocalswitches) then
  672. Begin
  673. { This release will be moved after the next }
  674. { instruction by the optimizer. No need to }
  675. { release left.location, since it's a }
  676. { constant (JM) }
  677. release_loc(right.location);
  678. location.register := getregister32;
  679. emitloadord2reg(right.location,torddef(u32bittype.def),location.register,false);
  680. emit_const_reg(A_SHL,S_L,power,location.register)
  681. End
  682. Else
  683. Begin
  684. {$EndIf NoShlMul}
  685. regstopush := $ff;
  686. remove_non_regvars_from_loc(right.location,regstopush);
  687. remove_non_regvars_from_loc(left.location,regstopush);
  688. { now, regstopush does NOT contain EAX and/or EDX if they are }
  689. { used in either the left or the right location, excepts if }
  690. {they are regvars. It DOES contain them if they are used in }
  691. { another location (JM) }
  692. if not(R_EAX in unused) and ((regstopush and ($80 shr byte(R_EAX))) <> 0) then
  693. begin
  694. emit_reg(A_PUSH,S_L,R_EAX);
  695. popeax:=true;
  696. end;
  697. if not(R_EDX in unused) and ((regstopush and ($80 shr byte(R_EDX))) <> 0) then
  698. begin
  699. emit_reg(A_PUSH,S_L,R_EDX);
  700. popedx:=true;
  701. end;
  702. { left.location can be R_EAX !!! }
  703. getexplicitregister32(R_EDI);
  704. { load the left value }
  705. emitloadord2reg(left.location,torddef(u32bittype.def),R_EDI,true);
  706. release_loc(left.location);
  707. { allocate EAX }
  708. if R_EAX in unused then
  709. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  710. { load he right value }
  711. emitloadord2reg(right.location,torddef(u32bittype.def),R_EAX,true);
  712. release_loc(right.location);
  713. { allocate EAX if it isn't yet allocated (JM) }
  714. if (R_EAX in unused) then
  715. exprasmList.concat(Tairegalloc.Alloc(R_EAX));
  716. { also allocate EDX, since it is also modified by }
  717. { a mul (JM) }
  718. if R_EDX in unused then
  719. exprasmList.concat(Tairegalloc.Alloc(R_EDX));
  720. emit_reg(A_MUL,S_L,R_EDI);
  721. ungetregister32(R_EDI);
  722. if R_EDX in unused then
  723. exprasmList.concat(Tairegalloc.DeAlloc(R_EDX));
  724. if R_EAX in unused then
  725. exprasmList.concat(Tairegalloc.DeAlloc(R_EAX));
  726. location.register := getregister32;
  727. emit_reg_reg(A_MOV,S_L,R_EAX,location.register);
  728. if popedx then
  729. emit_reg(A_POP,S_L,R_EDX);
  730. if popeax then
  731. emit_reg(A_POP,S_L,R_EAX);
  732. {$IfNDef NoShlMul}
  733. End;
  734. {$endif NoShlMul}
  735. SetResultLocation(false,true);
  736. exit;
  737. end;
  738. { Convert flags to register first }
  739. if (left.location.loc=LOC_FLAGS) then
  740. locflags2reg(left.location,opsize);
  741. if (right.location.loc=LOC_FLAGS) then
  742. locflags2reg(right.location,opsize);
  743. { left and right no register? }
  744. { then one must be demanded }
  745. if (left.location.loc<>LOC_REGISTER) and
  746. (right.location.loc<>LOC_REGISTER) then
  747. begin
  748. { register variable ? }
  749. if (left.location.loc=LOC_CREGISTER) then
  750. begin
  751. { it is OK if this is the destination }
  752. if is_in_dest then
  753. begin
  754. hregister:=location.register;
  755. emit_reg_reg(A_MOV,opsize,left.location.register,
  756. hregister);
  757. end
  758. else
  759. if cmpop then
  760. begin
  761. { do not disturb the register }
  762. hregister:=location.register;
  763. end
  764. else
  765. begin
  766. case opsize of
  767. S_L : hregister:=getregister32;
  768. S_B : hregister:=reg32toreg8(getregister32);
  769. end;
  770. emit_reg_reg(A_MOV,opsize,left.location.register,
  771. hregister);
  772. end
  773. end
  774. else
  775. begin
  776. ungetiftemp(left.location.reference);
  777. del_reference(left.location.reference);
  778. if is_in_dest then
  779. begin
  780. hregister:=location.register;
  781. emit_ref_reg(A_MOV,opsize,
  782. newreference(left.location.reference),hregister);
  783. end
  784. else
  785. begin
  786. { first give free, then demand new register }
  787. case opsize of
  788. S_L : hregister:=getregister32;
  789. S_W : hregister:=reg32toreg16(getregister32);
  790. S_B : hregister:=reg32toreg8(getregister32);
  791. end;
  792. emit_ref_reg(A_MOV,opsize,
  793. newreference(left.location.reference),hregister);
  794. end;
  795. end;
  796. clear_location(location);
  797. location.loc:=LOC_REGISTER;
  798. location.register:=hregister;
  799. end
  800. else
  801. { if on the right the register then swap }
  802. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  803. begin
  804. swap_location(location,right.location);
  805. { newly swapped also set swapped flag }
  806. toggleflag(nf_swaped);
  807. end;
  808. { at this point, location.loc should be LOC_REGISTER }
  809. { and location.register should be a valid register }
  810. { containing the left result }
  811. if right.location.loc<>LOC_REGISTER then
  812. begin
  813. if (nodetype=subn) and (nf_swaped in flags) then
  814. begin
  815. if right.location.loc=LOC_CREGISTER then
  816. begin
  817. if extra_not then
  818. emit_reg(A_NOT,opsize,location.register);
  819. getexplicitregister32(R_EDI);
  820. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  821. emit_reg_reg(op,opsize,location.register,R_EDI);
  822. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  823. ungetregister32(R_EDI);
  824. end
  825. else
  826. begin
  827. if extra_not then
  828. emit_reg(A_NOT,opsize,location.register);
  829. getexplicitregister32(R_EDI);
  830. emit_ref_reg(A_MOV,opsize,
  831. newreference(right.location.reference),R_EDI);
  832. emit_reg_reg(op,opsize,location.register,R_EDI);
  833. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  834. ungetregister32(R_EDI);
  835. ungetiftemp(right.location.reference);
  836. del_reference(right.location.reference);
  837. end;
  838. end
  839. else
  840. begin
  841. if (right.nodetype=ordconstn) and
  842. (op=A_CMP) and
  843. (tordconstnode(right).value=0) then
  844. begin
  845. emit_reg_reg(A_TEST,opsize,location.register,
  846. location.register);
  847. end
  848. else if (right.nodetype=ordconstn) and
  849. (op=A_ADD) and
  850. (tordconstnode(right).value=1) and
  851. not(cs_check_overflow in aktlocalswitches) then
  852. begin
  853. emit_reg(A_INC,opsize,
  854. location.register);
  855. end
  856. else if (right.nodetype=ordconstn) and
  857. (op=A_SUB) and
  858. (tordconstnode(right).value=1) and
  859. not(cs_check_overflow in aktlocalswitches) then
  860. begin
  861. emit_reg(A_DEC,opsize,
  862. location.register);
  863. end
  864. else if (right.nodetype=ordconstn) and
  865. (op=A_IMUL) and
  866. (ispowerof2(tordconstnode(right).value,power)) and
  867. not(cs_check_overflow in aktlocalswitches) then
  868. begin
  869. emit_const_reg(A_SHL,opsize,power,
  870. location.register);
  871. end
  872. else
  873. begin
  874. if (right.location.loc=LOC_CREGISTER) then
  875. begin
  876. if extra_not then
  877. begin
  878. getexplicitregister32(R_EDI);
  879. emit_reg_reg(A_MOV,S_L,right.location.register,R_EDI);
  880. emit_reg(A_NOT,S_L,R_EDI);
  881. emit_reg_reg(A_AND,S_L,R_EDI,
  882. location.register);
  883. ungetregister32(R_EDI);
  884. end
  885. else
  886. begin
  887. emit_reg_reg(op,opsize,right.location.register,
  888. location.register);
  889. end;
  890. end
  891. else
  892. begin
  893. if extra_not then
  894. begin
  895. getexplicitregister32(R_EDI);
  896. emit_ref_reg(A_MOV,S_L,newreference(
  897. right.location.reference),R_EDI);
  898. emit_reg(A_NOT,S_L,R_EDI);
  899. emit_reg_reg(A_AND,S_L,R_EDI,
  900. location.register);
  901. ungetregister32(R_EDI);
  902. end
  903. else
  904. begin
  905. emit_ref_reg(op,opsize,newreference(
  906. right.location.reference),location.register);
  907. end;
  908. ungetiftemp(right.location.reference);
  909. del_reference(right.location.reference);
  910. end;
  911. end;
  912. end;
  913. end
  914. else
  915. begin
  916. { when swapped another result register }
  917. if (nodetype=subn) and (nf_swaped in flags) then
  918. begin
  919. if extra_not then
  920. emit_reg(A_NOT,S_L,location.register);
  921. emit_reg_reg(op,opsize,
  922. location.register,right.location.register);
  923. swap_location(location,right.location);
  924. { newly swapped also set swapped flag }
  925. { just to maintain ordering }
  926. toggleflag(nf_swaped);
  927. end
  928. else
  929. begin
  930. if extra_not then
  931. emit_reg(A_NOT,S_L,right.location.register);
  932. emit_reg_reg(op,opsize,
  933. right.location.register,
  934. location.register);
  935. end;
  936. case opsize of
  937. S_L : ungetregister32(right.location.register);
  938. S_B : ungetregister32(reg8toreg32(right.location.register));
  939. end;
  940. end;
  941. if cmpop then
  942. case opsize of
  943. S_L : ungetregister32(location.register);
  944. S_B : ungetregister32(reg8toreg32(location.register));
  945. end;
  946. { only in case of overflow operations }
  947. { produce overflow code }
  948. { we must put it here directly, because sign of operation }
  949. { is in unsigned VAR!! }
  950. if mboverflow then
  951. begin
  952. if cs_check_overflow in aktlocalswitches then
  953. begin
  954. getlabel(hl4);
  955. if unsigned then
  956. emitjmp(C_NB,hl4)
  957. else
  958. emitjmp(C_NO,hl4);
  959. emitcall('FPC_OVERFLOW');
  960. emitlab(hl4);
  961. end;
  962. end;
  963. end
  964. else
  965. { Char type }
  966. if ((left.resulttype.def.deftype=orddef) and
  967. (torddef(left.resulttype.def).typ=uchar)) or
  968. { enumeration type 16 bit }
  969. ((left.resulttype.def.deftype=enumdef) and
  970. (left.resulttype.def.size=1)) then
  971. begin
  972. case nodetype of
  973. ltn,lten,gtn,gten,
  974. equaln,unequaln :
  975. cmpop:=true;
  976. else CGMessage(type_e_mismatch);
  977. end;
  978. unsigned:=true;
  979. { left and right no register? }
  980. { the one must be demanded }
  981. if (location.loc<>LOC_REGISTER) and
  982. (right.location.loc<>LOC_REGISTER) then
  983. begin
  984. if location.loc=LOC_CREGISTER then
  985. begin
  986. if cmpop then
  987. { do not disturb register }
  988. hregister:=location.register
  989. else
  990. begin
  991. hregister:=reg32toreg8(getregister32);
  992. emit_reg_reg(A_MOV,S_B,location.register,
  993. hregister);
  994. end;
  995. end
  996. else
  997. begin
  998. del_reference(location.reference);
  999. { first give free then demand new register }
  1000. hregister:=reg32toreg8(getregister32);
  1001. emit_ref_reg(A_MOV,S_B,newreference(location.reference),
  1002. hregister);
  1003. end;
  1004. clear_location(location);
  1005. location.loc:=LOC_REGISTER;
  1006. location.register:=hregister;
  1007. end;
  1008. { now p always a register }
  1009. if (right.location.loc=LOC_REGISTER) and
  1010. (location.loc<>LOC_REGISTER) then
  1011. begin
  1012. swap_location(location,right.location);
  1013. { newly swapped also set swapped flag }
  1014. toggleflag(nf_swaped);
  1015. end;
  1016. if right.location.loc<>LOC_REGISTER then
  1017. begin
  1018. if right.location.loc=LOC_CREGISTER then
  1019. begin
  1020. emit_reg_reg(A_CMP,S_B,
  1021. right.location.register,location.register);
  1022. end
  1023. else
  1024. begin
  1025. emit_ref_reg(A_CMP,S_B,newreference(
  1026. right.location.reference),location.register);
  1027. del_reference(right.location.reference);
  1028. end;
  1029. end
  1030. else
  1031. begin
  1032. emit_reg_reg(A_CMP,S_B,right.location.register,
  1033. location.register);
  1034. ungetregister32(reg8toreg32(right.location.register));
  1035. end;
  1036. ungetregister32(reg8toreg32(location.register));
  1037. end
  1038. else
  1039. { 16 bit enumeration type }
  1040. if ((left.resulttype.def.deftype=enumdef) and
  1041. (left.resulttype.def.size=2)) then
  1042. begin
  1043. case nodetype of
  1044. ltn,lten,gtn,gten,
  1045. equaln,unequaln :
  1046. cmpop:=true;
  1047. else CGMessage(type_e_mismatch);
  1048. end;
  1049. unsigned:=true;
  1050. { left and right no register? }
  1051. { the one must be demanded }
  1052. if (location.loc<>LOC_REGISTER) and
  1053. (right.location.loc<>LOC_REGISTER) then
  1054. begin
  1055. if location.loc=LOC_CREGISTER then
  1056. begin
  1057. if cmpop then
  1058. { do not disturb register }
  1059. hregister:=location.register
  1060. else
  1061. begin
  1062. hregister:=reg32toreg16(getregister32);
  1063. emit_reg_reg(A_MOV,S_W,location.register,
  1064. hregister);
  1065. end;
  1066. end
  1067. else
  1068. begin
  1069. del_reference(location.reference);
  1070. { first give free then demand new register }
  1071. hregister:=reg32toreg16(getregister32);
  1072. emit_ref_reg(A_MOV,S_W,newreference(location.reference),
  1073. hregister);
  1074. end;
  1075. clear_location(location);
  1076. location.loc:=LOC_REGISTER;
  1077. location.register:=hregister;
  1078. end;
  1079. { now p always a register }
  1080. if (right.location.loc=LOC_REGISTER) and
  1081. (location.loc<>LOC_REGISTER) then
  1082. begin
  1083. swap_location(location,right.location);
  1084. { newly swapped also set swapped flag }
  1085. toggleflag(nf_swaped);
  1086. end;
  1087. if right.location.loc<>LOC_REGISTER then
  1088. begin
  1089. if right.location.loc=LOC_CREGISTER then
  1090. begin
  1091. emit_reg_reg(A_CMP,S_W,
  1092. right.location.register,location.register);
  1093. end
  1094. else
  1095. begin
  1096. emit_ref_reg(A_CMP,S_W,newreference(
  1097. right.location.reference),location.register);
  1098. del_reference(right.location.reference);
  1099. end;
  1100. end
  1101. else
  1102. begin
  1103. emit_reg_reg(A_CMP,S_W,right.location.register,
  1104. location.register);
  1105. ungetregister32(reg16toreg32(right.location.register));
  1106. end;
  1107. ungetregister32(reg16toreg32(location.register));
  1108. end
  1109. else
  1110. { 64 bit types }
  1111. if is_64bitint(left.resulttype.def) then
  1112. begin
  1113. mboverflow:=false;
  1114. cmpop:=false;
  1115. unsigned:=((left.resulttype.def.deftype=orddef) and
  1116. (torddef(left.resulttype.def).typ=u64bit)) or
  1117. ((right.resulttype.def.deftype=orddef) and
  1118. (torddef(right.resulttype.def).typ=u64bit));
  1119. case nodetype of
  1120. addn : begin
  1121. begin
  1122. op:=A_ADD;
  1123. op2:=A_ADC;
  1124. mboverflow:=true;
  1125. end;
  1126. end;
  1127. subn : begin
  1128. op:=A_SUB;
  1129. op2:=A_SBB;
  1130. mboverflow:=true;
  1131. end;
  1132. ltn,lten,
  1133. gtn,gten,
  1134. equaln,unequaln:
  1135. begin
  1136. op:=A_CMP;
  1137. op2:=A_CMP;
  1138. cmpop:=true;
  1139. end;
  1140. xorn:
  1141. begin
  1142. op:=A_XOR;
  1143. op2:=A_XOR;
  1144. end;
  1145. orn:
  1146. begin
  1147. op:=A_OR;
  1148. op2:=A_OR;
  1149. end;
  1150. andn:
  1151. begin
  1152. op:=A_AND;
  1153. op2:=A_AND;
  1154. end;
  1155. muln:
  1156. ;
  1157. else
  1158. CGMessage(type_e_mismatch);
  1159. end;
  1160. if nodetype=muln then
  1161. begin
  1162. { should be handled in pass_1 (JM) }
  1163. internalerror(200109051);
  1164. end
  1165. else
  1166. begin
  1167. { left and right no register? }
  1168. { then one must be demanded }
  1169. if (left.location.loc<>LOC_REGISTER) and
  1170. (right.location.loc<>LOC_REGISTER) then
  1171. begin
  1172. { register variable ? }
  1173. if (left.location.loc=LOC_CREGISTER) then
  1174. begin
  1175. { it is OK if this is the destination }
  1176. if is_in_dest then
  1177. begin
  1178. hregister:=location.registerlow;
  1179. hregister2:=location.registerhigh;
  1180. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1181. hregister);
  1182. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1183. hregister2);
  1184. end
  1185. else
  1186. if cmpop then
  1187. begin
  1188. { do not disturb the register }
  1189. hregister:=location.registerlow;
  1190. hregister2:=location.registerhigh;
  1191. end
  1192. else
  1193. begin
  1194. hregister:=getregister32;
  1195. hregister2:=getregister32;
  1196. emit_reg_reg(A_MOV,S_L,left.location.registerlow,
  1197. hregister);
  1198. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,
  1199. hregister2);
  1200. end
  1201. end
  1202. else
  1203. begin
  1204. ungetiftemp(left.location.reference);
  1205. del_reference(left.location.reference);
  1206. if is_in_dest then
  1207. begin
  1208. hregister:=location.registerlow;
  1209. hregister2:=location.registerhigh;
  1210. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1211. end
  1212. else
  1213. begin
  1214. hregister:=getregister32;
  1215. hregister2:=getregister32;
  1216. emit_mov_ref_reg64(left.location.reference,hregister,hregister2);
  1217. end;
  1218. end;
  1219. clear_location(location);
  1220. location.loc:=LOC_REGISTER;
  1221. location.registerlow:=hregister;
  1222. location.registerhigh:=hregister2;
  1223. end
  1224. else
  1225. { if on the right the register then swap }
  1226. if not(noswap) and (right.location.loc=LOC_REGISTER) then
  1227. begin
  1228. swap_location(location,right.location);
  1229. { newly swapped also set swapped flag }
  1230. toggleflag(nf_swaped);
  1231. end;
  1232. { at this point, location.loc should be LOC_REGISTER }
  1233. { and location.register should be a valid register }
  1234. { containing the left result }
  1235. if right.location.loc<>LOC_REGISTER then
  1236. begin
  1237. if (nodetype=subn) and (nf_swaped in flags) then
  1238. begin
  1239. if right.location.loc=LOC_CREGISTER then
  1240. begin
  1241. getexplicitregister32(R_EDI);
  1242. emit_reg_reg(A_MOV,opsize,right.location.register,R_EDI);
  1243. emit_reg_reg(op,opsize,location.register,R_EDI);
  1244. emit_reg_reg(A_MOV,opsize,R_EDI,location.register);
  1245. ungetregister32(R_EDI);
  1246. getexplicitregister32(R_EDI);
  1247. emit_reg_reg(A_MOV,opsize,right.location.registerhigh,R_EDI);
  1248. { the carry flag is still ok }
  1249. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1250. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerhigh);
  1251. ungetregister32(R_EDI);
  1252. end
  1253. else
  1254. begin
  1255. getexplicitregister32(R_EDI);
  1256. emit_ref_reg(A_MOV,opsize,
  1257. newreference(right.location.reference),R_EDI);
  1258. emit_reg_reg(op,opsize,location.registerlow,R_EDI);
  1259. emit_reg_reg(A_MOV,opsize,R_EDI,location.registerlow);
  1260. ungetregister32(R_EDI);
  1261. getexplicitregister32(R_EDI);
  1262. hr:=newreference(right.location.reference);
  1263. inc(hr^.offset,4);
  1264. emit_ref_reg(A_MOV,opsize,
  1265. hr,R_EDI);
  1266. { here the carry flag is still preserved }
  1267. emit_reg_reg(op2,opsize,location.registerhigh,R_EDI);
  1268. emit_reg_reg(A_MOV,opsize,R_EDI,
  1269. location.registerhigh);
  1270. ungetregister32(R_EDI);
  1271. ungetiftemp(right.location.reference);
  1272. del_reference(right.location.reference);
  1273. end;
  1274. end
  1275. else if cmpop then
  1276. begin
  1277. if (right.location.loc=LOC_CREGISTER) then
  1278. begin
  1279. emit_reg_reg(A_CMP,S_L,right.location.registerhigh,
  1280. location.registerhigh);
  1281. firstjmp64bitcmp;
  1282. emit_reg_reg(A_CMP,S_L,right.location.registerlow,
  1283. location.registerlow);
  1284. secondjmp64bitcmp;
  1285. end
  1286. else
  1287. begin
  1288. hr:=newreference(right.location.reference);
  1289. inc(hr^.offset,4);
  1290. emit_ref_reg(A_CMP,S_L,
  1291. hr,location.registerhigh);
  1292. firstjmp64bitcmp;
  1293. emit_ref_reg(A_CMP,S_L,newreference(
  1294. right.location.reference),location.registerlow);
  1295. secondjmp64bitcmp;
  1296. emitjmp(C_None,falselabel);
  1297. ungetiftemp(right.location.reference);
  1298. del_reference(right.location.reference);
  1299. end;
  1300. end
  1301. else
  1302. begin
  1303. {
  1304. if (right.nodetype=ordconstn) and
  1305. (op=A_CMP) and
  1306. (right.value=0) then
  1307. begin
  1308. emit_reg_reg(A_TEST,opsize,location.register,
  1309. location.register);
  1310. end
  1311. else if (right.nodetype=ordconstn) and
  1312. (op=A_IMUL) and
  1313. (ispowerof2(right.value,power)) then
  1314. begin
  1315. emit_const_reg(A_SHL,opsize,power,
  1316. location.register);
  1317. end
  1318. else
  1319. }
  1320. begin
  1321. if (right.location.loc=LOC_CREGISTER) then
  1322. begin
  1323. emit_reg_reg(op,S_L,right.location.registerlow,
  1324. location.registerlow);
  1325. emit_reg_reg(op2,S_L,right.location.registerhigh,
  1326. location.registerhigh);
  1327. end
  1328. else
  1329. begin
  1330. emit_ref_reg(op,S_L,newreference(
  1331. right.location.reference),location.registerlow);
  1332. hr:=newreference(right.location.reference);
  1333. inc(hr^.offset,4);
  1334. emit_ref_reg(op2,S_L,
  1335. hr,location.registerhigh);
  1336. ungetiftemp(right.location.reference);
  1337. del_reference(right.location.reference);
  1338. end;
  1339. end;
  1340. end;
  1341. end
  1342. else
  1343. begin
  1344. { when swapped another result register }
  1345. if (nodetype=subn) and (nf_swaped in flags) then
  1346. begin
  1347. emit_reg_reg(op,S_L,
  1348. location.registerlow,
  1349. right.location.registerlow);
  1350. emit_reg_reg(op2,S_L,
  1351. location.registerhigh,
  1352. right.location.registerhigh);
  1353. swap_location(location,right.location);
  1354. { newly swapped also set swapped flag }
  1355. { just to maintain ordering }
  1356. toggleflag(nf_swaped);
  1357. end
  1358. else if cmpop then
  1359. begin
  1360. emit_reg_reg(A_CMP,S_L,
  1361. right.location.registerhigh,
  1362. location.registerhigh);
  1363. firstjmp64bitcmp;
  1364. emit_reg_reg(A_CMP,S_L,
  1365. right.location.registerlow,
  1366. location.registerlow);
  1367. secondjmp64bitcmp;
  1368. end
  1369. else
  1370. begin
  1371. emit_reg_reg(op,S_L,
  1372. right.location.registerlow,
  1373. location.registerlow);
  1374. emit_reg_reg(op2,S_L,
  1375. right.location.registerhigh,
  1376. location.registerhigh);
  1377. end;
  1378. ungetregister32(right.location.registerlow);
  1379. ungetregister32(right.location.registerhigh);
  1380. end;
  1381. if cmpop then
  1382. begin
  1383. ungetregister32(location.registerlow);
  1384. ungetregister32(location.registerhigh);
  1385. end;
  1386. { only in case of overflow operations }
  1387. { produce overflow code }
  1388. { we must put it here directly, because sign of operation }
  1389. { is in unsigned VAR!! }
  1390. if mboverflow then
  1391. begin
  1392. if cs_check_overflow in aktlocalswitches then
  1393. begin
  1394. getlabel(hl4);
  1395. if unsigned then
  1396. emitjmp(C_NB,hl4)
  1397. else
  1398. emitjmp(C_NO,hl4);
  1399. emitcall('FPC_OVERFLOW');
  1400. emitlab(hl4);
  1401. end;
  1402. end;
  1403. { we have LOC_JUMP as result }
  1404. if cmpop then
  1405. begin
  1406. clear_location(location);
  1407. location.loc:=LOC_JUMP;
  1408. cmpop:=false;
  1409. end;
  1410. end;
  1411. end
  1412. else
  1413. { Floating point }
  1414. if (left.resulttype.def.deftype=floatdef) then
  1415. begin
  1416. { real constants to the right, but only if it
  1417. isn't on the FPU stack, i.e. 1.0 or 0.0!
  1418. if (left.nodetype=realconstn) and
  1419. (left.location.loc<>LOC_FPU) then
  1420. swapleftright; obsolete, already swaped above PM }
  1421. cmpop:=false;
  1422. case nodetype of
  1423. addn : op:=A_FADDP;
  1424. muln : op:=A_FMULP;
  1425. subn : op:=A_FSUBP;
  1426. slashn : op:=A_FDIVP;
  1427. ltn,lten,gtn,gten,
  1428. equaln,unequaln : begin
  1429. op:=A_FCOMPP;
  1430. cmpop:=true;
  1431. end;
  1432. else CGMessage(type_e_mismatch);
  1433. end;
  1434. if (right.location.loc<>LOC_FPU) then
  1435. begin
  1436. if right.location.loc=LOC_CFPUREGISTER then
  1437. begin
  1438. emit_reg( A_FLD,S_NO,
  1439. correct_fpuregister(right.location.register,fpuvaroffset));
  1440. inc(fpuvaroffset);
  1441. end
  1442. else
  1443. begin
  1444. floatload(tfloatdef(right.resulttype.def).typ,right.location.reference);
  1445. if pushedfpu then
  1446. ungetiftemp(right.location.reference);
  1447. end;
  1448. if (left.location.loc<>LOC_FPU) then
  1449. begin
  1450. if left.location.loc=LOC_CFPUREGISTER then
  1451. begin
  1452. emit_reg( A_FLD,S_NO,
  1453. correct_fpuregister(left.location.register,fpuvaroffset));
  1454. inc(fpuvaroffset);
  1455. end
  1456. else
  1457. begin
  1458. floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
  1459. if pushedfpu then
  1460. ungetiftemp(left.location.reference);
  1461. end;
  1462. end
  1463. { left was on the stack => swap }
  1464. else
  1465. toggleflag(nf_swaped);
  1466. { releases the right reference }
  1467. del_reference(right.location.reference);
  1468. end
  1469. { the nominator in st0 }
  1470. else if (left.location.loc<>LOC_FPU) then
  1471. begin
  1472. if left.location.loc=LOC_CFPUREGISTER then
  1473. begin
  1474. emit_reg( A_FLD,S_NO,
  1475. correct_fpuregister(left.location.register,fpuvaroffset));
  1476. inc(fpuvaroffset);
  1477. end
  1478. else
  1479. begin
  1480. floatload(tfloatdef(left.resulttype.def).typ,left.location.reference);
  1481. if pushedfpu then
  1482. ungetiftemp(left.location.reference);
  1483. end;
  1484. end
  1485. { fpu operands are always in the wrong order on the stack }
  1486. else
  1487. toggleflag(nf_swaped);
  1488. { releases the left reference }
  1489. if (left.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  1490. del_reference(left.location.reference);
  1491. { if we swaped the tree nodes, then use the reverse operator }
  1492. if nf_swaped in flags then
  1493. begin
  1494. if (nodetype=slashn) then
  1495. op:=A_FDIVRP
  1496. else if (nodetype=subn) then
  1497. op:=A_FSUBRP;
  1498. end;
  1499. { to avoid the pentium bug
  1500. if (op=FDIVP) and (opt_processors=pentium) then
  1501. emitcall('EMUL_FDIVP')
  1502. else
  1503. }
  1504. { the Intel assemblers want operands }
  1505. if op<>A_FCOMPP then
  1506. begin
  1507. emit_reg_reg(op,S_NO,R_ST,R_ST1);
  1508. dec(fpuvaroffset);
  1509. end
  1510. else
  1511. begin
  1512. emit_none(op,S_NO);
  1513. dec(fpuvaroffset,2);
  1514. end;
  1515. { on comparison load flags }
  1516. if cmpop then
  1517. begin
  1518. if not(R_EAX in unused) then
  1519. begin
  1520. getexplicitregister32(R_EDI);
  1521. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  1522. end;
  1523. emit_reg(A_FNSTSW,S_NO,R_AX);
  1524. emit_none(A_SAHF,S_NO);
  1525. if not(R_EAX in unused) then
  1526. begin
  1527. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  1528. ungetregister32(R_EDI);
  1529. end;
  1530. if nf_swaped in flags then
  1531. begin
  1532. case nodetype of
  1533. equaln : resflags:=F_E;
  1534. unequaln : resflags:=F_NE;
  1535. ltn : resflags:=F_A;
  1536. lten : resflags:=F_AE;
  1537. gtn : resflags:=F_B;
  1538. gten : resflags:=F_BE;
  1539. end;
  1540. end
  1541. else
  1542. begin
  1543. case nodetype of
  1544. equaln : resflags:=F_E;
  1545. unequaln : resflags:=F_NE;
  1546. ltn : resflags:=F_B;
  1547. lten : resflags:=F_BE;
  1548. gtn : resflags:=F_A;
  1549. gten : resflags:=F_AE;
  1550. end;
  1551. end;
  1552. clear_location(location);
  1553. location.loc:=LOC_FLAGS;
  1554. location.resflags:=resflags;
  1555. cmpop:=false;
  1556. end
  1557. else
  1558. begin
  1559. clear_location(location);
  1560. location.loc:=LOC_FPU;
  1561. end;
  1562. end
  1563. {$ifdef SUPPORT_MMX}
  1564. else
  1565. { MMX Arrays }
  1566. if is_mmx_able_array(left.resulttype.def) then
  1567. begin
  1568. cmpop:=false;
  1569. mmxbase:=mmx_type(left.resulttype.def);
  1570. case nodetype of
  1571. addn : begin
  1572. if (cs_mmx_saturation in aktlocalswitches) then
  1573. begin
  1574. case mmxbase of
  1575. mmxs8bit:
  1576. op:=A_PADDSB;
  1577. mmxu8bit:
  1578. op:=A_PADDUSB;
  1579. mmxs16bit,mmxfixed16:
  1580. op:=A_PADDSB;
  1581. mmxu16bit:
  1582. op:=A_PADDUSW;
  1583. end;
  1584. end
  1585. else
  1586. begin
  1587. case mmxbase of
  1588. mmxs8bit,mmxu8bit:
  1589. op:=A_PADDB;
  1590. mmxs16bit,mmxu16bit,mmxfixed16:
  1591. op:=A_PADDW;
  1592. mmxs32bit,mmxu32bit:
  1593. op:=A_PADDD;
  1594. end;
  1595. end;
  1596. end;
  1597. muln : begin
  1598. case mmxbase of
  1599. mmxs16bit,mmxu16bit:
  1600. op:=A_PMULLW;
  1601. mmxfixed16:
  1602. op:=A_PMULHW;
  1603. end;
  1604. end;
  1605. subn : begin
  1606. if (cs_mmx_saturation in aktlocalswitches) then
  1607. begin
  1608. case mmxbase of
  1609. mmxs8bit:
  1610. op:=A_PSUBSB;
  1611. mmxu8bit:
  1612. op:=A_PSUBUSB;
  1613. mmxs16bit,mmxfixed16:
  1614. op:=A_PSUBSB;
  1615. mmxu16bit:
  1616. op:=A_PSUBUSW;
  1617. end;
  1618. end
  1619. else
  1620. begin
  1621. case mmxbase of
  1622. mmxs8bit,mmxu8bit:
  1623. op:=A_PSUBB;
  1624. mmxs16bit,mmxu16bit,mmxfixed16:
  1625. op:=A_PSUBW;
  1626. mmxs32bit,mmxu32bit:
  1627. op:=A_PSUBD;
  1628. end;
  1629. end;
  1630. end;
  1631. {
  1632. ltn,lten,gtn,gten,
  1633. equaln,unequaln :
  1634. begin
  1635. op:=A_CMP;
  1636. cmpop:=true;
  1637. end;
  1638. }
  1639. xorn:
  1640. op:=A_PXOR;
  1641. orn:
  1642. op:=A_POR;
  1643. andn:
  1644. op:=A_PAND;
  1645. else CGMessage(type_e_mismatch);
  1646. end;
  1647. { left and right no register? }
  1648. { then one must be demanded }
  1649. if (left.location.loc<>LOC_MMXREGISTER) and
  1650. (right.location.loc<>LOC_MMXREGISTER) then
  1651. begin
  1652. { register variable ? }
  1653. if (left.location.loc=LOC_CMMXREGISTER) then
  1654. begin
  1655. { it is OK if this is the destination }
  1656. if is_in_dest then
  1657. begin
  1658. hregister:=location.register;
  1659. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  1660. hregister);
  1661. end
  1662. else
  1663. begin
  1664. hregister:=getregistermmx;
  1665. emit_reg_reg(A_MOVQ,S_NO,left.location.register,
  1666. hregister);
  1667. end
  1668. end
  1669. else
  1670. begin
  1671. del_reference(left.location.reference);
  1672. if is_in_dest then
  1673. begin
  1674. hregister:=location.register;
  1675. emit_ref_reg(A_MOVQ,S_NO,
  1676. newreference(left.location.reference),hregister);
  1677. end
  1678. else
  1679. begin
  1680. hregister:=getregistermmx;
  1681. emit_ref_reg(A_MOVQ,S_NO,
  1682. newreference(left.location.reference),hregister);
  1683. end;
  1684. end;
  1685. clear_location(location);
  1686. location.loc:=LOC_MMXREGISTER;
  1687. location.register:=hregister;
  1688. end
  1689. else
  1690. { if on the right the register then swap }
  1691. if (right.location.loc=LOC_MMXREGISTER) then
  1692. begin
  1693. swap_location(location,right.location);
  1694. { newly swapped also set swapped flag }
  1695. toggleflag(nf_swaped);
  1696. end;
  1697. { at this point, location.loc should be LOC_MMXREGISTER }
  1698. { and location.register should be a valid register }
  1699. { containing the left result }
  1700. if right.location.loc<>LOC_MMXREGISTER then
  1701. begin
  1702. if (nodetype=subn) and (nf_swaped in flags) then
  1703. begin
  1704. if right.location.loc=LOC_CMMXREGISTER then
  1705. begin
  1706. emit_reg_reg(A_MOVQ,S_NO,right.location.register,R_MM7);
  1707. emit_reg_reg(op,S_NO,location.register,R_MM0);
  1708. emit_reg_reg(A_MOVQ,S_NO,R_MM7,location.register);
  1709. end
  1710. else
  1711. begin
  1712. emit_ref_reg(A_MOVQ,S_NO,
  1713. newreference(right.location.reference),R_MM7);
  1714. emit_reg_reg(op,S_NO,location.register,
  1715. R_MM7);
  1716. emit_reg_reg(A_MOVQ,S_NO,
  1717. R_MM7,location.register);
  1718. del_reference(right.location.reference);
  1719. end;
  1720. end
  1721. else
  1722. begin
  1723. if (right.location.loc=LOC_CREGISTER) then
  1724. begin
  1725. emit_reg_reg(op,S_NO,right.location.register,
  1726. location.register);
  1727. end
  1728. else
  1729. begin
  1730. emit_ref_reg(op,S_NO,newreference(
  1731. right.location.reference),location.register);
  1732. del_reference(right.location.reference);
  1733. end;
  1734. end;
  1735. end
  1736. else
  1737. begin
  1738. { when swapped another result register }
  1739. if (nodetype=subn) and (nf_swaped in flags) then
  1740. begin
  1741. emit_reg_reg(op,S_NO,
  1742. location.register,right.location.register);
  1743. swap_location(location,right.location);
  1744. { newly swapped also set swapped flag }
  1745. { just to maintain ordering }
  1746. toggleflag(nf_swaped);
  1747. end
  1748. else
  1749. begin
  1750. emit_reg_reg(op,S_NO,
  1751. right.location.register,
  1752. location.register);
  1753. end;
  1754. ungetregistermmx(right.location.register);
  1755. end;
  1756. end
  1757. {$endif SUPPORT_MMX}
  1758. else CGMessage(type_e_mismatch);
  1759. end;
  1760. SetResultLocation(cmpop,unsigned);
  1761. end;
  1762. begin
  1763. caddnode:=ti386addnode;
  1764. end.
  1765. {
  1766. $Log$
  1767. Revision 1.24 2001-09-17 21:29:13 peter
  1768. * merged netbsd, fpu-overflow from fixes branch
  1769. Revision 1.23 2001/09/05 15:22:09 jonas
  1770. * made multiplying, dividing and mod'ing of int64 and qword processor
  1771. independent with compilerprocs (+ small optimizations by using shift/and
  1772. where possible)
  1773. Revision 1.22 2001/09/04 11:38:55 jonas
  1774. + searchsystype() and searchsystype() functions in symtable
  1775. * changed ninl and nadd to use these functions
  1776. * i386 set comparison functions now return their results in al instead
  1777. of in the flags so that they can be sued as compilerprocs
  1778. - removed all processor specific code from n386add.pas that has to do
  1779. with set handling, it's now all done in nadd.pas
  1780. * fixed fpc_set_contains_sets in genset.inc
  1781. * fpc_set_in_byte is now coded inline in n386set.pas and doesn't use a
  1782. helper anymore
  1783. * some small fixes in compproc.inc/set.inc regarding the declaration of
  1784. internal helper types (fpc_small_set and fpc_normal_set)
  1785. Revision 1.21 2001/09/03 13:27:42 jonas
  1786. * compilerproc implementation of set addition/substraction/...
  1787. * changed the declaration of some set helpers somewhat to accomodate the
  1788. above change
  1789. * i386 still uses the old code for comparisons of sets, because its
  1790. helpers return the results in the flags
  1791. * dummy tc_normal_2_small_set type conversion because I need the original
  1792. resulttype of the set add nodes
  1793. NOTE: you have to start a cycle with 1.0.5!
  1794. Revision 1.20 2001/08/30 15:43:14 jonas
  1795. * converted adding/comparing of strings to compileproc. Note that due
  1796. to the way the shortstring helpers for i386 are written, they are
  1797. still handled by the old code (reason: fpc_shortstr_compare returns
  1798. results in the flags instead of in eax and fpc_shortstr_concat
  1799. has wierd parameter conventions). The compilerproc stuff should work
  1800. fine with the generic implementations though.
  1801. * removed some nested comments warnings
  1802. Revision 1.19 2001/08/29 17:50:45 jonas
  1803. * removed unused var
  1804. Revision 1.18 2001/08/29 12:03:23 jonas
  1805. * fixed wrong regalloc info around FPC_MUL/DIV/MOD_INT64/QWORD calls
  1806. * fixed partial result overwriting with the above calls too
  1807. Revision 1.17 2001/08/26 13:36:55 florian
  1808. * some cg reorganisation
  1809. * some PPC updates
  1810. Revision 1.16 2001/07/08 21:00:16 peter
  1811. * various widestring updates, it works now mostly without charset
  1812. mapping supported
  1813. Revision 1.15 2001/06/25 14:11:37 jonas
  1814. * fixed set bug discovered by Carl (merged)
  1815. Revision 1.14 2001/06/18 20:36:25 peter
  1816. * -Ur switch (merged)
  1817. * masm fixes (merged)
  1818. * quoted filenames for go32v2 and win32
  1819. Revision 1.13 2001/05/27 14:30:56 florian
  1820. + some widestring stuff added
  1821. Revision 1.12 2001/05/06 17:12:14 jonas
  1822. * fixed an IE10 and another bug with [var1..var2] construct
  1823. Revision 1.11 2001/04/13 01:22:18 peter
  1824. * symtable change to classes
  1825. * range check generation and errors fixed, make cycle DEBUG=1 works
  1826. * memory leaks fixed
  1827. Revision 1.10 2001/04/02 21:20:36 peter
  1828. * resulttype rewrite
  1829. Revision 1.9 2000/12/31 11:14:11 jonas
  1830. + implemented/fixed docompare() mathods for all nodes (not tested)
  1831. + nopt.pas, nadd.pas, i386/n386opt.pas: optimized nodes for adding strings
  1832. and constant strings/chars together
  1833. * n386add.pas: don't copy temp strings (of size 256) to another temp string
  1834. when adding
  1835. Revision 1.8 2000/12/25 00:07:32 peter
  1836. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1837. tlinkedlist objects)
  1838. Revision 1.7 2000/12/16 15:56:18 jonas
  1839. - removed all ifdef cardinalmulfix code
  1840. Revision 1.6 2000/12/05 11:44:32 jonas
  1841. + new integer regvar handling, should be much more efficient
  1842. Revision 1.5 2000/11/29 00:30:45 florian
  1843. * unused units removed from uses clause
  1844. * some changes for widestrings
  1845. Revision 1.4 2000/11/13 11:30:56 florian
  1846. * some bugs with interfaces and NIL fixed
  1847. Revision 1.3 2000/11/04 14:25:23 florian
  1848. + merged Attila's changes for interfaces, not tested yet
  1849. Revision 1.2 2000/10/31 22:02:56 peter
  1850. * symtable splitted, no real code changes
  1851. Revision 1.1 2000/10/15 09:33:31 peter
  1852. * moved n386*.pas to i386/ cpu_target dir
  1853. Revision 1.6 2000/10/14 10:14:47 peter
  1854. * moehrendorf oct 2000 rewrite
  1855. Revision 1.5 2000/09/30 16:08:45 peter
  1856. * more cg11 updates
  1857. Revision 1.4 2000/09/24 15:06:18 peter
  1858. * use defines.inc
  1859. Revision 1.3 2000/09/22 22:42:52 florian
  1860. * more fixes
  1861. Revision 1.2 2000/09/21 12:24:22 jonas
  1862. * small fix to my changes for full boolean evaluation support (moved
  1863. opsize determination for boolean operations back in boolean
  1864. processing block)
  1865. + full boolean evaluation support (from cg386add)
  1866. Revision 1.1 2000/09/20 21:23:32 florian
  1867. * initial revision
  1868. }