n386set.pas 42 KB

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