cg386set.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 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 cg386set;
  19. interface
  20. uses
  21. tree;
  22. procedure secondsetelement(var p : ptree);
  23. procedure secondin(var p : ptree);
  24. procedure secondcase(var p : ptree);
  25. implementation
  26. uses
  27. cobjects,verbose,globals,systems,
  28. symtable,aasm,types,
  29. hcodegen,temp_gen,pass_2,
  30. i386,cgai386,tgeni386;
  31. const
  32. bytes2Sxx:array[1..4] of Topsize=(S_B,S_W,S_NO,S_L);
  33. {*****************************************************************************
  34. SecondSetElement
  35. *****************************************************************************}
  36. procedure secondsetelement(var p : ptree);
  37. begin
  38. { load first value in 32bit register }
  39. secondpass(p^.left);
  40. if p^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  41. emit_to_reg32(p^.left^.location.register);
  42. { also a second value ? }
  43. if assigned(p^.right) then
  44. begin
  45. secondpass(p^.right);
  46. if p^.right^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  47. emit_to_reg32(p^.right^.location.register);
  48. end;
  49. { we doesn't modify the left side, we check only the type }
  50. set_location(p^.location,p^.left^.location);
  51. end;
  52. {*****************************************************************************
  53. SecondIn
  54. *****************************************************************************}
  55. procedure secondin(var p : ptree);
  56. type
  57. Tsetpart=record
  58. range : boolean; {Part is a range.}
  59. start,stop : byte; {Start/stop when range; Stop=element when an element.}
  60. end;
  61. var
  62. use_small,
  63. pushed,
  64. ranges : boolean;
  65. hr,hr2,
  66. pleftreg : tregister;
  67. opsize : topsize;
  68. setparts : array[1..8] of Tsetpart;
  69. i,numparts : byte;
  70. href,href2 : Treference;
  71. l,l2 : plabel;
  72. function analizeset(Aset:pconstset;is_small:boolean):boolean;
  73. type
  74. byteset=set of byte;
  75. var
  76. compares,maxcompares:word;
  77. i:byte;
  78. begin
  79. analizeset:=false;
  80. ranges:=false;
  81. numparts:=0;
  82. compares:=0;
  83. { Lots of comparisions take a lot of time, so do not allow
  84. too much comparisions. 8 comparisions are, however, still
  85. smalller than emitting the set }
  86. if cs_littlesize in aktglobalswitches then
  87. maxcompares:=8
  88. else
  89. maxcompares:=5;
  90. { when smallset is possible allow only 3 compares the smallset
  91. code is for littlesize also smaller when more compares are used }
  92. if is_small then
  93. maxcompares:=3;
  94. for i:=0 to 255 do
  95. if i in byteset(Aset^) then
  96. begin
  97. if (numparts=0) or (i<>setparts[numparts].stop+1) then
  98. begin
  99. {Set element is a separate element.}
  100. inc(compares);
  101. if compares>maxcompares then
  102. exit;
  103. inc(numparts);
  104. setparts[numparts].range:=false;
  105. setparts[numparts].stop:=i;
  106. end
  107. else
  108. {Set element is part of a range.}
  109. if not setparts[numparts].range then
  110. begin
  111. {Transform an element into a range.}
  112. setparts[numparts].range:=true;
  113. setparts[numparts].start:=setparts[numparts].stop;
  114. setparts[numparts].stop:=i;
  115. inc(compares);
  116. if compares>maxcompares then
  117. exit;
  118. end
  119. else
  120. begin
  121. {Extend a range.}
  122. setparts[numparts].stop:=i;
  123. {A range of two elements can better
  124. be checked as two separate ones.
  125. When extending a range, our range
  126. becomes larger than two elements.}
  127. ranges:=true;
  128. end;
  129. end;
  130. analizeset:=true;
  131. end;
  132. begin
  133. { calculate both operators }
  134. { the complex one first }
  135. firstcomplex(p);
  136. secondpass(p^.left);
  137. { are too few registers free? }
  138. pushed:=maybe_push(p^.right^.registers32,p^.left);
  139. secondpass(p^.right);
  140. if pushed then
  141. restore(p^.left);
  142. if codegenerror then
  143. exit;
  144. { ofcourse not commutative }
  145. if p^.swaped then
  146. swaptree(p);
  147. { check if we can use smallset operation using btl which is limited
  148. to 32 bits, the left side may also not contain higher values !! }
  149. use_small:=(psetdef(p^.right^.resulttype)^.settype=smallset) and
  150. ((p^.left^.resulttype^.deftype=orddef) and (porddef(p^.left^.resulttype)^.high<=32) or
  151. (p^.left^.resulttype^.deftype=enumdef) and (penumdef(p^.left^.resulttype)^.max<=32));
  152. { Can we generate jumps? Possible for all types of sets }
  153. if (p^.right^.treetype=setconstn) and
  154. analizeset(p^.right^.value_set,use_small) then
  155. begin
  156. { It gives us advantage to check for the set elements
  157. separately instead of using the SET_IN_BYTE procedure.
  158. To do: Build in support for LOC_JUMP }
  159. { If register is used, use only lower 8 bits }
  160. if p^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  161. begin
  162. pleftreg:=p^.left^.location.register;
  163. if pleftreg in [R_AX..R_DX] then
  164. begin
  165. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_W,255,pleftreg)));
  166. opsize:=S_W;
  167. end
  168. else
  169. if pleftreg in [R_EAX..R_EDI] then
  170. begin
  171. exprasmlist^.concat(new(pai386,op_const_reg(A_AND,S_L,255,pleftreg)));
  172. opsize:=S_L;
  173. end
  174. else
  175. opsize:=S_B;
  176. end;
  177. { Get a label to jump to the end }
  178. p^.location.loc:=LOC_FLAGS;
  179. { It's better to use the zero flag when there are
  180. no ranges }
  181. if ranges then
  182. p^.location.resflags:=F_C
  183. else
  184. p^.location.resflags:=F_E;
  185. reset_reference(href);
  186. getlabel(l);
  187. href.symbol:=stringdup(lab2str(l));
  188. for i:=1 to numparts do
  189. if setparts[i].range then
  190. begin
  191. { Check if left is in a range }
  192. { Get a label to jump over the check }
  193. reset_reference(href2);
  194. getlabel(l2);
  195. href.symbol:=stringdup(lab2str(l2));
  196. if setparts[i].start=setparts[i].stop-1 then
  197. begin
  198. case p^.left^.location.loc of
  199. LOC_REGISTER,
  200. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,
  201. setparts[i].start,pleftreg)));
  202. else
  203. exprasmlist^.concat(new(pai386,op_const_ref(A_CMP,S_B,
  204. setparts[i].start,newreference(p^.left^.location.reference))));
  205. end;
  206. { Result should be in carry flag when ranges are used }
  207. if ranges then
  208. exprasmlist^.concat(new(pai386,op_none(A_STC,S_NO)));
  209. { If found, jump to end }
  210. emitl(A_JE,l);
  211. case p^.left^.location.loc of
  212. LOC_REGISTER,
  213. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,
  214. setparts[i].stop,pleftreg)));
  215. else
  216. exprasmlist^.concat(new(pai386,op_const_ref(A_CMP,S_B,
  217. setparts[i].stop,newreference(p^.left^.location.reference))));
  218. end;
  219. { Result should be in carry flag when ranges are used }
  220. if ranges then
  221. exprasmlist^.concat(new(pai386,op_none(A_STC,S_NO)));
  222. { If found, jump to end }
  223. emitl(A_JE,l);
  224. end
  225. else
  226. begin
  227. if setparts[i].start<>0 then
  228. begin
  229. { We only check for the lower bound if it is > 0, because
  230. set elements lower than 0 dont exist }
  231. case p^.left^.location.loc of
  232. LOC_REGISTER,
  233. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,
  234. setparts[i].start,pleftreg)));
  235. else
  236. exprasmlist^.concat(new(pai386,op_const_ref(A_CMP,S_B,
  237. setparts[i].start,newreference(p^.left^.location.reference))));
  238. end;
  239. { If lower, jump to next check }
  240. emitl(A_JB,l2);
  241. end;
  242. { We only check for the high bound if it is < 255, because
  243. set elements higher than 255 do nt exist, the its always true,
  244. so only a JMP is generated }
  245. if setparts[i].stop<>255 then
  246. begin
  247. case p^.left^.location.loc of
  248. LOC_REGISTER,
  249. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,
  250. setparts[i].stop+1,pleftreg)));
  251. else
  252. exprasmlist^.concat(new(pai386,op_const_ref(A_CMP,S_B,
  253. setparts[i].stop+1,newreference(p^.left^.location.reference))));
  254. end;
  255. { If higher, element is in set }
  256. emitl(A_JB,l);
  257. end
  258. else
  259. begin
  260. exprasmlist^.concat(new(pai386,op_none(A_STC,S_NO)));
  261. emitl(A_JMP,l);
  262. end;
  263. end;
  264. { Emit the jump over label }
  265. exprasmlist^.concat(new(pai_label,init(l2)));
  266. end
  267. else
  268. begin
  269. { Emit code to check if left is an element }
  270. case p^.left^.location.loc of
  271. LOC_REGISTER,
  272. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,
  273. setparts[i].stop,pleftreg)));
  274. else
  275. exprasmlist^.concat(new(pai386,op_const_ref(A_CMP,S_B,
  276. setparts[i].stop,newreference(p^.left^.location.reference))));
  277. end;
  278. { Result should be in carry flag when ranges are used }
  279. if ranges then
  280. exprasmlist^.concat(new(pai386,op_none(A_STC,S_NO)));
  281. { If found, jump to end }
  282. emitl(A_JE,l);
  283. end;
  284. if ranges then
  285. exprasmlist^.concat(new(pai386,op_none(A_CLC,S_NO)));
  286. { To compensate for not doing a second pass }
  287. stringdispose(p^.right^.location.reference.symbol);
  288. { Now place the end label }
  289. exprasmlist^.concat(new(pai_label,init(l)));
  290. case p^.left^.location.loc of
  291. LOC_REGISTER,
  292. LOC_CREGISTER : ungetregister32(pleftreg);
  293. else
  294. del_reference(p^.left^.location.reference);
  295. end;
  296. end
  297. else
  298. begin
  299. { We will now generated code to check the set itself, no jmps,
  300. handle smallsets separate, because it allows faster checks }
  301. if use_small then
  302. begin
  303. if p^.left^.treetype=ordconstn then
  304. begin
  305. p^.location.resflags:=F_NE;
  306. case p^.right^.location.loc of
  307. LOC_REGISTER,
  308. LOC_CREGISTER:
  309. begin
  310. exprasmlist^.concat(new(pai386,op_const_reg(A_TEST,S_L,
  311. 1 shl (p^.left^.value and 31),p^.right^.location.register)));
  312. ungetregister32(p^.right^.location.register);
  313. end
  314. else
  315. begin
  316. exprasmlist^.concat(new(pai386,op_const_ref(A_TEST,S_L,1 shl (p^.left^.value and 31),
  317. newreference(p^.right^.location.reference))));
  318. del_reference(p^.right^.location.reference);
  319. end;
  320. end;
  321. end
  322. else
  323. begin
  324. case p^.left^.location.loc of
  325. LOC_REGISTER,
  326. LOC_CREGISTER:
  327. begin
  328. hr:=p^.left^.location.register;
  329. emit_to_reg32(hr);
  330. end;
  331. else
  332. begin
  333. { the set element isn't never samller than a byte }
  334. { and because it's a small set we need only 5 bits }
  335. { but 8 bits are easier to load }
  336. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVZX,S_BL,
  337. newreference(p^.left^.location.reference),R_EDI)));
  338. hr:=R_EDI;
  339. del_reference(p^.left^.location.reference);
  340. end;
  341. end;
  342. case p^.right^.location.loc of
  343. LOC_REGISTER,
  344. LOC_CREGISTER : exprasmlist^.concat(new(pai386,op_reg_reg(A_BT,S_L,hr,
  345. p^.right^.location.register)));
  346. else
  347. begin
  348. del_reference(p^.right^.location.reference);
  349. if p^.right^.location.reference.isintvalue then
  350. begin
  351. { We have to load the value into a register because
  352. btl does not accept values only refs or regs (PFV) }
  353. hr2:=getregister32;
  354. exprasmlist^.concat(new(pai386,op_const_reg(A_MOV,S_L,
  355. p^.right^.location.reference.offset,hr2)));
  356. exprasmlist^.concat(new(pai386,op_reg_reg(A_BT,S_L,hr,hr2)));
  357. ungetregister32(hr2);
  358. end
  359. else
  360. exprasmlist^.concat(new(pai386,op_reg_ref(A_BT,S_L,hr,
  361. newreference(p^.right^.location.reference))));
  362. end;
  363. end;
  364. ungetregister32(hr);
  365. p^.location.loc:=LOC_FLAGS;
  366. p^.location.resflags:=F_C;
  367. end;
  368. end
  369. else
  370. begin
  371. { do search in a normal set which could have >32 elementsm
  372. but also used if the left side contains higher values > 32 }
  373. if p^.left^.treetype=ordconstn then
  374. begin
  375. p^.location.resflags:=F_NE;
  376. inc(p^.right^.location.reference.offset,p^.left^.value shr 3);
  377. exprasmlist^.concat(new(pai386,op_const_ref(A_TEST,S_B,1 shl (p^.left^.value and 7),
  378. newreference(p^.right^.location.reference))));
  379. del_reference(p^.right^.location.reference);
  380. end
  381. else
  382. begin
  383. pushsetelement(p^.left);
  384. emitpushreferenceaddr(exprasmlist,p^.right^.location.reference);
  385. del_reference(p^.right^.location.reference);
  386. { registers need not be save. that happens in SET_IN_BYTE }
  387. { (EDI is changed) }
  388. emitcall('FPC_SET_IN_BYTE',true);
  389. { ungetiftemp(p^.right^.location.reference); }
  390. p^.location.loc:=LOC_FLAGS;
  391. p^.location.resflags:=F_C;
  392. end;
  393. end;
  394. end;
  395. end;
  396. {*****************************************************************************
  397. SecondCase
  398. *****************************************************************************}
  399. procedure secondcase(var p : ptree);
  400. var
  401. with_sign : boolean;
  402. opsize : topsize;
  403. jmp_gt,jmp_le,jmp_lee : tasmop;
  404. hp : ptree;
  405. { register with case expression }
  406. hregister : tregister;
  407. endlabel,elselabel : plabel;
  408. { true, if we can omit the range check of the jump table }
  409. jumptable_no_range : boolean;
  410. { where to put the jump table }
  411. jumpsegment : paasmoutput;
  412. procedure gentreejmp(p : pcaserecord);
  413. var
  414. lesslabel,greaterlabel : plabel;
  415. begin
  416. emitl(A_LABEL,p^._at);
  417. { calculate labels for left and right }
  418. if (p^.less=nil) then
  419. lesslabel:=elselabel
  420. else
  421. lesslabel:=p^.less^._at;
  422. if (p^.greater=nil) then
  423. greaterlabel:=elselabel
  424. else
  425. greaterlabel:=p^.greater^._at;
  426. { calculate labels for left and right }
  427. { no range label: }
  428. if p^._low=p^._high then
  429. begin
  430. exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,p^._low,hregister)));
  431. if greaterlabel=lesslabel then
  432. begin
  433. emitl(A_JNE,lesslabel);
  434. end
  435. else
  436. begin
  437. emitl(jmp_le,lesslabel);
  438. emitl(jmp_gt,greaterlabel);
  439. end;
  440. emitl(A_JMP,p^.statement);
  441. end
  442. else
  443. begin
  444. exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,p^._low,hregister)));
  445. emitl(jmp_le,lesslabel);
  446. exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,p^._high,hregister)));
  447. emitl(jmp_gt,greaterlabel);
  448. emitl(A_JMP,p^.statement);
  449. end;
  450. if assigned(p^.less) then
  451. gentreejmp(p^.less);
  452. if assigned(p^.greater) then
  453. gentreejmp(p^.greater);
  454. end;
  455. procedure genlinearlist(hp : pcaserecord);
  456. var
  457. first : boolean;
  458. last : longint;
  459. {helplabel : longint;}
  460. procedure genitem(t : pcaserecord);
  461. begin
  462. if assigned(t^.less) then
  463. genitem(t^.less);
  464. { need we to test the first value }
  465. if first and (t^._low>get_min_value(p^.left^.resulttype)) then
  466. begin
  467. exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,t^._low,hregister)));
  468. emitl(jmp_le,elselabel);
  469. end;
  470. if t^._low=t^._high then
  471. begin
  472. if t^._low-last=1 then
  473. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,hregister)))
  474. else if t^._low-last=0 then
  475. exprasmlist^.concat(new(pai386,op_reg_reg(A_OR,opsize,hregister,hregister)))
  476. else
  477. exprasmlist^.concat(new(pai386,op_const_reg(A_SUB,opsize,t^._low-last,hregister)));
  478. last:=t^._low;
  479. emitl(A_JZ,t^.statement);
  480. end
  481. else
  482. begin
  483. { it begins with the smallest label, if the value }
  484. { is even smaller then jump immediately to the }
  485. { ELSE-label }
  486. if first then
  487. begin
  488. { have we to ajust the first value ? }
  489. if t^._low>get_min_value(p^.left^.resulttype) then
  490. begin
  491. if t^._low=1 then
  492. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,
  493. hregister)))
  494. else
  495. exprasmlist^.concat(new(pai386,op_const_reg(A_SUB,opsize,
  496. t^._low,hregister)));
  497. end;
  498. { work around: if the lower range=0 and we
  499. do the subtraction we have to take care
  500. of the sign!
  501. this isn't necessary, this is tested before now (FK)
  502. if t^._low=0 then
  503. emitl(A_JBE,elselabel)
  504. else
  505. emitl(jmp_lee,elselabel);
  506. }
  507. end
  508. else
  509. { if there is no unused label between the last and the }
  510. { present label then the lower limit can be checked }
  511. { immediately. else check the range in between: }
  512. if (t^._low-last>1) then
  513. begin
  514. exprasmlist^.concat(new(pai386,op_const_reg(A_SUB,opsize,t^._low-last,hregister)));
  515. emitl(jmp_le,elselabel);
  516. end
  517. else
  518. exprasmlist^.concat(new(pai386,op_reg(A_DEC,opsize,hregister)));
  519. exprasmlist^.concat(new(pai386,op_const_reg(A_SUB,opsize,t^._high-t^._low,hregister)));
  520. emitl(jmp_lee,t^.statement);
  521. last:=t^._high;
  522. end;
  523. first:=false;
  524. if assigned(t^.greater) then
  525. genitem(t^.greater);
  526. end;
  527. begin
  528. last:=0;
  529. first:=true;
  530. genitem(hp);
  531. emitl(A_JMP,elselabel);
  532. end;
  533. procedure genjumptable(hp : pcaserecord;min_,max_ : longint);
  534. var
  535. table : plabel;
  536. last : longint;
  537. hr : preference;
  538. procedure genitem(t : pcaserecord);
  539. var
  540. i : longint;
  541. begin
  542. if assigned(t^.less) then
  543. genitem(t^.less);
  544. { fill possible hole }
  545. for i:=last+1 to t^._low-1 do
  546. jumpsegment^.concat(new(pai_const,init_symbol(strpnew(lab2str
  547. (elselabel)))));
  548. for i:=t^._low to t^._high do
  549. jumpsegment^.concat(new(pai_const,init_symbol(strpnew(lab2str
  550. (t^.statement)))));
  551. last:=t^._high;
  552. if assigned(t^.greater) then
  553. genitem(t^.greater);
  554. end;
  555. begin
  556. if not(jumptable_no_range) then
  557. begin
  558. exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,min_,hregister)));
  559. { case expr less than min_ => goto elselabel }
  560. emitl(jmp_le,elselabel);
  561. exprasmlist^.concat(new(pai386,op_const_reg(A_CMP,opsize,max_,hregister)));
  562. emitl(jmp_gt,elselabel);
  563. end;
  564. getlabel(table);
  565. { extend with sign }
  566. if opsize=S_W then
  567. begin
  568. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOVZX,S_WL,hregister,
  569. reg16toreg32(hregister))));
  570. hregister:=reg16toreg32(hregister);
  571. end
  572. else if opsize=S_B then
  573. begin
  574. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOVZX,S_BL,hregister,
  575. reg8toreg32(hregister))));
  576. hregister:=reg8toreg32(hregister);
  577. end;
  578. new(hr);
  579. reset_reference(hr^);
  580. hr^.symbol:=stringdup(lab2str(table));
  581. hr^.offset:=(-min_)*4;
  582. hr^.index:=hregister;
  583. hr^.scalefactor:=4;
  584. exprasmlist^.concat(new(pai386,op_ref(A_JMP,S_NO,hr)));
  585. { !!!!! generate tables
  586. if not(cs_littlesize in aktlocalswitches) then
  587. jumpsegment^.concat(new(pai386,op_const(A_ALIGN,S_NO,4)));
  588. }
  589. jumpsegment^.concat(new(pai_label,init(table)));
  590. last:=min_;
  591. genitem(hp);
  592. { !!!!!!!
  593. if not(cs_littlesize in aktlocalswitches) then
  594. exprasmlist^.concat(new(pai386,op_const(A_ALIGN,S_NO,4)));
  595. }
  596. end;
  597. var
  598. lv,hv,min_label,max_label,labels : longint;
  599. max_linear_list : longint;
  600. begin
  601. getlabel(endlabel);
  602. getlabel(elselabel);
  603. if (cs_smartlink in aktmoduleswitches) then
  604. jumpsegment:=procinfo.aktlocaldata
  605. else
  606. jumpsegment:=datasegment;
  607. with_sign:=is_signed(p^.left^.resulttype);
  608. if with_sign then
  609. begin
  610. jmp_gt:=A_JG;
  611. jmp_le:=A_JL;
  612. jmp_lee:=A_JLE;
  613. end
  614. else
  615. begin
  616. jmp_gt:=A_JA;
  617. jmp_le:=A_JB;
  618. jmp_lee:=A_JBE;
  619. end;
  620. cleartempgen;
  621. secondpass(p^.left);
  622. { determines the size of the operand }
  623. opsize:=bytes2Sxx[p^.left^.resulttype^.size];
  624. { copy the case expression to a register }
  625. case p^.left^.location.loc of
  626. LOC_REGISTER:
  627. hregister:=p^.left^.location.register;
  628. LOC_CREGISTER:
  629. begin
  630. hregister:=getregister32;
  631. case opsize of
  632. S_B : hregister:=reg32toreg8(hregister);
  633. S_W : hregister:=reg32toreg16(hregister);
  634. end;
  635. exprasmlist^.concat(new(pai386,op_reg_reg(A_MOV,opsize,
  636. p^.left^.location.register,hregister)));
  637. end;
  638. LOC_MEM,LOC_REFERENCE : begin
  639. del_reference(p^.left^.location.reference);
  640. hregister:=getregister32;
  641. case opsize of
  642. S_B : hregister:=reg32toreg8(hregister);
  643. S_W : hregister:=reg32toreg16(hregister);
  644. end;
  645. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,opsize,newreference(
  646. p^.left^.location.reference),hregister)));
  647. end;
  648. else internalerror(2002);
  649. end;
  650. { now generate the jumps }
  651. if cs_optimize in aktglobalswitches then
  652. begin
  653. { procedures are empirically passed on }
  654. { consumption can also be calculated }
  655. { but does it pay on the different }
  656. { processors? }
  657. { moreover can the size only be appro- }
  658. { ximated as it is not known if rel8, }
  659. { rel16 or rel32 jumps are used }
  660. min_label:=case_get_min(p^.nodes);
  661. max_label:=case_get_max(p^.nodes);
  662. labels:=case_count_labels(p^.nodes);
  663. { can we omit the range check of the jump table }
  664. getrange(p^.left^.resulttype,lv,hv);
  665. jumptable_no_range:=(lv=min_label) and (hv=max_label);
  666. { optimize for size ? }
  667. if cs_littlesize in aktglobalswitches then
  668. begin
  669. if (labels<=2) or ((max_label-min_label)>3*labels) then
  670. { a linear list is always smaller than a jump tree }
  671. genlinearlist(p^.nodes)
  672. else
  673. { if the labels less or more a continuum then }
  674. genjumptable(p^.nodes,min_label,max_label);
  675. end
  676. else
  677. begin
  678. if jumptable_no_range then
  679. max_linear_list:=4
  680. else
  681. max_linear_list:=2;
  682. { a jump table crashes the pipeline! }
  683. if aktoptprocessor=Class386 then
  684. inc(max_linear_list,3);
  685. if aktoptprocessor=ClassP5 then
  686. inc(max_linear_list,6);
  687. if aktoptprocessor>=ClassP6 then
  688. inc(max_linear_list,9);
  689. if (labels<=max_linear_list) then
  690. genlinearlist(p^.nodes)
  691. else
  692. begin
  693. if ((max_label-min_label)>4*labels) then
  694. begin
  695. if labels>16 then
  696. gentreejmp(p^.nodes)
  697. else
  698. genlinearlist(p^.nodes);
  699. end
  700. else
  701. genjumptable(p^.nodes,min_label,max_label);
  702. end;
  703. end;
  704. end
  705. else
  706. { it's always not bad }
  707. genlinearlist(p^.nodes);
  708. { now generate the instructions }
  709. hp:=p^.right;
  710. while assigned(hp) do
  711. begin
  712. cleartempgen;
  713. secondpass(hp^.right);
  714. { don't come back to case line }
  715. aktfilepos:=exprasmlist^.getlasttaifilepos^;
  716. emitl(A_JMP,endlabel);
  717. hp:=hp^.left;
  718. end;
  719. emitl(A_LABEL,elselabel);
  720. { ...and the else block }
  721. if assigned(p^.elseblock) then
  722. begin
  723. cleartempgen;
  724. secondpass(p^.elseblock);
  725. end;
  726. emitl(A_LABEL,endlabel);
  727. end;
  728. end.
  729. {
  730. $Log$
  731. Revision 1.17 1998-09-17 09:42:20 peter
  732. + pass_2 for cg386
  733. * Message() -> CGMessage() for pass_1/pass_2
  734. Revision 1.16 1998/09/14 10:43:53 peter
  735. * all internal RTL functions start with FPC_
  736. Revision 1.15 1998/09/09 17:51:59 florian
  737. * the next try to fix the case problem ...
  738. Revision 1.14 1998/09/09 16:44:21 florian
  739. * I hope, the case bug is fixed now
  740. Revision 1.13 1998/09/07 18:45:54 peter
  741. * update smartlinking, uses getdatalabel
  742. * renamed ptree.value vars to value_str,value_real,value_set
  743. Revision 1.12 1998/09/05 23:51:05 florian
  744. * possible bug with too few registers in first/secondin fixed
  745. Revision 1.11 1998/09/04 08:41:41 peter
  746. * updated some error messages
  747. Revision 1.10 1998/09/03 17:08:40 pierre
  748. * better lines for stabs
  749. (no scroll back to if before else part
  750. no return to case line at jump outside case)
  751. + source lines also if not in order
  752. Revision 1.9 1998/08/28 10:54:19 peter
  753. * fixed smallset generation from elements, it has never worked before!
  754. Revision 1.8 1998/08/25 11:51:46 peter
  755. * fixed -15 seen as byte in case
  756. Revision 1.7 1998/08/19 16:07:38 jonas
  757. * changed optimizer switches + cleanup of DestroyRefs in daopt386.pas
  758. Revision 1.6 1998/08/18 09:24:39 pierre
  759. * small warning position bug fixed
  760. * support_mmx switches splitting was missing
  761. * rhide error and warning output corrected
  762. Revision 1.5 1998/08/14 18:18:40 peter
  763. + dynamic set contruction
  764. * smallsets are now working (always longint size)
  765. Revision 1.4 1998/08/10 14:49:51 peter
  766. + localswitches, moduleswitches, globalswitches splitting
  767. Revision 1.3 1998/06/25 08:48:10 florian
  768. * first version of rtti support
  769. Revision 1.2 1998/06/16 08:56:18 peter
  770. + targetcpu
  771. * cleaner pmodules for newppu
  772. Revision 1.1 1998/06/05 17:44:13 peter
  773. * splitted cgi386
  774. }