Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .verdicts/unshadow-unboxed-array/asm_simd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# UNSHADOW unboxed-array asm — SIMD vectorization is the wall
# sizeof(HexaVal)=16 (tag+union) → boxed items[] = 16-byte stride, no SIMD gather
# native int64_t[] = 8-byte contiguous → clang -O2 vectorizes

## vector-op counts (.2d/.4s/q-reg/ldp):
a_boxed = 5
b_unbox = 5
c_native = 23

## bl _hexa_index_get:
a_boxed=1 b_unbox=0 c_native=0
53 changes: 53 additions & 0 deletions .verdicts/unshadow-unboxed-array/pilot.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
UNSHADOW milestone "🟢 unboxed-primitive array" (axis A, typed-repr RFC) — pilot verdict
mini (macOS arm64) · clang · best-of-9 wall · same runtime.o all arms · 2026-05-30
tool/unshadow_unboxed_array_bench.hexa (faithful A/B proxy — full self-host regen blocked by B9 wall, spec-accepted)

VERBATIM bench stdout (mini, --runs 9):

=== UNSHADOW unboxed-primitive array bench (axis A) ===
rt=/Users/mini/.hx/packages/hexa/self work=/tmp/uba-work runs=9
--- C: known-int-array hot-loop sum (4 arms) ---
[ref_c ] built=yes err_lines=0
[a_boxed ] built=yes err_lines=0
[b_unbox ] built=yes err_lines=0
[c_native] built=yes err_lines=0
g5 byte-diff (program output md5 — ALL FOUR MUST be identical):
ref_c : 35470124be79241c684dc5103ec55d20
a_boxed : 35470124be79241c684dc5103ec55d20
b_unbox : 35470124be79241c684dc5103ec55d20
c_native : 35470124be79241c684dc5103ec55d20
perf best-of-9 wall (s):
ref_c : 0.08
a_boxed : 1.12
b_unbox : 1.12
c_native : 0.08
asm bl _hexa_index_get (total): a_boxed=1 b_unbox=0 c_native=0
--- INTEGRITY: typed i64 array at a polymorphic boundary ---
[a_bnd] built=yes err_lines=0
[b_bnd] built=yes err_lines=0
boundary g5 (MUST be identical — unbox never changes a value):
a_bnd (boxed) : 9efbbf5d320a45f2ce6e89491a1ac726
b_bnd (unbox) : 9efbbf5d320a45f2ce6e89491a1ac726
→ both MUST match: the typed array boxes correctly when it reaches
the polymorphic boundary (hexa_len + checked element fetch).
=== done ===

INTERPRETATION (honest):
- g5 byte-diff IDENTICAL across all 4 arms + the dynamic-boundary case (both 9efbbf5d…).
Correctness PROVEN, integrity gate PASS — the typed array boxes correctly at a
polymorphic site, and dropping the tag-guard never changes a value.
- PERF = 🔴 CLOSED-NEGATIVE on the LANDED transform (boxed-storage tag-guard drop):
b_unbox 1.12s ≈ a_boxed 1.12s = ~0% Δ. The c-class tag-guard `HX_IS_ARRAY(arr)?`
is LOOP-INVARIANT — clang -O2 already hoists it out of the hot loop in arm A, so
removing it (arm B, index_get 1→0) yields no wall change.
- The REAL wall is the STORAGE representation, not the tag-guard. sizeof(HexaVal)=16
→ HexaArr.items[] is a 16-byte-strided boxed array; clang cannot SIMD-gather it
(a_boxed/b_unbox = 5 vector ops). The native int64_t[] (c_native) is 8-byte
contiguous → clang vectorizes (23 vector ops) and closes the gap 100%
(c_native 0.08s ≈ ref 0.08s). asm_simd.txt has the vector-op counts.
- MISSING INFRA (the determinant): a true native int64_t[]/double[] array
representation (HexaArrI64/F64) does NOT exist — HexaArr is boxed HexaVal* only.
That is a RUNTIME change (new struct + box/unbox helpers + every array primitive
must branch on element-kind), blocked here by the B9 generated-runtime wall and
out of scope for a codegen-only pilot. Axis A therefore RULES OUT "codegen-only
unbox (drop tag-guard, read boxed .i)" as a perf lever — the gap lives in storage.
49 changes: 49 additions & 0 deletions domains/UNSHADOW.bench.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,3 +581,52 @@ emit. 양쪽 arm 모두 "out of bounds" surfaced=1. **증명-안전한 read 만
full self-host regen 은 B9 generated-runtime 벽으로 차단(prior agents 도 동일) → faithful A/B
프록시(emit 문자열은 codegen L7661 과 byte-동일·스펙 허용) · repo 안 `.c` 0개. 재현 =
`tool/unshadow_cclass_bounds_bench.hexa --rt <self-with-runtime.o> --runs 9`.

