// // Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved. // #ifndef UTIL_HPP_ #define UTIL_HPP_ #include "top.hpp" #include "thread/atomic.hpp" #include namespace amd { /*! \addtogroup Utils Utilities * @{ */ //! \cond ignore template struct PairElement; template <> struct PairElement<0> { template static inline F& get(pair& p) { return p.first; } template static inline const F& get(const pair& p) { return p.first; } }; template <> struct PairElement<1> { template static inline S& get(pair& p) { return p.second; } template static inline const S& get(const pair& p) { return p.second; } }; // Forward declaration of the tuple_elements container class. template struct TupleElementsContainer; /*! \brief Return the type of the Nth element in the tuple. */ template struct TupleElementType { typedef typename T::tail_t next_element; typedef typename TupleElementType::type type; }; // break the recursion template struct TupleElementType<0,T> { typedef Null next_element; typedef typename T::head_t type; }; /*! \brief Helper struct to extract the Nth element from a tuple */ template struct TupleElementGetter { template static R get(TupleElementsContainer& t) { return TupleElementGetter::template get(t.tail); } template static R get(const TupleElementsContainer& t) { return TupleElementGetter::template get(t.tail); } }; // break the recursion template <> struct TupleElementGetter<0> { template static R get(TupleElementsContainer& t) { return t.head; } template static R get(const TupleElementsContainer& t) { return t.head; } }; /*! \brief Return the Nth element in the tuple. */ template inline typename TupleElementType >::type& getTupleElement(TupleElementsContainer& t) { return TupleElementGetter::template get< typename TupleElementType >::type&, H,T>(t); } template inline const typename TupleElementType >::type& getTupleElement(const TupleElementsContainer& t) { return TupleElementGetter::template get< const typename TupleElementType >::type&, H,T>(t); } /*! \brief The tuple elements struct */ template struct TupleElementsContainer { typedef H head_t; typedef T tail_t; head_t head; tail_t tail; TupleElementsContainer() : head(), tail() { } template TupleElementsContainer(T0& t0, T1& t1, T2& t2, T3& t3) : head(t0), tail(t1, t2, t3, null()) { } template TupleElementsContainer& operator= (const TupleElementsContainer& t) { head = t.head; tail = t.tail; return *this; } template TupleElementsContainer& operator= (const pair& p) { head = p.first; tail.head = p.second; return *this; } template typename TupleElementType::type& get() { return getTupleElement(*this); } }; // break the recursion template struct TupleElementsContainer { typedef H head_t; typedef Null tail_t; H head; TupleElementsContainer() : head() { } template TupleElementsContainer(T0& t0, const Null&, const Null&, const Null&) : head(t0) { } template TupleElementsContainer& operator = ( const TupleElementsContainer& t) { head = t.head; return *this; } template typename TupleElementType::type& get() { return getTupleElement(*this); } }; /*! \brief Rebind the TupleElementsContainer type. */ template struct TupleElementsBinder { typedef TupleElementsContainer< T0, typename TupleElementsBinder::type > type; }; // break the recursion template<> struct TupleElementsBinder { typedef Null type; }; //! \endcond /*! \brief A simple N-element (1 to 4) tuple. */ template class tuple : public TupleElementsBinder::type { private: typedef typename TupleElementsBinder::type base_t; public: tuple() { } tuple(T0 t0) : base_t(t0, null(), null(), null()) { } tuple(T0 t0, T1 t1) : base_t(t0, t1, null(), null()) { } tuple(T0 t0, T1 t1, T2 t2) : base_t(t0, t1, t2, null()) { } tuple(T0 t0, T1 t1, T2 t2, T3 t3) : base_t(t0, t1, t2, t3) { } template tuple(const TupleElementsContainer& te) : base_t(te) { } template tuple& operator = (const TupleElementsContainer& te) { base_t::operator = (te); return *this; } template tuple& operator = (const pair& p) { base_t::operator = (p); return *this; } }; // tuple / pair element getters. template inline typename TupleElementType >::type& get(TupleElementsContainer& te) { return getTupleElement(te); } template inline const typename TupleElementType >::type& get(const TupleElementsContainer& te) { return getTupleElement(te); } template inline typename TupleElementType >::type& get(pair& p) { return PairElement::get(p); } template inline const typename TupleElementType >::type& get(const pair& p) { return PairElement::get(p); } // Some tuple helpers (make_tuple() and tie()) template inline tuple make_tuple(const T0& t0) { return tuple(t0); } template inline tuple make_tuple(const T0& t0, const T1& t1) { return tuple(t0, t1); } template inline tuple make_tuple(const T0& t0, const T1& t1, const T2& t2) { return tuple(t0, t1, t2); } template inline tuple make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3) { return tuple(t0, t1, t2, t3); } template inline tuple tie(T0& t0) { return tuple(t0); } template inline tuple tie(T0& t0, T1& t1) { return tuple(t0, t1); } template inline tuple tie(T0& t0, T1& t1, T2& t2) { return tuple(t0, t1, t2); } template inline tuple tie(T0& t0, T1& t1, T2& t2, T3& t3) { return tuple(t0, t1, t2, t3); } //! \brief Check if the given value \a val is a power of 2. template static inline bool isPowerOfTwo(T val) { return (val & (val - 1)) == 0; } //! \cond ignore // Compute the next power of 2 helper. template struct NextPowerOfTwoFunction { template static T compute(T val) { val = NextPowerOfTwoFunction::compute(val); return (val >> N) | val; } }; // Specialized version for <1> to break the recursion. template <> struct NextPowerOfTwoFunction<1> { template static T compute(T val) { return (val >> 1) | val; } }; template struct NextPowerOfTwoHelper { static const uint prev = NextPowerOfTwoHelper::value; static const uint value = (prev >> S) | prev; }; template struct NextPowerOfTwoHelper { static const int value = (N >> 1) | N; }; template struct NextPowerOfTwo { static const uint value = NextPowerOfTwoHelper::value + 1; }; //! \endcond /*! \brief Return the next power of two for a value of type T. * * The compute function is (with n = sizeof(T)*8): * * val = (val >> 1) | val; * val = (val >> 2) | val; * ... * val = (val >> n/4) | val; * val = (val >> n/2) | val; * * The next power of two is: 1+compute(val-1) */ template inline T nextPowerOfTwo(T val) { return NextPowerOfTwoFunction::compute(val - 1) + 1; } // Compute log2(N) template struct Log2 { static const uint value = Log2::value + 1; }; // Break the recursion template <> struct Log2<1> { static const uint value = 0; }; /*! \brief Return the log2 for a value of type T. * * The compute function is (with n = sizeof(T)*8): * * uint l = 0; * if (val >= 1 << n/2) { val >>= n/2; l |= n/2; } * if (val >= 1 << n/4) { val >>= n/4; l |= n/4; } * ... * if (val >= 1 << 2) { val >>= 2; l |= 2; } * if (val >= 1 << 1) { l |= 1; } * return l; */ template struct Log2Function { template static uint compute(T val) { uint l = 0; if (val >= T(1) << N) { val >>= N; l = N; } return l + Log2Function::compute(val); } }; template <> struct Log2Function<1> { template static uint compute(T val) { return (val >= T(1)<<1) ? 1 : 0; } }; // log2 helper function template inline uint log2(T val) { return Log2Function::compute(val); } template inline T alignDown(T value, size_t alignment) { return (T) (value & ~(alignment - 1)); } template inline T* alignDown(T* value, size_t alignment) { return (T*) alignDown((intptr_t) value, alignment); } template inline T alignUp(T value, size_t alignment) { return alignDown((T) (value + alignment - 1), alignment); } template inline T* alignUp(T* value, size_t alignment) { return (T*) alignDown((intptr_t) (value + alignment - 1), alignment); } template struct SimplyLinkedNode : public AllocClass { typedef SimplyLinkedNode Node; protected: Atomic next_; /*!< \brief The next element. */ T volatile item_; public: //! \brief Return the next element in the linked-list. Node* next() const { return next_; } //! \brief Return the item. T item() const { return item_; } //! \brief Set the next element pointer. void setNext(Node* next) { next_ = next; } //! \brief Set the item. void setItem(T item) { item_ = item; } //! \brief Swap the next element pointer. Node* swapNext(Node* next) { return next_.swap(next); } //! \brief Compare and set the next element pointer. bool compareAndSetNext(Node* compare, Node* next) { return next_.compareAndSet(compare, next); } }; /* For the implementation of a doubly-linked list, check: * Lock-Free and Practical * Deques and Doubly Linked * Lists using Single-Word * Compare-And-Swap * * Hakan Sundell, Philippas Tsigas * Department of Computing Science * Chalmers Univ. of Technol. and Goteborg Univ. */ template struct DoublyLinkedNode { typedef SimplyLinkedNode Node; protected: Atomic prev_; //!< The previous element. Atomic next_; //!< The next element. T volatile item_; public: //! \brief Return the previous element in the linked-list. Node* prev() const { return prev_; } //! \brief Return the next element in the linked-list. Node* next() const { return next_; } //! \brief Return the item. T item() const { return item_; } //! \brief Set the previous element pointer. void setPrev(Node* prev) { prev_ = prev; } //! \brief Set the next element pointer. void setNext(Node* next) { next_ = next; } //! \brief Set the item. void setItem(T item) { item_ = item; } //! \brief Swap the previous element pointer. Node* swapPrev(Node* prev) { return prev_.swap(prev); } //! \brief Swap the next element pointer. Node* swapNext( Node* next) { return next_.swap(next); } //! \brief Compare and set the previous element pointer. bool compareAndSetPrev(Node* compare, Node* prev) { return prev_.compareAndSet(compare, prev, false, false); } //! \brief Compare and set the next element pointer. bool compareAndSetNext(Node* compare, Node* next) { return next_.compareAndSet(compare, next, false, false); } }; template struct DeviceMap { Reference ref_; Value value_; }; inline uint countBitsSet32(uint32_t value) { #if __GNUC__ >= 4 return (uint)__builtin_popcount(value); #else value = value - ((value >> 1) & 0x55555555); value = (value & 0x33333333) + ((value >> 2) & 0x33333333); return (uint)(((value + (value >> 4) & 0xF0F0F0F) * 0x1010101) >> 24); #endif } inline uint countBitsSet64(uint64_t value) { #if __GNUC__ >= 4 return (uint)__builtin_popcountll(value); #else value = value - ((value >> 1) & 0x5555555555555555ULL); value = (value & 0x3333333333333333ULL) + ((value >> 2) & 0x3333333333333333ULL); value = (value + (value >> 4)) & 0x0F0F0F0F0F0F0F0FULL; return (uint)((uint64_t)(value * 0x0101010101010101ULL) >> 56); #endif } inline uint leastBitSet32(uint32_t value) { #if defined(_WIN32) unsigned long idx; return _BitScanForward(&idx, (unsigned long)value) ? idx : (uint)-1; #else return value ? __builtin_ctz(value) : (uint)-1; #endif } inline uint leastBitSet64(uint64_t value) { #if defined(_WIN64) unsigned long idx; return _BitScanForward64(&idx, (unsigned __int64)value) ? idx : (uint)-1; #elif defined (__GNUC__) return value ? __builtin_ctzll(value) : (uint)-1; #else static const uint8_t lookup67[67+1] = { 64, 0, 1, 39, 2, 15, 40, 23, 3, 12, 16, 59, 41, 19, 24, 54, 4, -1, 13, 10, 17, 62, 60, 28, 42, 30, 20, 51, 25, 44, 55, 47, 5, 32, -1, 38, 14, 22, 11, 58, 18, 53, 63, 9, 61, 27, 29, 50, 43, 46, 31, 37, 21, 57, 52, 8, 26, 49, 45, 36, 56, 7, 48, 35, 6, 34, 33, -1 }; return (uint)lookup67[((int64_t)value & -(int64_t)value) % 67]; #endif } template inline uint countBitsSet(T value) { return (sizeof(T) == 8) ? countBitsSet64((uint64_t)value) : countBitsSet32((uint32_t)value); } template inline uint leastBitSet(T value) { return (sizeof(T) == 8) ? leastBitSet64((uint64_t)value) : leastBitSet32((uint32_t)value); } /*@}*/} // namespace amd #endif /*UTIL_HPP_*/