Skip to content

Implement V1 ABI rev 4: plan-time schema and code object loading - #25

Merged
BlivionIaG merged 5 commits into
masterfrom
claude/optimistic-noether-5fru6z
Sep 27, 2026
Merged

BlivionIaG merged 5 commits into
masterfrom
claude/optimistic-noether-5fru6z

Conversation

@BlivionIaG

Copy link
Copy Markdown
Owner

This PR implements the V1 ABI revision 4, a major refactoring of the consume interface that separates planning from execution and introduces schema-driven code generation.

Summary

The V1 ABI evolves from revision 3 to revision 4, introducing:

  • Plan-time separation: hippihx_v1_plan() runs host-only before capture to validate params, size scratch, and report readiness
  • Schema-driven code generation: Op parameters, tensors, scratch, and conditions are now declaratively specified in catalog.py and code-generated into C tables and enums
  • Code object loading: New hippihx_v1_load*() functions validate and load raw AMDGPU ELF files with architecture and ISA checks
  • Explore variants: Support for variant selection based on parameter enums (e.g., decode vs. prefill modes)

Key Changes

Core ABI and Tables (tiles/v1_abi.cpp, include/hippihx/v1.h):

  • Expanded from ~100 to ~600 lines with generated row tables: kOps, kArches, kParams, kConds, kChecks, kDims, kSlots, kScratch
  • New hippihx_v1_plan_t struct with ready, variant, scratch_nbytes, and per-scratch offsets
  • New status codes: ERR_PARAM, ERR_TENSOR, ERR_UNSUPPORTED_FABRIC, ERR_CODE_OBJECT, ERR_FOREIGN_ISA, ERR_NO_HIP
  • Code object loader: hippihx_v1_load_image() validates ELF headers, architecture, and ISA before hipModuleLoadData()

Schema and Catalog (hippihx/_lib/catalog.py):

  • New dataclasses: Cond, ParamSpec, Divisible, TensorSlot, ScratchRule, OpSpec (extended)
  • Each op now declares: parameters (int/enum/bool/float with bounds), cross-param checks, tensor slots (with dims, layout, dtype, roles), and scratch rules
  • FA_FDOT2 pinned with 10 params, 1 check, 7 slots, 3 scratch specs; other ops unpinned (ready=False)

Code Generation (hippihx/_lib/codegen.py, new):

  • Generates C tables, CMake lists, shell case statements, Mojo aliases, and arch macros from catalog
  • Markers: // hippihx:gen begin <name> -- python -m hippihx._lib.codegen; do not edit
  • Rewrite tool: python -m hippihx._lib.codegen updates stale blocks; --check exits 1 if any are stale

V1 Mirror and Helpers (hippihx/_lib/v1.py, extended):

  • V1Status enum with 13 codes (append-only)
  • Helper functions: param_values(), plan_variant(), scratch_layout(), arena_layout(), fabric_status(), variant_ranks()
  • Validation: schema_errors() checks param domains, tensor ranks, scratch bounds

ctypes Bindings (hippihx/_lib/v1_ctypes.py, new):

  • Mirrors C structs: Param, Fabric, Caps, Tensor, ScratchSpec, Plan
  • load(path) opens any shared object exporting hippihx_v1_*
  • Helper: params_array(), fabric_struct() for test setup

Code Object Validation (hippihx/_lib/codeobject.py, new):

  • check_code_object(): validates 64-bit little-endian AMDGPU HSA ELF
  • Refuses offload bundles, relocatable .o files, and mismatched `EF_A

https://claude.ai/code/session_01YM2kXWFyL3J2Gs4F1oZk7Y

The op table and arch lists were copied by hand into v1.h, v1_abi.cpp,
isa.hpp, arch.hpp, HippihxArch.cmake, CMakeLists.txt, build_fatbin.sh
and mojo/isa/contracts.mojo. python -m hippihx._lib.codegen now renders
the lines between hippihx:gen begin/end markers from catalog.OPS,
fatbin, isa and v1. --check fails on drift, and a host test runs it.

No contract change. v1_abi.cpp reads a generated arch slot table instead
of three hand lists. build_fatbin.sh used to accept gfx1013 and leave
the refusal to CMake. It now refuses both Later slots before cmake runs,
with the fatbin note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YM2kXWFyL3J2Gs4F1oZk7Y
Rev 3 could not launch a real kernel. hippihx_v1_run(op, caps, scratch)
took no stream, no tensors and no shapes, and plan could not size
scratch from caps alone. Rev 4 is generated from the catalog:

- hippihx_v1_plan(op, caps, params, nparams, &plan) is host-only and
  runs before capture. It fills a caller-owned hippihx_v1_plan_t: the
  ready bit (serve picks its fallback before capture), the explore
  variant, and zeroed scratch specs at 256-byte offsets in one block.
  A failed plan is zeroed and run refuses it.
- hippihx_v1_run(&plan, tensors, ntensors, scratch, nbytes, stream)
  checks each required slot (dtype, rank, extents against params,
  layout) and the scratch block, then returns NOT_READY. It never
  allocates and never reads device memory.
- caps.fabric carries hop + switch, so comm plans also key on arch +
  wave + hop + switch in C. A non-PIX hop fails with UNSUPPORTED_FABRIC
  and serve keeps RCCL.
- DOT plans refuse wave64 in C and in is_supported.

attention.fa_fdot2 is pinned from the extras fa_rdna2.cu host
signatures @ cd38a1d: 10 params, 7 tensor slots, and the fp32 split-K
partials as plan scratch (extras allocates them and O inside the op).
extras indexes those partials with 32-bit int in the decode kernels,
the combine and the prefill empty-split path, so plan refuses
T*H_q*S*D > 2^31-1. comm.pcie pins max_bytes <= AR_MAX_KB. Every other
op stays unpinned, and no op is ready.

Python plan(caps, **params) mirrors the C plan, and V1Error carries the
C status. plan(caps) stays a contract plan with no scratch. A new test
builds tiles/v1_abi.cpp with the host compiler and checks C against
Python through ctypes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YM2kXWFyL3J2Gs4F1oZk7Y
The docs promised hipModuleLoad, but the build only made a static
libhippihx_<arch>.a, which hipModuleLoad cannot open. Consume is now two
files per configure tree:

- libhippihx_v1.so: V1 symbols and generated tables, no device code, so
  one build serves every slot. With HIP it links libamdhip64.
- hippihx_<arch>.hsaco: the slot's device code as one raw AMDGPU ELF
  (one --offload-arch, --cuda-device-only, --no-gpu-bundle-output),
  built from the generated tiles/code_object.hip. DOT tiles are in it
  only on DOT slots.

New V1 entries hippihx_v1_load / _load_image / _loaded run at serve
init, before capture. They refuse a slot that is not built (gfx1013 and
gfx906 never load), HSA_OVERRIDE_GFX_VERSION in the environment, any
ELF whose EF_AMDGPU_MACH is not the slot's (FOREIGN_ISA), and anything
that is not one raw AMDGPU ELF (CODE_OBJECT). Only then do they call
hipModuleLoadData. plan.ready now also needs the slot loaded. The
additions are append-only, so the revision stays 4. Tile entries are
extern "C" so kernels resolve by plain name.

The mach table matches clang output for all 13 arches. Tests build the
real code object for every built slot with local clang, and check the C
loader against the Python mirror (hippihx._lib.codeobject). The HIP
branch is compile-checked against the hipModuleLoadData signature only.
The CMake .hsaco rule and hipModuleLoadData have not run on ROCm 7.14
or a V620 here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YM2kXWFyL3J2Gs4F1oZk7Y
rdna_extras loads libhippihx_v1.so from Python. Give it public names
(hippihx.v1_ctypes, hippihx.v1.find_spec / CODE_OBJECT / HOST_LIBRARY)
instead of reaching into hippihx._lib.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YM2kXWFyL3J2Gs4F1oZk7Y
Conflicts:
- hippihx/_lib/ops.py: keep the rev 4 contract/sized plan split and add
  #23's meta["mojo_registered"] / meta["authoring"] to the shared meta.
- README.md, docs/ARCHITECTURE.md: take #23's authoring-center layout.
  Its dest text still said V1 ABI rev 3; say rev 4, and name the
  libhippihx_v1.so + hippihx_<arch>.hsaco consume pair.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YM2kXWFyL3J2Gs4F1oZk7Y
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.

2 participants