blob: 138d9dd43d55bc3b320109872ec6281a3b950ca8 [file] [log] [blame]
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02001/*
Hans-Kristian Arntzen47044822021-01-14 16:07:49 +01002 * Copyright 2018-2021 Arm Limited
Jon Leechf2a65542021-05-08 01:47:48 -07003 * SPDX-License-Identifier: Apache-2.0 OR MIT
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +02004 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010018/*
19 * At your option, you may choose to accept this material under either:
20 * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
21 * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
Hans-Kristian Arntzencf1e9e02020-11-25 15:22:08 +010022 */
23
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020024#ifndef SPIRV_CROSS_PARSED_IR_HPP
25#define SPIRV_CROSS_PARSED_IR_HPP
26
27#include "spirv_common.hpp"
28#include <stdint.h>
29#include <unordered_map>
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020030
Hans-Kristian Arntzen9b92e682019-03-29 10:29:44 +010031namespace SPIRV_CROSS_NAMESPACE
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020032{
33
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.
38
39class ParsedIR
40{
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020041private:
42 // This must be destroyed after the "ids" vector.
43 std::unique_ptr<ObjectPoolGroup> pool_group;
44
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020045public:
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020046 ParsedIR();
47
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);
51
Hans-Kristian Arntzendede9be2019-04-09 10:25:41 +020052 // 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;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020056
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020057 // Resizes ids, meta and block_meta.
58 void set_id_bounds(uint32_t bounds);
59
60 // The raw SPIR-V, instructions and opcodes refer to this by offset + count.
Hans-Kristian Arntzen3fe57d32019-04-09 12:46:23 +020061 std::vector<uint32_t> spirv;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020062
63 // Holds various data structures which inherit from IVariant.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020064 SmallVector<Variant> ids;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020065
66 // Various meta data for IDs, decorations, names, etc.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020067 std::unordered_map<ID, Meta> meta;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020068
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +010069 // 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.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020072 SmallVector<ID> ids_for_type[TypeCount];
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +010073
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 of struct type, and struct array sizes can use specialization constants.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +020078 SmallVector<ID> ids_for_constant_or_type;
79 SmallVector<ID> ids_for_constant_or_variable;
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +010080
Sebastián Aedo250a0292021-11-03 16:12:14 -030081 // We need to keep track of the width the Ops that contains a type for the
Sebastián Aedof099d712021-11-02 17:17:13 -030082 // 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
Sebastián Aedo250a0292021-11-03 16:12:14 -030084 // 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;
Sebastián Aedof099d712021-11-02 17:17:13 -030087
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020088 // Declared capabilities and extensions in the SPIR-V module.
89 // Not really used except for reflection at the moment.
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +020090 SmallVector<spv::Capability> declared_capabilities;
91 SmallVector<std::string> declared_extensions;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +020092
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
96 {
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
102 };
103 using BlockMetaFlags = uint8_t;
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200104 SmallVector<BlockMetaFlags> block_meta;
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200105 std::unordered_map<BlockID, BlockID> continue_block_to_loop_header;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200106
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.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200109 std::unordered_map<FunctionID, SPIREntryPoint> entry_points;
110 FunctionID default_entry_point = 0;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200111
112 struct Source
113 {
114 uint32_t version = 0;
115 bool es = false;
116 bool known = false;
117 bool hlsl = false;
118
119 Source() = default;
120 };
121
122 Source source;
123
Hans-Kristian Arntzen2cc374a2019-04-24 14:12:50 +0200124 spv::AddressingModel addressing_model = spv::AddressingModelMax;
125 spv::MemoryModel memory_model = spv::MemoryModelMax;
126
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200127 // 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.
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200131 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);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200140
141 // Decoration handling methods (for members of a struct).
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200142 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,
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200146 const std::string &argument);
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200147 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);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200152
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200153 void mark_used_as_array_length(ID id);
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200154 uint32_t increase_bound_by(uint32_t count);
155 Bitset get_buffer_block_flags(const SPIRVariable &var) const;
Hans-Kristian Arntzenc5826b42020-11-23 16:26:33 +0100156 Bitset get_buffer_block_type_flags(const SPIRType &type) const;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200157
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200158 void add_typed_id(Types type, ID id);
159 void remove_typed_id(Types type, ID id);
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100160
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200161 class LoopLock
162 {
163 public:
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;
169 ~LoopLock();
170
171 private:
172 uint32_t *lock;
173 };
174
175 // This must be held while iterating over a type ID array.
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200176 // 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.
178
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;
Hans-Kristian Arntzena86308b2019-07-18 13:34:47 +0200185
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100186 template <typename T, typename Op>
187 void for_each_typed_id(const Op &op)
188 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200189 auto loop_lock = create_loop_hard_lock();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100190 for (auto &id : ids_for_type[T::type])
191 {
192 if (ids[id].get_type() == static_cast<Types>(T::type))
193 op(id, get<T>(id));
194 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100195 }
196
197 template <typename T, typename Op>
198 void for_each_typed_id(const Op &op) const
199 {
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200200 auto loop_lock = create_loop_hard_lock();
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100201 for (auto &id : ids_for_type[T::type])
202 {
203 if (ids[id].get_type() == static_cast<Types>(T::type))
204 op(id, get<T>(id));
205 }
206 }
207
208 template <typename T>
209 void reset_all_of_type()
210 {
211 reset_all_of_type(static_cast<Types>(T::type));
212 }
213
214 void reset_all_of_type(Types type);
215
Hans-Kristian Arntzen333980a2019-09-05 12:43:40 +0200216 Meta *find_meta(ID id);
217 const Meta *find_meta(ID id) const;
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100218
219 const std::string &get_empty_string() const
220 {
221 return empty_string;
222 }
223
Hans-Kristian Arntzenb8905bb2020-03-26 11:21:23 +0100224 void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set);
225
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200226 void fixup_reserved_names();
227
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);
231
Hans-Kristian Arntzen2097c302021-01-08 11:37:29 +0100232 uint32_t get_spirv_version() const;
233
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200234private:
235 template <typename T>
236 T &get(uint32_t id)
237 {
238 return variant_get<T>(ids[id]);
239 }
240
241 template <typename T>
242 const T &get(uint32_t id) const
243 {
244 return variant_get<T>(ids[id]);
245 }
Hans-Kristian Arntzend92de002019-01-10 09:49:33 +0100246
Hans-Kristian Arntzendd7ebaf2019-07-18 17:05:28 +0200247 mutable uint32_t loop_iteration_depth_hard = 0;
248 mutable uint32_t loop_iteration_depth_soft = 0;
Hans-Kristian Arntzenb6298782019-01-10 14:04:01 +0100249 std::string empty_string;
250 Bitset cleared_bitset;
Hans-Kristian Arntzena0744152020-08-21 16:14:13 +0200251
252 std::unordered_set<uint32_t> meta_needing_name_fixup;
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200253};
Hans-Kristian Arntzena489ba72019-04-02 11:19:03 +0200254} // namespace SPIRV_CROSS_NAMESPACE
Hans-Kristian Arntzen5bcf02f2018-10-05 11:30:57 +0200255
Hans-Kristian Arntzen318c17c2019-01-04 12:38:35 +0100256#endif