n386set.pas 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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 fpcdefs.inc}
  20. interface
  21. uses
  22. node,nset,pass_1,ncgset;
  23. type
  24. ti386innode = class(tinnode)
  25. procedure pass_2;override;
  26. function pass_1 : tnode;override;
  27. end;
  28. ti386casenode = class(tcgcasenode)
  29. procedure optimizevalues(var max_linear_list:longint;var max_dist:cardinal);override;
  30. function has_jumptable : boolean;override;
  31. procedure genjumptable(hp : pcaserecord;min_,max_ : longint);override;
  32. procedure genlinearlist(hp : pcaserecord);override;
  33. end;
  34. implementation
  35. uses
  36. globtype,systems,
  37. verbose,globals,
  38. symconst,symdef,defutil,
  39. aasmbase,aasmtai,aasmcpu,
  40. cginfo,cgbase,pass_2,
  41. ncon,
  42. cpubase,cpuinfo,
  43. cga,cgobj,tgobj,ncgutil,rgobj,
  44. cgx86;
  45. {*****************************************************************************
  46. TI386INNODE
  47. *****************************************************************************}
  48. function ti386innode.pass_1 : tnode;
  49. begin
  50. result:=nil;
  51. { this is the only difference from the generic version }
  52. expectloc:=LOC_FLAGS;
  53. firstpass(right);
  54. firstpass(left);
  55. if codegenerror then
  56. exit;
  57. left_right_max;
  58. { a smallset needs maybe an misc. register }
  59. if (left.nodetype<>ordconstn) and
  60. not(right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) and
  61. (right.registers32<1) then
  62. inc(registers32);
  63. end;
  64. procedure ti386innode.pass_2;
  65. type
  66. Tsetpart=record
  67. range : boolean; {Part is a range.}
  68. start,stop : byte; {Start/stop when range; Stop=element when an element.}
  69. end;
  70. var
  71. genjumps,
  72. use_small,
  73. ranges : boolean;
  74. hr,hr2,
  75. pleftreg : tregister;
  76. href : treference;
  77. opsize : topsize;
  78. setparts : array[1..8] of Tsetpart;
  79. i,numparts : byte;
  80. adjustment : longint;
  81. pushedregs : tmaybesave;
  82. l,l2 : tasmlabel;
  83. r : Tregister;
  84. {$ifdef CORRECT_SET_IN_FPC}
  85. AM : tasmop;
  86. {$endif CORRECT_SET_IN_FPC}
  87. function analizeset(Aset:pconstset;is_small:boolean):boolean;
  88. type
  89. byteset=set of byte;
  90. var
  91. compares,maxcompares:word;
  92. i:byte;
  93. begin
  94. if byteset(Aset^)=[] then
  95. {The expression...
  96. if expr in []
  97. ...is allways false. It should be optimized away in the
  98. resulttype pass, and thus never occur here. Since we
  99. do generate wrong code for it, do internalerror.}
  100. internalerror(2002072301);
  101. analizeset:=false;
  102. ranges:=false;
  103. numparts:=0;
  104. compares:=0;
  105. { Lots of comparisions take a lot of time, so do not allow
  106. too much comparisions. 8 comparisions are, however, still
  107. smalller than emitting the set }
  108. if cs_littlesize in aktglobalswitches then
  109. maxcompares:=8
  110. else
  111. maxcompares:=5;
  112. { when smallset is possible allow only 3 compares the smallset
  113. code is for littlesize also smaller when more compares are used }
  114. if is_small then
  115. maxcompares:=3;
  116. for i:=0 to 255 do
  117. if i in byteset(Aset^) then
  118. begin
  119. if (numparts=0) or (i<>setparts[numparts].stop+1) then
  120. begin
  121. {Set element is a separate element.}
  122. inc(compares);
  123. if compares>maxcompares then
  124. exit;
  125. inc(numparts);
  126. setparts[numparts].range:=false;
  127. setparts[numparts].stop:=i;
  128. end
  129. else
  130. {Set element is part of a range.}
  131. if not setparts[numparts].range then
  132. begin
  133. {Transform an element into a range.}
  134. setparts[numparts].range:=true;
  135. setparts[numparts].start:=setparts[numparts].stop;
  136. setparts[numparts].stop:=i;
  137. ranges := true;
  138. { there's only one compare per range anymore. Only a }
  139. { sub is added, but that's much faster than a }
  140. { cmp/jcc combo so neglect its effect }
  141. { inc(compares);
  142. if compares>maxcompares then
  143. exit; }
  144. end
  145. else
  146. begin
  147. {Extend a range.}
  148. setparts[numparts].stop:=i;
  149. end;
  150. end;
  151. analizeset:=true;
  152. end;
  153. begin
  154. { We check first if we can generate jumps, this can be done
  155. because the resulttype.def is already set in firstpass }
  156. { check if we can use smallset operation using btl which is limited
  157. to 32 bits, the left side may also not contain higher values !! }
  158. use_small:=(tsetdef(right.resulttype.def).settype=smallset) and
  159. ((left.resulttype.def.deftype=orddef) and (torddef(left.resulttype.def).high<=32) or
  160. (left.resulttype.def.deftype=enumdef) and (tenumdef(left.resulttype.def).max<=32));
  161. { Can we generate jumps? Possible for all types of sets }
  162. genjumps:=(right.nodetype=setconstn) and
  163. analizeset(tsetconstnode(right).value_set,use_small);
  164. { calculate both operators }
  165. { the complex one first }
  166. firstcomplex(self);
  167. secondpass(left);
  168. { Only process the right if we are not generating jumps }
  169. if not genjumps then
  170. begin
  171. {$ifndef newra}
  172. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  173. {$endif}
  174. secondpass(right);
  175. {$ifndef newra}
  176. maybe_restore(exprasmlist,left.location,pushedregs);
  177. {$endif newra}
  178. end;
  179. if codegenerror then
  180. exit;
  181. { ofcourse not commutative }
  182. if nf_swaped in flags then
  183. swapleftright;
  184. if genjumps then
  185. begin
  186. { It gives us advantage to check for the set elements
  187. separately instead of using the SET_IN_BYTE procedure.
  188. To do: Build in support for LOC_JUMP }
  189. opsize := def_opsize(left.resulttype.def);
  190. { If register is used, use only lower 8 bits }
  191. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  192. begin
  193. { for ranges we always need a 32bit register, because then we }
  194. { use the register as base in a reference (JM) }
  195. pleftreg.enum:=R_INTREGISTER;
  196. if ranges then
  197. begin
  198. pleftreg.number:=(left.location.register.number and not $ff) or R_SUBWHOLE;
  199. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_INT,left.location.register,pleftreg);
  200. if opsize <> S_L then
  201. emit_const_reg(A_AND,S_L,255,pleftreg);
  202. opsize := S_L;
  203. end
  204. else
  205. { otherwise simply use the lower 8 bits (no "and" }
  206. { necessary this way) (JM) }
  207. begin
  208. pleftreg.number:=(left.location.register.number and not $ff) or R_SUBL;
  209. opsize := S_B;
  210. end;
  211. end
  212. else
  213. begin
  214. { load the value in a register }
  215. {$ifdef newra}
  216. pleftreg:=rg.getregisterint(exprasmlist,OS_INT);
  217. {$else}
  218. pleftreg := rg.getexplicitregisterint(exprasmlist,NR_EDI);
  219. {$endif}
  220. opsize := S_L;
  221. emit_ref_reg(A_MOVZX,S_BL,left.location.reference,pleftreg);
  222. location_release(exprasmlist,left.location);
  223. end;
  224. { Get a label to jump to the end }
  225. location_reset(location,LOC_FLAGS,OS_NO);
  226. { It's better to use the zero flag when there are
  227. no ranges }
  228. if ranges then
  229. location.resflags:=F_C
  230. else
  231. location.resflags:=F_E;
  232. objectlibrary.getlabel(l);
  233. { how much have we already substracted from the x in the }
  234. { "x in [y..z]" expression }
  235. adjustment := 0;
  236. r.enum:=R_NO;
  237. for i:=1 to numparts do
  238. if setparts[i].range then
  239. { use fact that a <= x <= b <=> cardinal(x-a) <= cardinal(b-a) }
  240. begin
  241. { is the range different from all legal values? }
  242. if (setparts[i].stop-setparts[i].start <> 255) then
  243. begin
  244. { yes, is the lower bound <> 0? }
  245. if (setparts[i].start <> 0) then
  246. { we're going to substract from the left register, }
  247. { so in case of a LOC_CREGISTER first move the value }
  248. { to edi (not done before because now we can do the }
  249. { move and substract in one instruction with LEA) }
  250. if {$ifndef newra}(pleftreg.number <> NR_EDI) and{$endif}
  251. (left.location.loc = LOC_CREGISTER) then
  252. begin
  253. rg.ungetregister(exprasmlist,pleftreg);
  254. {$ifdef newra}
  255. r:=rg.getregisterint(exprasmlist,OS_INT);
  256. {$else}
  257. r.enum:=R_INTREGISTER;
  258. r.number:=NR_EDI;
  259. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  260. {$endif}
  261. reference_reset_base(href,pleftreg,-setparts[i].start);
  262. emit_ref_reg(A_LEA,S_L,href,r);
  263. { only now change pleftreg since previous value is }
  264. { still used in previous instruction }
  265. pleftreg := r;
  266. opsize := S_L;
  267. end
  268. else
  269. begin
  270. { otherwise, the value is already in a register }
  271. { that can be modified }
  272. if setparts[i].start-adjustment <> 1 then
  273. emit_const_reg(A_SUB,opsize,
  274. setparts[i].start-adjustment,pleftreg)
  275. else emit_reg(A_DEC,opsize,pleftreg);
  276. end;
  277. { new total value substracted from x: }
  278. { adjustment + (setparts[i].start - adjustment) }
  279. adjustment := setparts[i].start;
  280. { check if result < b-a+1 (not "result <= b-a", since }
  281. { we need a carry in case the element is in the range }
  282. { (this will never overflow since we check at the }
  283. { beginning whether stop-start <> 255) }
  284. emit_const_reg(A_CMP,opsize,
  285. setparts[i].stop-setparts[i].start+1,pleftreg);
  286. { use C_C instead of C_B: the meaning is the same, but }
  287. { then the optimizer can easier trace the jump to its }
  288. { final destination since the resultflag of this node }
  289. { is set to the carryflag }
  290. emitjmp(C_C,l);
  291. end
  292. else
  293. { if setparts[i].start = 0 and setparts[i].stop = 255, }
  294. { it's always true since "in" is only allowed for bytes }
  295. begin
  296. emit_none(A_STC,S_NO);
  297. cg.a_jmp_always(exprasmlist,l);
  298. end;
  299. end
  300. else
  301. begin
  302. { Emit code to check if left is an element }
  303. emit_const_reg(A_CMP,opsize,setparts[i].stop-adjustment,
  304. pleftreg);
  305. { Result should be in carry flag when ranges are used }
  306. if ranges then
  307. emit_none(A_STC,S_NO);
  308. { If found, jump to end }
  309. emitjmp(C_E,l);
  310. end;
  311. if ranges and
  312. { if the last one was a range, the carry flag is already }
  313. { set appropriately }
  314. not(setparts[numparts].range) then
  315. emit_none(A_CLC,S_NO);
  316. { To compensate for not doing a second pass }
  317. right.location.reference.symbol:=nil;
  318. { Now place the end label }
  319. cg.a_label(exprasmlist,l);
  320. {$ifdef newra}
  321. rg.ungetregisterint(exprasmlist,pleftreg);
  322. if r.enum=R_INTREGISTER then
  323. rg.ungetregisterint(exprasmlist,r);
  324. {$else}
  325. case left.location.loc of
  326. LOC_REGISTER,
  327. LOC_CREGISTER :
  328. rg.ungetregisterint(exprasmlist,pleftreg);
  329. else
  330. begin
  331. reference_release(exprasmlist,left.location.reference);
  332. r.enum:=R_INTREGISTER;
  333. r.number:=NR_EDI;
  334. rg.ungetregisterint(exprasmlist,r);
  335. end;
  336. end;
  337. {$endif}
  338. end
  339. else
  340. begin
  341. location_reset(location,LOC_FLAGS,OS_NO);
  342. { We will now generated code to check the set itself, no jmps,
  343. handle smallsets separate, because it allows faster checks }
  344. if use_small then
  345. begin
  346. if left.nodetype=ordconstn then
  347. begin
  348. location.resflags:=F_NE;
  349. case right.location.loc of
  350. LOC_REGISTER,
  351. LOC_CREGISTER:
  352. begin
  353. emit_const_reg(A_TEST,S_L,
  354. 1 shl (tordconstnode(left).value and 31),right.location.register);
  355. end;
  356. LOC_REFERENCE,
  357. LOC_CREFERENCE :
  358. begin
  359. emit_const_ref(A_TEST,S_L,1 shl (tordconstnode(left).value and 31),
  360. right.location.reference);
  361. end;
  362. else
  363. internalerror(200203312);
  364. end;
  365. location_release(exprasmlist,right.location);
  366. end
  367. else
  368. begin
  369. case left.location.loc of
  370. LOC_REGISTER,
  371. LOC_CREGISTER:
  372. begin
  373. hr:=rg.makeregsize(left.location.register,OS_INT);
  374. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_INT,left.location.register,hr);
  375. end;
  376. else
  377. begin
  378. { the set element isn't never samller than a byte }
  379. { and because it's a small set we need only 5 bits }
  380. { but 8 bits are easier to load }
  381. r.enum:=R_INTREGISTER;
  382. r.number:=NR_EDI;
  383. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  384. emit_ref_reg(A_MOVZX,S_BL,left.location.reference,r);
  385. hr:=r;
  386. location_release(exprasmlist,left.location);
  387. end;
  388. end;
  389. case right.location.loc of
  390. LOC_REGISTER,
  391. LOC_CREGISTER :
  392. begin
  393. emit_reg_reg(A_BT,S_L,hr,
  394. right.location.register);
  395. rg.ungetregisterint(exprasmlist,right.location.register);
  396. end;
  397. LOC_CONSTANT :
  398. begin
  399. { We have to load the value into a register because
  400. btl does not accept values only refs or regs (PFV) }
  401. hr2:=rg.getregisterint(exprasmlist,OS_INT);
  402. emit_const_reg(A_MOV,S_L,
  403. right.location.value,hr2);
  404. emit_reg_reg(A_BT,S_L,hr,hr2);
  405. rg.ungetregisterint(exprasmlist,hr2);
  406. end;
  407. LOC_CREFERENCE,
  408. LOC_REFERENCE :
  409. begin
  410. location_release(exprasmlist,right.location);
  411. emit_reg_ref(A_BT,S_L,hr,right.location.reference);
  412. end;
  413. else
  414. internalerror(2002032210);
  415. end;
  416. { simply to indicate EDI is deallocated here too (JM) }
  417. rg.ungetregisterint(exprasmlist,hr);
  418. location.resflags:=F_C;
  419. end;
  420. end
  421. else
  422. begin
  423. if right.location.loc=LOC_CONSTANT then
  424. begin
  425. location.resflags:=F_C;
  426. objectlibrary.getlabel(l);
  427. objectlibrary.getlabel(l2);
  428. { load constants to a register }
  429. if left.nodetype=ordconstn then
  430. location_force_reg(exprasmlist,left.location,OS_INT,true);
  431. case left.location.loc of
  432. LOC_REGISTER,
  433. LOC_CREGISTER:
  434. begin
  435. hr:=rg.makeregsize(left.location.register,OS_INT);
  436. cg.a_load_reg_reg(exprasmlist,left.location.size,OS_INT,left.location.register,hr);
  437. emit_const_reg(A_CMP,S_L,31,hr);
  438. emitjmp(C_NA,l);
  439. { reset carry flag }
  440. emit_none(A_CLC,S_NO);
  441. cg.a_jmp_always(exprasmlist,l2);
  442. cg.a_label(exprasmlist,l);
  443. { We have to load the value into a register because
  444. btl does not accept values only refs or regs (PFV) }
  445. hr2:=rg.getregisterint(exprasmlist,OS_INT);
  446. emit_const_reg(A_MOV,S_L,right.location.value,hr2);
  447. emit_reg_reg(A_BT,S_L,hr,hr2);
  448. rg.ungetregisterint(exprasmlist,hr2);
  449. end;
  450. else
  451. begin
  452. {$ifdef CORRECT_SET_IN_FPC}
  453. if m_tp in aktmodeswitches then
  454. begin
  455. {***WARNING only correct if
  456. reference is 32 bits (PM) *****}
  457. emit_const_ref(A_CMP,S_L,31,reference_copy(left.location.reference));
  458. end
  459. else
  460. {$endif CORRECT_SET_IN_FPC}
  461. begin
  462. emit_const_ref(A_CMP,S_B,31,left.location.reference);
  463. end;
  464. emitjmp(C_NA,l);
  465. { reset carry flag }
  466. emit_none(A_CLC,S_NO);
  467. cg.a_jmp_always(exprasmlist,l2);
  468. cg.a_label(exprasmlist,l);
  469. location_release(exprasmlist,left.location);
  470. hr:=rg.getregisterint(exprasmlist,OS_INT);
  471. emit_ref_reg(A_MOV,S_L,left.location.reference,hr);
  472. { We have to load the value into a register because
  473. btl does not accept values only refs or regs (PFV) }
  474. hr2:=rg.getregisterint(exprasmlist,OS_INT);
  475. emit_const_reg(A_MOV,S_L,
  476. right.location.value,hr2);
  477. emit_reg_reg(A_BT,S_L,hr,hr2);
  478. rg.ungetregisterint(exprasmlist,hr2);
  479. end;
  480. end;
  481. cg.a_label(exprasmlist,l2);
  482. end { of right.location.loc=LOC_CONSTANT }
  483. { do search in a normal set which could have >32 elementsm
  484. but also used if the left side contains higher values > 32 }
  485. else if left.nodetype=ordconstn then
  486. begin
  487. location.resflags:=F_NE;
  488. inc(right.location.reference.offset,tordconstnode(left).value shr 3);
  489. emit_const_ref(A_TEST,S_B,1 shl (tordconstnode(left).value and 7),right.location.reference);
  490. location_release(exprasmlist,right.location);
  491. end
  492. else
  493. begin
  494. if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  495. begin
  496. pleftreg.enum:=R_INTREGISTER;
  497. pleftreg.number:=(left.location.register.number and not $ff) or R_SUBWHOLE;
  498. end
  499. else
  500. {$ifdef newra}
  501. pleftreg:=rg.getregisterint(exprasmlist,OS_INT);
  502. {$else}
  503. pleftreg:=rg.getexplicitregisterint(exprasmlist,NR_EDI);
  504. {$endif}
  505. cg.a_load_loc_reg(exprasmlist,OS_INT,left.location,pleftreg);
  506. location_freetemp(exprasmlist,left.location);
  507. location_release(exprasmlist,left.location);
  508. emit_reg_ref(A_BT,S_L,pleftreg,right.location.reference);
  509. rg.ungetregisterint(exprasmlist,pleftreg);
  510. location_release(exprasmlist,right.location);
  511. { tg.ungetiftemp(exprasmlist,right.location.reference) happens below }
  512. location.resflags:=F_C;
  513. end;
  514. end;
  515. end;
  516. if not genjumps then
  517. location_freetemp(exprasmlist,right.location);
  518. end;
  519. {*****************************************************************************
  520. TI386CASENODE
  521. *****************************************************************************}
  522. procedure ti386casenode.optimizevalues(var max_linear_list:longint;var max_dist:cardinal);
  523. begin
  524. { a jump table crashes the pipeline! }
  525. if aktoptprocessor=Class386 then
  526. inc(max_linear_list,3)
  527. else if aktoptprocessor=ClassP5 then
  528. inc(max_linear_list,6)
  529. else if aktoptprocessor>=ClassP6 then
  530. inc(max_linear_list,9);
  531. end;
  532. function ti386casenode.has_jumptable : boolean;
  533. begin
  534. has_jumptable:=true;
  535. end;
  536. procedure ti386casenode.genjumptable(hp : pcaserecord;min_,max_ : longint);
  537. var
  538. table : tasmlabel;
  539. last : TConstExprInt;
  540. indexreg : tregister;
  541. href : treference;
  542. jumpsegment : TAAsmOutput;
  543. procedure genitem(t : pcaserecord);
  544. var
  545. i : longint;
  546. begin
  547. if assigned(t^.less) then
  548. genitem(t^.less);
  549. { fill possible hole }
  550. for i:=last+1 to t^._low-1 do
  551. jumpSegment.concat(Tai_const_symbol.Create(elselabel));
  552. for i:=t^._low to t^._high do
  553. jumpSegment.concat(Tai_const_symbol.Create(t^.statement));
  554. last:=t^._high;
  555. if assigned(t^.greater) then
  556. genitem(t^.greater);
  557. end;
  558. begin
  559. if (cs_create_smart in aktmoduleswitches) then
  560. jumpsegment:=current_procinfo.aktlocaldata
  561. else
  562. jumpsegment:=datasegment;
  563. if not(jumptable_no_range) then
  564. begin
  565. { case expr less than min_ => goto elselabel }
  566. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,aword(min_),hregister,elselabel);
  567. { case expr greater than max_ => goto elselabel }
  568. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_gt,aword(max_),hregister,elselabel);
  569. end;
  570. objectlibrary.getlabel(table);
  571. { make it a 32bit register }
  572. indexreg:=rg.makeregsize(hregister,OS_INT);
  573. cg.a_load_reg_reg(exprasmlist,opsize,OS_INT,hregister,indexreg);
  574. { create reference }
  575. reference_reset_symbol(href,table,0);
  576. href.offset:=(-longint(min_))*4;
  577. href.index:=indexreg;
  578. href.scalefactor:=4;
  579. emit_ref(A_JMP,S_NO,href);
  580. { generate jump table }
  581. if not(cs_littlesize in aktglobalswitches) then
  582. jumpSegment.concat(Tai_Align.Create_Op(4,0));
  583. jumpSegment.concat(Tai_label.Create(table));
  584. last:=min_;
  585. genitem(hp);
  586. end;
  587. procedure ti386casenode.genlinearlist(hp : pcaserecord);
  588. var
  589. first : boolean;
  590. lastrange : boolean;
  591. last : TConstExprInt;
  592. cond_lt,cond_le : tasmcond;
  593. procedure genitem(t : pcaserecord);
  594. begin
  595. if assigned(t^.less) then
  596. genitem(t^.less);
  597. { need we to test the first value }
  598. if first and (t^._low>get_min_value(left.resulttype.def)) then
  599. begin
  600. cg.a_cmp_const_reg_label(exprasmlist,opsize,jmp_lt,aword(t^._low),hregister,elselabel);
  601. end;
  602. if t^._low=t^._high then
  603. begin
  604. if t^._low-last=0 then
  605. cg.a_cmp_const_reg_label(exprasmlist, opsize, OC_EQ,0,hregister,t^.statement)
  606. else
  607. begin
  608. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, aword(t^._low-last), hregister);
  609. emitjmp(C_Z,t^.statement);
  610. end;
  611. last:=t^._low;
  612. lastrange:=false;
  613. end
  614. else
  615. begin
  616. { it begins with the smallest label, if the value }
  617. { is even smaller then jump immediately to the }
  618. { ELSE-label }
  619. if first then
  620. begin
  621. { have we to ajust the first value ? }
  622. if (t^._low>get_min_value(left.resulttype.def)) then
  623. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, longint(t^._low), hregister);
  624. end
  625. else
  626. begin
  627. { if there is no unused label between the last and the }
  628. { present label then the lower limit can be checked }
  629. { immediately. else check the range in between: }
  630. cg.a_op_const_reg(exprasmlist, OP_SUB, opsize, longint(t^._low-last), hregister);
  631. { no jump necessary here if the new range starts at }
  632. { at the value following the previous one }
  633. if ((t^._low-last) <> 1) or
  634. (not lastrange) then
  635. emitjmp(cond_lt,elselabel);
  636. end;
  637. {we need to use A_SUB, because A_DEC does not set the correct flags, therefor
  638. using a_op_const_reg(OP_SUB) is not possible }
  639. emit_const_reg(A_SUB,TCGSize2OpSize[opsize],longint(t^._high-t^._low),hregister);
  640. emitjmp(cond_le,t^.statement);
  641. last:=t^._high;
  642. lastrange:=true;
  643. end;
  644. first:=false;
  645. if assigned(t^.greater) then
  646. genitem(t^.greater);
  647. end;
  648. begin
  649. if with_sign then
  650. begin
  651. cond_lt:=C_L;
  652. cond_le:=C_LE;
  653. end
  654. else
  655. begin
  656. cond_lt:=C_B;
  657. cond_le:=C_BE;
  658. end;
  659. { do we need to generate cmps? }
  660. if (with_sign and (min_label<0)) then
  661. genlinearcmplist(hp)
  662. else
  663. begin
  664. last:=0;
  665. lastrange:=false;
  666. first:=true;
  667. genitem(hp);
  668. cg.a_jmp_always(exprasmlist,elselabel);
  669. end;
  670. end;
  671. begin
  672. {$ifndef TEST_GENERIC}
  673. cinnode:=ti386innode;
  674. {$endif}
  675. ccasenode:=ti386casenode;
  676. end.
  677. {
  678. $Log$
  679. Revision 1.62 2003-06-12 22:10:44 jonas
  680. * t386innode.pass_2 already doesn't call a helper anymore since a long
  681. time
  682. Revision 1.61 2003/06/03 21:11:09 peter
  683. * cg.a_load_* get a from and to size specifier
  684. * makeregsize only accepts newregister
  685. * i386 uses generic tcgnotnode,tcgunaryminus
  686. Revision 1.60 2003/06/01 21:38:06 peter
  687. * getregisterfpu size parameter added
  688. * op_const_reg size parameter added
  689. * sparc updates
  690. Revision 1.59 2003/05/31 15:04:31 peter
  691. * load_loc_reg update
  692. Revision 1.58 2003/05/22 21:32:29 peter
  693. * removed some unit dependencies
  694. Revision 1.57 2003/04/27 11:21:35 peter
  695. * aktprocdef renamed to current_procdef
  696. * procinfo renamed to current_procinfo
  697. * procinfo will now be stored in current_module so it can be
  698. cleaned up properly
  699. * gen_main_procsym changed to create_main_proc and release_main_proc
  700. to also generate a tprocinfo structure
  701. * fixed unit implicit initfinal
  702. Revision 1.56 2003/04/25 08:25:26 daniel
  703. * Ifdefs around a lot of calls to cleartempgen
  704. * Fixed registers that are allocated but not freed in several nodes
  705. * Tweak to register allocator to cause less spills
  706. * 8-bit registers now interfere with esi,edi and ebp
  707. Compiler can now compile rtl successfully when using new register
  708. allocator
  709. Revision 1.55 2003/04/23 09:51:16 daniel
  710. * Removed usage of edi in a lot of places when new register allocator used
  711. + Added newra versions of g_concatcopy and secondadd_float
  712. Revision 1.54 2003/04/22 23:50:23 peter
  713. * firstpass uses expectloc
  714. * checks if there are differences between the expectloc and
  715. location.loc from secondpass in EXTDEBUG
  716. Revision 1.53 2003/04/22 14:33:38 peter
  717. * removed some notes/hints
  718. Revision 1.52 2003/04/22 10:09:35 daniel
  719. + Implemented the actual register allocator
  720. + Scratch registers unavailable when new register allocator used
  721. + maybe_save/maybe_restore unavailable when new register allocator used
  722. Revision 1.51 2003/03/13 19:52:23 jonas
  723. * and more new register allocator fixes (in the i386 code generator this
  724. time). At least now the ppc cross compiler can compile the linux
  725. system unit again, but I haven't tested it.
  726. Revision 1.50 2003/02/26 23:06:13 daniel
  727. * Fixed an illegal use of makeregsize
  728. Revision 1.49 2003/02/19 22:39:56 daniel
  729. * Fixed a few issues
  730. Revision 1.48 2003/02/19 22:00:15 daniel
  731. * Code generator converted to new register notation
  732. - Horribily outdated todo.txt removed
  733. Revision 1.47 2003/01/13 14:54:34 daniel
  734. * Further work to convert codegenerator register convention;
  735. internalerror bug fixed.
  736. Revision 1.46 2003/01/08 18:43:57 daniel
  737. * Tregister changed into a record
  738. Revision 1.45 2002/11/25 17:43:27 peter
  739. * splitted defbase in defutil,symutil,defcmp
  740. * merged isconvertable and is_equal into compare_defs(_ext)
  741. * made operator search faster by walking the list only once
  742. Revision 1.44 2002/10/03 21:34:45 carl
  743. * range check error fixes
  744. Revision 1.43 2002/09/17 18:54:05 jonas
  745. * a_load_reg_reg() now has two size parameters: source and dest. This
  746. allows some optimizations on architectures that don't encode the
  747. register size in the register name.
  748. Revision 1.42 2002/09/16 18:08:26 peter
  749. * fix last optimization in genlinearlist, detected by bug tw1066
  750. * use generic casenode.pass2 routine and override genlinearlist
  751. * add jumptable support to generic casenode, by default there is
  752. no jumptable support
  753. Revision 1.41 2002/09/09 13:57:45 jonas
  754. * small optimization to case genlist() case statements
  755. Revision 1.40 2002/08/17 09:23:46 florian
  756. * first part of procinfo rewrite
  757. Revision 1.39 2002/08/12 15:08:42 carl
  758. + stab register indexes for powerpc (moved from gdb to cpubase)
  759. + tprocessor enumeration moved to cpuinfo
  760. + linker in target_info is now a class
  761. * many many updates for m68k (will soon start to compile)
  762. - removed some ifdef or correct them for correct cpu
  763. Revision 1.38 2002/08/11 14:32:30 peter
  764. * renamed current_library to objectlibrary
  765. Revision 1.37 2002/08/11 13:24:17 peter
  766. * saving of asmsymbols in ppu supported
  767. * asmsymbollist global is removed and moved into a new class
  768. tasmlibrarydata that will hold the info of a .a file which
  769. corresponds with a single module. Added librarydata to tmodule
  770. to keep the library info stored for the module. In the future the
  771. objectfiles will also be stored to the tasmlibrarydata class
  772. * all getlabel/newasmsymbol and friends are moved to the new class
  773. Revision 1.36 2002/07/23 14:31:00 daniel
  774. * Added internal error when asked to generate code for 'if expr in []'
  775. Revision 1.35 2002/07/20 11:58:04 florian
  776. * types.pas renamed to defbase.pas because D6 contains a types
  777. unit so this would conflicts if D6 programms are compiled
  778. + Willamette/SSE2 instructions to assembler added
  779. Revision 1.34 2002/07/11 14:41:34 florian
  780. * start of the new generic parameter handling
  781. Revision 1.33 2002/07/06 20:27:26 carl
  782. + generic set handling
  783. Revision 1.32 2002/07/01 18:46:33 peter
  784. * internal linker
  785. * reorganized aasm layer
  786. Revision 1.31 2002/05/18 13:34:25 peter
  787. * readded missing revisions
  788. Revision 1.30 2002/05/16 19:46:52 carl
  789. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  790. + try to fix temp allocation (still in ifdef)
  791. + generic constructor calls
  792. + start of tassembler / tmodulebase class cleanup
  793. Revision 1.28 2002/05/13 19:54:38 peter
  794. * removed n386ld and n386util units
  795. * maybe_save/maybe_restore added instead of the old maybe_push
  796. Revision 1.27 2002/05/12 16:53:17 peter
  797. * moved entry and exitcode to ncgutil and cgobj
  798. * foreach gets extra argument for passing local data to the
  799. iterator function
  800. * -CR checks also class typecasts at runtime by changing them
  801. into as
  802. * fixed compiler to cycle with the -CR option
  803. * fixed stabs with elf writer, finally the global variables can
  804. be watched
  805. * removed a lot of routines from cga unit and replaced them by
  806. calls to cgobj
  807. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  808. u32bit then the other is typecasted also to u32bit without giving
  809. a rangecheck warning/error.
  810. * fixed pascal calling method with reversing also the high tree in
  811. the parast, detected by tcalcst3 test
  812. Revision 1.26 2002/04/25 20:16:40 peter
  813. * moved more routines from cga/n386util
  814. Revision 1.25 2002/04/21 19:02:07 peter
  815. * removed newn and disposen nodes, the code is now directly
  816. inlined from pexpr
  817. * -an option that will write the secondpass nodes to the .s file, this
  818. requires EXTDEBUG define to actually write the info
  819. * fixed various internal errors and crashes due recent code changes
  820. Revision 1.24 2002/04/21 15:37:26 carl
  821. * changeregsize -> rg.makeregsize
  822. Revision 1.23 2002/04/19 15:39:35 peter
  823. * removed some more routines from cga
  824. * moved location_force_reg/mem to ncgutil
  825. * moved arrayconstructnode secondpass to ncgld
  826. Revision 1.22 2002/04/15 19:44:21 peter
  827. * fixed stackcheck that would be called recursively when a stack
  828. error was found
  829. * generic changeregsize(reg,size) for i386 register resizing
  830. * removed some more routines from cga unit
  831. * fixed returnvalue handling
  832. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  833. Revision 1.21 2002/04/02 17:11:36 peter
  834. * tlocation,treference update
  835. * LOC_CONSTANT added for better constant handling
  836. * secondadd splitted in multiple routines
  837. * location_force_reg added for loading a location to a register
  838. of a specified size
  839. * secondassignment parses now first the right and then the left node
  840. (this is compatible with Kylix). This saves a lot of push/pop especially
  841. with string operations
  842. * adapted some routines to use the new cg methods
  843. Revision 1.20 2002/03/31 20:26:39 jonas
  844. + a_loadfpu_* and a_loadmm_* methods in tcg
  845. * register allocation is now handled by a class and is mostly processor
  846. independent (+rgobj.pas and i386/rgcpu.pas)
  847. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  848. * some small improvements and fixes to the optimizer
  849. * some register allocation fixes
  850. * some fpuvaroffset fixes in the unary minus node
  851. * push/popusedregisters is now called rg.save/restoreusedregisters and
  852. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  853. also better optimizable)
  854. * fixed and optimized register saving/restoring for new/dispose nodes
  855. * LOC_FPU locations now also require their "register" field to be set to
  856. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  857. - list field removed of the tnode class because it's not used currently
  858. and can cause hard-to-find bugs
  859. }