From c59916710e2663e3ed954fefb65809e1b4d8dd6e Mon Sep 17 00:00:00 2001 From: LoopDawg Date: Thu, 17 May 2018 13:03:12 -0600 Subject: [PATCH] HLSL: allow self-type cast (as no-op passthrough) Previously, casting an object of a struct type to an identical type would produce an error. This PR allows this case. As a side-effect of the change, several self-type casts in existing tests go away. For example: 0:10 Construct float ( temp float) 0:10 'f' ( in float) becomes this (without the unneeded constructor op): 0:10 'f' ( in float) For vector or array types this can result in somewhat less overall code. Fixes: #1218 --- Test/baseResults/hlsl.cast.frag.out | 71 ++++++------- Test/baseResults/hlsl.self_cast.frag.out | 130 +++++++++++++++++++++++ Test/baseResults/hlsl.shapeConv.frag.out | 6 +- Test/hlsl.self_cast.frag | 25 +++++ gtests/Hlsl.FromFile.cpp | 1 + hlsl/hlslParseHelper.cpp | 20 +++- 6 files changed, 205 insertions(+), 48 deletions(-) create mode 100644 Test/baseResults/hlsl.self_cast.frag.out create mode 100644 Test/hlsl.self_cast.frag diff --git a/Test/baseResults/hlsl.cast.frag.out b/Test/baseResults/hlsl.cast.frag.out index 2fb376952..9eccd51fc 100755 --- a/Test/baseResults/hlsl.cast.frag.out +++ b/Test/baseResults/hlsl.cast.frag.out @@ -9,8 +9,7 @@ gl_FragCoord origin is upper left 0:3 Branch: Return with expression 0:3 add ( temp 4-component vector of float) 0:3 add ( temp 4-component vector of float) -0:3 Construct vec4 ( temp 4-component vector of float) -0:3 'input' ( in 4-component vector of float) +0:3 'input' ( in 4-component vector of float) 0:3 Convert int to float ( temp 4-component vector of float) 0:3 Convert float to int ( temp 4-component vector of int) 0:3 'input' ( in 4-component vector of float) @@ -47,8 +46,7 @@ gl_FragCoord origin is upper left 0:3 Branch: Return with expression 0:3 add ( temp 4-component vector of float) 0:3 add ( temp 4-component vector of float) -0:3 Construct vec4 ( temp 4-component vector of float) -0:3 'input' ( in 4-component vector of float) +0:3 'input' ( in 4-component vector of float) 0:3 Convert int to float ( temp 4-component vector of float) 0:3 Convert float to int ( temp 4-component vector of int) 0:3 'input' ( in 4-component vector of float) @@ -73,62 +71,57 @@ gl_FragCoord origin is upper left // Module Version 10000 // Generated by (magic number): 80006 -// Id's are bound by 39 +// Id's are bound by 34 Capability Shader 1: ExtInstImport "GLSL.std.450" MemoryModel Logical GLSL450 - EntryPoint Fragment 4 "PixelShaderFunction" 32 35 + EntryPoint Fragment 4 "PixelShaderFunction" 27 30 ExecutionMode 4 OriginUpperLeft Source HLSL 500 Name 4 "PixelShaderFunction" Name 11 "@PixelShaderFunction(vf4;" Name 10 "input" - Name 30 "input" - Name 32 "input" - Name 35 "@entryPointOutput" - Name 36 "param" - Decorate 32(input) Location 0 - Decorate 35(@entryPointOutput) Location 0 + Name 25 "input" + Name 27 "input" + Name 30 "@entryPointOutput" + Name 31 "param" + Decorate 27(input) Location 0 + Decorate 30(@entryPointOutput) Location 0 2: TypeVoid 3: TypeFunction 2 6: TypeFloat 32 7: TypeVector 6(float) 4 8: TypePointer Function 7(fvec4) 9: TypeFunction 7(fvec4) 8(ptr) - 20: TypeInt 32 1 - 21: TypeVector 20(int) 4 - 25: 6(float) Constant 1067014160 - 26: 7(fvec4) ConstantComposite 25 25 25 25 - 31: TypePointer Input 7(fvec4) - 32(input): 31(ptr) Variable Input - 34: TypePointer Output 7(fvec4) -35(@entryPointOutput): 34(ptr) Variable Output + 15: TypeInt 32 1 + 16: TypeVector 15(int) 4 + 20: 6(float) Constant 1067014160 + 21: 7(fvec4) ConstantComposite 20 20 20 20 + 26: TypePointer Input 7(fvec4) + 27(input): 26(ptr) Variable Input + 29: TypePointer Output 7(fvec4) +30(@entryPointOutput): 29(ptr) Variable Output 4(PixelShaderFunction): 2 Function None 3 5: Label - 30(input): 8(ptr) Variable Function - 36(param): 8(ptr) Variable Function - 33: 7(fvec4) Load 32(input) - Store 30(input) 33 - 37: 7(fvec4) Load 30(input) - Store 36(param) 37 - 38: 7(fvec4) FunctionCall 11(@PixelShaderFunction(vf4;) 36(param) - Store 35(@entryPointOutput) 38 + 25(input): 8(ptr) Variable Function + 31(param): 8(ptr) Variable Function + 28: 7(fvec4) Load 27(input) + Store 25(input) 28 + 32: 7(fvec4) Load 25(input) + Store 31(param) 32 + 33: 7(fvec4) FunctionCall 11(@PixelShaderFunction(vf4;) 31(param) + Store 30(@entryPointOutput) 33 Return FunctionEnd 11(@PixelShaderFunction(vf4;): 7(fvec4) Function None 9 10(input): 8(ptr) FunctionParameter 12: Label 13: 7(fvec4) Load 10(input) - 14: 6(float) CompositeExtract 13 0 - 15: 6(float) CompositeExtract 13 1 - 16: 6(float) CompositeExtract 13 2 - 17: 6(float) CompositeExtract 13 3 - 18: 7(fvec4) CompositeConstruct 14 15 16 17 - 19: 7(fvec4) Load 10(input) - 22: 21(ivec4) ConvertFToS 19 - 23: 7(fvec4) ConvertSToF 22 - 24: 7(fvec4) FAdd 18 23 - 27: 7(fvec4) FAdd 24 26 - ReturnValue 27 + 14: 7(fvec4) Load 10(input) + 17: 16(ivec4) ConvertFToS 14 + 18: 7(fvec4) ConvertSToF 17 + 19: 7(fvec4) FAdd 13 18 + 22: 7(fvec4) FAdd 19 21 + ReturnValue 22 FunctionEnd diff --git a/Test/baseResults/hlsl.self_cast.frag.out b/Test/baseResults/hlsl.self_cast.frag.out new file mode 100644 index 000000000..b2decf34c --- /dev/null +++ b/Test/baseResults/hlsl.self_cast.frag.out @@ -0,0 +1,130 @@ +hlsl.self_cast.frag +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:5 Function Definition: @main( ( temp void) +0:5 Function Parameters: +0:? Sequence +0:? Sequence +0:8 Sequence +0:8 move second child to first child ( temp structure{}) +0:8 'b' ( temp structure{}) +0:8 'a' ( temp structure{}) +0:? Sequence +0:13 Sequence +0:13 move second child to first child ( temp structure{ temp float f}) +0:13 'b' ( temp structure{ temp float f}) +0:13 'a' ( temp structure{ temp float f}) +0:? Sequence +0:18 Sequence +0:18 move second child to first child ( temp 2-element array of structure{}) +0:18 'b' ( temp 2-element array of structure{}) +0:18 'a' ( temp 2-element array of structure{}) +0:? Sequence +0:23 Sequence +0:23 move second child to first child ( temp 2-element array of structure{ temp float f}) +0:23 'b' ( temp 2-element array of structure{ temp float f}) +0:23 'a' ( temp 2-element array of structure{ temp float f}) +0:5 Function Definition: main( ( temp void) +0:5 Function Parameters: +0:? Sequence +0:5 Function Call: @main( ( temp void) +0:? Linker Objects + + +Linked fragment stage: + + +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:5 Function Definition: @main( ( temp void) +0:5 Function Parameters: +0:? Sequence +0:? Sequence +0:8 Sequence +0:8 move second child to first child ( temp structure{}) +0:8 'b' ( temp structure{}) +0:8 'a' ( temp structure{}) +0:? Sequence +0:13 Sequence +0:13 move second child to first child ( temp structure{ temp float f}) +0:13 'b' ( temp structure{ temp float f}) +0:13 'a' ( temp structure{ temp float f}) +0:? Sequence +0:18 Sequence +0:18 move second child to first child ( temp 2-element array of structure{}) +0:18 'b' ( temp 2-element array of structure{}) +0:18 'a' ( temp 2-element array of structure{}) +0:? Sequence +0:23 Sequence +0:23 move second child to first child ( temp 2-element array of structure{ temp float f}) +0:23 'b' ( temp 2-element array of structure{ temp float f}) +0:23 'a' ( temp 2-element array of structure{ temp float f}) +0:5 Function Definition: main( ( temp void) +0:5 Function Parameters: +0:? Sequence +0:5 Function Call: @main( ( temp void) +0:? Linker Objects + +// Module Version 10000 +// Generated by (magic number): 80006 +// Id's are bound by 32 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginUpperLeft + Source HLSL 500 + Name 4 "main" + Name 6 "@main(" + Name 8 "Test0" + Name 10 "b" + Name 11 "a" + Name 14 "Test1" + MemberName 14(Test1) 0 "f" + Name 16 "b" + Name 17 "a" + Name 23 "b" + Name 24 "a" + Name 28 "b" + Name 29 "a" + 2: TypeVoid + 3: TypeFunction 2 + 8(Test0): TypeStruct + 9: TypePointer Function 8(Test0) + 13: TypeFloat 32 + 14(Test1): TypeStruct 13(float) + 15: TypePointer Function 14(Test1) + 19: TypeInt 32 0 + 20: 19(int) Constant 2 + 21: TypeArray 8(Test0) 20 + 22: TypePointer Function 21 + 26: TypeArray 14(Test1) 20 + 27: TypePointer Function 26 + 4(main): 2 Function None 3 + 5: Label + 31: 2 FunctionCall 6(@main() + Return + FunctionEnd + 6(@main(): 2 Function None 3 + 7: Label + 10(b): 9(ptr) Variable Function + 11(a): 9(ptr) Variable Function + 16(b): 15(ptr) Variable Function + 17(a): 15(ptr) Variable Function + 23(b): 22(ptr) Variable Function + 24(a): 22(ptr) Variable Function + 28(b): 27(ptr) Variable Function + 29(a): 27(ptr) Variable Function + 12: 8(Test0) Load 11(a) + Store 10(b) 12 + 18: 14(Test1) Load 17(a) + Store 16(b) 18 + 25: 21 Load 24(a) + Store 23(b) 25 + 30: 26 Load 29(a) + Store 28(b) 30 + Return + FunctionEnd diff --git a/Test/baseResults/hlsl.shapeConv.frag.out b/Test/baseResults/hlsl.shapeConv.frag.out index 0a2a5b267..15ebe4dbc 100755 --- a/Test/baseResults/hlsl.shapeConv.frag.out +++ b/Test/baseResults/hlsl.shapeConv.frag.out @@ -40,8 +40,7 @@ gl_FragCoord origin is upper left 0:10 move second child to first child ( temp 3-component vector of float) 0:10 'u' ( temp 3-component vector of float) 0:10 Construct vec3 ( temp 3-component vector of float) -0:10 Construct float ( temp float) -0:10 'f' ( in float) +0:10 'f' ( in float) 0:11 Sequence 0:11 move second child to first child ( temp 2-component vector of float) 0:11 'w' ( temp 2-component vector of float) @@ -203,8 +202,7 @@ gl_FragCoord origin is upper left 0:10 move second child to first child ( temp 3-component vector of float) 0:10 'u' ( temp 3-component vector of float) 0:10 Construct vec3 ( temp 3-component vector of float) -0:10 Construct float ( temp float) -0:10 'f' ( in float) +0:10 'f' ( in float) 0:11 Sequence 0:11 move second child to first child ( temp 2-component vector of float) 0:11 'w' ( temp 2-component vector of float) diff --git a/Test/hlsl.self_cast.frag b/Test/hlsl.self_cast.frag new file mode 100644 index 000000000..8ef402708 --- /dev/null +++ b/Test/hlsl.self_cast.frag @@ -0,0 +1,25 @@ +struct Test0 {}; +struct Test1 { float f; }; + +void main() +{ + { + Test0 a; + Test0 b = (Test0)a; + } + + { + Test1 a; + Test1 b = (Test1)a; + } + + { + Test0 a[2]; + Test0 b[2] = (Test0[2])a; + } + + { + Test1 a[2]; + Test1 b[2] = (Test1[2])a; + } +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 390e3d370..861c09883 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -315,6 +315,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.semicolons.frag", "main"}, {"hlsl.shapeConv.frag", "main"}, {"hlsl.shapeConvRet.frag", "main"}, + {"hlsl.self_cast.frag", "main"}, {"hlsl.snorm.uav.comp", "main"}, {"hlsl.staticMemberFunction.frag", "main"}, {"hlsl.store.rwbyteaddressbuffer.type.comp", "main"}, diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 3ef9a5af0..d80f356b5 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -6401,12 +6401,18 @@ bool HlslParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node return true; } - if (op == EOpConstructStruct && ! type.isArray() && isScalarConstructor(node)) - return false; + if (op == EOpConstructStruct && ! type.isArray()) { + if (isScalarConstructor(node)) + return false; - if (op == EOpConstructStruct && ! type.isArray() && (int)type.getStruct()->size() != function.getParamCount()) { - error(loc, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); - return true; + // Self-type construction: e.g, we can construct a struct from a single identically typed object. + if (function.getParamCount() == 1 && type == *function[0].type) + return false; + + if ((int)type.getStruct()->size() != function.getParamCount()) { + error(loc, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); + return true; + } } if ((op != EOpConstructStruct && size != 1 && size < type.computeNumComponents()) || @@ -8132,6 +8138,10 @@ TIntermTyped* HlslParseContext::handleConstructor(const TSourceLoc& loc, TInterm if (node == nullptr) return nullptr; + // Construct identical type + if (type == node->getType()) + return node; + // Handle the idiom "(struct type)" if (type.isStruct() && isScalarConstructor(node)) { // 'node' will almost always get used multiple times, so should not be used directly,