Coverage Report

Created: 2025-11-11 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/shaderc/third_party/spirv-tools/source/util/bitutils.h
Line
Count
Source
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
15
#ifndef SOURCE_UTIL_BITUTILS_H_
16
#define SOURCE_UTIL_BITUTILS_H_
17
18
#include <cassert>
19
#include <cstdint>
20
#include <cstring>
21
#include <type_traits>
22
23
namespace spvtools {
24
namespace utils {
25
26
// Performs a bitwise copy of source to the destination type Dest.
27
template <typename Dest, typename Src>
28
11.3k
Dest BitwiseCast(Src source) {
29
11.3k
  Dest dest;
30
11.3k
  static_assert(sizeof(source) == sizeof(dest),
31
11.3k
                "BitwiseCast: Source and destination must have the same size");
32
11.3k
  std::memcpy(&dest, &source, sizeof(dest));
33
11.3k
  return dest;
34
11.3k
}
float spvtools::utils::BitwiseCast<float, unsigned int>(unsigned int)
Line
Count
Source
28
9.45k
Dest BitwiseCast(Src source) {
29
9.45k
  Dest dest;
30
9.45k
  static_assert(sizeof(source) == sizeof(dest),
31
9.45k
                "BitwiseCast: Source and destination must have the same size");
32
9.45k
  std::memcpy(&dest, &source, sizeof(dest));
33
9.45k
  return dest;
34
9.45k
}
unsigned int spvtools::utils::BitwiseCast<unsigned int, float>(float)
Line
Count
Source
28
1.93k
Dest BitwiseCast(Src source) {
29
1.93k
  Dest dest;
30
1.93k
  static_assert(sizeof(source) == sizeof(dest),
31
1.93k
                "BitwiseCast: Source and destination must have the same size");
32
1.93k
  std::memcpy(&dest, &source, sizeof(dest));
33
1.93k
  return dest;
34
1.93k
}
double spvtools::utils::BitwiseCast<double, unsigned long>(unsigned long)
Line
Count
Source
28
6
Dest BitwiseCast(Src source) {
29
6
  Dest dest;
30
6
  static_assert(sizeof(source) == sizeof(dest),
31
6
                "BitwiseCast: Source and destination must have the same size");
32
6
  std::memcpy(&dest, &source, sizeof(dest));
33
6
  return dest;
34
6
}
Unexecuted instantiation: unsigned long spvtools::utils::BitwiseCast<unsigned long, double>(double)
Unexecuted instantiation: unsigned int spvtools::utils::BitwiseCast<unsigned int, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >)
Unexecuted instantiation: unsigned long spvtools::utils::BitwiseCast<unsigned long, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >)
35
36
// Calculates the bit width of the integer type |T|.
37
template <typename T>
38
struct IntegerBitWidth {
39
  static_assert(std::is_integral<T>::value, "Integer type required");
40
  static const size_t kBitsPerByte = 8;
41
  static const size_t get = sizeof(T) * kBitsPerByte;
42
};
43
44
// SetBits<T, First, Num> returns an integer of type <T> with bits set
45
// for position <First> through <First + Num - 1>, counting from the least
46
// significant bit. In particular when Num == 0, no positions are set to 1.
47
// A static assert will be triggered if First + Num > sizeof(T) * 8, that is,
48
// a bit that will not fit in the underlying type is set.
49
template <typename T, size_t First = 0, size_t Num = 0>
50
struct SetBits {
51
  static_assert(First < IntegerBitWidth<T>::get,
52
                "Tried to set a bit that is shifted too far.");
53
  const static T get = (T(1) << First) | SetBits<T, First + 1, Num - 1>::get;
54
};
55
56
template <typename T, size_t Last>
57
struct SetBits<T, Last, 0> {
58
  const static T get = T(0);
59
};
60
61
// This is all compile-time so we can put our tests right here.
62
static_assert(IntegerBitWidth<uint32_t>::get == 32, "IntegerBitWidth mismatch");
63
static_assert(IntegerBitWidth<int32_t>::get == 32, "IntegerBitWidth mismatch");
64
static_assert(IntegerBitWidth<uint64_t>::get == 64, "IntegerBitWidth mismatch");
65
static_assert(IntegerBitWidth<uint8_t>::get == 8, "IntegerBitWidth mismatch");
66
67
static_assert(SetBits<uint32_t, 0, 0>::get == uint32_t(0x00000000),
68
              "SetBits failed");
