n386add.pas 91 KB

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