Browse Source

update spirv-cross

Alex Szpakowski 4 years ago
parent
commit
cc140ed1ad

+ 98 - 10
src/libraries/spirv_cross/spirv.h

@@ -54,11 +54,11 @@
 typedef unsigned int SpvId;
 typedef unsigned int SpvId;
 
 
 #define SPV_VERSION 0x10500
 #define SPV_VERSION 0x10500
-#define SPV_REVISION 3
+#define SPV_REVISION 4
 
 
 static const unsigned int SpvMagicNumber = 0x07230203;
 static const unsigned int SpvMagicNumber = 0x07230203;
 static const unsigned int SpvVersion = 0x00010500;
 static const unsigned int SpvVersion = 0x00010500;
-static const unsigned int SpvRevision = 3;
+static const unsigned int SpvRevision = 4;
 static const unsigned int SpvOpCodeMask = 0xffff;
 static const unsigned int SpvOpCodeMask = 0xffff;
 static const unsigned int SpvWordCountShift = 16;
 static const unsigned int SpvWordCountShift = 16;
 
 
@@ -172,6 +172,10 @@ typedef enum SpvExecutionMode_ {
     SpvExecutionModeSampleInterlockUnorderedEXT = 5369,
     SpvExecutionModeSampleInterlockUnorderedEXT = 5369,
     SpvExecutionModeShadingRateInterlockOrderedEXT = 5370,
     SpvExecutionModeShadingRateInterlockOrderedEXT = 5370,
     SpvExecutionModeShadingRateInterlockUnorderedEXT = 5371,
     SpvExecutionModeShadingRateInterlockUnorderedEXT = 5371,
+    SpvExecutionModeMaxWorkgroupSizeINTEL = 5893,
+    SpvExecutionModeMaxWorkDimINTEL = 5894,
+    SpvExecutionModeNoGlobalOffsetINTEL = 5895,
+    SpvExecutionModeNumSIMDWorkitemsINTEL = 5896,
     SpvExecutionModeMax = 0x7fffffff,
     SpvExecutionModeMax = 0x7fffffff,
 } SpvExecutionMode;
 } SpvExecutionMode;
 
 
@@ -203,6 +207,7 @@ typedef enum SpvStorageClass_ {
     SpvStorageClassShaderRecordBufferNV = 5343,
     SpvStorageClassShaderRecordBufferNV = 5343,
     SpvStorageClassPhysicalStorageBuffer = 5349,
     SpvStorageClassPhysicalStorageBuffer = 5349,
     SpvStorageClassPhysicalStorageBufferEXT = 5349,
     SpvStorageClassPhysicalStorageBufferEXT = 5349,
+    SpvStorageClassCodeSectionINTEL = 5605,
     SpvStorageClassMax = 0x7fffffff,
     SpvStorageClassMax = 0x7fffffff,
 } SpvStorageClass;
 } SpvStorageClass;
 
 
@@ -273,6 +278,8 @@ typedef enum SpvImageFormat_ {
     SpvImageFormatRg8ui = 37,
     SpvImageFormatRg8ui = 37,
     SpvImageFormatR16ui = 38,
     SpvImageFormatR16ui = 38,
     SpvImageFormatR8ui = 39,
     SpvImageFormatR8ui = 39,
+    SpvImageFormatR64ui = 40,
+    SpvImageFormatR64i = 41,
     SpvImageFormatMax = 0x7fffffff,
     SpvImageFormatMax = 0x7fffffff,
 } SpvImageFormat;
 } SpvImageFormat;
 
 
@@ -481,11 +488,24 @@ typedef enum SpvDecoration_ {
     SpvDecorationRestrictPointerEXT = 5355,
     SpvDecorationRestrictPointerEXT = 5355,
     SpvDecorationAliasedPointer = 5356,
     SpvDecorationAliasedPointer = 5356,
     SpvDecorationAliasedPointerEXT = 5356,
     SpvDecorationAliasedPointerEXT = 5356,
+    SpvDecorationReferencedIndirectlyINTEL = 5602,
     SpvDecorationCounterBuffer = 5634,
     SpvDecorationCounterBuffer = 5634,
     SpvDecorationHlslCounterBufferGOOGLE = 5634,
     SpvDecorationHlslCounterBufferGOOGLE = 5634,
     SpvDecorationHlslSemanticGOOGLE = 5635,
     SpvDecorationHlslSemanticGOOGLE = 5635,
     SpvDecorationUserSemantic = 5635,
     SpvDecorationUserSemantic = 5635,
     SpvDecorationUserTypeGOOGLE = 5636,
     SpvDecorationUserTypeGOOGLE = 5636,
+    SpvDecorationRegisterINTEL = 5825,
+    SpvDecorationMemoryINTEL = 5826,
+    SpvDecorationNumbanksINTEL = 5827,
+    SpvDecorationBankwidthINTEL = 5828,
+    SpvDecorationMaxPrivateCopiesINTEL = 5829,
+    SpvDecorationSinglepumpINTEL = 5830,
+    SpvDecorationDoublepumpINTEL = 5831,
+    SpvDecorationMaxReplicatesINTEL = 5832,
+    SpvDecorationSimpleDualPortINTEL = 5833,
+    SpvDecorationMergeINTEL = 5834,
+    SpvDecorationBankBitsINTEL = 5835,
+    SpvDecorationForcePow2DepthINTEL = 5836,
     SpvDecorationMax = 0x7fffffff,
     SpvDecorationMax = 0x7fffffff,
 } SpvDecoration;
 } SpvDecoration;
 
 
@@ -544,8 +564,10 @@ typedef enum SpvBuiltIn_ {
     SpvBuiltInBaseVertex = 4424,
     SpvBuiltInBaseVertex = 4424,
     SpvBuiltInBaseInstance = 4425,
     SpvBuiltInBaseInstance = 4425,
     SpvBuiltInDrawIndex = 4426,
     SpvBuiltInDrawIndex = 4426,
+    SpvBuiltInPrimitiveShadingRateKHR = 4432,
     SpvBuiltInDeviceIndex = 4438,
     SpvBuiltInDeviceIndex = 4438,
     SpvBuiltInViewIndex = 4440,
     SpvBuiltInViewIndex = 4440,
+    SpvBuiltInShadingRateKHR = 4444,
     SpvBuiltInBaryCoordNoPerspAMD = 4992,
     SpvBuiltInBaryCoordNoPerspAMD = 4992,
     SpvBuiltInBaryCoordNoPerspCentroidAMD = 4993,
     SpvBuiltInBaryCoordNoPerspCentroidAMD = 4993,
     SpvBuiltInBaryCoordNoPerspSampleAMD = 4994,
     SpvBuiltInBaryCoordNoPerspSampleAMD = 4994,
@@ -596,7 +618,6 @@ typedef enum SpvBuiltIn_ {
     SpvBuiltInObjectToWorldNV = 5330,
     SpvBuiltInObjectToWorldNV = 5330,
     SpvBuiltInWorldToObjectKHR = 5331,
     SpvBuiltInWorldToObjectKHR = 5331,
     SpvBuiltInWorldToObjectNV = 5331,
     SpvBuiltInWorldToObjectNV = 5331,
-    SpvBuiltInHitTKHR = 5332,
     SpvBuiltInHitTNV = 5332,
     SpvBuiltInHitTNV = 5332,
     SpvBuiltInHitKindKHR = 5333,
     SpvBuiltInHitKindKHR = 5333,
     SpvBuiltInHitKindNV = 5333,
     SpvBuiltInHitKindNV = 5333,
@@ -632,6 +653,13 @@ typedef enum SpvLoopControlShift_ {
     SpvLoopControlIterationMultipleShift = 6,
     SpvLoopControlIterationMultipleShift = 6,
     SpvLoopControlPeelCountShift = 7,
     SpvLoopControlPeelCountShift = 7,
     SpvLoopControlPartialCountShift = 8,
     SpvLoopControlPartialCountShift = 8,
+    SpvLoopControlInitiationIntervalINTELShift = 16,
+    SpvLoopControlMaxConcurrencyINTELShift = 17,
+    SpvLoopControlDependencyArrayINTELShift = 18,
+    SpvLoopControlPipelineEnableINTELShift = 19,
+    SpvLoopControlLoopCoalesceINTELShift = 20,
+    SpvLoopControlMaxInterleavingINTELShift = 21,
+    SpvLoopControlSpeculatedIterationsINTELShift = 22,
     SpvLoopControlMax = 0x7fffffff,
     SpvLoopControlMax = 0x7fffffff,
 } SpvLoopControlShift;
 } SpvLoopControlShift;
 
 
@@ -646,6 +674,13 @@ typedef enum SpvLoopControlMask_ {
     SpvLoopControlIterationMultipleMask = 0x00000040,
     SpvLoopControlIterationMultipleMask = 0x00000040,
     SpvLoopControlPeelCountMask = 0x00000080,
     SpvLoopControlPeelCountMask = 0x00000080,
     SpvLoopControlPartialCountMask = 0x00000100,
     SpvLoopControlPartialCountMask = 0x00000100,
+    SpvLoopControlInitiationIntervalINTELMask = 0x00010000,
+    SpvLoopControlMaxConcurrencyINTELMask = 0x00020000,
+    SpvLoopControlDependencyArrayINTELMask = 0x00040000,
+    SpvLoopControlPipelineEnableINTELMask = 0x00080000,
+    SpvLoopControlLoopCoalesceINTELMask = 0x00100000,
+    SpvLoopControlMaxInterleavingINTELMask = 0x00200000,
+    SpvLoopControlSpeculatedIterationsINTELMask = 0x00400000,
 } SpvLoopControlMask;
 } SpvLoopControlMask;
 
 
 typedef enum SpvFunctionControlShift_ {
 typedef enum SpvFunctionControlShift_ {
@@ -842,6 +877,7 @@ typedef enum SpvCapability_ {
     SpvCapabilityGroupNonUniformQuad = 68,
     SpvCapabilityGroupNonUniformQuad = 68,
     SpvCapabilityShaderLayer = 69,
     SpvCapabilityShaderLayer = 69,
     SpvCapabilityShaderViewportIndex = 70,
     SpvCapabilityShaderViewportIndex = 70,
+    SpvCapabilityFragmentShadingRateKHR = 4422,
     SpvCapabilitySubgroupBallotKHR = 4423,
     SpvCapabilitySubgroupBallotKHR = 4423,
     SpvCapabilityDrawParameters = 4427,
     SpvCapabilityDrawParameters = 4427,
     SpvCapabilitySubgroupVoteKHR = 4431,
     SpvCapabilitySubgroupVoteKHR = 4431,
@@ -866,12 +902,15 @@ typedef enum SpvCapability_ {
     SpvCapabilityRoundingModeRTE = 4467,
     SpvCapabilityRoundingModeRTE = 4467,
     SpvCapabilityRoundingModeRTZ = 4468,
     SpvCapabilityRoundingModeRTZ = 4468,
     SpvCapabilityRayQueryProvisionalKHR = 4471,
     SpvCapabilityRayQueryProvisionalKHR = 4471,
-    SpvCapabilityRayTraversalPrimitiveCullingProvisionalKHR = 4478,
+    SpvCapabilityRayQueryKHR = 4472,
+    SpvCapabilityRayTraversalPrimitiveCullingKHR = 4478,
+    SpvCapabilityRayTracingKHR = 4479,
     SpvCapabilityFloat16ImageAMD = 5008,
     SpvCapabilityFloat16ImageAMD = 5008,
     SpvCapabilityImageGatherBiasLodAMD = 5009,
     SpvCapabilityImageGatherBiasLodAMD = 5009,
     SpvCapabilityFragmentMaskAMD = 5010,
     SpvCapabilityFragmentMaskAMD = 5010,
     SpvCapabilityStencilExportEXT = 5013,
     SpvCapabilityStencilExportEXT = 5013,
     SpvCapabilityImageReadWriteLodAMD = 5015,
     SpvCapabilityImageReadWriteLodAMD = 5015,
+    SpvCapabilityInt64ImageEXT = 5016,
     SpvCapabilityShaderClockKHR = 5055,
     SpvCapabilityShaderClockKHR = 5055,
     SpvCapabilitySampleMaskOverrideCoverageNV = 5249,
     SpvCapabilitySampleMaskOverrideCoverageNV = 5249,
     SpvCapabilityGeometryShaderPassthroughNV = 5251,
     SpvCapabilityGeometryShaderPassthroughNV = 5251,
@@ -932,9 +971,20 @@ typedef enum SpvCapability_ {
     SpvCapabilitySubgroupImageBlockIOINTEL = 5570,
     SpvCapabilitySubgroupImageBlockIOINTEL = 5570,
     SpvCapabilitySubgroupImageMediaBlockIOINTEL = 5579,
     SpvCapabilitySubgroupImageMediaBlockIOINTEL = 5579,
     SpvCapabilityIntegerFunctions2INTEL = 5584,
     SpvCapabilityIntegerFunctions2INTEL = 5584,
+    SpvCapabilityFunctionPointersINTEL = 5603,
+    SpvCapabilityIndirectReferencesINTEL = 5604,
     SpvCapabilitySubgroupAvcMotionEstimationINTEL = 5696,
     SpvCapabilitySubgroupAvcMotionEstimationINTEL = 5696,
     SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697,
     SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697,
     SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698,
     SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698,
+    SpvCapabilityFPGAMemoryAttributesINTEL = 5824,
+    SpvCapabilityUnstructuredLoopControlsINTEL = 5886,
+    SpvCapabilityFPGALoopControlsINTEL = 5888,
+    SpvCapabilityKernelAttributesINTEL = 5892,
+    SpvCapabilityFPGAKernelAttributesINTEL = 5897,
+    SpvCapabilityBlockingPipesINTEL = 5945,
+    SpvCapabilityFPGARegINTEL = 5948,
+    SpvCapabilityAtomicFloat32AddEXT = 6033,
+    SpvCapabilityAtomicFloat64AddEXT = 6034,
     SpvCapabilityMax = 0x7fffffff,
     SpvCapabilityMax = 0x7fffffff,
 } SpvCapability;
 } SpvCapability;
 
 
@@ -985,6 +1035,22 @@ typedef enum SpvRayQueryCandidateIntersectionType_ {
     SpvRayQueryCandidateIntersectionTypeMax = 0x7fffffff,
     SpvRayQueryCandidateIntersectionTypeMax = 0x7fffffff,
 } SpvRayQueryCandidateIntersectionType;
 } SpvRayQueryCandidateIntersectionType;
 
 
+typedef enum SpvFragmentShadingRateShift_ {
+    SpvFragmentShadingRateVertical2PixelsShift = 0,
+    SpvFragmentShadingRateVertical4PixelsShift = 1,
+    SpvFragmentShadingRateHorizontal2PixelsShift = 2,
+    SpvFragmentShadingRateHorizontal4PixelsShift = 3,
+    SpvFragmentShadingRateMax = 0x7fffffff,
+} SpvFragmentShadingRateShift;
+
+typedef enum SpvFragmentShadingRateMask_ {
+    SpvFragmentShadingRateMaskNone = 0,
+    SpvFragmentShadingRateVertical2PixelsMask = 0x00000001,
+    SpvFragmentShadingRateVertical4PixelsMask = 0x00000002,
+    SpvFragmentShadingRateHorizontal2PixelsMask = 0x00000004,
+    SpvFragmentShadingRateHorizontal4PixelsMask = 0x00000008,
+} SpvFragmentShadingRateMask;
+
 typedef enum SpvOp_ {
 typedef enum SpvOp_ {
     SpvOpNop = 0,
     SpvOpNop = 0,
     SpvOpUndef = 1,
     SpvOpUndef = 1,
@@ -1330,13 +1396,19 @@ typedef enum SpvOp_ {
     SpvOpPtrEqual = 401,
     SpvOpPtrEqual = 401,
     SpvOpPtrNotEqual = 402,
     SpvOpPtrNotEqual = 402,
     SpvOpPtrDiff = 403,
     SpvOpPtrDiff = 403,
+    SpvOpTerminateInvocation = 4416,
     SpvOpSubgroupBallotKHR = 4421,
     SpvOpSubgroupBallotKHR = 4421,
     SpvOpSubgroupFirstInvocationKHR = 4422,
     SpvOpSubgroupFirstInvocationKHR = 4422,
     SpvOpSubgroupAllKHR = 4428,
     SpvOpSubgroupAllKHR = 4428,
     SpvOpSubgroupAnyKHR = 4429,
     SpvOpSubgroupAnyKHR = 4429,
     SpvOpSubgroupAllEqualKHR = 4430,
     SpvOpSubgroupAllEqualKHR = 4430,
     SpvOpSubgroupReadInvocationKHR = 4432,
     SpvOpSubgroupReadInvocationKHR = 4432,
-    SpvOpTypeRayQueryProvisionalKHR = 4472,
+    SpvOpTraceRayKHR = 4445,
+    SpvOpExecuteCallableKHR = 4446,
+    SpvOpConvertUToAccelerationStructureKHR = 4447,
+    SpvOpIgnoreIntersectionKHR = 4448,
+    SpvOpTerminateRayKHR = 4449,
+    SpvOpTypeRayQueryKHR = 4472,
     SpvOpRayQueryInitializeKHR = 4473,
     SpvOpRayQueryInitializeKHR = 4473,
     SpvOpRayQueryTerminateKHR = 4474,
     SpvOpRayQueryTerminateKHR = 4474,
     SpvOpRayQueryGenerateIntersectionKHR = 4475,
     SpvOpRayQueryGenerateIntersectionKHR = 4475,
@@ -1359,15 +1431,11 @@ typedef enum SpvOp_ {
     SpvOpWritePackedPrimitiveIndices4x8NV = 5299,
     SpvOpWritePackedPrimitiveIndices4x8NV = 5299,
     SpvOpReportIntersectionKHR = 5334,
     SpvOpReportIntersectionKHR = 5334,
     SpvOpReportIntersectionNV = 5334,
     SpvOpReportIntersectionNV = 5334,
-    SpvOpIgnoreIntersectionKHR = 5335,
     SpvOpIgnoreIntersectionNV = 5335,
     SpvOpIgnoreIntersectionNV = 5335,
-    SpvOpTerminateRayKHR = 5336,
     SpvOpTerminateRayNV = 5336,
     SpvOpTerminateRayNV = 5336,
     SpvOpTraceNV = 5337,
     SpvOpTraceNV = 5337,
-    SpvOpTraceRayKHR = 5337,
     SpvOpTypeAccelerationStructureKHR = 5341,
     SpvOpTypeAccelerationStructureKHR = 5341,
     SpvOpTypeAccelerationStructureNV = 5341,
     SpvOpTypeAccelerationStructureNV = 5341,
-    SpvOpExecuteCallableKHR = 5344,
     SpvOpExecuteCallableNV = 5344,
     SpvOpExecuteCallableNV = 5344,
     SpvOpTypeCooperativeMatrixNV = 5358,
     SpvOpTypeCooperativeMatrixNV = 5358,
     SpvOpCooperativeMatrixLoadNV = 5359,
     SpvOpCooperativeMatrixLoadNV = 5359,
@@ -1402,6 +1470,8 @@ typedef enum SpvOp_ {
     SpvOpUSubSatINTEL = 5596,
     SpvOpUSubSatINTEL = 5596,
     SpvOpIMul32x16INTEL = 5597,
     SpvOpIMul32x16INTEL = 5597,
     SpvOpUMul32x16INTEL = 5598,
     SpvOpUMul32x16INTEL = 5598,
+    SpvOpFunctionPointerINTEL = 5600,
+    SpvOpFunctionPointerCallINTEL = 5601,
     SpvOpDecorateString = 5632,
     SpvOpDecorateString = 5632,
     SpvOpDecorateStringGOOGLE = 5632,
     SpvOpDecorateStringGOOGLE = 5632,
     SpvOpMemberDecorateString = 5633,
     SpvOpMemberDecorateString = 5633,
@@ -1524,6 +1594,10 @@ typedef enum SpvOp_ {
     SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
     SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
     SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
     SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
     SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
     SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
+    SpvOpLoopControlINTEL = 5887,
+    SpvOpReadPipeBlockingINTEL = 5946,
+    SpvOpWritePipeBlockingINTEL = 5947,
+    SpvOpFPGARegINTEL = 5949,
     SpvOpRayQueryGetRayTMinKHR = 6016,
     SpvOpRayQueryGetRayTMinKHR = 6016,
     SpvOpRayQueryGetRayFlagsKHR = 6017,
     SpvOpRayQueryGetRayFlagsKHR = 6017,
     SpvOpRayQueryGetIntersectionTKHR = 6018,
     SpvOpRayQueryGetIntersectionTKHR = 6018,
@@ -1541,6 +1615,7 @@ typedef enum SpvOp_ {
     SpvOpRayQueryGetWorldRayOriginKHR = 6030,
     SpvOpRayQueryGetWorldRayOriginKHR = 6030,
     SpvOpRayQueryGetIntersectionObjectToWorldKHR = 6031,
     SpvOpRayQueryGetIntersectionObjectToWorldKHR = 6031,
     SpvOpRayQueryGetIntersectionWorldToObjectKHR = 6032,
     SpvOpRayQueryGetIntersectionWorldToObjectKHR = 6032,
+    SpvOpAtomicFAddEXT = 6035,
     SpvOpMax = 0x7fffffff,
     SpvOpMax = 0x7fffffff,
 } SpvOp;
 } SpvOp;
 
 
@@ -1893,13 +1968,19 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
     case SpvOpPtrEqual: *hasResult = true; *hasResultType = true; break;
     case SpvOpPtrEqual: *hasResult = true; *hasResultType = true; break;
     case SpvOpPtrNotEqual: *hasResult = true; *hasResultType = true; break;
     case SpvOpPtrNotEqual: *hasResult = true; *hasResultType = true; break;
     case SpvOpPtrDiff: *hasResult = true; *hasResultType = true; break;
     case SpvOpPtrDiff: *hasResult = true; *hasResultType = true; break;
+    case SpvOpTerminateInvocation: *hasResult = false; *hasResultType = false; break;
     case SpvOpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
-    case SpvOpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break;
+    case SpvOpTraceRayKHR: *hasResult = false; *hasResultType = false; break;
+    case SpvOpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break;
+    case SpvOpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break;
+    case SpvOpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break;
+    case SpvOpTerminateRayKHR: *hasResult = false; *hasResultType = false; break;
+    case SpvOpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break;
     case SpvOpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
     case SpvOpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
     case SpvOpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
     case SpvOpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
     case SpvOpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
     case SpvOpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
@@ -1959,6 +2040,8 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
     case SpvOpUSubSatINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpUSubSatINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
+    case SpvOpFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break;
+    case SpvOpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpDecorateString: *hasResult = false; *hasResultType = false; break;
     case SpvOpDecorateString: *hasResult = false; *hasResultType = false; break;
     case SpvOpMemberDecorateString: *hasResult = false; *hasResultType = false; break;
     case SpvOpMemberDecorateString: *hasResult = false; *hasResultType = false; break;
     case SpvOpVmeImageINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpVmeImageINTEL: *hasResult = true; *hasResultType = true; break;
@@ -2079,6 +2162,10 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
     case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
+    case SpvOpLoopControlINTEL: *hasResult = false; *hasResultType = false; break;
+    case SpvOpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break;
+    case SpvOpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break;
+    case SpvOpFPGARegINTEL: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
@@ -2096,6 +2183,7 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
     case SpvOpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
     case SpvOpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
+    case SpvOpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break;
     }
     }
 }
 }
 #endif /* SPV_ENABLE_UTILITY_CODE */
 #endif /* SPV_ENABLE_UTILITY_CODE */

+ 99 - 10
src/libraries/spirv_cross/spirv.hpp

@@ -50,11 +50,11 @@ namespace spv {
 typedef unsigned int Id;
 typedef unsigned int Id;
 
 
 #define SPV_VERSION 0x10500
 #define SPV_VERSION 0x10500
-#define SPV_REVISION 3
+#define SPV_REVISION 4
 
 
 static const unsigned int MagicNumber = 0x07230203;
 static const unsigned int MagicNumber = 0x07230203;
 static const unsigned int Version = 0x00010500;
 static const unsigned int Version = 0x00010500;
-static const unsigned int Revision = 3;
+static const unsigned int Revision = 4;
 static const unsigned int OpCodeMask = 0xffff;
 static const unsigned int OpCodeMask = 0xffff;
 static const unsigned int WordCountShift = 16;
 static const unsigned int WordCountShift = 16;
 
 
@@ -168,6 +168,10 @@ enum ExecutionMode {
     ExecutionModeSampleInterlockUnorderedEXT = 5369,
     ExecutionModeSampleInterlockUnorderedEXT = 5369,
     ExecutionModeShadingRateInterlockOrderedEXT = 5370,
     ExecutionModeShadingRateInterlockOrderedEXT = 5370,
     ExecutionModeShadingRateInterlockUnorderedEXT = 5371,
     ExecutionModeShadingRateInterlockUnorderedEXT = 5371,
+    ExecutionModeMaxWorkgroupSizeINTEL = 5893,
+    ExecutionModeMaxWorkDimINTEL = 5894,
+    ExecutionModeNoGlobalOffsetINTEL = 5895,
+    ExecutionModeNumSIMDWorkitemsINTEL = 5896,
     ExecutionModeMax = 0x7fffffff,
     ExecutionModeMax = 0x7fffffff,
 };
 };
 
 
@@ -199,6 +203,7 @@ enum StorageClass {
     StorageClassShaderRecordBufferNV = 5343,
     StorageClassShaderRecordBufferNV = 5343,
     StorageClassPhysicalStorageBuffer = 5349,
     StorageClassPhysicalStorageBuffer = 5349,
     StorageClassPhysicalStorageBufferEXT = 5349,
     StorageClassPhysicalStorageBufferEXT = 5349,
+    StorageClassCodeSectionINTEL = 5605,
     StorageClassMax = 0x7fffffff,
     StorageClassMax = 0x7fffffff,
 };
 };
 
 
@@ -269,6 +274,8 @@ enum ImageFormat {
     ImageFormatRg8ui = 37,
     ImageFormatRg8ui = 37,
     ImageFormatR16ui = 38,
     ImageFormatR16ui = 38,
     ImageFormatR8ui = 39,
     ImageFormatR8ui = 39,
+    ImageFormatR64ui = 40,
+    ImageFormatR64i = 41,
     ImageFormatMax = 0x7fffffff,
     ImageFormatMax = 0x7fffffff,
 };
 };
 
 
@@ -477,11 +484,24 @@ enum Decoration {
     DecorationRestrictPointerEXT = 5355,
     DecorationRestrictPointerEXT = 5355,
     DecorationAliasedPointer = 5356,
     DecorationAliasedPointer = 5356,
     DecorationAliasedPointerEXT = 5356,
     DecorationAliasedPointerEXT = 5356,
+    DecorationReferencedIndirectlyINTEL = 5602,
     DecorationCounterBuffer = 5634,
     DecorationCounterBuffer = 5634,
     DecorationHlslCounterBufferGOOGLE = 5634,
     DecorationHlslCounterBufferGOOGLE = 5634,
     DecorationHlslSemanticGOOGLE = 5635,
     DecorationHlslSemanticGOOGLE = 5635,
     DecorationUserSemantic = 5635,
     DecorationUserSemantic = 5635,
     DecorationUserTypeGOOGLE = 5636,
     DecorationUserTypeGOOGLE = 5636,
+    DecorationRegisterINTEL = 5825,
+    DecorationMemoryINTEL = 5826,
+    DecorationNumbanksINTEL = 5827,
+    DecorationBankwidthINTEL = 5828,
+    DecorationMaxPrivateCopiesINTEL = 5829,
+    DecorationSinglepumpINTEL = 5830,
+    DecorationDoublepumpINTEL = 5831,
+    DecorationMaxReplicatesINTEL = 5832,
+    DecorationSimpleDualPortINTEL = 5833,
+    DecorationMergeINTEL = 5834,
+    DecorationBankBitsINTEL = 5835,
+    DecorationForcePow2DepthINTEL = 5836,
     DecorationMax = 0x7fffffff,
     DecorationMax = 0x7fffffff,
 };
 };
 
 
