From 265c0618b147478a6364d99ad4f00b33779675c7 Mon Sep 17 00:00:00 2001 From: steve-lunarg Date: Tue, 27 Sep 2016 10:57:35 -0600 Subject: [PATCH] HLSL: allow implicit array sizing. In HLSL array sizes need not be provided explicitly in all circumstances. For example, this is valid (note no number between the [ ]): // no explicit array size uniform float g_array[] = { 1, 2, 3, 4, 5 }; This PR does not attempt to validate most invalid cases. A new test is added to verify the resulting linker objects. --- .../hlsl.array.implicit-size.frag.out | 264 ++++++++++++++++++ Test/hlsl.array.implicit-size.frag | 31 ++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslGrammar.cpp | 29 +- 4 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 Test/baseResults/hlsl.array.implicit-size.frag.out create mode 100644 Test/hlsl.array.implicit-size.frag diff --git a/Test/baseResults/hlsl.array.implicit-size.frag.out b/Test/baseResults/hlsl.array.implicit-size.frag.out new file mode 100644 index 00000000..6345c89c --- /dev/null +++ b/Test/baseResults/hlsl.array.implicit-size.frag.out @@ -0,0 +1,264 @@ +hlsl.array.implicit-size.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:26 Function Definition: main(struct-PS_OUTPUT-vf41; (global void) +0:26 Function Parameters: +0:26 'ps_output' (out structure{temp 4-component vector of float color}) +0:? Sequence +0:28 Sequence +0:28 move second child to first child (temp 3-element array of float) +0:28 'l_array' (temp 3-element array of float) +0:28 Constant: +0:28 1.000000 +0:28 2.000000 +0:28 3.000000 +0:30 move second child to first child (temp 4-component vector of float) +0:30 color: direct index for structure (temp 4-component vector of float) +0:30 'ps_output' (out structure{temp 4-component vector of float color}) +0:30 Constant: +0:30 0 (const int) +0:30 Construct vec4 (temp 4-component vector of float) +0:30 add (temp float) +0:30 add (temp float) +0:30 add (temp float) +0:30 add (temp float) +0:30 direct index (temp float) +0:30 'g_array' (uniform 5-element array of float) +0:30 1.000000 +0:30 2.000000 +0:30 3.000000 +0:30 4.000000 +0:30 5.000000 +0:30 Constant: +0:30 0 (const int) +0:30 direct index (temp float) +0:30 'g_array' (uniform 5-element array of float) +0:30 1.000000 +0:30 2.000000 +0:30 3.000000 +0:30 4.000000 +0:30 5.000000 +0:30 Constant: +0:30 4 (const int) +0:30 direct index (temp float) +0:30 'l_array' (temp 3-element array of float) +0:30 Constant: +0:30 1 (const int) +0:30 f: direct index for structure (temp float) +0:30 direct index (temp structure{temp int i, temp float f}) +0:30 'g_mystruct' (uniform 2-element array of structure{temp int i, temp float f}) +0:30 1 (const int) +0:30 2.000000 +0:30 3 (const int) +0:30 4.000000 +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 1 (const int) +0:30 indirect index (temp float) +0:30 'g_array' (uniform 5-element array of float) +0:30 1.000000 +0:30 2.000000 +0:30 3.000000 +0:30 4.000000 +0:30 5.000000 +0:30 'idx' (temp void) +0:? Linker Objects +0:? 'g_array' (uniform 5-element array of float) +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:? 4.000000 +0:? 5.000000 +0:? 'g_array_unused' (uniform 7-element array of float) +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:? 4.000000 +0:? 5.000000 +0:? 6.000000 +0:? 7.000000 +0:? 'g_mystruct' (uniform 2-element array of structure{temp int i, temp float f}) +0:? 1 (const int) +0:? 2.000000 +0:? 3 (const int) +0:? 4.000000 + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:26 Function Definition: main(struct-PS_OUTPUT-vf41; (global void) +0:26 Function Parameters: +0:26 'ps_output' (out structure{temp 4-component vector of float color}) +0:? Sequence +0:28 Sequence +0:28 move second child to first child (temp 3-element array of float) +0:28 'l_array' (temp 3-element array of float) +0:28 Constant: +0:28 1.000000 +0:28 2.000000 +0:28 3.000000 +0:30 move second child to first child (temp 4-component vector of float) +0:30 color: direct index for structure (temp 4-component vector of float) +0:30 'ps_output' (out structure{temp 4-component vector of float color}) +0:30 Constant: +0:30 0 (const int) +0:30 Construct vec4 (temp 4-component vector of float) +0:30 add (temp float) +0:30 add (temp float) +0:30 add (temp float) +0:30 add (temp float) +0:30 direct index (temp float) +0:30 'g_array' (uniform 5-element array of float) +0:30 1.000000 +0:30 2.000000 +0:30 3.000000 +0:30 4.000000 +0:30 5.000000 +0:30 Constant: +0:30 0 (const int) +0:30 direct index (temp float) +0:30 'g_array' (uniform 5-element array of float) +0:30 1.000000 +0:30 2.000000 +0:30 3.000000 +0:30 4.000000 +0:30 5.000000 +0:30 Constant: +0:30 4 (const int) +0:30 direct index (temp float) +0:30 'l_array' (temp 3-element array of float) +0:30 Constant: +0:30 1 (const int) +0:30 f: direct index for structure (temp float) +0:30 direct index (temp structure{temp int i, temp float f}) +0:30 'g_mystruct' (uniform 2-element array of structure{temp int i, temp float f}) +0:30 1 (const int) +0:30 2.000000 +0:30 3 (const int) +0:30 4.000000 +0:30 Constant: +0:30 0 (const int) +0:30 Constant: +0:30 1 (const int) +0:30 indirect index (temp float) +0:30 'g_array' (uniform 5-element array of float) +0:30 1.000000 +0:30 2.000000 +0:30 3.000000 +0:30 4.000000 +0:30 5.000000 +0:30 'idx' (temp void) +0:? Linker Objects +0:? 'g_array' (uniform 5-element array of float) +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:? 4.000000 +0:? 5.000000 +0:? 'g_array_unused' (uniform 7-element array of float) +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:? 4.000000 +0:? 5.000000 +0:? 6.000000 +0:? 7.000000 +0:? 'g_mystruct' (uniform 2-element array of structure{temp int i, temp float f}) +0:? 1 (const int) +0:? 2.000000 +0:? 3 (const int) +0:? 4.000000 + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 62 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "PixelShaderFunction" + ExecutionMode 4 OriginUpperLeft + Name 4 "PixelShaderFunction" + Name 8 "PS_OUTPUT" + MemberName 8(PS_OUTPUT) 0 "color" + Name 12 "main(struct-PS_OUTPUT-vf41;" + Name 11 "ps_output" + Name 18 "l_array" + Name 28 "g_array" + Name 41 "mystruct" + MemberName 41(mystruct) 0 "i" + MemberName 41(mystruct) 1 "f" + Name 45 "g_mystruct" + Name 50 "idx" + Name 61 "g_array_unused" + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8(PS_OUTPUT): TypeStruct 7(fvec4) + 9: TypePointer Function 8(PS_OUTPUT) + 10: TypeFunction 2 9(ptr) + 14: TypeInt 32 0 + 15: 14(int) Constant 3 + 16: TypeArray 6(float) 15 + 17: TypePointer Function 16 + 19: 6(float) Constant 1065353216 + 20: 6(float) Constant 1073741824 + 21: 6(float) Constant 1077936128 + 22: 16 ConstantComposite 19 20 21 + 23: TypeInt 32 1 + 24: 23(int) Constant 0 + 25: 14(int) Constant 5 + 26: TypeArray 6(float) 25 + 27: TypePointer UniformConstant 26 + 28(g_array): 27(ptr) Variable UniformConstant + 29: TypePointer UniformConstant 6(float) + 32: 23(int) Constant 4 + 36: 23(int) Constant 1 + 37: TypePointer Function 6(float) + 41(mystruct): TypeStruct 23(int) 6(float) + 42: 14(int) Constant 2 + 43: TypeArray 41(mystruct) 42 + 44: TypePointer UniformConstant 43 + 45(g_mystruct): 44(ptr) Variable UniformConstant + 49: TypePointer Function 2 + 56: TypePointer Function 7(fvec4) + 58: 14(int) Constant 7 + 59: TypeArray 6(float) 58 + 60: TypePointer UniformConstant 59 +61(g_array_unused): 60(ptr) Variable UniformConstant +4(PixelShaderFunction): 2 Function None 3 + 5: Label + FunctionEnd +12(main(struct-PS_OUTPUT-vf41;): 2 Function None 10 + 11(ps_output): 9(ptr) FunctionParameter + 13: Label + 18(l_array): 17(ptr) Variable Function + 50(idx): 49(ptr) Variable Function + Store 18(l_array) 22 + 30: 29(ptr) AccessChain 28(g_array) 24 + 31: 6(float) Load 30 + 33: 29(ptr) AccessChain 28(g_array) 32 + 34: 6(float) Load 33 + 35: 6(float) FAdd 31 34 + 38: 37(ptr) AccessChain 18(l_array) 36 + 39: 6(float) Load 38 + 40: 6(float) FAdd 35 39 + 46: 29(ptr) AccessChain 45(g_mystruct) 24 36 + 47: 6(float) Load 46 + 48: 6(float) FAdd 40 47 + 51: 2 Load 50(idx) + 52: 29(ptr) AccessChain 28(g_array) 51 + 53: 6(float) Load 52 + 54: 6(float) FAdd 48 53 + 55: 7(fvec4) CompositeConstruct 54 54 54 54 + 57: 56(ptr) AccessChain 11(ps_output) 24 + Store 57 55 + Return + FunctionEnd diff --git a/Test/hlsl.array.implicit-size.frag b/Test/hlsl.array.implicit-size.frag new file mode 100644 index 00000000..11f93b5e --- /dev/null +++ b/Test/hlsl.array.implicit-size.frag @@ -0,0 +1,31 @@ + +// implicit sized array +uniform float g_array [ ] = { 1, 2, 3, 4, 5 }; + +// Unused implicit sized array +uniform float g_array_unused [ ] = { 1, 2, 3, 4, 5, 6, 7 }; + +// Test implicit size arrayed structs +uniform struct mystruct { + int i; + float f; +} g_mystruct[] = { + { 1, 2.0 }, + { 3, 4.0 }, +}; + +struct PS_OUTPUT { float4 color : SV_Target0; }; + +// INVALID: implicit size requires an initializer expression. +// uniform float bad[]; + +// INVALID: function parameters cannot be implicitly sized +// void BadFunction(int a[]) { } + +void main(out PS_OUTPUT ps_output) +{ + // implicit sized local array + float l_array[] = { 1, 2, 3 }; + + ps_output.color = g_array[0] + g_array[4] + l_array[1] + g_mystruct[0].f + g_array[idx]; +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 55450a74..2e191ba2 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -81,6 +81,7 @@ INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, ::testing::ValuesIn(std::vector{ {"hlsl.array.frag", "PixelShaderFunction"}, + {"hlsl.array.implicit-size.frag", "PixelShaderFunction"}, {"hlsl.assoc.frag", "PixelShaderFunction"}, {"hlsl.attribute.frag", "PixelShaderFunction"}, {"hlsl.buffer.frag", "PixelShaderFunction"}, diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 30d42f10..48698e5a 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -1515,8 +1515,14 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function) // array_specifier TArraySizes* arraySizes = nullptr; acceptArraySpecifier(arraySizes); - if (arraySizes) + if (arraySizes) { + if (arraySizes->isImplicit()) { + parseContext.error(token.loc, "function parameter array cannot be implicitly sized", "", ""); + return false; + } + type->newArraySizes(*arraySizes); + } // post_decls acceptPostDecls(type->getQualifier()); @@ -2601,6 +2607,7 @@ bool HlslGrammar::acceptDefaultLabel(TIntermNode*& statement) // array_specifier // : LEFT_BRACKET integer_expression RGHT_BRACKET post_decls // optional +// : LEFT_BRACKET RGHT_BRACKET post_decls // optional // void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes) { @@ -2610,21 +2617,25 @@ void HlslGrammar::acceptArraySpecifier(TArraySizes*& arraySizes) return; TSourceLoc loc = token.loc; - TIntermTyped* sizeExpr; - if (! acceptAssignmentExpression(sizeExpr)) { - expected("array-sizing expression"); - return; - } + TIntermTyped* sizeExpr = nullptr; + + // Array sizing expression is optional. If ommitted, array is implicitly sized. + const bool hasArraySize = acceptAssignmentExpression(sizeExpr); if (! acceptTokenClass(EHTokRightBracket)) { expected("]"); return; } - TArraySize arraySize; - parseContext.arraySizeCheck(loc, sizeExpr, arraySize); arraySizes = new TArraySizes; - arraySizes->addInnerSize(arraySize); + + if (hasArraySize) { + TArraySize arraySize; + parseContext.arraySizeCheck(loc, sizeExpr, arraySize); + arraySizes->addInnerSize(arraySize); + } else { + arraySizes->addInnerSize(); // implicitly sized + } } // post_decls