ncgset.pas 48 KB

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