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