summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/build_reference.ps11
-rw-r--r--source/slang/core.meta.slang402
-rw-r--r--source/slang/hlsl.meta.slang22
-rw-r--r--source/slang/slang-doc-markdown-writer.cpp165
-rw-r--r--source/slang/slang-doc-markdown-writer.h9
-rw-r--r--source/slang/slang-mangle.cpp5
-rw-r--r--source/slang/slang.cpp2
7 files changed, 558 insertions, 48 deletions
diff --git a/docs/build_reference.ps1 b/docs/build_reference.ps1
index d08d7b30d..ebf745244 100644
--- a/docs/build_reference.ps1
+++ b/docs/build_reference.ps1
@@ -26,6 +26,7 @@ else {
Remove-Item -Path ".\stdlib-reference\global-decls" -Recurse -Force
Remove-Item -Path ".\stdlib-reference\interfaces" -Recurse -Force
Remove-Item -Path ".\stdlib-reference\types" -Recurse -Force
+Remove-Item -Path ".\stdlib-reference\attributes" -Recurse -Force
# Use git describe to produce a version string and write it to _includes/version.inc.
# This file will be included by the stdlib-reference Jekyll template.
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index d0f0fcee2..084654d0f 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -159,6 +159,37 @@ interface ILogical : IComparable
__init(int val);
}
+/// Represent a type that can be used for integer arithmetic operations.
+///
+/// Implemented by builtin scalar types: `int`, `uint`, `int64_t`, `uint64_t`, `int8_t`, `uint8_t`, `int16_t`, `uint16_t`.
+///
+/// Also implemented by `vector<T, N>` where `T` is one of the above scalar types.
+///
+/// @remarks This interface can be used to define generic functions that work with integer-like types. See example below.
+/// @example The following code defines a generic function that computes `a*b+1`, where `a`, `b` can be any integer scalar or vector types.
+/// ```csharp
+/// T compute<T:IInteger>(T a, T b)
+/// {
+/// return a * b + T(1);
+/// }
+///
+/// RWStructuredBuffer<int> outputBuffer;
+///
+/// [numthreads(1,1,1)]
+/// void test()
+/// {
+/// int a = 2;
+/// int b = 3;
+/// outputBuffer[0] = compute(a, b); // result = 2*3 + 1 = 7
+///
+/// int16_t2 a2 = int16_t2(2, 3);
+/// int16_t2 b2 = int16_t2(4, 5);
+/// // result2 = int16_t2(2*4 + 1, 3*5 + 1) = int16_t2(9, 16)
+/// int16_t2 result2 = compute<int16_t2>(a2, b2);
+/// outputBuffer[1] = result2.x;
+/// }
+/// ```
+///
interface IInteger : IArithmetic, ILogical
{
int toInt();
@@ -169,6 +200,37 @@ interface IInteger : IArithmetic, ILogical
__init(int64_t val);
}
+/// Represent a type that can be used for floating point arithmetic operations.
+///
+/// Implemented by builtin scalar types: `float`, `half`, `double`.
+///
+/// Also implemented by `vector<T, N>` where `T` is one of the above scalar types.
+///
+/// @remarks This interface can be used to define generic functions that work with floating-point-like types. See example below.
+/// @example The following code defines a generic function that computes `a*b+1`, where `a`, `b` can be any floating point scalar or vector types.
+/// ```csharp
+/// T compute<T:IFloat>(T a, T b)
+/// {
+/// return a * b + T(1.0f);
+/// }
+///
+/// RWStructuredBuffer<float> outputBuffer;
+///
+/// [numthreads(1,1,1)]
+/// void test()
+/// {
+/// float a = 2.0;
+/// float b = 3.0;
+/// outputBuffer[0] = compute(a, b); // result = 2.0*3.0 + 1.0 = 7.0
+///
+/// half2 a2 = half2(2.0h, 3.0h);
+/// half2 b2 = half2(4.0h, 5.0h);
+/// // result2 = half2(2*4 + 1, 3*5 + 1) = half2(9, 16)
+/// half2 result2 = compute(a2, b2);
+/// outputBuffer[1] = result2.x;
+/// }
+/// ```
+///
interface IFloat : IArithmetic, IDifferentiable
{
[TreatAsDifferentiable]
@@ -209,32 +271,35 @@ interface __BuiltinType
{
}
-/// A type that can be used for arithmetic operations
+/// A type that can be used for arithmetic operations. For defining generic functions that work with builtin scalar arithmetic types only.
+/// Builtin types implementing this interface: `int`, `uint`, `int64_t`, `uint64_t`, `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `float`, `half`, `double`.
+/// To define generic functions that work with both scalar and vector types, use `IInteger` or `IFloat` instead.
[sealed]
[builtin]
interface __BuiltinArithmeticType : __BuiltinType, IArithmetic
{
}
-/// A type that can be used for logical/bitwise operations
+/// A type that can be used for logical/bitwise operations. For defining generic functions that work with builtin scalar logical types only.
+/// Builtin types implementing this interface: `bool`, `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `int`, `uint`, `int64_t`, `uint64_t`.
[sealed]
[builtin]
interface __BuiltinLogicalType : __BuiltinType, ILogical
{
}
-/// A type that logically has a sign (positive/negative/zero)
+/// Represent builtin types that logically have a sign (positive/negative/zero).
[sealed]
[builtin]
interface __BuiltinSignedArithmeticType : __BuiltinArithmeticType {}
-/// A type that can represent integers
+/// Represent builtin types that can represent integers.
[sealed]
[builtin]
interface __BuiltinIntegerType : __BuiltinArithmeticType, IInteger
{}
-/// A type that can represent non-integers
+/// Represent builtin types that can represent a real number.
[sealed]
[builtin]
interface __BuiltinRealType : __BuiltinSignedArithmeticType {}
@@ -404,7 +469,8 @@ struct DifferentialPtrPair : IDifferentiablePtrType
};
-/// A type that uses a floating-point representation
+/// Represents builtin floating point scalar types.
+/// To define generic functions that work with both scalar and vector types, use `IFloat` instead.
[sealed]
[builtin]
[TreatAsDifferentiable]
@@ -490,6 +556,10 @@ __intrinsic_op($(kIROp_IntCast))
T __intCast<T : __BuiltinType, U : __BuiltinType>(U val);
//@hidden:
+__intrinsic_op($(kIROp_CastIntToFloat))
+T __castIntToFloat<T:__BuiltinType, U:__BuiltinType>(U v);
+
+//@hidden:
${{{{
// We are going to use code generation to produce the
// declarations for all of our base types.
@@ -1294,6 +1364,56 @@ __intrinsic_op($(kIROp_Eql))
vector<bool, N> __vectorEql<T, let N : int>(vector<T, N> left, vector<T, N> right);
//@public:
+__generic<T:__BuiltinIntegerType, let N : int>
+extension vector<T,N> : IInteger
+{
+ [__unsafeForceInlineEarly] bool lessThan(This other) { return this[0] < other[0]; }
+ [__unsafeForceInlineEarly] bool lessThanOrEquals(This other) { return this[0] <= other[0]; }
+ [__unsafeForceInlineEarly] bool equals(This other) { return all(__vectorEql(this, other)); }
+ __intrinsic_op($(kIROp_Add)) This add(This other);
+ __intrinsic_op($(kIROp_Sub)) This sub(This other);
+ __intrinsic_op($(kIROp_Mul)) This mul(This other);
+ __intrinsic_op($(kIROp_Div)) This div(This other);
+ __intrinsic_op($(kIROp_FRem)) This mod(This other);
+ __intrinsic_op($(kIROp_Neg)) This neg();
+
+ __intrinsic_op($(kIROp_Lsh))
+ This shl(int value);
+
+ __intrinsic_op($(kIROp_Rsh))
+ This shr(int value);
+
+ __intrinsic_op($(kIROp_BitAnd))
+ This bitAnd(This other);
+
+ __intrinsic_op($(kIROp_BitOr))
+ This bitOr(This other);
+
+ __intrinsic_op($(kIROp_BitXor))
+ This bitXor(This other);
+
+ __intrinsic_op($(kIROp_BitNot))
+ This bitNot();
+
+ __intrinsic_op($(kIROp_And))
+ This and(This other);
+
+ __intrinsic_op($(kIROp_Or))
+ This or(This other);
+
+ __intrinsic_op($(kIROp_Not))
+ This not();
+
+ [__unsafeForceInlineEarly] int toInt() { return __intCast<int>(this[0]); }
+ [__unsafeForceInlineEarly] int64_t toInt64() { return __intCast<int64_t>(this[0]); }
+ [__unsafeForceInlineEarly] uint toUInt() { return __intCast<uint>(this[0]); }
+ [__unsafeForceInlineEarly] uint64_t toUInt64() { return __intCast<uint64_t>(this[0]); }
+ [OverloadRank(-1)]
+ [__unsafeForceInlineEarly] __init(int v) { this = vector<T,N>(T(v)); }
+ [OverloadRank(-1)]
+ [__unsafeForceInlineEarly] __init(int64_t v) { this = vector<T,N>(T(v)); }
+}
+
__generic<T:__BuiltinFloatingPointType, let N : int>
extension vector<T,N> : IFloat
{
@@ -2791,8 +2911,16 @@ enum MemoryOrder
SeqCst = $(kIRMemoryOrder_SeqCst),
}
+/// Represent types that can be used in any atomic operations.
+/// Implemented by builtin scalar types: `int`, `uint`, `int64_t`, `uint64_t`, `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `float`, `double` and `half`.
[sealed] interface IAtomicable {}
+
+/// Represent types that can be used in atomic arithmetic operations.
+/// Implemented by builtin scalar types: `int`, `uint`, `int64_t`, `uint64_t`, `int8_t`, `uint8_t`, `int16_t`, `uint16_t`, `float`, `double` and `half`.
[sealed] interface IArithmeticAtomicable : IAtomicable, IArithmetic {}
+
+/// Represent types that can be used in atomic bit operations.
+/// Implemented by builtin scalar types: `int`, `uint`, `int64_t`, `uint64_t`, `int8_t`, `uint8_t`, `int16_t`, `uint16_t`.
[sealed] interface IBitAtomicable : IArithmeticAtomicable, IInteger {}
extension int : IBitAtomicable {}
@@ -2912,138 +3040,225 @@ __postfix T operator --(__ref Atomic<T> v)
}
// Binding Attributes
+//@public:
+
+/// Declare the Vulkan binding location of a global shader variable.
+/// @param binding The binding location.
+/// @param set The descriptor set index of the binding.
__attributeTarget(DeclBase)
attribute_syntax [vk_binding(binding: int, set: int = 0)] : GLSLBindingAttribute;
+/// Declare the Vulkan binding location of a global shader variable.
+/// @param binding The binding location.
+/// @param set The descriptor set index of the binding.
__attributeTarget(DeclBase)
attribute_syntax [gl_binding(binding: int, set: int = 0)] : GLSLBindingAttribute;
+/// Mark a global variable as a Vulkan shader record.
__attributeTarget(VarDeclBase)
attribute_syntax [vk_shader_record] : ShaderRecordAttribute;
+
+/// Mark a global variable as a Vulkan shader record.
__attributeTarget(VarDeclBase)
attribute_syntax [shader_record] : ShaderRecordAttribute;
+/// Mark a global variable as a Vulkan push constant.
__attributeTarget(VarDeclBase)
attribute_syntax [vk_push_constant] : PushConstantAttribute;
+
+/// Mark a global variable as a Vulkan push constant.
__attributeTarget(VarDeclBase)
attribute_syntax [push_constant] : PushConstantAttribute;
+/// Mark a global variable as a Vulkan specialization constant.
__attributeTarget(VarDeclBase)
attribute_syntax[vk_specialization_constant] : SpecializationConstantAttribute;
+/// Mark a global variable as a Vulkan specialization constant.
__attributeTarget(VarDeclBase)
attribute_syntax[SpecializationConstant] : SpecializationConstantAttribute;
+/// Mark a global variable as a Vulkan specialization constant.
+/// @param location The index of the specialization constant.
__attributeTarget(VarDeclBase)
attribute_syntax[vk_constant_id(location: int)] : VkConstantIdAttribute;
+/// Declare the Vulkan location of a global variable.
__attributeTarget(VarDeclBase)
attribute_syntax [vk_location(location : int)] : GLSLLocationAttribute;
+/// Declare the Vulkan binding index of a global variable.
__attributeTarget(VarDeclBase)
attribute_syntax [vk_index(index : int)] : GLSLIndexAttribute;
+/// @deprecated
+/// Use `spirv_asm` instead for inline SPIR-V assembly.
__attributeTarget(FuncDecl)
attribute_syntax [vk_spirv_instruction(op : int, set : String = "")] : SPIRVInstructionOpAttribute;
+/// Declare the Vulkan input attachment index of a global variable.
__attributeTarget(VarDeclBase)
attribute_syntax [vk_input_attachment_index(location : int)] : GLSLInputAttachmentIndexLayoutAttribute;
+/// @internal
__attributeTarget(FuncDecl)
attribute_syntax [spv_target_env_1_3] : SPIRVTargetEnv13Attribute;
+/// @internal
__attributeTarget(VarDeclBase)
attribute_syntax [disable_array_flattening] : DisableArrayFlatteningAttribute;
+/// Marks a enum type as an unscoped enum. The enum cases of an unscoped enum are not scoped within the enum type, and can be
+/// referenced directly without the enum type name.
__attributeTarget(EnumDecl)
attribute_syntax [UnscopedEnum] : UnscopedEnumAttribute;
+/// Marks a enum type as a bit flag enum. Bit flag enums will have their enum cases assigned to powers of 2 instead of consecutive integers.
+///
__attributeTarget(EnumDecl)
attribute_syntax[Flags] : FlagsAttribute;
// Statement Attributes
+/// A hint to the downstream compiler to unroll the loop until the specified number of iterations reached.
+/// This attribute does not affect Slang compiler's behavior.
+/// To unroll a loop in the Slang compiler before emitting target code, use the `[ForceUnroll]` attribute.
__attributeTarget(LoopStmt)
attribute_syntax [unroll(count: int = 0)] : UnrollAttribute;
+/// Instructs the Slang compiler to unroll the loop until the specified number of iterations before
+/// emiting targett code.
+/// @param count The maximun number of iterations to unroll the loop.
__attributeTarget(LoopStmt)
attribute_syntax [ForceUnroll(count: int = 0)] : ForceUnrollAttribute;
+/// A hint to the downstream compiler to preserve a loop.
__attributeTarget(LoopStmt)
attribute_syntax [loop] : LoopAttribute;
+/// Used on loop statements as a hint to the downstream compiler to perform less aggressive optimization on the loop
+/// in favor of faster compilation time.
+/// This attribute has no effect on targets other than HLSL.
__attributeTarget(LoopStmt)
attribute_syntax [fastopt] : FastOptAttribute;
+/// A hint to the downstream compiler that UAV conditions are allowed in the loop.
+/// This attribute has no effect on targets other than HLSL.
+/// @deprecated
__attributeTarget(LoopStmt)
attribute_syntax [allow_uav_condition] : AllowUAVConditionAttribute;
__attributeTarget(LoopStmt)
attribute_syntax [MaxIters(count)] : MaxItersAttribute;
+/// A hint to the downstream compiler to flatten an if statement.
__attributeTarget(IfStmt)
attribute_syntax [flatten] : FlattenAttribute;
+/// A hint to the downstream compiler to preserve the branching behavior of an if statement.
__attributeTarget(IfStmt)
__attributeTarget(SwitchStmt)
attribute_syntax [branch] : BranchAttribute;
+/// A hint to the downstream compiler to preserve the `switch` statement as is.
+/// This attribute has no effect on targets other than HLSL.
__attributeTarget(SwitchStmt)
attribute_syntax [forcecase] : ForceCaseAttribute;
+/// A hint to the downstream compiler to translate the `switch` statement into subroutine calls.
+/// This attribute has no effect on targets other than HLSL.
__attributeTarget(SwitchStmt)
attribute_syntax [call] : CallAttribute;
// Entry-point Attributes
// All Stages
+
+/// Marks a function as a shader entry point.
+/// @param stage The stage of the shader. Must be one of "vertex", "fragment", "compute", "geometry", "hull", "domain", "raygeneration",
+// "intersection", "anyhit", "closesthit", "miss", "callable", "task", "mesh".
__attributeTarget(FuncDecl)
attribute_syntax [shader(stage)] : EntryPointAttribute;
+/// Marks a function as a shader entry point.
+/// @param stage The stage of the shader. Must be one of "vertex", "fragment", "compute", "geometry", "hull", "domain", "raygeneration",
+// "intersection", "anyhit", "closesthit", "miss", "callable", "task", "mesh".
__attributeTarget(FuncDecl)
attribute_syntax [Shader(stage)] : EntryPointAttribute;
// Hull Shader
+/// Used on an hull shader entrypoint to declare the upperbound of the tessellation factor that the hull shader can return.
+/// @param factor The maximum tessellation factor the hull shader can return.
__attributeTarget(FuncDecl)
attribute_syntax [maxtessfactor(factor: float)] : MaxTessFactorAttribute;
+/// Used on an hull shader entrypoint to declare the number of control points the hull shader will produce per thread.
+/// @param count The number of control points the hull shader will produce per thread.
+/// @remarks The attribute indicates be the number of times the hull shader function will be executed.
__attributeTarget(FuncDecl)
attribute_syntax [outputcontrolpoints(count: int)] : OutputControlPointsAttribute;
+/// Used on an hull shader entrypoint to declare the output primitive type of the tessellator.
+/// @param topology The output primitive type, must be one of "point", "line", "triangle_cw", and "triangle_ccw".
__attributeTarget(FuncDecl)
attribute_syntax [outputtopology(topology)] : OutputTopologyAttribute;
+/// Used on an hull shader entrypoint to specify the patch type used by the hull shader.
+/// @param mode The patch type used by the hull shader. Valid values are "tri", "quad" and "isoline".
__attributeTarget(FuncDecl)
attribute_syntax [partitioning(mode)] : PartitioningAttribute;
+/// Used on a hull shader entrypoint to specify the associated function that computes the patch constant data.
+/// @param name The name of the function (in string literal) that computes the patch constant data.
__attributeTarget(FuncDecl)
attribute_syntax [patchconstantfunc(name)] : PatchConstantFuncAttribute;
// Hull/Domain Shader
+
+/// Used on an hull shader entrypoint to specify the patch type used by the hull shader.
+/// @param patchType The patch type used by the hull shader. Valid values are "tri", "quad" and "isoline".
__attributeTarget(FuncDecl)
-attribute_syntax [domain(domain)] : DomainAttribute;
+attribute_syntax [domain(patchType)] : DomainAttribute;
// Geometry Shader
+
+/// Used on a geometry shader entry point to specify the maximum number of vertices that the geometry shader can output.
+/// @param count The maximum number of vertices that the geometry shader can output.
__attributeTarget(FuncDecl)
attribute_syntax [maxvertexcount(count: int)] : MaxVertexCountAttribute;
+/// Used on a geometry shader entry point to specify the number of instances to execute for each input primitive.
+/// @param count The number of instances to execute for each input primitive.
+/// @remarks When using this attribute, a geometry shader can declare a parameter with `SV_GSInstanceID` semantic to get the instance index.
__attributeTarget(FuncDecl)
attribute_syntax [instance(count: int)] : InstanceAttribute;
// Fragment ("Pixel") Shader
+/// Used on a fragment shader entry point to specify that early depth stencil testing can be enabled.
__attributeTarget(FuncDecl)
attribute_syntax [earlydepthstencil] : EarlyDepthStencilAttribute;
// Compute Shader
+
+/// Specifies the size of the thread group a compute shader.
+/// @param x The number of threads in the x dimension of a thread group.
+/// @param y The number of threads in the y dimension of a thread group.
+/// @param z The number of threads in the z dimension of a thread group.
__attributeTarget(FuncDecl)
attribute_syntax [numthreads(x: int, y: int = 1, z: int = 1)] : NumThreadsAttribute;
+/// Specifies the size of the thread group a compute shader.
+/// @param x The number of threads in the x dimension of a thread group.
+/// @param y The number of threads in the y dimension of a thread group.
+/// @param z The number of threads in the z dimension of a thread group.
__attributeTarget(FuncDecl)
attribute_syntax [NumThreads(x: int, y: int = 1, z: int = 1)] : NumThreadsAttribute;
+/// Indicate a compute shader entry point is only compatible with the specified wave size.
+/// @param numLanes The wave size this shader entrypoint is compatible with. Must be one of 4, 8, 16, 32, 64, 128.
__attributeTarget(FuncDecl)
attribute_syntax [WaveSize(numLanes: int)] : WaveSizeAttribute;
-//
+//@hidden:
__attributeTarget(VarDeclBase)
attribute_syntax [__vulkanRayPayload(location : int = -1)] : VulkanRayPayloadAttribute;
@@ -3056,43 +3271,119 @@ attribute_syntax [__vulkanHitObjectAttributes(location : int = -1)] : VulkanHitO
__attributeTarget(VarDeclBase)
attribute_syntax [__vulkanHitAttributes] : VulkanHitAttributesAttribute;
+//@public:
+/// Mark a function or a property or subscript accessor as mutating. A mutating function receives the implicit `this` parameter
+/// as an `inout` parameter, so that mutations to members access from `this` argument will be visible to the caller.
+///
+/// @remarks
+/// By default, Slang treats all member functions as non-mutating. For example, consider the following function:
+/// ```csharp
+/// struct S
+/// {
+/// int x;
+/// void foo()
+/// {
+/// x = 1; // error: `x` is not an l-value.
+/// }
+/// }
+///
+/// ```
+/// The line `x = 1` will lead to a compile time error because by-default, all member methods in Slang are non-mutating. To
+/// allow `foo` to modify `x`, you can use `[mutating]` to mark the function as such:
+/// ```csharp
+/// struct S
+/// {
+/// int x;
+/// [mutating]
+/// void foo()
+/// {
+/// x = 1; // ok
+/// }
+/// }
+/// ```
+/// @see `[nonmutating]`.
+///
__attributeTarget(FunctionDeclBase)
attribute_syntax [mutating] : MutatingAttribute;
+/// Marks a function or a property and subscript accessor as non-mutating. A non-mutating function receives the implicit `this` parameter
+/// as an `in` parameter, so mutations to members accessed from `this` argument will be prohibited by the compiler.
+/// @remarks
+/// Member functions of a type are non-mutating by default, so this attribute is not necessary in most cases.
+/// However, the `set` accessor of a property or subscript is mutating by default, and you can use `[nonmutating]` to mark it as non-mutating.
+/// For example:
+/// ```csharp
+/// struct S
+/// {
+/// int* ptr_x;
+/// property x : int
+/// {
+/// get { return *ptr_x; }
+///
+/// [nonmutating]
+/// set { *ptr_x = value; }
+/// }
+/// }
+/// uniform S s; // `s` is not mutable.
+/// void test() { s.x = 1; } // OK, because the `set` accessor is non-mutating.
+/// ```
+/// In the above example, the property `x` reads and writes to a memory location pointed to by `ptr_x`. Therefore, the `set` accessor is not actually
+/// modifying any field of `S`, and does not need to take `this` as an `inout` parameter. Using `[nonmutating]` here on the set accessor will allow
+/// it to be called with a non-mutating value of `S`.
+/// @see `[mutating]`.
+///
__attributeTarget(AccessorDecl)
attribute_syntax [nonmutating] : NonmutatingAttribute;
+/// @internal
+/// Marks a member function to make `this` argument passed by const reference.
__attributeTarget(FunctionDeclBase)
attribute_syntax [constref] : ConstRefAttribute;
+/// @internal
+/// Marks a member function to make `this` argument passed by reference.
__attributeTarget(FunctionDeclBase)
attribute_syntax [__ref] : RefAttribute;
- /// Indicates that a function computes its result as a function of its arguments without loading/storing any memory or other state.
- ///
- /// This is equivalent to the LLVM `readnone` function attribute.
+/// @internal
+/// Indicates that a function computes its result as a function of its arguments without loading/storing any memory or other state.
+///
+/// This is equivalent to the LLVM `readnone` function attribute.
__attributeTarget(FunctionDeclBase)
attribute_syntax [__readNone] : ReadNoneAttribute;
+/// Represent the applicable target for an attribute.
enum _AttributeTargets
{
- Struct = $( (int) UserDefinedAttributeTargets::Struct),
- Var = $( (int) UserDefinedAttributeTargets::Var),
- Function = $( (int) UserDefinedAttributeTargets::Function),
- Param = $( (int) UserDefinedAttributeTargets::Param),
+ Struct = $( (int) UserDefinedAttributeTargets::Struct), /// Struct types.
+ Var = $( (int) UserDefinedAttributeTargets::Var), /// Global and local variables and constants.
+ Function = $( (int) UserDefinedAttributeTargets::Function), /// Functions or member functions.
+ Param = $( (int) UserDefinedAttributeTargets::Param), /// Function parameters.
};
+
+/// Mark a struct type as a user defined attribute type.
+/// @param target The type of declarations to which the attribute can be applied.
__attributeTarget(StructDecl)
attribute_syntax [__AttributeUsage(target : _AttributeTargets)] : AttributeUsageAttribute;
+/// Specify the storage format of a read-write texture. Can only be used on a texture typed struct field or global parameter.
+/// @param format The storage format of the texture.
+/// @see Please refer to `_Texture` for a complete list of allowed format strings.
__attributeTarget(VarDeclBase)
attribute_syntax [format(format : String)] : FormatAttribute;
+/// Specify the storage format of a read-write texture. Can only be used on a texture typed struct field or global parameter.
+/// This is an alias of the `[format]` attribute.
+/// @param format The storage format of the texture.
+/// @see Please refer to `_Texture` for a complete list of allowed format strings.
__attributeTarget(VarDeclBase)
attribute_syntax [vk_image_format(format : String)] : FormatAttribute;
__attributeTarget(Decl)
attribute_syntax [allow(diagnostic: String)] : AllowAttribute;
+/// Mark declaration to require a specific target capability.
+/// @param capability The required capability.
__attributeTarget(Decl)
attribute_syntax [require(capability)] : RequireCapabilityAttribute;
@@ -3103,85 +3394,141 @@ attribute_syntax [__extern] : ExternAttribute;
__attributeTarget(FunctionDeclBase)
attribute_syntax [__unsafeForceInlineEarly] : UnsafeForceInlineEarlyAttribute;
+/// Perform inlining of the function at the call site during Slang compilation.
+/// @remarks By default Slang does not inline user defined functions, and will preserve the function call hierarchy in the generated code.
+/// Use this attribute on a function to force the Slang compiler to inline the function before emitting target code.
__attributeTarget(FunctionDeclBase)
attribute_syntax [ForceInline] : ForceInlineAttribute;
+/// @internal
+/// Specify the overload rank of a function for overload resolution.
__attributeTarget(FunctionDeclBase)
attribute_syntax [OverloadRank] : OverloadRankAttribute;
+/// @experimental
+/// Mark a function as imported from a DLL. Valid only on CPU host targets.
__attributeTarget(FuncDecl)
attribute_syntax [DllImport(modulePath: String)] : DllImportAttribute;
+/// @experimental
+/// Mark a function to be exported as a DLL symbol. Valid only on CPU host targets.
__attributeTarget(FuncDecl)
attribute_syntax [DllExport] : DllExportAttribute;
+/// @experimental
+/// Mark a function as a pytorch kernel entrypoint.
__attributeTarget(FuncDecl)
attribute_syntax [TorchEntryPoint] : TorchEntryPointAttribute;
+/// @experimental
+/// Mark a function for export as a CUDA device function. Valid only on CUDA target.
__attributeTarget(FuncDecl)
attribute_syntax [CudaDeviceExport] : CudaDeviceExportAttribute;
+/// @experimental
+/// Mark a function for export as a CUDA host function. Valid only on CUDA target.
__attributeTarget(FuncDecl)
attribute_syntax [CudaHost] : CudaHostAttribute;
+/// @experimental
+/// Mark a function for export as a CUDA kernel function. Valid only on CUDA target.
__attributeTarget(FuncDecl)
attribute_syntax [CudaKernel] : CudaKernelAttribute;
+/// @experimental
+/// Mark a function for export as a CUDA device function. Valid only on CUDA target.
__attributeTarget(FuncDecl)
attribute_syntax [CUDADeviceExport] : CudaDeviceExportAttribute;
+/// @experimental
+/// Mark a function for export as a CUDA host function. Valid only on CUDA target.
__attributeTarget(FuncDecl)
attribute_syntax [CUDAHost] : CudaHostAttribute;
+/// @experimental
+/// Mark a function for export as a CUDA kernel function. Valid only on CUDA target.
__attributeTarget(FuncDecl)
attribute_syntax [CUDAKernel] : CudaKernelAttribute;
+/// @experimental
+/// Mark a function for automatic pytorch binding.
__attributeTarget(FuncDecl)
attribute_syntax [AutoPyBindCUDA] : AutoPyBindCudaAttribute;
+/// @experimental
+/// Mark a type for export to slang-torch.
__attributeTarget(AggTypeDecl)
attribute_syntax [PyExport(name: String)] : PyExportAttribute;
+/// @experimental
+/// Mark an interface as a COM interface. Valid only on CPU target.
+/// @param guid The GUID of the COM interface.
__attributeTarget(InterfaceDecl)
attribute_syntax [COM(guid: String)] : ComInterfaceAttribute;
// Inheritance Control
+
+/// @experimental
+/// Mark a type as sealed, preventing it from being inherited from or implemented by types defined in other modules.
+/// @see `[open]`.
__attributeTarget(AggTypeDecl)
attribute_syntax [sealed] : SealedAttribute;
+/// @experimental
+/// Mark a type as open, allowing it from being inherited from or implemented by types defined in other modules.
+/// This is the default behavior.
+/// @see `[sealed]`.
__attributeTarget(AggTypeDecl)
attribute_syntax [open] : OpenAttribute;
+/// @experimental
+/// Mark an interface type to allow dynmaic dispatch, and declare the maximum size in bytes that an implementation type
+/// of the interface can have.
__attributeTarget(InterfaceDecl)
attribute_syntax [anyValueSize(size:int)] : AnyValueSizeAttribute;
+/// @experimental
+/// Mark an interface type for specialization only. Such interface types cannot be used for dynamic dispatch.
__attributeTarget(InterfaceDecl)
attribute_syntax [Specialize] : SpecializeAttribute;
+/// @internal
+/// Marks a declaration as a builtin declaration.
__attributeTarget(DeclBase)
attribute_syntax [builtin] : BuiltinAttribute;
+// @hidden:
__attributeTarget(DeclBase)
attribute_syntax[__AutoDiffBuiltin] : AutoDiffBuiltinAttribute;
__attributeTarget(DeclBase)
attribute_syntax [__requiresNVAPI] : RequiresNVAPIAttribute;
+// @public:
+
+/// Mark a type to require a target specific prelude.
+/// The prelude will be included in the generated code for the specified target if the resulting code uses
+/// the marked type.
__attributeTarget(AggTypeDecl)
attribute_syntax[RequirePrelude(target, prelude:String)] : RequirePreludeAttribute;
__attributeTarget(DeclBase)
attribute_syntax [__AlwaysFoldIntoUseSiteAttribute] : AlwaysFoldIntoUseSiteAttribute;
+/// Inform the downstream compiler to not inline the function.
__attributeTarget(FunctionDeclBase)
attribute_syntax [noinline] : NoInlineAttribute;
__attributeTarget(StructDecl)
attribute_syntax [payload] : PayloadAttribute;
+/// Mark a declaration as deprecated.
+/// @param message The diagnostic message to show when the declaration is used.
__attributeTarget(DeclBase)
attribute_syntax [deprecated(message: String)] : DeprecatedAttribute;
+/// Controls the behavior of the compiler when a differentiable function is detected to have side-effects.
+/// @category misc_types
enum SideEffectBehavior
{
/// Causes a warning if the method is detected to have side-effects
@@ -3190,26 +3537,41 @@ enum SideEffectBehavior
/// Suppresses the warning
Allow = 1
};
+
+/// Mark a differentiable function to prefer recomputation over checkpointing when a value computed in the primal pass is needed
+/// during backward derivative propagation.
__attributeTarget(FunctionDeclBase)
attribute_syntax[PreferRecompute(behavior: SideEffectBehavior = SideEffectBehavior.Warn)] : PreferRecomputeAttribute;
+/// Mark a differentiable function to prefer checkpointing over recomputation when a value computed in the primal pass is needed
+/// during backward derivative propagation.
__attributeTarget(FunctionDeclBase)
attribute_syntax [PreferCheckpoint] : PreferCheckpointAttribute;
+// @hidden:
__attributeTarget(DeclBase)
attribute_syntax [KnownBuiltin(name : String)] : KnownBuiltinAttribute;
__attributeTarget(FunctionDeclBase)
-attribute_syntax [NonUniformReturn] : NonDynamicUniformAttribute;
+attribute_syntax [__GLSLRequireShaderInputParameter(parameterNumber:int)] : GLSLRequireShaderInputParameterAttribute;
+
+__attributeTarget(FuncDecl)
+attribute_syntax [noRefInline] : NoRefInlineAttribute;
+
+// @public:
+/// Mark a function's return value as non-uniform.
__attributeTarget(FunctionDeclBase)
-attribute_syntax [__GLSLRequireShaderInputParameter(parameterNumber:int)] : GLSLRequireShaderInputParameterAttribute;
+attribute_syntax [NonUniformReturn] : NonDynamicUniformAttribute;
+/// Mark a compute shader entry point to allow it to use implicit derivatives.
+/// @remarks This attributes causes Slang to emit `DerivativeGroupQuadsNV` execution mode when producing SPIR-V. The attribute has no
+/// effect on other targets.
__attributeTarget(FuncDecl)
attribute_syntax [DerivativeGroupQuad] : DerivativeGroupQuadAttribute;
+/// Mark a compute shader entry point to allow it to use implicit derivatives.
+/// @remarks This attributes causes Slang to emit `DerivativeGroupLinearNV` execution mode when producing SPIR-V. The attribute has no
+/// effect on other targets.
__attributeTarget(FuncDecl)
attribute_syntax [DerivativeGroupLinear] : DerivativeGroupLinearAttribute;
-
-__attributeTarget(FuncDecl)
-attribute_syntax [noRefInline] : NoRefInlineAttribute;
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index cf3f25e8f..191fa3195 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -324,6 +324,13 @@ struct ByteAddressBuffer
};
// Texture
+
+/// Represent a texture shape type that can be used to specify the shape of a texture.
+/// Used for the `Shape` parameter of the `_Texture` type.
+///
+/// Implemented by `__Shape1D`, `__Shape2D`, `__Shape3D`, `__ShapeCube` and `__ShapeBuffer`.
+/// @see `_Texture`.
+/// @internal
[sealed]
[builtin]
interface __ITextureShape
@@ -332,6 +339,12 @@ interface __ITextureShape
static const int dimensions;
static const int planeDimensions;
}
+
+/// Represent a 1D, 2D or 3D texture shape that can be used as the `Shape` parameter of the `_Texture` type.
+///
+/// Implemented by `__Shape1D`, `__Shape2D` and `__Shape3D`.
+/// @see `_Texture`.
+/// @internal
[sealed]
[builtin]
interface __ITextureShape1D2D3D : __ITextureShape
@@ -339,6 +352,7 @@ interface __ITextureShape1D2D3D : __ITextureShape
}
/// @category misc_types Miscelaneous types
+/// When used as the `Shape` parameter of the `_Texture` type, specifies a 1D texture.
__magic_type(TextureShape1DType)
__intrinsic_type($(kIROp_TextureShape1DType))
struct __Shape1D : __ITextureShape1D2D3D
@@ -347,7 +361,9 @@ struct __Shape1D : __ITextureShape1D2D3D
static const int dimensions = 1;
static const int planeDimensions = 1;
}
+
/// @category misc_types
+/// When used as the `Shape` parameter of the `_Texture` type, specifies a 2D texture.
__magic_type(TextureShape2DType)
__intrinsic_type($(kIROp_TextureShape2DType))
struct __Shape2D : __ITextureShape1D2D3D
@@ -356,7 +372,9 @@ struct __Shape2D : __ITextureShape1D2D3D
static const int dimensions = 2;
static const int planeDimensions = 2;
}
+
/// @category misc_types
+/// When used as the `Shape` parameter of the `_Texture` type, specifies a 3D texture.
__magic_type(TextureShape3DType)
__intrinsic_type($(kIROp_TextureShape3DType))
struct __Shape3D : __ITextureShape1D2D3D
@@ -365,7 +383,9 @@ struct __Shape3D : __ITextureShape1D2D3D
static const int dimensions = 3;
static const int planeDimensions = 3;
}
+
/// @category misc_types
+/// When used as the `Shape` parameter of the `_Texture` type, specifies a Cube texture.
__magic_type(TextureShapeCubeType)
__intrinsic_type($(kIROp_TextureShapeCubeType))
struct __ShapeCube : __ITextureShape
@@ -374,7 +394,9 @@ struct __ShapeCube : __ITextureShape
static const int dimensions = 3;
static const int planeDimensions = 2;
}
+
/// @category misc_types
+/// When used as the `Shape` parameter of the `_Texture` type, specifies a buffer texture.
__magic_type(TextureShapeBufferType)
__intrinsic_type($(kIROp_TextureShapeBufferType))
struct __ShapeBuffer : __ITextureShape
diff --git a/source/slang/slang-doc-markdown-writer.cpp b/source/slang/slang-doc-markdown-writer.cpp
index 2b4586db2..dcfe011f8 100644
--- a/source/slang/slang-doc-markdown-writer.cpp
+++ b/source/slang/slang-doc-markdown-writer.cpp
@@ -223,17 +223,39 @@ String DocMarkdownWriter::_getFullName(Decl* decl)
String _translateNameToPath(const UnownedStringSlice& name)
{
+ // We will generate an all-lowercase file name based on the name of the decl.
+ // We do so by converting all capital letters to lowercase, and append a disambiguator
+ // postfix at the end that tracks the location of the capital letters in the original name.
+ // For example, `MyType` will be converted to `mytype-02`, because there is one capital letter
+ // at location 0 and one at location 2.
+ // To prevent URL issues, all leading underscores are replaced with '0', and we
+ // will also append the location of the replaced character to the disambiguator postfix.
+ // For example, `_MyType` will be converted to `0mytype-013`.
+ // To keep disambiguators short, we use base 36 to represent each location.
+
StringBuilder buf;
- for (const char c : name)
+ StringBuilder disambiguatorSB;
+ for (Index i = 0; i < name.getLength(); i++)
{
+ auto c = name[i];
// Removing leading underscores to prevent url issues.
if (c == '_' && buf.getLength() == 0)
+ {
+ disambiguatorSB.append(String(i, 36));
+ buf.appendChar('0');
continue;
+ }
if (c == ' ')
{
buf.appendChar('-');
}
+ else if (c >= 'A' && c <= 'Z')
+ {
+ // Convert to lower case.
+ buf.appendChar((char)(c - 'A' + 'a'));
+ disambiguatorSB.append(String(i, 36));
+ }
else if (CharUtil::isAlphaOrDigit(c) || c == '_')
{
buf.appendChar(c);
@@ -244,6 +266,11 @@ String _translateNameToPath(const UnownedStringSlice& name)
buf << String((int)c, 16);
}
}
+ if (disambiguatorSB.getLength())
+ {
+ buf << "-";
+ buf << disambiguatorSB.produceString().toLower();
+ }
return buf;
}
@@ -263,6 +290,10 @@ String DocMarkdownWriter::_getDocFilePath(Decl* decl)
{
sb << "types/";
}
+ else if (as<AttributeDecl>(decl))
+ {
+ sb << "attributes/";
+ }
else
{
sb << "global-decls/";
@@ -319,12 +350,15 @@ DocMarkdownWriter::NameAndText DocMarkdownWriter::_getNameAndText(ASTMarkup::Ent
StringBuilder sb;
if (auto varDeclBase = as<VarDeclBase>(decl))
{
- sb << " : " << varDeclBase->type->toString();
-
- if (varDeclBase->initExpr)
+ if (varDeclBase->type)
{
- sb << " = ";
- _appendExpr(sb, varDeclBase->initExpr);
+ sb << " : " << varDeclBase->type->toString();
+
+ if (varDeclBase->initExpr)
+ {
+ sb << " = ";
+ _appendExpr(sb, varDeclBase->initExpr);
+ }
}
}
else if (auto typeParam = as<GenericTypeParamDeclBase>(decl))
@@ -629,6 +663,71 @@ void DocMarkdownWriter::writeTypeDef(const ASTMarkup::Entry& entry, TypeDefDecl*
declDoc.writeSection(out, this, typeDefDecl, DocPageSection::SeeAlso);
}
+static String getAttributeName(AttributeDecl* decl)
+{
+ auto name = getText(decl->getName());
+ if (name.startsWith("vk_"))
+ {
+ return String("vk::") + String(name.getUnownedSlice().tail(3));
+ }
+ return name;
+}
+
+void DocMarkdownWriter::writeAttribute(const ASTMarkup::Entry& entry, AttributeDecl* attributeDecl)
+{
+ auto& out = *m_builder;
+
+ out << toSlice("# attribute [");
+ out << escapeMarkdownText(getAttributeName(attributeDecl));
+ out << toSlice("]\n\n");
+ DeclDocumentation declDoc;
+ declDoc.parse(entry.m_markup.getUnownedSlice());
+ declDoc.writeDescription(out, this, attributeDecl);
+ registerCategory(m_currentPage, declDoc);
+
+ out << toSlice("## Signature\n\n");
+ List<Decl*> paramDecls;
+ for (auto param : attributeDecl->getMembersOfType<ParamDecl>())
+ {
+ paramDecls.add(param);
+ }
+ out << "<pre>\n";
+ out << "[" << translateToHTMLWithLinks(attributeDecl, getAttributeName(attributeDecl));
+ if (paramDecls.getCount() > 0)
+ {
+ out << "(";
+ for (Index i = 0; i < paramDecls.getCount(); i++)
+ {
+ if (i > 0)
+ out << ", ";
+ auto param = paramDecls[i];
+ out << translateToHTMLWithLinks(attributeDecl, _getName(param));
+ auto type = as<ParamDecl>(param)->type;
+ if (type)
+ {
+ out << " : ";
+ out << translateToHTMLWithLinks(attributeDecl, type->toString());
+ }
+ }
+ out << ")";
+ }
+ out << "]\n</pre>\n\n";
+
+ if (paramDecls.getCount() > 0)
+ {
+ out << "## Parameters\n\n";
+
+ // Document ordinary parameters
+ _appendAsBullets(_getUniqueParams(paramDecls, &declDoc), false, 0);
+
+ out << toSlice("\n");
+ }
+
+ declDoc.writeSection(out, this, attributeDecl, DocPageSection::Remarks);
+ declDoc.writeSection(out, this, attributeDecl, DocPageSection::Example);
+ declDoc.writeSection(out, this, attributeDecl, DocPageSection::SeeAlso);
+}
+
void DocMarkdownWriter::writeExtensionConditions(StringBuilder& out, ExtensionDecl* extensionDecl, const char* prefix, bool isHtml)
{
// Synthesize `where` clause for things defined in an extension.
@@ -1125,15 +1224,18 @@ void ParsedDescription::parse(UnownedStringSlice text)
ownedText = text;
List<UnownedStringSlice> lines;
StringUtil::calcLines(text, lines);
+ Index codeBlockIndent = 0;
bool isInCodeBlock = false;
for (auto line : lines)
{
+ auto originalLine = line;
line = line.trim();
if (line.startsWith("```"))
{
isInCodeBlock = !isInCodeBlock;
spans.add({ line, DocumentationSpanKind::OrdinaryText});
spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText });
+ codeBlockIndent = originalLine.indexOf('`');
continue;
}
@@ -1169,6 +1271,18 @@ void ParsedDescription::parse(UnownedStringSlice text)
}
else
{
+ line = originalLine;
+ for (Index i = 0; i < codeBlockIndent; i++)
+ {
+ if (line.startsWith(" "))
+ {
+ line = line.tail(1);
+ }
+ else
+ {
+ break;
+ }
+ }
spans.add({ line, DocumentationSpanKind::OrdinaryText });
spans.add({ toSlice("\n"), DocumentationSpanKind::OrdinaryText });
}
@@ -1183,7 +1297,8 @@ void DeclDocumentation::parse(const UnownedStringSlice& text)
Dictionary<DocPageSection, StringBuilder> sectionBuilders;
for (Index ptr = 0; ptr < lines.getCount(); ptr++)
{
- auto line = lines[ptr].trim();
+ auto originalLine = lines[ptr];
+ auto line = originalLine.trim();
if (line.startsWith("@param"))
{
currentSection = DocPageSection::Parameter;
@@ -1280,6 +1395,10 @@ void DeclDocumentation::parse(const UnownedStringSlice& text)
}
continue;
}
+ else
+ {
+ line = originalLine;
+ }
sectionBuilders[currentSection] << line << "\n";
// If the current directive is a callout, set currentSection back
@@ -2201,7 +2320,7 @@ void DeclDocumentation::writeSection(StringBuilder& out, DocMarkdownWriter* writ
}
}
-void DocMarkdownWriter::createPage(DocMarkdownWriter::WriteDeclMode mode, ASTMarkup::Entry& entry, Decl* decl)
+void DocMarkdownWriter::createPage(ASTMarkup::Entry& entry, Decl* decl)
{
// Skip these they will be output as part of their respective 'containers'
if (as<ParamDecl>(decl) ||
@@ -2218,35 +2337,33 @@ void DocMarkdownWriter::createPage(DocMarkdownWriter::WriteDeclMode mode, ASTMar
{
if (_isFirstOverridden(callableDecl))
{
- if (mode == WriteDeclMode::Header)
- ensureDeclPageCreated(entry);
+ ensureDeclPageCreated(entry);
}
}
else if (as<EnumDecl>(decl))
{
- if (mode == WriteDeclMode::Header)
- ensureDeclPageCreated(entry);
+ ensureDeclPageCreated(entry);
}
else if (as<AggTypeDeclBase>(decl))
{
- if (mode == WriteDeclMode::Header)
- ensureDeclPageCreated(entry);
+ ensureDeclPageCreated(entry);
}
else if (as<VarDecl>(decl))
{
// If part of aggregate type will be output there.
- if (mode == WriteDeclMode::Header)
- ensureDeclPageCreated(entry);
+ ensureDeclPageCreated(entry);
}
else if (as<TypeDefDecl>(decl))
{
- if (mode == WriteDeclMode::Header)
- ensureDeclPageCreated(entry);
+ ensureDeclPageCreated(entry);
}
else if (as<PropertyDecl>(decl))
{
- if (mode == WriteDeclMode::Header)
- ensureDeclPageCreated(entry);
+ ensureDeclPageCreated(entry);
+ }
+ else if (as<AttributeDecl>(decl))
+ {
+ ensureDeclPageCreated(entry);
}
else if (as<GenericDecl>(decl))
{
@@ -2504,6 +2621,7 @@ DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr)
m_interfacesPage = addBuiltinPage(m_rootPage.get(), toSlice("interfaces/index.md"), toSlice("Interfaces"), toSlice("Interfaces"));
m_typesPage = addBuiltinPage(m_rootPage.get(), toSlice("types/index.md"), toSlice("Types"), toSlice("Types"));
+ m_attributesPage = addBuiltinPage(m_rootPage.get(), toSlice("attributes/index.md"), toSlice("Attributes"), toSlice("Attributes"));
m_globalDeclsPage = addBuiltinPage(m_rootPage.get(), toSlice("global-decls/index.md"), toSlice("Global Declarations"), toSlice("Global Declarations"));
// In the first pass, we create all the pages so we can reference them
@@ -2514,7 +2632,7 @@ DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr)
if (decl && isVisible(entry))
{
- createPage(WriteDeclMode::Header, entry, decl);
+ createPage(entry, decl);
}
}
// In the second pass, actually writes the content to each page.
@@ -2522,6 +2640,7 @@ DocumentPage* DocMarkdownWriter::writeAll(UnownedStringSlice configStr)
generateSectionIndexPage(m_interfacesPage);
generateSectionIndexPage(m_typesPage);
+ generateSectionIndexPage(m_attributesPage);
generateSectionIndexPage(m_globalDeclsPage);
return m_rootPage.get();
@@ -2576,6 +2695,10 @@ void DocMarkdownWriter::writePage(DocumentPage* page)
{
writeTypeDef(*page->getFirstEntry(), typeDefDecl);
}
+ else if (AttributeDecl* attributeDecl = as<AttributeDecl>(decl))
+ {
+ writeAttribute(*page->getFirstEntry(), attributeDecl);
+ }
}
void DocMarkdownWriter::writePageRecursive(DocumentPage* page)
diff --git a/source/slang/slang-doc-markdown-writer.h b/source/slang/slang-doc-markdown-writer.h
index 20912af46..65e6c4720 100644
--- a/source/slang/slang-doc-markdown-writer.h
+++ b/source/slang/slang-doc-markdown-writer.h
@@ -102,11 +102,6 @@ struct DocMarkdownWriter
typedef ASTPrinter::Part Part;
typedef ASTPrinter::PartPair PartPair;
- enum WriteDeclMode
- {
- Header, Content
- };
-
struct Signature
{
struct GenericParam
@@ -151,8 +146,9 @@ struct DocMarkdownWriter
void writeVar(const ASTMarkup::Entry& entry, VarDecl* varDecl);
void writeProperty(const ASTMarkup::Entry& entry, PropertyDecl* propertyDecl);
void writeTypeDef(const ASTMarkup::Entry& entry, TypeDefDecl* typeDefDecl);
+ void writeAttribute(const ASTMarkup::Entry& entry, AttributeDecl* attributeDecl);
- void createPage(WriteDeclMode mode, ASTMarkup::Entry& entry, Decl* decl);
+ void createPage(ASTMarkup::Entry& entry, Decl* decl);
void registerCategory(DocumentPage* page, DeclDocumentation& doc);
void writePreamble();
@@ -251,6 +247,7 @@ struct DocMarkdownWriter
Dictionary<String, RefPtr<DocumentPage>> m_output;
RefPtr<DocumentPage> m_rootPage;
RefPtr<DocumentPage> m_typesPage;
+ RefPtr<DocumentPage> m_attributesPage;
RefPtr<DocumentPage> m_interfacesPage;
RefPtr<DocumentPage> m_globalDeclsPage;
diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp
index 93b29ccbe..438ab2187 100644
--- a/source/slang/slang-mangle.cpp
+++ b/source/slang/slang-mangle.cpp
@@ -444,6 +444,11 @@ namespace Slang
// be treated as equivalent to the type itself.
emit(context, "X");
emitType(context, getTargetType(context->astBuilder, extensionDeclRef));
+ for (auto inheritanceDecl : getMembersOfType<InheritanceDecl>(context->astBuilder, extensionDeclRef))
+ {
+ emit(context, "I");
+ emitType(context, getSup(context->astBuilder, inheritanceDecl));
+ }
return;
}
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 586a38b54..313e94439 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -5858,7 +5858,7 @@ void Session::addBuiltinSource(
SLANG_UNEXPECTED("error in Slang standard library");
}
-
+
// Compiling stdlib should not yield any warnings.
SLANG_ASSERT(sink.outputBuffer.getLength() == 0);