| /* | 
 |   This file is part of drd, a thread error detector. | 
 |  | 
 |   Copyright (C) 2006-2012 Bart Van Assche <bvanassche@acm.org>. | 
 |  | 
 |   This program is free software; you can redistribute it and/or | 
 |   modify it under the terms of the GNU General Public License as | 
 |   published by the Free Software Foundation; either version 2 of the | 
 |   License, or (at your option) any later version. | 
 |  | 
 |   This program is distributed in the hope that it will be useful, but | 
 |   WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |   General Public License for more details. | 
 |  | 
 |   You should have received a copy of the GNU General Public License | 
 |   along with this program; if not, write to the Free Software | 
 |   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | 
 |   02111-1307, USA. | 
 |  | 
 |   The GNU General Public License is contained in the file COPYING. | 
 | */ | 
 |  | 
 |  | 
 | #ifndef __DRD_BITMAP_H | 
 | #define __DRD_BITMAP_H | 
 |  | 
 |  | 
 | #include "pub_drd_bitmap.h" | 
 | #include "pub_tool_basics.h" | 
 | #include "pub_tool_oset.h" | 
 | #include "pub_tool_libcbase.h" | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 | #include "pub_tool_libcassert.h" | 
 | #endif | 
 |  | 
 |  | 
 | /* Bitmap representation. A bitmap is a data structure in which two bits are | 
 |  * reserved per 32 bit address: one bit that indicates that the data at the | 
 |  * specified address has been read, and one bit that indicates that the data | 
 |  * has been written to. | 
 |  */ | 
 |  | 
 | /* Client addresses are split into bitfields as follows: | 
 |  * ------------------------------------------------------ | 
 |  * | Address MSB |      Address LSB      | Ignored bits | | 
 |  * ------------------------------------------------------ | 
 |  * | Address MSB | UWord MSB | UWord LSB | Ignored bits | | 
 |  * ------------------------------------------------------ | 
 |  */ | 
 |  | 
 |  | 
 |  | 
 | /* Address MSB / LSB split. */ | 
 |  | 
 |  | 
 | /** Number of least significant address bits that are ignored. */ | 
 | #define ADDR_IGNORED_BITS 0 | 
 | #define ADDR_IGNORED_MASK ((1U << ADDR_IGNORED_BITS) - 1U) | 
 | #define ADDR_GRANULARITY  (1U << ADDR_IGNORED_BITS) | 
 |  | 
 | /** | 
 |  * Round argument a up to a multiple of (1 << ADDR_GRANULARITY), and next | 
 |  * shift it right ADDR_GRANULARITY bits. The expression below is optimized | 
 |  * for the case where a is a constant. | 
 |  */ | 
 | #define SCALED_SIZE(a)                                                  \ | 
 |    (((((a) - 1U) | ADDR_IGNORED_MASK) + 1U) >> ADDR_IGNORED_BITS) | 
 |  | 
 | /** | 
 |  * Number of bits assigned to the least significant component of an address. | 
 |  */ | 
 | #define ADDR_LSB_BITS 12 | 
 |  | 
 | /** | 
 |  * Mask that has to be applied to an address of type Addr in order to | 
 |  * compute the least significant part of an address split, after having | 
 |  * shifted the address bits ADDR_GRANULARITY to the right. | 
 |  */ | 
 | #define ADDR_LSB_MASK (((UWord)1 << ADDR_LSB_BITS) - 1U) | 
 |  | 
 | /** Compute least significant bits of an address of type Addr. */ | 
 | static __inline__ | 
 | UWord address_lsb(const Addr a) | 
 | { return (a >> ADDR_IGNORED_BITS) & ADDR_LSB_MASK; } | 
 |  | 
 | /** | 
 |  * Compute the first address for which address_lsb() is equal to | 
 |  * address_lsb(a). | 
 |  */ | 
 | static __inline__ | 
 | Addr first_address_with_same_lsb(const Addr a) | 
 | { | 
 |    return ((a | ADDR_IGNORED_MASK) ^ ADDR_IGNORED_MASK); | 
 | } | 
 |  | 
 | /** | 
 |  * Compute the first address for which address_lsb() is greater than | 
 |  * address_lsb(a). | 
 |  */ | 
 | static __inline__ | 
 | Addr first_address_with_higher_lsb(const Addr a) | 
 | { | 
 |    return ((a | ADDR_IGNORED_MASK) + 1U); | 
 | } | 
 |  | 
 | /** Compute most significant bits of an address of type Addr. */ | 
 | static __inline__ | 
 | UWord address_msb(const Addr a) | 
 | { return a >> (ADDR_LSB_BITS + ADDR_IGNORED_BITS); } | 
 |  | 
 | static __inline__ | 
 | Addr first_address_with_higher_msb(const Addr a) | 
 | { | 
 |    return ((a | ((ADDR_LSB_MASK << ADDR_IGNORED_BITS) | ADDR_IGNORED_MASK)) | 
 |            + 1U); | 
 | } | 
 |  | 
 | /** | 
 |  * Convert LSB and MSB back into an address. | 
 |  * | 
 |  * @note It is assumed that sizeof(Addr) == sizeof(UWord). | 
 |  */ | 
 | static __inline__ | 
 | Addr make_address(const UWord a1, const UWord a0) | 
 | { | 
 |    return ((a1 << (ADDR_LSB_BITS + ADDR_IGNORED_BITS)) | 
 |            | (a0 << ADDR_IGNORED_BITS)); | 
 | } | 
 |  | 
 |  | 
 |  | 
 |  | 
 |  | 
 | /** Number of bits that fit in a variable of type UWord. */ | 
 | #define BITS_PER_UWORD (8U * sizeof(UWord)) | 
 |  | 
 | /** Log2 of BITS_PER_UWORD. */ | 
 | #if defined(VGA_x86) || defined(VGA_ppc32) || defined(VGA_arm) \ | 
 |     || defined(VGA_mips32) | 
 | #define BITS_PER_BITS_PER_UWORD 5 | 
 | #elif defined(VGA_amd64) || defined(VGA_ppc64) || defined(VGA_s390x) | 
 | #define BITS_PER_BITS_PER_UWORD 6 | 
 | #else | 
 | #error Unknown platform. | 
 | #endif | 
 |  | 
 | /** Number of UWord's needed to store one bit per address LSB. */ | 
 | #define BITMAP1_UWORD_COUNT (1U << (ADDR_LSB_BITS - BITS_PER_BITS_PER_UWORD)) | 
 |  | 
 | /** | 
 |  * Mask that has to be applied to an (Addr >> ADDR_IGNORED_BITS) expression | 
 |  * in order to compute the least significant part of an UWord. | 
 |  */ | 
 | #define UWORD_LSB_MASK (((UWord)1 << BITS_PER_BITS_PER_UWORD) - 1) | 
 |  | 
 | /** | 
 |  * Compute index into bm0[] array. | 
 |  * | 
 |  * @param a Address shifted right ADDR_IGNORED_BITS bits. | 
 |  */ | 
 | static __inline__ | 
 | UWord uword_msb(const UWord a) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(a < (1U << ADDR_LSB_BITS)); | 
 | #endif | 
 |    return a >> BITS_PER_BITS_PER_UWORD; | 
 | } | 
 |  | 
 | /** | 
 |  * Return the least significant bits. | 
 |  * | 
 |  * @param a Address shifted right ADDR_IGNORED_BITS bits. | 
 |  */ | 
 | static __inline__ | 
 | UWord uword_lsb(const UWord a) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(a < (1U << ADDR_LSB_BITS)); | 
 | #endif | 
 |    return a & UWORD_LSB_MASK; | 
 | } | 
 |  | 
 | /** | 
 |  * Compute the highest address lower than a for which | 
 |  * uword_lsb(address_lsb(a)) == 0. | 
 |  * | 
 |  * @param a Address. | 
 |  */ | 
 | static __inline__ | 
 | Addr first_address_with_same_uword_lsb(const Addr a) | 
 | { | 
 |    return (a & (~UWORD_LSB_MASK << ADDR_IGNORED_BITS)); | 
 | } | 
 |  | 
 | /** | 
 |  * First address that will go in the UWord past the one 'a' goes in. | 
 |  * | 
 |  *  @param a Address. | 
 |  */ | 
 | static __inline__ | 
 | Addr first_address_with_higher_uword_msb(const Addr a) | 
 | { | 
 |    return ((a | ((UWORD_LSB_MASK << ADDR_IGNORED_BITS) | ADDR_IGNORED_MASK)) | 
 |            + 1); | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /* Local variables. */ | 
 |  | 
 | static ULong s_bitmap2_creation_count; | 
 |  | 
 |  | 
 |  | 
 | /*********************************************************************/ | 
 | /*           Functions for manipulating a struct bitmap1.            */ | 
 | /*********************************************************************/ | 
 |  | 
 |  | 
 | /* Lowest level, corresponding to the lowest ADDR_LSB_BITS of an address. */ | 
 | struct bitmap1 | 
 | { | 
 |    UWord bm0_r[BITMAP1_UWORD_COUNT]; | 
 |    UWord bm0_w[BITMAP1_UWORD_COUNT]; | 
 | }; | 
 |  | 
 | static __inline__ UWord bm0_mask(const UWord a) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 | #endif | 
 |    return ((UWord)1 << uword_lsb(a)); | 
 | } | 
 |  | 
 | /** Set the bit corresponding to address a in bitmap bm0. */ | 
 | static __inline__ void bm0_set(UWord* bm0, const UWord a) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 | #endif | 
 |    bm0[uword_msb(a)] |= (UWord)1 << uword_lsb(a); | 
 | } | 
 |  | 
 | /** | 
 |  * Set the bits corresponding to all of the addresses in range | 
 |  * [ a << ADDR_IGNORED_BITS .. (a + size) << ADDR_IGNORED_BITS [ | 
 |  * in bitmap bm0. | 
 |  */ | 
 | static __inline__ void bm0_set_range(UWord* bm0, | 
 |                                      const UWord a, const SizeT size) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(size > 0); | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 |    tl_assert(address_msb(make_address(0, a + size - 1)) == 0); | 
 |    tl_assert(uword_msb(a) == uword_msb(a + size - 1)); | 
 | #endif | 
 |    bm0[uword_msb(a)] | 
 |       |= (((UWord)1 << size) - 1) << uword_lsb(a); | 
 | } | 
 |  | 
 | /** Clear the bit corresponding to address a in bitmap bm0. */ | 
 | static __inline__ void bm0_clear(UWord* bm0, const UWord a) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 | #endif | 
 |    bm0[uword_msb(a)] &= ~((UWord)1 << uword_lsb(a)); | 
 | } | 
 |  | 
 | /** | 
 |  * Clear all of the addresses in range | 
 |  * [ a << ADDR_IGNORED_BITS .. (a + size) << ADDR_IGNORED_BITS [ | 
 |  * in bitmap bm0. | 
 |  */ | 
 | static __inline__ void bm0_clear_range(UWord* bm0, | 
 |                                        const UWord a, const SizeT size) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 |    tl_assert(size == 0 || address_msb(make_address(0, a + size - 1)) == 0); | 
 |    tl_assert(size == 0 || uword_msb(a) == uword_msb(a + size - 1)); | 
 | #endif | 
 |    /* | 
 |     * Note: although the expression below yields a correct result even if | 
 |     * size == 0, do not touch bm0[] if size == 0 because this might otherwise | 
 |     * cause an access of memory just past the end of the bm0[] array. | 
 |     */ | 
 |    if (size > 0) | 
 |    { | 
 |       bm0[uword_msb(a)] | 
 |          &= ~((((UWord)1 << size) - 1) << uword_lsb(a)); | 
 |    } | 
 | } | 
 |  | 
 | /** Test whether the bit corresponding to address a is set in bitmap bm0. */ | 
 | static __inline__ UWord bm0_is_set(const UWord* bm0, const UWord a) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 | #endif | 
 |    return (bm0[uword_msb(a)] & ((UWord)1 << uword_lsb(a))); | 
 | } | 
 |  | 
 | /** | 
 |  * Return true if a bit corresponding to any of the addresses in range | 
 |  * [ a << ADDR_IGNORED_BITS .. (a + size) << ADDR_IGNORED_BITS [ | 
 |  * is set in bm0. | 
 |  */ | 
 | static __inline__ UWord bm0_is_any_set(const UWord* bm0, | 
 |                                        const Addr a, const SizeT size) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(size > 0); | 
 |    tl_assert(address_msb(make_address(0, a)) == 0); | 
 |    tl_assert(address_msb(make_address(0, a + size - 1)) == 0); | 
 |    tl_assert(uword_msb(a) == uword_msb(a + size - 1)); | 
 | #endif | 
 |    return (bm0[uword_msb(a)] & ((((UWord)1 << size) - 1) << uword_lsb(a))); | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /*********************************************************************/ | 
 | /*           Functions for manipulating a struct bitmap.             */ | 
 | /*********************************************************************/ | 
 |  | 
 |  | 
 | /* Second level bitmap. */ | 
 | struct bitmap2 | 
 | { | 
 |    Addr           addr;   ///< address_msb(...) | 
 |    Bool           recalc; | 
 |    struct bitmap1 bm1; | 
 | }; | 
 |  | 
 |  | 
 | static void bm2_clear(struct bitmap2* const bm2); | 
 | static __inline__ | 
 | struct bitmap2* bm2_insert(struct bitmap* const bm, const UWord a1); | 
 |  | 
 |  | 
 |  | 
 | /** | 
 |  * Rotate elements cache[0..n-1] such that the element at position n-1 is | 
 |  * moved to position 0. This allows to speed up future cache lookups. | 
 |  */ | 
 | static __inline__ | 
 | void bm_cache_rotate(struct bm_cache_elem cache[], const int n) | 
 | { | 
 | #if 0 | 
 |    struct bm_cache_elem t; | 
 |  | 
 |    tl_assert(2 <= n && n <= 8); | 
 |  | 
 |    t = cache[0]; | 
 |    if (n > 1) | 
 |       cache[0] = cache[1]; | 
 |    if (n > 2) | 
 |       cache[1] = cache[2]; | 
 |    if (n > 3) | 
 |       cache[2] = cache[3]; | 
 |    if (n > 4) | 
 |       cache[3] = cache[4]; | 
 |    if (n > 5) | 
 |       cache[4] = cache[5]; | 
 |    if (n > 6) | 
 |       cache[5] = cache[6]; | 
 |    if (n > 7) | 
 |       cache[6] = cache[7]; | 
 |    cache[n - 1] = t; | 
 | #endif | 
 | } | 
 |  | 
 | static __inline__ | 
 | Bool bm_cache_lookup(struct bitmap* const bm, const UWord a1, | 
 |                      struct bitmap2** bm2) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 |    tl_assert(bm2); | 
 | #endif | 
 |  | 
 | #if DRD_BITMAP_N_CACHE_ELEM > 8 | 
 | #error Please update the code below. | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 1 | 
 |    if (a1 == bm->cache[0].a1) | 
 |    { | 
 |       *bm2 = bm->cache[0].bm2; | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 2 | 
 |    if (a1 == bm->cache[1].a1) | 
 |    { | 
 |       *bm2 = bm->cache[1].bm2; | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 3 | 
 |    if (a1 == bm->cache[2].a1) | 
 |    { | 
 |       *bm2 = bm->cache[2].bm2; | 
 |       bm_cache_rotate(bm->cache, 3); | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 4 | 
 |    if (a1 == bm->cache[3].a1) | 
 |    { | 
 |       *bm2 = bm->cache[3].bm2; | 
 |       bm_cache_rotate(bm->cache, 4); | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 5 | 
 |    if (a1 == bm->cache[4].a1) | 
 |    { | 
 |       *bm2 = bm->cache[4].bm2; | 
 |       bm_cache_rotate(bm->cache, 5); | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 6 | 
 |    if (a1 == bm->cache[5].a1) | 
 |    { | 
 |       *bm2 = bm->cache[5].bm2; | 
 |       bm_cache_rotate(bm->cache, 6); | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 7 | 
 |    if (a1 == bm->cache[6].a1) | 
 |    { | 
 |       *bm2 = bm->cache[6].bm2; | 
 |       bm_cache_rotate(bm->cache, 7); | 
 |       return True; | 
 |    } | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 8 | 
 |    if (a1 == bm->cache[7].a1) | 
 |    { | 
 |       *bm2 = bm->cache[7].bm2; | 
 |       bm_cache_rotate(bm->cache, 8); | 
 |       return True; | 
 |    } | 
 | #endif | 
 |    *bm2 = 0; | 
 |    return False; | 
 | } | 
 |  | 
 | static __inline__ | 
 | void bm_update_cache(struct bitmap* const bm, | 
 |                      const UWord a1, | 
 |                      struct bitmap2* const bm2) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 | #if DRD_BITMAP_N_CACHE_ELEM > 8 | 
 | #error Please update the code below. | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 8 | 
 |    bm->cache[7] = bm->cache[6]; | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 7 | 
 |    bm->cache[6] = bm->cache[5]; | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 6 | 
 |    bm->cache[5] = bm->cache[4]; | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 5 | 
 |    bm->cache[4] = bm->cache[3]; | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 4 | 
 |    bm->cache[3] = bm->cache[2]; | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 3 | 
 |    bm->cache[2] = bm->cache[1]; | 
 | #endif | 
 | #if DRD_BITMAP_N_CACHE_ELEM >= 2 | 
 |    bm->cache[1] = bm->cache[0]; | 
 | #endif | 
 |    bm->cache[0].a1  = a1; | 
 |    bm->cache[0].bm2 = bm2; | 
 | } | 
 |  | 
 | /** | 
 |  * Look up the address a1 in bitmap bm and return a pointer to a potentially | 
 |  * shared second level bitmap. The bitmap where the returned pointer points | 
 |  * at may not be modified by the caller. | 
 |  * | 
 |  * @param a1 client address shifted right by ADDR_LSB_BITS. | 
 |  * @param bm bitmap pointer. | 
 |  */ | 
 | static __inline__ | 
 | const struct bitmap2* bm2_lookup(struct bitmap* const bm, const UWord a1) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    if (! bm_cache_lookup(bm, a1, &bm2)) | 
 |    { | 
 |       bm2 = VG_(OSetGen_Lookup)(bm->oset, &a1); | 
 |       bm_update_cache(bm, a1, bm2); | 
 |    } | 
 |    return bm2; | 
 | } | 
 |  | 
 | /** | 
 |  * Look up the address a1 in bitmap bm and return a pointer to a second | 
 |  * level bitmap that is not shared and hence may be modified. | 
 |  * | 
 |  * @param a1 client address shifted right by ADDR_LSB_BITS. | 
 |  * @param bm bitmap pointer. | 
 |  */ | 
 | static __inline__ | 
 | struct bitmap2* | 
 | bm2_lookup_exclusive(struct bitmap* const bm, const UWord a1) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    if (! bm_cache_lookup(bm, a1, &bm2)) | 
 |    { | 
 |       bm2 = VG_(OSetGen_Lookup)(bm->oset, &a1); | 
 |    } | 
 |  | 
 |    return bm2; | 
 | } | 
 |  | 
 | /** Clear the content of the second-level bitmap. */ | 
 | static __inline__ | 
 | void bm2_clear(struct bitmap2* const bm2) | 
 | { | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm2); | 
 | #endif | 
 |    VG_(memset)(&bm2->bm1, 0, sizeof(bm2->bm1)); | 
 | } | 
 |  | 
 | /** | 
 |  * Insert an uninitialized second level bitmap for the address a1. | 
 |  * | 
 |  * @param bm bitmap pointer. | 
 |  * @param a1 client address shifted right by ADDR_LSB_BITS. | 
 |  * | 
 |  * @note bitmap2::recalc isn't initialized here on purpose. | 
 |  */ | 
 | static __inline__ | 
 | struct bitmap2* bm2_insert(struct bitmap* const bm, const UWord a1) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    s_bitmap2_creation_count++; | 
 |  | 
 |    bm2 = VG_(OSetGen_AllocNode)(bm->oset, sizeof(*bm2)); | 
 |    bm2->addr = a1; | 
 |    VG_(OSetGen_Insert)(bm->oset, bm2); | 
 |  | 
 |    bm_update_cache(bm, a1, bm2); | 
 |  | 
 |    return bm2; | 
 | } | 
 |  | 
 | static __inline__ | 
 | struct bitmap2* bm2_insert_copy(struct bitmap* const bm, | 
 |                                 struct bitmap2* const bm2) | 
 | { | 
 |    struct bitmap2* bm2_copy; | 
 |  | 
 |    bm2_copy = bm2_insert(bm, bm2->addr); | 
 |    VG_(memcpy)(&bm2_copy->bm1, &bm2->bm1, sizeof(bm2->bm1)); | 
 |    return bm2_copy; | 
 | } | 
 |  | 
 | /** | 
 |  * Look up the address a1 in bitmap bm, and insert it if not found. | 
 |  * The returned second level bitmap may not be modified. | 
 |  * | 
 |  * @param bm bitmap pointer. | 
 |  * @param a1 client address shifted right by ADDR_LSB_BITS. | 
 |  */ | 
 | static __inline__ | 
 | struct bitmap2* bm2_lookup_or_insert(struct bitmap* const bm, const UWord a1) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    if (bm_cache_lookup(bm, a1, &bm2)) | 
 |    { | 
 |       if (bm2 == 0) | 
 |       { | 
 |          bm2 = bm2_insert(bm, a1); | 
 |          bm2_clear(bm2); | 
 |       } | 
 |    } | 
 |    else | 
 |    { | 
 |       bm2 = VG_(OSetGen_Lookup)(bm->oset, &a1); | 
 |       if (! bm2) | 
 |       { | 
 |          bm2 = bm2_insert(bm, a1); | 
 |          bm2_clear(bm2); | 
 |       } | 
 |       bm_update_cache(bm, a1, bm2); | 
 |    } | 
 |    return bm2; | 
 | } | 
 |  | 
 | /** | 
 |  * Look up the address a1 in bitmap bm, and insert it if not found. | 
 |  * The returned second level bitmap may be modified. | 
 |  * | 
 |  * @param a1 client address shifted right by ADDR_LSB_BITS. | 
 |  * @param bm bitmap pointer. | 
 |  */ | 
 | static __inline__ | 
 | struct bitmap2* bm2_lookup_or_insert_exclusive(struct bitmap* const bm, | 
 |                                                const UWord a1) | 
 | { | 
 |    return bm2_lookup_or_insert(bm, a1); | 
 | } | 
 |  | 
 | static __inline__ | 
 | void bm2_remove(struct bitmap* const bm, const UWord a1) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    bm2 = VG_(OSetGen_Remove)(bm->oset, &a1); | 
 |    VG_(OSetGen_FreeNode)(bm->oset, bm2); | 
 |  | 
 |    bm_update_cache(bm, a1, NULL); | 
 | } | 
 |  | 
 | static __inline__ | 
 | void bm_access_aligned_load(struct bitmap* const bm, | 
 |                             const Addr a1, const SizeT size) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    bm2 = bm2_lookup_or_insert_exclusive(bm, address_msb(a1)); | 
 |    bm0_set_range(bm2->bm1.bm0_r, | 
 |                  (a1 >> ADDR_IGNORED_BITS) & ADDR_LSB_MASK, | 
 |                  SCALED_SIZE(size)); | 
 | } | 
 |  | 
 | static __inline__ | 
 | void bm_access_aligned_store(struct bitmap* const bm, | 
 |                              const Addr a1, const SizeT size) | 
 | { | 
 |    struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    bm2 = bm2_lookup_or_insert_exclusive(bm, address_msb(a1)); | 
 |    bm0_set_range(bm2->bm1.bm0_w, | 
 |                  (a1 >> ADDR_IGNORED_BITS) & ADDR_LSB_MASK, | 
 |                  SCALED_SIZE(size)); | 
 | } | 
 |  | 
 | static __inline__ | 
 | Bool bm_aligned_load_has_conflict_with(struct bitmap* const bm, | 
 |                                        const Addr a, const SizeT size) | 
 | { | 
 |    const struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    bm2 = bm2_lookup(bm, address_msb(a)); | 
 |    return (bm2 | 
 |            && bm0_is_any_set(bm2->bm1.bm0_w, | 
 |                              address_lsb(a), | 
 |                              SCALED_SIZE(size))); | 
 | } | 
 |  | 
 | static __inline__ | 
 | Bool bm_aligned_store_has_conflict_with(struct bitmap* const bm, | 
 |                                         const Addr a, const SizeT size) | 
 | { | 
 |    const struct bitmap2* bm2; | 
 |  | 
 | #ifdef ENABLE_DRD_CONSISTENCY_CHECKS | 
 |    tl_assert(bm); | 
 | #endif | 
 |  | 
 |    bm2 = bm2_lookup(bm, address_msb(a)); | 
 |    if (bm2) | 
 |    { | 
 |       if (bm0_is_any_set(bm2->bm1.bm0_r, address_lsb(a), SCALED_SIZE(size)) | 
 |           | bm0_is_any_set(bm2->bm1.bm0_w, address_lsb(a), SCALED_SIZE(size))) | 
 |       { | 
 |          return True; | 
 |       } | 
 |    } | 
 |    return False; | 
 | } | 
 |  | 
 | #endif /* __DRD_BITMAP_H */ |