/src/spirv-cross/spirv_common.hpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2015-2021 Arm Limited |
3 | | * SPDX-License-Identifier: Apache-2.0 OR MIT |
4 | | * |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | * |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | * |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | |
18 | | /* |
19 | | * At your option, you may choose to accept this material under either: |
20 | | * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or |
21 | | * 2. The MIT License, found at <http://opensource.org/licenses/MIT>. |
22 | | */ |
23 | | |
24 | | #ifndef SPIRV_CROSS_COMMON_HPP |
25 | | #define SPIRV_CROSS_COMMON_HPP |
26 | | |
27 | | #ifndef SPV_ENABLE_UTILITY_CODE |
28 | | #define SPV_ENABLE_UTILITY_CODE |
29 | | #endif |
30 | | |
31 | | // Pragmatic hack to avoid symbol conflicts when including both hpp11 and hpp headers in same translation unit. |
32 | | // This is an unfortunate SPIRV-Headers issue that we cannot easily deal with ourselves. |
33 | | #ifdef SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE |
34 | | #define spv SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE |
35 | | #define SPIRV_CROSS_SPV_HEADER_NAMESPACE SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE |
36 | | #else |
37 | | #define SPIRV_CROSS_SPV_HEADER_NAMESPACE spv |
38 | | #endif |
39 | | |
40 | | #include "spirv.hpp" |
41 | | #include "spirv_cross_containers.hpp" |
42 | | #include "spirv_cross_error_handling.hpp" |
43 | | #include <functional> |
44 | | |
45 | | // A bit crude, but allows projects which embed SPIRV-Cross statically to |
46 | | // effectively hide all the symbols from other projects. |
47 | | // There is a case where we have: |
48 | | // - Project A links against SPIRV-Cross statically. |
49 | | // - Project A links against Project B statically. |
50 | | // - Project B links against SPIRV-Cross statically (might be a different version). |
51 | | // This leads to a conflict with extremely bizarre results. |
52 | | // By overriding the namespace in one of the project builds, we can work around this. |
53 | | // If SPIRV-Cross is embedded in dynamic libraries, |
54 | | // prefer using -fvisibility=hidden on GCC/Clang instead. |
55 | | #ifdef SPIRV_CROSS_NAMESPACE_OVERRIDE |
56 | | #define SPIRV_CROSS_NAMESPACE SPIRV_CROSS_NAMESPACE_OVERRIDE |
57 | | #else |
58 | | #define SPIRV_CROSS_NAMESPACE spirv_cross |
59 | | #endif |
60 | | |
61 | | namespace SPIRV_CROSS_NAMESPACE |
62 | | { |
63 | | namespace inner |
64 | | { |
65 | | template <typename T> |
66 | | void join_helper(StringStream<> &stream, T &&t) |
67 | 0 | { |
68 | 0 | stream << std::forward<T>(t); |
69 | 0 | } |
70 | | |
71 | | template <typename T, typename... Ts> |
72 | | void join_helper(StringStream<> &stream, T &&t, Ts &&... ts) |
73 | 0 | { |
74 | 0 | stream << std::forward<T>(t); |
75 | 0 | join_helper(stream, std::forward<Ts>(ts)...); |
76 | 0 | } Unexecuted instantiation: void spirv_cross::inner::join_helper<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [21], char const*, char const (&) [2]>(spirv_cross::StringStream<4096ul, 4096ul>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const (&) [21], char const*&&, char const (&) [2]) Unexecuted instantiation: void spirv_cross::inner::join_helper<char const (&) [21], char const*, char const (&) [2]>(spirv_cross::StringStream<4096ul, 4096ul>&, char const (&) [21], char const*&&, char const (&) [2]) Unexecuted instantiation: void spirv_cross::inner::join_helper<char const*, char const (&) [2]>(spirv_cross::StringStream<4096ul, 4096ul>&, char const*&&, char const (&) [2]) |
77 | | } // namespace inner |
78 | | |
79 | | class Bitset |
80 | | { |
81 | | public: |
82 | 59.5M | Bitset() = default; |
83 | | explicit inline Bitset(uint64_t lower_) |
84 | | : lower(lower_) |
85 | 0 | { |
86 | 0 | } |
87 | | |
88 | | inline bool get(uint32_t bit) const |
89 | 86.8k | { |
90 | 86.8k | if (bit < 64) |
91 | 25.0k | return (lower & (1ull << bit)) != 0; |
92 | 61.7k | else |
93 | 61.7k | return higher.count(bit) != 0; |
94 | 86.8k | } |
95 | | |
96 | | inline void set(uint32_t bit) |
97 | 102k | { |
98 | 102k | if (bit < 64) |
99 | 38.6k | lower |= 1ull << bit; |
100 | 63.7k | else |
101 | 63.7k | higher.insert(bit); |
102 | 102k | } |
103 | | |
104 | | inline void clear(uint32_t bit) |
105 | 0 | { |
106 | 0 | if (bit < 64) |
107 | 0 | lower &= ~(1ull << bit); |
108 | 0 | else |
109 | 0 | higher.erase(bit); |
110 | 0 | } |
111 | | |
112 | | inline uint64_t get_lower() const |
113 | 0 | { |
114 | 0 | return lower; |
115 | 0 | } |
116 | | |
117 | | inline void reset() |
118 | 0 | { |
119 | 0 | lower = 0; |
120 | 0 | higher.clear(); |
121 | 0 | } |
122 | | |
123 | | inline void merge_and(const Bitset &other) |
124 | 0 | { |
125 | 0 | lower &= other.lower; |
126 | 0 | std::unordered_set<uint32_t> tmp_set; |
127 | 0 | for (auto &v : higher) |
128 | 0 | if (other.higher.count(v) != 0) |
129 | 0 | tmp_set.insert(v); |
130 | 0 | higher = std::move(tmp_set); |
131 | 0 | } |
132 | | |
133 | | inline void merge_or(const Bitset &other) |
134 | 0 | { |
135 | 0 | lower |= other.lower; |
136 | 0 | for (auto &v : other.higher) |
137 | 0 | higher.insert(v); |
138 | 0 | } |
139 | | |
140 | | inline bool operator==(const Bitset &other) const |
141 | 0 | { |
142 | 0 | if (lower != other.lower) |
143 | 0 | return false; |
144 | 0 |
|
145 | 0 | if (higher.size() != other.higher.size()) |
146 | 0 | return false; |
147 | 0 |
|
148 | 0 | for (auto &v : higher) |
149 | 0 | if (other.higher.count(v) == 0) |
150 | 0 | return false; |
151 | 0 |
|
152 | 0 | return true; |
153 | 0 | } |
154 | | |
155 | | inline bool operator!=(const Bitset &other) const |
156 | 0 | { |
157 | 0 | return !(*this == other); |
158 | 0 | } |
159 | | |
160 | | template <typename Op> |
161 | | void for_each_bit(const Op &op) const |
162 | 25.3k | { |
163 | | // TODO: Add ctz-based iteration. |
164 | 1.64M | for (uint32_t i = 0; i < 64; i++) |
165 | 1.62M | { |
166 | 1.62M | if (lower & (1ull << i)) |
167 | 25.0k | op(i); |
168 | 1.62M | } |
169 | | |
170 | 25.3k | if (higher.empty()) |
171 | 995 | return; |
172 | | |
173 | | // Need to enforce an order here for reproducible results, |
174 | | // but hitting this path should happen extremely rarely, so having this slow path is fine. |
175 | 24.3k | SmallVector<uint32_t> bits; |
176 | 24.3k | bits.reserve(higher.size()); |
177 | 24.3k | for (auto &v : higher) |
178 | 61.7k | bits.push_back(v); |
179 | 24.3k | std::sort(std::begin(bits), std::end(bits)); |
180 | | |
181 | 24.3k | for (auto &v : bits) |
182 | 61.7k | op(v); |
183 | 24.3k | } spirv_parser.cpp:void spirv_cross::Bitset::for_each_bit<spirv_cross::Parser::parse(spirv_cross::Instruction const&)::$_0>(spirv_cross::Parser::parse(spirv_cross::Instruction const&)::$_0 const&) const Line | Count | Source | 162 | 21.9k | { | 163 | | // TODO: Add ctz-based iteration. | 164 | 1.42M | for (uint32_t i = 0; i < 64; i++) | 165 | 1.40M | { | 166 | 1.40M | if (lower & (1ull << i)) | 167 | 21.4k | op(i); | 168 | 1.40M | } | 169 | | | 170 | 21.9k | if (higher.empty()) | 171 | 627 | return; | 172 | | | 173 | | // Need to enforce an order here for reproducible results, | 174 | | // but hitting this path should happen extremely rarely, so having this slow path is fine. | 175 | 21.2k | SmallVector<uint32_t> bits; | 176 | 21.2k | bits.reserve(higher.size()); | 177 | 21.2k | for (auto &v : higher) | 178 | 57.1k | bits.push_back(v); | 179 | 21.2k | std::sort(std::begin(bits), std::end(bits)); | 180 | | | 181 | 21.2k | for (auto &v : bits) | 182 | 57.1k | op(v); | 183 | 21.2k | } |
spirv_parser.cpp:void spirv_cross::Bitset::for_each_bit<spirv_cross::Parser::parse(spirv_cross::Instruction const&)::$_1>(spirv_cross::Parser::parse(spirv_cross::Instruction const&)::$_1 const&) const Line | Count | Source | 162 | 3.47k | { | 163 | | // TODO: Add ctz-based iteration. | 164 | 225k | for (uint32_t i = 0; i < 64; i++) | 165 | 222k | { | 166 | 222k | if (lower & (1ull << i)) | 167 | 3.62k | op(i); | 168 | 222k | } | 169 | | | 170 | 3.47k | if (higher.empty()) | 171 | 368 | return; | 172 | | | 173 | | // Need to enforce an order here for reproducible results, | 174 | | // but hitting this path should happen extremely rarely, so having this slow path is fine. | 175 | 3.10k | SmallVector<uint32_t> bits; | 176 | 3.10k | bits.reserve(higher.size()); | 177 | 3.10k | for (auto &v : higher) | 178 | 4.63k | bits.push_back(v); | 179 | 3.10k | std::sort(std::begin(bits), std::end(bits)); | 180 | | | 181 | 3.10k | for (auto &v : bits) | 182 | 4.63k | op(v); | 183 | 3.10k | } |
|
184 | | |
185 | | inline bool empty() const |
186 | 0 | { |
187 | 0 | return lower == 0 && higher.empty(); |
188 | 0 | } |
189 | | |
190 | | private: |
191 | | // The most common bits to set are all lower than 64, |
192 | | // so optimize for this case. Bits spilling outside 64 go into a slower data structure. |
193 | | // In almost all cases, higher data structure will not be used. |
194 | | uint64_t lower = 0; |
195 | | std::unordered_set<uint32_t> higher; |
196 | | }; |
197 | | |
198 | | // Helper template to avoid lots of nasty string temporary munging. |
199 | | template <typename... Ts> |
200 | | std::string join(Ts &&... ts) |
201 | 0 | { |
202 | 0 | StringStream<> stream; |
203 | 0 | inner::join_helper(stream, std::forward<Ts>(ts)...); |
204 | 0 | return stream.str(); |
205 | 0 | } |
206 | | |
207 | | inline std::string merge(const SmallVector<std::string> &list, const char *between = ", ") |
208 | 0 | { |
209 | 0 | StringStream<> stream; |
210 | 0 | for (auto &elem : list) |
211 | 0 | { |
212 | 0 | stream << elem; |
213 | 0 | if (&elem != &list.back()) |
214 | 0 | stream << between; |
215 | 0 | } |
216 | 0 | return stream.str(); |
217 | 0 | } |
218 | | |
219 | | // Make sure we don't accidentally call this with float or doubles with SFINAE. |
220 | | // Have to use the radix-aware overload. |
221 | | template <typename T, typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0> |
222 | | inline std::string convert_to_string(const T &t) |
223 | | { |
224 | | return std::to_string(t); |
225 | | } |
226 | | |
227 | | static inline std::string convert_to_string(int32_t value) |
228 | 0 | { |
229 | 0 | // INT_MIN is ... special on some backends. If we use a decimal literal, and negate it, we |
230 | 0 | // could accidentally promote the literal to long first, then negate. |
231 | 0 | // To workaround it, emit int(0x80000000) instead. |
232 | 0 | if (value == (std::numeric_limits<int32_t>::min)()) |
233 | 0 | return "int(0x80000000)"; |
234 | 0 | else |
235 | 0 | return std::to_string(value); |
236 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::convert_to_string(int) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::convert_to_string(int) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::convert_to_string(int) |
237 | | |
238 | | static inline std::string convert_to_string(int64_t value, const std::string &int64_type, bool long_long_literal_suffix) |
239 | 0 | { |
240 | 0 | // INT64_MIN is ... special on some backends. |
241 | 0 | // If we use a decimal literal, and negate it, we might overflow the representable numbers. |
242 | 0 | // To workaround it, emit int(0x80000000) instead. |
243 | 0 | if (value == (std::numeric_limits<int64_t>::min)()) |
244 | 0 | return join(int64_type, "(0x8000000000000000u", (long_long_literal_suffix ? "ll" : "l"), ")"); |
245 | 0 | else |
246 | 0 | return std::to_string(value) + (long_long_literal_suffix ? "ll" : "l"); |
247 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::convert_to_string(long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::convert_to_string(long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::convert_to_string(long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool) |
248 | | |
249 | | // Allow implementations to set a convenient standard precision |
250 | | #ifndef SPIRV_CROSS_FLT_FMT |
251 | | #define SPIRV_CROSS_FLT_FMT "%.32g" |
252 | | #endif |
253 | | |
254 | | // Disable sprintf and strcat warnings. |
255 | | // We cannot rely on snprintf and family existing because, ..., MSVC. |
256 | | #if defined(__clang__) || defined(__GNUC__) |
257 | | #pragma GCC diagnostic push |
258 | | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
259 | | #elif defined(_MSC_VER) |
260 | | #pragma warning(push) |
261 | | #pragma warning(disable : 4996) |
262 | | #endif |
263 | | |
264 | | static inline void fixup_radix_point(char *str, char radix_point) |
265 | 0 | { |
266 | 0 | // Setting locales is a very risky business in multi-threaded program, |
267 | 0 | // so just fixup locales instead. We only need to care about the radix point. |
268 | 0 | if (radix_point != '.') |
269 | 0 | { |
270 | 0 | while (*str != '\0') |
271 | 0 | { |
272 | 0 | if (*str == radix_point) |
273 | 0 | *str = '.'; |
274 | 0 | str++; |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::fixup_radix_point(char*, char) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::fixup_radix_point(char*, char) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::fixup_radix_point(char*, char) |
278 | | |
279 | | inline std::string convert_to_string(float t, char locale_radix_point) |
280 | 0 | { |
281 | 0 | // std::to_string for floating point values is broken. |
282 | 0 | // Fallback to something more sane. |
283 | 0 | char buf[64]; |
284 | 0 | sprintf(buf, SPIRV_CROSS_FLT_FMT, t); |
285 | 0 | fixup_radix_point(buf, locale_radix_point); |
286 | 0 |
|
287 | 0 | // Ensure that the literal is float. |
288 | 0 | if (!strchr(buf, '.') && !strchr(buf, 'e')) |
289 | 0 | strcat(buf, ".0"); |
290 | 0 | return buf; |
291 | 0 | } |
292 | | |
293 | | inline std::string convert_to_string(double t, char locale_radix_point) |
294 | 0 | { |
295 | 0 | // std::to_string for floating point values is broken. |
296 | 0 | // Fallback to something more sane. |
297 | 0 | char buf[64]; |
298 | 0 | sprintf(buf, SPIRV_CROSS_FLT_FMT, t); |
299 | 0 | fixup_radix_point(buf, locale_radix_point); |
300 | 0 |
|
301 | 0 | // Ensure that the literal is float. |
302 | 0 | if (!strchr(buf, '.') && !strchr(buf, 'e')) |
303 | 0 | strcat(buf, ".0"); |
304 | 0 | return buf; |
305 | 0 | } |
306 | | |
307 | | #if defined(__clang__) || defined(__GNUC__) |
308 | | #pragma GCC diagnostic pop |
309 | | #elif defined(_MSC_VER) |
310 | | #pragma warning(pop) |
311 | | #endif |
312 | | |
313 | | class FloatFormatter |
314 | | { |
315 | | public: |
316 | | virtual ~FloatFormatter() = default; |
317 | | virtual std::string format_float(float value) = 0; |
318 | | virtual std::string format_double(double value) = 0; |
319 | | }; |
320 | | |
321 | | template <typename T> |
322 | | struct ValueSaver |
323 | | { |
324 | | explicit ValueSaver(T ¤t_) |
325 | | : current(current_) |
326 | | , saved(current_) |
327 | | { |
328 | | } |
329 | | |
330 | | void release() |
331 | | { |
332 | | current = saved; |
333 | | } |
334 | | |
335 | | ~ValueSaver() |
336 | | { |
337 | | release(); |
338 | | } |
339 | | |
340 | | T ¤t; |
341 | | T saved; |
342 | | }; |
343 | | |
344 | | struct Instruction |
345 | | { |
346 | | uint16_t op = 0; |
347 | | uint16_t count = 0; |
348 | | // If offset is 0 (not a valid offset into the instruction stream), |
349 | | // we have an instruction stream which is embedded in the object. |
350 | | uint32_t offset = 0; |
351 | | uint32_t length = 0; |
352 | | |
353 | | inline bool is_embedded() const |
354 | 0 | { |
355 | 0 | return offset == 0; |
356 | 0 | } |
357 | | }; |
358 | | |
359 | | struct EmbeddedInstruction : Instruction |
360 | | { |
361 | | SmallVector<uint32_t> ops; |
362 | | }; |
363 | | |
364 | | enum Types |
365 | | { |
366 | | TypeNone, |
367 | | TypeType, |
368 | | TypeVariable, |
369 | | TypeConstant, |
370 | | TypeFunction, |
371 | | TypeFunctionPrototype, |
372 | | TypeBlock, |
373 | | TypeExtension, |
374 | | TypeExpression, |
375 | | TypeConstantOp, |
376 | | TypeCombinedImageSampler, |
377 | | TypeAccessChain, |
378 | | TypeUndef, |
379 | | TypeString, |
380 | | TypeDebugLocalVariable, |
381 | | TypeCount |
382 | | }; |
383 | | |
384 | | template <Types type> |
385 | | class TypedID; |
386 | | |
387 | | template <> |
388 | | class TypedID<TypeNone> |
389 | | { |
390 | | public: |
391 | 1.90M | TypedID() = default; |
392 | | TypedID(uint32_t id_) |
393 | 689k | : id(id_) |
394 | 689k | { |
395 | 689k | } |
396 | | |
397 | | template <Types U> |
398 | | TypedID(const TypedID<U> &other) |
399 | 11.9k | { |
400 | 11.9k | *this = other; |
401 | 11.9k | } spirv_cross::TypedID<(spirv_cross::Types)0>::TypedID<(spirv_cross::Types)1>(spirv_cross::TypedID<(spirv_cross::Types)1> const&) Line | Count | Source | 399 | 11.9k | { | 400 | 11.9k | *this = other; | 401 | 11.9k | } |
Unexecuted instantiation: spirv_cross::TypedID<(spirv_cross::Types)0>::TypedID<(spirv_cross::Types)3>(spirv_cross::TypedID<(spirv_cross::Types)3> const&) |
402 | | |
403 | | template <Types U> |
404 | | TypedID &operator=(const TypedID<U> &other) |
405 | 11.9k | { |
406 | 11.9k | id = uint32_t(other); |
407 | 11.9k | return *this; |
408 | 11.9k | } spirv_cross::TypedID<(spirv_cross::Types)0>& spirv_cross::TypedID<(spirv_cross::Types)0>::operator=<(spirv_cross::Types)1>(spirv_cross::TypedID<(spirv_cross::Types)1> const&) Line | Count | Source | 405 | 11.9k | { | 406 | 11.9k | id = uint32_t(other); | 407 | 11.9k | return *this; | 408 | 11.9k | } |
Unexecuted instantiation: spirv_cross::TypedID<(spirv_cross::Types)0>& spirv_cross::TypedID<(spirv_cross::Types)0>::operator=<(spirv_cross::Types)3>(spirv_cross::TypedID<(spirv_cross::Types)3> const&) |
409 | | |
410 | | // Implicit conversion to u32 is desired here. |
411 | | // As long as we block implicit conversion between TypedID<A> and TypedID<B> we're good. |
412 | | operator uint32_t() const |
413 | 1.53M | { |
414 | 1.53M | return id; |
415 | 1.53M | } |
416 | | |
417 | | template <Types U> |
418 | | operator TypedID<U>() const |
419 | 0 | { |
420 | 0 | return TypedID<U>(*this); |
421 | 0 | } |
422 | | |
423 | | private: |
424 | | uint32_t id = 0; |
425 | | }; |
426 | | |
427 | | template <Types type> |
428 | | class TypedID |
429 | | { |
430 | | public: |
431 | 10.4k | TypedID() = default; spirv_cross::TypedID<(spirv_cross::Types)1>::TypedID() Line | Count | Source | 431 | 9.95k | TypedID() = default; |
spirv_cross::TypedID<(spirv_cross::Types)6>::TypedID() Line | Count | Source | 431 | 524 | TypedID() = default; |
|
432 | | TypedID(uint32_t id_) |
433 | 239k | : id(id_) |
434 | 239k | { |
435 | 239k | } spirv_cross::TypedID<(spirv_cross::Types)1>::TypedID(unsigned int) Line | Count | Source | 433 | 118k | : id(id_) | 434 | 118k | { | 435 | 118k | } |
spirv_cross::TypedID<(spirv_cross::Types)6>::TypedID(unsigned int) Line | Count | Source | 433 | 93.1k | : id(id_) | 434 | 93.1k | { | 435 | 93.1k | } |
spirv_cross::TypedID<(spirv_cross::Types)2>::TypedID(unsigned int) Line | Count | Source | 433 | 14.0k | : id(id_) | 434 | 14.0k | { | 435 | 14.0k | } |
spirv_cross::TypedID<(spirv_cross::Types)4>::TypedID(unsigned int) Line | Count | Source | 433 | 8.65k | : id(id_) | 434 | 8.65k | { | 435 | 8.65k | } |
spirv_cross::TypedID<(spirv_cross::Types)3>::TypedID(unsigned int) Line | Count | Source | 433 | 5.25k | : id(id_) | 434 | 5.25k | { | 435 | 5.25k | } |
|
436 | | |
437 | | explicit TypedID(const TypedID<TypeNone> &other) |
438 | 2.65k | : id(uint32_t(other)) |
439 | 2.65k | { |
440 | 2.65k | } spirv_cross::TypedID<(spirv_cross::Types)6>::TypedID(spirv_cross::TypedID<(spirv_cross::Types)0> const&) Line | Count | Source | 438 | 2.65k | : id(uint32_t(other)) | 439 | 2.65k | { | 440 | 2.65k | } |
Unexecuted instantiation: spirv_cross::TypedID<(spirv_cross::Types)1>::TypedID(spirv_cross::TypedID<(spirv_cross::Types)0> const&) |
441 | | |
442 | | operator uint32_t() const |
443 | 112k | { |
444 | 112k | return id; |
445 | 112k | } spirv_cross::TypedID<(spirv_cross::Types)4>::operator unsigned int() const Line | Count | Source | 443 | 19.5k | { | 444 | 19.5k | return id; | 445 | 19.5k | } |
spirv_cross::TypedID<(spirv_cross::Types)1>::operator unsigned int() const Line | Count | Source | 443 | 72.4k | { | 444 | 72.4k | return id; | 445 | 72.4k | } |
spirv_cross::TypedID<(spirv_cross::Types)6>::operator unsigned int() const Line | Count | Source | 443 | 20.5k | { | 444 | 20.5k | return id; | 445 | 20.5k | } |
Unexecuted instantiation: spirv_cross::TypedID<(spirv_cross::Types)3>::operator unsigned int() const |
446 | | |
447 | | private: |
448 | | uint32_t id = 0; |
449 | | }; |
450 | | |
451 | | using VariableID = TypedID<TypeVariable>; |
452 | | using TypeID = TypedID<TypeType>; |
453 | | using ConstantID = TypedID<TypeConstant>; |
454 | | using FunctionID = TypedID<TypeFunction>; |
455 | | using BlockID = TypedID<TypeBlock>; |
456 | | using ID = TypedID<TypeNone>; |
457 | | |
458 | | // Helper for Variant interface. |
459 | | struct IVariant |
460 | | { |
461 | 95.0k | virtual ~IVariant() = default; |
462 | | virtual IVariant *clone(ObjectPoolBase *pool) = 0; |
463 | | ID self = 0; |
464 | | |
465 | | protected: |
466 | 90.4k | IVariant() = default; |
467 | 4.54k | IVariant(const IVariant&) = default; |
468 | 2.54k | IVariant &operator=(const IVariant&) = default; |
469 | | }; |
470 | | |
471 | | #define SPIRV_CROSS_DECLARE_CLONE(T) \ |
472 | | IVariant *clone(ObjectPoolBase *pool) override \ |
473 | 0 | { \ |
474 | 0 | return static_cast<ObjectPool<T> *>(pool)->allocate(*this); \ |
475 | 0 | } Unexecuted instantiation: spirv_cross::SPIRUndef::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRString::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRDebugLocalVariable::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRCombinedImageSampler::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRConstantOp::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRType::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRExtension::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRExpression::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRFunctionPrototype::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRBlock::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRFunction::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRAccessChain::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRVariable::clone(spirv_cross::ObjectPoolBase*) Unexecuted instantiation: spirv_cross::SPIRConstant::clone(spirv_cross::ObjectPoolBase*) |
476 | | |
477 | | struct SPIRUndef : IVariant |
478 | | { |
479 | | enum |
480 | | { |
481 | | type = TypeUndef |
482 | | }; |
483 | | |
484 | | explicit SPIRUndef(TypeID basetype_) |
485 | 70 | : basetype(basetype_) |
486 | 70 | { |
487 | 70 | } |
488 | | TypeID basetype; |
489 | | |
490 | | SPIRV_CROSS_DECLARE_CLONE(SPIRUndef) |
491 | | }; |
492 | | |
493 | | struct SPIRString : IVariant |
494 | | { |
495 | | enum |
496 | | { |
497 | | type = TypeString |
498 | | }; |
499 | | |
500 | | explicit SPIRString(std::string str_) |
501 | 667 | : str(std::move(str_)) |
502 | 667 | { |
503 | 667 | } |
504 | | |
505 | | std::string str; |
506 | | |
507 | | SPIRV_CROSS_DECLARE_CLONE(SPIRString) |
508 | | }; |
509 | | |
510 | | struct SPIRDebugLocalVariable : IVariant |
511 | | { |
512 | | enum |
513 | | { |
514 | | type = TypeDebugLocalVariable |
515 | | }; |
516 | | |
517 | | uint32_t name_id; |
518 | | |
519 | | SPIRV_CROSS_DECLARE_CLONE(SPIRDebugLocalVariable) |
520 | | }; |
521 | | |
522 | | // This type is only used by backends which need to access the combined image and sampler IDs separately after |
523 | | // the OpSampledImage opcode. |
524 | | struct SPIRCombinedImageSampler : IVariant |
525 | | { |
526 | | enum |
527 | | { |
528 | | type = TypeCombinedImageSampler |
529 | | }; |
530 | | SPIRCombinedImageSampler(TypeID type_, VariableID image_, VariableID sampler_) |
531 | | : combined_type(type_) |
532 | | , image(image_) |
533 | | , sampler(sampler_) |
534 | 0 | { |
535 | 0 | } |
536 | | TypeID combined_type; |
537 | | VariableID image; |
538 | | VariableID sampler; |
539 | | |
540 | | SPIRV_CROSS_DECLARE_CLONE(SPIRCombinedImageSampler) |
541 | | }; |
542 | | |
543 | | struct SPIRConstantOp : IVariant |
544 | | { |
545 | | enum |
546 | | { |
547 | | type = TypeConstantOp |
548 | | }; |
549 | | |
550 | | SPIRConstantOp(TypeID result_type, spv::Op op, const uint32_t *args, uint32_t length) |
551 | 517 | : opcode(op) |
552 | 517 | , basetype(result_type) |
553 | 517 | { |
554 | 517 | arguments.reserve(length); |
555 | 1.06k | for (uint32_t i = 0; i < length; i++) |
556 | 549 | arguments.push_back(args[i]); |
557 | 517 | } |
558 | | |
559 | | spv::Op opcode; |
560 | | SmallVector<uint32_t> arguments; |
561 | | TypeID basetype; |
562 | | |
563 | | SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp) |
564 | | }; |
565 | | |
566 | | struct SPIRType : IVariant |
567 | | { |
568 | | enum |
569 | | { |
570 | | type = TypeType |
571 | | }; |
572 | | |
573 | | spv::Op op = spv::Op::OpNop; |
574 | 9.95k | explicit SPIRType(spv::Op op_) : op(op_) {} |
575 | | |
576 | | enum BaseType |
577 | | { |
578 | | Unknown, |
579 | | Void, |
580 | | Boolean, |
581 | | SByte, |
582 | | UByte, |
583 | | Short, |
584 | | UShort, |
585 | | Int, |
586 | | UInt, |
587 | | Int64, |
588 | | UInt64, |
589 | | AtomicCounter, |
590 | | Half, |
591 | | Float, |
592 | | Double, |
593 | | Struct, |
594 | | Image, |
595 | | SampledImage, |
596 | | Sampler, |
597 | | AccelerationStructure, |
598 | | RayQuery, |
599 | | CoopVecNV, |
600 | | |
601 | | // Keep internal types at the end. |
602 | | ControlPointArray, |
603 | | Interpolant, |
604 | | Char, |
605 | | // MSL specific type, that is used by 'object'(analog of 'task' from glsl) shader. |
606 | | MeshGridProperties, |
607 | | BFloat16, |
608 | | FloatE4M3, |
609 | | FloatE5M2, |
610 | | |
611 | | Tensor |
612 | | }; |
613 | | |
614 | | // Scalar/vector/matrix support. |
615 | | BaseType basetype = Unknown; |
616 | | uint32_t width = 0; |
617 | | uint32_t vecsize = 1; |
618 | | uint32_t columns = 1; |
619 | | |
620 | | // Arrays, support array of arrays by having a vector of array sizes. |
621 | | SmallVector<uint32_t> array; |
622 | | |
623 | | // Array elements can be either specialization constants or specialization ops. |
624 | | // This array determines how to interpret the array size. |
625 | | // If an element is true, the element is a literal, |
626 | | // otherwise, it's an expression, which must be resolved on demand. |
627 | | // The actual size is not really known until runtime. |
628 | | SmallVector<bool> array_size_literal; |
629 | | |
630 | | // Pointers |
631 | | // Keep track of how many pointer layers we have. |
632 | | uint32_t pointer_depth = 0; |
633 | | bool pointer = false; |
634 | | bool forward_pointer = false; |
635 | | |
636 | | union |
637 | | { |
638 | | struct |
639 | | { |
640 | | uint32_t use_id; |
641 | | uint32_t rows_id; |
642 | | uint32_t columns_id; |
643 | | uint32_t scope_id; |
644 | | } cooperative; |
645 | | |
646 | | struct |
647 | | { |
648 | | uint32_t component_type_id; |
649 | | uint32_t component_count_id; |
650 | | } coopVecNV; |
651 | | |
652 | | struct |
653 | | { |
654 | | uint32_t type; |
655 | | uint32_t rank; |
656 | | uint32_t shape; |
657 | | } tensor; |
658 | | } ext; |
659 | | |
660 | | spv::StorageClass storage = spv::StorageClassGeneric; |
661 | | |
662 | | SmallVector<TypeID> member_types; |
663 | | |
664 | | // If member order has been rewritten to handle certain scenarios with Offset, |
665 | | // allow codegen to rewrite the index. |
666 | | SmallVector<uint32_t> member_type_index_redirection; |
667 | | |
668 | | struct ImageType |
669 | | { |
670 | | TypeID type; |
671 | | spv::Dim dim; |
672 | | bool depth; |
673 | | bool arrayed; |
674 | | bool ms; |
675 | | uint32_t sampled; |
676 | | spv::ImageFormat format; |
677 | | spv::AccessQualifier access; |
678 | | } image = {}; |
679 | | |
680 | | // Structs can be declared multiple times if they are used as part of interface blocks. |
681 | | // We want to detect this so that we only emit the struct definition once. |
682 | | // Since we cannot rely on OpName to be equal, we need to figure out aliases. |
683 | | TypeID type_alias = 0; |
684 | | |
685 | | // Denotes the type which this type is based on. |
686 | | // Allows the backend to traverse how a complex type is built up during access chains. |
687 | | TypeID parent_type = 0; |
688 | | |
689 | | // Used in backends to avoid emitting members with conflicting names. |
690 | | std::unordered_set<std::string> member_name_cache; |
691 | | |
692 | | SPIRV_CROSS_DECLARE_CLONE(SPIRType) |
693 | | }; |
694 | | |
695 | | struct SPIRExtension : IVariant |
696 | | { |
697 | | enum |
698 | | { |
699 | | type = TypeExtension |
700 | | }; |
701 | | |
702 | | enum Extension |
703 | | { |
704 | | Unsupported, |
705 | | GLSL, |
706 | | SPV_debug_info, |
707 | | SPV_AMD_shader_ballot, |
708 | | SPV_AMD_shader_explicit_vertex_parameter, |
709 | | SPV_AMD_shader_trinary_minmax, |
710 | | SPV_AMD_gcn_shader, |
711 | | NonSemanticDebugPrintf, |
712 | | NonSemanticShaderDebugInfo, |
713 | | NonSemanticGeneric |
714 | | }; |
715 | | |
716 | | enum ShaderDebugInfoOps |
717 | | { |
718 | | DebugLine = 103, |
719 | | DebugSource = 35 |
720 | | }; |
721 | | |
722 | | explicit SPIRExtension(Extension ext_) |
723 | 500 | : ext(ext_) |
724 | 500 | { |
725 | 500 | } |
726 | | |
727 | | Extension ext; |
728 | | SPIRV_CROSS_DECLARE_CLONE(SPIRExtension) |
729 | | }; |
730 | | |
731 | | // SPIREntryPoint is not a variant since its IDs are used to decorate OpFunction, |
732 | | // so in order to avoid conflicts, we can't stick them in the ids array. |
733 | | struct SPIREntryPoint |
734 | | { |
735 | | SPIREntryPoint(FunctionID self_, spv::ExecutionModel execution_model, const std::string &entry_name) |
736 | 2.89k | : self(self_) |
737 | 2.89k | , name(entry_name) |
738 | 2.89k | , orig_name(entry_name) |
739 | 2.89k | , model(execution_model) |
740 | 2.89k | { |
741 | 2.89k | } |
742 | 85 | SPIREntryPoint() = default; |
743 | | |
744 | | FunctionID self = 0; |
745 | | std::string name; |
746 | | std::string orig_name; |
747 | | std::unordered_map<uint32_t, uint32_t> fp_fast_math_defaults; |
748 | | bool signed_zero_inf_nan_preserve_8 = false; |
749 | | bool signed_zero_inf_nan_preserve_16 = false; |
750 | | bool signed_zero_inf_nan_preserve_32 = false; |
751 | | bool signed_zero_inf_nan_preserve_64 = false; |
752 | | SmallVector<VariableID> interface_variables; |
753 | | |
754 | | Bitset flags; |
755 | | struct WorkgroupSize |
756 | | { |
757 | | uint32_t x = 0, y = 0, z = 0; |
758 | | uint32_t id_x = 0, id_y = 0, id_z = 0; |
759 | | uint32_t constant = 0; // Workgroup size can be expressed as a constant/spec-constant instead. |
760 | | } workgroup_size; |
761 | | uint32_t invocations = 0; |
762 | | uint32_t output_vertices = 0; |
763 | | uint32_t output_primitives = 0; |
764 | | spv::ExecutionModel model = spv::ExecutionModelMax; |
765 | | bool geometry_passthrough = false; |
766 | | }; |
767 | | |
768 | | struct SPIRExpression : IVariant |
769 | | { |
770 | | enum |
771 | | { |
772 | | type = TypeExpression |
773 | | }; |
774 | | |
775 | | // Only created by the backend target to avoid creating tons of temporaries. |
776 | | SPIRExpression(std::string expr, TypeID expression_type_, bool immutable_) |
777 | | : expression(std::move(expr)) |
778 | | , expression_type(expression_type_) |
779 | | , immutable(immutable_) |
780 | 0 | { |
781 | 0 | } |
782 | | |
783 | | // If non-zero, prepend expression with to_expression(base_expression). |
784 | | // Used in amortizing multiple calls to to_expression() |
785 | | // where in certain cases that would quickly force a temporary when not needed. |
786 | | ID base_expression = 0; |
787 | | |
788 | | std::string expression; |
789 | | TypeID expression_type = 0; |
790 | | |
791 | | // If this expression is a forwarded load, |
792 | | // allow us to reference the original variable. |
793 | | ID loaded_from = 0; |
794 | | |
795 | | // If this expression will never change, we can avoid lots of temporaries |
796 | | // in high level source. |
797 | | // An expression being immutable can be speculative, |
798 | | // it is assumed that this is true almost always. |
799 | | bool immutable = false; |
800 | | |
801 | | // Before use, this expression must be transposed. |
802 | | // This is needed for targets which don't support row_major layouts. |
803 | | bool need_transpose = false; |
804 | | |
805 | | // Whether or not this is an access chain expression. |
806 | | bool access_chain = false; |
807 | | |
808 | | // Whether or not gl_MeshVerticesEXT[].gl_Position (as a whole or .y) is referenced |
809 | | bool access_meshlet_position_y = false; |
810 | | |
811 | | // A list of expressions which this expression depends on. |
812 | | SmallVector<ID> expression_dependencies; |
813 | | |
814 | | // Similar as expression dependencies, but does not stop the tracking for force-temporary variables. |
815 | | // We need to know the full chain from store back to any SSA variable. |
816 | | SmallVector<ID> invariance_dependencies; |
817 | | |
818 | | // By reading this expression, we implicitly read these expressions as well. |
819 | | // Used by access chain Store and Load since we read multiple expressions in this case. |
820 | | SmallVector<ID> implied_read_expressions; |
821 | | |
822 | | // The expression was emitted at a certain scope. Lets us track when an expression read means multiple reads. |
823 | | uint32_t emitted_loop_level = 0; |
824 | | |
825 | | SPIRV_CROSS_DECLARE_CLONE(SPIRExpression) |
826 | | }; |
827 | | |
828 | | struct SPIRFunctionPrototype : IVariant |
829 | | { |
830 | | enum |
831 | | { |
832 | | type = TypeFunctionPrototype |
833 | | }; |
834 | | |
835 | | explicit SPIRFunctionPrototype(TypeID return_type_) |
836 | 1.21k | : return_type(return_type_) |
837 | 1.21k | { |
838 | 1.21k | } |
839 | | |
840 | | TypeID return_type; |
841 | | SmallVector<uint32_t> parameter_types; |
842 | | |
843 | | SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype) |
844 | | }; |
845 | | |
846 | | struct SPIRBlock : IVariant |
847 | | { |
848 | | enum |
849 | | { |
850 | | type = TypeBlock |
851 | | }; |
852 | | |
853 | | enum Terminator |
854 | | { |
855 | | Unknown, |
856 | | Direct, // Emit next block directly without a particular condition. |
857 | | |
858 | | Select, // Block ends with an if/else block. |
859 | | MultiSelect, // Block ends with switch statement. |
860 | | |
861 | | Return, // Block ends with return. |
862 | | Unreachable, // Noop |
863 | | Kill, // Discard |
864 | | IgnoreIntersection, // Ray Tracing |
865 | | TerminateRay, // Ray Tracing |
866 | | EmitMeshTasks // Mesh shaders |
867 | | }; |
868 | | |
869 | | enum Merge |
870 | | { |
871 | | MergeNone, |
872 | | MergeLoop, |
873 | | MergeSelection |
874 | | }; |
875 | | |
876 | | enum Hints |
877 | | { |
878 | | HintNone, |
879 | | HintUnroll, |
880 | | HintDontUnroll, |
881 | | HintFlatten, |
882 | | HintDontFlatten |
883 | | }; |
884 | | |
885 | | enum Method |
886 | | { |
887 | | MergeToSelectForLoop, |
888 | | MergeToDirectForLoop, |
889 | | MergeToSelectContinueForLoop |
890 | | }; |
891 | | |
892 | | enum ContinueBlockType |
893 | | { |
894 | | ContinueNone, |
895 | | |
896 | | // Continue block is branchless and has at least one instruction. |
897 | | ForLoop, |
898 | | |
899 | | // Noop continue block. |
900 | | WhileLoop, |
901 | | |
902 | | // Continue block is conditional. |
903 | | DoWhileLoop, |
904 | | |
905 | | // Highly unlikely that anything will use this, |
906 | | // since it is really awkward/impossible to express in GLSL. |
907 | | ComplexLoop |
908 | | }; |
909 | | |
910 | | enum : uint32_t |
911 | | { |
912 | | NoDominator = 0xffffffffu |
913 | | }; |
914 | | |
915 | | Terminator terminator = Unknown; |
916 | | Merge merge = MergeNone; |
917 | | Hints hint = HintNone; |
918 | | BlockID next_block = 0; |
919 | | BlockID merge_block = 0; |
920 | | BlockID continue_block = 0; |
921 | | |
922 | | ID return_value = 0; // If 0, return nothing (void). |
923 | | ID condition = 0; |
924 | | BlockID true_block = 0; |
925 | | BlockID false_block = 0; |
926 | | BlockID default_block = 0; |
927 | | |
928 | | // If terminator is EmitMeshTasksEXT. |
929 | | struct |
930 | | { |
931 | | ID groups[3]; |
932 | | ID payload; |
933 | | } mesh = {}; |
934 | | |
935 | | SmallVector<Instruction> ops; |
936 | | |
937 | | struct Phi |
938 | | { |
939 | | ID local_variable; // flush local variable ... |
940 | | BlockID parent; // If we're in from_block and want to branch into this block ... |
941 | | VariableID function_variable; // to this function-global "phi" variable first. |
942 | | }; |
943 | | |
944 | | // Before entering this block flush out local variables to magical "phi" variables. |
945 | | SmallVector<Phi> phi_variables; |
946 | | |
947 | | // Declare these temporaries before beginning the block. |
948 | | // Used for handling complex continue blocks which have side effects. |
949 | | SmallVector<std::pair<TypeID, ID>> declare_temporary; |
950 | | |
951 | | // Declare these temporaries, but only conditionally if this block turns out to be |
952 | | // a complex loop header. |
953 | | SmallVector<std::pair<TypeID, ID>> potential_declare_temporary; |
954 | | |
955 | | struct Case |
956 | | { |
957 | | uint64_t value; |
958 | | BlockID block; |
959 | | }; |
960 | | SmallVector<Case> cases_32bit; |
961 | | SmallVector<Case> cases_64bit; |
962 | | |
963 | | // If we have tried to optimize code for this block but failed, |
964 | | // keep track of this. |
965 | | bool disable_block_optimization = false; |
966 | | |
967 | | // If the continue block is complex, fallback to "dumb" for loops. |
968 | | bool complex_continue = false; |
969 | | |
970 | | // Do we need a ladder variable to defer breaking out of a loop construct after a switch block? |
971 | | bool need_ladder_break = false; |
972 | | |
973 | | // If marked, we have explicitly handled Phi from this block, so skip any flushes related to that on a branch. |
974 | | // Used to handle an edge case with switch and case-label fallthrough where fall-through writes to Phi. |
975 | | BlockID ignore_phi_from_block = 0; |
976 | | |
977 | | // The dominating block which this block might be within. |
978 | | // Used in continue; blocks to determine if we really need to write continue. |
979 | | BlockID loop_dominator = 0; |
980 | | |
981 | | // All access to these variables are dominated by this block, |
982 | | // so before branching anywhere we need to make sure that we declare these variables. |
983 | | SmallVector<VariableID> dominated_variables; |
984 | | SmallVector<bool> rearm_dominated_variables; |
985 | | |
986 | | // These are variables which should be declared in a for loop header, if we |
987 | | // fail to use a classic for-loop, |
988 | | // we remove these variables, and fall back to regular variables outside the loop. |
989 | | SmallVector<VariableID> loop_variables; |
990 | | |
991 | | // Some expressions are control-flow dependent, i.e. any instruction which relies on derivatives or |
992 | | // sub-group-like operations. |
993 | | // Make sure that we only use these expressions in the original block. |
994 | | SmallVector<ID> invalidate_expressions; |
995 | | |
996 | | SPIRV_CROSS_DECLARE_CLONE(SPIRBlock) |
997 | | }; |
998 | | |
999 | | struct SPIRFunction : IVariant |
1000 | | { |
1001 | | enum |
1002 | | { |
1003 | | type = TypeFunction |
1004 | | }; |
1005 | | |
1006 | | SPIRFunction(TypeID return_type_, TypeID function_type_) |
1007 | 831 | : return_type(return_type_) |
1008 | 831 | , function_type(function_type_) |
1009 | 831 | { |
1010 | 831 | } |
1011 | | |
1012 | | struct Parameter |
1013 | | { |
1014 | | TypeID type; |
1015 | | ID id; |
1016 | | uint32_t read_count; |
1017 | | uint32_t write_count; |
1018 | | |
1019 | | // Set to true if this parameter aliases a global variable, |
1020 | | // used mostly in Metal where global variables |
1021 | | // have to be passed down to functions as regular arguments. |
1022 | | // However, for this kind of variable, we should not care about |
1023 | | // read and write counts as access to the function arguments |
1024 | | // is not local to the function in question. |
1025 | | bool alias_global_variable; |
1026 | | }; |
1027 | | |
1028 | | // When calling a function, and we're remapping separate image samplers, |
1029 | | // resolve these arguments into combined image samplers and pass them |
1030 | | // as additional arguments in this order. |
1031 | | // It gets more complicated as functions can pull in their own globals |
1032 | | // and combine them with parameters, |
1033 | | // so we need to distinguish if something is local parameter index |
1034 | | // or a global ID. |
1035 | | struct CombinedImageSamplerParameter |
1036 | | { |
1037 | | VariableID id; |
1038 | | VariableID image_id; |
1039 | | VariableID sampler_id; |
1040 | | bool global_image; |
1041 | | bool global_sampler; |
1042 | | bool depth; |
1043 | | }; |
1044 | | |
1045 | | TypeID return_type; |
1046 | | TypeID function_type; |
1047 | | SmallVector<Parameter> arguments; |
1048 | | |
1049 | | // Can be used by backends to add magic arguments. |
1050 | | // Currently used by combined image/sampler implementation. |
1051 | | |
1052 | | SmallVector<Parameter> shadow_arguments; |
1053 | | SmallVector<VariableID> local_variables; |
1054 | | BlockID entry_block = 0; |
1055 | | SmallVector<BlockID> blocks; |
1056 | | SmallVector<CombinedImageSamplerParameter> combined_parameters; |
1057 | | |
1058 | | struct EntryLine |
1059 | | { |
1060 | | uint32_t file_id = 0; |
1061 | | uint32_t line_literal = 0; |
1062 | | }; |
1063 | | EntryLine entry_line; |
1064 | | |
1065 | | void add_local_variable(VariableID id) |
1066 | 2.93k | { |
1067 | 2.93k | local_variables.push_back(id); |
1068 | 2.93k | } |
1069 | | |
1070 | | void add_parameter(TypeID parameter_type, ID id, bool alias_global_variable = false) |
1071 | 321 | { |
1072 | | // Arguments are read-only until proven otherwise. |
1073 | 321 | arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable }); |
1074 | 321 | } |
1075 | | |
1076 | | // Hooks to be run when the function returns. |
1077 | | // Mostly used for lowering internal data structures onto flattened structures. |
1078 | | // Need to defer this, because they might rely on things which change during compilation. |
1079 | | // Intentionally not a small vector, this one is rare, and std::function can be large. |
1080 | | Vector<std::function<void()>> fixup_hooks_out; |
1081 | | |
1082 | | // Hooks to be run when the function begins. |
1083 | | // Mostly used for populating internal data structures from flattened structures. |
1084 | | // Need to defer this, because they might rely on things which change during compilation. |
1085 | | // Intentionally not a small vector, this one is rare, and std::function can be large. |
1086 | | Vector<std::function<void()>> fixup_hooks_in; |
1087 | | |
1088 | | // On function entry, make sure to copy a constant array into thread addr space to work around |
1089 | | // the case where we are passing a constant array by value to a function on backends which do not |
1090 | | // consider arrays value types. |
1091 | | SmallVector<ID> constant_arrays_needed_on_stack; |
1092 | | |
1093 | | // Does this function (or any function called by it), emit geometry? |
1094 | | bool emits_geometry = false; |
1095 | | |
1096 | | bool active = false; |
1097 | | bool flush_undeclared = true; |
1098 | | bool do_combined_parameters = true; |
1099 | | |
1100 | | SPIRV_CROSS_DECLARE_CLONE(SPIRFunction) |
1101 | | }; |
1102 | | |
1103 | | struct SPIRAccessChain : IVariant |
1104 | | { |
1105 | | enum |
1106 | | { |
1107 | | type = TypeAccessChain |
1108 | | }; |
1109 | | |
1110 | | SPIRAccessChain(TypeID basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_, |
1111 | | int32_t static_index_) |
1112 | | : basetype(basetype_) |
1113 | | , storage(storage_) |
1114 | | , base(std::move(base_)) |
1115 | | , dynamic_index(std::move(dynamic_index_)) |
1116 | | , static_index(static_index_) |
1117 | 0 | { |
1118 | 0 | } |
1119 | | |
1120 | | // The access chain represents an offset into a buffer. |
1121 | | // Some backends need more complicated handling of access chains to be able to use buffers, like HLSL |
1122 | | // which has no usable buffer type ala GLSL SSBOs. |
1123 | | // StructuredBuffer is too limited, so our only option is to deal with ByteAddressBuffer which works with raw addresses. |
1124 | | |
1125 | | TypeID basetype; |
1126 | | spv::StorageClass storage; |
1127 | | std::string base; |
1128 | | std::string dynamic_index; |
1129 | | int32_t static_index; |
1130 | | |
1131 | | VariableID loaded_from = 0; |
1132 | | uint32_t matrix_stride = 0; |
1133 | | uint32_t array_stride = 0; |
1134 | | bool row_major_matrix = false; |
1135 | | bool immutable = false; |
1136 | | |
1137 | | // By reading this expression, we implicitly read these expressions as well. |
1138 | | // Used by access chain Store and Load since we read multiple expressions in this case. |
1139 | | SmallVector<ID> implied_read_expressions; |
1140 | | |
1141 | | SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain) |
1142 | | }; |
1143 | | |
1144 | | struct SPIRVariable : IVariant |
1145 | | { |
1146 | | enum |
1147 | | { |
1148 | | type = TypeVariable |
1149 | | }; |
1150 | | |
1151 | | SPIRVariable() = default; |
1152 | | SPIRVariable(TypeID basetype_, spv::StorageClass storage_, ID initializer_ = 0, VariableID basevariable_ = 0) |
1153 | 3.97k | : basetype(basetype_) |
1154 | 3.97k | , storage(storage_) |
1155 | 3.97k | , initializer(initializer_) |
1156 | 3.97k | , basevariable(basevariable_) |
1157 | 3.97k | { |
1158 | 3.97k | } |
1159 | | |
1160 | | TypeID basetype = 0; |
1161 | | spv::StorageClass storage = spv::StorageClassGeneric; |
1162 | | uint32_t decoration = 0; |
1163 | | ID initializer = 0; |
1164 | | VariableID basevariable = 0; |
1165 | | |
1166 | | SmallVector<uint32_t> dereference_chain; |
1167 | | bool compat_builtin = false; |
1168 | | |
1169 | | // If a variable is shadowed, we only statically assign to it |
1170 | | // and never actually emit a statement for it. |
1171 | | // When we read the variable as an expression, just forward |
1172 | | // shadowed_id as the expression. |
1173 | | bool statically_assigned = false; |
1174 | | ID static_expression = 0; |
1175 | | |
1176 | | // Temporaries which can remain forwarded as long as this variable is not modified. |
1177 | | SmallVector<ID> dependees; |
1178 | | |
1179 | | // ShaderDebugInfo local variables attached to this variable via DebugDeclare |
1180 | | SmallVector<ID> debug_local_variables; |
1181 | | |
1182 | | bool deferred_declaration = false; |
1183 | | bool phi_variable = false; |
1184 | | |
1185 | | // Used to deal with Phi variable flushes. See flush_phi(). |
1186 | | bool allocate_temporary_copy = false; |
1187 | | |
1188 | | bool remapped_variable = false; |
1189 | | uint32_t remapped_components = 0; |
1190 | | |
1191 | | // The block which dominates all access to this variable. |
1192 | | BlockID dominator = 0; |
1193 | | // If true, this variable is a loop variable, when accessing the variable |
1194 | | // outside a loop, |
1195 | | // we should statically forward it. |
1196 | | bool loop_variable = false; |
1197 | | // Set to true while we're inside the for loop. |
1198 | | bool loop_variable_enable = false; |
1199 | | |
1200 | | // Used to find global LUTs |
1201 | | bool is_written_to = false; |
1202 | | |
1203 | | SPIRFunction::Parameter *parameter = nullptr; |
1204 | | |
1205 | | SPIRV_CROSS_DECLARE_CLONE(SPIRVariable) |
1206 | | }; |
1207 | | |
1208 | | struct SPIRConstant : IVariant |
1209 | | { |
1210 | | enum |
1211 | | { |
1212 | | type = TypeConstant |
1213 | | }; |
1214 | | |
1215 | | union Constant |
1216 | | { |
1217 | | uint32_t u32; |
1218 | | int32_t i32; |
1219 | | float f32; |
1220 | | |
1221 | | uint64_t u64; |
1222 | | int64_t i64; |
1223 | | double f64; |
1224 | | }; |
1225 | | |
1226 | | struct ConstantVector |
1227 | | { |
1228 | | Constant r[4]; |
1229 | | // If != 0, this element is a specialization constant, and we should keep track of it as such. |
1230 | | ID id[4]; |
1231 | | uint32_t vecsize = 1; |
1232 | | |
1233 | | ConstantVector() |
1234 | 374k | { |
1235 | 374k | memset(r, 0, sizeof(r)); |
1236 | 374k | } |
1237 | | }; |
1238 | | |
1239 | | struct ConstantMatrix |
1240 | | { |
1241 | | ConstantVector c[4]; |
1242 | | // If != 0, this column is a specialization constant, and we should keep track of it as such. |
1243 | | ID id[4]; |
1244 | | uint32_t columns = 1; |
1245 | | }; |
1246 | | |
1247 | | static inline float f16_to_f32(uint16_t u16_value) |
1248 | 0 | { |
1249 | 0 | // Based on the GLM implementation. |
1250 | 0 | int s = (u16_value >> 15) & 0x1; |
1251 | 0 | int e = (u16_value >> 10) & 0x1f; |
1252 | 0 | int m = (u16_value >> 0) & 0x3ff; |
1253 | 0 |
|
1254 | 0 | union |
1255 | 0 | { |
1256 | 0 | float f32; |
1257 | 0 | uint32_t u32; |
1258 | 0 | } u; |
1259 | 0 |
|
1260 | 0 | if (e == 0) |
1261 | 0 | { |
1262 | 0 | if (m == 0) |
1263 | 0 | { |
1264 | 0 | u.u32 = uint32_t(s) << 31; |
1265 | 0 | return u.f32; |
1266 | 0 | } |
1267 | 0 | else |
1268 | 0 | { |
1269 | 0 | while ((m & 0x400) == 0) |
1270 | 0 | { |
1271 | 0 | m <<= 1; |
1272 | 0 | e--; |
1273 | 0 | } |
1274 | 0 |
|
1275 | 0 | e++; |
1276 | 0 | m &= ~0x400; |
1277 | 0 | } |
1278 | 0 | } |
1279 | 0 | else if (e == 31) |
1280 | 0 | { |
1281 | 0 | if (m == 0) |
1282 | 0 | { |
1283 | 0 | u.u32 = (uint32_t(s) << 31) | 0x7f800000u; |
1284 | 0 | return u.f32; |
1285 | 0 | } |
1286 | 0 | else |
1287 | 0 | { |
1288 | 0 | u.u32 = (uint32_t(s) << 31) | 0x7f800000u | (m << 13); |
1289 | 0 | return u.f32; |
1290 | 0 | } |
1291 | 0 | } |
1292 | 0 |
|
1293 | 0 | e += 127 - 15; |
1294 | 0 | m <<= 13; |
1295 | 0 | u.u32 = (uint32_t(s) << 31) | (e << 23) | m; |
1296 | 0 | return u.f32; |
1297 | 0 | } |
1298 | | |
1299 | | static inline float fe4m3_to_f32(uint8_t v) |
1300 | 0 | { |
1301 | 0 | if ((v & 0x7f) == 0x7f) |
1302 | 0 | { |
1303 | 0 | union |
1304 | 0 | { |
1305 | 0 | float f32; |
1306 | 0 | uint32_t u32; |
1307 | 0 | } u; |
1308 | 0 |
|
1309 | 0 | u.u32 = (v & 0x80) ? 0xffffffffu : 0x7fffffffu; |
1310 | 0 | return u.f32; |
1311 | 0 | } |
1312 | 0 | else |
1313 | 0 | { |
1314 | 0 | // Reuse the FP16 to FP32 code. Cute bit-hackery. |
1315 | 0 | return f16_to_f32((int16_t(int8_t(v)) << 7) & (0xffff ^ 0x4000)) * 256.0f; |
1316 | 0 | } |
1317 | 0 | } |
1318 | | |
1319 | | inline uint32_t specialization_constant_id(uint32_t col, uint32_t row) const |
1320 | 0 | { |
1321 | 0 | return m.c[col].id[row]; |
1322 | 0 | } |
1323 | | |
1324 | | inline uint32_t specialization_constant_id(uint32_t col) const |
1325 | 0 | { |
1326 | 0 | return m.id[col]; |
1327 | 0 | } |
1328 | | |
1329 | | inline uint32_t scalar(uint32_t col = 0, uint32_t row = 0) const |
1330 | 215 | { |
1331 | 215 | return m.c[col].r[row].u32; |
1332 | 215 | } |
1333 | | |
1334 | | inline int16_t scalar_i16(uint32_t col = 0, uint32_t row = 0) const |
1335 | 0 | { |
1336 | 0 | return int16_t(m.c[col].r[row].u32 & 0xffffu); |
1337 | 0 | } |
1338 | | |
1339 | | inline uint16_t scalar_u16(uint32_t col = 0, uint32_t row = 0) const |
1340 | 0 | { |
1341 | 0 | return uint16_t(m.c[col].r[row].u32 & 0xffffu); |
1342 | 0 | } |
1343 | | |
1344 | | inline int8_t scalar_i8(uint32_t col = 0, uint32_t row = 0) const |
1345 | 0 | { |
1346 | 0 | return int8_t(m.c[col].r[row].u32 & 0xffu); |
1347 | 0 | } |
1348 | | |
1349 | | inline uint8_t scalar_u8(uint32_t col = 0, uint32_t row = 0) const |
1350 | 0 | { |
1351 | 0 | return uint8_t(m.c[col].r[row].u32 & 0xffu); |
1352 | 0 | } |
1353 | | |
1354 | | inline float scalar_f16(uint32_t col = 0, uint32_t row = 0) const |
1355 | 0 | { |
1356 | 0 | return f16_to_f32(scalar_u16(col, row)); |
1357 | 0 | } |
1358 | | |
1359 | | inline float scalar_bf16(uint32_t col = 0, uint32_t row = 0) const |
1360 | 0 | { |
1361 | 0 | uint32_t v = scalar_u16(col, row) << 16; |
1362 | 0 | float fp32; |
1363 | 0 | memcpy(&fp32, &v, sizeof(float)); |
1364 | 0 | return fp32; |
1365 | 0 | } |
1366 | | |
1367 | | inline float scalar_floate4m3(uint32_t col = 0, uint32_t row = 0) const |
1368 | 0 | { |
1369 | 0 | return fe4m3_to_f32(scalar_u8(col, row)); |
1370 | 0 | } |
1371 | | |
1372 | | inline float scalar_bf8(uint32_t col = 0, uint32_t row = 0) const |
1373 | 0 | { |
1374 | 0 | return f16_to_f32(uint16_t(scalar_u8(col, row) << 8)); |
1375 | 0 | } |
1376 | | |
1377 | | inline float scalar_f32(uint32_t col = 0, uint32_t row = 0) const |
1378 | 0 | { |
1379 | 0 | return m.c[col].r[row].f32; |
1380 | 0 | } |
1381 | | |
1382 | | inline int32_t scalar_i32(uint32_t col = 0, uint32_t row = 0) const |
1383 | 90 | { |
1384 | 90 | return m.c[col].r[row].i32; |
1385 | 90 | } |
1386 | | |
1387 | | inline double scalar_f64(uint32_t col = 0, uint32_t row = 0) const |
1388 | 0 | { |
1389 | 0 | return m.c[col].r[row].f64; |
1390 | 0 | } |
1391 | | |
1392 | | inline int64_t scalar_i64(uint32_t col = 0, uint32_t row = 0) const |
1393 | 0 | { |
1394 | 0 | return m.c[col].r[row].i64; |
1395 | 0 | } |
1396 | | |
1397 | | inline uint64_t scalar_u64(uint32_t col = 0, uint32_t row = 0) const |
1398 | 0 | { |
1399 | 0 | return m.c[col].r[row].u64; |
1400 | 0 | } |
1401 | | |
1402 | | inline const ConstantVector &vector() const |
1403 | 0 | { |
1404 | 0 | return m.c[0]; |
1405 | 0 | } |
1406 | | |
1407 | | inline uint32_t vector_size() const |
1408 | 0 | { |
1409 | 0 | return m.c[0].vecsize; |
1410 | 0 | } |
1411 | | |
1412 | | inline uint32_t columns() const |
1413 | 0 | { |
1414 | 0 | return m.columns; |
1415 | 0 | } |
1416 | | |
1417 | | inline void make_null(const SPIRType &constant_type_) |
1418 | 28.8k | { |
1419 | 28.8k | m = {}; |
1420 | 28.8k | m.columns = constant_type_.columns; |
1421 | 28.8k | for (auto &c : m.c) |
1422 | 115k | c.vecsize = constant_type_.vecsize; |
1423 | 28.8k | } |
1424 | | |
1425 | | inline bool constant_is_null() const |
1426 | 0 | { |
1427 | 0 | if (specialization) |
1428 | 0 | return false; |
1429 | 0 | if (!subconstants.empty()) |
1430 | 0 | return false; |
1431 | 0 |
|
1432 | 0 | for (uint32_t col = 0; col < columns(); col++) |
1433 | 0 | for (uint32_t row = 0; row < vector_size(); row++) |
1434 | 0 | if (scalar_u64(col, row) != 0) |
1435 | 0 | return false; |
1436 | 0 |
|
1437 | 0 | return true; |
1438 | 0 | } |
1439 | | |
1440 | | explicit SPIRConstant(uint32_t constant_type_) |
1441 | 28.9k | : constant_type(constant_type_) |
1442 | 28.9k | { |
1443 | 28.9k | } |
1444 | | |
1445 | 1.54k | SPIRConstant() = default; |
1446 | | |
1447 | | SPIRConstant(TypeID constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized, bool replicated_ = false) |
1448 | 27.4k | : constant_type(constant_type_) |
1449 | 27.4k | , specialization(specialized) |
1450 | 27.4k | , replicated(replicated_) |
1451 | 27.4k | { |
1452 | 27.4k | subconstants.reserve(num_elements); |
1453 | 32.7k | for (uint32_t i = 0; i < num_elements; i++) |
1454 | 5.25k | subconstants.push_back(elements[i]); |
1455 | 27.4k | specialization = specialized; |
1456 | 27.4k | } |
1457 | | |
1458 | | // Construct scalar (32-bit). |
1459 | | SPIRConstant(TypeID constant_type_, uint32_t v0, bool specialized) |
1460 | 6.43k | : constant_type(constant_type_) |
1461 | 6.43k | , specialization(specialized) |
1462 | 6.43k | { |
1463 | 6.43k | m.c[0].r[0].u32 = v0; |
1464 | 6.43k | m.c[0].vecsize = 1; |
1465 | 6.43k | m.columns = 1; |
1466 | 6.43k | } |
1467 | | |
1468 | | // Construct scalar (64-bit). |
1469 | | SPIRConstant(TypeID constant_type_, uint64_t v0, bool specialized) |
1470 | 5 | : constant_type(constant_type_) |
1471 | 5 | , specialization(specialized) |
1472 | 5 | { |
1473 | 5 | m.c[0].r[0].u64 = v0; |
1474 | 5 | m.c[0].vecsize = 1; |
1475 | 5 | m.columns = 1; |
1476 | 5 | } |
1477 | | |
1478 | | // Construct vectors and matrices. |
1479 | | SPIRConstant(TypeID constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements, |
1480 | | bool specialized) |
1481 | 383 | : constant_type(constant_type_) |
1482 | 383 | , specialization(specialized) |
1483 | 383 | { |
1484 | 383 | bool matrix = vector_elements[0]->m.c[0].vecsize > 1; |
1485 | | |
1486 | 383 | if (matrix) |
1487 | 1 | { |
1488 | 1 | m.columns = num_elements; |
1489 | | |
1490 | 5 | for (uint32_t i = 0; i < num_elements; i++) |
1491 | 4 | { |
1492 | 4 | m.c[i] = vector_elements[i]->m.c[0]; |
1493 | 4 | if (vector_elements[i]->specialization) |
1494 | 1 | m.id[i] = vector_elements[i]->self; |
1495 | 4 | } |
1496 | 1 | } |
1497 | 382 | else |
1498 | 382 | { |
1499 | 382 | m.c[0].vecsize = num_elements; |
1500 | 382 | m.columns = 1; |
1501 | | |
1502 | 1.72k | for (uint32_t i = 0; i < num_elements; i++) |
1503 | 1.33k | { |
1504 | 1.33k | m.c[0].r[i] = vector_elements[i]->m.c[0].r[0]; |
1505 | 1.33k | if (vector_elements[i]->specialization) |
1506 | 5 | m.c[0].id[i] = vector_elements[i]->self; |
1507 | 1.33k | } |
1508 | 382 | } |
1509 | 383 | } |
1510 | | |
1511 | | TypeID constant_type = 0; |
1512 | | ConstantMatrix m; |
1513 | | |
1514 | | // If this constant is a specialization constant (i.e. created with OpSpecConstant*). |
1515 | | bool specialization = false; |
1516 | | // If this constant is used as an array length which creates specialization restrictions on some backends. |
1517 | | bool is_used_as_array_length = false; |
1518 | | |
1519 | | // If true, this is a LUT, and should always be declared in the outer scope. |
1520 | | bool is_used_as_lut = false; |
1521 | | |
1522 | | // If this is a null constant of array type with specialized length. |
1523 | | // May require special handling in initializer |
1524 | | bool is_null_array_specialized_length = false; |
1525 | | |
1526 | | // For composites which are constant arrays, etc. |
1527 | | SmallVector<ConstantID> subconstants; |
1528 | | |
1529 | | // Whether the subconstants are intended to be replicated (e.g. OpConstantCompositeReplicateEXT) |
1530 | | bool replicated = false; |
1531 | | |
1532 | | // Non-Vulkan GLSL, HLSL and sometimes MSL emits defines for each specialization constant, |
1533 | | // and uses them to initialize the constant. This allows the user |
1534 | | // to still be able to specialize the value by supplying corresponding |
1535 | | // preprocessor directives before compiling the shader. |
1536 | | std::string specialization_constant_macro_name; |
1537 | | |
1538 | | SPIRV_CROSS_DECLARE_CLONE(SPIRConstant) |
1539 | | }; |
1540 | | |
1541 | | // Variants have a very specific allocation scheme. |
1542 | | struct ObjectPoolGroup |
1543 | | { |
1544 | | std::unique_ptr<ObjectPoolBase> pools[TypeCount]; |
1545 | | }; |
1546 | | |
1547 | | class Variant |
1548 | | { |
1549 | | public: |
1550 | | explicit Variant(ObjectPoolGroup *group_) |
1551 | 106M | : group(group_) |
1552 | 106M | { |
1553 | 106M | } |
1554 | | |
1555 | | ~Variant() |
1556 | 106M | { |
1557 | 106M | if (holder) |
1558 | 45.0k | group->pools[type]->deallocate_opaque(holder); |
1559 | 106M | } |
1560 | | |
1561 | | // Marking custom move constructor as noexcept is important. |
1562 | | Variant(Variant &&other) SPIRV_CROSS_NOEXCEPT |
1563 | 41.0k | { |
1564 | 41.0k | *this = std::move(other); |
1565 | 41.0k | } |
1566 | | |
1567 | | // We cannot copy from other variant without our own pool group. |
1568 | | // Have to explicitly copy. |
1569 | | Variant(const Variant &variant) = delete; |
1570 | | |
1571 | | // Marking custom move constructor as noexcept is important. |
1572 | | Variant &operator=(Variant &&other) SPIRV_CROSS_NOEXCEPT |
1573 | 41.0k | { |
1574 | 41.0k | if (this != &other) |
1575 | 41.0k | { |
1576 | 41.0k | if (holder) |
1577 | 0 | group->pools[type]->deallocate_opaque(holder); |
1578 | 41.0k | holder = other.holder; |
1579 | 41.0k | group = other.group; |
1580 | 41.0k | type = other.type; |
1581 | 41.0k | allow_type_rewrite = other.allow_type_rewrite; |
1582 | | |
1583 | 41.0k | other.holder = nullptr; |
1584 | 41.0k | other.type = TypeNone; |
1585 | 41.0k | } |
1586 | 41.0k | return *this; |
1587 | 41.0k | } |
1588 | | |
1589 | | // This copy/clone should only be called in the Compiler constructor. |
1590 | | // If this is called inside ::compile(), we invalidate any references we took higher in the stack. |
1591 | | // This should never happen. |
1592 | | Variant &operator=(const Variant &other) |
1593 | 0 | { |
1594 | | //#define SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE |
1595 | | #ifdef SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE |
1596 | | abort(); |
1597 | | #endif |
1598 | 0 | if (this != &other) |
1599 | 0 | { |
1600 | 0 | if (holder) |
1601 | 0 | group->pools[type]->deallocate_opaque(holder); |
1602 | |
|
1603 | 0 | if (other.holder) |
1604 | 0 | holder = other.holder->clone(group->pools[other.type].get()); |
1605 | 0 | else |
1606 | 0 | holder = nullptr; |
1607 | |
|
1608 | 0 | type = other.type; |
1609 | 0 | allow_type_rewrite = other.allow_type_rewrite; |
1610 | 0 | } |
1611 | 0 | return *this; |
1612 | 0 | } |
1613 | | |
1614 | | void set(IVariant *val, Types new_type) |
1615 | 93.4k | { |
1616 | 93.4k | if (holder) |
1617 | 48.4k | group->pools[type]->deallocate_opaque(holder); |
1618 | 93.4k | holder = nullptr; |
1619 | | |
1620 | 93.4k | if (!allow_type_rewrite && type != TypeNone && type != new_type) |
1621 | 10 | { |
1622 | 10 | if (val) |
1623 | 10 | group->pools[new_type]->deallocate_opaque(val); |
1624 | 10 | SPIRV_CROSS_THROW("Overwriting a variant with new type."); |
1625 | 10 | } |
1626 | | |
1627 | 93.4k | holder = val; |
1628 | 93.4k | type = new_type; |
1629 | 93.4k | allow_type_rewrite = false; |
1630 | 93.4k | } |
1631 | | |
1632 | | template <typename T, typename... Ts> |
1633 | | T *allocate_and_set(Types new_type, Ts &&... ts) |
1634 | 93.4k | { |
1635 | 93.4k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); |
1636 | 93.4k | set(val, new_type); |
1637 | 93.4k | return val; |
1638 | 93.4k | } spirv_cross::SPIRString* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRString, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(spirv_cross::Types, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Line | Count | Source | 1634 | 627 | { | 1635 | 627 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 627 | set(val, new_type); | 1637 | 627 | return val; | 1638 | 627 | } |
spirv_cross::SPIRUndef* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRUndef, unsigned int&>(spirv_cross::Types, unsigned int&) Line | Count | Source | 1634 | 70 | { | 1635 | 70 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 70 | set(val, new_type); | 1637 | 70 | return val; | 1638 | 70 | } |
spirv_cross::SPIRExtension* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRExtension, spirv_cross::SPIRExtension::Extension&>(spirv_cross::Types, spirv_cross::SPIRExtension::Extension&) Line | Count | Source | 1634 | 500 | { | 1635 | 500 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 500 | set(val, new_type); | 1637 | 500 | return val; | 1638 | 500 | } |
spirv_cross::SPIRString* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRString, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(spirv_cross::Types, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 1634 | 40 | { | 1635 | 40 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 40 | set(val, new_type); | 1637 | 40 | return val; | 1638 | 40 | } |
spirv_cross::SPIRDebugLocalVariable* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRDebugLocalVariable>(spirv_cross::Types) Line | Count | Source | 1634 | 42 | { | 1635 | 42 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 42 | set(val, new_type); | 1637 | 42 | return val; | 1638 | 42 | } |
spirv_cross::SPIRType* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRType, spv::Op&>(spirv_cross::Types, spv::Op&) Line | Count | Source | 1634 | 9.88k | { | 1635 | 9.88k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 9.88k | set(val, new_type); | 1637 | 9.88k | return val; | 1638 | 9.88k | } |
spirv_cross::SPIRType* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRType, spirv_cross::SPIRType&>(spirv_cross::Types, spirv_cross::SPIRType&) Line | Count | Source | 1634 | 4.54k | { | 1635 | 4.54k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 4.54k | set(val, new_type); | 1637 | 4.54k | return val; | 1638 | 4.54k | } |
spirv_cross::SPIRFunctionPrototype* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRFunctionPrototype, unsigned int&>(spirv_cross::Types, unsigned int&) Line | Count | Source | 1634 | 1.21k | { | 1635 | 1.21k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 1.21k | set(val, new_type); | 1637 | 1.21k | return val; | 1638 | 1.21k | } |
spirv_cross::SPIRVariable* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRVariable, unsigned int&, spv::StorageClass&, unsigned int&>(spirv_cross::Types, unsigned int&, spv::StorageClass&, unsigned int&) Line | Count | Source | 1634 | 2.40k | { | 1635 | 2.40k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 2.40k | set(val, new_type); | 1637 | 2.40k | return val; | 1638 | 2.40k | } |
spirv_cross::SPIRVariable* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRVariable, unsigned int&, spv::StorageClass>(spirv_cross::Types, unsigned int&, spv::StorageClass&&) Line | Count | Source | 1634 | 1.56k | { | 1635 | 1.56k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 1.56k | set(val, new_type); | 1637 | 1.56k | return val; | 1638 | 1.56k | } |
Unexecuted instantiation: spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned int*, int, bool, bool>(spirv_cross::Types, unsigned int const&, unsigned int*&&, int&&, bool&&, bool&&) spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned long, bool>(spirv_cross::Types, unsigned int const&, unsigned long&&, bool&&) Line | Count | Source | 1634 | 5 | { | 1635 | 5 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 5 | set(val, new_type); | 1637 | 5 | return val; | 1638 | 5 | } |
spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned int const&, bool>(spirv_cross::Types, unsigned int const&, unsigned int const&, bool&&) Line | Count | Source | 1634 | 3.52k | { | 1635 | 3.52k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 3.52k | set(val, new_type); | 1637 | 3.52k | return val; | 1638 | 3.52k | } |
spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned int, bool>(spirv_cross::Types, unsigned int const&, unsigned int&&, bool&&) Line | Count | Source | 1634 | 2.90k | { | 1635 | 2.90k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 2.90k | set(val, new_type); | 1637 | 2.90k | return val; | 1638 | 2.90k | } |
spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int&, unsigned int const*, unsigned int, bool>(spirv_cross::Types, unsigned int&, unsigned int const*&&, unsigned int&&, bool&&) Line | Count | Source | 1634 | 215 | { | 1635 | 215 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 215 | set(val, new_type); | 1637 | 215 | return val; | 1638 | 215 | } |
spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int&, spirv_cross::SPIRConstant const* (&) [4], unsigned int&, bool>(spirv_cross::Types, unsigned int&, spirv_cross::SPIRConstant const* (&) [4], unsigned int&, bool&&) Line | Count | Source | 1634 | 383 | { | 1635 | 383 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 383 | set(val, new_type); | 1637 | 383 | return val; | 1638 | 383 | } |
spirv_cross::SPIRFunction* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRFunction, unsigned int&, unsigned int&>(spirv_cross::Types, unsigned int&, unsigned int&) Line | Count | Source | 1634 | 831 | { | 1635 | 831 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 831 | set(val, new_type); | 1637 | 831 | return val; | 1638 | 831 | } |
spirv_cross::SPIRBlock* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRBlock>(spirv_cross::Types) Line | Count | Source | 1634 | 7.95k | { | 1635 | 7.95k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 7.95k | set(val, new_type); | 1637 | 7.95k | return val; | 1638 | 7.95k | } |
spirv_cross::SPIRType* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRType, spv::Op>(spirv_cross::Types, spv::Op&&) Line | Count | Source | 1634 | 69 | { | 1635 | 69 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 69 | set(val, new_type); | 1637 | 69 | return val; | 1638 | 69 | } |
spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int&>(spirv_cross::Types, unsigned int&) Line | Count | Source | 1634 | 28.9k | { | 1635 | 28.9k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 28.9k | set(val, new_type); | 1637 | 28.9k | return val; | 1638 | 28.9k | } |
spirv_cross::SPIRConstantOp* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstantOp, unsigned int&, spv::Op&, unsigned int const*, unsigned int>(spirv_cross::Types, unsigned int&, spv::Op&, unsigned int const*&&, unsigned int&&) Line | Count | Source | 1634 | 517 | { | 1635 | 517 | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 517 | set(val, new_type); | 1637 | 517 | return val; | 1638 | 517 | } |
spirv_cross::SPIRConstant* spirv_cross::Variant::allocate_and_set<spirv_cross::SPIRConstant, unsigned int&, unsigned int*, unsigned int, bool>(spirv_cross::Types, unsigned int&, unsigned int*&&, unsigned int&&, bool&&) Line | Count | Source | 1634 | 27.2k | { | 1635 | 27.2k | T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...); | 1636 | 27.2k | set(val, new_type); | 1637 | 27.2k | return val; | 1638 | 27.2k | } |
|
1639 | | |
1640 | | template <typename T> |
1641 | | T &get() |
1642 | 87.9k | { |
1643 | 87.9k | if (!holder) |
1644 | 15 | SPIRV_CROSS_THROW("nullptr"); |
1645 | 87.8k | if (static_cast<Types>(T::type) != type) |
1646 | 4 | SPIRV_CROSS_THROW("Bad cast"); |
1647 | 87.8k | return *static_cast<T *>(holder); |
1648 | 87.8k | } spirv_cross::SPIRType& spirv_cross::Variant::get<spirv_cross::SPIRType>() Line | Count | Source | 1642 | 84.8k | { | 1643 | 84.8k | if (!holder) | 1644 | 5 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 84.7k | if (static_cast<Types>(T::type) != type) | 1646 | 0 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 84.7k | return *static_cast<T *>(holder); | 1648 | 84.7k | } |
spirv_cross::SPIRExtension& spirv_cross::Variant::get<spirv_cross::SPIRExtension>() Line | Count | Source | 1642 | 1.12k | { | 1643 | 1.12k | if (!holder) | 1644 | 2 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 1.12k | if (static_cast<Types>(T::type) != type) | 1646 | 0 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 1.12k | return *static_cast<T *>(holder); | 1648 | 1.12k | } |
spirv_cross::SPIRString& spirv_cross::Variant::get<spirv_cross::SPIRString>() Line | Count | Source | 1642 | 81 | { | 1643 | 81 | if (!holder) | 1644 | 2 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 79 | if (static_cast<Types>(T::type) != type) | 1646 | 1 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 78 | return *static_cast<T *>(holder); | 1648 | 79 | } |
spirv_cross::SPIRConstant& spirv_cross::Variant::get<spirv_cross::SPIRConstant>() Line | Count | Source | 1642 | 1.85k | { | 1643 | 1.85k | if (!holder) | 1644 | 4 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 1.84k | if (static_cast<Types>(T::type) != type) | 1646 | 2 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 1.84k | return *static_cast<T *>(holder); | 1648 | 1.84k | } |
spirv_cross::SPIRDebugLocalVariable& spirv_cross::Variant::get<spirv_cross::SPIRDebugLocalVariable>() Line | Count | Source | 1642 | 16 | { | 1643 | 16 | if (!holder) | 1644 | 1 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 15 | if (static_cast<Types>(T::type) != type) | 1646 | 1 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 14 | return *static_cast<T *>(holder); | 1648 | 15 | } |
spirv_cross::SPIRVariable& spirv_cross::Variant::get<spirv_cross::SPIRVariable>() Line | Count | Source | 1642 | 14 | { | 1643 | 14 | if (!holder) | 1644 | 1 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 13 | if (static_cast<Types>(T::type) != type) | 1646 | 0 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 13 | return *static_cast<T *>(holder); | 1648 | 13 | } |
Unexecuted instantiation: spirv_cross::SPIRConstantOp& spirv_cross::Variant::get<spirv_cross::SPIRConstantOp>() spirv_cross::SPIRUndef& spirv_cross::Variant::get<spirv_cross::SPIRUndef>() Line | Count | Source | 1642 | 16 | { | 1643 | 16 | if (!holder) | 1644 | 0 | SPIRV_CROSS_THROW("nullptr"); | 1645 | 16 | if (static_cast<Types>(T::type) != type) | 1646 | 0 | SPIRV_CROSS_THROW("Bad cast"); | 1647 | 16 | return *static_cast<T *>(holder); | 1648 | 16 | } |
|
1649 | | |
1650 | | template <typename T> |
1651 | | const T &get() const |
1652 | 2.49k | { |
1653 | 2.49k | if (!holder) |
1654 | 4 | SPIRV_CROSS_THROW("nullptr"); |
1655 | 2.48k | if (static_cast<Types>(T::type) != type) |
1656 | 0 | SPIRV_CROSS_THROW("Bad cast"); |
1657 | 2.48k | return *static_cast<const T *>(holder); |
1658 | 2.48k | } |
1659 | | |
1660 | | Types get_type() const |
1661 | 125k | { |
1662 | 125k | return type; |
1663 | 125k | } |
1664 | | |
1665 | | ID get_id() const |
1666 | 0 | { |
1667 | 0 | return holder ? holder->self : ID(0); |
1668 | 0 | } |
1669 | | |
1670 | | bool empty() const |
1671 | 186k | { |
1672 | 186k | return !holder; |
1673 | 186k | } |
1674 | | |
1675 | | void reset() |
1676 | 0 | { |
1677 | 0 | if (holder) |
1678 | 0 | group->pools[type]->deallocate_opaque(holder); |
1679 | 0 | holder = nullptr; |
1680 | 0 | type = TypeNone; |
1681 | 0 | } |
1682 | | |
1683 | | void set_allow_type_rewrite() |
1684 | 0 | { |
1685 | 0 | allow_type_rewrite = true; |
1686 | 0 | } |
1687 | | |
1688 | | private: |
1689 | | ObjectPoolGroup *group = nullptr; |
1690 | | IVariant *holder = nullptr; |
1691 | | Types type = TypeNone; |
1692 | | bool allow_type_rewrite = false; |
1693 | | }; |
1694 | | |
1695 | | template <typename T> |
1696 | | T &variant_get(Variant &var) |
1697 | 87.9k | { |
1698 | 87.9k | return var.get<T>(); |
1699 | 87.9k | } spirv_cross::SPIRType& spirv_cross::variant_get<spirv_cross::SPIRType>(spirv_cross::Variant&) Line | Count | Source | 1697 | 84.8k | { | 1698 | 84.8k | return var.get<T>(); | 1699 | 84.8k | } |
spirv_cross::SPIRExtension& spirv_cross::variant_get<spirv_cross::SPIRExtension>(spirv_cross::Variant&) Line | Count | Source | 1697 | 1.12k | { | 1698 | 1.12k | return var.get<T>(); | 1699 | 1.12k | } |
spirv_cross::SPIRString& spirv_cross::variant_get<spirv_cross::SPIRString>(spirv_cross::Variant&) Line | Count | Source | 1697 | 81 | { | 1698 | 81 | return var.get<T>(); | 1699 | 81 | } |
spirv_cross::SPIRConstant& spirv_cross::variant_get<spirv_cross::SPIRConstant>(spirv_cross::Variant&) Line | Count | Source | 1697 | 1.85k | { | 1698 | 1.85k | return var.get<T>(); | 1699 | 1.85k | } |
spirv_cross::SPIRDebugLocalVariable& spirv_cross::variant_get<spirv_cross::SPIRDebugLocalVariable>(spirv_cross::Variant&) Line | Count | Source | 1697 | 16 | { | 1698 | 16 | return var.get<T>(); | 1699 | 16 | } |
spirv_cross::SPIRVariable& spirv_cross::variant_get<spirv_cross::SPIRVariable>(spirv_cross::Variant&) Line | Count | Source | 1697 | 14 | { | 1698 | 14 | return var.get<T>(); | 1699 | 14 | } |
Unexecuted instantiation: spirv_cross::SPIRConstantOp& spirv_cross::variant_get<spirv_cross::SPIRConstantOp>(spirv_cross::Variant&) spirv_cross::SPIRUndef& spirv_cross::variant_get<spirv_cross::SPIRUndef>(spirv_cross::Variant&) Line | Count | Source | 1697 | 16 | { | 1698 | 16 | return var.get<T>(); | 1699 | 16 | } |
|
1700 | | |
1701 | | template <typename T> |
1702 | | const T &variant_get(const Variant &var) |
1703 | 2.49k | { |
1704 | 2.49k | return var.get<T>(); |
1705 | 2.49k | } |
1706 | | |
1707 | | template <typename T, typename... P> |
1708 | | T &variant_set(Variant &var, P &&... args) |
1709 | 93.4k | { |
1710 | 93.4k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); |
1711 | 93.4k | return *ptr; |
1712 | 93.4k | } spirv_cross::SPIRString& spirv_cross::variant_set<spirv_cross::SPIRString, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(spirv_cross::Variant&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Line | Count | Source | 1709 | 627 | { | 1710 | 627 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 627 | return *ptr; | 1712 | 627 | } |
spirv_cross::SPIRUndef& spirv_cross::variant_set<spirv_cross::SPIRUndef, unsigned int&>(spirv_cross::Variant&, unsigned int&) Line | Count | Source | 1709 | 70 | { | 1710 | 70 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 70 | return *ptr; | 1712 | 70 | } |
spirv_cross::SPIRExtension& spirv_cross::variant_set<spirv_cross::SPIRExtension, spirv_cross::SPIRExtension::Extension&>(spirv_cross::Variant&, spirv_cross::SPIRExtension::Extension&) Line | Count | Source | 1709 | 500 | { | 1710 | 500 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 500 | return *ptr; | 1712 | 500 | } |
spirv_cross::SPIRString& spirv_cross::variant_set<spirv_cross::SPIRString, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(spirv_cross::Variant&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 1709 | 40 | { | 1710 | 40 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 40 | return *ptr; | 1712 | 40 | } |
spirv_cross::SPIRDebugLocalVariable& spirv_cross::variant_set<spirv_cross::SPIRDebugLocalVariable>(spirv_cross::Variant&) Line | Count | Source | 1709 | 42 | { | 1710 | 42 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 42 | return *ptr; | 1712 | 42 | } |
spirv_cross::SPIRType& spirv_cross::variant_set<spirv_cross::SPIRType, spv::Op&>(spirv_cross::Variant&, spv::Op&) Line | Count | Source | 1709 | 9.88k | { | 1710 | 9.88k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 9.88k | return *ptr; | 1712 | 9.88k | } |
spirv_cross::SPIRType& spirv_cross::variant_set<spirv_cross::SPIRType, spirv_cross::SPIRType&>(spirv_cross::Variant&, spirv_cross::SPIRType&) Line | Count | Source | 1709 | 4.54k | { | 1710 | 4.54k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 4.54k | return *ptr; | 1712 | 4.54k | } |
spirv_cross::SPIRFunctionPrototype& spirv_cross::variant_set<spirv_cross::SPIRFunctionPrototype, unsigned int&>(spirv_cross::Variant&, unsigned int&) Line | Count | Source | 1709 | 1.21k | { | 1710 | 1.21k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 1.21k | return *ptr; | 1712 | 1.21k | } |
spirv_cross::SPIRVariable& spirv_cross::variant_set<spirv_cross::SPIRVariable, unsigned int&, spv::StorageClass&, unsigned int&>(spirv_cross::Variant&, unsigned int&, spv::StorageClass&, unsigned int&) Line | Count | Source | 1709 | 2.40k | { | 1710 | 2.40k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 2.40k | return *ptr; | 1712 | 2.40k | } |
spirv_cross::SPIRVariable& spirv_cross::variant_set<spirv_cross::SPIRVariable, unsigned int&, spv::StorageClass>(spirv_cross::Variant&, unsigned int&, spv::StorageClass&&) Line | Count | Source | 1709 | 1.56k | { | 1710 | 1.56k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 1.56k | return *ptr; | 1712 | 1.56k | } |
Unexecuted instantiation: spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned int*, int, bool, bool>(spirv_cross::Variant&, unsigned int const&, unsigned int*&&, int&&, bool&&, bool&&) spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned long, bool>(spirv_cross::Variant&, unsigned int const&, unsigned long&&, bool&&) Line | Count | Source | 1709 | 5 | { | 1710 | 5 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 5 | return *ptr; | 1712 | 5 | } |
spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned int const&, bool>(spirv_cross::Variant&, unsigned int const&, unsigned int const&, bool&&) Line | Count | Source | 1709 | 3.52k | { | 1710 | 3.52k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 3.52k | return *ptr; | 1712 | 3.52k | } |
spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int const&, unsigned int, bool>(spirv_cross::Variant&, unsigned int const&, unsigned int&&, bool&&) Line | Count | Source | 1709 | 2.90k | { | 1710 | 2.90k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 2.90k | return *ptr; | 1712 | 2.90k | } |
spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int&, unsigned int const*, unsigned int, bool>(spirv_cross::Variant&, unsigned int&, unsigned int const*&&, unsigned int&&, bool&&) Line | Count | Source | 1709 | 215 | { | 1710 | 215 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 215 | return *ptr; | 1712 | 215 | } |
spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int&, spirv_cross::SPIRConstant const* (&) [4], unsigned int&, bool>(spirv_cross::Variant&, unsigned int&, spirv_cross::SPIRConstant const* (&) [4], unsigned int&, bool&&) Line | Count | Source | 1709 | 383 | { | 1710 | 383 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 383 | return *ptr; | 1712 | 383 | } |
spirv_cross::SPIRFunction& spirv_cross::variant_set<spirv_cross::SPIRFunction, unsigned int&, unsigned int&>(spirv_cross::Variant&, unsigned int&, unsigned int&) Line | Count | Source | 1709 | 831 | { | 1710 | 831 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 831 | return *ptr; | 1712 | 831 | } |
spirv_cross::SPIRBlock& spirv_cross::variant_set<spirv_cross::SPIRBlock>(spirv_cross::Variant&) Line | Count | Source | 1709 | 7.95k | { | 1710 | 7.95k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 7.95k | return *ptr; | 1712 | 7.95k | } |
spirv_cross::SPIRType& spirv_cross::variant_set<spirv_cross::SPIRType, spv::Op>(spirv_cross::Variant&, spv::Op&&) Line | Count | Source | 1709 | 69 | { | 1710 | 69 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 69 | return *ptr; | 1712 | 69 | } |
spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int&>(spirv_cross::Variant&, unsigned int&) Line | Count | Source | 1709 | 28.9k | { | 1710 | 28.9k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 28.9k | return *ptr; | 1712 | 28.9k | } |
spirv_cross::SPIRConstantOp& spirv_cross::variant_set<spirv_cross::SPIRConstantOp, unsigned int&, spv::Op&, unsigned int const*, unsigned int>(spirv_cross::Variant&, unsigned int&, spv::Op&, unsigned int const*&&, unsigned int&&) Line | Count | Source | 1709 | 517 | { | 1710 | 517 | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 517 | return *ptr; | 1712 | 517 | } |
spirv_cross::SPIRConstant& spirv_cross::variant_set<spirv_cross::SPIRConstant, unsigned int&, unsigned int*, unsigned int, bool>(spirv_cross::Variant&, unsigned int&, unsigned int*&&, unsigned int&&, bool&&) Line | Count | Source | 1709 | 27.2k | { | 1710 | 27.2k | auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...); | 1711 | 27.2k | return *ptr; | 1712 | 27.2k | } |
|
1713 | | |
1714 | | struct AccessChainMeta |
1715 | | { |
1716 | | uint32_t storage_physical_type = 0; |
1717 | | bool need_transpose = false; |
1718 | | bool storage_is_packed = false; |
1719 | | bool storage_is_invariant = false; |
1720 | | bool flattened_struct = false; |
1721 | | bool relaxed_precision = false; |
1722 | | bool access_meshlet_position_y = false; |
1723 | | bool chain_is_builtin = false; |
1724 | | spv::BuiltIn builtin = {}; |
1725 | | }; |
1726 | | |
1727 | | enum ExtendedDecorations |
1728 | | { |
1729 | | // Marks if a buffer block is re-packed, i.e. member declaration might be subject to PhysicalTypeID remapping and padding. |
1730 | | SPIRVCrossDecorationBufferBlockRepacked = 0, |
1731 | | |
1732 | | // A type in a buffer block might be declared with a different physical type than the logical type. |
1733 | | // If this is not set, PhysicalTypeID == the SPIR-V type as declared. |
1734 | | SPIRVCrossDecorationPhysicalTypeID, |
1735 | | |
1736 | | // Marks if the physical type is to be declared with tight packing rules, i.e. packed_floatN on MSL and friends. |
1737 | | // If this is set, PhysicalTypeID might also be set. It can be set to same as logical type if all we're doing |
1738 | | // is converting float3 to packed_float3 for example. |
1739 | | // If this is marked on a struct, it means the struct itself must use only Packed types for all its members. |
1740 | | SPIRVCrossDecorationPhysicalTypePacked, |
1741 | | |
1742 | | // The padding in bytes before declaring this struct member. |
1743 | | // If used on a struct type, marks the target size of a struct. |
1744 | | SPIRVCrossDecorationPaddingTarget, |
1745 | | |
1746 | | SPIRVCrossDecorationInterfaceMemberIndex, |
1747 | | SPIRVCrossDecorationInterfaceOrigID, |
1748 | | SPIRVCrossDecorationResourceIndexPrimary, |
1749 | | // Used for decorations like resource indices for samplers when part of combined image samplers. |
1750 | | // A variable might need to hold two resource indices in this case. |
1751 | | SPIRVCrossDecorationResourceIndexSecondary, |
1752 | | // Used for resource indices for multiplanar images when part of combined image samplers. |
1753 | | SPIRVCrossDecorationResourceIndexTertiary, |
1754 | | SPIRVCrossDecorationResourceIndexQuaternary, |
1755 | | |
1756 | | // Marks a buffer block for using explicit offsets (GLSL/HLSL). |
1757 | | SPIRVCrossDecorationExplicitOffset, |
1758 | | |
1759 | | // Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase(), |
1760 | | // or the base vertex and instance indices passed to vkCmdDrawIndexed(). |
1761 | | // In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables in compute shaders, |
1762 | | // and to hold the BaseVertex and BaseInstance variables in vertex shaders. |
1763 | | SPIRVCrossDecorationBuiltInDispatchBase, |
1764 | | |
1765 | | // Apply to a variable that is a function parameter; marks it as being a "dynamic" |
1766 | | // combined image-sampler. In MSL, this is used when a function parameter might hold |
1767 | | // either a regular combined image-sampler or one that has an attached sampler |
1768 | | // Y'CbCr conversion. |
1769 | | SPIRVCrossDecorationDynamicImageSampler, |
1770 | | |
1771 | | // Apply to a variable in the Input storage class; marks it as holding the size of the stage |
1772 | | // input grid. |
1773 | | // In MSL, this is used to hold the vertex and instance counts in a tessellation pipeline |
1774 | | // vertex shader. |
1775 | | SPIRVCrossDecorationBuiltInStageInputSize, |
1776 | | |
1777 | | // Apply to any access chain of a tessellation I/O variable; stores the type of the sub-object |
1778 | | // that was chained to, as recorded in the input variable itself. This is used in case the pointer |
1779 | | // is itself used as the base of an access chain, to calculate the original type of the sub-object |
1780 | | // chained to, in case a swizzle needs to be applied. This should not happen normally with valid |
1781 | | // SPIR-V, but the MSL backend can change the type of input variables, necessitating the |
1782 | | // addition of swizzles to keep the generated code compiling. |
1783 | | SPIRVCrossDecorationTessIOOriginalInputTypeID, |
1784 | | |
1785 | | // Apply to any access chain of an interface variable used with pull-model interpolation, where the variable is a |
1786 | | // vector but the resulting pointer is a scalar; stores the component index that is to be accessed by the chain. |
1787 | | // This is used when emitting calls to interpolation functions on the chain in MSL: in this case, the component |
1788 | | // must be applied to the result, since pull-model interpolants in MSL cannot be swizzled directly, but the |
1789 | | // results of interpolation can. |
1790 | | SPIRVCrossDecorationInterpolantComponentExpr, |
1791 | | |
1792 | | // Apply to any struct type that is used in the Workgroup storage class. |
1793 | | // This causes matrices in MSL prior to Metal 3.0 to be emitted using a special |
1794 | | // class that is convertible to the standard matrix type, to work around the |
1795 | | // lack of constructors in the 'threadgroup' address space. |
1796 | | SPIRVCrossDecorationWorkgroupStruct, |
1797 | | |
1798 | | SPIRVCrossDecorationOverlappingBinding, |
1799 | | |
1800 | | SPIRVCrossDecorationCount |
1801 | | }; |
1802 | | |
1803 | | struct Meta |
1804 | | { |
1805 | | struct Decoration |
1806 | | { |
1807 | | std::string alias; |
1808 | | std::string qualified_alias; |
1809 | | std::string user_semantic; |
1810 | | std::string user_type; |
1811 | | Bitset decoration_flags; |
1812 | | spv::BuiltIn builtin_type = spv::BuiltInMax; |
1813 | | uint32_t location = 0; |
1814 | | uint32_t component = 0; |
1815 | | uint32_t set = 0; |
1816 | | uint32_t binding = 0; |
1817 | | uint32_t offset = 0; |
1818 | | uint32_t xfb_buffer = 0; |
1819 | | uint32_t xfb_stride = 0; |
1820 | | uint32_t stream = 0; |
1821 | | uint32_t array_stride = 0; |
1822 | | uint32_t matrix_stride = 0; |
1823 | | uint32_t input_attachment = 0; |
1824 | | uint32_t spec_id = 0; |
1825 | | uint32_t index = 0; |
1826 | | spv::FPRoundingMode fp_rounding_mode = spv::FPRoundingModeMax; |
1827 | | spv::FPFastMathModeMask fp_fast_math_mode = spv::FPFastMathModeMaskNone; |
1828 | | bool builtin = false; |
1829 | | bool qualified_alias_explicit_override = false; |
1830 | | |
1831 | | struct Extended |
1832 | | { |
1833 | | Extended() |
1834 | 29.7M | { |
1835 | | // MSVC 2013 workaround to init like this. |
1836 | 29.7M | for (auto &v : values) |
1837 | 536M | v = 0; |
1838 | 29.7M | } |
1839 | | |
1840 | | Bitset flags; |
1841 | | uint32_t values[SPIRVCrossDecorationCount]; |
1842 | | } extended; |
1843 | | }; |
1844 | | |
1845 | | Decoration decoration; |
1846 | | |
1847 | | // Intentionally not a SmallVector. Decoration is large and somewhat rare. |
1848 | | Vector<Decoration> members; |
1849 | | |
1850 | | std::unordered_map<uint32_t, uint32_t> decoration_word_offset; |
1851 | | |
1852 | | // For SPV_GOOGLE_hlsl_functionality1. |
1853 | | bool hlsl_is_magic_counter_buffer = false; |
1854 | | // ID for the sibling counter buffer. |
1855 | | uint32_t hlsl_magic_counter_buffer = 0; |
1856 | | }; |
1857 | | |
1858 | | // A user callback that remaps the type of any variable. |
1859 | | // var_name is the declared name of the variable. |
1860 | | // name_of_type is the textual name of the type which will be used in the code unless written to by the callback. |
1861 | | using VariableTypeRemapCallback = |
1862 | | std::function<void(const SPIRType &type, const std::string &var_name, std::string &name_of_type)>; |
1863 | | |
1864 | | class Hasher |
1865 | | { |
1866 | | public: |
1867 | | inline void u32(uint32_t value) |
1868 | 0 | { |
1869 | 0 | h = (h * 0x100000001b3ull) ^ value; |
1870 | 0 | } |
1871 | | |
1872 | | inline uint64_t get() const |
1873 | 0 | { |
1874 | 0 | return h; |
1875 | 0 | } |
1876 | | |
1877 | | private: |
1878 | | uint64_t h = 0xcbf29ce484222325ull; |
1879 | | }; |
1880 | | |
1881 | | static inline bool type_is_floating_point(const SPIRType &type) |
1882 | 0 | { |
1883 | 0 | return type.basetype == SPIRType::Half || type.basetype == SPIRType::Float || type.basetype == SPIRType::Double || |
1884 | 0 | type.basetype == SPIRType::BFloat16 || type.basetype == SPIRType::FloatE5M2 || type.basetype == SPIRType::FloatE4M3; |
1885 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::type_is_floating_point(spirv_cross::SPIRType const&) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::type_is_floating_point(spirv_cross::SPIRType const&) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::type_is_floating_point(spirv_cross::SPIRType const&) |
1886 | | |
1887 | | static inline bool type_is_integral(const SPIRType &type) |
1888 | 0 | { |
1889 | 0 | return type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte || type.basetype == SPIRType::Short || |
1890 | 0 | type.basetype == SPIRType::UShort || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt || |
1891 | 0 | type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64; |
1892 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::type_is_integral(spirv_cross::SPIRType const&) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::type_is_integral(spirv_cross::SPIRType const&) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::type_is_integral(spirv_cross::SPIRType const&) |
1893 | | |
1894 | | static inline SPIRType::BaseType to_signed_basetype(uint32_t width) |
1895 | 229 | { |
1896 | 229 | switch (width) |
1897 | 229 | { |
1898 | 1 | case 8: |
1899 | 1 | return SPIRType::SByte; |
1900 | 1 | case 16: |
1901 | 1 | return SPIRType::Short; |
1902 | 222 | case 32: |
1903 | 222 | return SPIRType::Int; |
1904 | 5 | case 64: |
1905 | 5 | return SPIRType::Int64; |
1906 | 0 | default: |
1907 | 0 | SPIRV_CROSS_THROW("Invalid bit width."); |
1908 | 229 | } |
1909 | 229 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::to_signed_basetype(unsigned int) spirv_parser.cpp:spirv_cross::to_signed_basetype(unsigned int) Line | Count | Source | 1895 | 229 | { | 1896 | 229 | switch (width) | 1897 | 229 | { | 1898 | 1 | case 8: | 1899 | 1 | return SPIRType::SByte; | 1900 | 1 | case 16: | 1901 | 1 | return SPIRType::Short; | 1902 | 222 | case 32: | 1903 | 222 | return SPIRType::Int; | 1904 | 5 | case 64: | 1905 | 5 | return SPIRType::Int64; | 1906 | 0 | default: | 1907 | 0 | SPIRV_CROSS_THROW("Invalid bit width."); | 1908 | 229 | } | 1909 | 229 | } |
Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::to_signed_basetype(unsigned int) |
1910 | | |
1911 | | static inline SPIRType::BaseType to_unsigned_basetype(uint32_t width) |
1912 | 321 | { |
1913 | 321 | switch (width) |
1914 | 321 | { |
1915 | 0 | case 8: |
1916 | 0 | return SPIRType::UByte; |
1917 | 0 | case 16: |
1918 | 0 | return SPIRType::UShort; |
1919 | 320 | case 32: |
1920 | 320 | return SPIRType::UInt; |
1921 | 0 | case 64: |
1922 | 0 | return SPIRType::UInt64; |
1923 | 1 | default: |
1924 | 1 | SPIRV_CROSS_THROW("Invalid bit width."); |
1925 | 321 | } |
1926 | 321 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::to_unsigned_basetype(unsigned int) spirv_parser.cpp:spirv_cross::to_unsigned_basetype(unsigned int) Line | Count | Source | 1912 | 321 | { | 1913 | 321 | switch (width) | 1914 | 321 | { | 1915 | 0 | case 8: | 1916 | 0 | return SPIRType::UByte; | 1917 | 0 | case 16: | 1918 | 0 | return SPIRType::UShort; | 1919 | 320 | case 32: | 1920 | 320 | return SPIRType::UInt; | 1921 | 0 | case 64: | 1922 | 0 | return SPIRType::UInt64; | 1923 | 1 | default: | 1924 | 1 | SPIRV_CROSS_THROW("Invalid bit width."); | 1925 | 321 | } | 1926 | 321 | } |
Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::to_unsigned_basetype(unsigned int) |
1927 | | |
1928 | | // Returns true if an arithmetic operation does not change behavior depending on signedness. |
1929 | | static inline bool opcode_is_sign_invariant(spv::Op opcode) |
1930 | 0 | { |
1931 | 0 | switch (opcode) |
1932 | 0 | { |
1933 | 0 | case spv::OpIEqual: |
1934 | 0 | case spv::OpINotEqual: |
1935 | 0 | case spv::OpISub: |
1936 | 0 | case spv::OpIAdd: |
1937 | 0 | case spv::OpIMul: |
1938 | 0 | case spv::OpShiftLeftLogical: |
1939 | 0 | case spv::OpBitwiseOr: |
1940 | 0 | case spv::OpBitwiseXor: |
1941 | 0 | case spv::OpBitwiseAnd: |
1942 | 0 | return true; |
1943 | 0 |
|
1944 | 0 | default: |
1945 | 0 | return false; |
1946 | 0 | } |
1947 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::opcode_is_sign_invariant(spv::Op) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::opcode_is_sign_invariant(spv::Op) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::opcode_is_sign_invariant(spv::Op) |
1948 | | |
1949 | | static inline bool opcode_can_promote_integer_implicitly(spv::Op opcode) |
1950 | 0 | { |
1951 | 0 | switch (opcode) |
1952 | 0 | { |
1953 | 0 | case spv::OpSNegate: |
1954 | 0 | case spv::OpNot: |
1955 | 0 | case spv::OpBitwiseAnd: |
1956 | 0 | case spv::OpBitwiseOr: |
1957 | 0 | case spv::OpBitwiseXor: |
1958 | 0 | case spv::OpShiftLeftLogical: |
1959 | 0 | case spv::OpShiftRightLogical: |
1960 | 0 | case spv::OpShiftRightArithmetic: |
1961 | 0 | case spv::OpIAdd: |
1962 | 0 | case spv::OpISub: |
1963 | 0 | case spv::OpIMul: |
1964 | 0 | case spv::OpSDiv: |
1965 | 0 | case spv::OpUDiv: |
1966 | 0 | case spv::OpSRem: |
1967 | 0 | case spv::OpUMod: |
1968 | 0 | case spv::OpSMod: |
1969 | 0 | return true; |
1970 | 0 |
|
1971 | 0 | default: |
1972 | 0 | return false; |
1973 | 0 | } |
1974 | 0 | } Unexecuted instantiation: parser_fuzzer.cpp:spirv_cross::opcode_can_promote_integer_implicitly(spv::Op) Unexecuted instantiation: spirv_parser.cpp:spirv_cross::opcode_can_promote_integer_implicitly(spv::Op) Unexecuted instantiation: spirv_cross_parsed_ir.cpp:spirv_cross::opcode_can_promote_integer_implicitly(spv::Op) |
1975 | | |
1976 | | struct SetBindingPair |
1977 | | { |
1978 | | uint32_t desc_set; |
1979 | | uint32_t binding; |
1980 | | |
1981 | | inline bool operator==(const SetBindingPair &other) const |
1982 | 0 | { |
1983 | 0 | return desc_set == other.desc_set && binding == other.binding; |
1984 | 0 | } |
1985 | | |
1986 | | inline bool operator<(const SetBindingPair &other) const |
1987 | 0 | { |
1988 | 0 | return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding); |
1989 | 0 | } |
1990 | | }; |
1991 | | |
1992 | | struct LocationComponentPair |
1993 | | { |
1994 | | uint32_t location; |
1995 | | uint32_t component; |
1996 | | |
1997 | | inline bool operator==(const LocationComponentPair &other) const |
1998 | 0 | { |
1999 | 0 | return location == other.location && component == other.component; |
2000 | 0 | } |
2001 | | |
2002 | | inline bool operator<(const LocationComponentPair &other) const |
2003 | 0 | { |
2004 | 0 | return location < other.location || (location == other.location && component < other.component); |
2005 | 0 | } |
2006 | | }; |
2007 | | |
2008 | | struct StageSetBinding |
2009 | | { |
2010 | | spv::ExecutionModel model; |
2011 | | uint32_t desc_set; |
2012 | | uint32_t binding; |
2013 | | |
2014 | | inline bool operator==(const StageSetBinding &other) const |
2015 | 0 | { |
2016 | 0 | return model == other.model && desc_set == other.desc_set && binding == other.binding; |
2017 | 0 | } |
2018 | | }; |
2019 | | |
2020 | | struct InternalHasher |
2021 | | { |
2022 | | inline size_t operator()(const SetBindingPair &value) const |
2023 | 0 | { |
2024 | 0 | // Quality of hash doesn't really matter here. |
2025 | 0 | auto hash_set = std::hash<uint32_t>()(value.desc_set); |
2026 | 0 | auto hash_binding = std::hash<uint32_t>()(value.binding); |
2027 | 0 | return (hash_set * 0x10001b31) ^ hash_binding; |
2028 | 0 | } |
2029 | | |
2030 | | inline size_t operator()(const LocationComponentPair &value) const |
2031 | 0 | { |
2032 | 0 | // Quality of hash doesn't really matter here. |
2033 | 0 | auto hash_set = std::hash<uint32_t>()(value.location); |
2034 | 0 | auto hash_binding = std::hash<uint32_t>()(value.component); |
2035 | 0 | return (hash_set * 0x10001b31) ^ hash_binding; |
2036 | 0 | } |
2037 | | |
2038 | | inline size_t operator()(const StageSetBinding &value) const |
2039 | 0 | { |
2040 | 0 | // Quality of hash doesn't really matter here. |
2041 | 0 | auto hash_model = std::hash<uint32_t>()(value.model); |
2042 | 0 | auto hash_set = std::hash<uint32_t>()(value.desc_set); |
2043 | 0 | auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set; |
2044 | 0 | return (tmp_hash * 0x10001b31) ^ value.binding; |
2045 | 0 | } |
2046 | | }; |
2047 | | |
2048 | | // Special constant used in a {MSL,HLSL}ResourceBinding desc_set |
2049 | | // element to indicate the bindings for the push constants. |
2050 | | static const uint32_t ResourceBindingPushConstantDescriptorSet = ~(0u); |
2051 | | |
2052 | | // Special constant used in a {MSL,HLSL}ResourceBinding binding |
2053 | | // element to indicate the bindings for the push constants. |
2054 | | static const uint32_t ResourceBindingPushConstantBinding = 0; |
2055 | | } // namespace SPIRV_CROSS_NAMESPACE |
2056 | | |
2057 | | namespace std |
2058 | | { |
2059 | | template <SPIRV_CROSS_NAMESPACE::Types type> |
2060 | | struct hash<SPIRV_CROSS_NAMESPACE::TypedID<type>> |
2061 | | { |
2062 | | size_t operator()(const SPIRV_CROSS_NAMESPACE::TypedID<type> &value) const |
2063 | 405k | { |
2064 | 405k | return std::hash<uint32_t>()(value); |
2065 | 405k | } std::__1::hash<spirv_cross::TypedID<(spirv_cross::Types)0> >::operator()(spirv_cross::TypedID<(spirv_cross::Types)0> const&) const Line | Count | Source | 2063 | 396k | { | 2064 | 396k | return std::hash<uint32_t>()(value); | 2065 | 396k | } |
std::__1::hash<spirv_cross::TypedID<(spirv_cross::Types)4> >::operator()(spirv_cross::TypedID<(spirv_cross::Types)4> const&) const Line | Count | Source | 2063 | 7.76k | { | 2064 | 7.76k | return std::hash<uint32_t>()(value); | 2065 | 7.76k | } |
std::__1::hash<spirv_cross::TypedID<(spirv_cross::Types)6> >::operator()(spirv_cross::TypedID<(spirv_cross::Types)6> const&) const Line | Count | Source | 2063 | 1.32k | { | 2064 | 1.32k | return std::hash<uint32_t>()(value); | 2065 | 1.32k | } |
|
2066 | | }; |
2067 | | } // namespace std |
2068 | | |
2069 | | #ifdef SPIRV_CROSS_SPV_HEADER_NAMESPACE_OVERRIDE |
2070 | | #undef spv |
2071 | | #endif |
2072 | | #endif |