summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/command-line-slangc-reference.mdbin78370 -> 77996 bytes
-rw-r--r--source/core/core.natvis82
-rw-r--r--source/core/slang-uint-set.h80
-rw-r--r--source/slang/hlsl.meta.slang2
-rw-r--r--source/slang/slang-capabilities.capdef125
-rw-r--r--source/slang/slang-capability.cpp105
-rw-r--r--source/slang/slang-capability.h11
-rw-r--r--source/slang/slang-serialize-ast-type-info.h6
-rw-r--r--tools/slang-capability-generator/capability-generator-main.cpp374
-rw-r--r--tools/slang-capability-generator/slang-capability-diagnostic-defs.h2
10 files changed, 555 insertions, 232 deletions
diff --git a/docs/command-line-slangc-reference.md b/docs/command-line-slangc-reference.md
index df913c0b5..7c2beb7e0 100644
--- a/docs/command-line-slangc-reference.md
+++ b/docs/command-line-slangc-reference.md
Binary files differ
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&lt;*,*&gt;">
+ <DisplayString>{{ {map.m_values} }}</DisplayString>
+ <Expand>
+ <Item Name="[items]">map.m_values</Item>
+ <Item Name="map">map</Item>
+ </Expand>
+</Type>
+
+<Type Name="Slang::HashSet&lt;*&gt;">
+ <DisplayString>{{ {dict} }}</DisplayString>
+ <Expand>
+ <Item Name="dict">dict</Item>
+ </Expand>
+</Type>
+
+<Type Name="Slang::OrderedHashSet&lt;*&gt;">
+ <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&lt;*,*&gt;">
<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 &gt;= m_bucketCountMinusOne">
- <Break/>
- </If>
- <Exec>
- isDeleted = m_marks.m_buffer.m_count &gt; (iBucket*2+1)/32
- ? ((m_marks.m_buffer.m_buffer[(iBucket*2+1)/32]&amp;(1&lt;&lt;(iBucket*2+1)%32)) != 0)
- : 0
- </Exec>
- <Exec>
- isEmpty = m_marks.m_buffer.m_count &gt; (iBucket*2)/32
- ? ((m_marks.m_buffer.m_buffer[(iBucket*2)/32]&amp;(1&lt;&lt;(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&lt;*&gt;">
- <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&lt;*,*&gt;">
- <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&lt;*&gt;">
<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