1 2 /*--------------------------------------------------------------------*/ 3 /*--- Sets of words, with unique set identifiers. ---*/ 4 /*--- hg_wordset.c ---*/ 5 /*--------------------------------------------------------------------*/ 6 7 /* 8 This file is part of Helgrind, a Valgrind tool for detecting errors 9 in threaded programs. 10 11 Copyright (C) 2007-2010 OpenWorks LLP 12 info (at) open-works.co.uk 13 14 This program is free software; you can redistribute it and/or 15 modify it under the terms of the GNU General Public License as 16 published by the Free Software Foundation; either version 2 of the 17 License, or (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 27 02111-1307, USA. 28 29 The GNU General Public License is contained in the file COPYING. 30 31 Neither the names of the U.S. Department of Energy nor the 32 University of California nor the names of its contributors may be 33 used to endorse or promote products derived from this software 34 without prior written permission. 35 */ 36 37 #include "pub_tool_basics.h" 38 #include "pub_tool_libcassert.h" 39 #include "pub_tool_libcbase.h" 40 #include "pub_tool_libcprint.h" 41 #include "pub_tool_threadstate.h" 42 #include "pub_tool_wordfm.h" 43 44 #include "hg_basics.h" 45 #include "hg_wordset.h" /* self */ 46 47 //------------------------------------------------------------------// 48 //--- Word Cache ---// 49 //------------------------------------------------------------------// 50 51 typedef 52 struct { UWord arg1; UWord arg2; UWord res; } 53 WCacheEnt; 54 55 /* Each cache is a fixed sized array of N_WCACHE_STAT_MAX entries. 56 However only the first .dynMax are used. This is because at some 57 point, expanding the cache further overall gives a slowdown because 58 searching more entries more than negates any performance advantage 59 from caching those entries in the first place. Hence use .dynMax 60 to allow the size of the cache(s) to be set differently for each 61 different WordSetU. */ 62 #define N_WCACHE_STAT_MAX 32 63 typedef 64 struct { 65 WCacheEnt ent[N_WCACHE_STAT_MAX]; 66 UWord dynMax; /* 1 .. N_WCACHE_STAT_MAX inclusive */ 67 UWord inUse; /* 0 .. dynMax inclusive */ 68 } 69 WCache; 70 71 #define WCache_INIT(_zzcache,_zzdynmax) \ 72 do { \ 73 tl_assert((_zzdynmax) >= 1); \ 74 tl_assert((_zzdynmax) <= N_WCACHE_STAT_MAX); \ 75 (_zzcache).dynMax = (_zzdynmax); \ 76 (_zzcache).inUse = 0; \ 77 } while (0) 78 79 #define WCache_LOOKUP_AND_RETURN(_retty,_zzcache,_zzarg1,_zzarg2) \ 80 do { \ 81 UWord _i; \ 82 UWord _arg1 = (UWord)(_zzarg1); \ 83 UWord _arg2 = (UWord)(_zzarg2); \ 84 WCache* _cache = &(_zzcache); \ 85 tl_assert(_cache->dynMax >= 1); \ 86 tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \ 87 tl_assert(_cache->inUse >= 0); \ 88 tl_assert(_cache->inUse <= _cache->dynMax); \ 89 if (_cache->inUse > 0) { \ 90 if (_cache->ent[0].arg1 == _arg1 \ 91 && _cache->ent[0].arg2 == _arg2) \ 92 return (_retty)_cache->ent[0].res; \ 93 for (_i = 1; _i < _cache->inUse; _i++) { \ 94 if (_cache->ent[_i].arg1 == _arg1 \ 95 && _cache->ent[_i].arg2 == _arg2) { \ 96 WCacheEnt tmp = _cache->ent[_i-1]; \ 97 _cache->ent[_i-1] = _cache->ent[_i]; \ 98 _cache->ent[_i] = tmp; \ 99 return (_retty)_cache->ent[_i-1].res; \ 100 } \ 101 } \ 102 } \ 103 } while (0) 104 105 #define WCache_UPDATE(_zzcache,_zzarg1,_zzarg2,_zzresult) \ 106 do { \ 107 Word _i; \ 108 UWord _arg1 = (UWord)(_zzarg1); \ 109 UWord _arg2 = (UWord)(_zzarg2); \ 110 UWord _res = (UWord)(_zzresult); \ 111 WCache* _cache = &(_zzcache); \ 112 tl_assert(_cache->dynMax >= 1); \ 113 tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \ 114 tl_assert(_cache->inUse >= 0); \ 115 tl_assert(_cache->inUse <= _cache->dynMax); \ 116 if (_cache->inUse < _cache->dynMax) \ 117 _cache->inUse++; \ 118 for (_i = _cache->inUse-1; _i >= 1; _i--) \ 119 _cache->ent[_i] = _cache->ent[_i-1]; \ 120 _cache->ent[0].arg1 = _arg1; \ 121 _cache->ent[0].arg2 = _arg2; \ 122 _cache->ent[0].res = _res; \ 123 } while (0) 124 125 126 //------------------------------------------------------------------// 127 //--- WordSet ---// 128 //--- Implementation ---// 129 //------------------------------------------------------------------// 130 131 typedef 132 struct { 133 WordSetU* owner; /* for sanity checking */ 134 UWord* words; 135 UWord size; /* Really this should be SizeT */ 136 } 137 WordVec; 138 139 /* ix2vec[0 .. ix2vec_used-1] are pointers to the lock sets (WordVecs) 140 really. vec2ix is the inverse mapping, mapping WordVec* to the 141 corresponding ix2vec entry number. The two mappings are mutually 142 redundant. */ 143 struct _WordSetU { 144 void* (*alloc)(HChar*,SizeT); 145 HChar* cc; 146 void (*dealloc)(void*); 147 WordFM* vec2ix; /* WordVec-to-WordSet mapping tree */ 148 WordVec** ix2vec; /* WordSet-to-WordVec mapping array */ 149 UWord ix2vec_size; 150 UWord ix2vec_used; 151 WordSet empty; /* cached, for speed */ 152 /* Caches for some operations */ 153 WCache cache_addTo; 154 WCache cache_delFrom; 155 WCache cache_intersect; 156 WCache cache_minus; 157 /* Stats */ 158 UWord n_add; 159 UWord n_add_uncached; 160 UWord n_del; 161 UWord n_del_uncached; 162 UWord n_union; 163 UWord n_intersect; 164 UWord n_intersect_uncached; 165 UWord n_minus; 166 UWord n_minus_uncached; 167 UWord n_elem; 168 UWord n_doubleton; 169 UWord n_isEmpty; 170 UWord n_isSingleton; 171 UWord n_anyElementOf; 172 UWord n_isSubsetOf; 173 }; 174 175 /* Create a new WordVec of the given size. */ 176 177 static WordVec* new_WV_of_size ( WordSetU* wsu, UWord sz ) 178 { 179 WordVec* wv; 180 tl_assert(sz >= 0); 181 wv = wsu->alloc( wsu->cc, sizeof(WordVec) ); 182 wv->owner = wsu; 183 wv->words = NULL; 184 wv->size = sz; 185 if (sz > 0) { 186 wv->words = wsu->alloc( wsu->cc, (SizeT)sz * sizeof(UWord) ); 187 } 188 return wv; 189 } 190 191 static void delete_WV ( WordVec* wv ) 192 { 193 void (*dealloc)(void*) = wv->owner->dealloc; 194 if (wv->words) { 195 dealloc(wv->words); 196 } 197 dealloc(wv); 198 } 199 static void delete_WV_for_FM ( UWord wv ) { 200 delete_WV( (WordVec*)wv ); 201 } 202 203 static Word cmp_WordVecs_for_FM ( UWord wv1W, UWord wv2W ) 204 { 205 UWord i; 206 WordVec* wv1 = (WordVec*)wv1W; 207 WordVec* wv2 = (WordVec*)wv2W; 208 UWord common = wv1->size < wv2->size ? wv1->size : wv2->size; 209 for (i = 0; i < common; i++) { 210 if (wv1->words[i] == wv2->words[i]) 211 continue; 212 if (wv1->words[i] < wv2->words[i]) 213 return -1; 214 if (wv1->words[i] > wv2->words[i]) 215 return 1; 216 tl_assert(0); 217 } 218 /* Ok, the common sections are identical. So now consider the 219 tails. Both sets are considered to finish in an implied 220 sequence of -infinity. */ 221 if (wv1->size < wv2->size) { 222 tl_assert(common == wv1->size); 223 return -1; /* impliedly, wv1 contains some -infinitys in places 224 where wv2 doesn't. */ 225 } 226 if (wv1->size > wv2->size) { 227 tl_assert(common == wv2->size); 228 return 1; 229 } 230 tl_assert(common == wv1->size); 231 return 0; /* identical */ 232 } 233 234 static void ensure_ix2vec_space ( WordSetU* wsu ) 235 { 236 UInt i, new_sz; 237 WordVec** new_vec; 238 tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size); 239 if (wsu->ix2vec_used < wsu->ix2vec_size) 240 return; 241 new_sz = 2 * wsu->ix2vec_size; 242 if (new_sz == 0) new_sz = 2; 243 new_vec = wsu->alloc( wsu->cc, new_sz * sizeof(WordVec*) ); 244 tl_assert(new_vec); 245 for (i = 0; i < wsu->ix2vec_size; i++) 246 new_vec[i] = wsu->ix2vec[i]; 247 if (wsu->ix2vec) 248 wsu->dealloc(wsu->ix2vec); 249 wsu->ix2vec = new_vec; 250 wsu->ix2vec_size = new_sz; 251 } 252 253 /* Index into a WordSetU, doing the obvious range check. Failure of 254 the assertions marked XXX and YYY is an indication of passing the 255 wrong WordSetU* in the public API of this module. */ 256 static WordVec* do_ix2vec ( WordSetU* wsu, WordSet ws ) 257 { 258 WordVec* wv; 259 tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size); 260 if (wsu->ix2vec_used > 0) 261 tl_assert(wsu->ix2vec); 262 /* If this assertion fails, it may mean you supplied a 'ws' 263 that does not come from the 'wsu' universe. */ 264 tl_assert(ws < wsu->ix2vec_used); /* XXX */ 265 wv = wsu->ix2vec[ws]; 266 /* Make absolutely sure that 'ws' is a member of 'wsu'. */ 267 tl_assert(wv); 268 tl_assert(wv->owner == wsu); /* YYY */ 269 return wv; 270 } 271 272 /* See if wv is contained within wsu. If so, deallocate wv and return 273 the index of the already-present copy. If not, add wv to both the 274 vec2ix and ix2vec mappings and return its index. 275 */ 276 static WordSet add_or_dealloc_WordVec( WordSetU* wsu, WordVec* wv_new ) 277 { 278 Bool have; 279 WordVec* wv_old; 280 UWord/*Set*/ ix_old = -1; 281 /* Really WordSet, but need something that can safely be casted to 282 a Word* in the lookupFM. Making it WordSet (which is 32 bits) 283 causes failures on a 64-bit platform. */ 284 tl_assert(wv_new->owner == wsu); 285 have = VG_(lookupFM)( wsu->vec2ix, 286 (Word*)&wv_old, (Word*)&ix_old, 287 (Word)wv_new ); 288 if (have) { 289 tl_assert(wv_old != wv_new); 290 tl_assert(wv_old); 291 tl_assert(wv_old->owner == wsu); 292 tl_assert(ix_old < wsu->ix2vec_used); 293 tl_assert(wsu->ix2vec[ix_old] == wv_old); 294 delete_WV( wv_new ); 295 return (WordSet)ix_old; 296 } else { 297 ensure_ix2vec_space( wsu ); 298 tl_assert(wsu->ix2vec); 299 tl_assert(wsu->ix2vec_used < wsu->ix2vec_size); 300 wsu->ix2vec[wsu->ix2vec_used] = wv_new; 301 VG_(addToFM)( wsu->vec2ix, (Word)wv_new, (Word)wsu->ix2vec_used ); 302 if (0) VG_(printf)("aodW %d\n", (Int)wsu->ix2vec_used ); 303 wsu->ix2vec_used++; 304 tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size); 305 return (WordSet)(wsu->ix2vec_used - 1); 306 } 307 } 308 309 310 WordSetU* HG_(newWordSetU) ( void* (*alloc_nofail)( HChar*, SizeT ), 311 HChar* cc, 312 void (*dealloc)(void*), 313 Word cacheSize ) 314 { 315 WordSetU* wsu; 316 WordVec* empty; 317 318 wsu = alloc_nofail( cc, sizeof(WordSetU) ); 319 VG_(memset)( wsu, 0, sizeof(WordSetU) ); 320 wsu->alloc = alloc_nofail; 321 wsu->cc = cc; 322 wsu->dealloc = dealloc; 323 wsu->vec2ix = VG_(newFM)( alloc_nofail, cc, 324 dealloc, cmp_WordVecs_for_FM ); 325 wsu->ix2vec_used = 0; 326 wsu->ix2vec_size = 0; 327 wsu->ix2vec = NULL; 328 WCache_INIT(wsu->cache_addTo, cacheSize); 329 WCache_INIT(wsu->cache_delFrom, cacheSize); 330 WCache_INIT(wsu->cache_intersect, cacheSize); 331 WCache_INIT(wsu->cache_minus, cacheSize); 332 empty = new_WV_of_size( wsu, 0 ); 333 wsu->empty = add_or_dealloc_WordVec( wsu, empty ); 334 335 return wsu; 336 } 337 338 void HG_(deleteWordSetU) ( WordSetU* wsu ) 339 { 340 void (*dealloc)(void*) = wsu->dealloc; 341 tl_assert(wsu->vec2ix); 342 VG_(deleteFM)( wsu->vec2ix, delete_WV_for_FM, NULL/*val-finalizer*/ ); 343 if (wsu->ix2vec) 344 dealloc(wsu->ix2vec); 345 dealloc(wsu); 346 } 347 348 WordSet HG_(emptyWS) ( WordSetU* wsu ) 349 { 350 return wsu->empty; 351 } 352 353 Bool HG_(isEmptyWS) ( WordSetU* wsu, WordSet ws ) 354 { 355 WordVec* wv = do_ix2vec( wsu, ws ); 356 wsu->n_isEmpty++; 357 if (wv->size == 0) { 358 tl_assert(ws == wsu->empty); 359 return True; 360 } else { 361 tl_assert(ws != wsu->empty); 362 return False; 363 } 364 } 365 366 Bool HG_(isSingletonWS) ( WordSetU* wsu, WordSet ws, UWord w ) 367 { 368 WordVec* wv; 369 tl_assert(wsu); 370 wsu->n_isSingleton++; 371 wv = do_ix2vec( wsu, ws ); 372 return (Bool)(wv->size == 1 && wv->words[0] == w); 373 } 374 375 UWord HG_(cardinalityWS) ( WordSetU* wsu, WordSet ws ) 376 { 377 WordVec* wv; 378 tl_assert(wsu); 379 wv = do_ix2vec( wsu, ws ); 380 tl_assert(wv->size >= 0); 381 return wv->size; 382 } 383 384 UWord HG_(anyElementOfWS) ( WordSetU* wsu, WordSet ws ) 385 { 386 WordVec* wv; 387 tl_assert(wsu); 388 wsu->n_anyElementOf++; 389 wv = do_ix2vec( wsu, ws ); 390 tl_assert(wv->size >= 1); 391 return wv->words[0]; 392 } 393 394 UWord HG_(cardinalityWSU) ( WordSetU* wsu ) 395 { 396 tl_assert(wsu); 397 return wsu->ix2vec_used; 398 } 399 400 void HG_(getPayloadWS) ( /*OUT*/UWord** words, /*OUT*/UWord* nWords, 401 WordSetU* wsu, WordSet ws ) 402 { 403 WordVec* wv; 404 tl_assert(wsu); 405 wv = do_ix2vec( wsu, ws ); 406 tl_assert(wv->size >= 0); 407 *nWords = wv->size; 408 *words = wv->words; 409 } 410 411 Bool HG_(plausibleWS) ( WordSetU* wsu, WordSet ws ) 412 { 413 if (wsu == NULL) return False; 414 if (ws < 0 || ws >= wsu->ix2vec_used) 415 return False; 416 return True; 417 } 418 419 Bool HG_(saneWS_SLOW) ( WordSetU* wsu, WordSet ws ) 420 { 421 WordVec* wv; 422 UWord i; 423 if (wsu == NULL) return False; 424 if (ws < 0 || ws >= wsu->ix2vec_used) 425 return False; 426 wv = do_ix2vec( wsu, ws ); 427 /* can never happen .. do_ix2vec will assert instead. Oh well. */ 428 if (wv->owner != wsu) return False; 429 if (wv->size < 0) return False; 430 if (wv->size > 0) { 431 for (i = 0; i < wv->size-1; i++) { 432 if (wv->words[i] >= wv->words[i+1]) 433 return False; 434 } 435 } 436 return True; 437 } 438 439 Bool HG_(elemWS) ( WordSetU* wsu, WordSet ws, UWord w ) 440 { 441 UWord i; 442 WordVec* wv = do_ix2vec( wsu, ws ); 443 wsu->n_elem++; 444 for (i = 0; i < wv->size; i++) { 445 if (wv->words[i] == w) 446 return True; 447 } 448 return False; 449 } 450 451 WordSet HG_(doubletonWS) ( WordSetU* wsu, UWord w1, UWord w2 ) 452 { 453 WordVec* wv; 454 wsu->n_doubleton++; 455 if (w1 == w2) { 456 wv = new_WV_of_size(wsu, 1); 457 wv->words[0] = w1; 458 } 459 else if (w1 < w2) { 460 wv = new_WV_of_size(wsu, 2); 461 wv->words[0] = w1; 462 wv->words[1] = w2; 463 } 464 else { 465 tl_assert(w1 > w2); 466 wv = new_WV_of_size(wsu, 2); 467 wv->words[0] = w2; 468 wv->words[1] = w1; 469 } 470 return add_or_dealloc_WordVec( wsu, wv ); 471 } 472 473 WordSet HG_(singletonWS) ( WordSetU* wsu, UWord w ) 474 { 475 return HG_(doubletonWS)( wsu, w, w ); 476 } 477 478 WordSet HG_(isSubsetOf) ( WordSetU* wsu, WordSet small, WordSet big ) 479 { 480 wsu->n_isSubsetOf++; 481 return small == HG_(intersectWS)( wsu, small, big ); 482 } 483 484 void HG_(ppWS) ( WordSetU* wsu, WordSet ws ) 485 { 486 UWord i; 487 WordVec* wv; 488 tl_assert(wsu); 489 wv = do_ix2vec( wsu, ws ); 490 VG_(printf)("{"); 491 for (i = 0; i < wv->size; i++) { 492 VG_(printf)("%p", (void*)wv->words[i]); 493 if (i < wv->size-1) 494 VG_(printf)(","); 495 } 496 VG_(printf)("}"); 497 } 498 499 void HG_(ppWSUstats) ( WordSetU* wsu, HChar* name ) 500 { 501 VG_(printf)(" WordSet \"%s\":\n", name); 502 VG_(printf)(" addTo %10lu (%lu uncached)\n", 503 wsu->n_add, wsu->n_add_uncached); 504 VG_(printf)(" delFrom %10lu (%lu uncached)\n", 505 wsu->n_del, wsu->n_del_uncached); 506 VG_(printf)(" union %10lu\n", wsu->n_union); 507 VG_(printf)(" intersect %10lu (%lu uncached) " 508 "[nb. incl isSubsetOf]\n", 509 wsu->n_intersect, wsu->n_intersect_uncached); 510 VG_(printf)(" minus %10lu (%lu uncached)\n", 511 wsu->n_minus, wsu->n_minus_uncached); 512 VG_(printf)(" elem %10lu\n", wsu->n_elem); 513 VG_(printf)(" doubleton %10lu\n", wsu->n_doubleton); 514 VG_(printf)(" isEmpty %10lu\n", wsu->n_isEmpty); 515 VG_(printf)(" isSingleton %10lu\n", wsu->n_isSingleton); 516 VG_(printf)(" anyElementOf %10lu\n", wsu->n_anyElementOf); 517 VG_(printf)(" isSubsetOf %10lu\n", wsu->n_isSubsetOf); 518 } 519 520 WordSet HG_(addToWS) ( WordSetU* wsu, WordSet ws, UWord w ) 521 { 522 UWord k, j; 523 WordVec* wv_new; 524 WordVec* wv; 525 WordSet result = (WordSet)(-1); /* bogus */ 526 527 wsu->n_add++; 528 WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_addTo, ws, w); 529 wsu->n_add_uncached++; 530 531 /* If already present, this is a no-op. */ 532 wv = do_ix2vec( wsu, ws ); 533 for (k = 0; k < wv->size; k++) { 534 if (wv->words[k] == w) { 535 result = ws; 536 goto out; 537 } 538 } 539 /* Ok, not present. Build a new one ... */ 540 wv_new = new_WV_of_size( wsu, wv->size + 1 ); 541 k = j = 0; 542 for (; k < wv->size && wv->words[k] < w; k++) { 543 wv_new->words[j++] = wv->words[k]; 544 } 545 wv_new->words[j++] = w; 546 for (; k < wv->size; k++) { 547 tl_assert(wv->words[k] > w); 548 wv_new->words[j++] = wv->words[k]; 549 } 550 tl_assert(j == wv_new->size); 551 552 /* Find any existing copy, or add the new one. */ 553 result = add_or_dealloc_WordVec( wsu, wv_new ); 554 tl_assert(result != (WordSet)(-1)); 555 556 out: 557 WCache_UPDATE(wsu->cache_addTo, ws, w, result); 558 return result; 559 } 560 561 WordSet HG_(delFromWS) ( WordSetU* wsu, WordSet ws, UWord w ) 562 { 563 UWord i, j, k; 564 WordVec* wv_new; 565 WordSet result = (WordSet)(-1); /* bogus */ 566 WordVec* wv = do_ix2vec( wsu, ws ); 567 568 wsu->n_del++; 569 570 /* special case empty set */ 571 if (wv->size == 0) { 572 tl_assert(ws == wsu->empty); 573 return ws; 574 } 575 576 WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_delFrom, ws, w); 577 wsu->n_del_uncached++; 578 579 /* If not already present, this is a no-op. */ 580 for (i = 0; i < wv->size; i++) { 581 if (wv->words[i] == w) 582 break; 583 } 584 if (i == wv->size) { 585 result = ws; 586 goto out; 587 } 588 /* So w is present in ws, and the new set will be one element 589 smaller. */ 590 tl_assert(i >= 0 && i < wv->size); 591 tl_assert(wv->size > 0); 592 593 wv_new = new_WV_of_size( wsu, wv->size - 1 ); 594 j = k = 0; 595 for (; j < wv->size; j++) { 596 if (j == i) 597 continue; 598 wv_new->words[k++] = wv->words[j]; 599 } 600 tl_assert(k == wv_new->size); 601 602 result = add_or_dealloc_WordVec( wsu, wv_new ); 603 if (wv->size == 1) { 604 tl_assert(result == wsu->empty); 605 } 606 607 out: 608 WCache_UPDATE(wsu->cache_delFrom, ws, w, result); 609 return result; 610 } 611 612 WordSet HG_(unionWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) 613 { 614 UWord i1, i2, k, sz; 615 WordVec* wv_new; 616 WordVec* wv1 = do_ix2vec( wsu, ws1 ); 617 WordVec* wv2 = do_ix2vec( wsu, ws2 ); 618 wsu->n_union++; 619 sz = 0; 620 i1 = i2 = 0; 621 while (1) { 622 if (i1 >= wv1->size || i2 >= wv2->size) 623 break; 624 sz++; 625 if (wv1->words[i1] < wv2->words[i2]) { 626 i1++; 627 } else 628 if (wv1->words[i1] > wv2->words[i2]) { 629 i2++; 630 } else { 631 i1++; 632 i2++; 633 } 634 } 635 tl_assert(i1 <= wv1->size); 636 tl_assert(i2 <= wv2->size); 637 tl_assert(i1 == wv1->size || i2 == wv2->size); 638 if (i1 == wv1->size && i2 < wv2->size) { 639 sz += (wv2->size - i2); 640 } 641 if (i2 == wv2->size && i1 < wv1->size) { 642 sz += (wv1->size - i1); 643 } 644 645 wv_new = new_WV_of_size( wsu, sz ); 646 k = 0; 647 648 i1 = i2 = 0; 649 while (1) { 650 if (i1 >= wv1->size || i2 >= wv2->size) 651 break; 652 if (wv1->words[i1] < wv2->words[i2]) { 653 wv_new->words[k++] = wv1->words[i1]; 654 i1++; 655 } else 656 if (wv1->words[i1] > wv2->words[i2]) { 657 wv_new->words[k++] = wv2->words[i2]; 658 i2++; 659 } else { 660 wv_new->words[k++] = wv1->words[i1]; 661 i1++; 662 i2++; 663 } 664 } 665 tl_assert(i1 <= wv1->size); 666 tl_assert(i2 <= wv2->size); 667 tl_assert(i1 == wv1->size || i2 == wv2->size); 668 if (i1 == wv1->size && i2 < wv2->size) { 669 while (i2 < wv2->size) 670 wv_new->words[k++] = wv2->words[i2++]; 671 } 672 if (i2 == wv2->size && i1 < wv1->size) { 673 while (i1 < wv1->size) 674 wv_new->words[k++] = wv1->words[i1++]; 675 } 676 677 tl_assert(k == sz); 678 679 return add_or_dealloc_WordVec( wsu, wv_new ); 680 } 681 682 WordSet HG_(intersectWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) 683 { 684 UWord i1, i2, k, sz; 685 WordSet ws_new = (WordSet)(-1); /* bogus */ 686 WordVec* wv_new; 687 WordVec* wv1; 688 WordVec* wv2; 689 690 wsu->n_intersect++; 691 692 /* Deal with an obvious case fast. */ 693 if (ws1 == ws2) 694 return ws1; 695 696 /* Since intersect(x,y) == intersect(y,x), convert both variants to 697 the same query. This reduces the number of variants the cache 698 has to deal with. */ 699 if (ws1 > ws2) { 700 WordSet wst = ws1; ws1 = ws2; ws2 = wst; 701 } 702 703 WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_intersect, ws1, ws2); 704 wsu->n_intersect_uncached++; 705 706 wv1 = do_ix2vec( wsu, ws1 ); 707 wv2 = do_ix2vec( wsu, ws2 ); 708 sz = 0; 709 i1 = i2 = 0; 710 while (1) { 711 if (i1 >= wv1->size || i2 >= wv2->size) 712 break; 713 if (wv1->words[i1] < wv2->words[i2]) { 714 i1++; 715 } else 716 if (wv1->words[i1] > wv2->words[i2]) { 717 i2++; 718 } else { 719 sz++; 720 i1++; 721 i2++; 722 } 723 } 724 tl_assert(i1 <= wv1->size); 725 tl_assert(i2 <= wv2->size); 726 tl_assert(i1 == wv1->size || i2 == wv2->size); 727 728 wv_new = new_WV_of_size( wsu, sz ); 729 k = 0; 730 731 i1 = i2 = 0; 732 while (1) { 733 if (i1 >= wv1->size || i2 >= wv2->size) 734 break; 735 if (wv1->words[i1] < wv2->words[i2]) { 736 i1++; 737 } else 738 if (wv1->words[i1] > wv2->words[i2]) { 739 i2++; 740 } else { 741 wv_new->words[k++] = wv1->words[i1]; 742 i1++; 743 i2++; 744 } 745 } 746 tl_assert(i1 <= wv1->size); 747 tl_assert(i2 <= wv2->size); 748 tl_assert(i1 == wv1->size || i2 == wv2->size); 749 750 tl_assert(k == sz); 751 752 ws_new = add_or_dealloc_WordVec( wsu, wv_new ); 753 if (sz == 0) { 754 tl_assert(ws_new == wsu->empty); 755 } 756 757 tl_assert(ws_new != (WordSet)(-1)); 758 WCache_UPDATE(wsu->cache_intersect, ws1, ws2, ws_new); 759 760 return ws_new; 761 } 762 763 WordSet HG_(minusWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) 764 { 765 UWord i1, i2, k, sz; 766 WordSet ws_new = (WordSet)(-1); /* bogus */ 767 WordVec* wv_new; 768 WordVec* wv1; 769 WordVec* wv2; 770 771 wsu->n_minus++; 772 WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_minus, ws1, ws2); 773 wsu->n_minus_uncached++; 774 775 wv1 = do_ix2vec( wsu, ws1 ); 776 wv2 = do_ix2vec( wsu, ws2 ); 777 sz = 0; 778 i1 = i2 = 0; 779 while (1) { 780 if (i1 >= wv1->size || i2 >= wv2->size) 781 break; 782 if (wv1->words[i1] < wv2->words[i2]) { 783 sz++; 784 i1++; 785 } else 786 if (wv1->words[i1] > wv2->words[i2]) { 787 i2++; 788 } else { 789 i1++; 790 i2++; 791 } 792 } 793 tl_assert(i1 <= wv1->size); 794 tl_assert(i2 <= wv2->size); 795 tl_assert(i1 == wv1->size || i2 == wv2->size); 796 if (i2 == wv2->size && i1 < wv1->size) { 797 sz += (wv1->size - i1); 798 } 799 800 wv_new = new_WV_of_size( wsu, sz ); 801 k = 0; 802 803 i1 = i2 = 0; 804 while (1) { 805 if (i1 >= wv1->size || i2 >= wv2->size) 806 break; 807 if (wv1->words[i1] < wv2->words[i2]) { 808 wv_new->words[k++] = wv1->words[i1]; 809 i1++; 810 } else 811 if (wv1->words[i1] > wv2->words[i2]) { 812 i2++; 813 } else { 814 i1++; 815 i2++; 816 } 817 } 818 tl_assert(i1 <= wv1->size); 819 tl_assert(i2 <= wv2->size); 820 tl_assert(i1 == wv1->size || i2 == wv2->size); 821 if (i2 == wv2->size && i1 < wv1->size) { 822 while (i1 < wv1->size) 823 wv_new->words[k++] = wv1->words[i1++]; 824 } 825 826 tl_assert(k == sz); 827 828 ws_new = add_or_dealloc_WordVec( wsu, wv_new ); 829 if (sz == 0) { 830 tl_assert(ws_new == wsu->empty); 831 } 832 833 tl_assert(ws_new != (WordSet)(-1)); 834 WCache_UPDATE(wsu->cache_minus, ws1, ws2, ws_new); 835 836 return ws_new; 837 } 838 839 static __attribute__((unused)) 840 void show_WS ( WordSetU* wsu, WordSet ws ) 841 { 842 UWord i; 843 WordVec* wv = do_ix2vec( wsu, ws ); 844 VG_(printf)("#%u{", ws); 845 for (i = 0; i < wv->size; i++) { 846 VG_(printf)("%lu", wv->words[i]); 847 if (i < wv->size-1) 848 VG_(printf)(","); 849 } 850 VG_(printf)("}\n"); 851 } 852 853 //------------------------------------------------------------------// 854 //--- end WordSet ---// 855 //--- Implementation ---// 856 //------------------------------------------------------------------// 857 858 /*--------------------------------------------------------------------*/ 859 /*--- end hg_wordset.c ---*/ 860 /*--------------------------------------------------------------------*/ 861