diff options
| author | ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> | 2025-08-29 15:52:34 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-29 22:52:34 +0000 |
| commit | 7758625d3fea67e55e98e7e4103d56c9918365be (patch) | |
| tree | 2ed40aeb4d16262866e5540dad1a519951b5f772 /source/slang/slang-check-expr.cpp | |
| parent | 450ef7934c1adfdf4a3a3c72967de3c5798a020d (diff) | |
[CBP] Pointer frontend changes + groupshared pointer support (#7848)
Resolves #7628
Resolves: #8197
Primary Goals:
1. Add `Access` to pointer
2. AddressSpace::GroupShared support for pointers (SPIR-V)
3. Add `__getAddress()` to replace `&`
* `&` is not updated to `require(cpu)` since slangpy uses `&`. This
means we must: (1) merge PR; (2) replace `&` with `__getAddress()`; (3)
add `require(cpu)` to `&`
Changes:
* Added to `Ptr` the `Access` generic argument & logic (for
`Access::Read`).
* Moved the generic argument `AddressSpace` from `Ptr` to the end of the
type.
* Added pointer casting support between any `Ptr` as long as the
`AddressSpace` is the same
* Disallow globallycoherent T* and coherent T*
* Disallow const T*, T const*, and const T*
* Fixed .natvis display of `ConstantValue` `ValOperandNode`
* Support generic resolution of type-casted integers
* Added `VariablePointer` emitting for spirv + other minor logic needed
for groupshared pointers
Breaking Changes:
* Anyone using the `AddressSpace` of `Ptr` will now have to account for
the `Access` argument
* we disallow various syntax paired with `Ptr` and `T*`
---------
Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 172 |
1 files changed, 171 insertions, 1 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index a874eaf43..ec249f56d 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -230,6 +230,7 @@ Expr* SemanticsVisitor::maybeOpenRef(Expr* expr) openRef->type.isLeftValue = (as<RefType>(exprType) != nullptr); openRef->type.type = refType->getValueType(); openRef->checked = true; + openRef->loc = expr->loc; return openRef; } return expr; @@ -4111,6 +4112,167 @@ Expr* SemanticsExprVisitor::visitSizeOfLikeExpr(SizeOfLikeExpr* sizeOfLikeExpr) return sizeOfLikeExpr; } +// Determines if we have a valid `AddressOf` target. +// Target to validate is `baseExpr`. +// Original type is `targetType`. +static PtrType* getValidTypeForAddressOf( + SemanticsVisitor* visitor, + ASTBuilder* m_astBuilder, + Expr* baseExpr, + Type* targetType) +{ + + // If our base is a variable like expression, we should check if this expr is a + // block of memory we allow getting the address of. + if (auto declRefExpr = as<DeclRefExpr>(baseExpr)) + { + visitor->ensureDecl(declRefExpr->declRef, DeclCheckState::DefinitionChecked); + if (auto varDeclRef = as<VarDeclBase>(declRefExpr->declRef)) + { + auto variableType = varDeclRef.substitute(m_astBuilder, targetType); + auto varDecl = varDeclRef.getDecl(); + bool hasVulkanHitObjectAttributesAttribute = false; + bool hasHLSLGroupSharedModifier = false; + for (auto modifier : varDecl->modifiers) + { + if (as<VulkanHitObjectAttributesAttribute>(modifier)) + hasVulkanHitObjectAttributesAttribute = true; + else if (as<HLSLGroupSharedModifier>(modifier)) + hasHLSLGroupSharedModifier = true; + + if (hasVulkanHitObjectAttributesAttribute || hasHLSLGroupSharedModifier) + break; + } + + // Handle variables tagged as [__vulkanHitObjectAttributes]. + // This support is needed for an internal "hack" Slang uses + // for raytracing with `__allocHitObjectAttributes`. + if (hasVulkanHitObjectAttributesAttribute) + { + return m_astBuilder->getPtrType( + variableType, + AccessQualifier::ReadWrite, + AddressSpace::Generic); + } + // Handle 'groupshared' variables. + else if (hasHLSLGroupSharedModifier) + { + return m_astBuilder->getPtrType( + variableType, + AccessQualifier::ReadWrite, + AddressSpace::GroupShared); + } + } + } + + // If our base is a variable like expression, which comes from a deref-like operation, + // we should check if we are able to return a pointer from that base. + auto getPtrTypeFromBaseOfDerefLikeOperation = [&](Expr* baseExpr) -> PtrType* + { + auto declRefExpr = as<DeclRefExpr>(baseExpr); + if (!declRefExpr) + return nullptr; + visitor->ensureDecl(declRefExpr->declRef, DeclCheckState::DefinitionChecked); + auto varDeclRef = as<VarDeclBase>(declRefExpr->declRef); + if (!varDeclRef) + return nullptr; + + auto variableType = varDeclRef.substitute(m_astBuilder, targetType); + + auto ptrType = as<PtrType>(getType(m_astBuilder, varDeclRef)); + if (!ptrType) + return nullptr; + + return m_astBuilder->getPtrType( + variableType, + ptrType->getAccessQualifier(), + ptrType->getAddressSpace()); + }; + + // This logic handles the recursive lookup of "does our operation lead up + // to an addressessable (can take the address-of) section of memory". + if (auto indexExpr = as<IndexExpr>(baseExpr)) + { + // If a user chooses to index into an array, we should check if the base + // expression is something we can get the address-of. + return getValidTypeForAddressOf( + visitor, + m_astBuilder, + indexExpr->baseExpression, + targetType); + } + else if (auto memberExpr = as<MemberExpr>(baseExpr)) + { + // If a user chooses to get a member of a base, we should check if the base + // is something we can get the address-of. + if (as<VarDeclBase>(memberExpr->declRef)) + return getValidTypeForAddressOf( + visitor, + m_astBuilder, + memberExpr->baseExpression, + targetType); + } + else if (auto derefExpr = as<DerefExpr>(baseExpr)) + { + // If a user deref's a variable-like-expression, we should + // check if this is a base expression we can get the address-of. + return getPtrTypeFromBaseOfDerefLikeOperation(derefExpr->base); + } + else if (auto invokeExpr = as<InvokeExpr>(baseExpr)) + { + // We only want to allow function calls if we are getting the address + // of a `GetOffsetPtr` to a pointer-variable + auto functionMemberExpr = as<MemberExpr>(invokeExpr->functionExpr); + if (!functionMemberExpr) + return nullptr; + auto subscriptDecl = as<SubscriptDecl>(functionMemberExpr->declRef.getDecl()); + if (!subscriptDecl) + return nullptr; + bool isOffsetIntrinsicOp = false; + for (auto refAccessor : subscriptDecl->getMembersOfType<RefAccessorDecl>()) + { + auto intrinsicOp = refAccessor->findModifier<IntrinsicOpModifier>(); + if (!intrinsicOp) + continue; + if (intrinsicOp->op != kIROp_GetOffsetPtr) + continue; + isOffsetIntrinsicOp = true; + } + if (!isOffsetIntrinsicOp) + return nullptr; + + return getPtrTypeFromBaseOfDerefLikeOperation(functionMemberExpr->baseExpression); + } + else if (auto swizzleExpr = as<SwizzleExpr>(baseExpr)) + { + // Only allow swizzle of 1 element since otherwise + // we may have a non-contiguous swizzle + // (`val.xxy` is non contiguous). + if (swizzleExpr->elementIndices.getCount() > 1) + return nullptr; + + // Check if the base expression is something we can get the address-of. + return getValidTypeForAddressOf(visitor, m_astBuilder, swizzleExpr->base, targetType); + } + return nullptr; +} + +Expr* SemanticsExprVisitor::visitAddressOfExpr(AddressOfExpr* expr) +{ + expr->arg = CheckTerm(expr->arg); + + // This address-of feature is purely experimental and for prototyping. + // Only allow known expressions. + expr->type = + getValidTypeForAddressOf(this, m_astBuilder, expr->arg, getType(m_astBuilder, expr->arg)); + if (!expr->type) + { + getSink()->diagnose(expr, Diagnostics::invalidAddressOf); + expr->type = m_astBuilder->getErrorType(); + } + return expr; +} + Expr* SemanticsExprVisitor::visitBuiltinCastExpr(BuiltinCastExpr* expr) { // All builtin cast exprs should already be checked. @@ -5744,7 +5906,10 @@ Expr* SemanticsExprVisitor::visitPointerTypeExpr(PointerTypeExpr* expr) expr->base = CheckProperType(expr->base); if (as<ErrorType>(expr->base.type)) expr->type = expr->base.type; - auto ptrType = m_astBuilder->getPtrType(expr->base.type, AddressSpace::UserPointer); + auto ptrType = m_astBuilder->getPtrType( + expr->base.type, + AccessQualifier::ReadWrite, + AddressSpace::UserPointer); expr->type = m_astBuilder->getTypeType(ptrType); return expr; } @@ -5830,6 +5995,11 @@ Val* SemanticsExprVisitor::checkTypeModifier(Modifier* modifier, Type* type) { return m_astBuilder->getNoDiffModifierVal(); } + else if (as<ConstModifier>(modifier)) + { + getSink()->diagnose(modifier, Diagnostics::constNotAllowedOnType); + return nullptr; + } else { // TODO: more complete error message here |
