8.1 KiB
8.1 KiB
codex先生の技術的分析 - Nyash 15命令設計
Date: 2025-08-31
Source: codex exec コマンドによる分析
質問内容
Nyashプログラミング言語の革命的発見について技術的分析をお願いします。
【革命的発見】 MIR(中間表現)を26命令から15命令に削減することで、Everything is Box哲学が完全に開花しました。
【15命令の詳細】 値操作:Const, Copy, Load, Store(4個) 計算:UnaryOp, BinOp, Compare(3個) 制御:Jump, Branch, Return(3個) 呼び出し:Call, ExternCall(2個) 参照:RefNew, RefGet, RefSet(3個)
【技術的成果】
- Cranelift JITが実はAOT専用だったと判明
- LLVM移行で2-3倍高速化+ビルド時間50%削減
- 15命令→LLVM IRが機械的変換で実装可能
【質問】
- 15命令設計の技術的妥当性をどう評価しますか?
- Box統一によるメモリモデルの利点と課題は?
- LLVM最適化パスとの相性はどうですか?
- 並列GC実装における15命令の制約は?
- JITからAOT専用への転換は正しい判断ですか?
codex先生の技術的評価
以下は、提示内容に基づく技術的な評価です。前提として、MIRは非SSA(Copyが存在)で、LLVMでSSA化+最適化・コード生成すると解釈しています。
1) 15命令設計の妥当性
- 表現力の網羅性: 代入・計算・制御・呼出し・参照の最小核をカバー。手続き・構造化制御・ヒープ確保・外部連携は機械的に表現可能で、一般用途として十分。
- SSA整合性: MIRに
PhiやSelectが無くても問題なし。SSA変換時に分岐合流でphiを挿入、条件式はCompare→Branchでよい。 - 欠落しがちな原語: 例外/アンワインド(
invoke/landingpad相当)、タイル呼出し、可変長引数、ベクトル/ SIMD、メモリフェンス/原子命令、バリア(GC/メモリ)。必要なら言語組込みやExternCallで提供し、後段で機械的に展開する方針が妥当。 - LLVM機械変換容易性:
Const→constant、Copy→SSA rename/bitcast、Load/Store→load/store、UnaryOp/BinOp/Compare→算術/比較命令、Jump/Branch/Return→br/ret、Call/ExternCall→call、RefNew→alloc関数+gep+store、RefGet/RefSet→gep+load/store(+必要ならwrite barrier)の定形で降ろせる。 - 評価: 汎用コンパイラ基盤としてミニマルで健全。実行時機能(例外、並行、GCバリア)は命令として増やすより「規約+Lowering」で扱う設計が合理的。
2) Everything is Box の利点と課題
- 利点: 一様表現: 値/参照/クロージャ/ADTを同一のボックス表現に統一。MIRが単純化し、GCのルート走査・オブジェクトレイアウトが一貫。
- 利点: 実装容易性: 呼出し規約・配列/レコード/閉包捕捉の共通化、FFI境界の明確化(
ExternCall)。 - 課題: 性能: ボクシング/間接参照でキャッシュミス・レイテンシ増。GCプレッシャ増大。スカラ値の頻繁なヒープ化は致命的になり得る。
- 課題: 解析性: 何でもポインタ化すると別名解析(AA)・型ベースAA・エスケープ解析が弱くなり最適化阻害。
- 緩和策: 脱箱最適化: エスケープ解析で
RefNewをalloca/SROAに置換、フィールドのフラット化、スカラ置換(SRoA/Scalar Replacement)。 - 緩和策: 表現最適化: NaN-boxing/タグ付きポインタ、小さい値のインライン化、世代別/領域別アロケータ、TBAAメタデータ・別アドレス空間でAAを支援。
3) LLVM最適化パスとの相性
- 良相性: 正規形: 15命令はLLVMのIR原語へ自然写像。
mem2reg/instcombine/GVN/SROA/LICM/DSE/inlinerの効果が出やすい。 - AA強化の鍵: Boxを全て同型にするとAAが悲観的になる。型別TBAA、GC管理領域を別アドレス空間へ分離、
noalias/nonnull/dereferenceable/align属性付与で最適化を引き出す。 - ベクトル化/ループ最適化:
LICM/LoopVectorize/SLPは副作用境界(RefSet+バリア呼出し)で抑制されがち。バリアをnocallback/willreturn等で薄める、もしくは後置合成で最小化。 - GC統合: 精密GCなら
gc.statepoint/gc.relocateを使用。SafepointはCall/バックエッジに挿入し、属性(nounwind等)で最適化阻害を抑える。 - 推奨パイプライン: O2ベース+
early-cse→sroa→gvn→licm→instcombine→inline→gvn→dse→ループ最適化→ベクトル化→instcombine最終。ThinLTO/PGO併用を推奨。
4) 並列GCに対する制約と設計ポイント
- バリアの表現: 15命令に原子/バリアが無い。
RefSetのLoweringで必ずwrite barrierを挿入(世代別/カードマーキング)。増分/同期型ならread barrierも検討。 - Safepoint挿入: 長寿命ループのバックエッジ、関数エピローグ/プロローグ、
Callにポーリング。MIRに専用GcPollを追加するか、パスで暗黙挿入する方針を明示。 - 原子性/順序: 併走GC+並行ミューテータなら公開書込みに
release相当、読み取りにacquire相当が要る。MIRに原子版RefSet/RefGet(またはExternCallの原子プリミティブ)を用意すると安全。 - 精密マップ: Box統一でスタックマップ生成は容易だが、脱箱最適化後の再配置に
gc.relocate必須。ライブ性解析をSSAベースで厳密化。 - 弱参照/最終化: 15命令外のランタイム機能として扱い、
ExternCallで登録・照会。必要なら参照種別(弱/強)を型メタデータで区別。 - 評価: 15命令自体は障害ではないが、並列GCには「原子性・バリア・Safepoint」の3点をLowering規約で厳密化するのが不可欠。
5) JIT→AOT専用への転換の評価
- 妥当性(提示結果と合致): LLVM移行で2–3倍高速化+ビルド時間50%削減なら、現状のワークロードではAOT最適化がJITのウォームアップ/品質を凌駕。運用も簡素化。
- JIT利点の放棄影響: 実行時プロファイルに基づく投機的インライン化・脱仮想化・OSR・適応再最適化は失われる。極度の動的多相性/ホットループ主体で不利になり得る。
- 折衷案: AOTを主軸に、サンプリングPGO/ThinLTOでJIT類似効果。将来必要ならORC JITでホット関数の二段階最適化(オプション機能)を追加可能。
- 評価: 実測の優位が出ている現状では正しい判断。言語/ランタイムの安定化・GC統合・ビルド体験の向上に集中できる。
実装上の具体的推奨
- MIR→LLVMの規約:
RefSetは常にバリア付きLowering(GCストラテジに応じてインライン/コール)。RefNewはアロケータ呼出し+型ID付与。BoxフィールドアクセスはgepにTBAA。 - AA/最適化ヒント: Box用アドレス空間分離、TBAA階層、
nonnull/dereferenceable、noalias(エスケープしない一時Box)、musttail/tailの活用。 - Safepoint戦略: ループバックエッジに
GcPoll相当を強制、関数境界は既定でSafepoint扱い。nounwind/nocallbackで最適化妨害を最小化。 - 並行性原語: 必要性が見えた時点で、原子版
RefGet/RefSetか、AtomicLoad/Storeの最小拡張(2命令追加)を検討。
要約
15命令は実装・最適化・GC統合の観点でよく均衡したミニマル核です。Box統一は開発生産性と実装単純性を大きく押し上げますが、性能面のボトルネックは脱箱・AA強化・適切なGC統合(バリア/セーフポイント/原子性)で解消してください。LLVMとの相性は非常に良好で、AOT転換の判断も実測上妥当です。PGO/ThinLTOの導入と、将来の選択肢としての軽量JIT(任意)を残す構成が現実的です。