1 #include <msp/core/algorithm.h>
2 #include <msp/core/maputils.h>
3 #include <msp/core/raii.h>
13 const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] =
15 { "radians", "f", "GLSL.std.450", GLSL450_RADIANS, { 1 }, 0, 0 },
16 { "degrees", "f", "GLSL.std.450", GLSL450_DEGREES, { 1 }, 0, 0 },
17 { "sin", "f", "GLSL.std.450", GLSL450_SIN, { 1 }, 0, 0 },
18 { "cos", "f", "GLSL.std.450", GLSL450_COS, { 1 }, 0, 0 },
19 { "tan", "f", "GLSL.std.450", GLSL450_TAN, { 1 }, 0, 0 },
20 { "asin", "f", "GLSL.std.450", GLSL450_ASIN, { 1 }, 0, 0 },
21 { "acos", "f", "GLSL.std.450", GLSL450_ACOS, { 1 }, 0, 0 },
22 { "atan", "f", "GLSL.std.450", GLSL450_ATAN, { 1 }, 0, 0 },
23 { "atan", "ff", "GLSL.std.450", GLSL450_ATAN2, { 1, 2 }, 0, 0 },
24 { "sinh", "f", "GLSL.std.450", GLSL450_SINH, { 1 }, 0, 0 },
25 { "cosh", "f", "GLSL.std.450", GLSL450_COSH, { 1 }, 0, 0 },
26 { "tanh", "f", "GLSL.std.450", GLSL450_TANH, { 1 }, 0, 0 },
27 { "asinh", "f", "GLSL.std.450", GLSL450_ASINH, { 1 }, 0, 0 },
28 { "acosh", "f", "GLSL.std.450", GLSL450_ACOSH, { 1 }, 0, 0 },
29 { "atanh", "f", "GLSL.std.450", GLSL450_ATANH, { 1 }, 0, 0 },
30 { "pow", "ff", "GLSL.std.450", GLSL450_POW, { 1, 2 }, 0, 0 },
31 { "exp", "f", "GLSL.std.450", GLSL450_EXP, { 1 }, 0, 0 },
32 { "log", "f", "GLSL.std.450", GLSL450_LOG, { 1 }, 0, 0 },
33 { "exp2", "f", "GLSL.std.450", GLSL450_EXP2, { 1 }, 0, 0 },
34 { "log2", "f", "GLSL.std.450", GLSL450_LOG2, { 1 }, 0, 0 },
35 { "sqrt", "f", "GLSL.std.450", GLSL450_SQRT, { 1 }, 0, 0 },
36 { "inversesqrt", "f", "GLSL.std.450", GLSL450_INVERSE_SQRT, { 1 }, 0, 0 },
37 { "abs", "f", "GLSL.std.450", GLSL450_F_ABS, { 1 }, 0, 0 },
38 { "abs", "i", "GLSL.std.450", GLSL450_S_ABS, { 1 }, 0, 0 },
39 { "sign", "f", "GLSL.std.450", GLSL450_F_SIGN, { 1 }, 0, 0 },
40 { "sign", "i", "GLSL.std.450", GLSL450_S_SIGN, { 1 }, 0, 0 },
41 { "floor", "f", "GLSL.std.450", GLSL450_FLOOR, { 1 }, 0, 0 },
42 { "trunc", "f", "GLSL.std.450", GLSL450_TRUNC, { 1 }, 0, 0 },
43 { "round", "f", "GLSL.std.450", GLSL450_ROUND, { 1 }, 0, 0 },
44 { "roundEven", "f", "GLSL.std.450", GLSL450_ROUND_EVEN, { 1 }, 0, 0 },
45 { "ceil", "f", "GLSL.std.450", GLSL450_CEIL, { 1 }, 0, 0 },
46 { "fract", "f", "GLSL.std.450", GLSL450_FRACT, { 1 }, 0, 0 },
47 { "mod", "f", "", OP_F_MOD, { 1, 2 }, 0, 0 },
48 { "min", "ff", "GLSL.std.450", GLSL450_F_MIN, { 1, 2 }, 0, 0 },
49 { "min", "ii", "GLSL.std.450", GLSL450_S_MIN, { 1, 2 }, 0, 0 },
50 { "min", "uu", "GLSL.std.450", GLSL450_U_MIN, { 1, 2 }, 0, 0 },
51 { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0, 0 },
52 { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0, 0 },
53 { "max", "uu", "GLSL.std.450", GLSL450_U_MAX, { 1, 2 }, 0, 0 },
54 { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0, 0 },
55 { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0, 0 },
56 { "clamp", "uuu", "GLSL.std.450", GLSL450_U_CLAMP, { 1, 2, 3 }, 0, 0 },
57 { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0, 0 },
58 { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
59 { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
60 { "mix", "uub", "", OP_SELECT, { 3, 2, 1 }, 0, 0 },
61 { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0, 0 },
62 { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0, 0 },
63 { "isnan", "f", "", OP_IS_NAN, { 1 }, 0, 0 },
64 { "isinf", "f", "", OP_IS_INF, { 1 }, 0, 0 },
65 { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0, 0 },
66 { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0, 0 },
67 { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0, 0 },
68 { "dot", "ff", "", OP_DOT, { 1, 2 }, 0, 0 },
69 { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0, 0 },
70 { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0, 0 },
71 { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0, 0 },
72 { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0, 0 },
73 { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0, 0 },
74 { "matrixCompMult", "ff", "", 0, { 0 }, 0, &SpirVGenerator::visit_builtin_matrix_comp_mult },
75 { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0, 0 },
76 { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0, 0 },
77 { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0, 0 },
78 { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0, 0 },
79 { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0, 0 },
80 { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0, 0 },
81 { "lessThan", "uu", "", OP_U_LESS_THAN, { 1, 2 }, 0, 0 },
82 { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
83 { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
84 { "lessThanEqual", "uu", "", OP_U_LESS_THAN_EQUAL, { 1, 2 }, 0, 0 },
85 { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0, 0 },
86 { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0, 0 },
87 { "greaterThan", "uu", "", OP_U_GREATER_THAN, { 1, 2 }, 0, 0 },
88 { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
89 { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
90 { "greaterThanEqual", "uu", "", OP_U_GREATER_THAN_EQUAL, { 1, 2 }, 0, 0 },
91 { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0, 0 },
92 { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0, 0 },
93 { "equal", "uu", "", OP_I_EQUAL, { 1, 2 }, 0, 0 },
94 { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0, 0 },
95 { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 },
96 { "notEqual", "uu", "", OP_I_NOT_EQUAL, { 1, 2 }, 0, 0 },
97 { "any", "b", "", OP_ANY, { 1 }, 0, 0 },
98 { "all", "b", "", OP_ALL, { 1 }, 0, 0 },
99 { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0, 0 },
100 { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0, 0 },
101 { "bitfieldExtract", "uii", "", OP_BIT_FIELD_U_EXTRACT, { 1, 2, 3 }, 0, 0 },
102 { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 },
103 { "bitfieldInsert", "uuii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0, 0 },
104 { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0, 0 },
105 { "bitfieldReverse", "u", "", OP_BIT_REVERSE, { 1 }, 0, 0 },
106 { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0, 0 },
107 { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 },
108 { "findLSB", "u", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0, 0 },
109 { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0, 0 },
110 { "findMSB", "u", "GLSL.std.450", GLSL450_FIND_U_MSB, { 1 }, 0, 0 },
111 { "textureSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
112 { "textureQueryLod", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
113 { "textureQueryLevels", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
114 { "textureSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
115 { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture },
116 { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture },
117 { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch },
118 { "imageSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
119 { "imageSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query },
120 { "imageLoad", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch },
121 { "imageStore", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_store },
122 { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 },
123 { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 },
124 { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 },
125 { "dFdy", "f", "", OP_DP_DY, { 1 }, 0, 0 },
126 { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
127 { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
128 { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
129 { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
130 { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0, 0 },
131 { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
132 { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, CAP_DERIVATIVE_CONTROL, 0 },
133 { "interpolateAtCentroid", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
134 { "interpolateAtSample", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
135 { "interpolateAtOffset", "", "", 0, { }, CAP_INTERPOLATION_FUNCTION, &SpirVGenerator::visit_builtin_interpolate },
136 { "", "", "", 0, { }, 0, 0 }
139 SpirVGenerator::SpirVGenerator():
143 void SpirVGenerator::apply(Module &module, const Features &f)
146 use_capability(CAP_SHADER);
148 for(Stage &s: module.stages)
151 interface_layouts.clear();
152 s.content.visit(*this);
155 writer.finalize(SPIRV_GENERATOR_MSP, next_id);
158 SpirVGenerator::StorageClass SpirVGenerator::get_interface_storage(const string &iface, bool block)
161 return STORAGE_INPUT;
162 else if(iface=="out")
163 return STORAGE_OUTPUT;
164 else if(iface=="uniform")
165 return (block ? STORAGE_UNIFORM : STORAGE_UNIFORM_CONSTANT);
166 else if(iface.empty())
167 return STORAGE_PRIVATE;
169 throw invalid_argument("SpirVGenerator::get_interface_storage");
172 SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const string &name)
174 if(name=="gl_Position")
175 return BUILTIN_POSITION;
176 else if(name=="gl_PointSize")
177 return BUILTIN_POINT_SIZE;
178 else if(name=="gl_ClipDistance")
179 return BUILTIN_CLIP_DISTANCE;
180 else if(name=="gl_VertexID")
181 return BUILTIN_VERTEX_ID;
182 else if(name=="gl_InstanceID")
183 return BUILTIN_INSTANCE_ID;
184 else if(name=="gl_PrimitiveID" || name=="gl_PrimitiveIDIn")
185 return BUILTIN_PRIMITIVE_ID;
186 else if(name=="gl_InvocationID")
187 return BUILTIN_INVOCATION_ID;
188 else if(name=="gl_Layer")
189 return BUILTIN_LAYER;
190 else if(name=="gl_TessLevelOuter")
191 return BUILTIN_TESS_LEVEL_OUTER;
192 else if(name=="gl_TessLevelInner")
193 return BUILTIN_TESS_LEVEL_INNER;
194 else if(name=="gl_TessCoord")
195 return BUILTIN_TESS_COORD;
196 else if(name=="gl_PatchVerticesIn")
197 return BUILTIN_PATCH_VERTICES;
198 else if(name=="gl_FragCoord")
199 return BUILTIN_FRAG_COORD;
200 else if(name=="gl_PointCoord")
201 return BUILTIN_POINT_COORD;
202 else if(name=="gl_FrontFacing")
203 return BUILTIN_FRONT_FACING;
204 else if(name=="gl_SampleId")
205 return BUILTIN_SAMPLE_ID;
206 else if(name=="gl_SamplePosition")
207 return BUILTIN_SAMPLE_POSITION;
208 else if(name=="gl_FragDepth")
209 return BUILTIN_FRAG_DEPTH;
210 else if(name=="gl_NumWorkGroups")
211 return BUILTIN_NUM_WORKGROUPS;
212 else if(name=="gl_WorkGroupSize")
213 return BUILTIN_WORKGROUP_SIZE;
214 else if(name=="gl_WorkGroupID")
215 return BUILTIN_WORKGROUP_ID;
216 else if(name=="gl_LocalInvocationID")
217 return BUILTIN_LOCAL_INVOCATION_ID;
218 else if(name=="gl_GlobalInvocationID")
219 return BUILTIN_GLOBAL_INVOCATION_ID;
220 else if(name=="gl_LocalInvocationIndex")
221 return BUILTIN_LOCAL_INVOCATION_INDEX;
223 throw invalid_argument("SpirVGenerator::get_builtin_semantic");
226 SpirVFormat SpirVGenerator::get_format(const std::string &name)
229 return FORMAT_UNKNOWN;
230 else if(name=="rgba32f")
231 return FORMAT_RGBA32F;
232 else if(name=="rgba16f")
233 return FORMAT_RGBA16F;
234 else if(name=="r32f")
236 else if(name=="rgba8")
238 else if(name=="rgba8_snorm")
239 return FORMAT_RGBA8_SNORM;
240 else if(name=="rg32f")
242 else if(name=="rg16f")
244 else if(name=="r16f")
246 else if(name=="rgba16")
247 return FORMAT_RGBA16;
248 else if(name=="rg16")
256 else if(name=="rgba16_snorm")
257 return FORMAT_RGBA16_SNORM;
258 else if(name=="rg16_snorm")
259 return FORMAT_RG16_SNORM;
260 else if(name=="rg8_snorm")
261 return FORMAT_RG8_SNORM;
262 else if(name=="r16_snorm")
263 return FORMAT_RG16_SNORM;
264 else if(name=="r8_snorm")
265 return FORMAT_RG8_SNORM;
267 throw invalid_argument("SpirVGenerator::get_format");
270 void SpirVGenerator::use_capability(Capability cap)
272 if(used_capabilities.count(cap))
275 used_capabilities.insert(cap);
276 writer.write_op(content.capabilities, OP_CAPABILITY, cap);
279 SpirVGenerator::Id SpirVGenerator::import_extension(const string &name)
281 Id &ext_id = imported_extension_ids[name];
285 writer.begin_op(content.extensions, OP_EXT_INST_IMPORT);
286 writer.write(ext_id);
287 writer.write_string(name);
288 writer.end_op(OP_EXT_INST_IMPORT);
293 SpirVGenerator::Id SpirVGenerator::get_id(Node &node) const
295 return get_item(declared_ids, &node).id;
298 SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id)
300 auto i = declared_ids.find(&node);
301 if(i!=declared_ids.end())
303 if(i->second.type_id)
304 throw key_error(&node);
305 i->second.type_id = type_id;
310 declared_ids.insert(make_pair(&node, Declaration(id, type_id)));
314 SpirVGenerator::Id SpirVGenerator::allocate_forward_id(Node &node)
316 auto i = declared_ids.find(&node);
317 if(i!=declared_ids.end())
321 declared_ids.insert(make_pair(&node, Declaration(id, 0)));
325 SpirVGenerator::Id SpirVGenerator::write_constant(Id type_id, Word value, bool spec)
327 Id const_id = next_id++;
328 if(is_scalar_type(type_id, BasicTypeDeclaration::BOOL))
330 Opcode opcode = (value ? (spec ? OP_SPEC_CONSTANT_TRUE : OP_CONSTANT_TRUE) :
331 (spec ? OP_SPEC_CONSTANT_FALSE : OP_CONSTANT_FALSE));
332 writer.write_op(content.globals, opcode, type_id, const_id);
336 Opcode opcode = (spec ? OP_SPEC_CONSTANT : OP_CONSTANT);
337 writer.write_op(content.globals, opcode, type_id, const_id, value);
342 SpirVGenerator::ConstantKey SpirVGenerator::get_constant_key(Id type_id, const Variant &value)
344 if(value.check_type<bool>())
345 return ConstantKey(type_id, value.value<bool>());
346 else if(value.check_type<int>())
347 return ConstantKey(type_id, value.value<int>());
348 else if(value.check_type<unsigned>())
349 return ConstantKey(type_id, value.value<unsigned>());
350 else if(value.check_type<float>())
351 return ConstantKey(type_id, value.value<float>());
353 throw invalid_argument("SpirVGenerator::get_constant_key");
356 SpirVGenerator::Id SpirVGenerator::get_constant_id(Id type_id, const Variant &value)
358 ConstantKey key = get_constant_key(type_id, value);
359 Id &const_id = constant_ids[key];
361 const_id = write_constant(type_id, key.int_value, false);
365 SpirVGenerator::Id SpirVGenerator::get_vector_constant_id(Id type_id, unsigned size, Id scalar_id)
367 Id &const_id = constant_ids[get_constant_key(type_id, static_cast<int>(scalar_id))];
370 const_id = next_id++;
371 writer.begin_op(content.globals, OP_CONSTANT_COMPOSITE, 3+size);
372 writer.write(type_id);
373 writer.write(const_id);
374 for(unsigned i=0; i<size; ++i)
375 writer.write(scalar_id);
376 writer.end_op(OP_CONSTANT_COMPOSITE);
381 SpirVGenerator::Id SpirVGenerator::get_standard_type_id(BasicTypeDeclaration::Kind kind, unsigned size, bool sign)
383 Id base_id = (size>1 ? get_standard_type_id(kind, 1, sign) : 0);
384 Id &type_id = standard_type_ids[base_id ? TypeKey(base_id, size) : TypeKey(kind, sign)];
389 writer.write_op(content.globals, OP_TYPE_VECTOR, type_id, base_id, size);
390 else if(kind==BasicTypeDeclaration::VOID)
391 writer.write_op(content.globals, OP_TYPE_VOID, type_id);
392 else if(kind==BasicTypeDeclaration::BOOL)
393 writer.write_op(content.globals, OP_TYPE_BOOL, type_id);
394 else if(kind==BasicTypeDeclaration::INT)
395 writer.write_op(content.globals, OP_TYPE_INT, type_id, 32, sign);
396 else if(kind==BasicTypeDeclaration::FLOAT)
397 writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, 32);
399 throw invalid_argument("SpirVGenerator::get_standard_type_id");
404 bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind) const
406 auto i = standard_type_ids.find(TypeKey(kind, true));
407 return (i!=standard_type_ids.end() && i->second==type_id);
410 SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id, bool extended_align)
412 Id base_type_id = get_id(base_type);
413 Id &array_type_id = array_type_ids[TypeKey(base_type_id, extended_align*0x400000 | size_id)];
416 array_type_id = next_id++;
418 writer.write_op(content.globals, OP_TYPE_ARRAY, array_type_id, base_type_id, size_id);
420 writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id);
422 unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride;
424 stride = (stride+15)&~15U;
425 writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride);
428 return array_type_id;
431 SpirVGenerator::Id SpirVGenerator::get_pointer_type_id(Id type_id, StorageClass storage)
433 Id &ptr_type_id = pointer_type_ids[TypeKey(type_id, storage)];
436 ptr_type_id = next_id++;
437 writer.write_op(content.globals, OP_TYPE_POINTER, ptr_type_id, storage, type_id);
442 SpirVGenerator::Id SpirVGenerator::get_variable_type_id(const VariableDeclaration &var)
444 if(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var.type_declaration))
445 if(basic->kind==BasicTypeDeclaration::ARRAY)
448 throw logic_error("array without size");
450 SetFlag set_const(constant_expression);
451 r_expression_result_id = 0;
452 var.array_size->visit(*this);
453 return get_array_type_id(*basic->base_type, r_expression_result_id, basic->extended_alignment);
456 return get_id(*var.type_declaration);
459 SpirVGenerator::Id SpirVGenerator::get_load_id(VariableDeclaration &var)
461 Id &load_result_id = variable_load_ids[&var];
464 load_result_id = next_id++;
465 writer.write_op(content.function_body, OP_LOAD, get_variable_type_id(var), load_result_id, get_id(var));
467 return load_result_id;
470 void SpirVGenerator::prune_loads(Id min_id)
472 for(auto i=variable_load_ids.begin(); i!=variable_load_ids.end(); )
474 if(i->second>=min_id)
475 variable_load_ids.erase(i++);
481 SpirVGenerator::Id SpirVGenerator::begin_expression(Opcode opcode, Id type_id, unsigned n_args)
483 bool has_result = (opcode==OP_FUNCTION_CALL || !is_scalar_type(type_id, BasicTypeDeclaration::VOID));
484 if(!constant_expression)
486 if(!current_function)
487 throw internal_error("non-constant expression outside a function");
489 writer.begin_op(content.function_body, opcode, (n_args ? 1+has_result*2+n_args : 0));
491 else if(opcode==OP_COMPOSITE_CONSTRUCT)
492 writer.begin_op(content.globals, (spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE),
493 (n_args ? 1+has_result*2+n_args : 0));
494 else if(!spec_constant)
495 throw internal_error("invalid non-specialization constant expression");
497 writer.begin_op(content.globals, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
499 Id result_id = next_id++;
502 writer.write(type_id);
503 writer.write(result_id);
505 if(spec_constant && opcode!=OP_COMPOSITE_CONSTRUCT)
506 writer.write(opcode);
511 void SpirVGenerator::end_expression(Opcode opcode)
513 if(constant_expression)
514 opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP);
515 writer.end_op(opcode);
518 SpirVGenerator::Id SpirVGenerator::write_expression(Opcode opcode, Id type_id, Id arg_id)
520 Id result_id = begin_expression(opcode, type_id, 1);
521 writer.write(arg_id);
522 end_expression(opcode);
526 SpirVGenerator::Id SpirVGenerator::write_expression(Opcode opcode, Id type_id, Id left_id, Id right_id)
528 Id result_id = begin_expression(opcode, type_id, 2);
529 writer.write(left_id);
530 writer.write(right_id);
531 end_expression(opcode);
535 void SpirVGenerator::write_deconstruct(Id elem_type_id, Id composite_id, Id *elem_ids, unsigned n_elems)
537 for(unsigned i=0; i<n_elems; ++i)
539 elem_ids[i] = begin_expression(OP_COMPOSITE_EXTRACT, elem_type_id, 2);
540 writer.write(composite_id);
542 end_expression(OP_COMPOSITE_EXTRACT);
546 SpirVGenerator::Id SpirVGenerator::write_construct(Id type_id, const Id *elem_ids, unsigned n_elems)
548 Id result_id = begin_expression(OP_COMPOSITE_CONSTRUCT, type_id, n_elems);
549 for(unsigned i=0; i<n_elems; ++i)
550 writer.write(elem_ids[i]);
551 end_expression(OP_COMPOSITE_CONSTRUCT);
556 void SpirVGenerator::visit(Block &block)
558 for(const RefPtr<Statement> &s: block.body)
562 void SpirVGenerator::visit(Literal &literal)
564 Id type_id = get_id(*literal.type);
566 r_expression_result_id = write_constant(type_id, get_constant_key(type_id, literal.value).int_value, true);
568 r_expression_result_id = get_constant_id(type_id, literal.value);
569 r_constant_result = true;
572 void SpirVGenerator::visit(VariableReference &var)
574 if(constant_expression || var.declaration->constant)
576 if(!var.declaration->constant)
577 throw internal_error("reference to non-constant variable in constant context");
579 r_expression_result_id = get_id(*var.declaration);
580 r_constant_result = true;
583 else if(!current_function)
584 throw internal_error("non-constant context outside a function");
586 r_constant_result = false;
589 r_expression_result_id = 0;
590 if(assignment_source_id)
591 variable_load_ids.erase(var.declaration);
594 auto i = variable_load_ids.find(var.declaration);
595 if(i!=variable_load_ids.end())
596 r_expression_result_id = i->second;
598 if(!r_expression_result_id)
599 r_composite_base = var.declaration;
601 else if(assignment_source_id)
603 writer.write_op(content.function_body, OP_STORE, get_id(*var.declaration), assignment_source_id);
604 variable_load_ids[var.declaration] = assignment_source_id;
605 r_expression_result_id = assignment_source_id;
608 r_expression_result_id = get_load_id(*var.declaration);
611 void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type)
614 Id result_type_id = get_id(result_type);
615 Id access_type_id = result_type_id;
618 if(constant_expression)
619 throw internal_error("composite access through pointer in constant context");
621 Id int32_type_id = get_standard_type_id(BasicTypeDeclaration::INT, 1);
622 for(unsigned &i: r_composite_chain)
623 i = (i<0x400000 ? get_constant_id(int32_type_id, static_cast<int>(i)) : i&0x3FFFFF);
625 /* Find the storage class of the base and obtain appropriate pointer type
627 const Declaration &base_decl = get_item(declared_ids, r_composite_base);
628 auto i = pointer_type_ids.begin();
629 for(; (i!=pointer_type_ids.end() && i->second!=base_decl.type_id); ++i) ;
630 if(i==pointer_type_ids.end())
631 throw internal_error("could not find storage class");
632 access_type_id = get_pointer_type_id(result_type_id, static_cast<StorageClass>(i->first.detail));
634 opcode = OP_ACCESS_CHAIN;
636 else if(assignment_source_id)
637 throw internal_error("assignment to temporary composite");
640 for(unsigned &i: r_composite_chain)
641 for(auto j=constant_ids.begin(); (i>=0x400000 && j!=constant_ids.end()); ++j)
642 if(j->second==(i&0x3FFFFF))
643 i = j->first.int_value;
645 opcode = OP_COMPOSITE_EXTRACT;
648 Id access_id = begin_expression(opcode, access_type_id, 1+r_composite_chain.size());
649 writer.write(r_composite_base_id);
650 for(unsigned i: r_composite_chain)
652 end_expression(opcode);
654 r_constant_result = false;
657 if(assignment_source_id)
659 writer.write_op(content.function_body, OP_STORE, access_id, assignment_source_id);
660 r_expression_result_id = assignment_source_id;
663 r_expression_result_id = write_expression(OP_LOAD, result_type_id, access_id);
666 r_expression_result_id = access_id;
669 void SpirVGenerator::visit_composite(Expression &base_expr, unsigned index, TypeDeclaration &type)
671 if(!composite_access)
673 r_composite_base = 0;
674 r_composite_base_id = 0;
675 r_composite_chain.clear();
679 SetFlag set_composite(composite_access);
680 base_expr.visit(*this);
683 if(!r_composite_base_id)
684 r_composite_base_id = (r_composite_base ? get_id(*r_composite_base) : r_expression_result_id);
686 r_composite_chain.push_back(index);
687 if(!composite_access)
688 generate_composite_access(type);
690 r_expression_result_id = 0;
693 void SpirVGenerator::visit_isolated(Expression &expr)
695 SetForScope<Id> clear_assign(assignment_source_id, 0);
696 SetFlag clear_composite(composite_access, false);
697 SetForScope<Node *> clear_base(r_composite_base, 0);
698 SetForScope<Id> clear_base_id(r_composite_base_id, 0);
699 vector<unsigned> saved_chain;
700 swap(saved_chain, r_composite_chain);
702 swap(saved_chain, r_composite_chain);
705 void SpirVGenerator::visit(MemberAccess &memacc)
707 visit_composite(*memacc.left, memacc.index, *memacc.type);
710 void SpirVGenerator::visit(Swizzle &swizzle)
713 visit_composite(*swizzle.left, swizzle.components[0], *swizzle.type);
714 else if(assignment_source_id)
716 const BasicTypeDeclaration &basic = dynamic_cast<const BasicTypeDeclaration &>(*swizzle.left->type);
719 for(unsigned i=0; i<swizzle.count; ++i)
720 mask |= 1<<swizzle.components[i];
722 visit_isolated(*swizzle.left);
724 Id combined_id = begin_expression(OP_VECTOR_SHUFFLE, get_id(*swizzle.left->type), 2+basic.size);
725 writer.write(r_expression_result_id);
726 writer.write(assignment_source_id);
727 for(unsigned i=0; i<basic.size; ++i)
728 writer.write(i+((mask>>i)&1)*basic.size);
729 end_expression(OP_VECTOR_SHUFFLE);
731 SetForScope<Id> set_assign(assignment_source_id, combined_id);
732 swizzle.left->visit(*this);
734 r_expression_result_id = combined_id;
738 swizzle.left->visit(*this);
739 Id left_id = r_expression_result_id;
741 r_expression_result_id = begin_expression(OP_VECTOR_SHUFFLE, get_id(*swizzle.type), 2+swizzle.count);
742 writer.write(left_id);
743 writer.write(left_id);
744 for(unsigned i=0; i<swizzle.count; ++i)
745 writer.write(swizzle.components[i]);
746 end_expression(OP_VECTOR_SHUFFLE);
748 r_constant_result = false;
751 void SpirVGenerator::visit(UnaryExpression &unary)
754 return visit_isolated(unary);
756 unary.expression->visit(*this);
758 char oper = unary.oper->token[0];
759 char oper2 = unary.oper->token[1];
760 if(oper=='+' && !oper2)
763 BasicTypeDeclaration &basic = dynamic_cast<BasicTypeDeclaration &>(*unary.expression->type);
764 BasicTypeDeclaration &elem = *get_element_type(basic);
766 if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
767 /* SPIR-V allows constant operations on floating-point values only for
769 throw internal_error("invalid operands for constant unary expression");
771 Id result_type_id = get_id(*unary.type);
772 Opcode opcode = OP_NOP;
774 r_constant_result = false;
776 opcode = OP_LOGICAL_NOT;
779 else if(oper=='-' && !oper2)
781 opcode = (elem.kind==BasicTypeDeclaration::INT ? OP_S_NEGATE : OP_F_NEGATE);
783 if(basic.kind==BasicTypeDeclaration::MATRIX)
785 Id column_type_id = get_id(*basic.base_type);
786 unsigned n_columns = basic.size&0xFFFF;
788 write_deconstruct(column_type_id, r_expression_result_id, column_ids, n_columns);
789 for(unsigned i=0; i<n_columns; ++i)
790 column_ids[i] = write_expression(opcode, column_type_id, column_ids[i]);
791 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
795 else if((oper=='+' || oper=='-') && oper2==oper)
797 if(constant_expression)
798 throw internal_error("increment or decrement in constant expression");
801 if(elem.kind==BasicTypeDeclaration::INT)
803 opcode = (oper=='+' ? OP_I_ADD : OP_I_SUB);
804 one_id = get_constant_id(get_id(elem), 1);
806 else if(elem.kind==BasicTypeDeclaration::FLOAT)
808 opcode = (oper=='+' ? OP_F_ADD : OP_F_SUB);
809 one_id = get_constant_id(get_id(elem), 1.0f);
812 throw internal_error("invalid increment/decrement");
814 if(basic.kind==BasicTypeDeclaration::VECTOR)
815 one_id = get_vector_constant_id(result_type_id, basic.size, one_id);
817 Id post_value_id = write_expression(opcode, result_type_id, r_expression_result_id, one_id);
819 SetForScope<Id> set_assign(assignment_source_id, post_value_id);
820 unary.expression->visit(*this);
822 r_expression_result_id = (unary.oper->type==Operator::POSTFIX ? r_expression_result_id : post_value_id);
827 throw internal_error("unknown unary operator");
829 r_expression_result_id = write_expression(opcode, result_type_id, r_expression_result_id);
832 void SpirVGenerator::visit(BinaryExpression &binary)
834 char oper = binary.oper->token[0];
837 visit_isolated(*binary.right);
838 return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type);
840 else if(composite_access)
841 return visit_isolated(binary);
843 if(assignment_source_id)
844 throw internal_error("invalid binary expression in assignment target");
846 BasicTypeDeclaration &basic_left = dynamic_cast<BasicTypeDeclaration &>(*binary.left->type);
847 BasicTypeDeclaration &basic_right = dynamic_cast<BasicTypeDeclaration &>(*binary.right->type);
848 // Expression resolver ensures that element types are the same
849 BasicTypeDeclaration &elem = *get_element_type(basic_left);
851 if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
852 /* SPIR-V allows constant operations on floating-point values only for
854 throw internal_error("invalid operands for constant binary expression");
856 binary.left->visit(*this);
857 Id left_id = r_expression_result_id;
858 binary.right->visit(*this);
859 Id right_id = r_expression_result_id;
861 Id result_type_id = get_id(*binary.type);
862 Opcode opcode = OP_NOP;
863 bool swap_operands = false;
865 r_constant_result = false;
867 char oper2 = binary.oper->token[1];
868 if((oper=='<' || oper=='>') && oper2!=oper)
870 if(basic_left.kind==BasicTypeDeclaration::INT)
873 opcode = (oper=='<' ? (oper2=='=' ? OP_S_LESS_THAN_EQUAL : OP_S_LESS_THAN) :
874 (oper2=='=' ? OP_S_GREATER_THAN_EQUAL : OP_S_GREATER_THAN));
876 opcode = (oper=='<' ? (oper2=='=' ? OP_U_LESS_THAN_EQUAL : OP_U_LESS_THAN) :
877 (oper2=='=' ? OP_U_GREATER_THAN_EQUAL : OP_U_GREATER_THAN));
879 else if(basic_left.kind==BasicTypeDeclaration::FLOAT)
880 opcode = (oper=='<' ? (oper2=='=' ? OP_F_ORD_LESS_THAN_EQUAL : OP_F_ORD_LESS_THAN) :
881 (oper2=='=' ? OP_F_ORD_GREATER_THAN_EQUAL : OP_F_ORD_GREATER_THAN));
883 else if((oper=='=' || oper=='!') && oper2=='=')
885 if(elem.kind==BasicTypeDeclaration::BOOL)
886 opcode = (oper=='=' ? OP_LOGICAL_EQUAL : OP_LOGICAL_NOT_EQUAL);
887 else if(elem.kind==BasicTypeDeclaration::INT)
888 opcode = (oper=='=' ? OP_I_EQUAL : OP_I_NOT_EQUAL);
889 else if(elem.kind==BasicTypeDeclaration::FLOAT)
890 opcode = (oper=='=' ? OP_F_ORD_EQUAL : OP_F_ORD_NOT_EQUAL);
892 if(opcode!=OP_NOP && basic_left.base_type)
894 /* The SPIR-V equality operations produce component-wise results, but
895 GLSL operators return a single boolean. Use the any/all operations to
896 combine the results. */
897 Opcode combine_op = (oper=='!' ? OP_ANY : OP_ALL);
898 unsigned n_elems = basic_left.size&0xFFFF;
899 Id bool_vec_type_id = get_standard_type_id(BasicTypeDeclaration::BOOL, n_elems);
902 if(basic_left.kind==BasicTypeDeclaration::VECTOR)
903 compare_id = write_expression(opcode, bool_vec_type_id, left_id, right_id);
904 else if(basic_left.kind==BasicTypeDeclaration::MATRIX)
906 Id column_type_id = get_id(*basic_left.base_type);
908 write_deconstruct(column_type_id, left_id, column_ids, n_elems);
909 write_deconstruct(column_type_id, right_id, column_ids+4, n_elems);
911 Id column_bvec_type_id = get_standard_type_id(BasicTypeDeclaration::BOOL, basic_left.size>>16);
912 for(unsigned i=0; i<n_elems; ++i)
914 compare_id = write_expression(opcode, column_bvec_type_id, column_ids[i], column_ids[4+i]);
915 column_ids[i] = write_expression(combine_op, result_type_id, compare_id);;
918 compare_id = write_construct(bool_vec_type_id, column_ids, n_elems);
922 r_expression_result_id = write_expression(combine_op, result_type_id, compare_id);
926 else if(oper2=='&' && elem.kind==BasicTypeDeclaration::BOOL)
927 opcode = OP_LOGICAL_AND;
928 else if(oper2=='|' && elem.kind==BasicTypeDeclaration::BOOL)
929 opcode = OP_LOGICAL_OR;
930 else if(oper2=='^' && elem.kind==BasicTypeDeclaration::BOOL)
931 opcode = OP_LOGICAL_NOT_EQUAL;
932 else if(oper=='&' && elem.kind==BasicTypeDeclaration::INT)
933 opcode = OP_BITWISE_AND;
934 else if(oper=='|' && elem.kind==BasicTypeDeclaration::INT)
935 opcode = OP_BITWISE_OR;
936 else if(oper=='^' && elem.kind==BasicTypeDeclaration::INT)
937 opcode = OP_BITWISE_XOR;
938 else if(oper=='<' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
939 opcode = OP_SHIFT_LEFT_LOGICAL;
940 else if(oper=='>' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
941 opcode = OP_SHIFT_RIGHT_ARITHMETIC;
942 else if(oper=='%' && elem.kind==BasicTypeDeclaration::INT)
943 opcode = (elem.sign ? OP_S_MOD : OP_U_MOD);
944 else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
946 Opcode elem_op = OP_NOP;
947 if(elem.kind==BasicTypeDeclaration::INT)
950 elem_op = (elem.sign ? OP_S_DIV : OP_U_DIV);
952 elem_op = (oper=='+' ? OP_I_ADD : oper=='-' ? OP_I_SUB : OP_I_MUL);
954 else if(elem.kind==BasicTypeDeclaration::FLOAT)
955 elem_op = (oper=='+' ? OP_F_ADD : oper=='-' ? OP_F_SUB : oper=='*' ? OP_F_MUL : OP_F_DIV);
957 if(oper=='*' && (basic_left.base_type || basic_right.base_type) && elem.kind==BasicTypeDeclaration::FLOAT)
959 /* Multiplication between floating-point vectors and matrices has
960 dedicated operations. */
961 if(basic_left.kind==BasicTypeDeclaration::MATRIX && basic_right.kind==BasicTypeDeclaration::MATRIX)
962 opcode = OP_MATRIX_TIMES_MATRIX;
963 else if(basic_left.kind==BasicTypeDeclaration::MATRIX || basic_right.kind==BasicTypeDeclaration::MATRIX)
965 if(basic_left.kind==BasicTypeDeclaration::VECTOR)
966 opcode = OP_VECTOR_TIMES_MATRIX;
967 else if(basic_right.kind==BasicTypeDeclaration::VECTOR)
968 opcode = OP_MATRIX_TIMES_VECTOR;
971 opcode = OP_MATRIX_TIMES_SCALAR;
972 swap_operands = (basic_right.kind==BasicTypeDeclaration::MATRIX);
975 else if(basic_left.kind==BasicTypeDeclaration::VECTOR && basic_right.kind==BasicTypeDeclaration::VECTOR)
979 opcode = OP_VECTOR_TIMES_SCALAR;
980 swap_operands = (basic_right.kind==BasicTypeDeclaration::VECTOR);
983 else if((basic_left.base_type!=0)!=(basic_right.base_type!=0))
985 /* One operand is scalar and the other is a vector or a matrix.
986 Expand the scalar to a vector of appropriate size. */
987 Id &scalar_id = (basic_left.base_type ? right_id : left_id);
988 BasicTypeDeclaration *vector_type = (basic_left.base_type ? &basic_left : &basic_right);
989 if(vector_type->kind==BasicTypeDeclaration::MATRIX)
990 vector_type = dynamic_cast<BasicTypeDeclaration *>(vector_type->base_type);
991 Id vector_type_id = get_id(*vector_type);
993 Id expanded_id = begin_expression(OP_COMPOSITE_CONSTRUCT, vector_type_id, vector_type->size);
994 for(unsigned i=0; i<vector_type->size; ++i)
995 writer.write(scalar_id);
996 end_expression(OP_COMPOSITE_CONSTRUCT);
998 scalar_id = expanded_id;
1000 if(basic_left.kind==BasicTypeDeclaration::MATRIX || basic_right.kind==BasicTypeDeclaration::MATRIX)
1002 // Apply matrix operation column-wise.
1003 Id matrix_id = (basic_left.base_type ? left_id : right_id);
1006 unsigned n_columns = (basic_left.base_type ? basic_left.size : basic_right.size)&0xFFFF;
1007 write_deconstruct(vector_type_id, matrix_id, column_ids, n_columns);
1009 for(unsigned i=0; i<n_columns; ++i)
1010 column_ids[i] = write_expression(elem_op, vector_type_id, column_ids[i], expanded_id);
1012 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1018 else if(basic_left.kind==BasicTypeDeclaration::MATRIX && basic_right.kind==BasicTypeDeclaration::MATRIX)
1021 throw internal_error("non-float matrix multiplication");
1023 /* Other operations involving matrices need to be performed
1025 Id column_type_id = get_id(*basic_left.base_type);
1028 unsigned n_columns = basic_left.size&0xFFFF;
1029 write_deconstruct(column_type_id, left_id, column_ids, n_columns);
1030 write_deconstruct(column_type_id, right_id, column_ids+4, n_columns);
1032 for(unsigned i=0; i<n_columns; ++i)
1033 column_ids[i] = write_expression(elem_op, column_type_id, column_ids[i], column_ids[4+i]);
1035 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1038 else if(basic_left.kind==basic_right.kind)
1039 // Both operands are either scalars or vectors.
1044 throw internal_error("unknown binary operator");
1047 swap(left_id, right_id);
1049 r_expression_result_id = write_expression(opcode, result_type_id, left_id, right_id);
1052 void SpirVGenerator::visit(Assignment &assign)
1054 if(assign.oper->token[0]!='=')
1055 visit(static_cast<BinaryExpression &>(assign));
1057 assign.right->visit(*this);
1059 SetForScope<Id> set_assign(assignment_source_id, r_expression_result_id);
1060 assign.left->visit(*this);
1061 r_constant_result = false;
1064 void SpirVGenerator::visit(TernaryExpression &ternary)
1066 if(composite_access)
1067 return visit_isolated(ternary);
1068 if(constant_expression)
1070 ternary.condition->visit(*this);
1071 Id condition_id = r_expression_result_id;
1072 ternary.true_expr->visit(*this);
1073 Id true_result_id = r_expression_result_id;
1074 ternary.false_expr->visit(*this);
1075 Id false_result_id = r_expression_result_id;
1077 r_expression_result_id = begin_expression(OP_SELECT, get_id(*ternary.type), 3);
1078 writer.write(condition_id);
1079 writer.write(true_result_id);
1080 writer.write(false_result_id);
1081 end_expression(OP_SELECT);
1086 ternary.condition->visit(*this);
1087 Id condition_id = r_expression_result_id;
1089 Id true_label_id = next_id++;
1090 Id false_label_id = next_id++;
1091 Id merge_block_id = next_id++;
1092 writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none)
1093 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, condition_id, true_label_id, false_label_id);
1095 std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
1097 writer.write_op_label(true_label_id);
1098 ternary.true_expr->visit(*this);
1099 Id true_result_id = r_expression_result_id;
1100 true_label_id = writer.get_current_block();
1101 writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
1103 swap(saved_load_ids, variable_load_ids);
1104 writer.write_op_label(false_label_id);
1105 ternary.false_expr->visit(*this);
1106 Id false_result_id = r_expression_result_id;
1107 false_label_id = writer.get_current_block();
1109 writer.write_op_label(merge_block_id);
1110 prune_loads(true_label_id);
1111 r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4);
1112 writer.write(true_result_id);
1113 writer.write(true_label_id);
1114 writer.write(false_result_id);
1115 writer.write(false_label_id);
1116 end_expression(OP_PHI);
1118 r_constant_result = false;
1121 void SpirVGenerator::visit(FunctionCall &call)
1123 if(assignment_source_id)
1124 throw internal_error("assignment to function call");
1125 else if(composite_access)
1126 return visit_isolated(call);
1127 else if(call.constructor && call.arguments.size()==1 && call.arguments[0]->type==call.type)
1128 return call.arguments[0]->visit(*this);
1130 vector<Id> argument_ids;
1131 argument_ids.reserve(call.arguments.size());
1132 bool all_args_const = true;
1133 for(const RefPtr<Expression> &a: call.arguments)
1136 argument_ids.push_back(r_expression_result_id);
1137 all_args_const &= r_constant_result;
1140 if(constant_expression && (!call.constructor || !all_args_const))
1141 throw internal_error("function call in constant expression");
1143 Id result_type_id = get_id(*call.type);
1144 r_constant_result = false;
1146 if(call.constructor)
1147 visit_constructor(call, argument_ids, all_args_const);
1148 else if(call.declaration->source==BUILTIN_SOURCE)
1151 for(const RefPtr<Expression> &a: call.arguments)
1152 if(BasicTypeDeclaration *basic_arg = dynamic_cast<BasicTypeDeclaration *>(a->type))
1154 BasicTypeDeclaration &elem_arg = *get_element_type(*basic_arg);
1155 switch(elem_arg.kind)
1157 case BasicTypeDeclaration::BOOL: arg_types += 'b'; break;
1158 case BasicTypeDeclaration::INT: arg_types += (elem_arg.sign ? 'i' : 'u'); break;
1159 case BasicTypeDeclaration::FLOAT: arg_types += 'f'; break;
1160 default: arg_types += '?';
1164 const BuiltinFunctionInfo *builtin_info;
1165 for(builtin_info=builtin_functions; builtin_info->function[0]; ++builtin_info)
1166 if(builtin_info->function==call.name && (!builtin_info->arg_types[0] || builtin_info->arg_types==arg_types))
1169 if(builtin_info->capability)
1170 use_capability(static_cast<Capability>(builtin_info->capability));
1172 if(builtin_info->opcode)
1175 if(builtin_info->extension[0])
1177 opcode = OP_EXT_INST;
1178 Id ext_id = import_extension(builtin_info->extension);
1180 r_expression_result_id = begin_expression(opcode, result_type_id);
1181 writer.write(ext_id);
1182 writer.write(builtin_info->opcode);
1186 opcode = static_cast<Opcode>(builtin_info->opcode);
1187 r_expression_result_id = begin_expression(opcode, result_type_id);
1190 for(unsigned i=0; i<call.arguments.size(); ++i)
1192 if(!builtin_info->arg_order[i] || builtin_info->arg_order[i]>argument_ids.size())
1193 throw internal_error("invalid builtin function info");
1194 writer.write(argument_ids[builtin_info->arg_order[i]-1]);
1197 end_expression(opcode);
1199 else if(builtin_info->handler)
1200 (this->*(builtin_info->handler))(call, argument_ids);
1202 throw internal_error("unknown builtin function "+call.name);
1206 r_expression_result_id = begin_expression(OP_FUNCTION_CALL, result_type_id, 1+call.arguments.size());
1207 writer.write(get_id(*call.declaration->definition));
1208 for(Id i: argument_ids)
1210 end_expression(OP_FUNCTION_CALL);
1212 // Any global variables the called function uses might have changed value
1213 set<Node *> dependencies = DependencyCollector().apply(*call.declaration->definition);
1214 for(Node *n: dependencies)
1215 if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
1216 variable_load_ids.erase(var);
1220 void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids, bool all_args_const)
1222 Id result_type_id = get_id(*call.type);
1224 BasicTypeDeclaration *basic = dynamic_cast<BasicTypeDeclaration *>(call.type);
1227 if(dynamic_cast<const StructDeclaration *>(call.type))
1228 r_expression_result_id = write_construct(result_type_id, &argument_ids[0], argument_ids.size());
1230 throw internal_error("unconstructable type "+call.name);
1234 SetFlag set_const(constant_expression, constant_expression || all_args_const);
1236 BasicTypeDeclaration &elem = *get_element_type(*basic);
1237 BasicTypeDeclaration &basic_arg0 = dynamic_cast<BasicTypeDeclaration &>(*call.arguments[0]->type);
1238 BasicTypeDeclaration &elem_arg0 = *get_element_type(basic_arg0);
1240 if(basic->kind==BasicTypeDeclaration::MATRIX)
1242 Id col_type_id = get_id(*basic->base_type);
1243 unsigned n_columns = basic->size&0xFFFF;
1244 unsigned n_rows = basic->size>>16;
1247 if(call.arguments.size()==1)
1249 // Construct diagonal matrix from a single scalar.
1250 Id zero_id = get_constant_id(get_id(elem), 0.0f);
1251 for(unsigned i=0; i<n_columns; ++i)
1253 column_ids[i] = begin_expression(OP_COMPOSITE_CONSTRUCT, col_type_id, n_rows);
1254 for(unsigned j=0; j<n_rows; ++j)
1255 writer.write(j==i ? argument_ids[0] : zero_id);
1256 end_expression(OP_COMPOSITE_CONSTRUCT);
1260 // Construct a matrix from column vectors
1261 copy(argument_ids.begin(), argument_ids.begin()+n_columns, column_ids);
1263 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1265 else if(basic->kind==BasicTypeDeclaration::VECTOR && (call.arguments.size()>1 || basic_arg0.kind!=BasicTypeDeclaration::VECTOR))
1267 /* There's either a single scalar argument or multiple arguments
1268 which make up the vector's components. */
1269 if(call.arguments.size()==1)
1271 r_expression_result_id = begin_expression(OP_COMPOSITE_CONSTRUCT, result_type_id);
1272 for(unsigned i=0; i<basic->size; ++i)
1273 writer.write(argument_ids[0]);
1274 end_expression(OP_COMPOSITE_CONSTRUCT);
1277 r_expression_result_id = write_construct(result_type_id, &argument_ids[0], argument_ids.size());
1279 else if(elem.kind==BasicTypeDeclaration::BOOL)
1281 if(constant_expression)
1282 throw internal_error("unconverted constant");
1284 // Conversion to boolean is implemented as comparing against zero.
1285 Id number_type_id = get_id(elem_arg0);
1286 Id zero_id = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ?
1287 get_constant_id(number_type_id, 0.0f) : get_constant_id(number_type_id, 0));
1288 if(basic_arg0.kind==BasicTypeDeclaration::VECTOR)
1289 zero_id = get_vector_constant_id(get_id(basic_arg0), basic_arg0.size, zero_id);
1291 Opcode opcode = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ? OP_F_ORD_NOT_EQUAL : OP_I_NOT_EQUAL);
1292 r_expression_result_id = write_expression(opcode, result_type_id, argument_ids[0], zero_id);
1294 else if(elem_arg0.kind==BasicTypeDeclaration::BOOL)
1296 if(constant_expression)
1297 throw internal_error("unconverted constant");
1299 /* Conversion from boolean is implemented as selecting from zero
1301 Id number_type_id = get_id(elem);
1302 Id zero_id = (elem.kind==BasicTypeDeclaration::FLOAT ?
1303 get_constant_id(number_type_id, 0.0f) : get_constant_id(number_type_id, 0));
1304 Id one_id = (elem.kind==BasicTypeDeclaration::FLOAT ?
1305 get_constant_id(number_type_id, 1.0f) : get_constant_id(number_type_id, 1));
1306 if(basic->kind==BasicTypeDeclaration::VECTOR)
1308 zero_id = get_vector_constant_id(get_id(*basic), basic->size, zero_id);
1309 one_id = get_vector_constant_id(get_id(*basic), basic->size, one_id);
1312 r_expression_result_id = begin_expression(OP_SELECT, result_type_id, 3);
1313 writer.write(argument_ids[0]);
1314 writer.write(zero_id);
1315 writer.write(one_id);
1316 end_expression(OP_SELECT);
1320 if(constant_expression)
1321 throw internal_error("unconverted constant");
1323 // Scalar or vector conversion between types of equal size.
1325 if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::FLOAT)
1326 opcode = (elem.sign ? OP_CONVERT_F_TO_S : OP_CONVERT_F_TO_U);
1327 else if(elem.kind==BasicTypeDeclaration::FLOAT && elem_arg0.kind==BasicTypeDeclaration::INT)
1328 opcode = (elem_arg0.sign ? OP_CONVERT_S_TO_F : OP_CONVERT_U_TO_F);
1329 else if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::INT)
1330 opcode = OP_BITCAST;
1332 throw internal_error("invalid conversion");
1334 r_expression_result_id = write_expression(opcode, result_type_id, argument_ids[0]);
1338 void SpirVGenerator::visit_builtin_matrix_comp_mult(FunctionCall &call, const vector<Id> &argument_ids)
1340 if(argument_ids.size()!=2)
1341 throw internal_error("invalid matrixCompMult call");
1343 const BasicTypeDeclaration &basic_arg0 = dynamic_cast<const BasicTypeDeclaration &>(*call.arguments[0]->type);
1344 Id column_type_id = get_id(*basic_arg0.base_type);
1347 unsigned n_columns = basic_arg0.size&0xFFFF;
1348 write_deconstruct(column_type_id, argument_ids[0], column_ids, n_columns);
1349 write_deconstruct(column_type_id, argument_ids[1], column_ids+4, n_columns);
1351 for(unsigned i=0; i<n_columns; ++i)
1352 column_ids[i] = write_expression(OP_F_MUL, column_type_id, column_ids[i], column_ids[4+i]);
1354 r_expression_result_id = write_construct(get_id(*call.type), column_ids, n_columns);
1357 void SpirVGenerator::visit_builtin_texture_query(FunctionCall &call, const vector<Id> &argument_ids)
1359 if(argument_ids.size()<1)
1360 throw internal_error("invalid texture query call");
1363 if(call.name=="textureSize")
1364 opcode = OP_IMAGE_QUERY_SIZE_LOD;
1365 else if(call.name=="imageSize")
1366 opcode = OP_IMAGE_QUERY_SIZE;
1367 else if(call.name=="textureQueryLod")
1368 opcode = OP_IMAGE_QUERY_LOD;
1369 else if(call.name=="textureQueryLevels")
1370 opcode = OP_IMAGE_QUERY_LEVELS;
1371 else if(call.name=="textureSamples" || call.name=="imageSamples")
1372 opcode = OP_IMAGE_QUERY_SAMPLES;
1374 throw internal_error("invalid texture query call");
1376 ImageTypeDeclaration &image_arg0 = dynamic_cast<ImageTypeDeclaration &>(*call.arguments[0]->type);
1379 if(image_arg0.sampled && opcode!=OP_IMAGE_QUERY_LOD)
1381 Id image_type_id = get_item(image_type_ids, get_id(image_arg0));
1382 image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]);
1385 image_id = argument_ids[0];
1387 Id result_type_id = get_id(*call.type);
1388 r_expression_result_id = begin_expression(opcode, result_type_id, argument_ids.size());
1389 writer.write(image_id);
1390 for(unsigned i=1; i<argument_ids.size(); ++i)
1391 writer.write(argument_ids[i]);
1392 end_expression(opcode);
1395 void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector<Id> &argument_ids)
1397 if(argument_ids.size()<2)
1398 throw internal_error("invalid texture sampling call");
1400 bool explicit_lod = (stage->type!=Stage::FRAGMENT || call.name=="textureLod");
1401 Id lod_id = (!explicit_lod ? 0 : call.name=="textureLod" ? argument_ids.back() :
1402 get_constant_id(get_standard_type_id(BasicTypeDeclaration::FLOAT, 1), 0.0f));
1404 const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*call.arguments[0]->type);
1407 Id result_type_id = get_id(*call.type);
1411 if(argument_ids.size()==2)
1413 const BasicTypeDeclaration &basic_arg1 = dynamic_cast<const BasicTypeDeclaration &>(*call.arguments[1]->type);
1414 dref_id = begin_expression(OP_COMPOSITE_EXTRACT, get_id(*basic_arg1.base_type), 2);
1415 writer.write(argument_ids.back());
1416 writer.write(basic_arg1.size-1);
1417 end_expression(OP_COMPOSITE_EXTRACT);
1420 dref_id = argument_ids[2];
1422 opcode = (explicit_lod ? OP_IMAGE_SAMPLE_DREF_EXPLICIT_LOD : OP_IMAGE_SAMPLE_DREF_IMPLICIT_LOD);
1423 r_expression_result_id = begin_expression(opcode, result_type_id, 3+explicit_lod*2);
1427 opcode = (explicit_lod ? OP_IMAGE_SAMPLE_EXPLICIT_LOD : OP_IMAGE_SAMPLE_IMPLICIT_LOD);
1428 r_expression_result_id = begin_expression(opcode, result_type_id, 2+explicit_lod*2);
1431 for(unsigned i=0; i<2; ++i)
1432 writer.write(argument_ids[i]);
1434 writer.write(dref_id);
1437 writer.write(2); // Lod
1438 writer.write(lod_id);
1441 end_expression(opcode);
1444 void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector<Id> &argument_ids)
1446 ImageTypeDeclaration &image = dynamic_cast<ImageTypeDeclaration &>(*call.arguments[0]->type);
1449 if(call.name=="texelFetch")
1450 opcode = OP_IMAGE_FETCH;
1451 else if(call.name=="imageLoad")
1452 opcode = OP_IMAGE_READ;
1454 throw internal_error("invalid texture fetch call");
1456 bool need_sample = image.multisample;
1457 bool need_lod = (opcode==OP_IMAGE_FETCH && !need_sample);
1459 if(argument_ids.size()!=2U+need_sample+need_lod)
1460 throw internal_error("invalid texture fetch call");
1465 Id image_type_id = get_item(image_type_ids, get_id(image));
1466 image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]);
1469 image_id = argument_ids[0];
1471 r_expression_result_id = begin_expression(opcode, get_id(*call.type), 2+(need_lod|need_sample)+need_lod+need_sample);
1472 writer.write(image_id);
1473 writer.write(argument_ids[1]);
1474 if(need_lod || need_sample)
1476 writer.write(need_lod*0x02 | need_sample*0x40);
1477 writer.write(argument_ids.back());
1479 end_expression(opcode);
1482 void SpirVGenerator::visit_builtin_texture_store(FunctionCall &call, const vector<Id> &argument_ids)
1484 if(argument_ids.size()!=3)
1485 throw internal_error("invalid texture store call");
1487 const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*call.arguments[0]->type);
1489 begin_expression(OP_IMAGE_WRITE, get_id(*call.type), 3+image.multisample*2);
1490 for(unsigned i=0; i<2; ++i)
1491 writer.write(argument_ids[i]);
1492 writer.write(argument_ids.back());
1493 if(image.multisample)
1495 writer.write(0x40); // Sample
1496 writer.write(argument_ids[2]);
1498 end_expression(OP_IMAGE_WRITE);
1500 r_expression_result_id = 0;
1503 void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector<Id> &argument_ids)
1505 if(argument_ids.size()<1)
1506 throw internal_error("invalid interpolate call");
1507 const VariableReference *var = dynamic_cast<const VariableReference *>(call.arguments[0].get());
1508 if(!var || !var->declaration || var->declaration->interface!="in")
1509 throw internal_error("invalid interpolate call");
1511 SpirVGlslStd450Opcode opcode;
1512 if(call.name=="interpolateAtCentroid")
1513 opcode = GLSL450_INTERPOLATE_AT_CENTROID;
1514 else if(call.name=="interpolateAtSample")
1515 opcode = GLSL450_INTERPOLATE_AT_SAMPLE;
1516 else if(call.name=="interpolateAtOffset")
1517 opcode = GLSL450_INTERPOLATE_AT_OFFSET;
1519 throw internal_error("invalid interpolate call");
1521 Id ext_id = import_extension("GLSL.std.450");
1522 r_expression_result_id = begin_expression(OP_EXT_INST, get_id(*call.type));
1523 writer.write(ext_id);
1524 writer.write(opcode);
1525 writer.write(get_id(*var->declaration));
1526 for(auto i=argument_ids.begin(); ++i!=argument_ids.end(); )
1528 end_expression(OP_EXT_INST);
1531 void SpirVGenerator::visit(ExpressionStatement &expr)
1533 expr.expression->visit(*this);
1536 void SpirVGenerator::visit(InterfaceLayout &layout)
1538 interface_layouts.push_back(&layout);
1541 bool SpirVGenerator::check_duplicate_type(TypeDeclaration &type)
1543 for(const auto &kvp: declared_ids)
1544 if(TypeDeclaration *type2 = dynamic_cast<TypeDeclaration *>(kvp.first))
1545 if(TypeComparer().apply(type, *type2))
1547 insert_unique(declared_ids, &type, kvp.second);
1554 bool SpirVGenerator::check_standard_type(BasicTypeDeclaration &basic)
1556 const BasicTypeDeclaration *elem = (basic.kind==BasicTypeDeclaration::VECTOR ?
1557 dynamic_cast<const BasicTypeDeclaration *>(basic.base_type) : &basic);
1558 if(!elem || elem->base_type)
1560 if((elem->kind==BasicTypeDeclaration::INT || elem->kind==BasicTypeDeclaration::FLOAT) && elem->size!=32)
1563 Id standard_id = get_standard_type_id(elem->kind, (basic.kind==BasicTypeDeclaration::VECTOR ? basic.size : 1), elem->sign);
1564 insert_unique(declared_ids, &basic, Declaration(standard_id, 0));
1565 writer.write_op_name(standard_id, basic.name);
1570 void SpirVGenerator::visit(BasicTypeDeclaration &basic)
1572 if(check_standard_type(basic))
1574 if(check_duplicate_type(basic))
1576 // Alias types shouldn't exist at this point and arrays are handled elsewhere
1577 if(basic.kind==BasicTypeDeclaration::ALIAS || basic.kind==BasicTypeDeclaration::ARRAY)
1580 Id type_id = allocate_id(basic, 0);
1581 writer.write_op_name(type_id, basic.name);
1585 case BasicTypeDeclaration::INT:
1586 writer.write_op(content.globals, OP_TYPE_INT, type_id, basic.size, basic.sign);
1588 case BasicTypeDeclaration::FLOAT:
1589 writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, basic.size);
1591 case BasicTypeDeclaration::VECTOR:
1592 writer.write_op(content.globals, OP_TYPE_VECTOR, type_id, get_id(*basic.base_type), basic.size);
1594 case BasicTypeDeclaration::MATRIX:
1595 writer.write_op(content.globals, OP_TYPE_MATRIX, type_id, get_id(*basic.base_type), basic.size&0xFFFF);
1598 throw internal_error("unknown basic type");
1602 void SpirVGenerator::visit(ImageTypeDeclaration &image)
1604 if(check_duplicate_type(image))
1607 Id type_id = allocate_id(image, 0);
1608 SpirVFormat format = get_format(image.format);
1610 Id image_id = (image.sampled ? next_id++ : type_id);
1611 writer.begin_op(content.globals, OP_TYPE_IMAGE, 9);
1612 writer.write(image_id);
1613 writer.write(get_id(*image.base_type));
1614 writer.write(image.dimensions-1);
1615 writer.write(image.shadow);
1616 writer.write(image.array);
1617 writer.write(image.multisample);
1618 writer.write(image.sampled ? 1 : 2);
1619 writer.write(format);
1620 writer.end_op(OP_TYPE_IMAGE);
1624 writer.write_op_name(type_id, image.name);
1625 writer.write_op(content.globals, OP_TYPE_SAMPLED_IMAGE, type_id, image_id);
1626 insert_unique(image_type_ids, type_id, image_id);
1629 if(image.dimensions==ImageTypeDeclaration::ONE)
1630 use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D);
1631 else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array)
1632 use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY);
1634 if(image.multisample && !image.sampled)
1635 use_capability(CAP_STORAGE_IMAGE_MULTISAMPLE);
1637 if(format>=FORMAT_RG32F && format<=FORMAT_R8_SNORM)
1638 use_capability(CAP_STORAGE_IMAGE_EXTENDED_FORMATS);
1641 void SpirVGenerator::visit(StructDeclaration &strct)
1643 if(check_duplicate_type(strct))
1646 Id type_id = allocate_id(strct, 0);
1647 writer.write_op_name(type_id, (strct.block_name.empty() ? strct.name : strct.block_name));
1649 if(!strct.block_name.empty())
1650 writer.write_op_decorate(type_id, DECO_BLOCK);
1652 bool builtin = !strct.block_name.compare(0, 3, "gl_");
1653 vector<Id> member_type_ids;
1654 member_type_ids.reserve(strct.members.body.size());
1655 for(const RefPtr<Statement> &s: strct.members.body)
1657 const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(s.get());
1661 unsigned index = member_type_ids.size();
1662 member_type_ids.push_back(get_variable_type_id(*var));
1664 writer.write_op_member_name(type_id, index, var->name);
1668 BuiltinSemantic semantic = get_builtin_semantic(var->name);
1669 writer.write_op_member_decorate(type_id, index, DECO_BUILTIN, semantic);
1675 for(const Layout::Qualifier &q: var->layout->qualifiers)
1677 if(q.name=="offset")
1678 writer.write_op_member_decorate(type_id, index, DECO_OFFSET, q.value);
1679 else if(q.name=="column_major")
1680 writer.write_op_member_decorate(type_id, index, DECO_COL_MAJOR);
1681 else if(q.name=="row_major")
1682 writer.write_op_member_decorate(type_id, index, DECO_ROW_MAJOR);
1686 const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var->type_declaration);
1687 while(basic && basic->kind==BasicTypeDeclaration::ARRAY)
1688 basic = dynamic_cast<const BasicTypeDeclaration *>(basic->base_type);
1689 if(basic && basic->kind==BasicTypeDeclaration::MATRIX)
1691 unsigned stride = MemoryRequirementsCalculator().apply(*basic->base_type).stride;
1692 writer.write_op_member_decorate(type_id, index, DECO_MATRIX_STRIDE, stride);
1697 writer.begin_op(content.globals, OP_TYPE_STRUCT);
1698 writer.write(type_id);
1699 for(Id i: member_type_ids)
1701 writer.end_op(OP_TYPE_STRUCT);
1704 void SpirVGenerator::visit(VariableDeclaration &var)
1706 Id type_id = get_variable_type_id(var);
1711 if(!var.init_expression)
1712 throw internal_error("const variable without initializer");
1714 int spec_id = get_layout_value(var.layout.get(), "constant_id");
1715 Id *spec_var_id = (spec_id>=0 ? &declared_spec_ids[spec_id] : 0);
1716 if(spec_id>=0 && *spec_var_id)
1718 insert_unique(declared_ids, &var, Declaration(*spec_var_id, type_id));
1722 SetFlag set_const(constant_expression);
1723 SetFlag set_spec(spec_constant, spec_id>=0);
1724 r_expression_result_id = 0;
1725 var.init_expression->visit(*this);
1726 var_id = r_expression_result_id;
1727 insert_unique(declared_ids, &var, Declaration(var_id, type_id));
1730 writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
1731 *spec_var_id = var_id;
1736 bool push_const = has_layout_qualifier(var.layout.get(), "push_constant");
1738 StorageClass storage;
1739 if(current_function)
1740 storage = STORAGE_FUNCTION;
1742 storage = STORAGE_PUSH_CONSTANT;
1744 storage = get_interface_storage(var.interface, var.block_declaration);
1746 Id ptr_type_id = get_pointer_type_id(type_id, storage);
1747 if(var.interface=="uniform")
1749 Id &uni_id = declared_uniform_ids[var.block_declaration ? "b"+var.block_declaration->block_name : "v"+var.name];
1752 insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id));
1756 uni_id = var_id = allocate_id(var, ptr_type_id);
1759 var_id = allocate_id(var, (var.constant ? type_id : ptr_type_id));
1762 if(var.init_expression)
1764 SetFlag set_const(constant_expression, !current_function);
1765 r_expression_result_id = 0;
1766 r_constant_result = false;
1767 var.init_expression->visit(*this);
1768 init_id = r_expression_result_id;
1771 vector<Word> &target = (current_function ? content.locals : content.globals);
1772 writer.begin_op(target, OP_VARIABLE, 4+(init_id && !current_function));
1773 writer.write(ptr_type_id);
1774 writer.write(var_id);
1775 writer.write(storage);
1776 if(init_id && !current_function)
1777 writer.write(init_id);
1778 writer.end_op(OP_VARIABLE);
1782 for(const Layout::Qualifier &q: var.layout->qualifiers)
1784 if(q.name=="location")
1785 writer.write_op_decorate(var_id, DECO_LOCATION, q.value);
1786 else if(q.name=="set")
1787 writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, q.value);
1788 else if(q.name=="binding")
1789 writer.write_op_decorate(var_id, DECO_BINDING, q.value);
1792 if(!var.block_declaration && !var.name.compare(0, 3, "gl_"))
1794 BuiltinSemantic semantic = get_builtin_semantic(var.name);
1795 writer.write_op_decorate(var_id, DECO_BUILTIN, semantic);
1797 if(var.sampling=="flat")
1798 writer.write_op_decorate(var_id, DECO_FLAT);
1799 if(var.sampling=="centroid")
1800 writer.write_op_decorate(var_id, DECO_CENTROID);
1801 if(var.sampling=="patch")
1802 writer.write_op_decorate(var_id, DECO_PATCH);
1804 if(init_id && current_function)
1806 writer.write_op(content.function_body, OP_STORE, var_id, init_id);
1807 variable_load_ids[&var] = init_id;
1811 if(var.name.find(' ')==string::npos)
1812 writer.write_op_name(var_id, var.name);
1815 void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id)
1817 writer.begin_op(content.entry_points, OP_ENTRY_POINT);
1820 case Stage::VERTEX: writer.write(0); break;
1821 case Stage::TESS_CONTROL: writer.write(1); break;
1822 case Stage::TESS_EVAL: writer.write(2); break;
1823 case Stage::GEOMETRY: writer.write(3); break;
1824 case Stage::FRAGMENT: writer.write(4); break;
1825 case Stage::COMPUTE: writer.write(5); break;
1826 default: throw internal_error("unknown stage");
1828 writer.write(func_id);
1829 writer.write_string(func.name);
1831 set<Node *> dependencies = DependencyCollector().apply(func);
1832 for(Node *n: dependencies)
1833 if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(n))
1834 if(!var->interface.empty())
1835 writer.write(get_id(*n));
1837 writer.end_op(OP_ENTRY_POINT);
1839 if(stage->type==Stage::FRAGMENT)
1841 SpirVExecutionMode origin = (features.target_api==VULKAN ? EXEC_ORIGIN_UPPER_LEFT : EXEC_ORIGIN_LOWER_LEFT);
1842 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, origin);
1844 else if(stage->type==Stage::GEOMETRY)
1846 use_capability(CAP_GEOMETRY);
1847 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INVOCATIONS, 1);
1849 else if(stage->type==Stage::TESS_CONTROL || stage->type==Stage::TESS_EVAL)
1851 use_capability(CAP_TESSELLATION);
1854 unsigned local_size[3] = { 0, 1, 1 };
1856 for(const InterfaceLayout *i: interface_layouts)
1858 for(const Layout::Qualifier &q: i->layout.qualifiers)
1861 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id,
1862 (i->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS));
1863 else if(q.name=="lines")
1864 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES);
1865 else if(q.name=="lines_adjacency")
1866 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES_ADJACENCY);
1867 else if(q.name=="triangles")
1868 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_TRIANGLES);
1869 else if(q.name=="triangles_adjacency")
1870 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_TRIANGLES_ADJACENCY);
1871 else if(q.name=="quads")
1872 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_QUADS);
1873 else if(q.name=="isolines")
1874 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ISOLINES);
1875 else if(q.name=="line_strip")
1876 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_LINE_STRIP);
1877 else if(q.name=="triangle_strip")
1878 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP);
1879 else if(q.name=="max_vertices" || q.name=="vertices")
1880 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, q.value);
1881 else if(q.name=="cw")
1882 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_VERTEX_ORDER_CW);
1883 else if(q.name=="ccw")
1884 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_VERTEX_ORDER_CCW);
1885 else if(q.name=="equal_spacing")
1886 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_EQUAL);
1887 else if(q.name=="fractional_even_spacing")
1888 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_FRACTIONAL_EVEN);
1889 else if(q.name=="fractional_odd_spacing")
1890 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_SPACING_FRACTIONAL_ODD);
1891 else if(q.name=="local_size_x")
1892 local_size[0] = q.value;
1893 else if(q.name=="local_size_y")
1894 local_size[1] = q.value;
1895 else if(q.name=="local_size_z")
1896 local_size[2] = q.value;
1900 if(stage->type==Stage::COMPUTE && local_size[0])
1902 writer.begin_op(content.exec_modes, OP_EXECUTION_MODE);
1903 writer.write(func_id);
1904 writer.write(EXEC_LOCAL_SIZE);
1905 for(unsigned j=0; j<3; ++j)
1906 writer.write(local_size[j]);
1907 writer.end_op(OP_EXECUTION_MODE);
1911 void SpirVGenerator::visit(FunctionDeclaration &func)
1913 if(func.source==BUILTIN_SOURCE)
1915 else if(func.definition!=&func)
1918 allocate_forward_id(*func.definition);
1922 Id return_type_id = get_id(*func.return_type_declaration);
1923 vector<unsigned> param_type_ids;
1924 param_type_ids.reserve(func.parameters.size());
1925 for(const RefPtr<VariableDeclaration> &p: func.parameters)
1926 param_type_ids.push_back(get_variable_type_id(*p));
1928 string sig_with_return = func.return_type+func.signature;
1929 Id &type_id = function_type_ids[sig_with_return];
1932 type_id = next_id++;
1933 writer.begin_op(content.globals, OP_TYPE_FUNCTION);
1934 writer.write(type_id);
1935 writer.write(return_type_id);
1936 for(unsigned i: param_type_ids)
1938 writer.end_op(OP_TYPE_FUNCTION);
1940 writer.write_op_name(type_id, sig_with_return);
1943 Id func_id = allocate_id(func, type_id);
1944 writer.write_op_name(func_id, func.name+func.signature);
1946 if(func.name=="main")
1947 visit_entry_point(func, func_id);
1949 writer.begin_op(content.functions, OP_FUNCTION, 5);
1950 writer.write(return_type_id);
1951 writer.write(func_id);
1952 writer.write(0); // Function control flags (none)
1953 writer.write(type_id);
1954 writer.end_op(OP_FUNCTION);
1956 for(unsigned i=0; i<func.parameters.size(); ++i)
1958 Id param_id = allocate_id(*func.parameters[i], param_type_ids[i]);
1959 writer.write_op(content.functions, OP_FUNCTION_PARAMETER, param_type_ids[i], param_id);
1960 writer.write_op_name(param_id, func.parameters[i]->name);
1961 // TODO This is probably incorrect if the parameter is assigned to.
1962 variable_load_ids[func.parameters[i].get()] = param_id;
1966 writer.begin_function_body(next_id++);
1967 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
1968 func.body.visit(*this);
1970 if(writer.get_current_block())
1973 writer.write_op(content.function_body, OP_UNREACHABLE);
1976 const BasicTypeDeclaration *basic_return = dynamic_cast<const BasicTypeDeclaration *>(func.return_type_declaration);
1977 if(basic_return && basic_return->kind==BasicTypeDeclaration::VOID)
1978 writer.write_op(content.function_body, OP_RETURN);
1980 throw internal_error("missing return in non-void function");
1983 writer.end_function_body();
1984 variable_load_ids.clear();
1987 void SpirVGenerator::visit(Conditional &cond)
1989 cond.condition->visit(*this);
1991 Id true_label_id = next_id++;
1992 Id merge_block_id = next_id++;
1993 Id false_label_id = (cond.else_body.body.empty() ? merge_block_id : next_id++);
1994 writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none)
1995 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id);
1997 std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
1999 writer.write_op_label(true_label_id);
2000 cond.body.visit(*this);
2001 if(writer.get_current_block())
2002 writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
2004 bool reachable_if_true = reachable;
2007 if(!cond.else_body.body.empty())
2009 swap(saved_load_ids, variable_load_ids);
2010 writer.write_op_label(false_label_id);
2011 cond.else_body.visit(*this);
2012 reachable |= reachable_if_true;
2015 writer.write_op_label(merge_block_id);
2016 prune_loads(true_label_id);
2019 void SpirVGenerator::visit(Iteration &iter)
2021 if(iter.init_statement)
2022 iter.init_statement->visit(*this);
2024 for(Node *n: AssignmentCollector().apply(iter))
2025 if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(n))
2026 variable_load_ids.erase(var);
2028 Id header_id = next_id++;
2029 Id continue_id = next_id++;
2030 Id merge_block_id = next_id++;
2032 SetForScope<Id> set_merge(loop_merge_block_id, merge_block_id);
2033 SetForScope<Id> set_continue(loop_continue_target_id, continue_id);
2035 writer.write_op_label(header_id);
2036 writer.write_op(content.function_body, OP_LOOP_MERGE, merge_block_id, continue_id, 0); // Loop control (none)
2038 Id body_id = next_id++;
2041 writer.write_op_label(next_id++);
2042 iter.condition->visit(*this);
2043 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, body_id, merge_block_id);
2046 writer.write_op_label(body_id);
2047 iter.body.visit(*this);
2049 writer.write_op_label(continue_id);
2050 if(iter.loop_expression)
2051 iter.loop_expression->visit(*this);
2052 writer.write_op(content.function_body, OP_BRANCH, header_id);
2054 writer.write_op_label(merge_block_id);
2055 prune_loads(header_id);
2059 void SpirVGenerator::visit(Return &ret)
2063 ret.expression->visit(*this);
2064 writer.write_op(content.function_body, OP_RETURN_VALUE, r_expression_result_id);
2067 writer.write_op(content.function_body, OP_RETURN);
2071 void SpirVGenerator::visit(Jump &jump)
2073 if(jump.keyword=="discard")
2074 writer.write_op(content.function_body, OP_KILL);
2075 else if(jump.keyword=="break")
2076 writer.write_op(content.function_body, OP_BRANCH, loop_merge_block_id);
2077 else if(jump.keyword=="continue")
2078 writer.write_op(content.function_body, OP_BRANCH, loop_continue_target_id);
2080 throw internal_error("unknown jump");
2085 SpirVGenerator::TypeKey::TypeKey(BasicTypeDeclaration::Kind kind, bool sign):
2090 case BasicTypeDeclaration::VOID: detail = 'v'; break;
2091 case BasicTypeDeclaration::BOOL: detail = 'b'; break;
2092 case BasicTypeDeclaration::INT: detail = (sign ? 'i' : 'u'); break;
2093 case BasicTypeDeclaration::FLOAT: detail = 'f'; break;
2094 default: throw invalid_argument("TypeKey::TypeKey");
2098 bool SpirVGenerator::TypeKey::operator<(const TypeKey &other) const
2100 if(type_id!=other.type_id)
2101 return type_id<other.type_id;
2102 return detail<other.detail;
2106 bool SpirVGenerator::ConstantKey::operator<(const ConstantKey &other) const
2108 if(type_id!=other.type_id)
2109 return type_id<other.type_id;
2110 return int_value<other.int_value;