cg386add.pas 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate i386 assembler for in add node
  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 cg386add;
  19. interface
  20. uses
  21. tree;
  22. procedure secondadd(var p : ptree);
  23. implementation
  24. uses
  25. cobjects,verbose,globals,
  26. symtable,aasm,i386,types,
  27. cgi386,cgai386,temp_gen,tgeni386,hcodegen;
  28. {*****************************************************************************
  29. Helpers
  30. *****************************************************************************}
  31. procedure SetResultLocation(cmpop,unsigned:boolean;var p :ptree);
  32. var
  33. flags : tresflags;
  34. begin
  35. { remove temporary location if not a set or string }
  36. if (p^.left^.resulttype^.deftype<>stringdef) and
  37. ((p^.left^.resulttype^.deftype<>setdef) or (psetdef(p^.left^.resulttype)^.settype=smallset)) and
  38. (p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  39. ungetiftemp(p^.left^.location.reference);
  40. if (p^.right^.resulttype^.deftype<>stringdef) and
  41. ((p^.right^.resulttype^.deftype<>setdef) or (psetdef(p^.right^.resulttype)^.settype=smallset)) and
  42. (p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  43. ungetiftemp(p^.right^.location.reference);
  44. { in case of comparison operation the put result in the flags }
  45. if cmpop then
  46. begin
  47. if not(unsigned) then
  48. begin
  49. if p^.swaped then
  50. case p^.treetype of
  51. equaln : flags:=F_E;
  52. unequaln : flags:=F_NE;
  53. ltn : flags:=F_G;
  54. lten : flags:=F_GE;
  55. gtn : flags:=F_L;
  56. gten : flags:=F_LE;
  57. end
  58. else
  59. case p^.treetype of
  60. equaln : flags:=F_E;
  61. unequaln : flags:=F_NE;
  62. ltn : flags:=F_L;
  63. lten : flags:=F_LE;
  64. gtn : flags:=F_G;
  65. gten : flags:=F_GE;
  66. end;
  67. end
  68. else
  69. begin
  70. if p^.swaped then
  71. case p^.treetype of
  72. equaln : flags:=F_E;
  73. unequaln : flags:=F_NE;
  74. ltn : flags:=F_A;
  75. lten : flags:=F_AE;
  76. gtn : flags:=F_B;
  77. gten : flags:=F_BE;
  78. end
  79. else
  80. case p^.treetype of
  81. equaln : flags:=F_E;
  82. unequaln : flags:=F_NE;
  83. ltn : flags:=F_B;
  84. lten : flags:=F_BE;
  85. gtn : flags:=F_A;
  86. gten : flags:=F_AE;
  87. end;
  88. end;
  89. p^.location.loc:=LOC_FLAGS;
  90. p^.location.resflags:=flags;
  91. end;
  92. end;
  93. {*****************************************************************************
  94. Addstring
  95. *****************************************************************************}
  96. procedure addstring(var p : ptree);
  97. var
  98. pushedregs : tpushed;
  99. href : treference;
  100. pushed,
  101. cmpop : boolean;
  102. begin
  103. { string operations are not commutative }
  104. if p^.swaped then
  105. swaptree(p);
  106. {$ifdef UseAnsiString}
  107. if is_ansistring(p^.left^.resulttype) then
  108. begin
  109. case p^.treetype of
  110. addn :
  111. begin
  112. { we do not need destination anymore }
  113. del_reference(p^.left^.location.reference);
  114. del_reference(p^.right^.location.reference);
  115. { concatansistring(p); }
  116. end;
  117. ltn,lten,gtn,gten,
  118. equaln,unequaln :
  119. begin
  120. pushusedregisters(pushedregs,$ff);
  121. secondpass(p^.left);
  122. del_reference(p^.left^.location.reference);
  123. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  124. secondpass(p^.right);
  125. del_reference(p^.right^.location.reference);
  126. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  127. emitcall('ANSISTRCMP',true);
  128. maybe_loadesi;
  129. popusedregisters(pushedregs);
  130. end;
  131. end;
  132. end
  133. else
  134. {$endif UseAnsiString}
  135. case p^.treetype of
  136. addn :
  137. begin
  138. cmpop:=false;
  139. secondpass(p^.left);
  140. { if str_concat is set in expr
  141. s:=s+ ... no need to create a temp string (PM) }
  142. if (p^.left^.treetype<>addn) and not (p^.use_strconcat) then
  143. begin
  144. { can only reference be }
  145. { string in register would be funny }
  146. { therefore produce a temporary string }
  147. { release the registers }
  148. del_reference(p^.left^.location.reference);
  149. gettempofsizereference(256,href);
  150. copystring(href,p^.left^.location.reference,255);
  151. ungetiftemp(p^.left^.location.reference);
  152. { does not hurt: }
  153. p^.left^.location.loc:=LOC_MEM;
  154. p^.left^.location.reference:=href;
  155. end;
  156. secondpass(p^.right);
  157. { on the right we do not need the register anymore too }
  158. del_reference(p^.right^.location.reference);
  159. { if p^.right^.resulttype^.deftype=orddef then
  160. begin
  161. pushusedregisters(pushedregs,$ff);
  162. exprasmlist^.concat(new(pai386,op_ref_reg(
  163. A_LEA,S_L,newreference(p^.left^.location.reference),R_EDI)));
  164. exprasmlist^.concat(new(pai386,op_reg_reg(
  165. A_XOR,S_L,R_EBX,R_EBX)));
  166. reset_reference(href);
  167. href.base:=R_EDI;
  168. exprasmlist^.concat(new(pai386,op_ref_reg(
  169. A_MOV,S_B,newreference(href),R_BL)));
  170. exprasmlist^.concat(new(pai386,op_reg(
  171. A_INC,S_L,R_EBX)));
  172. exprasmlist^.concat(new(pai386,op_reg_ref(
  173. A_MOV,S_B,R_BL,newreference(href))));
  174. href.index:=R_EBX;
  175. if p^.right^.treetype=ordconstn then
  176. exprasmlist^.concat(new(pai386,op_const_ref(
  177. A_MOV,S_L,p^.right^.value,newreference(href))))
  178. else
  179. begin
  180. if p^.right^.location.loc in [LOC_CREGISTER,LOC_REGISTER] then
  181. exprasmlist^.concat(new(pai386,op_reg_ref(
  182. A_MOV,S_B,p^.right^.location.register,newreference(href))))
  183. else
  184. begin
  185. exprasmlist^.concat(new(pai386,op_ref_reg(
  186. A_MOV,S_L,newreference(p^.right^.location.reference),R_EAX)));
  187. exprasmlist^.concat(new(pai386,op_reg_ref(
  188. A_MOV,S_B,R_AL,newreference(href))));
  189. end;
  190. end;
  191. popusedregisters(pushedregs);
  192. end
  193. else }
  194. begin
  195. pushusedregisters(pushedregs,$ff);
  196. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  197. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  198. emitcall('STRCONCAT',true);
  199. maybe_loadesi;
  200. popusedregisters(pushedregs);
  201. end;
  202. set_location(p^.location,p^.left^.location);
  203. ungetiftemp(p^.right^.location.reference);
  204. end;
  205. ltn,lten,gtn,gten,
  206. equaln,unequaln :
  207. begin
  208. cmpop:=true;
  209. { generate better code for s='' and s<>'' }
  210. if (p^.treetype in [equaln,unequaln]) and
  211. (((p^.left^.treetype=stringconstn) and (p^.left^.value_str^='')) or
  212. ((p^.right^.treetype=stringconstn) and (p^.right^.value_str^=''))) then
  213. begin
  214. secondpass(p^.left);
  215. { are too few registers free? }
  216. pushed:=maybe_push(p^.right^.registers32,p);
  217. secondpass(p^.right);
  218. if pushed then restore(p);
  219. del_reference(p^.right^.location.reference);
  220. del_reference(p^.left^.location.reference);
  221. { only one node can be stringconstn }
  222. { else pass 1 would have evaluted }
  223. { this node }
  224. if p^.left^.treetype=stringconstn then
  225. exprasmlist^.concat(new(pai386,op_const_ref(
  226. A_CMP,S_B,0,newreference(p^.right^.location.reference))))
  227. else
  228. exprasmlist^.concat(new(pai386,op_const_ref(
  229. A_CMP,S_B,0,newreference(p^.left^.location.reference))));
  230. end
  231. else
  232. begin
  233. pushusedregisters(pushedregs,$ff);
  234. secondpass(p^.left);
  235. del_reference(p^.left^.location.reference);
  236. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  237. secondpass(p^.right);
  238. del_reference(p^.right^.location.reference);
  239. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  240. emitcall('STRCMP',true);
  241. maybe_loadesi;
  242. popusedregisters(pushedregs);
  243. end;
  244. ungetiftemp(p^.left^.location.reference);
  245. ungetiftemp(p^.right^.location.reference);
  246. end;
  247. else Message(type_e_mismatch);
  248. end;
  249. SetResultLocation(cmpop,true,p);
  250. end;
  251. {*****************************************************************************
  252. Addset
  253. *****************************************************************************}
  254. procedure addset(var p : ptree);
  255. var
  256. cmpop,
  257. pushed : boolean;
  258. href : treference;
  259. pushedregs : tpushed;
  260. begin
  261. cmpop:=false;
  262. { not commutative }
  263. if p^.swaped then
  264. swaptree(p);
  265. secondpass(p^.left);
  266. { are too few registers free? }
  267. pushed:=maybe_push(p^.right^.registers32,p);
  268. secondpass(p^.right);
  269. if codegenerror then
  270. exit;
  271. if pushed then
  272. restore(p);
  273. set_location(p^.location,p^.left^.location);
  274. { handle operations }
  275. case p^.treetype of
  276. equaln,
  277. unequaln : begin
  278. cmpop:=true;
  279. del_reference(p^.left^.location.reference);
  280. del_reference(p^.right^.location.reference);
  281. pushusedregisters(pushedregs,$ff);
  282. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  283. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  284. emitcall('SET_COMP_SETS',true);
  285. maybe_loadesi;
  286. popusedregisters(pushedregs);
  287. ungetiftemp(p^.left^.location.reference);
  288. ungetiftemp(p^.right^.location.reference);
  289. end;
  290. addn : begin
  291. { add can be an other SET or Range or Element ! }
  292. del_reference(p^.left^.location.reference);
  293. del_reference(p^.right^.location.reference);
  294. pushusedregisters(pushedregs,$ff);
  295. href.symbol:=nil;
  296. gettempofsizereference(32,href);
  297. { add a range or a single element? }
  298. if p^.right^.treetype=setelementn then
  299. begin
  300. concatcopy(p^.left^.location.reference,href,32,false);
  301. if assigned(p^.right^.right) then
  302. begin
  303. pushsetelement(p^.right^.right);
  304. pushsetelement(p^.right^.left);
  305. emitpushreferenceaddr(exprasmlist,href);
  306. emitcall('SET_SET_RANGE',true);
  307. end
  308. else
  309. begin
  310. pushsetelement(p^.right^.left);
  311. emitpushreferenceaddr(exprasmlist,href);
  312. emitcall('SET_SET_BYTE',true);
  313. end;
  314. end
  315. else
  316. begin
  317. { must be an other set }
  318. emitpushreferenceaddr(exprasmlist,href);
  319. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  320. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  321. emitcall('SET_ADD_SETS',true);
  322. end;
  323. maybe_loadesi;
  324. popusedregisters(pushedregs);
  325. ungetiftemp(p^.left^.location.reference);
  326. ungetiftemp(p^.right^.location.reference);
  327. p^.location.loc:=LOC_MEM;
  328. stringdispose(p^.location.reference.symbol);
  329. p^.location.reference:=href;
  330. end;
  331. subn,
  332. symdifn,
  333. muln : begin
  334. del_reference(p^.left^.location.reference);
  335. del_reference(p^.right^.location.reference);
  336. href.symbol:=nil;
  337. pushusedregisters(pushedregs,$ff);
  338. gettempofsizereference(32,href);
  339. emitpushreferenceaddr(exprasmlist,href);
  340. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  341. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  342. case p^.treetype of
  343. subn : emitcall('SET_SUB_SETS',true);
  344. symdifn : emitcall('SET_SYMDIF_SETS',true);
  345. muln : emitcall('SET_MUL_SETS',true);
  346. end;
  347. maybe_loadesi;
  348. popusedregisters(pushedregs);
  349. ungetiftemp(p^.left^.location.reference);
  350. ungetiftemp(p^.right^.location.reference);
  351. p^.location.loc:=LOC_MEM;
  352. stringdispose(p^.location.reference.symbol);
  353. p^.location.reference:=href;
  354. end;
  355. else
  356. Message(type_e_mismatch);
  357. end;
  358. SetResultLocation(cmpop,true,p);
  359. end;
  360. {*****************************************************************************
  361. SecondAdd
  362. *****************************************************************************}
  363. procedure secondadd(var p : ptree);
  364. { is also being used for xor, and "mul", "sub, or and comparative }
  365. { operators }
  366. label do_normal;
  367. var
  368. hregister : tregister;
  369. noswap,
  370. pushed,mboverflow,cmpop : boolean;
  371. op : tasmop;
  372. flags : tresflags;
  373. otl,ofl : plabel;
  374. power : longint;
  375. opsize : topsize;
  376. hl4: plabel;
  377. { true, if unsigned types are compared }
  378. unsigned : boolean;
  379. { true, if a small set is handled with the longint code }
  380. is_set : boolean;
  381. { is_in_dest if the result is put directly into }
  382. { the resulting refernce or varregister }
  383. is_in_dest : boolean;
  384. { true, if for sets subtractions the extra not should generated }
  385. extra_not : boolean;
  386. {$ifdef SUPPORT_MMX}
  387. mmxbase : tmmxtype;
  388. {$endif SUPPORT_MMX}
  389. begin
  390. { to make it more readable, string and set (not smallset!) have their
  391. own procedures }
  392. case p^.left^.resulttype^.deftype of
  393. stringdef : begin
  394. addstring(p);
  395. exit;
  396. end;
  397. setdef : begin
  398. { normalsets are handled separate }
  399. if not(psetdef(p^.left^.resulttype)^.settype=smallset) then
  400. begin
  401. addset(p);
  402. exit;
  403. end;
  404. end;
  405. end;
  406. { defaults }
  407. unsigned:=false;
  408. is_in_dest:=false;
  409. extra_not:=false;
  410. noswap:=false;
  411. opsize:=S_L;
  412. { are we a (small)set, must be set here because the side can be
  413. swapped ! (PFV) }
  414. is_set:=(p^.left^.resulttype^.deftype=setdef);
  415. { calculate the operator which is more difficult }
  416. firstcomplex(p);
  417. { handling boolean expressions extra: }
  418. if ((p^.left^.resulttype^.deftype=orddef) and
  419. (porddef(p^.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) or
  420. ((p^.right^.resulttype^.deftype=orddef) and
  421. (porddef(p^.right^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit])) then
  422. begin
  423. if (porddef(p^.left^.resulttype)^.typ=bool8bit) or
  424. (porddef(p^.right^.resulttype)^.typ=bool8bit) then
  425. opsize:=S_B
  426. else
  427. if (porddef(p^.left^.resulttype)^.typ=bool16bit) or
  428. (porddef(p^.right^.resulttype)^.typ=bool16bit) then
  429. opsize:=S_W
  430. else
  431. opsize:=S_L;
  432. case p^.treetype of
  433. andn,
  434. orn : begin
  435. p^.location.loc:=LOC_JUMP;
  436. cmpop:=false;
  437. case p^.treetype of
  438. andn : begin
  439. otl:=truelabel;
  440. getlabel(truelabel);
  441. secondpass(p^.left);
  442. maketojumpbool(p^.left);
  443. emitl(A_LABEL,truelabel);
  444. truelabel:=otl;
  445. end;
  446. orn : begin
  447. ofl:=falselabel;
  448. getlabel(falselabel);
  449. secondpass(p^.left);
  450. maketojumpbool(p^.left);
  451. emitl(A_LABEL,falselabel);
  452. falselabel:=ofl;
  453. end;
  454. else
  455. Message(type_e_mismatch);
  456. end;
  457. secondpass(p^.right);
  458. maketojumpbool(p^.right);
  459. end;
  460. unequaln,
  461. equaln,xorn : begin
  462. if p^.left^.treetype=ordconstn then
  463. swaptree(p);
  464. secondpass(p^.left);
  465. p^.location:=p^.left^.location;
  466. { are enough registers free ? }
  467. pushed:=maybe_push(p^.right^.registers32,p);
  468. secondpass(p^.right);
  469. if pushed then restore(p);
  470. goto do_normal;
  471. end
  472. else
  473. Message(type_e_mismatch);
  474. end
  475. end
  476. else
  477. begin
  478. { in case of constant put it to the left }
  479. if (p^.left^.treetype=ordconstn) then
  480. swaptree(p);
  481. secondpass(p^.left);
  482. { this will be complicated as
  483. a lot of code below assumes that
  484. p^.location and p^.left^.location are the same }
  485. {$ifdef test_dest_loc}
  486. if dest_loc_known and (dest_loc_tree=p) and
  487. ((dest_loc.loc=LOC_REGISTER) or (dest_loc.loc=LOC_CREGISTER)) then
  488. begin
  489. set_location(p^.location,dest_loc);
  490. in_dest_loc:=true;
  491. is_in_dest:=true;
  492. end
  493. else
  494. {$endif test_dest_loc}
  495. set_location(p^.location,p^.left^.location);
  496. { are too few registers free? }
  497. pushed:=maybe_push(p^.right^.registers32,p);
  498. secondpass(p^.right);
  499. if pushed then
  500. restore(p);
  501. if (p^.left^.resulttype^.deftype=pointerdef) or
  502. (p^.right^.resulttype^.deftype=pointerdef) or
  503. ((p^.right^.resulttype^.deftype=objectdef) and
  504. pobjectdef(p^.right^.resulttype)^.isclass and
  505. (p^.left^.resulttype^.deftype=objectdef) and
  506. pobjectdef(p^.left^.resulttype)^.isclass
  507. ) or
  508. (p^.left^.resulttype^.deftype=classrefdef) or
  509. (p^.left^.resulttype^.deftype=procvardef) or
  510. (p^.left^.resulttype^.deftype=enumdef) or
  511. ((p^.left^.resulttype^.deftype=orddef) and
  512. (porddef(p^.left^.resulttype)^.typ=s32bit)) or
  513. ((p^.right^.resulttype^.deftype=orddef) and
  514. (porddef(p^.right^.resulttype)^.typ=s32bit)) or
  515. ((p^.left^.resulttype^.deftype=orddef) and
  516. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  517. ((p^.right^.resulttype^.deftype=orddef) and
  518. (porddef(p^.right^.resulttype)^.typ=u32bit)) or
  519. { as well as small sets }
  520. is_set then
  521. begin
  522. do_normal:
  523. mboverflow:=false;
  524. cmpop:=false;
  525. if (p^.left^.resulttype^.deftype=pointerdef) or
  526. (p^.right^.resulttype^.deftype=pointerdef) or
  527. ((p^.left^.resulttype^.deftype=orddef) and
  528. (porddef(p^.left^.resulttype)^.typ=u32bit)) or
  529. ((p^.right^.resulttype^.deftype=orddef) and
  530. (porddef(p^.right^.resulttype)^.typ=u32bit)) then
  531. unsigned:=true;
  532. case p^.treetype of
  533. addn : begin
  534. if is_set then
  535. begin
  536. { adding elements is not commutative }
  537. if p^.swaped and (p^.left^.treetype=setelementn) then
  538. swaptree(p);
  539. { are we adding set elements ? }
  540. if p^.right^.treetype=setelementn then
  541. begin
  542. { no range support for smallsets! }
  543. if assigned(p^.right^.right) then
  544. internalerror(43244);
  545. { bts requires both elements to be registers }
  546. if p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  547. begin
  548. del_reference(p^.left^.location.reference);
  549. hregister:=getregister32;
  550. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  551. newreference(p^.left^.location.reference),hregister)));
  552. p^.left^.location.loc:=LOC_REGISTER;
  553. p^.left^.location.register:=hregister;
  554. set_location(p^.location,p^.left^.location);
  555. end;
  556. if p^.right^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  557. begin
  558. del_reference(p^.right^.location.reference);
  559. hregister:=getregister32;
  560. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  561. newreference(p^.right^.location.reference),hregister)));
  562. p^.right^.location.loc:=LOC_REGISTER;
  563. p^.right^.location.register:=hregister;
  564. end;
  565. op:=A_BTS;
  566. noswap:=true;
  567. end
  568. else
  569. op:=A_OR;
  570. mboverflow:=false;
  571. unsigned:=false;
  572. end
  573. else
  574. begin
  575. op:=A_ADD;
  576. mboverflow:=true;
  577. end;
  578. end;
  579. symdifn : begin
  580. { the symetric diff is only for sets }
  581. if is_set then
  582. begin
  583. op:=A_XOR;
  584. mboverflow:=false;
  585. unsigned:=false;
  586. end
  587. else
  588. Message(type_e_mismatch);
  589. end;
  590. muln : begin
  591. if is_set then
  592. begin
  593. op:=A_AND;
  594. mboverflow:=false;
  595. unsigned:=false;
  596. end
  597. else
  598. begin
  599. if unsigned then
  600. op:=A_MUL
  601. else
  602. op:=A_IMUL;
  603. mboverflow:=true;
  604. end;
  605. end;
  606. subn : begin
  607. if is_set then
  608. begin
  609. op:=A_AND;
  610. mboverflow:=false;
  611. unsigned:=false;
  612. extra_not:=true;
  613. end
  614. else
  615. begin
  616. op:=A_SUB;
  617. mboverflow:=true;
  618. end;
  619. end;
  620. ltn,lten,
  621. gtn,gten,
  622. equaln,unequaln : begin
  623. op:=A_CMP;
  624. cmpop:=true;
  625. end;
  626. xorn : op:=A_XOR;
  627. orn : op:=A_OR;
  628. andn : op:=A_AND;
  629. else
  630. Message(type_e_mismatch);
  631. end;
  632. { left and right no register? }
  633. { then one must be demanded }
  634. if (p^.left^.location.loc<>LOC_REGISTER) and
  635. (p^.right^.location.loc<>LOC_REGISTER) then
  636. begin
  637. { register variable ? }
  638. if (p^.left^.location.loc=LOC_CREGISTER) then
  639. begin
  640. { it is OK if this is the destination }
  641. if is_in_dest then
  642. begin
  643. hregister:=p^.location.register;
  644. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  645. hregister);
  646. end
  647. else
  648. if cmpop then
  649. begin
  650. { do not disturb the register }
  651. hregister:=p^.location.register;
  652. end
  653. else
  654. begin
  655. case opsize of
  656. S_L : hregister:=getregister32;
  657. S_B : hregister:=reg32toreg8(getregister32);
  658. end;
  659. emit_reg_reg(A_MOV,opsize,p^.left^.location.register,
  660. hregister);
  661. end
  662. end
  663. else
  664. begin
  665. del_reference(p^.left^.location.reference);
  666. if is_in_dest then
  667. begin
  668. hregister:=p^.location.register;
  669. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  670. newreference(p^.left^.location.reference),hregister)));
  671. end
  672. else
  673. begin
  674. { first give free, then demand new register }
  675. case opsize of
  676. S_L : hregister:=getregister32;
  677. S_W : hregister:=reg32toreg16(getregister32);
  678. S_B : hregister:=reg32toreg8(getregister32);
  679. end;
  680. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  681. newreference(p^.left^.location.reference),hregister)));
  682. end;
  683. end;
  684. p^.location.loc:=LOC_REGISTER;
  685. p^.location.register:=hregister;
  686. end
  687. else
  688. { if on the right the register then swap }
  689. if not(noswap) and (p^.right^.location.loc=LOC_REGISTER) then
  690. begin
  691. swap_location(p^.location,p^.right^.location);
  692. { newly swapped also set swapped flag }
  693. p^.swaped:=not(p^.swaped);
  694. end;
  695. { at this point, p^.location.loc should be LOC_REGISTER }
  696. { and p^.location.register should be a valid register }
  697. { containing the left result }
  698. if p^.right^.location.loc<>LOC_REGISTER then
  699. begin
  700. if (p^.treetype=subn) and p^.swaped then
  701. begin
  702. if p^.right^.location.loc=LOC_CREGISTER then
  703. begin
  704. if extra_not then
  705. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  706. emit_reg_reg(A_MOV,opsize,p^.right^.location.register,R_EDI);
  707. emit_reg_reg(op,opsize,p^.location.register,R_EDI);
  708. emit_reg_reg(A_MOV,opsize,R_EDI,p^.location.register);
  709. end
  710. else
  711. begin
  712. if extra_not then
  713. exprasmlist^.concat(new(pai386,op_reg(A_NOT,opsize,p^.location.register)));
  714. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,
  715. newreference(p^.right^.location.reference),R_EDI)));
  716. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,p^.location.register,R_EDI)));
  717. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,opsize,R_EDI,p^.location.register)));
  718. del_reference(p^.right^.location.reference);
  719. end;
  720. end
  721. else
  722. begin
  723. if (p^.right^.treetype=ordconstn) and
  724. (op=A_CMP) and
  725. (p^.right^.value=0) then
  726. begin
  727. exprasmlist^.concat(new(pai386,op_reg_reg(A_TEST,opsize,p^.location.register,
  728. p^.location.register)));
  729. end
  730. else if (p^.right^.treetype=ordconstn) and
  731. (op=A_ADD) and
  732. (p^.right^.value=1) then
  733. begin
  734. exprasmlist^.concat(new(pai386,op_reg(A_INC,opsize,
  735. p^.location.register)));
  736. end
  737. else if (p^.right^.treetype=ordconstn) and
  738. (op=A_SUB) and
  739. (p^.right^.value=1) then
  740. begin
  741. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,
  742. p^.location.register)));
  743. end
  744. else if (p^.right^.treetype=ordconstn) and
  745. (op=A_IMUL) and
  746. (ispowerof2(p^.right^.value,power)) then
  747. begin
  748. exprasmlist^.concat(new(pai386,op_const_reg(A_SHL,opsize,power,
  749. p^.location.register)));
  750. end
  751. else
  752. begin
  753. if (p^.right^.location.loc=LOC_CREGISTER) then
  754. begin
  755. if extra_not then
  756. begin
  757. emit_reg_reg(A_MOV,S_L,p^.right^.location.register,R_EDI);
  758. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  759. emit_reg_reg(A_AND,S_L,R_EDI,
  760. p^.location.register);
  761. end
  762. else
  763. begin
  764. emit_reg_reg(op,opsize,p^.right^.location.register,
  765. p^.location.register);
  766. end;
  767. end
  768. else
  769. begin
  770. if extra_not then
  771. begin
  772. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,newreference(
  773. p^.right^.location.reference),R_EDI)));
  774. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,R_EDI)));
  775. emit_reg_reg(A_AND,S_L,R_EDI,
  776. p^.location.register);
  777. end
  778. else
  779. begin
  780. exprasmlist^.concat(new(pai386,op_ref_reg(op,opsize,newreference(
  781. p^.right^.location.reference),p^.location.register)));
  782. end;
  783. del_reference(p^.right^.location.reference);
  784. end;
  785. end;
  786. end;
  787. end
  788. else
  789. begin
  790. { when swapped another result register }
  791. if (p^.treetype=subn) and p^.swaped then
  792. begin
  793. if extra_not then
  794. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.location.register)));
  795. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  796. p^.location.register,p^.right^.location.register)));
  797. swap_location(p^.location,p^.right^.location);
  798. { newly swapped also set swapped flag }
  799. { just to maintain ordering }
  800. p^.swaped:=not(p^.swaped);
  801. end
  802. else
  803. begin
  804. if extra_not then
  805. exprasmlist^.concat(new(pai386,op_reg(A_NOT,S_L,p^.right^.location.register)));
  806. exprasmlist^.concat(new(pai386,op_reg_reg(op,opsize,
  807. p^.right^.location.register,
  808. p^.location.register)));
  809. end;
  810. case opsize of
  811. S_L : ungetregister32(p^.right^.location.register);
  812. S_B : ungetregister32(reg8toreg32(p^.right^.location.register));
  813. end;
  814. end;
  815. if cmpop then
  816. case opsize of
  817. S_L : ungetregister32(p^.location.register);
  818. S_B : ungetregister32(reg8toreg32(p^.location.register));
  819. end;
  820. { only in case of overflow operations }
  821. { produce overflow code }
  822. { we must put it here directly, because sign of operation }
  823. { is in unsigned VAR!! }
  824. if mboverflow then
  825. begin
  826. if cs_check_overflow in aktlocalswitches then
  827. begin
  828. getlabel(hl4);
  829. if unsigned then
  830. emitl(A_JNB,hl4)
  831. else
  832. emitl(A_JNO,hl4);
  833. emitcall('RE_OVERFLOW',true);
  834. emitl(A_LABEL,hl4);
  835. end;
  836. end;
  837. end
  838. else
  839. { Char type }
  840. if ((p^.left^.resulttype^.deftype=orddef) and
  841. (porddef(p^.left^.resulttype)^.typ=uchar)) then
  842. begin
  843. case p^.treetype of
  844. ltn,lten,gtn,gten,
  845. equaln,unequaln :
  846. cmpop:=true;
  847. else Message(type_e_mismatch);
  848. end;
  849. unsigned:=true;
  850. { left and right no register? }
  851. { the one must be demanded }
  852. if (p^.location.loc<>LOC_REGISTER) and
  853. (p^.right^.location.loc<>LOC_REGISTER) then
  854. begin
  855. if p^.location.loc=LOC_CREGISTER then
  856. begin
  857. if cmpop then
  858. { do not disturb register }
  859. hregister:=p^.location.register
  860. else
  861. begin
  862. hregister:=reg32toreg8(getregister32);
  863. emit_reg_reg(A_MOV,S_B,p^.location.register,
  864. hregister);
  865. end;
  866. end
  867. else
  868. begin
  869. del_reference(p^.location.reference);
  870. { first give free then demand new register }
  871. hregister:=reg32toreg8(getregister32);
  872. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_B,newreference(p^.location.reference),
  873. hregister)));
  874. end;
  875. p^.location.loc:=LOC_REGISTER;
  876. p^.location.register:=hregister;
  877. end;
  878. { now p always a register }
  879. if (p^.right^.location.loc=LOC_REGISTER) and
  880. (p^.location.loc<>LOC_REGISTER) then
  881. begin
  882. swap_location(p^.location,p^.right^.location);
  883. { newly swapped also set swapped flag }
  884. p^.swaped:=not(p^.swaped);
  885. end;
  886. if p^.right^.location.loc<>LOC_REGISTER then
  887. begin
  888. if p^.right^.location.loc=LOC_CREGISTER then
  889. begin
  890. emit_reg_reg(A_CMP,S_B,
  891. p^.right^.location.register,p^.location.register);
  892. end
  893. else
  894. begin
  895. exprasmlist^.concat(new(pai386,op_ref_reg(A_CMP,S_B,newreference(
  896. p^.right^.location.reference),p^.location.register)));
  897. del_reference(p^.right^.location.reference);
  898. end;
  899. end
  900. else
  901. begin
  902. emit_reg_reg(A_CMP,S_B,p^.right^.location.register,
  903. p^.location.register);
  904. ungetregister32(reg8toreg32(p^.right^.location.register));
  905. end;
  906. ungetregister32(reg8toreg32(p^.location.register));
  907. end
  908. else
  909. { Floating point }
  910. if (p^.left^.resulttype^.deftype=floatdef) and
  911. (pfloatdef(p^.left^.resulttype)^.typ<>f32bit) then
  912. begin
  913. { real constants to the left }
  914. if p^.left^.treetype=realconstn then
  915. swaptree(p);
  916. cmpop:=false;
  917. case p^.treetype of
  918. addn : op:=A_FADDP;
  919. muln : op:=A_FMULP;
  920. subn : op:=A_FSUBP;
  921. slashn : op:=A_FDIVP;
  922. ltn,lten,gtn,gten,
  923. equaln,unequaln : begin
  924. op:=A_FCOMPP;
  925. cmpop:=true;
  926. end;
  927. else Message(type_e_mismatch);
  928. end;
  929. if (p^.right^.location.loc<>LOC_FPU) then
  930. begin
  931. floatload(pfloatdef(p^.right^.resulttype)^.typ,p^.right^.location.reference);
  932. if (p^.left^.location.loc<>LOC_FPU) then
  933. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  934. { left was on the stack => swap }
  935. else
  936. p^.swaped:=not(p^.swaped);
  937. { releases the right reference }
  938. del_reference(p^.right^.location.reference);
  939. end
  940. { the nominator in st0 }
  941. else if (p^.left^.location.loc<>LOC_FPU) then
  942. floatload(pfloatdef(p^.left^.resulttype)^.typ,p^.left^.location.reference)
  943. { fpu operands are always in the wrong order on the stack }
  944. else
  945. p^.swaped:=not(p^.swaped);
  946. { releases the left reference }
  947. if (p^.left^.location.loc<>LOC_FPU) then
  948. del_reference(p^.left^.location.reference);
  949. { if we swaped the tree nodes, then use the reverse operator }
  950. if p^.swaped then
  951. begin
  952. if (p^.treetype=slashn) then
  953. op:=A_FDIVRP
  954. else if (p^.treetype=subn) then
  955. op:=A_FSUBRP;
  956. end;
  957. { to avoid the pentium bug
  958. if (op=FDIVP) and (opt_processors=pentium) then
  959. exprasmlist^.concat(new(pai386,op_CALL,S_NO,'EMUL_FDIVP')
  960. else
  961. }
  962. { the Intel assemblers want operands }
  963. if op<>A_FCOMPP then
  964. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,R_ST,R_ST1)))
  965. else
  966. exprasmlist^.concat(new(pai386,op_none(op,S_NO)));
  967. { on comparison load flags }
  968. if cmpop then
  969. begin
  970. if not(R_EAX in unused) then
  971. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  972. exprasmlist^.concat(new(pai386,op_reg(A_FNSTSW,S_NO,R_AX)));
  973. exprasmlist^.concat(new(pai386,op_none(A_SAHF,S_NO)));
  974. if not(R_EAX in unused) then
  975. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  976. if p^.swaped then
  977. begin
  978. case p^.treetype of
  979. equaln : flags:=F_E;
  980. unequaln : flags:=F_NE;
  981. ltn : flags:=F_A;
  982. lten : flags:=F_AE;
  983. gtn : flags:=F_B;
  984. gten : flags:=F_BE;
  985. end;
  986. end
  987. else
  988. begin
  989. case p^.treetype of
  990. equaln : flags:=F_E;
  991. unequaln : flags:=F_NE;
  992. ltn : flags:=F_B;
  993. lten : flags:=F_BE;
  994. gtn : flags:=F_A;
  995. gten : flags:=F_AE;
  996. end;
  997. end;
  998. p^.location.loc:=LOC_FLAGS;
  999. p^.location.resflags:=flags;
  1000. cmpop:=false;
  1001. end
  1002. else
  1003. p^.location.loc:=LOC_FPU;
  1004. end
  1005. {$ifdef SUPPORT_MMX}
  1006. else
  1007. { MMX Arrays }
  1008. if is_mmx_able_array(p^.left^.resulttype) then
  1009. begin
  1010. cmpop:=false;
  1011. mmxbase:=mmx_type(p^.left^.resulttype);
  1012. case p^.treetype of
  1013. addn : begin
  1014. if (cs_mmx_saturation in aktlocalswitches) then
  1015. begin
  1016. case mmxbase of
  1017. mmxs8bit:
  1018. op:=A_PADDSB;
  1019. mmxu8bit:
  1020. op:=A_PADDUSB;
  1021. mmxs16bit,mmxfixed16:
  1022. op:=A_PADDSB;
  1023. mmxu16bit:
  1024. op:=A_PADDUSW;
  1025. end;
  1026. end
  1027. else
  1028. begin
  1029. case mmxbase of
  1030. mmxs8bit,mmxu8bit:
  1031. op:=A_PADDB;
  1032. mmxs16bit,mmxu16bit,mmxfixed16:
  1033. op:=A_PADDW;
  1034. mmxs32bit,mmxu32bit:
  1035. op:=A_PADDD;
  1036. end;
  1037. end;
  1038. end;
  1039. muln : begin
  1040. case mmxbase of
  1041. mmxs16bit,mmxu16bit:
  1042. op:=A_PMULLW;
  1043. mmxfixed16:
  1044. op:=A_PMULHW;
  1045. end;
  1046. end;
  1047. subn : begin
  1048. if (cs_mmx_saturation in aktlocalswitches) then
  1049. begin
  1050. case mmxbase of
  1051. mmxs8bit:
  1052. op:=A_PSUBSB;
  1053. mmxu8bit:
  1054. op:=A_PSUBUSB;
  1055. mmxs16bit,mmxfixed16:
  1056. op:=A_PSUBSB;
  1057. mmxu16bit:
  1058. op:=A_PSUBUSW;
  1059. end;
  1060. end
  1061. else
  1062. begin
  1063. case mmxbase of
  1064. mmxs8bit,mmxu8bit:
  1065. op:=A_PSUBB;
  1066. mmxs16bit,mmxu16bit,mmxfixed16:
  1067. op:=A_PSUBW;
  1068. mmxs32bit,mmxu32bit:
  1069. op:=A_PSUBD;
  1070. end;
  1071. end;
  1072. end;
  1073. {
  1074. ltn,lten,gtn,gten,
  1075. equaln,unequaln :
  1076. begin
  1077. op:=A_CMP;
  1078. cmpop:=true;
  1079. end;
  1080. }
  1081. xorn:
  1082. op:=A_PXOR;
  1083. orn:
  1084. op:=A_POR;
  1085. andn:
  1086. op:=A_PAND;
  1087. else Message(type_e_mismatch);
  1088. end;
  1089. { left and right no register? }
  1090. { then one must be demanded }
  1091. if (p^.left^.location.loc<>LOC_MMXREGISTER) and
  1092. (p^.right^.location.loc<>LOC_MMXREGISTER) then
  1093. begin
  1094. { register variable ? }
  1095. if (p^.left^.location.loc=LOC_CMMXREGISTER) then
  1096. begin
  1097. { it is OK if this is the destination }
  1098. if is_in_dest then
  1099. begin
  1100. hregister:=p^.location.register;
  1101. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1102. hregister);
  1103. end
  1104. else
  1105. begin
  1106. hregister:=getregistermmx;
  1107. emit_reg_reg(A_MOVQ,S_NO,p^.left^.location.register,
  1108. hregister);
  1109. end
  1110. end
  1111. else
  1112. begin
  1113. del_reference(p^.left^.location.reference);
  1114. if is_in_dest then
  1115. begin
  1116. hregister:=p^.location.register;
  1117. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1118. newreference(p^.left^.location.reference),hregister)));
  1119. end
  1120. else
  1121. begin
  1122. hregister:=getregistermmx;
  1123. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1124. newreference(p^.left^.location.reference),hregister)));
  1125. end;
  1126. end;
  1127. p^.location.loc:=LOC_MMXREGISTER;
  1128. p^.location.register:=hregister;
  1129. end
  1130. else
  1131. { if on the right the register then swap }
  1132. if (p^.right^.location.loc=LOC_MMXREGISTER) then
  1133. begin
  1134. swap_location(p^.location,p^.right^.location);
  1135. { newly swapped also set swapped flag }
  1136. p^.swaped:=not(p^.swaped);
  1137. end;
  1138. { at this point, p^.location.loc should be LOC_MMXREGISTER }
  1139. { and p^.location.register should be a valid register }
  1140. { containing the left result }
  1141. if p^.right^.location.loc<>LOC_MMXREGISTER then
  1142. begin
  1143. if (p^.treetype=subn) and p^.swaped then
  1144. begin
  1145. if p^.right^.location.loc=LOC_CMMXREGISTER then
  1146. begin
  1147. emit_reg_reg(A_MOVQ,S_NO,p^.right^.location.register,R_MM7);
  1148. emit_reg_reg(op,S_NO,p^.location.register,R_EDI);
  1149. emit_reg_reg(A_MOVQ,S_NO,R_MM7,p^.location.register);
  1150. end
  1151. else
  1152. begin
  1153. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVQ,S_NO,
  1154. newreference(p^.right^.location.reference),R_MM7)));
  1155. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,p^.location.register,
  1156. R_MM7)));
  1157. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOVQ,S_NO,
  1158. R_MM7,p^.location.register)));
  1159. del_reference(p^.right^.location.reference);
  1160. end;
  1161. end
  1162. else
  1163. begin
  1164. if (p^.right^.location.loc=LOC_CREGISTER) then
  1165. begin
  1166. emit_reg_reg(op,S_NO,p^.right^.location.register,
  1167. p^.location.register);
  1168. end
  1169. else
  1170. begin
  1171. exprasmlist^.concat(new(pai386,op_ref_reg(op,S_NO,newreference(
  1172. p^.right^.location.reference),p^.location.register)));
  1173. del_reference(p^.right^.location.reference);
  1174. end;
  1175. end;
  1176. end
  1177. else
  1178. begin
  1179. { when swapped another result register }
  1180. if (p^.treetype=subn) and p^.swaped then
  1181. begin
  1182. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1183. p^.location.register,p^.right^.location.register)));
  1184. swap_location(p^.location,p^.right^.location);
  1185. { newly swapped also set swapped flag }
  1186. { just to maintain ordering }
  1187. p^.swaped:=not(p^.swaped);
  1188. end
  1189. else
  1190. begin
  1191. exprasmlist^.concat(new(pai386,op_reg_reg(op,S_NO,
  1192. p^.right^.location.register,
  1193. p^.location.register)));
  1194. end;
  1195. ungetregistermmx(p^.right^.location.register);
  1196. end;
  1197. end
  1198. {$endif SUPPORT_MMX}
  1199. else Message(type_e_mismatch);
  1200. end;
  1201. SetResultLocation(cmpop,unsigned,p);
  1202. end;
  1203. end.
  1204. {
  1205. $Log$
  1206. Revision 1.11 1998-09-07 18:45:52 peter
  1207. * update smartlinking, uses getdatalabel
  1208. * renamed ptree.value vars to value_str,value_real,value_set
  1209. Revision 1.10 1998/09/04 10:05:04 florian
  1210. * ugly fix for STRCAT, nevertheless it needs more fixing !!!!!!!
  1211. we need an new version of STRCAT which takes a length parameter
  1212. Revision 1.9 1998/09/04 08:41:36 peter
  1213. * updated some error messages
  1214. Revision 1.8 1998/08/28 10:54:18 peter
  1215. * fixed smallset generation from elements, it has never worked before!
  1216. Revision 1.7 1998/08/19 14:56:59 peter
  1217. * forgot to removed some unused code in addset for set<>set
  1218. Revision 1.6 1998/08/18 09:24:35 pierre
  1219. * small warning position bug fixed
  1220. * support_mmx switches splitting was missing
  1221. * rhide error and warning output corrected
  1222. Revision 1.5 1998/08/14 18:18:37 peter
  1223. + dynamic set contruction
  1224. * smallsets are now working (always longint size)
  1225. Revision 1.4 1998/08/10 14:49:42 peter
  1226. + localswitches, moduleswitches, globalswitches splitting
  1227. Revision 1.3 1998/06/25 08:48:04 florian
  1228. * first version of rtti support
  1229. Revision 1.2 1998/06/08 13:13:28 pierre
  1230. + temporary variables now in temp_gen.pas unit
  1231. because it is processor independent
  1232. * mppc68k.bat modified to undefine i386 and support_mmx
  1233. (which are defaults for i386)
  1234. Revision 1.1 1998/06/05 17:44:10 peter
  1235. * splitted cgi386
  1236. }