n386set.pas 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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;
  23. type
  24. ti386setelementnode = class(tsetelementnode)
  25. procedure pass_2;override;
  26. end;
  27. ti386innode = class(tinnode)
  28. procedure pass_2;override;
  29. end;
  30. ti386casenode = class(tcasenode)
  31. procedure pass_2;override;
  32. end;
  33. implementation
  34. uses
  35. globtype,systems,
  36. verbose,globals,
  37. symconst,symdef,aasm,types,
  38. cginfo,cgbase,pass_2,
  39. ncon,
  40. cpubase,
  41. cga,cgobj,tgobj,ncgutil,regvars,rgobj;
  42. const
  43. bytes2Sxx:array[1..8] of Topsize=(S_B,S_W,S_NO,S_L,S_NO,S_NO,S_NO,S_Q);
  44. {*****************************************************************************
  45. TI386SETELEMENTNODE
  46. *****************************************************************************}
  47. procedure ti386setelementnode.pass_2;
  48. var
  49. pushedregs : tmaybesave;
  50. begin
  51. { load first value in 32bit register }
  52. secondpass(left);
  53. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  54. location_force_reg(exprasmlist,left.location,OS_32,false);
  55. { also a second value ? }
  56. if assigned(right) then
  57. begin
  58. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  59. secondpass(right);
  60. if codegenerror then
  61. exit;
  62. maybe_restore(exprasmlist,left.location,pushedregs);
  63. if right.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  64. location_force_reg(exprasmlist,right.location,OS_32,false);
  65. end;
  66. { we doesn't modify the left side, we check only the type }
  67. location_copy(location,left.location);
  68. end;
  69. {*****************************************************************************
  70. TI386INNODE
  71. *****************************************************************************}
  72. procedure ti386innode.pass_2;
  73. type
  74. Tsetpart=record
  75. range : boolean; {Part is a range.}
  76. start,stop : byte; {Start/stop when range; Stop=element when an element.}
  77. end;
  78. var
  79. genjumps,
  80. use_small,
  81. ranges : boolean;
  82. hr,hr2,
  83. pleftreg : tregister;
  84. href : treference;
  85. opsize : topsize;
  86. setparts : array[1..8] of Tsetpart;
  87. i,numparts : byte;
  88. adjustment : longint;
  89. pushedregs : tmaybesave;
  90. l,l2 : tasmlabel;
  91. {$ifdef CORRECT_SET_IN_FPC}
  92. AM : tasmop;
  93. {$endif CORRECT_SET_IN_FPC}
  94. function analizeset(Aset:pconstset;is_small:boolean):boolean;
  95. type
  96. byteset=set of byte;
  97. var
  98. compares,maxcompares:word;
  99. i:byte;
  100. begin
  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. maybe_save(exprasmlist,right.registers32,left.location,pushedregs);
  172. secondpass(right);
  173. maybe_restore(exprasmlist,left.location,pushedregs);
  174. end;
  175. if codegenerror then
  176. exit;
  177. { ofcourse not commutative }
  178. if nf_swaped in flags then
  179. swapleftright;
  180. if genjumps then
  181. begin
  182. { It gives us advantage to check for the set elements
  183. separately instead of using the SET_IN_BYTE procedure.
  184. To do: Build in support for LOC_JUMP }
  185. opsize := def_opsize(left.resulttype.def);
  186. { If register is used, use only lower 8 bits }
  187. if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  188. begin
  189. { for ranges we always need a 32bit register, because then we }
  190. { use the register as base in a reference (JM) }
  191. if ranges then
  192. begin
  193. pleftreg:=rg.makeregsize(left.location.register,OS_INT);
  194. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,pleftreg);
  195. if opsize <> S_L then
  196. emit_const_reg(A_AND,S_L,255,pleftreg);
  197. opsize := S_L;
  198. end
  199. else
  200. { otherwise simply use the lower 8 bits (no "and" }
  201. { necessary this way) (JM) }
  202. begin
  203. pleftreg:=rg.makeregsize(left.location.register,OS_8);
  204. opsize := S_B;
  205. end;
  206. end
  207. else
  208. begin
  209. { load the value in a register }
  210. pleftreg := rg.getexplicitregisterint(exprasmlist,R_EDI);
  211. opsize := S_L;
  212. emit_ref_reg(A_MOVZX,S_BL,left.location.reference,pleftreg);
  213. end;
  214. { Get a label to jump to the end }
  215. location_reset(location,LOC_FLAGS,OS_NO);
  216. { It's better to use the zero flag when there are
  217. no ranges }
  218. if ranges then
  219. location.resflags:=F_C
  220. else
  221. location.resflags:=F_E;
  222. getlabel(l);
  223. { how much have we already substracted from the x in the }
  224. { "x in [y..z]" expression }
  225. adjustment := 0;
  226. for i:=1 to numparts do
  227. if setparts[i].range then
  228. { use fact that a <= x <= b <=> cardinal(x-a) <= cardinal(b-a) }
  229. begin
  230. { is the range different from all legal values? }
  231. if (setparts[i].stop-setparts[i].start <> 255) then
  232. begin
  233. { yes, is the lower bound <> 0? }
  234. if (setparts[i].start <> 0) then
  235. { we're going to substract from the left register, }
  236. { so in case of a LOC_CREGISTER first move the value }
  237. { to edi (not done before because now we can do the }
  238. { move and substract in one instruction with LEA) }
  239. if (pleftreg <> R_EDI) and
  240. (left.location.loc = LOC_CREGISTER) then
  241. begin
  242. rg.ungetregister(exprasmlist,pleftreg);
  243. rg.getexplicitregisterint(exprasmlist,R_EDI);
  244. reference_reset_base(href,pleftreg,-setparts[i].start);
  245. emit_ref_reg(A_LEA,S_L,href,R_EDI);
  246. { only now change pleftreg since previous value is }
  247. { still used in previous instruction }
  248. pleftreg := R_EDI;
  249. opsize := S_L;
  250. end
  251. else
  252. begin
  253. { otherwise, the value is already in a register }
  254. { that can be modified }
  255. if setparts[i].start-adjustment <> 1 then
  256. emit_const_reg(A_SUB,opsize,
  257. setparts[i].start-adjustment,pleftreg)
  258. else emit_reg(A_DEC,opsize,pleftreg);
  259. end;
  260. { new total value substracted from x: }
  261. { adjustment + (setparts[i].start - adjustment) }
  262. adjustment := setparts[i].start;
  263. { check if result < b-a+1 (not "result <= b-a", since }
  264. { we need a carry in case the element is in the range }
  265. { (this will never overflow since we check at the }
  266. { beginning whether stop-start <> 255) }
  267. emit_const_reg(A_CMP,opsize,
  268. setparts[i].stop-setparts[i].start+1,pleftreg);
  269. { use C_C instead of C_B: the meaning is the same, but }
  270. { then the optimizer can easier trace the jump to its }
  271. { final destination since the resultflag of this node }
  272. { is set to the carryflag }
  273. emitjmp(C_C,l);
  274. end
  275. else
  276. { if setparts[i].start = 0 and setparts[i].stop = 255, }
  277. { it's always true since "in" is only allowed for bytes }
  278. begin
  279. emit_none(A_STC,S_NO);
  280. cg.a_jmp_always(exprasmlist,l);
  281. end;
  282. end
  283. else
  284. begin
  285. { Emit code to check if left is an element }
  286. emit_const_reg(A_CMP,opsize,setparts[i].stop-adjustment,
  287. pleftreg);
  288. { Result should be in carry flag when ranges are used }
  289. if ranges then
  290. emit_none(A_STC,S_NO);
  291. { If found, jump to end }
  292. emitjmp(C_E,l);
  293. end;
  294. if ranges and
  295. { if the last one was a range, the carry flag is already }
  296. { set appropriately }
  297. not(setparts[numparts].range) then
  298. emit_none(A_CLC,S_NO);
  299. { To compensate for not doing a second pass }
  300. right.location.reference.symbol:=nil;
  301. { Now place the end label }
  302. cg.a_label(exprasmlist,l);
  303. case left.location.loc of
  304. LOC_REGISTER,
  305. LOC_CREGISTER :
  306. rg.ungetregister(exprasmlist,pleftreg);
  307. else
  308. begin
  309. reference_release(exprasmlist,left.location.reference);
  310. rg.ungetregister(exprasmlist,R_EDI);
  311. end;
  312. end;
  313. end
  314. else
  315. begin
  316. location_reset(location,LOC_FLAGS,OS_NO);
  317. { We will now generated code to check the set itself, no jmps,
  318. handle smallsets separate, because it allows faster checks }
  319. if use_small then
  320. begin
  321. if left.nodetype=ordconstn then
  322. begin
  323. location.resflags:=F_NE;
  324. case right.location.loc of
  325. LOC_REGISTER,
  326. LOC_CREGISTER:
  327. begin
  328. emit_const_reg(A_TEST,S_L,
  329. 1 shl (tordconstnode(left).value and 31),right.location.register);
  330. end;
  331. LOC_REFERENCE,
  332. LOC_CREFERENCE :
  333. begin
  334. emit_const_ref(A_TEST,S_L,1 shl (tordconstnode(left).value and 31),
  335. right.location.reference);
  336. end;
  337. else
  338. internalerror(200203312);
  339. end;
  340. location_release(exprasmlist,right.location);
  341. end
  342. else
  343. begin
  344. case left.location.loc of
  345. LOC_REGISTER,
  346. LOC_CREGISTER:
  347. begin
  348. hr:=rg.makeregsize(left.location.register,OS_INT);
  349. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,hr);
  350. end;
  351. else
  352. begin
  353. { the set element isn't never samller than a byte }
  354. { and because it's a small set we need only 5 bits }
  355. { but 8 bits are easier to load }
  356. rg.getexplicitregisterint(exprasmlist,R_EDI);
  357. emit_ref_reg(A_MOVZX,S_BL,left.location.reference,R_EDI);
  358. hr:=R_EDI;
  359. location_release(exprasmlist,left.location);
  360. end;
  361. end;
  362. case right.location.loc of
  363. LOC_REGISTER,
  364. LOC_CREGISTER :
  365. begin
  366. emit_reg_reg(A_BT,S_L,hr,
  367. right.location.register);
  368. rg.ungetregisterint(exprasmlist,right.location.register);
  369. end;
  370. LOC_CONSTANT :
  371. begin
  372. { We have to load the value into a register because
  373. btl does not accept values only refs or regs (PFV) }
  374. hr2:=rg.getregisterint(exprasmlist);
  375. emit_const_reg(A_MOV,S_L,
  376. right.location.value,hr2);
  377. emit_reg_reg(A_BT,S_L,hr,hr2);
  378. rg.ungetregisterint(exprasmlist,hr2);
  379. end;
  380. LOC_CREFERENCE,
  381. LOC_REFERENCE :
  382. begin
  383. location_release(exprasmlist,right.location);
  384. emit_reg_ref(A_BT,S_L,hr,right.location.reference);
  385. end;
  386. else
  387. internalerror(2002032210);
  388. end;
  389. { simply to indicate EDI is deallocated here too (JM) }
  390. rg.ungetregisterint(exprasmlist,hr);
  391. location.loc:=LOC_FLAGS;
  392. location.resflags:=F_C;
  393. end;
  394. end
  395. else
  396. begin
  397. if right.location.loc=LOC_CONSTANT then
  398. begin
  399. location.resflags:=F_C;
  400. getlabel(l);
  401. getlabel(l2);
  402. { Is this treated in firstpass ?? }
  403. if left.nodetype=ordconstn then
  404. begin
  405. hr:=rg.getregisterint(exprasmlist);
  406. left.location.loc:=LOC_REGISTER;
  407. left.location.register:=hr;
  408. emit_const_reg(A_MOV,S_L,
  409. tordconstnode(left).value,hr);
  410. end;
  411. case left.location.loc of
  412. LOC_REGISTER,
  413. LOC_CREGISTER:
  414. begin
  415. hr:=rg.makeregsize(left.location.register,OS_INT);
  416. cg.a_load_reg_reg(exprasmlist,left.location.size,left.location.register,hr);
  417. emit_const_reg(A_CMP,S_L,31,hr);
  418. emitjmp(C_NA,l);
  419. { reset carry flag }
  420. emit_none(A_CLC,S_NO);
  421. cg.a_jmp_always(exprasmlist,l2);
  422. cg.a_label(exprasmlist,l);
  423. { We have to load the value into a register because
  424. btl does not accept values only refs or regs (PFV) }
  425. hr2:=rg.getregisterint(exprasmlist);
  426. emit_const_reg(A_MOV,S_L,right.location.value,hr2);
  427. emit_reg_reg(A_BT,S_L,hr,hr2);
  428. rg.ungetregisterint(exprasmlist,hr2);
  429. end;
  430. else
  431. begin
  432. {$ifdef CORRECT_SET_IN_FPC}
  433. if m_tp in aktmodeswitches then
  434. begin
  435. {***WARNING only correct if
  436. reference is 32 bits (PM) *****}
  437. emit_const_ref(A_CMP,S_L,31,reference_copy(left.location.reference));
  438. end
  439. else
  440. {$endif CORRECT_SET_IN_FPC}
  441. begin
  442. emit_const_ref(A_CMP,S_B,31,left.location.reference);
  443. end;
  444. emitjmp(C_NA,l);
  445. { reset carry flag }
  446. emit_none(A_CLC,S_NO);
  447. cg.a_jmp_always(exprasmlist,l2);
  448. cg.a_label(exprasmlist,l);
  449. location_release(exprasmlist,left.location);
  450. hr:=rg.getregisterint(exprasmlist);
  451. emit_ref_reg(A_MOV,S_L,left.location.reference,hr);
  452. { We have to load the value into a register because
  453. btl does not accept values only refs or regs (PFV) }
  454. hr2:=rg.getregisterint(exprasmlist);
  455. emit_const_reg(A_MOV,S_L,
  456. right.location.value,hr2);
  457. emit_reg_reg(A_BT,S_L,hr,hr2);
  458. rg.ungetregisterint(exprasmlist,hr2);
  459. end;
  460. end;
  461. cg.a_label(exprasmlist,l2);
  462. end { of right.location.loc=LOC_CONSTANT }
  463. { do search in a normal set which could have >32 elementsm
  464. but also used if the left side contains higher values > 32 }
  465. else if left.nodetype=ordconstn then
  466. begin
  467. location.resflags:=F_NE;
  468. inc(right.location.reference.offset,tordconstnode(left).value shr 3);
  469. emit_const_ref(A_TEST,S_B,1 shl (tordconstnode(left).value and 7),right.location.reference);
  470. location_release(exprasmlist,right.location);
  471. end
  472. else
  473. begin
  474. if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  475. pleftreg:=rg.makeregsize(left.location.register,OS_INT)
  476. else
  477. pleftreg:=rg.getexplicitregisterint(exprasmlist,R_EDI);
  478. cg.a_load_loc_reg(exprasmlist,left.location,pleftreg);
  479. location_freetemp(exprasmlist,left.location);
  480. location_release(exprasmlist,left.location);
  481. emit_reg_ref(A_BT,S_L,pleftreg,right.location.reference);
  482. rg.ungetregister(exprasmlist,pleftreg);
  483. location_release(exprasmlist,right.location);
  484. { tg.ungetiftemp(exprasmlist,right.location.reference) happens below }
  485. location.resflags:=F_C;
  486. end;
  487. end;
  488. end;
  489. location_freetemp(exprasmlist,right.location);
  490. end;
  491. {*****************************************************************************
  492. TI386CASENODE
  493. *****************************************************************************}
  494. procedure ti386casenode.pass_2;
  495. var
  496. with_sign : boolean;
  497. opsize : topsize;
  498. jmp_gt,jmp_le,jmp_lee : tasmcond;
  499. hp : tnode;
  500. { register with case expression }
  501. hregister,hregister2 : tregister;
  502. endlabel,elselabel : tasmlabel;
  503. { true, if we can omit the range check of the jump table }
  504. jumptable_no_range : boolean;
  505. { where to put the jump table }
  506. jumpsegment : TAAsmoutput;
  507. min_label : TConstExprInt;
  508. procedure gentreejmp(p : pcaserecord);
  509. var
  510. lesslabel,greaterlabel : tasmlabel;
  511. begin
  512. cg.a_label(exprasmlist,p^._at);
  513. { calculate labels for left and right }
  514. if (p^.less=nil) then
  515. lesslabel:=elselabel
  516. else
  517. lesslabel:=p^.less^._at;
  518. if (p^.greater=nil) then
  519. greaterlabel:=elselabel
  520. else
  521. greaterlabel:=p^.greater^._at;
  522. { calculate labels for left and right }
  523. { no range label: }
  524. if p^._low=p^._high then
  525. begin
  526. emit_const_reg(A_CMP,opsize,p^._low,hregister);
  527. if greaterlabel=lesslabel then
  528. emitjmp(C_NE,lesslabel)
  529. else
  530. begin
  531. emitjmp(jmp_le,lesslabel);
  532. emitjmp(jmp_gt,greaterlabel);
  533. end;
  534. cg.a_jmp_always(exprasmlist,p^.statement);
  535. end
  536. else
  537. begin
  538. emit_const_reg(A_CMP,opsize,p^._low,hregister);
  539. emitjmp(jmp_le,lesslabel);
  540. emit_const_reg(A_CMP,opsize,p^._high,hregister);
  541. emitjmp(jmp_gt,greaterlabel);
  542. cg.a_jmp_always(exprasmlist,p^.statement);
  543. end;
  544. if assigned(p^.less) then
  545. gentreejmp(p^.less);
  546. if assigned(p^.greater) then
  547. gentreejmp(p^.greater);
  548. end;
  549. procedure genlinearcmplist(hp : pcaserecord);
  550. var
  551. first : boolean;
  552. last : TConstExprInt;
  553. procedure genitem(t : pcaserecord);
  554. var
  555. l1 : tasmlabel;
  556. begin
  557. if assigned(t^.less) then
  558. genitem(t^.less);
  559. if t^._low=t^._high then
  560. begin
  561. if opsize=S_Q then
  562. begin
  563. getlabel(l1);
  564. emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._low))),hregister2);
  565. emitjmp(C_NZ,l1);
  566. emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._low))),hregister);
  567. emitjmp(C_Z,t^.statement);
  568. cg.a_label(exprasmlist,l1);
  569. end
  570. else
  571. begin
  572. emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
  573. emitjmp(C_Z,t^.statement);
  574. last:=t^._low;
  575. end;
  576. end
  577. else
  578. begin
  579. { if there is no unused label between the last and the }
  580. { present label then the lower limit can be checked }
  581. { immediately. else check the range in between: }
  582. if first or (t^._low-last>1) then
  583. begin
  584. if opsize=S_Q then
  585. begin
  586. getlabel(l1);
  587. emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._low))),hregister2);
  588. emitjmp(jmp_le,elselabel);
  589. emitjmp(jmp_gt,l1);
  590. emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._low))),hregister);
  591. { the comparisation of the low dword must be always unsigned! }
  592. emitjmp(C_B,elselabel);
  593. cg.a_label(exprasmlist,l1);
  594. end
  595. else
  596. begin
  597. emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
  598. emitjmp(jmp_le,elselabel);
  599. end;
  600. end;
  601. if opsize=S_Q then
  602. begin
  603. getlabel(l1);
  604. emit_const_reg(A_CMP,S_L,longint(hi(int64(t^._high))),hregister2);
  605. emitjmp(jmp_le,t^.statement);
  606. emitjmp(jmp_gt,l1);
  607. emit_const_reg(A_CMP,S_L,longint(lo(int64(t^._high))),hregister);
  608. { the comparisation of the low dword must be always unsigned! }
  609. emitjmp(C_BE,t^.statement);
  610. cg.a_label(exprasmlist,l1);
  611. end
  612. else
  613. begin
  614. emit_const_reg(A_CMP,opsize,longint(t^._high),hregister);
  615. emitjmp(jmp_lee,t^.statement);
  616. end;
  617. last:=t^._high;
  618. end;
  619. first:=false;
  620. if assigned(t^.greater) then
  621. genitem(t^.greater);
  622. end;
  623. begin
  624. last:=0;
  625. first:=true;
  626. genitem(hp);
  627. cg.a_jmp_always(exprasmlist,elselabel);
  628. end;
  629. procedure genlinearlist(hp : pcaserecord);
  630. var
  631. first : boolean;
  632. last : TConstExprInt;
  633. {helplabel : longint;}
  634. procedure genitem(t : pcaserecord);
  635. procedure gensub(value:longint);
  636. begin
  637. if value=1 then
  638. emit_reg(A_DEC,opsize,hregister)
  639. else
  640. emit_const_reg(A_SUB,opsize,value,hregister);
  641. end;
  642. begin
  643. if assigned(t^.less) then
  644. genitem(t^.less);
  645. { need we to test the first value }
  646. if first and (t^._low>get_min_value(left.resulttype.def)) then
  647. begin
  648. emit_const_reg(A_CMP,opsize,longint(t^._low),hregister);
  649. emitjmp(jmp_le,elselabel);
  650. end;
  651. if t^._low=t^._high then
  652. begin
  653. if t^._low-last=0 then
  654. emit_reg_reg(A_OR,opsize,hregister,hregister)
  655. else
  656. gensub(longint(t^._low-last));
  657. last:=t^._low;
  658. emitjmp(C_Z,t^.statement);
  659. end
  660. else
  661. begin
  662. { it begins with the smallest label, if the value }
  663. { is even smaller then jump immediately to the }
  664. { ELSE-label }
  665. if first then
  666. begin
  667. { have we to ajust the first value ? }
  668. if (t^._low>get_min_value(left.resulttype.def)) then
  669. gensub(longint(t^._low));
  670. end
  671. else
  672. begin
  673. { if there is no unused label between the last and the }
  674. { present label then the lower limit can be checked }
  675. { immediately. else check the range in between: }
  676. { note: you can't use gensub() here because dec doesn't }
  677. { change the carry flag (needed for jmp_lxx) (JM) }
  678. emit_const_reg(A_SUB,opsize,longint(t^._low-last),hregister);
  679. emitjmp(jmp_le,elselabel);
  680. end;
  681. emit_const_reg(A_SUB,opsize,longint(t^._high-t^._low),hregister);
  682. emitjmp(jmp_lee,t^.statement);
  683. last:=t^._high;
  684. end;
  685. first:=false;
  686. if assigned(t^.greater) then
  687. genitem(t^.greater);
  688. end;
  689. begin
  690. { do we need to generate cmps? }
  691. if (with_sign and (min_label<0)) then
  692. genlinearcmplist(hp)
  693. else
  694. begin
  695. last:=0;
  696. first:=true;
  697. genitem(hp);
  698. cg.a_jmp_always(exprasmlist,elselabel);
  699. end;
  700. end;
  701. procedure genjumptable(hp : pcaserecord;min_,max_ : longint);
  702. var
  703. table : tasmlabel;
  704. last : TConstExprInt;
  705. href : treference;
  706. procedure genitem(t : pcaserecord);
  707. var
  708. i : longint;
  709. begin
  710. if assigned(t^.less) then
  711. genitem(t^.less);
  712. { fill possible hole }
  713. for i:=last+1 to t^._low-1 do
  714. jumpSegment.concat(Tai_const_symbol.Create(elselabel));
  715. for i:=t^._low to t^._high do
  716. jumpSegment.concat(Tai_const_symbol.Create(t^.statement));
  717. last:=t^._high;
  718. if assigned(t^.greater) then
  719. genitem(t^.greater);
  720. end;
  721. begin
  722. if not(jumptable_no_range) then
  723. begin
  724. emit_const_reg(A_CMP,opsize,longint(min_),hregister);
  725. { case expr less than min_ => goto elselabel }
  726. emitjmp(jmp_le,elselabel);
  727. emit_const_reg(A_CMP,opsize,longint(max_),hregister);
  728. emitjmp(jmp_gt,elselabel);
  729. end;
  730. getlabel(table);
  731. { extend with sign }
  732. if opsize=S_W then
  733. begin
  734. if with_sign then
  735. emit_reg_reg(A_MOVSX,S_WL,hregister,
  736. rg.makeregsize(hregister,OS_INT))
  737. else
  738. emit_reg_reg(A_MOVZX,S_WL,hregister,
  739. rg.makeregsize(hregister,OS_INT));
  740. hregister:=rg.makeregsize(hregister,OS_INT);
  741. end
  742. else if opsize=S_B then
  743. begin
  744. if with_sign then
  745. emit_reg_reg(A_MOVSX,S_BL,hregister,
  746. rg.makeregsize(hregister,OS_INT))
  747. else
  748. emit_reg_reg(A_MOVZX,S_BL,hregister,
  749. rg.makeregsize(hregister,OS_INT));
  750. hregister:=rg.makeregsize(hregister,OS_INT);
  751. end;
  752. reference_reset_symbol(href,table,0);
  753. href.offset:=(-longint(min_))*4;
  754. href.index:=hregister;
  755. href.scalefactor:=4;
  756. emit_ref(A_JMP,S_NO,href);
  757. { !!!!! generate tables
  758. if not(cs_littlesize in aktlocalswitches) then
  759. jumpSegment.concat(Taicpu.Op_const(A_ALIGN,S_NO,4));
  760. }
  761. jumpSegment.concat(Tai_label.Create(table));
  762. last:=min_;
  763. genitem(hp);
  764. { !!!!!!!
  765. if not(cs_littlesize in aktlocalswitches) then
  766. emit_const(A_ALIGN,S_NO,4);
  767. }
  768. end;
  769. var
  770. lv,hv,
  771. max_label: tconstexprint;
  772. labels : longint;
  773. max_linear_list : longint;
  774. otl, ofl: tasmlabel;
  775. isjump : boolean;
  776. {$ifdef Delphi}
  777. dist : cardinal;
  778. {$else Delphi}
  779. dist : dword;
  780. {$endif Delphi}
  781. begin
  782. getlabel(endlabel);
  783. getlabel(elselabel);
  784. if (cs_create_smart in aktmoduleswitches) then
  785. jumpsegment:=procinfo^.aktlocaldata
  786. else
  787. jumpsegment:=datasegment;
  788. with_sign:=is_signed(left.resulttype.def);
  789. if with_sign then
  790. begin
  791. jmp_gt:=C_G;
  792. jmp_le:=C_L;
  793. jmp_lee:=C_LE;
  794. end
  795. else
  796. begin
  797. jmp_gt:=C_A;
  798. jmp_le:=C_B;
  799. jmp_lee:=C_BE;
  800. end;
  801. rg.cleartempgen;
  802. { save current truelabel and falselabel }
  803. isjump:=false;
  804. if left.location.loc=LOC_JUMP then
  805. begin
  806. otl:=truelabel;
  807. getlabel(truelabel);
  808. ofl:=falselabel;
  809. getlabel(falselabel);
  810. isjump:=true;
  811. end;
  812. secondpass(left);
  813. { determines the size of the operand }
  814. opsize:=bytes2Sxx[left.resulttype.def.size];
  815. { copy the case expression to a register }
  816. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  817. if opsize=S_Q then
  818. begin
  819. hregister:=left.location.registerlow;
  820. hregister2:=left.location.registerhigh;
  821. end
  822. else
  823. hregister:=left.location.register;
  824. if isjump then
  825. begin
  826. truelabel:=otl;
  827. falselabel:=ofl;
  828. end;
  829. { we need the min_label always to choose between }
  830. { cmps and subs/decs }
  831. min_label:=case_get_min(nodes);
  832. load_all_regvars(exprasmlist);
  833. { now generate the jumps }
  834. if opsize=S_Q then
  835. genlinearcmplist(nodes)
  836. else
  837. begin
  838. if cs_optimize in aktglobalswitches then
  839. begin
  840. { procedures are empirically passed on }
  841. { consumption can also be calculated }
  842. { but does it pay on the different }
  843. { processors? }
  844. { moreover can the size only be appro- }
  845. { ximated as it is not known if rel8, }
  846. { rel16 or rel32 jumps are used }
  847. max_label:=case_get_max(nodes);
  848. labels:=case_count_labels(nodes);
  849. { can we omit the range check of the jump table ? }
  850. getrange(left.resulttype.def,lv,hv);
  851. jumptable_no_range:=(lv=min_label) and (hv=max_label);
  852. { hack a little bit, because the range can be greater }
  853. { than the positive range of a longint }
  854. if (min_label<0) and (max_label>0) then
  855. begin
  856. {$ifdef Delphi}
  857. if min_label=longint($80000000) then
  858. dist:=Cardinal(max_label)+Cardinal($80000000)
  859. else
  860. dist:=Cardinal(max_label)+Cardinal(-min_label)
  861. {$else Delphi}
  862. if min_label=$80000000 then
  863. dist:=dword(max_label)+dword($80000000)
  864. else
  865. dist:=dword(max_label)+dword(-min_label)
  866. {$endif Delphi}
  867. end
  868. else
  869. dist:=max_label-min_label;
  870. { optimize for size ? }
  871. if cs_littlesize in aktglobalswitches then
  872. begin
  873. if (labels<=2) or
  874. ((max_label-min_label)<0) or
  875. ((max_label-min_label)>3*labels) then
  876. { a linear list is always smaller than a jump tree }
  877. genlinearlist(nodes)
  878. else
  879. { if the labels less or more a continuum then }
  880. genjumptable(nodes,min_label,max_label);
  881. end
  882. else
  883. begin
  884. if jumptable_no_range then
  885. max_linear_list:=4
  886. else
  887. max_linear_list:=2;
  888. { a jump table crashes the pipeline! }
  889. if aktoptprocessor=Class386 then
  890. inc(max_linear_list,3);
  891. if aktoptprocessor=ClassP5 then
  892. inc(max_linear_list,6);
  893. if aktoptprocessor>=ClassP6 then
  894. inc(max_linear_list,9);
  895. if (labels<=max_linear_list) then
  896. genlinearlist(nodes)
  897. else
  898. begin
  899. if (dist>4*cardinal(labels)) then
  900. begin
  901. if labels>16 then
  902. gentreejmp(nodes)
  903. else
  904. genlinearlist(nodes);
  905. end
  906. else
  907. genjumptable(nodes,min_label,max_label);
  908. end;
  909. end;
  910. end
  911. else
  912. { it's always not bad }
  913. genlinearlist(nodes);
  914. end;
  915. rg.ungetregister(exprasmlist,hregister);
  916. { now generate the instructions }
  917. hp:=right;
  918. while assigned(hp) do
  919. begin
  920. rg.cleartempgen;
  921. secondpass(tbinarynode(hp).right);
  922. { don't come back to case line }
  923. aktfilepos:=exprasmList.getlasttaifilepos^;
  924. load_all_regvars(exprasmlist);
  925. cg.a_jmp_always(exprasmlist,endlabel);
  926. hp:=tbinarynode(hp).left;
  927. end;
  928. cg.a_label(exprasmlist,elselabel);
  929. { ...and the else block }
  930. if assigned(elseblock) then
  931. begin
  932. rg.cleartempgen;
  933. secondpass(elseblock);
  934. load_all_regvars(exprasmlist);
  935. end;
  936. cg.a_label(exprasmlist,endlabel);
  937. end;
  938. begin
  939. csetelementnode:=ti386setelementnode;
  940. cinnode:=ti386innode;
  941. ccasenode:=ti386casenode;
  942. end.
  943. {
  944. $Log$
  945. Revision 1.31 2002-05-18 13:34:25 peter
  946. * readded missing revisions
  947. Revision 1.30 2002/05/16 19:46:52 carl
  948. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  949. + try to fix temp allocation (still in ifdef)
  950. + generic constructor calls
  951. + start of tassembler / tmodulebase class cleanup
  952. Revision 1.28 2002/05/13 19:54:38 peter
  953. * removed n386ld and n386util units
  954. * maybe_save/maybe_restore added instead of the old maybe_push
  955. Revision 1.27 2002/05/12 16:53:17 peter
  956. * moved entry and exitcode to ncgutil and cgobj
  957. * foreach gets extra argument for passing local data to the
  958. iterator function
  959. * -CR checks also class typecasts at runtime by changing them
  960. into as
  961. * fixed compiler to cycle with the -CR option
  962. * fixed stabs with elf writer, finally the global variables can
  963. be watched
  964. * removed a lot of routines from cga unit and replaced them by
  965. calls to cgobj
  966. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  967. u32bit then the other is typecasted also to u32bit without giving
  968. a rangecheck warning/error.
  969. * fixed pascal calling method with reversing also the high tree in
  970. the parast, detected by tcalcst3 test
  971. Revision 1.26 2002/04/25 20:16:40 peter
  972. * moved more routines from cga/n386util
  973. Revision 1.25 2002/04/21 19:02:07 peter
  974. * removed newn and disposen nodes, the code is now directly
  975. inlined from pexpr
  976. * -an option that will write the secondpass nodes to the .s file, this
  977. requires EXTDEBUG define to actually write the info
  978. * fixed various internal errors and crashes due recent code changes
  979. Revision 1.24 2002/04/21 15:37:26 carl
  980. * changeregsize -> rg.makeregsize
  981. Revision 1.23 2002/04/19 15:39:35 peter
  982. * removed some more routines from cga
  983. * moved location_force_reg/mem to ncgutil
  984. * moved arrayconstructnode secondpass to ncgld
  985. Revision 1.22 2002/04/15 19:44:21 peter
  986. * fixed stackcheck that would be called recursively when a stack
  987. error was found
  988. * generic changeregsize(reg,size) for i386 register resizing
  989. * removed some more routines from cga unit
  990. * fixed returnvalue handling
  991. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  992. Revision 1.21 2002/04/02 17:11:36 peter
  993. * tlocation,treference update
  994. * LOC_CONSTANT added for better constant handling
  995. * secondadd splitted in multiple routines
  996. * location_force_reg added for loading a location to a register
  997. of a specified size
  998. * secondassignment parses now first the right and then the left node
  999. (this is compatible with Kylix). This saves a lot of push/pop especially
  1000. with string operations
  1001. * adapted some routines to use the new cg methods
  1002. Revision 1.20 2002/03/31 20:26:39 jonas
  1003. + a_loadfpu_* and a_loadmm_* methods in tcg
  1004. * register allocation is now handled by a class and is mostly processor
  1005. independent (+rgobj.pas and i386/rgcpu.pas)
  1006. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  1007. * some small improvements and fixes to the optimizer
  1008. * some register allocation fixes
  1009. * some fpuvaroffset fixes in the unary minus node
  1010. * push/popusedregisters is now called rg.save/restoreusedregisters and
  1011. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  1012. also better optimizable)
  1013. * fixed and optimized register saving/restoring for new/dispose nodes
  1014. * LOC_FPU locations now also require their "register" field to be set to
  1015. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  1016. - list field removed of the tnode class because it's not used currently
  1017. and can cause hard-to-find bugs
  1018. }