Edit

kc3-lang/angle/src/common/bitset_utils.h

Branch :

  • Show log

    Commit

  • Author : Qin Jiajia
    Date : 2019-06-11 14:47:59
    Hash : 3f2b4e7f
    Message : Fix the crash in angle_deqp_gles31_tests This crash only happened on a compute test which following a render test. This root case was that after the render test, mVertexArray11 became an invalid pointer. However, compute test still went to the common path to use mVertexArray11. mVertexArray11 is never updated since compute shader doesn't need to triger DIRTY_BIT_VERTEX_ARRAY_BINDING. This patch adds checking to avoid compute test to use mVertexArray11. Besides, more ASSERT checking are added to convenient debugging. Bug: angleproject:3518, angleproject:1663, angleproject:2619 Change-Id: I446214110d762fc259899cef7635f369fa1f59a7 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1652866 Reviewed-by: Geoff Lang <geofflang@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Jiajia Qin <jiajia.qin@intel.com>

  • src/common/bitset_utils.h
  • //
    // Copyright 2015 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // bitset_utils:
    //   Bitset-related helper classes, such as a fast iterator to scan for set bits.
    //
    
    #ifndef COMMON_BITSETITERATOR_H_
    #define COMMON_BITSETITERATOR_H_
    
    #include <stdint.h>
    
    #include <bitset>
    
    #include "common/angleutils.h"
    #include "common/debug.h"
    #include "common/mathutil.h"
    #include "common/platform.h"
    
    namespace angle
    {
    
    template <size_t N, typename BitsT, typename ParamT = std::size_t>
    class BitSetT final
    {
      public:
        class Reference final
        {
          public:
            ~Reference() {}
            Reference &operator=(bool x)
            {
                mParent->set(mBit, x);
                return *this;
            }
            explicit operator bool() const { return mParent->test(mBit); }
    
          private:
            friend class BitSetT;
    
            Reference(BitSetT *parent, ParamT bit) : mParent(parent), mBit(bit) {}
    
            BitSetT *mParent;
            ParamT mBit;
        };
    
        class Iterator final
        {
          public:
            Iterator(const BitSetT &bits);
            Iterator &operator++();
    
            bool operator==(const Iterator &other) const;
            bool operator!=(const Iterator &other) const;
            ParamT operator*() const;
    
            // These helper functions allow mutating an iterator in-flight.
            // They only operate on later bits to ensure we don't iterate the same bit twice.
            void resetLaterBit(std::size_t index)
            {
                ASSERT(index > mCurrentBit);
                mBitsCopy.reset(index);
            }
    
            void setLaterBit(std::size_t index)
            {
                ASSERT(index > mCurrentBit);
                mBitsCopy.set(index);
            }
    
          private:
            std::size_t getNextBit();
    
            BitSetT mBitsCopy;
            std::size_t mCurrentBit;
        };
    
        BitSetT();
        constexpr explicit BitSetT(BitsT value);
    
        BitSetT(const BitSetT &other);
        BitSetT &operator=(const BitSetT &other);
    
        bool operator==(const BitSetT &other) const;
        bool operator!=(const BitSetT &other) const;
    
        constexpr bool operator[](ParamT pos) const;
        Reference operator[](ParamT pos) { return Reference(this, pos); }
    
        bool test(ParamT pos) const;
    
        bool all() const;
        bool any() const;
        bool none() const;
        std::size_t count() const;
    
        constexpr std::size_t size() const { return N; }
    
        BitSetT &operator&=(const BitSetT &other);
        BitSetT &operator|=(const BitSetT &other);
        BitSetT &operator^=(const BitSetT &other);
        BitSetT operator~() const;
    
        BitSetT &operator&=(BitsT value);
        BitSetT &operator|=(BitsT value);
        BitSetT &operator^=(BitsT value);
    
        BitSetT operator<<(std::size_t pos) const;
        BitSetT &operator<<=(std::size_t pos);
        BitSetT operator>>(std::size_t pos) const;
        BitSetT &operator>>=(std::size_t pos);
    
        BitSetT &set();
        BitSetT &set(ParamT pos, bool value = true);
    
        BitSetT &reset();
        BitSetT &reset(ParamT pos);
    
        BitSetT &flip();
        BitSetT &flip(ParamT pos);
    
        unsigned long to_ulong() const { return static_cast<unsigned long>(mBits); }
        BitsT bits() const { return mBits; }
    
        Iterator begin() const { return Iterator(*this); }
        Iterator end() const { return Iterator(BitSetT()); }
    
      private:
        constexpr static BitsT Bit(ParamT x)
        {
            return (static_cast<BitsT>(1) << static_cast<size_t>(x));
        }
        // Produces a mask of ones up to the "x"th bit.
        constexpr static BitsT Mask(std::size_t x)
        {
            return ((Bit(static_cast<ParamT>(x - 1)) - 1) << 1) + 1;
        }
    
        BitsT mBits;
    };
    
    template <size_t N>
    class IterableBitSet : public std::bitset<N>
    {
      public:
        IterableBitSet() {}
        IterableBitSet(const std::bitset<N> &implicitBitSet) : std::bitset<N>(implicitBitSet) {}
    
        class Iterator final
        {
          public:
            Iterator(const std::bitset<N> &bits);
            Iterator &operator++();
    
            bool operator==(const Iterator &other) const;
            bool operator!=(const Iterator &other) const;
            unsigned long operator*() const { return mCurrentBit; }
    
            // These helper functions allow mutating an iterator in-flight.
            // They only operate on later bits to ensure we don't iterate the same bit twice.
            void resetLaterBit(std::size_t index)
            {
                ASSERT(index > mCurrentBit);
                mBits.reset(index - mOffset);
            }
    
            void setLaterBit(std::size_t index)
            {
                ASSERT(index > mCurrentBit);
                mBits.set(index - mOffset);
            }
    
          private:
            unsigned long getNextBit();
    
            static constexpr size_t BitsPerWord = sizeof(uint32_t) * 8;
            std::bitset<N> mBits;
            unsigned long mCurrentBit;
            unsigned long mOffset;
        };
    
        Iterator begin() const { return Iterator(*this); }
        Iterator end() const { return Iterator(std::bitset<N>(0)); }
    };
    
    template <size_t N>
    IterableBitSet<N>::Iterator::Iterator(const std::bitset<N> &bitset)
        : mBits(bitset), mCurrentBit(0), mOffset(0)
    {
        if (mBits.any())
        {
            mCurrentBit = getNextBit();
        }
        else
        {
            mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord));
        }
    }
    
    template <size_t N>
    ANGLE_INLINE typename IterableBitSet<N>::Iterator &IterableBitSet<N>::Iterator::operator++()
    {
        ASSERT(mBits.any());
        mBits.set(mCurrentBit - mOffset, 0);
        mCurrentBit = getNextBit();
        return *this;
    }
    
    template <size_t N>
    bool IterableBitSet<N>::Iterator::operator==(const Iterator &other) const
    {
        return mOffset == other.mOffset && mBits == other.mBits;
    }
    
    template <size_t N>
    bool IterableBitSet<N>::Iterator::operator!=(const Iterator &other) const
    {
        return !(*this == other);
    }
    
    template <size_t N>
    unsigned long IterableBitSet<N>::Iterator::getNextBit()
    {
        // TODO(jmadill): Use 64-bit scan when possible.
        static constexpr std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
    
        while (mOffset < N)
        {
            uint32_t wordBits = static_cast<uint32_t>((mBits & wordMask).to_ulong());
            if (wordBits != 0)
            {
                return gl::ScanForward(wordBits) + mOffset;
            }
    
            mBits >>= BitsPerWord;
            mOffset += BitsPerWord;
        }
        return 0;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT>::BitSetT() : mBits(0)
    {
        static_assert(N > 0, "Bitset type cannot support zero bits.");
        static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    constexpr BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N))
    {}
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
    {}
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator=(const BitSetT &other)
    {
        mBits = other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::operator==(const BitSetT &other) const
    {
        return mBits == other.mBits;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::operator!=(const BitSetT &other) const
    {
        return mBits != other.mBits;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    constexpr bool BitSetT<N, BitsT, ParamT>::operator[](ParamT pos) const
    {
        return test(pos);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::test(ParamT pos) const
    {
        return (mBits & Bit(pos)) != 0;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::all() const
    {
        ASSERT(mBits == (mBits & Mask(N)));
        return mBits == Mask(N);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::any() const
    {
        ASSERT(mBits == (mBits & Mask(N)));
        return (mBits != 0);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::none() const
    {
        ASSERT(mBits == (mBits & Mask(N)));
        return (mBits == 0);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    std::size_t BitSetT<N, BitsT, ParamT>::count() const
    {
        return gl::BitCount(mBits);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(const BitSetT &other)
    {
        mBits &= other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(const BitSetT &other)
    {
        mBits |= other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(const BitSetT &other)
    {
        mBits = mBits ^ other.mBits;
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator~() const
    {
        return BitSetT<N, BitsT, ParamT>(~mBits & Mask(N));
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(BitsT value)
    {
        mBits &= value;
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(BitsT value)
    {
        mBits |= value & Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(BitsT value)
    {
        mBits ^= value & Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator<<(std::size_t pos) const
    {
        return BitSetT<N, BitsT, ParamT>((mBits << pos) & Mask(N));
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator<<=(std::size_t pos)
    {
        mBits = (mBits << pos & Mask(N));
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator>>(std::size_t pos) const
    {
        return BitSetT<N, BitsT, ParamT>(mBits >> pos);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator>>=(std::size_t pos)
    {
        mBits = ((mBits >> pos) & Mask(N));
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::set()
    {
        ASSERT(mBits == (mBits & Mask(N)));
        mBits = Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::set(ParamT pos, bool value)
    {
        ASSERT(mBits == (mBits & Mask(N)));
        if (value)
        {
            mBits |= Bit(pos) & Mask(N);
        }
        else
        {
            reset(pos);
        }
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset()
    {
        ASSERT(mBits == (mBits & Mask(N)));
        mBits = 0;
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset(ParamT pos)
    {
        ASSERT(mBits == (mBits & Mask(N)));
        mBits &= ~Bit(pos);
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::flip()
    {
        ASSERT(mBits == (mBits & Mask(N)));
        mBits ^= Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::flip(ParamT pos)
    {
        ASSERT(mBits == (mBits & Mask(N)));
        mBits ^= Bit(pos) & Mask(N);
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    BitSetT<N, BitsT, ParamT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
    {
        if (bits.any())
        {
            mCurrentBit = getNextBit();
        }
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    ANGLE_INLINE typename BitSetT<N, BitsT, ParamT>::Iterator &BitSetT<N, BitsT, ParamT>::Iterator::
    operator++()
    {
        ASSERT(mBitsCopy.any());
        mBitsCopy.reset(static_cast<ParamT>(mCurrentBit));
        mCurrentBit = getNextBit();
        return *this;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::Iterator::operator==(const Iterator &other) const
    {
        return mBitsCopy == other.mBitsCopy;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    bool BitSetT<N, BitsT, ParamT>::Iterator::operator!=(const Iterator &other) const
    {
        return !(*this == other);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    ParamT BitSetT<N, BitsT, ParamT>::Iterator::operator*() const
    {
        return static_cast<ParamT>(mCurrentBit);
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    std::size_t BitSetT<N, BitsT, ParamT>::Iterator::getNextBit()
    {
        if (mBitsCopy.none())
        {
            return 0;
        }
    
        return gl::ScanForward(mBitsCopy.mBits);
    }
    
    template <size_t N>
    using BitSet32 = BitSetT<N, uint32_t>;
    
    // ScanForward for 64-bits requires a 64-bit implementation.
    #if defined(ANGLE_IS_64_BIT_CPU)
    template <size_t N>
    using BitSet64 = BitSetT<N, uint64_t>;
    #endif  // defined(ANGLE_IS_64_BIT_CPU)
    
    namespace priv
    {
    
    template <size_t N, typename T>
    using EnableIfBitsFit = typename std::enable_if<N <= sizeof(T) * 8>::type;
    
    template <size_t N, typename Enable = void>
    struct GetBitSet
    {
        using Type = IterableBitSet<N>;
    };
    
    // Prefer 64-bit bitsets on 64-bit CPUs. They seem faster than 32-bit.
    #if defined(ANGLE_IS_64_BIT_CPU)
    template <size_t N>
    struct GetBitSet<N, EnableIfBitsFit<N, uint64_t>>
    {
        using Type = BitSet64<N>;
    };
    #else
    template <size_t N>
    struct GetBitSet<N, EnableIfBitsFit<N, uint32_t>>
    {
        using Type = BitSet32<N>;
    };
    #endif  // defined(ANGLE_IS_64_BIT_CPU)
    
    }  // namespace priv
    
    template <size_t N>
    using BitSet = typename priv::GetBitSet<N>::Type;
    
    }  // namespace angle
    
    template <size_t N, typename BitsT, typename ParamT>
    inline angle::BitSetT<N, BitsT, ParamT> operator&(const angle::BitSetT<N, BitsT, ParamT> &lhs,
                                                      const angle::BitSetT<N, BitsT, ParamT> &rhs)
    {
        angle::BitSetT<N, BitsT, ParamT> result(lhs);
        result &= rhs.bits();
        return result;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    inline angle::BitSetT<N, BitsT, ParamT> operator|(const angle::BitSetT<N, BitsT, ParamT> &lhs,
                                                      const angle::BitSetT<N, BitsT, ParamT> &rhs)
    {
        angle::BitSetT<N, BitsT, ParamT> result(lhs);
        result |= rhs.bits();
        return result;
    }
    
    template <size_t N, typename BitsT, typename ParamT>
    inline angle::BitSetT<N, BitsT, ParamT> operator^(const angle::BitSetT<N, BitsT, ParamT> &lhs,
                                                      const angle::BitSetT<N, BitsT, ParamT> &rhs)
    {
        angle::BitSetT<N, BitsT, ParamT> result(lhs);
        result ^= rhs.bits();
        return result;
    }
    
    #endif  // COMMON_BITSETITERATOR_H_