@@ -540,8 +560,10 @@ enum BuiltIn {
     BuiltInBaseVertex = 4424,
     BuiltInBaseVertex = 4424,
     BuiltInBaseInstance = 4425,
     BuiltInBaseInstance = 4425,
     BuiltInDrawIndex = 4426,
     BuiltInDrawIndex = 4426,
+    BuiltInPrimitiveShadingRateKHR = 4432,
     BuiltInDeviceIndex = 4438,
     BuiltInDeviceIndex = 4438,
     BuiltInViewIndex = 4440,
     BuiltInViewIndex = 4440,
+    BuiltInShadingRateKHR = 4444,
     BuiltInBaryCoordNoPerspAMD = 4992,
     BuiltInBaryCoordNoPerspAMD = 4992,
     BuiltInBaryCoordNoPerspCentroidAMD = 4993,
     BuiltInBaryCoordNoPerspCentroidAMD = 4993,
     BuiltInBaryCoordNoPerspSampleAMD = 4994,
     BuiltInBaryCoordNoPerspSampleAMD = 4994,
@@ -592,7 +614,6 @@ enum BuiltIn {
     BuiltInObjectToWorldNV = 5330,
     BuiltInObjectToWorldNV = 5330,
     BuiltInWorldToObjectKHR = 5331,
     BuiltInWorldToObjectKHR = 5331,
     BuiltInWorldToObjectNV = 5331,
     BuiltInWorldToObjectNV = 5331,
-    BuiltInHitTKHR = 5332,
     BuiltInHitTNV = 5332,
     BuiltInHitTNV = 5332,
     BuiltInHitKindKHR = 5333,
     BuiltInHitKindKHR = 5333,
     BuiltInHitKindNV = 5333,
     BuiltInHitKindNV = 5333,
@@ -628,6 +649,13 @@ enum LoopControlShift {
     LoopControlIterationMultipleShift = 6,
     LoopControlIterationMultipleShift = 6,
     LoopControlPeelCountShift = 7,
     LoopControlPeelCountShift = 7,
     LoopControlPartialCountShift = 8,
     LoopControlPartialCountShift = 8,
+    LoopControlInitiationIntervalINTELShift = 16,
+    LoopControlMaxConcurrencyINTELShift = 17,
+    LoopControlDependencyArrayINTELShift = 18,
+    LoopControlPipelineEnableINTELShift = 19,
+    LoopControlLoopCoalesceINTELShift = 20,
+    LoopControlMaxInterleavingINTELShift = 21,
+    LoopControlSpeculatedIterationsINTELShift = 22,
     LoopControlMax = 0x7fffffff,
     LoopControlMax = 0x7fffffff,
 };
 };
 
 
@@ -642,6 +670,13 @@ enum LoopControlMask {
     LoopControlIterationMultipleMask = 0x00000040,
     LoopControlIterationMultipleMask = 0x00000040,
     LoopControlPeelCountMask = 0x00000080,
     LoopControlPeelCountMask = 0x00000080,
     LoopControlPartialCountMask = 0x00000100,
     LoopControlPartialCountMask = 0x00000100,
+    LoopControlInitiationIntervalINTELMask = 0x00010000,
+    LoopControlMaxConcurrencyINTELMask = 0x00020000,
+    LoopControlDependencyArrayINTELMask = 0x00040000,
+    LoopControlPipelineEnableINTELMask = 0x00080000,
+    LoopControlLoopCoalesceINTELMask = 0x00100000,
+    LoopControlMaxInterleavingINTELMask = 0x00200000,
+    LoopControlSpeculatedIterationsINTELMask = 0x00400000,
 };
 };
 
 
 enum FunctionControlShift {
 enum FunctionControlShift {
@@ -838,6 +873,7 @@ enum Capability {
     CapabilityGroupNonUniformQuad = 68,
     CapabilityGroupNonUniformQuad = 68,
     CapabilityShaderLayer = 69,
     CapabilityShaderLayer = 69,
     CapabilityShaderViewportIndex = 70,
     CapabilityShaderViewportIndex = 70,
+    CapabilityFragmentShadingRateKHR = 4422,
     CapabilitySubgroupBallotKHR = 4423,
     CapabilitySubgroupBallotKHR = 4423,
     CapabilityDrawParameters = 4427,
     CapabilityDrawParameters = 4427,
     CapabilitySubgroupVoteKHR = 4431,
     CapabilitySubgroupVoteKHR = 4431,
@@ -862,12 +898,15 @@ enum Capability {
     CapabilityRoundingModeRTE = 4467,
     CapabilityRoundingModeRTE = 4467,
     CapabilityRoundingModeRTZ = 4468,
     CapabilityRoundingModeRTZ = 4468,
     CapabilityRayQueryProvisionalKHR = 4471,
     CapabilityRayQueryProvisionalKHR = 4471,
-    CapabilityRayTraversalPrimitiveCullingProvisionalKHR = 4478,
+    CapabilityRayQueryKHR = 4472,
+    CapabilityRayTraversalPrimitiveCullingKHR = 4478,
+    CapabilityRayTracingKHR = 4479,
     CapabilityFloat16ImageAMD = 5008,
     CapabilityFloat16ImageAMD = 5008,
     CapabilityImageGatherBiasLodAMD = 5009,
     CapabilityImageGatherBiasLodAMD = 5009,
     CapabilityFragmentMaskAMD = 5010,
     CapabilityFragmentMaskAMD = 5010,
     CapabilityStencilExportEXT = 5013,
     CapabilityStencilExportEXT = 5013,
     CapabilityImageReadWriteLodAMD = 5015,
     CapabilityImageReadWriteLodAMD = 5015,
+    CapabilityInt64ImageEXT = 5016,
     CapabilityShaderClockKHR = 5055,
     CapabilityShaderClockKHR = 5055,
     CapabilitySampleMaskOverrideCoverageNV = 5249,
     CapabilitySampleMaskOverrideCoverageNV = 5249,
     CapabilityGeometryShaderPassthroughNV = 5251,
     CapabilityGeometryShaderPassthroughNV = 5251,
@@ -928,9 +967,20 @@ enum Capability {
     CapabilitySubgroupImageBlockIOINTEL = 5570,
     CapabilitySubgroupImageBlockIOINTEL = 5570,
     CapabilitySubgroupImageMediaBlockIOINTEL = 5579,
     CapabilitySubgroupImageMediaBlockIOINTEL = 5579,
     CapabilityIntegerFunctions2INTEL = 5584,
     CapabilityIntegerFunctions2INTEL = 5584,
+    CapabilityFunctionPointersINTEL = 5603,
+    CapabilityIndirectReferencesINTEL = 5604,
     CapabilitySubgroupAvcMotionEstimationINTEL = 5696,
     CapabilitySubgroupAvcMotionEstimationINTEL = 5696,
     CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697,
     CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697,
     CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698,
     CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698,
+    CapabilityFPGAMemoryAttributesINTEL = 5824,
+    CapabilityUnstructuredLoopControlsINTEL = 5886,
+    CapabilityFPGALoopControlsINTEL = 5888,
+    CapabilityKernelAttributesINTEL = 5892,
+    CapabilityFPGAKernelAttributesINTEL = 5897,
+    CapabilityBlockingPipesINTEL = 5945,
+    CapabilityFPGARegINTEL = 5948,
+    CapabilityAtomicFloat32AddEXT = 6033,
+    CapabilityAtomicFloat64AddEXT = 6034,
     CapabilityMax = 0x7fffffff,
     CapabilityMax = 0x7fffffff,
 };
 };
 
 
@@ -981,6 +1031,22 @@ enum RayQueryCandidateIntersectionType {
     RayQueryCandidateIntersectionTypeMax = 0x7fffffff,
     RayQueryCandidateIntersectionTypeMax = 0x7fffffff,
 };
 };
 
 
+enum FragmentShadingRateShift {
+    FragmentShadingRateVertical2PixelsShift = 0,
+    FragmentShadingRateVertical4PixelsShift = 1,
+    FragmentShadingRateHorizontal2PixelsShift = 2,
+    FragmentShadingRateHorizontal4PixelsShift = 3,
+    FragmentShadingRateMax = 0x7fffffff,
+};
+
+enum FragmentShadingRateMask {
+    FragmentShadingRateMaskNone = 0,
+    FragmentShadingRateVertical2PixelsMask = 0x00000001,
+    FragmentShadingRateVertical4PixelsMask = 0x00000002,
+    FragmentShadingRateHorizontal2PixelsMask = 0x00000004,
+    FragmentShadingRateHorizontal4PixelsMask = 0x00000008,
+};
+
 enum Op {
 enum Op {
     OpNop = 0,
     OpNop = 0,
     OpUndef = 1,
     OpUndef = 1,
@@ -1326,13 +1392,19 @@ enum Op {
     OpPtrEqual = 401,
     OpPtrEqual = 401,
     OpPtrNotEqual = 402,
     OpPtrNotEqual = 402,
     OpPtrDiff = 403,
     OpPtrDiff = 403,
+    OpTerminateInvocation = 4416,
     OpSubgroupBallotKHR = 4421,
     OpSubgroupBallotKHR = 4421,
     OpSubgroupFirstInvocationKHR = 4422,
     OpSubgroupFirstInvocationKHR = 4422,
     OpSubgroupAllKHR = 4428,
     OpSubgroupAllKHR = 4428,
     OpSubgroupAnyKHR = 4429,
     OpSubgroupAnyKHR = 4429,
     OpSubgroupAllEqualKHR = 4430,
     OpSubgroupAllEqualKHR = 4430,
     OpSubgroupReadInvocationKHR = 4432,
     OpSubgroupReadInvocationKHR = 4432,
-    OpTypeRayQueryProvisionalKHR = 4472,
+    OpTraceRayKHR = 4445,
+    OpExecuteCallableKHR = 4446,
+    OpConvertUToAccelerationStructureKHR = 4447,
+    OpIgnoreIntersectionKHR = 4448,
+    OpTerminateRayKHR = 4449,
+    OpTypeRayQueryKHR = 4472,
     OpRayQueryInitializeKHR = 4473,
     OpRayQueryInitializeKHR = 4473,
     OpRayQueryTerminateKHR = 4474,
     OpRayQueryTerminateKHR = 4474,
     OpRayQueryGenerateIntersectionKHR = 4475,
     OpRayQueryGenerateIntersectionKHR = 4475,
@@ -1355,15 +1427,11 @@ enum Op {
     OpWritePackedPrimitiveIndices4x8NV = 5299,
     OpWritePackedPrimitiveIndices4x8NV = 5299,
     OpReportIntersectionKHR = 5334,
     OpReportIntersectionKHR = 5334,
     OpReportIntersectionNV = 5334,
     OpReportIntersectionNV = 5334,
-    OpIgnoreIntersectionKHR = 5335,
     OpIgnoreIntersectionNV = 5335,
     OpIgnoreIntersectionNV = 5335,
-    OpTerminateRayKHR = 5336,
     OpTerminateRayNV = 5336,
     OpTerminateRayNV = 5336,
     OpTraceNV = 5337,
     OpTraceNV = 5337,
-    OpTraceRayKHR = 5337,
     OpTypeAccelerationStructureKHR = 5341,
     OpTypeAccelerationStructureKHR = 5341,
     OpTypeAccelerationStructureNV = 5341,
     OpTypeAccelerationStructureNV = 5341,
-    OpExecuteCallableKHR = 5344,
     OpExecuteCallableNV = 5344,
     OpExecuteCallableNV = 5344,
     OpTypeCooperativeMatrixNV = 5358,
     OpTypeCooperativeMatrixNV = 5358,
     OpCooperativeMatrixLoadNV = 5359,
     OpCooperativeMatrixLoadNV = 5359,
@@ -1398,6 +1466,8 @@ enum Op {
     OpUSubSatINTEL = 5596,
     OpUSubSatINTEL = 5596,
     OpIMul32x16INTEL = 5597,
     OpIMul32x16INTEL = 5597,
     OpUMul32x16INTEL = 5598,
     OpUMul32x16INTEL = 5598,
+    OpFunctionPointerINTEL = 5600,
+    OpFunctionPointerCallINTEL = 5601,
     OpDecorateString = 5632,
     OpDecorateString = 5632,
     OpDecorateStringGOOGLE = 5632,
     OpDecorateStringGOOGLE = 5632,
     OpMemberDecorateString = 5633,
     OpMemberDecorateString = 5633,
@@ -1520,6 +1590,10 @@ enum Op {
     OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
     OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
     OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
     OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
     OpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
     OpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
+    OpLoopControlINTEL = 5887,
+    OpReadPipeBlockingINTEL = 5946,
+    OpWritePipeBlockingINTEL = 5947,
+    OpFPGARegINTEL = 5949,
     OpRayQueryGetRayTMinKHR = 6016,
     OpRayQueryGetRayTMinKHR = 6016,
     OpRayQueryGetRayFlagsKHR = 6017,
     OpRayQueryGetRayFlagsKHR = 6017,
     OpRayQueryGetIntersectionTKHR = 6018,
     OpRayQueryGetIntersectionTKHR = 6018,
@@ -1537,6 +1611,7 @@ enum Op {
     OpRayQueryGetWorldRayOriginKHR = 6030,
     OpRayQueryGetWorldRayOriginKHR = 6030,
     OpRayQueryGetIntersectionObjectToWorldKHR = 6031,
     OpRayQueryGetIntersectionObjectToWorldKHR = 6031,
     OpRayQueryGetIntersectionWorldToObjectKHR = 6032,
     OpRayQueryGetIntersectionWorldToObjectKHR = 6032,
+    OpAtomicFAddEXT = 6035,
     OpMax = 0x7fffffff,
     OpMax = 0x7fffffff,
 };
 };
 
 
@@ -1889,13 +1964,19 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
     case OpPtrEqual: *hasResult = true; *hasResultType = true; break;
     case OpPtrEqual: *hasResult = true; *hasResultType = true; break;
     case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break;
     case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break;
     case OpPtrDiff: *hasResult = true; *hasResultType = true; break;
     case OpPtrDiff: *hasResult = true; *hasResultType = true; break;
+    case OpTerminateInvocation: *hasResult = false; *hasResultType = false; break;
     case OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
-    case OpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break;
+    case OpTraceRayKHR: *hasResult = false; *hasResultType = false; break;
+    case OpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break;
+    case OpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break;
+    case OpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break;
+    case OpTerminateRayKHR: *hasResult = false; *hasResultType = false; break;
+    case OpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break;
     case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
     case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
     case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
     case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
     case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
     case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
@@ -1955,6 +2036,8 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
     case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break;
     case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break;
     case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
     case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
     case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
     case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break;
+    case OpFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break;
+    case OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break;
     case OpDecorateString: *hasResult = false; *hasResultType = false; break;
     case OpDecorateString: *hasResult = false; *hasResultType = false; break;
     case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break;
     case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break;
     case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break;
     case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break;
@@ -2075,6 +2158,10 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
     case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
     case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
+    case OpLoopControlINTEL: *hasResult = false; *hasResultType = false; break;
+    case OpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break;
+    case OpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break;
+    case OpFPGARegINTEL: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
@@ -2092,6 +2179,7 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
     case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
     case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
+    case OpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break;
     }
     }
 }
 }
 #endif /* SPV_ENABLE_UTILITY_CODE */
 #endif /* SPV_ENABLE_UTILITY_CODE */
@@ -2107,6 +2195,7 @@ inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask
 inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }
 inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }
 inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }
 inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }
 inline RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) | unsigned(b)); }
 inline RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) | unsigned(b)); }
+inline FragmentShadingRateMask operator|(FragmentShadingRateMask a, FragmentShadingRateMask b) { return FragmentShadingRateMask(unsigned(a) | unsigned(b)); }
 
 
 }  // end namespace spv
 }  // end namespace spv
 
 

+ 8 - 1
src/libraries/spirv_cross/spirv_cfg.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2016-2020 Arm Limited
+ * Copyright 2016-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_cfg.hpp"
 #include "spirv_cfg.hpp"
 #include "spirv_cross.hpp"
 #include "spirv_cross.hpp"
 #include <algorithm>
 #include <algorithm>

+ 8 - 1
src/libraries/spirv_cross/spirv_cfg.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2016-2020 Arm Limited
+ * Copyright 2016-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_CFG_HPP
 #ifndef SPIRV_CROSS_CFG_HPP
 #define SPIRV_CROSS_CFG_HPP
 #define SPIRV_CROSS_CFG_HPP
 
 

+ 82 - 49
src/libraries/spirv_cross/spirv_common.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_COMMON_HPP
 #ifndef SPIRV_CROSS_COMMON_HPP
 #define SPIRV_CROSS_COMMON_HPP
 #define SPIRV_CROSS_COMMON_HPP
 
 
@@ -262,6 +269,29 @@ inline std::string convert_to_string(double t, char locale_radix_point)
 	return buf;
 	return buf;
 }
 }
 
 
+template <typename T>
+struct ValueSaver
+{
+	explicit ValueSaver(T &current_)
+	    : current(current_)
+	    , saved(current_)
+	{
+	}
+
+	void release()
+	{
+		current = saved;
+	}
+
+	~ValueSaver()
+	{
+		release();
+	}
+
+	T &current;
+	T saved;
+};
+
 #if defined(__clang__) || defined(__GNUC__)
 #if defined(__clang__) || defined(__GNUC__)
 #pragma GCC diagnostic pop
 #pragma GCC diagnostic pop
 #elif defined(_MSC_VER)
 #elif defined(_MSC_VER)
@@ -272,8 +302,20 @@ struct Instruction
 {
 {
 	uint16_t op = 0;
 	uint16_t op = 0;
 	uint16_t count = 0;
 	uint16_t count = 0;
+	// If offset is 0 (not a valid offset into the instruction stream),
+	// we have an instruction stream which is embedded in the object.
 	uint32_t offset = 0;
 	uint32_t offset = 0;
 	uint32_t length = 0;
 	uint32_t length = 0;
+
+	inline bool is_embedded() const
+	{
+		return offset == 0;
+	}
+};
+
+struct EmbeddedInstruction : Instruction
+{
+	SmallVector<uint32_t> ops;
 };
 };
 
 
 enum Types
 enum Types
@@ -334,28 +376,6 @@ public:
 		return TypedID<U>(*this);
 		return TypedID<U>(*this);
 	}
 	}
 
 
