1 /*
2  * Copyright 2015-2019 Arm Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SPIRV_CROSS_COMMON_HPP
18 #define SPIRV_CROSS_COMMON_HPP
19 
20 #include "spirv.hpp"
21 #include "spirv_cross_containers.hpp"
22 #include "spirv_cross_error_handling.hpp"
23 #include <functional>
24 
25 // A bit crude, but allows projects which embed SPIRV-Cross statically to
26 // effectively hide all the symbols from other projects.
27 // There is a case where we have:
28 // - Project A links against SPIRV-Cross statically.
29 // - Project A links against Project B statically.
30 // - Project B links against SPIRV-Cross statically (might be a different version).
31 // This leads to a conflict with extremely bizarre results.
32 // By overriding the namespace in one of the project builds, we can work around this.
33 // If SPIRV-Cross is embedded in dynamic libraries,
34 // prefer using -fvisibility=hidden on GCC/Clang instead.
35 #ifdef SPIRV_CROSS_NAMESPACE_OVERRIDE
36 #define SPIRV_CROSS_NAMESPACE SPIRV_CROSS_NAMESPACE_OVERRIDE
37 #else
38 #define SPIRV_CROSS_NAMESPACE spirv_cross
39 #endif
40 
41 namespace SPIRV_CROSS_NAMESPACE
42 {
43 namespace inner
44 {
45 template <typename T>
join_helper(StringStream<> & stream,T && t)46 void join_helper(StringStream<> &stream, T &&t)
47 {
48 	stream << std::forward<T>(t);
49 }
50 
51 template <typename T, typename... Ts>
join_helper(StringStream<> & stream,T && t,Ts &&...ts)52 void join_helper(StringStream<> &stream, T &&t, Ts &&... ts)
53 {
54 	stream << std::forward<T>(t);
55 	join_helper(stream, std::forward<Ts>(ts)...);
56 }
57 } // namespace inner
58 
59 class Bitset
60 {
61 public:
62 	Bitset() = default;
Bitset(uint64_t lower_)63 	explicit inline Bitset(uint64_t lower_)
64 	    : lower(lower_)
65 	{
66 	}
67 
get(uint32_t bit) const68 	inline bool get(uint32_t bit) const
69 	{
70 		if (bit < 64)
71 			return (lower & (1ull << bit)) != 0;
72 		else
73 			return higher.count(bit) != 0;
74 	}
75 
set(uint32_t bit)76 	inline void set(uint32_t bit)
77 	{
78 		if (bit < 64)
79 			lower |= 1ull << bit;
80 		else
81 			higher.insert(bit);
82 	}
83 
clear(uint32_t bit)84 	inline void clear(uint32_t bit)
85 	{
86 		if (bit < 64)
87 			lower &= ~(1ull << bit);
88 		else
89 			higher.erase(bit);
90 	}
91 
get_lower() const92 	inline uint64_t get_lower() const
93 	{
94 		return lower;
95 	}
96 
reset()97 	inline void reset()
98 	{
99 		lower = 0;
100 		higher.clear();
101 	}
102 
merge_and(const Bitset & other)103 	inline void merge_and(const Bitset &other)
104 	{
105 		lower &= other.lower;
106 		std::unordered_set<uint32_t> tmp_set;
107 		for (auto &v : higher)
108 			if (other.higher.count(v) != 0)
109 				tmp_set.insert(v);
110 		higher = std::move(tmp_set);
111 	}
112 
merge_or(const Bitset & other)113 	inline void merge_or(const Bitset &other)
114 	{
115 		lower |= other.lower;
116 		for (auto &v : other.higher)
117 			higher.insert(v);
118 	}
119 
operator ==(const Bitset & other) const120 	inline bool operator==(const Bitset &other) const
121 	{
122 		if (lower != other.lower)
123 			return false;
124 
125 		if (higher.size() != other.higher.size())
126 			return false;
127 
128 		for (auto &v : higher)
129 			if (other.higher.count(v) == 0)
130 				return false;
131 
132 		return true;
133 	}
134 
operator !=(const Bitset & other) const135 	inline bool operator!=(const Bitset &other) const
136 	{
137 		return !(*this == other);
138 	}
139 
140 	template <typename Op>
for_each_bit(const Op & op) const141 	void for_each_bit(const Op &op) const
142 	{
143 		// TODO: Add ctz-based iteration.
144 		for (uint32_t i = 0; i < 64; i++)
145 		{
146 			if (lower & (1ull << i))
147 				op(i);
148 		}
149 
150 		if (higher.empty())
151 			return;
152 
153 		// Need to enforce an order here for reproducible results,
154 		// but hitting this path should happen extremely rarely, so having this slow path is fine.
155 		SmallVector<uint32_t> bits;
156 		bits.reserve(higher.size());
157 		for (auto &v : higher)
158 			bits.push_back(v);
159 		std::sort(std::begin(bits), std::end(bits));
160 
161 		for (auto &v : bits)
162 			op(v);
163 	}
164 
empty() const165 	inline bool empty() const
166 	{
167 		return lower == 0 && higher.empty();
168 	}
169 
170 private:
171 	// The most common bits to set are all lower than 64,
172 	// so optimize for this case. Bits spilling outside 64 go into a slower data structure.
173 	// In almost all cases, higher data structure will not be used.
174 	uint64_t lower = 0;
175 	std::unordered_set<uint32_t> higher;
176 };
177 
178 // Helper template to avoid lots of nasty string temporary munging.
179 template <typename... Ts>
join(Ts &&...ts)180 std::string join(Ts &&... ts)
181 {
182 	StringStream<> stream;
183 	inner::join_helper(stream, std::forward<Ts>(ts)...);
184 	return stream.str();
185 }
186 
merge(const SmallVector<std::string> & list,const char * between=", ")187 inline std::string merge(const SmallVector<std::string> &list, const char *between = ", ")
188 {
189 	StringStream<> stream;
190 	for (auto &elem : list)
191 	{
192 		stream << elem;
193 		if (&elem != &list.back())
194 			stream << between;
195 	}
196 	return stream.str();
197 }
198 
199 // Make sure we don't accidentally call this with float or doubles with SFINAE.
200 // Have to use the radix-aware overload.
201 template <typename T, typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0>
convert_to_string(const T & t)202 inline std::string convert_to_string(const T &t)
203 {
204 	return std::to_string(t);
205 }
206 
207 // Allow implementations to set a convenient standard precision
208 #ifndef SPIRV_CROSS_FLT_FMT
209 #define SPIRV_CROSS_FLT_FMT "%.32g"
210 #endif
211 
212 #ifdef _MSC_VER
213 // sprintf warning.
214 // We cannot rely on snprintf existing because, ..., MSVC.
215 #pragma warning(push)
216 #pragma warning(disable : 4996)
217 #endif
218 
fixup_radix_point(char * str,char radix_point)219 static inline void fixup_radix_point(char *str, char radix_point)
220 {
221 	// Setting locales is a very risky business in multi-threaded program,
222 	// so just fixup locales instead. We only need to care about the radix point.
223 	if (radix_point != '.')
224 	{
225 		while (*str != '\0')
226 		{
227 			if (*str == radix_point)
228 				*str = '.';
229 			str++;
230 		}
231 	}
232 }
233 
convert_to_string(float t,char locale_radix_point)234 inline std::string convert_to_string(float t, char locale_radix_point)
235 {
236 	// std::to_string for floating point values is broken.
237 	// Fallback to something more sane.
238 	char buf[64];
239 	sprintf(buf, SPIRV_CROSS_FLT_FMT, t);
240 	fixup_radix_point(buf, locale_radix_point);
241 
242 	// Ensure that the literal is float.
243 	if (!strchr(buf, '.') && !strchr(buf, 'e'))
244 		strcat(buf, ".0");
245 	return buf;
246 }
247 
convert_to_string(double t,char locale_radix_point)248 inline std::string convert_to_string(double t, char locale_radix_point)
249 {
250 	// std::to_string for floating point values is broken.
251 	// Fallback to something more sane.
252 	char buf[64];
253 	sprintf(buf, SPIRV_CROSS_FLT_FMT, t);
254 	fixup_radix_point(buf, locale_radix_point);
255 
256 	// Ensure that the literal is float.
257 	if (!strchr(buf, '.') && !strchr(buf, 'e'))
258 		strcat(buf, ".0");
259 	return buf;
260 }
261 
262 #ifdef _MSC_VER
263 #pragma warning(pop)
264 #endif
265 
266 struct Instruction
267 {
268 	uint16_t op = 0;
269 	uint16_t count = 0;
270 	uint32_t offset = 0;
271 	uint32_t length = 0;
272 };
273 
274 enum Types
275 {
276 	TypeNone,
277 	TypeType,
278 	TypeVariable,
279 	TypeConstant,
280 	TypeFunction,
281 	TypeFunctionPrototype,
282 	TypeBlock,
283 	TypeExtension,
284 	TypeExpression,
285 	TypeConstantOp,
286 	TypeCombinedImageSampler,
287 	TypeAccessChain,
288 	TypeUndef,
289 	TypeString,
290 	TypeCount
291 };
292 
293 template <Types type>
294 class TypedID;
295 
296 template <>
297 class TypedID<TypeNone>
298 {
299 public:
300 	TypedID() = default;
TypedID(uint32_t id_)301 	TypedID(uint32_t id_)
302 	    : id(id_)
303 	{
304 	}
305 
306 	template <Types U>
TypedID(const TypedID<U> & other)307 	TypedID(const TypedID<U> &other)
308 	{
309 		*this = other;
310 	}
311 
312 	template <Types U>
operator =(const TypedID<U> & other)313 	TypedID &operator=(const TypedID<U> &other)
314 	{
315 		id = uint32_t(other);
316 		return *this;
317 	}
318 
319 	// Implicit conversion to u32 is desired here.
320 	// As long as we block implicit conversion between TypedID<A> and TypedID<B> we're good.
operator uint32_t() const321 	operator uint32_t() const
322 	{
323 		return id;
324 	}
325 
326 	template <Types U>
operator TypedID<U>() const327 	operator TypedID<U>() const
328 	{
329 		return TypedID<U>(*this);
330 	}
331 
operator ==(const TypedID & other) const332 	bool operator==(const TypedID &other) const
333 	{
334 		return id == other.id;
335 	}
336 
operator !=(const TypedID & other) const337 	bool operator!=(const TypedID &other) const
338 	{
339 		return id != other.id;
340 	}
341 
342 	template <Types type>
operator ==(const TypedID<type> & other) const343 	bool operator==(const TypedID<type> &other) const
344 	{
345 		return id == uint32_t(other);
346 	}
347 
348 	template <Types type>
operator !=(const TypedID<type> & other) const349 	bool operator!=(const TypedID<type> &other) const
350 	{
351 		return id != uint32_t(other);
352 	}
353 
354 private:
355 	uint32_t id = 0;
356 };
357 
358 template <Types type>
359 class TypedID
360 {
361 public:
362 	TypedID() = default;
TypedID(uint32_t id_)363 	TypedID(uint32_t id_)
364 	    : id(id_)
365 	{
366 	}
367 
TypedID(const TypedID<TypeNone> & other)368 	explicit TypedID(const TypedID<TypeNone> &other)
369 	    : id(uint32_t(other))
370 	{
371 	}
372 
operator uint32_t() const373 	operator uint32_t() const
374 	{
375 		return id;
376 	}
377 
operator ==(const TypedID & other) const378 	bool operator==(const TypedID &other) const
379 	{
380 		return id == other.id;
381 	}
382 
operator !=(const TypedID & other) const383 	bool operator!=(const TypedID &other) const
384 	{
385 		return id != other.id;
386 	}
387 
operator ==(const TypedID<TypeNone> & other) const388 	bool operator==(const TypedID<TypeNone> &other) const
389 	{
390 		return id == uint32_t(other);
391 	}
392 
operator !=(const TypedID<TypeNone> & other) const393 	bool operator!=(const TypedID<TypeNone> &other) const
394 	{
395 		return id != uint32_t(other);
396 	}
397 
398 private:
399 	uint32_t id = 0;
400 };
401 
402 using VariableID = TypedID<TypeVariable>;
403 using TypeID = TypedID<TypeType>;
404 using ConstantID = TypedID<TypeConstant>;
405 using FunctionID = TypedID<TypeFunction>;
406 using BlockID = TypedID<TypeBlock>;
407 using ID = TypedID<TypeNone>;
408 
409 // Helper for Variant interface.
410 struct IVariant
411 {
412 	virtual ~IVariant() = default;
413 	virtual IVariant *clone(ObjectPoolBase *pool) = 0;
414 	ID self = 0;
415 };
416 
417 #define SPIRV_CROSS_DECLARE_CLONE(T)                                \
418 	IVariant *clone(ObjectPoolBase *pool) override                  \
419 	{                                                               \
420 		return static_cast<ObjectPool<T> *>(pool)->allocate(*this); \
421 	}
422 
423 struct SPIRUndef : IVariant
424 {
425 	enum
426 	{
427 		type = TypeUndef
428 	};
429 
SPIRUndefSPIRV_CROSS_NAMESPACE::SPIRUndef430 	explicit SPIRUndef(TypeID basetype_)
431 	    : basetype(basetype_)
432 	{
433 	}
434 	TypeID basetype;
435 
436 	SPIRV_CROSS_DECLARE_CLONE(SPIRUndef)
437 };
438 
439 struct SPIRString : IVariant
440 {
441 	enum
442 	{
443 		type = TypeString
444 	};
445 
SPIRStringSPIRV_CROSS_NAMESPACE::SPIRString446 	explicit SPIRString(std::string str_)
447 	    : str(std::move(str_))
448 	{
449 	}
450 
451 	std::string str;
452 
453 	SPIRV_CROSS_DECLARE_CLONE(SPIRString)
454 };
455 
456 // This type is only used by backends which need to access the combined image and sampler IDs separately after
457 // the OpSampledImage opcode.
458 struct SPIRCombinedImageSampler : IVariant
459 {
460 	enum
461 	{
462 		type = TypeCombinedImageSampler
463 	};
SPIRCombinedImageSamplerSPIRV_CROSS_NAMESPACE::SPIRCombinedImageSampler464 	SPIRCombinedImageSampler(TypeID type_, VariableID image_, VariableID sampler_)
465 	    : combined_type(type_)
466 	    , image(image_)
467 	    , sampler(sampler_)
468 	{
469 	}
470 	TypeID combined_type;
471 	VariableID image;
472 	VariableID sampler;
473 
474 	SPIRV_CROSS_DECLARE_CLONE(SPIRCombinedImageSampler)
475 };
476 
477 struct SPIRConstantOp : IVariant
478 {
479 	enum
480 	{
481 		type = TypeConstantOp
482 	};
483 
SPIRConstantOpSPIRV_CROSS_NAMESPACE::SPIRConstantOp484 	SPIRConstantOp(TypeID result_type, spv::Op op, const uint32_t *args, uint32_t length)
485 	    : opcode(op)
486 	    , basetype(result_type)
487 	{
488 		arguments.reserve(length);
489 		for (uint32_t i = 0; i < length; i++)
490 			arguments.push_back(args[i]);
491 	}
492 
493 	spv::Op opcode;
494 	SmallVector<uint32_t> arguments;
495 	TypeID basetype;
496 
497 	SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp)
498 };
499 
500 struct SPIRType : IVariant
501 {
502 	enum
503 	{
504 		type = TypeType
505 	};
506 
507 	enum BaseType
508 	{
509 		Unknown,
510 		Void,
511 		Boolean,
512 		SByte,
513 		UByte,
514 		Short,
515 		UShort,
516 		Int,
517 		UInt,
518 		Int64,
519 		UInt64,
520 		AtomicCounter,
521 		Half,
522 		Float,
523 		Double,
524 		Struct,
525 		Image,
526 		SampledImage,
527 		Sampler,
528 		AccelerationStructureNV,
529 
530 		// Keep internal types at the end.
531 		ControlPointArray,
532 		Char
533 	};
534 
535 	// Scalar/vector/matrix support.
536 	BaseType basetype = Unknown;
537 	uint32_t width = 0;
538 	uint32_t vecsize = 1;
539 	uint32_t columns = 1;
540 
541 	// Arrays, support array of arrays by having a vector of array sizes.
542 	SmallVector<uint32_t> array;
543 
544 	// Array elements can be either specialization constants or specialization ops.
545 	// This array determines how to interpret the array size.
546 	// If an element is true, the element is a literal,
547 	// otherwise, it's an expression, which must be resolved on demand.
548 	// The actual size is not really known until runtime.
549 	SmallVector<bool> array_size_literal;
550 
551 	// Pointers
552 	// Keep track of how many pointer layers we have.
553 	uint32_t pointer_depth = 0;
554 	bool pointer = false;
555 
556 	spv::StorageClass storage = spv::StorageClassGeneric;
557 
558 	SmallVector<TypeID> member_types;
559 
560 	struct ImageType
561 	{
562 		TypeID type;
563 		spv::Dim dim;
564 		bool depth;
565 		bool arrayed;
566 		bool ms;
567 		uint32_t sampled;
568 		spv::ImageFormat format;
569 		spv::AccessQualifier access;
570 	} image;
571 
572 	// Structs can be declared multiple times if they are used as part of interface blocks.
573 	// We want to detect this so that we only emit the struct definition once.
574 	// Since we cannot rely on OpName to be equal, we need to figure out aliases.
575 	TypeID type_alias = 0;
576 
577 	// Denotes the type which this type is based on.
578 	// Allows the backend to traverse how a complex type is built up during access chains.
579 	TypeID parent_type = 0;
580 
581 	// Used in backends to avoid emitting members with conflicting names.
582 	std::unordered_set<std::string> member_name_cache;
583 
584 	SPIRV_CROSS_DECLARE_CLONE(SPIRType)
585 };
586 
587 struct SPIRExtension : IVariant
588 {
589 	enum
590 	{
591 		type = TypeExtension
592 	};
593 
594 	enum Extension
595 	{
596 		Unsupported,
597 		GLSL,
598 		SPV_debug_info,
599 		SPV_AMD_shader_ballot,
600 		SPV_AMD_shader_explicit_vertex_parameter,
601 		SPV_AMD_shader_trinary_minmax,
602 		SPV_AMD_gcn_shader
603 	};
604 
SPIRExtensionSPIRV_CROSS_NAMESPACE::SPIRExtension605 	explicit SPIRExtension(Extension ext_)
606 	    : ext(ext_)
607 	{
608 	}
609 
610 	Extension ext;
611 	SPIRV_CROSS_DECLARE_CLONE(SPIRExtension)
612 };
613 
614 // SPIREntryPoint is not a variant since its IDs are used to decorate OpFunction,
615 // so in order to avoid conflicts, we can't stick them in the ids array.
616 struct SPIREntryPoint
617 {
SPIREntryPointSPIRV_CROSS_NAMESPACE::SPIREntryPoint618 	SPIREntryPoint(FunctionID self_, spv::ExecutionModel execution_model, const std::string &entry_name)
619 	    : self(self_)
620 	    , name(entry_name)
621 	    , orig_name(entry_name)
622 	    , model(execution_model)
623 	{
624 	}
625 	SPIREntryPoint() = default;
626 
627 	FunctionID self = 0;
628 	std::string name;
629 	std::string orig_name;
630 	SmallVector<VariableID> interface_variables;
631 
632 	Bitset flags;
633 	struct
634 	{
635 		uint32_t x = 0, y = 0, z = 0;
636 		uint32_t constant = 0; // Workgroup size can be expressed as a constant/spec-constant instead.
637 	} workgroup_size;
638 	uint32_t invocations = 0;
639 	uint32_t output_vertices = 0;
640 	spv::ExecutionModel model = spv::ExecutionModelMax;
641 };
642 
643 struct SPIRExpression : IVariant
644 {
645 	enum
646 	{
647 		type = TypeExpression
648 	};
649 
650 	// Only created by the backend target to avoid creating tons of temporaries.
SPIRExpressionSPIRV_CROSS_NAMESPACE::SPIRExpression651 	SPIRExpression(std::string expr, TypeID expression_type_, bool immutable_)
652 	    : expression(move(expr))
653 	    , expression_type(expression_type_)
654 	    , immutable(immutable_)
655 	{
656 	}
657 
658 	// If non-zero, prepend expression with to_expression(base_expression).
659 	// Used in amortizing multiple calls to to_expression()
660 	// where in certain cases that would quickly force a temporary when not needed.
661 	ID base_expression = 0;
662 
663 	std::string expression;
664 	TypeID expression_type = 0;
665 
666 	// If this expression is a forwarded load,
667 	// allow us to reference the original variable.
668 	ID loaded_from = 0;
669 
670 	// If this expression will never change, we can avoid lots of temporaries
671 	// in high level source.
672 	// An expression being immutable can be speculative,
673 	// it is assumed that this is true almost always.
674 	bool immutable = false;
675 
676 	// Before use, this expression must be transposed.
677 	// This is needed for targets which don't support row_major layouts.
678 	bool need_transpose = false;
679 
680 	// Whether or not this is an access chain expression.
681 	bool access_chain = false;
682 
683 	// A list of expressions which this expression depends on.
684 	SmallVector<ID> expression_dependencies;
685 
686 	// By reading this expression, we implicitly read these expressions as well.
687 	// Used by access chain Store and Load since we read multiple expressions in this case.
688 	SmallVector<ID> implied_read_expressions;
689 
690 	SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
691 };
692 
693 struct SPIRFunctionPrototype : IVariant
694 {
695 	enum
696 	{
697 		type = TypeFunctionPrototype
698 	};
699 
SPIRFunctionPrototypeSPIRV_CROSS_NAMESPACE::SPIRFunctionPrototype700 	explicit SPIRFunctionPrototype(TypeID return_type_)
701 	    : return_type(return_type_)
702 	{
703 	}
704 
705 	TypeID return_type;
706 	SmallVector<uint32_t> parameter_types;
707 
708 	SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype)
709 };
710 
711 struct SPIRBlock : IVariant
712 {
713 	enum
714 	{
715 		type = TypeBlock
716 	};
717 
718 	enum Terminator
719 	{
720 		Unknown,
721 		Direct, // Emit next block directly without a particular condition.
722 
723 		Select, // Block ends with an if/else block.
724 		MultiSelect, // Block ends with switch statement.
725 
726 		Return, // Block ends with return.
727 		Unreachable, // Noop
728 		Kill // Discard
729 	};
730 
731 	enum Merge
732 	{
733 		MergeNone,
734 		MergeLoop,
735 		MergeSelection
736 	};
737 
738 	enum Hints
739 	{
740 		HintNone,
741 		HintUnroll,
742 		HintDontUnroll,
743 		HintFlatten,
744 		HintDontFlatten
745 	};
746 
747 	enum Method
748 	{
749 		MergeToSelectForLoop,
750 		MergeToDirectForLoop,
751 		MergeToSelectContinueForLoop
752 	};
753 
754 	enum ContinueBlockType
755 	{
756 		ContinueNone,
757 
758 		// Continue block is branchless and has at least one instruction.
759 		ForLoop,
760 
761 		// Noop continue block.
762 		WhileLoop,
763 
764 		// Continue block is conditional.
765 		DoWhileLoop,
766 
767 		// Highly unlikely that anything will use this,
768 		// since it is really awkward/impossible to express in GLSL.
769 		ComplexLoop
770 	};
771 
772 	enum
773 	{
774 		NoDominator = 0xffffffffu
775 	};
776 
777 	Terminator terminator = Unknown;
778 	Merge merge = MergeNone;
779 	Hints hint = HintNone;
780 	BlockID next_block = 0;
781 	BlockID merge_block = 0;
782 	BlockID continue_block = 0;
783 
784 	ID return_value = 0; // If 0, return nothing (void).
785 	ID condition = 0;
786 	BlockID true_block = 0;
787 	BlockID false_block = 0;
788 	BlockID default_block = 0;
789 
790 	SmallVector<Instruction> ops;
791 
792 	struct Phi
793 	{
794 		ID local_variable; // flush local variable ...
795 		BlockID parent; // If we're in from_block and want to branch into this block ...
796 		VariableID function_variable; // to this function-global "phi" variable first.
797 	};
798 
799 	// Before entering this block flush out local variables to magical "phi" variables.
800 	SmallVector<Phi> phi_variables;
801 
802 	// Declare these temporaries before beginning the block.
803 	// Used for handling complex continue blocks which have side effects.
804 	SmallVector<std::pair<TypeID, ID>> declare_temporary;
805 
806 	// Declare these temporaries, but only conditionally if this block turns out to be
807 	// a complex loop header.
808 	SmallVector<std::pair<TypeID, ID>> potential_declare_temporary;
809 
810 	struct Case
811 	{
812 		uint32_t value;
813 		BlockID block;
814 	};
815 	SmallVector<Case> cases;
816 
817 	// If we have tried to optimize code for this block but failed,
818 	// keep track of this.
819 	bool disable_block_optimization = false;
820 
821 	// If the continue block is complex, fallback to "dumb" for loops.
822 	bool complex_continue = false;
823 
824 	// Do we need a ladder variable to defer breaking out of a loop construct after a switch block?
825 	bool need_ladder_break = false;
826 
827 	// If marked, we have explicitly handled Phi from this block, so skip any flushes related to that on a branch.
828 	// Used to handle an edge case with switch and case-label fallthrough where fall-through writes to Phi.
829 	BlockID ignore_phi_from_block = 0;
830 
831 	// The dominating block which this block might be within.
832 	// Used in continue; blocks to determine if we really need to write continue.
833 	BlockID loop_dominator = 0;
834 
835 	// All access to these variables are dominated by this block,
836 	// so before branching anywhere we need to make sure that we declare these variables.
837 	SmallVector<VariableID> dominated_variables;
838 
839 	// These are variables which should be declared in a for loop header, if we
840 	// fail to use a classic for-loop,
841 	// we remove these variables, and fall back to regular variables outside the loop.
842 	SmallVector<VariableID> loop_variables;
843 
844 	// Some expressions are control-flow dependent, i.e. any instruction which relies on derivatives or
845 	// sub-group-like operations.
846 	// Make sure that we only use these expressions in the original block.
847 	SmallVector<ID> invalidate_expressions;
848 
849 	SPIRV_CROSS_DECLARE_CLONE(SPIRBlock)
850 };
851 
852 struct SPIRFunction : IVariant
853 {
854 	enum
855 	{
856 		type = TypeFunction
857 	};
858 
SPIRFunctionSPIRV_CROSS_NAMESPACE::SPIRFunction859 	SPIRFunction(TypeID return_type_, TypeID function_type_)
860 	    : return_type(return_type_)
861 	    , function_type(function_type_)
862 	{
863 	}
864 
865 	struct Parameter
866 	{
867 		TypeID type;
868 		ID id;
869 		uint32_t read_count;
870 		uint32_t write_count;
871 
872 		// Set to true if this parameter aliases a global variable,
873 		// used mostly in Metal where global variables
874 		// have to be passed down to functions as regular arguments.
875 		// However, for this kind of variable, we should not care about
876 		// read and write counts as access to the function arguments
877 		// is not local to the function in question.
878 		bool alias_global_variable;
879 	};
880 
881 	// When calling a function, and we're remapping separate image samplers,
882 	// resolve these arguments into combined image samplers and pass them
883 	// as additional arguments in this order.
884 	// It gets more complicated as functions can pull in their own globals
885 	// and combine them with parameters,
886 	// so we need to distinguish if something is local parameter index
887 	// or a global ID.
888 	struct CombinedImageSamplerParameter
889 	{
890 		VariableID id;
891 		VariableID image_id;
892 		VariableID sampler_id;
893 		bool global_image;
894 		bool global_sampler;
895 		bool depth;
896 	};
897 
898 	TypeID return_type;
899 	TypeID function_type;
900 	SmallVector<Parameter> arguments;
901 
902 	// Can be used by backends to add magic arguments.
903 	// Currently used by combined image/sampler implementation.
904 
905 	SmallVector<Parameter> shadow_arguments;
906 	SmallVector<VariableID> local_variables;
907 	BlockID entry_block = 0;
908 	SmallVector<BlockID> blocks;
909 	SmallVector<CombinedImageSamplerParameter> combined_parameters;
910 
911 	struct EntryLine
912 	{
913 		uint32_t file_id = 0;
914 		uint32_t line_literal = 0;
915 	};
916 	EntryLine entry_line;
917 
add_local_variableSPIRV_CROSS_NAMESPACE::SPIRFunction918 	void add_local_variable(VariableID id)
919 	{
920 		local_variables.push_back(id);
921 	}
922 
add_parameterSPIRV_CROSS_NAMESPACE::SPIRFunction923 	void add_parameter(TypeID parameter_type, ID id, bool alias_global_variable = false)
924 	{
925 		// Arguments are read-only until proven otherwise.
926 		arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable });
927 	}
928 
929 	// Hooks to be run when the function returns.
930 	// Mostly used for lowering internal data structures onto flattened structures.
931 	// Need to defer this, because they might rely on things which change during compilation.
932 	// Intentionally not a small vector, this one is rare, and std::function can be large.
933 	Vector<std::function<void()>> fixup_hooks_out;
934 
935 	// Hooks to be run when the function begins.
936 	// Mostly used for populating internal data structures from flattened structures.
937 	// Need to defer this, because they might rely on things which change during compilation.
938 	// Intentionally not a small vector, this one is rare, and std::function can be large.
939 	Vector<std::function<void()>> fixup_hooks_in;
940 
941 	bool active = false;
942 	bool flush_undeclared = true;
943 	bool do_combined_parameters = true;
944 
945 	SPIRV_CROSS_DECLARE_CLONE(SPIRFunction)
946 };
947 
948 struct SPIRAccessChain : IVariant
949 {
950 	enum
951 	{
952 		type = TypeAccessChain
953 	};
954 
SPIRAccessChainSPIRV_CROSS_NAMESPACE::SPIRAccessChain955 	SPIRAccessChain(TypeID basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_,
956 	                int32_t static_index_)
957 	    : basetype(basetype_)
958 	    , storage(storage_)
959 	    , base(std::move(base_))
960 	    , dynamic_index(std::move(dynamic_index_))
961 	    , static_index(static_index_)
962 	{
963 	}
964 
965 	// The access chain represents an offset into a buffer.
966 	// Some backends need more complicated handling of access chains to be able to use buffers, like HLSL
967 	// which has no usable buffer type ala GLSL SSBOs.
968 	// StructuredBuffer is too limited, so our only option is to deal with ByteAddressBuffer which works with raw addresses.
969 
970 	TypeID basetype;
971 	spv::StorageClass storage;
972 	std::string base;
973 	std::string dynamic_index;
974 	int32_t static_index;
975 
976 	VariableID loaded_from = 0;
977 	uint32_t matrix_stride = 0;
978 	bool row_major_matrix = false;
979 	bool immutable = false;
980 
981 	// By reading this expression, we implicitly read these expressions as well.
982 	// Used by access chain Store and Load since we read multiple expressions in this case.
983 	SmallVector<ID> implied_read_expressions;
984 
985 	SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain)
986 };
987 
988 struct SPIRVariable : IVariant
989 {
990 	enum
991 	{
992 		type = TypeVariable
993 	};
994 
995 	SPIRVariable() = default;
SPIRVariableSPIRV_CROSS_NAMESPACE::SPIRVariable996 	SPIRVariable(TypeID basetype_, spv::StorageClass storage_, ID initializer_ = 0, VariableID basevariable_ = 0)
997 	    : basetype(basetype_)
998 	    , storage(storage_)
999 	    , initializer(initializer_)
1000 	    , basevariable(basevariable_)
1001 	{
1002 	}
1003 
1004 	TypeID basetype = 0;
1005 	spv::StorageClass storage = spv::StorageClassGeneric;
1006 	uint32_t decoration = 0;
1007 	ID initializer = 0;
1008 	VariableID basevariable = 0;
1009 
1010 	SmallVector<uint32_t> dereference_chain;
1011 	bool compat_builtin = false;
1012 
1013 	// If a variable is shadowed, we only statically assign to it
1014 	// and never actually emit a statement for it.
1015 	// When we read the variable as an expression, just forward
1016 	// shadowed_id as the expression.
1017 	bool statically_assigned = false;
1018 	ID static_expression = 0;
1019 
1020 	// Temporaries which can remain forwarded as long as this variable is not modified.
1021 	SmallVector<ID> dependees;
1022 	bool forwardable = true;
1023 
1024 	bool deferred_declaration = false;
1025 	bool phi_variable = false;
1026 
1027 	// Used to deal with Phi variable flushes. See flush_phi().
1028 	bool allocate_temporary_copy = false;
1029 
1030 	bool remapped_variable = false;
1031 	uint32_t remapped_components = 0;
1032 
1033 	// The block which dominates all access to this variable.
1034 	BlockID dominator = 0;
1035 	// If true, this variable is a loop variable, when accessing the variable
1036 	// outside a loop,
1037 	// we should statically forward it.
1038 	bool loop_variable = false;
1039 	// Set to true while we're inside the for loop.
1040 	bool loop_variable_enable = false;
1041 
1042 	SPIRFunction::Parameter *parameter = nullptr;
1043 
1044 	SPIRV_CROSS_DECLARE_CLONE(SPIRVariable)
1045 };
1046 
1047 struct SPIRConstant : IVariant
1048 {
1049 	enum
1050 	{
1051 		type = TypeConstant
1052 	};
1053 
1054 	union Constant
1055 	{
1056 		uint32_t u32;
1057 		int32_t i32;
1058 		float f32;
1059 
1060 		uint64_t u64;
1061 		int64_t i64;
1062 		double f64;
1063 	};
1064 
1065 	struct ConstantVector
1066 	{
1067 		Constant r[4];
1068 		// If != 0, this element is a specialization constant, and we should keep track of it as such.
1069 		ID id[4];
1070 		uint32_t vecsize = 1;
1071 
ConstantVectorSPIRV_CROSS_NAMESPACE::SPIRConstant::ConstantVector1072 		ConstantVector()
1073 		{
1074 			memset(r, 0, sizeof(r));
1075 		}
1076 	};
1077 
1078 	struct ConstantMatrix
1079 	{
1080 		ConstantVector c[4];
1081 		// If != 0, this column is a specialization constant, and we should keep track of it as such.
1082 		ID id[4];
1083 		uint32_t columns = 1;
1084 	};
1085 
f16_to_f32SPIRV_CROSS_NAMESPACE::SPIRConstant1086 	static inline float f16_to_f32(uint16_t u16_value)
1087 	{
1088 		// Based on the GLM implementation.
1089 		int s = (u16_value >> 15) & 0x1;
1090 		int e = (u16_value >> 10) & 0x1f;
1091 		int m = (u16_value >> 0) & 0x3ff;
1092 
1093 		union
1094 		{
1095 			float f32;
1096 			uint32_t u32;
1097 		} u;
1098 
1099 		if (e == 0)
1100 		{
1101 			if (m == 0)
1102 			{
1103 				u.u32 = uint32_t(s) << 31;
1104 				return u.f32;
1105 			}
1106 			else
1107 			{
1108 				while ((m & 0x400) == 0)
1109 				{
1110 					m <<= 1;
1111 					e--;
1112 				}
1113 
1114 				e++;
1115 				m &= ~0x400;
1116 			}
1117 		}
1118 		else if (e == 31)
1119 		{
1120 			if (m == 0)
1121 			{
1122 				u.u32 = (uint32_t(s) << 31) | 0x7f800000u;
1123 				return u.f32;
1124 			}
1125 			else
1126 			{
1127 				u.u32 = (uint32_t(s) << 31) | 0x7f800000u | (m << 13);
1128 				return u.f32;
1129 			}
1130 		}
1131 
1132 		e += 127 - 15;
1133 		m <<= 13;
1134 		u.u32 = (uint32_t(s) << 31) | (e << 23) | m;
1135 		return u.f32;
1136 	}
1137 
specialization_constant_idSPIRV_CROSS_NAMESPACE::SPIRConstant1138 	inline uint32_t specialization_constant_id(uint32_t col, uint32_t row) const
1139 	{
1140 		return m.c[col].id[row];
1141 	}
1142 
specialization_constant_idSPIRV_CROSS_NAMESPACE::SPIRConstant1143 	inline uint32_t specialization_constant_id(uint32_t col) const
1144 	{
1145 		return m.id[col];
1146 	}
1147 
scalarSPIRV_CROSS_NAMESPACE::SPIRConstant1148 	inline uint32_t scalar(uint32_t col = 0, uint32_t row = 0) const
1149 	{
1150 		return m.c[col].r[row].u32;
1151 	}
1152 
scalar_i16SPIRV_CROSS_NAMESPACE::SPIRConstant1153 	inline int16_t scalar_i16(uint32_t col = 0, uint32_t row = 0) const
1154 	{
1155 		return int16_t(m.c[col].r[row].u32 & 0xffffu);
1156 	}
1157 
scalar_u16SPIRV_CROSS_NAMESPACE::SPIRConstant1158 	inline uint16_t scalar_u16(uint32_t col = 0, uint32_t row = 0) const
1159 	{
1160 		return uint16_t(m.c[col].r[row].u32 & 0xffffu);
1161 	}
1162 
scalar_i8SPIRV_CROSS_NAMESPACE::SPIRConstant1163 	inline int8_t scalar_i8(uint32_t col = 0, uint32_t row = 0) const
1164 	{
1165 		return int8_t(m.c[col].r[row].u32 & 0xffu);
1166 	}
1167 
scalar_u8SPIRV_CROSS_NAMESPACE::SPIRConstant1168 	inline uint8_t scalar_u8(uint32_t col = 0, uint32_t row = 0) const
1169 	{
1170 		return uint8_t(m.c[col].r[row].u32 & 0xffu);
1171 	}
1172 
scalar_f16SPIRV_CROSS_NAMESPACE::SPIRConstant1173 	inline float scalar_f16(uint32_t col = 0, uint32_t row = 0) const
1174 	{
1175 		return f16_to_f32(scalar_u16(col, row));
1176 	}
1177 
scalar_f32SPIRV_CROSS_NAMESPACE::SPIRConstant1178 	inline float scalar_f32(uint32_t col = 0, uint32_t row = 0) const
1179 	{
1180 		return m.c[col].r[row].f32;
1181 	}
1182 
scalar_i32SPIRV_CROSS_NAMESPACE::SPIRConstant1183 	inline int32_t scalar_i32(uint32_t col = 0, uint32_t row = 0) const
1184 	{
1185 		return m.c[col].r[row].i32;
1186 	}
1187 
scalar_f64SPIRV_CROSS_NAMESPACE::SPIRConstant1188 	inline double scalar_f64(uint32_t col = 0, uint32_t row = 0) const
1189 	{
1190 		return m.c[col].r[row].f64;
1191 	}
1192 
scalar_i64SPIRV_CROSS_NAMESPACE::SPIRConstant1193 	inline int64_t scalar_i64(uint32_t col = 0, uint32_t row = 0) const
1194 	{
1195 		return m.c[col].r[row].i64;
1196 	}
1197 
scalar_u64SPIRV_CROSS_NAMESPACE::SPIRConstant1198 	inline uint64_t scalar_u64(uint32_t col = 0, uint32_t row = 0) const
1199 	{
1200 		return m.c[col].r[row].u64;
1201 	}
1202 
vectorSPIRV_CROSS_NAMESPACE::SPIRConstant1203 	inline const ConstantVector &vector() const
1204 	{
1205 		return m.c[0];
1206 	}
1207 
vector_sizeSPIRV_CROSS_NAMESPACE::SPIRConstant1208 	inline uint32_t vector_size() const
1209 	{
1210 		return m.c[0].vecsize;
1211 	}
1212 
columnsSPIRV_CROSS_NAMESPACE::SPIRConstant1213 	inline uint32_t columns() const
1214 	{
1215 		return m.columns;
1216 	}
1217 
make_nullSPIRV_CROSS_NAMESPACE::SPIRConstant1218 	inline void make_null(const SPIRType &constant_type_)
1219 	{
1220 		m = {};
1221 		m.columns = constant_type_.columns;
1222 		for (auto &c : m.c)
1223 			c.vecsize = constant_type_.vecsize;
1224 	}
1225 
constant_is_nullSPIRV_CROSS_NAMESPACE::SPIRConstant1226 	inline bool constant_is_null() const
1227 	{
1228 		if (specialization)
1229 			return false;
1230 		if (!subconstants.empty())
1231 			return false;
1232 
1233 		for (uint32_t col = 0; col < columns(); col++)
1234 			for (uint32_t row = 0; row < vector_size(); row++)
1235 				if (scalar_u64(col, row) != 0)
1236 					return false;
1237 
1238 		return true;
1239 	}
1240 
SPIRConstantSPIRV_CROSS_NAMESPACE::SPIRConstant1241 	explicit SPIRConstant(uint32_t constant_type_)
1242 	    : constant_type(constant_type_)
1243 	{
1244 	}
1245 
1246 	SPIRConstant() = default;
1247 
SPIRConstantSPIRV_CROSS_NAMESPACE::SPIRConstant1248 	SPIRConstant(TypeID constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized)
1249 	    : constant_type(constant_type_)
1250 	    , specialization(specialized)
1251 	{
1252 		subconstants.reserve(num_elements);
1253 		for (uint32_t i = 0; i < num_elements; i++)
1254 			subconstants.push_back(elements[i]);
1255 		specialization = specialized;
1256 	}
1257 
1258 	// Construct scalar (32-bit).
SPIRConstantSPIRV_CROSS_NAMESPACE::SPIRConstant1259 	SPIRConstant(TypeID constant_type_, uint32_t v0, bool specialized)
1260 	    : constant_type(constant_type_)
1261 	    , specialization(specialized)
1262 	{
1263 		m.c[0].r[0].u32 = v0;
1264 		m.c[0].vecsize = 1;
1265 		m.columns = 1;
1266 	}
1267 
1268 	// Construct scalar (64-bit).
SPIRConstantSPIRV_CROSS_NAMESPACE::SPIRConstant1269 	SPIRConstant(TypeID constant_type_, uint64_t v0, bool specialized)
1270 	    : constant_type(constant_type_)
1271 	    , specialization(specialized)
1272 	{
1273 		m.c[0].r[0].u64 = v0;
1274 		m.c[0].vecsize = 1;
1275 		m.columns = 1;
1276 	}
1277 
1278 	// Construct vectors and matrices.
SPIRConstantSPIRV_CROSS_NAMESPACE::SPIRConstant1279 	SPIRConstant(TypeID constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements,
1280 	             bool specialized)
1281 	    : constant_type(constant_type_)
1282 	    , specialization(specialized)
1283 	{
1284 		bool matrix = vector_elements[0]->m.c[0].vecsize > 1;
1285 
1286 		if (matrix)
1287 		{
1288 			m.columns = num_elements;
1289 
1290 			for (uint32_t i = 0; i < num_elements; i++)
1291 			{
1292 				m.c[i] = vector_elements[i]->m.c[0];
1293 				if (vector_elements[i]->specialization)
1294 					m.id[i] = vector_elements[i]->self;
1295 			}
1296 		}
1297 		else
1298 		{
1299 			m.c[0].vecsize = num_elements;
1300 			m.columns = 1;
1301 
1302 			for (uint32_t i = 0; i < num_elements; i++)
1303 			{
1304 				m.c[0].r[i] = vector_elements[i]->m.c[0].r[0];
1305 				if (vector_elements[i]->specialization)
1306 					m.c[0].id[i] = vector_elements[i]->self;
1307 			}
1308 		}
1309 	}
1310 
1311 	TypeID constant_type = 0;
1312 	ConstantMatrix m;
1313 
1314 	// If this constant is a specialization constant (i.e. created with OpSpecConstant*).
1315 	bool specialization = false;
1316 	// If this constant is used as an array length which creates specialization restrictions on some backends.
1317 	bool is_used_as_array_length = false;
1318 
1319 	// If true, this is a LUT, and should always be declared in the outer scope.
1320 	bool is_used_as_lut = false;
1321 
1322 	// For composites which are constant arrays, etc.
1323 	SmallVector<ConstantID> subconstants;
1324 
1325 	// Non-Vulkan GLSL, HLSL and sometimes MSL emits defines for each specialization constant,
1326 	// and uses them to initialize the constant. This allows the user
1327 	// to still be able to specialize the value by supplying corresponding
1328 	// preprocessor directives before compiling the shader.
1329 	std::string specialization_constant_macro_name;
1330 
1331 	SPIRV_CROSS_DECLARE_CLONE(SPIRConstant)
1332 };
1333 
1334 // Variants have a very specific allocation scheme.
1335 struct ObjectPoolGroup
1336 {
1337 	std::unique_ptr<ObjectPoolBase> pools[TypeCount];
1338 };
1339 
1340 class Variant
1341 {
1342 public:
Variant(ObjectPoolGroup * group_)1343 	explicit Variant(ObjectPoolGroup *group_)
1344 	    : group(group_)
1345 	{
1346 	}
1347 
~Variant()1348 	~Variant()
1349 	{
1350 		if (holder)
1351 			group->pools[type]->free_opaque(holder);
1352 	}
1353 
1354 	// Marking custom move constructor as noexcept is important.
Variant(Variant && other)1355 	Variant(Variant &&other) SPIRV_CROSS_NOEXCEPT
1356 	{
1357 		*this = std::move(other);
1358 	}
1359 
1360 	// We cannot copy from other variant without our own pool group.
1361 	// Have to explicitly copy.
1362 	Variant(const Variant &variant) = delete;
1363 
1364 	// Marking custom move constructor as noexcept is important.
operator =(Variant && other)1365 	Variant &operator=(Variant &&other) SPIRV_CROSS_NOEXCEPT
1366 	{
1367 		if (this != &other)
1368 		{
1369 			if (holder)
1370 				group->pools[type]->free_opaque(holder);
1371 			holder = other.holder;
1372 			group = other.group;
1373 			type = other.type;
1374 			allow_type_rewrite = other.allow_type_rewrite;
1375 
1376 			other.holder = nullptr;
1377 			other.type = TypeNone;
1378 		}
1379 		return *this;
1380 	}
1381 
1382 	// This copy/clone should only be called in the Compiler constructor.
1383 	// If this is called inside ::compile(), we invalidate any references we took higher in the stack.
1384 	// This should never happen.
operator =(const Variant & other)1385 	Variant &operator=(const Variant &other)
1386 	{
1387 //#define SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE
1388 #ifdef SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE
1389 		abort();
1390 #endif
1391 		if (this != &other)
1392 		{
1393 			if (holder)
1394 				group->pools[type]->free_opaque(holder);
1395 
1396 			if (other.holder)
1397 				holder = other.holder->clone(group->pools[other.type].get());
1398 			else
1399 				holder = nullptr;
1400 
1401 			type = other.type;
1402 			allow_type_rewrite = other.allow_type_rewrite;
1403 		}
1404 		return *this;
1405 	}
1406 
set(IVariant * val,Types new_type)1407 	void set(IVariant *val, Types new_type)
1408 	{
1409 		if (holder)
1410 			group->pools[type]->free_opaque(holder);
1411 		holder = nullptr;
1412 
1413 		if (!allow_type_rewrite && type != TypeNone && type != new_type)
1414 		{
1415 			if (val)
1416 				group->pools[new_type]->free_opaque(val);
1417 			SPIRV_CROSS_THROW("Overwriting a variant with new type.");
1418 		}
1419 
1420 		holder = val;
1421 		type = new_type;
1422 		allow_type_rewrite = false;
1423 	}
1424 
1425 	template <typename T, typename... Ts>
1426 	T *allocate_and_set(Types new_type, Ts &&... ts)
1427 	{
1428 		T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...);
1429 		set(val, new_type);
1430 		return val;
1431 	}
1432 
1433 	template <typename T>
get()1434 	T &get()
1435 	{
1436 		if (!holder)
1437 			SPIRV_CROSS_THROW("nullptr");
1438 		if (static_cast<Types>(T::type) != type)
1439 			SPIRV_CROSS_THROW("Bad cast");
1440 		return *static_cast<T *>(holder);
1441 	}
1442 
1443 	template <typename T>
get() const1444 	const T &get() const
1445 	{
1446 		if (!holder)
1447 			SPIRV_CROSS_THROW("nullptr");
1448 		if (static_cast<Types>(T::type) != type)
1449 			SPIRV_CROSS_THROW("Bad cast");
1450 		return *static_cast<const T *>(holder);
1451 	}
1452 
get_type() const1453 	Types get_type() const
1454 	{
1455 		return type;
1456 	}
1457 
get_id() const1458 	ID get_id() const
1459 	{
1460 		return holder ? holder->self : ID(0);
1461 	}
1462 
empty() const1463 	bool empty() const
1464 	{
1465 		return !holder;
1466 	}
1467 
reset()1468 	void reset()
1469 	{
1470 		if (holder)
1471 			group->pools[type]->free_opaque(holder);
1472 		holder = nullptr;
1473 		type = TypeNone;
1474 	}
1475 
set_allow_type_rewrite()1476 	void set_allow_type_rewrite()
1477 	{
1478 		allow_type_rewrite = true;
1479 	}
1480 
1481 private:
1482 	ObjectPoolGroup *group = nullptr;
1483 	IVariant *holder = nullptr;
1484 	Types type = TypeNone;
1485 	bool allow_type_rewrite = false;
1486 };
1487 
1488 template <typename T>
variant_get(Variant & var)1489 T &variant_get(Variant &var)
1490 {
1491 	return var.get<T>();
1492 }
1493 
1494 template <typename T>
variant_get(const Variant & var)1495 const T &variant_get(const Variant &var)
1496 {
1497 	return var.get<T>();
1498 }
1499 
1500 template <typename T, typename... P>
1501 T &variant_set(Variant &var, P &&... args)
1502 {
1503 	auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...);
1504 	return *ptr;
1505 }
1506 
1507 struct AccessChainMeta
1508 {
1509 	uint32_t storage_physical_type = 0;
1510 	bool need_transpose = false;
1511 	bool storage_is_packed = false;
1512 	bool storage_is_invariant = false;
1513 };
1514 
1515 enum ExtendedDecorations
1516 {
1517 	// Marks if a buffer block is re-packed, i.e. member declaration might be subject to PhysicalTypeID remapping and padding.
1518 	SPIRVCrossDecorationBufferBlockRepacked = 0,
1519 
1520 	// A type in a buffer block might be declared with a different physical type than the logical type.
1521 	// If this is not set, PhysicalTypeID == the SPIR-V type as declared.
1522 	SPIRVCrossDecorationPhysicalTypeID,
1523 
1524 	// Marks if the physical type is to be declared with tight packing rules, i.e. packed_floatN on MSL and friends.
1525 	// If this is set, PhysicalTypeID might also be set. It can be set to same as logical type if all we're doing
1526 	// is converting float3 to packed_float3 for example.
1527 	// If this is marked on a struct, it means the struct itself must use only Packed types for all its members.
1528 	SPIRVCrossDecorationPhysicalTypePacked,
1529 
1530 	// The padding in bytes before declaring this struct member.
1531 	// If used on a struct type, marks the target size of a struct.
1532 	SPIRVCrossDecorationPaddingTarget,
1533 
1534 	SPIRVCrossDecorationInterfaceMemberIndex,
1535 	SPIRVCrossDecorationInterfaceOrigID,
1536 	SPIRVCrossDecorationResourceIndexPrimary,
1537 	// Used for decorations like resource indices for samplers when part of combined image samplers.
1538 	// A variable might need to hold two resource indices in this case.
1539 	SPIRVCrossDecorationResourceIndexSecondary,
1540 	// Used for resource indices for multiplanar images when part of combined image samplers.
1541 	SPIRVCrossDecorationResourceIndexTertiary,
1542 	SPIRVCrossDecorationResourceIndexQuaternary,
1543 
1544 	// Marks a buffer block for using explicit offsets (GLSL/HLSL).
1545 	SPIRVCrossDecorationExplicitOffset,
1546 
1547 	// Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase().
1548 	// In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables.
1549 	SPIRVCrossDecorationBuiltInDispatchBase,
1550 
1551 	// Apply to a variable that is a function parameter; marks it as being a "dynamic"
1552 	// combined image-sampler. In MSL, this is used when a function parameter might hold
1553 	// either a regular combined image-sampler or one that has an attached sampler
1554 	// Y'CbCr conversion.
1555 	SPIRVCrossDecorationDynamicImageSampler,
1556 
1557 	SPIRVCrossDecorationCount
1558 };
1559 
1560 struct Meta
1561 {
1562 	struct Decoration
1563 	{
1564 		std::string alias;
1565 		std::string qualified_alias;
1566 		std::string hlsl_semantic;
1567 		Bitset decoration_flags;
1568 		spv::BuiltIn builtin_type = spv::BuiltInMax;
1569 		uint32_t location = 0;
1570 		uint32_t component = 0;
1571 		uint32_t set = 0;
1572 		uint32_t binding = 0;
1573 		uint32_t offset = 0;
1574 		uint32_t array_stride = 0;
1575 		uint32_t matrix_stride = 0;
1576 		uint32_t input_attachment = 0;
1577 		uint32_t spec_id = 0;
1578 		uint32_t index = 0;
1579 		spv::FPRoundingMode fp_rounding_mode = spv::FPRoundingModeMax;
1580 		bool builtin = false;
1581 
1582 		struct Extended
1583 		{
ExtendedSPIRV_CROSS_NAMESPACE::Meta::Decoration::Extended1584 			Extended()
1585 			{
1586 				// MSVC 2013 workaround to init like this.
1587 				for (auto &v : values)
1588 					v = 0;
1589 			}
1590 
1591 			Bitset flags;
1592 			uint32_t values[SPIRVCrossDecorationCount];
1593 		} extended;
1594 	};
1595 
1596 	Decoration decoration;
1597 
1598 	// Intentionally not a SmallVector. Decoration is large and somewhat rare.
1599 	Vector<Decoration> members;
1600 
1601 	std::unordered_map<uint32_t, uint32_t> decoration_word_offset;
1602 
1603 	// For SPV_GOOGLE_hlsl_functionality1.
1604 	bool hlsl_is_magic_counter_buffer = false;
1605 	// ID for the sibling counter buffer.
1606 	uint32_t hlsl_magic_counter_buffer = 0;
1607 };
1608 
1609 // A user callback that remaps the type of any variable.
1610 // var_name is the declared name of the variable.
1611 // name_of_type is the textual name of the type which will be used in the code unless written to by the callback.
1612 using VariableTypeRemapCallback =
1613     std::function<void(const SPIRType &type, const std::string &var_name, std::string &name_of_type)>;
1614 
1615 class Hasher
1616 {
1617 public:
u32(uint32_t value)1618 	inline void u32(uint32_t value)
1619 	{
1620 		h = (h * 0x100000001b3ull) ^ value;
1621 	}
1622 
get() const1623 	inline uint64_t get() const
1624 	{
1625 		return h;
1626 	}
1627 
1628 private:
1629 	uint64_t h = 0xcbf29ce484222325ull;
1630 };
1631 
type_is_floating_point(const SPIRType & type)1632 static inline bool type_is_floating_point(const SPIRType &type)
1633 {
1634 	return type.basetype == SPIRType::Half || type.basetype == SPIRType::Float || type.basetype == SPIRType::Double;
1635 }
1636 
type_is_integral(const SPIRType & type)1637 static inline bool type_is_integral(const SPIRType &type)
1638 {
1639 	return type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte || type.basetype == SPIRType::Short ||
1640 	       type.basetype == SPIRType::UShort || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
1641 	       type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64;
1642 }
1643 
to_signed_basetype(uint32_t width)1644 static inline SPIRType::BaseType to_signed_basetype(uint32_t width)
1645 {
1646 	switch (width)
1647 	{
1648 	case 8:
1649 		return SPIRType::SByte;
1650 	case 16:
1651 		return SPIRType::Short;
1652 	case 32:
1653 		return SPIRType::Int;
1654 	case 64:
1655 		return SPIRType::Int64;
1656 	default:
1657 		SPIRV_CROSS_THROW("Invalid bit width.");
1658 	}
1659 }
1660 
to_unsigned_basetype(uint32_t width)1661 static inline SPIRType::BaseType to_unsigned_basetype(uint32_t width)
1662 {
1663 	switch (width)
1664 	{
1665 	case 8:
1666 		return SPIRType::UByte;
1667 	case 16:
1668 		return SPIRType::UShort;
1669 	case 32:
1670 		return SPIRType::UInt;
1671 	case 64:
1672 		return SPIRType::UInt64;
1673 	default:
1674 		SPIRV_CROSS_THROW("Invalid bit width.");
1675 	}
1676 }
1677 
1678 // Returns true if an arithmetic operation does not change behavior depending on signedness.
opcode_is_sign_invariant(spv::Op opcode)1679 static inline bool opcode_is_sign_invariant(spv::Op opcode)
1680 {
1681 	switch (opcode)
1682 	{
1683 	case spv::OpIEqual:
1684 	case spv::OpINotEqual:
1685 	case spv::OpISub:
1686 	case spv::OpIAdd:
1687 	case spv::OpIMul:
1688 	case spv::OpShiftLeftLogical:
1689 	case spv::OpBitwiseOr:
1690 	case spv::OpBitwiseXor:
1691 	case spv::OpBitwiseAnd:
1692 		return true;
1693 
1694 	default:
1695 		return false;
1696 	}
1697 }
1698 } // namespace SPIRV_CROSS_NAMESPACE
1699 
1700 namespace std
1701 {
1702 template <SPIRV_CROSS_NAMESPACE::Types type>
1703 struct hash<SPIRV_CROSS_NAMESPACE::TypedID<type>>
1704 {
operator ()std::hash1705 	size_t operator()(const SPIRV_CROSS_NAMESPACE::TypedID<type> &value) const
1706 	{
1707 		return std::hash<uint32_t>()(value);
1708 	}
1709 };
1710 } // namespace std
1711 
1712 #endif
1713