From 3778979cd49f2b4401589f0b4a7822d671b83537 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Tue, 21 Mar 2017 23:56:40 -0600 Subject: [PATCH] HLSL: non-static member functions: track and find active anonymous 'this' scopes and members. Thanks to @steve-lunarg for his input and discussions on handling member functions. --- SPIRV/GlslangToSpv.cpp | 13 +- SPIRV/spvIR.h | 7 +- .../hlsl.nonstaticMemberFunction.frag.out | 499 +++++++++++++----- Test/hlsl.nonstaticMemberFunction.frag | 21 +- glslang/Include/revision.h | 2 +- glslang/MachineIndependent/SymbolTable.cpp | 2 + glslang/MachineIndependent/SymbolTable.h | 60 ++- .../MachineIndependent/localintermediate.h | 2 + hlsl/hlslGrammar.cpp | 6 +- hlsl/hlslParseHelper.cpp | 50 +- hlsl/hlslParseHelper.h | 10 +- 11 files changed, 500 insertions(+), 172 deletions(-) diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 89f42177..4a5ddcfc 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -2743,12 +2743,16 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF std::vector paramPrecisions; glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence(); + bool implicitThis = (int)parameters.size() > 0 && parameters[0]->getAsSymbolNode()->getName() == glslangIntermediate->implicitThisName; + for (int p = 0; p < (int)parameters.size(); ++p) { const glslang::TType& paramType = parameters[p]->getAsTyped()->getType(); spv::Id typeId = convertGlslangToSpvType(paramType); - if (paramType.containsOpaque() || + // can we pass by reference? + if (paramType.containsOpaque() || // sampler, etc. (paramType.getBasicType() == glslang::EbtBlock && - paramType.getQualifier().storage == glslang::EvqBuffer)) + paramType.getQualifier().storage == glslang::EvqBuffer) || // SSBO + p == 0 && implicitThis) // implicit 'this' typeId = builder.makePointer(TranslateStorageClass(paramType), typeId); else if (paramType.getQualifier().storage != glslang::EvqConstReadOnly) typeId = builder.makePointer(spv::StorageClassFunction, typeId); @@ -2762,6 +2766,8 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(), paramTypes, paramPrecisions, &functionBlock); + if (implicitThis) + function->setImplicitThis(); // Track function to emit/call later functionMap[glslFunction->getName().c_str()] = function; @@ -3233,7 +3239,8 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); spv::Id arg; if (paramType.containsOpaque() || - (paramType.getBasicType() == glslang::EbtBlock && qualifiers[a] == glslang::EvqBuffer)) { + (paramType.getBasicType() == glslang::EbtBlock && qualifiers[a] == glslang::EvqBuffer) || + (a == 0 && function->hasImplicitThis())) { builder.setAccessChain(lValues[lValueCount]); arg = builder.accessChainGetLValue(); ++lValueCount; diff --git a/SPIRV/spvIR.h b/SPIRV/spvIR.h index 8cfef9e1..ce8b4b8a 100755 --- a/SPIRV/spvIR.h +++ b/SPIRV/spvIR.h @@ -273,6 +273,10 @@ public: const std::vector& getBlocks() const { return blocks; } void addLocalVariable(std::unique_ptr inst); Id getReturnType() const { return functionInstruction.getTypeId(); } + + void setImplicitThis() { implicitThis = true; } + bool hasImplicitThis() const { return implicitThis; } + void dump(std::vector& out) const { // OpFunction @@ -296,6 +300,7 @@ protected: Instruction functionInstruction; std::vector parameterInstructions; std::vector blocks; + bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument }; // @@ -354,7 +359,7 @@ protected: // - the OpFunction instruction // - all the OpFunctionParameter instructions __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent) - : parent(parent), functionInstruction(id, resultType, OpFunction) + : parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false) { // OpFunction functionInstruction.addImmediateOperand(FunctionControlMaskNone); diff --git a/Test/baseResults/hlsl.nonstaticMemberFunction.frag.out b/Test/baseResults/hlsl.nonstaticMemberFunction.frag.out index 142ce08d..d3049ec7 100755 --- a/Test/baseResults/hlsl.nonstaticMemberFunction.frag.out +++ b/Test/baseResults/hlsl.nonstaticMemberFunction.frag.out @@ -2,62 +2,133 @@ hlsl.nonstaticMemberFunction.frag Shader version: 450 gl_FragCoord origin is upper left 0:? Sequence -0:5 Function Definition: Test::memFun(vf4; ( temp 4-component vector of float) +0:1 Sequence +0:1 move second child to first child ( temp 2-component vector of float) +0:1 'i' ( global 2-component vector of float) +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:5 Function Definition: type1::setmem(vf4; ( temp void) 0:5 Function Parameters: -0:5 'this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) -0:5 'a' ( in 4-component vector of float) +0:5 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:5 'm' ( in 4-component vector of float) 0:? Sequence -0:6 Branch: Return with expression -0:6 vector-scale ( temp 4-component vector of float) +0:5 move second child to first child ( temp 4-component vector of float) +0:5 memVar: direct index for structure ( temp 4-component vector of float) +0:5 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:5 Constant: +0:5 0 (const uint) +0:5 'm' ( in 4-component vector of float) +0:6 Function Definition: type1::seti(i1; ( temp void) +0:6 Function Parameters: +0:6 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:6 'si' ( in int) +0:? Sequence +0:6 move second child to first child ( temp int) +0:6 i: direct index for structure ( temp int) +0:6 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) 0:6 Constant: -0:6 2.000000 -0:6 'a' ( in 4-component vector of float) -0:9 Function Definition: Test::memFun(i1; ( temp int) +0:6 1 (const uint) +0:6 'si' ( in int) +0:9 Function Definition: type1::memFun(vf4; ( temp 4-component vector of float) 0:9 Function Parameters: -0:9 'this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) -0:9 'a' ( in int) +0:9 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:9 'a' ( in 4-component vector of float) 0:? Sequence 0:10 Branch: Return with expression -0:10 add ( temp int) -0:10 Constant: -0:10 2 (const int) -0:10 'a' ( in int) -0:16 Function Definition: @main( ( temp 4-component vector of float) -0:16 Function Parameters: +0:10 add ( temp 4-component vector of float) +0:10 vector-scale ( temp 4-component vector of float) +0:10 Convert int to float ( temp float) +0:10 i: direct index for structure ( temp int) +0:10 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:10 Constant: +0:10 1 (const uint) +0:10 'a' ( in 4-component vector of float) +0:10 memVar: direct index for structure ( temp 4-component vector of float) +0:10 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:10 Constant: +0:10 0 (const uint) +0:13 Function Definition: type1::memFun(i1; ( temp int) +0:13 Function Parameters: +0:13 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:13 'a' ( in int) 0:? Sequence -0:18 Sequence -0:18 move second child to first child ( temp 4-component vector of float) -0:18 'f4' ( temp 4-component vector of float) +0:14 Branch: Return with expression +0:14 Convert float to int ( temp int) +0:14 subtract ( temp float) +0:14 Convert int to float ( temp float) +0:14 add ( temp int) +0:14 i: direct index for structure ( temp int) +0:14 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:14 Constant: +0:14 1 (const uint) +0:14 'a' ( in int) +0:14 direct index ( temp float) +0:14 memVar: direct index for structure ( temp 4-component vector of float) +0:14 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:14 Constant: +0:14 0 (const uint) +0:14 Constant: +0:14 2 (const int) +0:19 Sequence +0:19 move second child to first child ( temp 2-component vector of float) +0:19 'j' ( global 2-component vector of float) +0:19 'i' ( global 2-component vector of float) +0:23 Function Definition: type2::memFun( ( temp 2-component vector of float) +0:23 Function Parameters: +0:23 '@this' ( temp structure{}) +0:? Sequence +0:23 Branch: Return with expression +0:23 'i' ( global 2-component vector of float) +0:27 Function Definition: @main( ( temp 4-component vector of float) +0:27 Function Parameters: +0:? Sequence +0:29 Function Call: type1::setmem(vf4; ( temp void) +0:29 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:? Constant: +0:? 2.000000 +0:? 2.000000 +0:? 2.000000 +0:? 2.000000 +0:30 Function Call: type1::seti(i1; ( temp void) +0:30 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:30 Constant: +0:30 17 (const int) +0:31 Sequence +0:31 move second child to first child ( temp 4-component vector of float) +0:31 'f4' ( temp 4-component vector of float) 0:? Constant: 0:? 1.000000 0:? 1.000000 0:? 1.000000 0:? 1.000000 -0:19 add second child into first child ( temp 4-component vector of float) -0:19 'f4' ( temp 4-component vector of float) -0:19 Function Call: Test::memFun(vf4; ( temp 4-component vector of float) -0:19 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:32 add second child into first child ( temp 4-component vector of float) +0:32 'f4' ( temp 4-component vector of float) +0:32 Function Call: type1::memFun(vf4; ( temp 4-component vector of float) +0:32 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) 0:? Constant: 0:? 5.000000 0:? 5.000000 0:? 5.000000 0:? 5.000000 -0:20 add second child into first child ( temp 4-component vector of float) -0:20 'f4' ( temp 4-component vector of float) -0:20 Convert int to float ( temp float) -0:20 Function Call: Test::memFun(i1; ( temp int) -0:20 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) -0:20 Constant: -0:20 7 (const int) -0:21 Branch: Return with expression -0:21 'f4' ( temp 4-component vector of float) -0:16 Function Definition: main( ( temp void) -0:16 Function Parameters: +0:33 add second child into first child ( temp 4-component vector of float) +0:33 'f4' ( temp 4-component vector of float) +0:33 Convert int to float ( temp float) +0:33 Function Call: type1::memFun(i1; ( temp int) +0:33 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:33 Constant: +0:33 7 (const int) +0:34 Branch: Return with expression +0:34 'f4' ( temp 4-component vector of float) +0:27 Function Definition: main( ( temp void) +0:27 Function Parameters: 0:? Sequence -0:16 move second child to first child ( temp 4-component vector of float) +0:27 move second child to first child ( temp 4-component vector of float) 0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) -0:16 Function Call: @main( ( temp 4-component vector of float) +0:27 Function Call: @main( ( temp 4-component vector of float) 0:? Linker Objects +0:? 'i' ( global 2-component vector of float) +0:? 'j' ( global 2-component vector of float) 0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) @@ -67,156 +138,298 @@ Linked fragment stage: Shader version: 450 gl_FragCoord origin is upper left 0:? Sequence -0:5 Function Definition: Test::memFun(vf4; ( temp 4-component vector of float) +0:1 Sequence +0:1 move second child to first child ( temp 2-component vector of float) +0:1 'i' ( global 2-component vector of float) +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:5 Function Definition: type1::setmem(vf4; ( temp void) 0:5 Function Parameters: -0:5 'this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) -0:5 'a' ( in 4-component vector of float) +0:5 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:5 'm' ( in 4-component vector of float) 0:? Sequence -0:6 Branch: Return with expression -0:6 vector-scale ( temp 4-component vector of float) +0:5 move second child to first child ( temp 4-component vector of float) +0:5 memVar: direct index for structure ( temp 4-component vector of float) +0:5 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:5 Constant: +0:5 0 (const uint) +0:5 'm' ( in 4-component vector of float) +0:6 Function Definition: type1::seti(i1; ( temp void) +0:6 Function Parameters: +0:6 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:6 'si' ( in int) +0:? Sequence +0:6 move second child to first child ( temp int) +0:6 i: direct index for structure ( temp int) +0:6 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) 0:6 Constant: -0:6 2.000000 -0:6 'a' ( in 4-component vector of float) -0:9 Function Definition: Test::memFun(i1; ( temp int) +0:6 1 (const uint) +0:6 'si' ( in int) +0:9 Function Definition: type1::memFun(vf4; ( temp 4-component vector of float) 0:9 Function Parameters: -0:9 'this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) -0:9 'a' ( in int) +0:9 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:9 'a' ( in 4-component vector of float) 0:? Sequence 0:10 Branch: Return with expression -0:10 add ( temp int) -0:10 Constant: -0:10 2 (const int) -0:10 'a' ( in int) -0:16 Function Definition: @main( ( temp 4-component vector of float) -0:16 Function Parameters: +0:10 add ( temp 4-component vector of float) +0:10 vector-scale ( temp 4-component vector of float) +0:10 Convert int to float ( temp float) +0:10 i: direct index for structure ( temp int) +0:10 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:10 Constant: +0:10 1 (const uint) +0:10 'a' ( in 4-component vector of float) +0:10 memVar: direct index for structure ( temp 4-component vector of float) +0:10 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:10 Constant: +0:10 0 (const uint) +0:13 Function Definition: type1::memFun(i1; ( temp int) +0:13 Function Parameters: +0:13 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:13 'a' ( in int) 0:? Sequence -0:18 Sequence -0:18 move second child to first child ( temp 4-component vector of float) -0:18 'f4' ( temp 4-component vector of float) +0:14 Branch: Return with expression +0:14 Convert float to int ( temp int) +0:14 subtract ( temp float) +0:14 Convert int to float ( temp float) +0:14 add ( temp int) +0:14 i: direct index for structure ( temp int) +0:14 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:14 Constant: +0:14 1 (const uint) +0:14 'a' ( in int) +0:14 direct index ( temp float) +0:14 memVar: direct index for structure ( temp 4-component vector of float) +0:14 '@this' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:14 Constant: +0:14 0 (const uint) +0:14 Constant: +0:14 2 (const int) +0:19 Sequence +0:19 move second child to first child ( temp 2-component vector of float) +0:19 'j' ( global 2-component vector of float) +0:19 'i' ( global 2-component vector of float) +0:23 Function Definition: type2::memFun( ( temp 2-component vector of float) +0:23 Function Parameters: +0:23 '@this' ( temp structure{}) +0:? Sequence +0:23 Branch: Return with expression +0:23 'i' ( global 2-component vector of float) +0:27 Function Definition: @main( ( temp 4-component vector of float) +0:27 Function Parameters: +0:? Sequence +0:29 Function Call: type1::setmem(vf4; ( temp void) +0:29 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:? Constant: +0:? 2.000000 +0:? 2.000000 +0:? 2.000000 +0:? 2.000000 +0:30 Function Call: type1::seti(i1; ( temp void) +0:30 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:30 Constant: +0:30 17 (const int) +0:31 Sequence +0:31 move second child to first child ( temp 4-component vector of float) +0:31 'f4' ( temp 4-component vector of float) 0:? Constant: 0:? 1.000000 0:? 1.000000 0:? 1.000000 0:? 1.000000 -0:19 add second child into first child ( temp 4-component vector of float) -0:19 'f4' ( temp 4-component vector of float) -0:19 Function Call: Test::memFun(vf4; ( temp 4-component vector of float) -0:19 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:32 add second child into first child ( temp 4-component vector of float) +0:32 'f4' ( temp 4-component vector of float) +0:32 Function Call: type1::memFun(vf4; ( temp 4-component vector of float) +0:32 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) 0:? Constant: 0:? 5.000000 0:? 5.000000 0:? 5.000000 0:? 5.000000 -0:20 add second child into first child ( temp 4-component vector of float) -0:20 'f4' ( temp 4-component vector of float) -0:20 Convert int to float ( temp float) -0:20 Function Call: Test::memFun(i1; ( temp int) -0:20 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) -0:20 Constant: -0:20 7 (const int) -0:21 Branch: Return with expression -0:21 'f4' ( temp 4-component vector of float) -0:16 Function Definition: main( ( temp void) -0:16 Function Parameters: +0:33 add second child into first child ( temp 4-component vector of float) +0:33 'f4' ( temp 4-component vector of float) +0:33 Convert int to float ( temp float) +0:33 Function Call: type1::memFun(i1; ( temp int) +0:33 'test' ( temp structure{ temp 4-component vector of float memVar, temp int i}) +0:33 Constant: +0:33 7 (const int) +0:34 Branch: Return with expression +0:34 'f4' ( temp 4-component vector of float) +0:27 Function Definition: main( ( temp void) +0:27 Function Parameters: 0:? Sequence -0:16 move second child to first child ( temp 4-component vector of float) +0:27 move second child to first child ( temp 4-component vector of float) 0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) -0:16 Function Call: @main( ( temp 4-component vector of float) +0:27 Function Call: @main( ( temp 4-component vector of float) 0:? Linker Objects +0:? 'i' ( global 2-component vector of float) +0:? 'j' ( global 2-component vector of float) 0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) // Module Version 10000 // Generated by (magic number): 80001 -// Id's are bound by 61 +// Id's are bound by 111 Capability Shader 1: ExtInstImport "GLSL.std.450" MemoryModel Logical GLSL450 - EntryPoint Fragment 4 "main" 59 + EntryPoint Fragment 4 "main" 109 ExecutionMode 4 OriginUpperLeft Name 4 "main" - Name 9 "Test" - MemberName 9(Test) 0 "memVar" - MemberName 9(Test) 1 "i" - Name 15 "Test::memFun(vf4;" - Name 13 "this" - Name 14 "a" - Name 21 "Test::memFun(i1;" - Name 19 "this" - Name 20 "a" - Name 24 "@main(" - Name 36 "f4" - Name 39 "test" - Name 42 "param" - Name 43 "param" - Name 48 "param" - Name 49 "param" - Name 59 "@entryPointOutput" - Decorate 59(@entryPointOutput) Location 0 + Name 9 "type1" + MemberName 9(type1) 0 "memVar" + MemberName 9(type1) 1 "i" + Name 15 "type1::setmem(vf4;" + Name 13 "@this" + Name 14 "m" + Name 21 "type1::seti(i1;" + Name 19 "@this" + Name 20 "si" + Name 26 "type1::memFun(vf4;" + Name 24 "@this" + Name 25 "a" + Name 31 "type1::memFun(i1;" + Name 29 "@this" + Name 30 "a" + Name 33 "type2" + Name 38 "type2::memFun(" + Name 37 "@this" + Name 41 "@main(" + Name 44 "i" + Name 48 "j" + Name 83 "test" + Name 85 "param" + Name 88 "param" + Name 90 "f4" + Name 94 "param" + Name 99 "param" + Name 109 "@entryPointOutput" + Decorate 109(@entryPointOutput) Location 0 2: TypeVoid 3: TypeFunction 2 6: TypeFloat 32 7: TypeVector 6(float) 4 8: TypeInt 32 1 - 9(Test): TypeStruct 7(fvec4) 8(int) - 10: TypePointer Function 9(Test) + 9(type1): TypeStruct 7(fvec4) 8(int) + 10: TypePointer Function 9(type1) 11: TypePointer Function 7(fvec4) - 12: TypeFunction 7(fvec4) 10(ptr) 11(ptr) + 12: TypeFunction 2 10(ptr) 11(ptr) 17: TypePointer Function 8(int) - 18: TypeFunction 8(int) 10(ptr) 17(ptr) - 23: TypeFunction 7(fvec4) - 26: 6(float) Constant 1073741824 - 31: 8(int) Constant 2 - 37: 6(float) Constant 1065353216 - 38: 7(fvec4) ConstantComposite 37 37 37 37 - 40: 6(float) Constant 1084227584 - 41: 7(fvec4) ConstantComposite 40 40 40 40 - 47: 8(int) Constant 7 - 58: TypePointer Output 7(fvec4) -59(@entryPointOutput): 58(ptr) Variable Output + 18: TypeFunction 2 10(ptr) 17(ptr) + 23: TypeFunction 7(fvec4) 10(ptr) 11(ptr) + 28: TypeFunction 8(int) 10(ptr) 17(ptr) + 33(type2): TypeStruct + 34: TypePointer Function 33(type2) + 35: TypeVector 6(float) 2 + 36: TypeFunction 35(fvec2) 34(ptr) + 40: TypeFunction 7(fvec4) + 43: TypePointer Private 35(fvec2) + 44(i): 43(ptr) Variable Private + 45: 6(float) Constant 1065353216 + 46: 6(float) Constant 1073741824 + 47: 35(fvec2) ConstantComposite 45 46 + 48(j): 43(ptr) Variable Private + 50: 8(int) Constant 0 + 53: 8(int) Constant 1 + 71: TypeInt 32 0 + 72: 71(int) Constant 2 + 73: TypePointer Function 6(float) + 84: 7(fvec4) ConstantComposite 46 46 46 46 + 87: 8(int) Constant 17 + 91: 7(fvec4) ConstantComposite 45 45 45 45 + 92: 6(float) Constant 1084227584 + 93: 7(fvec4) ConstantComposite 92 92 92 92 + 98: 8(int) Constant 7 + 108: TypePointer Output 7(fvec4) +109(@entryPointOutput): 108(ptr) Variable Output 4(main): 2 Function None 3 5: Label - 60: 7(fvec4) FunctionCall 24(@main() - Store 59(@entryPointOutput) 60 + Store 44(i) 47 + 49: 35(fvec2) Load 44(i) + Store 48(j) 49 + 110: 7(fvec4) FunctionCall 41(@main() + Store 109(@entryPointOutput) 110 Return FunctionEnd -15(Test::memFun(vf4;): 7(fvec4) Function None 12 - 13(this): 10(ptr) FunctionParameter - 14(a): 11(ptr) FunctionParameter +15(type1::setmem(vf4;): 2 Function None 12 + 13(@this): 10(ptr) FunctionParameter + 14(m): 11(ptr) FunctionParameter 16: Label - 27: 7(fvec4) Load 14(a) - 28: 7(fvec4) VectorTimesScalar 27 26 - ReturnValue 28 + 51: 7(fvec4) Load 14(m) + 52: 11(ptr) AccessChain 13(@this) 50 + Store 52 51 + Return FunctionEnd -21(Test::memFun(i1;): 8(int) Function None 18 - 19(this): 10(ptr) FunctionParameter - 20(a): 17(ptr) FunctionParameter +21(type1::seti(i1;): 2 Function None 18 + 19(@this): 10(ptr) FunctionParameter + 20(si): 17(ptr) FunctionParameter 22: Label - 32: 8(int) Load 20(a) - 33: 8(int) IAdd 31 32 - ReturnValue 33 + 54: 8(int) Load 20(si) + 55: 17(ptr) AccessChain 19(@this) 53 + Store 55 54 + Return FunctionEnd - 24(@main(): 7(fvec4) Function None 23 - 25: Label - 36(f4): 11(ptr) Variable Function - 39(test): 10(ptr) Variable Function - 42(param): 10(ptr) Variable Function - 43(param): 11(ptr) Variable Function - 48(param): 10(ptr) Variable Function - 49(param): 17(ptr) Variable Function - Store 36(f4) 38 - Store 43(param) 41 - 44: 7(fvec4) FunctionCall 15(Test::memFun(vf4;) 42(param) 43(param) - 45: 7(fvec4) Load 36(f4) - 46: 7(fvec4) FAdd 45 44 - Store 36(f4) 46 - Store 49(param) 47 - 50: 8(int) FunctionCall 21(Test::memFun(i1;) 48(param) 49(param) - 51: 6(float) ConvertSToF 50 - 52: 7(fvec4) Load 36(f4) - 53: 7(fvec4) CompositeConstruct 51 51 51 51 - 54: 7(fvec4) FAdd 52 53 - Store 36(f4) 54 - 55: 7(fvec4) Load 36(f4) - ReturnValue 55 +26(type1::memFun(vf4;): 7(fvec4) Function None 23 + 24(@this): 10(ptr) FunctionParameter + 25(a): 11(ptr) FunctionParameter + 27: Label + 56: 17(ptr) AccessChain 24(@this) 53 + 57: 8(int) Load 56 + 58: 6(float) ConvertSToF 57 + 59: 7(fvec4) Load 25(a) + 60: 7(fvec4) VectorTimesScalar 59 58 + 61: 11(ptr) AccessChain 24(@this) 50 + 62: 7(fvec4) Load 61 + 63: 7(fvec4) FAdd 60 62 + ReturnValue 63 + FunctionEnd +31(type1::memFun(i1;): 8(int) Function None 28 + 29(@this): 10(ptr) FunctionParameter + 30(a): 17(ptr) FunctionParameter + 32: Label + 66: 17(ptr) AccessChain 29(@this) 53 + 67: 8(int) Load 66 + 68: 8(int) Load 30(a) + 69: 8(int) IAdd 67 68 + 70: 6(float) ConvertSToF 69 + 74: 73(ptr) AccessChain 29(@this) 50 72 + 75: 6(float) Load 74 + 76: 6(float) FSub 70 75 + 77: 8(int) ConvertFToS 76 + ReturnValue 77 + FunctionEnd +38(type2::memFun(): 35(fvec2) Function None 36 + 37(@this): 34(ptr) FunctionParameter + 39: Label + 80: 35(fvec2) Load 44(i) + ReturnValue 80 + FunctionEnd + 41(@main(): 7(fvec4) Function None 40 + 42: Label + 83(test): 10(ptr) Variable Function + 85(param): 11(ptr) Variable Function + 88(param): 17(ptr) Variable Function + 90(f4): 11(ptr) Variable Function + 94(param): 11(ptr) Variable Function + 99(param): 17(ptr) Variable Function + Store 85(param) 84 + 86: 2 FunctionCall 15(type1::setmem(vf4;) 83(test) 85(param) + Store 88(param) 87 + 89: 2 FunctionCall 21(type1::seti(i1;) 83(test) 88(param) + Store 90(f4) 91 + Store 94(param) 93 + 95: 7(fvec4) FunctionCall 26(type1::memFun(vf4;) 83(test) 94(param) + 96: 7(fvec4) Load 90(f4) + 97: 7(fvec4) FAdd 96 95 + Store 90(f4) 97 + Store 99(param) 98 + 100: 8(int) FunctionCall 31(type1::memFun(i1;) 83(test) 99(param) + 101: 6(float) ConvertSToF 100 + 102: 7(fvec4) Load 90(f4) + 103: 7(fvec4) CompositeConstruct 101 101 101 101 + 104: 7(fvec4) FAdd 102 103 + Store 90(f4) 104 + 105: 7(fvec4) Load 90(f4) + ReturnValue 105 FunctionEnd diff --git a/Test/hlsl.nonstaticMemberFunction.frag b/Test/hlsl.nonstaticMemberFunction.frag index c4f2b7b0..3655ed0f 100755 --- a/Test/hlsl.nonstaticMemberFunction.frag +++ b/Test/hlsl.nonstaticMemberFunction.frag @@ -1,20 +1,33 @@ -struct Test +static float2 i = float2(1.0, 2.0); + +struct type1 { + void setmem(float4 m) { memVar = m; } + void seti(int si) { i = si; } float4 memVar; float4 memFun(float4 a) : SV_Position { - return 2 * a; + return i * a + memVar; } int memFun(int a) : SV_Position { - return 2 + a; + return i + a - memVar.z; } int i; }; +static float2 j = i; + +struct type2 +{ + float2 memFun() { return i; } +}; + float4 main() : SV_Target0 { - Test test; + type1 test; + test.setmem(float4(2.0,2.0,2.0,2.0)); + test.seti(17); float4 f4 = float4(1.0,1.0,1.0,1.0); f4 += test.memFun(float4(5.0f,5.0f,5.0f,5.0f)); f4 += test.memFun(7); diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index da9de2d5..64e2c00f 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // For the version, it uses the latest git tag followed by the number of commits. // For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "Overload400-PrecQual.1923" +#define GLSLANG_REVISION "Overload400-PrecQual.1929" #define GLSLANG_DATE "21-Mar-2017" diff --git a/glslang/MachineIndependent/SymbolTable.cpp b/glslang/MachineIndependent/SymbolTable.cpp index d0033e8b..790b76b1 100644 --- a/glslang/MachineIndependent/SymbolTable.cpp +++ b/glslang/MachineIndependent/SymbolTable.cpp @@ -300,6 +300,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) defined = copyOf.defined; prototyped = copyOf.prototyped; implicitThis = copyOf.implicitThis; + illegalImplicitThis = copyOf.illegalImplicitThis; defaultParamCount = copyOf.defaultParamCount; } @@ -324,6 +325,7 @@ TSymbolTableLevel* TSymbolTableLevel::clone() const { TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); symTableLevel->anonId = anonId; + symTableLevel->thisLevel = thisLevel; std::vector containerCopied(anonId, false); tLevel::const_iterator iter; for (iter = level.begin(); iter != level.end(); ++iter) { diff --git a/glslang/MachineIndependent/SymbolTable.h b/glslang/MachineIndependent/SymbolTable.h index af78a04b..8dc154cd 100644 --- a/glslang/MachineIndependent/SymbolTable.h +++ b/glslang/MachineIndependent/SymbolTable.h @@ -219,12 +219,12 @@ public: explicit TFunction(TOperator o) : TSymbol(0), op(o), - defined(false), prototyped(false), implicitThis(false), defaultParamCount(0) { } + defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { } TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) : TSymbol(name), mangledName(*name + '('), op(tOp), - defined(false), prototyped(false), implicitThis(false), defaultParamCount(0) + defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { returnType.shallowCopy(retType); declaredBuiltIn = retType.getQualifier().builtIn; @@ -251,9 +251,9 @@ public: // Install 'this' as the first parameter. // 'this' is reflected in the list of parameters, but not the mangled name. - virtual void addThisParameter(TType& type) + virtual void addThisParameter(TType& type, const char* name) { - TParameter p = { NewPoolTString("this"), new TType, nullptr }; + TParameter p = { NewPoolTString(name), new TType, nullptr }; p.type->shallowCopy(type); parameters.insert(parameters.begin(), p); } @@ -276,6 +276,8 @@ public: virtual bool isPrototyped() const { return prototyped; } virtual void setImplicitThis() { assert(writable); implicitThis = true; } virtual bool hasImplicitThis() const { return implicitThis; } + virtual void setIllegalImplicitThis() { assert(writable); illegalImplicitThis = true; } + virtual bool hasIllegalImplicitThis() const { return illegalImplicitThis; } // Return total number of parameters virtual int getParamCount() const { return static_cast(parameters.size()); } @@ -302,7 +304,11 @@ protected: TOperator op; bool defined; bool prototyped; - bool implicitThis; + bool implicitThis; // True if this function is allowed to see all members of 'this' + bool illegalImplicitThis; // True if this function is not supposed to have access to dynamic members of 'this', + // even if it finds member variables in the symbol table. + // This is important for a static member function that has member variables in scope, + // but is not allowed to use them, or see hidden symbols instead. int defaultParamCount; }; @@ -350,7 +356,7 @@ protected: class TSymbolTableLevel { public: POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - TSymbolTableLevel() : defaultPrecision(0), anonId(0) { } + TSymbolTableLevel() : defaultPrecision(0), anonId(0), thisLevel(false) { } ~TSymbolTableLevel(); bool insert(TSymbol& symbol, bool separateNameSpaces) @@ -508,6 +514,9 @@ public: TSymbolTableLevel* clone() const; void readOnly(); + void setThisLevel() { thisLevel = true; } + bool isThisLevel() const { return thisLevel; } + protected: explicit TSymbolTableLevel(TSymbolTableLevel&); TSymbolTableLevel& operator=(TSymbolTableLevel&); @@ -519,6 +528,8 @@ protected: tLevel level; // named mappings TPrecisionQualifier *defaultPrecision; int anonId; + bool thisLevel; // True if this level of the symbol table is a structure scope containing member function + // that are supposed to see anonymous access to member variables. }; class TSymbolTable { @@ -575,6 +586,20 @@ public: table.push_back(new TSymbolTableLevel); } + // Make a new symbol-table level to represent the scope introduced by a structure + // containing member functions, such that the member functions can find anonymous + // references to member variables. + // + // 'thisSymbol' should have a name of "" to trigger anonymous structure-member + // symbol finds. + void pushThis(TSymbol& thisSymbol) + { + assert(thisSymbol.getName().size() == 0); + table.push_back(new TSymbolTableLevel); + table.back()->setThisLevel(); + insert(thisSymbol); + } + void pop(TPrecisionQualifier *p) { table[currentLevel()]->getPreviousDefaultPrecisions(p); @@ -661,6 +686,8 @@ public: } } + // Normal find of a symbol, that can optionally say whether the symbol was found + // at a built-in level or the current top-scope level. TSymbol* find(const TString& name, bool* builtIn = 0, bool *currentScope = 0) { int level = currentLevel(); @@ -678,6 +705,27 @@ public: return symbol; } + // Find of a symbol that returns how many layers deep of nested + // structures-with-member-functions ('this' scopes) deep the symbol was + // found in. + TSymbol* find(const TString& name, int& thisDepth) + { + int level = currentLevel(); + TSymbol* symbol; + thisDepth = 0; + do { + if (table[level]->isThisLevel()) + ++thisDepth; + symbol = table[level]->find(name); + --level; + } while (symbol == 0 && level >= 0); + + if (! table[level + 1]->isThisLevel()) + thisDepth = 0; + + return symbol; + } + bool isFunctionNameVariable(const TString& name) const { if (separateNameSpaces) diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 392a2ab0..5460dd5f 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -428,6 +428,8 @@ public: return semanticNameSet.insert(name).first->c_str(); } + const char* const implicitThisName = "@this"; + protected: TIntermSymbol* addSymbol(int Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); void error(TInfoSink& infoSink, const char*); diff --git a/hlsl/hlslGrammar.cpp b/hlsl/hlslGrammar.cpp index 0e54be52..d209a68a 100755 --- a/hlsl/hlslGrammar.cpp +++ b/hlsl/hlslGrammar.cpp @@ -1842,12 +1842,13 @@ bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList) for (int b = 0; b < (int)functionDeclarators.size(); ++b) { // update signature if (functionDeclarators[b].function->hasImplicitThis()) - functionDeclarators[b].function->addThisParameter(type); + functionDeclarators[b].function->addThisParameter(type, intermediate.implicitThisName); } // All member functions get parsed inside the class/struct namespace and with the // class/struct members in a symbol-table level. parseContext.pushNamespace(structName); + parseContext.pushThisScope(type); bool deferredSuccess = true; for (int b = 0; b < (int)functionDeclarators.size() && deferredSuccess; ++b) { // parse body @@ -1856,6 +1857,7 @@ bool HlslGrammar::acceptStruct(TType& type, TIntermNode*& nodeList) deferredSuccess = false; popTokenStream(); } + parseContext.popThisScope(); parseContext.popNamespace(); return deferredSuccess; @@ -2075,6 +2077,8 @@ bool HlslGrammar::acceptMemberFunctionDefinition(TIntermNode*& nodeList, const T declarator.function = new TFunction(functionName, type); if (type.getQualifier().storage == EvqTemporary) declarator.function->setImplicitThis(); + else + declarator.function->setIllegalImplicitThis(); // function_parameters if (acceptFunctionParameters(*declarator.function)) { diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 31aa1d32..a74629ec 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -603,7 +603,8 @@ int HlslParseContext::getMatrixComponentsColumn(int rows, const TSwizzleSelector // TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TString* string) { - TSymbol* symbol = symbolTable.find(*string); + int thisDepth; + TSymbol* symbol = symbolTable.find(*string, thisDepth); if (symbol && symbol->getAsVariable() && symbol->getAsVariable()->isUserType()) { error(loc, "expected symbol, not user-defined type", string->c_str(), ""); return nullptr; @@ -613,14 +614,21 @@ TIntermTyped* HlslParseContext::handleVariable(const TSourceLoc& loc, const TStr if (symbol && symbol->getNumExtensions()) requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str()); - const TVariable* variable; + const TVariable* variable = nullptr; const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr; TIntermTyped* node = nullptr; if (anon) { - // It was a member of an anonymous container. + // It was a member of an anonymous container, which could be a 'this' structure. // Create a subtree for its dereference. - variable = anon->getAnonContainer().getAsVariable(); + if (thisDepth > 0) { + variable = getImplicitThis(thisDepth); + if (variable == nullptr) + error(loc, "cannot access member variables (static member function?)", "this", ""); + } + if (variable == nullptr) + variable = anon->getAnonContainer().getAsVariable(); + TIntermTyped* container = intermediate.addSymbol(*variable, loc); TIntermTyped* constNode = intermediate.addConstantUnion(anon->getMemberNumber(), loc); node = intermediate.addIndex(EOpIndexDirectStruct, container, constNode, loc); @@ -1529,18 +1537,25 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l if (param.name != nullptr) { TVariable *variable = new TVariable(param.name, *param.type); - // Insert the parameters with name in the symbol table. - if (! symbolTable.insert(*variable)) - error(loc, "redefinition", variable->getName().c_str(), ""); - else { - // Add the parameter to the AST - paramNodes = intermediate.growAggregate(paramNodes, - intermediate.addSymbol(*variable, loc), - loc); + if (i == 0 && function.hasImplicitThis()) { + // 'this' members are already in a symbol-table level, + // and we need to know what function parameter to map them to + symbolTable.makeInternalVariable(*variable); + pushImplicitThis(variable); + } else { + // Insert the parameters with name in the symbol table. + if (! symbolTable.insert(*variable)) + error(loc, "redefinition", variable->getName().c_str(), ""); } + // Add the parameter to the AST + paramNodes = intermediate.growAggregate(paramNodes, + intermediate.addSymbol(*variable, loc), + loc); } else paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc); } + if (function.hasIllegalImplicitThis()) + pushImplicitThis(nullptr); intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc); loopNestingLevel = 0; @@ -1826,6 +1841,8 @@ void HlslParseContext::handleFunctionBody(const TSourceLoc& loc, TFunction& func node->getAsAggregate()->setName(function.getMangledName().c_str()); popScope(); + if (function.hasImplicitThis()) + popImplicitThis(); if (function.getType().getBasicType() != EbtVoid && ! functionReturnsValue) error(loc, "function does not return a value:", "", function.getName().c_str()); @@ -7087,6 +7104,15 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex return switchNode; } +// Make a new symbol-table level that is made out of the members of a structure. +// This should be done as an anonymous struct (name is "") so that the symbol table +// finds the members with on explicit reference to a 'this' variable. +void HlslParseContext::pushThisScope(const TType& thisStruct) +{ + TVariable& thisVariable = *new TVariable(NewPoolTString(""), thisStruct); + symbolTable.pushThis(thisVariable); +} + // Track levels of class/struct/namespace nesting with a prefix string using // the type names separated by the scoping operator. E.g., two levels // would look like: diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index b68f117e..aea1fcaf 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -160,6 +160,13 @@ public: void pushScope() { symbolTable.push(); } void popScope() { symbolTable.pop(0); } + void pushThisScope(const TType&); + void popThisScope() { symbolTable.pop(0); } + + void pushImplicitThis(TVariable* thisParameter) { implicitThisStack.push_back(thisParameter); } + void popImplicitThis() { implicitThisStack.pop_back(); } + TVariable* getImplicitThis(int thisDepth) const { return implicitThisStack[implicitThisStack.size() - thisDepth]; } + void pushNamespace(const TString& name); void popNamespace(); TString* getFullNamespaceName(const TString& localName) const; @@ -387,7 +394,8 @@ protected: TString patchConstantFunctionName; // hull shader patch constant function name, from function level attribute. TMap builtInLinkageSymbols; // used for tessellation, finding declared builtins - TVector currentTypePrefix; + TVector currentTypePrefix; // current scoping prefix for nested structures + TVector implicitThisStack; // currently active 'this' variables for nested structures }; // This is the prefix we use for builtin methods to avoid namespace collisions with