69
static_assert(SetBits<uint32_t, 0, 1>::get == uint32_t(0x00000001),
70
              "SetBits failed");
71
static_assert(SetBits<uint32_t, 31, 1>::get == uint32_t(0x80000000),
72
              "SetBits failed");
73
static_assert(SetBits<uint32_t, 1, 2>::get == uint32_t(0x00000006),
74
              "SetBits failed");
75
static_assert(SetBits<uint32_t, 30, 2>::get == uint32_t(0xc0000000),
76
              "SetBits failed");
77
static_assert(SetBits<uint32_t, 0, 31>::get == uint32_t(0x7FFFFFFF),
78
              "SetBits failed");
79
static_assert(SetBits<uint32_t, 0, 32>::get == uint32_t(0xFFFFFFFF),
80
              "SetBits failed");
81
static_assert(SetBits<uint32_t, 16, 16>::get == uint32_t(0xFFFF0000),
82
              "SetBits failed");
83
84
static_assert(SetBits<uint64_t, 0, 1>::get == uint64_t(0x0000000000000001LL),
85
              "SetBits failed");
86
static_assert(SetBits<uint64_t, 63, 1>::get == uint64_t(0x8000000000000000LL),
87
              "SetBits failed");
88
static_assert(SetBits<uint64_t, 62, 2>::get == uint64_t(0xc000000000000000LL),
89
              "SetBits failed");
90
static_assert(SetBits<uint64_t, 31, 1>::get == uint64_t(0x0000000080000000LL),
91
              "SetBits failed");
92
static_assert(SetBits<uint64_t, 16, 16>::get == uint64_t(0x00000000FFFF0000LL),
93
              "SetBits failed");
