Skip to content

Replace operator & usage with __getAddress#10280

Draft
aidanfnv wants to merge 18 commits intoshader-slang:masterfrom
aidanfnv:fix/replace-op-amp-w-get-address
Draft

Replace operator & usage with __getAddress#10280
aidanfnv wants to merge 18 commits intoshader-slang:masterfrom
aidanfnv:fix/replace-op-amp-w-get-address

Conversation

@aidanfnv
Copy link
Copy Markdown
Contributor

@aidanfnv aidanfnv commented Feb 27, 2026

The decision has been made to deprecate the use of & to get pointers, and replace any internal use of it with __getAddress.

Currently, __getAddress is more restrictive than &. it only produces typed pointers for groupshared and physical-storage-buffer variables, so it can't serve as a drop-in replacement. This PR relaxes __getAddress to fall back to UserPointer address space for all remaining variable types (function-locals, device-memory, etc.), making it functionally equivalent to &.

To preserve safety on GPU targets where function-local pointers are not representable, a new IR validation pass (validateGetAddressUsage) rejects __getAddress on function-local variables before codegen. The pass uses a new GetAddressDecoration on lowered IR vars to identify address-of sites, then walks derived-pointer ops to find the root allocation and check its address space. CPU and CUDA targets skip this validation since they have flat memory.

The __getAddress capability is also extended to the LLVM target via a new cpp_cuda_metal_spirv_llvm compound capability atom.

All existing slang-test uses of & are replaced with __getAddress.

Operator & for taking addresses will be deprecated in a follow-up PR. It cannot be deprecated in this PR because SlangPy uses &, and SlangPy needs to be updated to use __getAddress first, otherwise the deprecation would break SlangPy's CI before the fix can land.

@aidanfnv aidanfnv added the pr: non-breaking PRs without breaking changes label Feb 27, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 69abdc7 and 7ecf505.

📒 Files selected for processing (1)
  • source/slang/slang-diagnostics.lua

📝 Walkthrough

Walkthrough

Adds compound capability cpp_cuda_metal_spirv_llvm; introduces GetAddressDecoration and IR validation to reject storing function-local addresses; updates lowering and address-of handling to use __getAddress; bumps IR module max version; updates tests to replace & with __getAddress(...). No API signature removals.

Changes

