n386set.pas 42 KB

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