ncgset.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  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,cginfo,cgbase,cgobj,aasmbase,aasmtai;
  23. type
  24. tcgsetelementnode = class(tsetelementnode)
  25. procedure pass_2;override;
  26. end;
  27. tcginnode = class(tinnode)
  28. procedure pass_2;override;
  29. {# Routine to test bitnumber in bitnumber register on value
  30. in value register. The __result register should be set
  31. to one if the bit is set, otherwise __result register
  32. should be set to zero.
  33. Should be overriden on processors which have specific
  34. instructions to do bit tests.
  35. }
  36. procedure emit_bit_test_reg_reg(list : taasmoutput; bitnumber : tregister;
  37. value : tregister; __result :tregister);virtual;
  38. end;
  39. tcgcasenode = class(tcasenode)
  40. {
  41. Emits the case node statement. Contrary to the intel
  42. 80x86 version, this version does not emit jump tables,
  43. because of portability problems.
  44. }
  45. procedure pass_2;override;
  46. end;
  47. implementation
  48. uses
  49. globtype,systems,
  50. verbose,globals,
  51. symconst,symdef,defbase,
  52. paramgr,
  53. pass_2,
  54. ncon,
  55. cga,tgobj,ncgutil,regvars,rgobj;
  56. {*****************************************************************************
  57. TCGSETELEMENTNODE
  58. *****************************************************************************}
  59. procedure tcgsetelementnode.pass_2;
  60. var
  61. pushedregs : tmaybesave;
  62. begin
  63. { load first value in 32bit register }
  64. secondpass(left);
  65. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  66. location_force_reg(exprasmlist,left.location,OS_32,false);
  67. { also a second value ? }
  68. if assigned(right) then
  69. begin
  70. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  71. secondpass(right);
  72. if codegenerror then
  73. exit;
  74. maybe_restore(exprasmlist,left.location,pushedregs);
  75. if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  76. location_force_reg(exprasmlist,right.location,OS_32,false);
  77. end;
  78. { we doesn't modify the left side, we check only the type }
  79. location_copy(location,left.location);
  80. end;
  81. {*****************************************************************************
  82. *****************************************************************************}
  83. {**********************************************************************}
  84. { Description: Emit operation to do a bit test, where the bitnumber }
  85. { to test is in the bitnumber register. The value to test against is }
  86. { located in the value register. }
  87. { WARNING: Bitnumber register value is DESTROYED! }
  88. { __Result register is set to 1, if the bit is set otherwise, __Result}
  89. { is set to zero. __RESULT register is also used as scratch. }
  90. {**********************************************************************}
  91. procedure tcginnode.emit_bit_test_reg_reg(list : taasmoutput; bitnumber : tregister; value : tregister; __result :tregister);
  92. begin
  93. { first make sure that the bit number is modulo 32 }
  94. { not necessary, since if it's > 31, we have a range error -> will }
  95. { be caught when range checking is on! (JM) }
  96. { cg.a_op_const_reg(list,OP_AND,31,bitnumber); }
  97. { rotate value register "bitnumber" bits to the right }
  98. cg.a_op_reg_reg_reg(list,OP_SHR,OS_INT,bitnumber,value,__result);
  99. { extract the bit we want }
  100. cg.a_op_const_reg(list,OP_AND,1,__result);
  101. end;
  102. procedure tcginnode.pass_2;
  103. type
  104. Tsetpart=record
  105. range : boolean; {Part is a range.}
  106. start,stop : byte; {Start/stop when range; Stop=element when an element.}
  107. end;
  108. var
  109. genjumps,
  110. use_small,
  111. ranges : boolean;
  112. hr,hr2,hr3,
  113. pleftreg : tregister;
  114. href : treference;
  115. opsize : tcgsize;
  116. setparts : array[1..8] of Tsetpart;
  117. i,numparts : byte;
  118. adjustment : longint;
  119. pushedregs : tmaybesave;
  120. l,l2,l3 : tasmlabel;
  121. {$ifdef oldset}
  122. function analizeset(Aset:Pconstset;is_small:boolean):boolean;
  123. type
  124. byteset=set of byte;
  125. {$else}
  126. function analizeset(const Aset:Tconstset;is_small:boolean):boolean;
  127. {$endif}
  128. var
  129. compares,maxcompares:word;
  130. i:byte;
  131. begin
  132. if Aset=[] then
  133. {The expression...
  134. if expr in []
  135. ...is allways false. It should be optimized away in the
  136. resulttype pass, and thus never occur here. Since we
  137. do generate wrong code for it, do internalerror.}
  138. internalerror(2002072301);
  139. analizeset:=false;
  140. ranges:=false;
  141. numparts:=0;
  142. compares:=0;
  143. { Lots of comparisions take a lot of time, so do not allow
  144. too much comparisions. 8 comparisions are, however, still
  145. smalller than emitting the set }
  146. if cs_littlesize in aktglobalswitches then
  147. maxcompares:=8
  148. else
  149. maxcompares:=5;
  150. { when smallset is possible allow only 3 compares the smallset
  151. code is for littlesize also smaller when more compares are used }
  152. if is_small then
  153. maxcompares:=3;
  154. for i:=0 to 255 do
  155. {$ifdef oldset}
  156. if i in byteset(Aset^) then
  157. {$else}
  158. if i in Aset then
  159. {$endif}
  160. begin
  161. if (numparts=0) or (i<>setparts[numparts].stop+1) then
  162. begin
  163. {Set element is a separate element.}
  164. inc(compares);
  165. if compares>maxcompares then
  166. exit;
  167. inc(numparts);
  168. setparts[numparts].range:=false;
  169. setparts[numparts].stop:=i;
  170. end
  171. else
  172. {Set element is part of a range.}
  173. if not setparts[numparts].range then
  174. begin
  175. {Transform an element into a range.}
  176. setparts[numparts].range:=true;
  177. setparts[numparts].start:=setparts[numparts].stop;
  178. setparts[numparts].stop:=i;
  179. ranges := true;
  180. { there's only one compare per range anymore. Only a }
  181. { sub is added, but that's much faster than a }
  182. { cmp/jcc combo so neglect its effect }
  183. { inc(compares);
  184. if compares>maxcompares then
  185. exit; }
  186. end
  187. else
  188. begin
  189. {Extend a range.}
  190. setparts[numparts].stop:=i;
  191. end;
  192. end;
  193. analizeset:=true;
  194. end;
  195. begin
  196. { We check first if we can generate jumps, this can be done
  197. because the resulttype.def is already set in firstpass }
  198. { check if we can use smallset operation using btl which is limited
  199. to 32 bits, the left side may also not contain higher values !! }
  200. use_small:=(tsetdef(right.resulttype.def).settype=smallset) and
  201. ((left.resulttype.def.deftype=orddef) and (torddef(left.resulttype.def).high<=32) or
  202. (left.resulttype.def.deftype=enumdef) and (tenumdef(left.resulttype.def).max<=32));
  203. { Can we generate jumps? Possible for all types of sets }
  204. {$ifdef oldset}
  205. genjumps:=(right.nodetype=setconstn) and
  206. analizeset(Tsetconstnode(right).value_set,use_small);
  207. {$else}
  208. genjumps:=(right.nodetype=setconstn) and
  209. analizeset(Tsetconstnode(right).value_set^,use_small);
  210. {$endif}
  211. { calculate both operators }
  212. { the complex one first }
  213. firstcomplex(self);
  214. secondpass(left);
  215. { Only process the right if we are not generating jumps }
  216. if not genjumps then
  217. begin
  218. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  219. secondpass(right);
  220. maybe_restore(exprasmlist,left.location,pushedregs);
  221. end;
  222. if codegenerror then
  223. exit;
  224. { ofcourse not commutative }
  225. if nf_swaped in flags then
  226. swapleftright;
  227. { location is always LOC_JUMP }
  228. location_reset(location,LOC_REGISTER,OS_INT);
  229. { allocate a register for the result }
  230. location.register := rg.getregisterint(exprasmlist);
  231. { Get a label to jump to the end }
  232. getlabel(l);
  233. if genjumps then
  234. begin
  235. { clear the register value, indicating result is FALSE }
  236. cg.a_load_const_reg(exprasmlist,OS_INT,0,location.register);
  237. opsize := def_cgsize(left.resulttype.def);
  238. { If register is used, use only lower 8 bits }
  239. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  240. begin
  241. { for ranges we always need a 32bit register, because then we }
  242. { use the register as base in a reference (JM) }
  243. if ranges then
  244. begin
  245. pleftreg:=rg.makeregsize(left.location.register,OS_INT);
  246. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,pleftreg);
  247. if opsize <> OS_INT then
  248. cg.a_op_const_reg(exprasmlist,OP_AND,255,pleftreg);
  249. opsize := OS_INT;
  250. end
  251. else
  252. { otherwise simply use the lower 8 bits (no "and" }
  253. { necessary this way) (JM) }
  254. begin
  255. pleftreg:=rg.makeregsize(left.location.register,OS_8);
  256. opsize := OS_8;
  257. end;
  258. end
  259. else
  260. begin
  261. { load the value in a register }
  262. pleftreg := cg.get_scratch_reg_int(exprasmlist);
  263. opsize := OS_INT;
  264. cg.a_load_ref_reg(exprasmlist,def_cgsize(left.resulttype.def),left.location.reference,pleftreg);
  265. end;
  266. { how much have we already substracted from the x in the }
  267. { "x in [y..z]" expression }
  268. adjustment := 0;
  269. hr := R_NO;
  270. for i:=1 to numparts do
  271. if setparts[i].range then
  272. { use fact that a <= x <= b <=> cardinal(x-a) <= cardinal(b-a) }
  273. begin
  274. { is the range different from all legal values? }
  275. if (setparts[i].stop-setparts[i].start <> 255) then
  276. begin
  277. { yes, is the lower bound <> 0? }
  278. if (setparts[i].start <> 0) then
  279. { we're going to substract from the left register, }
  280. { so in case of a LOC_CREGISTER first move the value }
  281. { to edi (not done before because now we can do the }
  282. { move and substract in one instruction with LEA) }
  283. if (left.location.loc = LOC_CREGISTER) and
  284. (hr <> pleftreg) then
  285. begin
  286. hr:=cg.get_scratch_reg_int(exprasmlist);
  287. cg.a_op_const_reg_reg(exprasmlist,OP_SUB,opsize,setparts[i].start,pleftreg,hr);
  288. pleftreg:=hr;
  289. opsize := OS_INT;
  290. end
  291. else
  292. begin
  293. { otherwise, the value is already in a register }
  294. { that can be modified }
  295. cg.a_op_const_reg(exprasmlist,OP_SUB,
  296. setparts[i].start-adjustment,pleftreg)
  297. end;
  298. { new total value substracted from x: }
  299. { adjustment + (setparts[i].start - adjustment) }
  300. adjustment := setparts[i].start;
  301. { check if result < b-a+1 (not "result <= b-a", since }
  302. { we need a carry in case the element is in the range }
  303. { (this will never overflow since we check at the }
  304. { beginning whether stop-start <> 255) }
  305. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_B,
  306. setparts[i].stop-setparts[i].start+1,pleftreg,l);
  307. end
  308. else
  309. { if setparts[i].start = 0 and setparts[i].stop = 255, }
  310. { it's always true since "in" is only allowed for bytes }
  311. begin
  312. cg.a_jmp_always(exprasmlist,l);
  313. end;
  314. end
  315. else
  316. begin
  317. { Emit code to check if left is an element }
  318. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ,
  319. setparts[i].stop-adjustment,pleftreg,l);
  320. end;
  321. { To compensate for not doing a second pass }
  322. right.location.reference.symbol:=nil;
  323. getlabel(l3);
  324. cg.a_jmp_always(exprasmlist,l3);
  325. { Now place the end label if IN success }
  326. cg.a_label(exprasmlist,l);
  327. { result register is 1 }
  328. cg.a_load_const_reg(exprasmlist,OS_INT,1,location.register);
  329. { in case value is not found }
  330. cg.a_label(exprasmlist,l3);
  331. case left.location.loc of
  332. LOC_CREGISTER :
  333. cg.free_scratch_reg(exprasmlist,pleftreg);
  334. LOC_REGISTER :
  335. rg.ungetregister(exprasmlist,pleftreg);
  336. else
  337. begin
  338. reference_release(exprasmlist,left.location.reference);
  339. cg.free_scratch_reg(exprasmlist,pleftreg);
  340. end;
  341. end;
  342. end
  343. else
  344. {*****************************************************************}
  345. { NO JUMP TABLE GENERATION }
  346. {*****************************************************************}
  347. begin
  348. { We will now generated code to check the set itself, no jmps,
  349. handle smallsets separate, because it allows faster checks }
  350. if use_small then
  351. begin
  352. {**************************** SMALL SET **********************}
  353. if left.nodetype=ordconstn then
  354. begin
  355. { clear the register value, indicating result is FALSE }
  356. cg.a_load_const_reg(exprasmlist,OS_INT,0,location.register);
  357. hr:=cg.get_scratch_reg_int(exprasmlist);
  358. case right.location.loc of
  359. LOC_REGISTER,
  360. LOC_CREGISTER:
  361. begin
  362. { load set value into register }
  363. cg.a_load_reg_reg(exprasmlist,OS_32,
  364. right.location.register,hr);
  365. end;
  366. LOC_REFERENCE,
  367. LOC_CREFERENCE :
  368. begin
  369. { load set value into register }
  370. cg.a_load_ref_reg(exprasmlist,OS_32,
  371. right.location.reference,hr);
  372. end;
  373. else
  374. internalerror(200203312);
  375. end;
  376. { then do AND with constant and register }
  377. cg.a_op_const_reg(exprasmlist,OP_AND,1 shl
  378. (tordconstnode(left).value and 31),hr);
  379. { if the value in the AND register is <> 0 then the value is equal. }
  380. cg.a_cmp_const_reg_label(exprasmlist,OS_32,OC_EQ,1 shl
  381. (tordconstnode(left).value and 31),hr,l);
  382. cg.free_scratch_reg(exprasmlist,hr);
  383. getlabel(l3);
  384. cg.a_jmp_always(exprasmlist,l3);
  385. { Now place the end label if IN success }
  386. cg.a_label(exprasmlist,l);
  387. { result register is 1 : LOC_JUMP }
  388. cg.a_load_const_reg(exprasmlist,OS_INT,1,location.register);
  389. { in case value is not found }
  390. cg.a_label(exprasmlist,l3);
  391. location_release(exprasmlist,right.location);
  392. end
  393. else
  394. begin
  395. case left.location.loc of
  396. LOC_REGISTER,
  397. LOC_CREGISTER:
  398. begin
  399. hr3:=rg.makeregsize(left.location.register,OS_INT);
  400. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,hr3);
  401. hr:=cg.get_scratch_reg_int(exprasmlist);
  402. cg.a_load_reg_reg(exprasmlist,OS_INT,hr3,hr);
  403. end;
  404. else
  405. begin
  406. hr:=cg.get_scratch_reg_int(exprasmlist);
  407. cg.a_load_ref_reg(exprasmlist,def_cgsize(left.resulttype.def),
  408. left.location.reference,hr);
  409. location_release(exprasmlist,left.location);
  410. end;
  411. end;
  412. case right.location.loc of
  413. LOC_REGISTER,
  414. LOC_CREGISTER :
  415. begin
  416. hr2:=right.location.register;
  417. end;
  418. LOC_CONSTANT :
  419. begin
  420. hr2:=rg.getregisterint(exprasmlist);
  421. cg.a_load_const_reg(exprasmlist,OS_32,
  422. right.location.value,hr2);
  423. end;
  424. LOC_CREFERENCE,
  425. LOC_REFERENCE :
  426. begin
  427. location_release(exprasmlist,right.location);
  428. hr2:=rg.getregisterint(exprasmlist);
  429. cg.a_load_ref_reg(exprasmlist, OS_32,
  430. right.location.reference,hr2);
  431. end;
  432. else
  433. internalerror(2002032210);
  434. end;
  435. { emit bit test operation }
  436. emit_bit_test_reg_reg(exprasmlist,hr,hr2,location.register);
  437. { free the resources }
  438. case right.location.loc of
  439. LOC_REGISTER,
  440. LOC_CREGISTER :
  441. rg.ungetregisterint(exprasmlist,right.location.register);
  442. LOC_CONSTANT ,
  443. LOC_CREFERENCE,
  444. LOC_REFERENCE :
  445. rg.ungetregisterint(exprasmlist,hr2);
  446. else
  447. internalerror(2002032210);
  448. end;
  449. { free bitnumber register }
  450. cg.free_scratch_reg(exprasmlist,hr);
  451. end;
  452. end
  453. else
  454. {************************** NOT SMALL SET ********************}
  455. begin
  456. if right.location.loc=LOC_CONSTANT then
  457. begin
  458. { this section has not been tested! }
  459. { can it actually occur currently? CEC }
  460. internalerror(20020610);
  461. getlabel(l);
  462. getlabel(l2);
  463. { Is this treated in firstpass ?? }
  464. if left.nodetype=ordconstn then
  465. begin
  466. hr:=rg.getregisterint(exprasmlist);
  467. left.location.loc:=LOC_REGISTER;
  468. left.location.size:=OS_INT;
  469. left.location.register:=hr;
  470. cg.a_load_const_reg(exprasmlist,OS_INT,
  471. tordconstnode(left).value,hr);
  472. end;
  473. case left.location.loc of
  474. LOC_REGISTER,
  475. LOC_CREGISTER:
  476. begin
  477. hr:=rg.makeregsize(left.location.register,OS_INT);
  478. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,hr);
  479. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,OC_BE,31,hr,l);
  480. { reset of result register is done in routine entry }
  481. cg.a_jmp_always(exprasmlist,l2);
  482. cg.a_label(exprasmlist,l);
  483. { We have to load the value into a register because
  484. btl does not accept values only refs or regs (PFV) }
  485. hr2:=rg.getregisterint(exprasmlist);
  486. cg.a_load_const_reg(exprasmlist,OS_INT,right.location.value,hr2);
  487. end;
  488. else
  489. begin
  490. cg.a_cmp_const_ref_label(exprasmlist,OS_8,OC_BE,31,left.location.reference,l);
  491. cg.a_jmp_always(exprasmlist,l2);
  492. cg.a_label(exprasmlist,l);
  493. location_release(exprasmlist,left.location);
  494. hr:=rg.getregisterint(exprasmlist);
  495. cg.a_load_ref_reg(exprasmlist,OS_32,left.location.reference,hr);
  496. { We have to load the value into a register because
  497. btl does not accept values only refs or regs (PFV) }
  498. hr2:=rg.getregisterint(exprasmlist);
  499. cg.a_load_const_reg(exprasmlist,OS_INT,
  500. right.location.value,hr2);
  501. end;
  502. end;
  503. { emit bit test operation }
  504. emit_bit_test_reg_reg(exprasmlist,hr,hr2,location.register);
  505. rg.ungetregisterint(exprasmlist,hr2);
  506. if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  507. rg.ungetregisterint(exprasmlist,hr);
  508. cg.a_label(exprasmlist,l2);
  509. end { of right.location.loc=LOC_CONSTANT }
  510. { do search in a normal set which could have >32 elementsm
  511. but also used if the left side contains higher values > 32 }
  512. else if left.nodetype=ordconstn then
  513. begin
  514. getlabel(l2);
  515. getlabel(l);
  516. { use location.register as scratch register here }
  517. inc(right.location.reference.offset,tordconstnode(left).value shr 3);
  518. cg.a_load_ref_reg(exprasmlist, OS_8, right.location.reference, location.register);
  519. cg.a_op_const_reg(exprasmlist, OP_AND,1 shl (tordconstnode(left).value and 7),
  520. location.register);
  521. cg.a_cmp_const_reg_label(exprasmlist,OS_8, OC_NE,0,location.register,l2);
  522. cg.a_load_const_reg(exprasmlist, OS_INT,0, location.register);
  523. cg.a_jmp_always(exprasmlist,l);
  524. cg.a_label(exprasmlist,l2);
  525. cg.a_load_const_reg(exprasmlist, OS_INT,1, location.register);
  526. {emit_const_ref(A_TEST,S_B,1 shl (tordconstnode(left).value and 7),right.location.reference);}
  527. cg.a_label(exprasmlist,l);
  528. location_release(exprasmlist,right.location);
  529. end
  530. else
  531. begin
  532. if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  533. pleftreg:=rg.makeregsize(left.location.register,OS_INT)
  534. else
  535. pleftreg:=rg.getregisterint(exprasmlist);
  536. cg.a_load_loc_reg(exprasmlist,left.location,pleftreg);
  537. location_freetemp(exprasmlist,left.location);
  538. location_release(exprasmlist,left.location);
  539. cg.a_param_reg(exprasmlist,OS_8,pleftreg,paramanager.getintparaloc(2));
  540. cg.a_param_ref(exprasmlist,OS_ADDR,right.location.reference,paramanager.getintparaloc(1));
  541. cg.a_call_name(exprasmlist,'FPC_SET_IN_BYTE');
  542. { result of value is always one full register }
  543. cg.a_load_reg_reg(exprasmlist,OS_INT,ACCUMULATOR,location.register);
  544. { release the allocated register }
  545. if not (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  546. rg.ungetregisterint(exprasmlist,pleftreg);
  547. location_release(exprasmlist,right.location);
  548. end;
  549. end;
  550. end;
  551. location_freetemp(exprasmlist,right.location);
  552. end;
  553. {*****************************************************************************
  554. TCGCASENODE
  555. *****************************************************************************}
  556. procedure tcgcasenode.pass_2;
  557. var
  558. with_sign : boolean;
  559. opsize : tcgsize;
  560. jmp_gt,jmp_le,jmp_lee : topcmp;
  561. hp : tnode;
  562. { register with case expression }
  563. hregister,hregister2 : tregister;
  564. endlabel,elselabel : tasmlabel;
  565. { true, if we can omit the range check of the jump table }
  566. jumptable_no_range : boolean;
  567. min_label : tconstexprint;
  568. procedure gentreejmp(p : pcaserecord);
  569. var
  570. lesslabel,greaterlabel : tasmlabel;
  571. begin
  572. cg.a_label(exprasmlist,p^._at);
  573. { calculate labels for left and right }
  574. if (p^.less=nil) then
  575. lesslabel:=elselabel
  576. else
  577. lesslabel:=p^.less^._at;
  578. if (p^.greater=nil) then
  579. greaterlabel:=elselabel
  580. else
  581. greaterlabel:=p^.greater^._at;
  582. { calculate labels for left and right }
  583. { no range label: }
  584. if p^._low=p^._high then
  585. begin
  586. if greaterlabel=lesslabel then
  587. begin
  588. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_NE,p^._low,hregister, lesslabel);
  589. end
  590. else
  591. begin
  592. cg.a_cmp_const_reg_label(exprasmlist,OS_INT, jmp_le,p^._low,hregister, lesslabel);
  593. cg.a_cmp_const_reg_label(exprasmlist,OS_INT, jmp_gt,p^._low,hregister, greaterlabel);
  594. end;
  595. cg.a_jmp_always(exprasmlist,p^.statement);
  596. end
  597. else
  598. begin
  599. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_le,p^._low, hregister, lesslabel);
  600. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_gt,p^._high,hregister, greaterlabel);
  601. cg.a_jmp_always(exprasmlist,p^.statement);
  602. end;
  603. if assigned(p^.less) then
  604. gentreejmp(p^.less);
  605. if assigned(p^.greater) then
  606. gentreejmp(p^.greater);
  607. end;
  608. procedure genlinearcmplist(hp : pcaserecord);
  609. var
  610. first : boolean;
  611. last : TConstExprInt;
  612. procedure genitem(t : pcaserecord);
  613. var
  614. l1 : tasmlabel;
  615. begin
  616. if assigned(t^.less) then
  617. genitem(t^.less);
  618. if t^._low=t^._high then
  619. begin
  620. if opsize in [OS_S64,OS_64] then
  621. begin
  622. getlabel(l1);
  623. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_NE, longint(hi(int64(t^._low))),hregister2,l1);
  624. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ, longint(lo(int64(t^._low))),hregister, t^.statement);
  625. cg.a_label(exprasmlist,l1);
  626. end
  627. else
  628. begin
  629. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ,longint(t^._low) ,hregister, t^.statement);
  630. last:=t^._low;
  631. end;
  632. end
  633. else
  634. begin
  635. { if there is no unused label between the last and the }
  636. { present label then the lower limit can be checked }
  637. { immediately. else check the range in between: }
  638. if first or (t^._low-last>1) then
  639. begin
  640. if opsize in [OS_64,OS_S64] then
  641. begin
  642. getlabel(l1);
  643. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, jmp_le, longint(hi(int64(t^._low))),
  644. hregister2, elselabel);
  645. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, jmp_gt, longint(hi(int64(t^._low))),
  646. hregister2, l1);
  647. { the comparisation of the low dword must be always unsigned! }
  648. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_B, longint(lo(int64(t^._low))), hregister, elselabel);
  649. cg.a_label(exprasmlist,l1);
  650. end
  651. else
  652. begin
  653. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, jmp_le, longint(t^._low), hregister,
  654. elselabel);
  655. end;
  656. end;
  657. if opsize in [OS_S64,OS_64] then
  658. begin
  659. getlabel(l1);
  660. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, jmp_le, longint(hi(int64(t^._high))), hregister2,
  661. t^.statement);
  662. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, jmp_gt, longint(hi(int64(t^._high))), hregister2,
  663. l1);
  664. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_BE, longint(lo(int64(t^._high))), hregister, t^.statement);
  665. cg.a_label(exprasmlist,l1);
  666. end
  667. else
  668. begin
  669. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, jmp_lee,longint(t^._high) , hregister, t^.statement);
  670. end;
  671. last:=t^._high;
  672. end;
  673. first:=false;
  674. if assigned(t^.greater) then
  675. genitem(t^.greater);
  676. end;
  677. begin
  678. last:=0;
  679. first:=true;
  680. genitem(hp);
  681. cg.a_jmp_always(exprasmlist,elselabel);
  682. end;
  683. procedure genlinearlist(hp : pcaserecord);
  684. var
  685. first : boolean;
  686. last : TConstExprInt;
  687. scratch_reg : tregister;
  688. procedure genitem(t : pcaserecord);
  689. procedure gensub(value:longint);
  690. begin
  691. { here, since the sub and cmp are separate we need
  692. to move the result before subtract to a help
  693. register.
  694. }
  695. cg.a_load_reg_reg(exprasmlist, opsize, hregister, scratch_reg);
  696. cg.a_op_const_reg(exprasmlist, OP_SUB, value, hregister);
  697. end;
  698. begin
  699. if assigned(t^.less) then
  700. genitem(t^.less);
  701. { need we to test the first value }
  702. if first and (t^._low>get_min_value(left.resulttype.def)) then
  703. begin
  704. cg.a_cmp_const_reg_label(exprasmlist,OS_INT,jmp_le,longint(t^._low),hregister,elselabel);
  705. end;
  706. if t^._low=t^._high then
  707. begin
  708. if t^._low-last=0 then
  709. begin
  710. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ,0,hregister,t^.statement);
  711. end
  712. else
  713. begin
  714. gensub(longint(t^._low-last));
  715. cg.a_cmp_const_reg_label(exprasmlist, OS_INT, OC_EQ,0,hregister,t^.statement);
  716. end;
  717. last:=t^._low;
  718. end
  719. else
  720. begin
  721. { it begins with the smallest label, if the value }
  722. { is even smaller then jump immediately to the }
  723. { ELSE-label }
  724. if first then
  725. begin
  726. { have we to ajust the first value ? }
  727. if (t^._low>get_min_value(left.resulttype.def)) then
  728. gensub(longint(t^._low));
  729. end
  730. else
  731. begin
  732. { if there is no unused label between the last and the }
  733. { present label then the lower limit can be checked }
  734. { immediately. else check the range in between: }
  735. gensub(longint(t^._low-last));
  736. cg.a_cmp_const_reg_label(exprasmlist, OS_INT,jmp_le,longint(t^._low-last),scratch_reg,elselabel);
  737. end;
  738. gensub(longint(t^._high-t^._low));
  739. cg.a_cmp_const_reg_label(exprasmlist, OS_INT,jmp_lee,longint(t^._high-t^._low),scratch_reg,t^.statement);
  740. last:=t^._high;
  741. end;
  742. first:=false;
  743. if assigned(t^.greater) then
  744. genitem(t^.greater);
  745. end;
  746. begin
  747. { do we need to generate cmps? }
  748. if (with_sign and (min_label<0)) then
  749. genlinearcmplist(hp)
  750. else
  751. begin
  752. last:=0;
  753. first:=true;
  754. scratch_reg := cg.get_scratch_reg_int(exprasmlist);
  755. genitem(hp);
  756. cg.a_jmp_always(exprasmlist,elselabel);
  757. cg.free_scratch_reg(exprasmlist, scratch_reg);
  758. end;
  759. end;
  760. var
  761. lv,hv,
  762. max_label: tconstexprint;
  763. labels : longint;
  764. max_linear_list : longint;
  765. otl, ofl: tasmlabel;
  766. isjump : boolean;
  767. dist : cardinal;
  768. begin
  769. getlabel(endlabel);
  770. getlabel(elselabel);
  771. with_sign:=is_signed(left.resulttype.def);
  772. if with_sign then
  773. begin
  774. jmp_gt:=OC_GT;
  775. jmp_le:=OC_LT;
  776. jmp_lee:=OC_LTE;
  777. end
  778. else
  779. begin
  780. jmp_gt:=OC_A;
  781. jmp_le:=OC_B;
  782. jmp_lee:=OC_BE;
  783. end;
  784. rg.cleartempgen;
  785. { save current truelabel and falselabel }
  786. isjump:=false;
  787. if left.location.loc=LOC_JUMP then
  788. begin
  789. otl:=truelabel;
  790. getlabel(truelabel);
  791. ofl:=falselabel;
  792. getlabel(falselabel);
  793. isjump:=true;
  794. end;
  795. secondpass(left);
  796. { determines the size of the operand }
  797. opsize:=def_cgsize(left.resulttype.def);
  798. { copy the case expression to a register }
  799. location_force_reg(exprasmlist,left.location,opsize,false);
  800. if opsize in [OS_S64,OS_64] then
  801. begin
  802. hregister:=left.location.registerlow;
  803. hregister2:=left.location.registerhigh;
  804. end
  805. else
  806. hregister:=left.location.register;
  807. if isjump then
  808. begin
  809. truelabel:=otl;
  810. falselabel:=ofl;
  811. end;
  812. { we need the min_label always to choose between }
  813. { cmps and subs/decs }
  814. min_label:=case_get_min(nodes);
  815. load_all_regvars(exprasmlist);
  816. { now generate the jumps }
  817. if opsize in [OS_64,OS_S64] then
  818. genlinearcmplist(nodes)
  819. else
  820. begin
  821. if cs_optimize in aktglobalswitches then
  822. begin
  823. { procedures are empirically passed on }
  824. { consumption can also be calculated }
  825. { but does it pay on the different }
  826. { processors? }
  827. { moreover can the size only be appro- }
  828. { ximated as it is not known if rel8, }
  829. { rel16 or rel32 jumps are used }
  830. max_label:=case_get_max(nodes);
  831. labels:=case_count_labels(nodes);
  832. { can we omit the range check of the jump table ? }
  833. getrange(left.resulttype.def,lv,hv);
  834. jumptable_no_range:=(lv=min_label) and (hv=max_label);
  835. { hack a little bit, because the range can be greater }
  836. { than the positive range of a longint }
  837. if (min_label<0) and (max_label>0) then
  838. begin
  839. if min_label=TConstExprInt($80000000) then
  840. dist:=Cardinal(max_label)+Cardinal($80000000)
  841. else
  842. dist:=Cardinal(max_label)+Cardinal(-min_label)
  843. end
  844. else
  845. dist:=max_label-min_label;
  846. { optimize for size ? }
  847. if cs_littlesize in aktglobalswitches then
  848. begin
  849. { a linear list is always smaller than a jump tree }
  850. genlinearlist(nodes)
  851. end
  852. else
  853. begin
  854. if jumptable_no_range then
  855. max_linear_list:=4
  856. else
  857. max_linear_list:=2;
  858. if (labels<=max_linear_list) then
  859. genlinearlist(nodes)
  860. else
  861. begin
  862. if labels>16 then
  863. gentreejmp(nodes)
  864. else
  865. genlinearlist(nodes);
  866. end;
  867. end;
  868. end
  869. else
  870. { it's always not bad }
  871. genlinearlist(nodes);
  872. end;
  873. rg.ungetregister(exprasmlist,hregister);
  874. { now generate the instructions }
  875. hp:=right;
  876. while assigned(hp) do
  877. begin
  878. rg.cleartempgen;
  879. secondpass(tbinarynode(hp).right);
  880. { don't come back to case line }
  881. aktfilepos:=exprasmList.getlasttaifilepos^;
  882. load_all_regvars(exprasmlist);
  883. cg.a_jmp_always(exprasmlist,endlabel);
  884. hp:=tbinarynode(hp).left;
  885. end;
  886. cg.a_label(exprasmlist,elselabel);
  887. { ...and the else block }
  888. if assigned(elseblock) then
  889. begin
  890. rg.cleartempgen;
  891. secondpass(elseblock);
  892. load_all_regvars(exprasmlist);
  893. end;
  894. cg.a_label(exprasmlist,endlabel);
  895. end;
  896. begin
  897. csetelementnode:=tcgsetelementnode;
  898. cinnode:=tcginnode;
  899. ccasenode:=tcgcasenode;
  900. end.
  901. {
  902. $Log$
  903. Revision 1.11 2002-07-28 09:24:18 carl
  904. + generic case node
  905. Revision 1.10 2002/07/23 14:31:00 daniel
  906. * Added internal error when asked to generate code for 'if expr in []'
  907. Revision 1.9 2002/07/23 12:34:30 daniel
  908. * Readded old set code. To use it define 'oldset'. Activated by default
  909. for ppc.
  910. Revision 1.8 2002/07/22 11:48:04 daniel
  911. * Sets are now internally sets.
  912. Revision 1.7 2002/07/21 16:58:20 jonas
  913. * fixed some bugs in tcginnode.pass_2() and optimized the bit test
  914. Revision 1.6 2002/07/20 11:57:54 florian
  915. * types.pas renamed to defbase.pas because D6 contains a types
  916. unit so this would conflicts if D6 programms are compiled
  917. + Willamette/SSE2 instructions to assembler added
  918. Revision 1.5 2002/07/11 14:41:28 florian
  919. * start of the new generic parameter handling
  920. Revision 1.4 2002/07/07 10:16:29 florian
  921. * problems with last commit fixed
  922. Revision 1.3 2002/07/06 20:19:25 carl
  923. + generic set handling
  924. Revision 1.2 2002/07/01 16:23:53 peter
  925. * cg64 patch
  926. * basics for currency
  927. * asnode updates for class and interface (not finished)
  928. Revision 1.1 2002/06/16 08:14:56 carl
  929. + generic sets
  930. }