set.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Jonas Maebe, member of the
  5. Free Pascal development team
  6. Include file with set operations called by the compiler
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  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.
  12. **********************************************************************}
  13. procedure do_load_small(p : pointer;l:longint);assembler;[public,alias:'FPC_SET_LOAD_SMALL'];
  14. {
  15. load a normal set p from a smallset l
  16. on entry: p in r3, l in r4
  17. }
  18. asm
  19. stw r4,(r3)
  20. li r4,0
  21. stw r4,4(r3)
  22. stw r4,8(r3)
  23. stw r4,12(r3)
  24. stw r4,16(r3)
  25. stw r4,20(r3)
  26. stw r4,24(r3)
  27. stw r4,28(r3)
  28. end ['R4'];
  29. procedure do_create_element(p : pointer;b : byte);assembler;[public,alias:'FPC_SET_CREATE_ELEMENT'];
  30. {
  31. create a new set in p from an element b
  32. on entry: p in r3, b in r4
  33. }
  34. var
  35. saveR5, saveR6: longint;
  36. asm
  37. stw r5,saveR5
  38. li r5,0
  39. stw r6,saveR6
  40. stw r5,(r3)
  41. stw r5,4(r3)
  42. li r6,1
  43. stw r5,8(r3)
  44. stw r5,12(r3)
  45. stw r5,16(r3)
  46. stw r5,20(r3)
  47. // r6 := 1 shl r4[27-31] -> bit index in dword (shift instructions
  48. // with count in register only consider lower 5 bits of this register)
  49. slw r6,r6,r4
  50. stw r5,24(r3)
  51. stw r5,28(r3)
  52. // get the index of the correct *dword* in the set
  53. // (((b div 8) div 4)*4= (b div 8) and not(3))
  54. // r5 := (r4 rotl(32-3)) and (0x0fffffff8)
  55. rlwinm r5,r4,29,0,31-2
  56. // store the result
  57. stwx r6,r3,r5
  58. lwz r5,saveR5
  59. lwz r6,saveR6
  60. end ['R4'];
  61. procedure do_set_byte(p : pointer;b : byte);assembler;[public,alias:'FPC_SET_SET_BYTE'];
  62. {
  63. add the element b to the set pointed by p
  64. on entry: p in r3, b in r4
  65. }
  66. var
  67. saveR5, saveR6: longint;
  68. asm
  69. stw r5,saveR5
  70. stw r6,saveR6
  71. // get the index of the correct *dword* in the set
  72. rlwinm r5,r4,29,0,31-2 // r5 := (r4 rotl(32-3)) and (0x0fffffff8)
  73. // load dword in which the bit has to be set (and update r3 to this address)
  74. lwzxu r6,r3,r5
  75. li r5,1
  76. // generate bit which has to be inserted
  77. slw r4,r5,r4
  78. // insert it
  79. lwz r5,saveR5
  80. or r4,r7,r4
  81. lwz r6,saveR6
  82. // store result
  83. stw r4,(r3)
  84. end ['R3','R4'];
  85. procedure do_unset_byte(p : pointer;b : byte);assembler;[public,alias:'FPC_SET_UNSET_BYTE'];
  86. {
  87. suppresses the element b to the set pointed by p
  88. used for exclude(set,element)
  89. on entry: p in r3, b in r4
  90. }
  91. var
  92. saveR5, saveR6: longint;
  93. asm
  94. stw r5,saveR5
  95. stw r6,saveR6
  96. // get the index of the correct *dword* in the set
  97. rlwinm r5,r4,29,0,31-2 // r5 := (r4 rotl(32-3)) and (0x0fffffff8)
  98. // load dword in which the bit is (and update r3 to this address)
  99. lwzxu r6,r3,r5
  100. li r5,1
  101. // generate bit which has to be cleared
  102. slw r4,r5,r4
  103. lwz r5,saveR5
  104. // remove it
  105. andc r4,r6,r4
  106. lwz r6,saveR6
  107. // store result
  108. stw r4,(r3)
  109. end ['R3','R4'];
  110. procedure do_set_range(p : pointer;l,h : byte);assembler;[public,alias:'FPC_SET_SET_RANGE'];
  111. {
  112. on entry: p in r3, l in r4, h in r5
  113. }
  114. var
  115. saveR6, saveR7, saveR8: longint;
  116. asm
  117. cmplw cr0,r4,r5
  118. bg cr0,.LSET_RANGE_EXIT
  119. stw r6,saveR6
  120. stw r7,saveR7
  121. stw r8,saveR8
  122. rlwinm r6,r4,32-3,0,31-2 // divide by 8 to get starting and ending byte-
  123. { load the set the data cache }
  124. dcbt r3,r6
  125. rlwinm r7,r5,32-3,0,31-2 // address and clear two lowest bits to get
  126. // start/end longint address
  127. sub. r7,r6,r7 // are bit lo and hi in the same longint?
  128. rlwinm r5,r5,0,31-4,31 // hi := hi mod 32 (= "hi and 31", but the andi
  129. // instr. only exists in flags modifying form)
  130. eqv r8,r8,r8 // r8 = $0x0ffffffff = bitmask to be inserted
  131. subfic r5,r5,31 // hi := 31 - (hi mod 32) = shift count for later
  132. srw r8,r8,r4 // shift bitmask to clear bits below lo
  133. // note: shift right = opposite little endian!!
  134. lwzxu r4,r3,r6 // go to starting pos in set and load value
  135. // (lo is not necessary anymore)
  136. beq .Lset_range_hi // if bit lo and hi in same longint, keep
  137. // current mask and adjust for hi bit
  138. subic. r7,r7,4 // bit hi in next longint?
  139. or r4,r4,r8 // merge and
  140. stw r4,(r3) // store current mask
  141. eqv r8,r8,r8 // new mask
  142. lwzu r4,4(r3) // load next longint of set
  143. beq .Lset_range_hi // bit hi in this longint -> go to adjust for hi
  144. .Lset_range_loop:
  145. subic. r7,r7,4
  146. stwu r8,4(r3) // fill longints in between with full mask
  147. bne .Lset_range_loop
  148. lwzu r4,4(r3) // load next value from set
  149. .Lset_range_hi: // in all cases, r3 here contains the address of
  150. // the longint which contains the hi bit and r4
  151. // contains this longint
  152. slw r7,r8,r5 // r7 := bitmask shl (31 - (hi mod 32)) =
  153. // bitmask with bits higher than hi cleared
  154. // (r8 = $0xffffffff unless the first beq was
  155. // taken)
  156. and r8,r7,r8 // combine lo and hi bitmasks for this longint
  157. or r4,r4,r8 // and combine with existing set
  158. stw r4,(r3) // store to set
  159. lwz r6,saver6
  160. lwz r7,saver7
  161. lwz r8,saver8
  162. .Lset_range_exit:
  163. end ['R3','R4','R5'];
  164. procedure do_in_byte(p : pointer;b : byte);assembler;[public,alias:'FPC_SET_IN_BYTE'];
  165. {
  166. tests if the element b is in the set p, the **zero** flag is cleared if it's present
  167. on entry: p in r3, b in r4
  168. }
  169. var
  170. saveR5: longint;
  171. asm
  172. stw r5,saveR5
  173. // get the index of the correct *dword* in the set
  174. // r5 := (r4 rotl(32-3)) and (0x0fffffff8)
  175. rlwinm r5,r4,29,0,31-2
  176. // load dword in which the bit has to be tested
  177. lwzx r3,r3,r5
  178. li r5,1
  179. // generate bit which has to be tested
  180. slw r4,r5,r4
  181. lwz r5,saveR5
  182. // test it
  183. and. r3,r3,r4
  184. end ['R4'];
  185. procedure do_add_sets(set1,set2,dest : pointer);assembler;[public,alias:'FPC_SET_ADD_SETS'];
  186. {
  187. adds set1 and set2 into set dest
  188. on entry: set1 in r3, set2 in r4, dest in r5
  189. }
  190. var
  191. saveR6, saveR7, saveR8: longint;
  192. asm
  193. { load the begin of the first set in the data cache }
  194. dcbt r0,r3
  195. stw r6,saveR6
  196. stw r7,saveR7
  197. subi r5,r5,4
  198. li r6,8
  199. stw r8,saveR8
  200. subi r3,4
  201. subi r4,4
  202. .LMADDSETS1:
  203. subic. r6,r6,1
  204. lwzu r7,4(r3)
  205. lwzu r8,4(r4)
  206. or r7,r7,r8
  207. stwu r7,4(r5)
  208. bne cr0,.LMADDSETS1
  209. lwz r6,saveR6
  210. lwz r7,saveR7
  211. lwz r8,saveR8
  212. end ['R3','R4','R5'];
  213. procedure do_mul_sets(set1,set2,dest:pointer);assembler;[public,alias:'FPC_SET_MUL_SETS'];
  214. {
  215. multiplies (takes common elements of) set1 and set2 result put in dest
  216. on entry: set1 in r3, set2 in r4, dest in r5
  217. }
  218. var
  219. saveR6, saveR7, saveR8: longint;
  220. asm
  221. { load the begin of the first set in the data cache }
  222. dcbt r0,r3
  223. stw r6,saveR6
  224. stw r7,saveR7
  225. subi r5,r5,4
  226. li r6,8
  227. stw r8,saveR8
  228. subi r3,4
  229. subi r4,4
  230. .LMADDSETS1:
  231. subic. r6,r6,1
  232. lwzu r7,4(r3)
  233. lwzu r8,4(r4)
  234. and r7,r7,r8
  235. stwu r7,4(r5)
  236. bne cr0,.LMADDSETS1
  237. lwz r6,saveR6
  238. lwz r7,saveR7
  239. lwz r8,saveR8
  240. end ['R3','R4','R5'];
  241. procedure do_sub_sets(set1,set2,dest:pointer);assembler;[public,alias:'FPC_SET_SUB_SETS'];
  242. {
  243. computes the diff from set1 to set2 result in dest
  244. on entry: set1 in r3, set2 in r4, dest in r5
  245. }
  246. var
  247. saveR6, saveR7, saveR8: longint;
  248. asm
  249. { load the begin of the first set in the data cache }
  250. dcbt r0,r3
  251. stw r6,saveR6
  252. stw r7,saveR7
  253. subi r5,r5,4
  254. li r6,8
  255. stw r8,saveR8
  256. subi r3,4
  257. subi r4,4
  258. .LMSUBSETS1:
  259. subi. r6,r6,1
  260. lwzu r8,4(r4)
  261. lwzu r7,4(r3)
  262. andc r8,r8,r7
  263. stwu r8,4(r5)
  264. bne cr0,.LMSUBSETS1
  265. lwz r6,saveR6
  266. lwz r7,saveR7
  267. lwz r8,saveR8
  268. end ['R3','R4','R5'];
  269. procedure do_symdif_sets(set1,set2,dest:pointer);assembler;[public,alias:'FPC_SET_SYMDIF_SETS'];
  270. {
  271. computes the symetric diff from set1 to set2 result in dest
  272. on entry: set1 in r3, set2 in r4, dest in r5
  273. }
  274. var
  275. saveR6, saveR7, saveR8: longint;
  276. asm
  277. { load the begin of the first set in the data cache }
  278. dcbt r0,r3
  279. stw r6,saveR6
  280. stw r7,saveR7
  281. subi r5,r5,4
  282. li r6,8
  283. stw r8,saveR8
  284. subi r3,4
  285. subi r4,4
  286. .LMSYMDIFSETS1:
  287. subi. r6,r6,1
  288. lwzu r7,4(r3)
  289. lwzu r8,4(r4)
  290. xor r7,r7,r8
  291. stwu r7,4(r5)
  292. bne cr0,.LMSYMDIFSETS1
  293. lwz r6,saveR6
  294. lwz r7,saveR7
  295. lwz r8,saveR8
  296. end ['R3','R4','R5'];
  297. procedure do_comp_sets(set1,set2 : pointer);assembler;[public,alias:'FPC_SET_COMP_SETS'];
  298. {
  299. compares set1 and set2 zeroflag is set if they are equal
  300. on entry: set1 in r3, set2 in r4
  301. }
  302. var
  303. saveR5, saveR6, saveR7: longint;
  304. asm
  305. { load the begin of the first set in the data cache }
  306. dcbt r0,r3
  307. stw r5,saveR5
  308. mfctr r5
  309. stw r6,saveR6
  310. li r6,8
  311. stw r7,saveR7
  312. mtctr r6
  313. subi r3,4
  314. subi r4,4
  315. .LMCOMPSETS1:
  316. lwzu r6,4(r3)
  317. lwzu r7,4(r4)
  318. cmplw cr0,r6,r7
  319. bdnzt cr0*4+eq,.LMCOMPSETS1
  320. mtctr r5
  321. lwz r5,saveR5
  322. lwz r6,saveR6
  323. lwz r7,saveR7
  324. end ['R3','R4'];
  325. {$IfNDef NoSetInclusion}
  326. procedure do_contains_sets(set1,set2 : pointer);assembler;[public,alias:'FPC_SET_CONTAINS_SETS'];
  327. {
  328. on exit, zero flag is set if set1 <= set2 (set2 contains set1)
  329. on entry: set1 in r3, set2 in r4
  330. }
  331. var
  332. saveR5, saveR6, saveR7: longint;
  333. asm
  334. { load the begin of the first set in the data cache }
  335. dcbt r0,r3
  336. stw r5,saveR5
  337. mfctr r5
  338. stw r6,saveR6
  339. li r6,8
  340. stw r7,saveR7
  341. mtctr r6
  342. subi r3,4
  343. subi r4,4
  344. .LMCOMPSETS1:
  345. lwzu r7,4(r4)
  346. lwzu r6,4(r3)
  347. andc. r7,r6,r7
  348. bdnzt cr0*4+eq,.LMCOMPSETS1
  349. mtctr r5
  350. lwz r5,saveR5
  351. lwz r6,saveR6
  352. lwz r7,saveR7
  353. end ['R3','R4'];
  354. {$EndIf SetInclusion}
  355. {$ifdef LARGESETS}
  356. procedure do_set(p : pointer;b : word);assembler;[public,alias:'FPC_SET_SET_WORD'];
  357. {
  358. sets the element b in set p works for sets larger than 256 elements
  359. not yet use by the compiler so
  360. }
  361. asm
  362. pushl %eax
  363. movl p,%edi
  364. movw b,%ax
  365. andl $0xfff8,%eax
  366. shrl $3,%eax
  367. addl %eax,%edi
  368. movb 12(%ebp),%al
  369. andl $7,%eax
  370. btsl %eax,(%edi)
  371. popl %eax
  372. end;
  373. procedure do_in(p : pointer;b : word);assembler;[public,alias:'FPC_SET_IN_WORD'];
  374. {
  375. tests if the element b is in the set p the carryflag is set if it present
  376. works for sets larger than 256 elements
  377. }
  378. asm
  379. pushl %eax
  380. movl p,%edi
  381. movw b,%ax
  382. andl $0xfff8,%eax
  383. shrl $3,%eax
  384. addl %eax,%edi
  385. movb 12(%ebp),%al
  386. andl $7,%eax
  387. btl %eax,(%edi)
  388. popl %eax
  389. end;
  390. procedure add_sets(set1,set2,dest : pointer;size : longint);assembler;[public,alias:'FPC_SET_ADD_SETS_SIZE'];
  391. {
  392. adds set1 and set2 into set dest size is the number of bytes in the set
  393. }
  394. asm
  395. movl set1,%esi
  396. movl set2,%ebx
  397. movl dest,%edi
  398. movl size,%ecx
  399. .LMADDSETSIZES1:
  400. lodsl
  401. orl (%ebx),%eax
  402. stosl
  403. addl $4,%ebx
  404. decl %ecx
  405. jnz .LMADDSETSIZES1
  406. end;
  407. procedure mul_sets(set1,set2,dest : pointer;size : longint);assembler;[public,alias:'FPC_SET_MUL_SETS_SIZE'];
  408. {
  409. multiplies (i.E. takes common elements of) set1 and set2 result put in
  410. dest size is the number of bytes in the set
  411. }
  412. asm
  413. movl set1,%esi
  414. movl set2,%ebx
  415. movl dest,%edi
  416. movl size,%ecx
  417. .LMMULSETSIZES1:
  418. lodsl
  419. andl (%ebx),%eax
  420. stosl
  421. addl $4,%ebx
  422. decl %ecx
  423. jnz .LMMULSETSIZES1
  424. end;
  425. procedure sub_sets(set1,set2,dest : pointer;size : longint);assembler;[public,alias:'FPC_SET_SUB_SETS_SIZE'];
  426. asm
  427. movl set1,%esi
  428. movl set2,%ebx
  429. movl dest,%edi
  430. movl size,%ecx
  431. .LMSUBSETSIZES1:
  432. lodsl
  433. movl (%ebx),%edx
  434. notl %edx
  435. andl %edx,%eax
  436. stosl
  437. addl $4,%ebx
  438. decl %ecx
  439. jnz .LMSUBSETSIZES1
  440. end;
  441. procedure sym_sub_sets(set1,set2,dest : pointer;size : longint);assembler;[public,alias:'FPC_SET_SYMDIF_SETS_SIZE'];
  442. {
  443. computes the symetric diff from set1 to set2 result in dest
  444. }
  445. asm
  446. movl set1,%esi
  447. movl set2,%ebx
  448. movl dest,%edi
  449. movl size,%ecx
  450. .LMSYMDIFSETSIZE1:
  451. lodsl
  452. movl (%ebx),%edx
  453. xorl %edx,%eax
  454. stosl
  455. addl $4,%ebx
  456. decl %ecx
  457. jnz .LMSYMDIFSETSIZE1
  458. end;
  459. procedure comp_sets(set1,set2 : pointer;size : longint);assembler;[public,alias:'FPC_SET_COMP_SETS_SIZE'];
  460. asm
  461. movl set1,%esi
  462. movl set2,%edi
  463. movl size,%ecx
  464. .LMCOMPSETSIZES1:
  465. lodsl
  466. movl (%edi),%edx
  467. cmpl %edx,%eax
  468. jne .LMCOMPSETSIZEEND
  469. addl $4,%edi
  470. decl %ecx
  471. jnz .LMCOMPSETSIZES1
  472. { we are here only if the two sets are equal
  473. we have zero flag set, and that what is expected }
  474. .LMCOMPSETSIZEEND:
  475. end;
  476. {$IfNDef NoSetInclusion}
  477. procedure contains_sets(set1,set2 : pointer; size: longint);assembler;[public,alias:'FPC_SET_CONTAINS_SETS'];
  478. {
  479. on exit, zero flag is set if set1 <= set2 (set2 contains set1)
  480. }
  481. asm
  482. movl set1,%esi
  483. movl set2,%edi
  484. movl size,%ecx
  485. .LMCONTAINSSETS2:
  486. movl (%esi),%eax
  487. movl (%edi),%edx
  488. andl %eax,%edx
  489. cmpl %edx,%eax {set1 and set2 = set1?}
  490. jne .LMCONTAINSSETEND2
  491. addl $4,%esi
  492. addl $4,%edi
  493. decl %ecx
  494. jnz .LMCONTAINSSETS2
  495. { we are here only if set2 contains set1
  496. we have zero flag set, and that what is expected }
  497. .LMCONTAINSSETEND2:
  498. end;
  499. {$EndIf NoSetInclusion}
  500. {$endif LARGESET}
  501. {
  502. $Log$
  503. Revision 1.8 2001-07-07 12:46:12 jonas
  504. * some small bugfixes and cache optimizations
  505. Revision 1.7 2001/03/03 13:54:26 jonas
  506. * changed 'bdnzeq cr0' to 'bdnzt cr0*4+eq'
  507. Revision 1.6 2000/10/07 14:42:16 jonas
  508. * Fixed small error and did a small optimization
  509. Revision 1.5 2000/09/26 14:22:13 jonas
  510. * one more bug corrected
  511. Revision 1.4 2000/09/26 14:19:04 jonas
  512. * fixed several small bugs
  513. * fixed several typo's in the comments
  514. Revision 1.3 2000/09/22 10:03:18 jonas
  515. + implementation for FPC_SET_SET_RANGE
  516. * changed some routines so they never read data from after the actual
  517. set (could cause sigsegv's if the set is at the end of the heap)
  518. Revision 1.2 2000/07/13 11:33:56 michael
  519. + removed logs
  520. }