summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/core.meta.slang3
-rw-r--r--source/slang/slang-ast-modifier.h9
-rw-r--r--source/slang/slang-check-decl.cpp33
-rw-r--r--source/slang/slang-check-expr.cpp4
-rw-r--r--source/slang/slang-check-overload.cpp3
-rw-r--r--source/slang/slang-lookup.cpp7
-rw-r--r--source/slang/slang-lower-to-ir.cpp4
-rw-r--r--tests/spirv/ref-this.slang30
8 files changed, 90 insertions, 3 deletions
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 22822196c..bde943972 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -2561,6 +2561,9 @@ attribute_syntax [nonmutating] : NonmutatingAttribute;
__attributeTarget(FunctionDeclBase)
attribute_syntax [constref] : ConstRefAttribute;
+__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.
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 9a27b3c06..03d3e6fcf 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -1004,13 +1004,20 @@ class NonmutatingAttribute : public Attribute
};
// A `[constref]` attribute, which indicates that the `this` parameter of
-// a member function should be passed by reference.
+// a member function should be passed by const reference.
//
class ConstRefAttribute : public Attribute
{
SLANG_AST_CLASS(ConstRefAttribute)
};
+// A `[ref]` attribute, which indicates that the `this` parameter of
+// a member function should be passed by reference.
+//
+class RefAttribute : public Attribute
+{
+ SLANG_AST_CLASS(RefAttribute)
+};
// A `[__readNone]` attribute, which indicates that a function
// computes its results strictly based on argument values, without
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 0d089874e..875fddf2f 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -2753,6 +2753,15 @@ namespace Slang
return false;
}
+ if (satisfyingMemberDeclRef.getDecl()->hasModifier<RefAttribute>()
+ != requiredMemberDeclRef.getDecl()->hasModifier<RefAttribute>())
+ {
+ // A `[ref]` method can't satisfy a non-`[ref]` requirement.
+ // The opposite direction is okay, but we will need to synthesize a wrapper
+ // to ensure type matches, so we will return false here either way.
+ return false;
+ }
+
if(satisfyingMemberDeclRef.getDecl()->hasModifier<HLSLStaticModifier>()
!= requiredMemberDeclRef.getDecl()->hasModifier<HLSLStaticModifier>())
{
@@ -3647,6 +3656,16 @@ namespace Slang
auto synConstRefAttr = m_astBuilder->create<ConstRefAttribute>();
addModifier(synthesized, synConstRefAttr);
}
+ if (requiredMemberDeclRef.getDecl()->hasModifier<RefAttribute>())
+ {
+ // If the interface requirement is `[ref]` then our
+ // synthesized method should be too.
+ //
+ synThis->type.isLeftValue = true;
+
+ auto synConstRefAttr = m_astBuilder->create<RefAttribute>();
+ addModifier(synthesized, synConstRefAttr);
+ }
if (requiredMemberDeclRef.getDecl()->hasModifier<NoDiffThisAttribute>())
{
auto noDiffThisAttr = m_astBuilder->create<NoDiffThisAttribute>();
@@ -4311,7 +4330,18 @@ namespace Slang
auto synAttr = m_astBuilder->create<MutatingAttribute>();
synAccessorDecl->modifiers.first = synAttr;
}
+ else if (requiredAccessorDeclRef.getDecl()->hasModifier<RefAttribute>())
+ {
+ synThis->type.isLeftValue = true;
+ auto synAttr = m_astBuilder->create<RefAttribute>();
+ synAccessorDecl->modifiers.first = synAttr;
+ }
+ else if (requiredAccessorDeclRef.getDecl()->hasModifier<ConstRefAttribute>())
+ {
+ auto synAttr = m_astBuilder->create<ConstRefAttribute>();
+ synAccessorDecl->modifiers.first = synAttr;
+ }
// We are going to synthesize an expression and then perform
// semantic checking on it, but if there are semantic errors
// we do *not* want to report them to the user as such, and
@@ -7733,7 +7763,8 @@ namespace Slang
if (!isEffectivelyStatic(decl))
{
auto constrefAttr = decl->findModifier<ConstRefAttribute>();
- if (constrefAttr)
+ auto refAttr = decl->findModifier<RefAttribute>();
+ if (constrefAttr || refAttr)
{
if (isTypeDifferentiable(calcThisType(getParentDecl(decl))))
{
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index ff74f9a62..065a74c77 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -4173,6 +4173,10 @@ namespace Slang
{
expr->type.isLeftValue = true;
}
+ else if (funcDeclBase->hasModifier<RefAttribute>())
+ {
+ expr->type.isLeftValue = true;
+ }
}
else if( auto typeOrExtensionDecl = as<AggTypeDeclBase>(containerDecl) )
{
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp
index 703771e6e..6b51493e1 100644
--- a/source/slang/slang-check-overload.cpp
+++ b/source/slang/slang-check-overload.cpp
@@ -522,7 +522,8 @@ namespace Slang
{
if(decl->hasModifier<MutatingAttribute>())
return true;
-
+ if (decl->hasModifier<RefAttribute>())
+ return true;
if(decl->hasModifier<NonmutatingAttribute>())
return false;
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index 9c8b2fa0b..5e30e3ce9 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -862,6 +862,13 @@ static void _lookUpInScopes(
//
thisParameterMode = LookupResultItem::Breadcrumb::ThisParameterMode::MutableValue;
}
+ else if (funcDeclRef.getDecl()->hasModifier<RefAttribute>())
+ {
+ // In a non-`static` method marked `[ref]` there is
+ // an implicit `this` parameter that is mutable.
+ //
+ thisParameterMode = LookupResultItem::Breadcrumb::ThisParameterMode::MutableValue;
+ }
else
{
// In all other cases, there is an implicit `this` parameter
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index a8cf11cdc..0d666306b 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -2709,6 +2709,10 @@ ParameterDirection getThisParamDirection(Decl* parentDecl, ParameterDirection de
{
return kParameterDirection_ConstRef;
}
+ else if (parentDecl->hasModifier<RefAttribute>())
+ {
+ return kParameterDirection_Ref;
+ }
// A `set` accessor on a property or subscript declaration
// defaults to a mutable `this` parameter, but the programmer
diff --git a/tests/spirv/ref-this.slang b/tests/spirv/ref-this.slang
new file mode 100644
index 000000000..5eaa7f3a1
--- /dev/null
+++ b/tests/spirv/ref-this.slang
@@ -0,0 +1,30 @@
+//TEST:SIMPLE(filecheck=CHECK): -target spirv
+
+// CHECK: %[[PTR:[0-9a-zA-Z_]+]] = OpAccessChain %_ptr_PhysicalStorageBuffer_uint %{{.*}} %int_0
+// CHECK: %original = OpAtomicIAdd %uint %[[PTR]] %uint_1 %uint_0 %uint_1
+
+struct Buf
+{
+ uint t;
+
+ [__ref]
+ func tester()
+ {
+ uint prev;
+ InterlockedAdd(t, 1, prev);
+ }
+};
+
+struct Push
+{
+ Buf * b;
+};
+
+[[vk::push_constant]] Push push;
+
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void main()
+{
+ push.b->tester();
+} \ No newline at end of file