bitutils.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // Copyright (c) 2015-2016 The Khronos Group Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_UTIL_BITUTILS_H_
  15. #define SOURCE_UTIL_BITUTILS_H_
  16. #include <cassert>
  17. #include <cstdint>
  18. #include <cstring>
  19. #include <type_traits>
  20. namespace spvtools {
  21. namespace utils {
  22. // Performs a bitwise copy of source to the destination type Dest.
  23. template <typename Dest, typename Src>
  24. Dest BitwiseCast(Src source) {
  25. Dest dest;
  26. static_assert(sizeof(source) == sizeof(dest),
  27. "BitwiseCast: Source and destination must have the same size");
  28. std::memcpy(&dest, &source, sizeof(dest));
  29. return dest;
  30. }
  31. // Calculates the bit width of the integer type |T|.
  32. template <typename T>
  33. struct IntegerBitWidth {
  34. static_assert(std::is_integral<T>::value, "Integer type required");
  35. static const size_t kBitsPerByte = 8;
  36. static const size_t get = sizeof(T) * kBitsPerByte;
  37. };
  38. // SetBits<T, First, Num> returns an integer of type <T> with bits set
  39. // for position <First> through <First + Num - 1>, counting from the least
  40. // significant bit. In particular when Num == 0, no positions are set to 1.
  41. // A static assert will be triggered if First + Num > sizeof(T) * 8, that is,
  42. // a bit that will not fit in the underlying type is set.
  43. template <typename T, size_t First = 0, size_t Num = 0>
  44. struct SetBits {
  45. static_assert(First < IntegerBitWidth<T>::get,
  46. "Tried to set a bit that is shifted too far.");
  47. const static T get = (T(1) << First) | SetBits<T, First + 1, Num - 1>::get;
  48. };
  49. template <typename T, size_t Last>
  50. struct SetBits<T, Last, 0> {
  51. const static T get = T(0);
  52. };
  53. // This is all compile-time so we can put our tests right here.
  54. static_assert(IntegerBitWidth<uint32_t>::get == 32, "IntegerBitWidth mismatch");
  55. static_assert(IntegerBitWidth<int32_t>::get == 32, "IntegerBitWidth mismatch");
  56. static_assert(IntegerBitWidth<uint64_t>::get == 64, "IntegerBitWidth mismatch");
  57. static_assert(IntegerBitWidth<uint8_t>::get == 8, "IntegerBitWidth mismatch");
  58. static_assert(SetBits<uint32_t, 0, 0>::get == uint32_t(0x00000000),
  59. "SetBits failed");
  60. static_assert(SetBits<uint32_t, 0, 1>::get == uint32_t(0x00000001),
  61. "SetBits failed");
  62. static_assert(SetBits<uint32_t, 31, 1>::get == uint32_t(0x80000000),
  63. "SetBits failed");
  64. static_assert(SetBits<uint32_t, 1, 2>::get == uint32_t(0x00000006),
  65. "SetBits failed");
  66. static_assert(SetBits<uint32_t, 30, 2>::get == uint32_t(0xc0000000),
  67. "SetBits failed");
  68. static_assert(SetBits<uint32_t, 0, 31>::get == uint32_t(0x7FFFFFFF),
  69. "SetBits failed");
  70. static_assert(SetBits<uint32_t, 0, 32>::get == uint32_t(0xFFFFFFFF),
  71. "SetBits failed");
  72. static_assert(SetBits<uint32_t, 16, 16>::get == uint32_t(0xFFFF0000),
  73. "SetBits failed");
  74. static_assert(SetBits<uint64_t, 0, 1>::get == uint64_t(0x0000000000000001LL),
  75. "SetBits failed");
  76. static_assert(SetBits<uint64_t, 63, 1>::get == uint64_t(0x8000000000000000LL),
  77. "SetBits failed");
  78. static_assert(SetBits<uint64_t, 62, 2>::get == uint64_t(0xc000000000000000LL),
  79. "SetBits failed");
  80. static_assert(SetBits<uint64_t, 31, 1>::get == uint64_t(0x0000000080000000LL),
  81. "SetBits failed");
  82. static_assert(SetBits<uint64_t, 16, 16>::get == uint64_t(0x00000000FFFF0000LL),
  83. "SetBits failed");
  84. // Returns number of '1' bits in a word.
  85. template <typename T>
  86. size_t CountSetBits(T word) {
  87. static_assert(std::is_integral<T>::value,
  88. "CountSetBits requires integer type");
  89. uint32_t count = 0;
  90. while (word) {
  91. word &= word - 1;
  92. ++count;
  93. }
  94. return count;
  95. }
  96. // Checks if the bit at the |position| is set to '1'.
  97. // Bits zero-indexed starting at the least significant bit.
  98. // |position| must be within the bit width of |T|.
  99. template <typename T>
  100. bool IsBitAtPositionSet(T word, size_t position) {
  101. static_assert(std::is_integral<T>::value, "Integer type required");
  102. static_assert(std::is_unsigned<T>::value, "Unsigned type required");
  103. assert(position < IntegerBitWidth<T>::get &&
  104. "position must be less than the bit width");
  105. return word & T(T(1) << position);
  106. }
  107. // Returns a value obtained by setting a range of adjacent bits of |word| to
  108. // |value|. Affected bits are within the range:
  109. // [first_position, first_position + num_bits_to_mutate),
  110. // assuming zero-based indexing starting at the least
  111. // significant bit. Bits to mutate must be within the bit width of |T|.
  112. template <typename T>
  113. T MutateBits(T word, size_t first_position, size_t num_bits_to_mutate,
  114. bool value) {
  115. static_assert(std::is_integral<T>::value, "Integer type required");
  116. static_assert(std::is_unsigned<T>::value, "Unsigned type required");
  117. static const size_t word_bit_width = IntegerBitWidth<T>::get;
  118. assert(first_position < word_bit_width &&
  119. "Mutated bits must be within bit width");
  120. assert(first_position + num_bits_to_mutate <= word_bit_width &&
  121. "Mutated bits must be within bit width");
  122. if (num_bits_to_mutate == 0) {
  123. return word;
  124. }
  125. const T all_ones = ~T(0);
  126. const size_t num_unaffected_low_bits = first_position;
  127. const T unaffected_low_mask =
  128. T(T(all_ones >> num_unaffected_low_bits) << num_unaffected_low_bits);
  129. const size_t num_unaffected_high_bits =
  130. word_bit_width - (first_position + num_bits_to_mutate);
  131. const T unaffected_high_mask =
  132. T(T(all_ones << num_unaffected_high_bits) >> num_unaffected_high_bits);
  133. const T mutation_mask = unaffected_low_mask & unaffected_high_mask;
  134. if (value) {
  135. return word | mutation_mask;
  136. }
  137. return word & T(~mutation_mask);
  138. }
  139. // Returns a value obtained by setting the |num_bits_to_set| highest bits to
  140. // '1'. |num_bits_to_set| must be not be greater than the bit width of |T|.
  141. template <typename T>
  142. T SetHighBits(T word, size_t num_bits_to_set) {
  143. if (num_bits_to_set == 0) {
  144. return word;
  145. }
  146. const size_t word_bit_width = IntegerBitWidth<T>::get;
  147. assert(num_bits_to_set <= word_bit_width &&
  148. "Can't set more bits than bit width");
  149. return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
  150. true);
  151. }
  152. // Returns a value obtained by setting the |num_bits_to_set| highest bits to
  153. // '0'. |num_bits_to_set| must be not be greater than the bit width of |T|.
  154. template <typename T>
  155. T ClearHighBits(T word, size_t num_bits_to_set) {
  156. if (num_bits_to_set == 0) {
  157. return word;
  158. }
  159. const size_t word_bit_width = IntegerBitWidth<T>::get;
  160. assert(num_bits_to_set <= word_bit_width &&
  161. "Can't clear more bits than bit width");
  162. return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
  163. false);
  164. }
  165. // Returns the value obtained by extracting the |number_of_bits| least
  166. // significant bits from |value|, and sign-extending it to 64-bits.
  167. template <typename T>
  168. T SignExtendValue(T value, uint32_t number_of_bits) {
  169. const uint32_t bit_width = sizeof(value) * 8;
  170. if (number_of_bits == bit_width) return value;
  171. bool is_negative = utils::IsBitAtPositionSet(value, number_of_bits - 1);
  172. if (is_negative) {
  173. value = utils::SetHighBits(value, bit_width - number_of_bits);
  174. } else {
  175. value = utils::ClearHighBits(value, bit_width - number_of_bits);
  176. }
  177. return value;
  178. }
  179. // Returns the value obtained by extracting the |number_of_bits| least
  180. // significant bits from |value|, and zero-extending it to 64-bits.
  181. template <typename T>
  182. T ZeroExtendValue(T value, uint32_t number_of_bits) {
  183. const uint32_t bit_width = sizeof(value) * 8;
  184. if (number_of_bits == bit_width) return value;
  185. return utils::ClearHighBits(value, bit_width - number_of_bits);
  186. }
  187. } // namespace utils
  188. } // namespace spvtools
  189. #endif // SOURCE_UTIL_BITUTILS_H_