1 /** 2 * Compiler implementation of the 3 * $(LINK2 https://www.dlang.org, D programming language). 4 * 5 * Simple bit vector implementation. 6 * 7 * Copyright: Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved 8 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 9 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 10 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/dvec.d, backend/dvec.d) 11 */ 12 13 module dmd.backend.dvec; 14 15 import core.stdc.stdio; 16 import core.stdc.stdlib; 17 import core.stdc.string; 18 19 import core.bitop; 20 21 import dmd.backend.global : err_nomem; 22 23 extern (C): 24 25 nothrow: 26 @nogc: 27 @safe: 28 29 alias vec_base_t = size_t; // base type of vector 30 alias vec_t = vec_base_t*; 31 32 enum VECBITS = vec_base_t.sizeof * 8; // # of bits per entry 33 enum VECMASK = VECBITS - 1; // mask for bit position 34 enum VECSHIFT = (VECBITS == 16) ? 4 : (VECBITS == 32 ? 5 : 6); // # of bits in VECMASK 35 36 static assert(vec_base_t.sizeof == 2 && VECSHIFT == 4 || 37 vec_base_t.sizeof == 4 && VECSHIFT == 5 || 38 vec_base_t.sizeof == 8 && VECSHIFT == 6); 39 40 struct VecGlobal 41 { 42 int count; // # of vectors allocated 43 int initcount; // # of times package is initialized 44 vec_t[30] freelist; // free lists indexed by dim 45 46 nothrow: 47 @nogc: 48 49 void initialize() 50 { 51 if (initcount++ == 0) 52 count = 0; 53 } 54 55 @trusted 56 void terminate() 57 { 58 if (--initcount == 0) 59 { 60 debug 61 { 62 if (count != 0) 63 { 64 printf("vecGlobal.count = %d\n", count); 65 assert(0); 66 } 67 } 68 else 69 assert(count == 0); 70 71 foreach (size_t i; 0 .. freelist.length) 72 { 73 void **vn; 74 for (void** v = cast(void **)freelist[i]; v; v = vn) 75 { 76 vn = cast(void **)(*v); 77 //mem_free(v); 78 .free(v); 79 } 80 freelist[i] = null; 81 } 82 } 83 } 84 85 @trusted 86 vec_t allocate(size_t numbits) 87 { 88 if (numbits == 0) 89 return cast(vec_t) null; 90 const dim = (numbits + (VECBITS - 1)) >> VECSHIFT; 91 vec_t v; 92 if (dim < freelist.length && (v = freelist[dim]) != null) 93 { 94 freelist[dim] = *cast(vec_t *)v; 95 v += 2; 96 switch (dim) 97 { 98 case 5: v[4] = 0; goto case 4; 99 case 4: v[3] = 0; goto case 3; 100 case 3: v[2] = 0; goto case 2; 101 case 2: v[1] = 0; goto case 1; 102 case 1: v[0] = 0; 103 break; 104 default: memset(v,0,dim * vec_base_t.sizeof); 105 break; 106 } 107 goto L1; 108 } 109 else 110 { 111 if (dim >= size_t.max / vec_base_t.sizeof - 1024) 112 err_nomem(); // dim overflow 113 v = cast(vec_t) calloc(dim + 2, vec_base_t.sizeof); 114 if (!v) 115 err_nomem(); 116 } 117 if (v) 118 { 119 v += 2; 120 L1: 121 vec_dim(v) = dim; 122 vec_numbits(v) = numbits; 123 /*printf("vec_calloc(%d): v = %p vec_numbits = %d vec_dim = %d\n", 124 numbits,v,vec_numbits(v),vec_dim(v));*/ 125 count++; 126 } 127 return v; 128 } 129 130 @trusted 131 vec_t dup(const vec_t v) 132 { 133 if (!v) 134 return null; 135 136 const dim = vec_dim(v); 137 // don't need to check overflow, assuming dim is already valid 138 const nbytes = (dim + 2) * vec_base_t.sizeof; 139 vec_t vc; 140 vec_t result; 141 if (dim < freelist.length && (vc = freelist[dim]) != null) 142 { 143 freelist[dim] = *cast(vec_t *)vc; 144 goto L1; 145 } 146 else 147 { 148 vc = cast(vec_t) calloc(nbytes, 1); 149 if (!vc) 150 err_nomem(); 151 } 152 if (vc) 153 { 154 L1: 155 memcpy(vc,v - 2,nbytes); 156 count++; 157 result = vc + 2; 158 } 159 else 160 result = null; 161 return result; 162 } 163 164 @trusted 165 void free(vec_t v) 166 { 167 /*printf("vec_free(%p)\n",v);*/ 168 if (v) 169 { 170 const dim = vec_dim(v); 171 v -= 2; 172 if (dim < freelist.length) 173 { 174 *cast(vec_t *)v = freelist[dim]; 175 freelist[dim] = v; 176 } 177 else 178 .free(v); 179 count--; 180 } 181 } 182 183 } 184 185 __gshared VecGlobal vecGlobal; 186 187 private pure vec_base_t MASK(uint b) { return cast(vec_base_t)1 << (b & VECMASK); } 188 189 /**** 190 * Returns: 191 * number of bits in the vector 192 */ 193 @trusted 194 pure ref inout(vec_base_t) vec_numbits(inout vec_t v) { return v[-1]; } 195 /**** 196 * Returns: 197 * number of bytes in the vector 198 */ 199 @trusted 200 pure ref inout(vec_base_t) vec_dim(inout vec_t v) { return v[-2]; } 201 202 /************************** 203 * Initialize package. 204 */ 205 206 @trusted 207 void vec_init() 208 { 209 vecGlobal.initialize(); 210 } 211 212 213 /************************** 214 * Terminate package. 215 */ 216 217 @trusted 218 void vec_term() 219 { 220 vecGlobal.terminate(); 221 } 222 223 /******************************** 224 * Allocate a vector given # of bits in it. 225 * Clear the vector. 226 */ 227 228 @trusted 229 vec_t vec_calloc(size_t numbits) 230 { 231 return vecGlobal.allocate(numbits); 232 } 233 234 /******************************** 235 * Allocate copy of existing vector. 236 */ 237 238 @trusted 239 vec_t vec_clone(const vec_t v) 240 { 241 return vecGlobal.dup(v); 242 } 243 244 /************************** 245 * Free a vector. 246 */ 247 248 @trusted 249 void vec_free(vec_t v) 250 { 251 /*printf("vec_free(%p)\n",v);*/ 252 return vecGlobal.free(v); 253 } 254 255 /************************** 256 * Realloc a vector to have numbits bits in it. 257 * Extra bits are set to 0. 258 */ 259 260 @trusted 261 vec_t vec_realloc(vec_t v, size_t numbits) 262 { 263 /*printf("vec_realloc(%p,%d)\n",v,numbits);*/ 264 if (!v) 265 return vec_calloc(numbits); 266 if (!numbits) 267 { vec_free(v); 268 return null; 269 } 270 const vbits = vec_numbits(v); 271 if (numbits == vbits) 272 return v; 273 vec_t newv = vec_calloc(numbits); 274 if (newv) 275 { 276 const nbytes = (vec_dim(v) < vec_dim(newv)) ? vec_dim(v) : vec_dim(newv); 277 memcpy(newv,v,nbytes * vec_base_t.sizeof); 278 vec_clearextrabits(newv); 279 } 280 vec_free(v); 281 return newv; 282 } 283 284 /******************************** 285 * Recycle a vector `v` to a new size `numbits`, clear all bits. 286 * Re-uses original if possible. 287 */ 288 void vec_recycle(ref vec_t v, size_t numbits) 289 { 290 vec_free(v); 291 v = vec_calloc(numbits); 292 } 293 294 295 /************************** 296 * Set bit b in vector v. 297 */ 298 299 @trusted 300 pure 301 void vec_setbit(size_t b, vec_t v) 302 { 303 debug 304 { 305 if (!(v && b < vec_numbits(v))) 306 printf("vec_setbit(v = %p,b = %d): numbits = %d dim = %d\n", 307 v, cast(int) b, cast(int) (v ? vec_numbits(v) : 0), cast(int) (v ? vec_dim(v) : 0)); 308 } 309 assert(v && b < vec_numbits(v)); 310 core.bitop.bts(v, b); 311 } 312 313 /************************** 314 * Clear bit b in vector v. 315 */ 316 317 @trusted 318 pure 319 void vec_clearbit(size_t b, vec_t v) 320 { 321 assert(v && b < vec_numbits(v)); 322 core.bitop.btr(v, b); 323 } 324 325 /************************** 326 * Test bit b in vector v. 327 */ 328 329 @trusted 330 pure 331 size_t vec_testbit(size_t b, const vec_t v) 332 { 333 if (!v) 334 return 0; 335 debug 336 { 337 if (!(v && b < vec_numbits(v))) 338 printf("vec_setbit(v = %p,b = %d): numbits = %d dim = %d\n", 339 v, cast(int) b, cast(int) (v ? vec_numbits(v) : 0), cast(int) (v ? vec_dim(v) : 0)); 340 } 341 assert(v && b < vec_numbits(v)); 342 return core.bitop.bt(v, b); 343 } 344 345 /******************************** 346 * Find first set bit starting from b in vector v. 347 * If no bit is found, return vec_numbits(v). 348 */ 349 350 @trusted 351 pure 352 size_t vec_index(size_t b, const vec_t vec) 353 { 354 if (!vec) 355 return 0; 356 const(vec_base_t)* v = vec; 357 if (b < vec_numbits(v)) 358 { 359 const vtop = &vec[vec_dim(v)]; 360 const bit = b & VECMASK; 361 if (bit != b) // if not starting in first word 362 v += b >> VECSHIFT; 363 size_t starv = *v >> bit; 364 while (1) 365 { 366 while (starv) 367 { 368 if (starv & 1) 369 return b; 370 b++; 371 starv >>= 1; 372 } 373 b = (b + VECBITS) & ~VECMASK; // round up to next word 374 if (++v >= vtop) 375 break; 376 starv = *v; 377 } 378 } 379 return vec_numbits(vec); 380 } 381 382 /******************************** 383 * Count number of set bits in vector `v` 384 * Params: 385 * v = vector 386 * Returns: 387 * number of set bits 388 */ 389 pure 390 uint vec_numBitsSet(const vec_t vec) 391 { 392 uint n = 0; 393 size_t length = vec_numbits(vec); 394 for (size_t i = 0; (i = vec_index(i, vec)) < length; ++i) 395 ++n; 396 return n; 397 } 398 399 /******************************** 400 * Compute v1 &= v2. 401 */ 402 403 @trusted 404 pure 405 void vec_andass(vec_t v1, const(vec_base_t)* v2) 406 { 407 if (v1) 408 { 409 assert(v2); 410 assert(vec_numbits(v1)==vec_numbits(v2)); 411 const vtop = &v1[vec_dim(v1)]; 412 for (; v1 < vtop; v1++,v2++) 413 *v1 &= *v2; 414 } 415 else 416 assert(!v2); 417 } 418 419 /******************************** 420 * Compute v1 = v2 & v3. 421 */ 422 423 @trusted 424 pure 425 void vec_and(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 426 { 427 if (v1) 428 { 429 assert(v2 && v3); 430 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 431 const vtop = &v1[vec_dim(v1)]; 432 for (; v1 < vtop; v1++,v2++,v3++) 433 *v1 = *v2 & *v3; 434 } 435 else 436 assert(!v2 && !v3); 437 } 438 439 /******************************** 440 * Compute v1 ^= v2. 441 */ 442 443 @trusted 444 pure 445 void vec_xorass(vec_t v1, const(vec_base_t)* v2) 446 { 447 if (v1) 448 { 449 assert(v2); 450 assert(vec_numbits(v1)==vec_numbits(v2)); 451 const vtop = &v1[vec_dim(v1)]; 452 for (; v1 < vtop; v1++,v2++) 453 *v1 ^= *v2; 454 } 455 else 456 assert(!v2); 457 } 458 459 /******************************** 460 * Compute v1 = v2 ^ v3. 461 */ 462 463 @trusted 464 pure 465 void vec_xor(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 466 { 467 if (v1) 468 { 469 assert(v2 && v3); 470 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 471 const vtop = &v1[vec_dim(v1)]; 472 for (; v1 < vtop; v1++,v2++,v3++) 473 *v1 = *v2 ^ *v3; 474 } 475 else 476 assert(!v2 && !v3); 477 } 478 479 /******************************** 480 * Compute v1 |= v2. 481 */ 482 483 @trusted 484 pure 485 void vec_orass(vec_t v1, const(vec_base_t)* v2) 486 { 487 if (v1) 488 { 489 debug assert(v2); 490 debug assert(vec_numbits(v1)==vec_numbits(v2)); 491 const vtop = &v1[vec_dim(v1)]; 492 for (; v1 < vtop; v1++,v2++) 493 *v1 |= *v2; 494 } 495 else 496 assert(!v2); 497 } 498 499 /******************************** 500 * Compute v1 = v2 | v3. 501 */ 502 503 @trusted 504 pure 505 void vec_or(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 506 { 507 if (v1) 508 { 509 assert(v2 && v3); 510 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 511 const vtop = &v1[vec_dim(v1)]; 512 for (; v1 < vtop; v1++,v2++,v3++) 513 *v1 = *v2 | *v3; 514 } 515 else 516 assert(!v2 && !v3); 517 } 518 519 /******************************** 520 * Compute v1 -= v2. 521 */ 522 523 @trusted 524 pure 525 void vec_subass(vec_t v1, const(vec_base_t)* v2) 526 { 527 if (v1) 528 { 529 assert(v2); 530 assert(vec_numbits(v1)==vec_numbits(v2)); 531 const vtop = &v1[vec_dim(v1)]; 532 for (; v1 < vtop; v1++,v2++) 533 *v1 &= ~*v2; 534 } 535 else 536 assert(!v2); 537 } 538 539 /******************************** 540 * Compute v1 = v2 - v3. 541 */ 542 543 @trusted 544 pure 545 void vec_sub(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 546 { 547 if (v1) 548 { 549 assert(v2 && v3); 550 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 551 const vtop = &v1[vec_dim(v1)]; 552 for (; v1 < vtop; v1++,v2++,v3++) 553 *v1 = *v2 & ~*v3; 554 } 555 else 556 assert(!v2 && !v3); 557 } 558 559 /**************** 560 * Clear vector. 561 */ 562 563 @trusted 564 pure 565 void vec_clear(vec_t v) 566 { 567 if (v) 568 memset(v, 0, v[0].sizeof * vec_dim(v)); 569 } 570 571 /**************** 572 * Set vector. 573 */ 574 575 @trusted 576 pure 577 void vec_set(vec_t v) 578 { 579 if (v) 580 { 581 memset(v, ~0, v[0].sizeof * vec_dim(v)); 582 vec_clearextrabits(v); 583 } 584 } 585 586 /*************** 587 * Copy vector. 588 */ 589 590 @trusted 591 pure 592 void vec_copy(vec_t to, const vec_t from) 593 { 594 if (to != from) 595 { 596 debug 597 { 598 if (!(to && from && vec_numbits(to) == vec_numbits(from))) 599 printf("to = x%p, from = x%p, numbits(to) = %d, numbits(from) = %d\n", 600 to, from, cast(int) (to ? vec_numbits(to) : 0), 601 cast(int) (from ? vec_numbits(from): 0)); 602 } 603 assert(to && from && vec_numbits(to) == vec_numbits(from)); 604 memcpy(to, from, to[0].sizeof * vec_dim(to)); 605 } 606 } 607 608 /**************** 609 * Return 1 if vectors are equal. 610 */ 611 612 @trusted 613 pure 614 int vec_equal(const vec_t v1, const vec_t v2) 615 { 616 if (v1 == v2) 617 return 1; 618 assert(v1 && v2 && vec_numbits(v1) == vec_numbits(v2)); 619 return !memcmp(v1, v2, v1[0].sizeof * vec_dim(v1)); 620 } 621 622 /******************************** 623 * Return 1 if (v1 & v2) == 0 624 */ 625 626 @trusted 627 pure 628 int vec_disjoint(const(vec_base_t)* v1, const(vec_base_t)* v2) 629 { 630 assert(v1 && v2); 631 assert(vec_numbits(v1) == vec_numbits(v2)); 632 const vtop = &v1[vec_dim(v1)]; 633 for (; v1 < vtop; v1++,v2++) 634 if (*v1 & *v2) 635 return 0; 636 return 1; 637 } 638 639 /********************* 640 * Clear any extra bits in vector. 641 */ 642 643 @trusted 644 pure 645 void vec_clearextrabits(vec_t v) 646 { 647 assert(v); 648 const n = vec_numbits(v); 649 if (n & VECMASK) 650 v[vec_dim(v) - 1] &= MASK(cast(uint)n) - 1; 651 } 652 653 /************************************** 654 * Turn a vec_t into an InputRange so we can foreach 655 * over each bit in the bit vector. 656 * Replaces 657 * for (size_t i = 0; (i = vec_index(i, v)) < vec_numbits(v); ++i) { ... } 658 * With 659 * foreach (i; VecRange(v)) { ... } 660 */ 661 struct VecRange 662 { 663 size_t i; 664 const vec_t v; 665 666 @nogc nothrow pure: 667 this(const vec_t v) { this.v = v; i = vec_index(0, v); } 668 bool empty() const { return i == vec_numbits(v); } 669 size_t front() const { return i; } 670 void popFront() { i = vec_index(i + 1, v); } 671 } 672 673 /****************** 674 * Write out vector. 675 */ 676 677 pure 678 void vec_println(const vec_t v) 679 { 680 debug 681 { 682 vec_print(v); 683 fputc('\n',stdout); 684 } 685 } 686 687 @trusted 688 pure 689 void vec_print(const vec_t v) 690 { 691 debug 692 { 693 printf(" Vec %p, numbits %d dim %d", v, cast(int) vec_numbits(v), cast(int) vec_dim(v)); 694 if (v) 695 { 696 fputc('\t',stdout); 697 for (size_t i = 0; i < vec_numbits(v); i++) 698 fputc((vec_testbit(i,v)) ? '1' : '0',stdout); 699 } 700 } 701 }