X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fspirv.cpp;h=85312bc4edb67760f2e87d0591a0e7499707d114;hb=7272d97c23eedb3850661deec964c4a9c96337fe;hp=1da748a64eb297f23f5f135aa3743af92eabbaea;hpb=e9a898f315b5d1396f196d785913a283c30940f2;p=libs%2Fgl.git diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 1da748a6..85312bc4 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -111,9 +111,14 @@ const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] = { "textureSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "textureQueryLod", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "textureQueryLevels", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "textureSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, { "texture", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, { "textureLod", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture }, - { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texel_fetch }, + { "texelFetch", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageSize", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageSamples", "", "", 0, { }, CAP_IMAGE_QUERY, &SpirVGenerator::visit_builtin_texture_query }, + { "imageLoad", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_fetch }, + { "imageStore", "", "", 0, { }, 0, &SpirVGenerator::visit_builtin_texture_store }, { "EmitVertex", "", "", OP_EMIT_VERTEX, { }, 0, 0 }, { "EndPrimitive", "", "", OP_END_PRIMITIVE, { }, 0, 0 }, { "dFdx", "f", "", OP_DP_DX, { 1 }, 0, 0 }, @@ -132,24 +137,12 @@ const SpirVGenerator::BuiltinFunctionInfo SpirVGenerator::builtin_functions[] = }; SpirVGenerator::SpirVGenerator(): - stage(0), - current_function(0), - writer(content), - next_id(1), - r_expression_result_id(0), - constant_expression(false), - spec_constant(false), - reachable(false), - composite_access(false), - r_composite_base_id(0), - r_composite_base(0), - assignment_source_id(0), - loop_merge_block_id(0), - loop_continue_target_id(0) + writer(content) { } -void SpirVGenerator::apply(Module &module) +void SpirVGenerator::apply(Module &module, const Features &f) { + features = f; use_capability(CAP_SHADER); for(Stage &s: module.stages) @@ -206,10 +199,66 @@ SpirVGenerator::BuiltinSemantic SpirVGenerator::get_builtin_semantic(const strin return BUILTIN_SAMPLE_POSITION; else if(name=="gl_FragDepth") return BUILTIN_FRAG_DEPTH; + else if(name=="gl_NumWorkGroups") + return BUILTIN_NUM_WORKGROUPS; + else if(name=="gl_WorkGroupSize") + return BUILTIN_WORKGROUP_SIZE; + else if(name=="gl_WorkGroupID") + return BUILTIN_WORKGROUP_ID; + else if(name=="gl_LocalInvocationID") + return BUILTIN_LOCAL_INVOCATION_ID; + else if(name=="gl_GlobalInvocationID") + return BUILTIN_GLOBAL_INVOCATION_ID; + else if(name=="gl_LocalInvocationIndex") + return BUILTIN_LOCAL_INVOCATION_INDEX; else throw invalid_argument("SpirVGenerator::get_builtin_semantic"); } +SpirVFormat SpirVGenerator::get_format(const std::string &name) +{ + if(name.empty()) + return FORMAT_UNKNOWN; + else if(name=="rgba32f") + return FORMAT_RGBA32F; + else if(name=="rgba16f") + return FORMAT_RGBA16F; + else if(name=="r32f") + return FORMAT_R32F; + else if(name=="rgba8") + return FORMAT_RGBA8; + else if(name=="rgba8_snorm") + return FORMAT_RGBA8_SNORM; + else if(name=="rg32f") + return FORMAT_RG32F; + else if(name=="rg16f") + return FORMAT_RG16F; + else if(name=="r16f") + return FORMAT_R16F; + else if(name=="rgba16") + return FORMAT_RGBA16; + else if(name=="rg16") + return FORMAT_RG16; + else if(name=="rg8") + return FORMAT_RG8; + else if(name=="r16") + return FORMAT_RG16; + else if(name=="r8") + return FORMAT_RG8; + else if(name=="rgba16_snorm") + return FORMAT_RGBA16_SNORM; + else if(name=="rg16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="rg8_snorm") + return FORMAT_RG8_SNORM; + else if(name=="r16_snorm") + return FORMAT_RG16_SNORM; + else if(name=="r8_snorm") + return FORMAT_RG8_SNORM; + else + throw invalid_argument("SpirVGenerator::get_format"); +} + void SpirVGenerator::use_capability(Capability cap) { if(used_capabilities.count(cap)) @@ -350,10 +399,10 @@ bool SpirVGenerator::is_scalar_type(Id type_id, BasicTypeDeclaration::Kind kind) return (i!=standard_type_ids.end() && i->second==type_id); } -SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id) +SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, Id size_id, bool extended_align) { Id base_type_id = get_id(base_type); - Id &array_type_id = array_type_ids[TypeKey(base_type_id, size_id)]; + Id &array_type_id = array_type_ids[TypeKey(base_type_id, extended_align*0x400000 | size_id)]; if(!array_type_id) { array_type_id = next_id++; @@ -363,6 +412,8 @@ SpirVGenerator::Id SpirVGenerator::get_array_type_id(TypeDeclaration &base_type, writer.write_op(content.globals, OP_TYPE_RUNTIME_ARRAY, array_type_id, base_type_id); unsigned stride = MemoryRequirementsCalculator().apply(base_type).stride; + if(extended_align) + stride = (stride+15)&~15U; writer.write_op_decorate(array_type_id, DECO_ARRAY_STRIDE, stride); } @@ -385,17 +436,13 @@ SpirVGenerator::Id SpirVGenerator::get_variable_type_id(const VariableDeclaratio if(const BasicTypeDeclaration *basic = dynamic_cast(var.type_declaration)) if(basic->kind==BasicTypeDeclaration::ARRAY) { - Id size_id = 0; - if(var.array_size) - { - SetFlag set_const(constant_expression); - r_expression_result_id = 0; - var.array_size->visit(*this); - size_id = r_expression_result_id; - } - else - size_id = get_constant_id(get_standard_type_id(BasicTypeDeclaration::INT, 1), 1); - return get_array_type_id(*basic->base_type, size_id); + if(!var.array_size) + throw logic_error("array without size"); + + SetFlag set_const(constant_expression); + r_expression_result_id = 0; + var.array_size->visit(*this); + return get_array_type_id(*basic->base_type, r_expression_result_id, basic->extended_alignment); } return get_id(*var.type_declaration); @@ -531,8 +578,15 @@ void SpirVGenerator::visit(VariableReference &var) r_constant_result = false; if(composite_access) { - r_composite_base = var.declaration; r_expression_result_id = 0; + if(!assignment_source_id) + { + auto i = variable_load_ids.find(var.declaration); + if(i!=variable_load_ids.end()) + r_expression_result_id = i->second; + } + if(!r_expression_result_id) + r_composite_base = var.declaration; } else if(assignment_source_id) { @@ -544,16 +598,6 @@ void SpirVGenerator::visit(VariableReference &var) r_expression_result_id = get_load_id(*var.declaration); } -void SpirVGenerator::visit(InterfaceBlockReference &iface) -{ - if(!composite_access || !current_function) - throw internal_error("invalid interface block reference"); - - r_composite_base = iface.declaration; - r_expression_result_id = 0; - r_constant_result = false; -} - void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) { Opcode opcode; @@ -583,7 +627,7 @@ void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) throw internal_error("assignment to temporary composite"); else { - for(unsigned i: r_composite_chain) + for(unsigned &i: r_composite_chain) for(auto j=constant_ids.begin(); (i>=0x400000 && j!=constant_ids.end()); ++j) if(j->second==(i&0x3FFFFF)) i = j->first.int_value; @@ -696,6 +740,9 @@ void SpirVGenerator::visit(Swizzle &swizzle) void SpirVGenerator::visit(UnaryExpression &unary) { + if(composite_access) + return visit_isolated(unary); + unary.expression->visit(*this); char oper = unary.oper->token[0]; @@ -780,6 +827,8 @@ void SpirVGenerator::visit(BinaryExpression &binary) visit_isolated(*binary.right); return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type); } + else if(composite_access) + return visit_isolated(binary); if(assignment_source_id) throw internal_error("invalid binary expression in assignment target"); @@ -1004,6 +1053,8 @@ void SpirVGenerator::visit(Assignment &assign) void SpirVGenerator::visit(TernaryExpression &ternary) { + if(composite_access) + return visit_isolated(ternary); if(constant_expression) { ternary.condition->visit(*this); @@ -1031,16 +1082,22 @@ void SpirVGenerator::visit(TernaryExpression &ternary) writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none) writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, condition_id, true_label_id, false_label_id); + std::map saved_load_ids = variable_load_ids; + writer.write_op_label(true_label_id); ternary.true_expr->visit(*this); Id true_result_id = r_expression_result_id; + true_label_id = writer.get_current_block(); writer.write_op(content.function_body, OP_BRANCH, merge_block_id); + swap(saved_load_ids, variable_load_ids); writer.write_op_label(false_label_id); ternary.false_expr->visit(*this); Id false_result_id = r_expression_result_id; + false_label_id = writer.get_current_block(); writer.write_op_label(merge_block_id); + prune_loads(true_label_id); r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4); writer.write(true_result_id); writer.write(true_label_id); @@ -1295,17 +1352,21 @@ void SpirVGenerator::visit_builtin_texture_query(FunctionCall &call, const vecto Opcode opcode; if(call.name=="textureSize") opcode = OP_IMAGE_QUERY_SIZE_LOD; + else if(call.name=="imageSize") + opcode = OP_IMAGE_QUERY_SIZE; else if(call.name=="textureQueryLod") opcode = OP_IMAGE_QUERY_LOD; else if(call.name=="textureQueryLevels") opcode = OP_IMAGE_QUERY_LEVELS; + else if(call.name=="textureSamples" || call.name=="imageSamples") + opcode = OP_IMAGE_QUERY_SAMPLES; else throw internal_error("invalid texture query call"); ImageTypeDeclaration &image_arg0 = dynamic_cast(*call.arguments[0]->type); Id image_id; - if(image_arg0.sampled) + if(image_arg0.sampled && opcode!=OP_IMAGE_QUERY_LOD) { Id image_type_id = get_item(image_type_ids, get_id(image_arg0)); image_id = write_expression(OP_IMAGE, image_type_id, argument_ids[0]); @@ -1370,17 +1431,54 @@ void SpirVGenerator::visit_builtin_texture(FunctionCall &call, const vector end_expression(opcode); } -void SpirVGenerator::visit_builtin_texel_fetch(FunctionCall &call, const vector &argument_ids) +void SpirVGenerator::visit_builtin_texture_fetch(FunctionCall &call, const vector &argument_ids) +{ + const ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); + + Opcode opcode; + if(call.name=="texelFetch") + opcode = OP_IMAGE_FETCH; + else if(call.name=="imageLoad") + opcode = OP_IMAGE_READ; + else + throw internal_error("invalid texture fetch call"); + + bool need_sample = image.multisample; + bool need_lod = (opcode==OP_IMAGE_FETCH && !need_sample); + + if(argument_ids.size()!=2U+need_sample+need_lod) + throw internal_error("invalid texture fetch call"); + + r_expression_result_id = begin_expression(opcode, get_id(*call.type), 2+(need_lod|need_sample)+need_lod+need_sample); + for(unsigned i=0; i<2; ++i) + writer.write(argument_ids[i]); + if(need_lod || need_sample) + { + writer.write(need_lod*0x02 | need_sample*0x40); + writer.write(argument_ids.back()); + } + end_expression(opcode); +} + +void SpirVGenerator::visit_builtin_texture_store(FunctionCall &call, const vector &argument_ids) { if(argument_ids.size()!=3) - throw internal_error("invalid texelFetch call"); + throw internal_error("invalid texture store call"); - r_expression_result_id = begin_expression(OP_IMAGE_FETCH, get_id(*call.type), 4); + const ImageTypeDeclaration &image = dynamic_cast(*call.arguments[0]->type); + + begin_expression(OP_IMAGE_WRITE, get_id(*call.type), 3+image.multisample*2); for(unsigned i=0; i<2; ++i) writer.write(argument_ids[i]); - writer.write(2); // Lod writer.write(argument_ids.back()); - end_expression(OP_IMAGE_FETCH); + if(image.multisample) + { + writer.write(0x40); // Sample + writer.write(argument_ids[2]); + } + end_expression(OP_IMAGE_WRITE); + + r_expression_result_id = 0; } void SpirVGenerator::visit_builtin_interpolate(FunctionCall &call, const vector &argument_ids) @@ -1496,9 +1594,9 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) writer.write(image.dimensions-1); writer.write(image.shadow); writer.write(image.array); - writer.write(false); // Multisample + writer.write(image.multisample); writer.write(image.sampled ? 1 : 2); - writer.write(0); // Format (unknown) + writer.write(get_format(image.format)); writer.end_op(OP_TYPE_IMAGE); if(image.sampled) @@ -1512,6 +1610,9 @@ void SpirVGenerator::visit(ImageTypeDeclaration &image) use_capability(image.sampled ? CAP_SAMPLED_1D : CAP_IMAGE_1D); else if(image.dimensions==ImageTypeDeclaration::CUBE && image.array) use_capability(image.sampled ? CAP_SAMPLED_CUBE_ARRAY : CAP_IMAGE_CUBE_ARRAY); + + if(image.multisample && !image.sampled) + use_capability(CAP_STORAGE_IMAGE_MULTISAMPLE); } void SpirVGenerator::visit(StructDeclaration &strct) @@ -1520,12 +1621,12 @@ void SpirVGenerator::visit(StructDeclaration &strct) return; Id type_id = allocate_id(strct, 0); - writer.write_op_name(type_id, strct.name); + writer.write_op_name(type_id, (strct.block_name.empty() ? strct.name : strct.block_name)); - if(strct.interface_block) + if(!strct.block_name.empty()) writer.write_op_decorate(type_id, DECO_BLOCK); - bool builtin = (strct.interface_block && !strct.interface_block->block_name.compare(0, 3, "gl_")); + bool builtin = !strct.block_name.compare(0, 3, "gl_"); vector member_type_ids; member_type_ids.reserve(strct.members.body.size()); for(const RefPtr &s: strct.members.body) @@ -1579,16 +1680,6 @@ void SpirVGenerator::visit(StructDeclaration &strct) void SpirVGenerator::visit(VariableDeclaration &var) { - const vector *layout_ql = (var.layout ? &var.layout->qualifiers : 0); - - int spec_id = -1; - if(layout_ql) - { - auto i = find_member(*layout_ql, string("constant_id"), &Layout::Qualifier::name); - if(i!=layout_ql->end()) - spec_id = i->value; - } - Id type_id = get_variable_type_id(var); Id var_id; @@ -1597,26 +1688,42 @@ void SpirVGenerator::visit(VariableDeclaration &var) if(!var.init_expression) throw internal_error("const variable without initializer"); + int spec_id = get_layout_value(var.layout.get(), "constant_id"); + Id *spec_var_id = (spec_id>=0 ? &declared_spec_ids[spec_id] : 0); + if(spec_id>=0 && *spec_var_id) + { + insert_unique(declared_ids, &var, Declaration(*spec_var_id, type_id)); + return; + } + SetFlag set_const(constant_expression); SetFlag set_spec(spec_constant, spec_id>=0); r_expression_result_id = 0; var.init_expression->visit(*this); var_id = r_expression_result_id; insert_unique(declared_ids, &var, Declaration(var_id, type_id)); - writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id); - - /* It's unclear what should be done if a specialization constant is - initialized with anything other than a literal. GLSL doesn't seem to - prohibit that but SPIR-V says OpSpecConstantOp can't be updated via - specialization. */ + if(spec_id>=0) + { + writer.write_op_decorate(var_id, DECO_SPEC_ID, spec_id); + *spec_var_id = var_id; + } } else { - StorageClass storage = (current_function ? STORAGE_FUNCTION : get_interface_storage(var.interface, false)); + bool push_const = has_layout_qualifier(var.layout.get(), "push_constant"); + + StorageClass storage; + if(current_function) + storage = STORAGE_FUNCTION; + else if(push_const) + storage = STORAGE_PUSH_CONSTANT; + else + storage = get_interface_storage(var.interface, var.block_declaration); + Id ptr_type_id = get_pointer_type_id(type_id, storage); if(var.interface=="uniform") { - Id &uni_id = declared_uniform_ids["v"+var.name]; + Id &uni_id = declared_uniform_ids[var.block_declaration ? "b"+var.block_declaration->block_name : "v"+var.name]; if(uni_id) { insert_unique(declared_ids, &var, Declaration(uni_id, ptr_type_id)); @@ -1647,9 +1754,9 @@ void SpirVGenerator::visit(VariableDeclaration &var) writer.write(init_id); writer.end_op(OP_VARIABLE); - if(layout_ql) + if(var.layout) { - for(const Layout::Qualifier &q: *layout_ql) + for(const Layout::Qualifier &q: var.layout->qualifiers) { if(q.name=="location") writer.write_op_decorate(var_id, DECO_LOCATION, q.value); @@ -1659,6 +1766,15 @@ void SpirVGenerator::visit(VariableDeclaration &var) writer.write_op_decorate(var_id, DECO_BINDING, q.value); } } + if(!var.block_declaration && !var.name.compare(0, 3, "gl_")) + { + BuiltinSemantic semantic = get_builtin_semantic(var.name); + writer.write_op_decorate(var_id, DECO_BUILTIN, semantic); + } + if(var.sampling=="flat") + writer.write_op_decorate(var_id, DECO_FLAT); + if(var.sampling=="centroid") + writer.write_op_decorate(var_id, DECO_CENTROID); if(init_id && current_function) { @@ -1667,43 +1783,8 @@ void SpirVGenerator::visit(VariableDeclaration &var) } } - writer.write_op_name(var_id, var.name); -} - -void SpirVGenerator::visit(InterfaceBlock &iface) -{ - StorageClass storage = get_interface_storage(iface.interface, true); - Id type_id; - if(iface.array) - type_id = get_array_type_id(*iface.struct_declaration, 0); - else - type_id = get_id(*iface.struct_declaration); - Id ptr_type_id = get_pointer_type_id(type_id, storage); - - Id block_id; - if(iface.interface=="uniform") - { - Id &uni_id = declared_uniform_ids["b"+iface.block_name]; - if(uni_id) - { - insert_unique(declared_ids, &iface, Declaration(uni_id, ptr_type_id)); - return; - } - - uni_id = block_id = allocate_id(iface, ptr_type_id); - } - else - block_id = allocate_id(iface, ptr_type_id); - writer.write_op_name(block_id, iface.instance_name); - - writer.write_op(content.globals, OP_VARIABLE, ptr_type_id, block_id, storage); - - if(iface.layout) - { - auto i = find_member(iface.layout->qualifiers, string("binding"), &Layout::Qualifier::name); - if(i!=iface.layout->qualifiers.end()) - writer.write_op_decorate(block_id, DECO_BINDING, i->value); - } + if(var.name.find(' ')==string::npos) + writer.write_op_name(var_id, var.name); } void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) @@ -1714,6 +1795,7 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) case Stage::VERTEX: writer.write(0); break; case Stage::GEOMETRY: writer.write(3); break; case Stage::FRAGMENT: writer.write(4); break; + case Stage::COMPUTE: writer.write(5); break; default: throw internal_error("unknown stage"); } writer.write(func_id); @@ -1721,22 +1803,24 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) set dependencies = DependencyCollector().apply(func); for(Node *n: dependencies) - { if(const VariableDeclaration *var = dynamic_cast(n)) - { if(!var->interface.empty()) writer.write(get_id(*n)); - } - else if(dynamic_cast(n)) - writer.write(get_id(*n)); - } writer.end_op(OP_ENTRY_POINT); if(stage->type==Stage::FRAGMENT) - writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_ORIGIN_LOWER_LEFT); + { + SpirVExecutionMode origin = (features.target_api==VULKAN ? EXEC_ORIGIN_UPPER_LEFT : EXEC_ORIGIN_LOWER_LEFT); + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, origin); + } else if(stage->type==Stage::GEOMETRY) + { use_capability(CAP_GEOMETRY); + writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_INVOCATIONS, 1); + } + + unsigned local_size[3] = { 0, 1, 1 }; for(const InterfaceLayout *i: interface_layouts) { @@ -1759,8 +1843,24 @@ void SpirVGenerator::visit_entry_point(FunctionDeclaration &func, Id func_id) writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_TRIANGLE_STRIP); else if(q.name=="max_vertices") writer.write_op(content.exec_modes, OP_EXECUTION_MODE, func_id, EXEC_OUTPUT_VERTICES, q.value); + else if(q.name=="local_size_x") + local_size[0] = q.value; + else if(q.name=="local_size_y") + local_size[1] = q.value; + else if(q.name=="local_size_z") + local_size[2] = q.value; } } + + if(stage->type==Stage::COMPUTE && local_size[0]) + { + writer.begin_op(content.exec_modes, OP_EXECUTION_MODE); + writer.write(func_id); + writer.write(EXEC_LOCAL_SIZE); + for(unsigned j=0; j<3; ++j) + writer.write(local_size[j]); + writer.end_op(OP_EXECUTION_MODE); + } } void SpirVGenerator::visit(FunctionDeclaration &func) @@ -1812,15 +1912,17 @@ void SpirVGenerator::visit(FunctionDeclaration &func) { Id param_id = allocate_id(*func.parameters[i], param_type_ids[i]); writer.write_op(content.functions, OP_FUNCTION_PARAMETER, param_type_ids[i], param_id); + writer.write_op_name(param_id, func.parameters[i]->name); // TODO This is probably incorrect if the parameter is assigned to. variable_load_ids[func.parameters[i].get()] = param_id; } + reachable = true; writer.begin_function_body(next_id++); SetForScope set_func(current_function, &func); func.body.visit(*this); - if(writer.has_current_block()) + if(writer.get_current_block()) { if(!reachable) writer.write_op(content.function_body, OP_UNREACHABLE); @@ -1847,9 +1949,11 @@ void SpirVGenerator::visit(Conditional &cond) writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none) writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id); + std::map saved_load_ids = variable_load_ids; + writer.write_op_label(true_label_id); cond.body.visit(*this); - if(writer.has_current_block()) + if(writer.get_current_block()) writer.write_op(content.function_body, OP_BRANCH, merge_block_id); bool reachable_if_true = reachable; @@ -1857,6 +1961,7 @@ void SpirVGenerator::visit(Conditional &cond) reachable = true; if(!cond.else_body.body.empty()) { + swap(saved_load_ids, variable_load_ids); writer.write_op_label(false_label_id); cond.else_body.visit(*this); reachable |= reachable_if_true; @@ -1871,7 +1976,9 @@ void SpirVGenerator::visit(Iteration &iter) if(iter.init_statement) iter.init_statement->visit(*this); - variable_load_ids.clear(); + for(Node *n: AssignmentCollector().apply(iter)) + if(VariableDeclaration *var = dynamic_cast(n)) + variable_load_ids.erase(var); Id header_id = next_id++; Id continue_id = next_id++;