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 #ifndef SPIRV_CROSS_PARSED_IR_HPP
25 #define SPIRV_CROSS_PARSED_IR_HPP
27 #include "spirv_common.hpp"
29 #include <unordered_map>
31 namespace SPIRV_CROSS_NAMESPACE
34 // This data structure holds all information needed to perform cross-compilation and reflection.
35 // It is the output of the Parser, but any implementation could create this structure.
36 // It is intentionally very "open" and struct-like with some helper functions to deal with decorations.
37 // Parser is the reference implementation of how this data structure should be filled in.
42 // This must be destroyed after the "ids" vector.
43 std::unique_ptr
<ObjectPoolGroup
> pool_group
;
48 // Due to custom allocations from object pools, we cannot use a default copy constructor.
49 ParsedIR(const ParsedIR
&other
);
50 ParsedIR
&operator=(const ParsedIR
&other
);
52 // Moves are unproblematic, but we need to implement it anyways, since MSVC 2013 does not understand
53 // how to default-implement these.
54 ParsedIR(ParsedIR
&&other
) SPIRV_CROSS_NOEXCEPT
;
55 ParsedIR
&operator=(ParsedIR
&&other
) SPIRV_CROSS_NOEXCEPT
;
57 // Resizes ids, meta and block_meta.
58 void set_id_bounds(uint32_t bounds
);
60 // The raw SPIR-V, instructions and opcodes refer to this by offset + count.
61 std::vector
<uint32_t> spirv
;
63 // Holds various data structures which inherit from IVariant.
64 SmallVector
<Variant
> ids
;
66 // Various meta data for IDs, decorations, names, etc.
67 std::unordered_map
<ID
, Meta
> meta
;
69 // Holds all IDs which have a certain type.
70 // This is needed so we can iterate through a specific kind of resource quickly,
71 // and in-order of module declaration.
72 SmallVector
<ID
> ids_for_type
[TypeCount
];
74 // Special purpose lists which contain a union of types.
75 // This is needed so we can declare specialization constants and structs in an interleaved fashion,
76 // among other things.
77 // Constants can be undef or of struct type, and struct array sizes can use specialization constants.
78 SmallVector
<ID
> ids_for_constant_undef_or_type
;
79 SmallVector
<ID
> ids_for_constant_or_variable
;
81 // We need to keep track of the width the Ops that contains a type for the
82 // OpSwitch instruction, since this one doesn't contains the type in the
83 // instruction itself. And in some case we need to cast the condition to
84 // wider types. We only need the width to do the branch fixup since the
85 // type check itself can be done at runtime
86 std::unordered_map
<ID
, uint32_t> load_type_width
;
88 // Declared capabilities and extensions in the SPIR-V module.
89 // Not really used except for reflection at the moment.
90 SmallVector
<spv::Capability
> declared_capabilities
;
91 SmallVector
<std::string
> declared_extensions
;
93 // Meta data about blocks. The cross-compiler needs to query if a block is either of these types.
94 // It is a bitset as there can be more than one tag per block.
95 enum BlockMetaFlagBits
97 BLOCK_META_LOOP_HEADER_BIT
= 1 << 0,
98 BLOCK_META_CONTINUE_BIT
= 1 << 1,
99 BLOCK_META_LOOP_MERGE_BIT
= 1 << 2,
100 BLOCK_META_SELECTION_MERGE_BIT
= 1 << 3,
101 BLOCK_META_MULTISELECT_MERGE_BIT
= 1 << 4
103 using BlockMetaFlags
= uint8_t;
104 SmallVector
<BlockMetaFlags
> block_meta
;
105 std::unordered_map
<BlockID
, BlockID
> continue_block_to_loop_header
;
107 // Normally, we'd stick SPIREntryPoint in ids array, but it conflicts with SPIRFunction.
108 // Entry points can therefore be seen as some sort of meta structure.
109 std::unordered_map
<FunctionID
, SPIREntryPoint
> entry_points
;
110 FunctionID default_entry_point
= 0;
114 uint32_t version
= 0;
124 spv::AddressingModel addressing_model
= spv::AddressingModelMax
;
125 spv::MemoryModel memory_model
= spv::MemoryModelMax
;
127 // Decoration handling methods.
128 // Can be useful for simple "raw" reflection.
129 // However, most members are here because the Parser needs most of these,
130 // and might as well just have the whole suite of decoration/name handling in one place.
131 void set_name(ID id
, const std::string
&name
);
132 const std::string
&get_name(ID id
) const;
133 void set_decoration(ID id
, spv::Decoration decoration
, uint32_t argument
= 0);
134 void set_decoration_string(ID id
, spv::Decoration decoration
, const std::string
&argument
);
135 bool has_decoration(ID id
, spv::Decoration decoration
) const;
136 uint32_t get_decoration(ID id
, spv::Decoration decoration
) const;
137 const std::string
&get_decoration_string(ID id
, spv::Decoration decoration
) const;
138 const Bitset
&get_decoration_bitset(ID id
) const;
139 void unset_decoration(ID id
, spv::Decoration decoration
);
141 // Decoration handling methods (for members of a struct).
142 void set_member_name(TypeID id
, uint32_t index
, const std::string
&name
);
143 const std::string
&get_member_name(TypeID id
, uint32_t index
) const;
144 void set_member_decoration(TypeID id
, uint32_t index
, spv::Decoration decoration
, uint32_t argument
= 0);
145 void set_member_decoration_string(TypeID id
, uint32_t index
, spv::Decoration decoration
,
146 const std::string
&argument
);
147 uint32_t get_member_decoration(TypeID id
, uint32_t index
, spv::Decoration decoration
) const;
148 const std::string
&get_member_decoration_string(TypeID id
, uint32_t index
, spv::Decoration decoration
) const;
149 bool has_member_decoration(TypeID id
, uint32_t index
, spv::Decoration decoration
) const;
150 const Bitset
&get_member_decoration_bitset(TypeID id
, uint32_t index
) const;
151 void unset_member_decoration(TypeID id
, uint32_t index
, spv::Decoration decoration
);
153 void mark_used_as_array_length(ID id
);
154 uint32_t increase_bound_by(uint32_t count
);
155 Bitset
get_buffer_block_flags(const SPIRVariable
&var
) const;
156 Bitset
get_buffer_block_type_flags(const SPIRType
&type
) const;
158 void add_typed_id(Types type
, ID id
);
159 void remove_typed_id(Types type
, ID id
);
164 explicit LoopLock(uint32_t *counter
);
165 LoopLock(const LoopLock
&) = delete;
166 void operator=(const LoopLock
&) = delete;
167 LoopLock(LoopLock
&&other
) SPIRV_CROSS_NOEXCEPT
;
168 LoopLock
&operator=(LoopLock
&&other
) SPIRV_CROSS_NOEXCEPT
;
172 uint32_t *lock
= nullptr;
175 // This must be held while iterating over a type ID array.
176 // It is undefined if someone calls set<>() while we're iterating over a data structure, so we must
177 // make sure that this case is avoided.
179 // If we have a hard lock, it is an error to call set<>(), and an exception is thrown.
180 // If we have a soft lock, we silently ignore any additions to the typed arrays.
181 // This should only be used for physical ID remapping where we need to create an ID, but we will never
182 // care about iterating over them.
183 LoopLock
create_loop_hard_lock() const;
184 LoopLock
create_loop_soft_lock() const;
186 template <typename T
, typename Op
>
187 void for_each_typed_id(const Op
&op
)
189 auto loop_lock
= create_loop_hard_lock();
190 for (auto &id
: ids_for_type
[T::type
])
192 if (ids
[id
].get_type() == static_cast<Types
>(T::type
))
197 template <typename T
, typename Op
>
198 void for_each_typed_id(const Op
&op
) const
200 auto loop_lock
= create_loop_hard_lock();
201 for (auto &id
: ids_for_type
[T::type
])
203 if (ids
[id
].get_type() == static_cast<Types
>(T::type
))
208 template <typename T
>
209 void reset_all_of_type()
211 reset_all_of_type(static_cast<Types
>(T::type
));
214 void reset_all_of_type(Types type
);
216 Meta
*find_meta(ID id
);
217 const Meta
*find_meta(ID id
) const;
219 const std::string
&get_empty_string() const
224 void make_constant_null(uint32_t id
, uint32_t type
, bool add_to_typed_id_set
);
226 void fixup_reserved_names();
228 static void sanitize_underscores(std::string
&str
);
229 static void sanitize_identifier(std::string
&str
, bool member
, bool allow_reserved_prefixes
);
230 static bool is_globally_reserved_identifier(std::string
&str
, bool allow_reserved_prefixes
);
232 uint32_t get_spirv_version() const;
235 template <typename T
>
238 return variant_get
<T
>(ids
[id
]);
241 template <typename T
>
242 const T
&get(uint32_t id
) const
244 return variant_get
<T
>(ids
[id
]);
247 mutable uint32_t loop_iteration_depth_hard
= 0;
248 mutable uint32_t loop_iteration_depth_soft
= 0;
249 std::string empty_string
;
250 Bitset cleared_bitset
;
252 std::unordered_set
<uint32_t> meta_needing_name_fixup
;
254 } // namespace SPIRV_CROSS_NAMESPACE