CrownyJIT 6차 — asm 조립 레지스터 캐싱 + 인라인 norm + FP상대 지역루프 asm
개요
2026-07-06 6차 세션. 4차/5차가 남긴 이월 1과제(asm 레지스터 캐싱)와 2과제(FP상대 asm)를 배선.
4차 asm 조립경로는 정확하나
steady-state가 스텐실보다 20배 느렸다 — 회당 ~9개 콜백 blr
(LOAD마다 rd·STORE마다 wr·산술마다 norm·DIV마다 baldiv)이 병목. 6차는 루프변수를 레지스터/스크래치에
캐싱하고 norm을 완전 인라인화해 회당 콜백을 9→1(baldiv만)로 줄였고, 그 과정에서 FP상대 지역루프
asm 지원까지 통합 달성. 공유
crownyc.c/
crownyc 무접촉(20:01). 모든 채택은 런타임 차등검증
(byte-identical) 통과분만.
시작 시 그라운딩 (warm, self-test 캐시됨) — 4차 0.85s의 실체
| canon 3M | 실측 | 비고 |
|---|
| 스텐실 | 0.02s | 완전 네이티브 인라인(콜백 0) |
| asm(4차/5차) | 0.45s | 정확하나 회당 ~9 blr → 스텐실의 20배 |
| cc | 0.58s | cc 컴파일 대기 포함 |
- 4차 문서의 "asm 0.85s"는 self-test cc스폰 미캐시 콜드값. 캐시 warm 재실측 = 0.45s. 어느 쪽이든
병목은 동일: 회당 콜백 blr(rd/wr/norm/baldiv).
증분별 상태
| # | 목표 | 상태 | 요지 |
|---|
| 1 | asm 레지스터 캐싱 | 완주 | 접촉 스칼라변수를 프롤로그 rd()1회→hole.cached[k], 본체 ldr/str(blr無), 에필로그 wr()1회 |
| 2 | asm FP상대 지역루프 | 완주 | 주소=fpbase(=frame_ptr, 디스패치시 hole 전달)+off. 캐싱과 통합(본체 주소무관)이라 cacheload_fp/flush_fp만 추가 |
| + | 인라인 norm(계획외 필수) | 완주 | 산술 norm을 범위검사+모듈러감축(sdiv/msub/csel)까지 완전 인라인 → blr x27 소멸. canon ii는 대부분 범위초과라 이게 최대 병목이었음 |
| 3 | asm 배열 원소/설정 | 미착수(구조적 저ROI) | 배열 index는 회당 가변 → 캐싱 불가(6차 핵심 이점 무효). 배열루프는 cc경로가 이미 6.4~8.4×. 아래 판단 근거 참조 |
무엇을 배선했나
스니펫 라이브러리 (crownyc_jit_snippets.s)
- NORMINLINE 매크로:
ldr lim; cmp; b.gt/b.lt 범위검사 → 범위내 무동작. 초과 시 sdiv/msub로
v%M,
csel로 부호/범위 보정 —
완전 인라인, blr 없음. cj_norm/CJN_S와 bit-identical(모듈러식).
- cacheload_abs/fp: 프롤로그단계, 접촉주소마다 rd() 1회 → cached[k]. abs=movz/movk immediate addr,
fp=
ldr fpbase; add off.
cacheflush_abs/fp: 에필로그단계 wr() 1회.
- load_var/store_var: 본체 LOAD/STORE. 직전 DATA/loadfp/ADD가 push한 주소를 폐기(
sub x21) +
cached[k] ldr/str.
콜백 blr 없음. cached 오프셋은 str/ldr imm12(uoff) 패치.
- loadfp: LOAD_FP(80) — fpbase를 operand-stack에 push(주소형성용, 이후 load_var가 폐기).
- add/sub/mul/div/mod에 NORMINLINE 적용(div/mod의 baldiv만 blr x28 유지).
- 새 hole struct:
fpbase@32 lim@40 modM@64 cached[64]@72 ostk[128]@584 (x20=x19+584).
조립기 (crownyc_jit_hot.c cjasm_build — 2패스 재작성)
- pass1: expr-kind 시뮬(0=value 1=literal 2=fpbase 3=fpaddr)로 검증 + 접촉주소 (kind,off) 수집.
LOAD_FP;DATA off;ADD → FPADDR(off) 폴딩(cc경로와 동일). 미지원/계산된주소/주소산술 = BAIL(cc폴백).
- prologue → cacheload×N → body_start → pass2(본체 방출) → epi:cacheflush×N → epilogue.
guard 탈출/maxiter는 epi(cacheflush)로 분기 → 반드시 cacheflush 후 return.
- 캐싱 통합 덕에 본체는 cached[k]만 접근(주소 무관) → FP지원이 cacheload/flush 주소계산에만 국한.
- 슬롯메타 cj_taddr/cj_tkind(ABS/FP 혼합)로 차등게이트가 ABS·FP 양쪽 정확 검증.
- 새 패치헬퍼:
cj_patch_uoff(LDR/STR imm12=byte_off/8), cj_patch_add_imm(ADD imm12).
- cj_dispatch: h.fpbase=frame_ptr, h.lim=141214768240, h.modM=282429536481 세팅.
회당 콜백 blr 감축 (canon 캐노니컬 loop 기준)
| 연산 | 4차 asm | 6차 asm |
|---|
| LOAD i×4 (guard/mul/incr용) | 4 blr(rd) | 0 (cached ldr) |
| STORE s,i ×2 | 2 blr(wr) | 0 (cached str) |
| norm ×4 (mul/div/add/add) | 4 blr | 0 (인라인) |
| baldiv ×1 (DIV /7) | 1 blr | 1 blr(유지) |
| 회당 계 | ~11 blr | 1 blr |
- 잔여 격차(asm 0.05 vs 스텐실 0.02) = baldiv blr 1회 + operand-stack 메모리 트래픽(스텐실은 전부 레지스터).
벤치 (best-of-3, warm, 단일 wall-clock, 전부 BYTE-IDENTICAL)
| 커널 | base(no-JIT) | asm(6차) | stencil | cc | 승자 |
|---|
canon s+=(i*i)/7 3M | 10.31s | 0.05s | 0.02s | 0.58s | stencil(캐노니컬)·asm 2위 |
| finance 복리 3M(4 DIV) | 2.48s | 0.10s | 0.80s | 0.84s | asm(스텐실 미매칭→cc) |
| FP지역 10M(지역var loop) | 8.30s | 0.20s | 0.39s | 0.39s | asm(FP=6차 신규, 스텐실 미매칭) |
- \ 스텐실은 캐노니컬 1종만 매칭 → finance(다DIV)·FP는 BAIL→cc 폴백값.
6차 asm은 셋 모두 최고 또는 근접,
그리고 FP·다DIV 임의루프를 레지스터캐싱 속도로 가속하는
유일한 경로.
- canon asm: 0.45s→0.05s(9×), 목표(스텐실급 0.43s 이하) 초과 달성. asm_setup≈9µs.
- FP 10M asm(신규 능력): base 8.30s→0.20s(41×), cc 0.39s 대비 2×.
회귀 (base==cc==asm==shared 전부 IDENTICAL, md5)
| 커널 | 결과 |
|---|
| canon·arb·finance·fp지역 | ✅ IDENTICAL(4모드) |
| 배열합·배열쓰기·3D렌더러 | ✅ IDENTICAL(4모드) |
| 작업구분·브레인결재(stdin 판정코어) | ✅ IDENTICAL(4모드) |
| jithot 동반본(2488B stdout) | ✅ IDENTICAL(base/cc/asm/shared, diff clean) |
-
9커널+동반본 전부 IDENTICAL. 진짜 off =
env -u CROWNY_JIT.
- 공유
crownyc(20:01:53)·crownyc.c(20:01) mtime 무손상. JIT-off crownyc-jit==공유 crownyc.
- arb: opcode 94(TSHL/TSHR 트릿시프트,
i/3 피홀)로 asm BAIL→인터프리터(출력정확). 4차 남은과제 #3(미해소),
구 빌더도 동일 BAIL이라 회귀 아님.
- 배열 커널(asm 모드): asm 조립기가 배열 opcode(407/415)에서 BAIL→cc폴백. 배열합 8.7×·배열쓰기 4.5×·
3D 1.6× 유지(회귀 없음). asm은 순수 스칼라 전용.
왜 증분3(배열 asm)을 미착수했나 (판단 근거)
- 6차의 핵심 이점 = 루프변수를 경계로 호이스팅. 그러나 배열 원소
rd(base+i)의 index i는
회당 가변 → 프롤로그로 호이스팅 불가. 배열루프 asm은 결국 cc경로처럼 회당 rd/wr 콜백이 필요 →
캐싱 이득이 구조적으로 소멸(base만 캐싱 가능하나 index/값 콜백은 잔존).
- cc경로가 이미 배열 읽기 8.4×·쓰기 6.4×. asm 배열은 cc를 복제할 뿐 6차 캐싱 이점을 못 살림 → 저ROID.
- "여유 시" 항목이라 스칼라 캐싱(주 목표)에 집중. 배열 asm은 후순위 유지.
관련 파일 (전부 /Users/ef/CrownyOS/crownyc/)
crownyc_jit_snippets.s — ★NORMINLINE 매크로, cacheload/flush_abs/fp, load_var/store_var, loadfp
스니펫 추가. prologue x20=+584. add/sub/mul/div/mod에 인라인 norm. 새 hole 오프셋.
crownyc_jit_hot.c — ★cjasm_build 2패스 재작성(레지스터캐싱+FP+ABS 혼합), cjasm_hole 확장
(fpbase/lim/modM/cached[64]), cj_patch_uoff·cj_patch_add_imm, cjasm_find_slot, cj_dispatch fpbase/lim/modM.
crownyc_jit_hot.한선 — 판정 로직 동반본. 6차 증분L~N(레지스터캐싱·인라인norm·FP asm) 추가. 4모드 일치.
crownyc-jit — 산출 바이너리. 빌드:
cc -O2 -o crownyc-jit crownyc_jitmain.c crownyc_jit_snippets.s -framework Security -framework CoreFoundation
crownyc.c/crownyc — 공유, 무접촉(20:01).
- 벤치/회귀:
/tmp/JIT실적용/{canon,arb,finance,fp지역,배열합,배열쓰기,3D렌더러,작업구분,브레인결재}.toau.
fp지역.한선=6차 신규 FP 테스트(함수 지역var loop).
env 플래그 (불변)
CROWNY_JIT=1(켬), CROWNY_JIT_HOT=N(백엣지 임계), CROWNY_JIT_ASM=1(asm 조립 우선),
CROWNY_JIT_STENCIL=1,
CROWNY_JIT_GATE=1,
CROWNY_JIT_DUMP=1,
CROWNY_JIT_NOCACHE=1,
CROWNY_JIT_TIME=1.
남은 작업 (다음 세션 인수인계)
- asm baldiv 인라인: 마지막 1 blr/iter(DIV/MOD의 baldiv). sdiv+msub+abs+csel로 인라인하면
canon이 스텐실(0.02s)에 근접 가능. 정의 명확(잘 정의된 스니펫), 게이트가 검증. 저위험.
- operand-stack 레지스터화: 스텐실과의 잔여격차는 ostk 메모리 트래픽. 슬롯을 레지스터할당하려면
copy-and-patch 스니펫 연접 모델을 넘어 레지스터할당 컴파일러 필요 → 큰 작업. cc경로가 이미 그 역할.
- TSHR/TSHL(op94/95) 스니펫:
÷×3ⁿ 피홀. arb(i/3) 등 asm 조립 가능케. 4차부터 이월.
- asm 배열(증분3): 위 판단대로 저ROI. base 캐싱만 부분이득 — 필요시 index 가변 콜백 유지 설계.
- 다탈출 가드·비순수 잎(2차 이월). W^X 서명배포 시 MAP_JIT/entitlement.
안전수칙 준수
- 공유
crownyc.c/crownyc 무수정·무재빌드(20:01). 산출물 crownyc-jit 별도.
- 기본 오프(opt-in). 부팅 self-test + 런타임 차등검증 게이트 이중 안전. 신규영역(레지스터캐싱·인라인norm·
FP조립) 전부 동일 게이트 통과분만 채택 — 캐싱/패치/FP 버그는 출력 무오염(MISMATCH=BAIL=인터프리터).
CrownyJIT 7차 (2026-07-06) — asm baldiv 인라인 (마지막 1 blr/iter 제거)
개요
6차가 회당 콜백을 9→1(baldiv만)로 줄인 뒤 남은 이월 1과제. DIV/MOD의 마지막
blr x28(=cj_baldiv
콜백)을
sdiv+msub+cneg(abs)+eor(부호)+cneg(±1 보정)로 완전 인라인해 회당 콜백을 1→0으로 만들었다.
공유
crownyc.c/
crownyc 무접촉(20:01). 모든 채택은 런타임 차등검증(byte-identical) 통과분만.
무엇을 배선했나 (crownyc_jit_snippets.s만 수정, C·조립기 무변경)
- BALDIV 매크로 신설:
cj_baldiv/crownyc.c cube_divmod와 bit-identical.
cbz b→q=0 ·
sdiv q=a/b ·
msub r=a-q*b ·
cneg |r|,|b| ·
2|r|>|b|이면
eor a,b로
부호동일(≥0) 판정 후
cneg ±1 보정. clobber x2..x6(+x0), a·b 불변. blr 없음.
- _cjs_div:
blr x28 → BALDIV x0,x1 치환. 뒤이어 기존 NORMINLINE 유지.
- _cjs_mod: a=x7·b=x8로 로드(BALDIV·msub 불변 보존) →
BALDIV → msub r=a-q*b → NORMINLINE.
6차의 scr0/scr1(hole@48/56) 스크래치 왕복 제거(콜백 없어져 불필요).
- C측(
crownyc_jit_hot.c cjasm_build)은 무변경 — EMIT(div)/EMIT(mod)이 스팬 memcpy만 하고
div/mod엔 immediate 패치가 없어서 .s 재작성만으로 반영. prologue의 x28(bdiv) 로드는 잔존(무해).
회당 콜백 blr (canon 캐노니컬 loop)
| 연산 | 4차 | 6차 | 7차 |
|---|
| LOAD/STORE/norm | 다수 blr | 0 | 0 |
| baldiv (DIV/MOD) | 1 blr | 1 blr | 0 (인라인) |
| 회당 계 | ~11 | 1 | 0 |
A/B 실측 (같은 머신·빌드, best-of-N, asm+gate, BYTE-IDENTICAL)
6차 등가본(blr baldiv)을 별도 빌드해 7차(인라인)와 head-to-head:
| 커널 | 6차 blr | 7차 인라인 | delta |
|---|
| canon 30M (30M DIV) | 0.495s | 0.486s | 0.009s (0.30 ns/DIV) |
| finance 3M (12M DIV) | 0.103s | 0.092s | 0.011s (~0.9 ns/DIV) |
| canon 3M (3M DIV) | 0.058s | 0.057s | 0.001s(startup 노이즈 내) |
- 정직 소견: baldiv blr 제거는
회당 ~0.3~0.9ns 실이득(작지만 일관·양(+)). canon 3M 벽시계가
~0.05s에 머무는 건
operand-stack 메모리 트래픽(잔여 지배항, 레지스터할당 필요=별건 대공사)과
프로세스 startup(바이너리 로드+self-test)이 지배하기 때문 — baldiv는 이미 회당 최소항이었음.
"canon→스텐실 0.02s"는 이 증분 단독으론 미달(예상대로, 잔여=ostk 메모리·2번 이월과제).
전체 벤치 (best-of-5, wall-clock, warm, 4모드 BYTE-IDENTICAL)
| 커널 | base(no-JIT) | asm(7차) | on(default JIT) |
|---|
| canon 3M | 3.52s | 0.054s | 0.54s |
| finance 3M(4 DIV) | 2.41s | 0.088s | 0.80s |
| FP지역 10M | 8.31s | 0.203s | 0.40s |
회귀 (base==on==asm==shared md5 IDENTICAL)
| 커널 | 결과 |
|---|
| canon·arb·finance·fp지역 | ✅ IDENTICAL(4모드) |
| 배열합·배열쓰기·3D렌더러 | ✅ IDENTICAL(4모드) |
| 작업구분·브레인결재(stdin 판정코어) | ✅ IDENTICAL(base/asm/shared) |
| jithot 동반본(7차 섹션 추가·재컴파일) | ✅ IDENTICAL(base/asm/shared) |
-
인라인 DIV/MOD 스니펫 직접 검증(신규, asm ADOPT verified bit-identical):
canon(양수 DIV) ADOPT ✅ · div_neg(음수 피제수 DIV) divneg=-329671 4모드 일치 ADOPT ✅
mod2(양수 MOD) mod2=3 ADOPT ✅ · mod3(음수 피제수 MOD) mod3=-3 균형나머지 ADOPT ✅
→ 부호보정·|r|≤|b|/2 균형 시맨틱을 인라인이 정확 복제(게이트가 채택=byte-identical 확인).관련 파일 (전부 /Users/ef/CrownyOS/crownyc/)
crownyc_jit_snippets.s — ★BALDIV 매크로 신설, _cjs_div/_cjs_mod 인라인 재작성(blr x28 제거).
crownyc_jit_hot.한선 — 동반본에 7차 증분O(발디브인라인판정) 1함수+3출력 추가. 4모드 일치.
crownyc_jit_hot.c — 무변경(cjasm_build·hole struct 그대로, div/mod은 스팬 copy만).
crownyc-jit — 재빌드: cc -O2 -o crownyc-jit crownyc_jitmain.c crownyc_jit_snippets.s -framework Security -framework CoreFoundation
crownyc.c/crownyc — 공유, 무접촉(20:01).
남은 작업 (다음 세션)
- operand-stack 레지스터화 — 스텐실과의 잔여격차 지배항. copy-and-patch 연접 모델 넘어 레지스터할당
컴파일러 필요(대공사). cc경로가 이미 그 역할.
- TSHR/TSHL(op94/95) 스니펫 — arb(
i/3) asm 조립 가능케(4차부터 이월).
- asm 배열(증분3) — 저ROI(index 회당 가변→캐싱 불가). base만 부분이득.
- 다탈출 가드·비순수 잎(2차 이월). W^X 서명배포 시 MAP_JIT/entitlement.
안전수칙 준수
- 공유
crownyc.c/crownyc 무수정·무재빌드(20:01). 산출물 crownyc-jit 별도. 데몬·커밋 없음.
- 기본 오프(opt-in). 부팅 self-test + 런타임 차등검증 게이트 이중 안전. 인라인 baldiv 버그는
출력 무오염(MISMATCH=BAIL=인터프리터). 차등검증이 최종 심판.