blob: e1a3f84922dc5b5c028a30b83c945f2791796175 [file] [log] [blame]
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +01001/*
2 * Copyright 2015-2016 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
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020017#ifndef SPIRV_COMMON_HPP
18#define SPIRV_COMMON_HPP
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010019
20#include <sstream>
21#include <stdio.h>
Hans-Kristian Arntzen0ae2bcc2016-03-12 14:17:19 +010022#include <string.h>
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010023
Hans-Kristian Arntzen147e53a2016-04-04 09:36:04 +020024namespace spirv_cross
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010025{
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020026class CompilerError : public std::runtime_error
27{
28public:
29 CompilerError(const std::string &str)
30 : std::runtime_error(str)
31 {
32 }
33};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010034
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020035namespace inner
36{
37template <typename T>
38void join_helper(std::ostringstream &stream, T &&t)
39{
40 stream << std::forward<T>(t);
41}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010042
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020043template <typename T, typename... Ts>
44void join_helper(std::ostringstream &stream, T &&t, Ts &&... ts)
45{
46 stream << std::forward<T>(t);
47 join_helper(stream, std::forward<Ts>(ts)...);
48}
49}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010050
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020051// Helper template to avoid lots of nasty string temporary munging.
52template <typename... Ts>
53std::string join(Ts &&... ts)
54{
55 std::ostringstream stream;
56 inner::join_helper(stream, std::forward<Ts>(ts)...);
57 return stream.str();
58}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010059
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020060inline std::string merge(const std::vector<std::string> &list)
61{
62 std::string s;
63 for (auto &elem : list)
64 {
65 s += elem;
66 if (&elem != &list.back())
67 s += ", ";
68 }
69 return s;
70}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010071
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020072template <typename T>
73inline std::string convert_to_string(T &&t)
74{
75 return std::to_string(std::forward<T>(t));
76}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010077
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020078// Allow implementations to set a convenient standard precision
Bill Hollings6ddd80e2016-04-08 15:12:40 -040079#ifndef SPIRV_CROSS_FLT_FMT
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020080#define SPIRV_CROSS_FLT_FMT "%.32g"
Bill Hollings103aabf2016-04-06 17:42:27 -040081#endif
82
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020083inline std::string convert_to_string(float t)
84{
85 // std::to_string for floating point values is broken.
86 // Fallback to something more sane.
87 char buf[64];
88 sprintf(buf, SPIRV_CROSS_FLT_FMT, t);
89 // Ensure that the literal is float.
90 if (!strchr(buf, '.') && !strchr(buf, 'e'))
91 strcat(buf, ".0");
92 return buf;
93}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +010094
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +020095inline std::string convert_to_string(double t)
96{
97 // std::to_string for floating point values is broken.
98 // Fallback to something more sane.
99 char buf[64];
100 sprintf(buf, SPIRV_CROSS_FLT_FMT, t);
101 // Ensure that the literal is float.
102 if (!strchr(buf, '.') && !strchr(buf, 'e'))
103 strcat(buf, ".0");
104 return buf;
105}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100106
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200107struct Instruction
108{
109 Instruction(const std::vector<uint32_t> &spirv, uint32_t &index);
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100110
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200111 uint16_t op;
112 uint16_t count;
113 uint32_t offset;
114 uint32_t length;
115};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100116
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200117// Helper for Variant interface.
118struct IVariant
119{
120 virtual ~IVariant() = default;
121 uint32_t self = 0;
122};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100123
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200124enum Types
125{
126 TypeNone,
127 TypeType,
128 TypeVariable,
129 TypeConstant,
130 TypeFunction,
131 TypeFunctionPrototype,
132 TypePointer,
133 TypeBlock,
134 TypeExtension,
135 TypeExpression,
136 TypeUndef
137};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100138
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200139struct SPIRUndef : IVariant
140{
141 enum
142 {
143 type = TypeUndef
144 };
145 SPIRUndef(uint32_t basetype_)
146 : basetype(basetype_)
147 {
148 }
149 uint32_t basetype;
150};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100151
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200152struct SPIRType : IVariant
153{
154 enum
155 {
156 type = TypeType
157 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100158
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200159 enum BaseType
160 {
161 Unknown,
162 Void,
Hans-Kristian Arntzen5f629272016-06-05 20:13:45 +0200163 Boolean,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200164 Char,
165 Int,
166 UInt,
Hans-Kristian Arntzenfc2230f2016-07-27 11:27:00 +0200167 Int64,
168 UInt64,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200169 AtomicCounter,
170 Float,
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200171 Double,
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200172 Struct,
173 Image,
174 SampledImage,
175 Sampler
176 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100177
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200178 // Scalar/vector/matrix support.
179 BaseType basetype = Unknown;
180 uint32_t width = 0;
181 uint32_t vecsize = 1;
182 uint32_t columns = 1;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100183
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200184 // Arrays, suport array of arrays by having a vector of array sizes.
185 std::vector<uint32_t> array;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100186
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200187 // Pointers
188 bool pointer = false;
189 spv::StorageClass storage = spv::StorageClassGeneric;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100190
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200191 std::vector<uint32_t> member_types;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100192
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200193 bool is_packed = false; // Tightly packed in memory (no alignment padding)
Bill Hollings103aabf2016-04-06 17:42:27 -0400194
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200195 struct Image
196 {
197 uint32_t type;
198 spv::Dim dim;
199 bool depth;
200 bool arrayed;
201 bool ms;
202 uint32_t sampled;
203 spv::ImageFormat format;
204 } image;
Hans-Kristian Arntzenf05373b2016-05-23 10:57:22 +0200205
206 // Structs can be declared multiple times if they are used as part of interface blocks.
207 // We want to detect this so that we only emit the struct definition once.
208 // Since we cannot rely on OpName to be equal, we need to figure out aliases.
209 uint32_t type_alias = 0;
Hans-Kristian Arntzen6aa20072016-05-23 12:25:09 +0200210
211 // Used in backends to avoid emitting members with conflicting names.
212 std::unordered_set<std::string> member_name_cache;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200213};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100214
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200215struct SPIRExtension : IVariant
216{
217 enum
218 {
219 type = TypeExtension
220 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100221
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200222 enum Extension
223 {
224 GLSL
225 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100226
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200227 SPIRExtension(Extension ext_)
228 : ext(ext_)
229 {
230 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100231
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200232 Extension ext;
233};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100234
Hans-Kristian Arntzen042475e2016-07-28 11:16:02 +0200235// SPIREntryPoint is not a variant since its IDs are used to decorate OpFunction,
236// so in order to avoid conflicts, we can't stick them in the ids array.
237struct SPIREntryPoint
238{
239 SPIREntryPoint(uint32_t self_, spv::ExecutionModel execution_model, std::string entry_name)
240 : self(self_)
241 , name(std::move(entry_name))
242 , model(execution_model)
243 {
244 }
245 SPIREntryPoint() = default;
246
247 uint32_t self = 0;
248 std::string name;
249 std::vector<uint32_t> interface_variables;
250
251 uint64_t flags = 0;
252 struct
253 {
254 uint32_t x = 0, y = 0, z = 0;
255 } workgroup_size;
256 uint32_t invocations = 0;
257 uint32_t output_vertices = 0;
258 spv::ExecutionModel model = {};
259};
260
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200261struct SPIRExpression : IVariant
262{
263 enum
264 {
265 type = TypeExpression
266 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100267
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200268 // Only created by the backend target to avoid creating tons of temporaries.
269 SPIRExpression(std::string expr, uint32_t expression_type_, bool immutable_)
270 : expression(move(expr))
271 , expression_type(expression_type_)
272 , immutable(immutable_)
273 {
274 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100275
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200276 // If non-zero, prepend expression with to_expression(base_expression).
277 // Used in amortizing multiple calls to to_expression()
278 // where in certain cases that would quickly force a temporary when not needed.
279 uint32_t base_expression = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100280
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200281 std::string expression;
282 uint32_t expression_type = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100283
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200284 // If this expression is a forwarded load,
285 // allow us to reference the original variable.
286 uint32_t loaded_from = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100287
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200288 // If this expression will never change, we can avoid lots of temporaries
289 // in high level source.
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +0200290 // An expression being immutable can be speculative,
291 // it is assumed that this is true almost always.
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200292 bool immutable = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100293
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200294 // If this expression has been used while invalidated.
295 bool used_while_invalidated = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100296
Hans-Kristian Arntzen36a0b632016-07-12 14:33:04 +0200297 // A list of expressions which this expression depends on.
298 std::vector<uint32_t> expression_dependencies;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200299};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100300
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200301struct SPIRFunctionPrototype : IVariant
302{
303 enum
304 {
305 type = TypeFunctionPrototype
306 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100307
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200308 SPIRFunctionPrototype(uint32_t return_type_)
309 : return_type(return_type_)
310 {
311 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100312
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200313 uint32_t return_type;
314 std::vector<uint32_t> parameter_types;
315};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100316
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200317struct SPIRBlock : IVariant
318{
319 enum
320 {
321 type = TypeBlock
322 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100323
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200324 enum Terminator
325 {
326 Unknown,
327 Direct, // Emit next block directly without a particular condition.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100328
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200329 Select, // Block ends with an if/else block.
330 MultiSelect, // Block ends with switch statement.
331 Loop, // Block ends with a loop.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100332
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200333 Return, // Block ends with return.
334 Unreachable, // Noop
335 Kill // Discard
336 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100337
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200338 enum Merge
339 {
340 MergeNone,
341 MergeLoop,
342 MergeSelection
343 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100344
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200345 enum Method
346 {
347 MergeToSelectForLoop,
348 MergeToDirectForLoop
349 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100350
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200351 enum ContinueBlockType
352 {
353 ContinueNone,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100354
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200355 // Continue block is branchless and has at least one instruction.
356 ForLoop,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100357
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200358 // Noop continue block.
359 WhileLoop,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100360
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200361 // Continue block is conditional.
362 DoWhileLoop,
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100363
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200364 // Highly unlikely that anything will use this,
365 // since it is really awkward/impossible to express in GLSL.
366 ComplexLoop
367 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100368
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200369 enum
370 {
371 NoDominator = 0xffffffffu
372 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100373
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200374 Terminator terminator = Unknown;
375 Merge merge = MergeNone;
376 uint32_t next_block = 0;
377 uint32_t merge_block = 0;
378 uint32_t continue_block = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100379
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200380 uint32_t return_value = 0; // If 0, return nothing (void).
381 uint32_t condition = 0;
382 uint32_t true_block = 0;
383 uint32_t false_block = 0;
384 uint32_t default_block = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100385
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200386 std::vector<Instruction> ops;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100387
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200388 struct Phi
389 {
390 uint32_t local_variable; // flush local variable ...
391 uint32_t parent; // If we're in from_block and want to branch into this block ...
392 uint32_t function_variable; // to this function-global "phi" variable first.
393 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100394
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200395 // Before entering this block flush out local variables to magical "phi" variables.
396 std::vector<Phi> phi_variables;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100397
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200398 // Declare these temporaries before beginning the block.
399 // Used for handling complex continue blocks which have side effects.
400 std::vector<std::pair<uint32_t, uint32_t>> declare_temporary;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100401
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200402 struct Case
403 {
404 uint32_t value;
405 uint32_t block;
406 };
407 std::vector<Case> cases;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100408
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200409 // If we have tried to optimize code for this block but failed,
410 // keep track of this.
411 bool disable_block_optimization = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100412
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200413 // If the continue block is complex, fallback to "dumb" for loops.
414 bool complex_continue = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100415
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200416 // The dominating block which this block might be within.
417 // Used in continue; blocks to determine if we really need to write continue.
418 uint32_t loop_dominator = 0;
419};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100420
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200421struct SPIRFunction : IVariant
422{
423 enum
424 {
425 type = TypeFunction
426 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100427
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200428 SPIRFunction(uint32_t return_type_, uint32_t function_type_)
429 : return_type(return_type_)
430 , function_type(function_type_)
431 {
432 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100433
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200434 struct Parameter
435 {
436 uint32_t type;
437 uint32_t id;
438 uint32_t read_count;
439 uint32_t write_count;
440 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100441
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200442 uint32_t return_type;
443 uint32_t function_type;
444 std::vector<Parameter> arguments;
445 std::vector<uint32_t> local_variables;
446 uint32_t entry_block = 0;
447 std::vector<uint32_t> blocks;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100448
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200449 void add_local_variable(uint32_t id)
450 {
451 local_variables.push_back(id);
452 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100453
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200454 void add_parameter(uint32_t parameter_type, uint32_t id)
455 {
456 // Arguments are read-only until proven otherwise.
457 arguments.push_back({ parameter_type, id, 0u, 0u });
458 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100459
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200460 bool active = false;
461 bool flush_undeclared = true;
462};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100463
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200464struct SPIRVariable : IVariant
465{
466 enum
467 {
468 type = TypeVariable
469 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100470
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200471 SPIRVariable() = default;
472 SPIRVariable(uint32_t basetype_, spv::StorageClass storage_, uint32_t initializer_ = 0)
473 : basetype(basetype_)
474 , storage(storage_)
475 , initializer(initializer_)
476 {
477 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100478
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200479 uint32_t basetype = 0;
480 spv::StorageClass storage = spv::StorageClassGeneric;
481 uint32_t decoration = 0;
482 uint32_t initializer = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100483
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200484 std::vector<uint32_t> dereference_chain;
485 bool compat_builtin = false;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100486
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200487 // If a variable is shadowed, we only statically assign to it
488 // and never actually emit a statement for it.
489 // When we read the variable as an expression, just forward
490 // shadowed_id as the expression.
491 bool statically_assigned = false;
492 uint32_t static_expression = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100493
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200494 // Temporaries which can remain forwarded as long as this variable is not modified.
495 std::vector<uint32_t> dependees;
496 bool forwardable = true;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100497
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200498 bool deferred_declaration = false;
499 bool phi_variable = false;
500 bool remapped_variable = false;
Hans-Kristian Arntzen078eec52016-07-06 11:04:06 +0200501 uint32_t remapped_components = 0;
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100502
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200503 SPIRFunction::Parameter *parameter = nullptr;
504};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100505
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200506struct SPIRConstant : IVariant
507{
508 enum
509 {
510 type = TypeConstant
511 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100512
Hans-Kristian Arntzen5ea59bd2016-05-23 13:30:02 +0200513 union Constant {
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200514 uint32_t u32;
515 int32_t i32;
516 float f32;
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200517
518 uint64_t u64;
519 int64_t i64;
520 double f64;
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200521 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100522
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200523 struct ConstantVector
524 {
525 Constant r[4];
526 uint32_t vecsize;
527 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100528
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200529 struct ConstantMatrix
530 {
531 ConstantVector c[4];
532 uint32_t columns;
533 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100534
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200535 inline uint32_t scalar(uint32_t col = 0, uint32_t row = 0) const
536 {
537 return m.c[col].r[row].u32;
538 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100539
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200540 inline float scalar_f32(uint32_t col = 0, uint32_t row = 0) const
541 {
542 return m.c[col].r[row].f32;
543 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100544
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200545 inline int32_t scalar_i32(uint32_t col = 0, uint32_t row = 0) const
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200546 {
547 return m.c[col].r[row].i32;
548 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100549
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200550 inline double scalar_f64(uint32_t col = 0, uint32_t row = 0) const
551 {
552 return m.c[col].r[row].f64;
553 }
554
555 inline int64_t scalar_i64(uint32_t col = 0, uint32_t row = 0) const
556 {
557 return m.c[col].r[row].i64;
558 }
559
560 inline uint64_t scalar_u64(uint32_t col = 0, uint32_t row = 0) const
561 {
562 return m.c[col].r[row].u64;
563 }
564
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200565 inline const ConstantVector &vector() const
566 {
567 return m.c[0];
568 }
569 inline uint32_t vector_size() const
570 {
571 return m.c[0].vecsize;
572 }
573 inline uint32_t columns() const
574 {
575 return m.columns;
576 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100577
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200578 SPIRConstant(uint32_t constant_type_, const uint32_t *elements, uint32_t num_elements)
579 : constant_type(constant_type_)
580 {
581 subconstants.insert(end(subconstants), elements, elements + num_elements);
582 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100583
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200584 SPIRConstant(uint32_t constant_type_, uint32_t v0)
585 : constant_type(constant_type_)
586 {
587 m.c[0].r[0].u32 = v0;
588 m.c[0].vecsize = 1;
589 m.columns = 1;
590 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100591
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200592 SPIRConstant(uint32_t constant_type_, uint32_t v0, uint32_t v1)
593 : constant_type(constant_type_)
594 {
595 m.c[0].r[0].u32 = v0;
596 m.c[0].r[1].u32 = v1;
597 m.c[0].vecsize = 2;
598 m.columns = 1;
599 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100600
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200601 SPIRConstant(uint32_t constant_type_, uint32_t v0, uint32_t v1, uint32_t v2)
602 : constant_type(constant_type_)
603 {
604 m.c[0].r[0].u32 = v0;
605 m.c[0].r[1].u32 = v1;
606 m.c[0].r[2].u32 = v2;
607 m.c[0].vecsize = 3;
608 m.columns = 1;
609 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100610
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200611 SPIRConstant(uint32_t constant_type_, uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3)
612 : constant_type(constant_type_)
613 {
614 m.c[0].r[0].u32 = v0;
615 m.c[0].r[1].u32 = v1;
616 m.c[0].r[2].u32 = v2;
617 m.c[0].r[3].u32 = v3;
618 m.c[0].vecsize = 4;
619 m.columns = 1;
620 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100621
Hans-Kristian Arntzenfa0255c2016-07-27 10:59:00 +0200622 SPIRConstant(uint32_t constant_type_, uint64_t v0)
623 : constant_type(constant_type_)
624 {
625 m.c[0].r[0].u64 = v0;
626 m.c[0].vecsize = 1;
627 m.columns = 1;
628 }
629
630 SPIRConstant(uint32_t constant_type_, uint64_t v0, uint64_t v1)
631 : constant_type(constant_type_)
632 {
633 m.c[0].r[0].u64 = v0;
634 m.c[0].r[1].u64 = v1;
635 m.c[0].vecsize = 2;
636 m.columns = 1;
637 }
638
639 SPIRConstant(uint32_t constant_type_, uint64_t v0, uint64_t v1, uint64_t v2)
640 : constant_type(constant_type_)
641 {
642 m.c[0].r[0].u64 = v0;
643 m.c[0].r[1].u64 = v1;
644 m.c[0].r[2].u64 = v2;
645 m.c[0].vecsize = 3;
646 m.columns = 1;
647 }
648
649 SPIRConstant(uint32_t constant_type_, uint64_t v0, uint64_t v1, uint64_t v2, uint64_t v3)
650 : constant_type(constant_type_)
651 {
652 m.c[0].r[0].u64 = v0;
653 m.c[0].r[1].u64 = v1;
654 m.c[0].r[2].u64 = v2;
655 m.c[0].r[3].u64 = v3;
656 m.c[0].vecsize = 4;
657 m.columns = 1;
658 }
659
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200660 SPIRConstant(uint32_t constant_type_, const ConstantVector &vec0)
661 : constant_type(constant_type_)
662 {
663 m.columns = 1;
664 m.c[0] = vec0;
665 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100666
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200667 SPIRConstant(uint32_t constant_type_, const ConstantVector &vec0, const ConstantVector &vec1)
668 : constant_type(constant_type_)
669 {
670 m.columns = 2;
671 m.c[0] = vec0;
672 m.c[1] = vec1;
673 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100674
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200675 SPIRConstant(uint32_t constant_type_, const ConstantVector &vec0, const ConstantVector &vec1,
676 const ConstantVector &vec2)
677 : constant_type(constant_type_)
678 {
679 m.columns = 3;
680 m.c[0] = vec0;
681 m.c[1] = vec1;
682 m.c[2] = vec2;
683 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100684
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200685 SPIRConstant(uint32_t constant_type_, const ConstantVector &vec0, const ConstantVector &vec1,
686 const ConstantVector &vec2, const ConstantVector &vec3)
687 : constant_type(constant_type_)
688 {
689 m.columns = 4;
690 m.c[0] = vec0;
691 m.c[1] = vec1;
692 m.c[2] = vec2;
693 m.c[3] = vec3;
694 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100695
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200696 uint32_t constant_type;
697 ConstantMatrix m;
698 bool specialization = false; // If the constant is a specialization constant.
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100699
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200700 // For composites which are constant arrays, etc.
701 std::vector<uint32_t> subconstants;
702};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100703
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200704class Variant
705{
706public:
707 // MSVC 2013 workaround, we shouldn't need these constructors.
708 Variant() = default;
709 Variant(Variant &&other)
710 {
711 *this = std::move(other);
712 }
713 Variant &operator=(Variant &&other)
714 {
715 if (this != &other)
716 {
717 holder = move(other.holder);
718 type = other.type;
719 other.type = TypeNone;
720 }
721 return *this;
722 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100723
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200724 void set(std::unique_ptr<IVariant> val, uint32_t new_type)
725 {
726 holder = std::move(val);
727 if (type != TypeNone && type != new_type)
728 throw CompilerError("Overwriting a variant with new type.");
729 type = new_type;
730 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100731
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200732 template <typename T>
733 T &get()
734 {
735 if (!holder)
736 throw CompilerError("nullptr");
737 if (T::type != type)
738 throw CompilerError("Bad cast");
739 return *static_cast<T *>(holder.get());
740 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100741
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200742 template <typename T>
743 const T &get() const
744 {
745 if (!holder)
746 throw CompilerError("nullptr");
747 if (T::type != type)
748 throw CompilerError("Bad cast");
749 return *static_cast<const T *>(holder.get());
750 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100751
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200752 uint32_t get_type() const
753 {
754 return type;
755 }
756 bool empty() const
757 {
758 return !holder;
759 }
760 void reset()
761 {
762 holder.reset();
763 type = TypeNone;
764 }
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100765
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200766private:
767 std::unique_ptr<IVariant> holder;
768 uint32_t type = TypeNone;
769};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100770
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200771template <typename T>
772T &variant_get(Variant &var)
773{
774 return var.get<T>();
775}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100776
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200777template <typename T>
778const T &variant_get(const Variant &var)
779{
780 return var.get<T>();
781}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100782
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200783template <typename T, typename... P>
784T &variant_set(Variant &var, P &&... args)
785{
786 auto uptr = std::unique_ptr<T>(new T(std::forward<P>(args)...));
787 auto ptr = uptr.get();
788 var.set(std::move(uptr), T::type);
789 return *ptr;
790}
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100791
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200792struct Meta
793{
794 struct Decoration
795 {
796 std::string alias;
797 uint64_t decoration_flags = 0;
798 spv::BuiltIn builtin_type;
799 uint32_t location = 0;
800 uint32_t set = 0;
801 uint32_t binding = 0;
802 uint32_t offset = 0;
803 uint32_t array_stride = 0;
804 uint32_t input_attachment = 0;
805 bool builtin = false;
806 bool per_instance = false;
807 };
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100808
Hans-Kristian Arntzen4b8ed532016-05-05 09:33:18 +0200809 Decoration decoration;
810 std::vector<Decoration> members;
811 uint32_t sampler = 0;
812};
Hans-Kristian Arntzen75471fb2016-03-02 18:09:16 +0100813}
814
815#endif