94
95
// Returns number of '1' bits in a word.
96
template <typename T>
97
2.56k
size_t CountSetBits(T word) {
98
2.56k
  static_assert(std::is_integral<T>::value,
99
2.56k
                "CountSetBits requires integer type");
100
2.56k
  uint32_t count = 0;
101
3.47k
  while (word) {
102
914
    word &= word - 1;
103
914
    ++count;
104
914
  }
105
2.56k
  return count;
106
2.56k
}
107
108
// Checks if the bit at the |position| is set to '1'.
109
// Bits zero-indexed starting at the least significant bit.
110
// |position| must be within the bit width of |T|.
111
template <typename T>
112
1.44k
bool IsBitAtPositionSet(T word, size_t position) {
113
1.44k
  static_assert(std::is_integral<T>::value, "Integer type required");
114
1.44k
  static_assert(std::is_unsigned<T>::value, "Unsigned type required");
115
1.44k
  assert(position < IntegerBitWidth<T>::get &&
116
1.44k
         "position must be less than the bit width");
117
1.44k
  return word & T(T(1) << position);
118
1.44k
}
bool spvtools::utils::IsBitAtPositionSet<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
112
1.44k
bool IsBitAtPositionSet(T word, size_t position) {
113
1.44k
  static_assert(std::is_integral<T>::value, "Integer type required");
114
1.44k
  static_assert(std::is_unsigned<T>::value, "Unsigned type required");
115
  assert(position < IntegerBitWidth<T>::get &&
116
1.44k
         "position must be less than the bit width");
117
1.44k
  return word & T(T(1) << position);
118
1.44k
}
Unexecuted instantiation: bool spvtools::utils::IsBitAtPositionSet<unsigned int>(unsigned int, unsigned long)
119
120
// Returns a value obtained by setting a range of adjacent bits of |word| to
121
// |value|. Affected bits are within the range:
122
//   [first_position, first_position + num_bits_to_mutate),
123
// assuming zero-based indexing starting at the least
124
// significant bit. Bits to mutate must be within the bit width of |T|.
125
template <typename T>
126
T MutateBits(T word, size_t first_position, size_t num_bits_to_mutate,
127
1.46k
             bool value) {
128
1.46k
  static_assert(std::is_integral<T>::value, "Integer type required");
129
1.46k
  static_assert(std::is_unsigned<T>::value, "Unsigned type required");
130
1.46k
  static const size_t word_bit_width = IntegerBitWidth<T>::get;
131
1.46k
  assert(first_position < word_bit_width &&
132
1.46k
         "Mutated bits must be within bit width");
133
1.46k
  assert(first_position + num_bits_to_mutate <= word_bit_width &&
134
1.46k
         "Mutated bits must be within bit width");
135
1.46k
  if (num_bits_to_mutate == 0) {
136
0
    return word;
137
0
  }
138
139
1.46k
  const T all_ones = ~T(0);
140
1.46k
  const size_t num_unaffected_low_bits = first_position;
141
1.46k
  const T unaffected_low_mask =
142
1.46k
      T(T(all_ones >> num_unaffected_low_bits) << num_unaffected_low_bits);
143
144
1.46k
  const size_t num_unaffected_high_bits =
145
1.46k
      word_bit_width - (first_position + num_bits_to_mutate);
146
1.46k
  const T unaffected_high_mask =
147
1.46k
      T(T(all_ones << num_unaffected_high_bits) >> num_unaffected_high_bits);
148
149
1.46k
  const T mutation_mask = unaffected_low_mask & unaffected_high_mask;
150
1.46k
  if (value) {
151
8
    return word | mutation_mask;
152
8
  }
153
1.45k
  return word & T(~mutation_mask);
154
1.46k
}
unsigned long spvtools::utils::MutateBits<unsigned long>(unsigned long, unsigned long, unsigned long, bool)
Line
Count
Source
127
1.46k
             bool value) {
128
1.46k
  static_assert(std::is_integral<T>::value, "Integer type required");
129
1.46k
  static_assert(std::is_unsigned<T>::value, "Unsigned type required");
130
1.46k
  static const size_t word_bit_width = IntegerBitWidth<T>::get;
131
1.46k
  assert(first_position < word_bit_width &&
132
1.46k
         "Mutated bits must be within bit width");
133
1.46k
  assert(first_position + num_bits_to_mutate <= word_bit_width &&
134
1.46k
         "Mutated bits must be within bit width");
135
1.46k
  if (num_bits_to_mutate == 0) {
136
0
    return word;
137
0
  }
138
139
1.46k
  const T all_ones = ~T(0);
140
1.46k
  const size_t num_unaffected_low_bits = first_position;
141
1.46k
  const T unaffected_low_mask =
142
1.46k
      T(T(all_ones >> num_unaffected_low_bits) << num_unaffected_low_bits);
143
144
1.46k
  const size_t num_unaffected_high_bits =
145
1.46k
      word_bit_width - (first_position + num_bits_to_mutate);
146
1.46k
  const T unaffected_high_mask =
147
1.46k
      T(T(all_ones << num_unaffected_high_bits) >> num_unaffected_high_bits);
148
149
1.46k
  const T mutation_mask = unaffected_low_mask & unaffected_high_mask;
150
1.46k
  if (value) {
151
8
    return word | mutation_mask;
152
8
  }
153
1.45k
  return word & T(~mutation_mask);
154
1.46k
}
Unexecuted instantiation: unsigned int spvtools::utils::MutateBits<unsigned int>(unsigned int, unsigned long, unsigned long, bool)
155
156
// Returns a value obtained by setting the |num_bits_to_set| highest bits to
157
// '1'. |num_bits_to_set| must be not be greater than the bit width of |T|.
158
template <typename T>
159
8
T SetHighBits(T word, size_t num_bits_to_set) {
160
8
  if (num_bits_to_set == 0) {
161
0
    return word;
162
0
  }
163
8
  const size_t word_bit_width = IntegerBitWidth<T>::get;
164
8
  assert(num_bits_to_set <= word_bit_width &&
165
8
         "Can't set more bits than bit width");
166
8
  return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
167
8
                    true);
