Branimir Karadžić 8 лет назад
Родитель
Сommit
4d7fcf9f7d
50 измененных файлов с 1856 добавлено и 997 удалено
  1. 44 27
      3rdparty/glslang/SPIRV/GlslangToSpv.cpp
  2. 7 5
      3rdparty/glslang/SPIRV/SpvBuilder.cpp
  3. 3 2
      3rdparty/glslang/SPIRV/SpvBuilder.h
  4. 1 0
      3rdparty/glslang/SPIRV/doc.cpp
  5. 34 5
      3rdparty/glslang/SPIRV/spirv.hpp
  6. 2 2
      3rdparty/glslang/StandAlone/StandAlone.cpp
  7. 6 0
      3rdparty/glslang/Test/310AofA.vert
  8. 15 0
      3rdparty/glslang/Test/460.frag
  9. 1 1
      3rdparty/glslang/Test/baseResults/120.frag.out
  10. 1 1
      3rdparty/glslang/Test/baseResults/120.vert.out
  11. 19 0
      3rdparty/glslang/Test/baseResults/310AofA.vert.out
  12. 48 2
      3rdparty/glslang/Test/baseResults/460.frag.out
  13. 2 2
      3rdparty/glslang/Test/baseResults/hlsl.attribute.expression.comp.out
  14. 2 2
      3rdparty/glslang/Test/baseResults/hlsl.attribute.frag.out
  15. 4 4
      3rdparty/glslang/Test/baseResults/hlsl.doLoop.frag.out
  16. 2 2
      3rdparty/glslang/Test/baseResults/hlsl.forLoop.frag.out
  17. 2 2
      3rdparty/glslang/Test/baseResults/hlsl.if.frag.out
  18. 4 4
      3rdparty/glslang/Test/baseResults/hlsl.loopattr.frag.out
  19. 15 15
      3rdparty/glslang/Test/baseResults/hlsl.numthreads.comp.out
  20. 2 2
      3rdparty/glslang/Test/baseResults/hlsl.switch.frag.out
  21. 2 2
      3rdparty/glslang/Test/baseResults/hlsl.whileLoop.frag.out
  22. 238 0
      3rdparty/glslang/Test/baseResults/spv.controlFlowAttributes.frag.out
  23. 2 5
      3rdparty/glslang/Test/hlsl.numthreads.comp
  24. 39 0
      3rdparty/glslang/Test/spv.controlFlowAttributes.frag
  25. 2 0
      3rdparty/glslang/glslang/CMakeLists.txt
  26. 1 1
      3rdparty/glslang/glslang/Include/Common.h
  27. 3 3
      3rdparty/glslang/glslang/Include/ConstantUnion.h
  28. 40 35
      3rdparty/glslang/glslang/Include/intermediate.h
  29. 9 9
      3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp
  30. 2 2
      3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp
  31. 15 2
      3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h
  32. 1 0
      3rdparty/glslang/glslang/MachineIndependent/Scan.cpp
  33. 2 0
      3rdparty/glslang/glslang/MachineIndependent/Versions.cpp
  34. 1 0
      3rdparty/glslang/glslang/MachineIndependent/Versions.h
  35. 257 0
      3rdparty/glslang/glslang/MachineIndependent/attribute.cpp
  36. 102 0
      3rdparty/glslang/glslang/MachineIndependent/attribute.h
  37. 58 5
      3rdparty/glslang/glslang/MachineIndependent/glslang.y
  38. 477 434
      3rdparty/glslang/glslang/MachineIndependent/glslang_tab.cpp
  39. 3 2
      3rdparty/glslang/glslang/MachineIndependent/glslang_tab.cpp.h
  40. 25 3
      3rdparty/glslang/glslang/MachineIndependent/intermOut.cpp
  41. 5 4
      3rdparty/glslang/glslang/MachineIndependent/localintermediate.h
  42. 2 1
      3rdparty/glslang/glslang/Public/ShaderLang.h
  43. 1 1
      3rdparty/glslang/gtests/Hlsl.FromFile.cpp
  44. 1 0
      3rdparty/glslang/gtests/Spv.FromFile.cpp
  45. 29 113
      3rdparty/glslang/hlsl/hlslAttributes.cpp
  46. 4 75
      3rdparty/glslang/hlsl/hlslAttributes.h
  47. 57 34
      3rdparty/glslang/hlsl/hlslGrammar.cpp
  48. 6 7
      3rdparty/glslang/hlsl/hlslGrammar.h
  49. 247 173
      3rdparty/glslang/hlsl/hlslParseHelper.cpp
  50. 11 8
      3rdparty/glslang/hlsl/hlslParseHelper.h

+ 44 - 27
3rdparty/glslang/SPIRV/GlslangToSpv.cpp

@@ -107,7 +107,8 @@ private:
 //
 class TGlslangToSpvTraverser : public glslang::TIntermTraverser {
 public:
-    TGlslangToSpvTraverser(const glslang::TIntermediate*, spv::SpvBuildLogger* logger, glslang::SpvOptions& options);
+    TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate*, spv::SpvBuildLogger* logger,
+        glslang::SpvOptions& options);
     virtual ~TGlslangToSpvTraverser() { }
 
     bool visitAggregate(glslang::TVisit, glslang::TIntermAggregate*);
@@ -128,8 +129,9 @@ protected:
     spv::Decoration TranslateAuxiliaryStorageDecoration(const glslang::TQualifier& qualifier);
     spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable, bool memberDeclaration);
     spv::ImageFormat TranslateImageFormat(const glslang::TType& type);
-    spv::SelectionControlMask TranslateSelectionControl(glslang::TSelectionControl) const;
-    spv::LoopControlMask TranslateLoopControl(glslang::TLoopControl) const;
+    spv::SelectionControlMask TranslateSelectionControl(const glslang::TIntermSelection&) const;
+    spv::SelectionControlMask TranslateSwitchControl(const glslang::TIntermSwitch&) const;
+    spv::LoopControlMask TranslateLoopControl(const glslang::TIntermLoop&, unsigned int& dependencyLength) const;
     spv::StorageClass TranslateStorageClass(const glslang::TType&);
     spv::Id createSpvVariable(const glslang::TIntermSymbol*);
     spv::Id getSampledType(const glslang::TSampler&);
@@ -747,26 +749,42 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
     }
 }
 
-spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(glslang::TSelectionControl selectionControl) const
+spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const
 {
-    switch (selectionControl) {
-    case glslang::ESelectionControlNone:        return spv::SelectionControlMaskNone;
-    case glslang::ESelectionControlFlatten:     return spv::SelectionControlFlattenMask;
-    case glslang::ESelectionControlDontFlatten: return spv::SelectionControlDontFlattenMask;
-    default:                                    return spv::SelectionControlMaskNone;
-    }
+    if (selectionNode.getFlatten())
+        return spv::SelectionControlFlattenMask;
+    if (selectionNode.getDontFlatten())
+        return spv::SelectionControlDontFlattenMask;
+    return spv::SelectionControlMaskNone;
+}
+
+spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const
+{
+    if (switchNode.getFlatten())
+        return spv::SelectionControlFlattenMask;
+    if (switchNode.getDontFlatten())
+        return spv::SelectionControlDontFlattenMask;
+    return spv::SelectionControlMaskNone;
 }
 
-spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(glslang::TLoopControl loopControl) const
+// return a non-0 dependency if the dependency argument must be set
+spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang::TIntermLoop& loopNode,
+    unsigned int& dependencyLength) const
 {
-    switch (loopControl) {
-    case glslang::ELoopControlNone:       return spv::LoopControlMaskNone;
-    case glslang::ELoopControlUnroll:     return spv::LoopControlUnrollMask;
-    case glslang::ELoopControlDontUnroll: return spv::LoopControlDontUnrollMask;
-    // TODO: DependencyInfinite
-    // TODO: DependencyLength
-    default:                              return spv::LoopControlMaskNone;
+    spv::LoopControlMask control = spv::LoopControlMaskNone;
+
+    if (loopNode.getDontUnroll())
+        control = control | spv::LoopControlDontUnrollMask;
+    if (loopNode.getUnroll())
+        control = control | spv::LoopControlUnrollMask;
+    if (loopNode.getLoopDependency() == glslang::TIntermLoop::dependencyInfinite)
+        control = control | spv::LoopControlDependencyInfiniteMask;
+    else if (loopNode.getLoopDependency() > 0) {
+        control = control | spv::LoopControlDependencyLengthMask;
+        dependencyLength = loopNode.getLoopDependency();
     }
+
+    return control;
 }
 
 // Translate glslang type to SPIR-V storage class.
@@ -880,13 +898,13 @@ bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifie
 // Implement the TGlslangToSpvTraverser class.
 //
 
-TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate,
+TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate* glslangIntermediate,
                                                spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options)
     : TIntermTraverser(true, false, true),
       options(options),
       shaderEntry(nullptr), currentFunction(nullptr),
       sequenceDepth(0), logger(buildLogger),
-      builder((glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
+      builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
       inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
       glslangIntermediate(glslangIntermediate)
 {
@@ -2025,7 +2043,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang
     node->getCondition()->traverse(this);
 
     // Selection control:
-    const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
+    const spv::SelectionControlMask control = TranslateSelectionControl(*node);
 
     // make an "if" based on the value created by the condition
     spv::Builder::If ifBuilder(accessChainLoad(node->getCondition()->getType()), control, builder);
@@ -2067,7 +2085,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
     spv::Id selector = accessChainLoad(node->getCondition()->getAsTyped()->getType());
 
     // Selection control:
-    const spv::SelectionControlMask control = TranslateSelectionControl(node->getSelectionControl());
+    const spv::SelectionControlMask control = TranslateSwitchControl(*node);
 
     // browse the children to sort out code segments
     int defaultSegment = -1;
@@ -2127,9 +2145,8 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
     builder.createBranch(&blocks.head);
 
     // Loop control:
-    const spv::LoopControlMask control = TranslateLoopControl(node->getLoopControl());
-
-    // TODO: dependency length
+    unsigned int dependencyLength = glslang::TIntermLoop::dependencyInfinite;
+    const spv::LoopControlMask control = TranslateLoopControl(*node, dependencyLength);
 
     // Spec requires back edges to target header blocks, and every header block
     // must dominate its merge block.  Make a header block first to ensure these
@@ -2139,7 +2156,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn
     // including merges of its own.
     builder.setLine(node->getLoc().line);
     builder.setBuildPoint(&blocks.head);
-    builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control);
+    builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, dependencyLength);
     if (node->testFirst() && node->getTest()) {
         spv::Block& test = builder.makeNewBlock();
         builder.createBranch(&test);
@@ -6067,7 +6084,7 @@ void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsign
 
     glslang::GetThreadPoolAllocator().push();
 
-    TGlslangToSpvTraverser it(&intermediate, logger, *options);
+    TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options);
     root->traverse(&it);
     it.finishSpv();
     it.dumpSpv(spirv);

+ 7 - 5
3rdparty/glslang/SPIRV/SpvBuilder.cpp

@@ -56,7 +56,8 @@
 
 namespace spv {
 
-Builder::Builder(unsigned int magicNumber, SpvBuildLogger* buildLogger) :
+Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) :
+    spvVersion(spvVersion),
     source(SourceLanguageUnknown),
     sourceVersion(0),
     sourceFileStringId(NoResult),
@@ -2403,7 +2404,7 @@ void Builder::dump(std::vector<unsigned int>& out) const
 {
     // Header, before first instructions:
     out.push_back(MagicNumber);
-    out.push_back(Version);
+    out.push_back(spvVersion);
     out.push_back(builderNumber);
     out.push_back(uniqueId + 1);
     out.push_back(0);
@@ -2572,12 +2573,15 @@ void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
     buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
 }
 
-void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control)
+void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
+                              unsigned int dependencyLength)
 {
     Instruction* merge = new Instruction(OpLoopMerge);
     merge->addIdOperand(mergeBlock->getId());
     merge->addIdOperand(continueBlock->getId());
     merge->addImmediateOperand(control);
+    if ((control & LoopControlDependencyLengthMask) != 0)
+        merge->addImmediateOperand(dependencyLength);
     buildPoint->addInstruction(std::unique_ptr<Instruction>(merge));
 }
 
