From 0e6e2ffd9cee55769597465f5cdc4952de931701 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Sun, 16 Jul 2017 05:46:13 -0600 Subject: [PATCH] Fix #980: flatten opaque initializers to use aliases. --- .../hlsl.flattenOpaqueInit.vert.out | 132 +++++++++++++++ .../hlsl.flattenOpaqueInitMix.vert.out | 159 ++++++++++++++++++ Test/hlsl.flattenOpaqueInit.vert | 13 ++ Test/hlsl.flattenOpaqueInitMix.vert | 13 ++ gtests/Hlsl.FromFile.cpp | 2 + hlsl/hlslParseHelper.cpp | 106 ++++++++---- hlsl/hlslParseHelper.h | 4 +- 7 files changed, 398 insertions(+), 31 deletions(-) create mode 100755 Test/baseResults/hlsl.flattenOpaqueInit.vert.out create mode 100755 Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out create mode 100644 Test/hlsl.flattenOpaqueInit.vert create mode 100644 Test/hlsl.flattenOpaqueInitMix.vert diff --git a/Test/baseResults/hlsl.flattenOpaqueInit.vert.out b/Test/baseResults/hlsl.flattenOpaqueInit.vert.out new file mode 100755 index 00000000..774260fe --- /dev/null +++ b/Test/baseResults/hlsl.flattenOpaqueInit.vert.out @@ -0,0 +1,132 @@ +hlsl.flattenOpaqueInit.vert +Shader version: 500 +0:? Sequence +0:5 Function Definition: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float) +0:5 Function Parameters: +0:? 'smpl' ( in sampler) +0:? 'tex' ( in texture2D) +0:? Sequence +0:6 Branch: Return with expression +0:6 texture ( temp 4-component vector of float) +0:6 Construct combined texture-sampler ( temp sampler2D) +0:? 'tex' ( in texture2D) +0:? 'smpl' ( in sampler) +0:? Constant: +0:? 0.300000 +0:? 0.400000 +0:10 Function Definition: @main( ( temp 4-component vector of float) +0:10 Function Parameters: +0:? Sequence +0:12 Branch: Return with expression +0:12 Function Call: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float) +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:10 Function Definition: main( ( temp void) +0:10 Function Parameters: +0:? Sequence +0:10 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:10 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + + +Linked vertex stage: + + +Shader version: 500 +0:? Sequence +0:5 Function Definition: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float) +0:5 Function Parameters: +0:? 'smpl' ( in sampler) +0:? 'tex' ( in texture2D) +0:? Sequence +0:6 Branch: Return with expression +0:6 texture ( temp 4-component vector of float) +0:6 Construct combined texture-sampler ( temp sampler2D) +0:? 'tex' ( in texture2D) +0:? 'smpl' ( in sampler) +0:? Constant: +0:? 0.300000 +0:? 0.400000 +0:10 Function Definition: @main( ( temp 4-component vector of float) +0:10 Function Parameters: +0:? Sequence +0:12 Branch: Return with expression +0:12 Function Call: lookUp(struct-FxaaTex-p1-t211; ( temp 4-component vector of float) +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:10 Function Definition: main( ( temp void) +0:10 Function Parameters: +0:? Sequence +0:10 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:10 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 40 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 38 + Source HLSL 500 + Name 4 "main" + Name 15 "lookUp(struct-FxaaTex-p1-t211;" + Name 13 "smpl" + Name 14 "tex" + Name 18 "@main(" + Name 32 "g_tInputTexture_sampler" + Name 33 "g_tInputTexture" + Name 38 "@entryPointOutput" + Decorate 32(g_tInputTexture_sampler) DescriptorSet 0 + Decorate 33(g_tInputTexture) DescriptorSet 0 + Decorate 38(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeSampler + 7: TypePointer UniformConstant 6 + 8: TypeFloat 32 + 9: TypeImage 8(float) 2D sampled format:Unknown + 10: TypePointer UniformConstant 9 + 11: TypeVector 8(float) 4 + 12: TypeFunction 11(fvec4) 7(ptr) 10(ptr) + 17: TypeFunction 11(fvec4) + 22: TypeSampledImage 9 + 24: TypeVector 8(float) 2 + 25: 8(float) Constant 1050253722 + 26: 8(float) Constant 1053609165 + 27: 24(fvec2) ConstantComposite 25 26 + 28: 8(float) Constant 0 +32(g_tInputTexture_sampler): 7(ptr) Variable UniformConstant +33(g_tInputTexture): 10(ptr) Variable UniformConstant + 37: TypePointer Output 11(fvec4) +38(@entryPointOutput): 37(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 39: 11(fvec4) FunctionCall 18(@main() + Store 38(@entryPointOutput) 39 + Return + FunctionEnd +15(lookUp(struct-FxaaTex-p1-t211;): 11(fvec4) Function None 12 + 13(smpl): 7(ptr) FunctionParameter + 14(tex): 10(ptr) FunctionParameter + 16: Label + 20: 9 Load 14(tex) + 21: 6 Load 13(smpl) + 23: 22 SampledImage 20 21 + 29: 11(fvec4) ImageSampleExplicitLod 23 27 Lod 28 + ReturnValue 29 + FunctionEnd + 18(@main(): 11(fvec4) Function None 17 + 19: Label + 34: 11(fvec4) FunctionCall 15(lookUp(struct-FxaaTex-p1-t211;) 32(g_tInputTexture_sampler) 33(g_tInputTexture) + ReturnValue 34 + FunctionEnd diff --git a/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out b/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out new file mode 100755 index 00000000..3deaddd8 --- /dev/null +++ b/Test/baseResults/hlsl.flattenOpaqueInitMix.vert.out @@ -0,0 +1,159 @@ +hlsl.flattenOpaqueInitMix.vert +Shader version: 500 +0:? Sequence +0:5 Function Definition: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float) +0:5 Function Parameters: +0:? 'smpl' ( in sampler) +0:? 'tex' ( in texture2D) +0:? 'f' ( in float) +0:? Sequence +0:6 Branch: Return with expression +0:6 texture ( temp 4-component vector of float) +0:6 Construct combined texture-sampler ( temp sampler2D) +0:? 'tex' ( in texture2D) +0:? 'smpl' ( in sampler) +0:? Construct vec2 ( temp 2-component vector of float) +0:? 'f' ( in float) +0:? 'f' ( in float) +0:10 Function Definition: @main( ( temp 4-component vector of float) +0:10 Function Parameters: +0:? Sequence +0:11 Sequence +0:? Sequence +0:11 move second child to first child ( temp float) +0:? 'f' ( temp float) +0:11 Constant: +0:11 0.500000 +0:12 Branch: Return with expression +0:12 Function Call: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float) +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:? 'f' ( temp float) +0:10 Function Definition: main( ( temp void) +0:10 Function Parameters: +0:? Sequence +0:10 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:10 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + + +Linked vertex stage: + + +Shader version: 500 +0:? Sequence +0:5 Function Definition: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float) +0:5 Function Parameters: +0:? 'smpl' ( in sampler) +0:? 'tex' ( in texture2D) +0:? 'f' ( in float) +0:? Sequence +0:6 Branch: Return with expression +0:6 texture ( temp 4-component vector of float) +0:6 Construct combined texture-sampler ( temp sampler2D) +0:? 'tex' ( in texture2D) +0:? 'smpl' ( in sampler) +0:? Construct vec2 ( temp 2-component vector of float) +0:? 'f' ( in float) +0:? 'f' ( in float) +0:10 Function Definition: @main( ( temp 4-component vector of float) +0:10 Function Parameters: +0:? Sequence +0:11 Sequence +0:? Sequence +0:11 move second child to first child ( temp float) +0:? 'f' ( temp float) +0:11 Constant: +0:11 0.500000 +0:12 Branch: Return with expression +0:12 Function Call: lookUp(struct-FxaaTex-p1-t21-f11; ( temp 4-component vector of float) +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:? 'f' ( temp float) +0:10 Function Definition: main( ( temp void) +0:10 Function Parameters: +0:? Sequence +0:10 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:10 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tInputTexture_sampler' ( uniform sampler) +0:? 'g_tInputTexture' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 46 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" 44 + Source HLSL 500 + Name 4 "main" + Name 17 "lookUp(struct-FxaaTex-p1-t21-f11;" + Name 14 "smpl" + Name 15 "tex" + Name 16 "f" + Name 20 "@main(" + Name 34 "f" + Name 36 "g_tInputTexture_sampler" + Name 37 "g_tInputTexture" + Name 38 "param" + Name 44 "@entryPointOutput" + Decorate 36(g_tInputTexture_sampler) DescriptorSet 0 + Decorate 37(g_tInputTexture) DescriptorSet 0 + Decorate 44(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeSampler + 7: TypePointer UniformConstant 6 + 8: TypeFloat 32 + 9: TypeImage 8(float) 2D sampled format:Unknown + 10: TypePointer UniformConstant 9 + 11: TypePointer Function 8(float) + 12: TypeVector 8(float) 4 + 13: TypeFunction 12(fvec4) 7(ptr) 10(ptr) 11(ptr) + 19: TypeFunction 12(fvec4) + 24: TypeSampledImage 9 + 28: TypeVector 8(float) 2 + 30: 8(float) Constant 0 + 35: 8(float) Constant 1056964608 +36(g_tInputTexture_sampler): 7(ptr) Variable UniformConstant +37(g_tInputTexture): 10(ptr) Variable UniformConstant + 43: TypePointer Output 12(fvec4) +44(@entryPointOutput): 43(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 45: 12(fvec4) FunctionCall 20(@main() + Store 44(@entryPointOutput) 45 + Return + FunctionEnd +17(lookUp(struct-FxaaTex-p1-t21-f11;): 12(fvec4) Function None 13 + 14(smpl): 7(ptr) FunctionParameter + 15(tex): 10(ptr) FunctionParameter + 16(f): 11(ptr) FunctionParameter + 18: Label + 22: 9 Load 15(tex) + 23: 6 Load 14(smpl) + 25: 24 SampledImage 22 23 + 26: 8(float) Load 16(f) + 27: 8(float) Load 16(f) + 29: 28(fvec2) CompositeConstruct 26 27 + 31: 12(fvec4) ImageSampleExplicitLod 25 29 Lod 30 + ReturnValue 31 + FunctionEnd + 20(@main(): 12(fvec4) Function None 19 + 21: Label + 34(f): 11(ptr) Variable Function + 38(param): 11(ptr) Variable Function + Store 34(f) 35 + 39: 8(float) Load 34(f) + Store 38(param) 39 + 40: 12(fvec4) FunctionCall 17(lookUp(struct-FxaaTex-p1-t21-f11;) 36(g_tInputTexture_sampler) 37(g_tInputTexture) 38(param) + ReturnValue 40 + FunctionEnd diff --git a/Test/hlsl.flattenOpaqueInit.vert b/Test/hlsl.flattenOpaqueInit.vert new file mode 100644 index 00000000..5efb02ed --- /dev/null +++ b/Test/hlsl.flattenOpaqueInit.vert @@ -0,0 +1,13 @@ +struct FxaaTex { SamplerState smpl; Texture2D tex; }; +SamplerState g_tInputTexture_sampler; Texture2D g_tInputTexture; + +float4 lookUp(FxaaTex tex) +{ + return tex.tex.Sample(tex.smpl, float2(0.3, 0.4)); +} + +float4 main() : SV_TARGET0 +{ + FxaaTex tex = { g_tInputTexture_sampler, g_tInputTexture }; + return lookUp(tex); +} \ No newline at end of file diff --git a/Test/hlsl.flattenOpaqueInitMix.vert b/Test/hlsl.flattenOpaqueInitMix.vert new file mode 100644 index 00000000..2e712ee5 --- /dev/null +++ b/Test/hlsl.flattenOpaqueInitMix.vert @@ -0,0 +1,13 @@ +struct FxaaTex { SamplerState smpl; Texture2D tex; float f; }; +SamplerState g_tInputTexture_sampler; Texture2D g_tInputTexture; + +float4 lookUp(FxaaTex tex) +{ + return tex.tex.Sample(tex.smpl, float2(tex.f, tex.f)); +} + +float4 main() : SV_TARGET0 +{ + FxaaTex tex = { g_tInputTexture_sampler, g_tInputTexture, 0.5 }; + return lookUp(tex); +} \ No newline at end of file diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index ea90b62e..21f606e6 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -122,6 +122,8 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.float4.frag", "PixelShaderFunction"}, {"hlsl.flatten.return.frag", "main"}, {"hlsl.flattenOpaque.frag", "main"}, + {"hlsl.flattenOpaqueInit.vert", "main"}, + {"hlsl.flattenOpaqueInitMix.vert", "main"}, {"hlsl.forLoop.frag", "PixelShaderFunction"}, {"hlsl.gather.array.dx10.frag", "main"}, {"hlsl.gather.basic.dx10.frag", "main"}, diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 50d88d2f..6e12f820 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -506,12 +506,14 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* } // Deal with sampler aliasing: turning assignments into aliases +// Return a placeholder node for higher-level code that think assignments must +// generate code. TIntermTyped* HlslParseContext::handleSamplerLvalue(const TSourceLoc& loc, const char* op, TIntermTyped*& node) { // Can only alias an assignment: "s1 = s2" TIntermBinary* binary = node->getAsBinaryNode(); if (binary == nullptr || node->getAsOperator()->getOp() != EOpAssign || - binary->getLeft() ->getAsSymbolNode() == nullptr || + binary->getLeft()->getAsSymbolNode() == nullptr || binary->getRight()->getAsSymbolNode() == nullptr) { error(loc, "can't modify sampler", op, ""); return node; @@ -520,11 +522,25 @@ TIntermTyped* HlslParseContext::handleSamplerLvalue(const TSourceLoc& loc, const if (controlFlowNestingLevel > 0) warn(loc, "sampler or image aliased under control flow; consumption must be in same path", op, ""); + TIntermTyped* set = setOpaqueLvalue(binary->getLeft(), binary->getRight()); + if (set == nullptr) + warn(loc, "could not create alias for sampler", op, ""); + else + node = set; + + return node; +} + +// Do an opaque assignment that needs to turn into an alias. +// Return nullptr if it can't be done, otherwise return a placeholder +// node for higher-level code that think assignments must generate code. +TIntermTyped* HlslParseContext::setOpaqueLvalue(TIntermTyped* leftTyped, TIntermTyped* rightTyped) +{ // Best is if we are aliasing a flattened struct member "S.s1 = s2", // in which case we want to update the flattening information with the alias, // making everything else work seamlessly. - TIntermSymbol* left = binary->getLeft()->getAsSymbolNode(); - TIntermSymbol* right = binary->getRight()->getAsSymbolNode(); + TIntermSymbol* left = leftTyped->getAsSymbolNode(); + TIntermSymbol* right = rightTyped->getAsSymbolNode(); for (auto fit = flattenMap.begin(); fit != flattenMap.end(); ++fit) { for (auto mit = fit->second.members.begin(); mit != fit->second.members.end(); ++mit) { if ((*mit)->getUniqueId() == left->getId()) { @@ -533,15 +549,12 @@ TIntermTyped* HlslParseContext::handleSamplerLvalue(const TSourceLoc& loc, const (*mit)->setUniqueId(right->getId()); // replace node (rest of compiler expects either an error or code to generate) // with pointless access - node = binary->getRight(); - return node; + return right; } } } - warn(loc, "could not create alias for sampler", op, ""); - - return node; + return nullptr; } void HlslParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) @@ -2412,6 +2425,34 @@ TIntermAggregate* HlslParseContext::assignClipCullDistance(const TSourceLoc& loc return assignList; } +// For a declaration with an initializer, where the initialized symbol is flattened, +// and possibly contains opaque values, such that the initializer should never exist +// as emitted code, because even creating the initializer would write opaques. +// +// Decompose this into individual member-wise assignments, which themselves are +// expected to then not exist for opaque types, because they will turn into aliases. +// +// Return a node that contains the non-aliased assignments that must continue to exist. +TIntermAggregate* HlslParseContext::flattenedInit(const TSourceLoc& loc, TIntermSymbol* symbol, const TIntermAggregate& initializer) +{ + TIntermAggregate* initList = nullptr; + // synthesize an access to each member, and then an assignment to it + const TTypeList& typeList = *symbol->getType().getStruct(); + for (int member = 0; member < (int)typeList.size(); ++member) { + TIntermTyped* memberInitializer = initializer.getSequence()[member]->getAsTyped(); + TIntermTyped* flattenedMember = flattenAccess(symbol, member); + if (flattenedMember->getType().containsOpaque()) + setOpaqueLvalue(flattenedMember, memberInitializer); + else + initList = intermediate.growAggregate(initList, handleAssign(loc, EOpAssign, flattenedMember, + memberInitializer)); + } + + if (initList) + initList->setOperator(EOpSequence); + return initList; +} + // Some simple source assignments need to be flattened to a sequence // of AST assignments. Catch these and flatten, otherwise, pass through // to intermediate.addAssign(). @@ -2449,7 +2490,7 @@ TIntermTyped* HlslParseContext::handleAssign(const TSourceLoc& loc, TOperator op // A temporary to store the right node's value, so we don't keep indirecting into it // if it's not a simple symbol. - TVariable* rhsTempVar = nullptr; + TVariable* rhsTempVar = nullptr; // If the RHS is a simple symbol node, we'll copy it for each member. TIntermSymbol* cloneSymNode = nullptr; @@ -7222,27 +7263,22 @@ TIntermNode* HlslParseContext::declareVariable(const TSourceLoc& loc, const TStr error(loc, "cannot change the type of", "redeclaration", symbol->getName().c_str()); } - if (flattenVar) - flatten(loc, *symbol->getAsVariable()); - if (symbol == nullptr) return nullptr; + if (flattenVar) + flatten(loc, *symbol->getAsVariable()); + + if (initializer == nullptr) + return nullptr; + // Deal with initializer - TIntermNode* initNode = nullptr; - if (symbol && initializer) { - if (flattenVar) - error(loc, "flattened array with initializer list unsupported", identifier.c_str(), ""); - - TVariable* variable = symbol->getAsVariable(); - if (variable == nullptr) { - error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); - return nullptr; - } - initNode = executeInitializer(loc, initializer, variable); + TVariable* variable = symbol->getAsVariable(); + if (variable == nullptr) { + error(loc, "initializer requires a variable, not a member", identifier.c_str(), ""); + return nullptr; } - - return initNode; + return executeInitializer(loc, initializer, variable, flattenVar); } // Pick up global defaults from the provide global defaults into dst. @@ -7308,7 +7344,7 @@ TVariable* HlslParseContext::declareNonArray(const TSourceLoc& loc, const TStrin // Returning nullptr just means there is no code to execute to handle the // initializer, which will, for example, be the case for constant initializers. // -TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable) +TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyped* initializer, TVariable* variable, bool flattened) { // // Identifier must be of type constant, a global, or a temporary, and @@ -7329,6 +7365,7 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm TType skeletalType; skeletalType.shallowCopy(variable->getType()); skeletalType.getQualifier().makeTemporary(); + TIntermAggregate* initializerList = nullptr; if (initializer->getAsAggregate() && initializer->getAsAggregate()->getOp() == EOpNull) initializer = convertInitializerList(loc, skeletalType, initializer, nullptr); if (initializer == nullptr) { @@ -7388,11 +7425,20 @@ TIntermNode* HlslParseContext::executeInitializer(const TSourceLoc& loc, TInterm // normal assigning of a value to a variable... specializationCheck(loc, initializer->getType(), "initializer"); TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc); - TIntermNode* initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer); - if (initNode == nullptr) - assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); - return initNode; + // If we are flattening, it could be due to setting opaques, which must be handled + // as aliases, and the 'initializer' node cannot actually be emitted, because it + // itself stores the result of the constructor, and we can't store to opaques. + // handleAssign() will emit the initializer. + TIntermNode* initNode = nullptr; + if (flattened && intermSymbol->getType().containsOpaque()) + return flattenedInit(loc, intermSymbol, *initializer->getAsAggregate()); + else { + initNode = handleAssign(loc, EOpAssign, intermSymbol, initializer); + if (initNode == nullptr) + assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + return initNode; + } } return nullptr; diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index 713e8303..2d507c38 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -87,6 +87,7 @@ public: void remapNonEntryPointIO(TFunction& function); TIntermNode* handleReturnValue(const TSourceLoc&, TIntermTyped*); void handleFunctionArgument(TFunction*, TIntermTyped*& arguments, TIntermTyped* newArg); + TIntermAggregate* flattenedInit(const TSourceLoc&, TIntermSymbol*, const TIntermAggregate&); TIntermTyped* handleAssign(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleAssignToMatrixSwizzle(const TSourceLoc&, TOperator, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleFunctionCall(const TSourceLoc&, TFunction*, TIntermTyped*); @@ -191,6 +192,7 @@ public: // Apply L-value conversions. E.g, turning a write to a RWTexture into an ImageStore. TIntermTyped* handleLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node); TIntermTyped* handleSamplerLvalue(const TSourceLoc&, const char* op, TIntermTyped*& node); + TIntermTyped* setOpaqueLvalue(TIntermTyped* left, TIntermTyped* right); bool lValueErrorCheck(const TSourceLoc&, const char* op, TIntermTyped*) override; TLayoutFormat getLayoutFromTxType(const TSourceLoc&, const TType&); @@ -231,7 +233,7 @@ protected: TIntermSymbol* makeInternalVariableNode(const TSourceLoc&, const char* name, const TType&) const; TVariable* declareNonArray(const TSourceLoc&, const TString& identifier, const TType&, bool track); void declareArray(const TSourceLoc&, const TString& identifier, const TType&, TSymbol*&, bool track); - TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable); + TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable, bool flattened); TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer, TIntermTyped* scalarInit); bool isScalarConstructor(const TIntermNode*); TOperator mapAtomicOp(const TSourceLoc& loc, TOperator op, bool isImage);