diff options
| -rw-r--r-- | docs/command-line-slangc-reference.md | bin | 78370 -> 77996 bytes | |||
| -rw-r--r-- | source/core/core.natvis | 82 | ||||
| -rw-r--r-- | source/core/slang-uint-set.h | 80 | ||||
| -rw-r--r-- | source/slang/hlsl.meta.slang | 2 | ||||
| -rw-r--r-- | source/slang/slang-capabilities.capdef | 125 | ||||
| -rw-r--r-- | source/slang/slang-capability.cpp | 105 | ||||
| -rw-r--r-- | source/slang/slang-capability.h | 11 | ||||
| -rw-r--r-- | source/slang/slang-serialize-ast-type-info.h | 6 | ||||
| -rw-r--r-- | tools/slang-capability-generator/capability-generator-main.cpp | 374 | ||||
| -rw-r--r-- | tools/slang-capability-generator/slang-capability-diagnostic-defs.h | 2 |
10 files changed, 555 insertions, 232 deletions
diff --git a/docs/command-line-slangc-reference.md b/docs/command-line-slangc-reference.md Binary files differindex df913c0b5..7c2beb7e0 100644 --- a/docs/command-line-slangc-reference.md +++ b/docs/command-line-slangc-reference.md diff --git a/source/core/core.natvis b/source/core/core.natvis index 2448e2c88..f2547b3fe 100644 --- a/source/core/core.natvis +++ b/source/core/core.natvis @@ -55,62 +55,44 @@ </Type> <Type Name="Slang::Dictionary<*,*>"> + <DisplayString>{{ {map.m_values} }}</DisplayString> + <Expand> + <Item Name="[items]">map.m_values</Item> + <Item Name="map">map</Item> + </Expand> +</Type> + +<Type Name="Slang::HashSet<*>"> + <DisplayString>{{ {dict} }}</DisplayString> + <Expand> + <Item Name="dict">dict</Item> + </Expand> +</Type> + +<Type Name="Slang::OrderedHashSet<*>"> + <DisplayString>{{ size={dict._count} }}</DisplayString> + <Expand> + <LinkedListItems> + <Size>m_dict._count</Size> + <HeadPointer>m_dict.kvPairs.head</HeadPointer> + <NextPointer>next</NextPointer> + <ValueNode>value</ValueNode> + </LinkedListItems> + </Expand> +</Type> + +<Type Name="Slang::OrderedDictionary<*,*>"> <DisplayString>{{ size={m_count} }}</DisplayString> <Expand> - <Item Name="[size]">m_count</Item> - <Item Name="[capacity]">m_bucketCountMinusOne + 1</Item> - <CustomListItems MaxItemsPerView="5000" ExcludeView="Test"> - <Variable Name="iBucket" InitialValue="0" /> - <Variable Name="pBucket" InitialValue="m_hashMap" /> - <Variable Name="isDeleted" InitialValue="0" /> - <Variable Name="isEmpty" InitialValue="0" /> + <LinkedListItems> <Size>m_count</Size> - <Exec>pBucket = m_hashMap</Exec> - <Loop> - <If Condition="iBucket >= m_bucketCountMinusOne"> - <Break/> - </If> - <Exec> - isDeleted = m_marks.m_buffer.m_count > (iBucket*2+1)/32 - ? ((m_marks.m_buffer.m_buffer[(iBucket*2+1)/32]&(1<<(iBucket*2+1)%32)) != 0) - : 0 - </Exec> - <Exec> - isEmpty = m_marks.m_buffer.m_count > (iBucket*2)/32 - ? ((m_marks.m_buffer.m_buffer[(iBucket*2)/32]&(1<<(iBucket*2)%32)) == 0) - : 1 - </Exec> - <If Condition="isDeleted+isEmpty==0"> - <Item>*(m_hashMap + iBucket)</Item> - </If> - <Exec>iBucket++</Exec> - </Loop> - </CustomListItems> + <HeadPointer>m_kvPairs.head</HeadPointer> + <NextPointer>next</NextPointer> + <ValueNode>value</ValueNode> + </LinkedListItems> </Expand> </Type> - <Type Name="Slang::OrderedHashSet<*>"> - <DisplayString>{{ size={dict._count} }}</DisplayString> - <Expand> - <LinkedListItems> - <Size>m_dict._count</Size> - <HeadPointer>m_dict.kvPairs.head</HeadPointer> - <NextPointer>next</NextPointer> - <ValueNode>value</ValueNode> - </LinkedListItems> - </Expand> - </Type> - <Type Name="Slang::OrderedDictionary<*,*>"> - <DisplayString>{{ size={m_count} }}</DisplayString> - <Expand> - <LinkedListItems> - <Size>m_count</Size> - <HeadPointer>m_kvPairs.head</HeadPointer> - <NextPointer>next</NextPointer> - <ValueNode>value</ValueNode> - </LinkedListItems> - </Expand> - </Type> <Type Name="Slang::RefPtr<*>"> <SmartPointer Usage="Minimal">pointer</SmartPointer> <DisplayString Condition="pointer == 0">empty</DisplayString> diff --git a/source/core/slang-uint-set.h b/source/core/slang-uint-set.h index 22ca457b0..7e08500fd 100644 --- a/source/core/slang-uint-set.h +++ b/source/core/slang-uint-set.h @@ -14,19 +14,9 @@ namespace Slang { -template<typename T> -constexpr static Index computeElementShift() +constexpr Index intLog2(unsigned x) { - Index currentShift = 0; - Index currentShiftValue = 1; - - while (currentShiftValue != sizeof(T) * 8) - { - currentShift++; - currentShiftValue *= 2; - } - - return currentShift; + return x == 1 ? 0 : 1 + intLog2(x >> 1); } static inline Index bitscanForward(uint64_t in) @@ -65,13 +55,12 @@ public: constexpr static Index kElementSize = sizeof(Element) * 8; ///< The number of bits in an element. This also determines how many values a element can hold. constexpr static Index kElementMask = kElementSize - 1; ///< Mask to get shift from an index - constexpr static Index kElementShift = computeElementShift<Element>(); ///< How many bits to shift to get Element index from an index. 5 for 2^5=32 elements in a uint32_t. 6 for 2^6=64 in a uint64_t. + constexpr static Index kElementShift = intLog2(sizeof(Element)*8); ///< How many bits to shift to get Element index from an index. 5 for 2^5=32 elements in a uint32_t. 6 for 2^6=64 in a uint64_t. UIntSet() {} UIntSet(const UIntSet& other) { m_buffer = other.m_buffer; } UIntSet(UIntSet && other) { *this = (_Move(other)); } UIntSet(UInt maxVal) { resizeAndClear(maxVal); } - UIntSet(List<UIntSet::Element> buffer) { m_buffer = buffer; } UIntSet& operator=(UIntSet&& other); UIntSet& operator=(const UIntSet& other); @@ -81,7 +70,7 @@ public: /// Return the count of all bits directly represented Int getCount() const { return Int(m_buffer.getCount()) * kElementSize; } - List<Element>& getBuffer() { return m_buffer; } + const List<Element>& getBuffer() const { return m_buffer; } /// Resize such that val can be stored and clear contents void resizeAndClear(UInt val); @@ -101,6 +90,9 @@ public: /// Add a value inline void add(UInt val); inline void add(const UIntSet& val); + inline void addRange(const List<UInt>& other); + + inline void addRawElement(Element val, Index bitOffset); /// Remove a value inline void remove(UInt val); @@ -145,37 +137,38 @@ public: { friend class UIntSet; private: - const List<Element>* context; - Index block = 0; - Element processedElement = 0; - uint64_t LSB = 0; + const List<Element>* m_context; + Index m_block = 0; + Element m_processedElement = 0; + uint64_t m_LSB = 0; void clearLSB() { - LSB = bitscanForward(processedElement); - processedElement &= processedElement - 1; + m_LSB = bitscanForward(m_processedElement); + m_processedElement &= m_processedElement - 1; } - public: - Iterator(const List<Element>* inContext) + + Iterator(const List<Element>* context) { - context = inContext; + m_context = context; } + public: Element operator*() { - return Element(LSB + (kElementSize * block)); + return Element(m_LSB + (kElementSize * m_block)); } Iterator& operator++() { - while (processedElement == 0) + while (m_processedElement == 0) { - block++; - if (block >= context->getCount()) + m_block++; + if (m_block >= m_context->getCount()) { return *this; } - processedElement = (*context)[block]; + m_processedElement = (*m_context)[m_block]; } clearLSB(); return *this; @@ -186,8 +179,8 @@ public: } bool operator==(const Iterator& other) const { - return other.block == this->block - && other.processedElement == this->processedElement; + return other.m_block == this->m_block + && other.m_processedElement == this->m_processedElement; } bool operator!=(const Iterator& other) const { @@ -200,19 +193,21 @@ public: if (m_buffer.getCount() == 0) return tmp; - tmp.processedElement = m_buffer[0]; - if (tmp.processedElement == 0) + tmp.m_processedElement = m_buffer[0]; + if (tmp.m_processedElement == 0) + { tmp++; + return tmp; + } tmp.clearLSB(); - return tmp; } Iterator end() const { Iterator tmp(&m_buffer); - tmp.block = m_buffer.getCount(); - tmp.processedElement = 0; + tmp.m_block = m_buffer.getCount(); + tmp.m_processedElement = 0; return tmp; } @@ -307,6 +302,19 @@ inline void UIntSet::add(const UIntSet& other) m_buffer[i] |= other.m_buffer[i]; } +inline void UIntSet::addRange(const List<UInt>& other) +{ + for (auto i : other) + add(i); +} + +inline void UIntSet::addRawElement(Element other, Index elementIndex) +{ + if(this->m_buffer.getCount() <= elementIndex) + resizeBackingBufferDirectly(elementIndex+1); + m_buffer[elementIndex] |= other; +} + template<typename T> List<T> UIntSet::getElements() const { diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang index 1458467b9..13b1f0131 100644 --- a/source/slang/hlsl.meta.slang +++ b/source/slang/hlsl.meta.slang @@ -3665,7 +3665,7 @@ struct InputPatch }; __generic<T, let N : int> -[require(glsl_hlsl_spirv, shader_stages_domain_hull)] +[require(glsl_hlsl_spirv, domain_hull)] __magic_type(HLSLOutputPatchType) __intrinsic_type($(kIROp_HLSLOutputPatchType)) struct OutputPatch diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef index 5a0df9f9b..7567dd617 100644 --- a/source/slang/slang-capabilities.capdef +++ b/source/slang/slang-capabilities.capdef @@ -20,10 +20,22 @@ // There are three types of capability definitions: // - `def`: this will introduce an new capability atom. If there is an inheritance clause, // the capability name will expand to all inherited atoms plus the newly introduced atom. -// - `abstract`: an abstract capability does not introduce an actual atom, but it defines -// an implicit conflict group such that two capabilities inheriting the same abstract -// capability cannot be satisfied simultaneously. When used in an expression, `abstract` -// capability also expands into a disjunction (or) of all inherited capabilities. +// - `abstract`: an abstract capability does not introduce an actual atom. Primarily used to +// make disjunctions using the following rules: +// 1. Each type of abstract atom defines a "keyhole". `target` and `stage` are distinct "keyholes". +// 2. Any atom immediately derived off of an abstract atom is a "key atom". +// 3. Every conjunction may only populate each "keyhole" once, else the set is incompatible. +// * If joining ('+') incompatible sets, an invalid capability is made. +// * If Inclusive joining ('|') incompatible sets, a disjunction is made. +// 4. ex: `hlsl + glsl` both populate the same "keyhole" of `target`, this is incompatible. +// 5. ex: `hlsl + _sm_6_0` both populate same keyholes of `hlsl` and `hlsl`, this is compatible. +// 6. ex: `hlsl | glsl` creates a disjunction of 2 sets: `hlsl` and `glsl`. This is due to the +// 2 sets being incompatible. +// 7. Having a not populated "keyhole" means your set is compatible with any "key atom" of +// distinct "keyhole". +// 8. ex: `vertex + glsl` works because 'vertex' has a unpopulated `target` "keyhole", and +// therefore is compatible with all `target` "key atoms" + // - `alias`: this defines an alias and does not introduce actual atoms. // Several capabilities represent the target formats in which we generate code. @@ -173,27 +185,23 @@ alias tesscontrol = hull; alias tesseval = domain; alias amplification_mesh = amplification | mesh; alias raytracing_stages = raygen | intersection | anyhit | closesthit | miss | callable; -alias raytracing_stages_intersection = intersection; -alias raytracing_stages_raygen = raygen; -alias raytracing_stages_anyhit_closesthit = anyhit | closesthit; -alias raytracing_stages_raygen_closesthit_miss = raygen | closesthit | miss; -alias raytracing_stages_anyhit_closesthit_intersection = anyhit | closesthit | intersection; -alias raytracing_stages_anyhit_closesthit_intersection_miss = anyhit | closesthit | intersection | miss; -alias raytracing_stages_raygen_closesthit_miss_callable = raygen | closesthit | miss | callable; -alias shader_stages_compute_tesscontrol_tesseval = compute | tesscontrol | tesseval; -alias shader_stages_compute_fragment = compute | fragment; -alias shader_stages_compute_fragment_geometry_vertex = compute | fragment | geometry | vertex; -alias shader_stages_domain_hull = domain | hull; -alias raytracing_stages_fragment = raytracing_stages | fragment; -alias raytracing_stages_compute = raytracing_stages | compute; -alias raytracing_stages_compute_amplification_mesh = raytracing_stages_compute | amplification_mesh; -alias raytracing_stages_compute_fragment = raytracing_stages | shader_stages_compute_fragment; -alias raytracing_stages_compute_fragment_geometry_vertex = raytracing_stages | shader_stages_compute_fragment_geometry_vertex; +alias anyhit_closesthit = anyhit | closesthit; +alias raygen_closesthit_miss = raygen | closesthit | miss; +alias anyhit_closesthit_intersection = anyhit | closesthit | intersection; +alias anyhit_closesthit_intersection_miss = anyhit | closesthit | intersection | miss; +alias raygen_closesthit_miss_callable = raygen | closesthit | miss | callable; +alias compute_tesscontrol_tesseval = compute | tesscontrol | tesseval; +alias compute_fragment = compute | fragment; +alias compute_fragment_geometry_vertex = compute | fragment | geometry | vertex; +alias domain_hull = domain | hull; +alias raytracingstages_fragment = raytracing_stages | fragment; +alias raytracingstages_compute = raytracing_stages | compute; +alias raytracingstages_compute_amplification_mesh = raytracingstages_compute | amplification_mesh; +alias raytracingstages_compute_fragment = raytracing_stages | compute_fragment; +alias raytracingstages_compute_fragment_geometry_vertex = raytracing_stages | compute_fragment_geometry_vertex; // SPIRV extensions. -def SOURCE_EXT_GL_NV_compute_shader_derivatives : spirv_1_0; - def SPV_EXT_fragment_shader_interlock : spirv_1_0; def SPV_KHR_fragment_shader_barycentric : spirv_1_0; def SPV_EXT_fragment_fully_covered : spirv_1_0; @@ -342,7 +350,7 @@ alias GL_KHR_shader_subgroup_shuffle = _GL_KHR_shader_subgroup_shuffle | spvGrou alias GL_KHR_shader_subgroup_shuffle_relative = _GL_KHR_shader_subgroup_shuffle_relative | spvGroupNonUniformShuffle; alias GL_KHR_shader_subgroup_vote = _GL_KHR_shader_subgroup_vote | spvGroupNonUniformVote; alias GL_KHR_shader_subgroup_quad = _GL_KHR_shader_subgroup_quad | spvGroupNonUniformQuad; -alias GL_NV_compute_shader_derivatives = _GL_NV_compute_shader_derivatives | SOURCE_EXT_GL_NV_compute_shader_derivatives | SPV_NV_compute_shader_derivatives | _sm_6_6; +alias GL_NV_compute_shader_derivatives = _GL_NV_compute_shader_derivatives | SPV_NV_compute_shader_derivatives | _sm_6_6; alias GL_ARB_shader_image_size = _GL_ARB_shader_image_size | spvImageQuery | metal; alias GL_ARB_shader_texture_image_samples = _GL_ARB_shader_texture_image_samples | spvImageQuery | metal; alias GL_NV_shader_atomic_fp16_vector = _GL_NV_shader_atomic_fp16_vector + _GL_NV_gpu_shader5 | spirv_1_0; @@ -364,8 +372,8 @@ alias rayquery = GL_EXT_ray_query | _sm_6_5; alias raytracing_motionblur = raytracing + motionblur | cuda; alias ser_motion = ser + motionblur; alias shaderclock = GL_EXT_shader_realtime_clock | hlsl_nvapi | cpp | cuda; -alias meshshading_internal = spvMeshShadingEXT + _sm_6_5 + _GL_EXT_mesh_shader; -alias meshshading = amplification + meshshading_internal | mesh + meshshading_internal; +alias meshshading_internal = GL_EXT_mesh_shader | _sm_6_5; +alias meshshading = amplification_mesh + meshshading_internal; alias fragmentshaderinterlock = _GL_ARB_fragment_shader_interlock | hlsl_nvapi | spvFragmentShaderPixelInterlockEXT; alias atomic64 = GL_EXT_shader_atomic_int64 | _sm_6_6 | cpp | cuda; alias atomicfloat = GL_EXT_shader_atomic_float | _sm_6_0 + hlsl_nvapi | cpp | cuda; @@ -375,7 +383,7 @@ alias groupnonuniform = GL_KHR_shader_subgroup_ballot + GL_KHR_shader_subgroup_s | _sm_6_0 | cuda; alias fragmentshaderbarycentric = GL_EXT_fragment_shader_barycentric | _sm_6_1; alias shadermemorycontrol = glsl | spirv_1_0 | _sm_5_0; -alias shadermemorycontrol_compute = raytracing_stages_compute + shadermemorycontrol; +alias shadermemorycontrol_compute = raytracingstages_compute + shadermemorycontrol; alias subpass = fragment + any_gfx_target; alias waveprefix = _sm_6_5 | _cuda_sm_7_0 | GL_KHR_shader_subgroup_arithmetic; alias bufferreference = GL_EXT_buffer_reference; @@ -564,7 +572,7 @@ alias GLSL_460 = _GLSL_460 | cpp ; -alias GLSL_410_SPIRV_1_0 = _GLSL_410 + GLSL_400 | GLSL_400; +alias GLSL_410_SPIRV_1_0 = _GLSL_410 | spirv_1_0; alias GLSL_420_SPIRV_1_0 = _GLSL_420 + GLSL_410_SPIRV_1_0 | GLSL_410_SPIRV_1_0; alias GLSL_430_SPIRV_1_0 = _GLSL_430 + GLSL_420_SPIRV_1_0 | GLSL_420_SPIRV_1_0; @@ -587,41 +595,41 @@ alias METAL_2_4 = metallib_2_4; alias sm_2_0_GLSL_140 = _GLSL_140 + sm_4_0 | sm_4_0; alias sm_2_0_GLSL_400 = _GLSL_400 + sm_4_0 | sm_4_0; -alias appendstructuredbuffer = sm_5_0 + raytracing_stages_compute_fragment; +alias appendstructuredbuffer = sm_5_0 + raytracingstages_compute_fragment; alias atomic_hlsl = _sm_4_0; alias atomic_hlsl_nvapi = _sm_4_0 + hlsl_nvapi; alias atomic_hlsl_sm_6_6 = _sm_6_6; alias byteaddressbuffer = sm_4_0; -alias byteaddressbuffer_rw = sm_4_0 + raytracing_stages_compute_fragment; -alias consumestructuredbuffer = sm_5_0 + raytracing_stages_compute_fragment; +alias byteaddressbuffer_rw = sm_4_0 + raytracingstages_compute_fragment; +alias consumestructuredbuffer = sm_5_0 + raytracingstages_compute_fragment; alias fragmentprocessing = fragment + _sm_5_0 | fragment + glsl_spirv - | raytracing_stages_compute_amplification_mesh + GL_NV_compute_shader_derivatives + | raytracingstages_compute_amplification_mesh + GL_NV_compute_shader_derivatives ; alias fragmentprocessing_derivativecontrol = fragment + _sm_5_0 | fragment + GL_ARB_derivative_control - | raytracing_stages_compute_amplification_mesh + GL_NV_compute_shader_derivatives + | raytracingstages_compute_amplification_mesh + GL_NV_compute_shader_derivatives ; alias getattributeatvertex = fragment + _sm_6_1 | fragment + GL_EXT_fragment_shader_barycentric; -alias memorybarrier_compute = raytracing_stages_compute + sm_5_0; +alias memorybarrier_compute = raytracingstages_compute + sm_5_0; alias glsl_barrier = hlsl + memorybarrier_compute - | glsl_spirv + shader_stages_compute_tesscontrol_tesseval + | glsl_spirv + compute_tesscontrol_tesseval ; alias structuredbuffer = sm_4_0; -alias structuredbuffer_rw = sm_4_0 + raytracing_stages_compute_fragment; +alias structuredbuffer_rw = sm_4_0 + raytracingstages_compute_fragment; alias texture_sm_4_1 = sm_4_1 ; alias texture_sm_4_1_samplerless = cpp + texture_sm_4_1 | cuda + texture_sm_4_1 | glsl + texture_sm_4_1 + GL_EXT_samplerless_texture_functions - | hlsl + texture_sm_4_1 + raytracing_stages_compute_fragment + | hlsl + texture_sm_4_1 + raytracingstages_compute_fragment | spirv_1_0 + texture_sm_4_1 + GL_EXT_samplerless_texture_functions | metal + texture_sm_4_1 ; alias texture_sm_4_1_compute_fragment = cpp + texture_sm_4_1 | cuda + texture_sm_4_1 | glsl + texture_sm_4_1 - | hlsl + texture_sm_4_1 + raytracing_stages_compute_fragment + | hlsl + texture_sm_4_1 + raytracingstages_compute_fragment | spirv_1_0 + texture_sm_4_1 | metal + texture_sm_4_1 ; @@ -629,7 +637,7 @@ alias texture_sm_4_1_compute_fragment = cpp + texture_sm_4_1 alias texture_sm_4_1_fragment = cpp + texture_sm_4_1 | cuda + texture_sm_4_1 | glsl + texture_sm_4_1 - | hlsl + texture_sm_4_1 + raytracing_stages_compute_fragment + | hlsl + texture_sm_4_1 + raytracingstages_compute_fragment | spirv_1_0 + texture_sm_4_1 | metal + texture_sm_4_1 ; @@ -637,7 +645,7 @@ alias texture_sm_4_1_clamp_fragment = texture_sm_4_1_fragment + GL_ARB_sparse_te alias texture_sm_4_1_vertex_fragment_geometry = cpp + texture_sm_4_1 | cuda + texture_sm_4_1 | glsl + texture_sm_4_1 - | hlsl + texture_sm_4_1 + raytracing_stages_compute_fragment_geometry_vertex + | hlsl + texture_sm_4_1 + raytracingstages_compute_fragment_geometry_vertex | spirv_1_0 + texture_sm_4_1 | metal + texture_sm_4_1 ; @@ -665,8 +673,8 @@ alias printf = GL_EXT_debug_printf | _sm_4_0 | _cuda_sm_2_0 | cpp; alias texturefootprint = GL_NV_shader_texture_footprint + GLSL_450 | hlsl_nvapi + _sm_4_0; alias texturefootprintclamp = texturefootprint + GL_ARB_sparse_texture_clamp; -alias shader5_sm_4_0 = GL_ARB_gpu_shader5 + sm_4_0 | sm_4_0; -alias shader5_sm_5_0 = GL_ARB_gpu_shader5 + sm_4_0 | sm_5_0; +alias shader5_sm_4_0 = GL_ARB_gpu_shader5 + _GLSL_140 + sm_4_0 | sm_4_0; +alias shader5_sm_5_0 = GL_ARB_gpu_shader5 + _GLSL_140 + sm_4_0 | sm_5_0; alias subgroup_basic = GL_KHR_shader_subgroup_basic | _sm_6_0 | _cuda_sm_7_0; alias subgroup_ballot = spirv_1_0 + GL_KHR_shader_subgroup_ballot @@ -681,7 +689,8 @@ alias subgroup_ballot_activemask = spirv_1_0 + GL_KHR_shader_subgroup_ballot ; alias subgroup_basic_ballot = glsl + GL_KHR_shader_subgroup_basic + subgroup_ballot | spirv + GL_KHR_shader_subgroup_basic + subgroup_ballot - | hlsl + subgroup_ballot | cuda + subgroup_ballot + | hlsl + subgroup_ballot + | cuda + subgroup_ballot ; alias subgroup_vote = GL_KHR_shader_subgroup_vote | _sm_6_0 | _cuda_sm_7_0; alias shaderinvocationgroup = subgroup_vote; @@ -705,23 +714,23 @@ alias breakpoint = GL_EXT_debug_printf | hlsl | _cuda_sm_8_0 | cpp; alias rayobject = raytracing | rayquery; alias raytracing_allstages = raytracing_stages + raytracing; alias raytracing_anyhit = anyhit + raytracing; -alias raytracing_intersection = raytracing_stages_intersection + raytracing; -alias raytracing_anyhit_closesthit = raytracing_stages_anyhit_closesthit + raytracing; -alias raytracing_anyhit_closesthit_intersection = raytracing_stages_anyhit_closesthit_intersection + raytracing; -alias raytracing_raygen_closesthit_miss = raytracing_stages_raygen_closesthit_miss + raytracing; -alias raytracing_anyhit_closesthit_intersection_miss = raytracing_stages_anyhit_closesthit_intersection_miss + raytracing; -alias raytracing_raygen_closesthit_miss_callable = raytracing_stages_raygen_closesthit_miss_callable + raytracing; -alias raytracing_position = raytracing + GL_EXT_ray_tracing_position_fetch + anyhit + closesthit; -alias raytracing_motionblur_anyhit_closesthit_intersection_miss = raytracing_stages_anyhit_closesthit_intersection_miss + raytracing_motionblur; -alias raytracing_motionblur_raygen_closesthit_miss = raytracing_stages_raygen_closesthit_miss + raytracing_motionblur; +alias raytracing_intersection = intersection + raytracing; +alias raytracing_anyhit_closesthit = anyhit_closesthit + raytracing; +alias raytracing_anyhit_closesthit_intersection = anyhit_closesthit_intersection + raytracing; +alias raytracing_raygen_closesthit_miss = raygen_closesthit_miss + raytracing; +alias raytracing_anyhit_closesthit_intersection_miss = anyhit_closesthit_intersection_miss + raytracing; +alias raytracing_raygen_closesthit_miss_callable = raygen_closesthit_miss_callable + raytracing; +alias raytracing_position = raytracing + GL_EXT_ray_tracing_position_fetch + anyhit_closesthit; +alias raytracing_motionblur_anyhit_closesthit_intersection_miss = anyhit_closesthit_intersection_miss + raytracing_motionblur; +alias raytracing_motionblur_raygen_closesthit_miss = raygen_closesthit_miss + raytracing_motionblur; alias rayquery_position = rayquery + GL_EXT_ray_tracing_position_fetch; -alias ser_raygen = raytracing_stages_raygen + ser; -alias ser_raygen_closesthit_miss = raytracing_stages_raygen_closesthit_miss + ser; -alias ser_any_closesthit_intersection_miss = raytracing_stages_anyhit_closesthit_intersection_miss + ser; -alias ser_anyhit_closesthit_intersection = raytracing_stages_anyhit_closesthit_intersection + ser; -alias ser_anyhit_closesthit = raytracing_stages_anyhit_closesthit + ser; -alias ser_motion_raygen_closesthit_miss = raytracing_stages_raygen_closesthit_miss + ser_motion; -alias ser_motion_raygen = raytracing_stages_raygen + ser_motion; +alias ser_raygen = raygen + ser; +alias ser_raygen_closesthit_miss = raygen_closesthit_miss + ser; +alias ser_any_closesthit_intersection_miss = anyhit_closesthit_intersection_miss + ser; +alias ser_anyhit_closesthit_intersection = anyhit_closesthit_intersection + ser; +alias ser_anyhit_closesthit = anyhit_closesthit + ser; +alias ser_motion_raygen_closesthit_miss = raygen_closesthit_miss + ser_motion; +alias ser_motion_raygen = raygen + ser_motion; alias all = _sm_6_7 + hlsl_nvapi | glsl_spirv_1_5 + sm_6_7 diff --git a/source/slang/slang-capability.cpp b/source/slang/slang-capability.cpp index eae04f277..e77901b5b 100644 --- a/source/slang/slang-capability.cpp +++ b/source/slang/slang-capability.cpp @@ -25,11 +25,11 @@ enum class CapabilityNameFlavor : int32_t Concrete, // An abstract capability represents a class of feature - // where multiple different implementations might be possible. - // For example, "ray tracing" might be an abstract feature - // that a function can require, but a specific target will - // only be able to provide that abstract feature via some - // specific concrete feature (e.g., `GL_EXT_ray_tracing`). + // where multiple distinct implementations might be possible. + // 'raytracing' may be allowed with a 'raygen' "stage", but + // not a 'vertex' "stage" + // For more information (and a clearer description of the rules), + // read `slang-capabilities.capdef` Abstract, // An alias capability atom is one that is exactly equivalent @@ -490,9 +490,6 @@ CapabilitySet CapabilitySet::getTargetsThisHasButOtherDoesNot(const CapabilitySe return newSet; } -/// Join `this` with a compatble stage set of `CapabilityTargetSet other`. -/// Return false when `other` is fully incompatible. -/// incompatability is when `this->stage` is not a supported stage by `other.shaderStageSets`. bool CapabilityStageSet::tryJoin(const CapabilityTargetSet& other) { const CapabilityStageSet* otherStageSet = other.shaderStageSets.tryGetValue(this->stage); @@ -506,11 +503,6 @@ bool CapabilityStageSet::tryJoin(const CapabilityTargetSet& other) return true; } -/// Join a compatable target set from `this` with `CapabilityTargetSet other`. -/// Return false when `other` is fully incompatible. -/// incompatability is when one of 2 senarios are true: -/// 1. `this->target` is not a supported target by `other.shaderStageSets` -/// 2. `this` has completly disjoint shader stages from other. bool CapabilityTargetSet::tryJoin(const CapabilityTargetSets& other) { const CapabilityTargetSet* otherTargetSet = other.tryGetValue(this->target); @@ -631,9 +623,6 @@ bool CapabilitySet::hasSameTargets(const CapabilitySet& other) const #pragma warning(push) #pragma warning(disable:4702) #endif -/// returns true if 'this' is a better target for 'targetCaps' than 'that' -/// isEqual: is `this` and `that` equal -/// isIncompatible: is `this` and `that` incompatible bool CapabilitySet::isBetterForTarget(CapabilitySet const& that, CapabilitySet const& targetCaps, bool& isEqual) const { if (this->isEmpty() && (that.isEmpty() || that.isInvalid())) @@ -882,6 +871,16 @@ int TEST_findTargetStage( return capSet.getCapabilityTargetSets()[target].shaderStageSets.containsKey(stage); } + +int TEST_targetCapSetWithSpecificAtomInStage( + CapabilitySet& capSet, + CapabilityAtom target, + CapabilityAtom stage, + CapabilityAtom atom) +{ + return capSet.getCapabilityTargetSets()[target].shaderStageSets[stage].atomSet->contains((UInt)atom); +} + int TEST_targetCapSetWithSpecificSetInStage( CapabilitySet& capSet, CapabilityAtom target, @@ -943,8 +942,8 @@ void TEST_CapabilitySet_addAtom() testCapSet = CapabilitySet(CapabilityName::TEST_ADD_2); CHECK_CAPS(TEST_findTargetCapSet(testCapSet, CapabilityAtom::hlsl)); - CHECK_CAPS(TEST_targetCapSetWithSpecificSetInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::vertex, - { CapabilityAtom::textualTarget, CapabilityAtom::hlsl, CapabilityAtom::vertex, + CHECK_CAPS(TEST_targetCapSetWithSpecificSetInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::compute, + { CapabilityAtom::textualTarget, CapabilityAtom::hlsl, CapabilityAtom::compute, CapabilityAtom::_sm_4_0, CapabilityAtom::_sm_4_1 })); CHECK_CAPS(TEST_targetCapSetWithSpecificSetInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, { CapabilityAtom::textualTarget, CapabilityAtom::hlsl, CapabilityAtom::fragment, @@ -959,7 +958,54 @@ void TEST_CapabilitySet_addAtom() CHECK_CAPS(TEST_targetCapSetWithSpecificSetInStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment, { CapabilityAtom::textualTarget, CapabilityAtom::glsl, CapabilityAtom::fragment, CapabilityAtom::_GLSL_130 })); + + // ------------------------------------------------------------ + + testCapSet = CapabilitySet(CapabilityName::TEST_GEN_1); + + CHECK_CAPS(TEST_findTargetCapSet(testCapSet, CapabilityAtom::hlsl)); + CHECK_CAPS((int)!TEST_findTargetCapSet(testCapSet, CapabilityAtom::glsl)); + CHECK_CAPS(TEST_findTargetStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::vertex)); + CHECK_CAPS(TEST_findTargetStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_6_0)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_5_0)); + + // ------------------------------------------------------------ + + testCapSet = CapabilitySet(CapabilityName::TEST_GEN_2); + + CHECK_CAPS(TEST_findTargetCapSet(testCapSet, CapabilityAtom::hlsl)); + CHECK_CAPS((int)!TEST_findTargetCapSet(testCapSet, CapabilityAtom::glsl)); + CHECK_CAPS(TEST_findTargetStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_6_5)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_5_0)); + // ------------------------------------------------------------ + + testCapSet = CapabilitySet(CapabilityName::TEST_GEN_3); + + CHECK_CAPS(TEST_findTargetCapSet(testCapSet, CapabilityAtom::glsl)); + CHECK_CAPS(TEST_findTargetStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment, CapabilityAtom::_GL_NV_shader_texture_footprint)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment, CapabilityAtom::_GL_NV_compute_shader_derivatives)); + + // ------------------------------------------------------------ + + testCapSet = CapabilitySet(CapabilityName::TEST_GEN_4); + + CHECK_CAPS(TEST_findTargetCapSet(testCapSet, CapabilityAtom::glsl)); + CHECK_CAPS(TEST_findTargetStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment, CapabilityAtom::_GL_NV_shader_texture_footprint)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::glsl, CapabilityAtom::fragment, CapabilityAtom::_GL_ARB_shader_image_size)); + + // ------------------------------------------------------------ + + testCapSet = CapabilitySet(CapabilityName::TEST_GEN_5); + + CHECK_CAPS(TEST_findTargetCapSet(testCapSet, CapabilityAtom::hlsl)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_6_5)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_6_4)); + CHECK_CAPS(TEST_targetCapSetWithSpecificAtomInStage(testCapSet, CapabilityAtom::hlsl, CapabilityAtom::fragment, CapabilityAtom::_sm_6_0)); } void TEST_CapabilitySet_join() @@ -1034,15 +1080,15 @@ void TEST_CapabilitySet() /* /// Test Capabilities -alias TEST_ADD_1 = _sm_4_1 | _GLSL_130 | spirv_1_1 | metal - ; - -alias TEST_ADD_2 = _sm_4_1 | _sm_4_0 + shader_stages_compute_fragment - ; - -alias TEST_ADD_3 = _GLSL_130 + shader_stages_compute_fragment_geometry_vertex; +alias TEST_ADD_1 = _sm_4_1 | _GLSL_130 | spirv_1_1 | metal; +alias TEST_ADD_2 = _sm_4_1 |& _sm_4_0 + compute_fragment; +alias TEST_ADD_3 = _GLSL_130 + compute_fragment_geometry_vertex; -// +alias TEST_GEN_1 = _sm_6_5 + fragment | _sm_6_0 + vertex; +alias TEST_GEN_2 = _sm_6_5 + fragment; +alias TEST_GEN_3 = GL_NV_shader_texture_footprint + GL_NV_compute_shader_derivatives + fragment | _GL_NV_shader_texture_footprint + fragment; +alias TEST_GEN_4 = GL_ARB_shader_image_size |& GL_NV_shader_texture_footprint + fragment; +alias TEST_GEN_5 = sm_6_0 + compute_fragment| sm_6_5; alias TEST_JOIN_1A = hlsl; alias TEST_JOIN_1B = glsl; @@ -1065,6 +1111,13 @@ alias TEST_JOIN_3B = _sm_4_1 + fragment alias TEST_JOIN_4A = _GLSL_140 + _GL_EXT_texture_query_lod; alias TEST_JOIN_4B = _GLSL_150 + _GL_EXT_texture_shadow_lod; + +// Will cause capability generator failiure +alias TEST_ERROR_GEN_1 = GL_NV_shader_texture_footprint + GL_NV_compute_shader_derivatives + fragment | _GL_NV_shader_texture_footprint + _GL_NV_shader_atomic_fp16_vector + fragment; +alias TEST_ERROR_GEN_2 = GL_NV_shader_texture_footprint | GL_NV_ray_tracing_motion_blur; +alias TEST_ERROR_GEN_3 = GL_ARB_shader_image_size | GL_NV_shader_texture_footprint + fragment; +alias TEST_ERROR_GEN_4 = _sm_6_5 + fragment + vertex + cpp; + /// */ #undef CHECK_CAPS diff --git a/source/slang/slang-capability.h b/source/slang/slang-capability.h index 9e4bdb3a8..8bd03147e 100644 --- a/source/slang/slang-capability.h +++ b/source/slang/slang-capability.h @@ -73,6 +73,10 @@ struct CapabilityStageSet else atomSet->add(setToAdd); } + + /// Join `this` with a compatble stage set of `CapabilityTargetSet other`. + /// Return false when `other` is fully incompatible. + /// incompatability is when `this->stage` is not a supported stage by `other.shaderStageSets`. bool tryJoin(const CapabilityTargetSet& other); }; @@ -85,6 +89,11 @@ struct CapabilityTargetSet CapabilityStageSets shaderStageSets{}; + /// Join a compatable target set from `this` with `CapabilityTargetSet other`. + /// Return false when `other` is fully incompatible. + /// incompatability is when one of 2 senarios are true: + /// 1. `this->target` is not a supported target by `other.shaderStageSets` + /// 2. `this` has completly disjoint shader stages from other. bool tryJoin(const CapabilityTargetSets& other); void unionWith(const CapabilityTargetSet& other); }; @@ -157,6 +166,8 @@ public: void addCapability(List<List<CapabilityAtom>>& atomLists); /// Calculate a list of "compacted" atoms, which excludes any atoms from the expanded list that are implies by another item in the list. + /// returns true if 'this' is a better target for 'targetCaps' than 'that' + /// isEqual: is `this` and `that` equal bool isBetterForTarget(CapabilitySet const& that, CapabilitySet const& targetCaps, bool& isEqual) const; /// Find any capability sets which are in 'available' but not in 'required'. Return false if this situation occurs. diff --git a/source/slang/slang-serialize-ast-type-info.h b/source/slang/slang-serialize-ast-type-info.h index 1d7628cd4..a8f459247 100644 --- a/source/slang/slang-serialize-ast-type-info.h +++ b/source/slang/slang-serialize-ast-type-info.h @@ -101,7 +101,9 @@ struct SerialTypeInfo<CapabilityAtomSet> List<CapabilityAtomSet::Element> UIntSetBuffer; reader->getArray(src, UIntSetBuffer); - dst = CapabilityAtomSet(UIntSetBuffer); + dst = CapabilityAtomSet(); + for(Index i = 0; i < UIntSetBuffer.getCount(); i++) + dst.addRawElement(UIntSetBuffer[i], i); } }; @@ -244,11 +246,9 @@ struct SerialTypeInfo<CapabilitySet> auto& targetSets = dst.getCapabilityTargetSets(); targetSets.clear(); targetSets.reserve(items.getCount()); - Index iter = 0; for (auto& i : items) { targetSets[i.target] = i; - iter++; } } }; diff --git a/tools/slang-capability-generator/capability-generator-main.cpp b/tools/slang-capability-generator/capability-generator-main.cpp index c34b4c49e..a8e3e397d 100644 --- a/tools/slang-capability-generator/capability-generator-main.cpp +++ b/tools/slang-capability-generator/capability-generator-main.cpp @@ -30,6 +30,7 @@ struct CapabilityDef; struct CapabilityConjunctionExpr { List<CapabilityDef*> atoms; + SourceLoc sourceLoc; }; struct CapabilityDisjunctionExpr @@ -43,17 +44,60 @@ struct SerializedArrayView Index count; }; +struct CapabilitySharedContext +{ + CapabilityDef* ptrOfTarget = nullptr; + CapabilityDef* ptrOfStage = nullptr; +}; + +static void _removeFromOtherAtomsNotInThis(HashSet<const CapabilityDef*> thisSet, HashSet<const CapabilityDef*> otherSet, List<const CapabilityDef*> atomsToRemove) +{ + atomsToRemove.clear(); + atomsToRemove.reserve(otherSet.getCount()); + for (auto keyAtom : otherSet) + { + if (thisSet.contains(keyAtom)) + continue; + atomsToRemove.add(keyAtom); + } + + for (auto atomToRemove : atomsToRemove) + otherSet.remove(atomToRemove); +} + struct CapabilityDef : public RefObject { - Index enumValue; +public: + void operator=(const CapabilityDef& other) + { + this->name = other.name; + this->enumValue = other.enumValue; + this->expr = other.expr; + this->flavor = other.flavor; + this->rank = other.rank; + this->canonicalRepresentation = other.canonicalRepresentation; + this->serializedCanonicalRepresentation = other.serializedCanonicalRepresentation; + this->sourceLoc = other.sourceLoc; + this->keyAtomsPresent = other.keyAtomsPresent; + this->sharedContext = other.sharedContext; + } + String name; + Index enumValue; CapabilityDisjunctionExpr expr; CapabilityFlavor flavor; - int rank; + /// optional, 0 is default rank. + int rank = 0; List<List<CapabilityDef*>> canonicalRepresentation; SerializedArrayView serializedCanonicalRepresentation; + SourceLoc sourceLoc; + /// Stores key atoms a CapabilityDef refers to. + /// Shared key atoms: key atoms shared between every individual set in a canonicalRepresentation, added together. + HashSet<const CapabilityDef*> keyAtomsPresent; - CapabilityDef* getAbstractBase() + CapabilitySharedContext* sharedContext; + + CapabilityDef* getAbstractBase() const { if (flavor != CapabilityFlavor::Normal) return nullptr; @@ -65,13 +109,80 @@ struct CapabilityDef : public RefObject return nullptr; return expr.conjunctions[0].atoms[0]; } + + void fillKeyAtomsPresentInCannonicalRepresentation() + { + HashSet<const CapabilityDef*> sharedKeyAtomsInCanonicalSet_target; + HashSet<const CapabilityDef*> sharedKeyAtomsInCanonicalSet_stage; + HashSet<const CapabilityDef*> keyAtomsFound; + List<const CapabilityDef*> atomsToRemove; + for (auto& canonicalSet : canonicalRepresentation) + { + bool alreadySetTarget = false; + bool alreadySetStage = false; + sharedKeyAtomsInCanonicalSet_target.clear(); + sharedKeyAtomsInCanonicalSet_stage.clear(); + + // find key atoms all atoms in a canonical set share. + for (auto& atom : canonicalSet) + { + bool foundTarget = false; + bool foundStage = false; + for (auto otherkeyAtomsPresent : atom->keyAtomsPresent) + { + auto base = otherkeyAtomsPresent->getAbstractBase(); + // add all `target` key atoms associated with atom in canonicalSet + if (base == sharedContext->ptrOfTarget) + { + foundTarget = true; + if (!alreadySetTarget) + sharedKeyAtomsInCanonicalSet_target.add(otherkeyAtomsPresent); + } + // add all `stage` key atoms associated with atom in canonicalSet + else if (base == sharedContext->ptrOfStage) + { + foundStage = true; + if(!alreadySetTarget) + sharedKeyAtomsInCanonicalSet_stage.add(otherkeyAtomsPresent); + } + // all key atoms associated with atom + keyAtomsFound.add(otherkeyAtomsPresent); + } + + // remove all not shared key atoms + if (foundTarget) + { + alreadySetTarget = true; + _removeFromOtherAtomsNotInThis(keyAtomsFound, sharedKeyAtomsInCanonicalSet_target, atomsToRemove); + } + if (foundStage) + { + alreadySetStage = true; + _removeFromOtherAtomsNotInThis(keyAtomsFound, sharedKeyAtomsInCanonicalSet_stage, atomsToRemove); + } + keyAtomsFound.clear(); + } + + // add all shared key atoms + for (auto keyAtom : sharedKeyAtomsInCanonicalSet_target) + this->keyAtomsPresent.add(keyAtom); + for (auto keyAtom : sharedKeyAtomsInCanonicalSet_stage) + this->keyAtomsPresent.add(keyAtom); + } + if (auto base = this->getAbstractBase()) + keyAtomsPresent.add(this); + } }; struct CapabilityDefParser { - CapabilityDefParser(Lexer* lexer, DiagnosticSink* sink) + CapabilityDefParser( + Lexer* lexer, + DiagnosticSink* sink, + CapabilitySharedContext& sharedContext) : m_lexer(lexer) , m_sink(sink) + , m_sharedContext(sharedContext) { } @@ -80,6 +191,7 @@ struct CapabilityDefParser Dictionary<String, CapabilityDef*> m_mapNameToCapability; List<RefPtr<CapabilityDef>> m_defs; + CapabilitySharedContext& m_sharedContext; TokenReader m_tokenReader; @@ -126,7 +238,7 @@ struct CapabilityDefParser m_sink->diagnose(nameToken.loc, Diagnostics::undefinedIdentifier, nameToken); return SLANG_FAIL; } - if (!(advanceIf(TokenType::OpAnd) || advanceIf(TokenType::OpAdd))) + if (!(advanceIf(TokenType::OpAdd))) break; } return SLANG_OK; @@ -137,6 +249,7 @@ struct CapabilityDefParser for (;;) { CapabilityConjunctionExpr conjunction; + conjunction.sourceLoc = this->m_tokenReader.m_cursor->getLoc(); SLANG_RETURN_ON_FAIL(parseConjunction(conjunction)); expr.conjunctions.add(conjunction); if (!advanceIf(TokenType::OpBitOr)) @@ -152,6 +265,7 @@ struct CapabilityDefParser for (;;) { RefPtr<CapabilityDef> def = new CapabilityDef(); + def->sharedContext = &m_sharedContext; def->flavor = CapabilityFlavor::Normal; auto nextToken = m_tokenReader.advanceToken(); if (nextToken.getContent() == "alias") @@ -207,11 +321,21 @@ struct CapabilityDefParser } SLANG_RETURN_ON_FAIL(readToken(TokenType::Semicolon)); m_defs.add(def); - if (!m_mapNameToCapability.addIfNotExists(def->name, def)) + if (!m_mapNameToCapability.addIfNotExists(def->name, m_defs.getLast())) { m_sink->diagnose(nextToken.loc, Diagnostics::redefinition, def->name); return SLANG_FAIL; } + + //set abstract atom identifiers + if (!m_sharedContext.ptrOfTarget + && def->name.equals("target")) + m_sharedContext.ptrOfTarget = m_defs.getLast(); + else if (!m_sharedContext.ptrOfStage + && def->name.equals("stage")) + m_sharedContext.ptrOfStage = m_defs.getLast(); + + def->sourceLoc = nameToken.loc; } return SLANG_OK; } @@ -220,6 +344,24 @@ struct CapabilityDefParser struct CapabilityConjunction { HashSet<CapabilityDef*> atoms; + + String toString() const + { + bool first = true; + String result = "["; + for (auto atom : atoms) + { + if (!first) + { + result.append(" + "); + } + first = false; + result.append(atom->name); + } + result.appendChar(']'); + return result; + } + bool implies(const CapabilityConjunction& c) const { for (auto& atom : c.atoms) @@ -230,6 +372,41 @@ struct CapabilityConjunction return true; } + const CapabilityDef* getAbstractAtom(CapabilityDef* defToFilterFor) const + { + for (auto* atom : this->atoms) + { + for (auto present : atom->keyAtomsPresent) + { + auto base = present->getAbstractBase(); + if (base != defToFilterFor) + continue; + return present; + } + } + return nullptr; + } + + bool shareTargetAndStageAtom(const CapabilityConjunction& other, CapabilitySharedContext& context) + { + // shared target means thisTarget==otherTarget + // shared stage means either `nostage + ...` or `stage == stage` + + const CapabilityDef* thisTarget = this->getAbstractAtom(context.ptrOfTarget); + const CapabilityDef* otherTarget = other.getAbstractAtom(context.ptrOfTarget); + + if (thisTarget != otherTarget && thisTarget && otherTarget) + return false; + + const CapabilityDef* thisStage = this->getAbstractAtom(context.ptrOfStage); + const CapabilityDef* otherStage = other.getAbstractAtom(context.ptrOfStage); + + if (thisStage != otherStage && thisStage && otherStage) + return false; + + return true; + } + bool isImpossible() const { // Keep a map from an abstract base to the concrete atom defined in this conjunction that implements the base. @@ -263,7 +440,78 @@ struct CapabilityDisjunction { List<CapabilityConjunction> conjunctions; - void addConjunction(const CapabilityConjunction& c) + void addConjunction(DiagnosticSink* sink, SourceLoc sourceLoc, CapabilitySharedContext& context, CapabilityConjunction& c) + { + if (c.isImpossible()) + return; + bool cImpliesThis = false; + for (Index i = 0; i < conjunctions.getCount();) + { + // implied sets will be replaced + if (c.implies(conjunctions[i])) + { + cImpliesThis = true; + conjunctions.fastRemoveAt(i); + } + else + i++; + } + if (cImpliesThis) + { + conjunctions.add(_Move(c)); + return; + } + + for (Index i = 0; i < conjunctions.getCount();) + { + if (conjunctions[i].implies(c)) + { + // subset is implied, we do not need to add it. + return; + } + else + { + // validate we are not creating a disjunction of same targets + if (conjunctions[i].shareTargetAndStageAtom(c, context)) + { + if (sink) + { + sink->diagnose(sourceLoc, Diagnostics::unionWithSameKeyAtomButNotSubset, conjunctions[i].toString(), c.toString()); + sink = nullptr; + } + } + i++; + } + } + conjunctions.add(_Move(c)); + } + void removeImplied() + { + for (Index i = 0; i < conjunctions.getCount(); i++) + { + for (Index ii = 0; ii < conjunctions.getCount(); ii++) + { + if (ii == i) + continue; + + if (!conjunctions[i].implies(conjunctions[ii])) + continue; + + if(i < ii) + { + conjunctions.fastRemoveAt(ii); + } + else + { + conjunctions.removeAt(ii); + i--; + } + ii--; + } + } + } + + void inclusiveJoinConjunction(CapabilitySharedContext& context, CapabilityConjunction& c, List<CapabilityConjunction>& toAddAfter) { if (c.isImpossible()) return; @@ -274,9 +522,15 @@ struct CapabilityDisjunction } for (Index i = 0; i < conjunctions.getCount();) { - if (conjunctions[i].implies(c)) + if (conjunctions[i].shareTargetAndStageAtom(c, context)) { - conjunctions.fastRemoveAt(i); + CapabilityConjunction toAddAfterSet; + for (auto atom : conjunctions[i].atoms) + toAddAfterSet.atoms.add(atom); + for (auto atom : c.atoms) + toAddAfterSet.atoms.add(atom); + toAddAfter.add(toAddAfterSet); + return; } else { @@ -286,7 +540,7 @@ struct CapabilityDisjunction conjunctions.add(_Move(c)); } - CapabilityDisjunction joinWith(const CapabilityDisjunction& other) + CapabilityDisjunction joinWith(DiagnosticSink* sink, SourceLoc sourceLoc, CapabilitySharedContext& context, const CapabilityDisjunction& other) { if (conjunctions.getCount() == 0) { @@ -308,9 +562,14 @@ struct CapabilityDisjunction newC.atoms.add(atom); for (auto atom : thatC.atoms) newC.atoms.add(atom); - result.addConjunction(_Move(newC)); + result.addConjunction(sink, sourceLoc, context, newC); } } + + // incompatible abstract atoms + if (result.conjunctions.getCount() == 0) + sink->diagnose(sourceLoc, Diagnostics::invalidJoinInGenerator); + return result; } @@ -353,18 +612,18 @@ CapabilityDisjunction getCanonicalRepresentation(CapabilityDef* def) return result; } -CapabilityDisjunction evaluateConjunction(const List<CapabilityDef*>& atoms) +CapabilityDisjunction evaluateConjunction(DiagnosticSink* sink, SourceLoc sourceLoc, CapabilitySharedContext& context, const List<CapabilityDef*>& atoms) { CapabilityDisjunction result; - for (auto& def : atoms) + for (auto* def : atoms) { CapabilityDisjunction defCanonical = getCanonicalRepresentation(def); - result = result.joinWith(defCanonical); + result = result.joinWith(sink, sourceLoc, context, defCanonical); } return result; } -void calcCanonicalRepresentation(CapabilityDef* def, const List<CapabilityDef*>& mapEnumValueToDef) +void calcCanonicalRepresentation(DiagnosticSink* sink, CapabilityDef* def, const List<CapabilityDef*>& mapEnumValueToDef) { CapabilityDisjunction disjunction; if (def->flavor == CapabilityFlavor::Normal) @@ -376,54 +635,47 @@ void calcCanonicalRepresentation(CapabilityDef* def, const List<CapabilityDef*>& CapabilityDisjunction exprVal; for (auto& c : def->expr.conjunctions) { - CapabilityDisjunction evalD = evaluateConjunction(c.atoms); + CapabilityDisjunction evalD = evaluateConjunction(sink, c.sourceLoc, *def->sharedContext, c.atoms); + List<CapabilityConjunction> toAddAfter; for (auto& cc : evalD.conjunctions) - exprVal.addConjunction(cc); + { + exprVal.inclusiveJoinConjunction(*def->sharedContext, cc, toAddAfter); + } + for (auto& i : toAddAfter) + exprVal.conjunctions.add(i); + if (toAddAfter.getCount() > 0) + exprVal.removeImplied(); } - disjunction = disjunction.joinWith(exprVal); + disjunction = disjunction.joinWith(sink, def->sourceLoc, *def->sharedContext, exprVal); def->canonicalRepresentation = disjunction.canonicalize(); + def->fillKeyAtomsPresentInCannonicalRepresentation(); } -void calcCanonicalRepresentations(const List<RefPtr<CapabilityDef>>& defs, const List<CapabilityDef*>& mapEnumValueToDef) +void calcCanonicalRepresentations(DiagnosticSink* sink, List<RefPtr<CapabilityDef>>& defs, const List<CapabilityDef*>& mapEnumValueToDef) { for (auto def : defs) - calcCanonicalRepresentation(def, mapEnumValueToDef); -} - -const Index kUnusedEnumValue = -1; - -// Check if "def" uses a named ("name"/enumValueOfAbstract) abstract atom. If true, assign -// the enumValue of the found abstract atom (cache the unique ID) and increment counter. -bool maybeProcessConcreteAtomForAbstractCapability(CapabilityDef* def, Index& enumValueOfAbstract, const String& name, Index& counter) -{ - if (def->getAbstractBase() - && ( - (enumValueOfAbstract == def->getAbstractBase()->enumValue) - || - (enumValueOfAbstract == kUnusedEnumValue && def->getAbstractBase()->name.equals(name)) - ) - ) - { - counter++; - enumValueOfAbstract = def->getAbstractBase()->enumValue; - return true; - } - return false; + calcCanonicalRepresentation(sink, def, mapEnumValueToDef); } void outputUIntSetAsBufferValues(const String& nameOfBuffer, StringBuilder& resultBuilder, UIntSet& set) { // store UIntSet::Element as uint8_t to stay sizeof(UIntSet::Element) independent. // underlying type may change, bits stay the same. - resultBuilder << "const static CapabilityAtomSet " << nameOfBuffer << " = CapabilityAtomSet({\n"; - for (auto i : set.getBuffer()) + resultBuilder << "inline static CapabilityAtomSet generate_" << nameOfBuffer << "()\n"; + resultBuilder << "{\n"; + resultBuilder << " CapabilityAtomSet generatedSet;\n"; + + for (Index i = 0; i < set.getBuffer().getCount(); i++) { - resultBuilder << " UIntSet::Element(" << i << "U),\n"; + resultBuilder << " generatedSet.addRawElement(UIntSet::Element(" << set.getBuffer()[i] << "), " << i << ");\n"; } - resultBuilder << " 0\n});\n"; + resultBuilder << " return generatedSet;\n"; + resultBuilder << "}\n"; + + resultBuilder << "const static CapabilityAtomSet " << nameOfBuffer << " = generate_" << nameOfBuffer << "();\n"; } -SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringBuilder& sbHeader, StringBuilder& sbCpp) +SlangResult generateDefinitions(DiagnosticSink* sink, List<RefPtr<CapabilityDef>>& defs, StringBuilder& sbHeader, StringBuilder& sbCpp) { sbHeader << "enum class CapabilityAtom\n{\n"; @@ -482,9 +734,7 @@ SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringB sbHeader << " Count\n"; sbHeader << "};\n"; - Index enumValueOfTarget = kUnusedEnumValue; Index targetCount = 0; - Index enumValueOfStage = kUnusedEnumValue; Index stageCount = 0; UIntSet anyTargetAtomSet{}; @@ -494,10 +744,16 @@ SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringB for (auto def : defs) { - if (maybeProcessConcreteAtomForAbstractCapability(def.get(), enumValueOfTarget, "target", targetCount)) + if (def->getAbstractBase() == def->sharedContext->ptrOfTarget) + { + targetCount++; anyTargetAtomSet.add(def->enumValue); - else if (maybeProcessConcreteAtomForAbstractCapability(def.get(), enumValueOfStage, "stage", stageCount)) + } + else if (def->getAbstractBase() == def->sharedContext->ptrOfStage) + { + stageCount++; anyStageAtomSet.add(def->enumValue); + } } outputUIntSetAsBufferValues("kAnyTargetUIntSetBuffer", anyTargetUIntSetHash, anyTargetAtomSet); outputUIntSetAsBufferValues("kAnyStageUIntSetBuffer", anyStageUIntSetHash, anyStageAtomSet); @@ -507,8 +763,7 @@ SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringB sbHeader << " kCapabilityStageCount = " << stageCount << ",\n"; sbHeader << "};\n\n"; - calcCanonicalRepresentations(defs, mapEnumValueToDef); - + calcCanonicalRepresentations(sink, defs, mapEnumValueToDef); List<String> capabiltiyNameArray; List<SerializedArrayView> serializedCapabilityArrays; @@ -554,7 +809,7 @@ SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringB result.count = conjunctions.getCount(); return result; }; - for (auto& def : defs) + for (auto def : defs) { List<SerializedArrayView> conjunctions; for (auto& c : def->canonicalRepresentation) @@ -589,7 +844,7 @@ SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringB sbCpp << "};\n"; sbCpp << "static const CapabilityAtomInfo kCapabilityNameInfos[int(CapabilityName::Count)] = {\n"; - for (auto def : mapEnumValueToDef) + for (auto* def : mapEnumValueToDef) { if (!def) { @@ -636,7 +891,7 @@ SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringB } -SlangResult parseDefFile(DiagnosticSink* sink, String inputPath, List<RefPtr<CapabilityDef>>& outDefs) +SlangResult parseDefFile(DiagnosticSink* sink, String inputPath, List<RefPtr<CapabilityDef>>& outDefs, CapabilitySharedContext& capabilitySharedContext) { auto sourceManager = sink->getSourceManager(); @@ -651,7 +906,7 @@ SlangResult parseDefFile(DiagnosticSink* sink, String inputPath, List<RefPtr<Cap namePool.setRootNamePool(&rootPool); lexer.initialize(sourceView, sink, &namePool, sourceManager->getMemoryArena()); - CapabilityDefParser parser(&lexer, sink); + CapabilityDefParser parser(&lexer, sink, capabilitySharedContext); SLANG_RETURN_ON_FAIL(parser.parseDefs()); outDefs = _Move(parser.m_defs); @@ -708,15 +963,17 @@ int main(int argc, const char* const* argv) sourceManager.initialize(nullptr, OSFileSystem::getExtSingleton()); DiagnosticSink sink(&sourceManager, nullptr); List<RefPtr<CapabilityDef>> defs; - if (SLANG_FAILED(parseDefFile(&sink, inPath, defs))) + CapabilitySharedContext capabilitySharedContext; + if (SLANG_FAILED(parseDefFile(&sink, inPath, defs, capabilitySharedContext))) { printDiagnostics(&sink); return 1; } StringBuilder sbHeader, sbCpp; - if (SLANG_FAILED(generateDefinitions(defs, sbHeader, sbCpp))) + if (SLANG_FAILED(generateDefinitions(&sink, defs, sbHeader, sbCpp))) { + printDiagnostics(&sink); return 1; } @@ -734,5 +991,6 @@ int main(int argc, const char* const* argv) printDiagnostics(&sink); return 1; } + printDiagnostics(&sink); return 0; } diff --git a/tools/slang-capability-generator/slang-capability-diagnostic-defs.h b/tools/slang-capability-generator/slang-capability-diagnostic-defs.h index a9436cd9c..1415b1f59 100644 --- a/tools/slang-capability-generator/slang-capability-diagnostic-defs.h +++ b/tools/slang-capability-generator/slang-capability-diagnostic-defs.h @@ -54,4 +54,6 @@ DIAGNOSTIC(20001, Error, unexpectedEOF, " Unexpected end of file.") DIAGNOSTIC(20002, Error, syntaxError, "syntax error.") DIAGNOSTIC(20003, Error, undefinedIdentifier, "undefined identifier \"$0\".") DIAGNOSTIC(20004, Error, redefinition, "capability redefinition: '$0'.") +DIAGNOSTIC(20005, Error, unionWithSameKeyAtomButNotSubset, "unioning ('|') capability sets which have incompatible atoms but compatible 'key atoms', this: '$0', other: '$1'") +DIAGNOSTIC(20006, Error, invalidJoinInGenerator, "joining ('+') capability sets which have incompatible 'key atoms'") #undef DIAGNOSTIC |
