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