## §unboxed-array — 🟢 unboxed-primitive array (axis A) — perf 🔴 CLOSED-NEGATIVE

> milestone "🟢 unboxed-primitive array" 의 실측. **요지**: §c-class 가 명시한 미측정
> lever("known-array 추적기가 생기면 tag-guard 도 삭제")를 측정한다. codegen 이 불변
> `let xs=[int-lit…]` 를 monomorphic-i64 로 정적증명하면 in-range read `xs[i]` 의
> §c-class array-tag guard 를 삭제하고 raw `.i` 를 추출한다(boxed-storage unbox). **발견**:
> 이 unbox 는 갭을 안 닫는다 — 갭은 tag-guard 가 아니라 **boxed 저장 표현**에 산다.
> SSOT 도구 = `tool/unshadow_unboxed_array_bench.hexa` · verdict = `.verdicts/unshadow-unboxed-array/`.

측정: `mini` (macOS arm64) · clang · best-of-9 wall · 같은 `runtime.o` 링크 · 2026-05-30.
워크로드 = 256-elem 정수 배열의 sum × 4M outer iters (codegen 이 `let xs=[..]` +
`for i in 0..len(xs) { acc += xs[i] }` 에 emit 하는 정확한 C shape).

### 표 — 4-way wall min (s) + asm

| arm | 원소 read emit | wall (s) | `bl _hexa_index_get` | SIMD vec-op | 판정 |
|---|---|---|---|---|---|
| ref_c (idiomatic `int64_t buf[]`) | `buf[i]` | **0.08** | — | 23 | parity baseline |
| a_boxed (BEFORE = §c-class) | `(HX_IS_ARRAY(a)?items[i]:checked)` | 1.12 | 1 (cold) | 5 | boxed read + tag-guard |
| b_unbox (AFTER = 신규 codegen) | `a.arr_ptr->items[i]` (guard 삭제) | **1.12** | **0** | 5 | tag-guard 삭제 → **~0% Δ** |
| c_native (CEILING = HexaArrI64) | `data[i]` (native `int64_t*`) | **0.08** | 0 | 23 | 갭 100% close |

> g5: 4-arm stdout md5 전부 `35470124be79241c684dc5103ec55d20` (IDENTICAL).

### 무결성 게이트 — typed 배열이 polymorphic 경계서 정확히 box

typed `[i64]` 배열을 unboxed fast-path 로 sum 하면서 **동시에** polymorphic site
(`hexa_len` + checked `hexa_index_get` element fetch = codegen 이 non-proven 접근에 emit
하는 BOXED 경로)로 흘려보내는 boundary corpus. boxed(a_bnd)·unbox(b_bnd) 양쪽 arm md5
`9efbbf5d320a45f2ce6e89491a1ac726` 동일 → **typed array 가 동적 경계서 정확히 box, unbox 는
값 무변경**. (c-class 의 OOB-still-throws 에 대응하는 이 milestone 의 무결성 게이트.)

### 정직한 해석 — 갭은 tag-guard 가 아니라 STORAGE 에 산다

- **correctness WIN.** element-kind 증명(immutable int-literal-array + live in-range fact)
이 정확·좁고, byte-diff 4-arm + 동적경계 IDENTICAL. provably-dead guard 만 삭제(무회귀).
- **perf 🔴 CLOSED-NEGATIVE.** b_unbox 1.12s ≈ a_boxed 1.12s. tag-guard `HX_IS_ARRAY(arr)?`
는 **loop-invariant** 라 clang -O2 가 이미 hoist — 삭제해도(index_get 1→0, cold fallback
제거) wall 무변. §c-class 가 "미측정 lever" 라 한 그 lever 가 **null** 임을 측정으로 확정.
- **진짜 벽 = boxed 저장.** `sizeof(HexaVal)=16` → `HexaArr.items[]` 는 16B-stride 박스
배열, clang SIMD-gather 불가(5 vec-op). native `int64_t[]`(c_native, 8B contiguous)만
vectorize(23 vec-op)해 갭 100% close. `.verdicts/unshadow-unboxed-array/asm_simd.txt`.
- **누락 인프라 = native `HexaArrI64`/`F64` 저장 표현**(RUNTIME 변경 — 새 struct + box/unbox
헬퍼 + 모든 array primitive 의 element-kind 분기). B9 벽 밖·codegen-only pilot 범위 밖.
→ axis A 가 "codegen-only unbox 는 perf 레버 아님" 을 결정적 배제. 갭은 STORAGE.
- caveat: 단일 호스트(mini)·best-of-9·양 arm 동일 runtime.o·full self-host regen 은 B9 벽
차단 → faithful A/B 프록시(b_unbox emit 은 codegen L7666 신규 arm 과 byte-동일·스펙 허용) ·
repo 안 `.c` 0개. 재현 = `tool/unshadow_unboxed_array_bench.hexa --rt <self-with-runtime.o> --runs 9`.
45 changes: 45 additions & 0 deletions domains/UNSHADOW.log.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,3 +629,48 @@ elision 을 라이선스.
amalgam merge 가 pre-existing 타입에러로 실패, 내 edit 무관) → faithful A/B 프록시(emit 문자열
codegen L7661 과 byte-동일·스펙 허용). 잔존 lever = known-array 추적기(생기면 tag-guard 도 삭제).
verdict=`.verdicts/unshadow-cclass-bounds/` · 재현=`tool/unshadow_cclass_bounds_bench.hexa`.

