ncgset.pas 48 KB

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