diff --git a/src/tint/transform/promote_initializers_to_let.cc b/src/tint/transform/promote_initializers_to_let.cc index b57fb257ea..ec7ba9523b 100644 --- a/src/tint/transform/promote_initializers_to_let.cc +++ b/src/tint/transform/promote_initializers_to_let.cc @@ -75,19 +75,22 @@ void PromoteInitializersToLet::Run(CloneContext& ctx, const DataMap&, DataMap&) return true; }, [&](const ast::IdentifierExpression* expr) { - if (auto* user = ctx.src->Sem().Get(expr)) { - // Identifier resolves to a variable - if (auto* stmt = user->Stmt()) { - if (auto* decl = stmt->Declaration()->As(); - decl && decl->variable->Is()) { - // The identifier is used on the RHS of a 'const' declaration. Ignore. - return true; + if (auto* sem = ctx.src->Sem().Get(expr)) { + if (auto* user = sem->UnwrapMaterialize()->As()) { + // Identifier resolves to a variable + if (auto* stmt = user->Stmt()) { + if (auto* decl = stmt->Declaration()->As(); + decl && decl->variable->Is()) { + // The identifier is used on the RHS of a 'const' declaration. + // Ignore. + return true; + } + } + if (user->Variable()->Declaration()->Is()) { + // The identifier resolves to a 'const' variable, but isn't used to + // initialize another 'const'. This needs promoting. + return promote(user); } - } - if (user->Variable()->Declaration()->Is()) { - // The identifier resolves to a 'const' variable, but isn't used to - // initialize another 'const'. This needs promoting. - return promote(user); } } return true; diff --git a/src/tint/transform/promote_initializers_to_let_test.cc b/src/tint/transform/promote_initializers_to_let_test.cc index d4d9fb2b72..536d04a29e 100644 --- a/src/tint/transform/promote_initializers_to_let_test.cc +++ b/src/tint/transform/promote_initializers_to_let_test.cc @@ -158,6 +158,37 @@ fn f() { EXPECT_EQ(expect, str(got)); } +TEST_F(PromoteInitializersToLetTest, GlobalConstArrayDynamicIndex) { + auto* src = R"( +const TRI_VERTICES = array( + vec4(0., 0., 0., 1.), + vec4(0., 1., 0., 1.), + vec4(1., 1., 0., 1.), +); + +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { + // note: TRI_VERTICES requires a materialize before the dynamic index. + return TRI_VERTICES[in_vertex_index]; +} +)"; + + auto* expect = R"( +const TRI_VERTICES = array(vec4(0.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), vec4(1.0, 1.0, 0.0, 1.0)); + +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index : u32) -> @builtin(position) vec4 { + let tint_symbol = TRI_VERTICES; + return tint_symbol[in_vertex_index]; +} +)"; + + DataMap data; + auto got = Run(src); + + EXPECT_EQ(expect, str(got)); +} + TEST_F(PromoteInitializersToLetTest, GlobalConstBasicArray_OutOfOrder) { auto* src = R"( fn f() { diff --git a/test/tint/bug/tint/1653.wgsl b/test/tint/bug/tint/1653.wgsl new file mode 100644 index 0000000000..5b76964287 --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl @@ -0,0 +1,10 @@ +const TRI_VERTICES = array( + vec4(0., 0., 0., 1.), + vec4(0., 1., 0., 1.), + vec4(1., 1., 0., 1.), +); + +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { + return TRI_VERTICES[in_vertex_index]; +} diff --git a/test/tint/bug/tint/1653.wgsl.expected.dxc.hlsl b/test/tint/bug/tint/1653.wgsl.expected.dxc.hlsl new file mode 100644 index 0000000000..ac385e01f9 --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl.expected.dxc.hlsl @@ -0,0 +1,18 @@ +struct tint_symbol_1 { + uint in_vertex_index : SV_VertexID; +}; +struct tint_symbol_2 { + float4 value : SV_Position; +}; + +float4 vs_main_inner(uint in_vertex_index) { + const float4 tint_symbol_3[3] = {float4(0.0f, 0.0f, 0.0f, 1.0f), float4(0.0f, 1.0f, 0.0f, 1.0f), float4(1.0f, 1.0f, 0.0f, 1.0f)}; + return tint_symbol_3[in_vertex_index]; +} + +tint_symbol_2 vs_main(tint_symbol_1 tint_symbol) { + const float4 inner_result = vs_main_inner(tint_symbol.in_vertex_index); + tint_symbol_2 wrapper_result = (tint_symbol_2)0; + wrapper_result.value = inner_result; + return wrapper_result; +} diff --git a/test/tint/bug/tint/1653.wgsl.expected.fxc.hlsl b/test/tint/bug/tint/1653.wgsl.expected.fxc.hlsl new file mode 100644 index 0000000000..ac385e01f9 --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl.expected.fxc.hlsl @@ -0,0 +1,18 @@ +struct tint_symbol_1 { + uint in_vertex_index : SV_VertexID; +}; +struct tint_symbol_2 { + float4 value : SV_Position; +}; + +float4 vs_main_inner(uint in_vertex_index) { + const float4 tint_symbol_3[3] = {float4(0.0f, 0.0f, 0.0f, 1.0f), float4(0.0f, 1.0f, 0.0f, 1.0f), float4(1.0f, 1.0f, 0.0f, 1.0f)}; + return tint_symbol_3[in_vertex_index]; +} + +tint_symbol_2 vs_main(tint_symbol_1 tint_symbol) { + const float4 inner_result = vs_main_inner(tint_symbol.in_vertex_index); + tint_symbol_2 wrapper_result = (tint_symbol_2)0; + wrapper_result.value = inner_result; + return wrapper_result; +} diff --git a/test/tint/bug/tint/1653.wgsl.expected.glsl b/test/tint/bug/tint/1653.wgsl.expected.glsl new file mode 100644 index 0000000000..7775d99641 --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl.expected.glsl @@ -0,0 +1,15 @@ +#version 310 es + +vec4 vs_main(uint in_vertex_index) { + vec4 tint_symbol[3] = vec4[3](vec4(0.0f, 0.0f, 0.0f, 1.0f), vec4(0.0f, 1.0f, 0.0f, 1.0f), vec4(1.0f, 1.0f, 0.0f, 1.0f)); + return tint_symbol[in_vertex_index]; +} + +void main() { + gl_PointSize = 1.0; + vec4 inner_result = vs_main(uint(gl_VertexID)); + gl_Position = inner_result; + gl_Position.y = -(gl_Position.y); + gl_Position.z = ((2.0f * gl_Position.z) - gl_Position.w); + return; +} diff --git a/test/tint/bug/tint/1653.wgsl.expected.msl b/test/tint/bug/tint/1653.wgsl.expected.msl new file mode 100644 index 0000000000..09bd662f26 --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl.expected.msl @@ -0,0 +1,32 @@ +#include + +using namespace metal; + +template +struct tint_array { + const constant T& operator[](size_t i) const constant { return elements[i]; } + device T& operator[](size_t i) device { return elements[i]; } + const device T& operator[](size_t i) const device { return elements[i]; } + thread T& operator[](size_t i) thread { return elements[i]; } + const thread T& operator[](size_t i) const thread { return elements[i]; } + threadgroup T& operator[](size_t i) threadgroup { return elements[i]; } + const threadgroup T& operator[](size_t i) const threadgroup { return elements[i]; } + T elements[N]; +}; + +struct tint_symbol { + float4 value [[position]]; +}; + +float4 vs_main_inner(uint in_vertex_index) { + tint_array const tint_symbol_1 = tint_array{float4(0.0f, 0.0f, 0.0f, 1.0f), float4(0.0f, 1.0f, 0.0f, 1.0f), float4(1.0f, 1.0f, 0.0f, 1.0f)}; + return tint_symbol_1[in_vertex_index]; +} + +vertex tint_symbol vs_main(uint in_vertex_index [[vertex_id]]) { + float4 const inner_result = vs_main_inner(in_vertex_index); + tint_symbol wrapper_result = {}; + wrapper_result.value = inner_result; + return wrapper_result; +} + diff --git a/test/tint/bug/tint/1653.wgsl.expected.spvasm b/test/tint/bug/tint/1653.wgsl.expected.spvasm new file mode 100644 index 0000000000..b74723f99c --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl.expected.spvasm @@ -0,0 +1,60 @@ +; SPIR-V +; Version: 1.3 +; Generator: Google Tint Compiler; 0 +; Bound: 35 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %vs_main "vs_main" %in_vertex_index_1 %value %vertex_point_size + OpName %in_vertex_index_1 "in_vertex_index_1" + OpName %value "value" + OpName %vertex_point_size "vertex_point_size" + OpName %vs_main_inner "vs_main_inner" + OpName %in_vertex_index "in_vertex_index" + OpName %var_for_index "var_for_index" + OpName %vs_main "vs_main" + OpDecorate %in_vertex_index_1 BuiltIn VertexIndex + OpDecorate %value BuiltIn Position + OpDecorate %vertex_point_size BuiltIn PointSize + OpDecorate %_arr_v4float_uint_3 ArrayStride 16 + %uint = OpTypeInt 32 0 +%_ptr_Input_uint = OpTypePointer Input %uint +%in_vertex_index_1 = OpVariable %_ptr_Input_uint Input + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %8 = OpConstantNull %v4float + %value = OpVariable %_ptr_Output_v4float Output %8 +%_ptr_Output_float = OpTypePointer Output %float + %11 = OpConstantNull %float +%vertex_point_size = OpVariable %_ptr_Output_float Output %11 + %12 = OpTypeFunction %v4float %uint + %uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 + %float_1 = OpConstant %float 1 + %19 = OpConstantComposite %v4float %11 %11 %11 %float_1 + %20 = OpConstantComposite %v4float %11 %float_1 %11 %float_1 + %21 = OpConstantComposite %v4float %float_1 %float_1 %11 %float_1 + %22 = OpConstantComposite %_arr_v4float_uint_3 %19 %20 %21 +%_ptr_Function__arr_v4float_uint_3 = OpTypePointer Function %_arr_v4float_uint_3 + %25 = OpConstantNull %_arr_v4float_uint_3 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %void = OpTypeVoid + %29 = OpTypeFunction %void +%vs_main_inner = OpFunction %v4float None %12 +%in_vertex_index = OpFunctionParameter %uint + %15 = OpLabel +%var_for_index = OpVariable %_ptr_Function__arr_v4float_uint_3 Function %25 + OpStore %var_for_index %22 + %27 = OpAccessChain %_ptr_Function_v4float %var_for_index %in_vertex_index + %28 = OpLoad %v4float %27 + OpReturnValue %28 + OpFunctionEnd + %vs_main = OpFunction %void None %29 + %32 = OpLabel + %34 = OpLoad %uint %in_vertex_index_1 + %33 = OpFunctionCall %v4float %vs_main_inner %34 + OpStore %value %33 + OpStore %vertex_point_size %float_1 + OpReturn + OpFunctionEnd diff --git a/test/tint/bug/tint/1653.wgsl.expected.wgsl b/test/tint/bug/tint/1653.wgsl.expected.wgsl new file mode 100644 index 0000000000..19056be0ed --- /dev/null +++ b/test/tint/bug/tint/1653.wgsl.expected.wgsl @@ -0,0 +1,6 @@ +const TRI_VERTICES = array(vec4(0.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), vec4(1.0, 1.0, 0.0, 1.0)); + +@vertex +fn vs_main(@builtin(vertex_index) in_vertex_index : u32) -> @builtin(position) vec4 { + return TRI_VERTICES[in_vertex_index]; +}