---

## 🟢 unboxed-primitive array (axis A, typed-repr RFC) — 2026-05-30

§c-class 가 남긴 미측정 lever("known-array 추적기가 생기면 tag-guard 도 삭제")를 측정했다.
**결과 = correctness WIN · perf 🔴 CLOSED-NEGATIVE** — 갭이 tag-guard 가 아니라 **저장 표현**
에 산다는 것을 결정적으로 못 박았다.

**element-kind 증명 + unbox site (self/codegen.hexa).**
- `_is_int_literal_array(node)` — 배열 리터럴 `[1,2,3,…]` 의 모든 원소가 IntLit 인지 (정확·좁은
monomorphic-i64 증명, Ident·call·float·nesting 전부 거부).
- LetStmt 등록 (`gen2_stmt`, ~L2897): 불변 `let xs=[int-lit…]` → `_known_intarr_add(xs)`.
AssignStmt LHS Ident 재대입 → `_known_intarr_void` (re-let 비-int-array 도 void). LetMutStmt 제외.
- Index emit (~L7666): `xs[i]` 가 live in-range fact 로 덮이고(`_inrange_counter_for`) `xs` 가
known-int-array 이면 → §c-class ternary `(HX_IS_ARRAY(xs)?items[i]:checked)` 대신 **direct
`(xs.arr_ptr->items[ctr])`** (array-tag guard 삭제, array-ness 정적증명).
- `_is_known_int(node)` (~L9981): `node` 가 known-int-array 의 in-range read `arr[i]` 면 true →
주변 sum/dot BinOp 가 raw `.i` 를 HX_INT 로 추출(원소-당 tag dispatch 0). 두 게이트 모두
immutable-let 등록 AND live in-range fact 둘 다 요구 → unproven/boxed 접근엔 절대 발화 안 함.

**byte-diff IDENTICAL (g5, mini best-of-9).** 4-arm(ref_c·a_boxed=§c-class·b_unbox=신규·c_native
=ceiling) stdout md5 전부 `35470124…`. **무결성 게이트 PASS**: typed `[i64]` 배열을
polymorphic site(`hexa_len`+checked element fetch)로 흘려보낸 boundary corpus — boxed/unbox
양쪽 arm md5 `9efbbf5d…` 동일. unbox 는 값을 절대 안 바꾸고, typed array 는 동적 경계서 정확히 box.

**perf 🔴 CLOSED-NEGATIVE.** b_unbox 1.12s ≈ a_boxed 1.12s = **~0% Δ**. tag-guard
`HX_IS_ARRAY(arr)?` 는 **loop-invariant** 라 clang -O2 가 이미 hot loop 밖으로 hoist — 삭제해도
(asm `bl _hexa_index_get` 1→0, cold fallback 제거) wall 무변. 진짜 벽 = **boxed 저장**:
`sizeof(HexaVal)=16` → `HexaArr.items[]` 는 16B-stride 박스 배열, clang 이 SIMD-gather 불가
(a_boxed/b_unbox = 5 vec-op). native `int64_t[]`(c_native, 8B contiguous)만 vectorize
(23 vec-op)해 갭 100% close (c_native 0.08s ≈ ref 0.08s). asm=`.verdicts/unshadow-unboxed-array/asm_simd.txt`.

**누락 인프라 (축 ruled-out).** 진짜 native `int64_t[]`/`double[]` 저장 표현(`HexaArrI64`/`F64`)
이 **없다** — `HexaArr` 는 boxed `HexaVal*` 전용. 그건 RUNTIME 변경(새 struct + box/unbox 헬퍼 +
모든 array primitive 가 element-kind 분기)이고 B9 벽 밖·codegen-only pilot 범위 밖. → axis A 가
**"codegen-only unbox(tag-guard 삭제 + boxed `.i` read)는 perf 레버가 아니다"** 를 결정적으로
배제. 갭은 STORAGE 에 산다. paper_negative_ok: 데이터-표현 축 결정적 배제 = valid terminal.

