From 132d331870233da16aaea15b5d4a8dd2e884559d Mon Sep 17 00:00:00 2001 From: steve-lunarg Date: Mon, 19 Dec 2016 15:48:01 -0700 Subject: [PATCH] HLSL: struct splitting: assignments of hierarchical split types This commit adds support for copying nested hierarchical types of split types. E.g, a struct of a struct containing both user and builtin interstage IO variables. When copying split types, if any subtree does NOT contain builtin interstage IO, we can copy the whole subtree with one assignment, which saves a bunch of AST verbosity for memberwise copies of that subtree. --- Test/baseResults/hlsl.gather.basic.dx10.vert.out | 8 +- Test/baseResults/hlsl.getdimensions.dx10.vert.out | 8 +- Test/baseResults/hlsl.load.basic.dx10.vert.out | 8 +- .../hlsl.samplegrad.basic.dx10.vert.out | 8 +- .../hlsl.samplelevel.basic.dx10.vert.out | 8 +- Test/baseResults/hlsl.struct.split.array.geom.out | 295 ++++++++++++++++++++ Test/baseResults/hlsl.struct.split.nested.geom.out | 271 ++++++++++++++++++ .../baseResults/hlsl.struct.split.trivial.geom.out | 175 ++++++++++++ .../baseResults/hlsl.struct.split.trivial.vert.out | 8 +- Test/baseResults/hlsl.structarray.flatten.geom.out | 16 +- Test/baseResults/hlsl.structin.vert.out | 114 +++----- Test/hlsl.struct.split.array.geom | 21 ++ Test/hlsl.struct.split.nested.geom | 31 +++ Test/hlsl.struct.split.trivial.geom | 21 ++ glslang/Include/Types.h | 14 +- gtests/Hlsl.FromFile.cpp | 3 + hlsl/hlslGrammar.cpp | 2 +- hlsl/hlslParseHelper.cpp | 303 +++++++++++++-------- hlsl/hlslParseHelper.h | 35 ++- 19 files changed, 1114 insertions(+), 235 deletions(-) create mode 100644 Test/baseResults/hlsl.struct.split.array.geom.out create mode 100644 Test/baseResults/hlsl.struct.split.nested.geom.out create mode 100644 Test/baseResults/hlsl.struct.split.trivial.geom.out create mode 100644 Test/hlsl.struct.split.array.geom create mode 100644 Test/hlsl.struct.split.nested.geom create mode 100644 Test/hlsl.struct.split.trivial.geom diff --git a/Test/baseResults/hlsl.gather.basic.dx10.vert.out b/Test/baseResults/hlsl.gather.basic.dx10.vert.out index a893675..3226769 100644 --- a/Test/baseResults/hlsl.gather.basic.dx10.vert.out +++ b/Test/baseResults/hlsl.gather.basic.dx10.vert.out @@ -1,7 +1,7 @@ hlsl.gather.basic.dx10.vert Shader version: 450 0:? Sequence -0:28 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:28 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:28 Function Parameters: 0:? Sequence 0:33 Sequence @@ -87,7 +87,6 @@ Shader version: 450 0:45 0 (const int) 0:45 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_sSamp2d' (uniform sampler) 0:? 'g_tTex1df4a' (layout(binding=1 ) uniform texture1D) @@ -103,6 +102,7 @@ Shader version: 450 0:? 'g_tTexcdf4' (uniform textureCube) 0:? 'g_tTexcdi4' (uniform itextureCube) 0:? 'g_tTexcdu4' (uniform utextureCube) +0:? 'Pos' (out 4-component vector of float Position) Linked vertex stage: @@ -110,7 +110,7 @@ Linked vertex stage: Shader version: 450 0:? Sequence -0:28 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:28 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:28 Function Parameters: 0:? Sequence 0:33 Sequence @@ -196,7 +196,6 @@ Shader version: 450 0:45 0 (const int) 0:45 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_sSamp2d' (uniform sampler) 0:? 'g_tTex1df4a' (layout(binding=1 ) uniform texture1D) @@ -212,6 +211,7 @@ Shader version: 450 0:? 'g_tTexcdf4' (uniform textureCube) 0:? 'g_tTexcdi4' (uniform itextureCube) 0:? 'g_tTexcdu4' (uniform utextureCube) +0:? 'Pos' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 diff --git a/Test/baseResults/hlsl.getdimensions.dx10.vert.out b/Test/baseResults/hlsl.getdimensions.dx10.vert.out index c1c90f4..77316b1 100644 --- a/Test/baseResults/hlsl.getdimensions.dx10.vert.out +++ b/Test/baseResults/hlsl.getdimensions.dx10.vert.out @@ -1,7 +1,7 @@ hlsl.getdimensions.dx10.vert Shader version: 450 0:? Sequence -0:11 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:11 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:11 Function Parameters: 0:? Sequence 0:21 Sequence @@ -46,9 +46,9 @@ Shader version: 450 0:26 0 (const int) 0:26 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) +0:? 'Pos' (out 4-component vector of float Position) Linked vertex stage: @@ -56,7 +56,7 @@ Linked vertex stage: Shader version: 450 0:? Sequence -0:11 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:11 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:11 Function Parameters: 0:? Sequence 0:21 Sequence @@ -101,9 +101,9 @@ Shader version: 450 0:26 0 (const int) 0:26 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) +0:? 'Pos' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 diff --git a/Test/baseResults/hlsl.load.basic.dx10.vert.out b/Test/baseResults/hlsl.load.basic.dx10.vert.out index a86f0ae..7441d49 100644 --- a/Test/baseResults/hlsl.load.basic.dx10.vert.out +++ b/Test/baseResults/hlsl.load.basic.dx10.vert.out @@ -1,7 +1,7 @@ hlsl.load.basic.dx10.vert Shader version: 450 0:? Sequence -0:47 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:47 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:47 Function Parameters: 0:? Sequence 0:51 textureFetch (temp 4-component vector of float) @@ -195,7 +195,6 @@ Shader version: 450 0:69 0 (const int) 0:69 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) 0:? 'g_tTex1di4' (uniform itexture1D) @@ -219,6 +218,7 @@ Shader version: 450 0:? 'g_tTexcdi4a' (uniform itextureCubeArray) 0:? 'g_tTexcdu4a' (uniform utextureCubeArray) 0:? 'anon@0' (layout(row_major std140 ) uniform block{layout(offset=0 ) uniform int c1, layout(offset=8 ) uniform 2-component vector of int c2, layout(offset=16 ) uniform 3-component vector of int c3, layout(offset=32 ) uniform 4-component vector of int c4, layout(offset=48 ) uniform int o1, layout(offset=56 ) uniform 2-component vector of int o2, layout(offset=64 ) uniform 3-component vector of int o3, layout(offset=80 ) uniform 4-component vector of int o4}) +0:? 'Pos' (out 4-component vector of float Position) Linked vertex stage: @@ -226,7 +226,7 @@ Linked vertex stage: Shader version: 450 0:? Sequence -0:47 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:47 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:47 Function Parameters: 0:? Sequence 0:51 textureFetch (temp 4-component vector of float) @@ -420,7 +420,6 @@ Shader version: 450 0:69 0 (const int) 0:69 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) 0:? 'g_tTex1di4' (uniform itexture1D) @@ -444,6 +443,7 @@ Shader version: 450 0:? 'g_tTexcdi4a' (uniform itextureCubeArray) 0:? 'g_tTexcdu4a' (uniform utextureCubeArray) 0:? 'anon@0' (layout(row_major std140 ) uniform block{layout(offset=0 ) uniform int c1, layout(offset=8 ) uniform 2-component vector of int c2, layout(offset=16 ) uniform 3-component vector of int c3, layout(offset=32 ) uniform 4-component vector of int c4, layout(offset=48 ) uniform int o1, layout(offset=56 ) uniform 2-component vector of int o2, layout(offset=64 ) uniform 3-component vector of int o3, layout(offset=80 ) uniform 4-component vector of int o4}) +0:? 'Pos' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 diff --git a/Test/baseResults/hlsl.samplegrad.basic.dx10.vert.out b/Test/baseResults/hlsl.samplegrad.basic.dx10.vert.out index f6d37c3..d7ea386 100644 --- a/Test/baseResults/hlsl.samplegrad.basic.dx10.vert.out +++ b/Test/baseResults/hlsl.samplegrad.basic.dx10.vert.out @@ -1,7 +1,7 @@ hlsl.samplegrad.basic.dx10.vert Shader version: 450 0:? Sequence -0:27 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:27 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:27 Function Parameters: 0:? Sequence 0:30 Sequence @@ -225,7 +225,6 @@ Shader version: 450 0:48 0 (const int) 0:48 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4a' (layout(binding=1 ) uniform texture1D) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) @@ -240,6 +239,7 @@ Shader version: 450 0:? 'g_tTexcdf4' (uniform textureCube) 0:? 'g_tTexcdi4' (uniform itextureCube) 0:? 'g_tTexcdu4' (uniform utextureCube) +0:? 'Pos' (out 4-component vector of float Position) Linked vertex stage: @@ -247,7 +247,7 @@ Linked vertex stage: Shader version: 450 0:? Sequence -0:27 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:27 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:27 Function Parameters: 0:? Sequence 0:30 Sequence @@ -471,7 +471,6 @@ Shader version: 450 0:48 0 (const int) 0:48 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4a' (layout(binding=1 ) uniform texture1D) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) @@ -486,6 +485,7 @@ Shader version: 450 0:? 'g_tTexcdf4' (uniform textureCube) 0:? 'g_tTexcdi4' (uniform itextureCube) 0:? 'g_tTexcdu4' (uniform utextureCube) +0:? 'Pos' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 diff --git a/Test/baseResults/hlsl.samplelevel.basic.dx10.vert.out b/Test/baseResults/hlsl.samplelevel.basic.dx10.vert.out index 04d0870..35a9ede 100644 --- a/Test/baseResults/hlsl.samplelevel.basic.dx10.vert.out +++ b/Test/baseResults/hlsl.samplelevel.basic.dx10.vert.out @@ -1,7 +1,7 @@ hlsl.samplelevel.basic.dx10.vert Shader version: 450 0:? Sequence -0:27 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:27 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:27 Function Parameters: 0:? Sequence 0:30 Sequence @@ -171,7 +171,6 @@ Shader version: 450 0:48 0 (const int) 0:48 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4a' (layout(binding=1 ) uniform texture1D) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) @@ -186,6 +185,7 @@ Shader version: 450 0:? 'g_tTexcdf4' (uniform textureCube) 0:? 'g_tTexcdi4' (uniform itextureCube) 0:? 'g_tTexcdu4' (uniform utextureCube) +0:? 'Pos' (out 4-component vector of float Position) Linked vertex stage: @@ -193,7 +193,7 @@ Linked vertex stage: Shader version: 450 0:? Sequence -0:27 Function Definition: main( (temp structure{temp 4-component vector of float Pos}) +0:27 Function Definition: main( (temp structure{temp 4-component vector of float Position Pos}) 0:27 Function Parameters: 0:? Sequence 0:30 Sequence @@ -363,7 +363,6 @@ Shader version: 450 0:48 0 (const int) 0:48 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'g_sSamp' (layout(binding=0 ) uniform sampler) 0:? 'g_tTex1df4a' (layout(binding=1 ) uniform texture1D) 0:? 'g_tTex1df4' (layout(binding=0 ) uniform texture1D) @@ -378,6 +377,7 @@ Shader version: 450 0:? 'g_tTexcdf4' (uniform textureCube) 0:? 'g_tTexcdi4' (uniform itextureCube) 0:? 'g_tTexcdu4' (uniform utextureCube) +0:? 'Pos' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 diff --git a/Test/baseResults/hlsl.struct.split.array.geom.out b/Test/baseResults/hlsl.struct.split.array.geom.out new file mode 100644 index 0000000..e8921b6 --- /dev/null +++ b/Test/baseResults/hlsl.struct.split.array.geom.out @@ -0,0 +1,295 @@ +hlsl.struct.split.array.geom +Shader version: 450 +invocations = -1 +max_vertices = 4 +input primitive = points +output primitive = triangle_strip +0:? Sequence +0:13 Function Definition: main(u1[1];struct-PSInput-vf4-vf2-vf3-u11; (temp void) +0:13 Function Parameters: +0:13 'v' (layout(location=0 ) in 1-element array of uint) +0:13 'OutputStream' (out structure{temp 4-component vector of float Position Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:? Sequence +0:16 Sequence +0:16 move second child to first child (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:16 'Out' (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:16 Constant: +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0 (const uint) +0:18 Sequence +0:18 move second child to first child (temp int) +0:18 'x' (temp int) +0:18 Constant: +0:18 0 (const int) +0:18 Loop with condition tested first +0:18 Loop Condition +0:18 Compare Less Than (temp bool) +0:18 'x' (temp int) +0:18 Constant: +0:18 2 (const int) +0:18 Loop Body +0:19 Sequence +0:19 move second child to first child (temp int) +0:19 'y' (temp int) +0:19 Constant: +0:19 0 (const int) +0:19 Loop with condition tested first +0:19 Loop Condition +0:19 Compare Less Than (temp bool) +0:19 'y' (temp int) +0:19 Constant: +0:19 2 (const int) +0:19 Loop Body +0:20 move second child to first child (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 indirect index (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 indirect index (temp 3-element array of structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 'Verts' (temp 2-element array of 3-element array of structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 'x' (temp int) +0:20 'y' (temp int) +0:20 'Out' (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:19 Loop Terminal Expression +0:19 Pre-Increment (temp int) +0:19 'y' (temp int) +0:18 Loop Terminal Expression +0:18 Pre-Increment (temp int) +0:18 'x' (temp int) +0:? Linker Objects +0:? 'v' (layout(location=0 ) in 1-element array of uint) +0:? 'OutputStream' (layout(location=0 ) out structure{temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:? 'OutputStream.Pos' (out 4-component vector of float Position) + + +Linked geometry stage: + + +Shader version: 450 +invocations = 1 +max_vertices = 4 +input primitive = points +output primitive = triangle_strip +0:? Sequence +0:13 Function Definition: main(u1[1];struct-PSInput-vf4-vf2-vf3-u11; (temp void) +0:13 Function Parameters: +0:13 'v' (layout(location=0 ) in 1-element array of uint) +0:13 'OutputStream' (out structure{temp 4-component vector of float Position Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:? Sequence +0:16 Sequence +0:16 move second child to first child (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:16 'Out' (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:16 Constant: +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0.000000 +0:16 0 (const uint) +0:18 Sequence +0:18 move second child to first child (temp int) +0:18 'x' (temp int) +0:18 Constant: +0:18 0 (const int) +0:18 Loop with condition tested first +0:18 Loop Condition +0:18 Compare Less Than (temp bool) +0:18 'x' (temp int) +0:18 Constant: +0:18 2 (const int) +0:18 Loop Body +0:19 Sequence +0:19 move second child to first child (temp int) +0:19 'y' (temp int) +0:19 Constant: +0:19 0 (const int) +0:19 Loop with condition tested first +0:19 Loop Condition +0:19 Compare Less Than (temp bool) +0:19 'y' (temp int) +0:19 Constant: +0:19 2 (const int) +0:19 Loop Body +0:20 move second child to first child (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 indirect index (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 indirect index (temp 3-element array of structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 'Verts' (temp 2-element array of 3-element array of structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:20 'x' (temp int) +0:20 'y' (temp int) +0:20 'Out' (temp structure{temp 4-component vector of float Pos, temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:19 Loop Terminal Expression +0:19 Pre-Increment (temp int) +0:19 'y' (temp int) +0:18 Loop Terminal Expression +0:18 Pre-Increment (temp int) +0:18 'x' (temp int) +0:? Linker Objects +0:? 'v' (layout(location=0 ) in 1-element array of uint) +0:? 'OutputStream' (layout(location=0 ) out structure{temp 2-component vector of float TexCoord, temp 3-component vector of float TerrainPos, temp uint VertexID}) +0:? 'OutputStream.Pos' (out 4-component vector of float Position) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 89 + + Capability Geometry + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Geometry 4 "main" 83 86 88 + ExecutionMode 4 InputPoints + ExecutionMode 4 Invocations 1 + ExecutionMode 4 OutputTriangleStrip + ExecutionMode 4 OutputVertices 4 + Name 4 "main" + Name 11 "PSInput" + MemberName 11(PSInput) 0 "Pos" + MemberName 11(PSInput) 1 "TexCoord" + MemberName 11(PSInput) 2 "TerrainPos" + MemberName 11(PSInput) 3 "VertexID" + Name 13 "Out" + Name 14 "PSInput" + MemberName 14(PSInput) 0 "Pos" + MemberName 14(PSInput) 1 "TexCoord" + MemberName 14(PSInput) 2 "TerrainPos" + MemberName 14(PSInput) 3 "VertexID" + Name 39 "x" + Name 48 "y" + Name 56 "PSInput" + MemberName 56(PSInput) 0 "Pos" + MemberName 56(PSInput) 1 "TexCoord" + MemberName 56(PSInput) 2 "TerrainPos" + MemberName 56(PSInput) 3 "VertexID" + Name 62 "Verts" + Name 83 "v" + Name 84 "PSInput" + MemberName 84(PSInput) 0 "TexCoord" + MemberName 84(PSInput) 1 "TerrainPos" + MemberName 84(PSInput) 2 "VertexID" + Name 86 "OutputStream" + Name 88 "OutputStream.Pos" + MemberDecorate 14(PSInput) 0 BuiltIn Position + Decorate 83(v) Location 0 + Decorate 86(OutputStream) Location 0 + Decorate 88(OutputStream.Pos) BuiltIn Position + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeVector 6(float) 2 + 9: TypeVector 6(float) 3 + 10: TypeInt 32 0 + 11(PSInput): TypeStruct 7(fvec4) 8(fvec2) 9(fvec3) 10(int) + 12: TypePointer Function 11(PSInput) + 14(PSInput): TypeStruct 7(fvec4) 8(fvec2) 9(fvec3) 10(int) + 15: 6(float) Constant 0 + 16: 7(fvec4) ConstantComposite 15 15 15 15 + 17: 8(fvec2) ConstantComposite 15 15 + 18: 9(fvec3) ConstantComposite 15 15 15 + 19: 10(int) Constant 0 + 20: 14(PSInput) ConstantComposite 16 17 18 19 + 22: TypeInt 32 1 + 23: 22(int) Constant 0 + 24: TypePointer Function 7(fvec4) + 27: 22(int) Constant 1 + 28: TypePointer Function 8(fvec2) + 31: 22(int) Constant 2 + 32: TypePointer Function 9(fvec3) + 35: 22(int) Constant 3 + 36: TypePointer Function 10(int) + 38: TypePointer Function 22(int) + 46: TypeBool + 56(PSInput): TypeStruct 7(fvec4) 8(fvec2) 9(fvec3) 10(int) + 57: 10(int) Constant 3 + 58: TypeArray 56(PSInput) 57 + 59: 10(int) Constant 2 + 60: TypeArray 58 59 + 61: TypePointer Function 60 + 66: TypePointer Function 56(PSInput) + 80: 10(int) Constant 1 + 81: TypeArray 10(int) 80 + 82: TypePointer Input 81 + 83(v): 82(ptr) Variable Input + 84(PSInput): TypeStruct 8(fvec2) 9(fvec3) 10(int) + 85: TypePointer Output 84(PSInput) +86(OutputStream): 85(ptr) Variable Output + 87: TypePointer Output 7(fvec4) +88(OutputStream.Pos): 87(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 13(Out): 12(ptr) Variable Function + 39(x): 38(ptr) Variable Function + 48(y): 38(ptr) Variable Function + 62(Verts): 61(ptr) Variable Function + 21: 7(fvec4) CompositeExtract 20 0 + 25: 24(ptr) AccessChain 13(Out) 23 + Store 25 21 + 26: 8(fvec2) CompositeExtract 20 1 + 29: 28(ptr) AccessChain 13(Out) 27 + Store 29 26 + 30: 9(fvec3) CompositeExtract 20 2 + 33: 32(ptr) AccessChain 13(Out) 31 + Store 33 30 + 34: 10(int) CompositeExtract 20 3 + 37: 36(ptr) AccessChain 13(Out) 35 + Store 37 34 + Store 39(x) 23 + Branch 40 + 40: Label + LoopMerge 42 43 None + Branch 44 + 44: Label + 45: 22(int) Load 39(x) + 47: 46(bool) SLessThan 45 31 + BranchConditional 47 41 42 + 41: Label + Store 48(y) 23 + Branch 49 + 49: Label + LoopMerge 51 52 None + Branch 53 + 53: Label + 54: 22(int) Load 48(y) + 55: 46(bool) SLessThan 54 31 + BranchConditional 55 50 51 + 50: Label + 63: 22(int) Load 39(x) + 64: 22(int) Load 48(y) + 65: 11(PSInput) Load 13(Out) + 67: 66(ptr) AccessChain 62(Verts) 63 64 + 68: 7(fvec4) CompositeExtract 65 0 + 69: 24(ptr) AccessChain 67 23 + Store 69 68 + 70: 8(fvec2) CompositeExtract 65 1 + 71: 28(ptr) AccessChain 67 27 + Store 71 70 + 72: 9(fvec3) CompositeExtract 65 2 + 73: 32(ptr) AccessChain 67 31 + Store 73 72 + 74: 10(int) CompositeExtract 65 3 + 75: 36(ptr) AccessChain 67 35 + Store 75 74 + Branch 52 + 52: Label + 76: 22(int) Load 48(y) + 77: 22(int) IAdd 76 27 + Store 48(y) 77 + Branch 49 + 51: Label + Branch 43 + 43: Label + 78: 22(int) Load 39(x) + 79: 22(int) IAdd 78 27 + Store 39(x) 79 + Branch 40 + 42: Label + Return + FunctionEnd diff --git a/Test/baseResults/hlsl.struct.split.nested.geom.out b/Test/baseResults/hlsl.struct.split.nested.geom.out new file mode 100644 index 0000000..3dd8d9f --- /dev/null +++ b/Test/baseResults/hlsl.struct.split.nested.geom.out @@ -0,0 +1,271 @@ +hlsl.struct.split.nested.geom +Shader version: 450 +invocations = -1 +max_vertices = 3 +input primitive = triangles +output primitive = triangle_strip +0:? Sequence +0:24 Function Definition: main(struct-PS_IN-vf4-vf21[3];struct-GS_OUT-struct-PS_IN-vf4-vf21-struct-STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO-f1[2]-i111; (temp void) +0:24 Function Parameters: +0:24 'tin' (in 3-element array of structure{temp 4-component vector of float Position pos, temp 2-component vector of float tc}) +0:24 'ts' (out structure{temp structure{temp 4-component vector of float Position pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:? Sequence +0:27 move second child to first child (temp 4-component vector of float) +0:27 pos: direct index for structure (temp 4-component vector of float) +0:27 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:27 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:27 Constant: +0:27 0 (const int) +0:27 Constant: +0:27 0 (const int) +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:? 4.000000 +0:28 move second child to first child (temp 2-component vector of float) +0:28 tc: direct index for structure (temp 2-component vector of float) +0:28 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:28 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:28 Constant: +0:28 0 (const int) +0:28 Constant: +0:28 1 (const int) +0:? Constant: +0:? 5.000000 +0:? 6.000000 +0:30 Sequence +0:30 Sequence +0:30 move second child to first child (temp 4-component vector of float) +0:? 'ts.psIn.pos' (out 4-component vector of float Position) +0:30 pos: direct index for structure (temp 4-component vector of float) +0:30 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:30 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 0 (const int) +0:30 move second child to first child (temp 2-component vector of float) +0:30 tc: direct index for structure (temp 2-component vector of float) +0:30 psIn: direct index for structure (temp structure{temp 2-component vector of float tc}) +0:30 'ts' (layout(location=0 ) out structure{temp structure{temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 0 (const int) +0:30 tc: direct index for structure (temp 2-component vector of float) +0:30 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:30 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 1 (const int) +0:30 move second child to first child (temp structure{temp 2-element array of float m0_array, temp int m1}) +0:30 contains_no_builtin_io: direct index for structure (temp structure{temp 2-element array of float m0_array, temp int m1}) +0:30 'ts' (layout(location=0 ) out structure{temp structure{temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 1 (const int) +0:30 contains_no_builtin_io: direct index for structure (temp structure{temp 2-element array of float m0_array, temp int m1}) +0:30 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 1 (const int) +0:30 EmitVertex (temp void) +0:? Linker Objects +0:? 'tin' (layout(location=0 ) in 3-element array of structure{temp 2-component vector of float tc}) +0:? 'ts' (layout(location=0 ) out structure{temp structure{temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:? 'tin.pos' (in 3-element array of 4-component vector of float Position) +0:? 'ts.psIn.pos' (out 4-component vector of float Position) + + +Linked geometry stage: + + +Shader version: 450 +invocations = 1 +max_vertices = 3 +input primitive = triangles +output primitive = triangle_strip +0:? Sequence +0:24 Function Definition: main(struct-PS_IN-vf4-vf21[3];struct-GS_OUT-struct-PS_IN-vf4-vf21-struct-STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO-f1[2]-i111; (temp void) +0:24 Function Parameters: +0:24 'tin' (in 3-element array of structure{temp 4-component vector of float Position pos, temp 2-component vector of float tc}) +0:24 'ts' (out structure{temp structure{temp 4-component vector of float Position pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:? Sequence +0:27 move second child to first child (temp 4-component vector of float) +0:27 pos: direct index for structure (temp 4-component vector of float) +0:27 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:27 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:27 Constant: +0:27 0 (const int) +0:27 Constant: +0:27 0 (const int) +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:? 4.000000 +0:28 move second child to first child (temp 2-component vector of float) +0:28 tc: direct index for structure (temp 2-component vector of float) +0:28 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:28 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:28 Constant: +0:28 0 (const int) +0:28 Constant: +0:28 1 (const int) +0:? Constant: +0:? 5.000000 +0:? 6.000000 +0:30 Sequence +0:30 Sequence +0:30 move second child to first child (temp 4-component vector of float) +0:? 'ts.psIn.pos' (out 4-component vector of float Position) +0:30 pos: direct index for structure (temp 4-component vector of float) +0:30 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:30 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 0 (const int) +0:30 move second child to first child (temp 2-component vector of float) +0:30 tc: direct index for structure (temp 2-component vector of float) +0:30 psIn: direct index for structure (temp structure{temp 2-component vector of float tc}) +0:30 'ts' (layout(location=0 ) out structure{temp structure{temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 0 (const int) +0:30 tc: direct index for structure (temp 2-component vector of float) +0:30 psIn: direct index for structure (temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc}) +0:30 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 1 (const int) +0:30 move second child to first child (temp structure{temp 2-element array of float m0_array, temp int m1}) +0:30 contains_no_builtin_io: direct index for structure (temp structure{temp 2-element array of float m0_array, temp int m1}) +0:30 'ts' (layout(location=0 ) out structure{temp structure{temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 1 (const int) +0:30 contains_no_builtin_io: direct index for structure (temp structure{temp 2-element array of float m0_array, temp int m1}) +0:30 'o' (temp structure{temp structure{temp 4-component vector of float pos, temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:30 Constant: +0:30 1 (const int) +0:30 EmitVertex (temp void) +0:? Linker Objects +0:? 'tin' (layout(location=0 ) in 3-element array of structure{temp 2-component vector of float tc}) +0:? 'ts' (layout(location=0 ) out structure{temp structure{temp 2-component vector of float tc} psIn, temp structure{temp 2-element array of float m0_array, temp int m1} contains_no_builtin_io}) +0:? 'tin.pos' (in 3-element array of 4-component vector of float Position) +0:? 'ts.psIn.pos' (out 4-component vector of float Position) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 64 + + Capability Geometry + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Geometry 4 "main" 33 40 60 63 + ExecutionMode 4 Triangles + ExecutionMode 4 Invocations 1 + ExecutionMode 4 OutputTriangleStrip + ExecutionMode 4 OutputVertices 3 + Name 4 "main" + Name 9 "PS_IN" + MemberName 9(PS_IN) 0 "pos" + MemberName 9(PS_IN) 1 "tc" + Name 14 "STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO" + MemberName 14(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) 0 "m0_array" + MemberName 14(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) 1 "m1" + Name 15 "GS_OUT" + MemberName 15(GS_OUT) 0 "psIn" + MemberName 15(GS_OUT) 1 "contains_no_builtin_io" + Name 17 "o" + Name 33 "ts.psIn.pos" + Name 36 "PS_IN" + MemberName 36(PS_IN) 0 "tc" + Name 37 "STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO" + MemberName 37(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) 0 "m0_array" + MemberName 37(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) 1 "m1" + Name 38 "GS_OUT" + MemberName 38(GS_OUT) 0 "psIn" + MemberName 38(GS_OUT) 1 "contains_no_builtin_io" + Name 40 "ts" + Name 56 "PS_IN" + MemberName 56(PS_IN) 0 "tc" + Name 60 "tin" + Name 63 "tin.pos" + Decorate 33(ts.psIn.pos) BuiltIn Position + Decorate 40(ts) Location 0 + Decorate 60(tin) Location 0 + Decorate 63(tin.pos) BuiltIn Position + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeVector 6(float) 2 + 9(PS_IN): TypeStruct 7(fvec4) 8(fvec2) + 10: TypeInt 32 0 + 11: 10(int) Constant 2 + 12: TypeArray 6(float) 11 + 13: TypeInt 32 1 +14(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO): TypeStruct 12 13(int) + 15(GS_OUT): TypeStruct 9(PS_IN) 14(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) + 16: TypePointer Function 15(GS_OUT) + 18: 13(int) Constant 0 + 19: 6(float) Constant 1065353216 + 20: 6(float) Constant 1073741824 + 21: 6(float) Constant 1077936128 + 22: 6(float) Constant 1082130432 + 23: 7(fvec4) ConstantComposite 19 20 21 22 + 24: TypePointer Function 7(fvec4) + 26: 13(int) Constant 1 + 27: 6(float) Constant 1084227584 + 28: 6(float) Constant 1086324736 + 29: 8(fvec2) ConstantComposite 27 28 + 30: TypePointer Function 8(fvec2) + 32: TypePointer Output 7(fvec4) + 33(ts.psIn.pos): 32(ptr) Variable Output + 36(PS_IN): TypeStruct 8(fvec2) +37(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO): TypeStruct 12 13(int) + 38(GS_OUT): TypeStruct 36(PS_IN) 37(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) + 39: TypePointer Output 38(GS_OUT) + 40(ts): 39(ptr) Variable Output + 43: TypePointer Output 8(fvec2) + 45: TypePointer Function 14(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) + 48: TypePointer Output 37(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) + 51: TypePointer Output 12 + 54: TypePointer Output 13(int) + 56(PS_IN): TypeStruct 8(fvec2) + 57: 10(int) Constant 3 + 58: TypeArray 56(PS_IN) 57 + 59: TypePointer Input 58 + 60(tin): 59(ptr) Variable Input + 61: TypeArray 7(fvec4) 57 + 62: TypePointer Input 61 + 63(tin.pos): 62(ptr) Variable Input + 4(main): 2 Function None 3 + 5: Label + 17(o): 16(ptr) Variable Function + 25: 24(ptr) AccessChain 17(o) 18 18 + Store 25 23 + 31: 30(ptr) AccessChain 17(o) 18 26 + Store 31 29 + 34: 24(ptr) AccessChain 17(o) 18 18 + 35: 7(fvec4) Load 34 + Store 33(ts.psIn.pos) 35 + 41: 30(ptr) AccessChain 17(o) 18 26 + 42: 8(fvec2) Load 41 + 44: 43(ptr) AccessChain 40(ts) 18 18 + Store 44 42 + 46: 45(ptr) AccessChain 17(o) 26 + 47:14(STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO) Load 46 + 49: 48(ptr) AccessChain 40(ts) 26 + 50: 12 CompositeExtract 47 0 + 52: 51(ptr) AccessChain 49 18 + Store 52 50 + 53: 13(int) CompositeExtract 47 1 + 55: 54(ptr) AccessChain 49 26 + Store 55 53 + EmitVertex + Return + FunctionEnd diff --git a/Test/baseResults/hlsl.struct.split.trivial.geom.out b/Test/baseResults/hlsl.struct.split.trivial.geom.out new file mode 100644 index 0000000..8448ac4 --- /dev/null +++ b/Test/baseResults/hlsl.struct.split.trivial.geom.out @@ -0,0 +1,175 @@ +hlsl.struct.split.trivial.geom +Shader version: 450 +invocations = -1 +max_vertices = 3 +input primitive = triangles +output primitive = triangle_strip +0:? Sequence +0:14 Function Definition: main(struct-PS_IN-vf41[3];struct-GS_OUT-vf41; (temp void) +0:14 Function Parameters: +0:14 'i' (in 3-element array of structure{temp 4-component vector of float Position pos}) +0:14 'ts' (out structure{temp 4-component vector of float Position pos}) +0:? Sequence +0:17 Sequence +0:17 move second child to first child (temp int) +0:17 'x' (temp int) +0:17 Constant: +0:17 0 (const int) +0:17 Loop with condition tested first +0:17 Loop Condition +0:17 Compare Less Than (temp bool) +0:17 'x' (temp int) +0:17 Constant: +0:17 3 (const int) +0:17 Loop Body +0:? Sequence +0:18 move second child to first child (temp 4-component vector of float) +0:18 pos: direct index for structure (temp 4-component vector of float) +0:18 'o' (temp structure{temp 4-component vector of float pos}) +0:18 Constant: +0:18 0 (const int) +0:18 indirect index (temp 4-component vector of float Position) +0:18 'i.pos' (in 3-element array of 4-component vector of float Position) +0:18 'x' (temp int) +0:19 Sequence +0:19 Sequence +0:19 move second child to first child (temp 4-component vector of float) +0:? 'ts.pos' (out 4-component vector of float Position) +0:19 pos: direct index for structure (temp 4-component vector of float) +0:19 'o' (temp structure{temp 4-component vector of float pos}) +0:19 Constant: +0:19 0 (const int) +0:19 EmitVertex (temp void) +0:17 Loop Terminal Expression +0:17 Pre-Increment (temp int) +0:17 'x' (temp int) +0:? Linker Objects +0:? 'i.pos' (in 3-element array of 4-component vector of float Position) +0:? 'ts.pos' (out 4-component vector of float Position) + + +Linked geometry stage: + + +Shader version: 450 +invocations = 1 +max_vertices = 3 +input primitive = triangles +output primitive = triangle_strip +0:? Sequence +0:14 Function Definition: main(struct-PS_IN-vf41[3];struct-GS_OUT-vf41; (temp void) +0:14 Function Parameters: +0:14 'i' (in 3-element array of structure{temp 4-component vector of float Position pos}) +0:14 'ts' (out structure{temp 4-component vector of float Position pos}) +0:? Sequence +0:17 Sequence +0:17 move second child to first child (temp int) +0:17 'x' (temp int) +0:17 Constant: +0:17 0 (const int) +0:17 Loop with condition tested first +0:17 Loop Condition +0:17 Compare Less Than (temp bool) +0:17 'x' (temp int) +0:17 Constant: +0:17 3 (const int) +0:17 Loop Body +0:? Sequence +0:18 move second child to first child (temp 4-component vector of float) +0:18 pos: direct index for structure (temp 4-component vector of float) +0:18 'o' (temp structure{temp 4-component vector of float pos}) +0:18 Constant: +0:18 0 (const int) +0:18 indirect index (temp 4-component vector of float Position) +0:18 'i.pos' (in 3-element array of 4-component vector of float Position) +0:18 'x' (temp int) +0:19 Sequence +0:19 Sequence +0:19 move second child to first child (temp 4-component vector of float) +0:? 'ts.pos' (out 4-component vector of float Position) +0:19 pos: direct index for structure (temp 4-component vector of float) +0:19 'o' (temp structure{temp 4-component vector of float pos}) +0:19 Constant: +0:19 0 (const int) +0:19 EmitVertex (temp void) +0:17 Loop Terminal Expression +0:17 Pre-Increment (temp int) +0:17 'x' (temp int) +0:? Linker Objects +0:? 'i.pos' (in 3-element array of 4-component vector of float Position) +0:? 'ts.pos' (out 4-component vector of float Position) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 42 + + Capability Geometry + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Geometry 4 "main" 28 36 + ExecutionMode 4 Triangles + ExecutionMode 4 Invocations 1 + ExecutionMode 4 OutputTriangleStrip + ExecutionMode 4 OutputVertices 3 + Name 4 "main" + Name 8 "x" + Name 21 "GS_OUT" + MemberName 21(GS_OUT) 0 "pos" + Name 23 "o" + Name 28 "i.pos" + Name 36 "ts.pos" + Decorate 28(i.pos) BuiltIn Position + Decorate 36(ts.pos) BuiltIn Position + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeInt 32 1 + 7: TypePointer Function 6(int) + 9: 6(int) Constant 0 + 16: 6(int) Constant 3 + 17: TypeBool + 19: TypeFloat 32 + 20: TypeVector 19(float) 4 + 21(GS_OUT): TypeStruct 20(fvec4) + 22: TypePointer Function 21(GS_OUT) + 24: TypeInt 32 0 + 25: 24(int) Constant 3 + 26: TypeArray 20(fvec4) 25 + 27: TypePointer Input 26 + 28(i.pos): 27(ptr) Variable Input + 30: TypePointer Input 20(fvec4) + 33: TypePointer Function 20(fvec4) + 35: TypePointer Output 20(fvec4) + 36(ts.pos): 35(ptr) Variable Output + 40: 6(int) Constant 1 + 4(main): 2 Function None 3 + 5: Label + 8(x): 7(ptr) Variable Function + 23(o): 22(ptr) Variable Function + Store 8(x) 9 + Branch 10 + 10: Label + LoopMerge 12 13 None + Branch 14 + 14: Label + 15: 6(int) Load 8(x) + 18: 17(bool) SLessThan 15 16 + BranchConditional 18 11 12 + 11: Label + 29: 6(int) Load 8(x) + 31: 30(ptr) AccessChain 28(i.pos) 29 + 32: 20(fvec4) Load 31 + 34: 33(ptr) AccessChain 23(o) 9 + Store 34 32 + 37: 33(ptr) AccessChain 23(o) 9 + 38: 20(fvec4) Load 37 + Store 36(ts.pos) 38 + EmitVertex + Branch 13 + 13: Label + 39: 6(int) Load 8(x) + 41: 6(int) IAdd 39 40 + Store 8(x) 41 + Branch 10 + 12: Label + Return + FunctionEnd diff --git a/Test/baseResults/hlsl.struct.split.trivial.vert.out b/Test/baseResults/hlsl.struct.split.trivial.vert.out index d8846d2..bdf156c 100644 --- a/Test/baseResults/hlsl.struct.split.trivial.vert.out +++ b/Test/baseResults/hlsl.struct.split.trivial.vert.out @@ -1,7 +1,7 @@ hlsl.struct.split.trivial.vert Shader version: 450 0:? Sequence -0:16 Function Definition: main(struct-VS_INPUT-vf41;vf4; (temp structure{temp 4-component vector of float Pos}) +0:16 Function Definition: main(struct-VS_INPUT-vf41;vf4; (temp structure{temp 4-component vector of float Position Pos}) 0:16 Function Parameters: 0:16 'vsin' (in structure{temp 4-component vector of float Pos_in}) 0:16 'Pos_loose' (in 4-component vector of float Position) @@ -24,9 +24,9 @@ Shader version: 450 0:21 0 (const int) 0:21 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'Pos_in' (in 4-component vector of float Position) 0:? 'Pos_loose' (in 4-component vector of float Position) +0:? 'Pos' (out 4-component vector of float Position) Linked vertex stage: @@ -34,7 +34,7 @@ Linked vertex stage: Shader version: 450 0:? Sequence -0:16 Function Definition: main(struct-VS_INPUT-vf41;vf4; (temp structure{temp 4-component vector of float Pos}) +0:16 Function Definition: main(struct-VS_INPUT-vf41;vf4; (temp structure{temp 4-component vector of float Position Pos}) 0:16 Function Parameters: 0:16 'vsin' (in structure{temp 4-component vector of float Pos_in}) 0:16 'Pos_loose' (in 4-component vector of float Position) @@ -57,9 +57,9 @@ Shader version: 450 0:21 0 (const int) 0:21 Branch: Return 0:? Linker Objects -0:? 'Pos' (out 4-component vector of float Position) 0:? 'Pos_in' (in 4-component vector of float Position) 0:? 'Pos_loose' (in 4-component vector of float Position) +0:? 'Pos' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 diff --git a/Test/baseResults/hlsl.structarray.flatten.geom.out b/Test/baseResults/hlsl.structarray.flatten.geom.out index b17618b..0922bae 100644 --- a/Test/baseResults/hlsl.structarray.flatten.geom.out +++ b/Test/baseResults/hlsl.structarray.flatten.geom.out @@ -49,7 +49,7 @@ output primitive = triangle_strip 0:22 Sequence 0:22 Sequence 0:22 move second child to first child (temp 4-component vector of float) -0:? 'position' (out 4-component vector of float Position) +0:? 'outStream.position' (out 4-component vector of float Position) 0:22 position: direct index for structure (temp 4-component vector of float) 0:22 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) 0:22 Constant: @@ -76,7 +76,7 @@ output primitive = triangle_strip 0:? Linker Objects 0:? 'vin' (layout(location=0 ) in 2-element array of structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) 0:? 'outStream' (layout(location=0 ) out structure{temp 4-component vector of float color, temp 2-component vector of float uv}) -0:? 'position' (out 4-component vector of float Position) +0:? 'outStream.position' (out 4-component vector of float Position) Linked geometry stage: @@ -132,7 +132,7 @@ output primitive = triangle_strip 0:22 Sequence 0:22 Sequence 0:22 move second child to first child (temp 4-component vector of float) -0:? 'position' (out 4-component vector of float Position) +0:? 'outStream.position' (out 4-component vector of float Position) 0:22 position: direct index for structure (temp 4-component vector of float) 0:22 'vout' (temp structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) 0:22 Constant: @@ -159,7 +159,7 @@ output primitive = triangle_strip 0:? Linker Objects 0:? 'vin' (layout(location=0 ) in 2-element array of structure{temp 4-component vector of float position, temp 4-component vector of float color, temp 2-component vector of float uv}) 0:? 'outStream' (layout(location=0 ) out structure{temp 4-component vector of float color, temp 2-component vector of float uv}) -0:? 'position' (out 4-component vector of float Position) +0:? 'outStream.position' (out 4-component vector of float Position) // Module Version 10000 // Generated by (magic number): 80001 @@ -184,13 +184,13 @@ output primitive = triangle_strip MemberName 14(VertexData) 1 "color" MemberName 14(VertexData) 2 "uv" Name 19 "vin" - Name 36 "position" + Name 36 "outStream.position" Name 39 "PS_IN" MemberName 39(PS_IN) 0 "color" MemberName 39(PS_IN) 1 "uv" Name 41 "outStream" Decorate 19(vin) Location 0 - Decorate 36(position) BuiltIn Position + Decorate 36(outStream.position) BuiltIn Position Decorate 41(outStream) Location 0 2: TypeVoid 3: TypeFunction 2 @@ -214,7 +214,7 @@ output primitive = triangle_strip 29: TypePointer Function 8(fvec2) 31: 12(int) Constant 0 35: TypePointer Output 7(fvec4) - 36(position): 35(ptr) Variable Output +36(outStream.position): 35(ptr) Variable Output 39(PS_IN): TypeStruct 7(fvec4) 8(fvec2) 40: TypePointer Output 39(PS_IN) 41(outStream): 40(ptr) Variable Output @@ -236,7 +236,7 @@ output primitive = triangle_strip Store 34 33 37: 23(ptr) AccessChain 11(vout) 31 38: 7(fvec4) Load 37 - Store 36(position) 38 + Store 36(outStream.position) 38 42: 23(ptr) AccessChain 11(vout) 13 43: 7(fvec4) Load 42 44: 35(ptr) AccessChain 41(outStream) 31 diff --git a/Test/baseResults/hlsl.structin.vert.out b/Test/baseResults/hlsl.structin.vert.out index 6195471..5e83ed4 100755 --- a/Test/baseResults/hlsl.structin.vert.out +++ b/Test/baseResults/hlsl.structin.vert.out @@ -28,36 +28,15 @@ Shader version: 450 0:11 'e' (layout(location=5 ) in 4-component vector of float) 0:13 Sequence 0:13 Sequence -0:13 move second child to first child (temp 4-component vector of float) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) +0:13 move second child to first child (temp 2-element array of 4-component vector of float) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) 0:13 Constant: 0:13 0 (const int) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) 0:13 Constant: 0:13 0 (const int) -0:13 move second child to first child (temp 4-component vector of float) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) -0:13 Constant: -0:13 1 (const int) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) -0:13 Constant: -0:13 1 (const int) 0:13 move second child to first child (temp 2-component vector of uint) 0:13 coord: direct index for structure (temp 2-component vector of uint) 0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) @@ -68,7 +47,7 @@ Shader version: 450 0:13 Constant: 0:13 1 (const int) 0:13 move second child to first child (temp 4-component vector of float) -0:13 b: direct index for structure (temp 4-component vector of float) +0:13 b: direct index for structure (smooth temp 4-component vector of float) 0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) 0:13 Constant: 0:13 2 (const int) @@ -121,36 +100,15 @@ Shader version: 450 0:11 'e' (layout(location=5 ) in 4-component vector of float) 0:13 Sequence 0:13 Sequence -0:13 move second child to first child (temp 4-component vector of float) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) +0:13 move second child to first child (temp 2-element array of 4-component vector of float) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) 0:13 Constant: 0:13 0 (const int) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) +0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) +0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) 0:13 Constant: 0:13 0 (const int) -0:13 move second child to first child (temp 4-component vector of float) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) -0:13 Constant: -0:13 1 (const int) -0:13 direct index (temp 4-component vector of float) -0:13 m: direct index for structure (temp 2-element array of 4-component vector of float) -0:13 'local' (temp structure{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, temp 4-component vector of float b}) -0:13 Constant: -0:13 0 (const int) -0:13 Constant: -0:13 1 (const int) 0:13 move second child to first child (temp 2-component vector of uint) 0:13 coord: direct index for structure (temp 2-component vector of uint) 0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) @@ -161,7 +119,7 @@ Shader version: 450 0:13 Constant: 0:13 1 (const int) 0:13 move second child to first child (temp 4-component vector of float) -0:13 b: direct index for structure (temp 4-component vector of float) +0:13 b: direct index for structure (smooth temp 4-component vector of float) 0:13 '@entryPointOutput' (out structure Position{temp 2-element array of 4-component vector of float m, temp 2-component vector of uint coord, smooth temp 4-component vector of float b}) 0:13 Constant: 0:13 2 (const int) @@ -183,12 +141,12 @@ Shader version: 450 // Module Version 10000 // Generated by (magic number): 80001 -// Id's are bound by 62 +// Id's are bound by 61 Capability Shader 1: ExtInstImport "GLSL.std.450" MemoryModel Logical GLSL450 - EntryPoint Vertex 4 "main" 18 20 24 32 35 42 61 + EntryPoint Vertex 4 "main" 18 20 24 32 35 42 60 Name 4 "main" Name 12 "VI" MemberName 12(VI) 0 "m" @@ -205,14 +163,14 @@ Shader version: 450 MemberName 40(VI) 1 "coord" MemberName 40(VI) 2 "b" Name 42 "@entryPointOutput" - Name 61 "b" + Name 60 "b" Decorate 18(m[1]) Location 2 Decorate 20(m[0]) Location 1 Decorate 24(coord) Location 3 Decorate 32(d) Location 0 Decorate 35(e) Location 5 Decorate 42(@entryPointOutput) BuiltIn Position - Decorate 61(b) Location 4 + Decorate 60(b) Location 4 2: TypeVoid 3: TypeFunction 2 6: TypeFloat 32 @@ -239,11 +197,13 @@ Shader version: 450 41: TypePointer Output 40(VI) 42(@entryPointOutput): 41(ptr) Variable Output 43: 15(int) Constant 0 - 46: TypePointer Output 7(fvec4) - 48: 15(int) Constant 1 - 52: TypePointer Function 11(ivec2) - 55: TypePointer Output 11(ivec2) - 61(b): 17(ptr) Variable Input + 44: TypePointer Function 10 + 47: TypePointer Output 10 + 49: 15(int) Constant 1 + 50: TypePointer Function 11(ivec2) + 53: TypePointer Output 11(ivec2) + 57: TypePointer Output 7(fvec4) + 60(b): 17(ptr) Variable Input 4(main): 2 Function None 3 5: Label 14(local): 13(ptr) Variable Function @@ -261,21 +221,17 @@ Shader version: 450 37: 7(fvec4) FAdd 34 36 39: 38(ptr) AccessChain 14(local) 16 Store 39 37 - 44: 38(ptr) AccessChain 14(local) 43 43 - 45: 7(fvec4) Load 44 - 47: 46(ptr) AccessChain 42(@entryPointOutput) 43 43 - Store 47 45 - 49: 38(ptr) AccessChain 14(local) 43 48 - 50: 7(fvec4) Load 49 - 51: 46(ptr) AccessChain 42(@entryPointOutput) 43 48 - Store 51 50 - 53: 52(ptr) AccessChain 14(local) 48 - 54: 11(ivec2) Load 53 - 56: 55(ptr) AccessChain 42(@entryPointOutput) 48 - Store 56 54 - 57: 38(ptr) AccessChain 14(local) 16 - 58: 7(fvec4) Load 57 - 59: 46(ptr) AccessChain 42(@entryPointOutput) 16 - Store 59 58 + 45: 44(ptr) AccessChain 14(local) 43 + 46: 10 Load 45 + 48: 47(ptr) AccessChain 42(@entryPointOutput) 43 + Store 48 46 + 51: 50(ptr) AccessChain 14(local) 49 + 52: 11(ivec2) Load 51 + 54: 53(ptr) AccessChain 42(@entryPointOutput) 49 + Store 54 52 + 55: 38(ptr) AccessChain 14(local) 16 + 56: 7(fvec4) Load 55 + 58: 57(ptr) AccessChain 42(@entryPointOutput) 16 + Store 58 56 Return FunctionEnd diff --git a/Test/hlsl.struct.split.array.geom b/Test/hlsl.struct.split.array.geom new file mode 100644 index 0000000..9008df1 --- /dev/null +++ b/Test/hlsl.struct.split.array.geom @@ -0,0 +1,21 @@ +struct PSInput +{ + float4 Pos : SV_POSITION; + float2 TexCoord : TEXCOORD; + float3 TerrainPos : TERRAINPOS; + uint VertexID : VertexID; +}; + +typedef PSInput foo_t[2][3]; + +[maxvertexcount(4)] +void main(point uint v[1] : VertexID, inout TriangleStream OutputStream) +{ + foo_t Verts; + + PSInput Out = (PSInput) 0; + + for (int x=0; x<2; ++x) + for (int y=0; y<2; ++y) + Verts[x][y] = Out; +} diff --git a/Test/hlsl.struct.split.nested.geom b/Test/hlsl.struct.split.nested.geom new file mode 100644 index 0000000..03bf38f --- /dev/null +++ b/Test/hlsl.struct.split.nested.geom @@ -0,0 +1,31 @@ + +struct STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO +{ + float m0_array[2]; + int m1; +}; + +struct PS_IN +{ + float4 pos : SV_Position; + float2 tc : TEXCOORD0; + // float c : SV_ClipDistance0; +}; + +struct GS_OUT +{ + PS_IN psIn; + STRUCT_WITH_NO_BUILTIN_INTERSTAGE_IO contains_no_builtin_io; +}; + + +[maxvertexcount(3)] +void main(triangle PS_IN tin[3], inout TriangleStream ts ) +{ + GS_OUT o; + + o.psIn.pos = float4(1,2,3,4); + o.psIn.tc = float2(5,6); + + ts.Append(o); +} diff --git a/Test/hlsl.struct.split.trivial.geom b/Test/hlsl.struct.split.trivial.geom new file mode 100644 index 0000000..343da38 --- /dev/null +++ b/Test/hlsl.struct.split.trivial.geom @@ -0,0 +1,21 @@ + +struct PS_IN +{ + float4 pos : SV_Position; +}; + +struct GS_OUT +{ + float4 pos : SV_Position; +}; + +[maxvertexcount(3)] +void main(triangle PS_IN i[3], inout TriangleStream ts) +{ + GS_OUT o; + + for (int x=0; x<3; ++x) { + o.pos = i[x].pos; + ts.Append(o); + } +} diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index bbadac5..6bd201d 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -1320,7 +1320,7 @@ public: virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); } // Return true if this is interstage IO - virtual bool isInterstageIO() const + virtual bool isBuiltInInterstageIO() const { switch (getQualifier().builtIn) { case EbvPosition: @@ -1401,28 +1401,28 @@ public: } // Recursively checks if the type contains an interstage IO builtin - virtual bool containsInterstageIO() const + virtual bool containsBuiltInInterstageIO() const { - if (isInterstageIO()) + if (isBuiltInInterstageIO()) return true; if (! structure) return false; for (unsigned int i = 0; i < structure->size(); ++i) { - if ((*structure)[i].type->containsInterstageIO()) + if ((*structure)[i].type->containsBuiltInInterstageIO()) return true; } return false; } // Recursively checks whether a struct contains only interstage IO - virtual bool containsOnlyInterstageIO() const + virtual bool containsOnlyBuiltInInterstageIO() const { if (! structure) - return isInterstageIO(); + return isBuiltInInterstageIO(); for (unsigned int i = 0; i < structure->size(); ++i) { - if (!(*structure)[i].type->containsOnlyInterstageIO()) + if (!(*structure)[i].type->containsOnlyBuiltInInterstageIO()) return false; } return true; diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 7fdca87..3faf63a 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -205,7 +205,10 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.stringtoken.frag", "main"}, {"hlsl.string.frag", "main"}, {"hlsl.struct.split-1.vert", "main"}, + {"hlsl.struct.split.array.geom", "main"}, {"hlsl.struct.split.call.vert", "main"}, + {"hlsl.struct.split.nested.geom", "main"}, + {"hlsl.struct.split.trivial.geom", "main"}, {"hlsl.struct.split.trivial.vert", "main"}, {"hlsl.structarray.flatten.frag", "main"}, {"hlsl.structarray.flatten.geom", "main"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index b874aa8..bce43ed 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -478,7 +478,7 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type) // type_specifier if (! acceptType(type)) { // If this is not a type, we may have inadvertently gone down a wrong path - // py parsing "sample", which can be treated like either an identifier or a + // by parsing "sample", which can be treated like either an identifier or a // qualifier. Back it out, if we did. if (qualifier.sample) recedeToken(); diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index c81c3a2..1b1a782 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -59,9 +59,12 @@ HlslParseContext::HlslParseContext(TSymbolTable& symbolTable, TIntermediate& int loopNestingLevel(0), annotationNestingLevel(0), structNestingLevel(0), controlFlowNestingLevel(0), postEntryPointReturn(false), limits(resources.limits), + inEntryPoint(false), entryPointOutput(nullptr), nextInLocation(0), nextOutLocation(0), - sourceEntryPointName(sourceEntryPointName) + sourceEntryPointName(sourceEntryPointName), + builtInIoIndex(nullptr), + builtInIoBase(nullptr) { globalUniformDefaults.clear(); globalUniformDefaults.layoutMatrix = ElmRowMajor; @@ -656,11 +659,13 @@ TIntermTyped* HlslParseContext::handleBracketDereference(const TSourceLoc& loc, if (base->getAsSymbolNode() && (wasFlattened(base) || shouldFlatten(base->getType()))) { if (index->getQualifier().storage != EvqConst) - error(loc, "Invalid variable index to flattened uniform array", base->getAsSymbolNode()->getName().c_str(), ""); + error(loc, "Invalid variable index to flattened array", base->getAsSymbolNode()->getName().c_str(), ""); result = flattenAccess(base, indexValue); flattened = (result != base); } else { + splitAccessArray(loc, base, index); + if (index->getQualifier().storage == EvqConst) { if (base->getType().isImplicitlySizedArray()) updateImplicitArraySize(loc, base, indexValue); @@ -765,11 +770,9 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt } } else if (field == "Append" || field == "RestartStrip") { - // These methods only valid on stage in variables - // TODO: ... which are stream out types, if there's any way to test that here. - if (base->getType().getQualifier().storage == EvqVaryingOut) { - return intermediate.addMethod(base, TType(EbtVoid), &field, loc); - } + // We cannot check the type here: it may be sanitized if we're not compiling a geometry shader, but + // the code is around in the shader source. + return intermediate.addMethod(base, TType(EbtVoid), &field, loc); } // It's not .length() if we get to here. @@ -838,7 +841,7 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt result = flattenAccess(base, member); } else { // Update the base and member to access if this was a split structure. - result = splitAccess(loc, base, member); + result = splitAccessStruct(loc, base, member); fields = base->getType().getStruct(); if (result == nullptr) { @@ -859,23 +862,20 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt return result; } -// Determine whether we should split this structure -bool HlslParseContext::shouldSplit(const TSourceLoc& loc, const TType& type) +// Determine whether we should split this type +bool HlslParseContext::shouldSplit(const TType& type) { if (! inEntryPoint) return false; const TStorageQualifier qualifier = type.getQualifier().storage; - if (type.containsInterstageIO() && type.containsStructure()) - error(loc, "structure splitting not yet supported on nested structures", "", ""); - // If it contains interstage IO, but not ONLY interstage IO, split the struct. - return (type.containsInterstageIO() && !type.containsOnlyInterstageIO()) && + return type.isStruct() && type.containsBuiltInInterstageIO() && (qualifier == EvqVaryingIn || qualifier == EvqVaryingOut); } -// Split the type of the node into two structs: +// Split the type of the given node into two structs: // 1. interstage IO // 2. everything else // IO members are put into the ioStruct. The type is modified to remove them. @@ -890,38 +890,59 @@ void HlslParseContext::split(TIntermTyped* node) return; // Create a new variable: - splitIoVars[symNode->getId()] = makeInternalVariable(symNode->getName(), split(*symNode->getType().clone())); + TType& splitType = split(*symNode->getType().clone(), symNode->getName()); + + splitIoVars[symNode->getId()] = makeInternalVariable(symNode->getName(), splitType); } -// Split the type of the variable into two structs: +// Split the type of the given variable into two structs: void HlslParseContext::split(const TVariable& variable) { const TType& type = variable.getType(); + TString name = (&variable == entryPointOutput) ? "" : variable.getName(); + // Create a new variable: - splitIoVars[variable.getUniqueId()] = makeInternalVariable(variable.getName(), split(*type.clone())); + TType& splitType = split(*type.clone(), name); + + splitIoVars[variable.getUniqueId()] = makeInternalVariable(variable.getName(), splitType); } // Recursive implementation of split(const TVariable& variable). // Returns reference to the modified type. -TType& HlslParseContext::split(TType& type) +TType& HlslParseContext::split(TType& type, TString name, const TType* outerStructType) { + const TArraySizes* arraySizes = nullptr; + + // At the outer-most scope, remember the struct type so we can examine its storage class + // at deeper levels. + if (outerStructType == nullptr) + outerStructType = &type; + + if (type.isArray()) + arraySizes = &type.getArraySizes(); + // We can ignore arrayness: it's uninvolved. if (type.isStruct()) { TTypeList* userStructure = type.getWritableStruct(); - // Get iterator to (now at end) set of iterstage IO members + // Get iterator to (now at end) set of builtin iterstage IO members const auto firstIo = std::stable_partition(userStructure->begin(), userStructure->end(), - [](const TTypeLoc& t) {return !t.type->isInterstageIO();}); + [](const TTypeLoc& t) {return !t.type->isBuiltInInterstageIO();}); - // Move these to the IO. + // Move those to the builtin IO. However, we also propagate arrayness (just one level is handled + // now) to this variable. for (auto ioType = firstIo; ioType != userStructure->end(); ++ioType) { const TType& memberType = *ioType->type; - TVariable* ioVar = makeInternalVariable(memberType.getFieldName(), memberType); + TVariable* ioVar = makeInternalVariable(name + (name.empty() ? "" : ".") + memberType.getFieldName(), memberType); + + if (arraySizes) + ioVar->getWritableType().newArraySizes(*arraySizes); + + interstageBuiltInIo[tInterstageIoData(memberType, *outerStructType)] = ioVar; // Merge qualifier from the user structure - mergeQualifiers(ioVar->getWritableType().getQualifier(), type.getQualifier()); - interstageIo[memberType.getQualifier().builtIn] = ioVar; + mergeQualifiers(ioVar->getWritableType().getQualifier(), outerStructType->getQualifier()); } // Erase the IO vars from the user structure. @@ -929,7 +950,9 @@ TType& HlslParseContext::split(TType& type) // Recurse further into the members. for (unsigned int i = 0; i < userStructure->size(); ++i) - split(*(*userStructure)[i].type); + split(*(*userStructure)[i].type, + name + (name.empty() ? "" : ".") + (*userStructure)[i].type->getFieldName(), + outerStructType); } return type; @@ -953,11 +976,6 @@ bool HlslParseContext::shouldFlattenIO(const TType& type) const if (!type.isStruct()) return false; - // Regardless of stage, we flatten IO structs containing only interstage IO, - // to avoid degenerate structure splitting. - if (type.containsOnlyInterstageIO()) - return true; - return ((language == EShLangVertex && qualifier == EvqVaryingIn) || (language == EShLangFragment && qualifier == EvqVaryingOut)); } @@ -1015,13 +1033,6 @@ void HlslParseContext::flatten(const TSourceLoc& loc, const TVariable& variable) int HlslParseContext::flatten(const TSourceLoc& loc, const TVariable& variable, const TType& type, TFlattenData& flattenData, TString name) { - // This should be handled by structure splitting, not flattening. - if (language == EShLangGeometry) { - const TType derefType(type, 0); - if (!isFinalFlattening(derefType) && type.getQualifier().storage == EvqVaryingIn) - error(loc, "recursive type not supported in GS input", variable.getName().c_str(), ""); - } - // If something is an arrayed struct, the array flattener will recursively call flatten() // to then flatten the struct, so this is an "if else": we don't do both. if (type.isArray()) @@ -1207,16 +1218,39 @@ TVariable* HlslParseContext::getSplitIoVar(const TIntermTyped* node) const return getSplitIoVar(symbolNode->getId()); } +// Remember the index used to dereference into this structure, in case it has to be moved to a +// split-off builtin IO member. +void HlslParseContext::splitAccessArray(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index) +{ + const TVariable* splitIoVar = getSplitIoVar(base); + + // Not a split structure + if (splitIoVar == nullptr) + return; + + if (builtInIoBase) { + error(loc, "only one array dimension supported for builtIn IO variable", "", ""); + return; + } + + builtInIoBase = base; + builtInIoIndex = index; +} + -// Turn an access into an aggregate that was split to instead be -// an access to either the modified variable, or one of the split -// member variables. -TIntermTyped* HlslParseContext::splitAccess(const TSourceLoc& loc, TIntermTyped*& base, int& member) +// Turn an access into an struct that was split to instead be an +// access to either the modified structure, or a direct reference to +// one of the split member variables. +TIntermTyped* HlslParseContext::splitAccessStruct(const TSourceLoc& loc, TIntermTyped*& base, int& member) { // nothing to do - if (base == nullptr || base->getAsSymbolNode() == nullptr) + if (base == nullptr) return nullptr; + // We have a pending bracket reference to an outer struct that we may want to move to an inner member. + if (builtInIoBase) + base = builtInIoBase; + const TVariable* splitIoVar = getSplitIoVar(base); if (splitIoVar == nullptr) @@ -1224,16 +1258,33 @@ TIntermTyped* HlslParseContext::splitAccess(const TSourceLoc& loc, TIntermTyped* const TTypeList& members = *base->getType().getStruct(); - if (members[member].type->isInterstageIO()) { - // It's one of the interstage IO variables we split out. - return intermediate.addSymbol(*interstageIo[members[member].type->getQualifier().builtIn], loc); + const TType& memberType = *members[member].type; + + if (memberType.isBuiltInInterstageIO()) { + // It's one of the interstage IO variables we split off. + TIntermTyped* builtIn = intermediate.addSymbol(*interstageBuiltInIo[tInterstageIoData(memberType, base->getType())], loc); + + // If there's an array reference to an outer split struct, we re-apply it here. + if (builtInIoIndex != nullptr) { + if (builtInIoIndex->getQualifier().storage == EvqConst) + builtIn = intermediate.addIndex(EOpIndexDirect, builtIn, builtInIoIndex, loc); + else + builtIn = intermediate.addIndex(EOpIndexIndirect, builtIn, builtInIoIndex, loc); + + builtIn->setType(memberType); + + builtInIoIndex = nullptr; + builtInIoBase = nullptr; + } + + return builtIn; } else { // It's not an IO variable. Find the equivalent index into the new variable. base = intermediate.addSymbol(*splitIoVar, loc); int newMember = 0; for (int m=0; misInterstageIO()) + if (!members[m].type->isBuiltInInterstageIO()) ++newMember; member = newMember; @@ -1270,7 +1321,13 @@ void HlslParseContext::assignLocations(TVariable& variable) for (auto member = memberList.begin(); member != memberList.end(); ++member) assignLocation(**member); } else if (wasSplit(variable.getUniqueId())) { - assignLocation(*getSplitIoVar(&variable)); + TVariable* splitIoVar = getSplitIoVar(&variable); + const TTypeList* structure = splitIoVar->getType().getStruct(); + // Struct splitting can produce empty structures if the only members of the + // struct were builtin interstage IO types. Only assign locations if it + // isn't a struct, or is a non-empty struct. + if (structure == nullptr || !structure->empty()) + assignLocation(*splitIoVar); } else { assignLocation(variable); } @@ -1321,19 +1378,17 @@ TFunction& HlslParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFu // Add interstage IO variables to the linkage in canonical order. void HlslParseContext::addInterstageIoToLinkage() { - if (inEntryPoint) { - std::vector io; - io.reserve(interstageIo.size()); + std::vector io; + io.reserve(interstageBuiltInIo.size()); - for (auto ioVar = interstageIo.begin(); ioVar != interstageIo.end(); ++ioVar) - io.push_back(ioVar->first); + for (auto ioVar = interstageBuiltInIo.begin(); ioVar != interstageBuiltInIo.end(); ++ioVar) + io.push_back(ioVar->first); - // Our canonical order is the TBuiltInVariable value order. - std::sort(io.begin(), io.end()); + // Our canonical order is the TBuiltInVariable numeric order. + std::sort(io.begin(), io.end()); - for (int ioVar = 0; ioVar < int(io.size()); ++ioVar) - trackLinkageDeferred(*interstageIo[io[ioVar]]); - } + for (int idx = 0; idx < int(io.size()); ++idx) + trackLinkageDeferred(*interstageBuiltInIo[io[idx]]); } // @@ -1374,7 +1429,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l if (entryPointOutput) { if (shouldFlatten(entryPointOutput->getType())) flatten(loc, *entryPointOutput); - if (shouldSplit(loc, entryPointOutput->getType())) + if (shouldSplit(entryPointOutput->getType())) split(*entryPointOutput); assignLocations(*entryPointOutput); } @@ -1421,7 +1476,7 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l if (inEntryPoint) { if (shouldFlatten(*param.type)) flatten(loc, *variable); - if (shouldSplit(loc, *param.type)) + if (shouldSplit(*param.type)) split(*variable); assignLocations(*variable); } @@ -1593,15 +1648,15 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op if (left == nullptr || right == nullptr) return nullptr; - const bool splitLeft = wasSplit(left); - const bool splitRight = wasSplit(right); + const bool isSplitLeft = wasSplit(left); + const bool isSplitRight = wasSplit(right); - const bool flattenLeft = wasFlattened(left); - const bool flattenRight = wasFlattened(right); + const bool isFlattenLeft = wasFlattened(left); + const bool isFlattenRight = wasFlattened(right); // OK to do a single assign if both are split, or both are unsplit. But if one is and the other // isn't, we fall back to a memberwise copy. - if (! flattenLeft && ! flattenRight && !splitLeft && !splitRight) + if (! isFlattenLeft && ! isFlattenRight && !isSplitLeft && !isSplitRight) return intermediate.addAssign(op, left, right, loc); TIntermAggregate* assignList = nullptr; @@ -1627,10 +1682,10 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op if (left->getType().isArray()) memberCount = left->getType().getCumulativeArraySize(); - if (flattenLeft) + if (isFlattenLeft) leftVariables = &flattenMap.find(left->getAsSymbolNode()->getId())->second.members; - if (flattenRight) { + if (isFlattenRight) { rightVariables = &flattenMap.find(right->getAsSymbolNode()->getId())->second.members; } else { // The RHS is not flattened. There are several cases: @@ -1658,19 +1713,30 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op int memberIdx = 0; - const auto getMember = [&](bool flatten, bool split, TIntermTyped* node, - const TVector& memberVariables, int member, - TOperator op, const TType& memberType) -> TIntermTyped * { + // We track the outer-most aggregate, so that we can use its storage class later. + const TIntermTyped* outerLeft = left; + const TIntermTyped* outerRight = right; + + const auto getMember = [&](bool isLeft, TIntermTyped* node, int member, TIntermTyped* splitNode, int splitMember) -> TIntermTyped * { TIntermTyped* subTree; - if (split && memberType.isInterstageIO()) { - // copy from interstage IO variable if needed - subTree = intermediate.addSymbol(*interstageIo.find(memberType.getQualifier().builtIn)->second); - } else if (flatten && isFinalFlattening(memberType)) { - subTree = intermediate.addSymbol(*memberVariables[memberIdx++]); + const bool flattened = isLeft ? isFlattenLeft : isFlattenRight; + const bool split = isLeft ? isSplitLeft : isSplitRight; + const TIntermTyped* outer = isLeft ? outerLeft : outerRight; + const TVector& flatVariables = isLeft ? *leftVariables : *rightVariables; + const TOperator op = node->getType().isArray() ? EOpIndexDirect : EOpIndexDirectStruct; + const TType derefType(node->getType(), member); + + if (split && derefType.isBuiltInInterstageIO()) { + // copy from interstage IO builtin if needed + subTree = intermediate.addSymbol(*interstageBuiltInIo.find(tInterstageIoData(derefType, outer->getType()))->second); + } else if (flattened && isFinalFlattening(derefType)) { + subTree = intermediate.addSymbol(*flatVariables[memberIdx++]); } else { - subTree = intermediate.addIndex(op, node, intermediate.addConstantUnion(member, loc), loc); - subTree->setType(memberType); + const TType splitDerefType(splitNode->getType(), splitMember); + + subTree = intermediate.addIndex(op, splitNode, intermediate.addConstantUnion(splitMember, loc), loc); + subTree->setType(splitDerefType); } return subTree; @@ -1682,44 +1748,34 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op cloneSymNode ? intermediate.addSymbol(*cloneSymNode) : right; - TIntermTyped* leftVar = left; - TIntermTyped* rightVar = right; - // If either left or right was a split structure, use the split form when reading and writing - if (splitLeft) - leftVar = intermediate.addSymbol(*getSplitIoVar(left), loc); - - if (splitRight) - rightVar = intermediate.addSymbol(*getSplitIoVar(right), loc); - // Cannot use auto here, because this is recursive, and auto can't work out the type without seeing the // whole thing. So, we'll resort to an explicit type via std::function. - const std::function - traverse = [&](TIntermTyped* left, TIntermTyped* right) -> void { + const std::function + traverse = [&](TIntermTyped* left, TIntermTyped* right, TIntermTyped* splitLeft, TIntermTyped* splitRight) -> void { // If we get here, we are assigning to or from a whole array or struct that must be // flattened, so have to do member-by-member assignment: if (left->getType().isArray()) { - // array case const TType dereferencedType(left->getType(), 0); + // array case for (int element=0; element < left->getType().getOuterArraySize(); ++element) { // Add a new AST symbol node if we have a temp variable holding a complex RHS. - TIntermTyped* subRight = getMember(flattenRight, splitRight, right, *rightVariables, element, - EOpIndexDirect, dereferencedType); - TIntermTyped* subLeft = getMember(flattenLeft, splitLeft, left, *leftVariables, element, - EOpIndexDirect, dereferencedType); + TIntermTyped* subLeft = getMember(true, left, element, left, element); + TIntermTyped* subRight = getMember(false, right, element, right, element); if (isFinalFlattening(dereferencedType)) assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc); else - traverse(subLeft, subRight); + traverse(subLeft, subRight, splitLeft, splitRight); } } else if (left->getType().isStruct()) { // struct case const auto& membersL = *left->getType().getStruct(); const auto& membersR = *right->getType().getStruct(); - // These track the members in the split structures corresponding to the same in the unsplit structures. + // These track the members in the split structures corresponding to the same in the unsplit structures, + // which we traverse in parallel. int memberL = 0; int memberR = 0; @@ -1727,21 +1783,27 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op const TType& typeL = *membersL[member].type; const TType& typeR = *membersR[member].type; - TIntermTyped* subLeft = getMember(flattenLeft, splitLeft, leftVar, *leftVariables, - memberL, EOpIndexDirectStruct, typeL); - TIntermTyped* subRight = getMember(flattenRight, splitRight, rightVar, *rightVariables, - memberR, EOpIndexDirectStruct, typeR); - - if (!isFinalFlattening(typeL)) { - // TODO: if we're not flattening, that means we got here because of struct splitting, and - // we could copy whole sub-structures at once as long as they do not contain interstage IO themselves. - traverse(subLeft, subRight); + TIntermTyped* subLeft = getMember(true, left, member, left, member); + TIntermTyped* subRight = getMember(false, right, member, right, member); + + // If there is no splitting, use the same values to avoid inefficiency. + TIntermTyped* subSplitLeft = isSplitLeft ? getMember(true, left, member, splitLeft, memberL) : subLeft; + TIntermTyped* subSplitRight = isSplitRight ? getMember(false, right, member, splitRight, memberR) : subRight; + + // If this is the final flattening (no nested types below to flatten) we'll copy the member, else + // recurse into the type hierarchy. However, if splitting the struct, that means we can copy a whole + // subtree here IFF it does not itself contain any interstage built-in IO variables, so we only have to + // recurse into it if there's something for splitting to do. That can save a lot of AST verbosity for + // a bunch of memberwise copies. + if (isFinalFlattening(typeL) || (!isFlattenLeft && !isFlattenRight && + !typeL.containsBuiltInInterstageIO() && !typeR.containsBuiltInInterstageIO())) { + assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subSplitLeft, subSplitRight, loc), loc); } else { - assignList = intermediate.growAggregate(assignList, intermediate.addAssign(op, subLeft, subRight, loc), loc); + traverse(subLeft, subRight, subSplitLeft, subSplitRight); } - memberL += (typeL.isInterstageIO() ? 0 : 1); - memberR += (typeR.isInterstageIO() ? 0 : 1); + memberL += (typeL.isBuiltInInterstageIO() ? 0 : 1); + memberR += (typeR.isBuiltInInterstageIO() ? 0 : 1); } } else { assert(0); // we should never be called on a non-flattenable thing, because @@ -1750,8 +1812,19 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op }; + TIntermTyped* splitLeft = left; + TIntermTyped* splitRight = right; + + // If either left or right was a split structure, we must read or write it, but still have to + // parallel-recurse through the unsplit structure to identify the builtin IO vars. + if (isSplitLeft) + splitLeft = intermediate.addSymbol(*getSplitIoVar(left), loc); + + if (isSplitRight) + splitRight = intermediate.addSymbol(*getSplitIoVar(right), loc); + // This makes the whole assignment, recursing through subtypes as needed. - traverse(left, right); + traverse(left, right, splitLeft, splitRight); assert(assignList != nullptr); assignList->setOperator(EOpSequence); @@ -4962,9 +5035,17 @@ TType* HlslParseContext::sanitizeType(TType* type) if (sanitizedTypeIter != sanitizedTypeMap.end()) { // We've sanitized this before. Use that one. - return sanitizedTypeIter->second; + TType* sanitizedType = new TType(); + sanitizedType->shallowCopy(*sanitizedTypeIter->second); + + // Arrayness is not part of the sanitized type. Use the input type's arrayness. + if (type->isArray()) + sanitizedType->newArraySizes(type->getArraySizes()); + else + sanitizedType->clearArraySizes(); + return sanitizedType; } else { - if (type->containsInterstageIO()) { + if (type->containsBuiltInInterstageIO()) { // This means the type contains interstage IO, but we've never encountered it before. // Copy it, sanitize it, and remember it in the sanitizedTypeMap TType* sanitizedType = type->clone(); @@ -5000,7 +5081,7 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, TString& i inheritGlobalDefaults(type.getQualifier()); const bool flattenVar = shouldFlatten(type); - const bool splitVar = shouldSplit(loc, type); + const bool splitVar = shouldSplit(type); // Type sanitization: if this is declaring a variable of a type that contains // interstage IO, we want to make it a temporary. diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 6e7d77a..6b4cc1d 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -209,9 +209,10 @@ protected: bool isFinalFlattening(const TType& type) const { return !(type.isStruct() || type.isArray()); } // Structure splitting (splits interstage builtin types into its own struct) - bool shouldSplit(const TSourceLoc& loc, const TType&); - TIntermTyped* splitAccess(const TSourceLoc& loc, TIntermTyped*& base, int& member); - TType& split(TType& type); + bool shouldSplit(const TType&); + TIntermTyped* splitAccessStruct(const TSourceLoc& loc, TIntermTyped*& base, int& member); + void splitAccessArray(const TSourceLoc& loc, TIntermTyped* base, TIntermTyped* index); + TType& split(TType& type, TString name, const TType* outerStructType = nullptr); void split(TIntermTyped*); void split(const TVariable&); bool wasSplit(const TIntermTyped* node) const; @@ -301,8 +302,32 @@ protected: TMap sanitizedTypeMap; // Structure splitting data: - TMap interstageIo; // new structure created for interstage IO from user structs. - TMap splitIoVars; // individual flattened variables + TMap splitIoVars; // variables with the builtin interstage IO removed, indexed by unique ID. + + // The builtin interstage IO map considers e.g, EvqPosition on input and output separately, so that we + // can build the linkage correctly if position appears on both sides. Otherwise, multiple positions + // are considered identical. + struct tInterstageIoData { + tInterstageIoData(const TType& memberType, const TType& storageType) : + builtIn(memberType.getQualifier().builtIn), + storage(storageType.getQualifier().storage) { } + + TBuiltInVariable builtIn; + TStorageQualifier storage; + + // ordering for maps + bool operator<(const tInterstageIoData d) const { + return (builtIn != d.builtIn) ? (builtIn < d.builtIn) : (storage < d.storage); + } + }; + + TMap interstageBuiltInIo; // individual builtin interstage IO vars, inxed by builtin type. + + // We have to move array references to structs containing builtin interstage IO to the split variables. + // This is only handled for one level. This stores the index, because we'll need it in the future, since + // unlike normal array references, here the index happens before we discover what it applies to. + TIntermTyped* builtInIoIndex; + TIntermTyped* builtInIoBase; unsigned int nextInLocation; unsigned int nextOutLocation; -- 2.7.4