cg68kset.pas 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. Generate m68k 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 cg68kset;
  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. globtype,systems,
  28. cobjects,verbose,globals,
  29. symtable,aasm,types,
  30. hcodegen,temp_gen,pass_2,
  31. m68k,cga68k,tgen68k;
  32. const
  33. bytes2Sxx:array[1..4] of Topsize=(S_B,S_W,S_NO,S_L);
  34. {*****************************************************************************
  35. SecondSetElement
  36. *****************************************************************************}
  37. procedure secondsetelement(var p : ptree);
  38. begin
  39. { load first value in 32bit register }
  40. secondpass(p^.left);
  41. if p^.left^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  42. emit_to_reg32(p^.left^.location.register);
  43. { also a second value ? }
  44. if assigned(p^.right) then
  45. begin
  46. secondpass(p^.right);
  47. if p^.right^.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  48. emit_to_reg32(p^.right^.location.register);
  49. end;
  50. { we doesn't modify the left side, we check only the type }
  51. set_location(p^.location,p^.left^.location);
  52. end;
  53. {*****************************************************************************
  54. SecondIn
  55. *****************************************************************************}
  56. { could be built into secondadd but it }
  57. { should be easy to read }
  58. procedure secondin(var p : ptree);
  59. type Tsetpart=record
  60. range:boolean; {Part is a range.}
  61. start,stop:byte; {Start/stop when range; Stop=element
  62. when an element.}
  63. end;
  64. var
  65. pushed,ranges : boolean;
  66. hr : tregister;
  67. setparts:array[1..8] of Tsetpart;
  68. i,numparts:byte;
  69. {href,href2:Treference;}
  70. l,l2 : plabel;
  71. hl,hl1 : plabel;
  72. hl2, hl3: plabel;
  73. opsize : topsize;
  74. function swaplongint(l : longint): longint;
  75. var
  76. w1: word;
  77. w2: word;
  78. begin
  79. w1:=l and $ffff;
  80. w2:=l shr 16;
  81. l:=swap(w2)+(longint(swap(w1)) shl 16);
  82. swaplongint:=l;
  83. end;
  84. function analizeset(Aset:Pconstset):boolean;
  85. type byteset=set of byte;
  86. tlongset = array[0..7] of longint;
  87. var compares,maxcompares:word;
  88. someset : tlongset;
  89. i:byte;
  90. begin
  91. analizeset:=false;
  92. ranges:=false;
  93. numparts:=0;
  94. compares:=0;
  95. {Lots of comparisions take a lot of time, so do not allow
  96. too much comparisions. 8 comparisions are, however, still
  97. smalller than emitting the set.}
  98. maxcompares:=5;
  99. if cs_littlesize in aktglobalswitches then
  100. maxcompares:=8;
  101. move(ASet^,someset,32);
  102. { On Big endian machines sets are stored }
  103. { as INTEL Little-endian format, therefore }
  104. { we must convert it to the correct format }
  105. {$IFDEF BIG_ENDIAN}
  106. for I:=0 to 7 do
  107. someset[i]:=swaplongint(someset[i]);
  108. {$ENDIF}
  109. for i:=0 to 255 do
  110. if i in byteset(someset) then
  111. begin
  112. if (numparts=0) or
  113. (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:=
  130. setparts[numparts].stop;
  131. setparts[numparts].stop:=i;
  132. inc(compares);
  133. if compares>maxcompares then
  134. exit;
  135. end
  136. else
  137. begin
  138. {Extend a range.}
  139. setparts[numparts].stop:=i;
  140. {A range of two elements can better
  141. be checked as two separate ones.
  142. When extending a range, our range
  143. becomes larger than two elements.}
  144. ranges:=true;
  145. end;
  146. end;
  147. analizeset:=true;
  148. end; { end analizeset }
  149. begin
  150. if psetdef(p^.right^.resulttype)^.settype=smallset then
  151. begin
  152. if p^.left^.treetype=ordconstn then
  153. begin
  154. { only compulsory }
  155. secondpass(p^.left);
  156. secondpass(p^.right);
  157. if codegenerror then
  158. exit;
  159. p^.location.resflags:=F_NE;
  160. { Because of the Endian of the m68k, we have to consider this as a }
  161. { normal set and load it byte per byte, otherwise we will never get }
  162. { the correct result. }
  163. case p^.right^.location.loc of
  164. LOC_REGISTER,LOC_CREGISTER :
  165. begin
  166. emit_reg_reg(A_MOVE,S_L,p^.right^.location.register,R_D1);
  167. exprasmlist^.concat(new(pai68k,
  168. op_const_reg(A_AND,S_L, 1 shl (p^.left^.value and 31),R_D1)));
  169. end;
  170. else
  171. begin
  172. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(
  173. p^.right^.location.reference),R_D1)));
  174. exprasmlist^.concat(new(pai68k,op_const_reg(
  175. A_AND,S_L,1 shl (p^.left^.value and 31) ,R_D1)));
  176. end;
  177. end;
  178. del_reference(p^.right^.location.reference);
  179. end
  180. else
  181. begin
  182. { calculate both operators }
  183. { the complex one first }
  184. firstcomplex(p);
  185. secondpass(p^.left);
  186. { are too few registers free? }
  187. pushed:=maybe_push(p^.right^.registers32,p^.left);
  188. secondpass(p^.right);
  189. if pushed then
  190. restore(p^.left);
  191. { of course not commutative }
  192. if p^.swaped then
  193. swaptree(p);
  194. { load index into register }
  195. case p^.left^.location.loc of
  196. LOC_REGISTER,
  197. LOC_CREGISTER :
  198. hr:=p^.left^.location.register;
  199. else
  200. begin
  201. { Small sets are always 32 bit values, there is no }
  202. { way they can be anything else, so no problems here}
  203. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,
  204. newreference(p^.left^.location.reference),R_D1)));
  205. hr:=R_D1;
  206. del_reference(p^.left^.location.reference);
  207. end;
  208. end;
  209. case p^.right^.location.loc of
  210. LOC_REGISTER,
  211. LOC_CREGISTER : exprasmlist^.concat(new(pai68k, op_reg_reg(A_BTST,S_L,hr,p^.right^.location.register)));
  212. else
  213. begin
  214. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,S_L,newreference(p^.right^.location.reference),
  215. R_D0)));
  216. exprasmlist^.concat(new(pai68k,op_reg_reg(A_BTST,S_L,hr,R_D0)));
  217. del_reference(p^.right^.location.reference);
  218. end;
  219. end;
  220. { support carry routines }
  221. { sets the carry flags according to the result of BTST }
  222. { i.e the Z flag. }
  223. getlabel(hl);
  224. emitl(A_BNE,hl);
  225. { leave all bits unchanged except Carry = 0 }
  226. exprasmlist^.concat(new(pai68k, op_const_reg(A_AND, S_B, $FE, R_CCR)));
  227. getlabel(hl1);
  228. emitl(A_BRA,hl1);
  229. emitl(A_LABEL, hl);
  230. { set carry to 1 }
  231. exprasmlist^.concat(new(pai68k, op_const_reg(A_OR, S_B, $01, R_CCR)));
  232. emitl(A_LABEL, hl1);
  233. { end support carry routines }
  234. p^.location.loc:=LOC_FLAGS;
  235. p^.location.resflags:=F_C;
  236. end;
  237. end
  238. else { //// NOT a small set //// }
  239. begin
  240. if p^.left^.treetype=ordconstn then
  241. begin
  242. { only compulsory }
  243. secondpass(p^.left);
  244. secondpass(p^.right);
  245. if codegenerror then
  246. exit;
  247. p^.location.resflags:=F_NE;
  248. inc(p^.right^.location.reference.offset,(p^.left^.value div 32)*4);
  249. exprasmlist^.concat(new(pai68k, op_ref_reg(A_MOVE, S_L,
  250. newreference(p^.right^.location.reference), R_D1)));
  251. exprasmlist^.concat(new(pai68k, op_const_reg(A_AND, S_L,
  252. 1 shl (p^.left^.value mod 32),R_D1)));
  253. del_reference(p^.right^.location.reference);
  254. end
  255. else
  256. begin
  257. if (p^.right^.treetype=setconstn) and
  258. analizeset(p^.right^.value_set) then
  259. begin
  260. {It gives us advantage to check for the set elements
  261. separately instead of using the SET_IN_BYTE procedure.
  262. To do: Build in support for LOC_JUMP.}
  263. secondpass(p^.left);
  264. {We won't do a second pass on p^.right, because
  265. this will emit the constant set.}
  266. case p^.left^.location.loc of
  267. LOC_REGISTER,
  268. LOC_CREGISTER :
  269. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
  270. 255,p^.left^.location.register)));
  271. else
  272. Begin
  273. { Because of the m68k endian, then we must LOAD normally the }
  274. { value into a register first, all depending on the source }
  275. { size! }
  276. opsize:=S_NO;
  277. case integer(p^.left^.resulttype^.savesize) of
  278. 1 : opsize:=S_B;
  279. 2 : opsize:=S_W;
  280. 4 : opsize:=S_L;
  281. else
  282. internalerror(19);
  283. end;
  284. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,opsize,
  285. newreference(p^.left^.location.reference),R_D0)));
  286. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,
  287. 255,R_D0)));
  288. end;
  289. end;
  290. {Get a label to jump to the end.}
  291. p^.location.loc:=LOC_FLAGS;
  292. {It's better to use the zero flag when there are no ranges.}
  293. if ranges then
  294. p^.location.resflags:=F_C
  295. else
  296. p^.location.resflags:=F_E;
  297. {href.symbol := nil;
  298. clear_reference(href);}
  299. getlabel(l);
  300. {href.symbol:=stringdup(lab2str(l));}
  301. for i:=1 to numparts do
  302. if setparts[i].range then
  303. begin
  304. {Check if left is in a range.}
  305. {Get a label to jump over the check.}
  306. {href2.symbol := nil;
  307. clear_reference(href2);}
  308. getlabel(l2);
  309. {href.symbol:=stringdup(lab2str(l2));}
  310. if setparts[i].start=setparts[i].stop-1 then
  311. begin
  312. case p^.left^.location.loc of
  313. LOC_REGISTER,
  314. LOC_CREGISTER :
  315. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  316. setparts[i].start,p^.left^.location.register)));
  317. else
  318. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  319. setparts[i].start,R_D0)));
  320. { exprasmlist^.concat(new(pai68k,op_const_ref(A_CMP,S_B,
  321. setparts[i].start,newreference(p^.left^.location.reference))));}
  322. end;
  323. {Result should be in carry flag when ranges are used.}
  324. { Here the m68k does not affect any flag except the }
  325. { flag which is OR'ed }
  326. if ranges then
  327. exprasmlist^.concat(new(pai68k,op_const_reg(A_OR,S_B,$01,R_CCR)));
  328. {If found, jump to end.}
  329. emitl(A_BEQ,l);
  330. case p^.left^.location.loc of
  331. LOC_REGISTER,
  332. LOC_CREGISTER :
  333. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  334. setparts[i].stop,p^.left^.location.register)));
  335. else
  336. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  337. setparts[i].stop,R_D0)));
  338. { exprasmlist^.concat(new(pai68k,op_const_ref(A_CMP,S_B,
  339. setparts[i].stop,newreference(p^.left^.location.reference))));}
  340. end;
  341. {Result should be in carry flag when ranges are used.}
  342. { Here the m68k does not affect any flag except the }
  343. { flag which is OR'ed }
  344. if ranges then
  345. exprasmlist^.concat(new(pai68k,op_const_reg(A_OR,S_B,$01,R_CCR)));
  346. {If found, jump to end.}
  347. emitl(A_BEQ,l);
  348. end
  349. else
  350. begin
  351. if setparts[i].start<>0 then
  352. begin
  353. {We only check for the lower bound if it is > 0, because
  354. set elements lower than 0 do nt exist.}
  355. case p^.left^.location.loc of
  356. LOC_REGISTER,
  357. LOC_CREGISTER :
  358. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  359. setparts[i].start,p^.left^.location.register)));
  360. else
  361. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  362. setparts[i].start,R_D0)));
  363. { exprasmlist^.concat(new(pai68k,op_const_ref(A_CMP,S_B,
  364. setparts[i].start,newreference(p^.left^.location.reference)))); }
  365. end;
  366. {If lower, jump to next check.}
  367. emitl(A_BCS,l2);
  368. end;
  369. if setparts[i].stop<>255 then
  370. begin
  371. {We only check for the high bound if it is < 255, because
  372. set elements higher than 255 do nt exist.}
  373. case p^.left^.location.loc of
  374. LOC_REGISTER,
  375. LOC_CREGISTER :
  376. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  377. setparts[i].stop+1,p^.left^.location.register)));
  378. else
  379. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  380. setparts[i].stop+1,R_D0)));
  381. { exprasmlist^.concat(new(pai68k,op_const_ref(A_CMP,S_B,
  382. setparts[i].stop+1,newreference(p^.left^.location.reference))));}
  383. end; { end case }
  384. {If higher, element is in set.}
  385. emitl(A_BCS,l);
  386. end
  387. else
  388. begin
  389. exprasmlist^.concat(new(pai68k,op_const_reg(A_OR,S_B,$01,R_CCR)));
  390. emitl(A_JMP,l);
  391. end;
  392. end;
  393. {Emit the jump over label.}
  394. exprasmlist^.concat(new(pai_label,init(l2)));
  395. end
  396. else
  397. begin
  398. {Emit code to check if left is an element.}
  399. case p^.left^.location.loc of
  400. LOC_REGISTER,
  401. LOC_CREGISTER :
  402. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  403. setparts[i].stop,p^.left^.location.register)));
  404. else
  405. { exprasmlist^.concat(new(pai68k,op_const_ref(A_CMP,S_B,
  406. setparts[i].stop,newreference(p^.left^.location.reference))));}
  407. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,S_W,
  408. setparts[i].stop,R_D0)));
  409. end;
  410. {Result should be in carry flag when ranges are used.}
  411. if ranges then
  412. exprasmlist^.concat(new(pai68k, op_const_reg(A_OR,S_B,$01,R_CCR)));
  413. {If found, jump to end.}
  414. emitl(A_BEQ,l);
  415. end;
  416. if ranges then
  417. { clear carry flag }
  418. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_B,$FE,R_CCR)));
  419. {To compensate for not doing a second pass.}
  420. stringdispose(p^.right^.location.reference.symbol);
  421. {Now place the end label.}
  422. exprasmlist^.concat(new(pai_label,init(l)));
  423. end
  424. else
  425. begin
  426. { calculate both operators }
  427. { the complex one first }
  428. firstcomplex(p);
  429. secondpass(p^.left);
  430. {
  431. unnecessary !! PM
  432. set_location(p^.location,p^.left^.location);}
  433. { are too few registers free? }
  434. pushed:=maybe_push(p^.right^.registers32,p);
  435. secondpass(p^.right);
  436. if pushed then restore(p);
  437. { of course not commutative }
  438. if p^.swaped then
  439. swaptree(p);
  440. { SET_IN_BYTE is an inline assembler procedure instead }
  441. { of a normal procedure, which is *MUCH* faster }
  442. { Parameters are passed by registers, and FLAGS are set }
  443. { according to the result. }
  444. { a0 = address of set }
  445. { d0.b = value to compare with }
  446. { CARRY SET IF FOUND ON EXIT }
  447. loadsetelement(p^.left);
  448. exprasmlist^.concat(new(pai68k,op_ref_reg(A_LEA,S_L,
  449. newreference(p^.right^.location.reference),R_A0)));;
  450. { emitpushreferenceaddr(p^.right^.location.reference);}
  451. del_reference(p^.right^.location.reference);
  452. emitcall('FPC_SET_IN_BYTE',true);
  453. { ungetiftemp(p^.right^.location.reference); }
  454. p^.location.loc:=LOC_FLAGS;
  455. p^.location.resflags:=F_C;
  456. end;
  457. end;
  458. end;
  459. end;
  460. {*****************************************************************************
  461. SecondCase
  462. *****************************************************************************}
  463. procedure secondcase(var p : ptree);
  464. var
  465. with_sign : boolean;
  466. opsize : topsize;
  467. jmp_gt,jmp_le,jmp_lee : tasmop;
  468. hp : ptree;
  469. { register with case expression }
  470. hregister : tregister;
  471. endlabel,elselabel : plabel;
  472. { true, if we can omit the range check of the jump table }
  473. jumptable_no_range : boolean;
  474. procedure gentreejmp(p : pcaserecord);
  475. var
  476. lesslabel,greaterlabel : plabel;
  477. begin
  478. emitl(A_LABEL,p^._at);
  479. { calculate labels for left and right }
  480. if (p^.less=nil) then
  481. lesslabel:=elselabel
  482. else
  483. lesslabel:=p^.less^._at;
  484. if (p^.greater=nil) then
  485. greaterlabel:=elselabel
  486. else
  487. greaterlabel:=p^.greater^._at;
  488. { calculate labels for left and right }
  489. { no range label: }
  490. if p^._low=p^._high then
  491. begin
  492. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,opsize,p^._low,hregister)));
  493. if greaterlabel=lesslabel then
  494. begin
  495. emitl(A_BNE,lesslabel);
  496. end
  497. else
  498. begin
  499. emitl(jmp_le,lesslabel);
  500. emitl(jmp_gt,greaterlabel);
  501. end;
  502. emitl(A_JMP,p^.statement);
  503. end
  504. else
  505. begin
  506. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,opsize,p^._low,hregister)));
  507. emitl(jmp_le,lesslabel);
  508. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,opsize,p^._high,hregister)));
  509. emitl(jmp_gt,greaterlabel);
  510. emitl(A_JMP,p^.statement);
  511. end;
  512. if assigned(p^.less) then
  513. gentreejmp(p^.less);
  514. if assigned(p^.greater) then
  515. gentreejmp(p^.greater);
  516. end;
  517. procedure genlinearlist(hp : pcaserecord);
  518. var
  519. first : boolean;
  520. last : longint;
  521. procedure genitem(t : pcaserecord);
  522. begin
  523. if assigned(t^.less) then
  524. genitem(t^.less);
  525. if t^._low=t^._high then
  526. begin
  527. if (t^._low-last > 0) and (t^._low-last < 9) then
  528. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,opsize,t^._low-last,hregister)))
  529. else
  530. if (t^._low-last = 0) then
  531. exprasmlist^.concat(new(pai68k,op_reg(A_TST,opsize,hregister)))
  532. else
  533. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUB,opsize,t^._low-last,hregister)));
  534. last:=t^._low;
  535. emitl(A_BEQ,t^.statement);
  536. end
  537. else
  538. begin
  539. { it begins with the smallest label, if the value }
  540. { is even smaller then jump immediately to the }
  541. { ELSE-label }
  542. if first then
  543. begin
  544. if (t^._low-1 > 0) and (t^._low < 9) then
  545. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,opsize,t^._low-1,hregister)))
  546. else
  547. if t^._low-1=0 then
  548. exprasmlist^.concat(new(pai68k,op_reg(A_TST,opsize,hregister)))
  549. else
  550. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUB,opsize,t^._low-1,hregister)));
  551. if t^._low = 0 then
  552. emitl(A_BLE,elselabel)
  553. else
  554. emitl(jmp_lee,elselabel);
  555. end
  556. { if there is no unused label between the last and the }
  557. { present label then the lower limit can be checked }
  558. { immediately. else check the range in between: }
  559. else if (t^._low-last>1)then
  560. begin
  561. if ((t^._low-last-1) > 0) and ((t^._low-last-1) < 9) then
  562. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUBQ,opsize,t^._low-last-1,hregister)))
  563. else
  564. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUB,opsize,t^._low-last-1,hregister)));
  565. emitl(jmp_lee,elselabel);
  566. end;
  567. exprasmlist^.concat(new(pai68k,op_const_reg(A_SUB,opsize,t^._high-t^._low+1,hregister)));
  568. emitl(jmp_lee,t^.statement);
  569. last:=t^._high;
  570. end;
  571. first:=false;
  572. if assigned(t^.greater) then
  573. genitem(t^.greater);
  574. end;
  575. var
  576. hr : tregister;
  577. begin
  578. { case register is modified by the list evalution }
  579. if (p^.left^.location.loc=LOC_CREGISTER) then
  580. begin
  581. hr:=getregister32;
  582. end;
  583. last:=0;
  584. first:=true;
  585. genitem(hp);
  586. emitl(A_JMP,elselabel);
  587. end;
  588. procedure genjumptable(hp : pcaserecord;min_,max_ : longint);
  589. var
  590. table : plabel;
  591. last : longint;
  592. hr : preference;
  593. procedure genitem(t : pcaserecord);
  594. var
  595. i : longint;
  596. begin
  597. if assigned(t^.less) then
  598. genitem(t^.less);
  599. { fill possible hole }
  600. for i:=last+1 to t^._low-1 do
  601. datasegment^.concat(new(pai_const,init_symbol(strpnew(lab2str
  602. (elselabel)))));
  603. for i:=t^._low to t^._high do
  604. datasegment^.concat(new(pai_const,init_symbol(strpnew(lab2str
  605. (t^.statement)))));
  606. last:=t^._high;
  607. if assigned(t^.greater) then
  608. genitem(t^.greater);
  609. end;
  610. begin
  611. if not(jumptable_no_range) then
  612. begin
  613. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,opsize,min_,hregister)));
  614. { case expr less than min_ => goto elselabel }
  615. emitl(jmp_le,elselabel);
  616. exprasmlist^.concat(new(pai68k,op_const_reg(A_CMP,opsize,max_,hregister)));
  617. emitl(jmp_gt,elselabel);
  618. end;
  619. getlabel(table);
  620. { extend with sign }
  621. if opsize=S_W then
  622. begin
  623. { word to long - unsigned }
  624. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,$ffff,hregister)));
  625. end
  626. else if opsize=S_B then
  627. begin
  628. { byte to long - unsigned }
  629. exprasmlist^.concat(new(pai68k,op_const_reg(A_AND,S_L,$ff,hregister)));
  630. end;
  631. new(hr);
  632. reset_reference(hr^);
  633. hr^.symbol:=stringdup(lab2str(table));
  634. hr^.offset:=(-min_)*4;
  635. { add scalefactor *4 to index }
  636. exprasmlist^.concat(new(pai68k,op_const_reg(A_LSL,S_L,2,hregister)));
  637. { hr^.scalefactor:=4; }
  638. hr^.base:=getaddressreg;
  639. emit_reg_reg(A_MOVE,S_L,hregister,hr^.base);
  640. exprasmlist^.concat(new(pai68k,op_ref(A_JMP,S_NO,hr)));
  641. { if not(cs_littlesize in aktglobalswitches^ ) then
  642. datasegment^.concat(new(pai68k,op_const(A_ALIGN,S_NO,4))); }
  643. datasegment^.concat(new(pai_label,init(table)));
  644. last:=min_;
  645. genitem(hp);
  646. if hr^.base <> R_NO then ungetregister(hr^.base);
  647. { !!!!!!!
  648. if not(cs_littlesize in aktglobalswitches^ ) then
  649. exprasmlist^.concat(new(pai68k,op_const(A_ALIGN,S_NO,4)));
  650. }
  651. end;
  652. var
  653. lv,hv,min_label,max_label,labels : longint;
  654. max_linear_list : longint;
  655. begin
  656. getlabel(endlabel);
  657. getlabel(elselabel);
  658. with_sign:=is_signed(p^.left^.resulttype);
  659. if with_sign then
  660. begin
  661. jmp_gt:=A_BGT;
  662. jmp_le:=A_BLT;
  663. jmp_lee:=A_BLE;
  664. end
  665. else
  666. begin
  667. jmp_gt:=A_BHI;
  668. jmp_le:=A_BCS;
  669. jmp_lee:=A_BLS;
  670. end;
  671. cleartempgen;
  672. secondpass(p^.left);
  673. { determines the size of the operand }
  674. { determines the size of the operand }
  675. opsize:=bytes2Sxx[p^.left^.resulttype^.size];
  676. { copy the case expression to a register }
  677. { copy the case expression to a register }
  678. case p^.left^.location.loc of
  679. LOC_REGISTER,
  680. LOC_CREGISTER : hregister:=p^.left^.location.register;
  681. LOC_MEM,LOC_REFERENCE : begin
  682. del_reference(p^.left^.location.reference);
  683. hregister:=getregister32;
  684. exprasmlist^.concat(new(pai68k,op_ref_reg(A_MOVE,opsize,newreference(
  685. p^.left^.location.reference),hregister)));
  686. end;
  687. else internalerror(2002);
  688. end;
  689. { now generate the jumps }
  690. if cs_optimize in aktglobalswitches then
  691. begin
  692. { procedures are empirically passed on }
  693. { consumption can also be calculated }
  694. { but does it pay on the different }
  695. { processors? }
  696. { moreover can the size only be appro- }
  697. { ximated as it is not known if rel8, }
  698. { rel16 or rel32 jumps are used }
  699. min_label:=case_get_min(p^.nodes);
  700. max_label:=case_get_max(p^.nodes);
  701. labels:=case_count_labels(p^.nodes);
  702. { can we omit the range check of the jump table }
  703. getrange(p^.left^.resulttype,lv,hv);
  704. jumptable_no_range:=(lv=min_label) and (hv=max_label);
  705. { optimize for size ? }
  706. if cs_littlesize in aktglobalswitches then
  707. begin
  708. if (labels<=2) or ((max_label-min_label)>3*labels) then
  709. { a linear list is always smaller than a jump tree }
  710. genlinearlist(p^.nodes)
  711. else
  712. { if the labels less or more a continuum then }
  713. genjumptable(p^.nodes,min_label,max_label);
  714. end
  715. else
  716. begin
  717. if jumptable_no_range then
  718. max_linear_list:=4
  719. else
  720. max_linear_list:=2;
  721. if (labels<=max_linear_list) then
  722. genlinearlist(p^.nodes)
  723. else
  724. begin
  725. if ((max_label-min_label)>4*labels) then
  726. begin
  727. if labels>16 then
  728. gentreejmp(p^.nodes)
  729. else
  730. genlinearlist(p^.nodes);
  731. end
  732. else
  733. genjumptable(p^.nodes,min_label,max_label);
  734. end;
  735. end;
  736. end
  737. else
  738. { it's always not bad }
  739. genlinearlist(p^.nodes);
  740. { now generate the instructions }
  741. hp:=p^.right;
  742. while assigned(hp) do
  743. begin
  744. cleartempgen;
  745. secondpass(hp^.right);
  746. emitl(A_JMP,endlabel);
  747. hp:=hp^.left;
  748. end;
  749. emitl(A_LABEL,elselabel);
  750. { ... and the else block }
  751. if assigned(p^.elseblock) then
  752. begin
  753. cleartempgen;
  754. secondpass(p^.elseblock);
  755. end;
  756. emitl(A_LABEL,endlabel);
  757. end;
  758. end.
  759. {
  760. $Log$
  761. Revision 1.8 1998-12-11 00:03:08 peter
  762. + globtype,tokens,version unit splitted from globals
  763. Revision 1.7 1998/10/15 12:41:19 pierre
  764. * last memory leaks found when compiler
  765. a native atari compiler fixed
  766. Revision 1.6 1998/10/13 16:50:11 pierre
  767. * undid some changes of Peter that made the compiler wrong
  768. for m68k (I had to reinsert some ifdefs)
  769. * removed several memory leaks under m68k
  770. * removed the meory leaks for assembler readers
  771. * cross compiling shoud work again better
  772. ( crosscompiling sysamiga works
  773. but as68k still complain about some code !)
  774. Revision 1.5 1998/09/17 09:42:29 peter
  775. + pass_2 for cg386
  776. * Message() -> CGMessage() for pass_1/pass_2
  777. Revision 1.4 1998/09/14 10:44:03 peter
  778. * all internal RTL functions start with FPC_
  779. Revision 1.3 1998/09/07 18:45:59 peter
  780. * update smartlinking, uses getdatalabel
  781. * renamed ptree.value vars to value_str,value_real,value_set
  782. Revision 1.2 1998/09/04 08:41:49 peter
  783. * updated some error CGMessages
  784. Revision 1.1 1998/09/01 09:07:09 peter
  785. * m68k fixes, splitted cg68k like cgi386
  786. }