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