Skip to content

[AMDGPU] Address-space-at-source global memory optimization - #866

Open
paveltc wants to merge 2 commits into
Genesis-Embodied-AI:mainfrom
paveltc:feat/amdgpu-global-as
Open

[AMDGPU] Address-space-at-source global memory optimization#866
paveltc wants to merge 2 commits into
Genesis-Embodied-AI:mainfrom
paveltc:feat/amdgpu-global-as

Conversation

@paveltc

@paveltc paveltc commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

On the AMDGPU backend, device buffers are currently materialized as generic (flat) pointers. As a result, most memory traffic in generated kernels lowers to flat_load/flat_store instructions, which go through the slower generic-addressing path even though the underlying memory is always global. This PR tags device pointers as addrspace(1) (global) at the point where they are materialized, so that LLVM's InferAddressSpaces pass can propagate the global address space through the kernel and promote flat_* operations to global_* operations.

The change is fully gated behind the QD_AMDGPU_GLOBAL_AS environment variable and arch-guarded to AMDGPU only. When the gate is unset, code generation is byte-for-byte identical to upstream (verified — see Test Plan). CPU and CUDA backends are completely untouched.

What changes

The work is split into two layers:

Layer A — source-side tagging (codegen/amdgpu/codegen_amdgpu.cpp)
AMDGPU-specific codegen overrides that tag pointers as addrspace(1) where they are first materialized:

  • ExternalPtrStmt — ndarray data pointers
  • GlobalTemporaryStmt — runtime global-temporary buffer pointers
  • MatrixPtrStmt — preserves the origin address space through the byte-offset GEP, avoiding ptrtoint/inttoptr round-trips that would otherwise strip the address space.

Layer B — argument-walk provenance (codegen/llvm/codegen_llvm.cpp, .h)
Shared LLVM-layer changes that carry the global address space along the pointer-derivation chain, so the tag survives from the argument struct down to the element access and doesn't get re-stripped per iteration. A single choke-point helper, maybe_tag_amdgpu_global_ptr(), applies the tag only when the arch is AMDGPU and the gate is set; it is a no-op otherwise. This is applied in get_struct_arg(), get_args_ptr(), and visit(ExternalPtrStmt), and atomic_op_using_cas() is adjusted to preserve the destination's address space when forming the integer pointer for CAS loops (preventing invalid cross-addrspace bitcasts).

Diff footprint: 3 files, +103 / −5.

Effect on generated IR

With the gate on, generic (flat) loads collapse dramatically as the global address space propagates through the kernel — on the franka monolith kernel, flat loads dropped from 10,768 → 503, with the remainder promoted to global-addressed operations.

Relationship to #775

#775 (amdgpu-ieee / amdgpu-dx10-clamp attribute harmonization) is complementary but not required. This PR was built and validated on upstream main without #775 present, and delivers its speedups independently. The two compose cleanly and can land in either order.

Test Plan

All testing was performed on an MI300X (gfx942) node under ROCm/HIP, with GPU clocks locked to 1900 MHz for measurement determinism. Correctness and performance were measured A/B (gate ON vs. gate OFF) using the genesis test_rigid benchmark harness.

  • Correctness (franka + anymal, both arms): PASS. Both robots produce correct simulation results with the gate ON and OFF.
  • IR verification: PASS. With the gate ON, InferAddressSpaces promotes flat memory operations to global as intended (franka monolith: 10,768 → 503 flat loads).
  • Performance (A/B, gate ON vs OFF): franka +17.7% (n=8), anymal +4.7% (n=3).
  • Gate-OFF byte-identical IR: PASS. Built a pristine wheel from this branch's base commit (patch removed) and dumped the optimized AMDGPU IR for a representative kernel from both the patched-but-gate-OFF build and the pristine base. All 82 kernels are byte-identical (matching SHA-256 over the full set), confirming the gate is a true zero-footprint switch.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5cba42cc23

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread quadrants/codegen/llvm/codegen_llvm.cpp Outdated
paveltc and others added 2 commits August 14, 2026 16:13
Tag AMDGPU device pointers as addrspace(1) where they are materialized so
InferAddressSpaces propagates the tag and dependent loads/stores lower to
global_load/global_store/global_atomic instead of generic flat_*.

Layer A (codegen_amdgpu.cpp): source-side tagging of ExternalPtr /
GlobalTemporary data pointers and address-space-preserving MatrixPtr GEPs.

Layer B (codegen_llvm.cpp/.h): carry global provenance through the shared
argument-pointer walk via maybe_tag_amdgpu_global_ptr() (get_args_ptr,
get_struct_arg, ExternalPtrStmt) so per-iteration re-casts collapse, and
preserve dest address space in atomic_op_using_cas.

All tagging is gated on QD_AMDGPU_GLOBAL_AS and arch-guarded to AMDGPU, so
CPU/CUDA emit byte-identical IR whether or not the patch is present.

Reconstructs AMD-Ecosystem PRs Genesis-Embodied-AI#7 (6c9889f, 2d78505) + Genesis-Embodied-AI#3 (4e59c11)
plus the argument-walk provenance fix, rebased onto current upstream.
get_args_ptr() is shared between the top-level kernel and @qd.real_func
(Function) callees. Only the top-level kernel's arg buffer is device-staged
in global memory; a Function callee receives a caller-local alloca buffer
(see visit(FuncCallStmt)), so casting it to addrspace(1) under
QD_AMDGPU_GLOBAL_AS made the callee read its scalar parameters through global
memory pointing at private storage.

Guard the args-buffer tag on the callable not being a Function. The ndarray
data-pointer tags in get_struct_arg() and ExternalPtrStmt are unaffected, so
top-level kernel promotion (and the measured speedups) are preserved: the
franka gate-ON optimized IR is byte-identical before and after this change.

Fixes the get_args_ptr provenance issue flagged in review.

Co-authored-by: Cursor <cursoragent@cursor.com>
@paveltc
paveltc force-pushed the feat/amdgpu-global-as branch from 6b3b56c to 31c6a64 Compare August 14, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant