ncgset.pas 46 KB

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