@@ -2644,8 +2648,6 @@ void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector
 void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const
 {
     for (int i = 0; i < (int)moduleProcesses.size(); ++i) {
-        // TODO: switch this out for the 1.1 headers
-        const spv::Op OpModuleProcessed = (spv::Op)330;
         Instruction moduleProcessed(OpModuleProcessed);
         moduleProcessed.addStringOperand(moduleProcesses[i]);
         moduleProcessed.dump(out);

+ 3 - 2
3rdparty/glslang/SPIRV/SpvBuilder.h

@@ -60,7 +60,7 @@ namespace spv {
 
 class Builder {
 public:
-    Builder(unsigned int userNumber, SpvBuildLogger* logger);
+    Builder(unsigned int spvVersion, unsigned int userNumber, SpvBuildLogger* logger);
     virtual ~Builder();
 
     static const int maxMatrixSize = 4;
@@ -561,7 +561,7 @@ public:
 
     void createBranch(Block* block);
     void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
-    void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
+    void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, unsigned int dependencyLength);
 
     // Sets to generate opcode for specialization constants.
     void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
@@ -585,6 +585,7 @@ public:
     void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
     void dumpModuleProcesses(std::vector<unsigned int>&) const;
 
+    unsigned int spvVersion;     // the version of SPIR-V to emit in the header
     SourceLanguage source;
     int sourceVersion;
     spv::Id sourceFileStringId;

+ 1 - 0
3rdparty/glslang/SPIRV/doc.cpp

@@ -2558,6 +2558,7 @@ void Parameterize()
     InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'");
     InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'");
     InstructionDesc[OpLoopMerge].operands.push(OperandLoop, "");
+    InstructionDesc[OpLoopMerge].operands.push(OperandOptionalLiteral, "");
 
     InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'");
     InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, "");

+ 34 - 5
3rdparty/glslang/SPIRV/spirv.hpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2017 The Khronos Group Inc.
+// Copyright (c) 2014-2018 The Khronos Group Inc.
 // 
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and/or associated documentation files (the "Materials"),
@@ -46,12 +46,12 @@ namespace spv {
 
 typedef unsigned int Id;
 
-#define SPV_VERSION 0x10000
-#define SPV_REVISION 12
+#define SPV_VERSION 0x10200
+#define SPV_REVISION 3
 
 static const unsigned int MagicNumber = 0x07230203;
-static const unsigned int Version = 0x00010000;
-static const unsigned int Revision = 12;
+static const unsigned int Version = 0x00010200;
+static const unsigned int Revision = 3;
 static const unsigned int OpCodeMask = 0xffff;
 static const unsigned int WordCountShift = 16;
 
@@ -122,6 +122,13 @@ enum ExecutionMode {
     ExecutionModeOutputTriangleStrip = 29,
     ExecutionModeVecTypeHint = 30,
     ExecutionModeContractionOff = 31,
+    ExecutionModeInitializer = 33,
+    ExecutionModeFinalizer = 34,
+    ExecutionModeSubgroupSize = 35,
+    ExecutionModeSubgroupsPerWorkgroup = 36,
+    ExecutionModeSubgroupsPerWorkgroupId = 37,
+    ExecutionModeLocalSizeId = 38,
+    ExecutionModeLocalSizeHintId = 39,
     ExecutionModePostDepthCoverage = 4446,
     ExecutionModeStencilRefReplacingEXT = 5027,
     ExecutionModeMax = 0x7fffffff,
@@ -378,6 +385,9 @@ enum Decoration {
     DecorationNoContraction = 42,
     DecorationInputAttachmentIndex = 43,
     DecorationAlignment = 44,
+    DecorationMaxByteOffset = 45,
+    DecorationAlignmentId = 46,
+    DecorationMaxByteOffsetId = 47,
     DecorationExplicitInterpAMD = 4999,
     DecorationOverrideCoverageNV = 5248,
     DecorationPassthroughNV = 5250,
@@ -470,6 +480,8 @@ enum SelectionControlMask {
 enum LoopControlShift {
     LoopControlUnrollShift = 0,
     LoopControlDontUnrollShift = 1,
+    LoopControlDependencyInfiniteShift = 2,
+    LoopControlDependencyLengthShift = 3,
     LoopControlMax = 0x7fffffff,
 };
 
@@ -477,6 +489,8 @@ enum LoopControlMask {
     LoopControlMaskNone = 0,
     LoopControlUnrollMask = 0x00000001,
     LoopControlDontUnrollMask = 0x00000002,
+    LoopControlDependencyInfiniteMask = 0x00000004,
+    LoopControlDependencyLengthMask = 0x00000008,
 };
 
 enum FunctionControlShift {
@@ -627,6 +641,9 @@ enum Capability {
     CapabilityStorageImageReadWithoutFormat = 55,
     CapabilityStorageImageWriteWithoutFormat = 56,
     CapabilityMultiViewport = 57,
+    CapabilitySubgroupDispatch = 58,
+    CapabilityNamedBarrier = 59,
+    CapabilityPipeStorage = 60,
     CapabilitySubgroupBallotKHR = 4423,
     CapabilityDrawParameters = 4427,
     CapabilitySubgroupVoteKHR = 4431,
@@ -955,6 +972,18 @@ enum Op {
     OpAtomicFlagTestAndSet = 318,
     OpAtomicFlagClear = 319,
     OpImageSparseRead = 320,
+    OpSizeOf = 321,
+    OpTypePipeStorage = 322,
+    OpConstantPipeStorage = 323,
+    OpCreatePipeFromPipeStorage = 324,
+    OpGetKernelLocalSizeForSubgroupCount = 325,
+    OpGetKernelMaxNumSubgroups = 326,
+    OpTypeNamedBarrier = 327,
+    OpNamedBarrierInitialize = 328,
+    OpMemoryNamedBarrier = 329,
+    OpModuleProcessed = 330,
+    OpExecutionModeId = 331,
+    OpDecorateId = 332,
     OpSubgroupBallotKHR = 4421,
     OpSubgroupFirstInvocationKHR = 4422,
     OpSubgroupAllKHR = 4428,

+ 2 - 2
3rdparty/glslang/StandAlone/StandAlone.cpp

@@ -159,7 +159,7 @@ std::vector<std::string> IncludeDirectoryList;
 int ClientInputSemanticsVersion = 100;   // maps to, say, #define VULKAN 100
 int VulkanClientVersion = 100;           // would map to, say, Vulkan 1.0
 int OpenGLClientVersion = 450;           // doesn't influence anything yet, but maps to OpenGL 4.50
-unsigned int TargetVersion = 0x00001000; // maps to, say, SPIR-V 1.0
+unsigned int TargetVersion = 0x00010000; // maps to, say, SPIR-V 1.0
 std::vector<std::string> Processes;      // what should be recorded by OpModuleProcessed, or equivalent
 
 // Per descriptor-set binding base data
@@ -855,7 +855,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
                                                                 : glslang::EShSourceGlsl,
                                         compUnit.stage, glslang::EShClientVulkan, ClientInputSemanticsVersion);
                 shader->setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
-                shader->setEnvTarget(glslang::EshTargetSpv, TargetVersion);
+                shader->setEnvTarget(glslang::EShTargetSpv, TargetVersion);
             } else {
                 shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
                                                                 : glslang::EShSourceGlsl,

+ 6 - 0
3rdparty/glslang/Test/310AofA.vert

@@ -113,3 +113,9 @@ out float outArray[2][3];  // ERROR
 uniform ubaa {
     int a;
 } ubaaname[2][3];  // ERROR
+
+vec3 func(in mat3[2] x[3])
+{
+	mat3 a0 = x[2][1];
+    return a0[2];
+}

+ 15 - 0
3rdparty/glslang/Test/460.frag

@@ -15,3 +15,18 @@ void main()
     b1 = allInvocations(b1);
     b1 = allInvocationsEqual(b1);
 }
+
+void attExtBad()
+{
+    // ERRORs, not enabled
+    [[dependency_length(1+3)]] for (int i = 0; i < 8; ++i) { }
+    [[flatten]]                if (true) { } else { }
+}
+
+#extension GL_EXT_control_flow_attributes : enable
+
+void attExt()
+{
+    [[dependency_length(-3)]] do {  } while(true); // ERROR, not positive
+    [[dependency_length(0)]] do {  } while(true);  // ERROR, not positive
+}

+ 1 - 1
3rdparty/glslang/Test/baseResults/120.frag.out

@@ -19,7 +19,7 @@ ERROR: 0:82: 'xr' : vector swizzle selectors not from the same set
 ERROR: 0:83: 'xyxyx' : vector swizzle too long 
 ERROR: 0:84: 'z' : vector swizzle selection out of range 
 ERROR: 0:85: 'assign' :  l-value required 
-ERROR: 0:91: 'int' : overloaded functions must have the same return type 
+ERROR: 0:91: 'main' : overloaded functions must have the same return type 
 ERROR: 0:91: 'main' : function already has a body 
 ERROR: 0:91: 'int' :  entry point cannot return a value
 ERROR: 0:92: 'main' : function cannot take any parameter(s) 

+ 1 - 1
3rdparty/glslang/Test/baseResults/120.vert.out

@@ -34,7 +34,7 @@ ERROR: 0:51: 'arrays of arrays' : not supported with this profile: none
 ERROR: 0:52: 'arrays of arrays' : not supported with this profile: none
 ERROR: 0:53: 'arrays of arrays' : not supported with this profile: none
 ERROR: 0:56: 'out' : overloaded functions must have the same parameter storage qualifiers for argument 1
-ERROR: 0:57: 'float' : overloaded functions must have the same return type 
+ERROR: 0:57: 'overloadA' : overloaded functions must have the same return type 
 ERROR: 0:87: 'overloadC' : no matching overloaded function found 
 ERROR: 0:90: 'overloadC' : no matching overloaded function found 
 ERROR: 0:95: 'overloadD' : ambiguous function signature match: multiple signatures match under implicit type conversion 

+ 19 - 0
3rdparty/glslang/Test/baseResults/310AofA.vert.out

@@ -317,6 +317,25 @@ ERROR: node is still EOpNull!
 0:99              0 (const int)
 0:99          Constant:
 0:99            1 (const int)
+0:117  Function Definition: func(mf33[3][2]; ( global highp 3-component vector of float)
+0:117    Function Parameters: 
+0:117      'x' ( in 3-element array of 2-element array of highp 3X3 matrix of float)
+0:119    Sequence
+0:119      Sequence
+0:119        move second child to first child ( temp highp 3X3 matrix of float)
+0:119          'a0' ( temp highp 3X3 matrix of float)
+0:119          direct index ( temp highp 3X3 matrix of float)
+0:119            direct index ( temp 2-element array of highp 3X3 matrix of float)
+0:119              'x' ( in 3-element array of 2-element array of highp 3X3 matrix of float)
+0:119              Constant:
+0:119                2 (const int)
+0:119            Constant:
+0:119              1 (const int)
+0:120      Branch: Return with expression
+0:120        direct index ( temp highp 3-component vector of float)
+0:120          'a0' ( temp highp 3X3 matrix of float)
+0:120          Constant:
+0:120            2 (const int)
 0:?   Linker Objects
 0:?     'name' (layout( column_major shared) buffer 3-element array of block{layout( column_major shared) buffer implicitly-sized array of highp float u, layout( column_major shared) buffer implicitly-sized array of highp 4-component vector of float v})
 0:?     'uname' (layout( column_major shared) uniform 3-element array of block{layout( column_major shared) uniform highp float u, layout( column_major shared) uniform implicitly-sized array of highp 4-component vector of float v})

+ 48 - 2
3rdparty/glslang/Test/baseResults/460.frag.out

@@ -1,6 +1,14 @@
 460.frag
+ERROR: 0:22: 'attribute' : required extension not requested: GL_EXT_control_flow_attributes
+ERROR: 0:23: 'attribute' : required extension not requested: GL_EXT_control_flow_attributes
+ERROR: 0:30: 'dependency_length' : must be positive 
+ERROR: 0:31: 'dependency_length' : must be positive 
+ERROR: 4 compilation errors.  No code generated.
+
+
 Shader version: 460
-0:? Sequence
+Requested GL_EXT_control_flow_attributes
+ERROR: node is still EOpNull!
 0:10  Function Definition: main( ( global void)
 0:10    Function Parameters: 
 0:12    Sequence
@@ -21,6 +29,43 @@ Shader version: 460
 0:16        'b1' ( temp bool)
 0:16        allInvocationsEqual ( global bool)
 0:16          'b1' ( temp bool)
+0:19  Function Definition: attExtBad( ( global void)
+0:19    Function Parameters: 
+0:22    Sequence
+0:22      Sequence
+0:22        Sequence
+0:22          move second child to first child ( temp int)
+0:22            'i' ( temp int)
+0:22            Constant:
+0:22              0 (const int)
+0:22        Loop with condition tested first: Dependency 4
+0:22          Loop Condition
+0:22          Compare Less Than ( temp bool)
+0:22            'i' ( temp int)
+0:22            Constant:
+0:22              8 (const int)
+0:22          No loop body
+0:22          Loop Terminal Expression
+0:22          Pre-Increment ( temp int)
+0:22            'i' ( temp int)
+0:23      Test condition and select ( temp void): Flatten
+0:23        Condition
+0:23        Constant:
+0:23          true (const bool)
+0:23        true case is null
+0:28  Function Definition: attExt( ( global void)
+0:28    Function Parameters: 
+0:30    Sequence
+0:30      Loop with condition not tested first: Dependency -3
+0:30        Loop Condition
+0:30        Constant:
+0:30          true (const bool)
+0:30        No loop body
+0:31      Loop with condition not tested first
+0:31        Loop Condition
+0:31        Constant:
+0:31          true (const bool)
+0:31        No loop body
 0:?   Linker Objects
 0:?     's' ( smooth in structure{ global float f,  global 4-component vector of float v})
 
@@ -29,7 +74,8 @@ Linked fragment stage:
 
 
 Shader version: 460
-0:? Sequence
+Requested GL_EXT_control_flow_attributes
+ERROR: node is still EOpNull!
 0:10  Function Definition: main( ( global void)
 0:10    Function Parameters: 
 0:12    Sequence

+ 2 - 2
3rdparty/glslang/Test/baseResults/hlsl.attribute.expression.comp.out

@@ -10,7 +10,7 @@ local_size = (4, 6, 8)
 0:11          'x' ( temp int)
 0:11          Constant:
 0:11            0 (const int)
-0:11        Loop with condition tested first
+0:11        Loop with condition tested first: Unroll
 0:11          Loop Condition
 0:11          Compare Less Than ( temp bool)
 0:11            'x' ( temp int)
@@ -53,7 +53,7 @@ local_size = (4, 6, 8)
 0:11          'x' ( temp int)
 0:11          Constant:
 0:11            0 (const int)
-0:11        Loop with condition tested first
+0:11        Loop with condition tested first: Unroll
 0:11          Loop Condition
 0:11          Compare Less Than ( temp bool)
 0:11            'x' ( temp int)

+ 2 - 2
3rdparty/glslang/Test/baseResults/hlsl.attribute.frag.out

@@ -6,7 +6,7 @@ gl_FragCoord origin is upper left
 0:2    Function Parameters: 
 0:2      'input' ( in 4-component vector of float)
 0:?     Sequence
-0:11      Test condition and select ( temp void)
+0:11      Test condition and select ( temp void): DontFlatten
 0:11        Condition
 0:11        Constant:
 0:11          false (const bool)
@@ -33,7 +33,7 @@ gl_FragCoord origin is upper left
 0:2    Function Parameters: 
 0:2      'input' ( in 4-component vector of float)
 0:?     Sequence
-0:11      Test condition and select ( temp void)
+0:11      Test condition and select ( temp void): DontFlatten
 0:11        Condition
 0:11        Constant:
 0:11          false (const bool)

+ 4 - 4
3rdparty/glslang/Test/baseResults/hlsl.doLoop.frag.out

@@ -6,12 +6,12 @@ gl_FragCoord origin is upper left
 0:2    Function Parameters: 
 0:2      'input' ( in float)
 0:?     Sequence
-0:3      Loop with condition not tested first
+0:3      Loop with condition not tested first: Unroll
 0:3        Loop Condition
 0:3        Constant:
 0:3          false (const bool)
 0:3        No loop body
-0:4      Loop with condition not tested first
+0:4      Loop with condition not tested first: Unroll
 0:4        Loop Condition
 0:4        Constant:
 0:4          false (const bool)
@@ -80,12 +80,12 @@ gl_FragCoord origin is upper left
 0:2    Function Parameters: 
 0:2      'input' ( in float)
 0:?     Sequence
-0:3      Loop with condition not tested first
+0:3      Loop with condition not tested first: Unroll
 0:3        Loop Condition
 0:3        Constant:
 0:3          false (const bool)
 0:3        No loop body
-0:4      Loop with condition not tested first
+0:4      Loop with condition not tested first: Unroll
 0:4        Loop Condition
 0:4        Constant:
 0:4          false (const bool)

+ 2 - 2
3rdparty/glslang/Test/baseResults/hlsl.forLoop.frag.out

@@ -17,7 +17,7 @@ gl_FragCoord origin is upper left
 0:4          No loop condition
 0:4          No loop body
 0:?       Sequence
-0:5        Loop with condition tested first
+0:5        Loop with condition tested first: Unroll
 0:5          Loop Condition
 0:5          any ( temp bool)
 0:5            NotEqual ( temp 4-component vector of bool)
@@ -220,7 +220,7 @@ gl_FragCoord origin is upper left
 0:4          No loop condition
 0:4          No loop body
 0:?       Sequence
-0:5        Loop with condition tested first
+0:5        Loop with condition tested first: Unroll
 0:5          Loop Condition
 0:5          any ( temp bool)
 0:5            NotEqual ( temp 4-component vector of bool)

+ 2 - 2
3rdparty/glslang/Test/baseResults/hlsl.if.frag.out

@@ -42,7 +42,7 @@ gl_FragCoord origin is upper left
 0:14            'input' ( in 4-component vector of float)
 0:14            'input' ( in 4-component vector of float)
 0:14        true case is null
-0:19      Test condition and select ( temp void)
+0:19      Test condition and select ( temp void): Flatten
 0:19        Condition
 0:19        all ( temp bool)
 0:19          Equal ( temp 4-component vector of bool)
@@ -152,7 +152,7 @@ gl_FragCoord origin is upper left
 0:14            'input' ( in 4-component vector of float)
 0:14            'input' ( in 4-component vector of float)
 0:14        true case is null
-0:19      Test condition and select ( temp void)
+0:19      Test condition and select ( temp void): Flatten
 0:19        Condition
 0:19        all ( temp bool)
 0:19          Equal ( temp 4-component vector of bool)

+ 4 - 4
3rdparty/glslang/Test/baseResults/hlsl.loopattr.frag.out

@@ -10,7 +10,7 @@ gl_FragCoord origin is upper left
 0:5          'x' ( temp int)
 0:5          Constant:
 0:5            0 (const int)
-0:5        Loop with condition tested first
+0:5        Loop with condition tested first: Unroll
 0:5          Loop Condition
 0:5          Compare Less Than ( temp bool)
 0:5            'x' ( temp int)
@@ -25,7 +25,7 @@ gl_FragCoord origin is upper left
 0:8          'y' ( temp int)
 0:8          Constant:
 0:8            0 (const int)
-0:8        Loop with condition tested first
+0:8        Loop with condition tested first: DontUnroll
 0:8          Loop Condition
 0:8          Compare Less Than ( temp bool)
 0:8            'y' ( temp int)
@@ -80,7 +80,7 @@ gl_FragCoord origin is upper left
 0:5          'x' ( temp int)
 0:5          Constant:
 0:5            0 (const int)
-0:5        Loop with condition tested first
+0:5        Loop with condition tested first: Unroll
 0:5          Loop Condition
 0:5          Compare Less Than ( temp bool)
 0:5            'x' ( temp int)
@@ -95,7 +95,7 @@ gl_FragCoord origin is upper left
 0:8          'y' ( temp int)
 0:8          Constant:
 0:8            0 (const int)
-0:8        Loop with condition tested first
+0:8        Loop with condition tested first: DontUnroll
 0:8          Loop Condition
 0:8          Compare Less Than ( temp bool)
 0:8            'y' ( temp int)

+ 15 - 15
3rdparty/glslang/Test/baseResults/hlsl.numthreads.comp.out

@@ -1,20 +1,20 @@
 hlsl.numthreads.comp
 Shader version: 500
-local_size = (4, 4, 2)
+local_size = (1, 4, 8)
 0:? Sequence
 0:4  Function Definition: main(vu3; ( temp void)
 0:4    Function Parameters: 
 0:4      'tid' ( in 3-component vector of uint)
-0:9  Function Definition: @main_aux1(vu3; ( temp void)
+0:9  Function Definition: @main_aux2(vu3; ( temp void)
 0:9    Function Parameters: 
 0:9      'tid' ( in 3-component vector of uint)
-0:9  Function Definition: main_aux1( ( temp void)
+0:9  Function Definition: main_aux2( ( temp void)
 0:9    Function Parameters: 
 0:?     Sequence
 0:9      move second child to first child ( temp 3-component vector of uint)
 0:?         'tid' ( temp 3-component vector of uint)
 0:?         'tid' ( in 3-component vector of uint GlobalInvocationID)
-0:9      Function Call: @main_aux1(vu3; ( temp void)
+0:9      Function Call: @main_aux2(vu3; ( temp void)
 0:?         'tid' ( temp 3-component vector of uint)
 0:?   Linker Objects
 0:?     'tid' ( in 3-component vector of uint GlobalInvocationID)
@@ -24,21 +24,21 @@ Linked compute stage:
 
 
 Shader version: 500
-local_size = (4, 4, 2)
+local_size = (1, 4, 8)
 0:? Sequence
 0:4  Function Definition: main(vu3; ( temp void)
 0:4    Function Parameters: 
 0:4      'tid' ( in 3-component vector of uint)
-0:9  Function Definition: @main_aux1(vu3; ( temp void)
+0:9  Function Definition: @main_aux2(vu3; ( temp void)
 0:9    Function Parameters: 
 0:9      'tid' ( in 3-component vector of uint)
-0:9  Function Definition: main_aux1( ( temp void)
+0:9  Function Definition: main_aux2( ( temp void)
 0:9    Function Parameters: 
 0:?     Sequence
 0:9      move second child to first child ( temp 3-component vector of uint)
 0:?         'tid' ( temp 3-component vector of uint)
 0:?         'tid' ( in 3-component vector of uint GlobalInvocationID)
-0:9      Function Call: @main_aux1(vu3; ( temp void)
+0:9      Function Call: @main_aux2(vu3; ( temp void)
 0:?         'tid' ( temp 3-component vector of uint)
 0:?   Linker Objects
 0:?     'tid' ( in 3-component vector of uint GlobalInvocationID)
@@ -50,13 +50,13 @@ local_size = (4, 4, 2)
                               Capability Shader
                1:             ExtInstImport  "GLSL.std.450"
                               MemoryModel Logical GLSL450
-                              EntryPoint GLCompute 4  "main_aux1" 18
-                              ExecutionMode 4 LocalSize 4 4 2
+                              EntryPoint GLCompute 4  "main_aux2" 18
+                              ExecutionMode 4 LocalSize 1 4 8
                               Source HLSL 500
-                              Name 4  "main_aux1"
+                              Name 4  "main_aux2"
                               Name 11  "main(vu3;"
                               Name 10  "tid"
-                              Name 14  "@main_aux1(vu3;"
+                              Name 14  "@main_aux2(vu3;"
                               Name 13  "tid"
                               Name 16  "tid"
                               Name 18  "tid"
@@ -70,7 +70,7 @@ local_size = (4, 4, 2)
                9:             TypeFunction 2 8(ptr)
               17:             TypePointer Input 7(ivec3)
          18(tid):     17(ptr) Variable Input
-    4(main_aux1):           2 Function None 3
+    4(main_aux2):           2 Function None 3
                5:             Label
          16(tid):      8(ptr) Variable Function
        20(param):      8(ptr) Variable Function
@@ -78,7 +78,7 @@ local_size = (4, 4, 2)
                               Store 16(tid) 19
               21:    7(ivec3) Load 16(tid)
                               Store 20(param) 21
-              22:           2 FunctionCall 14(@main_aux1(vu3;) 20(param)
+              22:           2 FunctionCall 14(@main_aux2(vu3;) 20(param)
                               Return
                               FunctionEnd
    11(main(vu3;):           2 Function None 9
@@ -86,7 +86,7 @@ local_size = (4, 4, 2)
               12:             Label
                               Return
                               FunctionEnd
-14(@main_aux1(vu3;):           2 Function None 9
+14(@main_aux2(vu3;):           2 Function None 9
          13(tid):      8(ptr) FunctionParameter
               15:             Label
                               Return

+ 2 - 2
3rdparty/glslang/Test/baseResults/hlsl.switch.frag.out

@@ -36,7 +36,7 @@ gl_FragCoord origin is upper left
 0:17            Pre-Decrement ( temp 4-component vector of float)
 0:17              'input' ( in 4-component vector of float)
 0:18            Branch: Break
-0:21      switch
+0:21      switch: DontFlatten
 0:21      condition
 0:21        'c' ( in int)
 0:21      body
@@ -186,7 +186,7 @@ gl_FragCoord origin is upper left
 0:17            Pre-Decrement ( temp 4-component vector of float)
 0:17              'input' ( in 4-component vector of float)
 0:18            Branch: Break
-0:21      switch
+0:21      switch: DontFlatten
 0:21      condition
 0:21        'c' ( in int)
 0:21      body

+ 2 - 2
3rdparty/glslang/Test/baseResults/hlsl.whileLoop.frag.out

@@ -21,7 +21,7 @@ gl_FragCoord origin is upper left
 0:4        Constant:
 0:4          false (const bool)
 0:4        No loop body
-0:5      Loop with condition tested first
+0:5      Loop with condition tested first: Unroll
 0:5        Loop Condition
 0:5        Constant:
 0:5          false (const bool)
@@ -71,7 +71,7 @@ gl_FragCoord origin is upper left
 0:4        Constant:
 0:4          false (const bool)
 0:4        No loop body
-0:5      Loop with condition tested first
+0:5      Loop with condition tested first: Unroll
 0:5        Loop Condition
 0:5        Constant:
 0:5          false (const bool)

+ 238 - 0
3rdparty/glslang/Test/baseResults/spv.controlFlowAttributes.frag.out

@@ -0,0 +1,238 @@
+spv.controlFlowAttributes.frag
+WARNING: 0:20: '' : attribute with arguments not recognized, skipping 
+WARNING: 0:21: '' : attribute with arguments not recognized, skipping 
+WARNING: 0:22: '' : attribute with arguments not recognized, skipping 
+WARNING: 0:23: 'dependency_length' : expected a single integer argument 
+WARNING: 0:24: '' : attribute with arguments not recognized, skipping 
+WARNING: 0:25: '' : attribute with arguments not recognized, skipping 
+WARNING: 0:26: '' : attribute with arguments not recognized, skipping 
+
+// Module Version 10000
+// Generated by (magic number): 80003
+// Id's are bound by 118
+
+                              Capability Shader
+               1:             ExtInstImport  "GLSL.std.450"
+                              MemoryModel Logical GLSL450
+                              EntryPoint Fragment 4  "main"
+                              ExecutionMode 4 OriginUpperLeft
+                              Source GLSL 450
+                              SourceExtension  "GL_EXT_control_flow_attributes"
+                              Name 4  "main"
+                              Name 8  "i"
+                              Name 36  "i"
+                              Name 47  "cond"
+                              Name 60  "i"
+                              Name 79  "i"
+               2:             TypeVoid
+               3:             TypeFunction 2
+               6:             TypeInt 32 1
+               7:             TypePointer Function 6(int)
+               9:      6(int) Constant 0
+              16:      6(int) Constant 8
+              17:             TypeBool
+              20:      6(int) Constant 1
+              31:    17(bool) ConstantTrue
+              46:             TypePointer Private 17(bool)
+        47(cond):     46(ptr) Variable Private
+              54:    17(bool) ConstantFalse
+              55:      6(int) Constant 3
+         4(main):           2 Function None 3
+               5:             Label
+            8(i):      7(ptr) Variable Function
+           36(i):      7(ptr) Variable Function
+           60(i):      7(ptr) Variable Function
+           79(i):      7(ptr) Variable Function
+                              Store 8(i) 9
+                              Branch 10
+              10:             Label
+                              LoopMerge 12 13 Unroll 
+                              Branch 14
+              14:             Label
+              15:      6(int) Load 8(i)
+              18:    17(bool) SLessThan 15 16
+                              BranchConditional 18 11 12
+              11:               Label
+                                Branch 13
+              13:               Label
+              19:      6(int)   Load 8(i)
+              21:      6(int)   IAdd 19 20
+                                Store 8(i) 21
+                                Branch 10
+              12:             Label
+                              Branch 22
+              22:             Label
+                              LoopMerge 24 25 DontUnroll 
+                              Branch 23
+              23:             Label
+                              Branch 25
+              25:             Label
+                              Branch 22
+              24:             Label
+                              Branch 26
+              26:             Label
+                              LoopMerge 28 29 DontUnroll 
+                              Branch 30
+              30:             Label
+                              BranchConditional 31 27 28
+              27:               Label
+                                Branch 29
+              29:               Label
+                                Branch 26
+              28:             Label
+                              Branch 32
+              32:             Label
+                              LoopMerge 34 35 DependencyInfinite 
+                              Branch 33
+              33:             Label
+                              Branch 35
+              35:             Label
+                              BranchConditional 31 32 34
+              34:             Label
+                              Store 36(i) 9
+                              Branch 37
+              37:             Label
+                              LoopMerge 39 40 DependencyLength  4
+                              Branch 41
+              41:             Label
+              42:      6(int) Load 36(i)
+              43:    17(bool) SLessThan 42 16
+                              BranchConditional 43 38 39
+              38:               Label
+                                Branch 40
+              40:               Label
+              44:      6(int)   Load 36(i)
+              45:      6(int)   IAdd 44 20
+                                Store 36(i) 45
+                                Branch 37
+              39:             Label
+              48:    17(bool) Load 47(cond)
+                              SelectionMerge 50 Flatten 
+                              BranchConditional 48 49 50
+              49:               Label
+                                Branch 50
+              50:             Label
+              51:    17(bool) Load 47(cond)
+                              SelectionMerge 53 DontFlatten 
+                              BranchConditional 51 52 53
+              52:               Label
+                                Store 47(cond) 54
+                                Branch 53
+              53:             Label
+                              SelectionMerge 57 DontFlatten 
+                              Switch 55 57 
+                                     case 3: 56
+              56:               Label
+                                Branch 57
+              57:             Label
+                              Store 60(i) 9
+                              Branch 61
+              61:             Label
+                              LoopMerge 63 64 None
+                              Branch 65
+              65:             Label
+              66:      6(int) Load 60(i)
+              67:    17(bool) SLessThan 66 16
+                              BranchConditional 67 62 63
+              62:               Label
+                                Branch 64
+              64:               Label
+              68:      6(int)   Load 60(i)
+              69:      6(int)   IAdd 68 20
+                                Store 60(i) 69
+                                Branch 61
+              63:             Label
+                              Branch 70
+              70:             Label
+                              LoopMerge 72 73 None
+                              Branch 74
+              74:             Label
+                              BranchConditional 31 71 72
+              71:               Label
+                                Branch 73
+              73:               Label
+                                Branch 70
+              72:             Label
+                              Branch 75
+              75:             Label
+                              LoopMerge 77 78 None
+                              Branch 76
+              76:             Label
+                              Branch 78
+              78:             Label
+                              BranchConditional 31 75 77
+              77:             Label
+                              Store 79(i) 9
+                              Branch 80
+              80:             Label
+                              LoopMerge 82 83 None
+                              Branch 84
+              84:             Label
+              85:      6(int) Load 79(i)
+              86:    17(bool) SLessThan 85 16
+                              BranchConditional 86 81 82
+              81:               Label
+                                Branch 83
+              83:               Label
+              87:      6(int)   Load 79(i)
+              88:      6(int)   IAdd 87 20
+                                Store 79(i) 88
+                                Branch 80
+              82:             Label
+              89:    17(bool) Load 47(cond)
+                              SelectionMerge 91 None
+                              BranchConditional 89 90 91
+              90:               Label
+                                Branch 91
+              91:             Label
+              92:    17(bool) Load 47(cond)
+                              SelectionMerge 94 None
+                              BranchConditional 92 93 94
+              93:               Label
+                                Store 47(cond) 54
+                                Branch 94
+              94:             Label
+                              SelectionMerge 96 None
+                              Switch 55 96 
+                                     case 3: 95
+              95:               Label
+                                Branch 96
+              96:             Label
+                              Branch 99
+              99:             Label
+                              LoopMerge 101 102 Unroll DontUnroll DependencyLength  2
+                              Branch 103
+             103:             Label
+             104:    17(bool) Load 47(cond)
+                              BranchConditional 104 100 101
+             100:               Label
+                                Branch 102
+             102:               Label
+                                Branch 99
+             101:             Label
+                              SelectionMerge 106 DontFlatten 
+                              Switch 55 106 
+                                     case 3: 105
+             105:               Label
+                                Branch 106
+             106:             Label
+             109:    17(bool) Load 47(cond)
+                              SelectionMerge 111 Flatten 
+                              BranchConditional 109 110 111
+             110:               Label
+                                Branch 111
+             111:             Label
+                              Branch 112
+             112:             Label
+                              LoopMerge 114 115 DependencyInfinite 
+                              Branch 116
+             116:             Label
+             117:    17(bool) Load 47(cond)
+                              BranchConditional 117 113 114
+             113:               Label
+                                Branch 115
+             115:               Label
+                                Branch 112
+             114:             Label
+                              Return
+                              FunctionEnd

+ 2 - 5
3rdparty/glslang/Test/hlsl.numthreads.comp

@@ -4,11 +4,8 @@ void main(uint3 tid : SV_DispatchThreadID )
 {
 }
 
-[numTHreaDs(4,4,2)]  // case insensitive
-void main_aux1(uint3 tid : SV_DispatchThreadID )
+[numthreads(1,4,8)]
+void main_aux2(uint3 tid : SV_DispatchThreadID )
 {
 }
 
-[numthreads(1,4,8)]
-void main_aux2(uint3 tid : SV_DispatchThreadID );
-

+ 39 - 0
3rdparty/glslang/Test/spv.controlFlowAttributes.frag

@@ -0,0 +1,39 @@
+#version 450
+
+#extension GL_EXT_control_flow_attributes : enable
+
+bool cond;
+
+void main()
+{
+        [[unroll]]                 for (int i = 0; i < 8; ++i) { }
+        [[loop]]                   for (;;) { }
+        [[dont_unroll]]            while(true) {  }
+        [[dependency_infinite]]    do {  } while(true);
+        [[dependency_length(1+3)]] for (int i = 0; i < 8; ++i) { }
+        [[flatten]]                if (cond) { } else { }
+        [[branch]]                 if (cond) cond = false;
+        [[dont_flatten]]           switch(3) {  }                      // dropped
+        [[dont_flatten]]           switch(3) { case 3: break; }
+
+        // warnings on all these
+        [[unroll(2)]]              for (int i = 0; i < 8; ++i) { }
+        [[dont_unroll(-2)]]        while(true) {  }
+        [[dependency_infinite(3)]] do {  } while(true);
+        [[dependency_length]]      for (int i = 0; i < 8; ++i) { }
+        [[flatten(3)]]             if (cond) { } else { }
+        [[branch(5.2)]]            if (cond) cond = false;
+        [[dont_flatten(3 + 7)]]    switch(3) { case 3: break; }
+
+        // other valid uses
+        [[ unroll, dont_unroll, dependency_length(2) ]]  while(cond) {  }
+        [ [ dont_flatten , branch ] ]                    switch(3) { case 3: break; }
+        [
+            // attribute
+            [
+                // here
+                flatten
+            ]
+        ]                       if (cond) { } else { }
+        [[ dependency_length(2), dependency_infinite ]]  while(cond) {  }
+}

+ 2 - 0
3rdparty/glslang/glslang/CMakeLists.txt

@@ -9,6 +9,7 @@ endif(WIN32)
 set(SOURCES
     MachineIndependent/glslang.y
     MachineIndependent/glslang_tab.cpp
+    MachineIndependent/attribute.cpp
     MachineIndependent/Constant.cpp
     MachineIndependent/iomapper.cpp
     MachineIndependent/InfoSink.cpp
@@ -51,6 +52,7 @@ set(HEADERS
     Include/revision.h
     Include/ShHandle.h
     Include/Types.h
+    MachineIndependent/attribute.h
     MachineIndependent/glslang_tab.cpp.h
     MachineIndependent/gl_types.h
     MachineIndependent/Initialize.h

+ 1 - 1
3rdparty/glslang/glslang/Include/Common.h

@@ -155,7 +155,7 @@ inline TString* NewPoolTString(const char* s)
     return new(memory) TString(s);
 }
 
-template<class T> inline T* NewPoolObject(T)
+template<class T> inline T* NewPoolObject(T*)
 {
     return new(GetThreadPoolAllocator().allocate(sizeof(T))) T;
 }

+ 3 - 3
3rdparty/glslang/glslang/Include/ConstantUnion.h

@@ -37,6 +37,9 @@
 #ifndef _CONSTANT_UNION_INCLUDED_
 #define _CONSTANT_UNION_INCLUDED_
 
+#include "../Include/Common.h"
+#include "../Include/BaseTypes.h"
+
 namespace glslang {
 
 class TConstUnion {
@@ -595,9 +598,6 @@ public:
         if (! unionArray || ! rhs.unionArray)
             return false;
 
-        if (! unionArray || ! rhs.unionArray)
-            return false;
-
         return *unionArray == *rhs.unionArray;
     }
     bool operator!=(const TConstUnionArray& rhs) const { return ! operator==(rhs); }

+ 40 - 35
3rdparty/glslang/glslang/Include/intermediate.h

@@ -819,7 +819,7 @@ public:
     virtual       glslang::TIntermMethod*        getAsMethodNode()          { return 0; }
     virtual       glslang::TIntermSymbol*        getAsSymbolNode()          { return 0; }
     virtual       glslang::TIntermBranch*        getAsBranchNode()          { return 0; }
-	virtual       glslang::TIntermLoop*          getAsLoopNode()            { return 0; }
+    virtual       glslang::TIntermLoop*          getAsLoopNode()            { return 0; }
 
     virtual const glslang::TIntermTyped*         getAsTyped()         const { return 0; }
     virtual const glslang::TIntermOperator*      getAsOperator()      const { return 0; }
@@ -832,7 +832,7 @@ public:
     virtual const glslang::TIntermMethod*        getAsMethodNode()    const { return 0; }
     virtual const glslang::TIntermSymbol*        getAsSymbolNode()    const { return 0; }
     virtual const glslang::TIntermBranch*        getAsBranchNode()    const { return 0; }
-	virtual const glslang::TIntermLoop*          getAsLoopNode()      const { return 0; }
+    virtual const glslang::TIntermLoop*          getAsLoopNode()      const { return 0; }
     virtual ~TIntermNode() { }
 
 protected:
@@ -885,24 +885,6 @@ protected:
     TType type;
 };
 
-//
-// Selection control hints
-//
-enum TSelectionControl {
-    ESelectionControlNone,
-    ESelectionControlFlatten,
-    ESelectionControlDontFlatten,
-};
-
-//
-// Loop control hints
-//
-enum TLoopControl {
-    ELoopControlNone,
-    ELoopControlUnroll,
-    ELoopControlDontUnroll,
-};
-
 //
 // Handle for, do-while, and while loops.
 //
@@ -913,26 +895,36 @@ public:
         test(aTest),
         terminal(aTerminal),
         first(testFirst),
-        control(ELoopControlNone)
+        unroll(false),
+        dontUnroll(false),
+        dependency(0)
     { }
 
-	virtual       TIntermLoop* getAsLoopNode() { return this; }
-	virtual const TIntermLoop* getAsLoopNode() const { return this; }
+    virtual       TIntermLoop* getAsLoopNode() { return this; }
+    virtual const TIntermLoop* getAsLoopNode() const { return this; }
     virtual void traverse(TIntermTraverser*);
     TIntermNode*  getBody() const { return body; }
     TIntermTyped* getTest() const { return test; }
     TIntermTyped* getTerminal() const { return terminal; }
     bool testFirst() const { return first; }
 
-    void setLoopControl(TLoopControl c) { control = c; }
-    TLoopControl getLoopControl() const { return control; }
+    void setUnroll()     { unroll = true; }
+    void setDontUnroll() { dontUnroll = true; }
+    bool getUnroll()     const { return unroll; }
+    bool getDontUnroll() const { return dontUnroll; }
+
+    static const unsigned int dependencyInfinite = 0xFFFFFFFF;
+    void setLoopDependency(int d) { dependency = d; }
+    int getLoopDependency() const { return dependency; }
 
 protected:
     TIntermNode* body;       // code to loop over
     TIntermTyped* test;      // exit condition associated with loop, could be 0 for 'for' loops
     TIntermTyped* terminal;  // exists for for-loops
     bool first;              // true for while and for, not for do-while
-    TLoopControl control;    // loop control hint
+    bool unroll;             // true if unroll requested
+    bool dontUnroll;         // true if request to not unroll
+    unsigned int dependency; // loop dependency hint; 0 means not set or unknown
 };
 
 //
@@ -1343,22 +1335,29 @@ protected:
 class TIntermSelection : public TIntermTyped {
 public:
     TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
-        TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
+        TIntermTyped(EbtVoid), condition(cond), trueBlock(trueB), falseBlock(falseB),
+        flatten(false), dontFlatten(false) {}
     TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
-        TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB), control(ESelectionControlNone) {}
+        TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB),
+        flatten(false), dontFlatten(false) {}
     virtual void traverse(TIntermTraverser*);
     virtual TIntermTyped* getCondition() const { return condition; }
     virtual TIntermNode* getTrueBlock() const { return trueBlock; }
     virtual TIntermNode* getFalseBlock() const { return falseBlock; }
     virtual       TIntermSelection* getAsSelectionNode()       { return this; }
     virtual const TIntermSelection* getAsSelectionNode() const { return this; }
-    void setSelectionControl(TSelectionControl c) { control = c; }
-    TSelectionControl getSelectionControl() const { return control; }
+
+    void setFlatten()     { flatten = true; }
+    void setDontFlatten() { dontFlatten = true; }
+    bool getFlatten()     const { return flatten; }
+    bool getDontFlatten() const { return dontFlatten; }
+
 protected:
     TIntermTyped* condition;
     TIntermNode* trueBlock;
     TIntermNode* falseBlock;
-    TSelectionControl control;    // selection control hint
+    bool flatten;     // true if flatten requested
+    bool dontFlatten; // true if requested to not flatten
 };
 
 //
@@ -1369,18 +1368,24 @@ protected:
 //
 class TIntermSwitch : public TIntermNode {
 public:
-    TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b), control(ESelectionControlNone) { }
+    TIntermSwitch(TIntermTyped* cond, TIntermAggregate* b) : condition(cond), body(b),
+        flatten(false), dontFlatten(false) {}
     virtual void traverse(TIntermTraverser*);
     virtual TIntermNode* getCondition() const { return condition; }
     virtual TIntermAggregate* getBody() const { return body; }
     virtual       TIntermSwitch* getAsSwitchNode()       { return this; }
     virtual const TIntermSwitch* getAsSwitchNode() const { return this; }
-    void setSelectionControl(TSelectionControl c) { control = c; }
-    TSelectionControl getSelectionControl() const { return control; }
+
+    void setFlatten()     { flatten = true; }
+    void setDontFlatten() { dontFlatten = true; }
+    bool getFlatten()     const { return flatten; }
+    bool getDontFlatten() const { return dontFlatten; }
+
 protected:
     TIntermTyped* condition;
     TIntermAggregate* body;
-    TSelectionControl control;    // selection control hint
+    bool flatten;     // true if flatten requested
+    bool dontFlatten; // true if requested to not flatten
 };
 
 enum TVisit

+ 9 - 9
3rdparty/glslang/glslang/MachineIndependent/Intermediate.cpp

@@ -1614,7 +1614,7 @@ TIntermAggregate* TIntermediate::makeAggregate(const TSourceLoc& loc)
 //
 // Returns the selection node created.
 //
-TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc, TSelectionControl control)
+TIntermSelection* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, const TSourceLoc& loc)
 {
     //
     // Don't prune the false path for compile-time constants; it's needed
@@ -1623,7 +1623,6 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair no
 
     TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
     node->setLoc(loc);
-    node->setSelectionControl(control);
 
     return node;
 }
@@ -1666,12 +1665,13 @@ TIntermTyped* TIntermediate::addMethod(TIntermTyped* object, const TType& type,
 //
 // Returns the selection node created, or nullptr if one could not be.
 //
-TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc& loc, TSelectionControl control)
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock,
+                                          const TSourceLoc& loc)
 {
     // If it's void, go to the if-then-else selection()
     if (trueBlock->getBasicType() == EbtVoid && falseBlock->getBasicType() == EbtVoid) {
         TIntermNodePair pair = { trueBlock, falseBlock };
-        return addSelection(cond, pair, loc, control);
+        return addSelection(cond, pair, loc);
     }
 
     //
@@ -1909,11 +1909,11 @@ const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool
 //
 // Create while and do-while loop nodes.
 //
-TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
+TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst,
+    const TSourceLoc& loc)
 {
     TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
     node->setLoc(loc);
-    node->setLoopControl(control);
 
     return node;
 }
@@ -1921,11 +1921,11 @@ TIntermLoop* TIntermediate::addLoop(TIntermNode* body, TIntermTyped* test, TInte
 //
 // Create a for-loop sequence.
 //
-TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TLoopControl control)
+TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* initializer, TIntermTyped* test,
+    TIntermTyped* terminal, bool testFirst, const TSourceLoc& loc, TIntermLoop*& node)
 {
-    TIntermLoop* node = new TIntermLoop(body, test, terminal, testFirst);
+    node = new TIntermLoop(body, test, terminal, testFirst);
     node->setLoc(loc);
-    node->setLoopControl(control);
 
     // make a sequence of the initializer and statement, but try to reuse the
     // aggregate already created for whatever is in the initializer, if there is one

+ 2 - 2
3rdparty/glslang/glslang/MachineIndependent/ParseHelper.cpp

@@ -776,7 +776,7 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct
         if (prevDec->isPrototyped() && prototype)
             profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function");
         if (prevDec->getType() != function.getType())
-            error(loc, "overloaded functions must have the same return type", function.getType().getBasicTypeString().c_str(), "");
+            error(loc, "overloaded functions must have the same return type", function.getName().c_str(), "");
         for (int i = 0; i < prevDec->getParamCount(); ++i) {
             if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage)
                 error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1);
@@ -3103,7 +3103,7 @@ void TParseContext::arrayDimCheck(const TSourceLoc& loc, const TType* type, cons
 //
 void TParseContext::arrayDimMerge(TType& type, const TArraySizes* sizes)
 {
-    if (sizes)
+    if (sizes != nullptr)
         type.addArrayOuterSizes(*sizes);
 }
 

+ 15 - 2
3rdparty/glslang/glslang/MachineIndependent/ParseHelper.h

@@ -44,13 +44,15 @@
 #ifndef _PARSER_HELPER_INCLUDED_
 #define _PARSER_HELPER_INCLUDED_
 
+#include <cstdarg>
+#include <functional>
+
 #include "parseVersions.h"
 #include "../Include/ShHandle.h"
 #include "SymbolTable.h"
 #include "localintermediate.h"
 #include "Scan.h"
-#include <cstdarg>
-#include <functional>
+#include "attribute.h"
 
 namespace glslang {
 
@@ -409,6 +411,17 @@ public:
     TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body);
 
     void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
+    TAttributeType attributeFromName(const TString& name) const;
+    TAttributes* makeAttributes(const TString& identifier) const;
+    TAttributes* makeAttributes(const TString& identifier, TIntermNode* node) const;
+    TAttributes* mergeAttributes(TAttributes*, TAttributes*) const;
+
+    // Determine selection control from attributes
+    void handleSelectionAttributes(const TAttributes& attributes, TIntermNode*);
+    void handleSwitchAttributes(const TAttributes& attributes, TIntermNode*);
+
+    // Determine loop control from attributes
+    void handleLoopAttributes(const TAttributes& attributes, TIntermNode*);
 
 protected:
     void nonInitConstCheck(const TSourceLoc&, TString& identifier, TType& type);

+ 1 - 0
3rdparty/glslang/glslang/MachineIndependent/Scan.cpp

@@ -45,6 +45,7 @@
 #include "../Include/Types.h"
 #include "SymbolTable.h"
 #include "ParseHelper.h"
+#include "attribute.h"
 #include "glslang_tab.cpp.h"
 #include "ScanContext.h"
 #include "Scan.h"

+ 2 - 0
3rdparty/glslang/glslang/MachineIndependent/Versions.cpp

@@ -188,6 +188,7 @@ void TParseVersions::initializeExtensionBehavior()
     extensionBehavior[E_GL_EXT_shader_non_constant_global_initializers] = EBhDisable;
     extensionBehavior[E_GL_EXT_shader_image_load_formatted]             = EBhDisable;
     extensionBehavior[E_GL_EXT_post_depth_coverage]                     = EBhDisable;
+    extensionBehavior[E_GL_EXT_control_flow_attributes]                 = EBhDisable;
 
     // #line and #include
     extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive]          = EBhDisable;
@@ -328,6 +329,7 @@ void TParseVersions::getPreamble(std::string& preamble)
             "#define GL_EXT_shader_non_constant_global_initializers 1\n"
             "#define GL_EXT_shader_image_load_formatted 1\n"
             "#define GL_EXT_post_depth_coverage 1\n"
+            "#define GL_EXT_control_flow_attributes 1\n"
 
 #ifdef AMD_EXTENSIONS
             "#define GL_AMD_shader_ballot 1\n"

+ 1 - 0
3rdparty/glslang/glslang/MachineIndependent/Versions.h

@@ -146,6 +146,7 @@ const char* const E_GL_EXT_shader_image_load_formatted = "GL_EXT_shader_image_lo
 const char* const E_GL_EXT_device_group                 = "GL_EXT_device_group";
 const char* const E_GL_EXT_multiview                    = "GL_EXT_multiview";
 const char* const E_GL_EXT_post_depth_coverage          = "GL_EXT_post_depth_coverage";
+const char* const E_GL_EXT_control_flow_attributes      = "GL_EXT_control_flow_attributes";
 
 // Arrays of extensions for the above viewportEXTs duplications
 

+ 257 - 0
3rdparty/glslang/glslang/MachineIndependent/attribute.cpp

@@ -0,0 +1,257 @@
+//
+// Copyright (C) 2017 LunarG, Inc.
+// Copyright (C) 2018 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of Google, Inc., nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "attribute.h"
+#include "../Include/intermediate.h"
+#include "ParseHelper.h"
+
+namespace glslang {
+
+// extract integers out of attribute arguments stored in attribute aggregate
+bool TAttributeArgs::getInt(int& value, int argNum) const 
+{
+    const TConstUnion* intConst = getConstUnion(EbtInt, argNum);
+
+    if (intConst == nullptr)
+        return false;
+
+    value = intConst->getIConst();
+    return true;
+}
+
+// extract strings out of attribute arguments stored in attribute aggregate.
+// convert to lower case if converToLower is true (for case-insensitive compare convenience)
+bool TAttributeArgs::getString(TString& value, int argNum, bool convertToLower) const 
+{
+    const TConstUnion* stringConst = getConstUnion(EbtString, argNum);
+
+    if (stringConst == nullptr)
+        return false;
+
+    value = *stringConst->getSConst();
+
+    // Convenience.
+    if (convertToLower)
+        std::transform(value.begin(), value.end(), value.begin(), ::tolower);
+
+    return true;
+}
+
+// How many arguments were supplied?
+int TAttributeArgs::size() const
+{
+    return args == nullptr ? 0 : (int)args->getSequence().size();
+}
+
+// Helper to get attribute const union.  Returns nullptr on failure.
+const TConstUnion* TAttributeArgs::getConstUnion(TBasicType basicType, int argNum) const
+{
+    if (args == nullptr)
+        return nullptr;
+
+    if (argNum >= args->getSequence().size())
+        return nullptr;
+
+    const TConstUnion* constVal = &args->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
+    if (constVal == nullptr || constVal->getType() != basicType)
+        return nullptr;
+
+    return constVal;
+}
+
+// Implementation of TParseContext parts of attributes
+TAttributeType TParseContext::attributeFromName(const TString& name) const
+{
+    if (name == "branch" || name == "dont_flatten")
+        return EatBranch;
+    else if (name == "flatten")
+        return EatFlatten;
+    else if (name == "unroll")
+        return EatUnroll;
+    else if (name == "loop" || name == "dont_unroll")
+        return EatLoop;
+    else if (name == "dependency_infinite")
+        return EatDependencyInfinite;
+    else if (name == "dependency_length")
+        return EatDependencyLength;
+    else
+        return EatNone;
+}
+
+// Make an initial leaf for the grammar from a no-argument attribute
+TAttributes* TParseContext::makeAttributes(const TString& identifier) const
+{
+    TAttributes *attributes = nullptr;
+    attributes = NewPoolObject(attributes);
+    TAttributeArgs args = { attributeFromName(identifier), nullptr };
+    attributes->push_back(args);
+    return attributes;
+}
+
+// Make an initial leaf for the grammar from a one-argument attribute
+TAttributes* TParseContext::makeAttributes(const TString& identifier, TIntermNode* node) const
+{
+    TAttributes *attributes = nullptr;
+    attributes = NewPoolObject(attributes);
+
+    // for now, node is always a simple single expression, but other code expects
+    // a list, so make it so
+    TIntermAggregate* agg = intermediate.makeAggregate(node);
+    TAttributeArgs args = { attributeFromName(identifier), agg };
+    attributes->push_back(args);
+    return attributes;
+}
+
+// Merge two sets of attributes into a single set.
+// The second argument is destructively consumed.
+TAttributes* TParseContext::mergeAttributes(TAttributes* attr1, TAttributes* attr2) const
+{
+    attr1->splice(attr1->end(), *attr2);
+    return attr1;
+}
+
+//
+// Selection attributes
+//
+void TParseContext::handleSelectionAttributes(const TAttributes& attributes, TIntermNode* node)
+{
+    TIntermSelection* selection = node->getAsSelectionNode();
+    if (selection == nullptr)
+        return;
+
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        if (it->size() > 0) {
+            warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
+            continue;
+        }
+
+        switch (it->name) {
+        case EatFlatten:
+            selection->setFlatten();
+            break;
+        case EatBranch:
+            selection->setDontFlatten();
+            break;
+        default:
+            warn(node->getLoc(), "attribute does not apply to a selection", "", "");
+            break;
+        }
+    }
+}
+
+//
+// Switch attributes
+//
+void TParseContext::handleSwitchAttributes(const TAttributes& attributes, TIntermNode* node)
+{
+    TIntermSwitch* selection = node->getAsSwitchNode();
+    if (selection == nullptr)
+        return;
+
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        if (it->size() > 0) {
+            warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
+            continue;
+        }
+
+        switch (it->name) {
+        case EatFlatten:
+            selection->setFlatten();
+            break;
+        case EatBranch:
+            selection->setDontFlatten();
+            break;
+        default:
+            warn(node->getLoc(), "attribute does not apply to a switch", "", "");
+            break;
+        }
+    }
+}
+
+//
+// Loop attributes
+//
+void TParseContext::handleLoopAttributes(const TAttributes& attributes, TIntermNode* node)
+{
+    TIntermLoop* loop = node->getAsLoopNode();
+    if (loop == nullptr) {
+        // the actual loop might be part of a sequence
+        TIntermAggregate* agg = node->getAsAggregate();
+        if (agg == nullptr)
+            return;
+        for (auto it = agg->getSequence().begin(); it != agg->getSequence().end(); ++it) {
+            loop = (*it)->getAsLoopNode();
+            if (loop != nullptr)
+                break;
+        }
+        if (loop == nullptr)
+            return;
+    }
+
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        if (it->name != EatDependencyLength && it->size() > 0) {
+            warn(node->getLoc(), "attribute with arguments not recognized, skipping", "", "");
+            continue;
+        }
+
+        int value;
+        switch (it->name) {
+        case EatUnroll:
+            loop->setUnroll();
+            break;
+        case EatLoop:
+            loop->setDontUnroll();
+            break;
+        case EatDependencyInfinite:
+            loop->setLoopDependency(TIntermLoop::dependencyInfinite);
+            break;
+        case EatDependencyLength:
+            if (it->size() == 1 && it->getInt(value)) {
+                if (value <= 0)
+                    error(node->getLoc(), "must be positive", "dependency_length", "");
+                loop->setLoopDependency(value);
+            } else
+                warn(node->getLoc(), "expected a single integer argument", "dependency_length", "");
+            break;
+        default:
+            warn(node->getLoc(), "attribute does not apply to a loop", "", "");
+            break;
+        }
+    }
+}
+
+
+} // end namespace glslang

+ 102 - 0
3rdparty/glslang/glslang/MachineIndependent/attribute.h

@@ -0,0 +1,102 @@
+//
+// Copyright (C) 2017 LunarG, Inc.
+// Copyright (C) 2018 Google, Inc.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+//    Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//
+//    Redistributions in binary form must reproduce the above
+//    copyright notice, this list of conditions and the following
+//    disclaimer in the documentation and/or other materials provided
+//    with the distribution.
+//
+//    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
+//    contributors may be used to endorse or promote products derived
+//    from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef _ATTRIBUTE_INCLUDED_
+#define _ATTRIBUTE_INCLUDED_
+
+#include "../Include/Common.h"
+#include "../Include/ConstantUnion.h"
+
+namespace glslang {
+
+    enum TAttributeType {
+        EatNone,
+        EatAllow_uav_condition,
+        EatBranch,
+        EatCall,
+        EatDomain,
+        EatEarlyDepthStencil,
+        EatFastOpt,
+        EatFlatten,
+        EatForceCase,
+        EatInstance,
+        EatMaxTessFactor,
+        EatNumThreads,
+        EatMaxVertexCount,
+        EatOutputControlPoints,
+        EatOutputTopology,
+        EatPartitioning,
+        EatPatchConstantFunc,
+        EatPatchSize,
+        EatUnroll,
+        EatLoop,
+        EatBinding,
+        EatGlobalBinding,
+        EatLocation,
+        EatInputAttachment,
+        EatBuiltIn,
+        EatPushConstant,
+        EatConstantId,
+        EatDependencyInfinite,
+        EatDependencyLength
+    };
+
+    class TIntermAggregate;
+
+    struct TAttributeArgs {
+        TAttributeType name;
+        const TIntermAggregate* args;
+
+        // Obtain attribute as integer
+        // Return false if it cannot be obtained
+        bool getInt(int& value, int argNum = 0) const;
+
+        // Obtain attribute as string, with optional to-lower transform
+        // Return false if it cannot be obtained
+        bool getString(TString& value, int argNum = 0, bool convertToLower = true) const;
+
+        // How many arguments were provided to the attribute?
+        int size() const;
+
+    protected:
+        const TConstUnion* getConstUnion(TBasicType basicType, int argNum) const;
+    };
+
+    typedef TList<TAttributeArgs> TAttributes;
+
+} // end namespace glslang
+
+#endif // _ATTRIBUTE_INCLUDED_

+ 58 - 5
3rdparty/glslang/glslang/MachineIndependent/glslang.y

@@ -58,6 +58,7 @@ Jutta Degener, 1995
 #include "SymbolTable.h"
 #include "ParseHelper.h"
 #include "../Public/ShaderLang.h"
+#include "attribute.h"
 
 using namespace glslang;
 
@@ -86,6 +87,7 @@ using namespace glslang;
             TIntermNode* intermNode;
             glslang::TIntermNodePair nodePair;
             glslang::TIntermTyped* intermTypedNode;
+            glslang::TAttributes* attributes;
         };
         union {
             glslang::TPublicType type;
@@ -218,12 +220,12 @@ extern int yylex(YYSTYPE*, TParseContext&);
 %type <interm.intermNode> translation_unit function_definition
 %type <interm.intermNode> statement simple_statement
 %type <interm.intermNode> statement_list switch_statement_list compound_statement
-%type <interm.intermNode> declaration_statement selection_statement expression_statement
-%type <interm.intermNode> switch_statement case_label
+%type <interm.intermNode> declaration_statement selection_statement selection_statement_nonattributed expression_statement
+%type <interm.intermNode> switch_statement switch_statement_nonattributed case_label
 %type <interm.intermNode> declaration external_declaration
 %type <interm.intermNode> for_init_statement compound_statement_no_new_scope
 %type <interm.nodePair> selection_rest_statement for_rest_statement
-%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope statement_scoped
+%type <interm.intermNode> iteration_statement iteration_statement_nonattributed jump_statement statement_no_new_scope statement_scoped
 %type <interm> single_declaration init_declarator_list
 
 %type <interm> parameter_declaration parameter_declarator parameter_type_specifier
@@ -246,6 +248,8 @@ extern int yylex(YYSTYPE*, TParseContext&);
 
 %type <interm.identifierList> identifier_list
 
+%type <interm.attributes> attribute attribute_list single_attribute
+
 %start translation_unit
 %%
 
@@ -898,9 +902,9 @@ parameter_declarator
         parseContext.arraySizeRequiredCheck($3.loc, *$3.arraySizes);
         parseContext.reservedErrorCheck($2.loc, *$2.string);
 
-        $1.arraySizes = $3.arraySizes;
-
         TParameter param = { $2.string, new TType($1)};
+        parseContext.arrayDimMerge(*param.type, $3.arraySizes);
+
         $$.loc = $2.loc;
         $$.param = param;
     }
@@ -2673,6 +2677,15 @@ expression_statement
     ;
 
 selection_statement
+    : selection_statement_nonattributed {
+        $$ = $1;
+    }
+    | attribute selection_statement_nonattributed {
+        parseContext.handleSelectionAttributes(*$1, $2);
+        $$ = $2;
+    }
+
+selection_statement_nonattributed
     : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
         parseContext.boolCheck($1.loc, $3);
         $$ = parseContext.intermediate.addSelection($3, $5, $1.loc);
@@ -2709,6 +2722,15 @@ condition
     ;
 
 switch_statement
+    : switch_statement_nonattributed {
+        $$ = $1;
+    }
+    | attribute switch_statement_nonattributed {
+        parseContext.handleSwitchAttributes(*$1, $2);
+        $$ = $2;
+    }
+
+switch_statement_nonattributed
     : SWITCH LEFT_PAREN expression RIGHT_PAREN {
         // start new switch sequence on the switch stack
         ++parseContext.controlFlowNestingLevel;
@@ -2762,6 +2784,15 @@ case_label
     ;
 
 iteration_statement
+    : iteration_statement_nonattributed {
+        $$ = $1;
+    }
+    | attribute iteration_statement_nonattributed {
+        parseContext.handleLoopAttributes(*$1, $2);
+        $$ = $2;
+    }
+
+iteration_statement_nonattributed
     : WHILE LEFT_PAREN {
         if (! parseContext.limits.whileLoops)
             parseContext.error($1.loc, "while loops not available", "limitation", "");
@@ -2920,4 +2951,26 @@ function_definition
     }
     ;
 
+attribute
+    : LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET {
+        $$ = $3;
+        parseContext.requireExtensions($1.loc, 1, &E_GL_EXT_control_flow_attributes, "attribute");
+    }
+
+attribute_list
+    : single_attribute {
+        $$ = $1;
+    }
+    | attribute_list COMMA single_attribute {
+        $$ = parseContext.mergeAttributes($1, $3);
+    }
+
+single_attribute
+    : IDENTIFIER {
+        $$ = parseContext.makeAttributes(*$1.string);
+    }
+    | IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN {
+        $$ = parseContext.makeAttributes(*$1.string, $3);
+    }
+
 %%

Разница между файлами не показана из-за своего большого размера
+ 477 - 434
3rdparty/glslang/glslang/MachineIndependent/glslang_tab.cpp


+ 3 - 2
3rdparty/glslang/glslang/MachineIndependent/glslang_tab.cpp.h

@@ -348,7 +348,7 @@ extern int yydebug;
 typedef union YYSTYPE YYSTYPE;
 union YYSTYPE
 {
-#line 68 "MachineIndependent/glslang.y" /* yacc.c:1909  */
+#line 69 "MachineIndependent/glslang.y" /* yacc.c:1909  */
 
     struct {
         glslang::TSourceLoc loc;
@@ -370,6 +370,7 @@ union YYSTYPE
             TIntermNode* intermNode;
             glslang::TIntermNodePair nodePair;
             glslang::TIntermTyped* intermTypedNode;
+            glslang::TAttributes* attributes;
         };
         union {
             glslang::TPublicType type;
@@ -382,7 +383,7 @@ union YYSTYPE
         };
     } interm;
 
-#line 386 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909  */
+#line 387 "MachineIndependent/glslang_tab.cpp.h" /* yacc.c:1909  */
 };
 # define YYSTYPE_IS_TRIVIAL 1
 # define YYSTYPE_IS_DECLARED 1

+ 25 - 3
3rdparty/glslang/glslang/MachineIndependent/intermOut.cpp

@@ -817,7 +817,13 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node
     OutputTreeText(out, node, depth);
 
     out.debug << "Test condition and select";
-    out.debug << " (" << node->getCompleteString() << ")\n";
+    out.debug << " (" << node->getCompleteString() << ")";
+
+    if (node->getFlatten())
+        out.debug << ": Flatten";
+    if (node->getDontFlatten())
+        out.debug << ": DontFlatten";
+    out.debug << "\n";
 
     ++depth;
 
@@ -979,7 +985,17 @@ bool TOutputTraverser::visitLoop(TVisit /* visit */, TIntermLoop* node)
     out.debug << "Loop with condition ";
     if (! node->testFirst())
         out.debug << "not ";
-    out.debug << "tested first\n";
+    out.debug << "tested first";
+
+    if (node->getUnroll())
+        out.debug << ": Unroll";
+    if (node->getDontUnroll())
+        out.debug << ": DontUnroll";
+    if (node->getLoopDependency()) {
+        out.debug << ": Dependency ";
+        out.debug << node->getLoopDependency();
+    }
+    out.debug << "\n";
 
     ++depth;
 
@@ -1040,7 +1056,13 @@ bool TOutputTraverser::visitSwitch(TVisit /* visit */, TIntermSwitch* node)
     TInfoSink& out = infoSink;
 
     OutputTreeText(out, node, depth);
-    out.debug << "switch\n";
+    out.debug << "switch";
+
+    if (node->getFlatten())
+        out.debug << ": Flatten";
+    if (node->getDontFlatten())
+        out.debug << ": DontFlatten";
+    out.debug << "\n";
 
     OutputTreeText(out, node, depth);
     out.debug << "condition\n";

+ 5 - 4
3rdparty/glslang/glslang/MachineIndependent/localintermediate.h

@@ -420,8 +420,8 @@ public:
     TIntermAggregate* makeAggregate(const TSourceLoc&);
     TIntermTyped* setAggregateOperator(TIntermNode*, TOperator, const TType& type, TSourceLoc);
     bool areAllChildConst(TIntermAggregate* aggrNode);
-    TIntermTyped* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
-    TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&, TSelectionControl = ESelectionControlNone);
+    TIntermSelection* addSelection(TIntermTyped* cond, TIntermNodePair code, const TSourceLoc&);
+    TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, const TSourceLoc&);
     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, const TSourceLoc&);
     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, const TSourceLoc&);
     TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, const TSourceLoc&, bool literal = false) const;
@@ -439,8 +439,9 @@ public:
     TIntermConstantUnion* addConstantUnion(const TString*, const TSourceLoc&, bool literal = false) const;
     TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
-    TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
-    TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&, TLoopControl = ELoopControlNone);
+    TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, const TSourceLoc&);
+    TIntermAggregate* addForLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst,
+        const TSourceLoc&, TIntermLoop*&);
     TIntermBranch* addBranch(TOperator, const TSourceLoc&);
     TIntermBranch* addBranch(TOperator, TIntermTyped*, const TSourceLoc&);
     template<typename selectorType> TIntermTyped* addSwizzle(TSwizzleSelectors<selectorType>&, const TSourceLoc&);

+ 2 - 1
3rdparty/glslang/glslang/Public/ShaderLang.h

@@ -119,7 +119,8 @@ typedef enum {
 
 typedef enum {
     EShTargetNone,
-    EshTargetSpv,
+    EShTargetSpv,                 // preferred spelling
+    EshTargetSpv = EShTargetSpv,  // legacy spelling
 } EShTargetLanguage;
 
 struct TInputLanguage {

+ 1 - 1
3rdparty/glslang/gtests/Hlsl.FromFile.cpp

@@ -247,7 +247,7 @@ INSTANTIATE_TEST_CASE_P(
         {"hlsl.matrixindex.frag", "main"},
         {"hlsl.nonstaticMemberFunction.frag", "main"},
         {"hlsl.numericsuffixes.frag", "main"},
-        {"hlsl.numthreads.comp", "main_aux1"},
+        {"hlsl.numthreads.comp", "main_aux2"},
         {"hlsl.overload.frag", "PixelShaderFunction"},
         {"hlsl.opaque-type-bug.frag", "main"},
         {"hlsl.params.default.frag", "main"},

+ 1 - 0
3rdparty/glslang/gtests/Spv.FromFile.cpp

@@ -235,6 +235,7 @@ INSTANTIATE_TEST_CASE_P(
         "spv.branch-return.vert",
         "spv.builtInXFB.vert",
         "spv.conditionalDiscard.frag",
+        "spv.controlFlowAttributes.frag",
         "spv.conversion.frag",
         "spv.dataOut.frag",
         "spv.dataOutIndirect.frag",

+ 29 - 113
3rdparty/glslang/hlsl/hlslAttributes.cpp

@@ -34,157 +34,73 @@
 //
 
 #include "hlslAttributes.h"
-#include <cstdlib>
-#include <cctype>
-#include <algorithm>
+#include "hlslParseHelper.h"
 
 namespace glslang {
     // Map the given string to an attribute enum from TAttributeType,
     // or EatNone if invalid.
-    TAttributeType TAttributeMap::attributeFromName(const TString& nameSpace, const TString& name)
+    TAttributeType HlslParseContext::attributeFromName(const TString& nameSpace, const TString& name) const
     {
-        // These are case insensitive.
-        TString lowername(name);
-        std::transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);
-        TString lowernameSpace(nameSpace);
-        std::transform(lowernameSpace.begin(), lowernameSpace.end(), lowernameSpace.begin(), ::tolower);
-
         // handle names within a namespace
 
-        if (lowernameSpace == "vk") {
-            if (lowername == "input_attachment_index")
+        if (nameSpace == "vk") {
+            if (name == "input_attachment_index")
                 return EatInputAttachment;
-            else if (lowername == "location")
+            else if (name == "location")
                 return EatLocation;
-            else if (lowername == "binding")
+            else if (name == "binding")
                 return EatBinding;
-            else if (lowername == "global_cbuffer_binding")
+            else if (name == "global_cbuffer_binding")
                 return EatGlobalBinding;
-            else if (lowername == "builtin")
+            else if (name == "builtin")
                 return EatBuiltIn;
-            else if (lowername == "constant_id")
+            else if (name == "constant_id")
                 return EatConstantId;
-            else if (lowername == "push_constant")
+            else if (name == "push_constant")
                 return EatPushConstant;
-        } else if (lowernameSpace.size() > 0)
+        } else if (nameSpace.size() > 0)
             return EatNone;
 
         // handle names with no namespace
 
-        if (lowername == "allow_uav_condition")
+        if (name == "allow_uav_condition")
             return EatAllow_uav_condition;
-        else if (lowername == "branch")
+        else if (name == "branch")
             return EatBranch;
-        else if (lowername == "call")
+        else if (name == "call")
             return EatCall;
-        else if (lowername == "domain")
+        else if (name == "domain")
             return EatDomain;
-        else if (lowername == "earlydepthstencil")
+        else if (name == "earlydepthstencil")
             return EatEarlyDepthStencil;
-        else if (lowername == "fastopt")
+        else if (name == "fastopt")
             return EatFastOpt;
-        else if (lowername == "flatten")
+        else if (name == "flatten")
             return EatFlatten;
-        else if (lowername == "forcecase")
+        else if (name == "forcecase")
             return EatForceCase;
-        else if (lowername == "instance")
+        else if (name == "instance")
             return EatInstance;
-        else if (lowername == "maxtessfactor")
+        else if (name == "maxtessfactor")
             return EatMaxTessFactor;
-        else if (lowername == "maxvertexcount")
+        else if (name == "maxvertexcount")
             return EatMaxVertexCount;
-        else if (lowername == "numthreads")
+        else if (name == "numthreads")
             return EatNumThreads;
-        else if (lowername == "outputcontrolpoints")
+        else if (name == "outputcontrolpoints")
             return EatOutputControlPoints;
-        else if (lowername == "outputtopology")
+        else if (name == "outputtopology")
             return EatOutputTopology;
-        else if (lowername == "partitioning")
+        else if (name == "partitioning")
             return EatPartitioning;
-        else if (lowername == "patchconstantfunc")
+        else if (name == "patchconstantfunc")
             return EatPatchConstantFunc;
-        else if (lowername == "unroll")
+        else if (name == "unroll")
             return EatUnroll;
-        else if (lowername == "loop")
+        else if (name == "loop")
             return EatLoop;
         else
             return EatNone;
     }
 
-    // Look up entry, inserting if it's not there, and if name is a valid attribute name
-    // as known by attributeFromName.
-    TAttributeType TAttributeMap::setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value)
-    {
-        if (name == nullptr)
-            return EatNone;
-
-        const TAttributeType attr = attributeFromName(nameSpace, *name);
-
-        if (attr != EatNone)
-            attributes[attr] = value;
-
-        return attr;
-    }
-
-    // Look up entry (const version), and return aggregate node.  This cannot change the map.
-    const TIntermAggregate* TAttributeMap::operator[](TAttributeType attr) const
-    {
-        const auto entry = attributes.find(attr);
-
-        return (entry == attributes.end()) ? nullptr : entry->second;
-    }
-
-    // True if entry exists in map (even if value is nullptr)
-    bool TAttributeMap::contains(TAttributeType attr) const
-    {
-        return attributes.find(attr) != attributes.end();
-    }
-
-    // extract integers out of attribute arguments stored in attribute aggregate
-    bool TAttributeMap::getInt(TAttributeType attr, int& value, int argNum) const 
-    {
-        const TConstUnion* intConst = getConstUnion(attr, EbtInt, argNum);
-
-        if (intConst == nullptr)
-            return false;
-
-        value = intConst->getIConst();
-        return true;
-    };
-
-    // extract strings out of attribute arguments stored in attribute aggregate.
-    // convert to lower case if converToLower is true (for case-insensitive compare convenience)
-    bool TAttributeMap::getString(TAttributeType attr, TString& value, int argNum, bool convertToLower) const 
-    {
-        const TConstUnion* stringConst = getConstUnion(attr, EbtString, argNum);
-
-        if (stringConst == nullptr)
-            return false;
-
-        value = *stringConst->getSConst();
-
-        // Convenience.
-        if (convertToLower)
-            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
-
-        return true;
-    };
-
-    // Helper to get attribute const union.  Returns nullptr on failure.
-    const TConstUnion* TAttributeMap::getConstUnion(TAttributeType attr, TBasicType basicType, int argNum) const
-    {
-        const TIntermAggregate* attrAgg = (*this)[attr];
-        if (attrAgg == nullptr)
-            return nullptr;
-
-        if (argNum >= int(attrAgg->getSequence().size()))
-            return nullptr;
-
-        const TConstUnion* constVal = &attrAgg->getSequence()[argNum]->getAsConstantUnion()->getConstArray()[0];
-        if (constVal == nullptr || constVal->getType() != basicType)
-            return nullptr;
-
-        return constVal;
-    }
-
 } // end namespace glslang

+ 4 - 75
3rdparty/glslang/hlsl/hlslAttributes.h

@@ -38,93 +38,22 @@
 
 #include <unordered_map>
 #include <functional>
-#include "hlslScanContext.h"
-#include "../glslang/Include/Common.h"
 
-namespace glslang {
-    enum TAttributeType {
-        EatNone,
-        EatAllow_uav_condition,
-        EatBranch,
-        EatCall,
-        EatDomain,
-        EatEarlyDepthStencil,
-        EatFastOpt,
-        EatFlatten,
-        EatForceCase,
-        EatInstance,
-        EatMaxTessFactor,
-        EatNumThreads,
-        EatMaxVertexCount,
-        EatOutputControlPoints,
-        EatOutputTopology,
-        EatPartitioning,
-        EatPatchConstantFunc,
-        EatPatchSize,
-        EatUnroll,
-        EatLoop,
-        EatBinding,
-        EatGlobalBinding,
-        EatLocation,
-        EatInputAttachment,
-        EatBuiltIn,
-        EatPushConstant,
-        EatConstantId
-    };
-}
-
-namespace std {
-    // Allow use of TAttributeType enum in hash_map without calling code having to cast.
-    template <> struct hash<glslang::TAttributeType> {
-        std::size_t operator()(glslang::TAttributeType attr) const {
-            return std::hash<int>()(int(attr));
-        }
-    };
-} // end namespace std
+#include "../glslang/MachineIndependent/attribute.h"
+#include "../glslang/MachineIndependent/SymbolTable.h"
+#include "hlslScanContext.h"
 
 namespace glslang {
-    class TIntermAggregate;
-
-    class TAttributeMap {
-    public:
-        int size() const { return (int)attributes.size(); }
-
-        // Search for and potentially add the attribute into the map.  Return the
-        // attribute type enum for it, if found, else EatNone.
-        TAttributeType setAttribute(const TString& nameSpace, const TString* name, TIntermAggregate* value);
-
-        // Const lookup: search for (but do not modify) the attribute in the map.
-        const TIntermAggregate* operator[](TAttributeType) const;
-
-        // True if entry exists in map (even if value is nullptr)
-        bool contains(TAttributeType) const;
-
-        // Obtain attribute as integer
-        bool getInt(TAttributeType attr, int& value, int argNum = 0) const;
-
-        // Obtain attribute as string, with optional to-lower transform
-        bool getString(TAttributeType attr, TString& value, int argNum = 0, bool convertToLower = true) const;
-
-    protected:
-        // Helper to get attribute const union
-        const TConstUnion* getConstUnion(TAttributeType attr, TBasicType, int argNum) const;
-
-        // Find an attribute enum given its name.
-        static TAttributeType attributeFromName(const TString& nameSpace, const TString& name);
-
-        std::unordered_map<TAttributeType, TIntermAggregate*> attributes;
-    };
 
     class TFunctionDeclarator {
     public:
         TFunctionDeclarator() : function(nullptr), body(nullptr) { }
         TSourceLoc loc;
         TFunction* function;
-        TAttributeMap attributes;
+        TAttributes attributes;
         TVector<HlslToken>* body;
     };
 
 } // end namespace glslang
 
-
 #endif // HLSLATTRIBUTES_H_

+ 57 - 34
3rdparty/glslang/hlsl/hlslGrammar.cpp

@@ -396,6 +396,9 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
         if (peekTokenClass(EHTokLeftParen)) {
             // looks like function parameters
 
+            // merge in the attributes into the return type
+            parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType, true);
+
             // Potentially rename shader entry point function.  No-op most of the time.
             parseContext.renameShaderFunction(fullName);
 
@@ -423,7 +426,13 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
                 parseContext.handleFunctionDeclarator(declarator.loc, *declarator.function, true);
             }
         } else {
-            // A variable declaration. Fix the storage qualifier if it's a global.
+            // A variable declaration.
+
+            // merge in the attributes, the first time around, into the shared type
+            if (! declarator_list)
+                parseContext.transferTypeAttributes(token.loc, declarator.attributes, declaredType);
+
+            // Fix the storage qualifier if it's a global.
             if (declaredType.getQualifier().storage == EvqTemporary && parseContext.symbolTable.atGlobalLevel())
                 declaredType.getQualifier().storage = EvqUniform;
 
@@ -536,13 +545,16 @@ bool HlslGrammar::acceptDeclaration(TIntermNode*& nodeList)
 bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
 {
     node = nullptr;
-    TAttributeMap attributes;
+    TAttributes attributes;
 
     // fully_specified_type
     TType type;
     if (! acceptFullySpecifiedType(type, attributes))
         return false;
 
+    if (attributes.size() > 0)
+        parseContext.warn(token.loc, "attributes don't apply to control declaration", "", "");
+
     // filter out type casts
     if (peekTokenClass(EHTokLeftParen)) {
         recedeToken();
@@ -578,12 +590,12 @@ bool HlslGrammar::acceptControlDeclaration(TIntermNode*& node)
 //      : type_specifier
 //      | type_qualifier type_specifier
 //
-bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributeMap& attributes)
+bool HlslGrammar::acceptFullySpecifiedType(TType& type, const TAttributes& attributes)
 {
     TIntermNode* nodeList = nullptr;
     return acceptFullySpecifiedType(type, nodeList, attributes);
 }
-bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributeMap& attributes, bool forbidDeclarators)
+bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList, const TAttributes& attributes, bool forbidDeclarators)
 {
     // type_qualifier
     TQualifier qualifier;
@@ -608,7 +620,7 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
         parseContext.mergeQualifiers(type.getQualifier(), qualifier);
     
         // merge in the attributes
-        parseContext.transferTypeAttributes(attributes, type);
+        parseContext.transferTypeAttributes(token.loc, attributes, type);
 
         // further, it can create an anonymous instance of the block
         // (cbuffer and tbuffer don't consume the next identifier, and
@@ -633,9 +645,6 @@ bool HlslGrammar::acceptFullySpecifiedType(TType& type, TIntermNode*& nodeList,
             qualifier.builtIn = type.getQualifier().builtIn;
 
         type.getQualifier() = qualifier;
-
-        // merge in the attributes
-        parseContext.transferTypeAttributes(attributes, type);
     }
 
     return true;
@@ -2335,7 +2344,7 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
         // struct_declaration
 
         // attributes
-        TAttributeMap attributes;
+        TAttributes attributes;
         acceptAttributes(attributes);
 
         bool declarator_list = false;
@@ -2346,6 +2355,9 @@ bool HlslGrammar::acceptStructDeclarationList(TTypeList*& typeList, TIntermNode*
             expected("member type");
             return false;
         }
+        
+        // merge in the attributes
+        parseContext.transferTypeAttributes(token.loc, attributes, memberType);
 
         // struct_declarator COMMA struct_declarator ...
         bool functionDefinitionAccepted = false;
@@ -2542,7 +2554,7 @@ bool HlslGrammar::acceptDefaultParameterDeclaration(const TType& type, TIntermTy
 bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
 {
     // attributes
-    TAttributeMap attributes;
+    TAttributes attributes;
     acceptAttributes(attributes);
 
     // fully_specified_type
@@ -2550,6 +2562,9 @@ bool HlslGrammar::acceptParameterDeclaration(TFunction& function)
     if (! acceptFullySpecifiedType(*type, attributes))
         return false;
 
+    // merge in the attributes
+    parseContext.transferTypeAttributes(token.loc, attributes, *type);
+
     // identifier
     HlslToken idToken;
     acceptIdentifier(idToken);
@@ -3386,7 +3401,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
     statement = nullptr;
 
     // attributes
-    TAttributeMap attributes;
+    TAttributes attributes;
     acceptAttributes(attributes);
 
     // attributed_statement
@@ -3458,7 +3473,7 @@ bool HlslGrammar::acceptStatement(TIntermNode*& statement)
 //      | PATCHCONSTANTFUNC
 //      | NUMTHREADS LEFT_PAREN x_size, y_size,z z_size RIGHT_PAREN
 //
-void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
+void HlslGrammar::acceptAttributes(TAttributes& attributes)
 {
     // For now, accept the [ XXX(X) ] syntax, but drop all but
     // numthreads, which is used to set the CS local size.
@@ -3529,9 +3544,16 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
             return;
         }
 
-        // Add any values we found into the attribute map.  This accepts
-        // (and ignores) values not mapping to a known TAttributeType;
-        attributes.setAttribute(nameSpace, attributeToken.string, expressions);
+        // Add any values we found into the attribute map.
+        if (attributeToken.string != nullptr) {
+            TAttributeType attributeType = parseContext.attributeFromName(nameSpace, *attributeToken.string);
+            if (attributeType == EatNone)
+                parseContext.warn(attributeToken.loc, "unrecognized attribute", attributeToken.string->c_str(), "");
+            else {
+                TAttributeArgs attributeArgs = { attributeType, expressions };
+                attributes.push_back(attributeArgs);
+            }
+        }
     } while (true);
 }
 
@@ -3539,12 +3561,10 @@ void HlslGrammar::acceptAttributes(TAttributeMap& attributes)
 //      : IF LEFT_PAREN expression RIGHT_PAREN statement
 //      : IF LEFT_PAREN expression RIGHT_PAREN statement ELSE statement
 //
-bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributeMap& attributes)
+bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttributes& attributes)
 {
     TSourceLoc loc = token.loc;
 
-    const TSelectionControl control = parseContext.handleSelectionControl(attributes);
-
     // IF
     if (! acceptTokenClass(EHTokIf))
         return false;
@@ -3582,7 +3602,9 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
     }
 
     // Put the pieces together
-    statement = intermediate.addSelection(condition, thenElse, loc, control);
+    statement = intermediate.addSelection(condition, thenElse, loc);
+    parseContext.handleSelectionAttributes(loc, statement->getAsSelectionNode(), attributes);
+
     parseContext.popScope();
     --parseContext.controlFlowNestingLevel;
 
@@ -3592,13 +3614,11 @@ bool HlslGrammar::acceptSelectionStatement(TIntermNode*& statement, const TAttri
 // switch_statement
 //      : SWITCH LEFT_PAREN expression RIGHT_PAREN compound_statement
 //
-bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributeMap& attributes)
+bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttributes& attributes)
 {
     // SWITCH
     TSourceLoc loc = token.loc;
 
-    const TSelectionControl control = parseContext.handleSelectionControl(attributes);
-
     if (! acceptTokenClass(EHTokSwitch))
         return false;
 
@@ -3618,7 +3638,8 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
     --parseContext.controlFlowNestingLevel;
 
     if (statementOkay)
-        statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr, control);
+        statement = parseContext.addSwitch(loc, switchExpression, statement ? statement->getAsAggregate() : nullptr,
+                                           attributes);
 
     parseContext.popSwitchSequence();
     parseContext.popScope();
@@ -3632,7 +3653,7 @@ bool HlslGrammar::acceptSwitchStatement(TIntermNode*& statement, const TAttribut
 //      | FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement
 //
 // Non-speculative, only call if it needs to be found; WHILE or DO or FOR already seen.
-bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributeMap& attributes)
+bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttributes& attributes)
 {
     TSourceLoc loc = token.loc;
     TIntermTyped* condition = nullptr;
@@ -3642,9 +3663,8 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
 
     //  WHILE or DO or FOR
     advanceToken();
-    
-    const TLoopControl control = parseContext.handleLoopControl(attributes);
 
+    TIntermLoop* loopNode = nullptr;
     switch (loop) {
     case EHTokWhile:
         // so that something declared in the condition is scoped to the lifetime
@@ -3670,9 +3690,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
         parseContext.popScope();
         --parseContext.controlFlowNestingLevel;
 
-        statement = intermediate.addLoop(statement, condition, nullptr, true, loc, control);
-
-        return true;
+        loopNode = intermediate.addLoop(statement, condition, nullptr, true, loc);
+        statement = loopNode;
+        break;
 
     case EHTokDo:
         parseContext.nestLooping();  // this only needs to work right if no errors
@@ -3703,9 +3723,9 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
         parseContext.unnestLooping();
         --parseContext.controlFlowNestingLevel;
 
-        statement = intermediate.addLoop(statement, condition, 0, false, loc, control);
-
-        return true;
+        loopNode = intermediate.addLoop(statement, condition, 0, false, loc);
+        statement = loopNode;
+        break;
 
     case EHTokFor:
     {
@@ -3747,18 +3767,21 @@ bool HlslGrammar::acceptIterationStatement(TIntermNode*& statement, const TAttri
             return false;
         }
 
-        statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, control);
+        statement = intermediate.addForLoop(statement, initNode, condition, iterator, true, loc, loopNode);
 
         parseContext.popScope();
         parseContext.unnestLooping();
         --parseContext.controlFlowNestingLevel;
 
-        return true;
+        break;
     }
 
     default:
         return false;
     }
+
+    parseContext.handleLoopAttributes(loc, loopNode, attributes);
+    return true;
 }
 
 // jump_statement

+ 6 - 7
3rdparty/glslang/hlsl/hlslGrammar.h

@@ -43,7 +43,6 @@
 
 namespace glslang {
 
-    class TAttributeMap;
     class TFunctionDeclarator;
 
     // Should just be the grammar aspect of HLSL.
@@ -71,8 +70,8 @@ namespace glslang {
         bool acceptControlDeclaration(TIntermNode*& node);
         bool acceptSamplerDeclarationDX9(TType&);
         bool acceptSamplerState();
-        bool acceptFullySpecifiedType(TType&, const TAttributeMap&);
-        bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributeMap&, bool forbidDeclarators = false);
+        bool acceptFullySpecifiedType(TType&, const TAttributes&);
+        bool acceptFullySpecifiedType(TType&, TIntermNode*& nodeList, const TAttributes&, bool forbidDeclarators = false);
         bool acceptQualifier(TQualifier&);
         bool acceptLayoutQualifierList(TQualifier&);
         bool acceptType(TType&);
@@ -117,10 +116,10 @@ namespace glslang {
         bool acceptScopedCompoundStatement(TIntermNode*&);
         bool acceptStatement(TIntermNode*&);
         bool acceptNestedStatement(TIntermNode*&);
-        void acceptAttributes(TAttributeMap&);
-        bool acceptSelectionStatement(TIntermNode*&, const TAttributeMap&);
-        bool acceptSwitchStatement(TIntermNode*&, const TAttributeMap&);
-        bool acceptIterationStatement(TIntermNode*&, const TAttributeMap&);
+        void acceptAttributes(TAttributes&);
+        bool acceptSelectionStatement(TIntermNode*&, const TAttributes&);
+        bool acceptSwitchStatement(TIntermNode*&, const TAttributes&);
+        bool acceptIterationStatement(TIntermNode*&, const TAttributes&);
         bool acceptJumpStatement(TIntermNode*&);
         bool acceptCaseLabel(TIntermNode*&);
         bool acceptDefaultLabel(TIntermNode*&);

+ 247 - 173
3rdparty/glslang/hlsl/hlslParseHelper.cpp

@@ -1620,7 +1620,7 @@ void HlslParseContext::addStructBufferHiddenCounterParam(const TSourceLoc& loc,
 // Returns an aggregate of parameter-symbol nodes.
 //
 TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& loc, TFunction& function,
-                                                             const TAttributeMap& attributes,
+                                                             const TAttributes& attributes,
                                                              TIntermNode*& entryPointTree)
 {
     currentCaller = function.getMangledName();
@@ -1717,189 +1717,217 @@ TIntermAggregate* HlslParseContext::handleFunctionDefinition(const TSourceLoc& l
 }
 
 // Handle all [attrib] attribute for the shader entry point
-void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributeMap& attributes)
+void HlslParseContext::handleEntryPointAttributes(const TSourceLoc& loc, const TAttributes& attributes)
 {
-    // Handle entry-point function attributes
-    const TIntermAggregate* numThreads = attributes[EatNumThreads];
-    if (numThreads != nullptr) {
-        const TIntermSequence& sequence = numThreads->getSequence();
-
-        for (int lid = 0; lid < int(sequence.size()); ++lid)
-            intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
-    }
-
-    // MaxVertexCount
-    if (attributes.contains(EatMaxVertexCount)) {
-        int maxVertexCount;
-
-        if (! attributes.getInt(EatMaxVertexCount, maxVertexCount)) {
-            error(loc, "invalid maxvertexcount", "", "");
-        } else {
-            if (! intermediate.setVertices(maxVertexCount))
-                error(loc, "cannot change previously set maxvertexcount attribute", "", "");
-        }
-    }
-
-    // Handle [patchconstantfunction("...")]
-    if (attributes.contains(EatPatchConstantFunc)) {
-        TString pcfName;
-        if (! attributes.getString(EatPatchConstantFunc, pcfName, 0, false)) {
-            error(loc, "invalid patch constant function", "", "");
-        } else {
-            patchConstantFunctionName = pcfName;
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        switch (it->name) {
+        case EatNumThreads:
+        {
+            const TIntermSequence& sequence = it->args->getSequence();
+            for (int lid = 0; lid < int(sequence.size()); ++lid)
+                intermediate.setLocalSize(lid, sequence[lid]->getAsConstantUnion()->getConstArray()[0].getIConst());
+            break;
         }
-    }
+        case EatMaxVertexCount:
+        {
+            int maxVertexCount;
 
-    // Handle [domain("...")]
-    if (attributes.contains(EatDomain)) {
-        TString domainStr;
-        if (! attributes.getString(EatDomain, domainStr)) {
-            error(loc, "invalid domain", "", "");
-        } else {
-            TLayoutGeometry domain = ElgNone;
-
-            if (domainStr == "tri") {
-                domain = ElgTriangles;
-            } else if (domainStr == "quad") {
-                domain = ElgQuads;
-            } else if (domainStr == "isoline") {
-                domain = ElgIsolines;
+            if (! it->getInt(maxVertexCount)) {
+                error(loc, "invalid maxvertexcount", "", "");
             } else {
-                error(loc, "unsupported domain type", domainStr.c_str(), "");
+                if (! intermediate.setVertices(maxVertexCount))
+                    error(loc, "cannot change previously set maxvertexcount attribute", "", "");
             }
-
-            if (language == EShLangTessEvaluation) {
-                if (! intermediate.setInputPrimitive(domain))
-                    error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+            break;
+        }
+        case EatPatchConstantFunc:
+        {
+            TString pcfName;
+            if (! it->getString(pcfName, 0, false)) {
+                error(loc, "invalid patch constant function", "", "");
             } else {
-                if (! intermediate.setOutputPrimitive(domain))
-                    error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+                patchConstantFunctionName = pcfName;
             }
+            break;
         }
-    }
-
-    // Handle [outputtopology("...")]
-    if (attributes.contains(EatOutputTopology)) {
-        TString topologyStr;
-        if (! attributes.getString(EatOutputTopology, topologyStr)) {
-            error(loc, "invalid outputtopology", "", "");
-        } else {
-            TVertexOrder vertexOrder = EvoNone;
-            TLayoutGeometry primitive = ElgNone;
-
-            if (topologyStr == "point") {
-                intermediate.setPointMode();
-            } else if (topologyStr == "line") {
-                primitive = ElgIsolines;
-            } else if (topologyStr == "triangle_cw") {
-                vertexOrder = EvoCw;
-                primitive = ElgTriangles;
-            } else if (topologyStr == "triangle_ccw") {
-                vertexOrder = EvoCcw;
-                primitive = ElgTriangles;
+        case EatDomain:
+        {
+            // Handle [domain("...")]
+            TString domainStr;
+            if (! it->getString(domainStr)) {
+                error(loc, "invalid domain", "", "");
             } else {
-                error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
-            }
+                TLayoutGeometry domain = ElgNone;
+
+                if (domainStr == "tri") {
+                    domain = ElgTriangles;
+                } else if (domainStr == "quad") {
+                    domain = ElgQuads;
+                } else if (domainStr == "isoline") {
+                    domain = ElgIsolines;
+                } else {
+                    error(loc, "unsupported domain type", domainStr.c_str(), "");
+                }
 
-            if (vertexOrder != EvoNone) {
-                if (! intermediate.setVertexOrder(vertexOrder)) {
-                    error(loc, "cannot change previously set outputtopology",
-                          TQualifier::getVertexOrderString(vertexOrder), "");
+                if (language == EShLangTessEvaluation) {
+                    if (! intermediate.setInputPrimitive(domain))
+                        error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
+                } else {
+                    if (! intermediate.setOutputPrimitive(domain))
+                        error(loc, "cannot change previously set domain", TQualifier::getGeometryString(domain), "");
                 }
             }
-            if (primitive != ElgNone)
-                intermediate.setOutputPrimitive(primitive);
+            break;
         }
-    }
-
-    // Handle [partitioning("...")]
-    if (attributes.contains(EatPartitioning)) {
-        TString partitionStr;
-        if (! attributes.getString(EatPartitioning, partitionStr)) {
-            error(loc, "invalid partitioning", "", "");
-        } else {
-            TVertexSpacing partitioning = EvsNone;
-                
-            if (partitionStr == "integer") {
-                partitioning = EvsEqual;
-            } else if (partitionStr == "fractional_even") {
-                partitioning = EvsFractionalEven;
-            } else if (partitionStr == "fractional_odd") {
-                partitioning = EvsFractionalOdd;
-                //} else if (partition == "pow2") { // TODO: currently nothing to map this to.
+        case EatOutputTopology:
+        {
+            // Handle [outputtopology("...")]
+            TString topologyStr;
+            if (! it->getString(topologyStr)) {
+                error(loc, "invalid outputtopology", "", "");
             } else {
-                error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
-            }
+                TVertexOrder vertexOrder = EvoNone;
+                TLayoutGeometry primitive = ElgNone;
+
+                if (topologyStr == "point") {
+                    intermediate.setPointMode();
+                } else if (topologyStr == "line") {
+                    primitive = ElgIsolines;
+                } else if (topologyStr == "triangle_cw") {
+                    vertexOrder = EvoCw;
+                    primitive = ElgTriangles;
+                } else if (topologyStr == "triangle_ccw") {
+                    vertexOrder = EvoCcw;
+                    primitive = ElgTriangles;
+                } else {
+                    error(loc, "unsupported outputtopology type", topologyStr.c_str(), "");
+                }
 
-            if (! intermediate.setVertexSpacing(partitioning))
-                error(loc, "cannot change previously set partitioning",
-                      TQualifier::getVertexSpacingString(partitioning), "");
+                if (vertexOrder != EvoNone) {
+                    if (! intermediate.setVertexOrder(vertexOrder)) {
+                        error(loc, "cannot change previously set outputtopology",
+                              TQualifier::getVertexOrderString(vertexOrder), "");
+                    }
+                }
+                if (primitive != ElgNone)
+                    intermediate.setOutputPrimitive(primitive);
+            }
+            break;
         }
-    }
+        case EatPartitioning:
+        {
+            // Handle [partitioning("...")]
+            TString partitionStr;
+            if (! it->getString(partitionStr)) {
+                error(loc, "invalid partitioning", "", "");
+            } else {
+                TVertexSpacing partitioning = EvsNone;
+                
+                if (partitionStr == "integer") {
+                    partitioning = EvsEqual;
+                } else if (partitionStr == "fractional_even") {
+                    partitioning = EvsFractionalEven;
+                } else if (partitionStr == "fractional_odd") {
+                    partitioning = EvsFractionalOdd;
+                    //} else if (partition == "pow2") { // TODO: currently nothing to map this to.
+                } else {
+                    error(loc, "unsupported partitioning type", partitionStr.c_str(), "");
+                }
 
-    // Handle [outputcontrolpoints("...")]
-    if (attributes.contains(EatOutputControlPoints)) {
-        int ctrlPoints;
-        if (! attributes.getInt(EatOutputControlPoints, ctrlPoints)) {
-            error(loc, "invalid outputcontrolpoints", "", "");
-        } else {
-            if (! intermediate.setVertices(ctrlPoints)) {
-                error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
+                if (! intermediate.setVertexSpacing(partitioning))
+                    error(loc, "cannot change previously set partitioning",
+                          TQualifier::getVertexSpacingString(partitioning), "");
+            }
+            break;
+        }
+        case EatOutputControlPoints:
+        {
+            // Handle [outputcontrolpoints("...")]
+            int ctrlPoints;
+            if (! it->getInt(ctrlPoints)) {
+                error(loc, "invalid outputcontrolpoints", "", "");
+            } else {
+                if (! intermediate.setVertices(ctrlPoints)) {
+                    error(loc, "cannot change previously set outputcontrolpoints attribute", "", "");
+                }
             }
+            break;
+        }
+        case EatBuiltIn:
+        case EatLocation:
+            // tolerate these because of dual use of entrypoint and type attributes
+            break;
+        default:
+            warn(loc, "attribute does not apply to entry point", "", "");
+            break;
         }
     }
 }
 
 // Update the given type with any type-like attribute information in the
 // attributes.
-void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, TType& type)
+void HlslParseContext::transferTypeAttributes(const TSourceLoc& loc, const TAttributes& attributes, TType& type,
+    bool allowEntry)
 {
     if (attributes.size() == 0)
         return;
 
-    // location
     int value;
-    if (attributes.getInt(EatLocation, value))
-        type.getQualifier().layoutLocation = value;
-
-    // binding
-    if (attributes.getInt(EatBinding, value)) {
-        type.getQualifier().layoutBinding = value;
-        type.getQualifier().layoutSet = 0;
-    }
-
-    // set
-    if (attributes.getInt(EatBinding, value, 1))
-        type.getQualifier().layoutSet = value;
-
-    // global cbuffer binding
-    if (attributes.getInt(EatGlobalBinding, value))
-        globalUniformBinding = value;
-
-    // global cbuffer binding
-    if (attributes.getInt(EatGlobalBinding, value, 1))
-        globalUniformSet = value;
-
-    // input attachment
-    if (attributes.getInt(EatInputAttachment, value))
-        type.getQualifier().layoutAttachment = value;
-
-    // PointSize built-in
     TString builtInString;
-    if (attributes.getString(EatBuiltIn, builtInString, 0, false)) {
-        if (builtInString == "PointSize")
-            type.getQualifier().builtIn = EbvPointSize;
-    }
-
-    // push_constant
-    if (attributes.contains(EatPushConstant))
-        type.getQualifier().layoutPushConstant = true;
-
-    // specialization constant
-    if (attributes.getInt(EatConstantId, value)) {
-        TSourceLoc loc;
-        loc.init();
-        setSpecConstantId(loc, type.getQualifier(), value);
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        switch (it->name) {
+        case EatLocation:
+            // location
+            if (it->getInt(value))
+                type.getQualifier().layoutLocation = value;
+            break;
+        case EatBinding:
+            // binding
+            if (it->getInt(value)) {
+                type.getQualifier().layoutBinding = value;
+                type.getQualifier().layoutSet = 0;
+            }
+            // set
+            if (it->getInt(value, 1))
+                type.getQualifier().layoutSet = value;
+            break;
+        case EatGlobalBinding:
+            // global cbuffer binding
+            if (it->getInt(value))
+                globalUniformBinding = value;
+            // global cbuffer binding
+            if (it->getInt(value, 1))
+                globalUniformSet = value;
+            break;
+        case EatInputAttachment:
+            // input attachment
+            if (it->getInt(value))
+                type.getQualifier().layoutAttachment = value;
+            break;
+        case EatBuiltIn:
+            // PointSize built-in
+            if (it->getString(builtInString, 0, false)) {
+                if (builtInString == "PointSize")
+                    type.getQualifier().builtIn = EbvPointSize;
+            }
+            break;
+        case EatPushConstant:
+            // push_constant
+            type.getQualifier().layoutPushConstant = true;
+            break;
+        case EatConstantId:
+            // specialization constant
+            if (it->getInt(value)) {
+                TSourceLoc loc;
+                loc.init();
+                setSpecConstantId(loc, type.getQualifier(), value);
+            }
+            break;
+        default:
+            if (! allowEntry)
+                warn(loc, "attribute does not apply to a type", "", "");
+            break;
+        }
     }
 }
 
@@ -1936,7 +1964,7 @@ void HlslParseContext::transferTypeAttributes(const TAttributeMap& attributes, T
 // a subtree that creates the entry point.
 //
 TIntermNode* HlslParseContext::transformEntryPoint(const TSourceLoc& loc, TFunction& userFunction,
-                                                   const TAttributeMap& attributes)
+                                                   const TAttributes& attributes)
 {
     // Return true if this is a tessellation patch constant function input to a domain shader.
     const auto isDsPcfInput = [this](const TType& type) {
@@ -8792,29 +8820,75 @@ bool HlslParseContext::handleOutputGeometry(const TSourceLoc& loc, const TLayout
 }
 
 //
-// Selection hints
+// Selection attributes
 //
-TSelectionControl HlslParseContext::handleSelectionControl(const TAttributeMap& attributes) const
+void HlslParseContext::handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection* selection,
+    const TAttributes& attributes)
 {
-    if (attributes.contains(EatFlatten))
-        return ESelectionControlFlatten;
-    else if (attributes.contains(EatBranch))
-        return ESelectionControlDontFlatten;
-    else
-        return ESelectionControlNone;
+    if (selection == nullptr)
+        return;
+
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        switch (it->name) {
+        case EatFlatten:
+            selection->setFlatten();
+            break;
+        case EatBranch:
+            selection->setDontFlatten();
+            break;
+        default:
+            warn(loc, "attribute does not apply to a selection", "", "");
+            break;
+        }
+    }
 }
 
 //
-// Loop hints
+// Switch attributes
 //
-TLoopControl HlslParseContext::handleLoopControl(const TAttributeMap& attributes) const
+void HlslParseContext::handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch* selection,
+    const TAttributes& attributes)
 {
-    if (attributes.contains(EatUnroll))
-        return ELoopControlUnroll;
-    else if (attributes.contains(EatLoop))
-        return ELoopControlDontUnroll;
-    else
-        return ELoopControlNone;
+    if (selection == nullptr)
+        return;
+
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        switch (it->name) {
+        case EatFlatten:
+            selection->setFlatten();
+            break;
+        case EatBranch:
+            selection->setDontFlatten();
+            break;
+        default:
+            warn(loc, "attribute does not apply to a switch", "", "");
+            break;
+        }
+    }
+}
+
+//
+// Loop attributes
+//
+void HlslParseContext::handleLoopAttributes(const TSourceLoc& loc, TIntermLoop* loop,
+    const TAttributes& attributes)
+{
+    if (loop == nullptr)
+        return;
+
+    for (auto it = attributes.begin(); it != attributes.end(); ++it) {
+        switch (it->name) {
+        case EatUnroll:
+            loop->setUnroll();
+            break;
+        case EatLoop:
+            loop->setDontUnroll();
+            break;
+        default:
+            warn(loc, "attribute does not apply to a loop", "", "");
+            break;
+        }
+    }
 }
 
 //
@@ -8959,7 +9033,7 @@ void HlslParseContext::wrapupSwitchSubsequence(TIntermAggregate* statements, TIn
 // into a switch node.
 //
 TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* expression,
-                                         TIntermAggregate* lastStatements, TSelectionControl control)
+                                         TIntermAggregate* lastStatements, const TAttributes& attributes)
 {
     wrapupSwitchSubsequence(lastStatements, nullptr);
 
@@ -8986,7 +9060,7 @@ TIntermNode* HlslParseContext::addSwitch(const TSourceLoc& loc, TIntermTyped* ex
 
     TIntermSwitch* switchNode = new TIntermSwitch(expression, body);
     switchNode->setLoc(loc);
-    switchNode->setSelectionControl(control);
+    handleSwitchAttributes(loc, switchNode, attributes);
 
     return switchNode;
 }

+ 11 - 8
3rdparty/glslang/hlsl/hlslParseHelper.h

@@ -38,12 +38,12 @@
 
 #include "../glslang/MachineIndependent/parseVersions.h"
 #include "../glslang/MachineIndependent/ParseHelper.h"
+#include "../glslang/MachineIndependent/attribute.h"
 
 #include <array>
 
 namespace glslang {
 
-class TAttributeMap; // forward declare
 class TFunctionDeclarator;
 
 class HlslParseContext : public TParseContextBase {
@@ -80,10 +80,10 @@ public:
     bool isBuiltInMethod(const TSourceLoc&, TIntermTyped* base, const TString& field);
     void assignToInterface(TVariable& variable);
     void handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
-    TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributeMap&, TIntermNode*& entryPointTree);
-    TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributeMap&);
-    void handleEntryPointAttributes(const TSourceLoc&, const TAttributeMap&);
-    void transferTypeAttributes(const TAttributeMap&, TType&);
+    TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&, const TAttributes&, TIntermNode*& entryPointTree);
+    TIntermNode* transformEntryPoint(const TSourceLoc&, TFunction&, const TAttributes&);
+    void handleEntryPointAttributes(const TSourceLoc&, const TAttributes&);
+    void transferTypeAttributes(const TSourceLoc&, const TAttributes&, TType&, bool allowEntry = false);
     void handleFunctionBody(const TSourceLoc&, TFunction&, TIntermNode* functionBody, TIntermNode*& node);
     void remapEntryPointIO(TFunction& function, TVariable*& returnValue, TVector<TVariable*>& inputs, TVector<TVariable*>& outputs);
     void remapNonEntryPointIO(TFunction& function);
@@ -163,7 +163,7 @@ public:
     void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&);
     void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&);
     void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode);
-    TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, TSelectionControl control);
+    TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body, const TAttributes&);
 
     void updateImplicitArraySize(const TSourceLoc&, TIntermNode*, int index);
 
@@ -203,10 +203,11 @@ public:
     bool handleInputGeometry(const TSourceLoc&, const TLayoutGeometry& geometry);
 
     // Determine selection control from attributes
-    TSelectionControl handleSelectionControl(const TAttributeMap& attributes) const;
+    void handleSelectionAttributes(const TSourceLoc& loc, TIntermSelection*, const TAttributes& attributes);
+    void handleSwitchAttributes(const TSourceLoc& loc, TIntermSwitch*, const TAttributes& attributes);
 
     // Determine loop control from attributes
-    TLoopControl handleLoopControl(const TAttributeMap& attributes) const;
+    void handleLoopAttributes(const TSourceLoc& loc, TIntermLoop*, const TAttributes& attributes);
 
     // Share struct buffer deep types
     void shareStructBufferType(TType&);
@@ -217,6 +218,8 @@ public:
     // Obtain the sampler return type of the given sampler in retType.
     void getTextureReturnType(const TSampler& sampler, TType& retType) const;
 
+    TAttributeType attributeFromName(const TString& nameSpace, const TString& name) const;
+
 protected:
     struct TFlattenData {
         TFlattenData() : nextBinding(TQualifier::layoutBindingEnd),

Некоторые файлы не были показаны из-за большого количества измененных файлов