-	bool operator==(const TypedID &other) const
-	{
-		return id == other.id;
-	}
-
-	bool operator!=(const TypedID &other) const
-	{
-		return id != other.id;
-	}
-
-	template <Types type>
-	bool operator==(const TypedID<type> &other) const
-	{
-		return id == uint32_t(other);
-	}
-
-	template <Types type>
-	bool operator!=(const TypedID<type> &other) const
-	{
-		return id != uint32_t(other);
-	}
-
 private:
 private:
 	uint32_t id = 0;
 	uint32_t id = 0;
 };
 };
@@ -380,26 +400,6 @@ public:
 		return id;
 		return id;
 	}
 	}
 
 
-	bool operator==(const TypedID &other) const
-	{
-		return id == other.id;
-	}
-
-	bool operator!=(const TypedID &other) const
-	{
-		return id != other.id;
-	}
-
-	bool operator==(const TypedID<TypeNone> &other) const
-	{
-		return id == uint32_t(other);
-	}
-
-	bool operator!=(const TypedID<TypeNone> &other) const
-	{
-		return id != uint32_t(other);
-	}
-
 private:
 private:
 	uint32_t id = 0;
 	uint32_t id = 0;
 };
 };
@@ -535,6 +535,7 @@ struct SPIRType : IVariant
 
 
 		// Keep internal types at the end.
 		// Keep internal types at the end.
 		ControlPointArray,
 		ControlPointArray,
+		Interpolant,
 		Char
 		Char
 	};
 	};
 
 
@@ -641,7 +642,7 @@ struct SPIREntryPoint
 	SmallVector<VariableID> interface_variables;
 	SmallVector<VariableID> interface_variables;
 
 
 	Bitset flags;
 	Bitset flags;
-	struct
+	struct WorkgroupSize
 	{
 	{
 		uint32_t x = 0, y = 0, z = 0;
 		uint32_t x = 0, y = 0, z = 0;
 		uint32_t constant = 0; // Workgroup size can be expressed as a constant/spec-constant instead.
 		uint32_t constant = 0; // Workgroup size can be expressed as a constant/spec-constant instead.
@@ -699,6 +700,9 @@ struct SPIRExpression : IVariant
 	// Used by access chain Store and Load since we read multiple expressions in this case.
 	// Used by access chain Store and Load since we read multiple expressions in this case.
 	SmallVector<ID> implied_read_expressions;
 	SmallVector<ID> implied_read_expressions;
 
 
+	// The expression was emitted at a certain scope. Lets us track when an expression read means multiple reads.
+	uint32_t emitted_loop_level = 0;
+
 	SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
 	SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
 };
 };
 
 
@@ -737,7 +741,9 @@ struct SPIRBlock : IVariant
 
 
 		Return, // Block ends with return.
 		Return, // Block ends with return.
 		Unreachable, // Noop
 		Unreachable, // Noop
-		Kill // Discard
+		Kill, // Discard
+		IgnoreIntersection, // Ray Tracing
+		TerminateRay // Ray Tracing
 	};
 	};
 
 
 	enum Merge
 	enum Merge
@@ -1069,7 +1075,8 @@ struct SPIRConstant : IVariant
 		type = TypeConstant
 		type = TypeConstant
 	};
 	};
 
 
-	union Constant {
+	union Constant
+	{
 		uint32_t u32;
 		uint32_t u32;
 		int32_t i32;
 		int32_t i32;
 		float f32;
 		float f32;
@@ -1107,7 +1114,8 @@ struct SPIRConstant : IVariant
 		int e = (u16_value >> 10) & 0x1f;
 		int e = (u16_value >> 10) & 0x1f;
 		int m = (u16_value >> 0) & 0x3ff;
 		int m = (u16_value >> 0) & 0x3ff;
 
 
-		union {
+		union
+		{
 			float f32;
 			float f32;
 			uint32_t u32;
 			uint32_t u32;
 		} u;
 		} u;
@@ -1526,6 +1534,7 @@ struct AccessChainMeta
 	bool need_transpose = false;
 	bool need_transpose = false;
 	bool storage_is_packed = false;
 	bool storage_is_packed = false;
 	bool storage_is_invariant = false;
 	bool storage_is_invariant = false;
+	bool flattened_struct = false;
 };
 };
 
 
 enum ExtendedDecorations
 enum ExtendedDecorations
@@ -1560,8 +1569,10 @@ enum ExtendedDecorations
 	// Marks a buffer block for using explicit offsets (GLSL/HLSL).
 	// Marks a buffer block for using explicit offsets (GLSL/HLSL).
 	SPIRVCrossDecorationExplicitOffset,
 	SPIRVCrossDecorationExplicitOffset,
 
 
-	// Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase().
-	// In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables.
+	// Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase(),
+	// or the base vertex and instance indices passed to vkCmdDrawIndexed().
+	// In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables in compute shaders,
+	// and to hold the BaseVertex and BaseInstance variables in vertex shaders.
 	SPIRVCrossDecorationBuiltInDispatchBase,
 	SPIRVCrossDecorationBuiltInDispatchBase,
 
 
 	// Apply to a variable that is a function parameter; marks it as being a "dynamic"
 	// Apply to a variable that is a function parameter; marks it as being a "dynamic"
@@ -1570,6 +1581,27 @@ enum ExtendedDecorations
 	// Y'CbCr conversion.
 	// Y'CbCr conversion.
 	SPIRVCrossDecorationDynamicImageSampler,
 	SPIRVCrossDecorationDynamicImageSampler,
 
 
+	// Apply to a variable in the Input storage class; marks it as holding the size of the stage
+	// input grid.
+	// In MSL, this is used to hold the vertex and instance counts in a tessellation pipeline
+	// vertex shader.
+	SPIRVCrossDecorationBuiltInStageInputSize,
+
+	// Apply to any access chain of a tessellation I/O variable; stores the type of the sub-object
+	// that was chained to, as recorded in the input variable itself. This is used in case the pointer
+	// is itself used as the base of an access chain, to calculate the original type of the sub-object
+	// chained to, in case a swizzle needs to be applied. This should not happen normally with valid
+	// SPIR-V, but the MSL backend can change the type of input variables, necessitating the
+	// addition of swizzles to keep the generated code compiling.
+	SPIRVCrossDecorationTessIOOriginalInputTypeID,
+
+	// Apply to any access chain of an interface variable used with pull-model interpolation, where the variable is a
+	// vector but the resulting pointer is a scalar; stores the component index that is to be accessed by the chain.
+	// This is used when emitting calls to interpolation functions on the chain in MSL: in this case, the component
+	// must be applied to the result, since pull-model interpolants in MSL cannot be swizzled directly, but the
+	// results of interpolation can.
+	SPIRVCrossDecorationInterpolantComponentExpr,
+
 	SPIRVCrossDecorationCount
 	SPIRVCrossDecorationCount
 };
 };
 
 
@@ -1589,6 +1621,7 @@ struct Meta
 		uint32_t offset = 0;
 		uint32_t offset = 0;
 		uint32_t xfb_buffer = 0;
 		uint32_t xfb_buffer = 0;
 		uint32_t xfb_stride = 0;
 		uint32_t xfb_stride = 0;
+		uint32_t stream = 0;
 		uint32_t array_stride = 0;
 		uint32_t array_stride = 0;
 		uint32_t matrix_stride = 0;
 		uint32_t matrix_stride = 0;
 		uint32_t input_attachment = 0;
 		uint32_t input_attachment = 0;

+ 10 - 1
src/libraries/spirv_cross/spirv_cpp.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_cpp.hpp"
 #include "spirv_cpp.hpp"
 
 
 using namespace spv;
 using namespace spv;
@@ -306,6 +313,8 @@ void CompilerCPP::emit_resources()
 
 
 string CompilerCPP::compile()
 string CompilerCPP::compile()
 {
 {
+	ir.fixup_reserved_names();
+
 	// Do not deal with ES-isms like precision, older extensions and such.
 	// Do not deal with ES-isms like precision, older extensions and such.
 	options.es = false;
 	options.es = false;
 	options.version = 450;
 	options.version = 450;

+ 8 - 1
src/libraries/spirv_cross/spirv_cpp.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_CPP_HPP
 #ifndef SPIRV_CROSS_CPP_HPP
 #define SPIRV_CROSS_CPP_HPP
 #define SPIRV_CROSS_CPP_HPP
 
 

+ 332 - 40
src/libraries/spirv_cross/spirv_cross.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_cross.hpp"
 #include "spirv_cross.hpp"
 #include "GLSL.std.450.h"
 #include "GLSL.std.450.h"
 #include "spirv_cfg.hpp"
 #include "spirv_cfg.hpp"
@@ -89,7 +96,9 @@ bool Compiler::variable_storage_is_aliased(const SPIRVariable &v)
 bool Compiler::block_is_pure(const SPIRBlock &block)
 bool Compiler::block_is_pure(const SPIRBlock &block)
 {
 {
 	// This is a global side effect of the function.
 	// This is a global side effect of the function.
-	if (block.terminator == SPIRBlock::Kill)
+	if (block.terminator == SPIRBlock::Kill ||
+	    block.terminator == SPIRBlock::TerminateRay ||
+	    block.terminator == SPIRBlock::IgnoreIntersection)
 		return false;
 		return false;
 
 
 	for (auto &i : block.ops)
 	for (auto &i : block.ops)
@@ -151,11 +160,13 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
 			return false;
 			return false;
 
 
 		// Ray tracing builtins are impure.
 		// Ray tracing builtins are impure.
-		case OpReportIntersectionNV:
+		case OpReportIntersectionKHR:
 		case OpIgnoreIntersectionNV:
 		case OpIgnoreIntersectionNV:
 		case OpTerminateRayNV:
 		case OpTerminateRayNV:
 		case OpTraceNV:
 		case OpTraceNV:
+		case OpTraceRayKHR:
 		case OpExecuteCallableNV:
 		case OpExecuteCallableNV:
+		case OpExecuteCallableKHR:
 			return false;
 			return false;
 
 
 			// OpExtInst is potentially impure depending on extension, but GLSL builtins are at least pure.
 			// OpExtInst is potentially impure depending on extension, but GLSL builtins are at least pure.
@@ -273,11 +284,27 @@ SPIRVariable *Compiler::maybe_get_backing_variable(uint32_t chain)
 	return var;
 	return var;
 }
 }
 
 
-StorageClass Compiler::get_backing_variable_storage(uint32_t ptr)
+StorageClass Compiler::get_expression_effective_storage_class(uint32_t ptr)
 {
 {
 	auto *var = maybe_get_backing_variable(ptr);
 	auto *var = maybe_get_backing_variable(ptr);
-	if (var)
-		return var->storage;
+
+	// If the expression has been lowered to a temporary, we need to use the Generic storage class.
+	// We're looking for the effective storage class of a given expression.
+	// An access chain or forwarded OpLoads from such access chains
+	// will generally have the storage class of the underlying variable, but if the load was not forwarded
+	// we have lost any address space qualifiers.
+	bool forced_temporary = ir.ids[ptr].get_type() == TypeExpression && !get<SPIRExpression>(ptr).access_chain &&
+	                        (forced_temporaries.count(ptr) != 0 || forwarded_temporaries.count(ptr) == 0);
+
+	if (var && !forced_temporary)
+	{
+		// Normalize SSBOs to StorageBuffer here.
+		if (var->storage == StorageClassUniform &&
+		    has_decoration(get<SPIRType>(var->basetype).self, DecorationBufferBlock))
+			return StorageClassStorageBuffer;
+		else
+			return var->storage;
+	}
 	else
 	else
 		return expression_type(ptr).storage;
 		return expression_type(ptr).storage;
 }
 }
@@ -519,10 +546,16 @@ bool Compiler::is_hidden_variable(const SPIRVariable &var, bool include_builtins
 		return false;
 		return false;
 	}
 	}
 
 
-	bool hidden = false;
-	if (check_active_interface_variables && storage_class_is_interface(var.storage))
-		hidden = active_interface_variables.find(var.self) == end(active_interface_variables);
-	return hidden;
+	// In SPIR-V 1.4 and up we must also use the active variable interface to disable global variables
+	// which are not part of the entry point.
+	if (ir.get_spirv_version() >= 0x10400 && var.storage != spv::StorageClassGeneric &&
+	    var.storage != spv::StorageClassFunction && !interface_variable_exists_in_entry_point(var.self))
+	{
+		return true;
+	}
+
+	return check_active_interface_variables && storage_class_is_interface(var.storage) &&
+	       active_interface_variables.find(var.self) == end(active_interface_variables);
 }
 }
 
 
 bool Compiler::is_builtin_type(const SPIRType &type) const
 bool Compiler::is_builtin_type(const SPIRType &type) const
@@ -683,8 +716,31 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
 	{
 	{
 		if (length < 5)
 		if (length < 5)
 			return false;
 			return false;
-		uint32_t extension_set = args[2];
-		if (compiler.get<SPIRExtension>(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter)
+		auto &extension_set = compiler.get<SPIRExtension>(args[2]);
+		switch (extension_set.ext)
+		{
+		case SPIRExtension::GLSL:
+		{
+			auto op = static_cast<GLSLstd450>(args[3]);
+
+			switch (op)
+			{
+			case GLSLstd450InterpolateAtCentroid:
+			case GLSLstd450InterpolateAtSample:
+			case GLSLstd450InterpolateAtOffset:
+			{
+				auto *var = compiler.maybe_get<SPIRVariable>(args[4]);
+				if (var && storage_class_is_interface(var->storage))
+					variables.insert(args[4]);
+				break;
+			}
+
+			default:
+				break;
+			}
+			break;
+		}
+		case SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter:
 		{
 		{
 			enum AMDShaderExplicitVertexParameter
 			enum AMDShaderExplicitVertexParameter
 			{
 			{
@@ -706,6 +762,10 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t
 			default:
 			default:
 				break;
 				break;
 			}
 			}
+			break;
+		}
+		default:
+			break;
 		}
 		}
 		break;
 		break;
 	}
 	}
@@ -755,9 +815,17 @@ unordered_set<VariableID> Compiler::get_active_interface_variables() const
 	InterfaceVariableAccessHandler handler(*this, variables);
 	InterfaceVariableAccessHandler handler(*this, variables);
 	traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
 	traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
 
 
-	// Make sure we preserve output variables which are only initialized, but never accessed by any code.
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
-		if (var.storage == StorageClassOutput && var.initializer != ID(0))
+		if (var.storage != StorageClassOutput)
+			return;
+		if (!interface_variable_exists_in_entry_point(var.self))
+			return;
+
+		// An output variable which is just declared (but uninitialized) might be read by subsequent stages
+		// so we should force-enable these outputs,
+		// since compilation will fail if a subsequent stage attempts to read from the variable in question.
+		// Also, make sure we preserve output variables which are only initialized, but never accessed by any code.
+		if (var.initializer != ID(0) || get_execution_model() != ExecutionModelFragment)
 			variables.insert(var.self);
 			variables.insert(var.self);
 	});
 	});
 
 
@@ -1636,6 +1704,161 @@ size_t Compiler::get_declared_struct_size_runtime_array(const SPIRType &type, si
 	return size;
 	return size;
 }
 }
 
 
+uint32_t Compiler::evaluate_spec_constant_u32(const SPIRConstantOp &spec) const
+{
+	auto &result_type = get<SPIRType>(spec.basetype);
+	if (result_type.basetype != SPIRType::UInt && result_type.basetype != SPIRType::Int &&
+	    result_type.basetype != SPIRType::Boolean)
+	{
+		SPIRV_CROSS_THROW(
+		    "Only 32-bit integers and booleans are currently supported when evaluating specialization constants.\n");
+	}
+
+	if (!is_scalar(result_type))
+		SPIRV_CROSS_THROW("Spec constant evaluation must be a scalar.\n");
+
+	uint32_t value = 0;
+
+	const auto eval_u32 = [&](uint32_t id) -> uint32_t {
+		auto &type = expression_type(id);
+		if (type.basetype != SPIRType::UInt && type.basetype != SPIRType::Int && type.basetype != SPIRType::Boolean)
+		{
+			SPIRV_CROSS_THROW("Only 32-bit integers and booleans are currently supported when evaluating "
+			                  "specialization constants.\n");
+		}
+
+		if (!is_scalar(type))
+			SPIRV_CROSS_THROW("Spec constant evaluation must be a scalar.\n");
+		if (const auto *c = this->maybe_get<SPIRConstant>(id))
+			return c->scalar();
+		else
+			return evaluate_spec_constant_u32(this->get<SPIRConstantOp>(id));
+	};
+
+#define binary_spec_op(op, binary_op)                                              \
+	case Op##op:                                                                   \
+		value = eval_u32(spec.arguments[0]) binary_op eval_u32(spec.arguments[1]); \
+		break
+#define binary_spec_op_cast(op, binary_op, type)                                                         \
+	case Op##op:                                                                                         \
+		value = uint32_t(type(eval_u32(spec.arguments[0])) binary_op type(eval_u32(spec.arguments[1]))); \
+		break
+
+	// Support the basic opcodes which are typically used when computing array sizes.
+	switch (spec.opcode)
+	{
+		binary_spec_op(IAdd, +);
+		binary_spec_op(ISub, -);
+		binary_spec_op(IMul, *);
+		binary_spec_op(BitwiseAnd, &);
+		binary_spec_op(BitwiseOr, |);
+		binary_spec_op(BitwiseXor, ^);
+		binary_spec_op(LogicalAnd, &);
+		binary_spec_op(LogicalOr, |);
+		binary_spec_op(ShiftLeftLogical, <<);
+		binary_spec_op(ShiftRightLogical, >>);
+		binary_spec_op_cast(ShiftRightArithmetic, >>, int32_t);
+		binary_spec_op(LogicalEqual, ==);
+		binary_spec_op(LogicalNotEqual, !=);
+		binary_spec_op(IEqual, ==);
+		binary_spec_op(INotEqual, !=);
+		binary_spec_op(ULessThan, <);
+		binary_spec_op(ULessThanEqual, <=);
+		binary_spec_op(UGreaterThan, >);
+		binary_spec_op(UGreaterThanEqual, >=);
+		binary_spec_op_cast(SLessThan, <, int32_t);
+		binary_spec_op_cast(SLessThanEqual, <=, int32_t);
+		binary_spec_op_cast(SGreaterThan, >, int32_t);
+		binary_spec_op_cast(SGreaterThanEqual, >=, int32_t);
+#undef binary_spec_op
+#undef binary_spec_op_cast
+
+	case OpLogicalNot:
+		value = uint32_t(!eval_u32(spec.arguments[0]));
+		break;
+
+	case OpNot:
+		value = ~eval_u32(spec.arguments[0]);
+		break;
+
+	case OpSNegate:
+		value = uint32_t(-int32_t(eval_u32(spec.arguments[0])));
+		break;
+
+	case OpSelect:
+		value = eval_u32(spec.arguments[0]) ? eval_u32(spec.arguments[1]) : eval_u32(spec.arguments[2]);
+		break;
+
+	case OpUMod:
+	{
+		uint32_t a = eval_u32(spec.arguments[0]);
+		uint32_t b = eval_u32(spec.arguments[1]);
+		if (b == 0)
+			SPIRV_CROSS_THROW("Undefined behavior in UMod, b == 0.\n");
+		value = a % b;
+		break;
+	}
+
+	case OpSRem:
+	{
+		auto a = int32_t(eval_u32(spec.arguments[0]));
+		auto b = int32_t(eval_u32(spec.arguments[1]));
+		if (b == 0)
+			SPIRV_CROSS_THROW("Undefined behavior in SRem, b == 0.\n");
+		value = a % b;
+		break;
+	}
+
+	case OpSMod:
+	{
+		auto a = int32_t(eval_u32(spec.arguments[0]));
+		auto b = int32_t(eval_u32(spec.arguments[1]));
+		if (b == 0)
+			SPIRV_CROSS_THROW("Undefined behavior in SMod, b == 0.\n");
+		auto v = a % b;
+
+		// Makes sure we match the sign of b, not a.
+		if ((b < 0 && v > 0) || (b > 0 && v < 0))
+			v += b;
+		value = v;
+		break;
+	}
+
+	case OpUDiv:
+	{
+		uint32_t a = eval_u32(spec.arguments[0]);
+		uint32_t b = eval_u32(spec.arguments[1]);
+		if (b == 0)
+			SPIRV_CROSS_THROW("Undefined behavior in UDiv, b == 0.\n");
+		value = a / b;
+		break;
+	}
+
+	case OpSDiv:
+	{
+		auto a = int32_t(eval_u32(spec.arguments[0]));
+		auto b = int32_t(eval_u32(spec.arguments[1]));
+		if (b == 0)
+			SPIRV_CROSS_THROW("Undefined behavior in SDiv, b == 0.\n");
+		value = a / b;
+		break;
+	}
+
+	default:
+		SPIRV_CROSS_THROW("Unsupported spec constant opcode for evaluation.\n");
+	}
+
+	return value;
+}
+
+uint32_t Compiler::evaluate_constant_u32(uint32_t id) const
+{
+	if (const auto *c = maybe_get<SPIRConstant>(id))
+		return c->scalar();
+	else
+		return evaluate_spec_constant_u32(get<SPIRConstantOp>(id));
+}
+
 size_t Compiler::get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const
 size_t Compiler::get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const
 {
 {
 	if (struct_type.member_types.empty())
 	if (struct_type.member_types.empty())
@@ -1670,7 +1893,7 @@ size_t Compiler::get_declared_struct_member_size(const SPIRType &struct_type, ui
 	{
 	{
 		// For arrays, we can use ArrayStride to get an easy check.
 		// For arrays, we can use ArrayStride to get an easy check.
 		bool array_size_literal = type.array_size_literal.back();
 		bool array_size_literal = type.array_size_literal.back();
-		uint32_t array_size = array_size_literal ? type.array.back() : get<SPIRConstant>(type.array.back()).scalar();
+		uint32_t array_size = array_size_literal ? type.array.back() : evaluate_constant_u32(type.array.back());
 		return type_struct_member_array_stride(struct_type, index) * array_size;
 		return type_struct_member_array_stride(struct_type, index) * array_size;
 	}
 	}
 	else if (type.basetype == SPIRType::Struct)
 	else if (type.basetype == SPIRType::Struct)
@@ -1904,6 +2127,13 @@ bool Compiler::is_tessellation_shader(ExecutionModel model)
 	return model == ExecutionModelTessellationControl || model == ExecutionModelTessellationEvaluation;
 	return model == ExecutionModelTessellationControl || model == ExecutionModelTessellationEvaluation;
 }
 }
 
 
+bool Compiler::is_vertex_like_shader() const
+{
+	auto model = get_execution_model();
+	return model == ExecutionModelVertex || model == ExecutionModelGeometry ||
+	       model == ExecutionModelTessellationControl || model == ExecutionModelTessellationEvaluation;
+}
+
 bool Compiler::is_tessellation_shader() const
 bool Compiler::is_tessellation_shader() const
 {
 {
 	return is_tessellation_shader(get_execution_model());
 	return is_tessellation_shader(get_execution_model());
@@ -2067,16 +2297,22 @@ SPIREntryPoint &Compiler::get_entry_point()
 bool Compiler::interface_variable_exists_in_entry_point(uint32_t id) const
 bool Compiler::interface_variable_exists_in_entry_point(uint32_t id) const
 {
 {
 	auto &var = get<SPIRVariable>(id);
 	auto &var = get<SPIRVariable>(id);
-	if (var.storage != StorageClassInput && var.storage != StorageClassOutput &&
-	    var.storage != StorageClassUniformConstant)
-		SPIRV_CROSS_THROW("Only Input, Output variables and Uniform constants are part of a shader linking interface.");
-
-	// This is to avoid potential problems with very old glslang versions which did
-	// not emit input/output interfaces properly.
-	// We can assume they only had a single entry point, and single entry point
-	// shaders could easily be assumed to use every interface variable anyways.
-	if (ir.entry_points.size() <= 1)
-		return true;
+
+	if (ir.get_spirv_version() < 0x10400)
+	{
+		if (var.storage != StorageClassInput && var.storage != StorageClassOutput &&
+		    var.storage != StorageClassUniformConstant)
+			SPIRV_CROSS_THROW("Only Input, Output variables and Uniform constants are part of a shader linking interface.");
+
+		// This is to avoid potential problems with very old glslang versions which did
+		// not emit input/output interfaces properly.
+		// We can assume they only had a single entry point, and single entry point
+		// shaders could easily be assumed to use every interface variable anyways.
+		if (ir.entry_points.size() <= 1)
+			return true;
+	}
+
+	// In SPIR-V 1.4 and later, all global resource variables must be present.
 
 
 	auto &execution = get_entry_point();
 	auto &execution = get_entry_point();
 	return find(begin(execution.interface_variables), end(execution.interface_variables), VariableID(id)) !=
 	return find(begin(execution.interface_variables), end(execution.interface_variables), VariableID(id)) !=
@@ -2599,7 +2835,8 @@ const SPIRConstant &Compiler::get_constant(ConstantID id) const
 	return get<SPIRConstant>(id);
 	return get<SPIRConstant>(id);
 }
 }
 
 
-static bool exists_unaccessed_path_to_return(const CFG &cfg, uint32_t block, const unordered_set<uint32_t> &blocks)
+static bool exists_unaccessed_path_to_return(const CFG &cfg, uint32_t block, const unordered_set<uint32_t> &blocks,
+                                             unordered_set<uint32_t> &visit_cache)
 {
 {
 	// This block accesses the variable.
 	// This block accesses the variable.
 	if (blocks.find(block) != end(blocks))
 	if (blocks.find(block) != end(blocks))
@@ -2611,8 +2848,14 @@ static bool exists_unaccessed_path_to_return(const CFG &cfg, uint32_t block, con
 
 
 	// If any of our successors have a path to the end, there exists a path from block.
 	// If any of our successors have a path to the end, there exists a path from block.
 	for (auto &succ : cfg.get_succeeding_edges(block))
 	for (auto &succ : cfg.get_succeeding_edges(block))
-		if (exists_unaccessed_path_to_return(cfg, succ, blocks))
-			return true;
+	{
+		if (visit_cache.count(succ) == 0)
+		{
+			if (exists_unaccessed_path_to_return(cfg, succ, blocks, visit_cache))
+				return true;
+			visit_cache.insert(succ);
+		}
+	}
 
 
 	return false;
 	return false;
 }
 }
@@ -2669,7 +2912,8 @@ void Compiler::analyze_parameter_preservation(
 		// void foo(int &var) { if (cond) var = 10; }
 		// void foo(int &var) { if (cond) var = 10; }
 		// Using read/write counts, we will think it's just an out variable, but it really needs to be inout,
 		// Using read/write counts, we will think it's just an out variable, but it really needs to be inout,
 		// because if we don't write anything whatever we put into the function must return back to the caller.
 		// because if we don't write anything whatever we put into the function must return back to the caller.
-		if (exists_unaccessed_path_to_return(cfg, entry.entry_block, itr->second))
+		unordered_set<uint32_t> visit_cache;
+		if (exists_unaccessed_path_to_return(cfg, entry.entry_block, itr->second, visit_cache))
 			arg.read_count++;
 			arg.read_count++;
 	}
 	}
 }
 }
@@ -3627,23 +3871,55 @@ void Compiler::ActiveBuiltinHandler::handle_builtin(const SPIRType &type, BuiltI
 	}
 	}
 }
 }
 
 
-bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
+void Compiler::ActiveBuiltinHandler::add_if_builtin(uint32_t id, bool allow_blocks)
 {
 {
-	const auto add_if_builtin = [&](uint32_t id) {
-		// Only handles variables here.
-		// Builtins which are part of a block are handled in AccessChain.
-		auto *var = compiler.maybe_get<SPIRVariable>(id);
-		auto &decorations = compiler.ir.meta[id].decoration;
-		if (var && decorations.builtin)
+	// Only handle plain variables here.
+	// Builtins which are part of a block are handled in AccessChain.
+	// If allow_blocks is used however, this is to handle initializers of blocks,
+	// which implies that all members are written to.
+
+	auto *var = compiler.maybe_get<SPIRVariable>(id);
+	auto *m = compiler.ir.find_meta(id);
+	if (var && m)
+	{
+		auto &type = compiler.get<SPIRType>(var->basetype);
+		auto &decorations = m->decoration;
+		auto &flags = type.storage == StorageClassInput ?
+		              compiler.active_input_builtins : compiler.active_output_builtins;
+		if (decorations.builtin)
 		{
 		{
-			auto &type = compiler.get<SPIRType>(var->basetype);
-			auto &flags =
-			    type.storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
 			flags.set(decorations.builtin_type);
 			flags.set(decorations.builtin_type);
 			handle_builtin(type, decorations.builtin_type, decorations.decoration_flags);
 			handle_builtin(type, decorations.builtin_type, decorations.decoration_flags);
 		}
 		}
-	};
+		else if (allow_blocks && compiler.has_decoration(type.self, DecorationBlock))
+		{
+			uint32_t member_count = uint32_t(type.member_types.size());
+			for (uint32_t i = 0; i < member_count; i++)
+			{
+				if (compiler.has_member_decoration(type.self, i, DecorationBuiltIn))
+				{
+					auto &member_type = compiler.get<SPIRType>(type.member_types[i]);
+					BuiltIn builtin = BuiltIn(compiler.get_member_decoration(type.self, i, DecorationBuiltIn));
+					flags.set(builtin);
+					handle_builtin(member_type, builtin, compiler.get_member_decoration_bitset(type.self, i));
+				}
+			}
+		}
+	}
+}
 
 
+void Compiler::ActiveBuiltinHandler::add_if_builtin(uint32_t id)
+{
+	add_if_builtin(id, false);
+}
+
+void Compiler::ActiveBuiltinHandler::add_if_builtin_or_block(uint32_t id)
+{
+	add_if_builtin(id, true);
+}
+
+bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
+{
 	switch (opcode)
 	switch (opcode)
 	{
 	{
 	case OpStore:
 	case OpStore:
@@ -3781,6 +4057,17 @@ void Compiler::update_active_builtins()
 	clip_distance_count = 0;
 	clip_distance_count = 0;
 	ActiveBuiltinHandler handler(*this);
 	ActiveBuiltinHandler handler(*this);
 	traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
 	traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
+
+	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
+		if (var.storage != StorageClassOutput)
+			return;
+		if (!interface_variable_exists_in_entry_point(var.self))
+			return;
+
+		// Also, make sure we preserve output variables which are only initialized, but never accessed by any code.
+		if (var.initializer != ID(0))
+			handler.add_if_builtin_or_block(var.self);
+	});
 }
 }
 
 
 // Returns whether this shader uses a builtin of the storage class
 // Returns whether this shader uses a builtin of the storage class
@@ -4658,3 +4945,8 @@ bool Compiler::flush_phi_required(BlockID from, BlockID to) const
 			return true;
 			return true;
 	return false;
 	return false;
 }
 }
+
+void Compiler::add_loop_level()
+{
+	current_loop_level++;
+}

+ 49 - 5
src/libraries/spirv_cross/spirv_cross.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_HPP
 #ifndef SPIRV_CROSS_HPP
 #define SPIRV_CROSS_HPP
 #define SPIRV_CROSS_HPP
 
 
@@ -491,6 +498,12 @@ public:
 	// The most common use here is to check if a buffer is readonly or writeonly.
 	// The most common use here is to check if a buffer is readonly or writeonly.
 	Bitset get_buffer_block_flags(VariableID id) const;
 	Bitset get_buffer_block_flags(VariableID id) const;
 
 
+	// Returns whether the position output is invariant
+	bool is_position_invariant() const
+	{
+		return position_invariant;
+	}
+
 protected:
 protected:
 	const uint32_t *stream(const Instruction &instr) const
 	const uint32_t *stream(const Instruction &instr) const
 	{
 	{
@@ -500,9 +513,18 @@ protected:
 		if (!instr.length)
 		if (!instr.length)
 			return nullptr;
 			return nullptr;
 
 
-		if (instr.offset + instr.length > ir.spirv.size())
-			SPIRV_CROSS_THROW("Compiler::stream() out of range.");
-		return &ir.spirv[instr.offset];
+		if (instr.is_embedded())
+		{
+			auto &embedded = static_cast<const EmbeddedInstruction &>(instr);
+			assert(embedded.ops.size() == instr.length);
+			return embedded.ops.data();
+		}
+		else
+		{
+			if (instr.offset + instr.length > ir.spirv.size())
+				SPIRV_CROSS_THROW("Compiler::stream() out of range.");
+			return &ir.spirv[instr.offset];
+		}
 	}
 	}
 
 
 	ParsedIR ir;
 	ParsedIR ir;
@@ -513,9 +535,22 @@ protected:
 
 
 	SPIRFunction *current_function = nullptr;
 	SPIRFunction *current_function = nullptr;
 	SPIRBlock *current_block = nullptr;
 	SPIRBlock *current_block = nullptr;
+	uint32_t current_loop_level = 0;
 	std::unordered_set<VariableID> active_interface_variables;
 	std::unordered_set<VariableID> active_interface_variables;
 	bool check_active_interface_variables = false;
 	bool check_active_interface_variables = false;
 
 
+	void add_loop_level();
+
+	void set_initializers(SPIRExpression &e)
+	{
+		e.emitted_loop_level = current_loop_level;
+	}
+
+	template <typename T>
+	void set_initializers(const T &)
+	{
+	}
+
 	// If our IDs are out of range here as part of opcodes, throw instead of
 	// If our IDs are out of range here as part of opcodes, throw instead of
 	// undefined behavior.
 	// undefined behavior.
 	template <typename T, typename... P>
 	template <typename T, typename... P>
@@ -524,6 +559,7 @@ protected:
 		ir.add_typed_id(static_cast<Types>(T::type), id);
 		ir.add_typed_id(static_cast<Types>(T::type), id);
 		auto &var = variant_set<T>(ir.ids[id], std::forward<P>(args)...);
 		auto &var = variant_set<T>(ir.ids[id], std::forward<P>(args)...);
 		var.self = id;
 		var.self = id;
+		set_initializers(var);
 		return var;
 		return var;
 	}
 	}
 
 
@@ -611,7 +647,7 @@ protected:
 	bool expression_is_lvalue(uint32_t id) const;
 	bool expression_is_lvalue(uint32_t id) const;
 	bool variable_storage_is_aliased(const SPIRVariable &var);
 	bool variable_storage_is_aliased(const SPIRVariable &var);
 	SPIRVariable *maybe_get_backing_variable(uint32_t chain);
 	SPIRVariable *maybe_get_backing_variable(uint32_t chain);
-	spv::StorageClass get_backing_variable_storage(uint32_t ptr);
+	spv::StorageClass get_expression_effective_storage_class(uint32_t ptr);
 
 
 	void register_read(uint32_t expr, uint32_t chain, bool forwarded);
 	void register_read(uint32_t expr, uint32_t chain, bool forwarded);
 	void register_write(uint32_t chain);
 	void register_write(uint32_t chain);
@@ -812,6 +848,9 @@ protected:
 		Compiler &compiler;
 		Compiler &compiler;
 
 
 		void handle_builtin(const SPIRType &type, spv::BuiltIn builtin, const Bitset &decoration_flags);
 		void handle_builtin(const SPIRType &type, spv::BuiltIn builtin, const Bitset &decoration_flags);
+		void add_if_builtin(uint32_t id);
+		void add_if_builtin_or_block(uint32_t id);
+		void add_if_builtin(uint32_t id, bool allow_blocks);
 	};
 	};
 
 
 	bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
 	bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
@@ -1046,6 +1085,11 @@ protected:
 
 
 	bool flush_phi_required(BlockID from, BlockID to) const;
 	bool flush_phi_required(BlockID from, BlockID to) const;
 
 
+	uint32_t evaluate_spec_constant_u32(const SPIRConstantOp &spec) const;
+	uint32_t evaluate_constant_u32(uint32_t id) const;
+
+	bool is_vertex_like_shader() const;
+
 private:
 private:
 	// Used only to implement the old deprecated get_entry_point() interface.
 	// Used only to implement the old deprecated get_entry_point() interface.
 	const SPIREntryPoint &get_first_entry_point(const std::string &name) const;
 	const SPIREntryPoint &get_first_entry_point(const std::string &name) const;

+ 157 - 9
src/libraries/spirv_cross/spirv_cross_c.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2019-2020 Hans-Kristian Arntzen
+ * Copyright 2019-2021 Hans-Kristian Arntzen
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_cross_c.h"
 #include "spirv_cross_c.h"
 
 
 #if SPIRV_CROSS_C_API_CPP
 #if SPIRV_CROSS_C_API_CPP
@@ -459,6 +466,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS:
 	case SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS:
 		options->glsl.emit_uniform_buffer_as_plain_uniforms = value != 0;
 		options->glsl.emit_uniform_buffer_as_plain_uniforms = value != 0;
 		break;
 		break;
+	case SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS:
+		options->glsl.force_flattened_io_blocks = value != 0;
+		break;
 #endif
 #endif
 
 
 #if SPIRV_CROSS_C_API_HLSL
 #if SPIRV_CROSS_C_API_HLSL
@@ -489,6 +499,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES:
 	case SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES:
 		options->hlsl.enable_16bit_types = value != 0;
 		options->hlsl.enable_16bit_types = value != 0;
 		break;
 		break;
+
+	case SPVC_COMPILER_OPTION_HLSL_FLATTEN_MATRIX_VERTEX_INPUT_SEMANTICS:
+		options->hlsl.flatten_matrix_vertex_input_semantics = value != 0;
+		break;
 #endif
 #endif
 
 
 #if SPIRV_CROSS_C_API_MSL
 #if SPIRV_CROSS_C_API_MSL
@@ -596,8 +610,8 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 		options->msl.enable_base_index_zero = value != 0;
 		options->msl.enable_base_index_zero = value != 0;
 		break;
 		break;
 
 
-	case SPVC_COMPILER_OPTION_MSL_IOS_FRAMEBUFFER_FETCH_SUBPASS:
-		options->msl.ios_use_framebuffer_fetch_subpasses = value != 0;
+	case SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS:
+		options->msl.use_framebuffer_fetch_subpasses = value != 0;
 		break;
 		break;
 
 
 	case SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH:
 	case SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH:
@@ -635,6 +649,62 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
 	case SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING:
 	case SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING:
 		options->msl.enable_clip_distance_user_varying = value != 0;
 		options->msl.enable_clip_distance_user_varying = value != 0;
 		break;
 		break;
+
+	case SPVC_COMPILER_OPTION_MSL_MULTI_PATCH_WORKGROUP:
+		options->msl.multi_patch_workgroup = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_BUFFER_INDEX:
+		options->msl.shader_input_buffer_index = value;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_SHADER_INDEX_BUFFER_INDEX:
+		options->msl.shader_index_buffer_index = value;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION:
+		options->msl.vertex_for_tessellation = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE:
+		options->msl.vertex_index_type = static_cast<CompilerMSL::Options::IndexType>(value);
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING:
+		options->msl.multiview_layered_rendering = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT:
+		options->msl.arrayed_subpass_input = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT:
+		options->msl.r32ui_linear_texture_alignment = value;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID:
+		options->msl.r32ui_alignment_constant_id = value;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_IOS_USE_SIMDGROUP_FUNCTIONS:
+		options->msl.ios_use_simdgroup_functions = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_EMULATE_SUBGROUPS:
+		options->msl.emulate_subgroups = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_FIXED_SUBGROUP_SIZE:
+		options->msl.fixed_subgroup_size = value;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING:
+		options->msl.force_sample_rate_shading = value != 0;
+		break;
+
+	case SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE:
+		options->msl.ios_support_base_vertex_instance = value != 0;
+		break;
 #endif
 #endif
 
 
 	default:
 	default:
@@ -1019,11 +1089,11 @@ spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler, const
 	}
 	}
 
 
 	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
 	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
-	MSLVertexAttr attr;
+	MSLShaderInput attr;
 	attr.location = va->location;
 	attr.location = va->location;
-	attr.format = static_cast<MSLVertexFormat>(va->format);
+	attr.format = static_cast<MSLShaderInputFormat>(va->format);
 	attr.builtin = static_cast<spv::BuiltIn>(va->builtin);
 	attr.builtin = static_cast<spv::BuiltIn>(va->builtin);
-	msl.add_msl_vertex_attribute(attr);
+	msl.add_msl_shader_input(attr);
 	return SPVC_SUCCESS;
 	return SPVC_SUCCESS;
 #else
 #else
 	(void)va;
 	(void)va;
@@ -1032,6 +1102,30 @@ spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler, const
 #endif
 #endif
 }
 }
 
 
+spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler, const spvc_msl_shader_input *si)
+{
+#if SPIRV_CROSS_C_API_MSL
+	if (compiler->backend != SPVC_BACKEND_MSL)
+	{
+		compiler->context->report_error("MSL function used on a non-MSL backend.");
+		return SPVC_ERROR_INVALID_ARGUMENT;
+	}
+
+	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
+	MSLShaderInput input;
+	input.location = si->location;
+	input.format = static_cast<MSLShaderInputFormat>(si->format);
+	input.builtin = static_cast<spv::BuiltIn>(si->builtin);
+	input.vecsize = si->vecsize;
+	msl.add_msl_shader_input(input);
+	return SPVC_SUCCESS;
+#else
+	(void)si;
+	compiler->context->report_error("MSL function used on a non-MSL backend.");
+	return SPVC_ERROR_INVALID_ARGUMENT;
+#endif
+}
+
 spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler,
 spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler,
                                                    const spvc_msl_resource_binding *binding)
                                                    const spvc_msl_resource_binding *binding)
 {
 {
@@ -1139,7 +1233,7 @@ spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_comp
 #endif
 #endif
 }
 }
 
 
-spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location)
+spvc_bool spvc_compiler_msl_is_shader_input_used(spvc_compiler compiler, unsigned location)
 {
 {
 #if SPIRV_CROSS_C_API_MSL
 #if SPIRV_CROSS_C_API_MSL
 	if (compiler->backend != SPVC_BACKEND_MSL)
 	if (compiler->backend != SPVC_BACKEND_MSL)
@@ -1149,7 +1243,7 @@ spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, uns
 	}
 	}
 
 
 	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
 	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
-	return msl.is_msl_vertex_attribute_used(location) ? SPVC_TRUE : SPVC_FALSE;
+	return msl.is_msl_shader_input_used(location) ? SPVC_TRUE : SPVC_FALSE;
 #else
 #else
 	(void)location;
 	(void)location;
 	compiler->context->report_error("MSL function used on a non-MSL backend.");
 	compiler->context->report_error("MSL function used on a non-MSL backend.");
@@ -1157,6 +1251,11 @@ spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, uns
 #endif
 #endif
 }
 }
 
 
+spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location)
+{
+	return spvc_compiler_msl_is_shader_input_used(compiler, location);
+}
+
 spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set,
 spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set,
                                              unsigned binding)
                                              unsigned binding)
 {
 {
@@ -1179,6 +1278,42 @@ spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, SpvExecutio
 #endif
 #endif
 }
 }
 
 
+spvc_result spvc_compiler_msl_set_combined_sampler_suffix(spvc_compiler compiler, const char *suffix)
+{
+#if SPIRV_CROSS_C_API_MSL
+	if (compiler->backend != SPVC_BACKEND_MSL)
+	{
+		compiler->context->report_error("MSL function used on a non-MSL backend.");
+		return SPVC_ERROR_INVALID_ARGUMENT;
+	}
+
+	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
+	msl.set_combined_sampler_suffix(suffix);
+	return SPVC_SUCCESS;
+#else
+	(void)suffix;
+	compiler->context->report_error("MSL function used on a non-MSL backend.");
+	return SPVC_ERROR_INVALID_ARGUMENT;
+#endif
+}
+
+const char *spvc_compiler_msl_get_combined_sampler_suffix(spvc_compiler compiler)
+{
+#if SPIRV_CROSS_C_API_MSL
+	if (compiler->backend != SPVC_BACKEND_MSL)
+	{
+		compiler->context->report_error("MSL function used on a non-MSL backend.");
+		return "";
+	}
+
+	auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
+	return msl.get_combined_sampler_suffix();
+#else
+	compiler->context->report_error("MSL function used on a non-MSL backend.");
+	return "";
+#endif
+}
+
 #if SPIRV_CROSS_C_API_MSL
 #if SPIRV_CROSS_C_API_MSL
 static void spvc_convert_msl_sampler(MSLConstexprSampler &samp, const spvc_msl_constexpr_sampler *sampler)
 static void spvc_convert_msl_sampler(MSLConstexprSampler &samp, const spvc_msl_constexpr_sampler *sampler)
 {
 {
@@ -2258,7 +2393,7 @@ void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr)
 {
 {
 #if SPIRV_CROSS_C_API_MSL
 #if SPIRV_CROSS_C_API_MSL
 	// Crude, but works.
 	// Crude, but works.
-	MSLVertexAttr attr_default;
+	MSLShaderInput attr_default;
 	attr->location = attr_default.location;
 	attr->location = attr_default.location;
 	attr->format = static_cast<spvc_msl_vertex_format>(attr_default.format);
 	attr->format = static_cast<spvc_msl_vertex_format>(attr_default.format);
 	attr->builtin = static_cast<SpvBuiltIn>(attr_default.builtin);
 	attr->builtin = static_cast<SpvBuiltIn>(attr_default.builtin);
@@ -2267,6 +2402,19 @@ void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr)
 #endif
 #endif
 }
 }
 
 