168
8
}
unsigned long spvtools::utils::SetHighBits<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
159
8
T SetHighBits(T word, size_t num_bits_to_set) {
160
8
  if (num_bits_to_set == 0) {
161
0
    return word;
162
0
  }
163
8
  const size_t word_bit_width = IntegerBitWidth<T>::get;
164
  assert(num_bits_to_set <= word_bit_width &&
165
8
         "Can't set more bits than bit width");
166
8
  return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
167
8
                    true);
168
8
}
Unexecuted instantiation: unsigned int spvtools::utils::SetHighBits<unsigned int>(unsigned int, unsigned long)
169
170
// Returns a value obtained by setting the |num_bits_to_set| highest bits to
171
// '0'. |num_bits_to_set| must be not be greater than the bit width of |T|.
172
template <typename T>
173
1.45k
T ClearHighBits(T word, size_t num_bits_to_set) {
174
1.45k
  if (num_bits_to_set == 0) {
175
0
    return word;
176
0
  }
177
1.45k
  const size_t word_bit_width = IntegerBitWidth<T>::get;
178
1.45k
  assert(num_bits_to_set <= word_bit_width &&
179
1.45k
         "Can't clear more bits than bit width");
180
1.45k
  return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
181
1.45k
                    false);
182
1.45k
}
unsigned long spvtools::utils::ClearHighBits<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
173
1.45k
T ClearHighBits(T word, size_t num_bits_to_set) {
174
1.45k
  if (num_bits_to_set == 0) {
175
0
    return word;
176
0
  }
177
1.45k
  const size_t word_bit_width = IntegerBitWidth<T>::get;
178
  assert(num_bits_to_set <= word_bit_width &&
179
1.45k
         "Can't clear more bits than bit width");
180
1.45k
  return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set,
181
1.45k
                    false);
182
1.45k
}
Unexecuted instantiation: unsigned int spvtools::utils::ClearHighBits<unsigned int>(unsigned int, unsigned long)
183
184
// Returns the value obtained by extracting the |number_of_bits| least
185
// significant bits from |value|, and sign-extending it to 64-bits.
186
template <typename T>
187
1.44k
T SignExtendValue(T value, uint32_t number_of_bits) {
188
1.44k
  const uint32_t bit_width = sizeof(value) * 8;
189
1.44k
  if (number_of_bits == bit_width) return value;
190
191
1.44k
  bool is_negative = utils::IsBitAtPositionSet(value, number_of_bits - 1);
192
1.44k
  if (is_negative) {
193
8
    value = utils::SetHighBits(value, bit_width - number_of_bits);
194
1.43k
  } else {
195
1.43k
    value = utils::ClearHighBits(value, bit_width - number_of_bits);
196
1.43k
  }
197
1.44k
  return value;
198
1.44k
}
unsigned long spvtools::utils::SignExtendValue<unsigned long>(unsigned long, unsigned int)
Line
Count
Source
187
1.44k
T SignExtendValue(T value, uint32_t number_of_bits) {
188
1.44k
  const uint32_t bit_width = sizeof(value) * 8;
189
1.44k
  if (number_of_bits == bit_width) return value;
190
191
1.44k
  bool is_negative = utils::IsBitAtPositionSet(value, number_of_bits - 1);
192
1.44k
  if (is_negative) {
193
8
    value = utils::SetHighBits(value, bit_width - number_of_bits);
194
1.43k
  } else {
195
1.43k
    value = utils::ClearHighBits(value, bit_width - number_of_bits);
196
1.43k
  }
197
1.44k
  return value;
198
1.44k
}
Unexecuted instantiation: unsigned int spvtools::utils::SignExtendValue<unsigned int>(unsigned int, unsigned int)
199
200
// Returns the value obtained by extracting the |number_of_bits| least
201
// significant bits from |value|, and zero-extending it to 64-bits.
202
template <typename T>
203
12
T ZeroExtendValue(T value, uint32_t number_of_bits) {
204
12
  const uint32_t bit_width = sizeof(value) * 8;
205
12
  if (number_of_bits == bit_width) return value;
206
12
  return utils::ClearHighBits(value, bit_width - number_of_bits);
207
12
}
208
209
}  // namespace utils
210
}  // namespace spvtools
211
212
#endif  // SOURCE_UTIL_BITUTILS_H_