2 * Copyright 2018-2021 Arm Limited
3 * SPDX-License-Identifier: Apache-2.0 OR MIT
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
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>.
24 #include "spirv_cross_parsed_ir.hpp"
31 namespace SPIRV_CROSS_NAMESPACE
35 // If we move ParsedIR, we need to make sure the pointer stays fixed since the child Variant objects consume a pointer to this group,
36 // so need an extra pointer here.
37 pool_group
.reset(new ObjectPoolGroup
);
39 pool_group
->pools
[TypeType
].reset(new ObjectPool
<SPIRType
>);
40 pool_group
->pools
[TypeVariable
].reset(new ObjectPool
<SPIRVariable
>);
41 pool_group
->pools
[TypeConstant
].reset(new ObjectPool
<SPIRConstant
>);
42 pool_group
->pools
[TypeFunction
].reset(new ObjectPool
<SPIRFunction
>);
43 pool_group
->pools
[TypeFunctionPrototype
].reset(new ObjectPool
<SPIRFunctionPrototype
>);
44 pool_group
->pools
[TypeBlock
].reset(new ObjectPool
<SPIRBlock
>);
45 pool_group
->pools
[TypeExtension
].reset(new ObjectPool
<SPIRExtension
>);
46 pool_group
->pools
[TypeExpression
].reset(new ObjectPool
<SPIRExpression
>);
47 pool_group
->pools
[TypeConstantOp
].reset(new ObjectPool
<SPIRConstantOp
>);
48 pool_group
->pools
[TypeCombinedImageSampler
].reset(new ObjectPool
<SPIRCombinedImageSampler
>);
49 pool_group
->pools
[TypeAccessChain
].reset(new ObjectPool
<SPIRAccessChain
>);
50 pool_group
->pools
[TypeUndef
].reset(new ObjectPool
<SPIRUndef
>);
51 pool_group
->pools
[TypeString
].reset(new ObjectPool
<SPIRString
>);
54 // Should have been default-implemented, but need this on MSVC 2013.
55 ParsedIR::ParsedIR(ParsedIR
&&other
) SPIRV_CROSS_NOEXCEPT
57 *this = std::move(other
);
60 ParsedIR
&ParsedIR::operator=(ParsedIR
&&other
) SPIRV_CROSS_NOEXCEPT
64 pool_group
= std::move(other
.pool_group
);
65 spirv
= std::move(other
.spirv
);
66 meta
= std::move(other
.meta
);
67 for (int i
= 0; i
< TypeCount
; i
++)
68 ids_for_type
[i
] = std::move(other
.ids_for_type
[i
]);
69 ids_for_constant_undef_or_type
= std::move(other
.ids_for_constant_undef_or_type
);
70 ids_for_constant_or_variable
= std::move(other
.ids_for_constant_or_variable
);
71 declared_capabilities
= std::move(other
.declared_capabilities
);
72 declared_extensions
= std::move(other
.declared_extensions
);
73 block_meta
= std::move(other
.block_meta
);
74 continue_block_to_loop_header
= std::move(other
.continue_block_to_loop_header
);
75 entry_points
= std::move(other
.entry_points
);
76 ids
= std::move(other
.ids
);
77 addressing_model
= other
.addressing_model
;
78 memory_model
= other
.memory_model
;
80 default_entry_point
= other
.default_entry_point
;
81 source
= other
.source
;
82 loop_iteration_depth_hard
= other
.loop_iteration_depth_hard
;
83 loop_iteration_depth_soft
= other
.loop_iteration_depth_soft
;
85 meta_needing_name_fixup
= std::move(other
.meta_needing_name_fixup
);
86 load_type_width
= std::move(other
.load_type_width
);
91 ParsedIR::ParsedIR(const ParsedIR
&other
)
97 ParsedIR
&ParsedIR::operator=(const ParsedIR
&other
)
103 for (int i
= 0; i
< TypeCount
; i
++)
104 ids_for_type
[i
] = other
.ids_for_type
[i
];
105 ids_for_constant_undef_or_type
= other
.ids_for_constant_undef_or_type
;
106 ids_for_constant_or_variable
= other
.ids_for_constant_or_variable
;
107 declared_capabilities
= other
.declared_capabilities
;
108 declared_extensions
= other
.declared_extensions
;
109 block_meta
= other
.block_meta
;
110 continue_block_to_loop_header
= other
.continue_block_to_loop_header
;
111 entry_points
= other
.entry_points
;
112 default_entry_point
= other
.default_entry_point
;
113 source
= other
.source
;
114 loop_iteration_depth_hard
= other
.loop_iteration_depth_hard
;
115 loop_iteration_depth_soft
= other
.loop_iteration_depth_soft
;
116 addressing_model
= other
.addressing_model
;
117 memory_model
= other
.memory_model
;
120 meta_needing_name_fixup
= other
.meta_needing_name_fixup
;
121 load_type_width
= other
.load_type_width
;
123 // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
124 // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
126 ids
.reserve(other
.ids
.size());
127 for (size_t i
= 0; i
< other
.ids
.size(); i
++)
129 ids
.emplace_back(pool_group
.get());
130 ids
.back() = other
.ids
[i
];
136 void ParsedIR::set_id_bounds(uint32_t bounds
)
139 while (ids
.size() < bounds
)
140 ids
.emplace_back(pool_group
.get());
142 block_meta
.resize(bounds
);
145 // Roll our own versions of these functions to avoid potential locale shenanigans.
146 static bool is_alpha(char c
)
148 return (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z');
151 static bool is_numeric(char c
)
153 return c
>= '0' && c
<= '9';
156 static bool is_alphanumeric(char c
)
158 return is_alpha(c
) || is_numeric(c
);
161 static bool is_valid_identifier(const string
&name
)
166 if (is_numeric(name
[0]))
170 if (!is_alphanumeric(c
) && c
!= '_')
173 bool saw_underscore
= false;
174 // Two underscores in a row is not a valid identifier either.
175 // Technically reserved, but it's easier to treat it as invalid.
178 bool is_underscore
= c
== '_';
179 if (is_underscore
&& saw_underscore
)
181 saw_underscore
= is_underscore
;
187 static bool is_reserved_prefix(const string
&name
)
189 // Generic reserved identifiers used by the implementation.
190 return name
.compare(0, 3, "gl_", 3) == 0 ||
191 // Ignore this case for now, might rewrite internal code to always use spv prefix.
192 //name.compare(0, 11, "SPIRV_Cross", 11) == 0 ||
193 name
.compare(0, 3, "spv", 3) == 0;
196 static bool is_reserved_identifier(const string
&name
, bool member
, bool allow_reserved_prefixes
)
198 if (!allow_reserved_prefixes
&& is_reserved_prefix(name
))
203 // Reserved member identifiers come in one form:
208 if (name
.compare(0, 2, "_m", 2) != 0)
212 while (index
< name
.size() && is_numeric(name
[index
]))
215 return index
== name
.size();
219 // Reserved non-member identifiers come in two forms:
220 // _[0-9]+$, used for temporaries which map directly to a SPIR-V ID.
221 // _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID.
225 if (name
[0] != '_' || !is_numeric(name
[1]))
229 while (index
< name
.size() && is_numeric(name
[index
]))
232 return index
== name
.size() || (index
< name
.size() && name
[index
] == '_');
236 bool ParsedIR::is_globally_reserved_identifier(std::string
&str
, bool allow_reserved_prefixes
)
238 return is_reserved_identifier(str
, false, allow_reserved_prefixes
);
241 uint32_t ParsedIR::get_spirv_version() const
246 static string
make_unreserved_identifier(const string
&name
)
248 if (is_reserved_prefix(name
))
249 return "_RESERVED_IDENTIFIER_FIXUP_" + name
;
251 return "_RESERVED_IDENTIFIER_FIXUP" + name
;
254 void ParsedIR::sanitize_underscores(std::string
&str
)
256 // Compact adjacent underscores to make it valid.
257 auto dst
= str
.begin();
259 bool saw_underscore
= false;
260 while (src
!= str
.end())
262 bool is_underscore
= *src
== '_';
263 if (saw_underscore
&& is_underscore
)
273 saw_underscore
= is_underscore
;
276 str
.erase(dst
, str
.end());
279 static string
ensure_valid_identifier(const string
&name
)
281 // Functions in glslangValidator are mangled with name(<mangled> stuff.
282 // Normally, we would never see '(' in any legal identifiers, so just strip them out.
283 auto str
= name
.substr(0, name
.find('('));
288 if (is_numeric(str
[0]))
292 if (!is_alphanumeric(c
) && c
!= '_')
295 ParsedIR::sanitize_underscores(str
);
299 const string
&ParsedIR::get_name(ID id
) const
301 auto *m
= find_meta(id
);
303 return m
->decoration
.alias
;
308 const string
&ParsedIR::get_member_name(TypeID id
, uint32_t index
) const
310 auto *m
= find_meta(id
);
313 if (index
>= m
->members
.size())
315 return m
->members
[index
].alias
;
321 void ParsedIR::sanitize_identifier(std::string
&name
, bool member
, bool allow_reserved_prefixes
)
323 if (!is_valid_identifier(name
))
324 name
= ensure_valid_identifier(name
);
325 if (is_reserved_identifier(name
, member
, allow_reserved_prefixes
))
326 name
= make_unreserved_identifier(name
);
329 void ParsedIR::fixup_reserved_names()
331 for (uint32_t id
: meta_needing_name_fixup
)
333 // Don't rename remapped variables like 'gl_LastFragDepthARM'.
334 if (ids
[id
].get_type() == TypeVariable
&& get
<SPIRVariable
>(id
).remapped_variable
)
338 sanitize_identifier(m
.decoration
.alias
, false, false);
339 for (auto &memb
: m
.members
)
340 sanitize_identifier(memb
.alias
, true, false);
342 meta_needing_name_fixup
.clear();
345 void ParsedIR::set_name(ID id
, const string
&name
)
348 m
.decoration
.alias
= name
;
349 if (!is_valid_identifier(name
) || is_reserved_identifier(name
, false, false))
350 meta_needing_name_fixup
.insert(id
);
353 void ParsedIR::set_member_name(TypeID id
, uint32_t index
, const string
&name
)
356 m
.members
.resize(max(m
.members
.size(), size_t(index
) + 1));
357 m
.members
[index
].alias
= name
;
358 if (!is_valid_identifier(name
) || is_reserved_identifier(name
, true, false))
359 meta_needing_name_fixup
.insert(id
);
362 void ParsedIR::set_decoration_string(ID id
, Decoration decoration
, const string
&argument
)
364 auto &dec
= meta
[id
].decoration
;
365 dec
.decoration_flags
.set(decoration
);
369 case DecorationHlslSemanticGOOGLE
:
370 dec
.hlsl_semantic
= argument
;
373 case DecorationUserTypeGOOGLE
:
374 dec
.user_type
= argument
;
382 void ParsedIR::set_decoration(ID id
, Decoration decoration
, uint32_t argument
)
384 auto &dec
= meta
[id
].decoration
;
385 dec
.decoration_flags
.set(decoration
);
389 case DecorationBuiltIn
:
391 dec
.builtin_type
= static_cast<BuiltIn
>(argument
);
394 case DecorationLocation
:
395 dec
.location
= argument
;
398 case DecorationComponent
:
399 dec
.component
= argument
;
402 case DecorationOffset
:
403 dec
.offset
= argument
;
406 case DecorationXfbBuffer
:
407 dec
.xfb_buffer
= argument
;
410 case DecorationXfbStride
:
411 dec
.xfb_stride
= argument
;
414 case DecorationStream
:
415 dec
.stream
= argument
;
418 case DecorationArrayStride
:
419 dec
.array_stride
= argument
;
422 case DecorationMatrixStride
:
423 dec
.matrix_stride
= argument
;
426 case DecorationBinding
:
427 dec
.binding
= argument
;
430 case DecorationDescriptorSet
:
434 case DecorationInputAttachmentIndex
:
435 dec
.input_attachment
= argument
;
438 case DecorationSpecId
:
439 dec
.spec_id
= argument
;
442 case DecorationIndex
:
443 dec
.index
= argument
;
446 case DecorationHlslCounterBufferGOOGLE
:
447 meta
[id
].hlsl_magic_counter_buffer
= argument
;
448 meta
[argument
].hlsl_is_magic_counter_buffer
= true;
451 case DecorationFPRoundingMode
:
452 dec
.fp_rounding_mode
= static_cast<FPRoundingMode
>(argument
);
460 void ParsedIR::set_member_decoration(TypeID id
, uint32_t index
, Decoration decoration
, uint32_t argument
)
463 m
.members
.resize(max(m
.members
.size(), size_t(index
) + 1));
464 auto &dec
= m
.members
[index
];
465 dec
.decoration_flags
.set(decoration
);
469 case DecorationBuiltIn
:
471 dec
.builtin_type
= static_cast<BuiltIn
>(argument
);
474 case DecorationLocation
:
475 dec
.location
= argument
;
478 case DecorationComponent
:
479 dec
.component
= argument
;
482 case DecorationBinding
:
483 dec
.binding
= argument
;
486 case DecorationOffset
:
487 dec
.offset
= argument
;
490 case DecorationXfbBuffer
:
491 dec
.xfb_buffer
= argument
;
494 case DecorationXfbStride
:
495 dec
.xfb_stride
= argument
;
498 case DecorationStream
:
499 dec
.stream
= argument
;
502 case DecorationSpecId
:
503 dec
.spec_id
= argument
;
506 case DecorationMatrixStride
:
507 dec
.matrix_stride
= argument
;
510 case DecorationIndex
:
511 dec
.index
= argument
;
519 // Recursively marks any constants referenced by the specified constant instruction as being used
520 // as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
521 void ParsedIR::mark_used_as_array_length(ID id
)
523 switch (ids
[id
].get_type())
526 get
<SPIRConstant
>(id
).is_used_as_array_length
= true;
531 auto &cop
= get
<SPIRConstantOp
>(id
);
532 if (cop
.opcode
== OpCompositeExtract
)
533 mark_used_as_array_length(cop
.arguments
[0]);
534 else if (cop
.opcode
== OpCompositeInsert
)
536 mark_used_as_array_length(cop
.arguments
[0]);
537 mark_used_as_array_length(cop
.arguments
[1]);
540 for (uint32_t arg_id
: cop
.arguments
)
541 mark_used_as_array_length(arg_id
);
553 Bitset
ParsedIR::get_buffer_block_type_flags(const SPIRType
&type
) const
555 if (type
.member_types
.empty())
558 Bitset all_members_flags
= get_member_decoration_bitset(type
.self
, 0);
559 for (uint32_t i
= 1; i
< uint32_t(type
.member_types
.size()); i
++)
560 all_members_flags
.merge_and(get_member_decoration_bitset(type
.self
, i
));
561 return all_members_flags
;
564 Bitset
ParsedIR::get_buffer_block_flags(const SPIRVariable
&var
) const
566 auto &type
= get
<SPIRType
>(var
.basetype
);
567 if (type
.basetype
!= SPIRType::Struct
)
568 SPIRV_CROSS_THROW("Cannot get buffer block flags for non-buffer variable.");
570 // Some flags like non-writable, non-readable are actually found
571 // as member decorations. If all members have a decoration set, propagate
572 // the decoration up as a regular variable decoration.
574 auto *m
= find_meta(var
.self
);
576 base_flags
= m
->decoration
.decoration_flags
;
578 if (type
.member_types
.empty())
581 auto all_members_flags
= get_buffer_block_type_flags(type
);
582 base_flags
.merge_or(all_members_flags
);
586 const Bitset
&ParsedIR::get_member_decoration_bitset(TypeID id
, uint32_t index
) const
588 auto *m
= find_meta(id
);
591 if (index
>= m
->members
.size())
592 return cleared_bitset
;
593 return m
->members
[index
].decoration_flags
;
596 return cleared_bitset
;
599 bool ParsedIR::has_decoration(ID id
, Decoration decoration
) const
601 return get_decoration_bitset(id
).get(decoration
);
604 uint32_t ParsedIR::get_decoration(ID id
, Decoration decoration
) const
606 auto *m
= find_meta(id
);
610 auto &dec
= m
->decoration
;
611 if (!dec
.decoration_flags
.get(decoration
))
616 case DecorationBuiltIn
:
617 return dec
.builtin_type
;
618 case DecorationLocation
:
620 case DecorationComponent
:
621 return dec
.component
;
622 case DecorationOffset
:
624 case DecorationXfbBuffer
:
625 return dec
.xfb_buffer
;
626 case DecorationXfbStride
:
627 return dec
.xfb_stride
;
628 case DecorationStream
:
630 case DecorationBinding
:
632 case DecorationDescriptorSet
:
634 case DecorationInputAttachmentIndex
:
635 return dec
.input_attachment
;
636 case DecorationSpecId
:
638 case DecorationArrayStride
:
639 return dec
.array_stride
;
640 case DecorationMatrixStride
:
641 return dec
.matrix_stride
;
642 case DecorationIndex
:
644 case DecorationFPRoundingMode
:
645 return dec
.fp_rounding_mode
;
651 const string
&ParsedIR::get_decoration_string(ID id
, Decoration decoration
) const
653 auto *m
= find_meta(id
);
657 auto &dec
= m
->decoration
;
659 if (!dec
.decoration_flags
.get(decoration
))
664 case DecorationHlslSemanticGOOGLE
:
665 return dec
.hlsl_semantic
;
667 case DecorationUserTypeGOOGLE
:
668 return dec
.user_type
;
675 void ParsedIR::unset_decoration(ID id
, Decoration decoration
)
677 auto &dec
= meta
[id
].decoration
;
678 dec
.decoration_flags
.clear(decoration
);
681 case DecorationBuiltIn
:
685 case DecorationLocation
:
689 case DecorationComponent
:
693 case DecorationOffset
:
697 case DecorationXfbBuffer
:
701 case DecorationXfbStride
:
705 case DecorationStream
:
709 case DecorationBinding
:
713 case DecorationDescriptorSet
:
717 case DecorationInputAttachmentIndex
:
718 dec
.input_attachment
= 0;
721 case DecorationSpecId
:
725 case DecorationHlslSemanticGOOGLE
:
726 dec
.hlsl_semantic
.clear();
729 case DecorationFPRoundingMode
:
730 dec
.fp_rounding_mode
= FPRoundingModeMax
;
733 case DecorationHlslCounterBufferGOOGLE
:
735 auto &counter
= meta
[id
].hlsl_magic_counter_buffer
;
738 meta
[counter
].hlsl_is_magic_counter_buffer
= false;
749 bool ParsedIR::has_member_decoration(TypeID id
, uint32_t index
, Decoration decoration
) const
751 return get_member_decoration_bitset(id
, index
).get(decoration
);
754 uint32_t ParsedIR::get_member_decoration(TypeID id
, uint32_t index
, Decoration decoration
) const
756 auto *m
= find_meta(id
);
760 if (index
>= m
->members
.size())
763 auto &dec
= m
->members
[index
];
764 if (!dec
.decoration_flags
.get(decoration
))
769 case DecorationBuiltIn
:
770 return dec
.builtin_type
;
771 case DecorationLocation
:
773 case DecorationComponent
:
774 return dec
.component
;
775 case DecorationBinding
:
777 case DecorationOffset
:
779 case DecorationXfbBuffer
:
780 return dec
.xfb_buffer
;
781 case DecorationXfbStride
:
782 return dec
.xfb_stride
;
783 case DecorationStream
:
785 case DecorationSpecId
:
787 case DecorationMatrixStride
:
788 return dec
.matrix_stride
;
789 case DecorationIndex
:
796 const Bitset
&ParsedIR::get_decoration_bitset(ID id
) const
798 auto *m
= find_meta(id
);
801 auto &dec
= m
->decoration
;
802 return dec
.decoration_flags
;
805 return cleared_bitset
;
808 void ParsedIR::set_member_decoration_string(TypeID id
, uint32_t index
, Decoration decoration
, const string
&argument
)
811 m
.members
.resize(max(m
.members
.size(), size_t(index
) + 1));
812 auto &dec
= meta
[id
].members
[index
];
813 dec
.decoration_flags
.set(decoration
);
817 case DecorationHlslSemanticGOOGLE
:
818 dec
.hlsl_semantic
= argument
;
826 const string
&ParsedIR::get_member_decoration_string(TypeID id
, uint32_t index
, Decoration decoration
) const
828 auto *m
= find_meta(id
);
831 if (!has_member_decoration(id
, index
, decoration
))
834 auto &dec
= m
->members
[index
];
838 case DecorationHlslSemanticGOOGLE
:
839 return dec
.hlsl_semantic
;
849 void ParsedIR::unset_member_decoration(TypeID id
, uint32_t index
, Decoration decoration
)
852 if (index
>= m
.members
.size())
855 auto &dec
= m
.members
[index
];
857 dec
.decoration_flags
.clear(decoration
);
860 case DecorationBuiltIn
:
864 case DecorationLocation
:
868 case DecorationComponent
:
872 case DecorationOffset
:
876 case DecorationXfbBuffer
:
880 case DecorationXfbStride
:
884 case DecorationStream
:
888 case DecorationSpecId
:
892 case DecorationHlslSemanticGOOGLE
:
893 dec
.hlsl_semantic
.clear();
901 uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount
)
903 auto curr_bound
= ids
.size();
904 auto new_bound
= curr_bound
+ incr_amount
;
906 ids
.reserve(ids
.size() + incr_amount
);
907 for (uint32_t i
= 0; i
< incr_amount
; i
++)
908 ids
.emplace_back(pool_group
.get());
910 block_meta
.resize(new_bound
);
911 return uint32_t(curr_bound
);
914 void ParsedIR::remove_typed_id(Types type
, ID id
)
916 auto &type_ids
= ids_for_type
[type
];
917 type_ids
.erase(remove(begin(type_ids
), end(type_ids
), id
), end(type_ids
));
920 void ParsedIR::reset_all_of_type(Types type
)
922 for (auto &id
: ids_for_type
[type
])
923 if (ids
[id
].get_type() == type
)
926 ids_for_type
[type
].clear();
929 void ParsedIR::add_typed_id(Types type
, ID id
)
931 assert(id
< ids
.size());
933 if (loop_iteration_depth_hard
!= 0)
934 SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
936 if (loop_iteration_depth_soft
!= 0)
938 if (!ids
[id
].empty())
939 SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
943 if (ids
[id
].empty() || ids
[id
].get_type() != type
)
948 ids_for_constant_or_variable
.push_back(id
);
949 ids_for_constant_undef_or_type
.push_back(id
);
953 ids_for_constant_or_variable
.push_back(id
);
959 ids_for_constant_undef_or_type
.push_back(id
);
969 ids_for_type
[type
].push_back(id
);
971 else if (ids
[id
].get_type() != type
)
973 remove_typed_id(ids
[id
].get_type(), id
);
974 ids_for_type
[type
].push_back(id
);
978 const Meta
*ParsedIR::find_meta(ID id
) const
980 auto itr
= meta
.find(id
);
981 if (itr
!= end(meta
))
987 Meta
*ParsedIR::find_meta(ID id
)
989 auto itr
= meta
.find(id
);
990 if (itr
!= end(meta
))
996 ParsedIR::LoopLock
ParsedIR::create_loop_hard_lock() const
998 return ParsedIR::LoopLock(&loop_iteration_depth_hard
);
1001 ParsedIR::LoopLock
ParsedIR::create_loop_soft_lock() const
1003 return ParsedIR::LoopLock(&loop_iteration_depth_soft
);
1006 ParsedIR::LoopLock::~LoopLock()
1012 ParsedIR::LoopLock::LoopLock(uint32_t *lock_
)
1019 ParsedIR::LoopLock::LoopLock(LoopLock
&&other
) SPIRV_CROSS_NOEXCEPT
1021 *this = std::move(other
);
1024 ParsedIR::LoopLock
&ParsedIR::LoopLock::operator=(LoopLock
&&other
) SPIRV_CROSS_NOEXCEPT
1029 other
.lock
= nullptr;
1033 void ParsedIR::make_constant_null(uint32_t id
, uint32_t type
, bool add_to_typed_id_set
)
1035 assert(id
< ids
.size());
1037 auto &constant_type
= get
<SPIRType
>(type
);
1039 if (constant_type
.pointer
)
1041 if (add_to_typed_id_set
)
1042 add_typed_id(TypeConstant
, id
);
1043 auto &constant
= variant_set
<SPIRConstant
>(ids
[id
], type
);
1045 constant
.make_null(constant_type
);
1047 else if (!constant_type
.array
.empty())
1049 assert(constant_type
.parent_type
);
1050 uint32_t parent_id
= increase_bound_by(1);
1051 make_constant_null(parent_id
, constant_type
.parent_type
, add_to_typed_id_set
);
1053 if (!constant_type
.array_size_literal
.back())
1054 SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
1056 SmallVector
<uint32_t> elements(constant_type
.array
.back());
1057 for (uint32_t i
= 0; i
< constant_type
.array
.back(); i
++)
1058 elements
[i
] = parent_id
;
1060 if (add_to_typed_id_set
)
1061 add_typed_id(TypeConstant
, id
);
1062 variant_set
<SPIRConstant
>(ids
[id
], type
, elements
.data(), uint32_t(elements
.size()), false).self
= id
;
1064 else if (!constant_type
.member_types
.empty())
1066 uint32_t member_ids
= increase_bound_by(uint32_t(constant_type
.member_types
.size()));
1067 SmallVector
<uint32_t> elements(constant_type
.member_types
.size());
1068 for (uint32_t i
= 0; i
< constant_type
.member_types
.size(); i
++)
1070 make_constant_null(member_ids
+ i
, constant_type
.member_types
[i
], add_to_typed_id_set
);
1071 elements
[i
] = member_ids
+ i
;
1074 if (add_to_typed_id_set
)
1075 add_typed_id(TypeConstant
, id
);
1076 variant_set
<SPIRConstant
>(ids
[id
], type
, elements
.data(), uint32_t(elements
.size()), false).self
= id
;
1080 if (add_to_typed_id_set
)
1081 add_typed_id(TypeConstant
, id
);
1082 auto &constant
= variant_set
<SPIRConstant
>(ids
[id
], type
);
1084 constant
.make_null(constant_type
);
1088 } // namespace SPIRV_CROSS_NAMESPACE