n386add.pas 91 KB

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