tint/writer: Replace scope_stack_, fix type ctor scoping.
ScopeStack is not needed here - the resolver already provides variable scoping with the sem::Variables.
Re-purpose scope_stack_ for a stack of Scope, which now holds the type constructor -> SPIR-V ID map.
This map needs to be per-scope, to fix issues like crbug.com/tint/1520
Fixed: tint:1520
Change-Id: Ifa7749338abf63652a1369e76cf5400be1c37298
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/88301
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index cf98b5d..5bc2686 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -245,7 +245,7 @@
Builder::Builder(const Program* program, bool zero_initialize_workgroup_memory)
: builder_(ProgramBuilder::Wrap(program)),
- scope_stack_({}),
+ scope_stack_{Scope{}},
zero_initialize_workgroup_memory_(zero_initialize_workgroup_memory) {}
Builder::~Builder() = default;
@@ -279,6 +279,30 @@
return true;
}
+void Builder::RegisterVariable(const sem::Variable* var, uint32_t id) {
+ var_to_id_.emplace(var, id);
+ id_to_var_.emplace(id, var);
+}
+
+uint32_t Builder::LookupVariableID(const sem::Variable* var) {
+ auto it = var_to_id_.find(var);
+ if (it == var_to_id_.end()) {
+ error_ = "unable to find ID for variable: " +
+ builder_.Symbols().NameFor(var->Declaration()->symbol);
+ return 0;
+ }
+ return it->second;
+}
+
+void Builder::PushScope() {
+ // Push a new scope, by copying the top-most stack
+ scope_stack_.push_back(scope_stack_.back());
+}
+
+void Builder::PopScope() {
+ scope_stack_.pop_back();
+}
+
Operand Builder::result_op() {
return Operand::Int(next_id());
}
@@ -441,7 +465,7 @@
continue;
}
- uint32_t var_id = scope_stack_.Get(var->Declaration()->symbol);
+ uint32_t var_id = LookupVariableID(var);
if (var_id == 0) {
error_ = "unable to find ID for global variable: " +
builder_.Symbols().NameFor(var->Declaration()->symbol);
@@ -588,8 +612,8 @@
return false;
}
- scope_stack_.Push();
- TINT_DEFER(scope_stack_.Pop());
+ PushScope();
+ TINT_DEFER(PopScope());
auto definition_inst = Instruction{
spv::Op::OpFunction,
@@ -612,7 +636,7 @@
params.push_back(Instruction{spv::Op::OpFunctionParameter,
{Operand::Int(param_type_id), param_op}});
- scope_stack_.Set(param->Declaration()->symbol, param_id);
+ RegisterVariable(param, param_id);
}
push_function(Function{definition_inst, result_op(), std::move(params)});
@@ -680,20 +704,21 @@
}
}
+ auto* sem = builder_.Sem().Get(var);
+
if (var->is_const) {
if (!var->constructor) {
error_ = "missing constructor for constant";
return false;
}
- scope_stack_.Set(var->symbol, init_id);
- spirv_id_to_variable_[init_id] = var;
+ RegisterVariable(sem, init_id);
return true;
}
auto result = result_op();
auto var_id = result.to_i();
auto sc = ast::StorageClass::kFunction;
- auto* type = builder_.Sem().Get(var)->Type();
+ auto* type = sem->Type();
auto type_id = GenerateTypeIfNeeded(type);
if (type_id == 0) {
return false;
@@ -719,8 +744,7 @@
}
}
- scope_stack_.Set(var->symbol, var_id);
- spirv_id_to_variable_[var_id] = var;
+ RegisterVariable(sem, var_id);
return true;
}
@@ -775,8 +799,7 @@
{Operand::Int(init_id),
Operand::String(builder_.Symbols().NameFor(var->symbol))});
- scope_stack_.Set(var->symbol, init_id);
- spirv_id_to_variable_[init_id] = var;
+ RegisterVariable(sem, init_id);
return true;
}
@@ -898,8 +921,7 @@
}
}
- scope_stack_.Set(var->symbol, var_id);
- spirv_id_to_variable_[var_id] = var;
+ RegisterVariable(sem, var_id);
return true;
}
@@ -1174,12 +1196,13 @@
uint32_t Builder::GenerateIdentifierExpression(
const ast::IdentifierExpression* expr) {
- uint32_t val = scope_stack_.Get(expr->symbol);
- if (val == 0) {
- error_ = "unable to find variable with identifier: " +
- builder_.Symbols().NameFor(expr->symbol);
+ auto* sem = builder_.Sem().Get(expr);
+ if (auto* user = sem->As<sem::VariableUser>()) {
+ return LookupVariableID(user->Variable());
}
- return val;
+ error_ = "identifier '" + builder_.Symbols().NameFor(expr->symbol) +
+ "' does not resolve to a variable";
+ return 0;
}
uint32_t Builder::GenerateExpressionWithLoadIfNeeded(
@@ -1479,8 +1502,12 @@
}
}
+ auto& stack = (result_is_spec_composite || result_is_constant_composite)
+ ? scope_stack_[0] // Global scope
+ : scope_stack_.back(); // Lexical scope
+
return utils::GetOrCreate(
- type_constructor_to_id_, OperandListKey{ops}, [&]() -> uint32_t {
+ stack.type_ctor_to_id_, OperandListKey{ops}, [&]() -> uint32_t {
auto result = result_op();
ops[kOpsResultIdx] = result;
@@ -2193,8 +2220,8 @@
}
bool Builder::GenerateBlockStatement(const ast::BlockStatement* stmt) {
- scope_stack_.Push();
- TINT_DEFER(scope_stack_.Pop());
+ PushScope();
+ TINT_DEFER(PopScope());
return GenerateBlockStatementWithoutScoping(stmt);
}
@@ -3653,8 +3680,8 @@
// We need variables from the body to be visible in the continuing block, so
// manage scope outside of GenerateBlockStatement.
{
- scope_stack_.Push();
- TINT_DEFER(scope_stack_.Pop());
+ PushScope();
+ TINT_DEFER(PopScope());
if (!GenerateBlockStatementWithoutScoping(stmt->body)) {
return false;
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index cf07e27..cb3ba30 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -584,6 +584,22 @@
uint32_t GenerateConstantVectorSplatIfNeeded(const sem::Vector* type,
uint32_t value_id);
+ /// Registers the semantic variable to the given SPIR-V ID
+ /// @param var the semantic variable
+ /// @param id the generated SPIR-V identifier for the variable
+ void RegisterVariable(const sem::Variable* var, uint32_t id);
+
+ /// Looks up the SPIR-V ID for the variable, which must have been registered
+ /// with a call to RegisterVariable()
+ /// @returns the SPIR-V ID, or 0 if the variable was not found
+ uint32_t LookupVariableID(const sem::Variable* var);
+
+ /// Pushes a new scope
+ void PushScope();
+
+ /// Pops the top-most scope
+ void PopScope();
+
ProgramBuilder builder_;
std::string error_;
uint32_t next_id_ = 1;
@@ -599,18 +615,23 @@
InstructionList annotations_;
std::vector<Function> functions_;
+ // Scope holds per-block information
+ struct Scope {
+ std::unordered_map<OperandListKey, uint32_t> type_ctor_to_id_;
+ };
+
+ std::unordered_map<const sem::Variable*, uint32_t> var_to_id_;
+ std::unordered_map<uint32_t, const sem::Variable*> id_to_var_;
std::unordered_map<std::string, uint32_t> import_name_to_id_;
std::unordered_map<Symbol, uint32_t> func_symbol_to_id_;
std::unordered_map<sem::CallTargetSignature, uint32_t> func_sig_to_id_;
std::unordered_map<const sem::Type*, uint32_t> type_to_id_;
std::unordered_map<ScalarConstant, uint32_t> const_to_id_;
- std::unordered_map<OperandListKey, uint32_t> type_constructor_to_id_;
std::unordered_map<const sem::Type*, uint32_t> const_null_to_id_;
std::unordered_map<uint64_t, uint32_t> const_splat_to_id_;
std::unordered_map<const sem::Type*, uint32_t>
texture_type_to_sampled_image_type_id_;
- ScopeStack<uint32_t> scope_stack_;
- std::unordered_map<uint32_t, const ast::Variable*> spirv_id_to_variable_;
+ std::vector<Scope> scope_stack_;
std::vector<uint32_t> merge_stack_;
std::vector<uint32_t> continue_stack_;
std::unordered_set<uint32_t> capability_set_;
diff --git a/src/tint/writer/spirv/builder_constructor_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
index 495f1c4..ae56e5d 100644
--- a/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -1850,5 +1850,99 @@
EXPECT_FALSE(b.has_error());
}
+TEST_F(SpvBuilderConstructorTest, ConstantCompositeScoping) {
+ // if (true) {
+ // let x = vec3<f32>(1.0, 2.0, 3.0);
+ // }
+ // let y = vec3<f32>(1.0, 2.0, 3.0); // Reuses the ID 'x'
+
+ WrapInFunction(
+ If(true, Block(Decl(Let("x", nullptr, vec3<f32>(1.f, 2.f, 3.f))))),
+ Decl(Let("y", nullptr, vec3<f32>(1.f, 2.f, 3.f))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeBool
+%6 = OpConstantTrue %5
+%10 = OpTypeFloat 32
+%9 = OpTypeVector %10 3
+%11 = OpConstant %10 1
+%12 = OpConstant %10 2
+%13 = OpConstant %10 3
+%14 = OpConstantComposite %9 %11 %12 %13
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+OpSelectionMerge %7 None
+OpBranchConditional %6 %8 %7
+%8 = OpLabel
+OpBranch %7
+%7 = OpLabel
+OpReturn
+OpFunctionEnd
+)");
+ Validate(b);
+}
+
+// TODO(crbug.com/tint/1155) Implement when overrides are fully implemented.
+// TEST_F(SpvBuilderConstructorTest, SpecConstantCompositeScoping)
+
+TEST_F(SpvBuilderConstructorTest, CompositeConstructScoping) {
+ // var one = 1.0;
+ // if (true) {
+ // let x = vec3<f32>(one, 2.0, 3.0);
+ // }
+ // let y = vec3<f32>(one, 2.0, 3.0); // Mustn't reuse the ID 'x'
+
+ WrapInFunction(
+ Decl(Var("one", nullptr, Expr(1.f))),
+ If(true, Block(Decl(Let("x", nullptr, vec3<f32>("one", 2.f, 3.f))))),
+ Decl(Let("y", nullptr, vec3<f32>("one", 2.f, 3.f))));
+
+ spirv::Builder& b = SanitizeAndBuild();
+ ASSERT_TRUE(b.Build());
+
+ EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %7 "one"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%10 = OpTypeBool
+%11 = OpConstantTrue %10
+%14 = OpTypeVector %5 3
+%16 = OpConstant %5 2
+%17 = OpConstant %5 3
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+OpSelectionMerge %12 None
+OpBranchConditional %11 %13 %12
+%13 = OpLabel
+%15 = OpLoad %5 %7
+%18 = OpCompositeConstruct %14 %15 %16 %17
+OpBranch %12
+%12 = OpLabel
+%19 = OpLoad %5 %7
+%20 = OpCompositeConstruct %14 %19 %16 %17
+OpReturn
+OpFunctionEnd
+)");
+ Validate(b);
+}
} // namespace
} // namespace tint::writer::spirv
diff --git a/test/tint/bug/tint/1520.spvasm b/test/tint/bug/tint/1520.spvasm
new file mode 100644
index 0000000..a9071c2
--- /dev/null
+++ b/test/tint/bug/tint/1520.spvasm
@@ -0,0 +1,248 @@
+OpCapability Shader
+%1 = OpExtInstImport "GLSL.std.450"
+OpMemoryModel Logical GLSL450
+OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise %vcolor_S0
+OpExecutionMode %main OriginUpperLeft
+OpName %UniformBuffer "UniformBuffer"
+OpMemberName %UniformBuffer 0 "unknownInput_S1_c0"
+OpMemberName %UniformBuffer 1 "ucolorRed_S1_c0"
+OpMemberName %UniformBuffer 2 "ucolorGreen_S1_c0"
+OpMemberName %UniformBuffer 3 "umatrix_S1"
+OpName %sk_FragColor "sk_FragColor"
+OpName %sk_Clockwise "sk_Clockwise"
+OpName %vcolor_S0 "vcolor_S0"
+OpName %test_int_S1_c0_b "test_int_S1_c0_b"
+OpName %unknown "unknown"
+OpName %ok "ok"
+OpName %val "val"
+OpName %main "main"
+OpName %outputColor_S0 "outputColor_S0"
+OpName %output_S1 "output_S1"
+OpName %_8_unknown "_8_unknown"
+OpName %_9_ok "_9_ok"
+OpName %_10_val "_10_val"
+OpMemberDecorate %UniformBuffer 0 Offset 16
+OpMemberDecorate %UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %UniformBuffer 1 Offset 32
+OpMemberDecorate %UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %UniformBuffer 2 Offset 48
+OpMemberDecorate %UniformBuffer 2 RelaxedPrecision
+OpMemberDecorate %UniformBuffer 3 Offset 64
+OpMemberDecorate %UniformBuffer 3 ColMajor
+OpMemberDecorate %UniformBuffer 3 MatrixStride 16
+OpDecorate %UniformBuffer Block
+OpDecorate %4 Binding 0
+OpDecorate %4 DescriptorSet 0
+OpDecorate %sk_FragColor RelaxedPrecision
+OpDecorate %sk_FragColor Location 0
+OpDecorate %sk_FragColor Index 0
+OpDecorate %sk_Clockwise BuiltIn FrontFacing
+OpDecorate %vcolor_S0 RelaxedPrecision
+OpDecorate %vcolor_S0 Location 0
+OpDecorate %26 RelaxedPrecision
+OpDecorate %outputColor_S0 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %output_S1 RelaxedPrecision
+OpDecorate %_8_unknown RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %83 RelaxedPrecision
+OpDecorate %84 RelaxedPrecision
+OpDecorate %_10_val RelaxedPrecision
+OpDecorate %89 RelaxedPrecision
+OpDecorate %92 RelaxedPrecision
+OpDecorate %93 RelaxedPrecision
+OpDecorate %94 RelaxedPrecision
+OpDecorate %95 RelaxedPrecision
+OpDecorate %103 RelaxedPrecision
+OpDecorate %104 RelaxedPrecision
+OpDecorate %105 RelaxedPrecision
+OpDecorate %106 RelaxedPrecision
+OpDecorate %122 RelaxedPrecision
+OpDecorate %124 RelaxedPrecision
+OpDecorate %125 RelaxedPrecision
+%float = OpTypeFloat 32
+%v4float = OpTypeVector %float 4
+%v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%UniformBuffer = OpTypeStruct %float %v4float %v4float %mat3v3float
+%_ptr_Uniform_UniformBuffer = OpTypePointer Uniform %UniformBuffer
+%4 = OpVariable %_ptr_Uniform_UniformBuffer Uniform
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+%sk_FragColor = OpVariable %_ptr_Output_v4float Output
+%bool = OpTypeBool
+%_ptr_Input_bool = OpTypePointer Input %bool
+%sk_Clockwise = OpVariable %_ptr_Input_bool Input
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%vcolor_S0 = OpVariable %_ptr_Input_v4float Input
+%18 = OpTypeFunction %bool
+%int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+%int_0 = OpConstant %int 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+%_ptr_Function_bool = OpTypePointer Function %bool
+%true = OpConstantTrue %bool
+%false = OpConstantFalse %bool
+%v4int = OpTypeVector %int 4
+%35 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
+%v4bool = OpTypeVector %bool 4
+%_ptr_Function_v4int = OpTypePointer Function %v4int
+%int_1 = OpConstant %int 1
+%46 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+%int_2 = OpConstant %int 2
+%57 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
+%void = OpTypeVoid
+%68 = OpTypeFunction %void
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Function_float = OpTypePointer Function %float
+%float_0 = OpConstant %float 0
+%82 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%float_1 = OpConstant %float 1
+%91 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+%float_2 = OpConstant %float 2
+%102 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+%test_int_S1_c0_b = OpFunction %bool None %18
+%19 = OpLabel
+%unknown = OpVariable %_ptr_Function_int Function
+%ok = OpVariable %_ptr_Function_bool Function
+%val = OpVariable %_ptr_Function_v4int Function
+%24 = OpAccessChain %_ptr_Uniform_float %4 %int_0
+%26 = OpLoad %float %24
+%27 = OpConvertFToS %int %26
+OpStore %unknown %27
+OpStore %ok %true
+OpSelectionMerge %33 None
+OpBranchConditional %true %32 %33
+%32 = OpLabel
+%36 = OpCompositeConstruct %v4int %27 %27 %27 %27
+%37 = OpSDiv %v4int %35 %36
+%38 = OpIEqual %v4bool %37 %35
+%40 = OpAll %bool %38
+OpBranch %33
+%33 = OpLabel
+%41 = OpPhi %bool %false %19 %40 %32
+OpStore %ok %41
+%44 = OpCompositeConstruct %v4int %27 %27 %27 %27
+OpStore %val %44
+%47 = OpIAdd %v4int %44 %46
+OpStore %val %47
+%48 = OpISub %v4int %47 %46
+OpStore %val %48
+%49 = OpIAdd %v4int %48 %46
+OpStore %val %49
+%50 = OpISub %v4int %49 %46
+OpStore %val %50
+OpSelectionMerge %52 None
+OpBranchConditional %41 %51 %52
+%51 = OpLabel
+%53 = OpIEqual %v4bool %50 %44
+%54 = OpAll %bool %53
+OpBranch %52
+%52 = OpLabel
+%55 = OpPhi %bool %false %33 %54 %51
+OpStore %ok %55
+%58 = OpIMul %v4int %50 %57
+OpStore %val %58
+%59 = OpSDiv %v4int %58 %57
+OpStore %val %59
+%60 = OpIMul %v4int %59 %57
+OpStore %val %60
+%61 = OpSDiv %v4int %60 %57
+OpStore %val %61
+OpSelectionMerge %63 None
+OpBranchConditional %55 %62 %63
+%62 = OpLabel
+%64 = OpIEqual %v4bool %61 %44
+%65 = OpAll %bool %64
+OpBranch %63
+%63 = OpLabel
+%66 = OpPhi %bool %false %52 %65 %62
+OpStore %ok %66
+OpReturnValue %66
+OpFunctionEnd
+%main = OpFunction %void None %68
+%69 = OpLabel
+%outputColor_S0 = OpVariable %_ptr_Function_v4float Function
+%output_S1 = OpVariable %_ptr_Function_v4float Function
+%_8_unknown = OpVariable %_ptr_Function_float Function
+%_9_ok = OpVariable %_ptr_Function_bool Function
+%_10_val = OpVariable %_ptr_Function_v4float Function
+%116 = OpVariable %_ptr_Function_v4float Function
+%72 = OpLoad %v4float %vcolor_S0
+OpStore %outputColor_S0 %72
+%76 = OpAccessChain %_ptr_Uniform_float %4 %int_0
+%77 = OpLoad %float %76
+OpStore %_8_unknown %77
+OpStore %_9_ok %true
+OpSelectionMerge %80 None
+OpBranchConditional %true %79 %80
+%79 = OpLabel
+%83 = OpCompositeConstruct %v4float %77 %77 %77 %77
+%84 = OpFDiv %v4float %82 %83
+%85 = OpFOrdEqual %v4bool %84 %82
+%86 = OpAll %bool %85
+OpBranch %80
+%80 = OpLabel
+%87 = OpPhi %bool %false %69 %86 %79
+OpStore %_9_ok %87
+%89 = OpCompositeConstruct %v4float %77 %77 %77 %77
+OpStore %_10_val %89
+%92 = OpFAdd %v4float %89 %91
+OpStore %_10_val %92
+%93 = OpFSub %v4float %92 %91
+OpStore %_10_val %93
+%94 = OpFAdd %v4float %93 %91
+OpStore %_10_val %94
+%95 = OpFSub %v4float %94 %91
+OpStore %_10_val %95
+OpSelectionMerge %97 None
+OpBranchConditional %87 %96 %97
+%96 = OpLabel
+%98 = OpFOrdEqual %v4bool %95 %89
+%99 = OpAll %bool %98
+OpBranch %97
+%97 = OpLabel
+%100 = OpPhi %bool %false %80 %99 %96
+OpStore %_9_ok %100
+%103 = OpFMul %v4float %95 %102
+OpStore %_10_val %103
+%104 = OpFDiv %v4float %103 %102
+OpStore %_10_val %104
+%105 = OpFMul %v4float %104 %102
+OpStore %_10_val %105
+%106 = OpFDiv %v4float %105 %102
+OpStore %_10_val %106
+OpSelectionMerge %108 None
+OpBranchConditional %100 %107 %108
+%107 = OpLabel
+%109 = OpFOrdEqual %v4bool %106 %89
+%110 = OpAll %bool %109
+OpBranch %108
+%108 = OpLabel
+%111 = OpPhi %bool %false %97 %110 %107
+OpStore %_9_ok %111
+OpSelectionMerge %113 None
+OpBranchConditional %111 %112 %113
+%112 = OpLabel
+%114 = OpFunctionCall %bool %test_int_S1_c0_b
+OpBranch %113
+%113 = OpLabel
+%115 = OpPhi %bool %false %108 %114 %112
+OpSelectionMerge %119 None
+OpBranchConditional %115 %117 %118
+%117 = OpLabel
+%120 = OpAccessChain %_ptr_Uniform_v4float %4 %int_2
+%122 = OpLoad %v4float %120
+OpStore %116 %122
+OpBranch %119
+%118 = OpLabel
+%123 = OpAccessChain %_ptr_Uniform_v4float %4 %int_1
+%124 = OpLoad %v4float %123
+OpStore %116 %124
+OpBranch %119
+%119 = OpLabel
+%125 = OpLoad %v4float %116
+OpStore %output_S1 %125
+OpStore %sk_FragColor %125
+OpReturn
+OpFunctionEnd
diff --git a/test/tint/bug/tint/1520.spvasm.expected.glsl b/test/tint/bug/tint/1520.spvasm.expected.glsl
new file mode 100644
index 0000000..358bd77
--- /dev/null
+++ b/test/tint/bug/tint/1520.spvasm.expected.glsl
@@ -0,0 +1,171 @@
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in vec4 vcolor_S0_param_1;
+layout(location = 0) out vec4 sk_FragColor_1_1;
+struct UniformBuffer {
+ float unknownInput_S1_c0;
+ vec4 ucolorRed_S1_c0;
+ vec4 ucolorGreen_S1_c0;
+ mat3 umatrix_S1;
+};
+
+layout(binding = 0) uniform UniformBuffer_1 {
+ float unknownInput_S1_c0;
+ vec4 ucolorRed_S1_c0;
+ vec4 ucolorGreen_S1_c0;
+ mat3 umatrix_S1;
+} x_4;
+
+vec4 sk_FragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+bool sk_Clockwise = false;
+vec4 vcolor_S0 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+bool test_int_S1_c0_b() {
+ int unknown = 0;
+ bool ok = false;
+ ivec4 val = ivec4(0, 0, 0, 0);
+ bool x_40 = false;
+ bool x_54 = false;
+ bool x_65 = false;
+ bool x_41_phi = false;
+ bool x_55_phi = false;
+ bool x_66_phi = false;
+ float x_26 = x_4.unknownInput_S1_c0;
+ int x_27 = int(x_26);
+ unknown = x_27;
+ ok = true;
+ x_41_phi = false;
+ if (true) {
+ x_40 = all(equal((ivec4(0, 0, 0, 0) / ivec4(x_27, x_27, x_27, x_27)), ivec4(0, 0, 0, 0)));
+ x_41_phi = x_40;
+ }
+ bool x_41 = x_41_phi;
+ ok = x_41;
+ ivec4 x_44 = ivec4(x_27, x_27, x_27, x_27);
+ val = x_44;
+ ivec4 x_47 = (x_44 + ivec4(1, 1, 1, 1));
+ val = x_47;
+ ivec4 x_48 = (x_47 - ivec4(1, 1, 1, 1));
+ val = x_48;
+ ivec4 x_49 = (x_48 + ivec4(1, 1, 1, 1));
+ val = x_49;
+ ivec4 x_50 = (x_49 - ivec4(1, 1, 1, 1));
+ val = x_50;
+ x_55_phi = false;
+ if (x_41) {
+ x_54 = all(equal(x_50, x_44));
+ x_55_phi = x_54;
+ }
+ bool x_55 = x_55_phi;
+ ok = x_55;
+ ivec4 x_58 = (x_50 * ivec4(2, 2, 2, 2));
+ val = x_58;
+ ivec4 x_59 = (x_58 / ivec4(2, 2, 2, 2));
+ val = x_59;
+ ivec4 x_60 = (x_59 * ivec4(2, 2, 2, 2));
+ val = x_60;
+ ivec4 x_61 = (x_60 / ivec4(2, 2, 2, 2));
+ val = x_61;
+ x_66_phi = false;
+ if (x_55) {
+ x_65 = all(equal(x_61, x_44));
+ x_66_phi = x_65;
+ }
+ bool x_66 = x_66_phi;
+ ok = x_66;
+ return x_66;
+}
+
+void main_1() {
+ vec4 outputColor_S0 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ vec4 output_S1 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ float x_8_unknown = 0.0f;
+ bool x_9_ok = false;
+ vec4 x_10_val = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ vec4 x_116 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
+ bool x_86 = false;
+ bool x_99 = false;
+ bool x_110 = false;
+ bool x_114 = false;
+ bool x_87_phi = false;
+ bool x_100_phi = false;
+ bool x_111_phi = false;
+ bool x_115_phi = false;
+ outputColor_S0 = vcolor_S0;
+ float x_77 = x_4.unknownInput_S1_c0;
+ x_8_unknown = x_77;
+ x_9_ok = true;
+ x_87_phi = false;
+ if (true) {
+ x_86 = all(equal((vec4(0.0f, 0.0f, 0.0f, 0.0f) / vec4(x_77, x_77, x_77, x_77)), vec4(0.0f, 0.0f, 0.0f, 0.0f)));
+ x_87_phi = x_86;
+ }
+ bool x_87 = x_87_phi;
+ x_9_ok = x_87;
+ vec4 x_89 = vec4(x_77, x_77, x_77, x_77);
+ x_10_val = x_89;
+ vec4 x_92 = (x_89 + vec4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_92;
+ vec4 x_93 = (x_92 - vec4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_93;
+ vec4 x_94 = (x_93 + vec4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_94;
+ vec4 x_95 = (x_94 - vec4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_95;
+ x_100_phi = false;
+ if (x_87) {
+ x_99 = all(equal(x_95, x_89));
+ x_100_phi = x_99;
+ }
+ bool x_100 = x_100_phi;
+ x_9_ok = x_100;
+ vec4 x_103 = (x_95 * vec4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_103;
+ vec4 x_104 = (x_103 / vec4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_104;
+ vec4 x_105 = (x_104 * vec4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_105;
+ vec4 x_106 = (x_105 / vec4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_106;
+ x_111_phi = false;
+ if (x_100) {
+ x_110 = all(equal(x_106, x_89));
+ x_111_phi = x_110;
+ }
+ bool x_111 = x_111_phi;
+ x_9_ok = x_111;
+ x_115_phi = false;
+ if (x_111) {
+ x_114 = test_int_S1_c0_b();
+ x_115_phi = x_114;
+ }
+ if (x_115_phi) {
+ vec4 x_122 = x_4.ucolorGreen_S1_c0;
+ x_116 = x_122;
+ } else {
+ vec4 x_124 = x_4.ucolorRed_S1_c0;
+ x_116 = x_124;
+ }
+ vec4 x_125 = x_116;
+ output_S1 = x_125;
+ sk_FragColor = x_125;
+ return;
+}
+
+struct main_out {
+ vec4 sk_FragColor_1;
+};
+
+main_out tint_symbol(bool sk_Clockwise_param, vec4 vcolor_S0_param) {
+ sk_Clockwise = sk_Clockwise_param;
+ vcolor_S0 = vcolor_S0_param;
+ main_1();
+ main_out tint_symbol_1 = main_out(sk_FragColor);
+ return tint_symbol_1;
+}
+
+void main() {
+ main_out inner_result = tint_symbol(gl_FrontFacing, vcolor_S0_param_1);
+ sk_FragColor_1_1 = inner_result.sk_FragColor_1;
+ return;
+}
diff --git a/test/tint/bug/tint/1520.spvasm.expected.hlsl b/test/tint/bug/tint/1520.spvasm.expected.hlsl
new file mode 100644
index 0000000..052cd99
--- /dev/null
+++ b/test/tint/bug/tint/1520.spvasm.expected.hlsl
@@ -0,0 +1,168 @@
+int4 value_or_one_if_zero_int4(int4 value) {
+ return value == int4(0, 0, 0, 0) ? int4(1, 1, 1, 1) : value;
+}
+
+cbuffer cbuffer_x_4 : register(b0, space0) {
+ uint4 x_4[7];
+};
+static float4 sk_FragColor = float4(0.0f, 0.0f, 0.0f, 0.0f);
+static bool sk_Clockwise = false;
+static float4 vcolor_S0 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+bool test_int_S1_c0_b() {
+ int unknown = 0;
+ bool ok = false;
+ int4 val = int4(0, 0, 0, 0);
+ bool x_40 = false;
+ bool x_54 = false;
+ bool x_65 = false;
+ bool x_41_phi = false;
+ bool x_55_phi = false;
+ bool x_66_phi = false;
+ const float x_26 = asfloat(x_4[1].x);
+ const int x_27 = int(x_26);
+ unknown = x_27;
+ ok = true;
+ x_41_phi = false;
+ if (true) {
+ x_40 = all(((int4(0, 0, 0, 0) / value_or_one_if_zero_int4(int4(x_27, x_27, x_27, x_27))) == int4(0, 0, 0, 0)));
+ x_41_phi = x_40;
+ }
+ const bool x_41 = x_41_phi;
+ ok = x_41;
+ const int4 x_44 = int4(x_27, x_27, x_27, x_27);
+ val = x_44;
+ const int4 x_47 = (x_44 + int4(1, 1, 1, 1));
+ val = x_47;
+ const int4 x_48 = (x_47 - int4(1, 1, 1, 1));
+ val = x_48;
+ const int4 x_49 = (x_48 + int4(1, 1, 1, 1));
+ val = x_49;
+ const int4 x_50 = (x_49 - int4(1, 1, 1, 1));
+ val = x_50;
+ x_55_phi = false;
+ if (x_41) {
+ x_54 = all((x_50 == x_44));
+ x_55_phi = x_54;
+ }
+ const bool x_55 = x_55_phi;
+ ok = x_55;
+ const int4 x_58 = (x_50 * int4(2, 2, 2, 2));
+ val = x_58;
+ const int4 x_59 = (x_58 / int4(2, 2, 2, 2));
+ val = x_59;
+ const int4 x_60 = (x_59 * int4(2, 2, 2, 2));
+ val = x_60;
+ const int4 x_61 = (x_60 / int4(2, 2, 2, 2));
+ val = x_61;
+ x_66_phi = false;
+ if (x_55) {
+ x_65 = all((x_61 == x_44));
+ x_66_phi = x_65;
+ }
+ const bool x_66 = x_66_phi;
+ ok = x_66;
+ return x_66;
+}
+
+void main_1() {
+ float4 outputColor_S0 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 output_S1 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float x_8_unknown = 0.0f;
+ bool x_9_ok = false;
+ float4 x_10_val = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 x_116 = float4(0.0f, 0.0f, 0.0f, 0.0f);
+ bool x_86 = false;
+ bool x_99 = false;
+ bool x_110 = false;
+ bool x_114 = false;
+ bool x_87_phi = false;
+ bool x_100_phi = false;
+ bool x_111_phi = false;
+ bool x_115_phi = false;
+ outputColor_S0 = vcolor_S0;
+ const float x_77 = asfloat(x_4[1].x);
+ x_8_unknown = x_77;
+ x_9_ok = true;
+ x_87_phi = false;
+ if (true) {
+ x_86 = all(((float4(0.0f, 0.0f, 0.0f, 0.0f) / float4(x_77, x_77, x_77, x_77)) == float4(0.0f, 0.0f, 0.0f, 0.0f)));
+ x_87_phi = x_86;
+ }
+ const bool x_87 = x_87_phi;
+ x_9_ok = x_87;
+ const float4 x_89 = float4(x_77, x_77, x_77, x_77);
+ x_10_val = x_89;
+ const float4 x_92 = (x_89 + float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_92;
+ const float4 x_93 = (x_92 - float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_93;
+ const float4 x_94 = (x_93 + float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_94;
+ const float4 x_95 = (x_94 - float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_95;
+ x_100_phi = false;
+ if (x_87) {
+ x_99 = all((x_95 == x_89));
+ x_100_phi = x_99;
+ }
+ const bool x_100 = x_100_phi;
+ x_9_ok = x_100;
+ const float4 x_103 = (x_95 * float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_103;
+ const float4 x_104 = (x_103 / float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_104;
+ const float4 x_105 = (x_104 * float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_105;
+ const float4 x_106 = (x_105 / float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_106;
+ x_111_phi = false;
+ if (x_100) {
+ x_110 = all((x_106 == x_89));
+ x_111_phi = x_110;
+ }
+ const bool x_111 = x_111_phi;
+ x_9_ok = x_111;
+ x_115_phi = false;
+ if (x_111) {
+ x_114 = test_int_S1_c0_b();
+ x_115_phi = x_114;
+ }
+ if (x_115_phi) {
+ const float4 x_122 = asfloat(x_4[3]);
+ x_116 = x_122;
+ } else {
+ const float4 x_124 = asfloat(x_4[2]);
+ x_116 = x_124;
+ }
+ const float4 x_125 = x_116;
+ output_S1 = x_125;
+ sk_FragColor = x_125;
+ return;
+}
+
+struct main_out {
+ float4 sk_FragColor_1;
+};
+struct tint_symbol_1 {
+ float4 vcolor_S0_param : TEXCOORD0;
+ bool sk_Clockwise_param : SV_IsFrontFace;
+};
+struct tint_symbol_2 {
+ float4 sk_FragColor_1 : SV_Target0;
+};
+
+main_out main_inner(bool sk_Clockwise_param, float4 vcolor_S0_param) {
+ sk_Clockwise = sk_Clockwise_param;
+ vcolor_S0 = vcolor_S0_param;
+ main_1();
+ const main_out tint_symbol_5 = {sk_FragColor};
+ return tint_symbol_5;
+}
+
+tint_symbol_2 main(tint_symbol_1 tint_symbol) {
+ const main_out inner_result = main_inner(tint_symbol.sk_Clockwise_param, tint_symbol.vcolor_S0_param);
+ tint_symbol_2 wrapper_result = (tint_symbol_2)0;
+ wrapper_result.sk_FragColor_1 = inner_result.sk_FragColor_1;
+ return wrapper_result;
+}
diff --git a/test/tint/bug/tint/1520.spvasm.expected.msl b/test/tint/bug/tint/1520.spvasm.expected.msl
new file mode 100644
index 0000000..3e2b30a
--- /dev/null
+++ b/test/tint/bug/tint/1520.spvasm.expected.msl
@@ -0,0 +1,176 @@
+#include <metal_stdlib>
+
+using namespace metal;
+struct UniformBuffer {
+ /* 0x0000 */ int8_t tint_pad[16];
+ /* 0x0010 */ float unknownInput_S1_c0;
+ /* 0x0014 */ int8_t tint_pad_1[12];
+ /* 0x0020 */ float4 ucolorRed_S1_c0;
+ /* 0x0030 */ float4 ucolorGreen_S1_c0;
+ /* 0x0040 */ float3x3 umatrix_S1;
+};
+
+bool test_int_S1_c0_b(const constant UniformBuffer* const tint_symbol_5) {
+ int unknown = 0;
+ bool ok = false;
+ int4 val = 0;
+ bool x_40 = false;
+ bool x_54 = false;
+ bool x_65 = false;
+ bool x_41_phi = false;
+ bool x_55_phi = false;
+ bool x_66_phi = false;
+ float const x_26 = (*(tint_symbol_5)).unknownInput_S1_c0;
+ int const x_27 = int(x_26);
+ unknown = x_27;
+ ok = true;
+ x_41_phi = false;
+ if (true) {
+ x_40 = all(((int4(0, 0, 0, 0) / int4(x_27, x_27, x_27, x_27)) == int4(0, 0, 0, 0)));
+ x_41_phi = x_40;
+ }
+ bool const x_41 = x_41_phi;
+ ok = x_41;
+ int4 const x_44 = int4(x_27, x_27, x_27, x_27);
+ val = x_44;
+ int4 const x_47 = as_type<int4>((as_type<uint4>(x_44) + as_type<uint4>(int4(1, 1, 1, 1))));
+ val = x_47;
+ int4 const x_48 = as_type<int4>((as_type<uint4>(x_47) - as_type<uint4>(int4(1, 1, 1, 1))));
+ val = x_48;
+ int4 const x_49 = as_type<int4>((as_type<uint4>(x_48) + as_type<uint4>(int4(1, 1, 1, 1))));
+ val = x_49;
+ int4 const x_50 = as_type<int4>((as_type<uint4>(x_49) - as_type<uint4>(int4(1, 1, 1, 1))));
+ val = x_50;
+ x_55_phi = false;
+ if (x_41) {
+ x_54 = all((x_50 == x_44));
+ x_55_phi = x_54;
+ }
+ bool const x_55 = x_55_phi;
+ ok = x_55;
+ int4 const x_58 = as_type<int4>((as_type<uint4>(x_50) * as_type<uint4>(int4(2, 2, 2, 2))));
+ val = x_58;
+ int4 const x_59 = (x_58 / int4(2, 2, 2, 2));
+ val = x_59;
+ int4 const x_60 = as_type<int4>((as_type<uint4>(x_59) * as_type<uint4>(int4(2, 2, 2, 2))));
+ val = x_60;
+ int4 const x_61 = (x_60 / int4(2, 2, 2, 2));
+ val = x_61;
+ x_66_phi = false;
+ if (x_55) {
+ x_65 = all((x_61 == x_44));
+ x_66_phi = x_65;
+ }
+ bool const x_66 = x_66_phi;
+ ok = x_66;
+ return x_66;
+}
+
+void main_1(thread float4* const tint_symbol_6, const constant UniformBuffer* const tint_symbol_7, thread float4* const tint_symbol_8) {
+ float4 outputColor_S0 = 0.0f;
+ float4 output_S1 = 0.0f;
+ float x_8_unknown = 0.0f;
+ bool x_9_ok = false;
+ float4 x_10_val = 0.0f;
+ float4 x_116 = 0.0f;
+ bool x_86 = false;
+ bool x_99 = false;
+ bool x_110 = false;
+ bool x_114 = false;
+ bool x_87_phi = false;
+ bool x_100_phi = false;
+ bool x_111_phi = false;
+ bool x_115_phi = false;
+ float4 const x_72 = *(tint_symbol_6);
+ outputColor_S0 = x_72;
+ float const x_77 = (*(tint_symbol_7)).unknownInput_S1_c0;
+ x_8_unknown = x_77;
+ x_9_ok = true;
+ x_87_phi = false;
+ if (true) {
+ x_86 = all(((float4(0.0f, 0.0f, 0.0f, 0.0f) / float4(x_77, x_77, x_77, x_77)) == float4(0.0f, 0.0f, 0.0f, 0.0f)));
+ x_87_phi = x_86;
+ }
+ bool const x_87 = x_87_phi;
+ x_9_ok = x_87;
+ float4 const x_89 = float4(x_77, x_77, x_77, x_77);
+ x_10_val = x_89;
+ float4 const x_92 = (x_89 + float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_92;
+ float4 const x_93 = (x_92 - float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_93;
+ float4 const x_94 = (x_93 + float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_94;
+ float4 const x_95 = (x_94 - float4(1.0f, 1.0f, 1.0f, 1.0f));
+ x_10_val = x_95;
+ x_100_phi = false;
+ if (x_87) {
+ x_99 = all((x_95 == x_89));
+ x_100_phi = x_99;
+ }
+ bool const x_100 = x_100_phi;
+ x_9_ok = x_100;
+ float4 const x_103 = (x_95 * float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_103;
+ float4 const x_104 = (x_103 / float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_104;
+ float4 const x_105 = (x_104 * float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_105;
+ float4 const x_106 = (x_105 / float4(2.0f, 2.0f, 2.0f, 2.0f));
+ x_10_val = x_106;
+ x_111_phi = false;
+ if (x_100) {
+ x_110 = all((x_106 == x_89));
+ x_111_phi = x_110;
+ }
+ bool const x_111 = x_111_phi;
+ x_9_ok = x_111;
+ x_115_phi = false;
+ if (x_111) {
+ x_114 = test_int_S1_c0_b(tint_symbol_7);
+ x_115_phi = x_114;
+ }
+ bool const x_115 = x_115_phi;
+ if (x_115) {
+ float4 const x_122 = (*(tint_symbol_7)).ucolorGreen_S1_c0;
+ x_116 = x_122;
+ } else {
+ float4 const x_124 = (*(tint_symbol_7)).ucolorRed_S1_c0;
+ x_116 = x_124;
+ }
+ float4 const x_125 = x_116;
+ output_S1 = x_125;
+ *(tint_symbol_8) = x_125;
+ return;
+}
+
+struct main_out {
+ float4 sk_FragColor_1;
+};
+
+struct tint_symbol_2 {
+ float4 vcolor_S0_param [[user(locn0)]];
+};
+
+struct tint_symbol_3 {
+ float4 sk_FragColor_1 [[color(0)]];
+};
+
+main_out tint_symbol_inner(bool sk_Clockwise_param, float4 vcolor_S0_param, thread bool* const tint_symbol_9, thread float4* const tint_symbol_10, const constant UniformBuffer* const tint_symbol_11, thread float4* const tint_symbol_12) {
+ *(tint_symbol_9) = sk_Clockwise_param;
+ *(tint_symbol_10) = vcolor_S0_param;
+ main_1(tint_symbol_10, tint_symbol_11, tint_symbol_12);
+ main_out const tint_symbol_4 = {.sk_FragColor_1=*(tint_symbol_12)};
+ return tint_symbol_4;
+}
+
+fragment tint_symbol_3 tint_symbol(const constant UniformBuffer* tint_symbol_15 [[buffer(0)]], bool sk_Clockwise_param [[front_facing]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ thread bool tint_symbol_13 = false;
+ thread float4 tint_symbol_14 = 0.0f;
+ thread float4 tint_symbol_16 = 0.0f;
+ main_out const inner_result = tint_symbol_inner(sk_Clockwise_param, tint_symbol_1.vcolor_S0_param, &(tint_symbol_13), &(tint_symbol_14), tint_symbol_15, &(tint_symbol_16));
+ tint_symbol_3 wrapper_result = {};
+ wrapper_result.sk_FragColor_1 = inner_result.sk_FragColor_1;
+ return wrapper_result;
+}
+
diff --git a/test/tint/bug/tint/1520.spvasm.expected.spvasm b/test/tint/bug/tint/1520.spvasm.expected.spvasm
new file mode 100644
index 0000000..ad91329
--- /dev/null
+++ b/test/tint/bug/tint/1520.spvasm.expected.spvasm
@@ -0,0 +1,330 @@
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 175
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %sk_Clockwise_param_1 %vcolor_S0_param_1 %sk_FragColor_1_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %sk_Clockwise_param_1 "sk_Clockwise_param_1"
+ OpName %vcolor_S0_param_1 "vcolor_S0_param_1"
+ OpName %sk_FragColor_1_1 "sk_FragColor_1_1"
+ OpName %UniformBuffer "UniformBuffer"
+ OpMemberName %UniformBuffer 0 "unknownInput_S1_c0"
+ OpMemberName %UniformBuffer 1 "ucolorRed_S1_c0"
+ OpMemberName %UniformBuffer 2 "ucolorGreen_S1_c0"
+ OpMemberName %UniformBuffer 3 "umatrix_S1"
+ OpName %x_4 "x_4"
+ OpName %sk_FragColor "sk_FragColor"
+ OpName %sk_Clockwise "sk_Clockwise"
+ OpName %vcolor_S0 "vcolor_S0"
+ OpName %test_int_S1_c0_b "test_int_S1_c0_b"
+ OpName %unknown "unknown"
+ OpName %ok "ok"
+ OpName %val "val"
+ OpName %x_40 "x_40"
+ OpName %x_54 "x_54"
+ OpName %x_65 "x_65"
+ OpName %x_41_phi "x_41_phi"
+ OpName %x_55_phi "x_55_phi"
+ OpName %x_66_phi "x_66_phi"
+ OpName %main_1 "main_1"
+ OpName %outputColor_S0 "outputColor_S0"
+ OpName %output_S1 "output_S1"
+ OpName %x_8_unknown "x_8_unknown"
+ OpName %x_9_ok "x_9_ok"
+ OpName %x_10_val "x_10_val"
+ OpName %x_116 "x_116"
+ OpName %x_86 "x_86"
+ OpName %x_99 "x_99"
+ OpName %x_110 "x_110"
+ OpName %x_114 "x_114"
+ OpName %x_87_phi "x_87_phi"
+ OpName %x_100_phi "x_100_phi"
+ OpName %x_111_phi "x_111_phi"
+ OpName %x_115_phi "x_115_phi"
+ OpName %main_out "main_out"
+ OpMemberName %main_out 0 "sk_FragColor_1"
+ OpName %main_inner "main_inner"
+ OpName %sk_Clockwise_param "sk_Clockwise_param"
+ OpName %vcolor_S0_param "vcolor_S0_param"
+ OpName %main "main"
+ OpDecorate %sk_Clockwise_param_1 BuiltIn FrontFacing
+ OpDecorate %vcolor_S0_param_1 Location 0
+ OpDecorate %sk_FragColor_1_1 Location 0
+ OpDecorate %UniformBuffer Block
+ OpMemberDecorate %UniformBuffer 0 Offset 16
+ OpMemberDecorate %UniformBuffer 1 Offset 32
+ OpMemberDecorate %UniformBuffer 2 Offset 48
+ OpMemberDecorate %UniformBuffer 3 Offset 64
+ OpMemberDecorate %UniformBuffer 3 ColMajor
+ OpMemberDecorate %UniformBuffer 3 MatrixStride 16
+ OpDecorate %x_4 NonWritable
+ OpDecorate %x_4 Binding 0
+ OpDecorate %x_4 DescriptorSet 0
+ OpMemberDecorate %main_out 0 Offset 0
+ %bool = OpTypeBool
+%_ptr_Input_bool = OpTypePointer Input %bool
+%sk_Clockwise_param_1 = OpVariable %_ptr_Input_bool Input
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_ptr_Input_v4float = OpTypePointer Input %v4float
+%vcolor_S0_param_1 = OpVariable %_ptr_Input_v4float Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+ %10 = OpConstantNull %v4float
+%sk_FragColor_1_1 = OpVariable %_ptr_Output_v4float Output %10
+ %v3float = OpTypeVector %float 3
+%mat3v3float = OpTypeMatrix %v3float 3
+%UniformBuffer = OpTypeStruct %float %v4float %v4float %mat3v3float
+%_ptr_Uniform_UniformBuffer = OpTypePointer Uniform %UniformBuffer
+ %x_4 = OpVariable %_ptr_Uniform_UniformBuffer Uniform
+%_ptr_Private_v4float = OpTypePointer Private %v4float
+%sk_FragColor = OpVariable %_ptr_Private_v4float Private %10
+%_ptr_Private_bool = OpTypePointer Private %bool
+ %20 = OpConstantNull %bool
+%sk_Clockwise = OpVariable %_ptr_Private_bool Private %20
+ %vcolor_S0 = OpVariable %_ptr_Private_v4float Private %10
+ %22 = OpTypeFunction %bool
+ %int = OpTypeInt 32 1
+%_ptr_Function_int = OpTypePointer Function %int
+ %28 = OpConstantNull %int
+%_ptr_Function_bool = OpTypePointer Function %bool
+ %v4int = OpTypeVector %int 4
+%_ptr_Function_v4int = OpTypePointer Function %v4int
+ %34 = OpConstantNull %v4int
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Uniform_float = OpTypePointer Uniform %float
+ %true = OpConstantTrue %bool
+ %false = OpConstantFalse %bool
+ %int_0 = OpConstant %int 0
+ %53 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
+ %v4bool = OpTypeVector %bool 4
+ %int_1 = OpConstant %int 1
+ %62 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
+ %int_2 = OpConstant %int 2
+ %74 = OpConstantComposite %v4int %int_2 %int_2 %int_2 %int_2
+ %void = OpTypeVoid
+ %85 = OpTypeFunction %void
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%_ptr_Function_float = OpTypePointer Function %float
+ %94 = OpConstantNull %float
+ %float_0 = OpConstant %float 0
+ %113 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+ %float_1 = OpConstant %float 1
+ %121 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+ %float_2 = OpConstant %float 2
+ %133 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
+ %uint_2 = OpConstant %uint 2
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
+ %uint_1 = OpConstant %uint 1
+ %main_out = OpTypeStruct %v4float
+ %160 = OpTypeFunction %main_out %bool %v4float
+%test_int_S1_c0_b = OpFunction %bool None %22
+ %24 = OpLabel
+ %unknown = OpVariable %_ptr_Function_int Function %28
+ %ok = OpVariable %_ptr_Function_bool Function %20
+ %val = OpVariable %_ptr_Function_v4int Function %34
+ %x_40 = OpVariable %_ptr_Function_bool Function %20
+ %x_54 = OpVariable %_ptr_Function_bool Function %20
+ %x_65 = OpVariable %_ptr_Function_bool Function %20
+ %x_41_phi = OpVariable %_ptr_Function_bool Function %20
+ %x_55_phi = OpVariable %_ptr_Function_bool Function %20
+ %x_66_phi = OpVariable %_ptr_Function_bool Function %20
+ %44 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0
+ %45 = OpLoad %float %44
+ %46 = OpConvertFToS %int %45
+ OpStore %unknown %46
+ OpStore %ok %true
+ OpStore %x_41_phi %false
+ OpSelectionMerge %49 None
+ OpBranchConditional %true %50 %49
+ %50 = OpLabel
+ %54 = OpCompositeConstruct %v4int %46 %46 %46 %46
+ %55 = OpSDiv %v4int %53 %54
+ %56 = OpIEqual %v4bool %55 %53
+ %51 = OpAll %bool %56
+ OpStore %x_40 %51
+ %58 = OpLoad %bool %x_40
+ OpStore %x_41_phi %58
+ OpBranch %49
+ %49 = OpLabel
+ %59 = OpLoad %bool %x_41_phi
+ OpStore %ok %59
+ %60 = OpCompositeConstruct %v4int %46 %46 %46 %46
+ OpStore %val %60
+ %63 = OpIAdd %v4int %60 %62
+ OpStore %val %63
+ %64 = OpISub %v4int %63 %62
+ OpStore %val %64
+ %65 = OpIAdd %v4int %64 %62
+ OpStore %val %65
+ %66 = OpISub %v4int %65 %62
+ OpStore %val %66
+ OpStore %x_55_phi %false
+ OpSelectionMerge %67 None
+ OpBranchConditional %59 %68 %67
+ %68 = OpLabel
+ %70 = OpIEqual %v4bool %66 %60
+ %69 = OpAll %bool %70
+ OpStore %x_54 %69
+ %71 = OpLoad %bool %x_54
+ OpStore %x_55_phi %71
+ OpBranch %67
+ %67 = OpLabel
+ %72 = OpLoad %bool %x_55_phi
+ OpStore %ok %72
+ %75 = OpIMul %v4int %66 %74
+ OpStore %val %75
+ %76 = OpSDiv %v4int %75 %74
+ OpStore %val %76
+ %77 = OpIMul %v4int %76 %74
+ OpStore %val %77
+ %78 = OpSDiv %v4int %77 %74
+ OpStore %val %78
+ OpStore %x_66_phi %false
+ OpSelectionMerge %79 None
+ OpBranchConditional %72 %80 %79
+ %80 = OpLabel
+ %82 = OpIEqual %v4bool %78 %60
+ %81 = OpAll %bool %82
+ OpStore %x_65 %81
+ %83 = OpLoad %bool %x_65
+ OpStore %x_66_phi %83
+ OpBranch %79
+ %79 = OpLabel
+ %84 = OpLoad %bool %x_66_phi
+ OpStore %ok %84
+ OpReturnValue %84
+ OpFunctionEnd
+ %main_1 = OpFunction %void None %85
+ %88 = OpLabel
+%outputColor_S0 = OpVariable %_ptr_Function_v4float Function %10
+ %output_S1 = OpVariable %_ptr_Function_v4float Function %10
+%x_8_unknown = OpVariable %_ptr_Function_float Function %94
+ %x_9_ok = OpVariable %_ptr_Function_bool Function %20
+ %x_10_val = OpVariable %_ptr_Function_v4float Function %10
+ %x_116 = OpVariable %_ptr_Function_v4float Function %10
+ %x_86 = OpVariable %_ptr_Function_bool Function %20
+ %x_99 = OpVariable %_ptr_Function_bool Function %20
+ %x_110 = OpVariable %_ptr_Function_bool Function %20
+ %x_114 = OpVariable %_ptr_Function_bool Function %20
+ %x_87_phi = OpVariable %_ptr_Function_bool Function %20
+ %x_100_phi = OpVariable %_ptr_Function_bool Function %20
+ %x_111_phi = OpVariable %_ptr_Function_bool Function %20
+ %x_115_phi = OpVariable %_ptr_Function_bool Function %20
+ %106 = OpLoad %v4float %vcolor_S0
+ OpStore %outputColor_S0 %106
+ %107 = OpAccessChain %_ptr_Uniform_float %x_4 %uint_0
+ %108 = OpLoad %float %107
+ OpStore %x_8_unknown %108
+ OpStore %x_9_ok %true
+ OpStore %x_87_phi %false
+ OpSelectionMerge %109 None
+ OpBranchConditional %true %110 %109
+ %110 = OpLabel
+ %114 = OpCompositeConstruct %v4float %108 %108 %108 %108
+ %115 = OpFDiv %v4float %113 %114
+ %116 = OpFOrdEqual %v4bool %115 %113
+ %111 = OpAll %bool %116
+ OpStore %x_86 %111
+ %117 = OpLoad %bool %x_86
+ OpStore %x_87_phi %117
+ OpBranch %109
+ %109 = OpLabel
+ %118 = OpLoad %bool %x_87_phi
+ OpStore %x_9_ok %118
+ %119 = OpCompositeConstruct %v4float %108 %108 %108 %108
+ OpStore %x_10_val %119
+ %122 = OpFAdd %v4float %119 %121
+ OpStore %x_10_val %122
+ %123 = OpFSub %v4float %122 %121
+ OpStore %x_10_val %123
+ %124 = OpFAdd %v4float %123 %121
+ OpStore %x_10_val %124
+ %125 = OpFSub %v4float %124 %121
+ OpStore %x_10_val %125
+ OpStore %x_100_phi %false
+ OpSelectionMerge %126 None
+ OpBranchConditional %118 %127 %126
+ %127 = OpLabel
+ %129 = OpFOrdEqual %v4bool %125 %119
+ %128 = OpAll %bool %129
+ OpStore %x_99 %128
+ %130 = OpLoad %bool %x_99
+ OpStore %x_100_phi %130
+ OpBranch %126
+ %126 = OpLabel
+ %131 = OpLoad %bool %x_100_phi
+ OpStore %x_9_ok %131
+ %134 = OpFMul %v4float %125 %133
+ OpStore %x_10_val %134
+ %135 = OpFDiv %v4float %134 %133
+ OpStore %x_10_val %135
+ %136 = OpFMul %v4float %135 %133
+ OpStore %x_10_val %136
+ %137 = OpFDiv %v4float %136 %133
+ OpStore %x_10_val %137
+ OpStore %x_111_phi %false
+ OpSelectionMerge %138 None
+ OpBranchConditional %131 %139 %138
+ %139 = OpLabel
+ %141 = OpFOrdEqual %v4bool %137 %119
+ %140 = OpAll %bool %141
+ OpStore %x_110 %140
+ %142 = OpLoad %bool %x_110
+ OpStore %x_111_phi %142
+ OpBranch %138
+ %138 = OpLabel
+ %143 = OpLoad %bool %x_111_phi
+ OpStore %x_9_ok %143
+ OpStore %x_115_phi %false
+ OpSelectionMerge %144 None
+ OpBranchConditional %143 %145 %144
+ %145 = OpLabel
+ %146 = OpFunctionCall %bool %test_int_S1_c0_b
+ OpStore %x_114 %146
+ %147 = OpLoad %bool %x_114
+ OpStore %x_115_phi %147
+ OpBranch %144
+ %144 = OpLabel
+ %148 = OpLoad %bool %x_115_phi
+ OpSelectionMerge %149 None
+ OpBranchConditional %148 %150 %151
+ %150 = OpLabel
+ %154 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_2
+ %155 = OpLoad %v4float %154
+ OpStore %x_116 %155
+ OpBranch %149
+ %151 = OpLabel
+ %157 = OpAccessChain %_ptr_Uniform_v4float %x_4 %uint_1
+ %158 = OpLoad %v4float %157
+ OpStore %x_116 %158
+ OpBranch %149
+ %149 = OpLabel
+ %159 = OpLoad %v4float %x_116
+ OpStore %output_S1 %159
+ OpStore %sk_FragColor %159
+ OpReturn
+ OpFunctionEnd
+ %main_inner = OpFunction %main_out None %160
+%sk_Clockwise_param = OpFunctionParameter %bool
+%vcolor_S0_param = OpFunctionParameter %v4float
+ %165 = OpLabel
+ OpStore %sk_Clockwise %sk_Clockwise_param
+ OpStore %vcolor_S0 %vcolor_S0_param
+ %166 = OpFunctionCall %void %main_1
+ %167 = OpLoad %v4float %sk_FragColor
+ %168 = OpCompositeConstruct %main_out %167
+ OpReturnValue %168
+ OpFunctionEnd
+ %main = OpFunction %void None %85
+ %170 = OpLabel
+ %172 = OpLoad %bool %sk_Clockwise_param_1
+ %173 = OpLoad %v4float %vcolor_S0_param_1
+ %171 = OpFunctionCall %main_out %main_inner %172 %173
+ %174 = OpCompositeExtract %v4float %171 0
+ OpStore %sk_FragColor_1_1 %174
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/bug/tint/1520.spvasm.expected.wgsl b/test/tint/bug/tint/1520.spvasm.expected.wgsl
new file mode 100644
index 0000000..359389e
--- /dev/null
+++ b/test/tint/bug/tint/1520.spvasm.expected.wgsl
@@ -0,0 +1,165 @@
+struct UniformBuffer {
+ @size(16)
+ padding : u32,
+ unknownInput_S1_c0 : f32,
+ @size(12)
+ padding_1 : u32,
+ ucolorRed_S1_c0 : vec4<f32>,
+ ucolorGreen_S1_c0 : vec4<f32>,
+ umatrix_S1 : mat3x3<f32>,
+}
+
+@binding(0) @group(0) var<uniform> x_4 : UniformBuffer;
+
+var<private> sk_FragColor : vec4<f32>;
+
+var<private> sk_Clockwise : bool;
+
+var<private> vcolor_S0 : vec4<f32>;
+
+fn test_int_S1_c0_b() -> bool {
+ var unknown : i32;
+ var ok : bool;
+ var val : vec4<i32>;
+ var x_40 : bool;
+ var x_54 : bool;
+ var x_65 : bool;
+ var x_41_phi : bool;
+ var x_55_phi : bool;
+ var x_66_phi : bool;
+ let x_26 : f32 = x_4.unknownInput_S1_c0;
+ let x_27 : i32 = i32(x_26);
+ unknown = x_27;
+ ok = true;
+ x_41_phi = false;
+ if (true) {
+ x_40 = all(((vec4<i32>(0, 0, 0, 0) / vec4<i32>(x_27, x_27, x_27, x_27)) == vec4<i32>(0, 0, 0, 0)));
+ x_41_phi = x_40;
+ }
+ let x_41 : bool = x_41_phi;
+ ok = x_41;
+ let x_44 : vec4<i32> = vec4<i32>(x_27, x_27, x_27, x_27);
+ val = x_44;
+ let x_47 : vec4<i32> = (x_44 + vec4<i32>(1, 1, 1, 1));
+ val = x_47;
+ let x_48 : vec4<i32> = (x_47 - vec4<i32>(1, 1, 1, 1));
+ val = x_48;
+ let x_49 : vec4<i32> = (x_48 + vec4<i32>(1, 1, 1, 1));
+ val = x_49;
+ let x_50 : vec4<i32> = (x_49 - vec4<i32>(1, 1, 1, 1));
+ val = x_50;
+ x_55_phi = false;
+ if (x_41) {
+ x_54 = all((x_50 == x_44));
+ x_55_phi = x_54;
+ }
+ let x_55 : bool = x_55_phi;
+ ok = x_55;
+ let x_58 : vec4<i32> = (x_50 * vec4<i32>(2, 2, 2, 2));
+ val = x_58;
+ let x_59 : vec4<i32> = (x_58 / vec4<i32>(2, 2, 2, 2));
+ val = x_59;
+ let x_60 : vec4<i32> = (x_59 * vec4<i32>(2, 2, 2, 2));
+ val = x_60;
+ let x_61 : vec4<i32> = (x_60 / vec4<i32>(2, 2, 2, 2));
+ val = x_61;
+ x_66_phi = false;
+ if (x_55) {
+ x_65 = all((x_61 == x_44));
+ x_66_phi = x_65;
+ }
+ let x_66 : bool = x_66_phi;
+ ok = x_66;
+ return x_66;
+}
+
+fn main_1() {
+ var outputColor_S0 : vec4<f32>;
+ var output_S1 : vec4<f32>;
+ var x_8_unknown : f32;
+ var x_9_ok : bool;
+ var x_10_val : vec4<f32>;
+ var x_116 : vec4<f32>;
+ var x_86 : bool;
+ var x_99 : bool;
+ var x_110 : bool;
+ var x_114 : bool;
+ var x_87_phi : bool;
+ var x_100_phi : bool;
+ var x_111_phi : bool;
+ var x_115_phi : bool;
+ let x_72 : vec4<f32> = vcolor_S0;
+ outputColor_S0 = x_72;
+ let x_77 : f32 = x_4.unknownInput_S1_c0;
+ x_8_unknown = x_77;
+ x_9_ok = true;
+ x_87_phi = false;
+ if (true) {
+ x_86 = all(((vec4<f32>(0.0, 0.0, 0.0, 0.0) / vec4<f32>(x_77, x_77, x_77, x_77)) == vec4<f32>(0.0, 0.0, 0.0, 0.0)));
+ x_87_phi = x_86;
+ }
+ let x_87 : bool = x_87_phi;
+ x_9_ok = x_87;
+ let x_89 : vec4<f32> = vec4<f32>(x_77, x_77, x_77, x_77);
+ x_10_val = x_89;
+ let x_92 : vec4<f32> = (x_89 + vec4<f32>(1.0, 1.0, 1.0, 1.0));
+ x_10_val = x_92;
+ let x_93 : vec4<f32> = (x_92 - vec4<f32>(1.0, 1.0, 1.0, 1.0));
+ x_10_val = x_93;
+ let x_94 : vec4<f32> = (x_93 + vec4<f32>(1.0, 1.0, 1.0, 1.0));
+ x_10_val = x_94;
+ let x_95 : vec4<f32> = (x_94 - vec4<f32>(1.0, 1.0, 1.0, 1.0));
+ x_10_val = x_95;
+ x_100_phi = false;
+ if (x_87) {
+ x_99 = all((x_95 == x_89));
+ x_100_phi = x_99;
+ }
+ let x_100 : bool = x_100_phi;
+ x_9_ok = x_100;
+ let x_103 : vec4<f32> = (x_95 * vec4<f32>(2.0, 2.0, 2.0, 2.0));
+ x_10_val = x_103;
+ let x_104 : vec4<f32> = (x_103 / vec4<f32>(2.0, 2.0, 2.0, 2.0));
+ x_10_val = x_104;
+ let x_105 : vec4<f32> = (x_104 * vec4<f32>(2.0, 2.0, 2.0, 2.0));
+ x_10_val = x_105;
+ let x_106 : vec4<f32> = (x_105 / vec4<f32>(2.0, 2.0, 2.0, 2.0));
+ x_10_val = x_106;
+ x_111_phi = false;
+ if (x_100) {
+ x_110 = all((x_106 == x_89));
+ x_111_phi = x_110;
+ }
+ let x_111 : bool = x_111_phi;
+ x_9_ok = x_111;
+ x_115_phi = false;
+ if (x_111) {
+ x_114 = test_int_S1_c0_b();
+ x_115_phi = x_114;
+ }
+ let x_115 : bool = x_115_phi;
+ if (x_115) {
+ let x_122 : vec4<f32> = x_4.ucolorGreen_S1_c0;
+ x_116 = x_122;
+ } else {
+ let x_124 : vec4<f32> = x_4.ucolorRed_S1_c0;
+ x_116 = x_124;
+ }
+ let x_125 : vec4<f32> = x_116;
+ output_S1 = x_125;
+ sk_FragColor = x_125;
+ return;
+}
+
+struct main_out {
+ @location(0)
+ sk_FragColor_1 : vec4<f32>,
+}
+
+@stage(fragment)
+fn main(@builtin(front_facing) sk_Clockwise_param : bool, @location(0) vcolor_S0_param : vec4<f32>) -> main_out {
+ sk_Clockwise = sk_Clockwise_param;
+ vcolor_S0 = vcolor_S0_param;
+ main_1();
+ return main_out(sk_FragColor);
+}