ncgset.pas 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl and Carl Eric Codere
  4. Generate generic assembler for in set/case nodes
  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 ncgset;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,nset,cpubase,cgbase,cgobj,aasmbase,aasmtai,globals;
  23. type
  24. tcgsetelementnode = class(tsetelementnode)
  25. procedure pass_2;override;
  26. end;
  27. tcginnode = class(tinnode)
  28. procedure pass_2;override;
  29. protected
  30. {# Routine to test bitnumber in bitnumber register on value
  31. in value register. The __result register should be set
  32. to one if the bit is set, otherwise __result register
  33. should be set to zero.
  34. Should be overriden on processors which have specific
  35. instructions to do bit tests.
  36. }
  37. procedure emit_bit_test_reg_reg(list : taasmoutput; bitnumber : tregister;
  38. value : tregister; __result :tregister);virtual;
  39. end;
  40. tcgcasenode = class(tcasenode)
  41. {
  42. Emits the case node statement. Contrary to the intel
  43. 80x86 version, this version does not emit jump tables,
  44. because of portability problems.
  45. }
  46. procedure pass_2;override;
  47. protected
  48. with_sign : boolean;
  49. opsize : tcgsize;
  50. jmp_gt,jmp_lt,jmp_le : topcmp;
  51. { register with case expression }
  52. hregister,hregister2 : tregister;
  53. endlabel,elselabel : tasmlabel;
  54. { true, if we can omit the range check of the jump table }
  55. jumptable_no_range : boolean;
  56. { has the implementation jumptable support }
  57. min_label : tconstexprint;
  58. procedure optimizevalues(var max_linear_list:longint;var max_dist:cardinal);virtual;
  59. function has_jumptable : boolean;virtual;
  60. procedure genjumptable(hp : pcaserecord;min_,max_ : longint); virtual;
  61. procedure genlinearlist(hp : pcaserecord); virtual;
  62. procedure genlinearcmplist(hp : pcaserecord); virtual;
  63. procedure gentreejmp(p : pcaserecord);
  64. end;
  65. implementation
  66. uses
  67. globtype,systems,
  68. verbose,
  69. symconst,symdef,defutil,
  70. paramgr,
  71. pass_2,
  72. nbas,ncon,nflw,
  73. ncgutil,regvars,cpuinfo;
  74. {*****************************************************************************
  75. TCGSETELEMENTNODE
  76. *****************************************************************************}
  77. procedure tcgsetelementnode.pass_2;
  78. begin
  79. { load first value in 32bit register }
  80. secondpass(left);
  81. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  82. location_force_reg(exprasmlist,left.location,OS_32,false);
  83. { also a second value ? }
  84. if assigned(right) then
  85. begin
  86. secondpass(right);
  87. if codegenerror then
  88. exit;
  89. if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  90. location_force_reg(exprasmlist,right.location,OS_32,false);
  91. end;
  92. { we doesn't modify the left side, we check only the type }
  93. location_copy(location,left.location);
  94. end;
  95. {*****************************************************************************
  96. *****************************************************************************}
  97. {**********************************************************************}
  98. { Description: Emit operation to do a bit test, where the bitnumber }
  99. { to test is in the bitnumber register. The value to test against is }
  100. { located in the value register. }
  101. { WARNING: Bitnumber register value is DESTROYED! }
  102. { __Result register is set to 1, if the bit is set otherwise, __Result}
  103. { is set to zero. __RESULT register is also used as scratch. }
  104. {**********************************************************************}
  105. procedure tcginnode.emit_bit_test_reg_reg(list : taasmoutput; bitnumber : tregister; value : tregister; __result :tregister);
  106. begin
  107. { first make sure that the bit number is modulo 32 }
  108. { not necessary, since if it's > 31, we have a range error -> will }
  109. { be caught when range checking is on! (JM) }
  110. { cg.a_op_const_reg(list,OP_AND,31,bitnumber); }
  111. { rotate value register "bitnumber" bits to the right }
  112. cg.a_op_reg_reg_reg(list,OP_SHR,OS_INT,bitnumber,value,__result);
  113. { extract the bit we want }
  114. cg.a_op_const_reg(list,OP_AND,OS_INT,1,__result);
  115. end;
  116. procedure tcginnode.pass_2;
  117. type
  118. Tsetpart=record
  119. range : boolean; {Part is a range.}
  120. start,stop : byte; {Start/stop when range; Stop=element when an element.}
  121. end;
  122. var
  123. l,l2,l3 : tasmlabel;
  124. adjustment : longint;
  125. href : treference;
  126. hr,hr2,hr3,
  127. pleftreg : tregister;
  128. setparts : array[1..8] of Tsetpart;
  129. opsize : tcgsize;
  130. genjumps,
  131. use_small,
  132. ranges : boolean;
  133. i,numparts : byte;
  134. function analizeset(const Aset:Tconstset;is_small:boolean):boolean;
  135. var
  136. compares,maxcompares:word;
  137. i:byte;
  138. begin
  139. analizeset:=false;
  140. ranges:=false;
  141. numparts:=0;
  142. compares:=0;
  143. { Lots of comparisions take a lot of time, so do not allow
  144. too much comparisions. 8 comparisions are, however, still
  145. smalller than emitting the set }
  146. if cs_littlesize in aktglobalswitches then
  147. maxcompares:=8
  148. else
  149. maxcompares:=5;
  150. { when smallset is possible allow only 3 compares the smallset
  151. code is for littlesize also smaller when more compares are used }
  152. if is_small then
  153. maxcompares:=3;
  154. for i:=0 to 255 do
  155. if i in Aset then
  156. begin
  157. if (numparts=0) or (i<>setparts[numparts].stop+1) then
  158. begin
  159. {Set element is a separate element.}
  160. inc(compares);
  161. if compares>maxcompares then
  162. exit;
  163. inc(numparts);
  164. setparts[numparts].range:=false;
  165. setparts[numparts].stop:=i;
  166. end
  167. else
  168. {Set element is part of a range.}
  169. if not setparts[numparts].range then
  170. begin
  171. {Transform an element into a range.}
  172. setparts[numparts].range:=true;
  173. setparts[numparts].start:=setparts[numparts].stop;
  174. setparts[numparts].stop:=i;
  175. ranges := true;
  176. { there's only one compare per range anymore. Only a }
  177. { sub is added, but that's much faster than a }
  178. { cmp/jcc combo so neglect its effect }
  179. { inc(compares);
  180. if compares>maxcompares then
  181. exit; }
  182. end
  183. else
  184. begin
  185. {Extend a range.}
  186. setparts[numparts].stop:=i;
  187. end;
  188. end;
  189. analizeset:=true;
  190. end;
  191. begin
  192. { We check first if we can generate jumps, this can be done
  193. because the resulttype.def is already set in firstpass }
  194. { check if we can use smallset operation using btl which is limited
  195. to 32 bits, the left side may also not contain higher values !! }
  196. use_small:=(tsetdef(right.resulttype.def).settype=smallset) and
  197. ((left.resulttype.def.deftype=orddef) and (torddef(left.resulttype.def).high<=32) or
  198. (left.resulttype.def.deftype=enumdef) and (tenumdef(left.resulttype.def).max<=32));
  199. { Can we generate jumps? Possible for all types of sets }
  200. genjumps:=(right.nodetype=setconstn) and
  201. analizeset(Tsetconstnode(right).value_set^,use_small);
  202. { calculate both operators }
  203. { the complex one first }
  204. firstcomplex(self);
  205. secondpass(left);
  206. { Only process the right if we are not generating jumps }
  207. if not genjumps then
  208. secondpass(right);
  209. if codegenerror then
  210. exit;
  211. { ofcourse not commutative }
  212. if nf_swaped in flags then
  213. swapleftright;
  214. { location is always LOC_JUMP }
  215. location_reset(location,LOC_REGISTER,def_cgsize(resulttype.def));
  216. { allocate a register for the result }
  217. location.register := cg.getintregister(exprasmlist,location.size);
  218. if genjumps then
  219. begin
  220. { Get a label to jump to the end }
  221. objectlibrary.getlabel(l);
  222. { clear the register value, indicating result is FALSE }
  223. cg.a_load_const_reg(exprasmlist,location.size,0,location.register);
  224. opsize := def_cgsize(left.resulttype.def);
  225. { If register is used, use only lower 8 bits }
  226. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  227. begin
  228. { for ranges we always need a 32bit register, because then we }
  229. { use the register as base in a reference (JM) }
  230. if ranges then
  231. begin
  232. pleftreg:=cg.makeregsize(left.location.register,OS_INT);
  233. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_INT,left.location.register,pleftreg);
  234. if opsize <> OS_INT then
  235. cg.a_op_const_reg(exprasmlist,OP_AND,OS_INT,255,pleftreg);
  236. opsize := OS_INT;
  237. end
  238. else
  239. { otherwise simply use the lower 8 bits (no "and" }
  240. { necessary this way) (JM) }
  241. begin
  242. pleftreg:=cg.makeregsize(left.location.register,OS_8);
  243. opsize := OS_8;
  244. end;
  245. end
  246. else
  247. begin
  248. { load the value in a register }
  249. opsize := OS_INT;
  250. pleftreg:=cg.getintregister(exprasmlist,opsize);
  251. cg.a_load_ref_reg(exprasmlist,def_cgsize(left.resulttype.def),opsize,left.location.reference,pleftreg);
  252. end;
  253. { how much have we already substracted from the x in the }
  254. { "x in [y..z]" expression }
  255. adjustment := 0;
  256. hr:=NR_NO;
  257. for i:=1 to numparts do
  258. if setparts[i].range then
  259. { use fact that a <= x <= b <=> cardinal(x-a) <= cardinal(b-a) }
  260. begin
  261. { is the range different from all legal values? }
  262. if (setparts[i].stop-setparts[i].start <> 255) then
  263. begin
  264. { yes, is the lower bound <> 0? }
  265. if (setparts[i].start <> 0) then
  266. { we're going to substract from the left register, }
  267. { so in case of a LOC_CREGISTER first move the value }
  268. { to edi (not done before because now we can do the }
  269. { move and substract in one instruction with LEA) }
  270. if (left.location.loc = LOC_CREGISTER) and
  271. (hr<>pleftreg) then
  272. begin
  273. hr:=cg.getintregister(exprasmlist,OS_INT);
  274. cg.a_op_const_reg_reg(exprasmlist,OP_SUB,opsize,setparts[i].start,pleftreg,hr);
  275. pleftreg:=hr;
  276. opsize := OS_INT;
  277. end
  278. else
  279. begin
  280. { otherwise, the value is already in a register }
  281. { that can be modified }
  282. cg.a_op_const_reg(exprasmlist,OP_SUB,opsize,
  283. setparts[i].start-adjustment,pleftreg)
  284. end;
  285. { new total value substracted from x: }
  286. { adjustment + (setparts[i].start - adjustment) }
  287. adjustment := setparts[i].start;
  288. { check if result < b-a+1 (not "result <= b-a", since }
  289. { we need a carry in case the element is in the range }
  290. { (this will never overflow since we check at the }
  291. { beginning whether stop-start <> 255) }
  292. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_B,
  293. setparts[i].stop-setparts[i].start+1,pleftreg,l);
  294. end
  295. else
  296. { if setparts[i].start = 0 and setparts[i].stop = 255, }
  297. { it's always true since "in" is only allowed for bytes }
  298. begin
  299. cg.a_jmp_always(exprasmlist,l);
  300. end;
  301. end
  302. else
  303. begin
  304. { Emit code to check if left is an element }
  305. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ,
  306. setparts[i].stop-adjustment,pleftreg,l);
  307. end;
  308. { To compensate for not doing a second pass }
  309. right.location.reference.symbol:=nil;
  310. objectlibrary.getlabel(l3);
  311. cg.a_jmp_always(exprasmlist,l3);
  312. { Now place the end label if IN success }
  313. cg.a_label(exprasmlist,l);
  314. { result register is 1 }
  315. cg.a_load_const_reg(exprasmlist,location.size,1,location.register);
  316. { in case value is not found }
  317. cg.a_label(exprasmlist,l3);
  318. case left.location.loc of
  319. LOC_CREGISTER :
  320. cg.ungetregister(exprasmlist,pleftreg);
  321. LOC_REGISTER :
  322. cg.ungetregister(exprasmlist,pleftreg);
  323. else
  324. begin
  325. reference_release(exprasmlist,left.location.reference);
  326. cg.ungetregister(exprasmlist,pleftreg);
  327. end;
  328. end;
  329. end
  330. else
  331. {*****************************************************************}
  332. { NO JUMP TABLE GENERATION }
  333. {*****************************************************************}
  334. begin
  335. { We will now generated code to check the set itself, no jmps,
  336. handle smallsets separate, because it allows faster checks }
  337. if use_small then
  338. begin
  339. {**************************** SMALL SET **********************}
  340. if left.nodetype=ordconstn then
  341. begin
  342. location_force_reg(exprasmlist,right.location,OS_32,true);
  343. { then SHR the register }
  344. cg.a_op_const_reg_reg(exprasmlist,OP_SHR,OS_INT,
  345. tordconstnode(left).value and 31,right.location.register,location.register);
  346. cg.ungetregister(exprasmlist,right.location.register);
  347. { then extract the lowest bit }
  348. cg.a_op_const_reg(exprasmlist,OP_AND,OS_INT,1,location.register);
  349. end
  350. else
  351. begin
  352. case left.location.loc of
  353. LOC_REGISTER,
  354. LOC_CREGISTER:
  355. begin
  356. hr3:=cg.makeregsize(left.location.register,OS_INT);
  357. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_INT,left.location.register,hr3);
  358. hr:=cg.getintregister(exprasmlist,OS_INT);
  359. cg.a_load_reg_reg(exprasmlist,OS_INT,OS_INT,hr3,hr);
  360. end;
  361. else
  362. begin
  363. hr:=cg.getintregister(exprasmlist,OS_INT);
  364. cg.a_load_ref_reg(exprasmlist,def_cgsize(left.resulttype.def),OS_INT,
  365. left.location.reference,hr);
  366. location_release(exprasmlist,left.location);
  367. end;
  368. end;
  369. location_force_reg(exprasmlist,right.location,OS_32,true);
  370. { emit bit test operation }
  371. emit_bit_test_reg_reg(exprasmlist,hr,right.location.register,location.register);
  372. { free the resources }
  373. cg.ungetregister(exprasmlist,right.location.register);
  374. { free bitnumber register }
  375. cg.ungetregister(exprasmlist,hr);
  376. end;
  377. end
  378. else
  379. {************************** NOT SMALL SET ********************}
  380. begin
  381. if right.location.loc=LOC_CONSTANT then
  382. begin
  383. { this section has not been tested! }
  384. { can it actually occur currently? CEC }
  385. { yes: "if bytevar in [1,3,5,7,9,11,13,15]" (JM) }
  386. objectlibrary.getlabel(l);
  387. objectlibrary.getlabel(l2);
  388. case left.location.loc of
  389. LOC_REGISTER,
  390. LOC_CREGISTER:
  391. begin
  392. hr:=cg.makeregsize(left.location.register,OS_INT);
  393. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_INT,left.location.register,hr);
  394. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_BE,31,hr,l);
  395. { reset of result register is done in routine entry }
  396. cg.a_jmp_always(exprasmlist,l2);
  397. cg.a_label(exprasmlist,l);
  398. { We have to load the value into a register because
  399. btl does not accept values only refs or regs (PFV) }
  400. hr2:=cg.getintregister(exprasmlist,OS_INT);
  401. cg.a_load_const_reg(exprasmlist,OS_INT,right.location.value,hr2);
  402. end;
  403. LOC_REFERENCE,
  404. LOC_CREFERENCE:
  405. begin
  406. cg.a_cmp_const_ref_label(exprasmlist,OS_8,OC_BE,31,left.location.reference,l);
  407. cg.a_jmp_always(exprasmlist,l2);
  408. cg.a_label(exprasmlist,l);
  409. location_release(exprasmlist,left.location);
  410. hr:=cg.getintregister(exprasmlist,OS_INT);
  411. cg.a_load_ref_reg(exprasmlist,OS_INT,OS_INT,left.location.reference,hr);
  412. { We have to load the value into a register because
  413. btl does not accept values only refs or regs (PFV) }
  414. hr2:=cg.getintregister(exprasmlist,OS_INT);
  415. cg.a_load_const_reg(exprasmlist,OS_INT,right.location.value,hr2);
  416. end;
  417. else
  418. internalerror(2002081002);
  419. end;
  420. { emit bit test operation }
  421. emit_bit_test_reg_reg(exprasmlist,hr,hr2,location.register);
  422. cg.ungetregister(exprasmlist,hr2);
  423. if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  424. cg.ungetregister(exprasmlist,hr);
  425. cg.a_label(exprasmlist,l2);
  426. end { of right.location.loc=LOC_CONSTANT }
  427. { do search in a normal set which could have >32 elementsm
  428. but also used if the left side contains higher values > 32 }
  429. else if left.nodetype=ordconstn then
  430. begin
  431. { use location.register as scratch register here }
  432. if (target_info.endian = endian_little) then
  433. inc(right.location.reference.offset,tordconstnode(left).value shr 3)
  434. else
  435. { adjust for endianess differences }
  436. inc(right.location.reference.offset,(tordconstnode(left).value shr 3) xor 3);
  437. cg.a_load_ref_reg(exprasmlist,OS_8,location.size,right.location.reference, location.register);
  438. location_release(exprasmlist,right.location);
  439. cg.a_op_const_reg(exprasmlist,OP_SHR,location.size,tordconstnode(left).value and 7,
  440. location.register);
  441. cg.a_op_const_reg(exprasmlist,OP_AND,location.size,1,location.register);
  442. end
  443. else
  444. begin
  445. location_force_reg(exprasmlist,left.location,OS_INT,true);
  446. pleftreg := left.location.register;
  447. location_freetemp(exprasmlist,left.location);
  448. hr := cg.getaddressregister(exprasmlist);
  449. cg.a_op_const_reg_reg(exprasmlist,OP_SHR,OS_32,5,pleftreg,hr);
  450. cg.a_op_const_reg(exprasmlist,OP_SHL,OS_32,2,hr);
  451. href := right.location.reference;
  452. if (href.base = NR_NO) then
  453. href.base := hr
  454. else if (right.location.reference.index = NR_NO) then
  455. href.index := hr
  456. else
  457. begin
  458. reference_release(exprasmlist,href);
  459. hr2 := cg.getaddressregister(exprasmlist);
  460. cg.a_loadaddr_ref_reg(exprasmlist,href, hr2);
  461. reference_reset_base(href,hr2,0);
  462. href.index := hr;
  463. end;
  464. reference_release(exprasmlist,href);
  465. cg.a_load_ref_reg(exprasmlist,OS_32,OS_32,href,location.register);
  466. cg.ungetregister(exprasmlist,pleftreg);
  467. hr := cg.getintregister(exprasmlist,OS_32);
  468. cg.a_op_const_reg_reg(exprasmlist,OP_AND,OS_32,31,pleftreg,hr);
  469. cg.a_op_reg_reg(exprasmlist,OP_SHR,OS_32,hr,location.register);
  470. cg.ungetregister(exprasmlist,hr);
  471. cg.a_op_const_reg(exprasmlist,OP_AND,OS_32,1,location.register);
  472. end;
  473. end;
  474. end;
  475. location_freetemp(exprasmlist,right.location);
  476. end;
  477. {*****************************************************************************
  478. TCGCASENODE
  479. *****************************************************************************}
  480. procedure tcgcasenode.optimizevalues(var max_linear_list:longint;var max_dist:cardinal);
  481. begin
  482. { no changes by default }
  483. end;
  484. function tcgcasenode.has_jumptable : boolean;
  485. begin
  486. { No jumptable support in the default implementation }
  487. has_jumptable:=false;
  488. end;
  489. procedure tcgcasenode.genjumptable(hp : pcaserecord;min_,max_ : longint);
  490. begin
  491. internalerror(200209161);
  492. end;
  493. procedure tcgcasenode.genlinearlist(hp : pcaserecord);
  494. var
  495. first : boolean;
  496. last : TConstExprInt;
  497. scratch_reg: tregister;
  498. procedure genitem(t : pcaserecord);
  499. procedure gensub(value:longint);
  500. begin
  501. { here, since the sub and cmp are separate we need
  502. to move the result before subtract to a help
  503. register.
  504. }
  505. cg.a_load_reg_reg(exprasmlist, opsize, opsize, hregister, scratch_reg);
  506. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, value, hregister);
  507. end;
  508. begin
  509. if assigned(t^.less) then
  510. genitem(t^.less);
  511. { need we to test the first value }
  512. if first and (t^._low>get_min_value(left.resulttype.def)) then
  513. begin
  514. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,aword(t^._low),hregister,elselabel);
  515. end;
  516. if t^._low=t^._high then
  517. begin
  518. if t^._low-last=0 then
  519. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ,0,hregister,t^.statement)
  520. else
  521. begin
  522. gensub(longint(t^._low-last));
  523. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ,aword(t^._low-last),scratch_reg,t^.statement);
  524. end;
  525. last:=t^._low;
  526. end
  527. else
  528. begin
  529. { it begins with the smallest label, if the value }
  530. { is even smaller then jump immediately to the }
  531. { ELSE-label }
  532. if first then
  533. begin
  534. { have we to ajust the first value ? }
  535. if (t^._low>get_min_value(left.resulttype.def)) then
  536. gensub(longint(t^._low));
  537. end
  538. else
  539. begin
  540. { if there is no unused label between the last and the }
  541. { present label then the lower limit can be checked }
  542. { immediately. else check the range in between: }
  543. gensub(longint(t^._low-last));
  544. cg.a_cmp_const_reg_label(exprasmlist, opsize,jmp_lt,aword(t^._low-last),scratch_reg,elselabel);
  545. end;
  546. gensub(longint(t^._high-t^._low));
  547. cg.a_cmp_const_reg_label(exprasmlist, opsize,jmp_le,aword(t^._high-t^._low),scratch_reg,t^.statement);
  548. last:=t^._high;
  549. end;
  550. first:=false;
  551. if assigned(t^.greater) then
  552. genitem(t^.greater);
  553. end;
  554. begin
  555. { do we need to generate cmps? }
  556. if (with_sign and (min_label<0)) then
  557. genlinearcmplist(hp)
  558. else
  559. begin
  560. last:=0;
  561. first:=true;
  562. scratch_reg:=cg.getintregister(exprasmlist,opsize);
  563. genitem(hp);
  564. cg.ungetregister(exprasmlist,scratch_reg);
  565. cg.a_jmp_always(exprasmlist,elselabel);
  566. end;
  567. end;
  568. procedure tcgcasenode.genlinearcmplist(hp : pcaserecord);
  569. var
  570. first : boolean;
  571. last : TConstExprInt;
  572. procedure genitem(t : pcaserecord);
  573. var
  574. l1 : tasmlabel;
  575. begin
  576. if assigned(t^.less) then
  577. genitem(t^.less);
  578. if t^._low=t^._high then
  579. begin
  580. if opsize in [OS_S64,OS_64] then
  581. begin
  582. objectlibrary.getlabel(l1);
  583. {$ifdef Delphi}
  584. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_NE, hi((t^._low)),hregister2,l1);
  585. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_EQ, lo((t^._low)),hregister, t^.statement);
  586. {$else}
  587. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_NE, aword(hi(int64(t^._low))),hregister2,l1);
  588. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_EQ, aword(lo(int64(t^._low))),hregister, t^.statement);
  589. {$endif}
  590. cg.a_label(exprasmlist,l1);
  591. end
  592. else
  593. begin
  594. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ, aword(t^._low),hregister, t^.statement);
  595. end;
  596. { Reset last here, because we've only checked for one value and need to compare
  597. for the next range both the lower and upper bound }
  598. last:=0;
  599. end
  600. else
  601. begin
  602. { it begins with the smallest label, if the value }
  603. { is even smaller then jump immediately to the }
  604. { ELSE-label }
  605. if first or (t^._low-last>1) then
  606. begin
  607. if opsize in [OS_64,OS_S64] then
  608. begin
  609. objectlibrary.getlabel(l1);
  610. {$ifdef Delphi}
  611. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_lt, aword(hi((t^._low))),
  612. hregister2, elselabel);
  613. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_gt, aword(hi((t^._low))),
  614. hregister2, l1);
  615. { the comparisation of the low dword must be always unsigned! }
  616. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_B, aword(lo((t^._low))), hregister, elselabel);
  617. {$else}
  618. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_lt, aword(hi(int64(t^._low))),
  619. hregister2, elselabel);
  620. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_gt, aword(hi(int64(t^._low))),
  621. hregister2, l1);
  622. { the comparisation of the low dword must be always unsigned! }
  623. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_B, aword(lo(int64(t^._low))), hregister, elselabel);
  624. {$endif}
  625. cg.a_label(exprasmlist,l1);
  626. end
  627. else
  628. begin
  629. cg.a_cmp_const_reg_label(exprasmlist, opsize, jmp_lt, aword(t^._low), hregister,
  630. elselabel);
  631. end;
  632. end;
  633. if opsize in [OS_S64,OS_64] then
  634. begin
  635. objectlibrary.getlabel(l1);
  636. {$ifdef Delphi}
  637. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_lt, aword(hi(t^._high)), hregister2,
  638. t^.statement);
  639. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_gt, aword(hi(t^._high)), hregister2,
  640. l1);
  641. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_BE, aword(lo(t^._high)), hregister, t^.statement);
  642. {$else}
  643. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_lt, aword(hi(int64(t^._high))), hregister2,
  644. t^.statement);
  645. cg.a_cmp_const_reg_label(exprasmlist, OS_32, jmp_gt, aword(hi(int64(t^._high))), hregister2,
  646. l1);
  647. cg.a_cmp_const_reg_label(exprasmlist, OS_32, OC_BE, aword(lo(int64(t^._high))), hregister, t^.statement);
  648. {$endif}
  649. cg.a_label(exprasmlist,l1);
  650. end
  651. else
  652. begin
  653. cg.a_cmp_const_reg_label(exprasmlist, opsize, jmp_le, aword(t^._high), hregister, t^.statement);
  654. end;
  655. last:=t^._high;
  656. end;
  657. first:=false;
  658. if assigned(t^.greater) then
  659. genitem(t^.greater);
  660. end;
  661. begin
  662. last:=0;
  663. first:=true;
  664. genitem(hp);
  665. cg.a_jmp_always(exprasmlist,elselabel);
  666. end;
  667. procedure tcgcasenode.gentreejmp(p : pcaserecord);
  668. var
  669. lesslabel,greaterlabel : tasmlabel;
  670. begin
  671. cg.a_label(exprasmlist,p^._at);
  672. { calculate labels for left and right }
  673. if (p^.less=nil) then
  674. lesslabel:=elselabel
  675. else
  676. lesslabel:=p^.less^._at;
  677. if (p^.greater=nil) then
  678. greaterlabel:=elselabel
  679. else
  680. greaterlabel:=p^.greater^._at;
  681. { calculate labels for left and right }
  682. { no range label: }
  683. if p^._low=p^._high then
  684. begin
  685. if greaterlabel=lesslabel then
  686. begin
  687. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_NE,p^._low,hregister, lesslabel);
  688. end
  689. else
  690. begin
  691. cg.a_cmp_const_reg_label(exprasmlist,opsize, jmp_lt,p^._low,hregister, lesslabel);
  692. cg.a_cmp_const_reg_label(exprasmlist,opsize, jmp_gt,p^._low,hregister, greaterlabel);
  693. end;
  694. cg.a_jmp_always(exprasmlist,p^.statement);
  695. end
  696. else
  697. begin
  698. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,p^._low, hregister, lesslabel);
  699. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_gt,p^._high,hregister, greaterlabel);
  700. cg.a_jmp_always(exprasmlist,p^.statement);
  701. end;
  702. if assigned(p^.less) then
  703. gentreejmp(p^.less);
  704. if assigned(p^.greater) then
  705. gentreejmp(p^.greater);
  706. end;
  707. procedure ReLabel(var p:tasmsymbol);
  708. begin
  709. if p.defbind = AB_LOCAL then
  710. begin
  711. if not assigned(p.altsymbol) then
  712. objectlibrary.GenerateAltSymbol(p);
  713. p:=p.altsymbol;
  714. p.increfs;
  715. end;
  716. end;
  717. procedure relabelcaserecord(p : pcaserecord);
  718. begin
  719. Relabel(p^.statement);
  720. Relabel(p^._at);
  721. if assigned(p^.greater) then
  722. relabelcaserecord(p^.greater);
  723. if assigned(p^.less) then
  724. relabelcaserecord(p^.less);
  725. end;
  726. procedure tcgcasenode.pass_2;
  727. var
  728. lv,hv,
  729. max_label: tconstexprint;
  730. labels : longint;
  731. max_linear_list : longint;
  732. otl, ofl: tasmlabel;
  733. isjump : boolean;
  734. max_dist,
  735. dist : cardinal;
  736. hp : tstatementnode;
  737. begin
  738. location_reset(location,LOC_VOID,OS_NO);
  739. { Relabel for inlining? }
  740. if inlining_procedure and assigned(nodes) then
  741. begin
  742. objectlibrary.CreateUsedAsmSymbolList;
  743. relabelcaserecord(nodes);
  744. end;
  745. objectlibrary.getlabel(endlabel);
  746. objectlibrary.getlabel(elselabel);
  747. with_sign:=is_signed(left.resulttype.def);
  748. if with_sign then
  749. begin
  750. jmp_gt:=OC_GT;
  751. jmp_lt:=OC_LT;
  752. jmp_le:=OC_LTE;
  753. end
  754. else
  755. begin
  756. jmp_gt:=OC_A;
  757. jmp_lt:=OC_B;
  758. jmp_le:=OC_BE;
  759. end;
  760. { save current truelabel and falselabel }
  761. isjump:=false;
  762. if left.location.loc=LOC_JUMP then
  763. begin
  764. otl:=truelabel;
  765. objectlibrary.getlabel(truelabel);
  766. ofl:=falselabel;
  767. objectlibrary.getlabel(falselabel);
  768. isjump:=true;
  769. end;
  770. secondpass(left);
  771. { determines the size of the operand }
  772. opsize:=def_cgsize(left.resulttype.def);
  773. { copy the case expression to a register }
  774. location_force_reg(exprasmlist,left.location,opsize,false);
  775. if opsize in [OS_S64,OS_64] then
  776. begin
  777. hregister:=left.location.registerlow;
  778. hregister2:=left.location.registerhigh;
  779. end
  780. else
  781. hregister:=left.location.register;
  782. if isjump then
  783. begin
  784. truelabel:=otl;
  785. falselabel:=ofl;
  786. end;
  787. { we need the min_label always to choose between }
  788. { cmps and subs/decs }
  789. min_label:=case_get_min(nodes);
  790. {$ifdef OLDREGVARS}
  791. load_all_regvars(exprasmlist);
  792. {$endif OLDREGVARS}
  793. { now generate the jumps }
  794. if opsize in [OS_64,OS_S64] then
  795. genlinearcmplist(nodes)
  796. else
  797. begin
  798. if cs_optimize in aktglobalswitches then
  799. begin
  800. { procedures are empirically passed on }
  801. { consumption can also be calculated }
  802. { but does it pay on the different }
  803. { processors? }
  804. { moreover can the size only be appro- }
  805. { ximated as it is not known if rel8, }
  806. { rel16 or rel32 jumps are used }
  807. max_label:=case_get_max(nodes);
  808. labels:=case_count_labels(nodes);
  809. { can we omit the range check of the jump table ? }
  810. getrange(left.resulttype.def,lv,hv);
  811. jumptable_no_range:=(lv=min_label) and (hv=max_label);
  812. { hack a little bit, because the range can be greater }
  813. { than the positive range of a longint }
  814. if (min_label<0) and (max_label>0) then
  815. begin
  816. if min_label=TConstExprInt($80000000) then
  817. dist:=Cardinal(max_label)+Cardinal($80000000)
  818. else
  819. dist:=Cardinal(max_label)+Cardinal(-min_label)
  820. end
  821. else
  822. dist:=max_label-min_label;
  823. { optimize for size ? }
  824. if cs_littlesize in aktglobalswitches then
  825. begin
  826. if (has_jumptable) and
  827. not((labels<=2) or
  828. ((max_label-min_label)<0) or
  829. ((max_label-min_label)>3*labels)) then
  830. begin
  831. { if the labels less or more a continuum then }
  832. genjumptable(nodes,min_label,max_label);
  833. end
  834. else
  835. begin
  836. { a linear list is always smaller than a jump tree }
  837. genlinearlist(nodes);
  838. end;
  839. end
  840. else
  841. begin
  842. max_dist:=4*cardinal(labels);
  843. if jumptable_no_range then
  844. max_linear_list:=4
  845. else
  846. max_linear_list:=2;
  847. { allow processor specific values }
  848. optimizevalues(max_linear_list,max_dist);
  849. if (labels<=max_linear_list) then
  850. genlinearlist(nodes)
  851. else
  852. begin
  853. if (has_jumptable) and
  854. (dist<max_dist) then
  855. genjumptable(nodes,min_label,max_label)
  856. else
  857. begin
  858. {
  859. This one expects that the case labels are a
  860. perfectly balanced tree, which is not the case
  861. very often -> generates really bad code (JM)
  862. if labels>16 then
  863. gentreejmp(nodes)
  864. else
  865. }
  866. genlinearlist(nodes);
  867. end;
  868. end;
  869. end;
  870. end
  871. else
  872. { it's always not bad }
  873. genlinearlist(nodes);
  874. end;
  875. cg.ungetregister(exprasmlist,hregister);
  876. { now generate the instructions }
  877. hp:=tstatementnode(right);
  878. while assigned(hp) do
  879. begin
  880. { relabel when inlining }
  881. if inlining_procedure then
  882. begin
  883. if hp.left.nodetype<>labeln then
  884. internalerror(200211261);
  885. Relabel(tlabelnode(hp.left).labelnr);
  886. end;
  887. secondpass(hp.left);
  888. { don't come back to case line }
  889. aktfilepos:=exprasmList.getlasttaifilepos^;
  890. {$ifdef OLDREGVARS}
  891. load_all_regvars(exprasmlist);
  892. {$endif OLDREGVARS}
  893. cg.a_jmp_always(exprasmlist,endlabel);
  894. hp:=tstatementnode(hp.right);
  895. end;
  896. cg.a_label(exprasmlist,elselabel);
  897. { ...and the else block }
  898. if assigned(elseblock) then
  899. begin
  900. secondpass(elseblock);
  901. {$ifdef OLDREGVARS}
  902. load_all_regvars(exprasmlist);
  903. {$endif OLDREGVARS}
  904. end;
  905. cg.a_label(exprasmlist,endlabel);
  906. { Remove relabels for inlining }
  907. if inlining_procedure and
  908. assigned(nodes) then
  909. begin
  910. { restore used symbols }
  911. objectlibrary.UsedAsmSymbolListResetAltSym;
  912. objectlibrary.DestroyUsedAsmSymbolList;
  913. end;
  914. end;
  915. begin
  916. csetelementnode:=tcgsetelementnode;
  917. cinnode:=tcginnode;
  918. ccasenode:=tcgcasenode;
  919. end.
  920. {
  921. $Log$
  922. Revision 1.53 2003-11-10 19:10:31 peter
  923. * fixed range compare when the last value was an equal
  924. compare. The compare for the lower range was skipped
  925. Revision 1.52 2003/10/17 14:38:32 peter
  926. * 64k registers supported
  927. * fixed some memory leaks
  928. Revision 1.51 2003/10/10 17:48:13 peter
  929. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  930. * tregisteralloctor renamed to trgobj
  931. * removed rgobj from a lot of units
  932. * moved location_* and reference_* to cgobj
  933. * first things for mmx register allocation
  934. Revision 1.50 2003/10/09 21:31:37 daniel
  935. * Register allocator splitted, ans abstract now
  936. Revision 1.49 2003/10/01 20:34:48 peter
  937. * procinfo unit contains tprocinfo
  938. * cginfo renamed to cgbase
  939. * moved cgmessage to verbose
  940. * fixed ppc and sparc compiles
  941. Revision 1.48 2003/09/03 15:55:01 peter
  942. * NEWRA branch merged
  943. Revision 1.47.2.1 2003/08/29 17:28:59 peter
  944. * next batch of updates
  945. Revision 1.47 2003/08/20 20:29:06 daniel
  946. * Some more R_NO changes
  947. * Preventive code to loadref added
  948. Revision 1.46 2003/07/23 11:02:53 jonas
  949. * final (?) fix to in-code
  950. Revision 1.45 2003/07/20 18:03:27 jonas
  951. * fixed bug in tcginnode.pass_2
  952. Revision 1.44 2003/07/06 14:28:04 jonas
  953. * fixed register leak
  954. * changed a couple of case-statements to location_force_reg()
  955. Revision 1.43 2003/06/12 22:09:54 jonas
  956. * tcginnode.pass_2 doesn't call a helper anymore in any case
  957. * fixed ungetregisterfpu compilation problems
  958. Revision 1.42 2003/06/08 16:03:22 jonas
  959. - disabled gentreejmp for now, it expects that the case labels are
  960. ordered as a perfectly balanced tree, while they are often a linked
  961. list -> generates extremely bad code
  962. Revision 1.41 2003/06/07 18:57:04 jonas
  963. + added freeintparaloc
  964. * ppc get/freeintparaloc now check whether the parameter regs are
  965. properly allocated/deallocated (and get an extra list para)
  966. * ppc a_call_* now internalerrors if pi_do_call is not yet set
  967. * fixed lot of missing pi_do_call's
  968. Revision 1.40 2003/06/03 21:11:09 peter
  969. * cg.a_load_* get a from and to size specifier
  970. * makeregsize only accepts newregister
  971. * i386 uses generic tcgnotnode,tcgunaryminus
  972. Revision 1.39 2003/06/01 21:38:06 peter
  973. * getregisterfpu size parameter added
  974. * op_const_reg size parameter added
  975. * sparc updates
  976. Revision 1.38 2003/05/30 23:57:08 peter
  977. * more sparc cleanup
  978. * accumulator removed, splitted in function_return_reg (called) and
  979. function_result_reg (caller)
  980. Revision 1.37 2003/05/30 23:49:18 jonas
  981. * a_load_loc_reg now has an extra size parameter for the destination
  982. register (properly fixes what I worked around in revision 1.106 of
  983. ncgutil.pas)
  984. Revision 1.36 2003/05/24 19:48:49 jonas
  985. * fixed tcginnode endian bug again, but correcty this time :)
  986. Revision 1.35 2003/05/23 21:10:50 florian
  987. * fixed sparc compiler compilation
  988. Revision 1.34 2003/05/23 19:52:28 jonas
  989. * corrected fix for endian differences in tcginnode
  990. Revision 1.33 2003/05/17 19:17:35 jonas
  991. * fixed size setting of result location of innodes
  992. Revision 1.32 2003/05/01 12:26:50 jonas
  993. * fixed endian issue in inlined in-test for smallsets
  994. * pass the address of normalsets to fpc_set_in_set_byte instead of the
  995. contents of the first 4 bytes
  996. Revision 1.31 2003/04/25 08:25:26 daniel
  997. * Ifdefs around a lot of calls to cleartempgen
  998. * Fixed registers that are allocated but not freed in several nodes
  999. * Tweak to register allocator to cause less spills
  1000. * 8-bit registers now interfere with esi,edi and ebp
  1001. Compiler can now compile rtl successfully when using new register
  1002. allocator
  1003. Revision 1.30 2003/04/22 23:50:23 peter
  1004. * firstpass uses expectloc
  1005. * checks if there are differences between the expectloc and
  1006. location.loc from secondpass in EXTDEBUG
  1007. Revision 1.29 2003/04/22 14:33:38 peter
  1008. * removed some notes/hints
  1009. Revision 1.28 2003/04/22 12:45:58 florian
  1010. * fixed generic in operator code
  1011. + added debug code to check if all scratch registers are released
  1012. Revision 1.27 2003/04/22 10:09:35 daniel
  1013. + Implemented the actual register allocator
  1014. + Scratch registers unavailable when new register allocator used
  1015. + maybe_save/maybe_restore unavailable when new register allocator used
  1016. Revision 1.26 2003/02/19 22:00:14 daniel
  1017. * Code generator converted to new register notation
  1018. - Horribily outdated todo.txt removed
  1019. Revision 1.25 2003/01/08 18:43:56 daniel
  1020. * Tregister changed into a record
  1021. Revision 1.24 2002/11/27 02:37:13 peter
  1022. * case statement inlining added
  1023. * fixed inlining of write()
  1024. * switched statementnode left and right parts so the statements are
  1025. processed in the correct order when getcopy is used. This is
  1026. required for tempnodes
  1027. Revision 1.23 2002/11/25 17:43:18 peter
  1028. * splitted defbase in defutil,symutil,defcmp
  1029. * merged isconvertable and is_equal into compare_defs(_ext)
  1030. * made operator search faster by walking the list only once
  1031. Revision 1.22 2002/10/05 12:43:25 carl
  1032. * fixes for Delphi 6 compilation
  1033. (warning : Some features do not work under Delphi)
  1034. Revision 1.21 2002/10/03 21:31:10 carl
  1035. * range check error fixes
  1036. Revision 1.20 2002/09/17 18:54:03 jonas
  1037. * a_load_reg_reg() now has two size parameters: source and dest. This
  1038. allows some optimizations on architectures that don't encode the
  1039. register size in the register name.
  1040. Revision 1.19 2002/09/16 18:08:26 peter
  1041. * fix last optimization in genlinearlist, detected by bug tw1066
  1042. * use generic casenode.pass2 routine and override genlinearlist
  1043. * add jumptable support to generic casenode, by default there is
  1044. no jumptable support
  1045. Revision 1.18 2002/08/15 15:11:53 carl
  1046. * oldset define is now correct for all cpu's except i386
  1047. * correct compilation problems because of the above
  1048. Revision 1.17 2002/08/13 18:01:52 carl
  1049. * rename swatoperands to swapoperands
  1050. + m68k first compilable version (still needs a lot of testing):
  1051. assembler generator, system information , inline
  1052. assembler reader.
  1053. Revision 1.16 2002/08/11 14:32:27 peter
  1054. * renamed current_library to objectlibrary
  1055. Revision 1.15 2002/08/11 13:24:12 peter
  1056. * saving of asmsymbols in ppu supported
  1057. * asmsymbollist global is removed and moved into a new class
  1058. tasmlibrarydata that will hold the info of a .a file which
  1059. corresponds with a single module. Added librarydata to tmodule
  1060. to keep the library info stored for the module. In the future the
  1061. objectfiles will also be stored to the tasmlibrarydata class
  1062. * all getlabel/newasmsymbol and friends are moved to the new class
  1063. Revision 1.14 2002/08/11 11:37:42 jonas
  1064. * genlinear(cmp)list can now be overridden by descendents
  1065. Revision 1.13 2002/08/11 06:14:40 florian
  1066. * fixed powerpc compilation problems
  1067. Revision 1.12 2002/08/10 17:15:12 jonas
  1068. * optimizations and bugfix
  1069. Revision 1.11 2002/07/28 09:24:18 carl
  1070. + generic case node
  1071. Revision 1.10 2002/07/23 14:31:00 daniel
  1072. * Added internal error when asked to generate code for 'if expr in []'
  1073. Revision 1.9 2002/07/23 12:34:30 daniel
  1074. * Readded old set code. To use it define 'oldset'. Activated by default
  1075. for ppc.
  1076. Revision 1.8 2002/07/22 11:48:04 daniel
  1077. * Sets are now internally sets.
  1078. Revision 1.7 2002/07/21 16:58:20 jonas
  1079. * fixed some bugs in tcginnode.pass_2() and optimized the bit test
  1080. Revision 1.6 2002/07/20 11:57:54 florian
  1081. * types.pas renamed to defbase.pas because D6 contains a types
  1082. unit so this would conflicts if D6 programms are compiled
  1083. + Willamette/SSE2 instructions to assembler added
  1084. Revision 1.5 2002/07/11 14:41:28 florian
  1085. * start of the new generic parameter handling
  1086. Revision 1.4 2002/07/07 10:16:29 florian
  1087. * problems with last commit fixed
  1088. Revision 1.3 2002/07/06 20:19:25 carl
  1089. + generic set handling
  1090. Revision 1.2 2002/07/01 16:23:53 peter
  1091. * cg64 patch
  1092. * basics for currency
  1093. * asnode updates for class and interface (not finished)
  1094. Revision 1.1 2002/06/16 08:14:56 carl
  1095. + generic sets
  1096. }