n386set.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Generate i386 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 n386set;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,nset;
  23. type
  24. ti386setelementnode = class(tsetelementnode)
  25. procedure pass_2;override;
  26. end;
  27. ti386innode = class(tinnode)
  28. procedure pass_2;override;
  29. end;
  30. ti386casenode = class(tcasenode)
  31. procedure pass_2;override;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,cpuinfo,
  36. verbose,globals,
  37. symconst,symdef,aasm,types,
  38. hcodegen,temp_gen,pass_2,
  39. ncon,
  40. cpubase,
  41. cgai386,tgcpu,n386util,regvars;
  42. const
  43. bytes2Sxx:array[1..8] of Topsize=(S_B,S_W,S_NO,S_L,S_NO,S_NO,S_NO,S_Q);
  44. {*****************************************************************************
  45. TI386SETELEMENTNODE
  46. *****************************************************************************}
  47. procedure ti386setelementnode.pass_2;
  48. begin
  49. { load first value in 32bit register }
  50. secondpass(left);
  51. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  52. emit_to_reg32(left.location.register);
  53. { also a second value ? }
  54. if assigned(right) then
  55. begin
  56. secondpass(right);
  57. if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  58. emit_to_reg32(right.location.register);
  59. end;
  60. { we doesn't modify the left side, we check only the type }
  61. set_location(location,left.location);
  62. end;
  63. {*****************************************************************************
  64. TI386INNODE
  65. *****************************************************************************}
  66. procedure ti386innode.pass_2;
  67. type
  68. Tsetpart=record
  69. range : boolean; {Part is a range.}
  70. start,stop : byte; {Start/stop when range; Stop=element when an element.}
  71. end;
  72. var
  73. genjumps,
  74. use_small,
  75. pushed,
  76. ranges : boolean;
  77. hr,hr2,
  78. pleftreg : tregister;
  79. opsize : topsize;
  80. setparts : array[1..8] of Tsetpart;
  81. i,numparts : byte;
  82. {href,href2 : Treference;}
  83. l,l2 : pasmlabel;
  84. {$ifdef CORRECT_SET_IN_FPC}
  85. AM : tasmop;
  86. {$endif CORRECT_SET_IN_FPC}
  87. function analizeset(Aset:pconstset;is_small:boolean):boolean;
  88. type
  89. byteset=set of byte;
  90. var
  91. compares,maxcompares:word;
  92. i:byte;
  93. begin
  94. analizeset:=false;
  95. ranges:=false;
  96. numparts:=0;
  97. compares:=0;
  98. { Lots of comparisions take a lot of time, so do not allow
  99. too much comparisions. 8 comparisions are, however, still
  100. smalller than emitting the set }
  101. if cs_littlesize in aktglobalswitches then
  102. maxcompares:=8
  103. else
  104. maxcompares:=5;
  105. { when smallset is possible allow only 3 compares the smallset
  106. code is for littlesize also smaller when more compares are used }
  107. if is_small then
  108. maxcompares:=3;
  109. for i:=0 to 255 do
  110. if i in byteset(Aset^) then
  111. begin
  112. if (numparts=0) or (i<>setparts[numparts].stop+1) then
  113. begin
  114. {Set element is a separate element.}
  115. inc(compares);
  116. if compares>maxcompares then
  117. exit;
  118. inc(numparts);
  119. setparts[numparts].range:=false;
  120. setparts[numparts].stop:=i;
  121. end
  122. else
  123. {Set element is part of a range.}
  124. if not setparts[numparts].range then
  125. begin
  126. {Transform an element into a range.}
  127. setparts[numparts].range:=true;
  128. setparts[numparts].start:=setparts[numparts].stop;
  129. setparts[numparts].stop:=i;
  130. inc(compares);
  131. if compares>maxcompares then
  132. exit;
  133. end
  134. else
  135. begin
  136. {Extend a range.}
  137. setparts[numparts].stop:=i;
  138. {A range of two elements can better
  139. be checked as two separate ones.
  140. When extending a range, our range
  141. becomes larger than two elements.}
  142. ranges:=true;
  143. end;
  144. end;
  145. analizeset:=true;
  146. end;
  147. begin
  148. { We check first if we can generate jumps, this can be done
  149. because the resulttype is already set in firstpass }
  150. { check if we can use smallset operation using btl which is limited
  151. to 32 bits, the left side may also not contain higher values !! }
  152. use_small:=(psetdef(right.resulttype)^.settype=smallset) and
  153. ((left.resulttype^.deftype=orddef) and (porddef(left.resulttype)^.high<=32) or
  154. (left.resulttype^.deftype=enumdef) and (penumdef(left.resulttype)^.max<=32));
  155. { Can we generate jumps? Possible for all types of sets }
  156. genjumps:=(right.nodetype=setconstn) and
  157. analizeset(tsetconstnode(right).value_set,use_small);
  158. { calculate both operators }
  159. { the complex one first }
  160. firstcomplex(self);
  161. secondpass(left);
  162. { Only process the right if we are not generating jumps }
  163. if not genjumps then
  164. begin
  165. pushed:=maybe_push(right.registers32,left,false);
  166. secondpass(right);
  167. if pushed then
  168. restore(left,false);
  169. end;
  170. if codegenerror then
  171. exit;
  172. { ofcourse not commutative }
  173. if nf_swaped in flags then
  174. swapleftright;
  175. if genjumps then
  176. begin
  177. { It gives us advantage to check for the set elements
  178. separately instead of using the SET_IN_BYTE procedure.
  179. To do: Build in support for LOC_JUMP }
  180. { If register is used, use only lower 8 bits }
  181. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  182. begin
  183. pleftreg:=left.location.register;
  184. if pleftreg in [R_AX..R_DX] then
  185. begin
  186. emit_const_reg(A_AND,S_W,255,pleftreg);
  187. opsize:=S_W;
  188. end
  189. else
  190. if pleftreg in [R_EAX..R_EDI] then
  191. begin
  192. emit_const_reg(A_AND,S_L,255,pleftreg);
  193. opsize:=S_L;
  194. end
  195. else
  196. opsize:=S_B;
  197. end;
  198. { Get a label to jump to the end }
  199. location.loc:=LOC_FLAGS;
  200. { It's better to use the zero flag when there are
  201. no ranges }
  202. if ranges then
  203. location.resflags:=F_C
  204. else
  205. location.resflags:=F_E;
  206. getlabel(l);
  207. for i:=1 to numparts do
  208. if setparts[i].range then
  209. begin
  210. { Check if left is in a range }
  211. { Get a label to jump over the check }
  212. getlabel(l2);
  213. if setparts[i].start=setparts[i].stop-1 then
  214. begin
  215. case left.location.loc of
  216. LOC_REGISTER,
  217. LOC_CREGISTER : emit_const_reg(A_CMP,opsize,
  218. setparts[i].start,pleftreg);
  219. else
  220. emit_const_ref(A_CMP,S_B,
  221. setparts[i].start,newreference(left.location.reference));
  222. end;
  223. { Result should be in carry flag when ranges are used }
  224. if ranges then
  225. emit_none(A_STC,S_NO);
  226. { If found, jump to end }
  227. emitjmp(C_E,l);
  228. case left.location.loc of
  229. LOC_REGISTER,
  230. LOC_CREGISTER : emit_const_reg(A_CMP,opsize,
  231. setparts[i].stop,pleftreg);
  232. else
  233. emit_const_ref(A_CMP,S_B,
  234. setparts[i].stop,newreference(left.location.reference));
  235. end;
  236. { Result should be in carry flag when ranges are used }
  237. if ranges then
  238. emit_none(A_STC,S_NO);
  239. { If found, jump to end }
  240. emitjmp(C_E,l);
  241. end
  242. else
  243. begin
  244. if setparts[i].start<>0 then
  245. begin
  246. { We only check for the lower bound if it is > 0, because
  247. set elements lower than 0 dont exist }
  248. case left.location.loc of
  249. LOC_REGISTER,
  250. LOC_CREGISTER :
  251. emit_const_reg(A_CMP,opsize,
  252. setparts[i].start,pleftreg);
  253. else
  254. emit_const_ref(A_CMP,S_B,
  255. setparts[i].start,newreference(left.location.reference));
  256. end;
  257. { If lower, jump to next check }
  258. emitjmp(C_B,l2);
  259. end;
  260. { We only check for the high bound if it is < 255, because
  261. set elements higher than 255 do nt exist, the its always true,
  262. so only a JMP is generated }
  263. if setparts[i].stop<>255 then
  264. begin
  265. case left.location.loc of
  266. LOC_REGISTER,
  267. LOC_CREGISTER : emit_const_reg(A_CMP,opsize,
  268. setparts[i].stop+1,pleftreg);
  269. else
  270. emit_const_ref(A_CMP,S_B,
  271. setparts[i].stop+1,newreference(left.location.reference));
  272. end;
  273. { If higher, element is in set }
  274. emitjmp(C_B,l);
  275. end
  276. else
  277. begin
  278. emit_none(A_STC,S_NO);
  279. emitjmp(C_None,l);
  280. end;
  281. end;
  282. { Emit the jump over label }
  283. emitlab(l2);
  284. end
  285. else
  286. begin
  287. { Emit code to check if left is an element }
  288. case left.location.loc of
  289. LOC_REGISTER,
  290. LOC_CREGISTER : emit_const_reg(A_CMP,opsize,
  291. setparts[i].stop,pleftreg);
  292. else
  293. emit_const_ref(A_CMP,S_B,
  294. setparts[i].stop,newreference(left.location.reference));
  295. end;
  296. { Result should be in carry flag when ranges are used }
  297. if ranges then
  298. emit_none(A_STC,S_NO);
  299. { If found, jump to end }
  300. emitjmp(C_E,l);
  301. end;
  302. if ranges then
  303. emit_none(A_CLC,S_NO);
  304. { To compensate for not doing a second pass }
  305. right.location.reference.symbol:=nil;
  306. { Now place the end label }
  307. emitlab(l);
  308. case left.location.loc of
  309. LOC_REGISTER,
  310. LOC_CREGISTER : ungetregister(pleftreg);
  311. else
  312. del_reference(left.location.reference);
  313. end;
  314. end
  315. else
  316. begin
  317. { We will now generated code to check the set itself, no jmps,
  318. handle smallsets separate, because it allows faster checks }
  319. if use_small then
  320. begin
  321. if left.nodetype=ordconstn then
  322. begin
  323. location.resflags:=F_NE;
  324. case right.location.loc of
  325. LOC_REGISTER,
  326. LOC_CREGISTER:
  327. begin
  328. emit_const_reg(A_TEST,S_L,
  329. 1 shl (tordconstnode(left).value and 31),right.location.register);
  330. ungetregister32(right.location.register);
  331. end
  332. else
  333. begin
  334. emit_const_ref(A_TEST,S_L,1 shl (tordconstnode(left).value and 31),
  335. newreference(right.location.reference));
  336. del_reference(right.location.reference);
  337. end;
  338. end;
  339. end
  340. else
  341. begin
  342. case left.location.loc of
  343. LOC_REGISTER,
  344. LOC_CREGISTER:
  345. begin
  346. hr:=left.location.register;
  347. emit_to_reg32(hr);
  348. end;
  349. else
  350. begin
  351. { the set element isn't never samller than a byte }
  352. { and because it's a small set we need only 5 bits }
  353. { but 8 bits are easier to load }
  354. getexplicitregister32(R_EDI);
  355. emit_ref_reg(A_MOVZX,S_BL,
  356. newreference(left.location.reference),R_EDI);
  357. hr:=R_EDI;
  358. del_reference(left.location.reference);
  359. end;
  360. end;
  361. case right.location.loc of
  362. LOC_REGISTER,
  363. LOC_CREGISTER :
  364. begin
  365. emit_reg_reg(A_BT,S_L,hr,
  366. right.location.register);
  367. ungetregister32(right.location.register);
  368. end
  369. else
  370. begin
  371. del_reference(right.location.reference);
  372. if right.location.reference.is_immediate then
  373. begin
  374. { We have to load the value into a register because
  375. btl does not accept values only refs or regs (PFV) }
  376. hr2:=getregister32;
  377. emit_const_reg(A_MOV,S_L,
  378. right.location.reference.offset,hr2);
  379. emit_reg_reg(A_BT,S_L,hr,hr2);
  380. ungetregister32(hr2);
  381. end
  382. else
  383. emit_reg_ref(A_BT,S_L,hr,
  384. newreference(right.location.reference));
  385. end;
  386. end;
  387. { simply to indicate EDI is deallocated here too (JM) }
  388. ungetregister32(hr);
  389. location.loc:=LOC_FLAGS;
  390. location.resflags:=F_C;
  391. end;
  392. end
  393. else
  394. begin
  395. if right.location.reference.is_immediate then
  396. begin
  397. location.resflags:=F_C;
  398. getlabel(l);
  399. getlabel(l2);
  400. { Is this treated in firstpass ?? }
  401. if left.nodetype=ordconstn then
  402. begin
  403. hr:=getregister32;
  404. left.location.loc:=LOC_REGISTER;
  405. left.location.register:=hr;
  406. emit_const_reg(A_MOV,S_L,
  407. tordconstnode(left).value,hr);
  408. end;
  409. case left.location.loc of
  410. LOC_REGISTER,
  411. LOC_CREGISTER:
  412. begin
  413. hr:=left.location.register;
  414. emit_to_reg32(hr);
  415. emit_const_reg(A_CMP,S_L,31,hr);
  416. emitjmp(C_NA,l);
  417. { reset carry flag }
  418. emit_none(A_CLC,S_NO);
  419. emitjmp(C_NONE,l2);
  420. emitlab(l);
  421. { We have to load the value into a register because
  422. btl does not accept values only refs or regs (PFV) }
  423. hr2:=getregister32;
  424. emit_const_reg(A_MOV,S_L,right.location.reference.offset,hr2);
  425. emit_reg_reg(A_BT,S_L,hr,hr2);
  426. ungetregister32(hr2);
  427. end;
  428. else
  429. begin
  430. {$ifdef CORRECT_SET_IN_FPC}
  431. if m_tp in aktmodeswitches then
  432. begin
  433. {***WARNING only correct if
  434. reference is 32 bits (PM) *****}
  435. emit_const_ref(A_CMP,S_L,
  436. 31,newreference(left.location.reference));
  437. end
  438. else
  439. {$endif CORRECT_SET_IN_FPC}
  440. begin
  441. emit_const_ref(A_CMP,S_B,
  442. 31,newreference(left.location.reference));
  443. end;
  444. emitjmp(C_NA,l);
  445. { reset carry flag }
  446. emit_none(A_CLC,S_NO);
  447. emitjmp(C_NONE,l2);
  448. emitlab(l);
  449. del_reference(left.location.reference);
  450. hr:=getregister32;
  451. emit_ref_reg(A_MOV,S_L,
  452. newreference(left.location.reference),hr);
  453. { We have to load the value into a register because
  454. btl does not accept values only refs or regs (PFV) }
  455. hr2:=getregister32;
  456. emit_const_reg(A_MOV,S_L,
  457. right.location.reference.offset,hr2);
  458. emit_reg_reg(A_BT,S_L,hr,hr2);
  459. ungetregister32(hr2);
  460. end;
  461. end;
  462. emitlab(l2);
  463. end { of right.location.reference.is_immediate }
  464. { do search in a normal set which could have >32 elementsm
  465. but also used if the left side contains higher values > 32 }
  466. else if left.nodetype=ordconstn then
  467. begin
  468. location.resflags:=F_NE;
  469. inc(right.location.reference.offset,tordconstnode(left).value shr 3);
  470. emit_const_ref(A_TEST,S_B,1 shl (tordconstnode(left).value and 7),
  471. newreference(right.location.reference));
  472. del_reference(right.location.reference);
  473. end
  474. else
  475. begin
  476. pushsetelement(left);
  477. emitpushreferenceaddr(right.location.reference);
  478. del_reference(right.location.reference);
  479. { registers need not be save. that happens in SET_IN_BYTE }
  480. { (EDI is changed) }
  481. emitcall('FPC_SET_IN_BYTE');
  482. { ungetiftemp(right.location.reference); }
  483. location.loc:=LOC_FLAGS;
  484. location.resflags:=F_C;
  485. end;
  486. end;
  487. end;
  488. if (right.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  489. ungetiftemp(right.location.reference);
  490. end;
  491. {*****************************************************************************
  492. TI386CASENODE
  493. *****************************************************************************}
  494. procedure ti386casenode.pass_2;
  495. var
  496. with_sign : boolean;
  497. opsize : topsize;
  498. jmp_gt,jmp_le,jmp_lee : tasmcond;
  499. hp : tnode;
  500. { register with case expression }
  501. hregister,hregister2 : tregister;
  502. endlabel,elselabel : pasmlabel;
  503. { true, if we can omit the range check of the jump table }
  504. jumptable_no_range : boolean;
  505. { where to put the jump table }
  506. jumpsegment : TAAsmoutput;
  507. min_label : TConstExprInt;
  508. procedure gentreejmp(p : pcaserecord);
  509. var
  510. lesslabel,greaterlabel : pasmlabel;
  511. begin
  512. emitlab(p^._at);
  513. { calculate labels for left and right }
  514. if (p^.less=nil) then
  515. lesslabel:=elselabel
  516. else
  517. lesslabel:=p^.less^._at;
  518. if (p^.greater=nil) then
  519. greaterlabel:=elselabel
  520. else
  521. greaterlabel:=p^.greater^._at;
  522. { calculate labels for left and right }
  523. { no range label: }
  524. if p^._low=p^._high then
  525. begin
  526. emit_const_reg(A_CMP,opsize,p^._low,hregister);
  527. if greaterlabel=lesslabel then
  528. emitjmp(C_NE,lesslabel)
  529. else
  530. begin
  531. emitjmp(jmp_le,lesslabel);
  532. emitjmp(jmp_gt,greaterlabel);
  533. end;
  534. emitjmp(C_None,p^.statement);
  535. end
  536. else
  537. begin
  538. emit_const_reg(A_CMP,opsize,p^._low,hregister);
  539. emitjmp(jmp_le,lesslabel);
  540. emit_const_reg(A_CMP,opsize,p^._high,hregister);
  541. emitjmp(jmp_gt,greaterlabel);
  542. emitjmp(C_None,p^.statement);
  543. end;
  544. if assigned(p^.less) then
  545. gentreejmp(p^.less);
  546. if assigned(p^.greater) then
  547. gentreejmp(p^.greater);
  548. end;
  549. procedure genlinearcmplist(hp : pcaserecord);
  550. var
  551. first : boolean;
  552. last : TConstExprInt;
  553. procedure genitem(t : pcaserecord);
  554. var
  555. l1 : pasmlabel;
  556. begin
  557. if assigned(t^.less) then
  558. genitem(t^.less);
  559. if t^._low=t^._high then
  560. begin
  561. if opsize=S_Q then
  562. begin
  563. getlabel(l1);
  564. emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._low))),hregister2);
  565. emitjmp(C_NZ,l1);
  566. emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._low))),hregister);
  567. emitjmp(C_Z,t^.statement);
  568. emitlab(l1);
  569. end
  570. else
  571. begin
  572. emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
  573. emitjmp(C_Z,t^.statement);
  574. last:=t^._low;
  575. end;
  576. end
  577. else
  578. begin
  579. { if there is no unused label between the last and the }
  580. { present label then the lower limit can be checked }
  581. { immediately. else check the range in between: }
  582. if first or (t^._low-last>1) then
  583. begin
  584. if opsize=S_Q then
  585. begin
  586. getlabel(l1);
  587. emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._low))),hregister2);
  588. emitjmp(jmp_le,elselabel);
  589. emitjmp(jmp_gt,l1);
  590. emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._low))),hregister);
  591. { the comparisation of the low dword must be always unsigned! }
  592. emitjmp(C_B,elselabel);
  593. emitlab(l1);
  594. end
  595. else
  596. begin
  597. emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
  598. emitjmp(jmp_le,elselabel);
  599. end;
  600. end;
  601. if opsize=S_Q then
  602. begin
  603. getlabel(l1);
  604. emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._high))),hregister2);
  605. emitjmp(jmp_le,t^.statement);
  606. emitjmp(jmp_gt,l1);
  607. emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._high))),hregister);
  608. { the comparisation of the low dword must be always unsigned! }
  609. emitjmp(C_BE,t^.statement);
  610. emitlab(l1);
  611. end
  612. else
  613. begin
  614. emit_const_reg(A_CMP,opsize,longint(t^._high),hregister);
  615. emitjmp(jmp_lee,t^.statement);
  616. end;
  617. last:=t^._high;
  618. end;
  619. first:=false;
  620. if assigned(t^.greater) then
  621. genitem(t^.greater);
  622. end;
  623. begin
  624. last:=0;
  625. first:=true;
  626. genitem(hp);
  627. emitjmp(C_None,elselabel);
  628. end;
  629. procedure genlinearlist(hp : pcaserecord);
  630. var
  631. first : boolean;
  632. last : TConstExprInt;
  633. {helplabel : longint;}
  634. procedure genitem(t : pcaserecord);
  635. procedure gensub(value:longint);
  636. begin
  637. if value=1 then
  638. emit_reg(A_DEC,opsize,hregister)
  639. else
  640. emit_const_reg(A_SUB,opsize,value,hregister);
  641. end;
  642. begin
  643. if assigned(t^.less) then
  644. genitem(t^.less);
  645. { need we to test the first value }
  646. if first and (t^._low>get_min_value(left.resulttype)) then
  647. begin
  648. emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
  649. emitjmp(jmp_le,elselabel);
  650. end;
  651. if t^._low=t^._high then
  652. begin
  653. if t^._low-last=0 then
  654. emit_reg_reg(A_OR,opsize,hregister,hregister)
  655. else
  656. gensub(longint(t^._low-last));
  657. last:=t^._low;
  658. emitjmp(C_Z,t^.statement);
  659. end
  660. else
  661. begin
  662. { it begins with the smallest label, if the value }
  663. { is even smaller then jump immediately to the }
  664. { ELSE-label }
  665. if first then
  666. begin
  667. { have we to ajust the first value ? }
  668. if (t^._low>get_min_value(left.resulttype)) then
  669. gensub(t^._low);
  670. end
  671. else
  672. begin
  673. { if there is no unused label between the last and the }
  674. { present label then the lower limit can be checked }
  675. { immediately. else check the range in between: }
  676. { note: you can't use gensub() here because dec doesn't }
  677. { change the carry flag (needed for jmp_lxx) (JM) }
  678. emit_const_reg(A_SUB,opsize,longint(t^._low-last),hregister);
  679. emitjmp(jmp_le,elselabel);
  680. end;
  681. emit_const_reg(A_SUB,opsize,longint(t^._high-t^._low),hregister);
  682. emitjmp(jmp_lee,t^.statement);
  683. last:=t^._high;
  684. end;
  685. first:=false;
  686. if assigned(t^.greater) then
  687. genitem(t^.greater);
  688. end;
  689. begin
  690. { do we need to generate cmps? }
  691. if (with_sign and (min_label<0)) then
  692. genlinearcmplist(hp)
  693. else
  694. begin
  695. last:=0;
  696. first:=true;
  697. genitem(hp);
  698. emitjmp(C_None,elselabel);
  699. end;
  700. end;
  701. procedure genjumptable(hp : pcaserecord;min_,max_ : longint);
  702. var
  703. table : pasmlabel;
  704. last : TConstExprInt;
  705. hr : preference;
  706. procedure genitem(t : pcaserecord);
  707. var
  708. i : longint;
  709. begin
  710. if assigned(t^.less) then
  711. genitem(t^.less);
  712. { fill possible hole }
  713. for i:=last+1 to t^._low-1 do
  714. jumpSegment.concat(Tai_const_symbol.Create(elselabel));
  715. for i:=t^._low to t^._high do
  716. jumpSegment.concat(Tai_const_symbol.Create(t^.statement));
  717. last:=t^._high;
  718. if assigned(t^.greater) then
  719. genitem(t^.greater);
  720. end;
  721. begin
  722. if not(jumptable_no_range) then
  723. begin
  724. emit_const_reg(A_CMP,opsize,longint(min_),hregister);
  725. { case expr less than min_ => goto elselabel }
  726. emitjmp(jmp_le,elselabel);
  727. emit_const_reg(A_CMP,opsize,longint(max_),hregister);
  728. emitjmp(jmp_gt,elselabel);
  729. end;
  730. getlabel(table);
  731. { extend with sign }
  732. if opsize=S_W then
  733. begin
  734. if with_sign then
  735. emit_reg_reg(A_MOVSX,S_WL,hregister,
  736. reg16toreg32(hregister))
  737. else
  738. emit_reg_reg(A_MOVZX,S_WL,hregister,
  739. reg16toreg32(hregister));
  740. hregister:=reg16toreg32(hregister);
  741. end
  742. else if opsize=S_B then
  743. begin
  744. if with_sign then
  745. emit_reg_reg(A_MOVSX,S_BL,hregister,
  746. reg8toreg32(hregister))
  747. else
  748. emit_reg_reg(A_MOVZX,S_BL,hregister,
  749. reg8toreg32(hregister));
  750. hregister:=reg8toreg32(hregister);
  751. end;
  752. new(hr);
  753. reset_reference(hr^);
  754. hr^.symbol:=table;
  755. hr^.offset:=(-longint(min_))*4;
  756. hr^.index:=hregister;
  757. hr^.scalefactor:=4;
  758. emit_ref(A_JMP,S_NO,hr);
  759. { !!!!! generate tables
  760. if not(cs_littlesize in aktlocalswitches) then
  761. jumpSegment.concat(Taicpu.Op_const(A_ALIGN,S_NO,4));
  762. }
  763. jumpSegment.concat(Tai_label.Create(table));
  764. last:=min_;
  765. genitem(hp);
  766. { !!!!!!!
  767. if not(cs_littlesize in aktlocalswitches) then
  768. emit_const(A_ALIGN,S_NO,4);
  769. }
  770. end;
  771. var
  772. max_label: tconstexprint;
  773. lv,hv,labels : longint;
  774. max_linear_list : longint;
  775. otl, ofl: pasmlabel;
  776. {$ifdef Delphi}
  777. dist : cardinal;
  778. {$else Delphi}
  779. dist : dword;
  780. {$endif Delphi}
  781. hr : preference;
  782. begin
  783. getlabel(endlabel);
  784. getlabel(elselabel);
  785. if (cs_create_smart in aktmoduleswitches) then
  786. jumpsegment:=procinfo^.aktlocaldata
  787. else
  788. jumpsegment:=datasegment;
  789. with_sign:=is_signed(left.resulttype);
  790. if with_sign then
  791. begin
  792. jmp_gt:=C_G;
  793. jmp_le:=C_L;
  794. jmp_lee:=C_LE;
  795. end
  796. else
  797. begin
  798. jmp_gt:=C_A;
  799. jmp_le:=C_B;
  800. jmp_lee:=C_BE;
  801. end;
  802. cleartempgen;
  803. { save current truelabel and falselabel (they are restored in }
  804. { locjump2reg) (JM) }
  805. if left.location.loc=LOC_JUMP then
  806. begin
  807. otl:=truelabel;
  808. getlabel(truelabel);
  809. ofl:=falselabel;
  810. getlabel(falselabel);
  811. end;
  812. secondpass(left);
  813. { determines the size of the operand }
  814. opsize:=bytes2Sxx[left.resulttype^.size];
  815. { copy the case expression to a register }
  816. case left.location.loc of
  817. LOC_REGISTER:
  818. begin
  819. if opsize=S_Q then
  820. begin
  821. hregister:=left.location.registerlow;
  822. hregister2:=left.location.registerhigh;
  823. end
  824. else
  825. hregister:=left.location.register;
  826. end;
  827. LOC_FLAGS :
  828. begin
  829. locflags2reg(left.location,opsize);
  830. hregister := left.location.register;
  831. end;
  832. LOC_JUMP:
  833. begin
  834. locjump2reg(left.location,opsize,otl,ofl);
  835. hregister := left.location.register;
  836. end;
  837. LOC_CREGISTER:
  838. begin
  839. hregister:=getregister32;
  840. case opsize of
  841. S_B:
  842. hregister:=reg32toreg8(hregister);
  843. S_W:
  844. hregister:=reg32toreg16(hregister);
  845. S_Q:
  846. hregister2:=R_EDI;
  847. end;
  848. if opsize=S_Q then
  849. begin
  850. emit_reg_reg(A_MOV,S_L,left.location.registerlow,hregister);
  851. hr:=newreference(left.location.reference);
  852. inc(hr^.offset,4);
  853. emit_reg_reg(A_MOV,S_L,left.location.registerhigh,hregister2);
  854. end
  855. else
  856. emit_reg_reg(A_MOV,opsize,
  857. left.location.register,hregister);
  858. end;
  859. LOC_MEM,LOC_REFERENCE:
  860. begin
  861. del_reference(left.location.reference);
  862. hregister:=getregister32;
  863. case opsize of
  864. S_B:
  865. hregister:=reg32toreg8(hregister);
  866. S_W:
  867. hregister:=reg32toreg16(hregister);
  868. S_Q:
  869. hregister2:=R_EDI;
  870. end;
  871. if opsize=S_Q then
  872. begin
  873. emit_ref_reg(A_MOV,S_L,newreference(
  874. left.location.reference),hregister);
  875. hr:=newreference(left.location.reference);
  876. inc(hr^.offset,4);
  877. emit_ref_reg(A_MOV,S_L,hr,hregister2);
  878. end
  879. else
  880. emit_ref_reg(A_MOV,opsize,newreference(
  881. left.location.reference),hregister);
  882. end;
  883. else internalerror(2002);
  884. end;
  885. { we need the min_label always to choose between }
  886. { cmps and subs/decs }
  887. min_label:=case_get_min(nodes);
  888. load_all_regvars(exprasmlist);
  889. { now generate the jumps }
  890. if opsize=S_Q then
  891. genlinearcmplist(nodes)
  892. else
  893. begin
  894. if cs_optimize in aktglobalswitches then
  895. begin
  896. { procedures are empirically passed on }
  897. { consumption can also be calculated }
  898. { but does it pay on the different }
  899. { processors? }
  900. { moreover can the size only be appro- }
  901. { ximated as it is not known if rel8, }
  902. { rel16 or rel32 jumps are used }
  903. max_label:=case_get_max(nodes);
  904. labels:=case_count_labels(nodes);
  905. { can we omit the range check of the jump table ? }
  906. getrange(left.resulttype,lv,hv);
  907. jumptable_no_range:=(lv=min_label) and (hv=max_label);
  908. { hack a little bit, because the range can be greater }
  909. { than the positive range of a longint }
  910. if (min_label<0) and (max_label>0) then
  911. begin
  912. {$ifdef Delphi}
  913. if min_label=longint($80000000) then
  914. dist:=Cardinal(max_label)+Cardinal($80000000)
  915. else
  916. dist:=Cardinal(max_label)+Cardinal(-min_label)
  917. {$else Delphi}
  918. if min_label=$80000000 then
  919. dist:=dword(max_label)+dword($80000000)
  920. else
  921. dist:=dword(max_label)+dword(-min_label)
  922. {$endif Delphi}
  923. end
  924. else
  925. dist:=max_label-min_label;
  926. { optimize for size ? }
  927. if cs_littlesize in aktglobalswitches then
  928. begin
  929. if (labels<=2) or
  930. ((max_label-min_label)<0) or
  931. ((max_label-min_label)>3*labels) then
  932. { a linear list is always smaller than a jump tree }
  933. genlinearlist(nodes)
  934. else
  935. { if the labels less or more a continuum then }
  936. genjumptable(nodes,min_label,max_label);
  937. end
  938. else
  939. begin
  940. if jumptable_no_range then
  941. max_linear_list:=4
  942. else
  943. max_linear_list:=2;
  944. { a jump table crashes the pipeline! }
  945. if aktoptprocessor=Class386 then
  946. inc(max_linear_list,3);
  947. if aktoptprocessor=ClassP5 then
  948. inc(max_linear_list,6);
  949. if aktoptprocessor>=ClassP6 then
  950. inc(max_linear_list,9);
  951. if (labels<=max_linear_list) then
  952. genlinearlist(nodes)
  953. else
  954. begin
  955. if (dist>4*cardinal(labels)) then
  956. begin
  957. if labels>16 then
  958. gentreejmp(nodes)
  959. else
  960. genlinearlist(nodes);
  961. end
  962. else
  963. genjumptable(nodes,min_label,max_label);
  964. end;
  965. end;
  966. end
  967. else
  968. { it's always not bad }
  969. genlinearlist(nodes);
  970. end;
  971. ungetregister(hregister);
  972. { now generate the instructions }
  973. hp:=right;
  974. while assigned(hp) do
  975. begin
  976. cleartempgen;
  977. secondpass(tbinarynode(hp).right);
  978. { don't come back to case line }
  979. aktfilepos:=exprasmList.getlasttaifilepos^;
  980. load_all_regvars(exprasmlist);
  981. emitjmp(C_None,endlabel);
  982. hp:=tbinarynode(hp).left;
  983. end;
  984. emitlab(elselabel);
  985. { ...and the else block }
  986. if assigned(elseblock) then
  987. begin
  988. cleartempgen;
  989. secondpass(elseblock);
  990. load_all_regvars(exprasmlist);
  991. end;
  992. emitlab(endlabel);
  993. end;
  994. begin
  995. csetelementnode:=ti386setelementnode;
  996. cinnode:=ti386innode;
  997. ccasenode:=ti386casenode;
  998. end.
  999. {
  1000. $Log$
  1001. Revision 1.10 2000-12-25 00:07:33 peter
  1002. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1003. tlinkedlist objects)
  1004. Revision 1.9 2000/12/18 17:45:32 jonas
  1005. * int64 case fixes
  1006. * explicit longint type casts for constants used in assembler code
  1007. generation s,ice they can be cardinals too (or even int64's in case of
  1008. range check errors)
  1009. Revision 1.8 2000/12/16 15:58:18 jonas
  1010. * removed warnings about possible range check errors
  1011. Revision 1.7 2000/12/05 11:44:34 jonas
  1012. + new integer regvar handling, should be much more efficient
  1013. Revision 1.6 2000/11/29 00:30:49 florian
  1014. * unused units removed from uses clause
  1015. * some changes for widestrings
  1016. Revision 1.5 2000/11/17 14:09:00 jonas
  1017. * fixed webbug 1222 ("merged")
  1018. Revision 1.4 2000/11/13 14:44:36 jonas
  1019. * fixes so no more range errors with improved range checking code
  1020. Revision 1.3 2000/10/31 22:02:57 peter
  1021. * symtable splitted, no real code changes
  1022. Revision 1.2 2000/10/26 15:53:27 jonas
  1023. * fixed web bug1192 (changed an ungetregister32 to ungetregister)
  1024. ("merged" from fixes)
  1025. Revision 1.1 2000/10/15 09:33:32 peter
  1026. * moved n386*.pas to i386/ cpu_target dir
  1027. Revision 1.4 2000/10/14 10:14:49 peter
  1028. * moehrendorf oct 2000 rewrite
  1029. Revision 1.3 2000/09/30 16:08:45 peter
  1030. * more cg11 updates
  1031. Revision 1.2 2000/09/24 20:17:44 florian
  1032. * more conversion work done
  1033. Revision 1.1 2000/09/24 19:38:39 florian
  1034. * initial implementation
  1035. }