+void spvc_msl_shader_input_init(spvc_msl_shader_input *input)
+{
+#if SPIRV_CROSS_C_API_MSL
+	MSLShaderInput input_default;
+	input->location = input_default.location;
+	input->format = static_cast<spvc_msl_shader_input_format>(input_default.format);
+	input->builtin = static_cast<SpvBuiltIn>(input_default.builtin);
+	input->vecsize = input_default.vecsize;
+#else
+	memset(input, 0, sizeof(*input));
+#endif
+}
+
 void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding)
 void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding)
 {
 {
 #if SPIRV_CROSS_C_API_MSL
 #if SPIRV_CROSS_C_API_MSL

+ 80 - 7
src/libraries/spirv_cross/spirv_cross_c.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2019-2020 Hans-Kristian Arntzen
+ * Copyright 2019-2021 Hans-Kristian Arntzen
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_C_API_H
 #ifndef SPIRV_CROSS_C_API_H
 #define SPIRV_CROSS_C_API_H
 #define SPIRV_CROSS_C_API_H
 
 
@@ -33,7 +40,7 @@ extern "C" {
 /* Bumped if ABI or API breaks backwards compatibility. */
 /* Bumped if ABI or API breaks backwards compatibility. */
 #define SPVC_C_API_VERSION_MAJOR 0
 #define SPVC_C_API_VERSION_MAJOR 0
 /* Bumped if APIs or enumerations are added in a backwards compatible way. */
 /* Bumped if APIs or enumerations are added in a backwards compatible way. */
-#define SPVC_C_API_VERSION_MINOR 34
+#define SPVC_C_API_VERSION_MINOR 45
 /* Bumped if internal implementation details change. */
 /* Bumped if internal implementation details change. */
 #define SPVC_C_API_VERSION_PATCH 0
 #define SPVC_C_API_VERSION_PATCH 0
 
 
@@ -259,14 +266,32 @@ typedef enum spvc_msl_platform
 } spvc_msl_platform;
 } spvc_msl_platform;
 
 
 /* Maps to C++ API. */
 /* Maps to C++ API. */
-typedef enum spvc_msl_vertex_format
+typedef enum spvc_msl_index_type
 {
 {
-	SPVC_MSL_VERTEX_FORMAT_OTHER = 0,
-	SPVC_MSL_VERTEX_FORMAT_UINT8 = 1,
-	SPVC_MSL_VERTEX_FORMAT_UINT16 = 2
-} spvc_msl_vertex_format;
+	SPVC_MSL_INDEX_TYPE_NONE = 0,
+	SPVC_MSL_INDEX_TYPE_UINT16 = 1,
+	SPVC_MSL_INDEX_TYPE_UINT32 = 2,
+	SPVC_MSL_INDEX_TYPE_MAX_INT = 0x7fffffff
+} spvc_msl_index_type;
 
 
 /* Maps to C++ API. */
 /* Maps to C++ API. */
+typedef enum spvc_msl_shader_input_format
+{
+	SPVC_MSL_SHADER_INPUT_FORMAT_OTHER = 0,
+	SPVC_MSL_SHADER_INPUT_FORMAT_UINT8 = 1,
+	SPVC_MSL_SHADER_INPUT_FORMAT_UINT16 = 2,
+	SPVC_MSL_SHADER_INPUT_FORMAT_ANY16 = 3,
+	SPVC_MSL_SHADER_INPUT_FORMAT_ANY32 = 4,
+
+	/* Deprecated names. */
+	SPVC_MSL_VERTEX_FORMAT_OTHER = SPVC_MSL_SHADER_INPUT_FORMAT_OTHER,
+	SPVC_MSL_VERTEX_FORMAT_UINT8 = SPVC_MSL_SHADER_INPUT_FORMAT_UINT8,
+	SPVC_MSL_VERTEX_FORMAT_UINT16 = SPVC_MSL_SHADER_INPUT_FORMAT_UINT16,
+
+	SPVC_MSL_SHADER_INPUT_FORMAT_INT_MAX = 0x7fffffff
+} spvc_msl_shader_input_format, spvc_msl_vertex_format;
+
+/* Maps to C++ API. Deprecated; use spvc_msl_shader_input. */
 typedef struct spvc_msl_vertex_attribute
 typedef struct spvc_msl_vertex_attribute
 {
 {
 	unsigned location;
 	unsigned location;
@@ -289,6 +314,20 @@ typedef struct spvc_msl_vertex_attribute
  */
  */
 SPVC_PUBLIC_API void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr);
 SPVC_PUBLIC_API void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr);
 
 
+/* Maps to C++ API. */
+typedef struct spvc_msl_shader_input
+{
+	unsigned location;
+	spvc_msl_vertex_format format;
+	SpvBuiltIn builtin;
+	unsigned vecsize;
+} spvc_msl_shader_input;
+
+/*
+ * Initializes the shader input struct.
+ */
+SPVC_PUBLIC_API void spvc_msl_shader_input_init(spvc_msl_shader_input *input);
+
 /* Maps to C++ API. */
 /* Maps to C++ API. */
 typedef struct spvc_msl_resource_binding
 typedef struct spvc_msl_resource_binding
 {
 {
@@ -574,7 +613,11 @@ typedef enum spvc_compiler_option
 	SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX = 43 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX = 43 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D = 44 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D = 44 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO = 45 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO = 45 | SPVC_COMPILER_OPTION_MSL_BIT,
+
+	/* Obsolete. Use MSL_FRAMEBUFFER_FETCH_SUBPASS instead. */
 	SPVC_COMPILER_OPTION_MSL_IOS_FRAMEBUFFER_FETCH_SUBPASS = 46 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_IOS_FRAMEBUFFER_FETCH_SUBPASS = 46 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS = 46 | SPVC_COMPILER_OPTION_MSL_BIT,
+
 	SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
 	SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
@@ -596,6 +639,27 @@ typedef enum spvc_compiler_option
 
 
 	SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES = 60 | SPVC_COMPILER_OPTION_HLSL_BIT,
 	SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES = 60 | SPVC_COMPILER_OPTION_HLSL_BIT,
 
 
+	SPVC_COMPILER_OPTION_MSL_MULTI_PATCH_WORKGROUP = 61 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_BUFFER_INDEX = 62 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_SHADER_INDEX_BUFFER_INDEX = 63 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION = 64 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE = 65 | SPVC_COMPILER_OPTION_MSL_BIT,
+
+	SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT,
+
+	SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING = 67 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT = 68 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT = 69 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID = 70 | SPVC_COMPILER_OPTION_MSL_BIT,
+
+	SPVC_COMPILER_OPTION_HLSL_FLATTEN_MATRIX_VERTEX_INPUT_SEMANTICS = 71 | SPVC_COMPILER_OPTION_HLSL_BIT,
+
+	SPVC_COMPILER_OPTION_MSL_IOS_USE_SIMDGROUP_FUNCTIONS = 72 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_EMULATE_SUBGROUPS = 73 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_FIXED_SUBGROUP_SIZE = 74 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING = 75 | SPVC_COMPILER_OPTION_MSL_BIT,
+	SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE = 76 | SPVC_COMPILER_OPTION_MSL_BIT,
+
 	SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
 	SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
 } spvc_compiler_option;
 } spvc_compiler_option;
 
 
@@ -698,9 +762,15 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler
                                                                    const spvc_msl_vertex_attribute *attrs);
                                                                    const spvc_msl_vertex_attribute *attrs);
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler,
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler,
                                                                    const spvc_msl_resource_binding *binding);
                                                                    const spvc_msl_resource_binding *binding);
+SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler,
+                                                               const spvc_msl_shader_input *input);
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set);
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set);
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address);
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address);
+
+/* Obsolete, use is_shader_input_used. */
 SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location);
 SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location);
+SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_shader_input_used(spvc_compiler compiler, unsigned location);
+
 SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler,
 SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler,
                                                              SpvExecutionModel model,
                                                              SpvExecutionModel model,
                                                              unsigned set,
                                                              unsigned set,
@@ -718,6 +788,9 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler c
 
 
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding);
 SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding);
 
 
+SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_combined_sampler_suffix(spvc_compiler compiler, const char *suffix);
+SPVC_PUBLIC_API const char *spvc_compiler_msl_get_combined_sampler_suffix(spvc_compiler compiler);
+
 /*
 /*
  * Reflect resources.
  * Reflect resources.
  * Maps almost 1:1 to C++ API.
  * Maps almost 1:1 to C++ API.

+ 17 - 4
src/libraries/spirv_cross/spirv_cross_containers.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2019-2020 Hans-Kristian Arntzen
+ * Copyright 2019-2021 Hans-Kristian Arntzen
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_CONTAINERS_HPP
 #ifndef SPIRV_CROSS_CONTAINERS_HPP
 #define SPIRV_CROSS_CONTAINERS_HPP
 #define SPIRV_CROSS_CONTAINERS_HPP
 
 
@@ -63,7 +70,8 @@ public:
 private:
 private:
 #if defined(_MSC_VER) && _MSC_VER < 1900
 #if defined(_MSC_VER) && _MSC_VER < 1900
 	// MSVC 2013 workarounds, sigh ...
 	// MSVC 2013 workarounds, sigh ...
-	union {
+	union
+	{
 		char aligned_char[sizeof(T) * N];
 		char aligned_char[sizeof(T) * N];
 		double dummy_aligner;
 		double dummy_aligner;
 	} u;
 	} u;
@@ -211,6 +219,10 @@ public:
 		this->buffer_size = count;
 		this->buffer_size = count;
 	}
 	}
 
 
+	SmallVector(std::initializer_list<T> init) SPIRV_CROSS_NOEXCEPT : SmallVector(init.begin(), init.end())
+	{
+	}
+
 	SmallVector(SmallVector &&other) SPIRV_CROSS_NOEXCEPT : SmallVector()
 	SmallVector(SmallVector &&other) SPIRV_CROSS_NOEXCEPT : SmallVector()
 	{
 	{
 		*this = std::move(other);
 		*this = std::move(other);
@@ -327,8 +339,9 @@ public:
 			size_t target_capacity = buffer_capacity;
 			size_t target_capacity = buffer_capacity;
 			if (target_capacity == 0)
 			if (target_capacity == 0)
 				target_capacity = 1;
 				target_capacity = 1;
-			if (target_capacity < N)
-				target_capacity = N;
+
+			// Weird parens works around macro issues on Windows if NOMINMAX is not used.
+			target_capacity = (std::max)(target_capacity, N);
 
 
 			// Need to ensure there is a POT value of target capacity which is larger than count,
 			// Need to ensure there is a POT value of target capacity which is larger than count,
 			// otherwise this will overflow.
 			// otherwise this will overflow.

+ 8 - 1
src/libraries/spirv_cross/spirv_cross_error_handling.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_ERROR_HANDLING
 #ifndef SPIRV_CROSS_ERROR_HANDLING
 #define SPIRV_CROSS_ERROR_HANDLING
 #define SPIRV_CROSS_ERROR_HANDLING
 
 

+ 203 - 49
src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2018-2020 Arm Limited
+ * Copyright 2018-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_cross_parsed_ir.hpp"
 #include "spirv_cross_parsed_ir.hpp"
 #include <algorithm>
 #include <algorithm>
 #include <assert.h>
 #include <assert.h>
@@ -74,6 +81,8 @@ ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
 		source = other.source;
 		source = other.source;
 		loop_iteration_depth_hard = other.loop_iteration_depth_hard;
 		loop_iteration_depth_hard = other.loop_iteration_depth_hard;
 		loop_iteration_depth_soft = other.loop_iteration_depth_soft;
 		loop_iteration_depth_soft = other.loop_iteration_depth_soft;
+
+		meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
 	}
 	}
 	return *this;
 	return *this;
 }
 }
@@ -106,6 +115,8 @@ ParsedIR &ParsedIR::operator=(const ParsedIR &other)
 		addressing_model = other.addressing_model;
 		addressing_model = other.addressing_model;
 		memory_model = other.memory_model;
 		memory_model = other.memory_model;
 
 
+		meta_needing_name_fixup = other.meta_needing_name_fixup;
+
 		// Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
 		// Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
 		// Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
 		// Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
 		ids.clear();
 		ids.clear();
@@ -134,42 +145,151 @@ static bool is_alpha(char c)
 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 }
 }
 
 
+static bool is_numeric(char c)
+{
+	return c >= '0' && c <= '9';
+}
+
 static bool is_alphanumeric(char c)
 static bool is_alphanumeric(char c)
 {
 {
-	return is_alpha(c) || (c >= '0' && c <= '9');
+	return is_alpha(c) || is_numeric(c);
 }
 }
 
 
-static string ensure_valid_identifier(const string &name, bool member)
+static bool is_valid_identifier(const string &name)
 {
 {
-	// Functions in glslangValidator are mangled with name(<mangled> stuff.
-	// Normally, we would never see '(' in any legal identifiers, so just strip them out.
-	auto str = name.substr(0, name.find('('));
+	if (name.empty())
+		return true;
+
+	if (is_numeric(name[0]))
+		return false;
 
 
-	for (uint32_t i = 0; i < str.size(); i++)
+	for (auto c : name)
+		if (!is_alphanumeric(c) && c != '_')
+			return false;
+
+	bool saw_underscore = false;
+	// Two underscores in a row is not a valid identifier either.
+	// Technically reserved, but it's easier to treat it as invalid.
+	for (auto c : name)
+	{
+		bool is_underscore = c == '_';
+		if (is_underscore && saw_underscore)
+			return false;
+		saw_underscore = is_underscore;
+	}
+
+	return true;
+}
+
+static bool is_reserved_prefix(const string &name)
+{
+	// Generic reserved identifiers used by the implementation.
+	return name.compare(0, 3, "gl_", 3) == 0 ||
+	       // Ignore this case for now, might rewrite internal code to always use spv prefix.
+	       //name.compare(0, 11, "SPIRV_Cross", 11) == 0 ||
+	       name.compare(0, 3, "spv", 3) == 0;
+}
+
+static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes)
+{
+	if (!allow_reserved_prefixes && is_reserved_prefix(name))
+		return true;
+
+	if (member)
 	{
 	{
-		auto &c = str[i];
+		// Reserved member identifiers come in one form:
+		// _m[0-9]+$.
+		if (name.size() < 3)
+			return false;
+
+		if (name.compare(0, 2, "_m", 2) != 0)
+			return false;
 
 
-		if (member)
+		size_t index = 2;
+		while (index < name.size() && is_numeric(name[index]))
+			index++;
+
+		return index == name.size();
+	}
+	else
+	{
+		// Reserved non-member identifiers come in two forms:
+		// _[0-9]+$, used for temporaries which map directly to a SPIR-V ID.
+		// _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID.
+		if (name.size() < 2)
+			return false;
+
+		if (name[0] != '_' || !is_numeric(name[1]))
+			return false;
+
+		size_t index = 2;
+		while (index < name.size() && is_numeric(name[index]))
+			index++;
+
+		return index == name.size() || (index < name.size() && name[index] == '_');
+	}
+}
+
+bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes)
+{
+	return is_reserved_identifier(str, false, allow_reserved_prefixes);
+}
+
+uint32_t ParsedIR::get_spirv_version() const
+{
+	return spirv[1];
+}
+
+static string make_unreserved_identifier(const string &name)
+{
+	if (is_reserved_prefix(name))
+		return "_RESERVED_IDENTIFIER_FIXUP_" + name;
+	else
+		return "_RESERVED_IDENTIFIER_FIXUP" + name;
+}
+
+void ParsedIR::sanitize_underscores(std::string &str)
+{
+	// Compact adjacent underscores to make it valid.
+	auto dst = str.begin();
+	auto src = dst;
+	bool saw_underscore = false;
+	while (src != str.end())
+	{
+		bool is_underscore = *src == '_';
+		if (saw_underscore && is_underscore)
 		{
 		{
-			// _m<num> variables are reserved by the internal implementation,
-			// otherwise, make sure the name is a valid identifier.
-			if (i == 0)
-				c = is_alpha(c) ? c : '_';
-			else if (i == 2 && str[0] == '_' && str[1] == 'm')
-				c = is_alpha(c) ? c : '_';
-			else
-				c = is_alphanumeric(c) ? c : '_';
+			src++;
 		}
 		}
 		else
 		else
 		{
 		{
-			// _<num> variables are reserved by the internal implementation,
-			// otherwise, make sure the name is a valid identifier.
-			if (i == 0 || (str[0] == '_' && i == 1))
-				c = is_alpha(c) ? c : '_';
-			else
-				c = is_alphanumeric(c) ? c : '_';
+			if (dst != src)
+				*dst = *src;
+			dst++;
+			src++;
+			saw_underscore = is_underscore;
 		}
 		}
 	}
 	}
+	str.erase(dst, str.end());
+}
+
+static string ensure_valid_identifier(const string &name)
+{
+	// Functions in glslangValidator are mangled with name(<mangled> stuff.
+	// Normally, we would never see '(' in any legal identifiers, so just strip them out.
+	auto str = name.substr(0, name.find('('));
+
+	if (str.empty())
+		return str;
+
+	if (is_numeric(str[0]))
+		str[0] = '_';
+
+	for (auto &c : str)
+		if (!is_alphanumeric(c) && c != '_')
+			c = '_';
+
+	ParsedIR::sanitize_underscores(str);
 	return str;
 	return str;
 }
 }
 
 
@@ -195,35 +315,41 @@ const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
 		return empty_string;
 		return empty_string;
 }
 }
 
 
-void ParsedIR::set_name(ID id, const string &name)
+void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes)
 {
 {
-	auto &str = meta[id].decoration.alias;
-	str.clear();
-
-	if (name.empty())
-		return;
+	if (!is_valid_identifier(name))
+		name = ensure_valid_identifier(name);
+	if (is_reserved_identifier(name, member, allow_reserved_prefixes))
+		name = make_unreserved_identifier(name);
+}
 
 
-	// Reserved for temporaries.
-	if (name[0] == '_' && name.size() >= 2 && isdigit(name[1]))
-		return;
+void ParsedIR::fixup_reserved_names()
+{
+	for (uint32_t id : meta_needing_name_fixup)
+	{
+		auto &m = meta[id];
+		sanitize_identifier(m.decoration.alias, false, false);
+		for (auto &memb : m.members)
+			sanitize_identifier(memb.alias, true, false);
+	}
+	meta_needing_name_fixup.clear();
+}
 
 
-	str = ensure_valid_identifier(name, false);
+void ParsedIR::set_name(ID id, const string &name)
+{
+	auto &m = meta[id];
+	m.decoration.alias = name;
+	if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
+		meta_needing_name_fixup.insert(id);
 }
 }
 
 
 void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
 void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
 {
 {
-	meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1));
-
-	auto &str = meta[id].members[index].alias;
-	str.clear();
-	if (name.empty())
-		return;
-
-	// Reserved for unnamed members.
-	if (name[0] == '_' && name.size() >= 3 && name[1] == 'm' && isdigit(name[2]))
-		return;
-
-	str = ensure_valid_identifier(name, true);
+	auto &m = meta[id];
+	m.members.resize(max(meta[id].members.size(), size_t(index) + 1));
+	m.members[index].alias = name;
+	if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
+		meta_needing_name_fixup.insert(id);
 }
 }
 
 
 void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
 void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
@@ -274,6 +400,10 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
 		dec.xfb_stride = argument;
 		dec.xfb_stride = argument;
 		break;
 		break;
 
 
+	case DecorationStream:
+		dec.stream = argument;
+		break;
+
 	case DecorationArrayStride:
 	case DecorationArrayStride:
 		dec.array_stride = argument;
 		dec.array_stride = argument;
 		break;
 		break;
@@ -353,6 +483,10 @@ void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decor
 		dec.xfb_stride = argument;
 		dec.xfb_stride = argument;
 		break;
 		break;
 
 
+	case DecorationStream:
+		dec.stream = argument;
+		break;
+
 	case DecorationSpecId:
 	case DecorationSpecId:
 		dec.spec_id = argument;
 		dec.spec_id = argument;
 		break;
 		break;
@@ -404,6 +538,17 @@ void ParsedIR::mark_used_as_array_length(ID id)
 	}
 	}
 }
 }
 
 
+Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
+{
+	if (type.member_types.empty())
+		return {};
+
+	Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
+	for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
+		all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
+	return all_members_flags;
+}
+
 Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
 Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
 {
 {
 	auto &type = get<SPIRType>(var.basetype);
 	auto &type = get<SPIRType>(var.basetype);
@@ -420,10 +565,7 @@ Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
 	if (type.member_types.empty())
 	if (type.member_types.empty())
 		return base_flags;
 		return base_flags;
 
 
-	Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
-	for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
-		all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
-
+	auto all_members_flags = get_buffer_block_type_flags(type);
 	base_flags.merge_or(all_members_flags);
 	base_flags.merge_or(all_members_flags);
 	return base_flags;
 	return base_flags;
 }
 }
@@ -470,6 +612,8 @@ uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
 		return dec.xfb_buffer;
 		return dec.xfb_buffer;
 	case DecorationXfbStride:
 	case DecorationXfbStride:
 		return dec.xfb_stride;
 		return dec.xfb_stride;
+	case DecorationStream:
+		return dec.stream;
 	case DecorationBinding:
 	case DecorationBinding:
 		return dec.binding;
 		return dec.binding;
 	case DecorationDescriptorSet:
 	case DecorationDescriptorSet:
@@ -542,6 +686,10 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration)
 		dec.xfb_stride = 0;
 		dec.xfb_stride = 0;
 		break;
 		break;
 
 
+	case DecorationStream:
+		dec.stream = 0;
+		break;
+
 	case DecorationBinding:
 	case DecorationBinding:
 		dec.binding = 0;
 		dec.binding = 0;
 		break;
 		break;
@@ -616,6 +764,8 @@ uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration d
 		return dec.xfb_buffer;
 		return dec.xfb_buffer;
 	case DecorationXfbStride:
 	case DecorationXfbStride:
 		return dec.xfb_stride;
 		return dec.xfb_stride;
+	case DecorationStream:
+		return dec.stream;
 	case DecorationSpecId:
 	case DecorationSpecId:
 		return dec.spec_id;
 		return dec.spec_id;
 	case DecorationIndex:
 	case DecorationIndex:
@@ -712,6 +862,10 @@ void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration dec
 		dec.xfb_stride = 0;
 		dec.xfb_stride = 0;
 		break;
 		break;
 
 
+	case DecorationStream:
+		dec.stream = 0;
+		break;
+
 	case DecorationSpecId:
 	case DecorationSpecId:
 		dec.spec_id = 0;
 		dec.spec_id = 0;
 		break;
 		break;

+ 19 - 1
src/libraries/spirv_cross/spirv_cross_parsed_ir.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2018-2020 Arm Limited
+ * Copyright 2018-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_PARSED_IR_HPP
 #ifndef SPIRV_CROSS_PARSED_IR_HPP
 #define SPIRV_CROSS_PARSED_IR_HPP
 #define SPIRV_CROSS_PARSED_IR_HPP
 
 
@@ -139,6 +146,7 @@ public:
 	void mark_used_as_array_length(ID id);
 	void mark_used_as_array_length(ID id);
 	uint32_t increase_bound_by(uint32_t count);
 	uint32_t increase_bound_by(uint32_t count);
 	Bitset get_buffer_block_flags(const SPIRVariable &var) const;
 	Bitset get_buffer_block_flags(const SPIRVariable &var) const;
+	Bitset get_buffer_block_type_flags(const SPIRType &type) const;
 
 
 	void add_typed_id(Types type, ID id);
 	void add_typed_id(Types type, ID id);
 	void remove_typed_id(Types type, ID id);
 	void remove_typed_id(Types type, ID id);
@@ -208,6 +216,14 @@ public:
 
 
 	void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set);
 	void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set);
 
 
+	void fixup_reserved_names();
+
+	static void sanitize_underscores(std::string &str);
+	static void sanitize_identifier(std::string &str, bool member, bool allow_reserved_prefixes);
+	static bool is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes);
+
+	uint32_t get_spirv_version() const;
+
 private:
 private:
 	template <typename T>
 	template <typename T>
 	T &get(uint32_t id)
 	T &get(uint32_t id)
@@ -225,6 +241,8 @@ private:
 	mutable uint32_t loop_iteration_depth_soft = 0;
 	mutable uint32_t loop_iteration_depth_soft = 0;
 	std::string empty_string;
 	std::string empty_string;
 	Bitset cleared_bitset;
 	Bitset cleared_bitset;
+
+	std::unordered_set<uint32_t> meta_needing_name_fixup;
 };
 };
 } // namespace SPIRV_CROSS_NAMESPACE
 } // namespace SPIRV_CROSS_NAMESPACE
 
 

+ 8 - 1
src/libraries/spirv_cross/spirv_cross_util.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_cross_util.hpp"
 #include "spirv_cross_util.hpp"
 #include "spirv_common.hpp"
 #include "spirv_common.hpp"
 
 

+ 8 - 1
src/libraries/spirv_cross/spirv_cross_util.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_UTIL_HPP
 #ifndef SPIRV_CROSS_UTIL_HPP
 #define SPIRV_CROSS_UTIL_HPP
 #define SPIRV_CROSS_UTIL_HPP
 
 

File diff suppressed because it is too large
+ 438 - 135
src/libraries/spirv_cross/spirv_glsl.cpp


+ 182 - 30
src/libraries/spirv_cross/spirv_glsl.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2015-2020 Arm Limited
+ * Copyright 2015-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_GLSL_HPP
 #ifndef SPIRV_CROSS_GLSL_HPP
 #define SPIRV_CROSS_GLSL_HPP
 #define SPIRV_CROSS_GLSL_HPP
 
 
@@ -57,7 +64,8 @@ enum AccessChainFlagBits
 	ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1,
 	ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1,
 	ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2,
 	ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2,
 	ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3,
 	ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3,
-	ACCESS_CHAIN_LITERAL_MSB_FORCE_ID = 1 << 4
+	ACCESS_CHAIN_LITERAL_MSB_FORCE_ID = 1 << 4,
+	ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT = 1 << 5
 };
 };
 typedef uint32_t AccessChainFlags;
 typedef uint32_t AccessChainFlags;
 
 
@@ -120,6 +128,10 @@ public:
 		// which would otherwise be uninitialized will now be initialized to 0 instead.
 		// which would otherwise be uninitialized will now be initialized to 0 instead.
 		bool force_zero_initialized_variables = false;
 		bool force_zero_initialized_variables = false;
 
 
+		// In GLSL, force use of I/O block flattening, similar to
+		// what happens on legacy GLSL targets for blocks and structs.
+		bool force_flattened_io_blocks = false;
+
 		enum Precision
 		enum Precision
 		{
 		{
 			DontCare,
 			DontCare,
@@ -128,14 +140,16 @@ public:
 			Highp
 			Highp
 		};
 		};
 
 
-		struct
+		struct VertexOptions
 		{
 		{
-			// GLSL: In vertex shaders, rewrite [0, w] depth (Vulkan/D3D style) to [-w, w] depth (GL style).
-			// MSL: In vertex shaders, rewrite [-w, w] depth (GL style) to [0, w] depth.
-			// HLSL: In vertex shaders, rewrite [-w, w] depth (GL style) to [0, w] depth.
+			// "Vertex-like shader" here is any shader stage that can write BuiltInPosition.
+
+			// GLSL: In vertex-like shaders, rewrite [0, w] depth (Vulkan/D3D style) to [-w, w] depth (GL style).
+			// MSL: In vertex-like shaders, rewrite [-w, w] depth (GL style) to [0, w] depth.
+			// HLSL: In vertex-like shaders, rewrite [-w, w] depth (GL style) to [0, w] depth.
 			bool fixup_clipspace = false;
 			bool fixup_clipspace = false;
 
 
-			// Inverts gl_Position.y or equivalent.
+			// In vertex-like shaders, inverts gl_Position.y or equivalent.
 			bool flip_vert_y = false;
 			bool flip_vert_y = false;
 
 
 			// GLSL only, for HLSL version of this option, see CompilerHLSL.
 			// GLSL only, for HLSL version of this option, see CompilerHLSL.
@@ -145,7 +159,7 @@ public:
 			bool support_nonzero_base_instance = true;
 			bool support_nonzero_base_instance = true;
 		} vertex;
 		} vertex;
 
 
-		struct
+		struct FragmentOptions
 		{
 		{
 			// Add precision mediump float in ES targets when emitting GLES source.
 			// Add precision mediump float in ES targets when emitting GLES source.
 			// Add precision highp int in ES targets when emitting GLES source.
 			// Add precision highp int in ES targets when emitting GLES source.
@@ -237,6 +251,82 @@ public:
 	bool variable_is_depth_or_compare(VariableID id) const;
 	bool variable_is_depth_or_compare(VariableID id) const;
 
 
 protected:
 protected:
+	struct ShaderSubgroupSupportHelper
+	{
+		// lower enum value = greater priority
+		enum Candidate
+		{
+			KHR_shader_subgroup_ballot,
+			KHR_shader_subgroup_basic,
+			KHR_shader_subgroup_vote,
+			NV_gpu_shader_5,
+			NV_shader_thread_group,
+			NV_shader_thread_shuffle,
+			ARB_shader_ballot,
+			ARB_shader_group_vote,
+			AMD_gcn_shader,
+
+			CandidateCount
+		};
+
+		static const char *get_extension_name(Candidate c);
+		static SmallVector<std::string> get_extra_required_extension_names(Candidate c);
+		static const char *get_extra_required_extension_predicate(Candidate c);
+
+		enum Feature
+		{
+			SubgroupMask = 0,
+			SubgroupSize = 1,
+			SubgroupInvocationID = 2,
+			SubgroupID = 3,
+			NumSubgroups = 4,
+			SubgroupBroadcast_First = 5,
+			SubgroupBallotFindLSB_MSB = 6,
+			SubgroupAll_Any_AllEqualBool = 7,
+			SubgroupAllEqualT = 8,
+			SubgroupElect = 9,
+			SubgroupBarrier = 10,
+			SubgroupMemBarrier = 11,
+			SubgroupBallot = 12,
+			SubgroupInverseBallot_InclBitCount_ExclBitCout = 13,
+			SubgroupBallotBitExtract = 14,
+			SubgroupBallotBitCount = 15,
+
+			FeatureCount
+		};
+
+		using FeatureMask = uint32_t;
+		static_assert(sizeof(FeatureMask) * 8u >= FeatureCount, "Mask type needs more bits.");
+
+		using CandidateVector = SmallVector<Candidate, CandidateCount>;
+		using FeatureVector = SmallVector<Feature>;
+
+		static FeatureVector get_feature_dependencies(Feature feature);
+		static FeatureMask get_feature_dependency_mask(Feature feature);
+		static bool can_feature_be_implemented_without_extensions(Feature feature);
+		static Candidate get_KHR_extension_for_feature(Feature feature);
+
+		struct Result
+		{
+			Result();
+			uint32_t weights[CandidateCount];
+		};
+
+		void request_feature(Feature feature);
+		bool is_feature_requested(Feature feature) const;
+		Result resolve() const;
+
+		static CandidateVector get_candidates_for_feature(Feature ft, const Result &r);
+
+	private:
+		static CandidateVector get_candidates_for_feature(Feature ft);
+		static FeatureMask build_mask(const SmallVector<Feature> &features);
+		FeatureMask feature_mask = 0;
+	};
+
+	// TODO remove this function when all subgroup ops are supported (or make it always return true)
+	static bool is_supported_subgroup_op_in_opengl(spv::Op op);
+
 	void reset();
 	void reset();
 	void emit_function(SPIRFunction &func, const Bitset &return_flags);
 	void emit_function(SPIRFunction &func, const Bitset &return_flags);
 
 
@@ -267,9 +357,11 @@ protected:
 	void build_workgroup_size(SmallVector<std::string> &arguments, const SpecializationConstant &x,
 	void build_workgroup_size(SmallVector<std::string> &arguments, const SpecializationConstant &x,
 	                          const SpecializationConstant &y, const SpecializationConstant &z);
 	                          const SpecializationConstant &y, const SpecializationConstant &z);
 
 
+	void request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature);
+
 	virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
 	virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
-	virtual void emit_texture_op(const Instruction &i);
-	virtual std::string to_texture_op(const Instruction &i, bool *forward,
+	virtual void emit_texture_op(const Instruction &i, bool sparse);
+	virtual std::string to_texture_op(const Instruction &i, bool sparse, bool *forward,
 	                                  SmallVector<uint32_t> &inherited_expressions);
 	                                  SmallVector<uint32_t> &inherited_expressions);
 	virtual void emit_subgroup_op(const Instruction &i);
 	virtual void emit_subgroup_op(const Instruction &i);
 	virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0);
 	virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0);
@@ -284,14 +376,42 @@ protected:
 	virtual void emit_fixup();
 	virtual void emit_fixup();
 	virtual std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0);
 	virtual std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0);
 	virtual std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id);
 	virtual std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id);
-	virtual std::string to_function_name(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather,
-	                                     bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad,
-	                                     bool has_dref, uint32_t lod, uint32_t minlod);
-	virtual std::string to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather,
-	                                     bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref,
-	                                     uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset,
-	                                     uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample,
-	                                     uint32_t minlod, bool *p_forward);
+
+	struct TextureFunctionBaseArguments
+	{
+		// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor.
+		TextureFunctionBaseArguments() = default;
+		VariableID img = 0;
+		const SPIRType *imgtype = nullptr;
+		bool is_fetch = false, is_gather = false, is_proj = false;
+	};
+
+	struct TextureFunctionNameArguments
+	{
+		// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor.
+		TextureFunctionNameArguments() = default;
+		TextureFunctionBaseArguments base;
+		bool has_array_offsets = false, has_offset = false, has_grad = false;
+		bool has_dref = false, is_sparse_feedback = false, has_min_lod = false;
+		uint32_t lod = 0;
+	};
+	virtual std::string to_function_name(const TextureFunctionNameArguments &args);
+
+	struct TextureFunctionArguments
+	{
+		// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor.
+		TextureFunctionArguments() = default;
+		TextureFunctionBaseArguments base;
+		uint32_t coord = 0, coord_components = 0, dref = 0;
+		uint32_t grad_x = 0, grad_y = 0, lod = 0, coffset = 0, offset = 0;
+		uint32_t bias = 0, component = 0, sample = 0, sparse_texel = 0, min_lod = 0;
+		bool nonuniform_expression = false;
+	};
+	virtual std::string to_function_args(const TextureFunctionArguments &args, bool *p_forward);
+
+	void emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id,
+	                                      uint32_t &texel_id);
+	uint32_t get_sparse_feedback_texel_id(uint32_t id) const;
 	virtual void emit_buffer_block(const SPIRVariable &type);
 	virtual void emit_buffer_block(const SPIRVariable &type);
 	virtual void emit_push_constant_block(const SPIRVariable &var);
 	virtual void emit_push_constant_block(const SPIRVariable &var);
 	virtual void emit_uniform(const SPIRVariable &var);
 	virtual void emit_uniform(const SPIRVariable &var);
@@ -441,25 +561,34 @@ protected:
 		bool supports_extensions = false;
 		bool supports_extensions = false;
 		bool supports_empty_struct = false;
 		bool supports_empty_struct = false;
 		bool array_is_value_type = true;
 		bool array_is_value_type = true;
+		bool buffer_offset_array_is_value_type = true;
 		bool comparison_image_samples_scalar = false;
 		bool comparison_image_samples_scalar = false;
 		bool native_pointers = false;
 		bool native_pointers = false;
 		bool support_small_type_sampling_result = false;
 		bool support_small_type_sampling_result = false;
 		bool support_case_fallthrough = true;
 		bool support_case_fallthrough = true;
 		bool use_array_constructor = false;
 		bool use_array_constructor = false;
+		bool needs_row_major_load_workaround = false;
+		bool support_pointer_to_pointer = false;
 	} backend;
 	} backend;
 
 
 	void emit_struct(SPIRType &type);
 	void emit_struct(SPIRType &type);
 	void emit_resources();
 	void emit_resources();
+	void emit_extension_workarounds(spv::ExecutionModel model);
 	void emit_buffer_block_native(const SPIRVariable &var);
 	void emit_buffer_block_native(const SPIRVariable &var);
 	void emit_buffer_reference_block(SPIRType &type, bool forward_declaration);
 	void emit_buffer_reference_block(SPIRType &type, bool forward_declaration);
 	void emit_buffer_block_legacy(const SPIRVariable &var);
 	void emit_buffer_block_legacy(const SPIRVariable &var);
 	void emit_buffer_block_flattened(const SPIRVariable &type);
 	void emit_buffer_block_flattened(const SPIRVariable &type);
+	void fixup_implicit_builtin_block_names();
 	void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
 	void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
 	bool should_force_emit_builtin_block(spv::StorageClass storage);
 	bool should_force_emit_builtin_block(spv::StorageClass storage);
 	void emit_push_constant_block_vulkan(const SPIRVariable &var);
 	void emit_push_constant_block_vulkan(const SPIRVariable &var);
 	void emit_push_constant_block_glsl(const SPIRVariable &var);
 	void emit_push_constant_block_glsl(const SPIRVariable &var);
 	void emit_interface_block(const SPIRVariable &type);
 	void emit_interface_block(const SPIRVariable &type);
 	void emit_flattened_io_block(const SPIRVariable &var, const char *qual);
 	void emit_flattened_io_block(const SPIRVariable &var, const char *qual);
+	void emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual,
+	                                    const SmallVector<uint32_t> &indices);
+	void emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual,
+	                                    const SmallVector<uint32_t> &indices);
 	void emit_block_chain(SPIRBlock &block);
 	void emit_block_chain(SPIRBlock &block);
 	void emit_hoisted_temporaries(SmallVector<std::pair<TypeID, ID>> &temporaries);
 	void emit_hoisted_temporaries(SmallVector<std::pair<TypeID, ID>> &temporaries);
 	std::string constant_value_macro_name(uint32_t id);
 	std::string constant_value_macro_name(uint32_t id);
@@ -522,6 +651,7 @@ protected:
 	void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
 	void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
 	bool expression_is_forwarded(uint32_t id) const;
 	bool expression_is_forwarded(uint32_t id) const;
 	bool expression_suppresses_usage_tracking(uint32_t id) const;
 	bool expression_suppresses_usage_tracking(uint32_t id) const;
+	bool expression_read_implies_multiple_reads(uint32_t id) const;
 	SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
 	SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
 	                        bool suppress_usage_tracking = false);
 	                        bool suppress_usage_tracking = false);
 
 
@@ -531,6 +661,9 @@ protected:
 	std::string access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, AccessChainFlags flags,
 	std::string access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, AccessChainFlags flags,
 	                                  AccessChainMeta *meta);
 	                                  AccessChainMeta *meta);
 
 
+	virtual void prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type,
+	                                                    spv::StorageClass storage, bool &is_packed);
+
 	std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
 	std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type,
 	                         AccessChainMeta *meta = nullptr, bool ptr_chain = false);
 	                         AccessChainMeta *meta = nullptr, bool ptr_chain = false);
 
 
@@ -559,7 +692,7 @@ protected:
 	SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id);
 	SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id);
 	void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
 	void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
 	std::string to_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_expression(uint32_t id, bool register_expression_read = true);
-	std::string to_composite_constructor_expression(uint32_t id);
+	std::string to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset);
 	std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type);
 	std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type);
 	std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true);
@@ -569,15 +702,20 @@ protected:
 	std::string to_pointer_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_pointer_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_enclosed_pointer_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_enclosed_pointer_expression(uint32_t id, bool register_expression_read = true);
 	std::string to_extract_component_expression(uint32_t id, uint32_t index);
 	std::string to_extract_component_expression(uint32_t id, uint32_t index);
+	std::string to_extract_constant_composite_expression(uint32_t result_type, const SPIRConstant &c,
+	                                                     const uint32_t *chain, uint32_t length);
 	std::string enclose_expression(const std::string &expr);
 	std::string enclose_expression(const std::string &expr);
 	std::string dereference_expression(const SPIRType &expression_type, const std::string &expr);
 	std::string dereference_expression(const SPIRType &expression_type, const std::string &expr);
 	std::string address_of_expression(const std::string &expr);
 	std::string address_of_expression(const std::string &expr);
 	void strip_enclosed_expression(std::string &expr);
 	void strip_enclosed_expression(std::string &expr);
 	std::string to_member_name(const SPIRType &type, uint32_t index);
 	std::string to_member_name(const SPIRType &type, uint32_t index);
 	virtual std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain);
 	virtual std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain);
+	std::string to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices);
 	std::string type_to_glsl_constructor(const SPIRType &type);
 	std::string type_to_glsl_constructor(const SPIRType &type);
 	std::string argument_decl(const SPIRFunction::Parameter &arg);
 	std::string argument_decl(const SPIRFunction::Parameter &arg);
 	virtual std::string to_qualifiers_glsl(uint32_t id);
 	virtual std::string to_qualifiers_glsl(uint32_t id);
+	void fixup_io_block_patch_qualifiers(const SPIRVariable &var);
+	void emit_output_variable_initializer(const SPIRVariable &var);
 	const char *to_precision_qualifiers_glsl(uint32_t id);
 	const char *to_precision_qualifiers_glsl(uint32_t id);
 	virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var);
 	virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var);
 	const char *flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags);
 	const char *flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags);
@@ -624,8 +762,7 @@ protected:
 
 
 	void replace_fragment_output(SPIRVariable &var);
 	void replace_fragment_output(SPIRVariable &var);
 	void replace_fragment_outputs();
 	void replace_fragment_outputs();
-	bool check_explicit_lod_allowed(uint32_t lod);
-	std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t id);
+	std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t id);
 
 
 	uint32_t indent = 0;
 	uint32_t indent = 0;
 
 
@@ -635,11 +772,16 @@ protected:
 	std::unordered_set<uint32_t> flushed_phi_variables;
 	std::unordered_set<uint32_t> flushed_phi_variables;
 
 
 	std::unordered_set<uint32_t> flattened_buffer_blocks;
 	std::unordered_set<uint32_t> flattened_buffer_blocks;
-	std::unordered_set<uint32_t> flattened_structs;
+	std::unordered_map<uint32_t, bool> flattened_structs;
+
+	ShaderSubgroupSupportHelper shader_subgroup_supporter;
 
 
-	std::string load_flattened_struct(SPIRVariable &var);
-	std::string to_flattened_struct_member(const SPIRVariable &var, uint32_t index);
-	void store_flattened_struct(SPIRVariable &var, uint32_t value);
+	std::string load_flattened_struct(const std::string &basename, const SPIRType &type);
+	std::string to_flattened_struct_member(const std::string &basename, const SPIRType &type, uint32_t index);
+	void store_flattened_struct(uint32_t lhs_id, uint32_t value);
+	void store_flattened_struct(const std::string &basename, uint32_t rhs, const SPIRType &type,
+	                            const SmallVector<uint32_t> &indices);
+	std::string to_flattened_access_chain_expression(uint32_t id);
 
 
 	// Usage tracking. If a temporary is used more than once, use the temporary instead to
 	// Usage tracking. If a temporary is used more than once, use the temporary instead to
 	// avoid AST explosion when SPIRV is generated with pure SSA and doesn't write stuff to variables.
 	// avoid AST explosion when SPIRV is generated with pure SSA and doesn't write stuff to variables.
@@ -654,6 +796,10 @@ protected:
 	// Currently used by NMin/Max/Clamp implementations.
 	// Currently used by NMin/Max/Clamp implementations.
 	std::unordered_map<uint32_t, uint32_t> extra_sub_expressions;
 	std::unordered_map<uint32_t, uint32_t> extra_sub_expressions;
 
 
+	SmallVector<TypeID> workaround_ubo_load_overload_types;
+	void request_workaround_wrapper_overload(TypeID id);
+	void rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr);
+
 	uint32_t statement_count = 0;
 	uint32_t statement_count = 0;
 
 
 	inline bool is_legacy() const
 	inline bool is_legacy() const
@@ -671,6 +817,12 @@ protected:
 		return !options.es && options.version < 130;
 		return !options.es && options.version < 130;
 	}
 	}
 
 
+	bool requires_transpose_2x2 = false;
+	bool requires_transpose_3x3 = false;
+	bool requires_transpose_4x4 = false;
+	bool ray_tracing_is_khr = false;
+	void ray_tracing_khr_fixup_locations();
+
 	bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure);
 	bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure);
 	void register_call_out_argument(uint32_t id);
 	void register_call_out_argument(uint32_t id);
 	void register_impure_function_call();
 	void register_impure_function_call();
@@ -712,8 +864,6 @@ protected:
 
 
 	virtual void declare_undefined_values();
 	virtual void declare_undefined_values();
 
 
-	static std::string sanitize_underscores(const std::string &str);
-
 	bool can_use_io_location(spv::StorageClass storage, bool block);
 	bool can_use_io_location(spv::StorageClass storage, bool block);
 	const Instruction *get_next_instruction_in_block(const Instruction &instr);
 	const Instruction *get_next_instruction_in_block(const Instruction &instr);
 	static uint32_t mask_relevant_memory_semantics(uint32_t semantics);
 	static uint32_t mask_relevant_memory_semantics(uint32_t semantics);
@@ -726,16 +876,18 @@ protected:
 
 
 	// Builtins in GLSL are always specific signedness, but the SPIR-V can declare them
 	// Builtins in GLSL are always specific signedness, but the SPIR-V can declare them
 	// as either unsigned or signed.
 	// as either unsigned or signed.
-	// Sometimes we will need to automatically perform bitcasts on load and store to make this work.
-	virtual void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type);
-	virtual void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type);
+	// Sometimes we will need to automatically perform casts on load and store to make this work.
+	virtual void cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type);
+	virtual void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type);
 	void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr);
 	void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr);
+	bool unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id);
 	void convert_non_uniform_expression(const SPIRType &type, std::string &expr);
 	void convert_non_uniform_expression(const SPIRType &type, std::string &expr);
 
 
 	void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id);
 	void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id);
 	void disallow_forwarding_in_expression_chain(const SPIRExpression &expr);
 	void disallow_forwarding_in_expression_chain(const SPIRExpression &expr);
 
 
 	bool expression_is_constant_null(uint32_t id) const;
 	bool expression_is_constant_null(uint32_t id) const;
+	bool expression_is_non_value_type_array(uint32_t ptr);
 	virtual void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression);
 	virtual void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression);
 
 
 	uint32_t get_integer_width_for_instruction(const Instruction &instr) const;
 	uint32_t get_integer_width_for_instruction(const Instruction &instr) const;

File diff suppressed because it is too large
+ 267 - 126
src/libraries/spirv_cross/spirv_hlsl.cpp


+ 21 - 3
src/libraries/spirv_cross/spirv_hlsl.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2016-2020 Robert Konrad
+ * Copyright 2016-2021 Robert Konrad
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_HLSL_HPP
 #ifndef SPIRV_HLSL_HPP
 #define SPIRV_HLSL_HPP
 #define SPIRV_HLSL_HPP
 
 
@@ -124,6 +131,12 @@ public:
 		// Uses half/int16_t/uint16_t instead of min16* types.
 		// Uses half/int16_t/uint16_t instead of min16* types.
 		// Also adds support for 16-bit load-store from (RW)ByteAddressBuffer.
 		// Also adds support for 16-bit load-store from (RW)ByteAddressBuffer.
 		bool enable_16bit_types = false;
 		bool enable_16bit_types = false;
+
+		// If matrices are used as IO variables, flatten the attribute declaration to use
+		// TEXCOORD{N,N+1,N+2,...} rather than TEXCOORDN_{0,1,2,3}.
+		// If add_vertex_attribute_remap is used and this feature is used,
+		// the semantic name will be queried once per active location.
+		bool flatten_matrix_vertex_input_semantics = false;
 	};
 	};
 
 
 	explicit CompilerHLSL(std::vector<uint32_t> spirv_)
 	explicit CompilerHLSL(std::vector<uint32_t> spirv_)
@@ -209,7 +222,7 @@ private:
 	void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
 	void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
 	void emit_builtin_inputs_in_struct();
 	void emit_builtin_inputs_in_struct();
 	void emit_builtin_outputs_in_struct();
 	void emit_builtin_outputs_in_struct();
-	void emit_texture_op(const Instruction &i) override;
+	void emit_texture_op(const Instruction &i, bool sparse) override;
 	void emit_instruction(const Instruction &instruction) override;
 	void emit_instruction(const Instruction &instruction) override;
 	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
 	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
 	                  uint32_t count) override;
 	                  uint32_t count) override;
@@ -231,6 +244,7 @@ private:
 	std::string to_resource_binding(const SPIRVariable &var);
 	std::string to_resource_binding(const SPIRVariable &var);
 	std::string to_resource_binding_sampler(const SPIRVariable &var);
 	std::string to_resource_binding_sampler(const SPIRVariable &var);
 	std::string to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t set);
 	std::string to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t set);
+	std::string to_initializer_expression(const SPIRVariable &var) override;
 	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
 	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
 	void emit_access_chain(const Instruction &instruction);
 	void emit_access_chain(const Instruction &instruction);
 	void emit_load(const Instruction &instruction);
 	void emit_load(const Instruction &instruction);
@@ -291,7 +305,8 @@ private:
 	} required_texture_size_variants;
 	} required_texture_size_variants;
 
 
 	void require_texture_query_variant(uint32_t var_id);
 	void require_texture_query_variant(uint32_t var_id);
-	void emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, const char *type_qualifier);
+	void emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav,
+	                                const char *type_qualifier);
 
 
 	enum TextureQueryVariantDim
 	enum TextureQueryVariantDim
 	{
 	{
@@ -351,6 +366,9 @@ private:
 	void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding);
 	void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding);
 
 
 	std::unordered_set<SetBindingPair, InternalHasher> force_uav_buffer_bindings;
 	std::unordered_set<SetBindingPair, InternalHasher> force_uav_buffer_bindings;
+
+	// Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but SV_Coverage is a scalar in HLSL.
+	bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override;
 };
 };
 } // namespace SPIRV_CROSS_NAMESPACE
 } // namespace SPIRV_CROSS_NAMESPACE
 
 

File diff suppressed because it is too large
+ 564 - 140
src/libraries/spirv_cross/spirv_msl.cpp


+ 191 - 41
src/libraries/spirv_cross/spirv_msl.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2016-2020 The Brenwill Workshop Ltd.
+ * Copyright 2016-2021 The Brenwill Workshop Ltd.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_MSL_HPP
 #ifndef SPIRV_CROSS_MSL_HPP
 #define SPIRV_CROSS_MSL_HPP
 #define SPIRV_CROSS_MSL_HPP
 
 
@@ -27,29 +34,44 @@
 namespace SPIRV_CROSS_NAMESPACE
 namespace SPIRV_CROSS_NAMESPACE
 {
 {
 
 
-// Indicates the format of the vertex attribute. Currently limited to specifying
-// if the attribute is an 8-bit unsigned integer, 16-bit unsigned integer, or
+// Indicates the format of a shader input. Currently limited to specifying
+// if the input is an 8-bit unsigned integer, 16-bit unsigned integer, or
 // some other format.
 // some other format.
-enum MSLVertexFormat
+enum MSLShaderInputFormat
 {
 {
-	MSL_VERTEX_FORMAT_OTHER = 0,
-	MSL_VERTEX_FORMAT_UINT8 = 1,
-	MSL_VERTEX_FORMAT_UINT16 = 2,
-	MSL_VERTEX_FORMAT_INT_MAX = 0x7fffffff
+	MSL_SHADER_INPUT_FORMAT_OTHER = 0,
+	MSL_SHADER_INPUT_FORMAT_UINT8 = 1,
+	MSL_SHADER_INPUT_FORMAT_UINT16 = 2,
+	MSL_SHADER_INPUT_FORMAT_ANY16 = 3,
+	MSL_SHADER_INPUT_FORMAT_ANY32 = 4,
+
+	// Deprecated aliases.
+	MSL_VERTEX_FORMAT_OTHER = MSL_SHADER_INPUT_FORMAT_OTHER,
+	MSL_VERTEX_FORMAT_UINT8 = MSL_SHADER_INPUT_FORMAT_UINT8,
+	MSL_VERTEX_FORMAT_UINT16 = MSL_SHADER_INPUT_FORMAT_UINT16,
+
+	MSL_SHADER_INPUT_FORMAT_INT_MAX = 0x7fffffff
 };
 };
 
 
-// Defines MSL characteristics of a vertex attribute at a particular location.
+// Defines MSL characteristics of an input variable at a particular location.
 // After compilation, it is possible to query whether or not this location was used.
 // After compilation, it is possible to query whether or not this location was used.
-struct MSLVertexAttr
+// If vecsize is nonzero, it must be greater than or equal to the vecsize declared in the shader,
+// or behavior is undefined.
+struct MSLShaderInput
 {
 {
 	uint32_t location = 0;
 	uint32_t location = 0;
-	MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER;
+	MSLShaderInputFormat format = MSL_SHADER_INPUT_FORMAT_OTHER;
 	spv::BuiltIn builtin = spv::BuiltInMax;
 	spv::BuiltIn builtin = spv::BuiltInMax;
+	uint32_t vecsize = 0;
 };
 };
 
 
 // Matches the binding index of a MSL resource for a binding within a descriptor set.
 // Matches the binding index of a MSL resource for a binding within a descriptor set.
 // Taken together, the stage, desc_set and binding combine to form a reference to a resource
 // Taken together, the stage, desc_set and binding combine to form a reference to a resource
-// descriptor used in a particular shading stage.
+// descriptor used in a particular shading stage. The count field indicates the number of
+// resources consumed by this binding, if the binding represents an array of resources.
+// If the resource array is a run-time-sized array, which are legal in GLSL or SPIR-V, this value
+// will be used to declare the array size in MSL, which does not support run-time-sized arrays.
+// For resources that are not held in a run-time-sized array, the count field does not need to be populated.
 // If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set,
 // If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set,
 // and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we
 // and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we
 // remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure.
 // remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure.
@@ -60,6 +82,7 @@ struct MSLResourceBinding
 	spv::ExecutionModel stage = spv::ExecutionModelMax;
 	spv::ExecutionModel stage = spv::ExecutionModelMax;
 	uint32_t desc_set = 0;
 	uint32_t desc_set = 0;
 	uint32_t binding = 0;
 	uint32_t binding = 0;
+	uint32_t count = 0;
 	uint32_t msl_buffer = 0;
 	uint32_t msl_buffer = 0;
 	uint32_t msl_texture = 0;
 	uint32_t msl_texture = 0;
 	uint32_t msl_sampler = 0;
 	uint32_t msl_sampler = 0;
@@ -238,6 +261,9 @@ static const uint32_t kArgumentBufferBinding = ~(3u);
 
 
 static const uint32_t kMaxArgumentBuffers = 8;
 static const uint32_t kMaxArgumentBuffers = 8;
 
 
+// The arbitrary maximum for the nesting of array of array copies.
+static const uint32_t kArrayCopyMultidimMax = 6;
+
 // Decompiles SPIR-V to Metal Shading Language
 // Decompiles SPIR-V to Metal Shading Language
 class CompilerMSL : public CompilerGLSL
 class CompilerMSL : public CompilerGLSL
 {
 {
@@ -254,6 +280,8 @@ public:
 		Platform platform = macOS;
 		Platform platform = macOS;
 		uint32_t msl_version = make_msl_version(1, 2);
 		uint32_t msl_version = make_msl_version(1, 2);
 		uint32_t texel_buffer_texture_width = 4096; // Width of 2D Metal textures used as 1D texel buffers
 		uint32_t texel_buffer_texture_width = 4096; // Width of 2D Metal textures used as 1D texel buffers
+		uint32_t r32ui_linear_texture_alignment = 4;
+		uint32_t r32ui_alignment_constant_id = 65535;
 		uint32_t swizzle_buffer_index = 30;
 		uint32_t swizzle_buffer_index = 30;
 		uint32_t indirect_params_buffer_index = 29;
 		uint32_t indirect_params_buffer_index = 29;
 		uint32_t shader_output_buffer_index = 28;
 		uint32_t shader_output_buffer_index = 28;
@@ -262,9 +290,15 @@ public:
 		uint32_t buffer_size_buffer_index = 25;
 		uint32_t buffer_size_buffer_index = 25;
 		uint32_t view_mask_buffer_index = 24;
 		uint32_t view_mask_buffer_index = 24;
 		uint32_t dynamic_offsets_buffer_index = 23;
 		uint32_t dynamic_offsets_buffer_index = 23;
+		uint32_t shader_input_buffer_index = 22;
+		uint32_t shader_index_buffer_index = 21;
 		uint32_t shader_input_wg_index = 0;
 		uint32_t shader_input_wg_index = 0;
 		uint32_t device_index = 0;
 		uint32_t device_index = 0;
 		uint32_t enable_frag_output_mask = 0xffffffff;
 		uint32_t enable_frag_output_mask = 0xffffffff;
+		// Metal doesn't allow setting a fixed sample mask directly in the pipeline.
+		// We can evade this restriction by ANDing the internal sample_mask output
+		// of the shader with the additional fixed sample mask.
+		uint32_t additional_fixed_sample_mask = 0xffffffff;
 		bool enable_point_size_builtin = true;
 		bool enable_point_size_builtin = true;
 		bool enable_frag_depth_builtin = true;
 		bool enable_frag_depth_builtin = true;
 		bool enable_frag_stencil_ref_builtin = true;
 		bool enable_frag_stencil_ref_builtin = true;
@@ -273,6 +307,7 @@ public:
 		bool swizzle_texture_samples = false;
 		bool swizzle_texture_samples = false;
 		bool tess_domain_origin_lower_left = false;
 		bool tess_domain_origin_lower_left = false;
 		bool multiview = false;
 		bool multiview = false;
+		bool multiview_layered_rendering = true;
 		bool view_index_from_device_index = false;
 		bool view_index_from_device_index = false;
 		bool dispatch_base = false;
 		bool dispatch_base = false;
 		bool texture_1D_as_2D = false;
 		bool texture_1D_as_2D = false;
@@ -292,7 +327,7 @@ public:
 		bool ios_support_base_vertex_instance = false;
 		bool ios_support_base_vertex_instance = false;
 
 
 		// Use Metal's native frame-buffer fetch API for subpass inputs.
 		// Use Metal's native frame-buffer fetch API for subpass inputs.
-		bool ios_use_framebuffer_fetch_subpasses = false;
+		bool use_framebuffer_fetch_subpasses = false;
 
 
 		// Enables use of "fma" intrinsic for invariant float math
 		// Enables use of "fma" intrinsic for invariant float math
 		bool invariant_float_math = false;
 		bool invariant_float_math = false;
@@ -320,6 +355,64 @@ public:
 		// can be read in subsequent stages.
 		// can be read in subsequent stages.
 		bool enable_clip_distance_user_varying = true;
 		bool enable_clip_distance_user_varying = true;
 
 
+		// In a tessellation control shader, assume that more than one patch can be processed in a
+		// single workgroup. This requires changes to the way the InvocationId and PrimitiveId
+		// builtins are processed, but should result in more efficient usage of the GPU.
+		bool multi_patch_workgroup = false;
+
+		// If set, a vertex shader will be compiled as part of a tessellation pipeline.
+		// It will be translated as a compute kernel, so it can use the global invocation ID
+		// to index the output buffer.
+		bool vertex_for_tessellation = false;
+
+		// Assume that SubpassData images have multiple layers. Layered input attachments
+		// are addressed relative to the Layer output from the vertex pipeline. This option
+		// has no effect with multiview, since all input attachments are assumed to be layered
+		// and will be addressed using the current ViewIndex.
+		bool arrayed_subpass_input = false;
+
+		// Whether to use SIMD-group or quadgroup functions to implement group nnon-uniform
+		// operations. Some GPUs on iOS do not support the SIMD-group functions, only the
+		// quadgroup functions.
+		bool ios_use_simdgroup_functions = false;
+
+		// If set, the subgroup size will be assumed to be one, and subgroup-related
+		// builtins and operations will be emitted accordingly. This mode is intended to
+		// be used by MoltenVK on hardware/software configurations which do not provide
+		// sufficient support for subgroups.
+		bool emulate_subgroups = false;
+
+		// If nonzero, a fixed subgroup size to assume. Metal, similarly to VK_EXT_subgroup_size_control,
+		// allows the SIMD-group size (aka thread execution width) to vary depending on
+		// register usage and requirements. In certain circumstances--for example, a pipeline
+		// in MoltenVK without VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT--
+		// this is undesirable. This fixes the value of the SubgroupSize builtin, instead of
+		// mapping it to the Metal builtin [[thread_execution_width]]. If the thread
+		// execution width is reduced, the extra invocations will appear to be inactive.
+		// If zero, the SubgroupSize will be allowed to vary, and the builtin will be mapped
+		// to the Metal [[thread_execution_width]] builtin.
+		uint32_t fixed_subgroup_size = 0;
+
+		enum class IndexType
+		{
+			None = 0,
+			UInt16 = 1,
+			UInt32 = 2
+		};
+
+		// The type of index in the index buffer, if present. For a compute shader, Metal
+		// requires specifying the indexing at pipeline creation, rather than at draw time
+		// as with graphics pipelines. This means we must create three different pipelines,
+		// for no indexing, 16-bit indices, and 32-bit indices. Each requires different
+		// handling for the gl_VertexIndex builtin. We may as well, then, create three
+		// different shaders for these three scenarios.
+		IndexType vertex_index_type = IndexType::None;
+
+		// If set, a dummy [[sample_id]] input is added to a fragment shader if none is present.
+		// This will force the shader to run at sample rate, assuming Metal does not optimize
+		// the extra threads away.
+		bool force_sample_rate_shading = false;
+
 		bool is_ios() const
 		bool is_ios() const
 		{
 		{
 			return platform == iOS;
 			return platform == iOS;
@@ -419,11 +512,10 @@ public:
 	explicit CompilerMSL(const ParsedIR &ir);
 	explicit CompilerMSL(const ParsedIR &ir);
 	explicit CompilerMSL(ParsedIR &&ir);
 	explicit CompilerMSL(ParsedIR &&ir);
 
 
-	// attr is a vertex attribute binding used to match
-	// vertex content locations to MSL attributes. If vertex attributes are provided,
-	// is_msl_vertex_attribute_used() will return true after calling ::compile() if
-	// the location was used by the MSL code.
-	void add_msl_vertex_attribute(const MSLVertexAttr &attr);
+	// input is a shader input description used to fix up shader input variables.
+	// If shader inputs are provided, is_msl_shader_input_used() will return true after
+	// calling ::compile() if the location was used by the MSL code.
+	void add_msl_shader_input(const MSLShaderInput &input);
 
 
 	// resource is a resource binding to indicate the MSL buffer,
 	// resource is a resource binding to indicate the MSL buffer,
 	// texture or sampler index to use for a particular SPIR-V description set
 	// texture or sampler index to use for a particular SPIR-V description set
@@ -455,8 +547,15 @@ public:
 	// constant. Opt-in to this behavior here on a per set basis.
 	// constant. Opt-in to this behavior here on a per set basis.
 	void set_argument_buffer_device_address_space(uint32_t desc_set, bool device_storage);
 	void set_argument_buffer_device_address_space(uint32_t desc_set, bool device_storage);
 
 
-	// Query after compilation is done. This allows you to check if a location or set/binding combination was used by the shader.
-	bool is_msl_vertex_attribute_used(uint32_t location);
+	// Query after compilation is done. This allows you to check if an input location was used by the shader.
+	bool is_msl_shader_input_used(uint32_t location);
+
+	// If not using add_msl_shader_input, it's possible
+	// that certain builtin attributes need to be automatically assigned locations.
+	// This is typical for tessellation builtin inputs such as tess levels, gl_Position, etc.
+	// This returns k_unknown_location if the location was explicitly assigned with
+	// add_msl_shader_input or the builtin is not used, otherwise returns N in [[attribute(N)]].
+	uint32_t get_automatic_builtin_input_location(spv::BuiltIn builtin) const;
 
 
 	// NOTE: Only resources which are remapped using add_msl_resource_binding will be reported here.
 	// NOTE: Only resources which are remapped using add_msl_resource_binding will be reported here.
 	// Constexpr samplers are always assumed to be emitted.
 	// Constexpr samplers are always assumed to be emitted.
@@ -475,6 +574,7 @@ public:
 
 
 	// Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers, in which case the
 	// Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers, in which case the
 	// sampler's binding is returned instead. For any other resource type, -1 is returned.
 	// sampler's binding is returned instead. For any other resource type, -1 is returned.
+	// Secondary bindings are also used for the auxillary image atomic buffer.
 	uint32_t get_automatic_msl_resource_binding_secondary(uint32_t id) const;
 	uint32_t get_automatic_msl_resource_binding_secondary(uint32_t id) const;
 
 
 	// Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers for multiplanar images,
 	// Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers for multiplanar images,
@@ -505,6 +605,9 @@ public:
 	// to use for a particular location. The default is 4 if number of components is not overridden.
 	// to use for a particular location. The default is 4 if number of components is not overridden.
 	void set_fragment_output_components(uint32_t location, uint32_t components);
 	void set_fragment_output_components(uint32_t location, uint32_t components);
 
 
+	void set_combined_sampler_suffix(const char *suffix);
+	const char *get_combined_sampler_suffix() const;
+
 protected:
 protected:
 	// An enum of SPIR-V functions that are implemented in additional
 	// An enum of SPIR-V functions that are implemented in additional
 	// source code that is added to the shader if necessary.
 	// source code that is added to the shader if necessary.
@@ -544,12 +647,20 @@ protected:
 		SPVFuncImplTextureSwizzle,
 		SPVFuncImplTextureSwizzle,
 		SPVFuncImplGatherSwizzle,
 		SPVFuncImplGatherSwizzle,
 		SPVFuncImplGatherCompareSwizzle,
 		SPVFuncImplGatherCompareSwizzle,
+		SPVFuncImplSubgroupBroadcast,
+		SPVFuncImplSubgroupBroadcastFirst,
 		SPVFuncImplSubgroupBallot,
 		SPVFuncImplSubgroupBallot,
 		SPVFuncImplSubgroupBallotBitExtract,
 		SPVFuncImplSubgroupBallotBitExtract,
 		SPVFuncImplSubgroupBallotFindLSB,
 		SPVFuncImplSubgroupBallotFindLSB,
 		SPVFuncImplSubgroupBallotFindMSB,
 		SPVFuncImplSubgroupBallotFindMSB,
 		SPVFuncImplSubgroupBallotBitCount,
 		SPVFuncImplSubgroupBallotBitCount,
 		SPVFuncImplSubgroupAllEqual,
 		SPVFuncImplSubgroupAllEqual,
+		SPVFuncImplSubgroupShuffle,
+		SPVFuncImplSubgroupShuffleXor,
+		SPVFuncImplSubgroupShuffleUp,
+		SPVFuncImplSubgroupShuffleDown,
+		SPVFuncImplQuadBroadcast,
+		SPVFuncImplQuadSwap,
 		SPVFuncImplReflectScalar,
 		SPVFuncImplReflectScalar,
 		SPVFuncImplRefractScalar,
 		SPVFuncImplRefractScalar,
 		SPVFuncImplFaceForwardScalar,
 		SPVFuncImplFaceForwardScalar,
@@ -573,13 +684,11 @@ protected:
 		SPVFuncImplConvertYCbCrBT601,
 		SPVFuncImplConvertYCbCrBT601,
 		SPVFuncImplConvertYCbCrBT2020,
 		SPVFuncImplConvertYCbCrBT2020,
 		SPVFuncImplDynamicImageSampler,
 		SPVFuncImplDynamicImageSampler,
-
-		SPVFuncImplArrayCopyMultidimMax = 6
 	};
 	};
 
 
 	// If the underlying resource has been used for comparison then duplicate loads of that resource must be too
 	// If the underlying resource has been used for comparison then duplicate loads of that resource must be too
 	// Use Metal's native frame-buffer fetch API for subpass inputs.
 	// Use Metal's native frame-buffer fetch API for subpass inputs.
-	void emit_texture_op(const Instruction &i) override;
+	void emit_texture_op(const Instruction &i, bool sparse) override;
 	void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
 	void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
 	void emit_instruction(const Instruction &instr) override;
 	void emit_instruction(const Instruction &instr) override;
 	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
 	void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
@@ -590,7 +699,7 @@ protected:
 	void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override;
 	void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override;
 	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
 	void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
 	void emit_subgroup_op(const Instruction &i) override;
 	void emit_subgroup_op(const Instruction &i) override;
-	std::string to_texture_op(const Instruction &i, bool *forward,
+	std::string to_texture_op(const Instruction &i, bool sparse, bool *forward,
 	                          SmallVector<uint32_t> &inherited_expressions) override;
 	                          SmallVector<uint32_t> &inherited_expressions) override;
 	void emit_fixup() override;
 	void emit_fixup() override;
 	std::string to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
 	std::string to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
@@ -610,17 +719,12 @@ protected:
 	std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override;
 	std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override;
 
 
 	std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override;
 	std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override;
-	std::string sampler_type(const SPIRType &type);
+	std::string sampler_type(const SPIRType &type, uint32_t id);
 	std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override;
 	std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override;
 	std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override;
 	std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override;
 	std::string to_name(uint32_t id, bool allow_alias = true) const override;
 	std::string to_name(uint32_t id, bool allow_alias = true) const override;
-	std::string to_function_name(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
-	                             bool has_array_offsets, bool has_offset, bool has_grad, bool has_dref, uint32_t lod,
-	                             uint32_t minlod) override;
-	std::string to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
-	                             uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x,
-	                             uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias,
-	                             uint32_t comp, uint32_t sample, uint32_t minlod, bool *p_forward) override;
+	std::string to_function_name(const TextureFunctionNameArguments &args) override;
+	std::string to_function_args(const TextureFunctionArguments &args, bool *p_forward) override;
 	std::string to_initializer_expression(const SPIRVariable &var) override;
 	std::string to_initializer_expression(const SPIRVariable &var) override;
 	std::string to_zero_initialized_expression(uint32_t type_id) override;
 	std::string to_zero_initialized_expression(uint32_t type_id) override;
 
 
@@ -639,6 +743,12 @@ protected:
 	void declare_undefined_values() override;
 	void declare_undefined_values() override;
 	void declare_constant_arrays();
 	void declare_constant_arrays();
 
 
+	void replace_illegal_entry_point_names();
+	void sync_entry_point_aliases_and_names();
+
+	static const std::unordered_set<std::string> &get_reserved_keyword_set();
+	static const std::unordered_set<std::string> &get_illegal_func_names();
+
 	// Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries
 	// Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries
 	void declare_complex_constant_arrays();
 	void declare_complex_constant_arrays();
 
 
@@ -689,9 +799,9 @@ protected:
 
 
 	void fix_up_interface_member_indices(spv::StorageClass storage, uint32_t ib_type_id);
 	void fix_up_interface_member_indices(spv::StorageClass storage, uint32_t ib_type_id);
 
 
-	void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage);
+	void mark_location_as_used_by_shader(uint32_t location, const SPIRType &type, spv::StorageClass storage);
 	uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin);
 	uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin);
-	uint32_t ensure_correct_attribute_type(uint32_t type_id, uint32_t location, uint32_t num_components = 0);
+	uint32_t ensure_correct_input_type(uint32_t type_id, uint32_t location, uint32_t num_components = 0);
 
 
 	void emit_custom_templates();
 	void emit_custom_templates();
 	void emit_custom_functions();
 	void emit_custom_functions();
@@ -699,6 +809,7 @@ protected:
 	void emit_specialization_constants_and_structs();
 	void emit_specialization_constants_and_structs();
 	void emit_interface_block(uint32_t ib_var_id);
 	void emit_interface_block(uint32_t ib_var_id);
 	bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs);
 	bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs);
+	uint32_t get_resource_array_size(uint32_t id) const;
 
 
 	void fix_up_shader_inputs_outputs();
 	void fix_up_shader_inputs_outputs();
 
 
@@ -713,6 +824,8 @@ protected:
 	std::string to_sampler_expression(uint32_t id);
 	std::string to_sampler_expression(uint32_t id);
 	std::string to_swizzle_expression(uint32_t id);
 	std::string to_swizzle_expression(uint32_t id);
 	std::string to_buffer_size_expression(uint32_t id);
 	std::string to_buffer_size_expression(uint32_t id);
+	bool is_sample_rate() const;
+	bool is_direct_input_builtin(spv::BuiltIn builtin);
 	std::string builtin_qualifier(spv::BuiltIn builtin);
 	std::string builtin_qualifier(spv::BuiltIn builtin);
 	std::string builtin_type_decl(spv::BuiltIn builtin, uint32_t id = 0);
 	std::string builtin_type_decl(spv::BuiltIn builtin, uint32_t id = 0);
 	std::string built_in_func_arg(spv::BuiltIn builtin, bool prefix_comma);
 	std::string built_in_func_arg(spv::BuiltIn builtin, bool prefix_comma);
@@ -720,7 +833,11 @@ protected:
 	std::string argument_decl(const SPIRFunction::Parameter &arg);
 	std::string argument_decl(const SPIRFunction::Parameter &arg);
 	std::string round_fp_tex_coords(std::string tex_coords, bool coord_is_fp);
 	std::string round_fp_tex_coords(std::string tex_coords, bool coord_is_fp);
 	uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype, uint32_t plane = 0);
 	uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype, uint32_t plane = 0);
-	uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index, uint32_t *comp = nullptr);
+	uint32_t get_member_location(uint32_t type_id, uint32_t index, uint32_t *comp = nullptr) const;
+	uint32_t get_or_allocate_builtin_input_member_location(spv::BuiltIn builtin,
+	                                                       uint32_t type_id, uint32_t index, uint32_t *comp = nullptr);
+
+	uint32_t get_physical_tess_level_array_size(spv::BuiltIn builtin) const;
 
 
 	// MSL packing rules. These compute the effective packing rules as observed by the MSL compiler in the MSL output.
 	// MSL packing rules. These compute the effective packing rules as observed by the MSL compiler in the MSL output.
 	// These values can change depending on various extended decorations which control packing rules.
 	// These values can change depending on various extended decorations which control packing rules.
@@ -735,7 +852,13 @@ protected:
 	uint32_t get_declared_struct_member_matrix_stride_msl(const SPIRType &struct_type, uint32_t index) const;
 	uint32_t get_declared_struct_member_matrix_stride_msl(const SPIRType &struct_type, uint32_t index) const;
 	uint32_t get_declared_struct_member_alignment_msl(const SPIRType &struct_type, uint32_t index) const;
 	uint32_t get_declared_struct_member_alignment_msl(const SPIRType &struct_type, uint32_t index) const;
 
 
+	uint32_t get_declared_input_size_msl(const SPIRType &struct_type, uint32_t index) const;
+	uint32_t get_declared_input_array_stride_msl(const SPIRType &struct_type, uint32_t index) const;
+	uint32_t get_declared_input_matrix_stride_msl(const SPIRType &struct_type, uint32_t index) const;
+	uint32_t get_declared_input_alignment_msl(const SPIRType &struct_type, uint32_t index) const;
+
 	const SPIRType &get_physical_member_type(const SPIRType &struct_type, uint32_t index) const;
 	const SPIRType &get_physical_member_type(const SPIRType &struct_type, uint32_t index) const;
+	SPIRType get_presumed_input_type(const SPIRType &struct_type, uint32_t index) const;
 
 
 	uint32_t get_declared_struct_size_msl(const SPIRType &struct_type, bool ignore_alignment = false,
 	uint32_t get_declared_struct_size_msl(const SPIRType &struct_type, bool ignore_alignment = false,
 	                                      bool ignore_padding = false) const;
 	                                      bool ignore_padding = false) const;
@@ -754,6 +877,8 @@ protected:
 	SPIRType &get_patch_stage_in_struct_type();
 	SPIRType &get_patch_stage_in_struct_type();
 	SPIRType &get_patch_stage_out_struct_type();
 	SPIRType &get_patch_stage_out_struct_type();
 	std::string get_tess_factor_struct_name();
 	std::string get_tess_factor_struct_name();
+	SPIRType &get_uint_type();
+	uint32_t get_uint_type_id();
 	void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, uint32_t mem_order_1,
 	void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, uint32_t mem_order_1,
 	                         uint32_t mem_order_2, bool has_mem_order_2, uint32_t op0, uint32_t op1 = 0,
 	                         uint32_t mem_order_2, bool has_mem_order_2, uint32_t op0, uint32_t op1 = 0,
 	                         bool op1_is_pointer = false, bool op1_is_literal = false, uint32_t op2 = 0);
 	                         bool op1_is_pointer = false, bool op1_is_literal = false, uint32_t op2 = 0);
@@ -768,6 +893,7 @@ protected:
 	void emit_entry_point_declarations() override;
 	void emit_entry_point_declarations() override;
 	uint32_t builtin_frag_coord_id = 0;
 	uint32_t builtin_frag_coord_id = 0;
 	uint32_t builtin_sample_id_id = 0;
 	uint32_t builtin_sample_id_id = 0;
+	uint32_t builtin_sample_mask_id = 0;
 	uint32_t builtin_vertex_idx_id = 0;
 	uint32_t builtin_vertex_idx_id = 0;
 	uint32_t builtin_base_vertex_id = 0;
 	uint32_t builtin_base_vertex_id = 0;
 	uint32_t builtin_instance_idx_id = 0;
 	uint32_t builtin_instance_idx_id = 0;
@@ -779,17 +905,26 @@ protected:
 	uint32_t builtin_subgroup_invocation_id_id = 0;
 	uint32_t builtin_subgroup_invocation_id_id = 0;
 	uint32_t builtin_subgroup_size_id = 0;
 	uint32_t builtin_subgroup_size_id = 0;
 	uint32_t builtin_dispatch_base_id = 0;
 	uint32_t builtin_dispatch_base_id = 0;
+	uint32_t builtin_stage_input_size_id = 0;
+	uint32_t builtin_local_invocation_index_id = 0;
+	uint32_t builtin_workgroup_size_id = 0;
 	uint32_t swizzle_buffer_id = 0;
 	uint32_t swizzle_buffer_id = 0;
 	uint32_t buffer_size_buffer_id = 0;
 	uint32_t buffer_size_buffer_id = 0;
 	uint32_t view_mask_buffer_id = 0;
 	uint32_t view_mask_buffer_id = 0;
 	uint32_t dynamic_offsets_buffer_id = 0;
 	uint32_t dynamic_offsets_buffer_id = 0;
+	uint32_t uint_type_id = 0;
+
+	bool does_shader_write_sample_mask = false;
 
 
-	void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
-	void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override;
+	void cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
+	void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override;
 	void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression) override;
 	void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression) override;
 
 
 	void analyze_sampled_image_usage();
 	void analyze_sampled_image_usage();
 
 
+	void prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, spv::StorageClass storage,
+	                                            bool &is_packed) override;
+	void fix_up_interpolant_access_chain(const uint32_t *ops, uint32_t length);
 	bool emit_tessellation_access_chain(const uint32_t *ops, uint32_t length);
 	bool emit_tessellation_access_chain(const uint32_t *ops, uint32_t length);
 	bool emit_tessellation_io_load(uint32_t result_type, uint32_t id, uint32_t ptr);
 	bool emit_tessellation_io_load(uint32_t result_type, uint32_t id, uint32_t ptr);
 	bool is_out_of_bounds_tessellation_level(uint32_t id_lhs);
 	bool is_out_of_bounds_tessellation_level(uint32_t id_lhs);
@@ -802,15 +937,18 @@ protected:
 
 
 	Options msl_options;
 	Options msl_options;
 	std::set<SPVFuncImpl> spv_function_implementations;
 	std::set<SPVFuncImpl> spv_function_implementations;
-	std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_location;
-	std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_builtin;
-	std::unordered_set<uint32_t> vtx_attrs_in_use;
+	// Must be ordered to ensure declarations are in a specific order.
+	std::map<uint32_t, MSLShaderInput> inputs_by_location;
+	std::unordered_map<uint32_t, MSLShaderInput> inputs_by_builtin;
+	std::unordered_set<uint32_t> location_inputs_in_use;
 	std::unordered_map<uint32_t, uint32_t> fragment_output_components;
 	std::unordered_map<uint32_t, uint32_t> fragment_output_components;
+	std::unordered_map<uint32_t, uint32_t> builtin_to_automatic_input_location;
 	std::set<std::string> pragma_lines;
 	std::set<std::string> pragma_lines;
 	std::set<std::string> typedef_lines;
 	std::set<std::string> typedef_lines;
 	SmallVector<uint32_t> vars_needing_early_declaration;
 	SmallVector<uint32_t> vars_needing_early_declaration;
 
 
 	std::unordered_map<StageSetBinding, std::pair<MSLResourceBinding, bool>, InternalHasher> resource_bindings;
 	std::unordered_map<StageSetBinding, std::pair<MSLResourceBinding, bool>, InternalHasher> resource_bindings;
+	uint32_t type_to_location_count(const SPIRType &type) const;
 
 
 	uint32_t next_metal_resource_index_buffer = 0;
 	uint32_t next_metal_resource_index_buffer = 0;
 	uint32_t next_metal_resource_index_texture = 0;
 	uint32_t next_metal_resource_index_texture = 0;
@@ -847,6 +985,8 @@ protected:
 	bool used_swizzle_buffer = false;
 	bool used_swizzle_buffer = false;
 	bool added_builtin_tess_level = false;
 	bool added_builtin_tess_level = false;
 	bool needs_subgroup_invocation_id = false;
 	bool needs_subgroup_invocation_id = false;
+	bool needs_subgroup_size = false;
+	bool needs_sample_id = false;
 	std::string qual_pos_var_name;
 	std::string qual_pos_var_name;
 	std::string stage_in_var_name = "in";
 	std::string stage_in_var_name = "in";
 	std::string stage_out_var_name = "out";
 	std::string stage_out_var_name = "out";
@@ -857,9 +997,11 @@ protected:
 	std::string buffer_size_name_suffix = "BufferSize";
 	std::string buffer_size_name_suffix = "BufferSize";
 	std::string plane_name_suffix = "Plane";
 	std::string plane_name_suffix = "Plane";
 	std::string input_wg_var_name = "gl_in";
 	std::string input_wg_var_name = "gl_in";
+	std::string input_buffer_var_name = "spvIn";
 	std::string output_buffer_var_name = "spvOut";
 	std::string output_buffer_var_name = "spvOut";
 	std::string patch_output_buffer_var_name = "spvPatchOut";
 	std::string patch_output_buffer_var_name = "spvPatchOut";
 	std::string tess_factor_buffer_var_name = "spvTessLevel";
 	std::string tess_factor_buffer_var_name = "spvTessLevel";
+	std::string index_buffer_var_name = "spvIndices";
 	spv::Op previous_instruction_opcode = spv::OpNop;
 	spv::Op previous_instruction_opcode = spv::OpNop;
 
 
 	// Must be ordered since declaration is in a specific order.
 	// Must be ordered since declaration is in a specific order.
@@ -870,6 +1012,7 @@ protected:
 	std::unordered_set<uint32_t> buffers_requiring_array_length;
 	std::unordered_set<uint32_t> buffers_requiring_array_length;
 	SmallVector<uint32_t> buffer_arrays;
 	SmallVector<uint32_t> buffer_arrays;
 	std::unordered_set<uint32_t> atomic_image_vars; // Emulate texture2D atomic operations
 	std::unordered_set<uint32_t> atomic_image_vars; // Emulate texture2D atomic operations
+	std::unordered_set<uint32_t> pull_model_inputs;
 
 
 	// Must be ordered since array is in a specific order.
 	// Must be ordered since array is in a specific order.
 	std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset;
 	std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset;
@@ -886,7 +1029,9 @@ protected:
 	bool descriptor_set_is_argument_buffer(uint32_t desc_set) const;
 	bool descriptor_set_is_argument_buffer(uint32_t desc_set) const;
 
 
 	uint32_t get_target_components_for_fragment_location(uint32_t location) const;
 	uint32_t get_target_components_for_fragment_location(uint32_t location) const;
-	uint32_t build_extended_vector_type(uint32_t type_id, uint32_t components);
+	uint32_t build_extended_vector_type(uint32_t type_id, uint32_t components,
+	                                    SPIRType::BaseType basetype = SPIRType::Unknown);
+	uint32_t build_msl_interpolant_type(uint32_t type_id, bool is_noperspective);
 
 
 	bool suppress_missing_prototypes = false;
 	bool suppress_missing_prototypes = false;
 
 
@@ -895,6 +1040,9 @@ protected:
 	void activate_argument_buffer_resources();
 	void activate_argument_buffer_resources();
 
 
 	bool type_is_msl_framebuffer_fetch(const SPIRType &type) const;
 	bool type_is_msl_framebuffer_fetch(const SPIRType &type) const;
+	bool type_is_pointer(const SPIRType &type) const;
+	bool type_is_pointer_to_pointer(const SPIRType &type) const;
+	bool is_supported_argument_buffer_type(const SPIRType &type) const;
 
 
 	// OpcodeHandler that handles several MSL preprocessing operations.
 	// OpcodeHandler that handles several MSL preprocessing operations.
 	struct OpCodePreprocessor : OpcodeHandler
 	struct OpCodePreprocessor : OpcodeHandler
@@ -915,6 +1063,8 @@ protected:
 		bool uses_atomics = false;
 		bool uses_atomics = false;
 		bool uses_resource_write = false;
 		bool uses_resource_write = false;
 		bool needs_subgroup_invocation_id = false;
 		bool needs_subgroup_invocation_id = false;
+		bool needs_subgroup_size = false;
+		bool needs_sample_id = false;
 	};
 	};
 
 
 	// OpcodeHandler that scans for uses of sampled images
 	// OpcodeHandler that scans for uses of sampled images

+ 35 - 5
src/libraries/spirv_cross/spirv_parser.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2018-2020 Arm Limited
+ * Copyright 2018-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_parser.hpp"
 #include "spirv_parser.hpp"
 #include <assert.h>
 #include <assert.h>
 
 
@@ -133,6 +140,8 @@ void Parser::parse()
 		SPIRV_CROSS_THROW("Function was not terminated.");
 		SPIRV_CROSS_THROW("Function was not terminated.");
 	if (current_block)
 	if (current_block)
 		SPIRV_CROSS_THROW("Block was not terminated.");
 		SPIRV_CROSS_THROW("Block was not terminated.");
+	if (ir.default_entry_point == 0)
+		SPIRV_CROSS_THROW("There is no entry point in the SPIR-V module.");
 }
 }
 
 
 const uint32_t *Parser::stream(const Instruction &instr) const
 const uint32_t *Parser::stream(const Instruction &instr) const
@@ -623,10 +632,15 @@ void Parser::parse(const Instruction &instruction)
 	{
 	{
 		uint32_t id = ops[0];
 		uint32_t id = ops[0];
 
 
-		auto &base = get<SPIRType>(ops[2]);
+		// Very rarely, we might receive a FunctionPrototype here.
+		// We won't be able to compile it, but we shouldn't crash when parsing.
+		// We should be able to reflect.
+		auto *base = maybe_get<SPIRType>(ops[2]);
 		auto &ptrbase = set<SPIRType>(id);
 		auto &ptrbase = set<SPIRType>(id);
 
 
-		ptrbase = base;
+		if (base)
+			ptrbase = *base;
+
 		ptrbase.pointer = true;
 		ptrbase.pointer = true;
 		ptrbase.pointer_depth++;
 		ptrbase.pointer_depth++;
 		ptrbase.storage = static_cast<StorageClass>(ops[1]);
 		ptrbase.storage = static_cast<StorageClass>(ops[1]);
@@ -634,7 +648,7 @@ void Parser::parse(const Instruction &instruction)
 		if (ptrbase.storage == StorageClassAtomicCounter)
 		if (ptrbase.storage == StorageClassAtomicCounter)
 			ptrbase.basetype = SPIRType::AtomicCounter;
 			ptrbase.basetype = SPIRType::AtomicCounter;
 
 
-		if (base.forward_pointer)
+		if (base && base->forward_pointer)
 			forward_pointer_fixups.push_back({ id, ops[2] });
 			forward_pointer_fixups.push_back({ id, ops[2] });
 
 
 		ptrbase.parent_type = ops[2];
 		ptrbase.parent_type = ops[2];
@@ -715,7 +729,7 @@ void Parser::parse(const Instruction &instruction)
 		break;
 		break;
 	}
 	}
 
 
-	case OpTypeRayQueryProvisionalKHR:
+	case OpTypeRayQueryKHR:
 	{
 	{
 		uint32_t id = ops[0];
 		uint32_t id = ops[0];
 		auto &type = set<SPIRType>(id);
 		auto &type = set<SPIRType>(id);
@@ -980,6 +994,22 @@ void Parser::parse(const Instruction &instruction)
 		break;
 		break;
 	}
 	}
 
 
+	case OpTerminateRayKHR:
+		// NV variant is not a terminator.
+		if (!current_block)
+			SPIRV_CROSS_THROW("Trying to end a non-existing block.");
+		current_block->terminator = SPIRBlock::TerminateRay;
+		current_block = nullptr;
+		break;
+
+	case OpIgnoreIntersectionKHR:
+		// NV variant is not a terminator.
+		if (!current_block)
+			SPIRV_CROSS_THROW("Trying to end a non-existing block.");
+		current_block->terminator = SPIRBlock::IgnoreIntersection;
+		current_block = nullptr;
+		break;
+
 	case OpReturn:
 	case OpReturn:
 	{
 	{
 		if (!current_block)
 		if (!current_block)

+ 8 - 1
src/libraries/spirv_cross/spirv_parser.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2018-2020 Arm Limited
+ * Copyright 2018-2021 Arm Limited
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_PARSER_HPP
 #ifndef SPIRV_CROSS_PARSER_HPP
 #define SPIRV_CROSS_PARSER_HPP
 #define SPIRV_CROSS_PARSER_HPP
 
 

+ 11 - 8
src/libraries/spirv_cross/spirv_reflect.cpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2018-2020 Bradley Austin Davis
+ * Copyright 2018-2021 Bradley Austin Davis
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #include "spirv_reflect.hpp"
 #include "spirv_reflect.hpp"
 #include "spirv_glsl.hpp"
 #include "spirv_glsl.hpp"
 #include <iomanip>
 #include <iomanip>
@@ -267,7 +274,6 @@ string CompilerReflection::compile()
 	json_stream = std::make_shared<simple_json::Stream>();
 	json_stream = std::make_shared<simple_json::Stream>();
 	json_stream->set_current_locale_radix_character(current_locale_radix_character);
 	json_stream->set_current_locale_radix_character(current_locale_radix_character);
 	json_stream->begin_json_object();
 	json_stream->begin_json_object();
-	fixup_type_alias();
 	reorder_type_alias();
 	reorder_type_alias();
 	emit_entry_points();
 	emit_entry_points();
 	emit_types();
 	emit_types();
@@ -305,8 +311,8 @@ void CompilerReflection::emit_types()
 		else if (type_is_reference(type))
 		else if (type_is_reference(type))
 		{
 		{
 			if (!naturally_emit_type(this->get<SPIRType>(type.parent_type)) &&
 			if (!naturally_emit_type(this->get<SPIRType>(type.parent_type)) &&
-			    find(physical_pointee_types.begin(), physical_pointee_types.end(),
-			         type.parent_type) == physical_pointee_types.end())
+			    find(physical_pointee_types.begin(), physical_pointee_types.end(), type.parent_type) ==
+			        physical_pointee_types.end())
 			{
 			{
 				physical_pointee_types.push_back(type.parent_type);
 				physical_pointee_types.push_back(type.parent_type);
 			}
 			}
@@ -327,9 +333,6 @@ void CompilerReflection::emit_type(uint32_t type_id, bool &emitted_open_tag)
 	auto &type = get<SPIRType>(type_id);
 	auto &type = get<SPIRType>(type_id);
 	auto name = type_to_glsl(type);
 	auto name = type_to_glsl(type);
 
 
-	if (type.type_alias != TypeID(0))
-		return;
-
 	if (!emitted_open_tag)
 	if (!emitted_open_tag)
 	{
 	{
 		json_stream->emit_json_key_object("types");
 		json_stream->emit_json_key_object("types");
@@ -651,7 +654,7 @@ void CompilerReflection::emit_specialization_constants()
 		return;
 		return;
 
 
 	json_stream->emit_json_key_array("specialization_constants");
 	json_stream->emit_json_key_array("specialization_constants");
-	for (const auto spec_const : specialization_constants)
+	for (const auto &spec_const : specialization_constants)
 	{
 	{
 		auto &c = get<SPIRConstant>(spec_const.id);
 		auto &c = get<SPIRConstant>(spec_const.id);
 		auto type = get<SPIRType>(c.constant_type);
 		auto type = get<SPIRType>(c.constant_type);

+ 8 - 1
src/libraries/spirv_cross/spirv_reflect.hpp

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2018-2020 Bradley Austin Davis
+ * Copyright 2018-2021 Bradley Austin Davis
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,13 @@
  * limitations under the License.
  * limitations under the License.
  */
  */
 
 
+/*
+ * At your option, you may choose to accept this material under either:
+ *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
+ *  2. The MIT License, found at <http://opensource.org/licenses/MIT>.
+ * SPDX-License-Identifier: Apache-2.0 OR MIT.
+ */
+
 #ifndef SPIRV_CROSS_REFLECT_HPP
 #ifndef SPIRV_CROSS_REFLECT_HPP
 #define SPIRV_CROSS_REFLECT_HPP
 #define SPIRV_CROSS_REFLECT_HPP
 
 

Some files were not shown because too many files changed in this diff