8.9 KiB
8.9 KiB
Phase 11.8 技術仕様書:Core‑13 MIR命令セット(既定ON)
0. 変換スイッチとルーティング(Core‑13 既定ON)
推奨既定(nyash.toml の [env])
- NYASH_MIR_CORE13=1 … Core‑13 一括ON(Array/Ref→BoxCall 等を内包)
- NYASH_OPT_DIAG_FORBID_LEGACY=1 … 旧命令が最終MIRに残ったらエラー
Builder/MIR 生成
- Builder は ArrayGet/ArraySet/RefGet/RefSet/PluginInvoke を emit せず、最初から BoxCall/Call/ExternCall に正規化する。
- Optimizer は保険として既存の正規化パスを維持(二重化で確実性を上げる)。
1. ArrayGet/ArraySet → BoxCall 統合仕様
1.1 変換規則
// MIR Optimizer での変換
match instruction {
MirInstruction::ArrayGet { dst, array, index } => {
MirInstruction::BoxCall {
dst: Some(*dst),
box_val: *array,
method: "get".to_string(),
method_id: Some(UNIVERSAL_GET_ID), // 予約ID: 4
args: vec![*index],
effects: EffectMask::READS_MEMORY,
}
}
MirInstruction::ArraySet { array, index, value } => {
MirInstruction::BoxCall {
dst: None,
box_val: *array,
method: "set".to_string(),
method_id: Some(UNIVERSAL_SET_ID), // 予約ID: 5
args: vec![*index, *value],
effects: EffectMask::WRITES_MEMORY | EffectMask::MAY_GC,
}
}
}
1.2 VM最適化
// VM execute_boxcall での特殊化
fn execute_boxcall(...) {
// 高速パス:ArrayBoxの既知メソッド
if let Some(method_id) = method_id {
match (type_id, method_id) {
(ARRAY_BOX_TYPE, UNIVERSAL_GET_ID) => {
// 直接配列アクセス(BoxCall経由でも高速)
return fast_array_get(receiver, args[0]);
}
(ARRAY_BOX_TYPE, UNIVERSAL_SET_ID) => {
return fast_array_set(receiver, args[0], args[1]);
}
_ => {}
}
}
// 通常パス
plugin_invoke(...)
}
1.3 JIT最適化
// JIT Lowering での認識
fn lower_boxcall(builder: &mut IRBuilder, ...) {
if is_known_array_type(receiver_type) {
match method_id {
Some(UNIVERSAL_GET_ID) => {
// GEP + Load にインライン展開
emit_array_bounds_check(...);
emit_array_get_inline(...);
return;
}
Some(UNIVERSAL_SET_ID) => {
// Write barrier + GEP + Store
emit_write_barrier(...);
emit_array_set_inline(...);
return;
}
_ => {}
}
}
// 通常のBoxCall
emit_plugin_invoke(...);
}
2. Load/Store 削減仕様(SSA最優先)
2.1 SSA変数活用の最大化
// Before(Load/Store使用)
bb0:
Store %slot1, %x
Branch %cond, bb1, bb2
bb1:
Store %slot1, %y
Jump bb3
bb2:
// slot1 は x のまま
Jump bb3
bb3:
%result = Load %slot1
Return %result
// After(Phi使用)
bb0:
Branch %cond, bb1, bb2
bb1:
Jump bb3(%y)
bb2:
Jump bb3(%x)
bb3(%result):
Return %result
2.2 フィールドアクセスの統合
// Before(RefGet/RefSet)
%field_val = RefGet %obj, "field"
RefSet %obj, "field", %new_val
// After(BoxCall)
%field_val = BoxCall %obj, "getField", ["field"]
BoxCall %obj, "setField", ["field", %new_val]
2.3 残すべきLoad/Store
- スタックスロット: JIT/AOTでの一時変数
- C FFI境界: 外部関数とのやり取り
- 最適化中間状態: Phi導入前の一時的使用
3. Const統合仕様(設計)
3.1 統一表現
pub enum MirConst {
// Before: 5種類
Integer(i64),
Float(f64),
Bool(bool),
String(String),
Null,
// After: 1種類
Unified {
ty: ConstType,
bits: u64, // i64/f64/bool/null はビット表現
aux: Option<Arc<String>>, // 文字列用
}
}
pub enum ConstType {
I64, F64, Bool, Null, String, Handle
}
3.2 エンコーディング
impl MirConst {
fn encode_i64(val: i64) -> Self {
Self::Unified {
ty: ConstType::I64,
bits: val as u64,
aux: None,
}
}
fn encode_f64(val: f64) -> Self {
Self::Unified {
ty: ConstType::F64,
bits: val.to_bits(),
aux: None,
}
}
fn encode_bool(val: bool) -> Self {
Self::Unified {
ty: ConstType::Bool,
bits: val as u64,
aux: None,
}
}
}
4. パフォーマンス保証(CI基準)
4.1 ベンチマーク項目
必須ベンチマーク:
- array_access_sequential: 配列順次アクセス
- array_access_random: 配列ランダムアクセス
- field_access: フィールド読み書き
- local_variables: ローカル変数操作
- arithmetic_loop: 算術演算ループ
許容範囲:
- 速度: ベースライン ±5%
- メモリ: ベースライン ±10%
- MIRサイズ: -20%以上の削減
4.2 最適化保証
// 必須最適化パス
const REQUIRED_OPTIMIZATIONS: &[&str] = &[
"array_bounds_elim", // 配列境界チェック除去
"boxcall_devirt", // BoxCall脱仮想化
"const_fold", // 定数畳み込み
"dead_store_elim", // 不要Store除去
"phi_simplify", // Phi簡約
];
5. 移行戦略(段階→固定)
5.1 段階的有効化
// 環境変数による制御
// 実装上は env トグルを残しつつ、CI/既定は CORE13=1 / FORBID_LEGACY=1 とする。
5.2 互換性レイヤー
// Rewrite パス
pub fn rewrite_legacy_mir(module: &mut MirModule) {
for (_, func) in &mut module.functions {
for (_, block) in &mut func.blocks {
let mut new_instructions = vec![];
for inst in &block.instructions {
match inst {
// ArrayGet/ArraySet → BoxCall
MirInstruction::ArrayGet { .. } => {
new_instructions.push(convert_array_get(inst));
}
MirInstruction::ArraySet { .. } => {
new_instructions.push(convert_array_set(inst));
}
// RefGet/RefSet → BoxCall
MirInstruction::RefGet { .. } => {
new_instructions.push(convert_ref_get(inst));
}
MirInstruction::RefSet { .. } => {
new_instructions.push(convert_ref_set(inst));
}
// そのまま
_ => new_instructions.push(inst.clone()),
}
}
block.instructions = new_instructions;
}
}
}
6. 検証項目
6.1 正当性検証
#[cfg(test)]
mod core13_tests {
// 各変換の意味保存を検証
#[test]
fn test_array_get_conversion() {
let before = MirInstruction::ArrayGet { ... };
let after = convert_to_boxcall(before);
assert_semantic_equivalence(before, after);
}
// SSA形式の保持を検証
#[test]
fn test_ssa_preservation() {
let module = build_test_module();
eliminate_load_store(&mut module);
assert_is_valid_ssa(&module);
}
}
6.2 性能検証
// ベンチマークハーネス
pub fn benchmark_core13_migration() {
let scenarios = vec![
"array_intensive",
"field_intensive",
"arithmetic_heavy",
"mixed_workload",
];
for scenario in scenarios {
let baseline = run_with_core15(scenario);
let core13 = run_with_core13(scenario);
assert!(
(core13.time - baseline.time).abs() / baseline.time < 0.05,
"Performance regression in {}", scenario
);
}
}
7. エラーハンドリング
7.1 診断メッセージ
pub enum Core13Error {
UnsupportedInstruction(String),
ConversionFailed { from: String, to: String },
PerformanceRegression { metric: String, delta: f64 },
}
impl Core13Error {
fn diagnostic(&self) -> Diagnostic {
match self {
Self::UnsupportedInstruction(inst) => {
Diagnostic::error()
.with_message(format!("Instruction '{}' not supported in Core-13", inst))
.with_note("Consider using BoxCall for this operation")
.with_help("Set NYASH_MIR_LEGACY=1 for compatibility mode")
}
// ...
}
}
}
この仕様に従い、MIRを「最小の接着剤」として純化し、Boxに「無限の可能性」を委ねる