diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/glsl.meta.slang | 24 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 85 | ||||
| -rw-r--r-- | source/slang/slang-capabilities.capdef | 12 | ||||
| -rw-r--r-- | source/slang/slang-capability.cpp | 131 | ||||
| -rw-r--r-- | source/slang/slang-capability.h | 32 | ||||
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 335 | ||||
| -rw-r--r-- | source/slang/slang-check-stmt.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 27 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang.natvis | 3 |
11 files changed, 446 insertions, 213 deletions
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang index 782c09bb9..eeaf2a58c 100644 --- a/source/slang/glsl.meta.slang +++ b/source/slang/glsl.meta.slang @@ -4778,9 +4778,9 @@ public property uint3 gl_LaunchSizeEXT // casting conflict due to the spirv implementation of PrimitiveIndex(). internal in uint __gl_PrimitiveID : SV_PrimitiveID; -public property int gl_PrimitiveID +public property int gl_PrimitiveID { - [require(cuda_glsl_hlsl_spirv)] + [require(cuda_glsl_hlsl_spirv, raytracing_allstages)] get { __stage_switch @@ -4796,9 +4796,9 @@ public property int gl_PrimitiveID } } -public property int gl_InstanceID +public property int gl_InstanceID { - [require(cuda_glsl_hlsl_spirv)] + [require(cuda_glsl_hlsl_spirv, raytracing_allstages)] get { __stage_switch @@ -8473,7 +8473,7 @@ public vector<T, N> subgroupPartitionedInclusiveMulNV(vector<T, N> value, uvec4 __generic<T : __BuiltinArithmeticType> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public T subgroupPartitionedInclusiveMinNV(T value, uvec4 ballot) { return WaveMultiPrefixInclusiveMin(value, ballot); @@ -8481,7 +8481,7 @@ public T subgroupPartitionedInclusiveMinNV(T value, uvec4 ballot) __generic<T : __BuiltinArithmeticType, let N : int> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public vector<T, N> subgroupPartitionedInclusiveMinNV(vector<T, N> value, uvec4 ballot) { return WaveMultiPrefixInclusiveMin(value, ballot); @@ -8489,7 +8489,7 @@ public vector<T, N> subgroupPartitionedInclusiveMinNV(vector<T, N> value, uvec4 __generic<T : __BuiltinArithmeticType> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public T subgroupPartitionedInclusiveMaxNV(T value, uvec4 ballot) { return WaveMultiPrefixInclusiveMax(value, ballot); @@ -8497,7 +8497,7 @@ public T subgroupPartitionedInclusiveMaxNV(T value, uvec4 ballot) __generic<T : __BuiltinArithmeticType, let N : int> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public vector<T, N> subgroupPartitionedInclusiveMaxNV(vector<T, N> value, uvec4 ballot) { return WaveMultiPrefixInclusiveMax(value, ballot); @@ -8585,7 +8585,7 @@ public vector<T, N> subgroupPartitionedExclusiveMulNV(vector<T, N> value, uvec4 __generic<T : __BuiltinArithmeticType> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public T subgroupPartitionedExclusiveMinNV(T value, uvec4 ballot) { return WaveMultiPrefixExclusiveMin(value, ballot); @@ -8593,7 +8593,7 @@ public T subgroupPartitionedExclusiveMinNV(T value, uvec4 ballot) __generic<T : __BuiltinArithmeticType, let N : int> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public vector<T, N> subgroupPartitionedExclusiveMinNV(vector<T, N> value, uvec4 ballot) { return WaveMultiPrefixExclusiveMin(value, ballot); @@ -8601,7 +8601,7 @@ public vector<T, N> subgroupPartitionedExclusiveMinNV(vector<T, N> value, uvec4 __generic<T : __BuiltinArithmeticType> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public T subgroupPartitionedExclusiveMaxNV(T value, uvec4 ballot) { return WaveMultiPrefixExclusiveMax(value, ballot); @@ -8609,7 +8609,7 @@ public T subgroupPartitionedExclusiveMaxNV(T value, uvec4 ballot) __generic<T : __BuiltinArithmeticType, let N : int> [ForceInline] -[require(cuda_glsl_spirv, subgroup_partitioned)] +[require(glsl_spirv, subgroup_partitioned)] public vector<T, N> subgroupPartitionedExclusiveMaxNV(vector<T, N> value, uvec4 ballot) { return WaveMultiPrefixExclusiveMax(value, ballot); diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 2d9543716..07f59ac46 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -4947,6 +4947,7 @@ T __getElement<T, U, I>(U collection, I index); /// @category stage_io Stage IO types __generic<T, let N : int> +[require(glsl_hlsl_spirv, geometry)] [require(glsl_hlsl_spirv, hull)] __magic_type(HLSLInputPatchType) __intrinsic_type($(kIROp_HLSLInputPatchType)) @@ -5017,6 +5018,7 @@ This type is supported natively when targeting HLSL. */ __magic_type(HLSL$(item.name)Type) __intrinsic_type($(item.op)) +[require(byteaddressbuffer_rw)] struct $(item.name) { // Note(tfoley): supports all operations from `ByteAddressBuffer` @@ -5025,7 +5027,7 @@ struct $(item.name) /// Get the number of bytes in the buffer. ///@param[out] dim The number of bytes in the buffer. [ForceInline] - [require(cpp_cuda_glsl_hlsl_spirv_wgsl, structuredbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_spirv_wgsl)] void GetDimensions(out uint dim) { __target_switch @@ -5054,7 +5056,7 @@ struct $(item.name) /// When targeting non-HLSL, the status is always 0. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl)] uint Load(int location) { __target_switch @@ -5067,7 +5069,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(hlsl, byteaddressbuffer_rw)] + [require(hlsl)] uint Load(int location, out uint status) { __target_switch @@ -5093,7 +5095,7 @@ struct $(item.name) /// When targeting non-HLSL, the status is always 0. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint2 Load2(uint location) { __target_switch @@ -5106,7 +5108,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint2 Load2Aligned(uint location, uint alignment) { __target_switch @@ -5123,7 +5125,7 @@ struct $(item.name) ///@return `uint2` Two 32-bit unsigned integers loaded from the buffer. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint2 Load2Aligned(uint location) { __target_switch @@ -5136,7 +5138,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(hlsl, byteaddressbuffer_rw)] + [require(hlsl)] uint2 Load2(uint location, out uint status) { __target_switch @@ -5161,7 +5163,7 @@ struct $(item.name) /// When targeting non-HLSL, the status is always 0. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint3 Load3(uint location) { __target_switch @@ -5174,7 +5176,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint3 Load3Aligned(uint location, uint alignment) { __target_switch @@ -5191,7 +5193,7 @@ struct $(item.name) ///@return `uint3` Three 32-bit unsigned integer value loaded from the buffer. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint3 Load3Aligned(uint location) { __target_switch @@ -5204,7 +5206,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(hlsl, byteaddressbuffer_rw)] + [require(hlsl)] uint3 Load3(uint location, out uint status) { __target_switch @@ -5228,7 +5230,7 @@ struct $(item.name) /// If any values were taken from an unmapped tile, `CheckAccessFullyMapped` returns FALSE. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint4 Load4(uint location) { __target_switch @@ -5241,7 +5243,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint4 Load4Aligned(uint location, uint alignment) { __target_switch @@ -5258,7 +5260,7 @@ struct $(item.name) ///@return `uint4` Four 32-bit unsigned integer value loaded from the buffer. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] uint4 Load4Aligned(uint location) { __target_switch @@ -5271,7 +5273,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(hlsl, byteaddressbuffer_rw)] + [require(hlsl)] uint4 Load4(uint location, out uint status) { __target_switch @@ -5282,7 +5284,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] T Load<T>(uint location) { return __byteAddressBufferLoad<T>(this, location, 0); @@ -5290,7 +5292,7 @@ struct $(item.name) [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] T LoadAligned<T>(uint location, uint alignment) { return __byteAddressBufferLoad<T>(this, location, alignment); @@ -5303,7 +5305,7 @@ struct $(item.name) ///Currently, this function only supports when `T` is scalar, vector, or matrix type. [__NoSideEffect] [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] T LoadAligned<T>(uint location) { return __byteAddressBufferLoad<T>(this, location, __naturalStrideOf<T>()); @@ -5420,6 +5422,7 @@ ${{{{ /// maps to `atomicAdd`. [__requiresNVAPI] [ForceInline] + [require(sm_5_0)] void InterlockedAddF16(uint byteAddress, half value, out half originalValue) { __target_switch @@ -5459,6 +5462,7 @@ ${{{{ /// maps to `atomicAdd`. [__requiresNVAPI] [ForceInline] + [require(sm_5_0)] void InterlockedAddF16Emulated(uint byteAddress, half value, out half originalValue) { __target_switch @@ -5735,7 +5739,7 @@ ${{{{ /// @param value The operand of the atomic operation. /// @param original_value The original value at `dest` before the $(op.internalName) operation. [ForceInline] - [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal, byteaddressbuffer_rw)] + [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal)] void Interlocked$(op.name)( UINT dest, UINT value, @@ -5751,7 +5755,7 @@ ${{{{ } [ForceInline] - [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal, byteaddressbuffer_rw)] + [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal)] void Interlocked$(op.name)( UINT dest, UINT value) @@ -5778,7 +5782,7 @@ ${{{{ /// translates to `InterlockedCompareExchange`. /// For CUDA, this function maps to `atomicCAS`. [ForceInline] - [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal, byteaddressbuffer_rw)] + [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal)] void InterlockedCompareExchange( UINT dest, UINT compare_value, @@ -5803,7 +5807,7 @@ ${{{{ /// translates to `InterlockedCompareStore`. /// For CUDA, this function maps to `atomicCAS`. [ForceInline] - [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal, byteaddressbuffer_rw)] + [require(cuda_glsl_hlsl_metal_spirv, atomic_glsl_hlsl_cuda_metal)] void InterlockedCompareStore( UINT dest, UINT compare_value, @@ -5824,7 +5828,7 @@ ${{{{ ///@param address The input address in bytes, which must be a multiple of 4. ///@param alignment Specifies the alignment of the location, which must be a multiple of 4. [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store(uint address, uint value) { __target_switch @@ -5841,7 +5845,7 @@ ${{{{ ///@param value Two input values. ///@param alignment Specifies the alignment of the location, which must be a multiple of 4. [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store2(uint address, uint2 value) { __target_switch @@ -5854,7 +5858,7 @@ ${{{{ [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store2(uint address, uint2 value, uint alignment) { __target_switch @@ -5870,7 +5874,7 @@ ${{{{ ///@param address The input address in bytes, which must be a multiple of 8. ///@param value Two input values. [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store2Aligned(uint address, uint2 value) { __target_switch @@ -5886,7 +5890,7 @@ ${{{{ ///@param value Three input values. ///@param alignment Specifies the alignment of the location, which must be a multiple of 4. [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store3(uint address, uint3 value) { __target_switch @@ -5898,7 +5902,7 @@ ${{{{ } [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store3(uint address, uint3 value, uint alignment) { __target_switch @@ -5914,7 +5918,7 @@ ${{{{ ///@param address The input address in bytes, which must be a multiple of 12. ///@param value Three input values. [ForceInline] - [require(cpp_cuda_glsl_hlsl_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_spirv)] void Store3Aligned(uint address, uint3 value) { __target_switch @@ -5930,7 +5934,7 @@ ${{{{ ///@param value Four input values. ///@param alignment Specifies the alignment of the location, which must be a multiple of 4. [ForceInline] - [require(cpp_cuda_glsl_hlsl_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_spirv)] void Store4(uint address, uint4 value) { __target_switch @@ -5943,7 +5947,7 @@ ${{{{ [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store4(uint address, uint4 value, uint alignment) { __target_switch @@ -5959,7 +5963,7 @@ ${{{{ ///@param address The input address in bytes, which must be a multiple of 16. ///@param value Four input values. [ForceInline] - [require(cpp_cuda_glsl_hlsl_metal_spirv, byteaddressbuffer_rw)] + [require(cpp_cuda_glsl_hlsl_metal_spirv)] void Store4Aligned(uint address, uint4 value) { __target_switch @@ -7392,7 +7396,6 @@ float16_t asfloat16(uint16_t value) } [__readNone] -[require(cuda_glsl_hlsl_spirv, shader5_sm_5_0)] vector<float16_t,N> asfloat16<let N : int>(vector<uint16_t,N> value) { __target_switch @@ -7414,7 +7417,6 @@ matrix<float16_t,R,C> asfloat16<let R : int, let C : int>(matrix<uint16_t,R,C> v [__unsafeForceInlineEarly] [__readNone] -[require(cuda_hlsl_metal_spirv, shader5_sm_5_0)] int16_t asint16(float16_t value) { __target_switch @@ -7430,8 +7432,7 @@ int16_t asint16(float16_t value) } [__unsafeForceInlineEarly] -[__readNone] -[require(cuda_hlsl_metal_spirv, shader5_sm_5_0)] +[__readNone] vector<int16_t,N> asint16<let N : int>(vector<float16_t,N> value) { __target_switch @@ -7444,7 +7445,6 @@ vector<int16_t,N> asint16<let N : int>(vector<float16_t,N> value) [__unsafeForceInlineEarly] [__readNone] -[require(cuda_hlsl_spirv, shader5_sm_5_0)] matrix<int16_t,R,C> asint16<let R : int, let C : int>(matrix<float16_t,R,C> value) { __target_switch @@ -7455,8 +7455,7 @@ matrix<int16_t,R,C> asint16<let R : int, let C : int>(matrix<float16_t,R,C> valu } [__readNone] -[__unsafeForceInlineEarly] -[require(cuda_hlsl_metal_spirv, shader5_sm_5_0)] +[__unsafeForceInlineEarly] float16_t asfloat16(int16_t value) { __target_switch @@ -7473,7 +7472,6 @@ float16_t asfloat16(int16_t value) [__unsafeForceInlineEarly] [__readNone] -[require(cuda_hlsl_metal_spirv, shader5_sm_5_0)] vector<float16_t,N> asfloat16<let N : int>(vector<int16_t,N> value) { __target_switch @@ -7489,7 +7487,6 @@ vector<float16_t,N> asfloat16<let N : int>(vector<int16_t,N> value) [__unsafeForceInlineEarly] [__readNone] -[require(cuda_hlsl_spirv, shader5_sm_5_0)] matrix<float16_t,R,C> asfloat16<let R : int, let C : int>(matrix<int16_t,R,C> value) { __target_switch @@ -10270,7 +10267,7 @@ vector<T, N> fwidth_coarse(vector<T, N> x) __generic<T : __BuiltinFloatingPointType, let N : int, let M : int> [__readNone] -[require(glsl_hlsl_spirv, fragmentprocessing)] +[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)] matrix<T, N, M> fwidth_coarse(matrix<T, N, M> x) { __target_switch @@ -10332,7 +10329,7 @@ vector<T, N> fwidth_fine(vector<T, N> x) __generic<T : __BuiltinFloatingPointType, let N : int, let M : int> [__readNone] -[require(glsl_hlsl_spirv, fragmentprocessing)] +[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)] matrix<T, N, M> fwidth_fine(matrix<T, N, M> x) { __target_switch @@ -26175,8 +26172,10 @@ CoopVec<T, N> atan<T : __BuiltinFloatingPointType, let N : int>(CoopVec<T, N> yO // [ForceInline] [require(cooperative_vector)] +[require(cooperative_vector)] [require(hlsl_coopvec_poc)] [require(optix_coopvec)] +[require(GL_ARB_gpu_shader5)] CoopVec<T, N> fma<T : __BuiltinFloatingPointType, let N : int>(CoopVec<T, N> a, CoopVec<T, N> b, CoopVec<T, N> c) { // TODO: Investigate, why does this fail if it's not inlined diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef index ec821ef21..95f1335da 100644 --- a/source/slang/slang-capabilities.capdef +++ b/source/slang/slang-capabilities.capdef @@ -152,7 +152,7 @@ def glsl_spirv_1_6 : glsl_spirv_1_5; // We have multiple capabilities for the various SPIR-V versions, // arranged so that they inherit from one another to represent which versions -// provide a super-set of the features of earlier ones (e.g., SPIR-V 1.4 is +// provide a superset of the features of earlier ones (e.g., SPIR-V 1.4 is // expressed as inheriting from SPIR-V 1.3). def _spirv_1_0 : spirv; @@ -887,6 +887,7 @@ def _GL_NV_shader_invocation_reorder : _GLSL_460; def _GL_NV_shader_subgroup_partitioned : _GLSL_140; def _GL_NV_shader_texture_footprint : _GLSL_450; def _GL_NV_cluster_acceleration_structure : _GLSL_460; +def _GL_NV_cooperative_vector : _GLSL_450; // GLSL extension and SPV extension associations. @@ -1134,6 +1135,10 @@ alias GL_NV_shader_texture_footprint = _GL_NV_shader_texture_footprint | spvImag /// [EXT] alias GL_NV_cluster_acceleration_structure = _GL_NV_cluster_acceleration_structure | spvRayTracingClusterAccelerationStructureNV; +/// Represents the GL_NV_cooperative_vector extension. +/// [EXT] +alias GL_NV_cooperative_vector = _GL_NV_cooperative_vector | spvCooperativeVectorNV + spvCooperativeVectorTrainingNV; + // Define feature names not reliant on shader stages /// NVAPI capability for HLSL @@ -1190,11 +1195,10 @@ alias bufferreference_int64 = bufferreference + GL_EXT_shader_explicit_arithmeti /// Note that cpp and cuda are supported via a fallback non-cooperative implementation /// No HLSL shader model bound yet /// [Compound] -alias cooperative_vector = _sm_6_9 | cpp | _cuda_sm_9_0 | spvCooperativeVectorNV; +alias cooperative_vector = _sm_6_9 | cpp | _cuda_sm_9_0 | spvCooperativeVectorNV | _GL_NV_cooperative_vector; /// Capabilities needed to train cooperative vectors /// [Compound] -alias cooperative_vector_training = spvCooperativeVectorTrainingNV; - +alias cooperative_vector_training = spvCooperativeVectorTrainingNV | _GL_NV_cooperative_vector; /// Capabilities needed to use cooperative matrices /// [Compound] alias cooperative_matrix = spvCooperativeMatrixKHR; diff --git a/source/slang/slang-capability.cpp b/source/slang/slang-capability.cpp index a2fef9f8a..a965ecd93 100644 --- a/source/slang/slang-capability.cpp +++ b/source/slang/slang-capability.cpp @@ -269,6 +269,22 @@ CapabilityAtomSet CapabilityAtomSet::newSetWithoutImpliedAtoms() const //// CapabiltySet +CapabilityAtomSet getTargetAtomsInSet(const CapabilitySet& set) +{ + CapabilityAtomSet out; + for (auto i : set.getCapabilityTargetSets()) + out.add((UInt)i.first); + return out; +} + +CapabilityAtomSet getStageAtomsInSet(const CapabilityTargetSet& set) +{ + CapabilityAtomSet out; + for (auto i : set.getShaderStageSets()) + out.add((UInt)i.first); + return out; +} + CapabilityAtom getTargetAtomInSet(const CapabilityAtomSet& atomSet) { auto targetSet = getAtomSetOfTargets(); @@ -959,56 +975,117 @@ CapabilitySet::AtomSets::Iterator CapabilitySet::getAtomSets() const return CapabilitySet::AtomSets::Iterator(&this->getCapabilityTargetSets()).begin(); } -bool CapabilitySet::checkCapabilityRequirement( +void CapabilitySet::checkCapabilityRequirement( + CheckCapabilityRequirementOptions options, CapabilitySet const& available, CapabilitySet const& required, - CapabilityAtomSet& outFailedAvailableSet) + CapabilityAtomSet& outFailedAvailableSet, + CheckCapabilityRequirementResult& result) { - // Requirements x are met by available disjoint capabilities (a | b) iff + // 'required' capabilities x are met by 'available' disjoint capabilities (a | b) iff // both 'a' satisfies x and 'b' satisfies x. // If we have a caller function F() decorated with: // [require(hlsl, _sm_6_3)] [require(spirv, _spv_ray_tracing)] void F() { g(); } // We'd better make sure that `g()` can be compiled with both (hlsl+_sm_6_3) and // (spirv+_spv_ray_tracing) capability sets. In this method, F()'s capability declaration is // represented by `available`, and g()'s capability is represented by `required`. We will check - // that for every capability conjunction X of F(), there is one capability conjunction Y in g() + // that for every capability conjunction X of F(), there is a capability conjunction Y in g() // such that X implies Y. // - // if empty there is no body, all capabilities are supported. - if (required.isEmpty()) - return true; + // If empty, all capabilities are supported. + // Either, we require no capabilities (return true) + // or we have no capability requirements (return true) + if (required.isEmpty() || available.isEmpty()) + { + result = CheckCapabilityRequirementResult::AvailableIsASuperSetToRequired; + return; + } + // invalid isn't a fail because the capabilities already threw an error. if (required.isInvalid()) { outFailedAvailableSet.add((UInt)CapabilityAtom::Invalid); - return false; + result = CheckCapabilityRequirementResult::AvailableIsASuperSetToRequired; + return; } - // If F's capability is empty, we can satisfy any non-empty requirements. - // - if (available.isEmpty() && !required.isEmpty()) - return false; + auto availableTargetSets = available.getCapabilityTargetSets(); + auto requiredTargetSets = required.getCapabilityTargetSets(); + if (options == CheckCapabilityRequirementOptions::MustHaveEqualAbstractAtoms) + { + // If we have a mismatch in capability-target count we clearly have a + // mismatch and will fail + auto availableTargetSetsCount = availableTargetSets.getCount(); + auto requiredTargetSetsCount = requiredTargetSets.getCount(); + if (availableTargetSetsCount != requiredTargetSetsCount) + { + auto availableTargets = getTargetAtomsInSet(available); + auto requiredTargets = getTargetAtomsInSet(required); + if (requiredTargetSetsCount > availableTargetSetsCount) + { + result = CheckCapabilityRequirementResult::AvailableIsNotASuperSetToRequired; + requiredTargets.subtractWith((UIntSet)availableTargets); + outFailedAvailableSet.add((UIntSet)requiredTargets); + } + else + { + result = CheckCapabilityRequirementResult::RequiredIsMissingAbstractAtoms; + availableTargets.subtractWith((UIntSet)requiredTargets); + outFailedAvailableSet.add((UIntSet)availableTargets); + } + return; + } + } - // if all sets in `available` are not a super-set to at least 1 `required` set, then we have an - // err - for (auto& availableTarget : available.m_targetSets) + // if all sets in `available` are not a superset to `required` then we have an + // error. + for (auto& availableTarget : availableTargetSets) { - auto reqTarget = required.m_targetSets.tryGetValue(availableTarget.first); + auto reqTarget = requiredTargetSets.tryGetValue(availableTarget.first); if (!reqTarget) { outFailedAvailableSet.add((UInt)availableTarget.first); - return false; + result = CheckCapabilityRequirementResult::RequiredIsMissingAbstractAtoms; + return; } - for (auto& availableStage : availableTarget.second.shaderStageSets) + if (options == CheckCapabilityRequirementOptions::MustHaveEqualAbstractAtoms) { - auto reqStage = reqTarget->shaderStageSets.tryGetValue(availableStage.first); + // If we have a mismatch in capability-stage count we clearly have a + // mismatch and will fail + auto availableStageSetsCount = availableTarget.second.getShaderStageSets().getCount(); + auto requiredStageSetsCount = reqTarget->getShaderStageSets().getCount(); + if (availableStageSetsCount != requiredStageSetsCount) + { + auto availableStages = getStageAtomsInSet(availableTarget.second); + auto requiredStages = getStageAtomsInSet(*reqTarget); + + if (requiredStageSetsCount > availableStageSetsCount) + { + result = CheckCapabilityRequirementResult::AvailableIsNotASuperSetToRequired; + requiredStages.subtractWith((UIntSet)availableStages); + outFailedAvailableSet.add((UIntSet)requiredStages); + } + else + { + result = CheckCapabilityRequirementResult::RequiredIsMissingAbstractAtoms; + availableStages.subtractWith((UIntSet)requiredStages); + outFailedAvailableSet.add((UIntSet)availableStages); + } + return; + } + } + + for (auto& availableStage : availableTarget.second.getShaderStageSets()) + { + auto reqStage = reqTarget->getShaderStageSets().tryGetValue(availableStage.first); if (!reqStage) { outFailedAvailableSet.add((UInt)availableStage.first); - return false; + result = CheckCapabilityRequirementResult::RequiredIsMissingAbstractAtoms; + return; } const CapabilityAtomSet* lastBadStage = nullptr; @@ -1020,7 +1097,7 @@ bool CapabilitySet::checkCapabilityRequirement( { const auto& reqStageSet = reqStage->atomSet.value(); if (availableStageSet.contains(reqStageSet)) - break; + continue; else lastBadStage = &reqStageSet; } @@ -1031,13 +1108,19 @@ bool CapabilitySet::checkCapabilityRequirement( outFailedAvailableSet, *lastBadStage, availableStageSet); - return false; + + // Not a failiure if nothing is missing + if (outFailedAvailableSet.isEmpty()) + continue; + result = CheckCapabilityRequirementResult::AvailableIsNotASuperSetToRequired; + return; } } } } - return true; + result = CheckCapabilityRequirementResult::AvailableIsASuperSetToRequired; + return; } /// Converts spirv version atom to the glsl_spirv equivlent. If not possible, Invalid is returned @@ -1097,7 +1180,7 @@ UnownedStringSlice capabilityNameToStringWithoutPrefix(CapabilityName capability return name; } -void printDiagnosticArg(StringBuilder& sb, const CapabilityAtomSet atomSet) +void printDiagnosticArg(StringBuilder& sb, const CapabilityAtomSet& atomSet) { bool isFirst = true; for (auto atom : atomSet.newSetWithoutImpliedAtoms()) diff --git a/source/slang/slang-capability.h b/source/slang/slang-capability.h index 4bf0704a0..43f933620 100644 --- a/source/slang/slang-capability.h +++ b/source/slang/slang-capability.h @@ -36,7 +36,7 @@ namespace Slang // The situation is slightly more complicated for a function. A function // might require a specific set of atomic feature, and that is the simple // case. In this simple case, we know that a target can run a function -// if the features of the target are a super-set of those required by +// if the features of the target are a superset of those required by // the function. // // In the more general case, we might have a function that can be used @@ -98,6 +98,27 @@ struct CapabilityTargetSet /// 2. `this` has completly disjoint shader stages from other. bool tryJoin(const CapabilityTargetSets& other); void unionWith(const CapabilityTargetSet& other); + + const CapabilityStageSets& getShaderStageSets() const { return shaderStageSets; } +}; + +enum class CheckCapabilityRequirementOptions +{ + // `available` can have a subset of the abstract atoms `required` has + AvailableCanHaveSubsetOfAbstractAtoms, + // `available` and `required` both must have equal abstract stage & target atoms + MustHaveEqualAbstractAtoms, +}; + +enum class CheckCapabilityRequirementResult +{ + // `available` is a superset to `required` + AvailableIsASuperSetToRequired, + // `available` is not a superset to `required` + AvailableIsNotASuperSetToRequired, + // `available` has abstract atoms that `required` is missing. + // Only possible with CheckCapabilityRequirementOptions::MustHaveEqualAbstractAtoms + RequiredIsMissingAbstractAtoms, }; struct CapabilitySet @@ -186,12 +207,14 @@ public: CapabilitySet const& targetCaps, bool& isEqual) const; - /// Find any capability sets which are in 'available' but not in 'required'. Return false if + /// Identify capability sets which are in 'available' but not in 'required'. Return false if /// this situation occurs. - static bool checkCapabilityRequirement( + static void checkCapabilityRequirement( + CheckCapabilityRequirementOptions options, CapabilitySet const& available, CapabilitySet const& required, - CapabilityAtomSet& outFailedAvailableSet); + CapabilityAtomSet& outFailedAvailableSet, + CheckCapabilityRequirementResult& result); // For each element in `elementsToPermutateWith`, create and add a different conjunction // permutation by adding to `setToPermutate`. @@ -370,6 +393,7 @@ bool isSpirvExtensionAtom(CapabilityAtom name); void printDiagnosticArg(StringBuilder& sb, CapabilityAtom atom); void printDiagnosticArg(StringBuilder& sb, CapabilityName name); +void printDiagnosticArg(StringBuilder& sb, const CapabilityAtomSet& atomSet); const CapabilityAtomSet& getAtomSetOfTargets(); const CapabilityAtomSet& getAtomSetOfStages(); diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 72b5c19db..0a9853012 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -995,12 +995,10 @@ struct SemanticsDeclCapabilityVisitor : public SemanticsDeclVisitorBase, CapabilitySet getDeclaredCapabilitySet(Decl* decl); - void visitDecl(Decl*) {} void visitDeclGroup(DeclGroup*) {} void checkVarDeclCommon(VarDeclBase* varDecl); - void visitAggTypeDeclBase(AggTypeDeclBase* decl); - void visitNamespaceDeclBase(NamespaceDeclBase* decl); + void visitContainerDecl(ContainerDecl* decl); void visitVarDecl(VarDecl* varDecl) { checkVarDeclCommon(varDecl); } @@ -1013,7 +1011,8 @@ struct SemanticsDeclCapabilityVisitor : public SemanticsDeclVisitorBase, void diagnoseUndeclaredCapability( Decl* decl, const DiagnosticInfo& diagnosticInfo, - const CapabilityAtomSet& failedAtomsInsideAvailableSet); + const CapabilityAtomSet& failedAtomsInsideAvailableSet, + bool printProvenance); }; @@ -14382,26 +14381,29 @@ struct CapabilityDeclReferenceVisitor auto targetCaseCount = stmt->targetCases.getCount(); for (Index targetCaseIndex = 0; targetCaseIndex < targetCaseCount; targetCaseIndex++) { - // We may recieve a `default:` case for a `__target_switch`. If this is the case, - // we must resolve the target capability for a non empty set of - // `calling_functions_targets`: - // ``` default_target = calling_functions_targets-{other_case_targets} ``` + // The logic here is to collect a list of `case` statment capabilities + // so that down-the-line we can specialize according to the compile-capabilities. // - // * `calling_functions_capability` = `requirement attribute` of the calling - // function; if missing - // we can assume it is `any_target` + // The additional goal we have is to merge all case-capabilities into 1 set + // so that we can propegate them to the parent-function so that a user may break-down + // a functon into `stage`/`target` specific code. // - // * `{other_case_targets}` = set of all capabilities all `case` statments target - // inside the `__target_switch` - - // If we do not handle `default:`, the codegen will fail when trying to find a - // specific codegen target not handled explicitly by a `case` statment. We must also - // ensure the `default` case is last so we have priority to hit `case` statments and - // can preprocess `case` statments before the `default` case. + // A few important details + // 1. Case statments (other than `default:`) may have overlapping capabilities. This is + // to allow "more specialized" `case` statments to support specializing code on + // higher-feature-levels to support writing 1 function to handle cases such as sm_5_0 + // and sm_6_0 support all in 1 function. + // + // 2. All `case:` statments are explicit with their own-capabilities, `default:` + // statments are not. `default:` statments have the value `CapabilityName::Invalid`. If + // we find a `default` statment we assign it all shader target/stage capabilities that + // the other `case` statments did not specify which is legal for the current calling + // function (based on the parent function `require` decl). CapabilitySet targetCap; if (CapabilityName(stmt->targetCases[targetCaseIndex]->capability) == CapabilityName::Invalid) { + // swap the `default` case to the end so that we process it last if (targetCaseCount - 1 != targetCaseIndex) { for (Index i = targetCaseIndex; i < targetCaseCount - 1; i++) @@ -14594,30 +14596,22 @@ CapabilitySet SemanticsDeclCapabilityVisitor::getDeclaredCapabilitySet(Decl* dec return declaredCaps; } -void SemanticsDeclCapabilityVisitor::visitAggTypeDeclBase(AggTypeDeclBase* decl) -{ - decl->inferredCapabilityRequirements = getDeclaredCapabilitySet(decl); -} - -void SemanticsDeclCapabilityVisitor::visitNamespaceDeclBase(NamespaceDeclBase* decl) +void SemanticsDeclCapabilityVisitor::visitContainerDecl(ContainerDecl* decl) { + // Any potential child must get it's capabilities from `getDeclaredCapabilitySet`. decl->inferredCapabilityRequirements = getDeclaredCapabilitySet(decl); } -template<typename ProcessFunc, typename ParentDiagnosticFunc> -static inline void _dispatchCapabilitiesVisitorOfFunctionDecl( - SemanticsVisitor* visitor, - FunctionDeclBase* funcDecl, - const ProcessFunc& processFunc, - const ParentDiagnosticFunc& parentDiagnosticFunc) +void SemanticsDeclCapabilityVisitor::visitFunctionDeclBase(FunctionDeclBase* funcDecl) { - visitor->setParentFuncOfVisitor(funcDecl); + setParentFuncOfVisitor(funcDecl); + // visit the members of our funcDecl for (auto member : funcDecl->getDirectMemberDecls()) { - visitor->ensureDecl(member, DeclCheckState::CapabilityChecked); + ensureDecl(member, DeclCheckState::CapabilityChecked); _propagateRequirement( - visitor, + this, funcDecl->inferredCapabilityRequirements, funcDecl, member, @@ -14625,22 +14619,35 @@ static inline void _dispatchCapabilitiesVisitorOfFunctionDecl( member->loc); } + // visit the body of our funcDecl, propagate capabilities. visitReferencedDecls( - *visitor, + *this, funcDecl->body, funcDecl->loc, funcDecl->findModifier<RequireCapabilityAttribute>(), - processFunc, - parentDiagnosticFunc); + [this, funcDecl](SyntaxNode* node, const CapabilitySet& nodeCaps, SourceLoc refLoc) + { + _propagateRequirement( + this, + funcDecl->inferredCapabilityRequirements, + funcDecl, + node, + nodeCaps, + refLoc); + }, + [this, funcDecl](DiagnosticCategory category) + { _propagateSeeDefinitionOf(this, funcDecl, category); }); + // non-static function join's capabilities with parent + // to become a superset of the parent. if (!isEffectivelyStatic(funcDecl)) { auto parentAggTypeDecl = getParentAggTypeDecl(funcDecl); if (parentAggTypeDecl) { - visitor->ensureDecl(parentAggTypeDecl, DeclCheckState::CapabilityChecked); + ensureDecl(parentAggTypeDecl, DeclCheckState::CapabilityChecked); _propagateRequirement( - visitor, + this, funcDecl->inferredCapabilityRequirements, funcDecl, parentAggTypeDecl, @@ -14648,34 +14655,13 @@ static inline void _dispatchCapabilitiesVisitorOfFunctionDecl( funcDecl->loc); } } -} - -void SemanticsDeclCapabilityVisitor::visitFunctionDeclBase(FunctionDeclBase* funcDecl) -{ - // If the function is an entrypoint and specifies a target stage, add the capabilities to - // our function capabilities. - _dispatchCapabilitiesVisitorOfFunctionDecl( - this, - funcDecl, - [this, funcDecl](SyntaxNode* node, const CapabilitySet& nodeCaps, SourceLoc refLoc) - { - _propagateRequirement( - this, - funcDecl->inferredCapabilityRequirements, - funcDecl, - node, - nodeCaps, - refLoc); - }, - [this, funcDecl](DiagnosticCategory category) - { _propagateSeeDefinitionOf(this, funcDecl, category); }); + // Get require of decl + add parents auto declaredCaps = getDeclaredCapabilitySet(funcDecl); - auto vis = getDeclVisibility(funcDecl); - // If 0 capabilities were annotated on a function, capabilities are inferred from the - // function body + // If 0 capabilities were annotated on this function, + // capabilities are inferred from the children. if (declaredCaps.isEmpty()) { declaredCaps = funcDecl->inferredCapabilityRequirements; @@ -14687,30 +14673,37 @@ void SemanticsDeclCapabilityVisitor::visitFunctionDeclBase(FunctionDeclBase* fun addModifier(funcDecl, declaredCapModifier); if (vis == DeclVisibility::Public) { - // For public decls, we need to enforce that the function - // only uses capabilities that it declares. - // At a minimum we will propagate shader requirements to our - // function from calling children in all cases so the parent - // can enforce shader targets correctly and propagate to `main` + // We need to enforce that the function-body + // only uses capabilities that the function-decl declares. + // + // A small exception to this rule is that the body must + // implement all shader stages/targets of the functionDecl + // requirements. The body can support *more* stages/targets, + // these will just be not accessible (which is fine since a user + // may only need hlsl support for a function, using an STD-LIB function + // implemented for all targets/stages). CapabilityAtomSet failedAvailableCapabilityConjunction; - if (!CapabilitySet::checkCapabilityRequirement( - declaredCaps, - funcDecl->inferredCapabilityRequirements, - failedAvailableCapabilityConjunction)) - { - diagnoseUndeclaredCapability( - funcDecl, - Diagnostics::useOfUndeclaredCapability, - failedAvailableCapabilityConjunction); - funcDecl->inferredCapabilityRequirements = declaredCaps; - } - else - funcDecl->inferredCapabilityRequirements.nonDestructiveJoin(declaredCaps); + CheckCapabilityRequirementResult checkCapabilityResult; + CapabilitySet::checkCapabilityRequirement( + CheckCapabilityRequirementOptions::AvailableCanHaveSubsetOfAbstractAtoms, + declaredCaps, + funcDecl->inferredCapabilityRequirements, + failedAvailableCapabilityConjunction, + checkCapabilityResult); + diagnoseUndeclaredCapability( + funcDecl, + Diagnostics::useOfUndeclaredCapability, + failedAvailableCapabilityConjunction, + true); + + // declared capabilities must be a superset. + funcDecl->inferredCapabilityRequirements = declaredCaps; } else { // For internal decls, their inferred capability should be joined - // with the declared capabilities. + // with the declared capabilities since we are assuming the stdlib + // is not wrong. funcDecl->inferredCapabilityRequirements.join(declaredCaps); } } @@ -14718,8 +14711,29 @@ void SemanticsDeclCapabilityVisitor::visitFunctionDeclBase(FunctionDeclBase* fun void SemanticsDeclCapabilityVisitor::visitInheritanceDecl(InheritanceDecl* inheritanceDecl) { - // Check that the implementation of an interface requirement is not using more capabilities - // than what's declared on the interface method. + auto inheritanceParentDecl = inheritanceDecl->parentDecl; + ensureDecl(inheritanceParentDecl, DeclCheckState::CapabilityChecked); + + // Propegate capabilities of inheritance `base` to + // `InheritanceDecl` + visitReferencedDecls( + *this, + inheritanceDecl->base, + inheritanceDecl->loc, + nullptr, + [this, inheritanceDecl](SyntaxNode* node, const CapabilitySet& nodeCaps, SourceLoc refLoc) + { + _propagateRequirement( + this, + inheritanceDecl->inferredCapabilityRequirements, + inheritanceDecl, + node, + nodeCaps, + refLoc); + }, + [this, inheritanceDecl](DiagnosticCategory category) + { _propagateSeeDefinitionOf(this, inheritanceDecl, category); }); + if (inheritanceDecl->witnessTable) { for (auto& kv : inheritanceDecl->witnessTable->m_requirementDictionary) @@ -14727,29 +14741,116 @@ void SemanticsDeclCapabilityVisitor::visitInheritanceDecl(InheritanceDecl* inher if (kv.value.getFlavor() != RequirementWitness::Flavor::declRef) continue; auto requirementDecl = kv.key; - auto implDecl = kv.value.getDeclRef(); - if (!implDecl) + auto implDeclRef = kv.value.getDeclRef(); + if (!implDeclRef) continue; - if (getModuleDecl(implDecl.getDecl())->languageVersion == SLANG_LANGUAGE_VERSION_LEGACY) + if (getModuleDecl(implDeclRef.getDecl())->languageVersion == + SLANG_LANGUAGE_VERSION_LEGACY) break; ensureDecl(requirementDecl, DeclCheckState::CapabilityChecked); - ensureDecl(implDecl.declRefBase, DeclCheckState::CapabilityChecked); + ensureDecl(implDeclRef.declRefBase, DeclCheckState::CapabilityChecked); + + // Only if capabilities are opted-into, should we error. + auto implDecl = implDeclRef.getDecl(); + if (!requirementDecl->hasModifier<ExplicitlyDeclaredCapabilityModifier>() && + !implDecl->hasModifier<ExplicitlyDeclaredCapabilityModifier>()) + continue; CapabilityAtomSet failedAvailableCapabilityConjunction; - if (!CapabilitySet::checkCapabilityRequirement( - requirementDecl->inferredCapabilityRequirements, - implDecl.getDecl()->inferredCapabilityRequirements, - failedAvailableCapabilityConjunction)) + CheckCapabilityRequirementResult checkCapabilityResult; + CapabilitySet::checkCapabilityRequirement( + CheckCapabilityRequirementOptions::MustHaveEqualAbstractAtoms, + requirementDecl->inferredCapabilityRequirements, + implDecl->inferredCapabilityRequirements, + failedAvailableCapabilityConjunction, + checkCapabilityResult); + + if (checkCapabilityResult == + CheckCapabilityRequirementResult::AvailableIsNotASuperSetToRequired) { diagnoseUndeclaredCapability( - implDecl.getDecl(), + implDecl, Diagnostics::useOfUndeclaredCapabilityOfInterfaceRequirement, + failedAvailableCapabilityConjunction, + false); + maybeDiagnose( + getSink(), + getOptionSet(), + DiagnosticCategory::Capability, + requirementDecl, + Diagnostics::seeDeclarationOf, + requirementDecl); + } + else if ( + checkCapabilityResult == + CheckCapabilityRequirementResult::RequiredIsMissingAbstractAtoms) + { + maybeDiagnose( + getSink(), + getOptionSet(), + DiagnosticCategory::Capability, + implDecl, + Diagnostics::requirmentHasSubsetOfAbstractAtomsToImplementation, + implDecl, failedAvailableCapabilityConjunction); + maybeDiagnose( + getSink(), + getOptionSet(), + DiagnosticCategory::Capability, + requirementDecl, + Diagnostics::seeDeclarationOf, + requirementDecl); } } } + + // validate that super-type is a super set of capabilities + CapabilityAtomSet failedAvailableCapabilityConjunction; + CheckCapabilityRequirementResult checkCapabilityResult; + CapabilitySet::checkCapabilityRequirement( + CheckCapabilityRequirementOptions::MustHaveEqualAbstractAtoms, + inheritanceDecl->inferredCapabilityRequirements, + inheritanceParentDecl->inferredCapabilityRequirements, + failedAvailableCapabilityConjunction, + checkCapabilityResult); + + if (checkCapabilityResult == + CheckCapabilityRequirementResult::AvailableIsNotASuperSetToRequired) + { + diagnoseUndeclaredCapability( + inheritanceParentDecl, + Diagnostics::useOfUndeclaredCapabilityOfInheritanceDecl, + failedAvailableCapabilityConjunction, + false); + maybeDiagnose( + getSink(), + getOptionSet(), + DiagnosticCategory::Capability, + inheritanceDecl->base, + Diagnostics::seeDeclarationOf, + inheritanceDecl->base); + } + else if ( + checkCapabilityResult == CheckCapabilityRequirementResult::RequiredIsMissingAbstractAtoms) + { + maybeDiagnose( + getSink(), + getOptionSet(), + DiagnosticCategory::Capability, + inheritanceParentDecl, + Diagnostics::subTypeHasSubsetOfAbstractAtomsToSuperType, + inheritanceParentDecl, + failedAvailableCapabilityConjunction); + maybeDiagnose( + getSink(), + getOptionSet(), + DiagnosticCategory::Capability, + inheritanceDecl->base, + Diagnostics::seeDeclarationOf, + inheritanceDecl->base); + } } DeclVisibility getDeclVisibility(Decl* decl) @@ -15044,13 +15145,11 @@ void diagnoseCapabilityProvenance( void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability( Decl* decl, const DiagnosticInfo& diagnosticInfo, - const CapabilityAtomSet& failedAtomsInsideAvailableSet) + const CapabilityAtomSet& failedAtomsInsideAvailableSet, + bool printProvenance) { if (decl->inferredCapabilityRequirements.isEmpty()) return; - if (failedAtomsInsideAvailableSet.isEmpty() || - failedAtomsInsideAvailableSet.contains((UInt)CapabilityAtom::Invalid)) - return; // There are two causes for why type checking failed on failedAvailableSet. // The first scenario is that failedAvailableSet defines a set of capabilities on a @@ -15075,7 +15174,7 @@ void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability( getSink(), this->getOptionSet(), DiagnosticCategory::Capability, - decl->loc, + decl, Diagnostics::declHasDependenciesNotCompatibleOnTarget, decl, outFailedAtom); @@ -15090,16 +15189,19 @@ void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability( getAtomSetOfTargets(), failedAtomSet); - HashSet<Decl*> printedDecls; - for (auto atom : targetsNotUsedSet) + if (printProvenance) { - CapabilityAtom formattedAtom = asAtom(atom); - diagnoseCapabilityProvenance( - this->getOptionSet(), - getSink(), - decl, - formattedAtom, - printedDecls); + HashSet<Decl*> printedDecls; + for (auto atom : targetsNotUsedSet) + { + CapabilityAtom formattedAtom = asAtom(atom); + diagnoseCapabilityProvenance( + this->getOptionSet(), + getSink(), + decl, + formattedAtom, + printedDecls); + } } return; } @@ -15130,7 +15232,7 @@ void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability( getSink(), this->getOptionSet(), DiagnosticCategory::Capability, - decl->loc, + decl, Diagnostics::declHasDependenciesNotCompatibleOnStage, decl, formattedAtom); @@ -15141,18 +15243,21 @@ void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability( getSink(), this->getOptionSet(), DiagnosticCategory::Capability, - decl->loc, + decl, diagnosticInfo, decl, formattedAtom); } - // Print provenances. - diagnoseCapabilityProvenance( - this->getOptionSet(), - getSink(), - decl, - formattedAtom, - printedDecls); + if (printProvenance) + { + // Print provenances. + diagnoseCapabilityProvenance( + this->getOptionSet(), + getSink(), + decl, + formattedAtom, + printedDecls); + } } } diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp index 8c9e24d48..4c45db1d7 100644 --- a/source/slang/slang-check-stmt.cpp +++ b/source/slang/slang-check-stmt.cpp @@ -442,14 +442,14 @@ void SemanticsStmtVisitor::visitTargetSwitchStmt(TargetSwitchStmt* stmt) bool isStage = isStageAtom((CapabilityName)caseStmt->capability, canonicalStage); if (as<StageSwitchStmt>(stmt)) { - if (!isStage && caseStmt->capability != 0) + if (!isStage && caseStmt->capability != (int32_t)CapabilityName::Invalid) { getSink()->diagnose( caseStmt->capabilityToken.loc, Diagnostics::unknownStageName, caseStmt->capabilityToken); } - caseStmt->capability = (int)canonicalStage; + caseStmt->capability = (int32_t)canonicalStage; } else { diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 8ec910f15..8d20483a4 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -1157,24 +1157,30 @@ DIAGNOSTIC( missingCapabilityRequirementOnPublicDecl, "public symbol '$0' is missing capability requirement declaration, the symbol is assumed to " "require inferred capabilities '$1'.") -DIAGNOSTIC(36104, Error, useOfUndeclaredCapability, "'$0' uses undeclared capability '$1'.") +DIAGNOSTIC(36104, Error, useOfUndeclaredCapability, "'$0' uses undeclared capability '$1'") DIAGNOSTIC( 36104, Error, useOfUndeclaredCapabilityOfInterfaceRequirement, - "'$0' uses capability '$1' that is missing from the interface requirement.") + "'$0' uses capability '$1' that is incompatable with the interface requirement") +DIAGNOSTIC( + 36104, + Error, + useOfUndeclaredCapabilityOfInheritanceDecl, + "'$0' uses capability '$1' that is incompatable with the supertype") DIAGNOSTIC(36105, Error, unknownCapability, "unknown capability name '$0'.") DIAGNOSTIC(36106, Error, expectCapability, "expect a capability name.") DIAGNOSTIC( 36107, Error, entryPointUsesUnavailableCapability, - "entrypoint '$0' uses features that are not available in '$2' stage for '$1' target.") + "entrypoint '$0' uses features that are not available in '$2' stage for '$1' compilation " + "target.") DIAGNOSTIC( 36108, Error, declHasDependenciesNotCompatibleOnTarget, - "'$0' has dependencies that are not compatible on the required target '$1'.") + "'$0' has dependencies that are not compatible on the required compilation target '$1'.") DIAGNOSTIC(36109, Error, invalidTargetSwitchCase, "'$0' cannot be used as a target_switch case.") DIAGNOSTIC( 36110, @@ -1211,7 +1217,18 @@ DIAGNOSTIC( 36117, Error, declHasDependenciesNotCompatibleOnStage, - "'$0' uses features that are not available in '$1' stage.") + "'$0' requires support for stage '$1', but stage is unsupported.") +DIAGNOSTIC( + 36118, + Error, + subTypeHasSubsetOfAbstractAtomsToSuperType, + "subtype '$0' must have the same target/stage support as the supertype; '$0' is missing '$1'") +DIAGNOSTIC( + 36118, + Error, + requirmentHasSubsetOfAbstractAtomsToImplementation, + "requirement '$0' must have the same target/stage support as the implementation; '$0' is " + "missing '$1'") // Attributes DIAGNOSTIC(31000, Warning, unknownAttributeName, "unknown attribute '$0'") diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 526e2f952..52d24ff7d 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -7186,7 +7186,7 @@ struct StmtLoweringVisitor : StmtVisitor<StmtLoweringVisitor> if (!builder->getBlock()->getTerminator()) builder->emitBranch(breakLabel); } - if (targetCase->capability == 0) + if (targetCase->capability == (int32_t)CapabilityName::Invalid) { info.defaultLabel = caseBlock; } diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 7e9740b53..1302975df 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -5754,7 +5754,7 @@ static Stmt* parseTargetSwitchStmtImpl(Parser* parser, TargetSwitchStmt* stmt) Diagnostics::unknownTargetName, caseName.getContent()); } - targetCase->capability = int32_t(cap); + targetCase->capability = (int32_t)cap; targetCase->capabilityToken = caseName; targetCase->loc = caseName.loc; targetCase->body = bodyStmt; @@ -8743,7 +8743,7 @@ Expr* Parser::ParseLeafExpression() /// Parse an argument to an application of a generic static Expr* _parseGenericArg(Parser* parser) { - // The grammar for generic arguments needs to be a super-set of the + // The grammar for generic arguments needs to be a superset of the // grammar for types and for expressions, because we do not know // which to expect at each argument position during parsing. // diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index 38ec85b62..3dd3ef1af 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -286,7 +286,8 @@ <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::ContinueStmt">(Slang::ContinueStmt*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::ReturnStmt">(Slang::ReturnStmt*)&astNodeType</ExpandedItem> <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::ExpressionStmt">(Slang::ExpressionStmt*)&astNodeType</ExpandedItem> - <Item Name="[Stmt]">(Slang::Stmt*)this,!</Item> + <ExpandedItem Condition="astNodeType == Slang::ASTNodeType::TargetSwitchStmt">(Slang::TargetSwitchStmt*)&astNodeType</ExpandedItem> + <Item Name="[Stmt]">(Slang::Stmt*)this,!</Item> </Expand> </Type> <Type Name="Slang::Name"> |
