Skip to content

draft: artisan-macros — auditable SIMD dispatch proc-macros - #41

Draft
lilith wants to merge 2 commits into
mainfrom
feat/artisan-macros-draft
Draft

draft: artisan-macros — auditable SIMD dispatch proc-macros#41
lilith wants to merge 2 commits into
mainfrom
feat/artisan-macros-draft

Conversation

@lilith

@lilith lilith commented Apr 20, 2026

Copy link
Copy Markdown
Member

Summary

Draft of artisan-macros, a single-file proc-macro crate exploring an alternative to archmage's dispatch macro stack. Two attribute macros (#[cpu_tier], #[chain]) plus a thread-local test-hook layer. Convention-forward, user-owned feature strings, no registry, #![forbid(unsafe_code)]-compat downstream.

Do not merge. This lives on feat/artisan-macros-draft and is intentionally isolated from main until the design questions in the SPECs and HANDOFF.md are resolved.

What's here

  • Single-file impl in artisan-macros/src/lib.rs (~840 LoC)
  • #[cpu_tier(enable = "features")] attaches #[target_feature] + inferred #[cfg(target_arch)] + #[inline]; emits a hidden normalized feature const
  • #[chain(arch = [fn = "features", ...], default = fn)] generates trampoline chains: per-tier AtomicU8 tri-state caches, compile-time arch switch, top-tier compile-time feature elision
  • Per-chain thread-local force_max_tier RAII scope for parity-test isolation (no #[serial] or RUST_TEST_THREADS=1 needed)
  • Compile-time feature-string equality check between #[cpu_tier] and #[chain] — mismatch fails to build with a specific error; verified by deliberate mutation
  • 10 passing tests on x86_64: scalar smoke (3), real AVX2+FMA and NEON sum kernel (6), macrotest snapshots (1)
  • Committed macro-expansion snapshots under artisan-macros/tests/expand/
  • Dedicated CI at .github/workflows/artisan-macros.yml, path-filtered so archmage main CI is untouched. Matrix: ubuntu/windows/windows-11-arm/macos-26-intel/macos-latest native, i686/aarch64/armv7 cross, clippy (base + artisan_test_hooks feature), fmt, docs (-D warnings), expansion-drift check, feature-mismatch self-test
  • Nine markdown files: DESIGN.md, SPEC-CPU-TIER.md, SPEC-CHAIN.md, SPEC-TEST-HOOKS.md, README.md, HANDOFF.md, plus two unposted archmage GH issue drafts (PARITY_HARNESS_ISSUE_DRAFT.md, ARCHMAGE-THREAD-LOCAL-ISSUE.md)

What's not here yet

  • SPEC-CPU-TIER.md and SPEC-CHAIN.md predate the feature-string const — they need a Revisions section documenting the emitted __ARTISAN_CPU_TIER_FEATS_<fn> and the const _: () = { assert!(str_eq(...)) } blocks
  • #![forbid(unsafe_code)] downstream verification crate — claim documented, not compiled yet
  • Real downstream consumer — archmage itself doesn't use this yet
  • First CI run — this push is the trigger

Test plan

  • CI green on all matrix entries (the interesting ones: windows-11-arm, macos-latest Apple Silicon, aarch64 cross)
  • Feature-string mismatch self-test proves the compile-time check fires on a bad-chain crate
  • Expansion-drift check passes on x86_64 (snapshots are committed)
  • Reviewer reads HANDOFF.md first, then DESIGN.md + each SPEC-*.md; flags the open questions worth resolving before v0.1.0
  • Decide: adopt as archmage's internal dispatch (migration story), keep as separate crate, or discard

See artisan-macros/HANDOFF.md for the full review checklist and file inventory.

@codecov-commenter

codecov-commenter commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.77%. Comparing base (3ccf38d) to head (b293a77).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #41      +/-   ##
==========================================
- Coverage   74.32%   73.77%   -0.56%     
==========================================
  Files           6        6              
  Lines        1079     1079              
==========================================
- Hits          802      796       -6     
- Misses        277      283       +6     
Flag Coverage Δ
aarch64 71.97% <ø> (-1.04%) ⬇️
x86_64 73.09% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Status: experimental draft on bookmark feat/artisan-macros-draft.
Explicitly not for merge to main. Review artifact, not production code.

Two proc-macros plus a thread-local test-hook layer:

1. #[cpu_tier(enable = "features")] — attaches #[target_feature] +
   #[cfg(target_arch)] + #[inline]. Arch inferred from unambiguous
   feature names (avx2 → x86_64, neon → aarch64, simd128 → wasm32).
   Ambiguous-only feature sets (aes, sha2, crc, fp16) fail inference
   with an explicit-arch prompt. Emits a hidden const
   __ARTISAN_CPU_TIER_FEATS_<fn> carrying the normalized feature string.

2. #[chain(arch = [...], default = ...)] — applied to empty-body fn.
   Generates entry dispatcher with compile-time arch switch and
   top-tier compile-time feature elision, per-tier trampolines with
   AtomicU8 tri-state caches (empty / unsupported / supported), and
   per-arch const _: () blocks that assert feature-string equality
   against each tier's __ARTISAN_CPU_TIER_FEATS_<fn> const. Mismatches
   fail to compile with a clear error naming the tier and both strings.

3. Test hooks behind cfg(any(test, feature = "artisan_test_hooks")):
   per-chain enum, thread-local Option<u8>, RAII scope guard, and a
   <chain>_force_max_tier function. Per-thread isolation — forcing on
   thread A doesn't affect thread B. No #[serial] or
   RUST_TEST_THREADS=1 needed. Rayon workers don't inherit (documented).

Tests (10 passing on x86_64 Linux):
- tests/smoke.rs: scalar-body dispatch mechanics (3 tests)
- tests/real_kernel.rs: real AVX2+FMA and NEON sum kernels (6 tests)
- tests/expand.rs: macrotest snapshot driver (1 test)
- tests/expand/{cpu_tier_basic,cpu_tier_explicit_arch,chain_simple,chain_multi_arch}.{rs,expanded.rs}:
  committed macro-expansion snapshots, regenerable with MACROTEST=overwrite

CI (.github/workflows/artisan-macros.yml):
- Path-filtered to artisan-macros/** so archmage main CI is untouched
- Native: ubuntu-latest, windows-latest, windows-11-arm, macos-26-intel, macos-latest
- Cross: i686, aarch64, armv7 via cross
- Lint: clippy (base + artisan_test_hooks feature), fmt, docs -D warnings
- Expand-snapshots: installs cargo-expand, runs macrotest, fails on drift
- Feature-mismatch-catches: builds a deliberate-mismatch crate and
  asserts the build fails with the expected error text

Specs and documentation (9 markdown files, ~1000 lines):
- DESIGN.md, README.md, HANDOFF.md
- SPEC-CPU-TIER.md, SPEC-CHAIN.md, SPEC-TEST-HOOKS.md (SPEC files predate
  the feature-string const — a Revisions section is pending)
- PARITY_HARNESS_ISSUE_DRAFT.md, ARCHMAGE-THREAD-LOCAL-ISSUE.md
  (unposted archmage enhancement drafts)

Total: ~840 LoC impl in single src/lib.rs, ~1000 lines of specs,
~260 lines of tests, ~230 lines of CI. Publish = false throughout.
@lilith
lilith force-pushed the feat/artisan-macros-draft branch from 159103a to 7733d10 Compare April 20, 2026 20:28
Two independent bugs surfaced in the first CI run on PR #41.

1. detect_macro_for emitted `::std::is_aarch64_feature_detected` and
   `::std::is_arm_feature_detected` but these paths fail to resolve
   under some cross-compile configurations (reproduced locally via
   `cargo check --target aarch64-unknown-linux-gnu`: E0433 'cannot
   find in std'). Archmage itself uses `::std::arch::is_*_feature_detected`
   consistently — that path works across all targets we care about.
   Routed all three detection macros (x86, aarch64, arm) through
   `::std::arch::`. Snapshot files are byte-identical because `cargo
   expand` fully expands the macro to `::std_detect::detect::`... the
   path change is invisible post-expansion.

2. The expand test was running on every native job but cargo-expand is
   only installed in the dedicated expand-snapshots job. Result: all
   five native `Test` jobs failed with 'no such command: expand' from
   inside macrotest. Put the expand test behind a new
   `run_expand_test` Cargo feature via Cargo.toml's
   `required-features`; the test target is skipped entirely at build
   time unless the feature is on. The expand-snapshots job enables it
   with `--features run_expand_test`. Native test jobs no longer need
   cargo-expand. Also switched the expand-snapshots job from
   `cargo install cargo-expand` to `taiki-e/install-action` for a
   faster precompiled binary.

Local verification:
- `cargo check --tests --target aarch64-unknown-linux-gnu` passes
- `cargo check --tests --target armv7-unknown-linux-gnueabihf` passes
- `cargo check --tests --target i686-unknown-linux-gnu` passes
- `cargo test -p artisan-macros` (default features) 9 tests pass
- `cargo test -p artisan-macros --features run_expand_test` all pass
- clippy -D warnings clean on both feature sets, fmt clean
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