Skip to content

Commit 017fd13

Browse files
dancinlifenbcorr-agentclaude
authored
feat(axis-② #4 f64 PR-2): array f64 typed-leaf seed + C-shim + resolver (default-OFF byte-neutral) (#4921)
* feat(axis-② #4 f64 PR-1a): bind.hexa allowlist __hx_f64_bits/__hx_bits_f64 (ADD-only byte-neutral) f64<->i64 bit-reinterpret leaf 2개 allowlist(census 완료 conv bind-hexa-1: f2i/i2f는 numeric convert·부재 확인). ADD-only·frozen 151c52c-safe(compiler never emits)→gen3==gen4 preserved. codegen lowering(x86_64 movq 66REX.W0F7E/6E·arm64 fmov 0x9E66/0x9E67·gen2 C union bitcast)=다음 커밋(PR-1b). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(axis-② #4 f64): spec v2 — float-param ABI crux resolved (C-shim GO, arm64 wall 회피) Fable 교정: float param SSE-ABI는 hxlcl 화이트리스트 전용(conv x86-64-linux-hexa-1)→seed는 xbits:int(GP)로 받고 3줄 C shim이 xmm0→GP union bitcast. 3-target 동시 flip(arm64 fp-ABI 벽 우회·per-target 불요)·leaf=trivial tag-swap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(axis-② #4 f64 PR-1b): __hx_f64_bits/__hx_bits_f64 tag-swap lowering (x86_64+arm64+gen2 C) f64<->i64 bit-reinterpret = TAG-SWAP(payload passthrough·NaN-boxed FLOAT payload=double bits). x86_64=payload→dst +store_tag_imm(INT/FLOAT) · arm64=_hv_load+movz x0 tag imm · gen2 C=((HexaVal){.tag=TAG_INT/FLOAT,.i=HX_INT(a)}). NOT movq/fmov/cvttsd2si(numeric/xmm·C-shim이 xmm0↔GP crossing 소유·conv x86-64-linux-hexa-1). __hx_make_val/__hx_tag 미러. ADD-only(compiler never emits). 검증=summer bit-pattern probe 양 backend + gen3≡gen4 byteeq 3-target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(axis-② #4 f64 PR-2a): array_typed_leaf_f64.hexa seed (hexa_arr_f64_{new,push_bits,len,box}) f64 typed-array 4-fn native seed. i64 seed 미러(8B stride 동일)·push_bits(xbits:int GP·C-shim이 double→bits)· box=__hx_bits_f64(FLOAT HexaVal·hexa_float 불요). float-param SSE-ABI 벽 우회(C-shim·conv x86-64-linux-hexa-1). seed-only·미배선·byte-neutral. wiring(에미터 shim+resolver+regen)=PR-1 #4920 머지 후. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(axis-② #4 f64 PR-2b-emit): f64 block 3-way + C-shim (F64_LEAF guard·byte-neutral) 에미터 f64 블록(3049) 재구조화: #if HEXA_RT_CORE_ARRAY_F64_LEAF_NATIVE(seed extern new/len/box/push_bits + static inline C-shim push(double→union.i→push_bits)) / #elif SELFEMIT||TYPED(기존) / #else(C bodies). C-shim이 float-param SSE-ABI 벽 소유(conv x86-64-linux-hexa-1). F64_LEAF OFF(default)→#elif=원본 #if→byte-identical. seed=array_typed_leaf_f64.hexa(별도 커밋). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(axis-② #4 f64 PR-2b-wire): resolver + regen + def-var (default-OFF byte-neutral) stage_resolve_runtime_a: resolve_native_array_f64_leaf_seed(i64 미러·own-obj --isolate+frozen-.s·KG=hexa_arr_f64_new/ push_bits/len/box·U-floor {malloc,realloc,write,hexa_exit,hexa_throw}·A0 shortcut HEXA_RT_OWNOBJ=0 게이트=conv stage-resolve-runtime-a-2)+rt_arr_f64_def def-var 5-라인 threading(trailing space=stage-resolve-flag-space-1)+call site. regen_array_typed_leaf_f64_native_s.sh(NSYMS=4·SYMS push_bits·ALLOWED_U hexa_int 제외). default-OFF byte-neutral. bash -n OK. seed+에미터 C-shim=이전 커밋. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: nbcorr-agent <nbcorr-agent@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 92d83ec commit 017fd13

4 files changed

Lines changed: 291 additions & 6 deletions

File tree

‎self/runtime_core_emit.hexa‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3046,7 +3046,17 @@ fn emit_runtime_core_to(out_path: str) {
30463046
// raw native double load through the runtime.o wall (§c-class). The box helper
30473047
// is used at the dynamic boundary (a typed-f64 array flowing to a polymorphic
30483048
// site re-boxes each element correctly as a TAG_FLOAT HexaVal).
3049-
buf = buf + "#if defined(HEXA_RT_SELFEMIT) || defined(HEXA_RT_CORE_ARRAY_TYPED_LEAF_NATIVE)\n"
3049+
// axis-② f64 typed-leaf flip (HEXA_RT_CORE_ARRAY_F64_LEAF_NATIVE): the seed provides
3050+
// new/len/box + push_bits(HexaVal, int64_t) directly (all GP-class), and a C shim owns
3051+
// the double→bits crossing (float-param SSE-ABI wall · convergence x86-64-linux-hexa-1).
3052+
// OFF (default) → the #elif is the original SELFEMIT||TYPED arm → byte-identical.
3053+
buf = buf + "#if defined(HEXA_RT_CORE_ARRAY_F64_LEAF_NATIVE)\n"
3054+
buf = buf + "extern HexaVal hexa_arr_f64_new(int cap);\n"
3055+
buf = buf + "extern int hexa_arr_f64_len(HexaVal v);\n"
3056+
buf = buf + "extern HexaVal hexa_arr_f64_box(HexaVal v, int64_t i);\n"
3057+
buf = buf + "extern HexaVal hexa_arr_f64_push_bits(HexaVal v, int64_t xbits);\n"
3058+
buf = buf + "static inline HexaVal hexa_arr_f64_push(HexaVal v, double x) { union { double d; long long i; } u; u.d = x; return hexa_arr_f64_push_bits(v, u.i); }\n"
3059+
buf = buf + "#elif defined(HEXA_RT_SELFEMIT) || defined(HEXA_RT_CORE_ARRAY_TYPED_LEAF_NATIVE)\n"
30503060
buf = buf + "extern HexaVal hexa_arr_f64_new(int cap);\n"
30513061
buf = buf + "extern HexaVal hexa_arr_f64_push(HexaVal v, double x);\n"
30523062
buf = buf + "extern int hexa_arr_f64_len(HexaVal v);\n"
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// stdlib/runtime/array_typed_leaf_f64.hexa — axis-② Tier-1 #4 typed-array TYPED-LEAF natives (f64).
2+
//
3+
// The hexa-source bodies for the packed-f64 array dispatchers that runtime_core.c
4+
// externs away under the HEXA_RT_CORE_ARRAY_F64_LEAF_NATIVE sub-guard (the f64 twin
5+
// of array_typed_leaf.hexa's i64 unit). Each body mirrors the i64 seed — the packed
6+
// layout is IDENTICAL (a double is 8 bytes, same stride as int64) so new/len are
7+
// byte-for-byte the same and push/box differ only in how the payload is read/written.
8+
//
9+
// ★ FLOAT-PARAM ABI (convergence x86-64-linux-hexa-1): a hexa `float` param does NOT
10+
// land in xmm0 by default (SSE fp-ABI is a hxlcl_* whitelist only), so the seed CANNOT
11+
// take a `double x` and match the C dispatcher hexa_arr_f64_push(HexaVal, double) whose
12+
// C callers pass the double in xmm0. RESOLUTION (C-shim, spec v2): the seed's push takes
13+
// `xbits: int` (a GP-class i64 = the double's raw bits), and a 3-line C shim in the
14+
// emitter — hexa_arr_f64_push(HexaVal v, double x){union{double d;long long i;}u; u.d=x;
15+
// return hexa_arr_f64_push_bits(v, u.i);} — owns the xmm0→GP crossing (correct on all 3
16+
// targets via the system C compiler, no arm64 fp-ABI wall). So this file is 100% GP-class.
17+
//
18+
// box() returns the element re-boxed as TAG_FLOAT via __hx_bits_f64 (bit-reinterpret the
19+
// loaded i64 payload → a FLOAT HexaVal whose .f reads those bits) — no hexa_float carrier
20+
// needed (the earlier design's hexa_float(double) is dropped; __hx_bits_f64 is exact).
21+
//
22+
// LAYOUT: HexaArrF64 { double* data @0(8B); int len @8(i32); int cap @12(i32) } sizeof 16,
23+
// 8-byte stride. __hx_ptr_load/store{32,64} raw-mem + __hx_payload_* leaf arithmetic (plain
24+
// int → boxed hexa_mul/add_slow; convergence array-core-hexa-1).
25+
//
26+
// SEED-ONLY SSOT: imported by NOTHING — enters runtime.a only via
27+
// tool/regen_array_typed_leaf_f64_native_s.sh / stage_resolve_runtime_a
28+
// resolve_native_array_f64_leaf_seed. nm contract = hexa_arr_f64_{new,push_bits,len,box}.
29+
30+
extern fn malloc(n: int) -> int
31+
extern fn realloc(p: int, n: int) -> int
32+
extern fn write(fd: int, buf: int, n: int) -> int
33+
extern fn exit(code: int)
34+
extern fn hexa_throw(v: HexaVal)
35+
36+
// hexa_arr_f64_new(cap): malloc a HexaArrF64 (16B) + a data buffer (cap*8, cap>=1),
37+
// zero len, set cap, box as TAG_ARRAY. Byte-identical to the i64 new (8B stride).
38+
pub fn hexa_arr_f64_new(cap: int) -> HexaVal {
39+
let mut c = cap
40+
if __hx_payload_lt(c, 1) { c = 1 }
41+
let a = malloc(16) // sizeof(HexaArrF64)
42+
let bytes = __hx_payload_mul(c, 8) // sizeof(double) * cap
43+
let d = malloc(bytes)
44+
__hx_ptr_store64(a, 0, d) // data <- d
45+
__hx_ptr_store32(a, 8, 0) // len <- 0 (i32)
46+
__hx_ptr_store32(a, 12, c) // cap <- c (i32)
47+
return __hx_make_val(5, a) // TAG_ARRAY=5, payload = HexaArrF64* a
48+
}
49+
50+
// hexa_arr_f64_push_bits(v, xbits): amortized-doubling append of the raw double bits
51+
// xbits (the C shim's union.i). Grow via extern realloc when len>=cap. The stored word
52+
// is the double's 8-byte bit pattern (store64), so data[len]=x bit-exact.
53+
pub fn hexa_arr_f64_push_bits(v: HexaVal, xbits: int) -> HexaVal {
54+
let a = __hx_payload_add(v, 0) // HexaArrF64* out of the TAG_ARRAY payload
55+
let len = __hx_ptr_load32(a, 8)
56+
let cap = __hx_ptr_load32(a, 12)
57+
if __hx_payload_ge(len, cap) {
58+
let ncap = __hx_payload_mul(cap, 2)
59+
let old = __hx_ptr_load64(a, 0)
60+
let nbytes = __hx_payload_mul(ncap, 8)
61+
let nd = realloc(old, nbytes)
62+
if __hx_payload_eq(nd, 0) {
63+
let msg = __hx_str_ptr("OOM in arr_f64_push\n") // char* bridge (parity msg)
64+
write(2, msg, 20)
65+
exit(1)
66+
}
67+
__hx_ptr_store64(a, 0, nd) // data <- realloc'd buffer
68+
__hx_ptr_store32(a, 12, ncap) // cap <- ncap
69+
}
70+
let data = __hx_ptr_load64(a, 0)
71+
let off = __hx_payload_mul(len, 8) // byte offset of data[len]
72+
__hx_ptr_store64(data, off, xbits) // data[len] <- the double's raw bits
73+
let nlen = __hx_payload_add(len, 1)
74+
__hx_ptr_store32(a, 8, nlen) // len <- len + 1
75+
return v
76+
}
77+
78+
// hexa_arr_f64_len(v): HexaArrF64.len @ +8 (i32). Byte-identical to i64 len.
79+
pub fn hexa_arr_f64_len(v: HexaVal) -> int {
80+
let a = __hx_payload_add(v, 0)
81+
return __hx_ptr_load32(a, 8)
82+
}
83+
84+
// hexa_arr_f64_box(v, i): bounds-checked read of data[i] re-boxed as TAG_FLOAT via
85+
// __hx_bits_f64 (reinterpret the loaded i64 payload as a double's bits → FLOAT HexaVal).
86+
pub fn hexa_arr_f64_box(v: HexaVal, i: int) -> HexaVal {
87+
let a = __hx_payload_add(v, 0)
88+
let len = __hx_ptr_load32(a, 8)
89+
if __hx_payload_lt(i, 0) { hexa_throw("index out of bounds") }
90+
if __hx_payload_ge(i, len) { hexa_throw("index out of bounds") }
91+
let data = __hx_ptr_load64(a, 0)
92+
let off = __hx_payload_mul(i, 8)
93+
let bits = __hx_ptr_load64(data, off)
94+
return __hx_bits_f64(bits) // raw bits → TAG_FLOAT HexaVal
95+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env bash
2+
# regen_array_typed_leaf_f64_native_s.sh — re-bake the frozen array typed-leaf i64
3+
# DISPATCHER native .s seeds from the SSOT stdlib/runtime/array_typed_leaf_f64.hexa
4+
# (axis-② Tier-1 #3 array typed-leaf i64).
5+
#
6+
# The 4 packed-i64 array dispatchers (hexa_arr_f64_new/push/len/box) that
7+
# runtime_core.c externs away under HEXA_RT_CORE_ARRAY_I64_LEAF_NATIVE. Each is the
8+
# EXACT C body (single-thread arm) re-authored native: __hx_ptr_load/store{32,64}
9+
# raw-mem field access + __hx_payload_* leaf arithmetic (NOT plain int ops — those
10+
# emit boxed hexa_mul/add_slow/cmp_ge; convergence array-core-hexa-1) + extern
11+
# realloc grow (the array_core.hexa:25 "realloc stays C" wall dissolved via the seed
12+
# CALLING libc realloc — the C body carries the same libc undefs, net floor unchanged).
13+
#
14+
# 1) aprime_cc _drv.hexa --emit=asm --target=<triple> -o <out>.s array_typed_leaf_f64.hexa
15+
# 2) frozen into self/native/array_typed_leaf_f64_{x86_64,arm64,arm64-linux}.s
16+
#
17+
# Requires a native compiler at $APRIME (default build/aprime_cc) + $CC (clang) to
18+
# cross-assemble the sanity check. POOL ONLY (aprime emit is a heavy build).
19+
#
20+
# tool/regen_array_typed_leaf_f64_native_s.sh [darwin|x86_64|arm64-linux|all]
21+
set -uo pipefail
22+
23+
HX="${HX_ROOT:-$(cd "$(dirname "$0")/.."; pwd)}"
24+
APRIME="${APRIME:-$HX/build/aprime_cc}"
25+
CC="${CC:-clang}"
26+
WHICH="${1:-all}"
27+
28+
[ -x "$APRIME" ] || { echo "[regen_arr_f64] ERROR: native compiler not at $APRIME (set APRIME=)" >&2; exit 1; }
29+
30+
SRC="$HX/stdlib/runtime/array_typed_leaf_f64.hexa"
31+
[ -f "$SRC" ] || { echo "[regen_arr_f64] ERROR: SSOT missing: $SRC" >&2; exit 1; }
32+
33+
TMP="$(mktemp -d -t regen_arr_f64.XXXXXX)"
34+
trap 'rm -rf "$TMP"' EXIT
35+
printf 'fn _drv_unused() {}\n' > "$TMP/_drv.hexa"
36+
37+
# the 4 native i64 typed-leaf dispatcher globals this seed must export.
38+
SYMS="hexa_arr_f64_new hexa_arr_f64_push_bits hexa_arr_f64_len hexa_arr_f64_box"
39+
NSYMS=4
40+
# the carrier/libc externs this seed is ALLOWED to leave undefined. UNLIKE map-query
41+
# (ZERO libc), this seed is libc-BEARING: malloc/realloc/write are the whole point
42+
# (the realloc-grow the wall said "stays C"). hexa_exit/int/throw are runtime.a carriers.
43+
ALLOWED_U="malloc realloc write hexa_exit hexa_throw"
44+
45+
emit_one() {
46+
local triple="$1" out="$2" abi="$3"
47+
local raw="$TMP/raw.s"
48+
"$APRIME" "$TMP/_drv.hexa" --emit=asm --target="$triple" -o "$raw" "$SRC" >/dev/null 2>&1
49+
local sym n
50+
for sym in $SYMS; do
51+
n="$(grep -cE "^[[:space:]]*\.globl[[:space:]]+_?${sym}\$" "$raw" || true)"
52+
[ "${n:-0}" -ge 1 ] || { echo "[regen_arr_f64] ERROR: $triple emitted only ${n:-0}/1 $sym" >&2; exit 1; }
53+
done
54+
# sealed contract: EXACTLY 4 .globl (extern decls emit no .globl).
55+
local gtot; gtot="$(grep -cE '^[[:space:]]*\.globl[[:space:]]' "$raw" || true)"
56+
[ "${gtot:-0}" -eq "$NSYMS" ] || { echo "[regen_arr_f64] ERROR: $triple emitted ${gtot:-0} .globl, want $NSYMS (sibling-global leak)" >&2; exit 1; }
57+
{
58+
printf '// %s — FROZEN BOOTSTRAP SEED (RT-NATIVE — array typed-leaf i64 DISPATCH).\n' "$(basename "$out")"
59+
printf '// GENERATED: tool/regen_array_typed_leaf_f64_native_s.sh — aprime_cc _drv.hexa --emit=asm\n'
60+
printf '// --target=%s -o %s stdlib/runtime/array_typed_leaf_f64.hexa.\n' "$triple" "$(basename "$out")"
61+
printf '// Provides the 4 packed-i64 array dispatcher natives (hexa_arr_f64_new/push/len/box).\n'
62+
printf '// ABI: %s. External U-floor: %s (libc-bearing: realloc grow dissolves the\n' "$abi" "$ALLOWED_U"
63+
printf '// array_core.hexa:25 wall via extern realloc CALL; the C body carries the same undefs).\n'
64+
printf '// Lets stage_resolve_runtime_a define HEXA_RT_CORE_ARRAY_I64_LEAF_NATIVE + ar this\n'
65+
printf '// .o into runtime.a so the 4 i64 dispatchers drop from the compiled runtime_core.c.\n'
66+
sed -E -e 's#"[^"]*array_typed_leaf_f64\.hexa"#"stdlib/runtime/array_typed_leaf_f64.hexa"#g' \
67+
-e 's#^// source: .*array_typed_leaf_f64\.hexa#// source: stdlib/runtime/array_typed_leaf_f64.hexa#' "$raw"
68+
} > "$out"
69+
# Sanity: cross-assemble + count defined-globals + assert the U-floor.
70+
local cc_extra="" s="$TMP/check.s" o="$TMP/check.o"
71+
grep -vE '^// ' "$out" > "$s"
72+
case "$triple" in
73+
x86_64-linux-gnu) [ "$(uname -s)" = Darwin ] && cc_extra="-target x86_64-linux-gnu" ;;
74+
arm64-linux-gnu) [ "$(uname -s)" = Darwin ] && cc_extra="-target aarch64-linux-gnu" ;;
75+
esac
76+
if $CC $cc_extra -c "$s" -o "$o" 2>/dev/null; then
77+
local tcount=0 t
78+
for sym in $SYMS; do
79+
t="$( (nm "$o" 2>/dev/null || echo) | grep -cE " T _?${sym}\$" || true)"
80+
tcount=$((tcount + ${t:-0}))
81+
done
82+
# U-floor: every undefined external must be in ALLOWED_U (carrier/libc only).
83+
local bad; bad="$(nm "$o" 2>/dev/null | awk '$1=="U"||$2=="U"{print $NF}' | while read -r u; do
84+
b="${u#_}"; printf '%s\n' " $ALLOWED_U " | grep -q " $b " || echo "$b"; done | tr '\n' ' ')"
85+
[ -z "${bad// /}" ] || { echo "[regen_arr_f64] ERROR: $triple carries non-carrier undefined externals ($bad) — U-floor breach" >&2; exit 1; }
86+
echo "[regen_arr_f64] $triple → $out ($tcount/$NSYMS T defined, U-floor clean)"
87+
else
88+
echo "[regen_arr_f64] WARN $triple: cross-assemble check skipped (no matching toolchain)" >&2
89+
echo "[regen_arr_f64] $triple → $out (globl emitted)"
90+
fi
91+
}
92+
93+
case "$WHICH" in
94+
darwin) emit_one arm64-apple-darwin "$HX/self/native/array_typed_leaf_f64_arm64.s" "Mach-O, _-prefixed" ;;
95+
x86_64) emit_one x86_64-linux-gnu "$HX/self/native/array_typed_leaf_f64_x86_64.s" "ELF, no underscore" ;;
96+
arm64-linux) emit_one arm64-linux-gnu "$HX/self/native/array_typed_leaf_f64_arm64-linux.s" "ELF aarch64, no underscore" ;;
97+
all)
98+
emit_one arm64-apple-darwin "$HX/self/native/array_typed_leaf_f64_arm64.s" "Mach-O, _-prefixed"
99+
emit_one x86_64-linux-gnu "$HX/self/native/array_typed_leaf_f64_x86_64.s" "ELF, no underscore"
100+
emit_one arm64-linux-gnu "$HX/self/native/array_typed_leaf_f64_arm64-linux.s" "ELF aarch64, no underscore"
101+
;;
102+
*) echo "[regen_arr_f64] usage: $0 [darwin|x86_64|arm64-linux|all]" >&2; exit 1 ;;
103+
esac
104+
echo "[regen_arr_f64] done."

0 commit comments

Comments
 (0)