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 @safe 390 pure 391 uint vec_numBitsSet(const vec_t vec) 392 { 393 uint n = 0; 394 size_t length = vec_numbits(vec); 395 for (size_t i = 0; (i = vec_index(i, vec)) < length; ++i) 396 ++n; 397 return n; 398 } 399 400 /******************************** 401 * Compute v1 &= v2. 402 */ 403 404 @trusted 405 pure 406 void vec_andass(vec_t v1, const(vec_base_t)* v2) 407 { 408 if (v1) 409 { 410 assert(v2); 411 assert(vec_numbits(v1)==vec_numbits(v2)); 412 const vtop = &v1[vec_dim(v1)]; 413 for (; v1 < vtop; v1++,v2++) 414 *v1 &= *v2; 415 } 416 else 417 assert(!v2); 418 } 419 420 /******************************** 421 * Compute v1 = v2 & v3. 422 */ 423 424 @trusted 425 pure 426 void vec_and(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 427 { 428 if (v1) 429 { 430 assert(v2 && v3); 431 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 432 const vtop = &v1[vec_dim(v1)]; 433 for (; v1 < vtop; v1++,v2++,v3++) 434 *v1 = *v2 & *v3; 435 } 436 else 437 assert(!v2 && !v3); 438 } 439 440 /******************************** 441 * Compute v1 ^= v2. 442 */ 443 444 @trusted 445 pure 446 void vec_xorass(vec_t v1, const(vec_base_t)* v2) 447 { 448 if (v1) 449 { 450 assert(v2); 451 assert(vec_numbits(v1)==vec_numbits(v2)); 452 const vtop = &v1[vec_dim(v1)]; 453 for (; v1 < vtop; v1++,v2++) 454 *v1 ^= *v2; 455 } 456 else 457 assert(!v2); 458 } 459 460 /******************************** 461 * Compute v1 = v2 ^ v3. 462 */ 463 464 @trusted 465 pure 466 void vec_xor(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 467 { 468 if (v1) 469 { 470 assert(v2 && v3); 471 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 472 const vtop = &v1[vec_dim(v1)]; 473 for (; v1 < vtop; v1++,v2++,v3++) 474 *v1 = *v2 ^ *v3; 475 } 476 else 477 assert(!v2 && !v3); 478 } 479 480 /******************************** 481 * Compute v1 |= v2. 482 */ 483 484 @trusted 485 pure 486 void vec_orass(vec_t v1, const(vec_base_t)* v2) 487 { 488 if (v1) 489 { 490 debug assert(v2); 491 debug assert(vec_numbits(v1)==vec_numbits(v2)); 492 const vtop = &v1[vec_dim(v1)]; 493 for (; v1 < vtop; v1++,v2++) 494 *v1 |= *v2; 495 } 496 else 497 assert(!v2); 498 } 499 500 /******************************** 501 * Compute v1 = v2 | v3. 502 */ 503 504 @trusted 505 pure 506 void vec_or(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 507 { 508 if (v1) 509 { 510 assert(v2 && v3); 511 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 512 const vtop = &v1[vec_dim(v1)]; 513 for (; v1 < vtop; v1++,v2++,v3++) 514 *v1 = *v2 | *v3; 515 } 516 else 517 assert(!v2 && !v3); 518 } 519 520 /******************************** 521 * Compute v1 -= v2. 522 */ 523 524 @trusted 525 pure 526 void vec_subass(vec_t v1, const(vec_base_t)* v2) 527 { 528 if (v1) 529 { 530 assert(v2); 531 assert(vec_numbits(v1)==vec_numbits(v2)); 532 const vtop = &v1[vec_dim(v1)]; 533 for (; v1 < vtop; v1++,v2++) 534 *v1 &= ~*v2; 535 } 536 else 537 assert(!v2); 538 } 539 540 /******************************** 541 * Compute v1 = v2 - v3. 542 */ 543 544 @trusted 545 pure 546 void vec_sub(vec_t v1, const(vec_base_t)* v2, const(vec_base_t)* v3) 547 { 548 if (v1) 549 { 550 assert(v2 && v3); 551 assert(vec_numbits(v1)==vec_numbits(v2) && vec_numbits(v1)==vec_numbits(v3)); 552 const vtop = &v1[vec_dim(v1)]; 553 for (; v1 < vtop; v1++,v2++,v3++) 554 *v1 = *v2 & ~*v3; 555 } 556 else 557 assert(!v2 && !v3); 558 } 559 560 /**************** 561 * Clear vector. 562 */ 563 564 @trusted 565 pure 566 void vec_clear(vec_t v) 567 { 568 if (v) 569 memset(v, 0, v[0].sizeof * vec_dim(v)); 570 } 571 572 /**************** 573 * Set vector. 574 */ 575 576 @trusted 577 pure 578 void vec_set(vec_t v) 579 { 580 if (v) 581 { 582 memset(v, ~0, v[0].sizeof * vec_dim(v)); 583 vec_clearextrabits(v); 584 } 585 } 586 587 /*************** 588 * Copy vector. 589 */ 590 591 @trusted 592 pure 593 void vec_copy(vec_t to, const vec_t from) 594 { 595 if (to != from) 596 { 597 debug 598 { 599 if (!(to && from && vec_numbits(to) == vec_numbits(from))) 600 printf("to = x%p, from = x%p, numbits(to) = %d, numbits(from) = %d\n", 601 to, from, cast(int) (to ? vec_numbits(to) : 0), 602 cast(int) (from ? vec_numbits(from): 0)); 603 } 604 assert(to && from && vec_numbits(to) == vec_numbits(from)); 605 memcpy(to, from, to[0].sizeof * vec_dim(to)); 606 } 607 } 608 609 /**************** 610 * Return 1 if vectors are equal. 611 */ 612 613 @trusted 614 pure 615 int vec_equal(const vec_t v1, const vec_t v2) 616 { 617 if (v1 == v2) 618 return 1; 619 assert(v1 && v2 && vec_numbits(v1) == vec_numbits(v2)); 620 return !memcmp(v1, v2, v1[0].sizeof * vec_dim(v1)); 621 } 622 623 /******************************** 624 * Return 1 if (v1 & v2) == 0 625 */ 626 627 @trusted 628 pure 629 int vec_disjoint(const(vec_base_t)* v1, const(vec_base_t)* v2) 630 { 631 assert(v1 && v2); 632 assert(vec_numbits(v1) == vec_numbits(v2)); 633 const vtop = &v1[vec_dim(v1)]; 634 for (; v1 < vtop; v1++,v2++) 635 if (*v1 & *v2) 636 return 0; 637 return 1; 638 } 639 640 /********************* 641 * Clear any extra bits in vector. 642 */ 643 644 @trusted 645 pure 646 void vec_clearextrabits(vec_t v) 647 { 648 assert(v); 649 const n = vec_numbits(v); 650 if (n & VECMASK) 651 v[vec_dim(v) - 1] &= MASK(cast(uint)n) - 1; 652 } 653 654 /************************************** 655 * Turn a vec_t into an InputRange so we can foreach 656 * over each bit in the bit vector. 657 * Replaces 658 * for (size_t i = 0; (i = vec_index(i, v)) < vec_numbits(v); ++i) { ... } 659 * With 660 * foreach (i; VecRange(v)) { ... } 661 */ 662 struct VecRange 663 { 664 size_t i; 665 const vec_t v; 666 667 @nogc @safe nothrow pure: 668 this(const vec_t v) { this.v = v; i = vec_index(0, v); } 669 bool empty() const { return i == vec_numbits(v); } 670 size_t front() const { return i; } 671 void popFront() { i = vec_index(i + 1, v); } 672 } 673 674 /****************** 675 * Write out vector. 676 */ 677 678 pure 679 void vec_println(const vec_t v) 680 { 681 debug 682 { 683 vec_print(v); 684 fputc('\n',stdout); 685 } 686 } 687 688 @trusted 689 pure 690 void vec_print(const vec_t v) 691 { 692 debug 693 { 694 printf(" Vec %p, numbits %d dim %d", v, cast(int) vec_numbits(v), cast(int) vec_dim(v)); 695 if (v) 696 { 697 fputc('\t',stdout); 698 for (size_t i = 0; i < vec_numbits(v); i++) 699 fputc((vec_testbit(i,v)) ? '1' : '0',stdout); 700 } 701 } 702 }