n386add.pas 91 KB

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