set.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. Include file with set operations called by the compiler
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$ifndef FPC_SYSTEM_HAS_FPC_VARSET_ADD_SETS}
  12. procedure fpc_varset_add_sets(const set1,set2; var dest;size : ptrint); compilerproc; assembler; nostackframe;
  13. { eax = set1, edx = set2, ecx = dest, [esp + 4] = size }
  14. asm
  15. push %ebx
  16. push %esi
  17. mov 12(%esp), %esi { esi = size }
  18. sub $4, %esi
  19. jl .LBytewise_Prepare { probably dead branch... }
  20. .L4x_Loop:
  21. mov (%eax,%esi), %ebx
  22. or (%edx,%esi), %ebx
  23. mov %ebx, (%ecx,%esi)
  24. sub $4, %esi
  25. ja .L4x_Loop
  26. mov (%eax), %ebx { Tail, just in case (if size is always divisible by 4, 4x_Loop can be altered to handle everything instead). }
  27. or (%edx), %ebx
  28. mov %ebx, (%ecx)
  29. pop %esi
  30. pop %ebx
  31. ret $4
  32. .LBytewise_Prepare:
  33. add $3, %esi
  34. .LBytewise_Loop:
  35. movzbl (%eax,%esi), %ebx
  36. or (%edx,%esi), %bl
  37. mov %bl, (%ecx,%esi)
  38. sub $1, %esi
  39. jae .LBytewise_Loop
  40. pop %esi
  41. pop %ebx
  42. end;
  43. {$define FPC_SYSTEM_HAS_FPC_VARSET_ADD_SETS}
  44. {$endif ndef FPC_SYSTEM_HAS_FPC_VARSET_ADD_SETS}
  45. {$ifndef FPC_SYSTEM_HAS_FPC_VARSET_MUL_SETS}
  46. procedure fpc_varset_mul_sets(const set1,set2; var dest;size : ptrint); compilerproc; assembler; nostackframe;
  47. { Same as fpc_varset_add_sets but with 'and' instead of 'or'. }
  48. asm
  49. push %ebx
  50. push %esi
  51. mov 12(%esp), %esi { esi = size }
  52. sub $4, %esi
  53. jl .LBytewise_Prepare { probably dead branch... }
  54. .L4x_Loop:
  55. mov (%eax,%esi), %ebx
  56. and (%edx,%esi), %ebx
  57. mov %ebx, (%ecx,%esi)
  58. sub $4, %esi
  59. ja .L4x_Loop
  60. mov (%eax), %ebx { Tail, just in case (if size is always divisible by 4, 4x_Loop can be altered to handle everything instead). }
  61. and (%edx), %ebx
  62. mov %ebx, (%ecx)
  63. pop %esi
  64. pop %ebx
  65. ret $4
  66. .LBytewise_Prepare:
  67. add $3, %esi
  68. .LBytewise_Loop:
  69. movzbl (%eax,%esi), %ebx
  70. and (%edx,%esi), %bl
  71. mov %bl, (%ecx,%esi)
  72. sub $1, %esi
  73. jae .LBytewise_Loop
  74. pop %esi
  75. pop %ebx
  76. end;
  77. {$define FPC_SYSTEM_HAS_FPC_VARSET_MUL_SETS}
  78. {$endif ndef FPC_SYSTEM_HAS_FPC_VARSET_MUL_SETS}
  79. {$ifndef FPC_SYSTEM_HAS_FPC_VARSET_SUB_SETS}
  80. procedure fpc_varset_sub_sets(const set1,set2; var dest;size : ptrint); compilerproc; assembler; nostackframe;
  81. { eax = set1, edx = set2, ecx = dest, [esp + 4] = size }
  82. asm
  83. push %ebx
  84. push %esi
  85. mov 12(%esp), %esi { esi = size }
  86. sub $4, %esi
  87. jl .LBytewise_Prepare { probably dead branch... }
  88. mov (%edx), %ebx { Tail, just in case (if size is always divisible by 4, 4x_Loop can be altered to handle everything instead). }
  89. not %ebx { Precalculated because operation is not idempotent and dest can be equal to set1/set2. }
  90. and (%eax), %ebx
  91. push %ebx
  92. .L4x_Loop:
  93. mov (%edx,%esi), %ebx
  94. not %ebx
  95. and (%eax,%esi), %ebx
  96. mov %ebx, (%ecx,%esi)
  97. sub $4, %esi
  98. ja .L4x_Loop
  99. pop %ebx
  100. mov %ebx, (%ecx) { Write precalculated tail. }
  101. pop %esi
  102. pop %ebx
  103. ret $4
  104. .LBytewise_Prepare:
  105. add $3, %esi
  106. .LBytewise_Loop:
  107. movzbl (%edx,%esi), %ebx
  108. not %ebx
  109. and (%eax,%esi), %bl
  110. mov %bl, (%ecx,%esi)
  111. sub $1, %esi
  112. jae .LBytewise_Loop
  113. pop %esi
  114. pop %ebx
  115. end;
  116. {$define FPC_SYSTEM_HAS_FPC_VARSET_SUB_SETS}
  117. {$endif ndef FPC_SYSTEM_HAS_FPC_VARSET_SUB_SETS}
  118. {$ifndef FPC_SYSTEM_HAS_FPC_VARSET_SYMDIF_SETS}
  119. procedure fpc_varset_symdif_sets(const set1,set2; var dest;size : ptrint); compilerproc; assembler; nostackframe;
  120. { Same as fpc_varset_mul_sets but with 'xor' instead of 'and not'.
  121. eax = set1, edx = set2, ecx = dest, [esp + 4] = size }
  122. asm
  123. push %ebx
  124. push %esi
  125. mov 12(%esp), %esi { esi = size }
  126. sub $4, %esi
  127. jl .LBytewise_Prepare { probably dead branch... }
  128. mov (%eax), %ebx { Tail, just in case (if size is always divisible by 4, 4x_Loop can be altered to handle everything instead). }
  129. xor (%edx), %ebx { Precalculated because operation is not idempotent and dest can be equal to set1/set2. }
  130. push %ebx
  131. .L4x_Loop:
  132. mov (%eax,%esi), %ebx
  133. xor (%edx,%esi), %ebx
  134. mov %ebx, (%ecx,%esi)
  135. sub $4, %esi
  136. ja .L4x_Loop
  137. pop %ebx
  138. mov %ebx, (%ecx) { Write precalculated tail. }
  139. pop %esi
  140. pop %ebx
  141. ret $4
  142. .LBytewise_Prepare:
  143. add $3, %esi
  144. .LBytewise_Loop:
  145. movzbl (%eax,%esi), %ebx
  146. xor (%edx,%esi), %bl
  147. mov %bl, (%ecx,%esi)
  148. sub $1, %esi
  149. jae .LBytewise_Loop
  150. pop %esi
  151. pop %ebx
  152. end;
  153. {$define FPC_SYSTEM_HAS_FPC_VARSET_SYMDIF_SETS}
  154. {$endif ndef FPC_SYSTEM_HAS_FPC_VARSET_SYMDIF_SETS}
  155. {$ifndef FPC_SYSTEM_HAS_FPC_VARSET_CONTAINS_SET}
  156. function fpc_varset_contains_sets(const set1,set2;size : ptrint):boolean; compilerproc; assembler; nostackframe;
  157. { eax = set1, edx = set2, ecx = size }
  158. asm
  159. push %ebx
  160. sub $4, %ecx
  161. jl .LBytewise_Prepare { probably dead branch... }
  162. add %ecx, %eax
  163. add %ecx, %edx
  164. neg %ecx { Now ecx = -(size - 4), eax points to set1 + size - 4, edx points to set2 + size - 4. Loop ends on size >= 0, leaving up to 4 tail bytes. }
  165. .L4x_Loop:
  166. mov (%edx,%ecx), %ebx
  167. not %ebx
  168. test %ebx, (%eax,%ecx)
  169. jnz .LNo
  170. add $4, %ecx
  171. js .L4x_Loop
  172. mov (%edx), %ebx { Tail. }
  173. not %ebx
  174. mov %eax, %ecx { eax value is still required to access set1 tail, but eax is going to be xor-zeroed for setz. }
  175. xor %eax, %eax
  176. test %ebx, (%ecx)
  177. setz %al
  178. pop %ebx
  179. ret
  180. .LNo:
  181. xor %eax, %eax
  182. pop %ebx
  183. ret
  184. .LBytewise_Prepare:
  185. add $4, %ecx
  186. neg %ecx
  187. sub %ecx, %eax
  188. sub %ecx, %edx
  189. .LBytewise_Loop:
  190. movzbl (%edx,%ecx), %ebx
  191. not %ebx
  192. test %bl, (%eax,%ecx)
  193. jnz .LNo
  194. inc %ecx
  195. jnz .LBytewise_Loop
  196. mov $1, %eax
  197. pop %ebx
  198. end;
  199. {$define FPC_SYSTEM_HAS_FPC_VARSET_CONTAINS_SET}
  200. {$endif ndef FPC_SYSTEM_HAS_FPC_VARSET_CONTAINS_SET}
  201. { the following code is exactly big endian set-related, but specific to the old
  202. scheme whereby sets were either 4 or 32 bytes. I've left the routines here
  203. so if someone wants to, they can create equivalents of the new varset helpers
  204. from rtl/inc/genset.inc
  205. }
  206. {$ifdef FPC_OLD_BIGENDIAN_SETS}
  207. {$define FPC_SYSTEM_HAS_FPC_SET_LOAD_SMALL}
  208. function fpc_set_load_small(l: fpc_small_set): fpc_normal_set;assembler;[public,alias:'FPC_SET_LOAD_SMALL']; compilerproc;
  209. {
  210. load a normal set p from a smallset l
  211. }
  212. var
  213. saveedi : longint;
  214. asm
  215. movl %edi,saveedi
  216. movl __RESULT,%edi
  217. movl l,%eax
  218. {$ifdef FPC_ENABLED_CLD}
  219. cld
  220. {$endif FPC_ENABLED_CLD}
  221. stosl
  222. xorl %eax,%eax
  223. movl $7,%ecx
  224. rep
  225. stosl
  226. movl saveedi,%edi
  227. end;
  228. {$define FPC_SYSTEM_HAS_FPC_SET_CREATE_ELEMENT}
  229. function fpc_set_create_element(b : byte): fpc_normal_set;assembler;[public,alias:'FPC_SET_CREATE_ELEMENT']; compilerproc;
  230. {
  231. create a new set in p from an element b
  232. }
  233. var
  234. saveedi : longint;
  235. asm
  236. movl %edi,saveedi
  237. movl __RESULT,%edi
  238. movzbl b,%edx
  239. xorl %eax,%eax
  240. movl $8,%ecx
  241. {$ifdef FPC_ENABLED_CLD}
  242. cld
  243. {$endif FPC_ENABLED_CLD}
  244. rep
  245. stosl
  246. leal -32(%edi),%eax
  247. btsl %edx,(%eax)
  248. movl saveedi,%edi
  249. end;
  250. {$define FPC_SYSTEM_HAS_FPC_SET_SET_BYTE}
  251. function fpc_set_set_byte(const source: fpc_normal_set; b : byte): fpc_normal_set;assembler; compilerproc;
  252. {
  253. add the element b to the set pointed by source
  254. }
  255. var
  256. saveesi,saveedi : longint;
  257. asm
  258. movl %edi,saveedi
  259. movl %esi,saveesi
  260. movl source,%esi
  261. movl __RESULT,%edi
  262. movzbl b,%edx
  263. movl $8,%ecx
  264. {$ifdef FPC_ENABLED_CLD}
  265. cld
  266. {$endif FPC_ENABLED_CLD}
  267. rep
  268. movsl
  269. leal -32(%edi),%eax
  270. btsl %edx,(%eax)
  271. movl saveedi,%edi
  272. movl saveesi,%esi
  273. end;
  274. {$define FPC_SYSTEM_HAS_FPC_SET_UNSET_BYTE}
  275. function fpc_set_unset_byte(const source: fpc_normal_set; b : byte): fpc_normal_set;assembler; compilerproc;
  276. {
  277. add the element b to the set pointed by source
  278. }
  279. var
  280. saveesi,saveedi : longint;
  281. asm
  282. movl %edi,saveedi
  283. movl %esi,saveesi
  284. movl source,%esi
  285. movl __RESULT,%edi
  286. movzbl b,%edx
  287. movl $8,%ecx
  288. {$ifdef FPC_ENABLED_CLD}
  289. cld
  290. {$endif FPC_ENABLED_CLD}
  291. rep
  292. movsl
  293. leal -32(%edi),%eax
  294. btrl %edx,(%eax)
  295. movl saveedi,%edi
  296. movl saveesi,%esi
  297. end;
  298. {$define FPC_SYSTEM_HAS_FPC_SET_SET_RANGE}
  299. function fpc_set_set_range(const orgset: fpc_normal_set; l,h : byte): fpc_normal_set;assembler; compilerproc;
  300. {
  301. adds the range [l..h] to the set pointed to by p
  302. }
  303. var
  304. saveh : byte;
  305. saveesi,saveedi,saveebx : longint;
  306. asm
  307. movl %edi,saveedi
  308. movl %esi,saveesi
  309. movl %ebx,saveebx
  310. movl __RESULT,%edi // target set address in edi
  311. movl orgset, %esi // source set address in esi
  312. movzbl l,%eax // lowest bit to be set in eax
  313. movzbl h,%ebx // highest in ebx
  314. movb %bl,saveh
  315. movl $8,%ecx // we have to copy 32 bytes
  316. cmpl %eax,%ebx // high < low?
  317. {$ifdef FPC_ENABLED_CLD}
  318. cld
  319. {$endif FPC_ENABLED_CLD}
  320. rep // copy source to dest (it's possible to do the range
  321. movsl // setting and copying simultanuously of course, but
  322. // that would result in many more jumps and code)
  323. movl %eax,%ecx // lowest also in ecx
  324. jb .Lset_range_done // if high > low, then dest := source
  325. shrl $3,%eax // divide by 8 to get starting and ending byte
  326. shrl $3,%ebx // address
  327. andb $31,%cl // low five bits of lo determine start of bit mask
  328. andl $0x0fffffffc,%eax // clear two lowest bits to get start/end longint
  329. subl $32,%edi // get back to start of dest
  330. andl $0x0fffffffc,%ebx // address * 4
  331. movl $0x0ffffffff,%edx // edx = bitmask to be inserted
  332. shll %cl,%edx // shift bitmask to clear bits below lo
  333. addl %eax,%edi // go to starting pos in set
  334. subl %eax,%ebx // are bit lo and hi in the same longint?
  335. jz .Lset_range_hi // yes, keep current mask and adjust for hi bit
  336. orl %edx,(%edi) // no, store current mask
  337. movl $0x0ffffffff,%edx // new mask
  338. addl $4,%edi // next longint of set
  339. subl $4,%ebx // bit hi in this longint?
  340. jz .Lset_range_hi // yes, keep full mask and adjust for hi bit
  341. .Lset_range_loop:
  342. movl %edx,(%edi) // no, fill longints in between with full mask
  343. addl $4,%edi
  344. subl $4,%ebx
  345. jnz .Lset_range_loop
  346. .Lset_range_hi:
  347. movb saveh,%cl // this is ok, h is on the stack
  348. movl %edx,%ebx // save current bitmask
  349. andb $31,%cl
  350. subb $31,%cl // cl := (31 - (hi and 31)) = shift count to
  351. negb %cl // adjust bitmask for hi bit
  352. shrl %cl,%edx // shift bitmask to clear bits higher than hi
  353. andl %edx,%ebx // combine both bitmasks
  354. orl %ebx,(%edi) // store to set
  355. .Lset_range_done:
  356. movl saveedi,%edi
  357. movl saveesi,%esi
  358. movl saveebx,%ebx
  359. end;
  360. {$define FPC_SYSTEM_HAS_FPC_SET_IN_BYTE}
  361. function fpc_set_in_byte(const p: fpc_normal_set; b: byte): boolean; assembler; [public,alias:'FPC_SET_IN_BYTE']; compilerproc;
  362. {
  363. tests if the element b is in the set p the carryflag is set if it present
  364. }
  365. asm
  366. {$ifdef REGCALL}
  367. xchgl %edx,%eax
  368. andl $0xff,%eax
  369. {$else}
  370. movl p,%edx
  371. movzbl b,%eax
  372. {$endif}
  373. btl %eax,(%edx)
  374. end;
  375. {$define FPC_SYSTEM_HAS_FPC_SET_COMP_SETS}
  376. function fpc_set_comp_sets(const set1,set2: fpc_normal_set): boolean;assembler;[public,alias:'FPC_SET_COMP_SETS']; compilerproc;
  377. {
  378. compares set1 and set2 zeroflag is set if they are equal
  379. }
  380. var
  381. saveesi,saveedi : longint;
  382. asm
  383. movl %edi,saveedi
  384. movl %esi,saveesi
  385. movl set1,%esi
  386. movl set2,%edi
  387. movl $8,%ecx
  388. .LMCOMPSETS1:
  389. movl (%esi),%eax
  390. movl (%edi),%edx
  391. cmpl %edx,%eax
  392. jne .LMCOMPSETEND
  393. addl $4,%esi
  394. addl $4,%edi
  395. decl %ecx
  396. jnz .LMCOMPSETS1
  397. { we are here only if the two sets are equal
  398. we have zero flag set, and that what is expected }
  399. .LMCOMPSETEND:
  400. seteb %al
  401. movl saveedi,%edi
  402. movl saveesi,%esi
  403. end;
  404. {$ifdef LARGESETS}
  405. {$error Needs to be fixed for register calling first!}
  406. procedure fpc_largeset_set_word(p : pointer;b : word);assembler;[public,alias:'FPC_LARGESET_SET_WORD']; compilerproc;
  407. {
  408. sets the element b in set p works for sets larger than 256 elements
  409. not yet use by the compiler so
  410. }
  411. asm
  412. pushl %eax
  413. movl p,%edi
  414. movw b,%ax
  415. andl $0xfff8,%eax
  416. shrl $3,%eax
  417. addl %eax,%edi
  418. movb 12(%ebp),%al
  419. andl $7,%eax
  420. btsl %eax,(%edi)
  421. popl %eax
  422. end;
  423. procedure fpc_largeset_in_word(p : pointer;b : word);assembler;[public,alias:'FPC_LARGESET_IN_WORD']; compilerproc;
  424. {
  425. tests if the element b is in the set p the carryflag is set if it present
  426. works for sets larger than 256 elements
  427. }
  428. asm
  429. pushl %eax
  430. movl p,%edi
  431. movw b,%ax
  432. andl $0xfff8,%eax
  433. shrl $3,%eax
  434. addl %eax,%edi
  435. movb 12(%ebp),%al
  436. andl $7,%eax
  437. btl %eax,(%edi)
  438. popl %eax
  439. end;
  440. procedure fpc_largeset_comp_sets(set1,set2 : pointer;size : longint);assembler;[public,alias:'FPC_LARGESET_COMP_SETS']; compilerproc;
  441. asm
  442. movl set1,%esi
  443. movl set2,%edi
  444. movl size,%ecx
  445. {$ifdef FPC_ENABLED_CLD}
  446. cld
  447. {$endif FPC_ENABLED_CLD}
  448. .LMCOMPSETSIZES1:
  449. lodsl
  450. movl (%edi),%edx
  451. cmpl %edx,%eax
  452. jne .LMCOMPSETSIZEEND
  453. addl $4,%edi
  454. decl %ecx
  455. jnz .LMCOMPSETSIZES1
  456. { we are here only if the two sets are equal
  457. we have zero flag set, and that what is expected }
  458. .LMCOMPSETSIZEEND:
  459. end;
  460. {$endif LARGESET}
  461. {$endif FPC_OLD_BIGENDIAN_SETS}