ncgset.pas 48 KB

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