Skip to content

Refactor hwygen arm64 asm dispatch ownership - #65

Merged
ajroetker merged 10 commits into
mainfrom
hwygen-arm64-dispatch-cleanup
Mar 24, 2026
Merged

Refactor hwygen arm64 asm dispatch ownership#65
ajroetker merged 10 commits into
mainfrom
hwygen-arm64-dispatch-cleanup

Conversation

@ajroetker

Copy link
Copy Markdown
Owner

Summary

  • persist shared slice-length expressions in hwygen parse metadata and validate specialization compatibility
  • move arm64 asm dispatch ownership into generated dispatcher/bridge files instead of z_c init ordering
  • add ARM64 roaring regeneration coverage in CI and regenerate roaring outputs

Testing

  • env GOCACHE=/tmp/go-build-cache go test ./cmd/hwygen
  • env GOCACHE=/tmp/go-build-cache go generate ./hwy/contrib/roaring
  • env GOCACHE=/tmp/go-build-cache go test ./hwy/contrib/roaring
  • env GOCACHE=/tmp/go-build-cache go test ./cmd/hwygen ./hwy/contrib/roaring

Replace the roaring-only regenerate + git-diff-exit-code check with a
full `go generate ./hwy/contrib/...` on ARM64. The bit-identical diff
check was failing because CI's clang produces different register
allocation than the macOS clang used to check in the assembly.

Now CI regenerates and tests all contrib packages (matmul, vec, nn,
etc.) on ARM64, catching hwygen regressions without requiring
deterministic assembly output.
GoAT compiles C → .s → .o, then runs objdump on the .o to get binary
encodings. When cross-compiling to a different OS (e.g. darwin from
linux), the .o was in Mach-O format which the Linux system objdump
can't read.

Fix: when the target OS differs from the host OS (but same arch),
assemble the .o using the host OS target triple. The instructions are
identical — only the container format (ELF vs Mach-O) changes — so
objdump can read it and extract the same binary encodings.

Also regenerate all contrib packages on ARM64 CI, not just roaring.
@ajroetker
ajroetker force-pushed the hwygen-arm64-dispatch-cleanup branch from 1bfa628 to 59ae7d1 Compare March 23, 2026 05:46
When cross-compiling to a different OS (e.g. darwin from linux), the .s
file uses target-specific assembly syntax (Mach-O directives, ; comments)
that the host assembler can't parse. Instead, compile the .o directly
from the C source using the host OS triple. The instructions are
identical regardless of OS, so objdump extracts the same binary encodings.

Also revert the llvm-objdump approach since it has incompatible output
format (different symbol names, leading whitespace).
When cross-compiling (e.g. generating Darwin SME assembly on Linux),
the system objdump can't read Mach-O object files. GoAT now falls
back to llvm-objdump, which handles both Mach-O and ELF formats.

llvm-objdump emits synthetic symbol names (e.g. "ltmp0") for the
first function in Mach-O files. The ARM64 objdump parser now accepts
an ordered function name list and falls back to positional matching
when a symbol isn't found in the function map.

Install llvm on CI runners to provide llvm-objdump.
Different clang versions produce functionally different assembly
(different optimization choices, register allocation), which causes
test failures in floating-point precision tests. The checked-in
assembly is already tested in the earlier CI steps.

The regeneration step now just verifies the hwygen + GoAT pipeline
produces compilable code.
When GoAT fails to compile a C file (e.g., bf16 NEON ops unsupported
by the host clang), it may have already generated .go and .s stubs
before clang failed. These orphaned files conflict with checked-in
.gen.go files, causing "redeclared in this block" errors. Remove all
intermediate files (.c, .o, .go, .s) in the error cleanup path.
@ajroetker
ajroetker merged commit 25fa00a into main Mar 24, 2026
2 checks passed
@ajroetker
ajroetker deleted the hwygen-arm64-dispatch-cleanup branch March 24, 2026 19:02
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