**정직 caveat**: full self-host regen 은 B9 generated-runtime 벽 차단 → faithful A/B 프록시
(b_unbox emit 은 codegen L7666 신규 arm 과 byte-동일·스펙 허용, prior round 들과 동일). 단일
호스트(mini)·best-of-9·양 arm 동일 runtime.o·repo 안 `.c` 0개. codegen 변경은 byte-identical
+ provably-dead guard 삭제(무회귀)라 axis B(monomorphic struct)의 element-kind 증명·box/unbox
경계 규율 기반으로 유지. verdict=`.verdicts/unshadow-unboxed-array/` ·
재현=`tool/unshadow_unboxed_array_bench.hexa`.
2 changes: 1 addition & 1 deletion domains/UNSHADOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@

> 백로그 재개 — E(🔴) 의 근본 원인 "typed 표현 부재" 를 다음 frontier 레버로 등록. 둘 다 `.c=0` LTO 졸업과 직교(§c-class 가 입증: codegen 증명은 runtime.o 벽과 독립). 선후 = A → B → (B 완료 시) E 재오픈. 설계·착지점·게이트 상세 = `UNSHADOW.typed-repr.md`.

- [ ] 🟢 unboxed-primitive array (`[i64]`/`[f64]` → native `int64_t[]`/`double[]`, boxed HexaVal[] 아님) — §parity-attest(7.9×~1263×) 의 array 축 · §hexaval-unbox(scalar 0.98× closed) 의 array 확장 · §c-class 가 남긴 미측정 lever(boxed-on-read + tag-guard 잔존, bench L577-579)의 직계. 착지=element-kind 추론(check) + ArrayLit/Index emit(codegen `:7594`/`:7661`) typed-arm + box/unbox 헬퍼(runtime.h public). 발화=원소타입 정적 i64/f64 증명 시만, else 기존 BOXED 무변경. 게이트=byte-diff IDENTICAL(typed ON/OFF·동적경계 box 정확) + parity Δ 측정(array hot-loop). RFC=domains/UNSHADOW.typed-repr.md
- [x] 🟢 unboxed-primitive array — **correctness WIN · perf 🔴 CLOSED-NEGATIVE (축 ruled-out: 갭은 tag-guard 아니라 STORAGE).** codegen 에 element-kind 추론 착지(self/codegen.hexa): 불변 `let xs=[int-lit…]`(전부 IntLit) → `_known_intarr_set` 등록, in-range fact 가 덮는 `xs[i]` read 가 (a)receiver TAG_ARRAY (b)elem TAG_INT 둘 다 정적증명 → §c-class array-tag guard(`HX_IS_ARRAY?`) 삭제 + `_is_known_int(xs[i])=true`(sum/dot 가 raw `.i` 추출). 발화=불변-let+live in-range fact 둘 다일 때만, 재대입/re-let 즉시 void, else 기존 BOXED 무변경. g5 byte-diff IDENTICAL 4-arm(ref·a_boxed·b_unbox·c_native, md5 `35470124`) + 동적경계 box 정확(typed array→polymorphic site, md5 `9efbbf5d` 양쪽 동일). **perf**: b_unbox 1.12s ≈ a_boxed 1.12s = ~0% Δ — tag-guard 는 loop-invariant 라 clang -O2 가 이미 hoist(삭제해도 wall 무변). 진짜 벽 = boxed 저장(sizeof HexaVal=16 → items[] 16B-stride, SIMD-gather 불가 5 vec-op); native int64_t[](c_native, 8B contiguous, 23 vec-op) 만 갭 100% close(0.08s≈ref). **누락 인프라 = native HexaArrI64/F64 저장 표현(runtime 변경, B9 벽 밖·codegen-only 범위 밖)** = 갭이 사는 곳. mini macOS arm64 best-of-9. verdict=`.verdicts/unshadow-unboxed-array/` · 재현=`tool/unshadow_unboxed_array_bench.hexa`. RFC=domains/UNSHADOW.typed-repr.md
- [ ] 🔵 typed monomorphic struct layout (flat C-struct typedef + offset field access, hash-map 아님) — E(AoS↔SoA) 재오픈 선결 · 현 struct=`hexa_struct_pack_map` 해시맵(`:8043`)·field=`hexa_map_get_ic` strcmp/IC(`:5394`)·valstruct 는 12-슬롯 carrier 전용(일반화 불가, `:7995`). monomorphic 증명(닫힌 필드집합·정적 접근) 시 per-type flat-struct emit + `obj.vs->f_k` offset 접근. 착지=struct shape 증명(check) + gen2_struct_decl(`:7982`) typedef arm + field access(`:5373`) offset arm. 다형/동적-키 struct 는 hash-map 유지. 게이트=byte-diff IDENTICAL + hash-lookup→offset Δ(instr+wall). RFC=domains/UNSHADOW.typed-repr.md
Loading
Loading