Cohort / File(s) Summary
Capability files
docs/user-guide/a3-02-reference-capability-atoms.md, source/slang/slang-capabilities.capdef
Added compound capability cpp_cuda_metal_spirv_llvm (docs + capdef). Note: slang-capabilities.capdef contains a duplicate alias declaration for the same name/signature.
Address-of handling (frontend & lowering)
source/slang/slang-check-decl.cpp, source/slang/slang-check-expr.cpp, source/slang/slang-lower-to-ir.cpp, source/slang/slang-diagnostics.lua
Switched capability lookup to the new compound alias; added a UserPointer fallback in address-of type resolution for DeclRef paths; changed diagnostic primary span for invalid address-of to location; lowered address-of temporaries and annotate IRVars with GetAddressDecoration.
IR: decorations, stable names, version
source/slang/slang-ir-insts.lua, source/slang/slang-ir-insts-stable-names.lua, source/slang/slang-ir.h
Added GetAddressDecoration to IR defs and stable-names mapping; appended stable-name entry Decoration.GetAddressDecoration = 737; bumped k_maxSupportedModuleVersion from 7 → 8 (two occurrences).
IR validation & emit pipeline
source/slang/slang-ir-validate.h, source/slang/slang-ir-validate.cpp, source/slang/slang-emit.cpp
Declared and implemented validateGetAddressUsage to trace derived-pointer roots and emit diagnostics when __getAddress stores function-local addresses; integrated this validation into the emit/pass pipeline for non-CPU/CUDA targets (inserted two SLANG_PASS calls).
Tests: replace & with __getAddress
tests/...
tests/bugs/gh-3601.slang, tests/bugs/gh-7499.slang, tests/bugs/gh-8659.slang, tests/cpu-program/gfx-smoke.slang, tests/cpu-program/pointer-basics.slang, tests/cpu-program/pointer-deref.slang, tests/language-feature/bitfield/*.slang, tests/language-feature/pointer/coherent-load-store-physical-storage-buffer.slang, tests/llvm/inline-llvm-ir.slang, tests/spirv/pointer.slang
Replaced direct & uses with __getAddress(...) across many tests to reflect new address-of lowering/validation semantics.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Frontend as Frontend (AST)
    participant Lower as Lowering (IR)
    participant IRMod as IRModule
    participant Validator as validateGetAddressUsage
    participant Emitter as Emitter/PassManager
    participant Sink as DiagnosticSink

    Frontend->>Lower: produce AddressOfExpr / __getAddress() nodes
    Lower->>IRMod: lower to IR, attach GetAddressDecoration to IRVar
    Emitter->>Validator: run validateGetAddressUsage(module, sink)
    Validator->>IRMod: traverse IR, follow derived-pointer chains
    Validator->>Sink: emit invalid-address-of diagnostic if function-local addresses stored
    Emitter->>Emitter: continue remaining passes / emit target code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

🐰 I hopped through code both near and far,
Marked addresses with a shiny star ✨
"__getAddress" leads the way, no fuss,
IR tags and checks now follow us,
Safe hops, safe stores — carrot for us!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the primary change: replacing internal usage of the address-of operator (&) with the __getAddress builtin function.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the motivation, implementation approach, safety mechanisms, and scope of changes throughout the codebase.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@slangbot
Copy link
Copy Markdown
Contributor

⚠️ IR Instruction Files Changed

This PR modifies IR instruction definition files. Please review if you need to update the following constants in source/slang/slang-ir.h:

  • k_minSupportedModuleVersion: Should be incremented if you're removing instructions or making breaking changes
  • k_maxSupportedModuleVersion: Should be incremented when adding new instructions

These version numbers help ensure compatibility between different versions of compiled modules.

github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

@aidanfnv aidanfnv marked this pull request as ready for review February 28, 2026 00:21
@aidanfnv aidanfnv requested a review from a team as a code owner February 28, 2026 00:21
@aidanfnv aidanfnv requested review from bmillsNV and Copilot and removed request for a team and bmillsNV February 28, 2026 00:21
@aidanfnv aidanfnv marked this pull request as draft February 28, 2026 00:21
github-actions[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates test and compiler behavior away from using the unary & address-of operator and toward __getAddress, adding IR plumbing to track/validate __getAddress usage across targets.

Changes:

  • Updated multiple .slang tests to replace address-of (&) with __getAddress(...).
  • Added a new IR decoration (GetAddressDecoration) and an IR validation pass to reject __getAddress of function-local variables on non-CPU/CUDA targets.
  • Extended capability sets/documentation to include an LLVM-capable compound target and bumped IR module max supported version.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/spirv/pointer.slang Uses __getAddress instead of & in SPIR-V pointer test.
tests/llvm/inline-llvm-ir.slang Uses __getAddress for taking address of a local in LLVM test.
tests/language-feature/pointer/coherent-load-store-physical-storage-buffer.slang Replaces & with __getAddress for coherent load/store pointer formation.
tests/language-feature/bitfield/repr.slang Replaces & with __getAddress in bitfield representation test.
tests/language-feature/bitfield/repr-mixed.slang Same address-of migration in mixed packing test.
tests/language-feature/bitfield/msvc-repr.slang Same address-of migration in MSVC packing test.
tests/cpu-program/pointer-deref.slang Replaces & with __getAddress in CPU pointer deref test.
tests/cpu-program/pointer-basics.slang Replaces & with __getAddress in pointer casting/basic ops test.
tests/cpu-program/gfx-smoke.slang Replaces & with __getAddress for passing struct addresses into gfx APIs.
tests/bugs/gh-8659.slang Replaces & with __getAddress in bug regression test.
tests/bugs/gh-7499.slang Replaces & with __getAddress in bug regression test.
tests/bugs/gh-3601.slang Replaces & with __getAddress in bug regression test.
source/slang/slang-lower-to-ir.cpp Marks lowered __getAddress temporaries with GetAddressDecoration.
source/slang/slang-ir.h Bumps max supported IR module version (7 → 8).
source/slang/slang-ir-validate.h Declares validateGetAddressUsage validation pass.
source/slang/slang-ir-validate.cpp Implements validateGetAddressUsage and helper logic.
source/slang/slang-ir-insts.lua Adds GetAddressDecoration IR decoration opcode.
source/slang/slang-ir-insts-stable-names.lua Adds stable name mapping for the new decoration.
source/slang/slang-emit.cpp Runs validateGetAddressUsage for non-CPU/non-CUDA targets.
source/slang/slang-check-expr.cpp Diagnoses calls to built-in address-of operator and adjusts __getAddress typing rules.
source/slang/slang-check-decl.cpp Updates capability requirement for __getAddress to include LLVM compound capability.
source/slang/slang-capabilities.capdef Adds cpp_cuda_metal_spirv_llvm compound capability alias.
docs/user-guide/a3-02-reference-capability-atoms.md Documents the new compound capability alias.
Comments suppressed due to low confidence (1)

source/slang/slang-check-expr.cpp:3020

  • This new unconditional Diagnostics::invalidAddressOf for invocations of the built-in address-of operator (KnownBuiltinDeclName::OperatorAddressOf) will report an error message that specifically mentions __getAddress, even when the user wrote &expr. It also appears likely to change expected diagnostic IDs in existing tests that still use & (e.g., tests/diagnostics/invalid-constant-pointer-taking.slang currently checks for error 30079 on &constant_float_buffer[...]). Consider introducing a dedicated diagnostic for the & operator (with migration guidance), and/or updating the affected diagnostic tests to match the new behavior.
            Index paramCount = funcType->getParamCount();
            for (Index pp = 0; pp < paramCount; ++pp)
            {
                auto paramType = funcType->getParamTypeWithModeWrapper(pp);
                Expr* argExpr = nullptr;
                ParamDecl* paramDecl = nullptr;
                if (pp < invoke->arguments.getCount())
                {
                    argExpr = invoke->arguments[pp];
                    if (funcDeclBase)
                        paramDecl = funcDeclBase->getParameters()[pp];
                }
                compareMemoryQualifierOfParamToArgument(paramDecl, argExpr);

                if (as<OutParamTypeBase>(paramType) || as<RefParamType>(paramType))

@aidanfnv aidanfnv marked this pull request as ready for review February 28, 2026 00:55
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/slang/slang-ir-insts-stable-names.lua`:
- Line 739: You added a new stable name entry "Decoration.GetAddressDecoration"
with ID 737 but did not bump the module version; update the constant
k_maxSupportedModuleVersion from 8 to 9 in the header where it is defined
(symbol k_maxSupportedModuleVersion) so the new instruction ID is covered by the
supported module version.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 48d73cd and 70bac1a.

📒 Files selected for processing (23)
  • docs/user-guide/a3-02-reference-capability-atoms.md
  • source/slang/slang-capabilities.capdef
  • source/slang/slang-check-decl.cpp
  • source/slang/slang-check-expr.cpp
  • source/slang/slang-emit.cpp
  • source/slang/slang-ir-insts-stable-names.lua
  • source/slang/slang-ir-insts.lua
  • source/slang/slang-ir-validate.cpp
  • source/slang/slang-ir-validate.h
  • source/slang/slang-ir.h
  • source/slang/slang-lower-to-ir.cpp
  • tests/bugs/gh-3601.slang
  • tests/bugs/gh-7499.slang
  • tests/bugs/gh-8659.slang
  • tests/cpu-program/gfx-smoke.slang
  • tests/cpu-program/pointer-basics.slang
  • tests/cpu-program/pointer-deref.slang
  • tests/language-feature/bitfield/msvc-repr.slang
  • tests/language-feature/bitfield/repr-mixed.slang
  • tests/language-feature/bitfield/repr.slang
  • tests/language-feature/pointer/coherent-load-store-physical-storage-buffer.slang
  • tests/llvm/inline-llvm-ir.slang
  • tests/spirv/pointer.slang

github-actions[bot]

This comment was marked as outdated.

@aidanfnv aidanfnv requested a review from csyonghe February 28, 2026 01:11
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@source/slang/slang-ir-validate.cpp`:
- Around line 817-840: Add a new unit/IR diagnostic test that exercises
validateGetAddressUsageImpl's path for plain function-local scalar variables so
the Diagnostics::invalidAddressOf case is triggered; create a test that compiles
the provided compute shader snippet (with a local int and int* p =
__getAddress(local);) and asserts the error code (31160) is emitted. Locate the
test harness that runs stage=compute/-entry computeMain (matching other
address-of tests) and model the new test after the existing structured-buffer
and group-shared tests so it exercises validateGetAddressUsageImpl, referencing
the function name computeMain, the validation function
validateGetAddressUsageImpl, and the diagnostic symbol invalidAddressOf to
ensure the code path and diagnostic are covered. Ensure the test is
named/described consistently with other tests so it runs in the same suite and
fails if the diagnostic is not produced.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 70bac1a and 9385684.

📒 Files selected for processing (1)
  • source/slang/slang-ir-validate.cpp

Comment on lines +817 to +840
static void validateGetAddressUsageImpl(DiagnosticSink* sink, IRInst* inst)
{
if (inst->getOp() == kIROp_Var && inst->findDecoration<IRGetAddressDecoration>())
{
for (auto use = inst->firstUse; use; use = use->nextUse)
{
auto user = use->getUser();
if (user->getOp() != kIROp_Store)
continue;
auto store = as<IRStore>(user);
if (store->getPtr() != inst)
continue;
if (isFunctionLocalAddress(store->getVal()))
{
sink->diagnose(inst->sourceLoc, Diagnostics::invalidAddressOf);
}
}
}

for (auto child : inst->getModifiableChildren())
{
validateGetAddressUsageImpl(sink, child);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if there are any existing tests that exercise the invalidAddressOf diagnostic for __getAddress

# Search for tests that use __getAddress with expected diagnostics
rg -l '__getAddress.*local|invalidAddressOf' --glob '*.slang' tests/ 2>/dev/null

# Search for diagnostic test files related to getAddress
fd -e slang -e hlsl . tests/diagnostics/ --exec grep -l -i 'getaddress\|getAddress' {} \; 2>/dev/null

# Check if error code 31160 (invalidAddressOf) is tested anywhere
rg '31160|invalidAddressOf' tests/ 2>/dev/null

# Search for files mentioning the validation function itself
rg 'validateGetAddressUsageImpl' . 2>/dev/null

Repository: shader-slang/slang

Length of output: 719


🏁 Script executed:

#!/bin/bash
# Check the content of the existing test files
echo "=== get-address-validation.slang ==="
cat tests/language-feature/pointer/get-address-validation.slang

echo ""
echo "=== invalid-constant-pointer-taking.slang ==="
cat tests/diagnostics/invalid-constant-pointer-taking.slang

Repository: shader-slang/slang

Length of output: 3416


Add a diagnostic test for function-local scalar address validation.

Tests exist for taking addresses from structured buffers and group-shared memory, but there is no test verifying the invalidAddressOf diagnostic fires when attempting to take the address of a plain function-local scalar variable. This validation path should be covered:

//TEST:SIMPLE(filecheck=CHECK):-stage compute -entry computeMain -target spirv

[numthreads(1,1,1)]
void computeMain()
{
    int local = 42;
    // CHECK: error 31160
    int* p = __getAddress(local);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/slang/slang-ir-validate.cpp` around lines 817 - 840, Add a new unit/IR
diagnostic test that exercises validateGetAddressUsageImpl's path for plain
function-local scalar variables so the Diagnostics::invalidAddressOf case is
triggered; create a test that compiles the provided compute shader snippet (with
a local int and int* p = __getAddress(local);) and asserts the error code
(31160) is emitted. Locate the test harness that runs stage=compute/-entry
computeMain (matching other address-of tests) and model the new test after the
existing structured-buffer and group-shared tests so it exercises
validateGetAddressUsageImpl, referencing the function name computeMain, the
validation function validateGetAddressUsageImpl, and the diagnostic symbol
invalidAddressOf to ensure the code path and diagnostic are covered. Ensure the
test is named/described consistently with other tests so it runs in the same
suite and fails if the diagnostic is not produced.

github-actions[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
source/slang/slang-emit.cpp (1)

1628-1631: ⚠️ Potential issue | 🟠 Major

Run validateGetAddressUsage earlier to avoid optimization-elided false negatives.

At this stage, the IR has already gone through several simplification/DCE passes, so the decorated-var/store pattern this check relies on may already be rewritten away. Please move this pass closer to post-link/pre-optimization validation.

Suggested pass placement adjustment
@@
-    if (!isCPUTarget(targetRequest) && !isCUDATarget(targetRequest))
-    {
-        SLANG_PASS(validateGetAddressUsage, sink);
-    }
+    // Run early while AddressOf lowering artifacts are still intact.
+    if (!isCPUTarget(targetRequest) && !isCUDATarget(targetRequest))
+    {
+        SLANG_PASS(validateGetAddressUsage, sink);
+    }
@@
-    if (!isCPUTarget(targetRequest) && !isCUDATarget(targetRequest))
-    {
-        SLANG_PASS(validateGetAddressUsage, sink);
-    }
+    // (moved earlier in pipeline)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/slang/slang-emit.cpp` around lines 1628 - 1631, The
validateGetAddressUsage check is being run too late (after simplification/DCE)
causing false negatives; call validateGetAddressUsage(sink) earlier in the
pipeline before the optimization passes that rewrite the decorated-var/store
pattern — i.e., move the SLANG_PASS(validateGetAddressUsage, sink) invocation
out of the current isCPUTarget/isCUDATarget gated block and into the
post-link/pre-optimization validation stage (ensure the call still respects
targetRequest checks via isCPUTarget/isCUDATarget if needed), updating the
placement so validateGetAddressUsage sees the IR prior to DCE/simplification.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@source/slang/slang-emit.cpp`:
- Around line 1628-1631: The validateGetAddressUsage check is being run too late
(after simplification/DCE) causing false negatives; call
validateGetAddressUsage(sink) earlier in the pipeline before the optimization
passes that rewrite the decorated-var/store pattern — i.e., move the
SLANG_PASS(validateGetAddressUsage, sink) invocation out of the current
isCPUTarget/isCUDATarget gated block and into the post-link/pre-optimization
validation stage (ensure the call still respects targetRequest checks via
isCPUTarget/isCUDATarget if needed), updating the placement so
validateGetAddressUsage sees the IR prior to DCE/simplification.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9385684 and 3c3d06b.

📒 Files selected for processing (6)
  • docs/command-line-slangc-reference.md
  • source/slang/slang-check-decl.cpp
  • source/slang/slang-check-expr.cpp
  • source/slang/slang-emit.cpp
  • source/slang/slang-ir-validate.cpp
  • source/slang/slang-lower-to-ir.cpp
🚧 Files skipped from review as they are similar to previous changes (2)
  • source/slang/slang-check-expr.cpp
  • source/slang/slang-check-decl.cpp

github-actions[bot]

This comment was marked as outdated.

@aidanfnv aidanfnv marked this pull request as draft March 2, 2026 18:02
@aidanfnv aidanfnv marked this pull request as ready for review March 2, 2026 20:46
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
source/slang/slang-ir-validate.cpp (1)

831-844: Avoid duplicate InvalidAddressOf emissions per decorated var.

If multiple invalid stores reference the same decorated IRVar, this loop can report the same site repeatedly. Emitting once per decorated var keeps diagnostics clean.

Proposed tweak
         for (auto use = inst->firstUse; use; use = use->nextUse)
         {
             auto user = use->getUser();
             if (user->getOp() != kIROp_Store)
                 continue;
             auto store = as<IRStore>(user);
             if (store->getPtr() != inst)
                 continue;
             if (isFunctionLocalAddress(store->getVal()))
             {
                 sink->diagnose(Diagnostics::InvalidAddressOf{
                     .location = inst->sourceLoc,
                 });
+                break;
             }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@source/slang/slang-ir-validate.cpp` around lines 831 - 844, This loop can
emit duplicate Diagnostics::InvalidAddressOf for the same decorated variable
when multiple stores reference the same inst; fix by tracking which var/address
has already been diagnosed (e.g., maintain a small hash/set of IRInst* or IRVar*
called diagnosedAddrs) in the surrounding function, and before calling
sink->diagnose(...) check if inst (or the related IRVar) is already in
diagnosedAddrs; if not, insert it and emit the diagnostic—use the existing
symbols inst, use, user, IRStore, store, isFunctionLocalAddress and
sink->diagnose to locate and guard the diagnostic emission.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@source/slang/slang-ir-validate.cpp`:
- Around line 831-844: This loop can emit duplicate
Diagnostics::InvalidAddressOf for the same decorated variable when multiple
stores reference the same inst; fix by tracking which var/address has already
been diagnosed (e.g., maintain a small hash/set of IRInst* or IRVar* called
diagnosedAddrs) in the surrounding function, and before calling
sink->diagnose(...) check if inst (or the related IRVar) is already in
diagnosedAddrs; if not, insert it and emit the diagnostic—use the existing
symbols inst, use, user, IRStore, store, isFunctionLocalAddress and
sink->diagnose to locate and guard the diagnostic emission.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3c3d06b and 69abdc7.

📒 Files selected for processing (3)
  • source/slang/slang-check-expr.cpp
  • source/slang/slang-diagnostics.lua
  • source/slang/slang-ir-validate.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • source/slang/slang-check-expr.cpp

github-actions[bot]

This comment was marked as outdated.

github-actions[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR replaces all internal uses of the & (address-of) operator with __getAddress() as a step toward deprecating & for pointer creation. The key changes are:

  1. Relaxes __getAddress semantics: Previously only worked for groupshared/physical-storage-buffer variables; now accepts all variable types, falling back to UserPointer address space.
  2. New IR validation pass (validateGetAddressUsage): Rejects __getAddress on function-local variables for GPU targets (non-CPU/CUDA), using a new GetAddressDecoration on lowered IR vars.
  3. New capability atom: cpp_cuda_metal_spirv_llvm to extend __getAddress to LLVM targets.
  4. Test migration: All & usages in slang-test files replaced with __getAddress.

Key Findings

  1. Diagnostic message is stale (slang-diagnostics.lua): The error message still says '__getAddress' only supports groupshared variables and members of groupshared/device memory. This is no longer accurate — __getAddress now works for all variables at the semantic level, with the IR pass catching function-local cases on GPU targets. The two different uses of this diagnostic (semantic check vs IR validation) warrant either different messages or a more generic phrasing.

  2. LLVM target coverage in validation skip (slang-emit.cpp): The skip condition !isCPUTarget && !isCUDATarget should implicitly cover LLVM targets (since isCPUTarget uses isCpuLikeTarget which includes LLVM), but this relationship is non-obvious. Explicitly including isCPUTargetViaLLVM would improve clarity.

  3. Validation pass ordering (slang-ir-validate.cpp): The validation runs late in the pipeline after IR simplification has already run. Optimization may fold the store-to-decorated-var pattern the pass looks for, making the check a best-effort diagnostic rather than a guaranteed safety net.

Positive Aspects

  • Clean separation of concerns: The semantic layer accepts the broader set of cases, and the IR validation pass acts as a target-specific safety net — aligning with Slang's philosophy of doing heavy validation/transforms in IR passes.
  • Well-structured IR integration: Proper use of FIDDLE-generated decoration, stable name registration, and module version bump.
  • Thorough test migration: All & usages systematically replaced.
  • Good documentation: PR description clearly explains the rationale and the multi-PR deprecation plan.

Overall Assessment

The approach is sound and well-motivated. The three inline comments are suggestions/observations rather than blocking issues. The diagnostic message accuracy is the most actionable item — consider updating it in this PR or a follow-up. The validation pass ordering concern is an inherent limitation of the pattern-matching approach and is acceptable for a best-effort diagnostic.

31160,
"invalid __getAddress usage",
span { loc = "expr:Expr", message = "'__getAddress' only supports groupshared variables and members of groupshared/device memory." }
span { loc = "location", message = "'__getAddress' only supports groupshared variables and members of groupshared/device memory." }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diagnostic message says '__getAddress' only supports groupshared variables and members of groupshared/device memory. but this is no longer accurate after this PR. Now __getAddress accepts all variable types at the semantic level; it's only the IR validation pass that rejects function-local addresses on GPU targets.

This message is now used in two contexts:

  1. Semantic check (visitAddressOfExpr): fires for non-lvalue expressions that can't be addressed at all
  2. IR validation (validateGetAddressUsageImpl): fires for function-local vars on GPU targets

For case 2, the message should probably say something like '__getAddress' cannot take the address of a function-local variable on this target. Consider either splitting into two diagnostics or updating the message to be more generic (e.g., '__getAddress' cannot take the address of this expression.).

}

if (!isCPUTarget(targetRequest) && !isCUDATarget(targetRequest))
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation skip uses !isCPUTarget(targetRequest) && !isCUDATarget(targetRequest). The LLVM target (e.g., HostLLVMIR) is a CPU-like target with flat memory that should also skip validation.

I believe isCPUTarget() does cover LLVM targets (via ArtifactDescUtil::isCpuLikeTarget), so this should work correctly. However, the relationship is implicit and non-obvious — elsewhere in the codebase doesTargetSupportUnrestrictedPointers explicitly includes isCPUTargetViaLLVM(req) as a separate check. Consider adding !isCPUTargetViaLLVM(targetRequest) here as well for clarity and robustness, since the new cpp_cuda_metal_spirv_llvm capability explicitly enables __getAddress on LLVM targets.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isCPUTarget() check is correct in this context. isCPUTargetViaLLVM() only exists due to a potential future direction where LLVM could be used for some GPU targets as well and it's only supposed to be used when doing something specific to the combination of targeting CPUs with LLVM.

Comment on lines +831 to +856
for (auto use = inst->firstUse; use; use = use->nextUse)
{
auto user = use->getUser();
if (user->getOp() != kIROp_Store)
continue;
auto store = as<IRStore>(user);
if (store->getPtr() != inst)
continue;
if (isFunctionLocalAddress(store->getVal()))
{
sink->diagnose(Diagnostics::InvalidAddressOf{
.location = inst->sourceLoc,
});
}
}
}

for (auto child : inst->getModifiableChildren())
{
validateGetAddressUsageImpl(sink, child);
}
}

void validateGetAddressUsage(IRModule* module, DiagnosticSink* sink)
{
validateGetAddressUsageImpl(sink, module->getModuleInst());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation pattern relies on finding kIROp_Store to the GetAddressDecoration-decorated var. However, IR simplification passes (which run much earlier in the pipeline — around line 1165 vs the validation placement at ~1627) may fold the store-load pair, eliminating the store and DCE-ing the var. In that case the function-local address flows through the IR undetected by this validation.

This is likely acceptable as a best-effort diagnostic (the invalid code would still fail during codegen/SPIRV-validation), but worth noting. You might consider placing this validation earlier (e.g. right after lowering, before simplification), or alternatively walking all uses of kIROp_Var with AddressSpace::Function to find any pointer-to-pointer escape paths rather than relying on the decoration.


// Walk through derived-pointer ops to find the root allocation,
// then check if it lives in function-local memory.
static bool isFunctionLocalAddress(IRInst* val)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can call getRootAddr() instead.

Copy link
Copy Markdown
Collaborator

@csyonghe csyonghe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tmp = kIROp_AssumeAddress(addr);
The checking behavior is:

  1. When emitting code for cuda/cpp, no validation needed.
  2. Immediately after linkIr, When emitting code for other targets,
    validate that getRootAddr(addr) is in
    UserPointer address space, and if not emit an error.

After running the validation pass, immediately replace assumeAddr(x) with x.
so none of the backend IR passes need to worry about this new opcode.

@aidanfnv aidanfnv marked this pull request as draft March 18, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: non-breaking PRs without breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants