1 #include <msp/core/maputils.h>
2 #include <msp/core/raii.h>
12 const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] =
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 { "max", "ff", "GLSL.std.450", GLSL450_F_MAX, { 1, 2 }, 0 },
50 { "max", "ii", "GLSL.std.450", GLSL450_S_MAX, { 1, 2 }, 0 },
51 { "clamp", "fff", "GLSL.std.450", GLSL450_F_CLAMP, { 1, 2, 3 }, 0 },
52 { "clamp", "iii", "GLSL.std.450", GLSL450_S_CLAMP, { 1, 2, 3 }, 0 },
53 { "mix", "fff", "GLSL.std.450", GLSL450_F_MIX, { 1, 2, 3 }, 0 },
54 { "mix", "ffb", "", OP_SELECT, { 3, 2, 1 }, 0 },
55 { "mix", "iib", "", OP_SELECT, { 3, 2, 1 }, 0 },
56 { "step", "ff", "GLSL.std.450", GLSL450_F_STEP, { 1, 2 }, 0 },
57 { "smoothstep", "fff", "GLSL.std.450", GLSL450_F_SMOOTH_STEP, { 1, 2, 3 }, 0 },
58 { "isnan", "f", "", OP_IS_NAN, { 1 }, 0 },
59 { "isinf", "f", "", OP_IS_INF, { 1 }, 0 },
60 { "fma", "fff", "GLSL.std.450", GLSL450_F_FMA, { 1, 2, 3 }, 0 },
61 { "length", "f", "GLSL.std.450", GLSL450_LENGTH, { 1 }, 0 },
62 { "distance", "ff", "GLSL.std.450", GLSL450_DISTANCE, { 1, 2 }, 0 },
63 { "dot", "ff", "", OP_DOT, { 1, 2 }, 0 },
64 { "cross", "ff", "GLSL.std.450", GLSL450_CROSS, { 1, 2 }, 0 },
65 { "normalize", "f", "GLSL.std.450", GLSL450_NORMALIZE, { 1 }, 0 },
66 { "faceforward", "fff", "GLSL.std.450", GLSL450_FACE_FORWARD, { 1, 2, 3 }, 0 },
67 { "reflect", "ff", "GLSL.std.450", GLSL450_REFLECT, { 1, 2 }, 0 },
68 { "refract", "fff", "GLSL.std.450", GLSL450_REFRACT, { 1, 2, 3 }, 0 },
69 { "matrixCompMult", "ff", "", 0, { 0 }, &SpirVGenerator::visit_builtin_matrix_comp_mult },
70 { "outerProduct", "ff", "", OP_OUTER_PRODUCT, { 1, 2 }, 0 },
71 { "transpose", "f", "", OP_TRANSPOSE, { 1 }, 0 },
72 { "determinant", "f", "GLSL.std.450", GLSL450_DETERMINANT, { 1 }, 0 },
73 { "inverse", "f", "GLSL.std.450", GLSL450_MATRIX_INVERSE, { 1 }, 0 },
74 { "lessThan", "ff", "", OP_F_ORD_LESS_THAN, { 1, 2 }, 0 },
75 { "lessThan", "ii", "", OP_S_LESS_THAN, { 1, 2 }, 0 },
76 { "lessThanEqual", "ff", "", OP_F_ORD_LESS_THAN_EQUAL, { 1, 2 }, 0 },
77 { "lessThanEqual", "ii", "", OP_S_LESS_THAN_EQUAL, { 1, 2 }, 0 },
78 { "greaterThan", "ff", "", OP_F_ORD_GREATER_THAN, { 1, 2 }, 0 },
79 { "greaterThan", "ii", "", OP_S_GREATER_THAN, { 1, 2 }, 0 },
80 { "greaterThanEqual", "ff", "", OP_F_ORD_GREATER_THAN_EQUAL, { 1, 2 }, 0 },
81 { "greaterThanEqual", "ii", "", OP_S_GREATER_THAN_EQUAL, { 1, 2 }, 0 },
82 { "equal", "ff", "", OP_F_ORD_EQUAL, { 1, 2 }, 0 },
83 { "equal", "ii", "", OP_I_EQUAL, { 1, 2 }, 0 },
84 { "notEqual", "ff", "", OP_F_ORD_NOT_EQUAL, { 1, 2 }, 0 },
85 { "notEqual", "ii", "", OP_I_NOT_EQUAL, { 1, 2 }, 0 },
86 { "any", "b", "", OP_ANY, { 1 }, 0 },
87 { "all", "b", "", OP_ALL, { 1 }, 0 },
88 { "not", "b", "", OP_LOGICAL_NOT, { 1 }, 0 },
89 { "bitfieldExtract", "iii", "", OP_BIT_FIELD_S_EXTRACT, { 1, 2, 3 }, 0 },
90 { "bitfieldInsert", "iiii", "", OP_BIT_FIELD_INSERT, { 1, 2, 3, 4 }, 0 },
91 { "bitfieldReverse", "i", "", OP_BIT_REVERSE, { 1 }, 0 },
92 { "bitCount", "i", "", OP_BIT_COUNT, { 1 }, 0 },
93 { "findLSB", "i", "GLSL.std.450", GLSL450_FIND_I_LSB, { 1 }, 0 },
94 { "findMSB", "i", "GLSL.std.450", GLSL450_FIND_S_MSB, { 1 }, 0 },
95 { "textureSize", "", "", OP_IMAGE_QUERY_SIZE_LOD, { 1, 2 }, 0 },
96 { "texture", "", "", 0, { }, &SpirVGenerator::visit_builtin_texture },
97 { "textureLod", "", "", 0, { }, &SpirVGenerator::visit_builtin_texture },
98 { "texelFetch", "", "", 0, { }, &SpirVGenerator::visit_builtin_texel_fetch },
99 { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0 },
100 { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0 },
101 { "dFdx", "f", "", OP_DP_DX, { 1 }, 0 },
102 { "dFdy", "f", "", OP_DP_DY, { 1 }, 0 },
103 { "dFdxFine", "f", "", OP_DP_DX_FINE, { 1 }, 0 },
104 { "dFdyFine", "f", "", OP_DP_DY_FINE, { 1 }, 0 },
105 { "dFdxCoarse", "f", "", OP_DP_DX_COARSE, { 1 }, 0 },
106 { "dFdyCoarse", "f", "", OP_DP_DY_COARSE, { 1 }, 0 },
107 { "fwidth", "f", "", OP_FWIDTH, { 1 }, 0 },
108 { "fwidthFine", "f", "", OP_FWIDTH_FINE, { 1 }, 0 },
109 { "fwidthCoarse", "f", "", OP_FWIDTH_COARSE, { 1 }, 0 },
110 { "interpolateAtCentroid", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate },
111 { "interpolateAtSample", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate },
112 { "interpolateAtOffset", "", "", 0, { }, &SpirVGenerator::visit_builtin_interpolate },
113 { "", "", "", 0, { }, 0 }
116 SpirVGenerator::SpirVGenerator():
121 r_expression_result_id(0),
122 constant_expression(false),
123 spec_constant(false),
125 composite_access(false),
126 r_composite_base_id(0),
128 assignment_source_id(0),
129 loop_merge_block_id(0),
130 loop_continue_target_id(0)
133 void SpirVGenerator::apply(Module &module)
135 use_capability(CAP_SHADER);
137 for(list<Stage>::iterator i=module.stages.begin(); i!=module.stages.end(); ++i)
140 interface_layouts.clear();
141 i->content.visit(*this);
144 writer.finalize(next_id);
147 SpirVGenerator::StorageClass SpirVGenerator::get_interface_storage(const string &iface, bool block)
150 return STORAGE_INPUT;
151 else if(iface=="out")
152 return STORAGE_OUTPUT;
153 else if(iface=="uniform")
154 return (block ? STORAGE_UNIFORM : STORAGE_UNIFORM_CONSTANT);
155 else if(iface.empty())
156 return STORAGE_PRIVATE;
158 throw invalid_argument("SpirVGenerator::get_interface_storage");
161 SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const string &name)
163 if(name=="gl_Position")
164 return BUILTIN_POSITION;
165 else if(name=="gl_PointSize")
166 return BUILTIN_POINT_SIZE;
167 else if(name=="gl_ClipDistance")
168 return BUILTIN_CLIP_DISTANCE;
169 else if(name=="gl_VertexID")
170 return BUILTIN_VERTEX_ID;
171 else if(name=="gl_InstanceID")
172 return BUILTIN_INSTANCE_ID;
173 else if(name=="gl_PrimitiveID" || name=="gl_PrimitiveIDIn")
174 return BUILTIN_PRIMITIVE_ID;
175 else if(name=="gl_InvocationID")
176 return BUILTIN_INVOCATION_ID;
177 else if(name=="gl_Layer")
178 return BUILTIN_LAYER;
179 else if(name=="gl_FragCoord")
180 return BUILTIN_FRAG_COORD;
181 else if(name=="gl_PointCoord")
182 return BUILTIN_POINT_COORD;
183 else if(name=="gl_FrontFacing")
184 return BUILTIN_FRONT_FACING;
185 else if(name=="gl_SampleId")
186 return BUILTIN_SAMPLE_ID;
187 else if(name=="gl_SamplePosition")
188 return BUILTIN_SAMPLE_POSITION;
189 else if(name=="gl_FragDepth")
190 return BUILTIN_FRAG_DEPTH;
192 throw invalid_argument("SpirVGenerator::get_builtin_semantic");
195 void SpirVGenerator::use_capability(Capability cap)
197 if(used_capabilities.count(cap))
200 used_capabilities.insert(cap);
201 writer.write_op(content.capabilities, OP_CAPABILITY, cap);
204 SpirVGenerator::Id SpirVGenerator::import_extension(const string &name)
206 Id &ext_id = imported_extension_ids[name];
210 writer.begin_op(content.extensions, OP_EXT_INST_IMPORT);
211 writer.write(ext_id);
212 writer.write_string(name);
213 writer.end_op(OP_EXT_INST_IMPORT);
218 SpirVGenerator::Id SpirVGenerator::get_id(Node &node) const
220 return get_item(declared_ids, &node).id;
223 SpirVGenerator::Id SpirVGenerator::allocate_id(Node &node, Id type_id)
226 insert_unique(declared_ids, &node, Declaration(id, type_id));
230 SpirVGenerator::Id SpirVGenerator::write_constant(Id type_id, Word value, bool spec)
232 Id const_id = next_id++;
233 if(is_scalar_type(type_id, BasicTypeDeclaration::BOOL))
235 Opcode opcode = (value ? (spec ? OP_SPEC_CONSTANT_TRUE : OP_CONSTANT_TRUE) :
236 (spec ? OP_SPEC_CONSTANT_FALSE : OP_CONSTANT_FALSE));
237 writer.write_op(content.globals, opcode, type_id, const_id);
241 Opcode opcode = (spec ? OP_SPEC_CONSTANT : OP_CONSTANT);
242 writer.write_op(content.globals, opcode, type_id, const_id, value);
247 SpirVGenerator::ConstantKey SpirVGenerator::get_constant_key(Id type_id, const Variant &value)
249 if(value.check_type<bool>())
250 return ConstantKey(type_id, value.value<bool>());
251 else if(value.check_type<int>())
252 return ConstantKey(type_id, value.value<int>());
253 else if(value.check_type<float>())
254 return ConstantKey(type_id, value.value<float>());
256 throw invalid_argument("SpirVGenerator::get_constant_key");
259 SpirVGenerator::Id SpirVGenerator::get_constant_id(Id type_id, const Variant &value)
261 ConstantKey key = get_constant_key(type_id, value);
262 Id &const_id = constant_ids[key];
264 const_id = write_constant(type_id, key.int_value, false);
268 SpirVGenerator::Id SpirVGenerator::get_vector_constant_id(Id type_id, unsigned size, Id scalar_id)
270 Id &const_id = constant_ids[get_constant_key(type_id, static_cast<int>(scalar_id))];
273 const_id = next_id++;
274 writer.begin_op(content.globals, OP_CONSTANT_COMPOSITE, 3+size);
275 writer.write(type_id);
276 writer.write(const_id);
277 for(unsigned i=0; i<size; ++i)
278 writer.write(scalar_id);
279 writer.end_op(OP_CONSTANT_COMPOSITE);
284 SpirVGenerator::Id SpirVGenerator::get_standard_type_id(BasicTypeDeclaration::Kind kind, unsigned size)
286 Id base_id = (size>1 ? get_standard_type_id(kind, 1) : 0);
287 Id &type_id = standard_type_ids[TypeKey(base_id, (size>1 ? size : static_cast<unsigned>(kind)))];
292 writer.write_op(content.globals, OP_TYPE_VECTOR, type_id, base_id, size);
293 else if(kind==BasicTypeDeclaration::VOID)
294 writer.write_op(content.globals, OP_TYPE_VOID, type_id);
295 else if(kind==BasicTypeDeclaration::BOOL)
296 writer.write_op(content.globals, OP_TYPE_BOOL, type_id);
297 else if(kind==BasicTypeDeclaration::INT)
298 writer.write_op(content.globals, OP_TYPE_INT, type_id, 32, 1);
299 else if(kind==BasicTypeDeclaration::FLOAT)
300 writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, 32);
302 throw invalid_argument("SpirVGenerator::get_standard_type_id");
307 bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind) const
309 map<TypeKey, Id>::const_iterator i = standard_type_ids.find(TypeKey(0, kind));
310 return (i!=standard_type_ids.end() && i->second==type_id);
313 SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id)
315 Id base_type_id = get_id(base_type);
316 Id &array_type_id = array_type_ids[TypeKey(base_type_id, size_id)];
319 array_type_id = next_id++;
321 writer.write_op(content.globals, OP_TYPE_ARRAY, array_type_id, base_type_id, size_id);
323 writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id);
325 unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride;
326 writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride);
329 return array_type_id;
332 SpirVGenerator::Id SpirVGenerator::get_pointer_type_id(Id type_id, StorageClass storage)
334 Id &ptr_type_id = pointer_type_ids[TypeKey(type_id, storage)];
337 ptr_type_id = next_id++;
338 writer.write_op(content.globals, OP_TYPE_POINTER, ptr_type_id, storage, type_id);
343 SpirVGenerator::Id SpirVGenerator::get_variable_type_id(const VariableDeclaration &var)
345 if(const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var.type_declaration))
346 if(basic->kind==BasicTypeDeclaration::ARRAY)
351 SetFlag set_const(constant_expression);
352 r_expression_result_id = 0;
353 var.array_size->visit(*this);
354 size_id = r_expression_result_id;
357 size_id = get_constant_id(get_standard_type_id(BasicTypeDeclaration::INT, 1), 1);
358 return get_array_type_id(*basic->base_type, size_id);
361 return get_id(*var.type_declaration);
364 SpirVGenerator::Id SpirVGenerator::get_load_id(VariableDeclaration &var)
366 Id &load_result_id = variable_load_ids[&var];
369 load_result_id = next_id++;
370 writer.write_op(content.function_body, OP_LOAD, get_variable_type_id(var), load_result_id, get_id(var));
372 return load_result_id;
375 void SpirVGenerator::prune_loads(Id min_id)
377 for(map<const VariableDeclaration *, Id>::iterator i=variable_load_ids.begin(); i!=variable_load_ids.end(); )
379 if(i->second>=min_id)
380 variable_load_ids.erase(i++);
386 SpirVGenerator::Id SpirVGenerator::begin_expression(Opcode opcode, Id type_id, unsigned n_args)
388 bool has_result = (opcode==OP_FUNCTION_CALL || !is_scalar_type(type_id, BasicTypeDeclaration::VOID));
389 if(!constant_expression)
391 if(!current_function)
392 throw internal_error("non-constant expression outside a function");
394 writer.begin_op(content.function_body, opcode, (n_args ? 1+has_result*2+n_args : 0));
396 else if(opcode==OP_COMPOSITE_CONSTRUCT)
397 writer.begin_op(content.function_body, OP_SPEC_CONSTANT_COMPOSITE, (n_args ? 1+has_result*2+n_args : 0));
399 writer.begin_op(content.function_body, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
401 Id result_id = next_id++;
404 writer.write(type_id);
405 writer.write(result_id);
407 if(constant_expression && opcode!=OP_COMPOSITE_CONSTRUCT)
408 writer.write(opcode);
413 void SpirVGenerator::end_expression(Opcode opcode)
415 if(constant_expression)
416 opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? OP_SPEC_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP);
417 writer.end_op(opcode);
420 SpirVGenerator::Id SpirVGenerator::write_expression(Opcode opcode, Id type_id, Id arg_id)
422 Id result_id = begin_expression(opcode, type_id, 1);
423 writer.write(arg_id);
424 end_expression(opcode);
428 SpirVGenerator::Id SpirVGenerator::write_expression(Opcode opcode, Id type_id, Id left_id, Id right_id)
430 Id result_id = begin_expression(opcode, type_id, 2);
431 writer.write(left_id);
432 writer.write(right_id);
433 end_expression(opcode);
437 void SpirVGenerator::write_deconstruct(Id elem_type_id, Id composite_id, Id *elem_ids, unsigned n_elems)
439 for(unsigned i=0; i<n_elems; ++i)
441 elem_ids[i] = begin_expression(OP_COMPOSITE_EXTRACT, elem_type_id, 2);
442 writer.write(composite_id);
444 end_expression(OP_COMPOSITE_EXTRACT);
448 SpirVGenerator::Id SpirVGenerator::write_construct(Id type_id, const Id *elem_ids, unsigned n_elems)
450 Id result_id = begin_expression(OP_COMPOSITE_CONSTRUCT, type_id, n_elems);
451 for(unsigned i=0; i<n_elems; ++i)
452 writer.write(elem_ids[i]);
453 end_expression(OP_COMPOSITE_CONSTRUCT);
458 BasicTypeDeclaration &SpirVGenerator::get_element_type(BasicTypeDeclaration &basic)
460 if(basic.kind==BasicTypeDeclaration::BOOL || basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
462 else if((basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX) && basic.base_type)
463 return get_element_type(dynamic_cast<BasicTypeDeclaration &>(*basic.base_type));
465 throw invalid_argument("SpirVGenerator::get_element_type");
468 void SpirVGenerator::visit(Block &block)
470 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
474 void SpirVGenerator::visit(Literal &literal)
476 Id type_id = get_id(*literal.type);
478 r_expression_result_id = write_constant(type_id, get_constant_key(type_id, literal.value).int_value, true);
480 r_expression_result_id = get_constant_id(type_id, literal.value);
483 void SpirVGenerator::visit(VariableReference &var)
485 if(constant_expression || var.declaration->constant)
487 if(!var.declaration->constant)
488 throw internal_error("reference to non-constant variable in constant context");
490 r_expression_result_id = get_id(*var.declaration);
493 else if(!current_function)
494 throw internal_error("non-constant context outside a function");
498 r_composite_base = var.declaration;
499 r_expression_result_id = 0;
501 else if(assignment_source_id)
503 writer.write_op(content.function_body, OP_STORE, get_id(*var.declaration), assignment_source_id);
504 variable_load_ids[var.declaration] = assignment_source_id;
505 r_expression_result_id = assignment_source_id;
508 r_expression_result_id = get_load_id(*var.declaration);
511 void SpirVGenerator::visit(InterfaceBlockReference &iface)
513 if(!composite_access || !current_function)
514 throw internal_error("invalid interface block reference");
516 r_composite_base = iface.declaration;
517 r_expression_result_id = 0;
520 void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type)
523 Id result_type_id = get_id(result_type);
524 Id access_type_id = result_type_id;
527 if(constant_expression)
528 throw internal_error("composite access through pointer in constant context");
530 Id int32_type_id = get_standard_type_id(BasicTypeDeclaration::INT, 1);
531 for(vector<unsigned>::iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i)
532 *i = (*i<0x400000 ? get_constant_id(int32_type_id, static_cast<int>(*i)) : *i&0x3FFFFF);
534 /* Find the storage class of the base and obtain appropriate pointer type
536 const Declaration &base_decl = get_item(declared_ids, r_composite_base);
537 map<TypeKey, Id>::const_iterator i = pointer_type_ids.begin();
538 for(; (i!=pointer_type_ids.end() && i->second!=base_decl.type_id); ++i) ;
539 if(i==pointer_type_ids.end())
540 throw internal_error("could not find storage class");
541 access_type_id = get_pointer_type_id(result_type_id, static_cast<StorageClass>(i->first.detail));
543 opcode = OP_ACCESS_CHAIN;
545 else if(assignment_source_id)
546 throw internal_error("assignment to temporary composite");
549 for(vector<unsigned>::iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i)
550 for(map<ConstantKey, Id>::iterator j=constant_ids.begin(); (*i>=0x400000 && j!=constant_ids.end()); ++j)
551 if(j->second==(*i&0x3FFFFF))
552 *i = j->first.int_value;
554 opcode = OP_COMPOSITE_EXTRACT;
557 Id access_id = begin_expression(opcode, access_type_id, 1+r_composite_chain.size());
558 writer.write(r_composite_base_id);
559 for(vector<unsigned>::const_iterator i=r_composite_chain.begin(); i!=r_composite_chain.end(); ++i)
561 end_expression(opcode);
565 if(assignment_source_id)
567 writer.write_op(content.function_body, OP_STORE, access_id, assignment_source_id);
568 r_expression_result_id = assignment_source_id;
571 r_expression_result_id = write_expression(OP_LOAD, result_type_id, access_id);
574 r_expression_result_id = access_id;
577 void SpirVGenerator::visit_composite(Expression &base_expr, unsigned index, TypeDeclaration &type)
579 if(!composite_access)
581 r_composite_base = 0;
582 r_composite_base_id = 0;
583 r_composite_chain.clear();
587 SetFlag set_composite(composite_access);
588 base_expr.visit(*this);
591 if(!r_composite_base_id)
592 r_composite_base_id = (r_composite_base ? get_id(*r_composite_base) : r_expression_result_id);
594 r_composite_chain.push_back(index);
595 if(!composite_access)
596 generate_composite_access(type);
598 r_expression_result_id = 0;
601 void SpirVGenerator::visit_isolated(Expression &expr)
603 SetForScope<Id> clear_assign(assignment_source_id, 0);
604 SetFlag clear_composite(composite_access, false);
605 SetForScope<Node *> clear_base(r_composite_base, 0);
606 SetForScope<Id> clear_base_id(r_composite_base_id, 0);
607 vector<unsigned> saved_chain;
608 swap(saved_chain, r_composite_chain);
610 swap(saved_chain, r_composite_chain);
613 void SpirVGenerator::visit(MemberAccess &memacc)
615 visit_composite(*memacc.left, memacc.index, *memacc.type);
618 void SpirVGenerator::visit(Swizzle &swizzle)
621 visit_composite(*swizzle.left, swizzle.components[0], *swizzle.type);
622 else if(assignment_source_id)
624 const BasicTypeDeclaration &basic = dynamic_cast<const BasicTypeDeclaration &>(*swizzle.left->type);
627 for(unsigned i=0; i<swizzle.count; ++i)
628 mask |= 1<<swizzle.components[i];
630 visit_isolated(*swizzle.left);
632 Id combined_id = begin_expression(OP_VECTOR_SHUFFLE, get_id(*swizzle.left->type), 2+basic.size);
633 writer.write(r_expression_result_id);
634 writer.write(assignment_source_id);
635 for(unsigned i=0; i<basic.size; ++i)
636 writer.write(i+((mask>>i)&1)*basic.size);
637 end_expression(OP_VECTOR_SHUFFLE);
639 SetForScope<Id> set_assign(assignment_source_id, combined_id);
640 swizzle.left->visit(*this);
642 r_expression_result_id = combined_id;
646 swizzle.left->visit(*this);
647 Id left_id = r_expression_result_id;
649 r_expression_result_id = begin_expression(OP_VECTOR_SHUFFLE, get_id(*swizzle.type), 2+swizzle.count);
650 writer.write(left_id);
651 writer.write(left_id);
652 for(unsigned i=0; i<swizzle.count; ++i)
653 writer.write(swizzle.components[i]);
654 end_expression(OP_VECTOR_SHUFFLE);
658 void SpirVGenerator::visit(UnaryExpression &unary)
660 unary.expression->visit(*this);
662 char oper = unary.oper->token[0];
663 char oper2 = unary.oper->token[1];
664 if(oper=='+' && !oper2)
667 BasicTypeDeclaration &basic = dynamic_cast<BasicTypeDeclaration &>(*unary.expression->type);
668 BasicTypeDeclaration &elem = get_element_type(basic);
670 if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
671 /* SPIR-V allows constant operations on floating-point values only for
673 throw internal_error("invalid operands for constant unary expression");
675 Id result_type_id = get_id(*unary.type);
676 Opcode opcode = OP_NOP;
679 opcode = OP_LOGICAL_NOT;
682 else if(oper=='-' && !oper2)
684 opcode = (elem.kind==BasicTypeDeclaration::INT ? OP_S_NEGATE : OP_F_NEGATE);
686 if(basic.kind==BasicTypeDeclaration::MATRIX)
688 Id column_type_id = get_id(*basic.base_type);
689 unsigned n_columns = basic.size&0xFFFF;
691 write_deconstruct(column_type_id, r_expression_result_id, column_ids, n_columns);
692 for(unsigned i=0; i<n_columns; ++i)
693 column_ids[i] = write_expression(opcode, column_type_id, column_ids[i]);
694 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
698 else if((oper=='+' || oper=='-') && oper2==oper)
700 if(constant_expression)
701 throw internal_error("increment or decrement in constant expression");
704 if(elem.kind==BasicTypeDeclaration::INT)
706 opcode = (oper=='+' ? OP_I_ADD : OP_I_SUB);
707 one_id = get_constant_id(get_id(elem), 1);
709 else if(elem.kind==BasicTypeDeclaration::FLOAT)
711 opcode = (oper=='+' ? OP_F_ADD : OP_F_SUB);
712 one_id = get_constant_id(get_id(elem), 1.0f);
715 throw internal_error("invalid increment/decrement");
717 if(basic.kind==BasicTypeDeclaration::VECTOR)
718 one_id = get_vector_constant_id(result_type_id, basic.size, one_id);
720 Id post_value_id = write_expression(opcode, result_type_id, r_expression_result_id, one_id);
722 SetForScope<Id> set_assign(assignment_source_id, post_value_id);
723 unary.expression->visit(*this);
725 r_expression_result_id = (unary.oper->type==Operator::POSTFIX ? r_expression_result_id : post_value_id);
730 throw internal_error("unknown unary operator");
732 r_expression_result_id = write_expression(opcode, result_type_id, r_expression_result_id);
735 void SpirVGenerator::visit(BinaryExpression &binary)
737 char oper = binary.oper->token[0];
740 visit_isolated(*binary.right);
741 return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type);
744 if(assignment_source_id)
745 throw internal_error("invalid binary expression in assignment target");
747 BasicTypeDeclaration &basic_left = dynamic_cast<BasicTypeDeclaration &>(*binary.left->type);
748 BasicTypeDeclaration &basic_right = dynamic_cast<BasicTypeDeclaration &>(*binary.right->type);
749 // Expression resolver ensures that element types are the same
750 BasicTypeDeclaration &elem = get_element_type(basic_left);
752 if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT)
753 /* SPIR-V allows constant operations on floating-point values only for
755 throw internal_error("invalid operands for constant binary expression");
757 binary.left->visit(*this);
758 Id left_id = r_expression_result_id;
759 binary.right->visit(*this);
760 Id right_id = r_expression_result_id;
762 Id result_type_id = get_id(*binary.type);
763 Opcode opcode = OP_NOP;
764 bool swap_operands = false;
766 char oper2 = binary.oper->token[1];
767 if((oper=='<' || oper=='>') && oper2!=oper)
769 if(basic_left.kind==BasicTypeDeclaration::INT)
770 opcode = (oper=='<' ? (oper2=='=' ? OP_S_LESS_THAN_EQUAL : OP_S_LESS_THAN) :
771 (oper2=='=' ? OP_S_GREATER_THAN_EQUAL : OP_S_GREATER_THAN));
772 else if(basic_left.kind==BasicTypeDeclaration::FLOAT)
773 opcode = (oper=='<' ? (oper2=='=' ? OP_F_ORD_LESS_THAN_EQUAL : OP_F_ORD_LESS_THAN) :
774 (oper2=='=' ? OP_F_ORD_GREATER_THAN_EQUAL : OP_F_ORD_GREATER_THAN));
776 else if((oper=='=' || oper=='!') && oper2=='=')
778 if(elem.kind==BasicTypeDeclaration::BOOL)
779 opcode = (oper=='=' ? OP_LOGICAL_EQUAL : OP_LOGICAL_NOT_EQUAL);
780 else if(elem.kind==BasicTypeDeclaration::INT)
781 opcode = (oper=='=' ? OP_I_EQUAL : OP_I_NOT_EQUAL);
782 else if(elem.kind==BasicTypeDeclaration::FLOAT)
783 opcode = (oper=='=' ? OP_F_ORD_EQUAL : OP_F_ORD_NOT_EQUAL);
785 if(opcode!=OP_NOP && basic_left.base_type)
787 /* The SPIR-V equality operations produce component-wise results, but
788 GLSL operators return a single boolean. Use the any/all operations to
789 combine the results. */
790 Opcode combine_op = (oper=='!' ? OP_ANY : OP_ALL);
791 unsigned n_elems = basic_left.size&0xFFFF;
792 Id bool_vec_type_id = get_standard_type_id(BasicTypeDeclaration::BOOL, n_elems);
795 if(basic_left.kind==BasicTypeDeclaration::VECTOR)
796 compare_id = write_expression(opcode, bool_vec_type_id, left_id, right_id);
797 else if(basic_left.kind==BasicTypeDeclaration::MATRIX)
799 Id column_type_id = get_id(*basic_left.base_type);
801 write_deconstruct(column_type_id, left_id, column_ids, n_elems);
802 write_deconstruct(column_type_id, right_id, column_ids+4, n_elems);
804 Id column_bvec_type_id = get_standard_type_id(BasicTypeDeclaration::BOOL, basic_left.size>>16);
805 for(unsigned i=0; i<n_elems; ++i)
807 compare_id = write_expression(opcode, column_bvec_type_id, column_ids[i], column_ids[4+i]);
808 column_ids[i] = write_expression(combine_op, result_type_id, compare_id);;
811 compare_id = write_construct(bool_vec_type_id, column_ids, n_elems);
815 r_expression_result_id = write_expression(combine_op, result_type_id, compare_id);
819 else if(oper2=='&' && elem.kind==BasicTypeDeclaration::BOOL)
820 opcode = OP_LOGICAL_AND;
821 else if(oper2=='|' && elem.kind==BasicTypeDeclaration::BOOL)
822 opcode = OP_LOGICAL_OR;
823 else if(oper2=='^' && elem.kind==BasicTypeDeclaration::BOOL)
824 opcode = OP_LOGICAL_NOT_EQUAL;
825 else if(oper=='&' && elem.kind==BasicTypeDeclaration::INT)
826 opcode = OP_BITWISE_AND;
827 else if(oper=='|' && elem.kind==BasicTypeDeclaration::INT)
828 opcode = OP_BITWISE_OR;
829 else if(oper=='^' && elem.kind==BasicTypeDeclaration::INT)
830 opcode = OP_BITWISE_XOR;
831 else if(oper=='<' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
832 opcode = OP_SHIFT_LEFT_LOGICAL;
833 else if(oper=='>' && oper2==oper && elem.kind==BasicTypeDeclaration::INT)
834 opcode = OP_SHIFT_RIGHT_ARITHMETIC;
835 else if(oper=='%' && elem.kind==BasicTypeDeclaration::INT)
837 else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
839 Opcode elem_op = OP_NOP;
840 if(elem.kind==BasicTypeDeclaration::INT)
841 elem_op = (oper=='+' ? OP_I_ADD : oper=='-' ? OP_I_SUB : oper=='*' ? OP_I_MUL : OP_S_DIV);
842 else if(elem.kind==BasicTypeDeclaration::FLOAT)
843 elem_op = (oper=='+' ? OP_F_ADD : oper=='-' ? OP_F_SUB : oper=='*' ? OP_F_MUL : OP_F_DIV);
845 if(oper=='*' && (basic_left.base_type || basic_right.base_type) && elem.kind==BasicTypeDeclaration::FLOAT)
847 /* Multiplication between floating-point vectors and matrices has
848 dedicated operations. */
849 if(basic_left.kind==BasicTypeDeclaration::MATRIX && basic_right.kind==BasicTypeDeclaration::MATRIX)
850 opcode = OP_MATRIX_TIMES_MATRIX;
851 else if(basic_left.kind==BasicTypeDeclaration::MATRIX || basic_right.kind==BasicTypeDeclaration::MATRIX)
853 if(basic_left.kind==BasicTypeDeclaration::VECTOR)
854 opcode = OP_VECTOR_TIMES_MATRIX;
855 else if(basic_right.kind==BasicTypeDeclaration::VECTOR)
856 opcode = OP_MATRIX_TIMES_VECTOR;
859 opcode = OP_MATRIX_TIMES_SCALAR;
860 swap_operands = (basic_right.kind==BasicTypeDeclaration::MATRIX);
863 else if(basic_left.kind==BasicTypeDeclaration::VECTOR && basic_right.kind==BasicTypeDeclaration::VECTOR)
867 opcode = OP_VECTOR_TIMES_SCALAR;
868 swap_operands = (basic_right.kind==BasicTypeDeclaration::VECTOR);
871 else if((basic_left.base_type!=0)!=(basic_right.base_type!=0))
873 /* One operand is scalar and the other is a vector or a matrix.
874 Expand the scalar to a vector of appropriate size. */
875 Id &scalar_id = (basic_left.base_type ? right_id : left_id);
876 BasicTypeDeclaration *vector_type = (basic_left.base_type ? &basic_left : &basic_right);
877 if(vector_type->kind==BasicTypeDeclaration::MATRIX)
878 vector_type = dynamic_cast<BasicTypeDeclaration *>(vector_type->base_type);
879 Id vector_type_id = get_id(*vector_type);
881 Id expanded_id = begin_expression(OP_COMPOSITE_CONSTRUCT, vector_type_id, vector_type->size);
882 for(unsigned i=0; i<vector_type->size; ++i)
883 writer.write(scalar_id);
884 end_expression(OP_COMPOSITE_CONSTRUCT);
886 scalar_id = expanded_id;
888 if(basic_left.kind==BasicTypeDeclaration::MATRIX || basic_right.kind==BasicTypeDeclaration::MATRIX)
890 // Apply matrix operation column-wise.
891 Id matrix_id = (basic_left.base_type ? left_id : right_id);
894 unsigned n_columns = (basic_left.base_type ? basic_left.size : basic_right.size)&0xFFFF;
895 write_deconstruct(vector_type_id, matrix_id, column_ids, n_columns);
897 for(unsigned i=0; i<n_columns; ++i)
898 column_ids[i] = write_expression(elem_op, vector_type_id, column_ids[i], expanded_id);
900 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
906 else if(basic_left.kind==BasicTypeDeclaration::MATRIX && basic_right.kind==BasicTypeDeclaration::MATRIX)
909 throw internal_error("non-float matrix multiplication");
911 /* Other operations involving matrices need to be performed
913 Id column_type_id = get_id(*basic_left.base_type);
916 unsigned n_columns = basic_left.size&0xFFFF;
917 write_deconstruct(column_type_id, left_id, column_ids, n_columns);
918 write_deconstruct(column_type_id, right_id, column_ids+4, n_columns);
920 for(unsigned i=0; i<n_columns; ++i)
921 column_ids[i] = write_expression(elem_op, column_type_id, column_ids[i], column_ids[4+i]);
923 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
926 else if(basic_left.kind==basic_right.kind)
927 // Both operands are either scalars or vectors.
932 throw internal_error("unknown binary operator");
935 swap(left_id, right_id);
937 r_expression_result_id = write_expression(opcode, result_type_id, left_id, right_id);
940 void SpirVGenerator::visit(Assignment &assign)
942 if(assign.oper->token[0]!='=')
943 visit(static_cast<BinaryExpression &>(assign));
945 assign.right->visit(*this);
947 SetForScope<Id> set_assign(assignment_source_id, r_expression_result_id);
948 assign.left->visit(*this);
951 void SpirVGenerator::visit(TernaryExpression &ternary)
953 if(constant_expression)
955 ternary.condition->visit(*this);
956 Id condition_id = r_expression_result_id;
957 ternary.true_expr->visit(*this);
958 Id true_result_id = r_expression_result_id;
959 ternary.false_expr->visit(*this);
960 Id false_result_id = r_expression_result_id;
962 r_expression_result_id = begin_expression(OP_SELECT, get_id(*ternary.type), 3);
963 writer.write(condition_id);
964 writer.write(true_result_id);
965 writer.write(false_result_id);
966 end_expression(OP_SELECT);
971 ternary.condition->visit(*this);
972 Id condition_id = r_expression_result_id;
974 Id true_label_id = next_id++;
975 Id false_label_id = next_id++;
976 Id merge_block_id = next_id++;
977 writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none)
978 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, condition_id, true_label_id, false_label_id);
980 writer.write_op_label(true_label_id);
981 ternary.true_expr->visit(*this);
982 Id true_result_id = r_expression_result_id;
983 writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
985 writer.write_op_label(false_label_id);
986 ternary.false_expr->visit(*this);
987 Id false_result_id = r_expression_result_id;
989 writer.write_op_label(merge_block_id);
990 r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4);
991 writer.write(true_result_id);
992 writer.write(true_label_id);
993 writer.write(false_result_id);
994 writer.write(false_label_id);
995 end_expression(OP_PHI);
998 void SpirVGenerator::visit(FunctionCall &call)
1000 if(constant_expression)
1001 throw internal_error("function call in constant expression");
1002 else if(assignment_source_id)
1003 throw internal_error("assignment to function call");
1004 else if(composite_access)
1005 return visit_isolated(call);
1006 else if(call.constructor && call.arguments.size()==1 && call.arguments[0]->type==call.type)
1007 return call.arguments[0]->visit(*this);
1009 vector<Id> argument_ids;
1010 argument_ids.reserve(call.arguments.size());
1011 for(NodeArray<Expression>::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
1014 argument_ids.push_back(r_expression_result_id);
1017 Id result_type_id = get_id(*call.type);
1019 if(call.constructor)
1020 visit_constructor(call, argument_ids);
1021 else if(call.declaration->source==BUILTIN_SOURCE)
1024 for(NodeArray<Expression>::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
1025 if(BasicTypeDeclaration *basic_arg = dynamic_cast<BasicTypeDeclaration *>((*i)->type))
1027 BasicTypeDeclaration &elem_arg = get_element_type(*basic_arg);
1028 switch(elem_arg.kind)
1030 case BasicTypeDeclaration::BOOL: arg_types += 'b'; break;
1031 case BasicTypeDeclaration::INT: arg_types += 'i'; break;
1032 case BasicTypeDeclaration::FLOAT: arg_types += 'f'; break;
1033 default: arg_types += '?';
1037 const BuiltinFunctionInfo *builtin_info;
1038 for(builtin_info=builtin_functions; builtin_info->function[0]; ++builtin_info)
1039 if(builtin_info->function==call.name && (!builtin_info->arg_types[0] || builtin_info->arg_types==arg_types))
1042 if(builtin_info->opcode)
1045 if(builtin_info->extension[0])
1047 opcode = OP_EXT_INST;
1048 Id ext_id = import_extension(builtin_info->extension);
1050 r_expression_result_id = begin_expression(opcode, result_type_id);
1051 writer.write(ext_id);
1052 writer.write(builtin_info->opcode);
1056 opcode = static_cast<Opcode>(builtin_info->opcode);
1057 r_expression_result_id = begin_expression(opcode, result_type_id);
1060 for(unsigned i=0; i<call.arguments.size(); ++i)
1062 if(!builtin_info->arg_order[i] || builtin_info->arg_order[i]>argument_ids.size())
1063 throw internal_error("invalid builtin function info");
1064 writer.write(argument_ids[builtin_info->arg_order[i]-1]);
1067 end_expression(opcode);
1069 else if(builtin_info->handler)
1070 (this->*(builtin_info->handler))(call, argument_ids);
1072 throw internal_error("unknown builtin function "+call.name);
1076 r_expression_result_id = begin_expression(OP_FUNCTION_CALL, result_type_id, 1+call.arguments.size());
1077 writer.write(get_id(*call.declaration->definition));
1078 for(vector<Id>::const_iterator i=argument_ids.begin(); i!=argument_ids.end(); ++i)
1080 end_expression(OP_FUNCTION_CALL);
1082 // Any global variables the called function uses might have changed value
1083 set<Node *> dependencies = DependencyCollector().apply(*call.declaration->definition);
1084 for(set<Node *>::const_iterator i=dependencies.begin(); i!=dependencies.end(); ++i)
1085 if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(*i))
1086 variable_load_ids.erase(var);
1090 void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids)
1092 Id result_type_id = get_id(*call.type);
1094 BasicTypeDeclaration *basic = dynamic_cast<BasicTypeDeclaration *>(call.type);
1097 if(dynamic_cast<const StructDeclaration *>(call.type))
1098 r_expression_result_id = write_construct(result_type_id, &argument_ids[0], argument_ids.size());
1100 throw internal_error("unconstructable type "+call.name);
1104 BasicTypeDeclaration &elem = get_element_type(*basic);
1105 BasicTypeDeclaration &basic_arg0 = dynamic_cast<BasicTypeDeclaration &>(*call.arguments[0]->type);
1106 BasicTypeDeclaration &elem_arg0 = get_element_type(basic_arg0);
1108 if(basic->kind==BasicTypeDeclaration::MATRIX)
1110 Id col_type_id = get_id(*basic->base_type);
1111 unsigned n_columns = basic->size&0xFFFF;
1112 unsigned n_rows = basic->size>>16;
1115 if(call.arguments.size()==1)
1117 // Construct diagonal matrix from a single scalar.
1118 Id zero_id = get_constant_id(get_id(elem), 0.0f);
1119 for(unsigned i=0; i<n_columns; ++i)
1121 column_ids[i] = begin_expression(OP_COMPOSITE_CONSTRUCT, col_type_id, n_rows);;
1122 for(unsigned j=0; j<n_rows; ++j)
1123 writer.write(j==i ? argument_ids[0] : zero_id);
1124 end_expression(OP_COMPOSITE_CONSTRUCT);
1128 // Construct a matrix from column vectors
1129 copy(argument_ids.begin(), argument_ids.begin()+n_columns, column_ids);
1131 r_expression_result_id = write_construct(result_type_id, column_ids, n_columns);
1133 else if(basic->kind==BasicTypeDeclaration::VECTOR && (call.arguments.size()>1 || basic_arg0.kind!=BasicTypeDeclaration::VECTOR))
1135 /* There's either a single scalar argument or multiple arguments
1136 which make up the vector's components. */
1137 if(call.arguments.size()==1)
1139 r_expression_result_id = begin_expression(OP_COMPOSITE_CONSTRUCT, result_type_id);
1140 for(unsigned i=0; i<basic->size; ++i)
1141 writer.write(argument_ids[0]);
1142 end_expression(OP_COMPOSITE_CONSTRUCT);
1145 r_expression_result_id = write_construct(result_type_id, &argument_ids[0], argument_ids.size());
1147 else if(elem.kind==BasicTypeDeclaration::BOOL)
1149 // Conversion to boolean is implemented as comparing against zero.
1150 Id number_type_id = get_id(elem_arg0);
1151 Id zero_id = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ?
1152 get_constant_id(number_type_id, 0.0f) : get_constant_id(number_type_id, 0));
1153 if(basic_arg0.kind==BasicTypeDeclaration::VECTOR)
1154 zero_id = get_vector_constant_id(get_id(basic_arg0), basic_arg0.size, zero_id);
1156 Opcode opcode = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ? OP_F_ORD_NOT_EQUAL : OP_I_NOT_EQUAL);
1157 r_expression_result_id = write_expression(opcode, result_type_id, argument_ids[0], zero_id);
1159 else if(elem_arg0.kind==BasicTypeDeclaration::BOOL)
1161 /* Conversion from boolean is implemented as selecting from zero
1163 Id number_type_id = get_id(elem);
1164 Id zero_id = (elem.kind==BasicTypeDeclaration::FLOAT ?
1165 get_constant_id(number_type_id, 0.0f) : get_constant_id(number_type_id, 0));
1166 Id one_id = (elem.kind==BasicTypeDeclaration::FLOAT ?
1167 get_constant_id(number_type_id, 1.0f) : get_constant_id(number_type_id, 1));
1168 if(basic->kind==BasicTypeDeclaration::VECTOR)
1170 zero_id = get_vector_constant_id(get_id(*basic), basic->size, zero_id);
1171 one_id = get_vector_constant_id(get_id(*basic), basic->size, one_id);
1174 r_expression_result_id = begin_expression(OP_SELECT, result_type_id, 3);
1175 writer.write(argument_ids[0]);
1176 writer.write(zero_id);
1177 writer.write(one_id);
1178 end_expression(OP_SELECT);
1182 // Scalar or vector conversion between types of equal size.
1184 if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::FLOAT)
1185 opcode = OP_CONVERT_F_TO_S;
1186 else if(elem.kind==BasicTypeDeclaration::FLOAT && elem_arg0.kind==BasicTypeDeclaration::INT)
1187 opcode = OP_CONVERT_S_TO_F;
1189 throw internal_error("invalid conversion");
1191 r_expression_result_id = write_expression(opcode, result_type_id, argument_ids[0]);
1195 void SpirVGenerator::visit_builtin_matrix_comp_mult(FunctionCall &call, const vector<Id> &argument_ids)
1197 if(argument_ids.size()!=2)
1198 throw internal_error("invalid matrixCompMult call");
1200 const BasicTypeDeclaration &basic_arg0 = dynamic_cast<const BasicTypeDeclaration &>(*call.arguments[0]->type);
1201 Id column_type_id = get_id(*basic_arg0.base_type);
1204 unsigned n_columns = basic_arg0.size&0xFFFF;
1205 write_deconstruct(column_type_id, argument_ids[0], column_ids, n_columns);
1206 write_deconstruct(column_type_id, argument_ids[1], column_ids+4, n_columns);
1208 for(unsigned i=0; i<n_columns; ++i)
1209 column_ids[i] = write_expression(OP_F_MUL, column_type_id, column_ids[i], column_ids[4+i]);
1211 r_expression_result_id = write_construct(get_id(*call.type), column_ids, n_columns);
1214 void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector<Id> &argument_ids)
1216 if(argument_ids.size()<2)
1217 throw internal_error("invalid texture sampling call");
1219 bool explicit_lod = (stage->type!=Stage::FRAGMENT || call.name=="textureLod");
1220 Id lod_id = (!explicit_lod ? 0 : call.name=="textureLod" ? argument_ids.back() :
1221 get_constant_id(get_standard_type_id(BasicTypeDeclaration::FLOAT, 1), 0.0f));
1223 const ImageTypeDeclaration &image = dynamic_cast<const ImageTypeDeclaration &>(*call.arguments[0]->type);
1226 Id result_type_id = get_id(*call.type);
1230 if(argument_ids.size()==2)
1232 const BasicTypeDeclaration &basic_arg1 = dynamic_cast<const BasicTypeDeclaration &>(*call.arguments[1]->type);
1233 dref_id = begin_expression(OP_COMPOSITE_EXTRACT, get_id(*basic_arg1.base_type), 2);
1234 writer.write(argument_ids.back());
1235 writer.write(basic_arg1.size-1);
1236 end_expression(OP_COMPOSITE_EXTRACT);
1239 dref_id = argument_ids[2];
1241 opcode = (explicit_lod ? OP_IMAGE_SAMPLE_DREF_EXPLICIT_LOD : OP_IMAGE_SAMPLE_DREF_IMPLICIT_LOD);
1242 r_expression_result_id = begin_expression(opcode, result_type_id, 3+explicit_lod*2);
1246 opcode = (explicit_lod ? OP_IMAGE_SAMPLE_EXPLICIT_LOD : OP_IMAGE_SAMPLE_IMPLICIT_LOD);
1247 r_expression_result_id = begin_expression(opcode, result_type_id, 2+explicit_lod*2);
1250 for(unsigned i=0; i<2; ++i)
1251 writer.write(argument_ids[i]);
1253 writer.write(dref_id);
1256 writer.write(2); // Lod
1257 writer.write(lod_id);
1260 end_expression(opcode);
1263 void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector<Id> &argument_ids)
1265 if(argument_ids.size()!=3)
1266 throw internal_error("invalid texelFetch call");
1268 r_expression_result_id = begin_expression(OP_IMAGE_FETCH, get_id(*call.type), 4);
1269 for(unsigned i=0; i<2; ++i)
1270 writer.write(argument_ids[i]);
1271 writer.write(2); // Lod
1272 writer.write(argument_ids.back());
1273 end_expression(OP_IMAGE_FETCH);
1276 void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector<Id> &argument_ids)
1278 if(argument_ids.size()<1)
1279 throw internal_error("invalid interpolate call");
1280 const VariableReference *var = dynamic_cast<const VariableReference *>(call.arguments[0].get());
1281 if(!var || !var->declaration || var->declaration->interface!="in")
1282 throw internal_error("invalid interpolate call");
1284 SpirVGlslStd450Opcode opcode;
1285 if(call.name=="interpolateAtCentroid")
1286 opcode = GLSL450_INTERPOLATE_AT_CENTROID;
1287 else if(call.name=="interpolateAtSample")
1288 opcode = GLSL450_INTERPOLATE_AT_SAMPLE;
1289 else if(call.name=="interpolateAtOffset")
1290 opcode = GLSL450_INTERPOLATE_AT_OFFSET;
1292 throw internal_error("invalid interpolate call");
1294 use_capability(CAP_INTERPOLATION_FUNCTION);
1296 Id ext_id = import_extension("GLSL.std.450");
1297 r_expression_result_id = begin_expression(OP_EXT_INST, get_id(*call.type));
1298 writer.write(ext_id);
1299 writer.write(opcode);
1300 writer.write(get_id(*var->declaration));
1301 for(vector<Id>::const_iterator i=argument_ids.begin(); ++i!=argument_ids.end(); )
1303 end_expression(OP_EXT_INST);
1306 void SpirVGenerator::visit(ExpressionStatement &expr)
1308 expr.expression->visit(*this);
1311 void SpirVGenerator::visit(InterfaceLayout &layout)
1313 interface_layouts.push_back(&layout);
1316 bool SpirVGenerator::check_duplicate_type(TypeDeclaration &type)
1318 for(map<Node *, Declaration>::const_iterator i=declared_ids.begin(); i!=declared_ids.end(); ++i)
1319 if(TypeDeclaration *type2 = dynamic_cast<TypeDeclaration *>(i->first))
1320 if(TypeComparer().apply(type, *type2))
1322 insert_unique(declared_ids, &type, i->second);
1329 bool SpirVGenerator::check_standard_type(BasicTypeDeclaration &basic)
1331 const BasicTypeDeclaration *elem = (basic.kind==BasicTypeDeclaration::VECTOR ?
1332 dynamic_cast<const BasicTypeDeclaration *>(basic.base_type) : &basic);
1333 if(!elem || elem->base_type)
1335 if((elem->kind==BasicTypeDeclaration::INT || elem->kind==BasicTypeDeclaration::FLOAT) && elem->size!=32)
1338 Id standard_id = get_standard_type_id(elem->kind, (basic.kind==BasicTypeDeclaration::VECTOR ? basic.size : 1));
1339 insert_unique(declared_ids, &basic, Declaration(standard_id, 0));
1340 writer.write_op_name(standard_id, basic.name);
1345 void SpirVGenerator::visit(BasicTypeDeclaration &basic)
1347 if(check_standard_type(basic))
1349 if(check_duplicate_type(basic))
1351 // Alias types shouldn't exist at this point and arrays are handled elsewhere
1352 if(basic.kind==BasicTypeDeclaration::ALIAS || basic.kind==BasicTypeDeclaration::ARRAY)
1355 Id type_id = allocate_id(basic, 0);
1356 writer.write_op_name(type_id, basic.name);
1360 case BasicTypeDeclaration::INT:
1361 writer.write_op(content.globals, OP_TYPE_INT, type_id, basic.size, 1);
1363 case BasicTypeDeclaration::FLOAT:
1364 writer.write_op(content.globals, OP_TYPE_FLOAT, type_id, basic.size);
1366 case BasicTypeDeclaration::VECTOR:
1367 writer.write_op(content.globals, OP_TYPE_VECTOR, type_id, get_id(*basic.base_type), basic.size);
1369 case BasicTypeDeclaration::MATRIX:
1370 writer.write_op(content.globals, OP_TYPE_MATRIX, type_id, get_id(*basic.base_type), basic.size&0xFFFF);
1373 throw internal_error("unknown basic type");
1377 void SpirVGenerator::visit(ImageTypeDeclaration &image)
1379 if(check_duplicate_type(image))
1382 Id type_id = allocate_id(image, 0);
1384 Id image_id = (image.sampled ? next_id++ : type_id);
1385 writer.begin_op(content.globals, OP_TYPE_IMAGE, 9);
1386 writer.write(image_id);
1387 writer.write(get_id(*image.base_type));
1388 writer.write(image.dimensions-1);
1389 writer.write(image.shadow);
1390 writer.write(image.array);
1391 writer.write(false); // Multisample
1392 writer.write(image.sampled ? 1 : 2);
1393 writer.write(0); // Format (unknown)
1394 writer.end_op(OP_TYPE_IMAGE);
1398 writer.write_op_name(type_id, image.name);
1399 writer.write_op(content.globals, OP_TYPE_SAMPLED_IMAGE, type_id, image_id);
1402 if(image.dimensions==ImageTypeDeclaration::ONE)
1403 use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D);
1404 else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array)
1405 use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY);
1408 void SpirVGenerator::visit(StructDeclaration &strct)
1410 if(check_duplicate_type(strct))
1413 Id type_id = allocate_id(strct, 0);
1414 writer.write_op_name(type_id, strct.name);
1416 if(strct.interface_block)
1417 writer.write_op_decorate(type_id, DECO_BLOCK);
1419 bool builtin = (strct.interface_block && !strct.interface_block->block_name.compare(0, 3, "gl_"));
1420 vector<Id> member_type_ids;
1421 member_type_ids.reserve(strct.members.body.size());
1422 for(NodeList<Statement>::const_iterator i=strct.members.body.begin(); i!=strct.members.body.end(); ++i)
1424 const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(i->get());
1428 unsigned index = member_type_ids.size();
1429 member_type_ids.push_back(get_variable_type_id(*var));
1431 writer.write_op_member_name(type_id, index, var->name);
1435 BuiltinSemantic semantic = get_builtin_semantic(var->name);
1436 writer.write_op_member_decorate(type_id, index, DECO_BUILTIN, semantic);
1442 const vector<Layout::Qualifier> &qualifiers = var->layout->qualifiers;
1443 for(vector<Layout::Qualifier>::const_iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j)
1445 if(j->name=="offset")
1446 writer.write_op_member_decorate(type_id, index, DECO_OFFSET, j->value);
1447 else if(j->name=="column_major")
1448 writer.write_op_member_decorate(type_id, index, DECO_COL_MAJOR);
1449 else if(j->name=="row_major")
1450 writer.write_op_member_decorate(type_id, index, DECO_ROW_MAJOR);
1454 const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(var->type_declaration);
1455 while(basic && basic->kind==BasicTypeDeclaration::ARRAY)
1456 basic = dynamic_cast<const BasicTypeDeclaration *>(basic->base_type);
1457 if(basic && basic->kind==BasicTypeDeclaration::MATRIX)
1459 unsigned stride = MemoryRequirementsCalculator().apply(*basic->base_type).stride;
1460 writer.write_op_member_decorate(type_id, index, DECO_MATRIX_STRIDE, stride);
1465 writer.begin_op(content.globals, OP_TYPE_STRUCT);
1466 writer.write(type_id);
1467 for(vector<Id>::const_iterator i=member_type_ids.begin(); i!=member_type_ids.end(); ++i)
1469 writer.end_op(OP_TYPE_STRUCT);
1472 void SpirVGenerator::visit(VariableDeclaration &var)
1474 const vector<Layout::Qualifier> *layout_ql = (var.layout ? &var.layout->qualifiers : 0);
1479 for(vector<Layout::Qualifier>::const_iterator i=layout_ql->begin(); (spec_id<0 && i!=layout_ql->end()); ++i)
1480 if(i->name=="constant_id")
1484 Id type_id = get_variable_type_id(var);
1489 if(!var.init_expression)
1490 throw internal_error("const variable without initializer");
1492 SetFlag set_const(constant_expression);
1493 SetFlag set_spec(spec_constant, spec_id>=0);
1494 r_expression_result_id = 0;
1495 var.init_expression->visit(*this);
1496 var_id = r_expression_result_id;
1497 insert_unique(declared_ids, &var, Declaration(var_id, type_id));
1498 writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id);
1500 /* It's unclear what should be done if a specialization constant is
1501 initialized with anything other than a literal. GLSL doesn't seem to
1502 prohibit that but SPIR-V says OpSpecConstantOp can't be updated via
1507 StorageClass storage = (current_function ? STORAGE_FUNCTION : get_interface_storage(var.interface, false));
1508 Id ptr_type_id = get_pointer_type_id(type_id, storage);
1509 if(var.interface=="uniform")
1511 Id &uni_id = declared_uniform_ids["v"+var.name];
1514 insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id));
1518 uni_id = var_id = allocate_id(var, ptr_type_id);
1521 var_id = allocate_id(var, (var.constant ? type_id : ptr_type_id));
1524 if(var.init_expression)
1526 SetFlag set_const(constant_expression, !current_function);
1527 r_expression_result_id = 0;
1528 var.init_expression->visit(*this);
1529 init_id = r_expression_result_id;
1532 vector<Word> &target = (current_function ? content.locals : content.globals);
1533 writer.begin_op(target, OP_VARIABLE, 4+(init_id && !current_function));
1534 writer.write(ptr_type_id);
1535 writer.write(var_id);
1536 writer.write(storage);
1537 if(init_id && !current_function)
1538 writer.write(init_id);
1539 writer.end_op(OP_VARIABLE);
1543 for(vector<Layout::Qualifier>::const_iterator i=layout_ql->begin(); i!=layout_ql->end(); ++i)
1545 if(i->name=="location")
1546 writer.write_op_decorate(var_id, DECO_LOCATION, i->value);
1547 else if(i->name=="set")
1548 writer.write_op_decorate(var_id, DECO_DESCRIPTOR_SET, i->value);
1549 else if(i->name=="binding")
1550 writer.write_op_decorate(var_id, DECO_BINDING, i->value);
1554 if(init_id && current_function)
1555 writer.write_op(content.function_body, OP_STORE, var_id, init_id);
1558 writer.write_op_name(var_id, var.name);
1561 void SpirVGenerator::visit(InterfaceBlock &iface)
1563 StorageClass storage = get_interface_storage(iface.interface, true);
1566 type_id = get_array_type_id(*iface.struct_declaration, 0);
1568 type_id = get_id(*iface.struct_declaration);
1569 Id ptr_type_id = get_pointer_type_id(type_id, storage);
1572 if(iface.interface=="uniform")
1574 Id &uni_id = declared_uniform_ids["b"+iface.block_name];
1577 insert_unique(declared_ids, &iface, Declaration(uni_id, ptr_type_id));
1581 uni_id = block_id = allocate_id(iface, ptr_type_id);
1584 block_id = allocate_id(iface, ptr_type_id);
1585 writer.write_op_name(block_id, iface.instance_name);
1587 writer.write_op(content.globals, OP_VARIABLE, ptr_type_id, block_id, storage);
1591 const vector<Layout::Qualifier> &qualifiers = iface.layout->qualifiers;
1592 for(vector<Layout::Qualifier>::const_iterator i=qualifiers.begin(); i!=qualifiers.end(); ++i)
1593 if(i->name=="binding")
1594 writer.write_op_decorate(block_id, DECO_BINDING, i->value);
1598 void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id)
1600 writer.begin_op(content.entry_points, OP_ENTRY_POINT);
1603 case Stage::VERTEX: writer.write(0); break;
1604 case Stage::GEOMETRY: writer.write(3); break;
1605 case Stage::FRAGMENT: writer.write(4); break;
1606 default: throw internal_error("unknown stage");
1608 writer.write(func_id);
1609 writer.write_string(func.name);
1611 set<Node *> dependencies = DependencyCollector().apply(func);
1612 for(set<Node *>::const_iterator i=dependencies.begin(); i!=dependencies.end(); ++i)
1614 if(const VariableDeclaration *var = dynamic_cast<const VariableDeclaration *>(*i))
1616 if(!var->interface.empty())
1617 writer.write(get_id(**i));
1619 else if(dynamic_cast<InterfaceBlock *>(*i))
1620 writer.write(get_id(**i));
1623 writer.end_op(OP_ENTRY_POINT);
1625 if(stage->type==Stage::FRAGMENT)
1626 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ORIGIN_LOWER_LEFT);
1627 else if(stage->type==Stage::GEOMETRY)
1628 use_capability(CAP_GEOMETRY);
1630 for(vector<const InterfaceLayout *>::const_iterator i=interface_layouts.begin(); i!=interface_layouts.end(); ++i)
1632 const vector<Layout::Qualifier> &qualifiers = (*i)->layout.qualifiers;
1633 for(vector<Layout::Qualifier>::const_iterator j=qualifiers.begin(); j!=qualifiers.end(); ++j)
1635 if(j->name=="point")
1636 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id,
1637 ((*i)->interface=="in" ? EXEC_INPUT_POINTS : EXEC_OUTPUT_POINTS));
1638 else if(j->name=="lines")
1639 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES);
1640 else if(j->name=="lines_adjacency")
1641 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_LINES_ADJACENCY);
1642 else if(j->name=="triangles")
1643 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_TRIANGLES);
1644 else if(j->name=="triangles_adjacency")
1645 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INPUT_TRIANGLES_ADJACENCY);
1646 else if(j->name=="line_strip")
1647 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_LINE_STRIP);
1648 else if(j->name=="triangle_strip")
1649 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP);
1650 else if(j->name=="max_vertices")
1651 writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, j->value);
1656 void SpirVGenerator::visit(FunctionDeclaration &func)
1658 if(func.source==BUILTIN_SOURCE || func.definition!=&func)
1661 Id return_type_id = get_id(*func.return_type_declaration);
1662 vector<unsigned> param_type_ids;
1663 param_type_ids.reserve(func.parameters.size());
1664 for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
1665 param_type_ids.push_back(get_variable_type_id(**i));
1667 string sig_with_return = func.return_type+func.signature;
1668 Id &type_id = function_type_ids[sig_with_return];
1671 type_id = next_id++;
1672 writer.begin_op(content.globals, OP_TYPE_FUNCTION);
1673 writer.write(type_id);
1674 writer.write(return_type_id);
1675 for(vector<unsigned>::const_iterator i=param_type_ids.begin(); i!=param_type_ids.end(); ++i)
1677 writer.end_op(OP_TYPE_FUNCTION);
1679 writer.write_op_name(type_id, sig_with_return);
1682 Id func_id = allocate_id(func, type_id);
1683 writer.write_op_name(func_id, func.name+func.signature);
1685 if(func.name=="main")
1686 visit_entry_point(func, func_id);
1688 writer.begin_op(content.functions, OP_FUNCTION, 5);
1689 writer.write(return_type_id);
1690 writer.write(func_id);
1691 writer.write(0); // Function control flags (none)
1692 writer.write(type_id);
1693 writer.end_op(OP_FUNCTION);
1695 for(unsigned i=0; i<func.parameters.size(); ++i)
1697 Id param_id = allocate_id(*func.parameters[i], param_type_ids[i]);
1698 writer.write_op(content.functions, OP_FUNCTION_PARAMETER, param_type_ids[i], param_id);
1699 // TODO This is probably incorrect if the parameter is assigned to.
1700 variable_load_ids[func.parameters[i].get()] = param_id;
1703 writer.begin_function_body(next_id++);
1704 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
1705 func.body.visit(*this);
1707 if(writer.has_current_block())
1710 writer.write_op(content.function_body, OP_UNREACHABLE);
1713 const BasicTypeDeclaration *basic_return = dynamic_cast<const BasicTypeDeclaration *>(func.return_type_declaration);
1714 if(basic_return && basic_return->kind==BasicTypeDeclaration::VOID)
1715 writer.write_op(content.function_body, OP_RETURN);
1717 throw internal_error("missing return in non-void function");
1720 writer.end_function_body();
1721 variable_load_ids.clear();
1724 void SpirVGenerator::visit(Conditional &cond)
1726 cond.condition->visit(*this);
1728 Id true_label_id = next_id++;
1729 Id merge_block_id = next_id++;
1730 Id false_label_id = (cond.else_body.body.empty() ? merge_block_id : next_id++);
1731 writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none)
1732 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id);
1734 writer.write_op_label(true_label_id);
1735 cond.body.visit(*this);
1736 if(writer.has_current_block())
1737 writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
1739 bool reachable_if_true = reachable;
1742 if(!cond.else_body.body.empty())
1744 writer.write_op_label(false_label_id);
1745 cond.else_body.visit(*this);
1746 reachable |= reachable_if_true;
1749 writer.write_op_label(merge_block_id);
1750 prune_loads(true_label_id);
1753 void SpirVGenerator::visit(Iteration &iter)
1755 if(iter.init_statement)
1756 iter.init_statement->visit(*this);
1758 Id header_id = next_id++;
1759 Id continue_id = next_id++;
1760 Id merge_block_id = next_id++;
1762 SetForScope<Id> set_merge(loop_merge_block_id, merge_block_id);
1763 SetForScope<Id> set_continue(loop_continue_target_id, continue_id);
1765 writer.write_op_label(header_id);
1766 writer.write_op(content.function_body, OP_LOOP_MERGE, merge_block_id, continue_id, 0); // Loop control (none)
1768 Id body_id = next_id++;
1771 writer.write_op_label(next_id++);
1772 iter.condition->visit(*this);
1773 writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, body_id, merge_block_id);
1776 writer.write_op_label(body_id);
1777 iter.body.visit(*this);
1779 writer.write_op_label(continue_id);
1780 if(iter.loop_expression)
1781 iter.loop_expression->visit(*this);
1782 writer.write_op(content.function_body, OP_BRANCH, header_id);
1784 writer.write_op_label(merge_block_id);
1785 prune_loads(header_id);
1789 void SpirVGenerator::visit(Return &ret)
1793 ret.expression->visit(*this);
1794 writer.write_op(content.function_body, OP_RETURN_VALUE, r_expression_result_id);
1797 writer.write_op(content.function_body, OP_RETURN);
1801 void SpirVGenerator::visit(Jump &jump)
1803 if(jump.keyword=="discard")
1804 writer.write_op(content.function_body, OP_KILL);
1805 else if(jump.keyword=="break")
1806 writer.write_op(content.function_body, OP_BRANCH, loop_merge_block_id);
1807 else if(jump.keyword=="continue")
1808 writer.write_op(content.function_body, OP_BRANCH, loop_continue_target_id);
1810 throw internal_error("unknown jump");
1815 bool SpirVGenerator::TypeKey::operator<(const TypeKey &other) const
1817 if(type_id!=other.type_id)
1818 return type_id<other.type_id;
1819 return detail<other.detail;
1823 bool SpirVGenerator::ConstantKey::operator<(const ConstantKey &other) const
1825 if(type_id!=other.type_id)
1826 return type_id<other.type_id;
1827 return int_value<other.int_value;