blob: e656a9a078f7cdcd32bc7f06e917e718b5c6a52a [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2015-2021 Arm Limited
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01004 *
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
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010018/*
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>.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010022 */
23
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +010024#ifndef SPIRV_CROSS_COMMON_HPP
25#define SPIRV_CROSS_COMMON_HPP
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010026
Hans-Kristian Arntzenbf5c0752017-03-25 16:28:44 +010027#include "spirv.hpp"
Hans-Kristian Arntzen03ddea82019-04-09 13:07:30 +020028#include "spirv_cross_containers.hpp"
Hans-Kristian Arntzen3fa00f92019-04-09 15:10:02 +020029#include "spirv_cross_error_handling.hpp"
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020030#include <functional>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010031
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010032// A bit crude, but allows projects which embed SPIRV-Cross statically to
33// effectively hide all the symbols from other projects.
34// There is a case where we have:
35// - Project A links against SPIRV-Cross statically.
36// - Project A links against Project B statically.
37// - Project B links against SPIRV-Cross statically (might be a different version).
38// This leads to a conflict with extremely bizarre results.
39// By overriding the namespace in one of the project builds, we can work around this.
40// If SPIRV-Cross is embedded in dynamic libraries,
41// prefer using -fvisibility=hidden on GCC/Clang instead.
42#ifdef SPIRV_CROSS_NAMESPACE_OVERRIDE
43#define SPIRV_CROSS_NAMESPACE SPIRV_CROSS_NAMESPACE_OVERRIDE
44#else
45#define SPIRV_CROSS_NAMESPACE spirv_cross
46#endif
47
48namespace SPIRV_CROSS_NAMESPACE
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010049{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020050namespace inner
51{
52template <typename T>
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020053void join_helper(StringStream<> &stream, T &&t)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020054{
55 stream << std::forward<T>(t);
56}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010057
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020058template <typename T, typename... Ts>
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020059void join_helper(StringStream<> &stream, T &&t, Ts &&... ts)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020060{
61 stream << std::forward<T>(t);
62 join_helper(stream, std::forward<Ts>(ts)...);
63}
Hans-Kristian Arntzen382101b2018-04-03 14:08:15 +020064} // namespace inner
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010065
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010066class Bitset
67{
68public:
69 Bitset() = default;
70 explicit inline Bitset(uint64_t lower_)
Hans-Kristian Arntzen719cf9d2018-03-13 14:05:33 +010071 : lower(lower_)
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +010072 {
73 }
74
75 inline bool get(uint32_t bit) const
76 {
77 if (bit < 64)
78 return (lower & (1ull << bit)) != 0;
79 else
80 return higher.count(bit) != 0;
81 }
82
83 inline void set(uint32_t bit)
84 {
85 if (bit < 64)
86 lower |= 1ull << bit;
87 else
88 higher.insert(bit);
89 }
90
91 inline void clear(uint32_t bit)
92 {
93 if (bit < 64)
94 lower &= ~(1ull << bit);
95 else
96 higher.erase(bit);
97 }
98
99 inline uint64_t get_lower() const
100 {
101 return lower;
102 }
103
104 inline void reset()
105 {
106 lower = 0;
107 higher.clear();
108 }
109
110 inline void merge_and(const Bitset &other)
111 {
112 lower &= other.lower;
113 std::unordered_set<uint32_t> tmp_set;
114 for (auto &v : higher)
115 if (other.higher.count(v) != 0)
116 tmp_set.insert(v);
117 higher = std::move(tmp_set);
118 }
119
120 inline void merge_or(const Bitset &other)
121 {
122 lower |= other.lower;
123 for (auto &v : other.higher)
124 higher.insert(v);
125 }
126
127 inline bool operator==(const Bitset &other) const
128 {
129 if (lower != other.lower)
130 return false;
131
132 if (higher.size() != other.higher.size())
133 return false;
134
135 for (auto &v : higher)
136 if (other.higher.count(v) == 0)
137 return false;
138
139 return true;
140 }
141
142 inline bool operator!=(const Bitset &other) const
143 {
144 return !(*this == other);
145 }
146
147 template <typename Op>
148 void for_each_bit(const Op &op) const
149 {
150 // TODO: Add ctz-based iteration.
151 for (uint32_t i = 0; i < 64; i++)
152 {
153 if (lower & (1ull << i))
154 op(i);
155 }
156
157 if (higher.empty())
158 return;
159
160 // Need to enforce an order here for reproducible results,
161 // but hitting this path should happen extremely rarely, so having this slow path is fine.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200162 SmallVector<uint32_t> bits;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100163 bits.reserve(higher.size());
164 for (auto &v : higher)
165 bits.push_back(v);
166 std::sort(std::begin(bits), std::end(bits));
167
168 for (auto &v : bits)
169 op(v);
170 }
171
172 inline bool empty() const
173 {
174 return lower == 0 && higher.empty();
175 }
176
177private:
178 // The most common bits to set are all lower than 64,
179 // so optimize for this case. Bits spilling outside 64 go into a slower data structure.
180 // In almost all cases, higher data structure will not be used.
181 uint64_t lower = 0;
182 std::unordered_set<uint32_t> higher;
183};
184
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200185// Helper template to avoid lots of nasty string temporary munging.
186template <typename... Ts>
187std::string join(Ts &&... ts)
188{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200189 StringStream<> stream;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200190 inner::join_helper(stream, std::forward<Ts>(ts)...);
191 return stream.str();
192}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100193
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +0200194inline std::string merge(const SmallVector<std::string> &list, const char *between = ", ")
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200195{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200196 StringStream<> stream;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200197 for (auto &elem : list)
198 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200199 stream << elem;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200200 if (&elem != &list.back())
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +0200201 stream << between;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200202 }
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200203 return stream.str();
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200204}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100205
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100206// Make sure we don't accidentally call this with float or doubles with SFINAE.
207// Have to use the radix-aware overload.
208template <typename T, typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0>
209inline std::string convert_to_string(const T &t)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200210{
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100211 return std::to_string(t);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200212}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100213
Hans-Kristian Arntzenf72bb3c2021-09-30 16:17:04 +0200214static inline std::string convert_to_string(int32_t value)
215{
216 // INT_MIN is ... special on some backends. If we use a decimal literal, and negate it, we
217 // could accidentally promote the literal to long first, then negate.
218 // To workaround it, emit int(0x80000000) instead.
219 if (value == std::numeric_limits<int32_t>::min())
220 return "int(0x80000000)";
221 else
222 return std::to_string(value);
223}
224
225static inline std::string convert_to_string(int64_t value, const std::string &int64_type, bool long_long_literal_suffix)
226{
227 // INT64_MIN is ... special on some backends.
228 // If we use a decimal literal, and negate it, we might overflow the representable numbers.
229 // To workaround it, emit int(0x80000000) instead.
230 if (value == std::numeric_limits<int64_t>::min())
231 return join(int64_type, "(0x8000000000000000u", (long_long_literal_suffix ? "ll" : "l"), ")");
232 else
233 return std::to_string(value) + (long_long_literal_suffix ? "ll" : "l");
234}
235
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200236// Allow implementations to set a convenient standard precision
Bill Hollings6ddd80e2016-04-08 15:12:40 -0400237#ifndef SPIRV_CROSS_FLT_FMT
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200238#define SPIRV_CROSS_FLT_FMT "%.32g"
Bill Hollings103aabf2016-04-06 17:42:27 -0400239#endif
240
Hanno4560ee22020-04-09 17:30:20 +0200241// Disable sprintf and strcat warnings.
242// We cannot rely on snprintf and family existing because, ..., MSVC.
243#if defined(__clang__) || defined(__GNUC__)
244#pragma GCC diagnostic push
245#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
246#elif defined(_MSC_VER)
Hans-Kristian Arntzence3fe292017-01-12 10:57:44 +0100247#pragma warning(push)
Hans-Kristian Arntzen27f4f752017-01-13 16:32:54 +0100248#pragma warning(disable : 4996)
Hans-Kristian Arntzence3fe292017-01-12 10:57:44 +0100249#endif
250
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100251static inline void fixup_radix_point(char *str, char radix_point)
252{
253 // Setting locales is a very risky business in multi-threaded program,
254 // so just fixup locales instead. We only need to care about the radix point.
255 if (radix_point != '.')
256 {
257 while (*str != '\0')
258 {
259 if (*str == radix_point)
260 *str = '.';
261 str++;
262 }
263 }
264}
265
266inline std::string convert_to_string(float t, char locale_radix_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200267{
268 // std::to_string for floating point values is broken.
269 // Fallback to something more sane.
270 char buf[64];
271 sprintf(buf, SPIRV_CROSS_FLT_FMT, t);
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100272 fixup_radix_point(buf, locale_radix_point);
273
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200274 // Ensure that the literal is float.
275 if (!strchr(buf, '.') && !strchr(buf, 'e'))
276 strcat(buf, ".0");
277 return buf;
278}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100279
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100280inline std::string convert_to_string(double t, char locale_radix_point)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200281{
282 // std::to_string for floating point values is broken.
283 // Fallback to something more sane.
284 char buf[64];
285 sprintf(buf, SPIRV_CROSS_FLT_FMT, t);
Hans-Kristian Arntzen825ff4a2019-02-28 11:26:26 +0100286 fixup_radix_point(buf, locale_radix_point);
287
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200288 // Ensure that the literal is float.
289 if (!strchr(buf, '.') && !strchr(buf, 'e'))
290 strcat(buf, ".0");
291 return buf;
292}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100293
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200294template <typename T>
295struct ValueSaver
296{
297 explicit ValueSaver(T &current_)
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +0200298 : current(current_)
299 , saved(current_)
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200300 {
301 }
302
303 void release()
304 {
305 current = saved;
306 }
307
308 ~ValueSaver()
309 {
310 release();
311 }
312
313 T &current;
314 T saved;
315};
316
Hanno4560ee22020-04-09 17:30:20 +0200317#if defined(__clang__) || defined(__GNUC__)
318#pragma GCC diagnostic pop
319#elif defined(_MSC_VER)
Hans-Kristian Arntzence3fe292017-01-12 10:57:44 +0100320#pragma warning(pop)
321#endif
322
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200323struct Instruction
324{
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200325 uint16_t op = 0;
326 uint16_t count = 0;
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +0100327 // If offset is 0 (not a valid offset into the instruction stream),
328 // we have an instruction stream which is embedded in the object.
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200329 uint32_t offset = 0;
330 uint32_t length = 0;
Hans-Kristian Arntzen4ca06c72021-03-08 14:09:32 +0100331
332 inline bool is_embedded() const
333 {
334 return offset == 0;
335 }
336};
337
338struct EmbeddedInstruction : Instruction
339{
340 SmallVector<uint32_t> ops;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200341};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100342
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200343enum Types
344{
345 TypeNone,
346 TypeType,
347 TypeVariable,
348 TypeConstant,
349 TypeFunction,
350 TypeFunctionPrototype,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200351 TypeBlock,
352 TypeExtension,
353 TypeExpression,
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200354 TypeConstantOp,
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +0200355 TypeCombinedImageSampler,
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +0200356 TypeAccessChain,
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100357 TypeUndef,
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +0200358 TypeString,
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100359 TypeCount
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200360};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100361
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200362template <Types type>
363class TypedID;
364
365template <>
366class TypedID<TypeNone>
367{
368public:
369 TypedID() = default;
370 TypedID(uint32_t id_)
371 : id(id_)
372 {
373 }
374
375 template <Types U>
376 TypedID(const TypedID<U> &other)
377 {
378 *this = other;
379 }
380
381 template <Types U>
382 TypedID &operator=(const TypedID<U> &other)
383 {
384 id = uint32_t(other);
385 return *this;
386 }
387
388 // Implicit conversion to u32 is desired here.
389 // As long as we block implicit conversion between TypedID<A> and TypedID<B> we're good.
390 operator uint32_t() const
391 {
392 return id;
393 }
394
395 template <Types U>
396 operator TypedID<U>() const
397 {
398 return TypedID<U>(*this);
399 }
400
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200401private:
402 uint32_t id = 0;
403};
404
405template <Types type>
406class TypedID
407{
408public:
409 TypedID() = default;
410 TypedID(uint32_t id_)
411 : id(id_)
412 {
413 }
414
415 explicit TypedID(const TypedID<TypeNone> &other)
416 : id(uint32_t(other))
417 {
418 }
419
420 operator uint32_t() const
421 {
422 return id;
423 }
424
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200425private:
426 uint32_t id = 0;
427};
428
429using VariableID = TypedID<TypeVariable>;
430using TypeID = TypedID<TypeType>;
431using ConstantID = TypedID<TypeConstant>;
432using FunctionID = TypedID<TypeFunction>;
433using BlockID = TypedID<TypeBlock>;
434using ID = TypedID<TypeNone>;
435
436// Helper for Variant interface.
437struct IVariant
438{
439 virtual ~IVariant() = default;
440 virtual IVariant *clone(ObjectPoolBase *pool) = 0;
441 ID self = 0;
Corentin Wallez6a85c692021-06-21 13:18:21 +0200442
443protected:
444 IVariant() = default;
445 IVariant(const IVariant&) = default;
446 IVariant &operator=(const IVariant&) = default;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200447};
448
449#define SPIRV_CROSS_DECLARE_CLONE(T) \
450 IVariant *clone(ObjectPoolBase *pool) override \
451 { \
452 return static_cast<ObjectPool<T> *>(pool)->allocate(*this); \
453 }
454
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200455struct SPIRUndef : IVariant
456{
457 enum
458 {
459 type = TypeUndef
460 };
Hans-Kristian Arntzen9bbdccd2019-02-12 11:11:29 +0100461
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200462 explicit SPIRUndef(TypeID basetype_)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200463 : basetype(basetype_)
464 {
465 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200466 TypeID basetype;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200467
468 SPIRV_CROSS_DECLARE_CLONE(SPIRUndef)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200469};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100470
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +0200471struct SPIRString : IVariant
472{
473 enum
474 {
475 type = TypeString
476 };
477
478 explicit SPIRString(std::string str_)
479 : str(std::move(str_))
480 {
481 }
482
483 std::string str;
484
485 SPIRV_CROSS_DECLARE_CLONE(SPIRString)
486};
487
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +0200488// This type is only used by backends which need to access the combined image and sampler IDs separately after
489// the OpSampledImage opcode.
490struct SPIRCombinedImageSampler : IVariant
491{
492 enum
493 {
494 type = TypeCombinedImageSampler
495 };
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200496 SPIRCombinedImageSampler(TypeID type_, VariableID image_, VariableID sampler_)
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +0200497 : combined_type(type_)
498 , image(image_)
499 , sampler(sampler_)
500 {
501 }
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200502 TypeID combined_type;
503 VariableID image;
504 VariableID sampler;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200505
506 SPIRV_CROSS_DECLARE_CLONE(SPIRCombinedImageSampler)
Hans-Kristian Arntzen100e9d32017-04-25 10:44:55 +0200507};
508
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200509struct SPIRConstantOp : IVariant
510{
511 enum
512 {
513 type = TypeConstantOp
514 };
515
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200516 SPIRConstantOp(TypeID result_type, spv::Op op, const uint32_t *args, uint32_t length)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200517 : opcode(op)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200518 , basetype(result_type)
519 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200520 arguments.reserve(length);
521 for (uint32_t i = 0; i < length; i++)
522 arguments.push_back(args[i]);
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200523 }
524
525 spv::Op opcode;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200526 SmallVector<uint32_t> arguments;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200527 TypeID basetype;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200528
529 SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp)
Hans-Kristian Arntzen7e8afa82016-10-03 15:54:02 +0200530};
531
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200532struct SPIRType : IVariant
533{
534 enum
535 {
536 type = TypeType
537 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100538
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200539 enum BaseType
540 {
541 Unknown,
542 Void,
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +0200543 Boolean,
Chip Davis117ccf42018-11-01 17:20:07 -0500544 SByte,
545 UByte,
546 Short,
547 UShort,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200548 Int,
549 UInt,
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200550 Int64,
551 UInt64,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200552 AtomicCounter,
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +0100553 Half,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200554 Float,
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200555 Double,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200556 Struct,
557 Image,
558 SampledImage,
Chip Davise75add42019-02-05 18:13:26 -0600559 Sampler,
Hans-Kristian Arntzen6b0e5582020-04-21 14:25:18 +0200560 AccelerationStructure,
561 RayQuery,
Hans-Kristian Arntzen88ce9582019-03-27 10:21:30 +0100562
563 // Keep internal types at the end.
Patrick Moursda39a7b2019-02-26 15:43:03 +0100564 ControlPointArray,
Chip Davisaca9b682020-11-02 20:56:46 -0600565 Interpolant,
Hans-Kristian Arntzen88ce9582019-03-27 10:21:30 +0100566 Char
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200567 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100568
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200569 // Scalar/vector/matrix support.
570 BaseType basetype = Unknown;
571 uint32_t width = 0;
572 uint32_t vecsize = 1;
573 uint32_t columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100574
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200575 // Arrays, support array of arrays by having a vector of array sizes.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200576 SmallVector<uint32_t> array;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100577
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200578 // Array elements can be either specialization constants or specialization ops.
579 // This array determines how to interpret the array size.
580 // If an element is true, the element is a literal,
581 // otherwise, it's an expression, which must be resolved on demand.
582 // The actual size is not really known until runtime.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200583 SmallVector<bool> array_size_literal;
Hans-Kristian Arntzen5d4bb682016-10-03 17:17:11 +0200584
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200585 // Pointers
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +0100586 // Keep track of how many pointer layers we have.
587 uint32_t pointer_depth = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200588 bool pointer = false;
Hans-Kristian Arntzen58dad822020-05-25 11:05:42 +0200589 bool forward_pointer = false;
Hans-Kristian Arntzend0b93722018-11-26 12:23:28 +0100590
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200591 spv::StorageClass storage = spv::StorageClassGeneric;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100592
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200593 SmallVector<TypeID> member_types;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100594
Hans-Kristian Arntzen0ebb88c2020-04-30 11:48:53 +0200595 // If member order has been rewritten to handle certain scenarios with Offset,
596 // allow codegen to rewrite the index.
597 SmallVector<uint32_t> member_type_index_redirection;
598
Hans-Kristian Arntzenafc2c0c2017-10-24 10:25:38 +0200599 struct ImageType
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200600 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200601 TypeID type;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200602 spv::Dim dim;
603 bool depth;
604 bool arrayed;
605 bool ms;
606 uint32_t sampled;
607 spv::ImageFormat format;
Bill Hollingsb41e1482017-05-29 20:45:05 -0400608 spv::AccessQualifier access;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200609 } image;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200610
611 // Structs can be declared multiple times if they are used as part of interface blocks.
612 // We want to detect this so that we only emit the struct definition once.
613 // Since we cannot rely on OpName to be equal, we need to figure out aliases.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200614 TypeID type_alias = 0;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200615
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +0100616 // Denotes the type which this type is based on.
617 // Allows the backend to traverse how a complex type is built up during access chains.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200618 TypeID parent_type = 0;
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +0100619
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200620 // Used in backends to avoid emitting members with conflicting names.
621 std::unordered_set<std::string> member_name_cache;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200622
623 SPIRV_CROSS_DECLARE_CLONE(SPIRType)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200624};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100625
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200626struct SPIRExtension : IVariant
627{
628 enum
629 {
630 type = TypeExtension
631 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100632
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200633 enum Extension
634 {
Hans-Kristian Arntzen299e19f2017-03-21 16:33:54 +0100635 Unsupported,
Lou Kramer6671f522017-11-21 14:04:57 +0100636 GLSL,
Lifeng Pan5ca87792019-07-04 16:03:06 +0800637 SPV_debug_info,
Lou Kramer6671f522017-11-21 14:04:57 +0100638 SPV_AMD_shader_ballot,
639 SPV_AMD_shader_explicit_vertex_parameter,
640 SPV_AMD_shader_trinary_minmax,
641 SPV_AMD_gcn_shader
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200642 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100643
Hans-Kristian Arntzen9bbdccd2019-02-12 11:11:29 +0100644 explicit SPIRExtension(Extension ext_)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200645 : ext(ext_)
646 {
647 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100648
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200649 Extension ext;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200650 SPIRV_CROSS_DECLARE_CLONE(SPIRExtension)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200651};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100652
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200653// SPIREntryPoint is not a variant since its IDs are used to decorate OpFunction,
654// so in order to avoid conflicts, we can't stick them in the ids array.
655struct SPIREntryPoint
656{
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200657 SPIREntryPoint(FunctionID self_, spv::ExecutionModel execution_model, const std::string &entry_name)
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200658 : self(self_)
Bill Hollings1c180782017-11-05 21:34:42 -0500659 , name(entry_name)
660 , orig_name(entry_name)
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200661 , model(execution_model)
662 {
663 }
664 SPIREntryPoint() = default;
665
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200666 FunctionID self = 0;
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200667 std::string name;
Bill Hollings1c180782017-11-05 21:34:42 -0500668 std::string orig_name;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200669 SmallVector<VariableID> interface_variables;
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200670
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +0100671 Bitset flags;
Hans-Kristian Arntzen36c999a2020-07-11 13:35:44 +0200672 struct WorkgroupSize
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200673 {
674 uint32_t x = 0, y = 0, z = 0;
Hans-Kristian Arntzen7c83fc22022-01-05 15:53:51 +0100675 uint32_t id_x = 0, id_y = 0, id_z = 0;
Hans-Kristian Arntzen86eb8742017-09-28 11:33:30 +0200676 uint32_t constant = 0; // Workgroup size can be expressed as a constant/spec-constant instead.
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200677 } workgroup_size;
678 uint32_t invocations = 0;
679 uint32_t output_vertices = 0;
Hans-Kristian Arntzen9bbdccd2019-02-12 11:11:29 +0100680 spv::ExecutionModel model = spv::ExecutionModelMax;
Hans-Kristian Arntzen55fe6052020-01-15 16:18:29 +0100681 bool geometry_passthrough = false;
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200682};
683
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200684struct SPIRExpression : IVariant
685{
686 enum
687 {
688 type = TypeExpression
689 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100690
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200691 // Only created by the backend target to avoid creating tons of temporaries.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200692 SPIRExpression(std::string expr, TypeID expression_type_, bool immutable_)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200693 : expression(move(expr))
694 , expression_type(expression_type_)
695 , immutable(immutable_)
696 {
697 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100698
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200699 // If non-zero, prepend expression with to_expression(base_expression).
700 // Used in amortizing multiple calls to to_expression()
701 // where in certain cases that would quickly force a temporary when not needed.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200702 ID base_expression = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200704 std::string expression;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200705 TypeID expression_type = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100706
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200707 // If this expression is a forwarded load,
708 // allow us to reference the original variable.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200709 ID loaded_from = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100710
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200711 // If this expression will never change, we can avoid lots of temporaries
712 // in high level source.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +0200713 // An expression being immutable can be speculative,
714 // it is assumed that this is true almost always.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200715 bool immutable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100716
Hans-Kristian Arntzenfadaec22017-01-13 16:31:13 +0100717 // Before use, this expression must be transposed.
718 // This is needed for targets which don't support row_major layouts.
719 bool need_transpose = false;
720
Chip Davis3bfb2f92018-12-03 02:06:33 -0600721 // Whether or not this is an access chain expression.
722 bool access_chain = false;
723
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +0200724 // A list of expressions which this expression depends on.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200725 SmallVector<ID> expression_dependencies;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200726
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +0100727 // By reading this expression, we implicitly read these expressions as well.
728 // Used by access chain Store and Load since we read multiple expressions in this case.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200729 SmallVector<ID> implied_read_expressions;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +0100730
Hans-Kristian Arntzen3afbfdb2020-06-29 12:20:35 +0200731 // The expression was emitted at a certain scope. Lets us track when an expression read means multiple reads.
732 uint32_t emitted_loop_level = 0;
733
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200734 SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200735};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100736
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200737struct SPIRFunctionPrototype : IVariant
738{
739 enum
740 {
741 type = TypeFunctionPrototype
742 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100743
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200744 explicit SPIRFunctionPrototype(TypeID return_type_)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200745 : return_type(return_type_)
746 {
747 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100748
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200749 TypeID return_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200750 SmallVector<uint32_t> parameter_types;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200751
752 SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200753};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100754
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200755struct SPIRBlock : IVariant
756{
757 enum
758 {
759 type = TypeBlock
760 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100761
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200762 enum Terminator
763 {
764 Unknown,
765 Direct, // Emit next block directly without a particular condition.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100766
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200767 Select, // Block ends with an if/else block.
768 MultiSelect, // Block ends with switch statement.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100769
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200770 Return, // Block ends with return.
771 Unreachable, // Noop
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100772 Kill, // Discard
773 IgnoreIntersection, // Ray Tracing
774 TerminateRay // Ray Tracing
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200775 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100776
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200777 enum Merge
778 {
779 MergeNone,
780 MergeLoop,
781 MergeSelection
782 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100783
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +0200784 enum Hints
785 {
786 HintNone,
787 HintUnroll,
788 HintDontUnroll,
789 HintFlatten,
790 HintDontFlatten
791 };
792
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200793 enum Method
794 {
795 MergeToSelectForLoop,
Hans-Kristian Arntzen28cccc32018-03-08 17:51:55 +0100796 MergeToDirectForLoop,
797 MergeToSelectContinueForLoop
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200798 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100799
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200800 enum ContinueBlockType
801 {
802 ContinueNone,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100803
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200804 // Continue block is branchless and has at least one instruction.
805 ForLoop,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100806
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200807 // Noop continue block.
808 WhileLoop,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100809
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200810 // Continue block is conditional.
811 DoWhileLoop,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100812
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200813 // Highly unlikely that anything will use this,
814 // since it is really awkward/impossible to express in GLSL.
815 ComplexLoop
816 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100817
Corentin Walleza3a590a2020-04-30 10:00:28 +0200818 enum : uint32_t
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200819 {
820 NoDominator = 0xffffffffu
821 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100822
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200823 Terminator terminator = Unknown;
824 Merge merge = MergeNone;
Hans-Kristian Arntzen33c61d22018-06-25 10:33:13 +0200825 Hints hint = HintNone;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200826 BlockID next_block = 0;
827 BlockID merge_block = 0;
828 BlockID continue_block = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100829
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200830 ID return_value = 0; // If 0, return nothing (void).
831 ID condition = 0;
832 BlockID true_block = 0;
833 BlockID false_block = 0;
834 BlockID default_block = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100835
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200836 SmallVector<Instruction> ops;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100837
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200838 struct Phi
839 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200840 ID local_variable; // flush local variable ...
841 BlockID parent; // If we're in from_block and want to branch into this block ...
842 VariableID function_variable; // to this function-global "phi" variable first.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200843 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100844
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200845 // Before entering this block flush out local variables to magical "phi" variables.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200846 SmallVector<Phi> phi_variables;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100847
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200848 // Declare these temporaries before beginning the block.
849 // Used for handling complex continue blocks which have side effects.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200850 SmallVector<std::pair<TypeID, ID>> declare_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100851
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +0100852 // Declare these temporaries, but only conditionally if this block turns out to be
853 // a complex loop header.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200854 SmallVector<std::pair<TypeID, ID>> potential_declare_temporary;
Hans-Kristian Arntzenc1947aa2018-03-24 04:16:18 +0100855
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200856 struct Case
857 {
Sebastián Aedo3eb55322021-10-28 19:57:41 -0300858 uint64_t value;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200859 BlockID block;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200860 };
Sebastián Aedo75e37522021-11-12 10:17:38 -0300861 SmallVector<Case> cases_32bit;
Sebastián Aedof099d712021-11-02 17:17:13 -0300862 SmallVector<Case> cases_64bit;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100863
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200864 // If we have tried to optimize code for this block but failed,
865 // keep track of this.
866 bool disable_block_optimization = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100867
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200868 // If the continue block is complex, fallback to "dumb" for loops.
869 bool complex_continue = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100870
Hans-Kristian Arntzen3b5968b2018-09-18 10:50:48 +0200871 // Do we need a ladder variable to defer breaking out of a loop construct after a switch block?
872 bool need_ladder_break = false;
873
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +0200874 // If marked, we have explicitly handled Phi from this block, so skip any flushes related to that on a branch.
875 // Used to handle an edge case with switch and case-label fallthrough where fall-through writes to Phi.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200876 BlockID ignore_phi_from_block = 0;
Hans-Kristian Arntzenc365cc12019-06-21 11:16:51 +0200877
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200878 // The dominating block which this block might be within.
879 // Used in continue; blocks to determine if we really need to write continue.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200880 BlockID loop_dominator = 0;
Hans-Kristian Arntzendad4a342016-11-11 18:04:14 +0100881
882 // All access to these variables are dominated by this block,
883 // so before branching anywhere we need to make sure that we declare these variables.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200884 SmallVector<VariableID> dominated_variables;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +0100885
886 // These are variables which should be declared in a for loop header, if we
887 // fail to use a classic for-loop,
888 // we remove these variables, and fall back to regular variables outside the loop.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200889 SmallVector<VariableID> loop_variables;
Hans-Kristian Arntzen938c7de2018-03-12 17:34:54 +0100890
891 // Some expressions are control-flow dependent, i.e. any instruction which relies on derivatives or
892 // sub-group-like operations.
893 // Make sure that we only use these expressions in the original block.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200894 SmallVector<ID> invalidate_expressions;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200895
896 SPIRV_CROSS_DECLARE_CLONE(SPIRBlock)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200897};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100898
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200899struct SPIRFunction : IVariant
900{
901 enum
902 {
903 type = TypeFunction
904 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100905
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200906 SPIRFunction(TypeID return_type_, TypeID function_type_)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200907 : return_type(return_type_)
908 , function_type(function_type_)
909 {
910 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100911
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200912 struct Parameter
913 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200914 TypeID type;
915 ID id;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200916 uint32_t read_count;
917 uint32_t write_count;
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +0100918
919 // Set to true if this parameter aliases a global variable,
920 // used mostly in Metal where global variables
921 // have to be passed down to functions as regular arguments.
922 // However, for this kind of variable, we should not care about
923 // read and write counts as access to the function arguments
924 // is not local to the function in question.
925 bool alias_global_variable;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200926 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100927
Hans-Kristian Arntzened98a8e2016-09-11 11:39:20 +0200928 // When calling a function, and we're remapping separate image samplers,
929 // resolve these arguments into combined image samplers and pass them
930 // as additional arguments in this order.
931 // It gets more complicated as functions can pull in their own globals
932 // and combine them with parameters,
933 // so we need to distinguish if something is local parameter index
934 // or a global ID.
935 struct CombinedImageSamplerParameter
936 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200937 VariableID id;
938 VariableID image_id;
939 VariableID sampler_id;
Hans-Kristian Arntzen378fbe82016-09-11 13:47:06 +0200940 bool global_image;
Hans-Kristian Arntzened98a8e2016-09-11 11:39:20 +0200941 bool global_sampler;
Hans-Kristian Arntzenf4d72682017-05-06 13:21:35 +0200942 bool depth;
Hans-Kristian Arntzened98a8e2016-09-11 11:39:20 +0200943 };
944
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200945 TypeID return_type;
946 TypeID function_type;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200947 SmallVector<Parameter> arguments;
Hans-Kristian Arntzen948930b2016-09-11 12:36:12 +0200948
949 // Can be used by backends to add magic arguments.
950 // Currently used by combined image/sampler implementation.
951
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200952 SmallVector<Parameter> shadow_arguments;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200953 SmallVector<VariableID> local_variables;
954 BlockID entry_block = 0;
955 SmallVector<BlockID> blocks;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200956 SmallVector<CombinedImageSamplerParameter> combined_parameters;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100957
Hans-Kristian Arntzen65af09d2019-05-28 13:41:46 +0200958 struct EntryLine
959 {
960 uint32_t file_id = 0;
961 uint32_t line_literal = 0;
962 };
963 EntryLine entry_line;
964
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200965 void add_local_variable(VariableID id)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200966 {
967 local_variables.push_back(id);
968 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100969
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200970 void add_parameter(TypeID parameter_type, ID id, bool alias_global_variable = false)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200971 {
972 // Arguments are read-only until proven otherwise.
Hans-Kristian Arntzen9cb86162017-02-05 10:50:14 +0100973 arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable });
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200974 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100975
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +0200976 // Hooks to be run when the function returns.
Hans-Kristian Arntzen8e903822018-03-13 14:03:35 +0100977 // Mostly used for lowering internal data structures onto flattened structures.
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +0200978 // Need to defer this, because they might rely on things which change during compilation.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200979 // Intentionally not a small vector, this one is rare, and std::function can be large.
980 Vector<std::function<void()>> fixup_hooks_out;
Bill Hollings9b4defe2018-06-12 11:41:35 -0400981
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +0200982 // Hooks to be run when the function begins.
Bill Hollings9b4defe2018-06-12 11:41:35 -0400983 // Mostly used for populating internal data structures from flattened structures.
Hans-Kristian Arntzen340957a2018-09-17 14:04:55 +0200984 // Need to defer this, because they might rely on things which change during compilation.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200985 // Intentionally not a small vector, this one is rare, and std::function can be large.
986 Vector<std::function<void()>> fixup_hooks_in;
Hans-Kristian Arntzen8e903822018-03-13 14:03:35 +0100987
Hans-Kristian Arntzen30343f32020-02-24 13:22:52 +0100988 // On function entry, make sure to copy a constant array into thread addr space to work around
989 // the case where we are passing a constant array by value to a function on backends which do not
990 // consider arrays value types.
991 SmallVector<ID> constant_arrays_needed_on_stack;
992
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200993 bool active = false;
994 bool flush_undeclared = true;
Hans-Kristian Arntzened98a8e2016-09-11 11:39:20 +0200995 bool do_combined_parameters = true;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200996
997 SPIRV_CROSS_DECLARE_CLONE(SPIRFunction)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200998};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100999
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02001000struct SPIRAccessChain : IVariant
1001{
1002 enum
1003 {
1004 type = TypeAccessChain
1005 };
1006
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001007 SPIRAccessChain(TypeID basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_,
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02001008 int32_t static_index_)
1009 : basetype(basetype_)
1010 , storage(storage_)
Hans-Kristian Arntzen9bbdccd2019-02-12 11:11:29 +01001011 , base(std::move(base_))
Hans-Kristian Arntzen713bd7c2017-08-28 09:01:03 +02001012 , dynamic_index(std::move(dynamic_index_))
1013 , static_index(static_index_)
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02001014 {
1015 }
1016
1017 // The access chain represents an offset into a buffer.
1018 // Some backends need more complicated handling of access chains to be able to use buffers, like HLSL
1019 // which has no usable buffer type ala GLSL SSBOs.
1020 // StructuredBuffer is too limited, so our only option is to deal with ByteAddressBuffer which works with raw addresses.
1021
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001022 TypeID basetype;
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02001023 spv::StorageClass storage;
1024 std::string base;
1025 std::string dynamic_index;
1026 int32_t static_index;
1027
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001028 VariableID loaded_from = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02001029 uint32_t matrix_stride = 0;
Hans-Kristian Arntzenca9398c2020-01-08 13:05:56 +01001030 uint32_t array_stride = 0;
Hans-Kristian Arntzen551424c2017-10-26 16:35:18 +02001031 bool row_major_matrix = false;
Hans-Kristian Arntzen7d7f4b32017-08-10 17:12:48 +02001032 bool immutable = false;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001033
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01001034 // By reading this expression, we implicitly read these expressions as well.
1035 // Used by access chain Store and Load since we read multiple expressions in this case.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001036 SmallVector<ID> implied_read_expressions;
Hans-Kristian Arntzenacae6072019-01-04 13:19:50 +01001037
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001038 SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain)
Hans-Kristian Arntzen3cbdbec2017-08-10 15:36:30 +02001039};
1040
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001041struct SPIRVariable : IVariant
1042{
1043 enum
1044 {
1045 type = TypeVariable
1046 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001047
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001048 SPIRVariable() = default;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001049 SPIRVariable(TypeID basetype_, spv::StorageClass storage_, ID initializer_ = 0, VariableID basevariable_ = 0)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001050 : basetype(basetype_)
1051 , storage(storage_)
1052 , initializer(initializer_)
Vadim Shcherbakov6c41f9e2017-12-06 09:51:23 -08001053 , basevariable(basevariable_)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001054 {
1055 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001056
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001057 TypeID basetype = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001058 spv::StorageClass storage = spv::StorageClassGeneric;
1059 uint32_t decoration = 0;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001060 ID initializer = 0;
1061 VariableID basevariable = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001062
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001063 SmallVector<uint32_t> dereference_chain;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001064 bool compat_builtin = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001065
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001066 // If a variable is shadowed, we only statically assign to it
1067 // and never actually emit a statement for it.
1068 // When we read the variable as an expression, just forward
1069 // shadowed_id as the expression.
1070 bool statically_assigned = false;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001071 ID static_expression = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001072
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001073 // Temporaries which can remain forwarded as long as this variable is not modified.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001074 SmallVector<ID> dependees;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001075 bool forwardable = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001076
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001077 bool deferred_declaration = false;
1078 bool phi_variable = false;
Hans-Kristian Arntzend4926a02019-01-07 14:19:27 +01001079
1080 // Used to deal with Phi variable flushes. See flush_phi().
1081 bool allocate_temporary_copy = false;
1082
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001083 bool remapped_variable = false;
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +02001084 uint32_t remapped_components = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001085
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01001086 // The block which dominates all access to this variable.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001087 BlockID dominator = 0;
Hans-Kristian Arntzen4f07a322016-12-15 17:14:47 +01001088 // If true, this variable is a loop variable, when accessing the variable
1089 // outside a loop,
1090 // we should statically forward it.
1091 bool loop_variable = false;
1092 // Set to true while we're inside the for loop.
1093 bool loop_variable_enable = false;
1094
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001095 SPIRFunction::Parameter *parameter = nullptr;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001096
1097 SPIRV_CROSS_DECLARE_CLONE(SPIRVariable)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001098};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001099
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001100struct SPIRConstant : IVariant
1101{
1102 enum
1103 {
1104 type = TypeConstant
1105 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001106
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02001107 union Constant
1108 {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001109 uint32_t u32;
1110 int32_t i32;
1111 float f32;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001112
1113 uint64_t u64;
1114 int64_t i64;
1115 double f64;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001116 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001117
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001118 struct ConstantVector
1119 {
1120 Constant r[4];
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001121 // If != 0, this element is a specialization constant, and we should keep track of it as such.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001122 ID id[4];
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001123 uint32_t vecsize = 1;
twinaphexe3f40412018-02-03 23:33:08 +01001124
1125 ConstantVector()
1126 {
Hans-Kristian Arntzen903b7982018-05-07 23:41:53 +02001127 memset(r, 0, sizeof(r));
twinaphexe3f40412018-02-03 23:33:08 +01001128 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001129 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001130
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001131 struct ConstantMatrix
1132 {
1133 ConstantVector c[4];
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001134 // If != 0, this column is a specialization constant, and we should keep track of it as such.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001135 ID id[4];
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001136 uint32_t columns = 1;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001137 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001138
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01001139 static inline float f16_to_f32(uint16_t u16_value)
1140 {
1141 // Based on the GLM implementation.
1142 int s = (u16_value >> 15) & 0x1;
1143 int e = (u16_value >> 10) & 0x1f;
1144 int m = (u16_value >> 0) & 0x3ff;
1145
Hans-Kristian Arntzend573a952020-07-01 11:42:58 +02001146 union
1147 {
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01001148 float f32;
1149 uint32_t u32;
1150 } u;
1151
1152 if (e == 0)
1153 {
1154 if (m == 0)
1155 {
1156 u.u32 = uint32_t(s) << 31;
1157 return u.f32;
1158 }
1159 else
1160 {
1161 while ((m & 0x400) == 0)
1162 {
1163 m <<= 1;
1164 e--;
1165 }
1166
1167 e++;
1168 m &= ~0x400;
1169 }
1170 }
1171 else if (e == 31)
1172 {
1173 if (m == 0)
1174 {
1175 u.u32 = (uint32_t(s) << 31) | 0x7f800000u;
1176 return u.f32;
1177 }
1178 else
1179 {
1180 u.u32 = (uint32_t(s) << 31) | 0x7f800000u | (m << 13);
1181 return u.f32;
1182 }
1183 }
1184
1185 e += 127 - 15;
1186 m <<= 13;
1187 u.u32 = (uint32_t(s) << 31) | (e << 23) | m;
1188 return u.f32;
1189 }
1190
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001191 inline uint32_t specialization_constant_id(uint32_t col, uint32_t row) const
1192 {
1193 return m.c[col].id[row];
1194 }
1195
1196 inline uint32_t specialization_constant_id(uint32_t col) const
1197 {
1198 return m.id[col];
1199 }
1200
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001201 inline uint32_t scalar(uint32_t col = 0, uint32_t row = 0) const
1202 {
1203 return m.c[col].r[row].u32;
1204 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001205
Chip Davis117ccf42018-11-01 17:20:07 -05001206 inline int16_t scalar_i16(uint32_t col = 0, uint32_t row = 0) const
1207 {
1208 return int16_t(m.c[col].r[row].u32 & 0xffffu);
1209 }
1210
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01001211 inline uint16_t scalar_u16(uint32_t col = 0, uint32_t row = 0) const
1212 {
1213 return uint16_t(m.c[col].r[row].u32 & 0xffffu);
1214 }
1215
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01001216 inline int8_t scalar_i8(uint32_t col = 0, uint32_t row = 0) const
1217 {
1218 return int8_t(m.c[col].r[row].u32 & 0xffu);
1219 }
1220
1221 inline uint8_t scalar_u8(uint32_t col = 0, uint32_t row = 0) const
1222 {
1223 return uint8_t(m.c[col].r[row].u32 & 0xffu);
1224 }
1225
Hans-Kristian Arntzen91f85d32018-03-06 15:32:26 +01001226 inline float scalar_f16(uint32_t col = 0, uint32_t row = 0) const
1227 {
1228 return f16_to_f32(scalar_u16(col, row));
1229 }
1230
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001231 inline float scalar_f32(uint32_t col = 0, uint32_t row = 0) const
1232 {
1233 return m.c[col].r[row].f32;
1234 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001235
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001236 inline int32_t scalar_i32(uint32_t col = 0, uint32_t row = 0) const
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001237 {
1238 return m.c[col].r[row].i32;
1239 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001240
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001241 inline double scalar_f64(uint32_t col = 0, uint32_t row = 0) const
1242 {
1243 return m.c[col].r[row].f64;
1244 }
1245
1246 inline int64_t scalar_i64(uint32_t col = 0, uint32_t row = 0) const
1247 {
1248 return m.c[col].r[row].i64;
1249 }
1250
1251 inline uint64_t scalar_u64(uint32_t col = 0, uint32_t row = 0) const
1252 {
1253 return m.c[col].r[row].u64;
1254 }
1255
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001256 inline const ConstantVector &vector() const
1257 {
1258 return m.c[0];
1259 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001261 inline uint32_t vector_size() const
1262 {
1263 return m.c[0].vecsize;
1264 }
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001265
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001266 inline uint32_t columns() const
1267 {
1268 return m.columns;
1269 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001270
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02001271 inline void make_null(const SPIRType &constant_type_)
1272 {
Hans-Kristian Arntzen903b7982018-05-07 23:41:53 +02001273 m = {};
Hans-Kristian Arntzen48ccde32017-08-03 14:32:07 +02001274 m.columns = constant_type_.columns;
1275 for (auto &c : m.c)
1276 c.vecsize = constant_type_.vecsize;
1277 }
1278
Hans-Kristian Arntzen649ce3c2019-01-07 10:01:00 +01001279 inline bool constant_is_null() const
1280 {
1281 if (specialization)
1282 return false;
1283 if (!subconstants.empty())
1284 return false;
1285
1286 for (uint32_t col = 0; col < columns(); col++)
1287 for (uint32_t row = 0; row < vector_size(); row++)
1288 if (scalar_u64(col, row) != 0)
1289 return false;
1290
1291 return true;
1292 }
1293
Hans-Kristian Arntzen84f8c992017-09-29 10:13:45 +02001294 explicit SPIRConstant(uint32_t constant_type_)
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02001295 : constant_type(constant_type_)
1296 {
Hans-Kristian Arntzen2abdc132017-08-02 10:33:03 +02001297 }
1298
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02001299 SPIRConstant() = default;
1300
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001301 SPIRConstant(TypeID constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized)
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001302 : constant_type(constant_type_)
1303 , specialization(specialized)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001304 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001305 subconstants.reserve(num_elements);
1306 for (uint32_t i = 0; i < num_elements; i++)
1307 subconstants.push_back(elements[i]);
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001308 specialization = specialized;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001309 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001310
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001311 // Construct scalar (32-bit).
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001312 SPIRConstant(TypeID constant_type_, uint32_t v0, bool specialized)
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001313 : constant_type(constant_type_)
1314 , specialization(specialized)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001315 {
1316 m.c[0].r[0].u32 = v0;
1317 m.c[0].vecsize = 1;
1318 m.columns = 1;
1319 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001320
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001321 // Construct scalar (64-bit).
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001322 SPIRConstant(TypeID constant_type_, uint64_t v0, bool specialized)
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001323 : constant_type(constant_type_)
1324 , specialization(specialized)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001325 {
1326 m.c[0].r[0].u64 = v0;
1327 m.c[0].vecsize = 1;
1328 m.columns = 1;
1329 }
1330
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001331 // Construct vectors and matrices.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001332 SPIRConstant(TypeID constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements,
Hans-Kristian Arntzen153fed02017-09-28 13:28:44 +02001333 bool specialized)
1334 : constant_type(constant_type_)
1335 , specialization(specialized)
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001336 {
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001337 bool matrix = vector_elements[0]->m.c[0].vecsize > 1;
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001338
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001339 if (matrix)
Hans-Kristian Arntzen5e1d6fb2017-09-27 15:16:33 +02001340 {
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001341 m.columns = num_elements;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +02001342
Hans-Kristian Arntzenceefae52017-09-27 16:10:29 +02001343 for (uint32_t i = 0; i < num_elements; i++)
1344 {
1345 m.c[i] = vector_elements[i]->m.c[0];
1346 if (vector_elements[i]->specialization)
1347 m.id[i] = vector_elements[i]->self;
1348 }
1349 }
1350 else
1351 {
1352 m.c[0].vecsize = num_elements;
1353 m.columns = 1;
1354
1355 for (uint32_t i = 0; i < num_elements; i++)
1356 {
1357 m.c[0].r[i] = vector_elements[i]->m.c[0].r[0];
1358 if (vector_elements[i]->specialization)
1359 m.c[0].id[i] = vector_elements[i]->self;
1360 }
1361 }
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001362 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001363
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001364 TypeID constant_type = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001365 ConstantMatrix m;
Hans-Kristian Arntzen3951b942018-05-15 11:16:06 +02001366
1367 // If this constant is a specialization constant (i.e. created with OpSpecConstant*).
1368 bool specialization = false;
1369 // If this constant is used as an array length which creates specialization restrictions on some backends.
1370 bool is_used_as_array_length = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001371
Hans-Kristian Arntzend29f48e2018-07-05 13:25:57 +02001372 // If true, this is a LUT, and should always be declared in the outer scope.
1373 bool is_used_as_lut = false;
1374
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001375 // For composites which are constant arrays, etc.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001376 SmallVector<ConstantID> subconstants;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001377
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001378 // Non-Vulkan GLSL, HLSL and sometimes MSL emits defines for each specialization constant,
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001379 // and uses them to initialize the constant. This allows the user
1380 // to still be able to specialize the value by supplying corresponding
1381 // preprocessor directives before compiling the shader.
Hans-Kristian Arntzenfd6ff362018-11-01 10:53:00 +01001382 std::string specialization_constant_macro_name;
Grigory Dzhavadyana5d82d12018-10-29 23:31:32 -07001383
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001384 SPIRV_CROSS_DECLARE_CLONE(SPIRConstant)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001385};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001386
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001387// Variants have a very specific allocation scheme.
1388struct ObjectPoolGroup
1389{
1390 std::unique_ptr<ObjectPoolBase> pools[TypeCount];
1391};
1392
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001393class Variant
1394{
1395public:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001396 explicit Variant(ObjectPoolGroup *group_)
1397 : group(group_)
1398 {
1399 }
1400
1401 ~Variant()
1402 {
1403 if (holder)
Hans-Kristian Arntzen96d95fb2021-09-30 14:12:08 +02001404 group->pools[type]->deallocate_opaque(holder);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001405 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001406
1407 // Marking custom move constructor as noexcept is important.
1408 Variant(Variant &&other) SPIRV_CROSS_NOEXCEPT
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001409 {
1410 *this = std::move(other);
1411 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001412
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001413 // We cannot copy from other variant without our own pool group.
1414 // Have to explicitly copy.
1415 Variant(const Variant &variant) = delete;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001416
1417 // Marking custom move constructor as noexcept is important.
1418 Variant &operator=(Variant &&other) SPIRV_CROSS_NOEXCEPT
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001419 {
1420 if (this != &other)
1421 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001422 if (holder)
Hans-Kristian Arntzen96d95fb2021-09-30 14:12:08 +02001423 group->pools[type]->deallocate_opaque(holder);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001424 holder = other.holder;
1425 group = other.group;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001426 type = other.type;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001427 allow_type_rewrite = other.allow_type_rewrite;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001428
1429 other.holder = nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001430 other.type = TypeNone;
1431 }
1432 return *this;
1433 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001434
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001435 // This copy/clone should only be called in the Compiler constructor.
1436 // If this is called inside ::compile(), we invalidate any references we took higher in the stack.
1437 // This should never happen.
1438 Variant &operator=(const Variant &other)
1439 {
Hans-Kristian Arntzen03ddea82019-04-09 13:07:30 +02001440//#define SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001441#ifdef SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE
1442 abort();
1443#endif
1444 if (this != &other)
1445 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001446 if (holder)
Hans-Kristian Arntzen96d95fb2021-09-30 14:12:08 +02001447 group->pools[type]->deallocate_opaque(holder);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001448
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001449 if (other.holder)
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001450 holder = other.holder->clone(group->pools[other.type].get());
Hans-Kristian Arntzen0262f602019-04-09 15:25:11 +02001451 else
1452 holder = nullptr;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001453
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001454 type = other.type;
1455 allow_type_rewrite = other.allow_type_rewrite;
1456 }
1457 return *this;
1458 }
1459
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001460 void set(IVariant *val, Types new_type)
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001461 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001462 if (holder)
Hans-Kristian Arntzen96d95fb2021-09-30 14:12:08 +02001463 group->pools[type]->deallocate_opaque(holder);
Hans-Kristian Arntzen0262f602019-04-09 15:25:11 +02001464 holder = nullptr;
1465
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04001466 if (!allow_type_rewrite && type != TypeNone && type != new_type)
Hans-Kristian Arntzen0262f602019-04-09 15:25:11 +02001467 {
1468 if (val)
Hans-Kristian Arntzen96d95fb2021-09-30 14:12:08 +02001469 group->pools[new_type]->deallocate_opaque(val);
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001470 SPIRV_CROSS_THROW("Overwriting a variant with new type.");
Lukas Hermanns7ad0a842019-09-23 18:05:04 -04001471 }
Hans-Kristian Arntzen0262f602019-04-09 15:25:11 +02001472
1473 holder = val;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001474 type = new_type;
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +02001475 allow_type_rewrite = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001476 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001477
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001478 template <typename T, typename... Ts>
1479 T *allocate_and_set(Types new_type, Ts &&... ts)
1480 {
1481 T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...);
1482 set(val, new_type);
1483 return val;
1484 }
1485
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001486 template <typename T>
1487 T &get()
1488 {
1489 if (!holder)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001490 SPIRV_CROSS_THROW("nullptr");
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001491 if (static_cast<Types>(T::type) != type)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001492 SPIRV_CROSS_THROW("Bad cast");
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001493 return *static_cast<T *>(holder);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001494 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001495
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001496 template <typename T>
1497 const T &get() const
1498 {
1499 if (!holder)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001500 SPIRV_CROSS_THROW("nullptr");
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001501 if (static_cast<Types>(T::type) != type)
Panagiotis Christopoulos Charitos946f7792016-12-12 22:33:22 +01001502 SPIRV_CROSS_THROW("Bad cast");
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001503 return *static_cast<const T *>(holder);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001504 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001505
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001506 Types get_type() const
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001507 {
1508 return type;
1509 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001510
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001511 ID get_id() const
Bill Hollings1c180782017-11-05 21:34:42 -05001512 {
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001513 return holder ? holder->self : ID(0);
Bill Hollings1c180782017-11-05 21:34:42 -05001514 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001515
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001516 bool empty() const
1517 {
1518 return !holder;
1519 }
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001520
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001521 void reset()
1522 {
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001523 if (holder)
Hans-Kristian Arntzen96d95fb2021-09-30 14:12:08 +02001524 group->pools[type]->deallocate_opaque(holder);
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001525 holder = nullptr;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001526 type = TypeNone;
1527 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001528
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +02001529 void set_allow_type_rewrite()
1530 {
1531 allow_type_rewrite = true;
1532 }
1533
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001534private:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001535 ObjectPoolGroup *group = nullptr;
1536 IVariant *holder = nullptr;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +01001537 Types type = TypeNone;
Hans-Kristian Arntzen7eba2472018-05-11 10:14:20 +02001538 bool allow_type_rewrite = false;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001539};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001540
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001541template <typename T>
1542T &variant_get(Variant &var)
1543{
1544 return var.get<T>();
1545}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001546
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001547template <typename T>
1548const T &variant_get(const Variant &var)
1549{
1550 return var.get<T>();
1551}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001552
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001553template <typename T, typename... P>
1554T &variant_set(Variant &var, P &&... args)
1555{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001556 auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...);
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001557 return *ptr;
1558}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001559
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01001560struct AccessChainMeta
1561{
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001562 uint32_t storage_physical_type = 0;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01001563 bool need_transpose = false;
1564 bool storage_is_packed = false;
1565 bool storage_is_invariant = false;
Hans-Kristian Arntzen2d431032020-07-03 13:12:05 +02001566 bool flattened_struct = false;
Hans-Kristian Arntzen816c1162018-11-22 11:55:57 +01001567};
1568
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001569enum ExtendedDecorations
1570{
1571 // Marks if a buffer block is re-packed, i.e. member declaration might be subject to PhysicalTypeID remapping and padding.
1572 SPIRVCrossDecorationBufferBlockRepacked = 0,
1573
1574 // A type in a buffer block might be declared with a different physical type than the logical type.
1575 // If this is not set, PhysicalTypeID == the SPIR-V type as declared.
1576 SPIRVCrossDecorationPhysicalTypeID,
1577
1578 // Marks if the physical type is to be declared with tight packing rules, i.e. packed_floatN on MSL and friends.
1579 // If this is set, PhysicalTypeID might also be set. It can be set to same as logical type if all we're doing
1580 // is converting float3 to packed_float3 for example.
Hans-Kristian Arntzene90d8162019-07-19 14:18:14 +02001581 // If this is marked on a struct, it means the struct itself must use only Packed types for all its members.
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001582 SPIRVCrossDecorationPhysicalTypePacked,
1583
1584 // The padding in bytes before declaring this struct member.
Hans-Kristian Arntzenbe2fccd2019-07-22 10:23:39 +02001585 // If used on a struct type, marks the target size of a struct.
1586 SPIRVCrossDecorationPaddingTarget,
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001587
1588 SPIRVCrossDecorationInterfaceMemberIndex,
1589 SPIRVCrossDecorationInterfaceOrigID,
1590 SPIRVCrossDecorationResourceIndexPrimary,
1591 // Used for decorations like resource indices for samplers when part of combined image samplers.
1592 // A variable might need to hold two resource indices in this case.
1593 SPIRVCrossDecorationResourceIndexSecondary,
Chip Davis39dce882019-08-02 15:11:19 -05001594 // Used for resource indices for multiplanar images when part of combined image samplers.
1595 SPIRVCrossDecorationResourceIndexTertiary,
1596 SPIRVCrossDecorationResourceIndexQuaternary,
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001597
1598 // Marks a buffer block for using explicit offsets (GLSL/HLSL).
1599 SPIRVCrossDecorationExplicitOffset,
1600
Chip Davis688c5fc2020-02-20 21:38:28 -06001601 // Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase(),
1602 // or the base vertex and instance indices passed to vkCmdDrawIndexed().
1603 // In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables in compute shaders,
1604 // and to hold the BaseVertex and BaseInstance variables in vertex shaders.
Chip Davisfb5ee4c2019-07-22 13:08:04 -05001605 SPIRVCrossDecorationBuiltInDispatchBase,
1606
Chip Davis39dce882019-08-02 15:11:19 -05001607 // Apply to a variable that is a function parameter; marks it as being a "dynamic"
1608 // combined image-sampler. In MSL, this is used when a function parameter might hold
1609 // either a regular combined image-sampler or one that has an attached sampler
1610 // Y'CbCr conversion.
1611 SPIRVCrossDecorationDynamicImageSampler,
1612
Chip Davis688c5fc2020-02-20 21:38:28 -06001613 // Apply to a variable in the Input storage class; marks it as holding the size of the stage
1614 // input grid.
1615 // In MSL, this is used to hold the vertex and instance counts in a tessellation pipeline
1616 // vertex shader.
1617 SPIRVCrossDecorationBuiltInStageInputSize,
1618
1619 // Apply to any access chain of a tessellation I/O variable; stores the type of the sub-object
1620 // that was chained to, as recorded in the input variable itself. This is used in case the pointer
1621 // is itself used as the base of an access chain, to calculate the original type of the sub-object
1622 // chained to, in case a swizzle needs to be applied. This should not happen normally with valid
1623 // SPIR-V, but the MSL backend can change the type of input variables, necessitating the
1624 // addition of swizzles to keep the generated code compiling.
1625 SPIRVCrossDecorationTessIOOriginalInputTypeID,
1626
Chip Davisaca9b682020-11-02 20:56:46 -06001627 // Apply to any access chain of an interface variable used with pull-model interpolation, where the variable is a
1628 // vector but the resulting pointer is a scalar; stores the component index that is to be accessed by the chain.
1629 // This is used when emitting calls to interpolation functions on the chain in MSL: in this case, the component
1630 // must be applied to the result, since pull-model interpolants in MSL cannot be swizzled directly, but the
1631 // results of interpolation can.
1632 SPIRVCrossDecorationInterpolantComponentExpr,
1633
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001634 SPIRVCrossDecorationCount
1635};
1636
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001637struct Meta
1638{
1639 struct Decoration
1640 {
1641 std::string alias;
Bill Hollingsac00c602016-10-24 09:24:24 -04001642 std::string qualified_alias;
Hans-Kristian Arntzen215d3ca2018-03-20 20:04:12 +01001643 std::string hlsl_semantic;
Hans-Kristian Arntzene8e58842018-03-12 13:09:25 +01001644 Bitset decoration_flags;
Hans-Kristian Arntzen53457562019-01-08 11:03:59 +01001645 spv::BuiltIn builtin_type = spv::BuiltInMax;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001646 uint32_t location = 0;
Chip Davis4b99fdd2018-09-05 17:31:10 -05001647 uint32_t component = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001648 uint32_t set = 0;
1649 uint32_t binding = 0;
1650 uint32_t offset = 0;
Hans-Kristian Arntzen655312c2020-01-27 12:56:48 +01001651 uint32_t xfb_buffer = 0;
1652 uint32_t xfb_stride = 0;
Hans-Kristian Arntzene0c9aad2020-09-30 13:01:35 +02001653 uint32_t stream = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001654 uint32_t array_stride = 0;
Hans-Kristian Arntzend3cad992017-01-21 11:30:33 +01001655 uint32_t matrix_stride = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001656 uint32_t input_attachment = 0;
Hans-Kristian Arntzen6bd545b2016-09-17 15:16:07 +02001657 uint32_t spec_id = 0;
Hans-Kristian Arntzena6e211e2018-04-03 15:56:22 +02001658 uint32_t index = 0;
Hans-Kristian Arntzen6e5df7a2019-01-07 10:51:44 +01001659 spv::FPRoundingMode fp_rounding_mode = spv::FPRoundingModeMax;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001660 bool builtin = false;
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001661
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001662 struct Extended
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001663 {
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +02001664 Extended()
1665 {
1666 // MSVC 2013 workaround to init like this.
1667 for (auto &v : values)
1668 v = 0;
1669 }
1670
1671 Bitset flags;
1672 uint32_t values[SPIRVCrossDecorationCount];
Hans-Kristian Arntzende7e5cc2019-01-17 11:22:24 +01001673 } extended;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001674 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001675
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001676 Decoration decoration;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001677
1678 // Intentionally not a SmallVector. Decoration is large and somewhat rare.
1679 Vector<Decoration> members;
Hans-Kristian Arntzen93fe19c2017-04-25 20:10:24 +02001680
Hans-Kristian Arntzen173dc9e2017-04-26 09:25:28 +02001681 std::unordered_map<uint32_t, uint32_t> decoration_word_offset;
Hans-Kristian Arntzenec45c9e2017-04-19 17:33:14 +02001682
Hans-Kristian Arntzen9aa623a2018-11-22 10:23:58 +01001683 // For SPV_GOOGLE_hlsl_functionality1.
Hans-Kristian Arntzen215d3ca2018-03-20 20:04:12 +01001684 bool hlsl_is_magic_counter_buffer = false;
1685 // ID for the sibling counter buffer.
1686 uint32_t hlsl_magic_counter_buffer = 0;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +02001687};
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +02001688
1689// A user callback that remaps the type of any variable.
Hans-Kristian Arntzen4d4e6d72016-09-20 10:55:09 +02001690// var_name is the declared name of the variable.
1691// name_of_type is the textual name of the type which will be used in the code unless written to by the callback.
Panagiotis Christopoulos Charitos66e76d92016-09-20 10:17:41 +02001692using VariableTypeRemapCallback =
1693 std::function<void(const SPIRType &type, const std::string &var_name, std::string &name_of_type)>;
Endre Oma6ad8b302017-01-11 15:57:05 +01001694
Hans-Kristian Arntzena04bdcc2018-02-23 14:13:46 +01001695class Hasher
1696{
1697public:
1698 inline void u32(uint32_t value)
1699 {
1700 h = (h * 0x100000001b3ull) ^ value;
1701 }
1702
1703 inline uint64_t get() const
1704 {
1705 return h;
1706 }
1707
1708private:
1709 uint64_t h = 0xcbf29ce484222325ull;
1710};
Hans-Kristian Arntzen47d94ff2018-03-07 10:21:25 +01001711
1712static inline bool type_is_floating_point(const SPIRType &type)
1713{
1714 return type.basetype == SPIRType::Half || type.basetype == SPIRType::Float || type.basetype == SPIRType::Double;
1715}
Chip Davis9e6469b2018-09-04 16:08:22 -05001716
1717static inline bool type_is_integral(const SPIRType &type)
1718{
Chip Davis117ccf42018-11-01 17:20:07 -05001719 return type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte || type.basetype == SPIRType::Short ||
1720 type.basetype == SPIRType::UShort || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
1721 type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64;
Chip Davis9e6469b2018-09-04 16:08:22 -05001722}
Hans-Kristian Arntzen2ed171e2019-01-30 14:49:55 +01001723
1724static inline SPIRType::BaseType to_signed_basetype(uint32_t width)
1725{
1726 switch (width)
1727 {
1728 case 8:
1729 return SPIRType::SByte;
1730 case 16:
1731 return SPIRType::Short;
1732 case 32:
1733 return SPIRType::Int;
1734 case 64:
1735 return SPIRType::Int64;
1736 default:
1737 SPIRV_CROSS_THROW("Invalid bit width.");
1738 }
1739}
1740
1741static inline SPIRType::BaseType to_unsigned_basetype(uint32_t width)
1742{
1743 switch (width)
1744 {
1745 case 8:
1746 return SPIRType::UByte;
1747 case 16:
1748 return SPIRType::UShort;
1749 case 32:
1750 return SPIRType::UInt;
1751 case 64:
1752 return SPIRType::UInt64;
1753 default:
1754 SPIRV_CROSS_THROW("Invalid bit width.");
1755 }
1756}
1757
1758// Returns true if an arithmetic operation does not change behavior depending on signedness.
1759static inline bool opcode_is_sign_invariant(spv::Op opcode)
1760{
1761 switch (opcode)
1762 {
1763 case spv::OpIEqual:
1764 case spv::OpINotEqual:
1765 case spv::OpISub:
1766 case spv::OpIAdd:
1767 case spv::OpIMul:
1768 case spv::OpShiftLeftLogical:
1769 case spv::OpBitwiseOr:
1770 case spv::OpBitwiseXor:
1771 case spv::OpBitwiseAnd:
1772 return true;
1773
1774 default:
1775 return false;
1776 }
1777}
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01001778
1779struct SetBindingPair
1780{
1781 uint32_t desc_set;
1782 uint32_t binding;
1783
1784 inline bool operator==(const SetBindingPair &other) const
1785 {
1786 return desc_set == other.desc_set && binding == other.binding;
1787 }
1788
1789 inline bool operator<(const SetBindingPair &other) const
1790 {
1791 return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding);
1792 }
1793};
1794
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +01001795struct LocationComponentPair
1796{
1797 uint32_t location;
1798 uint32_t component;
1799
1800 inline bool operator==(const LocationComponentPair &other) const
1801 {
1802 return location == other.location && component == other.component;
1803 }
1804
1805 inline bool operator<(const LocationComponentPair &other) const
1806 {
1807 return location < other.location || (location == other.location && component < other.component);
1808 }
1809};
1810
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01001811struct StageSetBinding
1812{
1813 spv::ExecutionModel model;
1814 uint32_t desc_set;
1815 uint32_t binding;
1816
1817 inline bool operator==(const StageSetBinding &other) const
1818 {
1819 return model == other.model && desc_set == other.desc_set && binding == other.binding;
1820 }
1821};
1822
1823struct InternalHasher
1824{
1825 inline size_t operator()(const SetBindingPair &value) const
1826 {
1827 // Quality of hash doesn't really matter here.
1828 auto hash_set = std::hash<uint32_t>()(value.desc_set);
1829 auto hash_binding = std::hash<uint32_t>()(value.binding);
1830 return (hash_set * 0x10001b31) ^ hash_binding;
1831 }
1832
Hans-Kristian Arntzen2a2d57d2021-03-25 18:08:49 +01001833 inline size_t operator()(const LocationComponentPair &value) const
1834 {
1835 // Quality of hash doesn't really matter here.
1836 auto hash_set = std::hash<uint32_t>()(value.location);
1837 auto hash_binding = std::hash<uint32_t>()(value.component);
1838 return (hash_set * 0x10001b31) ^ hash_binding;
1839 }
1840
Hans-Kristian Arntzencc153f82020-01-09 11:18:14 +01001841 inline size_t operator()(const StageSetBinding &value) const
1842 {
1843 // Quality of hash doesn't really matter here.
1844 auto hash_model = std::hash<uint32_t>()(value.model);
1845 auto hash_set = std::hash<uint32_t>()(value.desc_set);
1846 auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set;
1847 return (tmp_hash * 0x10001b31) ^ value.binding;
1848 }
1849};
1850
1851// Special constant used in a {MSL,HLSL}ResourceBinding desc_set
1852// element to indicate the bindings for the push constants.
1853static const uint32_t ResourceBindingPushConstantDescriptorSet = ~(0u);
1854
1855// Special constant used in a {MSL,HLSL}ResourceBinding binding
1856// element to indicate the bindings for the push constants.
1857static const uint32_t ResourceBindingPushConstantBinding = 0;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +02001858} // namespace SPIRV_CROSS_NAMESPACE
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001859
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +02001860namespace std
1861{
1862template <SPIRV_CROSS_NAMESPACE::Types type>
1863struct hash<SPIRV_CROSS_NAMESPACE::TypedID<type>>
1864{
1865 size_t operator()(const SPIRV_CROSS_NAMESPACE::TypedID<type> &value) const
1866 {
1867 return std::hash<uint32_t>()(value);
1868 }
1869};
1870} // namespace std
1871
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001872#endif