gstaichi 2.1.1rc3__cp310-cp310-macosx_11_0_arm64.whl

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