]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/spirv.cpp
Handle the flat and centroid qualifiers in SPIR-V output
[libs/gl.git] / source / glsl / spirv.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/core/maputils.h>
3 #include <msp/core/raii.h>
4 #include "reflect.h"
5 #include "spirv.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11 namespace SL {
12
13 const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] =
14 {
15         { "radians", "f", "GLSL.std.450", GLSL450_RADIANS, { 1 }, 0, 0 },
16         { "degrees", "f", "GLSL.std.450", GLSL450_DEGREES, { 1 }, 0, 0 },
17         { "sin", "f", "GLSL.std.450", GLSL450_SIN, { 1 }, 0, 0 },
18         { "cos", "f", "GLSL.std.450", GLSL450_COS, { 1 }, 0, 0 },
19         { "tan", "f", "GLSL.std.450", GLSL450_TAN, { 1 }, 0, 0 },
20         { "asin", "f", "GLSL.std.450", GLSL450_ASIN, { 1 }, 0, 0 },
21         { "acos", "f", "GLSL.std.450", GLSL450_ACOS, { 1 }, 0, 0 },
22         { "atan", "f", "GLSL.std.450", GLSL450_ATAN, { 1 }, 0, 0 },
23         { "atan", "ff", "GLSL.std.450", GLSL450_ATAN2, { 1, 2 }, 0, 0 },
24         { "sinh", "f", "GLSL.std.450", GLSL450_SINH, { 1 }, 0, 0 },
25         { "cosh", "f", "GLSL.std.450", GLSL450_COSH, { 1 }, 0, 0 },
26         { "tanh", "f", "GLSL.std.450", GLSL450_TANH, { 1 }, 0, 0 },
27         { "asinh", "f", "GLSL.std.450", GLSL450_ASINH, { 1 }, 0, 0 },
28         { "acosh", "f", "GLSL.std.450", GLSL450_ACOSH, { 1 }, 0, 0 },
29         { "atanh", "f", "GLSL.std.450", GLSL450_ATANH, { 1 }, 0, 0 },
30         { "pow", "ff", "GLSL.std.450", GLSL450_POW, { 1, 2 }, 0, 0 },
31         { "exp", "f", "GLSL.std.450", GLSL450_EXP, { 1 }, 0, 0 },
32         { "log", "f", "GLSL.std.450", GLSL450_LOG, { 1 }, 0, 0 },
33         { "exp2", "f", "GLSL.std.450", GLSL450_EXP2, { 1 }, 0, 0 },
34         { "log2", "f", "GLSL.std.450", GLSL450_LOG2, { 1 }, 0, 0 },
35         { "sqrt", "f", "GLSL.std.450", GLSL450_SQRT, { 1 }, 0, 0 },
36         { "inversesqrt", "f", "GLSL.std.450", GLSL450_INVERSE_SQRT, { 1 }, 0, 0 },
37         { "abs", "f", "GLSL.std.450", GLSL450_F_ABS, { 1 }, 0, 0 },
38         { "abs", "i", "GLSL.std.450", GLSL450_S_ABS, { 1 }, 0, 0 },
39         { "sign", "f", "GLSL.std.450", GLSL450_F_SIGN, { 1 }, 0, 0 },
40         { "sign", "i", "GLSL.std.450", GLSL450_S_SIGN, { 1 }, 0, 0 },
41         { "floor", "f", "GLSL.std.450", GLSL450_FLOOR, { 1 }, 0, 0 },
42         { "trunc", "f", "GLSL.std.450", GLSL450_TRUNC, { 1 }, 0, 0 },
43         { "round", "f", "GLSL.std.450", GLSL450_ROUND, { 1 }, 0, 0 },
44         { "roundEven", "f", "GLSL.std.450", GLSL450_ROUND_EVEN, { 1 }, 0, 0 },
45         { "ceil", "f", "GLSL.std.450", GLSL450_CEIL, { 1 }, 0, 0 },
46         { "fract", "f", "GLSL.std.450", GLSL450_FRACT, { 1 }, 0, 0 },
47         { "mod", "f", "", OP_F_MOD, { 1, 2 }, 0, 0 },
48         { "min", "ff", "GLSL.std.450", GLSL450_F_MIN, { 1, 2 }, 0, 0 },
49         { "min", "ii", "GLSL.std.450", GLSL450_S_MIN, { 1, 2 }, 0, 0 },
50         { "min", "uu", "GLSL.std.450", GLSL450_U_MIN, { 1, 2 }, 0, 0 },
51         { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0, 0 },
52         { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0, 0 },
53         { "max", "uu", "GLSL.std.450", GLSL450_U_MAX, { 1, 2 }, 0, 0 },
54         { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0, 0 },
55         { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0, 0 },
56         { "clamp", "uuu", "GLSL.std.450", GLSL450_U_CLAMP, { 1, 2, 3 }, 0, 0 },
57         { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0, 0 },
58         { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
59         { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
60         { "mix", "uub", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
61         { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0, 0 },
62         { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0, 0 },
63         { "isnan", "f", "", OP_IS_NAN, { 1 }, 0, 0 },
64         { "isinf", "f", "", OP_IS_INF, { 1 }, 0, 0 },
65         { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0, 0 },
66         { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0, 0 },
67         { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0, 0 },
68         { "dot", "ff", "", OP_DOT, { 1, 2 }, 0, 0 },
69         { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0, 0 },
70         { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0, 0 },
71         { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0, 0 },
72         { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0, 0 },
73         { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0, 0 },
74         { "matrixCompMult", "ff", "", 0, { 0 }, 0, &SpirVGenerator::visit_builtin_matrix_comp_mult },
75         { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0, 0 },
76         { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0, 0 },
77         { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0, 0 },
78         { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0, 0 },
79         { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0, 0 },
80         { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0, 0 },
81         { "lessThan", "uu", "", OP_U_LESS_THAN, { 1, 2 }, 0, 0 },
82         { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
83         { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
84         { "lessThanEqual", "uu", "", OP_U_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
85         { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0, 0 },
86         { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0, 0 },
87         { "greaterThan", "uu", "", OP_U_GREATER_THAN, { 1, 2 }, 0, 0 },
88         { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
89         { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
90         { "greaterThanEqual", "uu", "", OP_U_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
91         { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0, 0 },
92         { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0, 0 },
93         { "equal", "uu", "", OP_I_EQUAL, { 1, 2 }, 0, 0 },
94         { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0, 0 },
95         { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 },
96         { "notEqual", "uu", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 },
97         { "any", "b", "", OP_ANY, { 1 }, 0, 0 },
98         { "all", "b", "", OP_ALL, { 1 }, 0, 0 },
99         { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0, 0 },
100         { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0, 0 },
101         { "bitfieldExtract", "uii", "", OP_BIT_FIELD_U_EXTRACT, { 1, 2, 3 }, 0, 0 },
102         { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 },
103         { "bitfieldInsert", "uuii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 },
104         { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0, 0 },
105         { "bitfieldReverse", "u", "", OP_BIT_REVERSE, { 1 }, 0, 0 },
106         { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0, 0 },
107         { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 },
108         { "findLSB", "u", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 },
109         { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0, 0 },
110         { "findMSB", "u", "GLSL.std.450", GLSL450_FIND_U_MSB, { 1 }, 0, 0 },
111         { "textureSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
112         { "textureQueryLod", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
113         { "textureQueryLevels", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
114         { "textureSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
115         { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture },
116         { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture },
117         { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch },
118         { "imageSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
119         { "imageSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
120         { "imageLoad", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch },
121         { "imageStore", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_store },
122         { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 },
123         { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 },
124         { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 },
125         { "dFdy", "f", "", OP_DP_DY, { 1 }, 0, 0 },
126         { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
127         { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
128         { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
129         { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
130         { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0, 0 },
131         { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
132         { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
133         { "interpolateAtCentroid", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
134         { "interpolateAtSample", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
135         { "interpolateAtOffset", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
136         { "", "", "", 0, { }, 0, 0 }
137 };
138
139 SpirVGenerator::SpirVGenerator():
140         writer(content)
141 { }
142
143 void SpirVGenerator::apply(Module &module, const Features &f)
144 {
145         features = f;
146         use_capability(CAP_SHADER);
147
148         for(Stage &s: module.stages)
149         {
150                 stage = &s;
151                 interface_layouts.clear();
152                 s.content.visit(*this);
153         }
154
155         writer.finalize(SPIRV_GENERATOR_MSP, next_id);
156 }
157
158 SpirVGenerator::StorageClass SpirVGenerator::get_interface_storage(const string &iface, bool block)
159 {
160         if(iface=="in")
161                 return STORAGE_INPUT;
162         else if(iface=="out")
163                 return STORAGE_OUTPUT;
164         else if(iface=="uniform")
165                 return (block ? STORAGE_UNIFORM : STORAGE_UNIFORM_CONSTANT);
166         else if(iface.empty())
167                 return STORAGE_PRIVATE;
168         else
169                 throw invalid_argument("SpirVGenerator::get_interface_storage");
170 }
171
172 SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const string &name)
173 {
174         if(name=="gl_Position")
175                 return BUILTIN_POSITION;
176         else if(name=="gl_PointSize")
177                 return BUILTIN_POINT_SIZE;
178         else if(name=="gl_ClipDistance")
179                 return BUILTIN_CLIP_DISTANCE;
180         else if(name=="gl_VertexID")
181                 return BUILTIN_VERTEX_ID;
182         else if(name=="gl_InstanceID")
183                 return BUILTIN_INSTANCE_ID;
184         else if(name=="gl_PrimitiveID" || name=="gl_PrimitiveIDIn")
185                 return BUILTIN_PRIMITIVE_ID;
186         else if(name=="gl_InvocationID")
187                 return BUILTIN_INVOCATION_ID;
188         else if(name=="gl_Layer")
189                 return BUILTIN_LAYER;
190         else if(name=="gl_FragCoord")
191                 return BUILTIN_FRAG_COORD;
192         else if(name=="gl_PointCoord")
193                 return BUILTIN_POINT_COORD;
194         else if(name=="gl_FrontFacing")
195                 return BUILTIN_FRONT_FACING;
196         else if(name=="gl_SampleId")
197                 return BUILTIN_SAMPLE_ID;
198         else if(name=="gl_SamplePosition")
199                 return BUILTIN_SAMPLE_POSITION;
200         else if(name=="gl_FragDepth")
201                 return BUILTIN_FRAG_DEPTH;
202         else if(name=="gl_NumWorkGroups")
203                 return BUILTIN_NUM_WORKGROUPS;
204         else if(name=="gl_WorkGroupSize")
205                 return BUILTIN_WORKGROUP_SIZE;
206         else if(name=="gl_WorkGroupID")
207                 return BUILTIN_WORKGROUP_ID;
208         else if(name=="gl_LocalInvocationID")
209                 return BUILTIN_LOCAL_INVOCATION_ID;
210         else if(name=="gl_GlobalInvocationID")
211                 return BUILTIN_GLOBAL_INVOCATION_ID;
212         else if(name=="gl_LocalInvocationIndex")
213                 return BUILTIN_LOCAL_INVOCATION_INDEX;
214         else
215                 throw invalid_argument("SpirVGenerator::get_builtin_semantic");
216 }
217
218 SpirVFormat SpirVGenerator::get_format(const std::string &name)
219 {
220         if(name.empty())
221                 return FORMAT_UNKNOWN;
222         else if(name=="rgba32f")
223                 return FORMAT_RGBA32F;
224         else if(name=="rgba16f")
225                 return FORMAT_RGBA16F;
226         else if(name=="r32f")
227                 return FORMAT_R32F;
228         else if(name=="rgba8")
229                 return FORMAT_RGBA8;
230         else if(name=="rgba8_snorm")
231                 return FORMAT_RGBA8_SNORM;
232         else if(name=="rg32f")
233                 return FORMAT_RG32F;
234         else if(name=="rg16f")
235                 return FORMAT_RG16F;
236         else if(name=="r16f")
237                 return FORMAT_R16F;
238         else if(name=="rgba16")
239                 return FORMAT_RGBA16;
240         else if(name=="rg16")
241                 return FORMAT_RG16;
242         else if(name=="rg8")
243                 return FORMAT_RG8;
244         else if(name=="r16")
245                 return FORMAT_RG16;
246         else if(name=="r8")
247                 return FORMAT_RG8;
248         else if(name=="rgba16_snorm")
249                 return FORMAT_RGBA16_SNORM;
250         else if(name=="rg16_snorm")
251                 return FORMAT_RG16_SNORM;
252         else if(name=="rg8_snorm")
253                 return FORMAT_RG8_SNORM;
254         else if(name=="r16_snorm")
255                 return FORMAT_RG16_SNORM;
256         else if(name=="r8_snorm")
257                 return FORMAT_RG8_SNORM;
258         else
259                 throw invalid_argument("SpirVGenerator::get_format");
260 }
261
262 void SpirVGenerator::use_capability(Capability cap)
263 {
264         if(used_capabilities.count(cap))
265                 return;
266
267         used_capabilities.insert(cap);
268         writer.write_op(content.capabilities, OP_CAPABILITY, cap);
269 }
270
271 SpirVGenerator::Id SpirVGenerator::import_extension(const string &name)
272 {
273         Id &ext_id = imported_extension_ids[name];
274         if(!ext_id)
275         {
276                 ext_id = next_id++;
277                 writer.begin_op(content.extensions, OP_EXT_INST_IMPORT);
278                 writer.write(ext_id);
279                 writer.write_string(name);
280                 writer.end_op(OP_EXT_INST_IMPORT);
281         }
282         return ext_id;
283 }
284
285 SpirVGenerator::Id SpirVGenerator::get_id(Node &node) const
286 {
287         return get_item(declared_ids, &node).id;
288 }
289
290 SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id)
291 {
292         auto i = declared_ids.find(&node);
293         if(i!=declared_ids.end())
294         {
295                 if(i->second.type_id)
296                         throw key_error(&node);
297                 i->second.type_id = type_id;
298                 return i->second.id;
299         }
300
301         Id id = next_id++;
302         declared_ids.insert(make_pair(&node, Declaration(id, type_id)));
303         return id;
304 }
305
306 SpirVGenerator::Id SpirVGenerator::allocate_forward_id(Node &node)
307 {
308         auto i = declared_ids.find(&node);
309         if(i!=declared_ids.end())
310                 return i->second.id;
311
312         Id id = next_id++;
313         declared_ids.insert(make_pair(&node, Declaration(id, 0)));
314         return id;
315 }
316
317 SpirVGenerator::Id SpirVGenerator::write_constant(Id type_id, Word value, bool spec)
318 {
319         Id const_id = next_id++;
320         if(is_scalar_type(type_id, BasicTypeDeclaration::BOOL))
321         {
322                 Opcode opcode = (value ? (spec ? OP_SPEC_CONSTANT_TRUE : OP_CONSTANT_TRUE) :
323                         (spec ? OP_SPEC_CONSTANT_FALSE : OP_CONSTANT_FALSE));
324                 writer.write_op(content.globals, opcode, type_id, const_id);
325         }
326         else
327         {
328                 Opcode opcode = (spec ? OP_SPEC_CONSTANT : OP_CONSTANT);
329                 writer.write_op(content.globals, opcode, type_id, const_id, value);
330         }
331         return const_id;
332 }
333
334 SpirVGenerator::ConstantKey SpirVGenerator::get_constant_key(Id type_id, const Variant &value)
335 {
336         if(value.check_type<bool>())
337                 return ConstantKey(type_id, value.value<bool>());
338         else if(value.check_type<int>())
339                 return ConstantKey(type_id, value.value<int>());
340         else if(value.check_type<unsigned>())
341                 return ConstantKey(type_id, value.value<unsigned>());
342         else if(value.check_type<float>())
343                 return ConstantKey(type_id, value.value<float>());
344         else
345                 throw invalid_argument("SpirVGenerator::get_constant_key");
346 }
347
348 SpirVGenerator::Id SpirVGenerator::get_constant_id(Id type_id, const Variant &value)
349 {
350         ConstantKey key = get_constant_key(type_id, value);
351         Id &const_id = constant_ids[key];
352         if(!const_id)
353                 const_id = write_constant(type_id, key.int_value, false);
354         return const_id;
355 }
356
357 SpirVGenerator::Id SpirVGenerator::get_vector_constant_id(Id type_id, unsigned size, Id scalar_id)
358 {
359         Id &const_id = constant_ids[get_constant_key(type_id, static_cast<int>(scalar_id))];
360         if(!const_id)
361         {
362                 const_id = next_id++;
363                 writer.begin_op(content.globals, OP_CONSTANT_COMPOSITE, 3+size);
364                 writer.write(type_id);
365                 writer.write(const_id);
366                 for(unsigned i=0; i<size; ++i)
367                         writer.write(scalar_id);
368                 writer.end_op(OP_CONSTANT_COMPOSITE);
369         }
370         return const_id;
371 }
372
373 SpirVGenerator::Id SpirVGenerator::get_standard_type_id(BasicTypeDeclaration::Kind kind, unsigned size, bool sign)
374 {
375         Id base_id = (size>1 ? get_standard_type_id(kind, 1, sign) : 0);
376         Id &type_id = standard_type_ids[base_id ? TypeKey(base_id, size) : TypeKey(kind, sign)];
377         if(!type_id)
378         {
379                 type_id = next_id++;
380                 if(size>1)
381                         writer.write_op(content.globals, OP_TYPE_VECTOR, type_id, base_id, size);
382                 else if(kind==BasicTypeDeclaration::VOID)
383                         writer.write_op(content.globals, OP_TYPE_VOID, type_id);
384                 else if(kind==BasicTypeDeclaration::BOOL)
385                         writer.write_op(content.globals, OP_TYPE_BOOL, type_id);
386                 else if(kind==BasicTypeDeclaration::INT)
387                         writer.write_op(content.globals, OP_TYPE_INT, type_id, 32, sign);
388                 else if(kind==BasicTypeDeclaration::FLOAT)
389                         writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, 32);
390                 else
391                         throw invalid_argument("SpirVGenerator::get_standard_type_id");
392         }
393         return type_id;
394 }
395
396 bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind) const
397 {
398         auto i = standard_type_ids.find(TypeKey(kind, true));
399         return (i!=standard_type_ids.end() && i->second==type_id);
400 }
401
402 SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id, bool extended_align)
403 {
404         Id base_type_id = get_id(base_type);
405         Id &array_type_id = array_type_ids[TypeKey(base_type_id, extended_align*0x400000 | size_id)];
406         if(!array_type_id)
407         {
408                 array_type_id = next_id++;
409                 if(size_id)
410                         writer.write_op(content.globals, OP_TYPE_ARRAY, array_type_id, base_type_id, size_id);
411                 else
412                         writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id);
413
414                 unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride;
415                 if(extended_align)
416                         stride = (stride+15)&~15U;
417                 writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride);
418         }
419
420         return array_type_id;
421 }
422
423 SpirVGenerator::Id SpirVGenerator::get_pointer_type_id(Id type_id, StorageClass storage)
424 {
425         Id &ptr_type_id = pointer_type_ids[TypeKey(type_id, storage)];
426         if(!ptr_type_id)
427         {
428                 ptr_type_id = next_id++;
429                 writer.write_op(content.globals, OP_TYPE_POINTER, ptr_type_id, storage, type_id);
430         }
431         return ptr_type_id;
432 }
433
434 SpirVGenerator::Id SpirVGenerator::get_variable_type_id(const VariableDeclaration &var)
435 {
436         if(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var.type_declaration))
437                 if(basic->kind==BasicTypeDeclaration::ARRAY)
438                 {
439                         if(!var.array_size)
440                                 throw logic_error("array without size");
441
442                         SetFlag set_const(constant_expression);
443                         r_expression_result_id = 0;
444                         var.array_size->visit(*this);
445                         return get_array_type_id(*basic->base_type, r_expression_result_id, basic->extended_alignment);
446                 }
447
448         return get_id(*var.type_declaration);
449 }
450
451 SpirVGenerator::Id SpirVGenerator::get_load_id(VariableDeclaration &var)
452 {
453         Id &load_result_id = variable_load_ids[&var];
454         if(!load_result_id)
455         {
456                 load_result_id = next_id++;
457                 writer.write_op(content.function_body, OP_LOAD, get_variable_type_id(var), load_result_id, get_id(var));
458         }
459         return load_result_id;
460 }
461
462 void SpirVGenerator::prune_loads(Id min_id)
463 {
464         for(auto i=variable_load_ids.begin(); i!=variable_load_ids.end(); )
465         {
466                 if(i->second>=min_id)
467                         variable_load_ids.erase(i++);
468                 else
469                         ++i;
470         }
471 }
472
473 SpirVGenerator::Id SpirVGenerator::begin_expression(Opcode opcode, Id type_id, unsigned n_args)
474 {
475         bool has_result = (opcode==OP_FUNCTION_CALL || !is_scalar_type(type_id, BasicTypeDeclaration::VOID));
476         if(!constant_expression)
477         {
478                 if(!current_function)
479                         throw internal_error("non-constant expression outside a function");
480
481                 writer.begin_op(content.function_body, opcode, (n_args ? 1+has_result*2+n_args : 0));
482         }
483         else if(opcode==OP_COMPOSITE_CONSTRUCT)
484                 writer.begin_op(content.globals, (spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE),
485                         (n_args ? 1+has_result*2+n_args : 0));
486         else if(!spec_constant)
487                 throw internal_error("invalid non-specialization constant expression");
488         else
489                 writer.begin_op(content.globals, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
490
491         Id result_id = next_id++;
492         if(has_result)
493         {
494                 writer.write(type_id);
495                 writer.write(result_id);
496         }
497         if(spec_constant && opcode!=OP_COMPOSITE_CONSTRUCT)
498                 writer.write(opcode);
499
500         return result_id;
501 }
502
503 void SpirVGenerator::end_expression(Opcode opcode)
504 {
505         if(constant_expression)
506                 opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP);
507         writer.end_op(opcode);
508 }
509
510 SpirVGenerator::Id SpirVGenerator::write_expression(Opcode opcode, Id type_id, Id arg_id)
511 {
512         Id result_id = begin_expression(opcode, type_id, 1);
513         writer.write(arg_id);
514         end_expression(opcode);
515         return result_id;
516 }
517
518 SpirVGenerator::Id SpirVGenerator::write_expression(Opcode opcode, Id type_id, Id left_id, Id right_id)
519 {
520         Id result_id = begin_expression(opcode, type_id, 2);
521         writer.write(left_id);
522         writer.write(right_id);
523         end_expression(opcode);
524         return result_id;
525 }
526
527 void SpirVGenerator::write_deconstruct(Id elem_type_id, Id composite_id, Id *elem_ids, unsigned n_elems)
528 {
529         for(unsigned i=0; i<n_elems; ++i)
530         {
531                 elem_ids[i] = begin_expression(OP_COMPOSITE_EXTRACT, elem_type_id, 2);
532                 writer.write(composite_id);
533                 writer.write(i);
534                 end_expression(OP_COMPOSITE_EXTRACT);
535         }
536 }
537
538 SpirVGenerator::Id SpirVGenerator::write_construct(Id type_id, const Id *elem_ids, unsigned n_elems)
539 {
540         Id result_id = begin_expression(OP_COMPOSITE_CONSTRUCT, type_id, n_elems);
541         for(unsigned i=0; i<n_elems; ++i)
542                 writer.write(elem_ids[i]);
543         end_expression(OP_COMPOSITE_CONSTRUCT);
544
545         return result_id;
546 }
547
548 void SpirVGenerator::visit(Block &block)
549 {
550         for(const RefPtr<Statement> &s: block.body)
551                 s->visit(*this);
552 }
553
554 void SpirVGenerator::visit(Literal &literal)
555 {
556         Id type_id = get_id(*literal.type);
557         if(spec_constant)
558                 r_expression_result_id = write_constant(type_id, get_constant_key(type_id, literal.value).int_value, true);
559         else
560                 r_expression_result_id = get_constant_id(type_id, literal.value);
561         r_constant_result = true;
562 }
563
564 void SpirVGenerator::visit(VariableReference &var)
565 {
566         if(constant_expression || var.declaration->constant)
567         {
568                 if(!var.declaration->constant)
569                         throw internal_error("reference to non-constant variable in constant context");
570
571                 r_expression_result_id = get_id(*var.declaration);
572                 r_constant_result = true;
573                 return;
574         }
575         else if(!current_function)
576                 throw internal_error("non-constant context outside a function");
577
578         r_constant_result = false;
579         if(composite_access)
580         {
581                 r_expression_result_id = 0;
582                 if(!assignment_source_id)
583                 {
584                         auto i = variable_load_ids.find(var.declaration);
585                         if(i!=variable_load_ids.end())
586                                 r_expression_result_id = i->second;
587                 }
588                 if(!r_expression_result_id)
589                         r_composite_base = var.declaration;
590         }
591         else if(assignment_source_id)
592         {
593                 writer.write_op(content.function_body, OP_STORE, get_id(*var.declaration), assignment_source_id);
594                 variable_load_ids[var.declaration] = assignment_source_id;
595                 r_expression_result_id = assignment_source_id;
596         }
597         else
598                 r_expression_result_id = get_load_id(*var.declaration);
599 }
600
601 void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type)
602 {
603         Opcode opcode;
604         Id result_type_id = get_id(result_type);
605         Id access_type_id = result_type_id;
606         if(r_composite_base)
607         {
608                 if(constant_expression)
609                         throw internal_error("composite access through pointer in constant context");
610
611                 Id int32_type_id = get_standard_type_id(BasicTypeDeclaration::INT, 1);
612                 for(unsigned &i: r_composite_chain)
613                         i = (i<0x400000 ? get_constant_id(int32_type_id, static_cast<int>(i)) : i&0x3FFFFF);
614
615                 /* Find the storage class of the base and obtain appropriate pointer type
616                 for the result. */
617                 const Declaration &base_decl = get_item(declared_ids, r_composite_base);
618                 auto i = pointer_type_ids.begin();
619                 for(; (i!=pointer_type_ids.end() && i->second!=base_decl.type_id); ++i) ;
620                 if(i==pointer_type_ids.end())
621                         throw internal_error("could not find storage class");
622                 access_type_id = get_pointer_type_id(result_type_id, static_cast<StorageClass>(i->first.detail));
623
624                 opcode = OP_ACCESS_CHAIN;
625         }
626         else if(assignment_source_id)
627                 throw internal_error("assignment to temporary composite");
628         else
629         {
630                 for(unsigned &i: r_composite_chain)
631                         for(auto j=constant_ids.begin(); (i>=0x400000 && j!=constant_ids.end()); ++j)
632                                 if(j->second==(i&0x3FFFFF))
633                                         i = j->first.int_value;
634
635                 opcode = OP_COMPOSITE_EXTRACT;
636         }
637
638         Id access_id = begin_expression(opcode, access_type_id, 1+r_composite_chain.size());
639         writer.write(r_composite_base_id);
640         for(unsigned i: r_composite_chain)
641                 writer.write(i);
642         end_expression(opcode);
643
644         r_constant_result = false;
645         if(r_composite_base)
646         {
647                 if(assignment_source_id)
648                 {
649                         writer.write_op(content.function_body, OP_STORE, access_id, assignment_source_id);
650                         r_expression_result_id = assignment_source_id;
651                 }
652                 else
653                         r_expression_result_id = write_expression(OP_LOAD, result_type_id, access_id);
654         }
655         else
656                 r_expression_result_id = access_id;
657 }
658
659 void SpirVGenerator::visit_composite(Expression &base_expr, unsigned index, TypeDeclaration &type)
660 {
661         if(!composite_access)
662         {
663                 r_composite_base = 0;
664                 r_composite_base_id = 0;
665                 r_composite_chain.clear();
666         }
667
668         {
669                 SetFlag set_composite(composite_access);
670                 base_expr.visit(*this);
671         }
672
673         if(!r_composite_base_id)
674                 r_composite_base_id = (r_composite_base ? get_id(*r_composite_base) : r_expression_result_id);
675
676         r_composite_chain.push_back(index);
677         if(!composite_access)
678                 generate_composite_access(type);
679         else
680                 r_expression_result_id = 0;
681 }
682
683 void SpirVGenerator::visit_isolated(Expression &expr)
684 {
685         SetForScope<Id> clear_assign(assignment_source_id, 0);
686         SetFlag clear_composite(composite_access, false);
687         SetForScope<Node *> clear_base(r_composite_base, 0);
688         SetForScope<Id> clear_base_id(r_composite_base_id, 0);
689         vector<unsigned> saved_chain;
690         swap(saved_chain, r_composite_chain);
691         expr.visit(*this);
692         swap(saved_chain, r_composite_chain);
693 }
694
695 void SpirVGenerator::visit(MemberAccess &memacc)
696 {
697         visit_composite(*memacc.left, memacc.index, *memacc.type);
698 }
699
700 void SpirVGenerator::visit(Swizzle &swizzle)
701 {
702         if(swizzle.count==1)
703                 visit_composite(*swizzle.left, swizzle.components[0], *swizzle.type);
704         else if(assignment_source_id)
705         {
706                 const BasicTypeDeclaration &basic = dynamic_cast<const BasicTypeDeclaration &>(*swizzle.left->type);
707
708                 unsigned mask = 0;
709                 for(unsigned i=0; i<swizzle.count; ++i)
710                         mask |= 1<<swizzle.components[i];
711
712                 visit_isolated(*swizzle.left);
713
714                 Id combined_id = begin_expression(OP_VECTOR_SHUFFLE, get_id(*swizzle.left->type), 2+basic.size);
715                 writer.write(r_expression_result_id);
716                 writer.write(assignment_source_id);
717                 for(unsigned i=0; i<basic.size; ++i)
718                         writer.write(i+((mask>>i)&1)*basic.size);
719                 end_expression(OP_VECTOR_SHUFFLE);
720
721                 SetForScope<Id> set_assign(assignment_source_id, combined_id);
722                 swizzle.left->visit(*this);
723
724                 r_expression_result_id = combined_id;
725         }
726         else
727         {
728                 swizzle.left->visit(*this);
729                 Id left_id = r_expression_result_id;
730
731                 r_expression_result_id = begin_expression(OP_VECTOR_SHUFFLE, get_id(*swizzle.type), 2+swizzle.count);
732                 writer.write(left_id);
733                 writer.write(left_id);
734                 for(unsigned i=0; i<swizzle.count; ++i)
735                         writer.write(swizzle.components[i]);
736                 end_expression(OP_VECTOR_SHUFFLE);
737         }
738         r_constant_result = false;
739 }
740
741 void SpirVGenerator::visit(UnaryExpression &unary)
742 {
743         if(composite_access)
744                 return visit_isolated(unary);
745
746         unary.expression->visit(*this);
747
748         char oper = unary.oper->token[0];
749         char oper2 = unary.oper->token[1];
750         if(oper=='+' && !oper2)
751                 return;
752
753         BasicTypeDeclaration &basic = dynamic_cast<BasicTypeDeclaration &>(*unary.expression->type);
754         BasicTypeDeclaration &elem = *get_element_type(basic);
755
756         if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
757                 /* SPIR-V allows constant operations on floating-point values only for
758                 OpenGL kernels. */
759                 throw internal_error("invalid operands for constant unary expression");
760
761         Id result_type_id = get_id(*unary.type);
762         Opcode opcode = OP_NOP;
763
764         r_constant_result = false;
765         if(oper=='!')
766                 opcode = OP_LOGICAL_NOT;
767         else if(oper=='~')
768                 opcode = OP_NOT;
769         else if(oper=='-' && !oper2)
770         {
771                 opcode = (elem.kind==BasicTypeDeclaration::INT ? OP_S_NEGATE : OP_F_NEGATE);
772
773                 if(basic.kind==BasicTypeDeclaration::MATRIX)
774                 {
775                         Id column_type_id = get_id(*basic.base_type);
776                         unsigned n_columns = basic.size&0xFFFF;
777                         Id column_ids[4];
778                         write_deconstruct(column_type_id, r_expression_result_id, column_ids, n_columns);
779                         for(unsigned i=0; i<n_columns; ++i)
780                                 column_ids[i] = write_expression(opcode, column_type_id, column_ids[i]);
781                         r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
782                         return;
783                 }
784         }
785         else if((oper=='+' || oper=='-') && oper2==oper)
786         {
787                 if(constant_expression)
788                         throw internal_error("increment or decrement in constant expression");
789
790                 Id one_id = 0;
791                 if(elem.kind==BasicTypeDeclaration::INT)
792                 {
793                         opcode = (oper=='+' ? OP_I_ADD : OP_I_SUB);
794                         one_id = get_constant_id(get_id(elem), 1);
795                 }
796                 else if(elem.kind==BasicTypeDeclaration::FLOAT)
797                 {
798                         opcode = (oper=='+' ? OP_F_ADD : OP_F_SUB);
799                         one_id = get_constant_id(get_id(elem), 1.0f);
800                 }
801                 else
802                         throw internal_error("invalid increment/decrement");
803
804                 if(basic.kind==BasicTypeDeclaration::VECTOR)
805                         one_id = get_vector_constant_id(result_type_id, basic.size, one_id);
806
807                 Id post_value_id = write_expression(opcode, result_type_id, r_expression_result_id, one_id);
808
809                 SetForScope<Id> set_assign(assignment_source_id, post_value_id);
810                 unary.expression->visit(*this);
811
812                 r_expression_result_id = (unary.oper->type==Operator::POSTFIX ? r_expression_result_id : post_value_id);
813                 return;
814         }
815
816         if(opcode==OP_NOP)
817                 throw internal_error("unknown unary operator");
818
819         r_expression_result_id = write_expression(opcode, result_type_id, r_expression_result_id);
820 }
821
822 void SpirVGenerator::visit(BinaryExpression &binary)
823 {
824         char oper = binary.oper->token[0];
825         if(oper=='[')
826         {
827                 visit_isolated(*binary.right);
828                 return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type);
829         }
830         else if(composite_access)
831                 return visit_isolated(binary);
832
833         if(assignment_source_id)
834                 throw internal_error("invalid binary expression in assignment target");
835
836         BasicTypeDeclaration &basic_left = dynamic_cast<BasicTypeDeclaration &>(*binary.left->type);
837         BasicTypeDeclaration &basic_right = dynamic_cast<BasicTypeDeclaration &>(*binary.right->type);
838         // Expression resolver ensures that element types are the same
839         BasicTypeDeclaration &elem = *get_element_type(basic_left);
840
841         if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
842                 /* SPIR-V allows constant operations on floating-point values only for
843                 OpenGL kernels. */
844                 throw internal_error("invalid operands for constant binary expression");
845
846         binary.left->visit(*this);
847         Id left_id = r_expression_result_id;
848         binary.right->visit(*this);
849         Id right_id = r_expression_result_id;
850
851         Id result_type_id = get_id(*binary.type);
852         Opcode opcode = OP_NOP;
853         bool swap_operands = false;
854
855         r_constant_result = false;
856
857         char oper2 = binary.oper->token[1];
858         if((oper=='<' || oper=='>') && oper2!=oper)
859         {
860                 if(basic_left.kind==BasicTypeDeclaration::INT)
861                 {
862                         if(basic_left.sign)
863                                 opcode = (oper=='<' ? (oper2=='=' ? OP_S_LESS_THAN_EQUAL : OP_S_LESS_THAN) :
864                                         (oper2=='=' ? OP_S_GREATER_THAN_EQUAL : OP_S_GREATER_THAN));
865                         else
866                                 opcode = (oper=='<' ? (oper2=='=' ? OP_U_LESS_THAN_EQUAL : OP_U_LESS_THAN) :
867                                         (oper2=='=' ? OP_U_GREATER_THAN_EQUAL : OP_U_GREATER_THAN));
868                 }
869                 else if(basic_left.kind==BasicTypeDeclaration::FLOAT)
870                         opcode = (oper=='<' ? (oper2=='=' ? OP_F_ORD_LESS_THAN_EQUAL : OP_F_ORD_LESS_THAN) :
871                                 (oper2=='=' ? OP_F_ORD_GREATER_THAN_EQUAL : OP_F_ORD_GREATER_THAN));
872         }
873         else if((oper=='=' || oper=='!') && oper2=='=')
874         {
875                 if(elem.kind==BasicTypeDeclaration::BOOL)
876                         opcode = (oper=='=' ? OP_LOGICAL_EQUAL : OP_LOGICAL_NOT_EQUAL);
877                 else if(elem.kind==BasicTypeDeclaration::INT)
878                         opcode = (oper=='=' ? OP_I_EQUAL : OP_I_NOT_EQUAL);
879                 else if(elem.kind==BasicTypeDeclaration::FLOAT)
880                         opcode = (oper=='=' ? OP_F_ORD_EQUAL : OP_F_ORD_NOT_EQUAL);
881
882                 if(opcode!=OP_NOP && basic_left.base_type)
883                 {
884                         /* The SPIR-V equality operations produce component-wise results, but
885                         GLSL operators return a single boolean.  Use the any/all operations to
886                         combine the results. */
887                         Opcode combine_op = (oper=='!' ? OP_ANY : OP_ALL);
888                         unsigned n_elems = basic_left.size&0xFFFF;
889                         Id bool_vec_type_id = get_standard_type_id(BasicTypeDeclaration::BOOL, n_elems);
890
891                         Id compare_id = 0;
892                         if(basic_left.kind==BasicTypeDeclaration::VECTOR)
893                                 compare_id = write_expression(opcode, bool_vec_type_id, left_id, right_id);
894                         else if(basic_left.kind==BasicTypeDeclaration::MATRIX)
895                         {
896                                 Id column_type_id = get_id(*basic_left.base_type);
897                                 Id column_ids[8];
898                                 write_deconstruct(column_type_id, left_id, column_ids, n_elems);
899                                 write_deconstruct(column_type_id, right_id, column_ids+4, n_elems);
900
901                                 Id column_bvec_type_id = get_standard_type_id(BasicTypeDeclaration::BOOL, basic_left.size>>16);
902                                 for(unsigned i=0; i<n_elems; ++i)
903                                 {
904                                         compare_id = write_expression(opcode, column_bvec_type_id, column_ids[i], column_ids[4+i]);
905                                         column_ids[i] = write_expression(combine_op, result_type_id, compare_id);;
906                                 }
907
908                                 compare_id = write_construct(bool_vec_type_id, column_ids, n_elems);
909                         }
910
911                         if(compare_id)
912                                 r_expression_result_id = write_expression(combine_op, result_type_id, compare_id);
913                         return;
914                 }
915         }
916         else if(oper2=='&' && elem.kind==BasicTypeDeclaration::BOOL)
917                 opcode = OP_LOGICAL_AND;
918         else if(oper2=='|' && elem.kind==BasicTypeDeclaration::BOOL)
919                 opcode = OP_LOGICAL_OR;
920         else if(oper2=='^' && elem.kind==BasicTypeDeclaration::BOOL)
921                 opcode = OP_LOGICAL_NOT_EQUAL;
922         else if(oper=='&' && elem.kind==BasicTypeDeclaration::INT)
923                 opcode = OP_BITWISE_AND;
924         else if(oper=='|' && elem.kind==BasicTypeDeclaration::INT)
925                 opcode = OP_BITWISE_OR;
926         else if(oper=='^' && elem.kind==BasicTypeDeclaration::INT)
927                 opcode = OP_BITWISE_XOR;
928         else if(oper=='<' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
929                 opcode = OP_SHIFT_LEFT_LOGICAL;
930         else if(oper=='>' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
931                 opcode = OP_SHIFT_RIGHT_ARITHMETIC;
932         else if(oper=='%' && elem.kind==BasicTypeDeclaration::INT)
933                 opcode = (elem.sign ? OP_S_MOD : OP_U_MOD);
934         else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
935         {
936                 Opcode elem_op = OP_NOP;
937                 if(elem.kind==BasicTypeDeclaration::INT)
938                 {
939                         if(oper=='/')
940                                 elem_op = (elem.sign ? OP_S_DIV : OP_U_DIV);
941                         else
942                                 elem_op = (oper=='+' ? OP_I_ADD : oper=='-' ? OP_I_SUB : OP_I_MUL);
943                 }
944                 else if(elem.kind==BasicTypeDeclaration::FLOAT)
945                         elem_op = (oper=='+' ? OP_F_ADD : oper=='-' ? OP_F_SUB : oper=='*' ? OP_F_MUL : OP_F_DIV);
946
947                 if(oper=='*' && (basic_left.base_type || basic_right.base_type) && elem.kind==BasicTypeDeclaration::FLOAT)
948                 {
949                         /* Multiplication between floating-point vectors and matrices has
950                         dedicated operations. */
951                         if(basic_left.kind==BasicTypeDeclaration::MATRIX && basic_right.kind==BasicTypeDeclaration::MATRIX)
952                                 opcode = OP_MATRIX_TIMES_MATRIX;
953                         else if(basic_left.kind==BasicTypeDeclaration::MATRIX || basic_right.kind==BasicTypeDeclaration::MATRIX)
954                         {
955                                 if(basic_left.kind==BasicTypeDeclaration::VECTOR)
956                                         opcode = OP_VECTOR_TIMES_MATRIX;
957                                 else if(basic_right.kind==BasicTypeDeclaration::VECTOR)
958                                         opcode = OP_MATRIX_TIMES_VECTOR;
959                                 else
960                                 {
961                                         opcode = OP_MATRIX_TIMES_SCALAR;
962                                         swap_operands = (basic_right.kind==BasicTypeDeclaration::MATRIX);
963                                 }
964                         }
965                         else if(basic_left.kind==BasicTypeDeclaration::VECTOR && basic_right.kind==BasicTypeDeclaration::VECTOR)
966                                 opcode = elem_op;
967                         else
968                         {
969                                 opcode = OP_VECTOR_TIMES_SCALAR;
970                                 swap_operands = (basic_right.kind==BasicTypeDeclaration::VECTOR);
971                         }
972                 }
973                 else if((basic_left.base_type!=0)!=(basic_right.base_type!=0))
974                 {
975                         /* One operand is scalar and the other is a vector or a matrix.
976                         Expand the scalar to a vector of appropriate size. */
977                         Id &scalar_id = (basic_left.base_type ? right_id : left_id);
978                         BasicTypeDeclaration *vector_type = (basic_left.base_type ? &basic_left : &basic_right);
979                         if(vector_type->kind==BasicTypeDeclaration::MATRIX)
980                                 vector_type = dynamic_cast<BasicTypeDeclaration *>(vector_type->base_type);
981                         Id vector_type_id = get_id(*vector_type);
982
983                         Id expanded_id = begin_expression(OP_COMPOSITE_CONSTRUCT, vector_type_id, vector_type->size);
984                         for(unsigned i=0; i<vector_type->size; ++i)
985                                 writer.write(scalar_id);
986                         end_expression(OP_COMPOSITE_CONSTRUCT);
987
988                         scalar_id = expanded_id;
989
990                         if(basic_left.kind==BasicTypeDeclaration::MATRIX || basic_right.kind==BasicTypeDeclaration::MATRIX)
991                         {
992                                 // Apply matrix operation column-wise.
993                                 Id matrix_id = (basic_left.base_type ? left_id : right_id);
994
995                                 Id column_ids[4];
996                                 unsigned n_columns = (basic_left.base_type ? basic_left.size : basic_right.size)&0xFFFF;
997                                 write_deconstruct(vector_type_id, matrix_id, column_ids, n_columns);
998
999                                 for(unsigned i=0; i<n_columns; ++i)
1000                                         column_ids[i] = write_expression(elem_op, vector_type_id, column_ids[i], expanded_id);
1001
1002                                 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1003                                 return;
1004                         }
1005                         else
1006                                 opcode = elem_op;
1007                 }
1008                 else if(basic_left.kind==BasicTypeDeclaration::MATRIX && basic_right.kind==BasicTypeDeclaration::MATRIX)
1009                 {
1010                         if(oper=='*')
1011                                 throw internal_error("non-float matrix multiplication");
1012
1013                         /* Other operations involving matrices need to be performed
1014                         column-wise. */
1015                         Id column_type_id = get_id(*basic_left.base_type);
1016                         Id column_ids[8];
1017
1018                         unsigned n_columns = basic_left.size&0xFFFF;
1019                         write_deconstruct(column_type_id, left_id, column_ids, n_columns);
1020                         write_deconstruct(column_type_id, right_id, column_ids+4, n_columns);
1021
1022                         for(unsigned i=0; i<n_columns; ++i)
1023                                 column_ids[i] = write_expression(elem_op, column_type_id, column_ids[i], column_ids[4+i]);
1024
1025                         r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1026                         return;
1027                 }
1028                 else if(basic_left.kind==basic_right.kind)
1029                         // Both operands are either scalars or vectors.
1030                         opcode = elem_op;
1031         }
1032
1033         if(opcode==OP_NOP)
1034                 throw internal_error("unknown binary operator");
1035
1036         if(swap_operands)
1037                 swap(left_id, right_id);
1038
1039         r_expression_result_id = write_expression(opcode, result_type_id, left_id, right_id);
1040 }
1041
1042 void SpirVGenerator::visit(Assignment &assign)
1043 {
1044         if(assign.oper->token[0]!='=')
1045                 visit(static_cast<BinaryExpression &>(assign));
1046         else
1047                 assign.right->visit(*this);
1048
1049         SetForScope<Id> set_assign(assignment_source_id, r_expression_result_id);
1050         assign.left->visit(*this);
1051         r_constant_result = false;
1052 }
1053
1054 void SpirVGenerator::visit(TernaryExpression &ternary)
1055 {
1056         if(composite_access)
1057                 return visit_isolated(ternary);
1058         if(constant_expression)
1059         {
1060                 ternary.condition->visit(*this);
1061                 Id condition_id = r_expression_result_id;
1062                 ternary.true_expr->visit(*this);
1063                 Id true_result_id = r_expression_result_id;
1064                 ternary.false_expr->visit(*this);
1065                 Id false_result_id = r_expression_result_id;
1066
1067                 r_expression_result_id = begin_expression(OP_SELECT, get_id(*ternary.type), 3);
1068                 writer.write(condition_id);
1069                 writer.write(true_result_id);
1070                 writer.write(false_result_id);
1071                 end_expression(OP_SELECT);
1072
1073                 return;
1074         }
1075
1076         ternary.condition->visit(*this);
1077         Id condition_id = r_expression_result_id;
1078
1079         Id true_label_id = next_id++;
1080         Id false_label_id = next_id++;
1081         Id merge_block_id = next_id++;
1082         writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0);  // Selection control (none)
1083         writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, condition_id, true_label_id, false_label_id);
1084
1085         std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
1086
1087         writer.write_op_label(true_label_id);
1088         ternary.true_expr->visit(*this);
1089         Id true_result_id = r_expression_result_id;
1090         true_label_id = writer.get_current_block();
1091         writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
1092
1093         swap(saved_load_ids, variable_load_ids);
1094         writer.write_op_label(false_label_id);
1095         ternary.false_expr->visit(*this);
1096         Id false_result_id = r_expression_result_id;
1097         false_label_id = writer.get_current_block();
1098
1099         writer.write_op_label(merge_block_id);
1100         prune_loads(true_label_id);
1101         r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4);
1102         writer.write(true_result_id);
1103         writer.write(true_label_id);
1104         writer.write(false_result_id);
1105         writer.write(false_label_id);
1106         end_expression(OP_PHI);
1107
1108         r_constant_result = false;
1109 }
1110
1111 void SpirVGenerator::visit(FunctionCall &call)
1112 {
1113         if(assignment_source_id)
1114                 throw internal_error("assignment to function call");
1115         else if(composite_access)
1116                 return visit_isolated(call);
1117         else if(call.constructor && call.arguments.size()==1 && call.arguments[0]->type==call.type)
1118                 return call.arguments[0]->visit(*this);
1119
1120         vector<Id> argument_ids;
1121         argument_ids.reserve(call.arguments.size());
1122         bool all_args_const = true;
1123         for(const RefPtr<Expression> &a: call.arguments)
1124         {
1125                 a->visit(*this);
1126                 argument_ids.push_back(r_expression_result_id);
1127                 all_args_const &= r_constant_result;
1128         }
1129
1130         if(constant_expression && (!call.constructor || !all_args_const))
1131                 throw internal_error("function call in constant expression");
1132
1133         Id result_type_id = get_id(*call.type);
1134         r_constant_result = false;
1135
1136         if(call.constructor)
1137                 visit_constructor(call, argument_ids, all_args_const);
1138         else if(call.declaration->source==BUILTIN_SOURCE)
1139         {
1140                 string arg_types;
1141                 for(const RefPtr<Expression> &a: call.arguments)
1142                         if(BasicTypeDeclaration *basic_arg = dynamic_cast<BasicTypeDeclaration *>(a->type))
1143                         {
1144                                 BasicTypeDeclaration &elem_arg = *get_element_type(*basic_arg);
1145                                 switch(elem_arg.kind)
1146                                 {
1147                                 case BasicTypeDeclaration::BOOL: arg_types += 'b'; break;
1148                                 case BasicTypeDeclaration::INT: arg_types += (elem_arg.sign ? 'i' : 'u'); break;
1149                                 case BasicTypeDeclaration::FLOAT: arg_types += 'f'; break;
1150                                 default: arg_types += '?';
1151                                 }
1152                         }
1153
1154                 const BuiltinFunctionInfo *builtin_info;
1155                 for(builtin_info=builtin_functions; builtin_info->function[0]; ++builtin_info)
1156                         if(builtin_info->function==call.name && (!builtin_info->arg_types[0] || builtin_info->arg_types==arg_types))
1157                                 break;
1158
1159                 if(builtin_info->capability)
1160                         use_capability(static_cast<Capability>(builtin_info->capability));
1161
1162                 if(builtin_info->opcode)
1163                 {
1164                         Opcode opcode;
1165                         if(builtin_info->extension[0])
1166                         {
1167                                 opcode = OP_EXT_INST;
1168                                 Id ext_id = import_extension(builtin_info->extension);
1169
1170                                 r_expression_result_id = begin_expression(opcode, result_type_id);
1171                                 writer.write(ext_id);
1172                                 writer.write(builtin_info->opcode);
1173                         }
1174                         else
1175                         {
1176                                 opcode = static_cast<Opcode>(builtin_info->opcode);
1177                                 r_expression_result_id = begin_expression(opcode, result_type_id);
1178                         }
1179
1180                         for(unsigned i=0; i<call.arguments.size(); ++i)
1181                         {
1182                                 if(!builtin_info->arg_order[i] || builtin_info->arg_order[i]>argument_ids.size())
1183                                         throw internal_error("invalid builtin function info");
1184                                 writer.write(argument_ids[builtin_info->arg_order[i]-1]);
1185                         }
1186
1187                         end_expression(opcode);
1188                 }
1189                 else if(builtin_info->handler)
1190                         (this->*(builtin_info->handler))(call, argument_ids);
1191                 else
1192                         throw internal_error("unknown builtin function "+call.name);
1193         }
1194         else
1195         {
1196                 r_expression_result_id = begin_expression(OP_FUNCTION_CALL, result_type_id, 1+call.arguments.size());
1197                 writer.write(get_id(*call.declaration->definition));
1198                 for(Id i: argument_ids)
1199                         writer.write(i);
1200                 end_expression(OP_FUNCTION_CALL);
1201
1202                 // Any global variables the called function uses might have changed value
1203                 set<Node *> dependencies = DependencyCollector().apply(*call.declaration->definition);
1204                 for(Node *n: dependencies)
1205                         if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
1206                                 variable_load_ids.erase(var);
1207         }
1208 }
1209
1210 void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids, bool all_args_const)
1211 {
1212         Id result_type_id = get_id(*call.type);
1213
1214         BasicTypeDeclaration *basic = dynamic_cast<BasicTypeDeclaration *>(call.type);
1215         if(!basic)
1216         {
1217                 if(dynamic_cast<const StructDeclaration *>(call.type))
1218                         r_expression_result_id = write_construct(result_type_id, &argument_ids[0], argument_ids.size());
1219                 else
1220                         throw internal_error("unconstructable type "+call.name);
1221                 return;
1222         }
1223
1224         SetFlag set_const(constant_expression, constant_expression || all_args_const);
1225
1226         BasicTypeDeclaration &elem = *get_element_type(*basic);
1227         BasicTypeDeclaration &basic_arg0 = dynamic_cast<BasicTypeDeclaration &>(*call.arguments[0]->type);
1228         BasicTypeDeclaration &elem_arg0 = *get_element_type(basic_arg0);
1229
1230         if(basic->kind==BasicTypeDeclaration::MATRIX)
1231         {
1232                 Id col_type_id = get_id(*basic->base_type);
1233                 unsigned n_columns = basic->size&0xFFFF;
1234                 unsigned n_rows = basic->size>>16;
1235
1236                 Id column_ids[4];
1237                 if(call.arguments.size()==1)
1238                 {
1239                         // Construct diagonal matrix from a single scalar.
1240                         Id zero_id = get_constant_id(get_id(elem), 0.0f);
1241                         for(unsigned i=0; i<n_columns; ++i)
1242                         {
1243                                 column_ids[i] = begin_expression(OP_COMPOSITE_CONSTRUCT, col_type_id, n_rows);
1244                                 for(unsigned j=0; j<n_rows; ++j)
1245                                         writer.write(j==i ? argument_ids[0] : zero_id);
1246                                 end_expression(OP_COMPOSITE_CONSTRUCT);
1247                         }
1248                 }
1249                 else
1250                         // Construct a matrix from column vectors
1251                         copy(argument_ids.begin(), argument_ids.begin()+n_columns, column_ids);
1252
1253                 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1254         }
1255         else if(basic->kind==BasicTypeDeclaration::VECTOR && (call.arguments.size()>1 || basic_arg0.kind!=BasicTypeDeclaration::VECTOR))
1256         {
1257                 /* There's either a single scalar argument or multiple arguments
1258                 which make up the vector's components. */
1259                 if(call.arguments.size()==1)
1260                 {
1261                         r_expression_result_id = begin_expression(OP_COMPOSITE_CONSTRUCT, result_type_id);
1262                         for(unsigned i=0; i<basic->size; ++i)
1263                                 writer.write(argument_ids[0]);
1264                         end_expression(OP_COMPOSITE_CONSTRUCT);
1265                 }
1266                 else
1267                         r_expression_result_id = write_construct(result_type_id, &argument_ids[0], argument_ids.size());
1268         }
1269         else if(elem.kind==BasicTypeDeclaration::BOOL)
1270         {
1271                 if(constant_expression)
1272                         throw internal_error("unconverted constant");
1273
1274                 // Conversion to boolean is implemented as comparing against zero.
1275                 Id number_type_id = get_id(elem_arg0);
1276                 Id zero_id = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ?
1277                         get_constant_id(number_type_id, 0.0f) : get_constant_id(number_type_id, 0));
1278                 if(basic_arg0.kind==BasicTypeDeclaration::VECTOR)
1279                         zero_id = get_vector_constant_id(get_id(basic_arg0), basic_arg0.size, zero_id);
1280
1281                 Opcode opcode = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ? OP_F_ORD_NOT_EQUAL : OP_I_NOT_EQUAL);
1282                 r_expression_result_id = write_expression(opcode, result_type_id, argument_ids[0], zero_id);
1283         }
1284         else if(elem_arg0.kind==BasicTypeDeclaration::BOOL)
1285         {
1286                 if(constant_expression)
1287                         throw internal_error("unconverted constant");
1288
1289                 /* Conversion from boolean is implemented as selecting from zero
1290                 or one. */
1291                 Id number_type_id = get_id(elem);
1292                 Id zero_id = (elem.kind==BasicTypeDeclaration::FLOAT ?
1293                         get_constant_id(number_type_id, 0.0f) : get_constant_id(number_type_id, 0));
1294                 Id one_id = (elem.kind==BasicTypeDeclaration::FLOAT ?
1295                         get_constant_id(number_type_id, 1.0f) : get_constant_id(number_type_id, 1));
1296                 if(basic->kind==BasicTypeDeclaration::VECTOR)
1297                 {
1298                         zero_id = get_vector_constant_id(get_id(*basic), basic->size, zero_id);
1299                         one_id = get_vector_constant_id(get_id(*basic), basic->size, one_id);
1300                 }
1301
1302                 r_expression_result_id = begin_expression(OP_SELECT, result_type_id, 3);
1303                 writer.write(argument_ids[0]);
1304                 writer.write(zero_id);
1305                 writer.write(one_id);
1306                 end_expression(OP_SELECT);
1307         }
1308         else
1309         {
1310                 if(constant_expression)
1311                         throw internal_error("unconverted constant");
1312
1313                 // Scalar or vector conversion between types of equal size.
1314                 Opcode opcode;
1315                 if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::FLOAT)
1316                         opcode = (elem.sign ? OP_CONVERT_F_TO_S : OP_CONVERT_F_TO_U);
1317                 else if(elem.kind==BasicTypeDeclaration::FLOAT && elem_arg0.kind==BasicTypeDeclaration::INT)
1318                         opcode = (elem_arg0.sign ? OP_CONVERT_S_TO_F : OP_CONVERT_U_TO_F);
1319                 else if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::INT)
1320                         opcode = OP_BITCAST;
1321                 else
1322                         throw internal_error("invalid conversion");
1323
1324                 r_expression_result_id = write_expression(opcode, result_type_id, argument_ids[0]);
1325         }
1326 }
1327
1328 void SpirVGenerator::visit_builtin_matrix_comp_mult(FunctionCall &call, const vector<Id> &argument_ids)
1329 {
1330         if(argument_ids.size()!=2)
1331                 throw internal_error("invalid matrixCompMult call");
1332
1333         const BasicTypeDeclaration &basic_arg0 = dynamic_cast<const BasicTypeDeclaration &>(*call.arguments[0]->type);
1334         Id column_type_id = get_id(*basic_arg0.base_type);
1335         Id column_ids[8];
1336
1337         unsigned n_columns = basic_arg0.size&0xFFFF;
1338         write_deconstruct(column_type_id, argument_ids[0], column_ids, n_columns);
1339         write_deconstruct(column_type_id, argument_ids[1], column_ids+4, n_columns);
1340
1341         for(unsigned i=0; i<n_columns; ++i)
1342                 column_ids[i] = write_expression(OP_F_MUL, column_type_id, column_ids[i], column_ids[4+i]);
1343
1344         r_expression_result_id = write_construct(get_id(*call.type), column_ids, n_columns);
1345 }
1346
1347 void SpirVGenerator::visit_builtin_texture_query(FunctionCall &call, const vector<Id> &argument_ids)
1348 {
1349         if(argument_ids.size()<1)
1350                 throw internal_error("invalid texture query call");
1351
1352         Opcode opcode;
1353         if(call.name=="textureSize")
1354                 opcode = OP_IMAGE_QUERY_SIZE_LOD;
1355         else if(call.name=="imageSize")
1356                 opcode = OP_IMAGE_QUERY_SIZE;
1357         else if(call.name=="textureQueryLod")
1358                 opcode = OP_IMAGE_QUERY_LOD;
1359         else if(call.name=="textureQueryLevels")
1360                 opcode = OP_IMAGE_QUERY_LEVELS;
1361         else if(call.name=="textureSamples" || call.name=="imageSamples")
1362                 opcode = OP_IMAGE_QUERY_SAMPLES;
1363         else
1364                 throw internal_error("invalid texture query call");
1365
1366         ImageTypeDeclaration &image_arg0 = dynamic_cast<ImageTypeDeclaration &>(*call.arguments[0]->type);
1367
1368         Id image_id;
1369         if(image_arg0.sampled && opcode!=OP_IMAGE_QUERY_LOD)
1370         {
1371                 Id image_type_id = get_item(image_type_ids, get_id(image_arg0));
1372                 image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]);
1373         }
1374         else
1375                 image_id = argument_ids[0];
1376
1377         Id result_type_id = get_id(*call.type);
1378         r_expression_result_id = begin_expression(opcode, result_type_id, argument_ids.size());
1379         writer.write(image_id);
1380         for(unsigned i=1; i<argument_ids.size(); ++i)
1381                 writer.write(argument_ids[i]);
1382         end_expression(opcode);
1383 }
1384
1385 void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector<Id> &argument_ids)
1386 {
1387         if(argument_ids.size()<2)
1388                 throw internal_error("invalid texture sampling call");
1389
1390         bool explicit_lod = (stage->type!=Stage::FRAGMENT || call.name=="textureLod");
1391         Id lod_id = (!explicit_lod ? 0 : call.name=="textureLod" ? argument_ids.back() :
1392                 get_constant_id(get_standard_type_id(BasicTypeDeclaration::FLOAT, 1), 0.0f));
1393
1394         const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*call.arguments[0]->type);
1395
1396         Opcode opcode;
1397         Id result_type_id = get_id(*call.type);
1398         Id dref_id = 0;
1399         if(image.shadow)
1400         {
1401                 if(argument_ids.size()==2)
1402                 {
1403                         const BasicTypeDeclaration &basic_arg1 = dynamic_cast<const BasicTypeDeclaration &>(*call.arguments[1]->type);
1404                         dref_id = begin_expression(OP_COMPOSITE_EXTRACT, get_id(*basic_arg1.base_type), 2);
1405                         writer.write(argument_ids.back());
1406                         writer.write(basic_arg1.size-1);
1407                         end_expression(OP_COMPOSITE_EXTRACT);
1408                 }
1409                 else
1410                         dref_id = argument_ids[2];
1411
1412                 opcode = (explicit_lod ? OP_IMAGE_SAMPLE_DREF_EXPLICIT_LOD : OP_IMAGE_SAMPLE_DREF_IMPLICIT_LOD);
1413                 r_expression_result_id = begin_expression(opcode, result_type_id, 3+explicit_lod*2);
1414         }
1415         else
1416         {
1417                 opcode = (explicit_lod ? OP_IMAGE_SAMPLE_EXPLICIT_LOD : OP_IMAGE_SAMPLE_IMPLICIT_LOD);
1418                 r_expression_result_id = begin_expression(opcode, result_type_id, 2+explicit_lod*2);
1419         }
1420
1421         for(unsigned i=0; i<2; ++i)
1422                 writer.write(argument_ids[i]);
1423         if(dref_id)
1424                 writer.write(dref_id);
1425         if(explicit_lod)
1426         {
1427                 writer.write(2);  // Lod
1428                 writer.write(lod_id);
1429         }
1430
1431         end_expression(opcode);
1432 }
1433
1434 void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector<Id> &argument_ids)
1435 {
1436         const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*call.arguments[0]->type);
1437
1438         Opcode opcode;
1439         if(call.name=="texelFetch")
1440                 opcode = OP_IMAGE_FETCH;
1441         else if(call.name=="imageLoad")
1442                 opcode = OP_IMAGE_READ;
1443         else
1444                 throw internal_error("invalid texture fetch call");
1445
1446         bool need_sample = image.multisample;
1447         bool need_lod = (opcode==OP_IMAGE_FETCH && !need_sample);
1448
1449         if(argument_ids.size()!=2U+need_sample+need_lod)
1450                 throw internal_error("invalid texture fetch call");
1451
1452         r_expression_result_id = begin_expression(opcode, get_id(*call.type), 2+(need_lod|need_sample)+need_lod+need_sample);
1453         for(unsigned i=0; i<2; ++i)
1454                 writer.write(argument_ids[i]);
1455         if(need_lod || need_sample)
1456         {
1457                 writer.write(need_lod*0x02 | need_sample*0x40);
1458                 writer.write(argument_ids.back());
1459         }
1460         end_expression(opcode);
1461 }
1462
1463 void SpirVGenerator::visit_builtin_texture_store(FunctionCall &call, const vector<Id> &argument_ids)
1464 {
1465         if(argument_ids.size()!=3)
1466                 throw internal_error("invalid texture store call");
1467
1468         const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*call.arguments[0]->type);
1469
1470         begin_expression(OP_IMAGE_WRITE, get_id(*call.type), 3+image.multisample*2);
1471         for(unsigned i=0; i<2; ++i)
1472                 writer.write(argument_ids[i]);
1473         writer.write(argument_ids.back());
1474         if(image.multisample)
1475         {
1476                 writer.write(0x40);  // Sample
1477                 writer.write(argument_ids[2]);
1478         }
1479         end_expression(OP_IMAGE_WRITE);
1480
1481         r_expression_result_id = 0;
1482 }
1483
1484 void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector<Id> &argument_ids)
1485 {
1486         if(argument_ids.size()<1)
1487                 throw internal_error("invalid interpolate call");
1488         const VariableReference *var = dynamic_cast<const VariableReference *>(call.arguments[0].get());
1489         if(!var || !var->declaration || var->declaration->interface!="in")
1490                 throw internal_error("invalid interpolate call");
1491
1492         SpirVGlslStd450Opcode opcode;
1493         if(call.name=="interpolateAtCentroid")
1494                 opcode = GLSL450_INTERPOLATE_AT_CENTROID;
1495         else if(call.name=="interpolateAtSample")
1496                 opcode = GLSL450_INTERPOLATE_AT_SAMPLE;
1497         else if(call.name=="interpolateAtOffset")
1498                 opcode = GLSL450_INTERPOLATE_AT_OFFSET;
1499         else
1500                 throw internal_error("invalid interpolate call");
1501
1502         Id ext_id = import_extension("GLSL.std.450");
1503         r_expression_result_id = begin_expression(OP_EXT_INST, get_id(*call.type));
1504         writer.write(ext_id);
1505         writer.write(opcode);
1506         writer.write(get_id(*var->declaration));
1507         for(auto i=argument_ids.begin(); ++i!=argument_ids.end(); )
1508                 writer.write(*i);
1509         end_expression(OP_EXT_INST);
1510 }
1511
1512 void SpirVGenerator::visit(ExpressionStatement &expr)
1513 {
1514         expr.expression->visit(*this);
1515 }
1516
1517 void SpirVGenerator::visit(InterfaceLayout &layout)
1518 {
1519         interface_layouts.push_back(&layout);
1520 }
1521
1522 bool SpirVGenerator::check_duplicate_type(TypeDeclaration &type)
1523 {
1524         for(const auto &kvp: declared_ids)
1525                 if(TypeDeclaration *type2 = dynamic_cast<TypeDeclaration *>(kvp.first))
1526                         if(TypeComparer().apply(type, *type2))
1527                         {
1528                                 insert_unique(declared_ids, &type, kvp.second);
1529                                 return true;
1530                         }
1531
1532         return false;
1533 }
1534
1535 bool SpirVGenerator::check_standard_type(BasicTypeDeclaration &basic)
1536 {
1537         const BasicTypeDeclaration *elem = (basic.kind==BasicTypeDeclaration::VECTOR ?
1538                 dynamic_cast<const BasicTypeDeclaration *>(basic.base_type) : &basic);
1539         if(!elem || elem->base_type)
1540                 return false;
1541         if((elem->kind==BasicTypeDeclaration::INT || elem->kind==BasicTypeDeclaration::FLOAT) && elem->size!=32)
1542                 return false;
1543
1544         Id standard_id = get_standard_type_id(elem->kind, (basic.kind==BasicTypeDeclaration::VECTOR ? basic.size : 1), elem->sign);
1545         insert_unique(declared_ids, &basic, Declaration(standard_id, 0));
1546         writer.write_op_name(standard_id, basic.name);
1547
1548         return true;
1549 }
1550
1551 void SpirVGenerator::visit(BasicTypeDeclaration &basic)
1552 {
1553         if(check_standard_type(basic))
1554                 return;
1555         if(check_duplicate_type(basic))
1556                 return;
1557         // Alias types shouldn't exist at this point and arrays are handled elsewhere
1558         if(basic.kind==BasicTypeDeclaration::ALIAS || basic.kind==BasicTypeDeclaration::ARRAY)
1559                 return;
1560
1561         Id type_id = allocate_id(basic, 0);
1562         writer.write_op_name(type_id, basic.name);
1563
1564         switch(basic.kind)
1565         {
1566         case BasicTypeDeclaration::INT:
1567                 writer.write_op(content.globals, OP_TYPE_INT, type_id, basic.size, basic.sign);
1568                 break;
1569         case BasicTypeDeclaration::FLOAT:
1570                 writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, basic.size);
1571                 break;
1572         case BasicTypeDeclaration::VECTOR:
1573                 writer.write_op(content.globals, OP_TYPE_VECTOR, type_id, get_id(*basic.base_type), basic.size);
1574                 break;
1575         case BasicTypeDeclaration::MATRIX:
1576                 writer.write_op(content.globals, OP_TYPE_MATRIX, type_id, get_id(*basic.base_type), basic.size&0xFFFF);
1577                 break;
1578         default:
1579                 throw internal_error("unknown basic type");
1580         }
1581 }
1582
1583 void SpirVGenerator::visit(ImageTypeDeclaration &image)
1584 {
1585         if(check_duplicate_type(image))
1586                 return;
1587
1588         Id type_id = allocate_id(image, 0);
1589
1590         Id image_id = (image.sampled ? next_id++ : type_id);
1591         writer.begin_op(content.globals, OP_TYPE_IMAGE, 9);
1592         writer.write(image_id);
1593         writer.write(get_id(*image.base_type));
1594         writer.write(image.dimensions-1);
1595         writer.write(image.shadow);
1596         writer.write(image.array);
1597         writer.write(image.multisample);
1598         writer.write(image.sampled ? 1 : 2);
1599         writer.write(get_format(image.format));
1600         writer.end_op(OP_TYPE_IMAGE);
1601
1602         if(image.sampled)
1603         {
1604                 writer.write_op_name(type_id, image.name);
1605                 writer.write_op(content.globals, OP_TYPE_SAMPLED_IMAGE, type_id, image_id);
1606                 insert_unique(image_type_ids, type_id, image_id);
1607         }
1608
1609         if(image.dimensions==ImageTypeDeclaration::ONE)
1610                 use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D);
1611         else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array)
1612                 use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY);
1613
1614         if(image.multisample && !image.sampled)
1615                 use_capability(CAP_STORAGE_IMAGE_MULTISAMPLE);
1616 }
1617
1618 void SpirVGenerator::visit(StructDeclaration &strct)
1619 {
1620         if(check_duplicate_type(strct))
1621                 return;
1622
1623         Id type_id = allocate_id(strct, 0);
1624         writer.write_op_name(type_id, (strct.block_name.empty() ? strct.name : strct.block_name));
1625
1626         if(!strct.block_name.empty())
1627                 writer.write_op_decorate(type_id, DECO_BLOCK);
1628
1629         bool builtin = !strct.block_name.compare(0, 3, "gl_");
1630         vector<Id> member_type_ids;
1631         member_type_ids.reserve(strct.members.body.size());
1632         for(const RefPtr<Statement> &s: strct.members.body)
1633         {
1634                 const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(s.get());
1635                 if(!var)
1636                         continue;
1637
1638                 unsigned index = member_type_ids.size();
1639                 member_type_ids.push_back(get_variable_type_id(*var));
1640
1641                 writer.write_op_member_name(type_id, index, var->name);
1642
1643                 if(builtin)
1644                 {
1645                         BuiltinSemantic semantic = get_builtin_semantic(var->name);
1646                         writer.write_op_member_decorate(type_id, index, DECO_BUILTIN, semantic);
1647                 }
1648                 else
1649                 {
1650                         if(var->layout)
1651                         {
1652                                 for(const Layout::Qualifier &q: var->layout->qualifiers)
1653                                 {
1654                                         if(q.name=="offset")
1655                                                 writer.write_op_member_decorate(type_id, index, DECO_OFFSET, q.value);
1656                                         else if(q.name=="column_major")
1657                                                 writer.write_op_member_decorate(type_id, index, DECO_COL_MAJOR);
1658                                         else if(q.name=="row_major")
1659                                                 writer.write_op_member_decorate(type_id, index, DECO_ROW_MAJOR);
1660                                 }
1661                         }
1662
1663                         const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var->type_declaration);
1664                         while(basic && basic->kind==BasicTypeDeclaration::ARRAY)
1665                                 basic = dynamic_cast<const BasicTypeDeclaration *>(basic->base_type);
1666                         if(basic && basic->kind==BasicTypeDeclaration::MATRIX)
1667                         {
1668                                 unsigned stride = MemoryRequirementsCalculator().apply(*basic->base_type).stride;
1669                                 writer.write_op_member_decorate(type_id, index, DECO_MATRIX_STRIDE, stride);
1670                         }
1671                 }
1672         }
1673
1674         writer.begin_op(content.globals, OP_TYPE_STRUCT);
1675         writer.write(type_id);
1676         for(Id i: member_type_ids)
1677                 writer.write(i);
1678         writer.end_op(OP_TYPE_STRUCT);
1679 }
1680
1681 void SpirVGenerator::visit(VariableDeclaration &var)
1682 {
1683         Id type_id = get_variable_type_id(var);
1684         Id var_id;
1685
1686         if(var.constant)
1687         {
1688                 if(!var.init_expression)
1689                         throw internal_error("const variable without initializer");
1690
1691                 int spec_id = get_layout_value(var.layout.get(), "constant_id");
1692                 Id *spec_var_id = (spec_id>=0 ? &declared_spec_ids[spec_id] : 0);
1693                 if(spec_id>=0 && *spec_var_id)
1694                 {
1695                         insert_unique(declared_ids, &var, Declaration(*spec_var_id, type_id));
1696                         return;
1697                 }
1698
1699                 SetFlag set_const(constant_expression);
1700                 SetFlag set_spec(spec_constant, spec_id>=0);
1701                 r_expression_result_id = 0;
1702                 var.init_expression->visit(*this);
1703                 var_id = r_expression_result_id;
1704                 insert_unique(declared_ids, &var, Declaration(var_id, type_id));
1705                 if(spec_id>=0)
1706                 {
1707                         writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
1708                         *spec_var_id = var_id;
1709                 }
1710         }
1711         else
1712         {
1713                 bool push_const = has_layout_qualifier(var.layout.get(), "push_constant");
1714
1715                 StorageClass storage;
1716                 if(current_function)
1717                         storage = STORAGE_FUNCTION;
1718                 else if(push_const)
1719                         storage = STORAGE_PUSH_CONSTANT;
1720                 else
1721                         storage = get_interface_storage(var.interface, var.block_declaration);
1722
1723                 Id ptr_type_id = get_pointer_type_id(type_id, storage);
1724                 if(var.interface=="uniform")
1725                 {
1726                         Id &uni_id = declared_uniform_ids[var.block_declaration ? "b"+var.block_declaration->block_name : "v"+var.name];
1727                         if(uni_id)
1728                         {
1729                                 insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id));
1730                                 return;
1731                         }
1732
1733                         uni_id = var_id = allocate_id(var, ptr_type_id);
1734                 }
1735                 else
1736                         var_id = allocate_id(var, (var.constant ? type_id : ptr_type_id));
1737
1738                 Id init_id = 0;
1739                 if(var.init_expression)
1740                 {
1741                         SetFlag set_const(constant_expression, !current_function);
1742                         r_expression_result_id = 0;
1743                         r_constant_result = false;
1744                         var.init_expression->visit(*this);
1745                         init_id = r_expression_result_id;
1746                 }
1747
1748                 vector<Word> &target = (current_function ? content.locals : content.globals);
1749                 writer.begin_op(target, OP_VARIABLE, 4+(init_id && !current_function));
1750                 writer.write(ptr_type_id);
1751                 writer.write(var_id);
1752                 writer.write(storage);
1753                 if(init_id && !current_function)
1754                         writer.write(init_id);
1755                 writer.end_op(OP_VARIABLE);
1756
1757                 if(var.layout)
1758                 {
1759                         for(const Layout::Qualifier &q: var.layout->qualifiers)
1760                         {
1761                                 if(q.name=="location")
1762                                         writer.write_op_decorate(var_id, DECO_LOCATION, q.value);
1763                                 else if(q.name=="set")
1764                                         writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, q.value);
1765                                 else if(q.name=="binding")
1766                                         writer.write_op_decorate(var_id, DECO_BINDING, q.value);
1767                         }
1768                 }
1769                 if(!var.block_declaration && !var.name.compare(0, 3, "gl_"))
1770                 {
1771                         BuiltinSemantic semantic = get_builtin_semantic(var.name);
1772                         writer.write_op_decorate(var_id, DECO_BUILTIN, semantic);
1773                 }
1774                 if(var.sampling=="flat")
1775                         writer.write_op_decorate(var_id, DECO_FLAT);
1776                 if(var.sampling=="centroid")
1777                         writer.write_op_decorate(var_id, DECO_CENTROID);
1778
1779                 if(init_id && current_function)
1780                 {
1781                         writer.write_op(content.function_body, OP_STORE, var_id, init_id);
1782                         variable_load_ids[&var] = init_id;
1783                 }
1784         }
1785
1786         if(var.name.find(' ')==string::npos)
1787                 writer.write_op_name(var_id, var.name);
1788 }
1789
1790 void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id)
1791 {
1792         writer.begin_op(content.entry_points, OP_ENTRY_POINT);
1793         switch(stage->type)
1794         {
1795         case Stage::VERTEX: writer.write(0); break;
1796         case Stage::GEOMETRY: writer.write(3); break;
1797         case Stage::FRAGMENT: writer.write(4); break;
1798         case Stage::COMPUTE: writer.write(5); break;
1799         default: throw internal_error("unknown stage");
1800         }
1801         writer.write(func_id);
1802         writer.write_string(func.name);
1803
1804         set<Node *> dependencies = DependencyCollector().apply(func);
1805         for(Node *n: dependencies)
1806                 if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
1807                         if(!var->interface.empty())
1808                                 writer.write(get_id(*n));
1809
1810         writer.end_op(OP_ENTRY_POINT);
1811
1812         if(stage->type==Stage::FRAGMENT)
1813         {
1814                 SpirVExecutionMode origin = (features.target_api==VULKAN ? EXEC_ORIGIN_UPPER_LEFT : EXEC_ORIGIN_LOWER_LEFT);
1815                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, origin);
1816         }
1817         else if(stage->type==Stage::GEOMETRY)
1818         {
1819                 use_capability(CAP_GEOMETRY);
1820                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INVOCATIONS, 1);
1821         }
1822
1823         unsigned local_size[3] = { 0, 1, 1 };
1824
1825         for(const InterfaceLayout *i: interface_layouts)
1826         {
1827                 for(const Layout::Qualifier &q: i->layout.qualifiers)
1828                 {
1829                         if(q.name=="point")
1830                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id,
1831                                         (i->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS));
1832                         else if(q.name=="lines")
1833                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES);
1834                         else if(q.name=="lines_adjacency")
1835                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES_ADJACENCY);
1836                         else if(q.name=="triangles")
1837                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_TRIANGLES);
1838                         else if(q.name=="triangles_adjacency")
1839                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_TRIANGLES_ADJACENCY);
1840                         else if(q.name=="line_strip")
1841                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_LINE_STRIP);
1842                         else if(q.name=="triangle_strip")
1843                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP);
1844                         else if(q.name=="max_vertices")
1845                                 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, q.value);
1846                         else if(q.name=="local_size_x")
1847                                 local_size[0] = q.value;
1848                         else if(q.name=="local_size_y")
1849                                 local_size[1] = q.value;
1850                         else if(q.name=="local_size_z")
1851                                 local_size[2] = q.value;
1852                 }
1853         }
1854
1855         if(stage->type==Stage::COMPUTE && local_size[0])
1856         {
1857                 writer.begin_op(content.exec_modes, OP_EXECUTION_MODE);
1858                 writer.write(func_id);
1859                 writer.write(EXEC_LOCAL_SIZE);
1860                 for(unsigned j=0; j<3; ++j)
1861                         writer.write(local_size[j]);
1862                 writer.end_op(OP_EXECUTION_MODE);
1863         }
1864 }
1865
1866 void SpirVGenerator::visit(FunctionDeclaration &func)
1867 {
1868         if(func.source==BUILTIN_SOURCE)
1869                 return;
1870         else if(func.definition!=&func)
1871         {
1872                 if(func.definition)
1873                         allocate_forward_id(*func.definition);
1874                 return;
1875         }
1876
1877         Id return_type_id = get_id(*func.return_type_declaration);
1878         vector<unsigned> param_type_ids;
1879         param_type_ids.reserve(func.parameters.size());
1880         for(const RefPtr<VariableDeclaration> &p: func.parameters)
1881                 param_type_ids.push_back(get_variable_type_id(*p));
1882
1883         string sig_with_return = func.return_type+func.signature;
1884         Id &type_id = function_type_ids[sig_with_return];
1885         if(!type_id)
1886         {
1887                 type_id = next_id++;
1888                 writer.begin_op(content.globals, OP_TYPE_FUNCTION);
1889                 writer.write(type_id);
1890                 writer.write(return_type_id);
1891                 for(unsigned i: param_type_ids)
1892                         writer.write(i);
1893                 writer.end_op(OP_TYPE_FUNCTION);
1894
1895                 writer.write_op_name(type_id, sig_with_return);
1896         }
1897
1898         Id func_id = allocate_id(func, type_id);
1899         writer.write_op_name(func_id, func.name+func.signature);
1900
1901         if(func.name=="main")
1902                 visit_entry_point(func, func_id);
1903
1904         writer.begin_op(content.functions, OP_FUNCTION, 5);
1905         writer.write(return_type_id);
1906         writer.write(func_id);
1907         writer.write(0);  // Function control flags (none)
1908         writer.write(type_id);
1909         writer.end_op(OP_FUNCTION);
1910
1911         for(unsigned i=0; i<func.parameters.size(); ++i)
1912         {
1913                 Id param_id = allocate_id(*func.parameters[i], param_type_ids[i]);
1914                 writer.write_op(content.functions, OP_FUNCTION_PARAMETER, param_type_ids[i], param_id);
1915                 writer.write_op_name(param_id, func.parameters[i]->name);
1916                 // TODO This is probably incorrect if the parameter is assigned to.
1917                 variable_load_ids[func.parameters[i].get()] = param_id;
1918         }
1919
1920         reachable = true;
1921         writer.begin_function_body(next_id++);
1922         SetForScope<FunctionDeclaration *> set_func(current_function, &func);
1923         func.body.visit(*this);
1924
1925         if(writer.get_current_block())
1926         {
1927                 if(!reachable)
1928                         writer.write_op(content.function_body, OP_UNREACHABLE);
1929                 else
1930                 {
1931                         const BasicTypeDeclaration *basic_return = dynamic_cast<const BasicTypeDeclaration *>(func.return_type_declaration);
1932                         if(basic_return && basic_return->kind==BasicTypeDeclaration::VOID)
1933                                 writer.write_op(content.function_body, OP_RETURN);
1934                         else
1935                                 throw internal_error("missing return in non-void function");
1936                 }
1937         }
1938         writer.end_function_body();
1939         variable_load_ids.clear();
1940 }
1941
1942 void SpirVGenerator::visit(Conditional &cond)
1943 {
1944         cond.condition->visit(*this);
1945
1946         Id true_label_id = next_id++;
1947         Id merge_block_id = next_id++;
1948         Id false_label_id = (cond.else_body.body.empty() ? merge_block_id : next_id++);
1949         writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0);  // Selection control (none)
1950         writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id);
1951
1952         std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
1953
1954         writer.write_op_label(true_label_id);
1955         cond.body.visit(*this);
1956         if(writer.get_current_block())
1957                 writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
1958
1959         bool reachable_if_true = reachable;
1960
1961         reachable = true;
1962         if(!cond.else_body.body.empty())
1963         {
1964                 swap(saved_load_ids, variable_load_ids);
1965                 writer.write_op_label(false_label_id);
1966                 cond.else_body.visit(*this);
1967                 reachable |= reachable_if_true;
1968         }
1969
1970         writer.write_op_label(merge_block_id);
1971         prune_loads(true_label_id);
1972 }
1973
1974 void SpirVGenerator::visit(Iteration &iter)
1975 {
1976         if(iter.init_statement)
1977                 iter.init_statement->visit(*this);
1978
1979         for(Node *n: AssignmentCollector().apply(iter))
1980                 if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(n))
1981                         variable_load_ids.erase(var);
1982
1983         Id header_id = next_id++;
1984         Id continue_id = next_id++;
1985         Id merge_block_id = next_id++;
1986
1987         SetForScope<Id> set_merge(loop_merge_block_id, merge_block_id);
1988         SetForScope<Id> set_continue(loop_continue_target_id, continue_id);
1989
1990         writer.write_op_label(header_id);
1991         writer.write_op(content.function_body, OP_LOOP_MERGE, merge_block_id, continue_id, 0);  // Loop control (none)
1992
1993         Id body_id = next_id++;
1994         if(iter.condition)
1995         {
1996                 writer.write_op_label(next_id++);
1997                 iter.condition->visit(*this);
1998                 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, body_id, merge_block_id);
1999         }
2000
2001         writer.write_op_label(body_id);
2002         iter.body.visit(*this);
2003
2004         writer.write_op_label(continue_id);
2005         if(iter.loop_expression)
2006                 iter.loop_expression->visit(*this);
2007         writer.write_op(content.function_body, OP_BRANCH, header_id);
2008
2009         writer.write_op_label(merge_block_id);
2010         prune_loads(header_id);
2011         reachable = true;
2012 }
2013
2014 void SpirVGenerator::visit(Return &ret)
2015 {
2016         if(ret.expression)
2017         {
2018                 ret.expression->visit(*this);
2019                 writer.write_op(content.function_body, OP_RETURN_VALUE, r_expression_result_id);
2020         }
2021         else
2022                 writer.write_op(content.function_body, OP_RETURN);
2023         reachable = false;
2024 }
2025
2026 void SpirVGenerator::visit(Jump &jump)
2027 {
2028         if(jump.keyword=="discard")
2029                 writer.write_op(content.function_body, OP_KILL);
2030         else if(jump.keyword=="break")
2031                 writer.write_op(content.function_body, OP_BRANCH, loop_merge_block_id);
2032         else if(jump.keyword=="continue")
2033                 writer.write_op(content.function_body, OP_BRANCH, loop_continue_target_id);
2034         else
2035                 throw internal_error("unknown jump");
2036         reachable = false;
2037 }
2038
2039
2040 SpirVGenerator::TypeKey::TypeKey(BasicTypeDeclaration::Kind kind, bool sign):
2041         type_id(0)
2042 {
2043         switch(kind)
2044         {
2045         case BasicTypeDeclaration::VOID: detail = 'v'; break;
2046         case BasicTypeDeclaration::BOOL: detail = 'b'; break;
2047         case BasicTypeDeclaration::INT: detail = (sign ? 'i' : 'u'); break;
2048         case BasicTypeDeclaration::FLOAT: detail = 'f'; break;
2049         default: throw invalid_argument("TypeKey::TypeKey");
2050         }
2051 }
2052
2053 bool SpirVGenerator::TypeKey::operator<(const TypeKey &other) const
2054 {
2055         if(type_id!=other.type_id)
2056                 return type_id<other.type_id;
2057         return detail<other.detail;
2058 }
2059
2060
2061 bool SpirVGenerator::ConstantKey::operator<(const ConstantKey &other) const
2062 {
2063         if(type_id!=other.type_id)
2064                 return type_id<other.type_id;
2065         return int_value<other.int_value;
2066 }
2067
2068 } // namespace SL
2069 } // namespace GL
2070 } // namespace Msp