Phase47-B/C: extend P3 normalized shapes and quiet dev warnings
This commit is contained in:
@ -87,13 +87,11 @@
|
|||||||
- JsonParser P2 ライン(_skip_whitespace/_atoi/_parse_number)全て canonical Normalized 化完了。
|
- JsonParser P2 ライン(_skip_whitespace/_atoi/_parse_number)全て canonical Normalized 化完了。
|
||||||
- P3/P4 Normalized 対応は NORM-P3/NORM-P4 フェーズで実施(今回スコープ外)。
|
- P3/P4 Normalized 対応は NORM-P3/NORM-P4 フェーズで実施(今回スコープ外)。
|
||||||
- 937/937 tests PASS。
|
- 937/937 tests PASS。
|
||||||
- **Phase 47-A-IMPL(実装中 2025-12-12)**:
|
- **Phase 47-B/C(P3 if-sum 拡張 + canonical 化 ✅ 2025-12-21)**:
|
||||||
- StepScheduleBox 汎用化: pattern2_step_schedule.rs → step_schedule.rs リネーム
|
- フィクスチャ追加: `pattern3_if_sum_multi_min`(sum+count)/ `jsonparser_if_sum_min`(JsonParser 簡約形)
|
||||||
- P3 StepKind 追加: IfCond, ThenUpdates, ElseUpdates(P2 lowering との分離完了)
|
- ShapeGuard: `Pattern3IfSumMulti` / `Pattern3IfSumJson` 追加、capability=P3IfSum、canonical set に P3 minimal/multi/json を追加
|
||||||
- ShapeGuard: Pattern3IfSumMinimal 検出追加(placeholder stub実装)
|
- Normalizer/Bridge: P3 if-sum minimal/multi/json を Structured→Normalized→MIR(direct) で dev A/B、canonical ルートでも常時 Normalized 経由
|
||||||
- Normalized bridge: P3 shape handling 追加(P2 normalization 使用)
|
- テスト: normalized_joinir_min.rs に P3 if-sum multi/json の VM ブリッジ比較テスト追加(Structured と一致)
|
||||||
- 938/938 tests PASS(regression なし)
|
|
||||||
- 次ステップ: Phase 47-A-LOWERING で full P3 Normalized lowering 実装
|
|
||||||
- **Phase 45-NORM-MODE(実装済み✅ 2025-12-12)**:
|
- **Phase 45-NORM-MODE(実装済み✅ 2025-12-12)**:
|
||||||
- JoinIR モード一本化: バラバラだったフラグ/feature を `JoinIrMode` enum に集約(StructuredOnly / NormalizedDev / NormalizedCanonical)。
|
- JoinIR モード一本化: バラバラだったフラグ/feature を `JoinIrMode` enum に集約(StructuredOnly / NormalizedDev / NormalizedCanonical)。
|
||||||
- `current_joinir_mode()` でモード取得、bridge/runner で `normalized_dev_enabled()` → mode pattern matching に移行。
|
- `current_joinir_mode()` でモード取得、bridge/runner で `normalized_dev_enabled()` → mode pattern matching に移行。
|
||||||
|
|||||||
@ -1404,32 +1404,43 @@ Pattern3 (if-sum) ループを Normalized JoinIR に対応させる。P2 と同
|
|||||||
- ✅ shape_guard に `Pattern3IfSumMinimal` を追加し、構造ベースで P3 最小 if-sum 形状を検出
|
- ✅ shape_guard に `Pattern3IfSumMinimal` を追加し、構造ベースで P3 最小 if-sum 形状を検出
|
||||||
- ✅ `normalize_pattern3_if_sum_minimal` を通じて P3 最小ケースを Normalized→MIR(direct) パイプラインに載せ、P1/P2 と同じ direct ブリッジで実行結果一致を確認(dev-only)
|
- ✅ `normalize_pattern3_if_sum_minimal` を通じて P3 最小ケースを Normalized→MIR(direct) パイプラインに載せ、P1/P2 と同じ direct ブリッジで実行結果一致を確認(dev-only)
|
||||||
|
|
||||||
**Phase 47-B**: array_filter (dev-only, body-local + method calls)
|
**Phase 47-B**: Extended dev(sum+count / JsonParser if-sum mini)
|
||||||
|
- ✅ フィクスチャ追加: `pattern3_if_sum_multi_min`(sum+count)/ `jsonparser_if_sum_min`(JsonParser 由来)
|
||||||
|
- ✅ ShapeGuard: `Pattern3IfSumMulti` / `Pattern3IfSumJson` 追加、capability=P3IfSum
|
||||||
|
- ✅ Normalizer/Bridge: P3 if-sum multi/json を Structured→Normalized→MIR(direct) で dev A/B(Structured と一致)
|
||||||
|
- ✅ VM Bridge テスト: `normalized_pattern3_if_sum_multi_vm_bridge_direct_matches_structured` / `normalized_pattern3_json_if_sum_min_vm_bridge_direct_matches_structured`
|
||||||
|
|
||||||
**Phase 47-C**: Canonical promotion (P3 minimal → canonical)
|
**Phase 47-C**: Canonical promotion(P3 minimal/multi/json → canonical Normalized)
|
||||||
|
- Canonical set 拡張: P3 if-sum minimal/multi/json を `is_canonical_shape()` に追加、mode/env 無視で Normalized→MIR(direct) ルートを使用
|
||||||
|
- Bridge/runner: canonical shapes は Structured fallback せず fail-fast(dev logs は normalized-dev プレフィックスに統一)
|
||||||
|
|
||||||
**スコープ外**: P4 (continue) 対応(NORM-P4 フェーズで実施)、Complex P3 patterns(後続フェーズ)
|
**スコープ外**: P4 (continue) 対応(NORM-P4 フェーズで実施)、Complex P3 patterns(後続フェーズ)
|
||||||
|
|
||||||
### 3.25 Phase 48-NORM-P4 – Normalized P4 (Continue) Design 📋 DESIGN PHASE (2025-12-12)
|
### 3.25 Phase 48-NORM-P4 – Normalized P4 (Continue) 🏗️ DESIGN + PHASE 48-A MINIMAL DEV COMPLETE (2025-12-12)
|
||||||
|
|
||||||
**設計詳細**: [phase48-norm-p4-design.md](./phase48-norm-p4-design.md)
|
**設計詳細 / 実装サマリ**: [phase48-norm-p4-design.md](./phase48-norm-p4-design.md)
|
||||||
|
|
||||||
P4 (continue) will use the **same `loop_step(env, k_exit)` skeleton** as P1/P2/P3.
|
P4 (continue) は P1/P2/P3 と同じ `loop_step(env, k_exit)` 骨格を使う設計だよ。
|
||||||
|
**Key insight**: `continue` = 「更新済み Env での `TailCallFn(loop_step, env', k_exit)`」で表現できる(新しい命令種別は不要)。
|
||||||
**Key insight**: `continue` = immediate `TailCallFn(loop_step, env', k_exit)` (skip to next iteration early), not a new instruction.
|
|
||||||
|
|
||||||
**Target loops** (JsonParser):
|
**Target loops** (JsonParser):
|
||||||
- ◎ _parse_array (skip whitespace) - PRIMARY (Phase 48-A)
|
- ◎ `_parse_array` (skip whitespace) – PRIMARY(Phase 48-A 対象)
|
||||||
- ○ _parse_object (skip whitespace) - Extended
|
- ○ `_parse_object` (skip whitespace) – Extended
|
||||||
- △ _unescape_string, _parse_string - Later
|
- △ `_unescape_string`, `_parse_string` – Later
|
||||||
|
|
||||||
**Infrastructure reuse**: 95%+ of P2/P3 Normalized code works for P4
|
**Infrastructure reuse**: P2/P3 Normalized の 95% 以上をそのまま再利用
|
||||||
- Same: EnvLayout, ConditionEnv, CarrierInfo, ExitLine, JpInst
|
- 共通: EnvLayout / ConditionEnv / CarrierInfo / ExitLine / JpInst
|
||||||
- New: `ContinueCheck` step kind in StepScheduleBox
|
- 追加: StepScheduleBox に `ContinueCheck` step kind を追加
|
||||||
|
|
||||||
**Phase 48 doc is SSOT** for P4 Normalized design.
|
**Phase 48-A(Minimal continue, dev-only)実装ステータス**:
|
||||||
|
- Fixture: `pattern4_continue_min.program.json`(`i == 2` を `continue` でスキップする最小 P4 ループ)
|
||||||
|
- ShapeGuard: `NormalizedDevShape::Pattern4ContinueMinimal` を追加し、構造ベースで minimal continue 形状を検出
|
||||||
|
- StepSchedule: `HeaderCond → ContinueCheck → Updates → Tail` の順序を固定
|
||||||
|
- Normalized lowering: `normalize_pattern4_continue_minimal()` を実装し、P2 正規化ロジックを約 95% 再利用
|
||||||
|
- テスト:
|
||||||
|
- Normalized dev スイートに P4 minimal の比較テストを 4 本追加
|
||||||
|
(Structured→Normalized→MIR(direct) vs Structured→MIR / runner / VM bridge)
|
||||||
|
- `cargo test --release` ベースで **939/939 tests PASS**(Phase 48-A 実装時点)
|
||||||
|
|
||||||
**Implementation phases**:
|
**Phase 48 doc is SSOT** for P4 Normalized design + 48-A 実装サマリだよ。
|
||||||
- Phase 48-A: Minimal continue (dev-only)
|
Phase 48-B(multi-carrier / string ops 拡張)と 48-C(canonical 昇格)は今後のフェーズで扱う。
|
||||||
- Phase 48-B: Extended patterns (multi-carrier)
|
|
||||||
- Phase 48-C: Canonical promotion
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Phase 47: Normalized P3 (If-Sum) Design
|
# Phase 47: Normalized P3 (If-Sum) Design
|
||||||
|
|
||||||
**Status**: Design Complete, Minimal Dev Test Implemented
|
**Status**: Design Complete, Minimal → Extended Dev → Canonical (P3 Core) 実装中
|
||||||
**Date**: 2025-12-12
|
**Date**: 2025-12-21
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|
||||||
@ -127,27 +127,17 @@ loop(i < n) {
|
|||||||
- EnvLayout: `{ i: int, sum: int, count: int }`
|
- EnvLayout: `{ i: int, sum: int, count: int }`
|
||||||
- StepSchedule: `[HeaderCond(i < n), IfCond(i % 2 == 1), ThenUpdates(sum, count), Updates(i), Tail]`
|
- StepSchedule: `[HeaderCond(i < n), IfCond(i % 2 == 1), ThenUpdates(sum, count), Updates(i), Tail]`
|
||||||
|
|
||||||
### Phase 47-B: JsonParser array_filter
|
### Phase 47-B: Extended dev targets(今回の範囲)
|
||||||
|
|
||||||
**Example**: JsonParser `array_filter` (if present in codebase)
|
| Fixture | Carriers / Params | 条件式 | EnvLayout 期待 |
|
||||||
|
|---------|------------------|--------|----------------|
|
||||||
|
| `pattern3_if_sum_multi_min` | `i`, `sum`, `count` | `i > 0` | `i, sum, count, len` |
|
||||||
|
| `jsonparser_if_sum_min` | `i`, `sum` | `i > 0`(JsonParser 由来の簡約形) | `i, sum, len` |
|
||||||
|
|
||||||
```nyash
|
特徴:
|
||||||
local out = new ArrayBox()
|
- どちらも if/else を持ち、Else は no-op(Select/If PHI を確実に通すため)
|
||||||
local i = 0
|
- MethodCall は含めず、まずは条件+複数キャリア更新に絞った dev 拡張
|
||||||
|
- P3 if-sum capability (= P3IfSum) に乗せ、Structured→Normalized→MIR(direct) で A/B 比較する
|
||||||
loop(i < arr.length()) {
|
|
||||||
local v = arr.get(i)
|
|
||||||
if (predicate(v)) {
|
|
||||||
out.push(v)
|
|
||||||
}
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Characteristics**:
|
|
||||||
- Method calls: `arr.length()`, `arr.get(i)`, `out.push(v)`
|
|
||||||
- Body-local: `v` (used in if condition)
|
|
||||||
- Conditional side effect: `out.push(v)`
|
|
||||||
|
|
||||||
**Complexity**: Higher than sum_count (method calls, body-local)
|
**Complexity**: Higher than sum_count (method calls, body-local)
|
||||||
|
|
||||||
@ -171,10 +161,16 @@ Complex P3 patterns from selfhost compiler (deferred to later phase).
|
|||||||
- ✅ Runner / VM tests: P3 minimal について Structured 経路と Normalized→MIR(direct) 経路が一致することを dev-only スイートで確認
|
- ✅ Runner / VM tests: P3 minimal について Structured 経路と Normalized→MIR(direct) 経路が一致することを dev-only スイートで確認
|
||||||
- ✅ 938/938 tests PASS(退行なし)
|
- ✅ 938/938 tests PASS(退行なし)
|
||||||
|
|
||||||
**Next Phase**(Phase 47-B 以降):
|
**Phase 47-B (✅ Extended dev)**:
|
||||||
- array_filter など body-local + method call を含む P3 ループへの適用
|
- Fixture 拡張: `pattern3_if_sum_multi_min.program.json`(sum+count) / `jsonparser_if_sum_min.program.json` を normalized_dev フィクスチャに追加
|
||||||
- multi-carrier if-sum(sum + count)や JsonParser 由来 P3 への拡張
|
- ShapeGuard: `Pattern3IfSumMulti` / `Pattern3IfSumJson` 追加、capability=P3IfSum
|
||||||
- Canonical 昇格(P3 minimal を dev-only から常時 Normalized 経路へ)
|
- Normalizer/Bridge: P3 if-sum multi/json を Structured→Normalized→MIR(direct) で dev 実行、Structured と一致
|
||||||
|
- Tests: `normalized_pattern3_if_sum_multi_vm_bridge_direct_matches_structured` / `normalized_pattern3_json_if_sum_min_vm_bridge_direct_matches_structured`
|
||||||
|
|
||||||
|
**Phase 47-C (⏩ Canonical 化)**:
|
||||||
|
- P3 if-sum minimal/multi/json を canonical Normalized セットに昇格(mode/env に関わらず direct ルート)
|
||||||
|
- Bridge/runner は P2 と同様に P3 を常時 Normalized→MIR(direct) へルーティング
|
||||||
|
- Docs/overview を canonical セット拡張に合わせて更新
|
||||||
|
|
||||||
## Implementation Strategy
|
## Implementation Strategy
|
||||||
|
|
||||||
|
|||||||
@ -67,6 +67,8 @@ fn resolve_function_route(func_name: &str) -> Result<FunctionRoute, String> {
|
|||||||
("jsonparser_atoi_mini", FunctionRoute::LoopFrontend),
|
("jsonparser_atoi_mini", FunctionRoute::LoopFrontend),
|
||||||
("jsonparser_atoi_real", FunctionRoute::LoopFrontend),
|
("jsonparser_atoi_real", FunctionRoute::LoopFrontend),
|
||||||
("jsonparser_parse_number_real", FunctionRoute::LoopFrontend),
|
("jsonparser_parse_number_real", FunctionRoute::LoopFrontend),
|
||||||
|
("pattern3_if_sum_multi_min", FunctionRoute::LoopFrontend),
|
||||||
|
("jsonparser_if_sum_min", FunctionRoute::LoopFrontend),
|
||||||
// Phase 48-A: Pattern4 continue minimal
|
// Phase 48-A: Pattern4 continue minimal
|
||||||
("pattern4_continue_minimal", FunctionRoute::LoopFrontend),
|
("pattern4_continue_minimal", FunctionRoute::LoopFrontend),
|
||||||
];
|
];
|
||||||
|
|||||||
@ -13,6 +13,7 @@ use crate::mir::join_ir::lowering::carrier_info::{CarrierInfo, CarrierInit};
|
|||||||
use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv;
|
use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv;
|
||||||
|
|
||||||
/// Steps that can be reordered by the scheduler.
|
/// Steps that can be reordered by the scheduler.
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub(crate) enum Pattern2StepKind {
|
pub(crate) enum Pattern2StepKind {
|
||||||
// P2 (Pattern2 Break) steps
|
// P2 (Pattern2 Break) steps
|
||||||
@ -154,6 +155,7 @@ fn log_schedule(ctx: &Pattern2ScheduleContext, schedule: &Pattern2StepSchedule)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 47-A: Generate step schedule for Pattern3 (if-sum) loops
|
/// Phase 47-A: Generate step schedule for Pattern3 (if-sum) loops
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) fn pattern3_if_sum_schedule() -> Vec<Pattern2StepKind> {
|
pub(crate) fn pattern3_if_sum_schedule() -> Vec<Pattern2StepKind> {
|
||||||
vec![
|
vec![
|
||||||
Pattern2StepKind::HeaderCond, // loop(i < n)
|
Pattern2StepKind::HeaderCond, // loop(i < n)
|
||||||
@ -165,6 +167,7 @@ pub(crate) fn pattern3_if_sum_schedule() -> Vec<Pattern2StepKind> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 48-A: Generate step schedule for Pattern4 (continue) loops
|
/// Phase 48-A: Generate step schedule for Pattern4 (continue) loops
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) fn pattern4_continue_schedule() -> Vec<Pattern2StepKind> {
|
pub(crate) fn pattern4_continue_schedule() -> Vec<Pattern2StepKind> {
|
||||||
vec![
|
vec![
|
||||||
Pattern2StepKind::HeaderCond, // loop(i < n)
|
Pattern2StepKind::HeaderCond, // loop(i < n)
|
||||||
|
|||||||
@ -333,6 +333,16 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
|||||||
{
|
{
|
||||||
max = max.max(6);
|
max = max.max(6);
|
||||||
}
|
}
|
||||||
|
if shapes.iter().any(|s| {
|
||||||
|
matches!(
|
||||||
|
s,
|
||||||
|
NormalizedDevShape::Pattern3IfSumMinimal
|
||||||
|
| NormalizedDevShape::Pattern3IfSumMulti
|
||||||
|
| NormalizedDevShape::Pattern3IfSumJson
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
max = max.max(6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
max
|
max
|
||||||
};
|
};
|
||||||
@ -528,29 +538,49 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
|||||||
norm
|
norm
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 47-A: Normalize Pattern3 if-sum minimal to Normalized JoinIR
|
/// Phase 47-A/B: Normalize Pattern3 if-sum shapes to Normalized JoinIR
|
||||||
#[cfg(feature = "normalized_dev")]
|
#[cfg(feature = "normalized_dev")]
|
||||||
pub fn normalize_pattern3_if_sum_minimal(
|
pub fn normalize_pattern3_if_sum_minimal(
|
||||||
structured: &JoinModule,
|
structured: &JoinModule,
|
||||||
) -> Result<NormalizedModule, String> {
|
) -> Result<NormalizedModule, String> {
|
||||||
// Guard: Must be Structured and match Pattern3IfSumMinimal shape
|
normalize_pattern3_if_sum_shape(structured, NormalizedDevShape::Pattern3IfSumMinimal)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 47-B: Normalize Pattern3 if-sum multi-carrier (sum+count) shape.
|
||||||
|
#[cfg(feature = "normalized_dev")]
|
||||||
|
pub fn normalize_pattern3_if_sum_multi_minimal(
|
||||||
|
structured: &JoinModule,
|
||||||
|
) -> Result<NormalizedModule, String> {
|
||||||
|
normalize_pattern3_if_sum_shape(structured, NormalizedDevShape::Pattern3IfSumMulti)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 47-B: Normalize JsonParser if-sum (mini) shape.
|
||||||
|
#[cfg(feature = "normalized_dev")]
|
||||||
|
pub fn normalize_pattern3_if_sum_json_minimal(
|
||||||
|
structured: &JoinModule,
|
||||||
|
) -> Result<NormalizedModule, String> {
|
||||||
|
normalize_pattern3_if_sum_shape(structured, NormalizedDevShape::Pattern3IfSumJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "normalized_dev")]
|
||||||
|
fn normalize_pattern3_if_sum_shape(
|
||||||
|
structured: &JoinModule,
|
||||||
|
target_shape: NormalizedDevShape,
|
||||||
|
) -> Result<NormalizedModule, String> {
|
||||||
if !structured.is_structured() {
|
if !structured.is_structured() {
|
||||||
return Err("[normalize_p3] Not structured JoinIR".to_string());
|
return Err("[normalize_p3] Not structured JoinIR".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use shape detection to verify P3 shape
|
let shapes = shape_guard::supported_shapes(structured);
|
||||||
let shapes = shape_guard::supported_shapes(&structured);
|
if !shapes.contains(&target_shape) {
|
||||||
if !shapes.contains(&NormalizedDevShape::Pattern3IfSumMinimal) {
|
return Err(format!(
|
||||||
return Err("[normalize_p3] Not Pattern3IfSumMinimal shape".to_string());
|
"[normalize_p3] shape mismatch: expected {:?}, got {:?}",
|
||||||
|
target_shape, shapes
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 47-A minimal: Reuse P2 normalization temporarily
|
// Phase 47-B: P3 if-sum は既存の P2 ミニ正規化器で十分に表現できる
|
||||||
// TODO: Implement proper P3-specific normalization with:
|
// (Select/If/Compare/BinOp をそのまま JpInst に写す)。
|
||||||
// - EnvLayout for i, sum carriers
|
|
||||||
// - IfCond → ThenUpdates / ElseUpdates step sequence
|
|
||||||
// - Proper JpInst::If for conditional carrier updates
|
|
||||||
|
|
||||||
// For now, delegate to P2 normalization (works for simple cases)
|
|
||||||
Ok(normalize_pattern2_minimal(structured))
|
Ok(normalize_pattern2_minimal(structured))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,6 +1004,16 @@ pub(crate) fn normalized_dev_roundtrip_structured(
|
|||||||
.expect("P3 normalization failed");
|
.expect("P3 normalization failed");
|
||||||
normalized_pattern2_to_structured(&norm)
|
normalized_pattern2_to_structured(&norm)
|
||||||
})),
|
})),
|
||||||
|
NormalizedDevShape::Pattern3IfSumMulti => catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
let norm = normalize_pattern3_if_sum_multi_minimal(module)
|
||||||
|
.expect("P3 multi normalization failed");
|
||||||
|
normalized_pattern2_to_structured(&norm)
|
||||||
|
})),
|
||||||
|
NormalizedDevShape::Pattern3IfSumJson => catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
let norm = normalize_pattern3_if_sum_json_minimal(module)
|
||||||
|
.expect("P3 json normalization failed");
|
||||||
|
normalized_pattern2_to_structured(&norm)
|
||||||
|
})),
|
||||||
// Phase 48-A: P4 minimal (delegates to P2 for now, but uses proper guard)
|
// Phase 48-A: P4 minimal (delegates to P2 for now, but uses proper guard)
|
||||||
NormalizedDevShape::Pattern4ContinueMinimal => catch_unwind(AssertUnwindSafe(|| {
|
NormalizedDevShape::Pattern4ContinueMinimal => catch_unwind(AssertUnwindSafe(|| {
|
||||||
let norm = normalize_pattern4_continue_minimal(module)
|
let norm = normalize_pattern4_continue_minimal(module)
|
||||||
|
|||||||
@ -8,11 +8,51 @@ use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
|||||||
use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr;
|
use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr;
|
||||||
use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal;
|
use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal;
|
||||||
use crate::mir::join_ir::lowering::loop_with_if_phi_if_sum::lower_if_sum_pattern;
|
use crate::mir::join_ir::lowering::loop_with_if_phi_if_sum::lower_if_sum_pattern;
|
||||||
use crate::mir::join_ir::JoinModule;
|
use crate::mir::join_ir::{
|
||||||
|
BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule, MirLikeInst,
|
||||||
|
UnaryOp,
|
||||||
|
};
|
||||||
use crate::mir::{BasicBlockId, ValueId};
|
use crate::mir::{BasicBlockId, ValueId};
|
||||||
use crate::{config::env::joinir_dev_enabled, config::env::joinir_test_debug_enabled};
|
use crate::{config::env::joinir_dev_enabled, config::env::joinir_test_debug_enabled};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
|
fn const_i64(func: &mut JoinFunction, dst: ValueId, value: i64) {
|
||||||
|
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst,
|
||||||
|
value: ConstValue::Integer(value),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare(func: &mut JoinFunction, dst: ValueId, op: CompareOp, lhs: ValueId, rhs: ValueId) {
|
||||||
|
func.body.push(JoinInst::Compute(MirLikeInst::Compare { dst, op, lhs, rhs }));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unary_not(func: &mut JoinFunction, dst: ValueId, operand: ValueId) {
|
||||||
|
func.body.push(JoinInst::Compute(MirLikeInst::UnaryOp {
|
||||||
|
dst,
|
||||||
|
op: UnaryOp::Not,
|
||||||
|
operand,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bin_add(func: &mut JoinFunction, dst: ValueId, lhs: ValueId, rhs: ValueId) {
|
||||||
|
func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||||
|
dst,
|
||||||
|
op: BinOpKind::Add,
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select(func: &mut JoinFunction, dst: ValueId, cond: ValueId, then_val: ValueId, else_val: ValueId) {
|
||||||
|
func.body.push(JoinInst::Compute(MirLikeInst::Select {
|
||||||
|
dst,
|
||||||
|
cond,
|
||||||
|
then_val,
|
||||||
|
else_val,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
/// Structured Pattern2 (joinir_min_loop 相当) をテスト用に生成するヘルパー。
|
/// Structured Pattern2 (joinir_min_loop 相当) をテスト用に生成するヘルパー。
|
||||||
pub fn build_pattern2_minimal_structured() -> JoinModule {
|
pub fn build_pattern2_minimal_structured() -> JoinModule {
|
||||||
let loop_cond = ASTNode::BinaryOp {
|
let loop_cond = ASTNode::BinaryOp {
|
||||||
@ -163,6 +203,245 @@ pub fn build_jsonparser_parse_number_real_structured_for_normalized_dev() -> Joi
|
|||||||
module
|
module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 47-B: Pattern3 if-sum (multi carrier) を Structured で組み立てるヘルパー。
|
||||||
|
///
|
||||||
|
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/pattern3_if_sum_multi_min.program.json
|
||||||
|
pub fn build_pattern3_if_sum_multi_min_structured_for_normalized_dev() -> JoinModule {
|
||||||
|
// 手書き JoinIR(i/sum/count の 3 キャリア)
|
||||||
|
let mut module = JoinModule::new();
|
||||||
|
let mut next_id = 0u32;
|
||||||
|
let mut alloc = || {
|
||||||
|
let id = ValueId(next_id);
|
||||||
|
next_id += 1;
|
||||||
|
id
|
||||||
|
};
|
||||||
|
|
||||||
|
let main_id = JoinFuncId::new(0);
|
||||||
|
let loop_id = JoinFuncId::new(1);
|
||||||
|
let exit_id = JoinFuncId::new(2);
|
||||||
|
|
||||||
|
// main: init i/sum/count = 0 → tail call loop_step
|
||||||
|
let i0 = alloc();
|
||||||
|
let sum0 = alloc();
|
||||||
|
let count0 = alloc();
|
||||||
|
let mut main = JoinFunction::new(main_id, "main".to_string(), vec![]);
|
||||||
|
const_i64(&mut main, i0, 0);
|
||||||
|
const_i64(&mut main, sum0, 0);
|
||||||
|
const_i64(&mut main, count0, 0);
|
||||||
|
main.body.push(JoinInst::Call {
|
||||||
|
func: loop_id,
|
||||||
|
args: vec![i0, sum0, count0],
|
||||||
|
k_next: None,
|
||||||
|
dst: None,
|
||||||
|
});
|
||||||
|
module.add_function(main);
|
||||||
|
|
||||||
|
// loop_step params: i, sum, count
|
||||||
|
let i_param = alloc();
|
||||||
|
let sum_param = alloc();
|
||||||
|
let count_param = alloc();
|
||||||
|
let mut loop_step = JoinFunction::new(
|
||||||
|
loop_id,
|
||||||
|
"loop_step".to_string(),
|
||||||
|
vec![i_param, sum_param, count_param],
|
||||||
|
);
|
||||||
|
|
||||||
|
// loop condition: i < 3
|
||||||
|
let limit_const = alloc();
|
||||||
|
let cmp_loop = alloc();
|
||||||
|
let exit_cond = alloc();
|
||||||
|
const_i64(&mut loop_step, limit_const, 3);
|
||||||
|
compare(
|
||||||
|
&mut loop_step,
|
||||||
|
cmp_loop,
|
||||||
|
CompareOp::Lt,
|
||||||
|
i_param,
|
||||||
|
limit_const,
|
||||||
|
);
|
||||||
|
unary_not(&mut loop_step, exit_cond, cmp_loop);
|
||||||
|
loop_step.body.push(JoinInst::Jump {
|
||||||
|
cont: exit_id.as_cont(),
|
||||||
|
args: vec![sum_param, count_param],
|
||||||
|
cond: Some(exit_cond),
|
||||||
|
});
|
||||||
|
|
||||||
|
// if condition: i > 0
|
||||||
|
let cond_cmp = alloc();
|
||||||
|
let zero_const = alloc();
|
||||||
|
const_i64(&mut loop_step, zero_const, 0);
|
||||||
|
compare(
|
||||||
|
&mut loop_step,
|
||||||
|
cond_cmp,
|
||||||
|
CompareOp::Gt,
|
||||||
|
i_param,
|
||||||
|
zero_const,
|
||||||
|
);
|
||||||
|
|
||||||
|
// then: sum = sum + 1, count = count + 1
|
||||||
|
let one_const = alloc();
|
||||||
|
let sum_then = alloc();
|
||||||
|
let count_then = alloc();
|
||||||
|
const_i64(&mut loop_step, one_const, 1);
|
||||||
|
bin_add(&mut loop_step, sum_then, sum_param, one_const);
|
||||||
|
bin_add(&mut loop_step, count_then, count_param, one_const);
|
||||||
|
|
||||||
|
// else: identity
|
||||||
|
let sum_else = alloc();
|
||||||
|
let count_else = alloc();
|
||||||
|
bin_add(&mut loop_step, sum_else, sum_param, zero_const);
|
||||||
|
bin_add(&mut loop_step, count_else, count_param, zero_const);
|
||||||
|
|
||||||
|
// select
|
||||||
|
let sum_new = alloc();
|
||||||
|
let count_new = alloc();
|
||||||
|
select(&mut loop_step, sum_new, cond_cmp, sum_then, sum_else);
|
||||||
|
select(&mut loop_step, count_new, cond_cmp, count_then, count_else);
|
||||||
|
|
||||||
|
// counter update: i = i + 1
|
||||||
|
let one_const2 = alloc();
|
||||||
|
let i_next = alloc();
|
||||||
|
const_i64(&mut loop_step, one_const2, 1);
|
||||||
|
bin_add(&mut loop_step, i_next, i_param, one_const2);
|
||||||
|
|
||||||
|
loop_step.body.push(JoinInst::Call {
|
||||||
|
func: loop_id,
|
||||||
|
args: vec![i_next, sum_new, count_new],
|
||||||
|
k_next: None,
|
||||||
|
dst: None,
|
||||||
|
});
|
||||||
|
module.add_function(loop_step);
|
||||||
|
|
||||||
|
// k_exit(sum, count)
|
||||||
|
let sum_final = alloc();
|
||||||
|
let count_final = alloc();
|
||||||
|
let mut k_exit = JoinFunction::new(exit_id, "k_exit".to_string(), vec![sum_final, count_final]);
|
||||||
|
k_exit.body.push(JoinInst::Ret {
|
||||||
|
value: Some(sum_final),
|
||||||
|
});
|
||||||
|
module.add_function(k_exit);
|
||||||
|
|
||||||
|
module.entry = Some(main_id);
|
||||||
|
module.phase = crate::mir::join_ir::JoinIrPhase::Structured;
|
||||||
|
module
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 47-B: JsonParser if-sum mini を Structured で組み立てるヘルパー。
|
||||||
|
///
|
||||||
|
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_if_sum_min.program.json
|
||||||
|
pub fn build_pattern3_json_if_sum_min_structured_for_normalized_dev() -> JoinModule {
|
||||||
|
// 手書き JoinIR(i/sum の 2 キャリア、JsonParser 由来の簡約 if-sum)
|
||||||
|
let mut module = JoinModule::new();
|
||||||
|
let mut next_id = 0u32;
|
||||||
|
let mut alloc = || {
|
||||||
|
let id = ValueId(next_id);
|
||||||
|
next_id += 1;
|
||||||
|
id
|
||||||
|
};
|
||||||
|
|
||||||
|
let main_id = JoinFuncId::new(0);
|
||||||
|
let loop_id = JoinFuncId::new(1);
|
||||||
|
let exit_id = JoinFuncId::new(2);
|
||||||
|
|
||||||
|
// main: init i/sum = 0 → tail call loop_step
|
||||||
|
let i0 = alloc();
|
||||||
|
let sum0 = alloc();
|
||||||
|
let mut main = JoinFunction::new(main_id, "main".to_string(), vec![]);
|
||||||
|
main.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: i0,
|
||||||
|
value: ConstValue::Integer(0),
|
||||||
|
}));
|
||||||
|
main.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: sum0,
|
||||||
|
value: ConstValue::Integer(0),
|
||||||
|
}));
|
||||||
|
main.body.push(JoinInst::Call {
|
||||||
|
func: loop_id,
|
||||||
|
args: vec![i0, sum0],
|
||||||
|
k_next: None,
|
||||||
|
dst: None,
|
||||||
|
});
|
||||||
|
module.add_function(main);
|
||||||
|
|
||||||
|
// loop_step params: i, sum
|
||||||
|
let i_param = alloc();
|
||||||
|
let sum_param = alloc();
|
||||||
|
let mut loop_step = JoinFunction::new(loop_id, "loop_step".to_string(), vec![i_param, sum_param]);
|
||||||
|
|
||||||
|
// loop condition: i < 5
|
||||||
|
let limit_const = alloc();
|
||||||
|
let cmp_loop = alloc();
|
||||||
|
let exit_cond = alloc();
|
||||||
|
loop_step
|
||||||
|
.body
|
||||||
|
.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: limit_const,
|
||||||
|
value: ConstValue::Integer(5),
|
||||||
|
}));
|
||||||
|
compare(
|
||||||
|
&mut loop_step,
|
||||||
|
cmp_loop,
|
||||||
|
CompareOp::Lt,
|
||||||
|
i_param,
|
||||||
|
limit_const,
|
||||||
|
);
|
||||||
|
unary_not(&mut loop_step, exit_cond, cmp_loop);
|
||||||
|
loop_step.body.push(JoinInst::Jump {
|
||||||
|
cont: exit_id.as_cont(),
|
||||||
|
args: vec![sum_param],
|
||||||
|
cond: Some(exit_cond),
|
||||||
|
});
|
||||||
|
|
||||||
|
// if condition: i > 0
|
||||||
|
let cond_cmp = alloc();
|
||||||
|
let zero_const = alloc();
|
||||||
|
const_i64(&mut loop_step, zero_const, 0);
|
||||||
|
compare(
|
||||||
|
&mut loop_step,
|
||||||
|
cond_cmp,
|
||||||
|
CompareOp::Gt,
|
||||||
|
i_param,
|
||||||
|
zero_const,
|
||||||
|
);
|
||||||
|
|
||||||
|
// then: sum = sum + i
|
||||||
|
let sum_then = alloc();
|
||||||
|
bin_add(&mut loop_step, sum_then, sum_param, i_param);
|
||||||
|
|
||||||
|
// else: identity sum
|
||||||
|
let sum_else = alloc();
|
||||||
|
bin_add(&mut loop_step, sum_else, sum_param, zero_const);
|
||||||
|
|
||||||
|
// select
|
||||||
|
let sum_new = alloc();
|
||||||
|
select(&mut loop_step, sum_new, cond_cmp, sum_then, sum_else);
|
||||||
|
|
||||||
|
// counter update: i = i + 1
|
||||||
|
let one_const = alloc();
|
||||||
|
let i_next = alloc();
|
||||||
|
const_i64(&mut loop_step, one_const, 1);
|
||||||
|
bin_add(&mut loop_step, i_next, i_param, one_const);
|
||||||
|
|
||||||
|
loop_step.body.push(JoinInst::Call {
|
||||||
|
func: loop_id,
|
||||||
|
args: vec![i_next, sum_new],
|
||||||
|
k_next: None,
|
||||||
|
dst: None,
|
||||||
|
});
|
||||||
|
module.add_function(loop_step);
|
||||||
|
|
||||||
|
// k_exit(sum)
|
||||||
|
let sum_final = alloc();
|
||||||
|
let mut k_exit = JoinFunction::new(exit_id, "k_exit".to_string(), vec![sum_final]);
|
||||||
|
k_exit.body.push(JoinInst::Ret {
|
||||||
|
value: Some(sum_final),
|
||||||
|
});
|
||||||
|
module.add_function(k_exit);
|
||||||
|
|
||||||
|
module.entry = Some(main_id);
|
||||||
|
module.phase = crate::mir::join_ir::JoinIrPhase::Structured;
|
||||||
|
module
|
||||||
|
}
|
||||||
|
|
||||||
/// JsonParser _atoi 相当のミニ P2 ループを Structured で組み立てるヘルパー。
|
/// JsonParser _atoi 相当のミニ P2 ループを Structured で組み立てるヘルパー。
|
||||||
///
|
///
|
||||||
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_atoi_mini.program.json
|
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_atoi_mini.program.json
|
||||||
@ -333,6 +612,8 @@ pub mod prelude {
|
|||||||
build_jsonparser_skip_ws_structured_for_normalized_dev,
|
build_jsonparser_skip_ws_structured_for_normalized_dev,
|
||||||
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
|
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
|
||||||
build_pattern3_if_sum_min_structured_for_normalized_dev,
|
build_pattern3_if_sum_min_structured_for_normalized_dev,
|
||||||
|
build_pattern3_if_sum_multi_min_structured_for_normalized_dev,
|
||||||
|
build_pattern3_json_if_sum_min_structured_for_normalized_dev,
|
||||||
build_pattern4_continue_min_structured_for_normalized_dev,
|
build_pattern4_continue_min_structured_for_normalized_dev,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,9 @@ pub enum ShapeCapabilityKind {
|
|||||||
/// P2 Mid: _parse_number real (p + num_str + result)
|
/// P2 Mid: _parse_number real (p + num_str + result)
|
||||||
P2MidParseNumber,
|
P2MidParseNumber,
|
||||||
|
|
||||||
|
/// P3 If-Sum family (minimal/multi/json)
|
||||||
|
P3IfSum,
|
||||||
|
|
||||||
// Future: Other P2 patterns
|
// Future: Other P2 patterns
|
||||||
// P2MidAtOfLoop,
|
// P2MidAtOfLoop,
|
||||||
// P2HeavyString,
|
// P2HeavyString,
|
||||||
@ -52,6 +55,9 @@ pub enum NormalizedDevShape {
|
|||||||
JsonparserParseNumberReal,
|
JsonparserParseNumberReal,
|
||||||
// Phase 47-A: Pattern3 (if-sum) minimal
|
// Phase 47-A: Pattern3 (if-sum) minimal
|
||||||
Pattern3IfSumMinimal,
|
Pattern3IfSumMinimal,
|
||||||
|
// Phase 47-B: Pattern3 extended (multi/json)
|
||||||
|
Pattern3IfSumMulti,
|
||||||
|
Pattern3IfSumJson,
|
||||||
// Phase 48-A: Pattern4 (continue) minimal
|
// Phase 48-A: Pattern4 (continue) minimal
|
||||||
Pattern4ContinueMinimal,
|
Pattern4ContinueMinimal,
|
||||||
}
|
}
|
||||||
@ -86,6 +92,14 @@ const SHAPE_DETECTORS: &[(NormalizedDevShape, Detector)] = &[
|
|||||||
NormalizedDevShape::Pattern3IfSumMinimal,
|
NormalizedDevShape::Pattern3IfSumMinimal,
|
||||||
detectors::is_pattern3_if_sum_minimal,
|
detectors::is_pattern3_if_sum_minimal,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
NormalizedDevShape::Pattern3IfSumMulti,
|
||||||
|
detectors::is_pattern3_if_sum_multi,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
NormalizedDevShape::Pattern3IfSumJson,
|
||||||
|
detectors::is_pattern3_if_sum_json,
|
||||||
|
),
|
||||||
// Phase 48-A: Pattern4 continue minimal
|
// Phase 48-A: Pattern4 continue minimal
|
||||||
(
|
(
|
||||||
NormalizedDevShape::Pattern4ContinueMinimal,
|
NormalizedDevShape::Pattern4ContinueMinimal,
|
||||||
@ -118,8 +132,8 @@ pub fn capability_for_shape(shape: &NormalizedDevShape) -> ShapeCapability {
|
|||||||
JsonparserAtoiMini | JsonparserAtoiReal => P2CoreAtoi,
|
JsonparserAtoiMini | JsonparserAtoiReal => P2CoreAtoi,
|
||||||
JsonparserParseNumberReal => P2MidParseNumber,
|
JsonparserParseNumberReal => P2MidParseNumber,
|
||||||
Pattern1Mini => P2CoreSimple, // Also core simple pattern
|
Pattern1Mini => P2CoreSimple, // Also core simple pattern
|
||||||
// Phase 47-A: P3 minimal maps to P2CoreSimple for now (future: P3CoreSimple)
|
// Phase 47-B: P3 if-sum family
|
||||||
Pattern3IfSumMinimal => P2CoreSimple,
|
Pattern3IfSumMinimal | Pattern3IfSumMulti | Pattern3IfSumJson => P3IfSum,
|
||||||
// Phase 48-A: P4 minimal maps to P2CoreSimple for now (future: P4CoreSimple)
|
// Phase 48-A: P4 minimal maps to P2CoreSimple for now (future: P4CoreSimple)
|
||||||
Pattern4ContinueMinimal => P2CoreSimple,
|
Pattern4ContinueMinimal => P2CoreSimple,
|
||||||
};
|
};
|
||||||
@ -146,6 +160,10 @@ pub fn is_canonical_shape(shape: &NormalizedDevShape) -> bool {
|
|||||||
// Phase 46: Add P2-Mid patterns
|
// Phase 46: Add P2-Mid patterns
|
||||||
| JsonparserAtoiReal
|
| JsonparserAtoiReal
|
||||||
| JsonparserParseNumberReal
|
| JsonparserParseNumberReal
|
||||||
|
// Phase 47-C: P3 if-sum canonical set
|
||||||
|
| Pattern3IfSumMinimal
|
||||||
|
| Pattern3IfSumMulti
|
||||||
|
| Pattern3IfSumJson
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +173,10 @@ pub fn is_canonical_shape(shape: &NormalizedDevShape) -> bool {
|
|||||||
/// Use `is_canonical_shape()` for exact canonical filtering.
|
/// Use `is_canonical_shape()` for exact canonical filtering.
|
||||||
pub fn is_p2_core_capability(cap: &ShapeCapability) -> bool {
|
pub fn is_p2_core_capability(cap: &ShapeCapability) -> bool {
|
||||||
use ShapeCapabilityKind::*;
|
use ShapeCapabilityKind::*;
|
||||||
matches!(cap.kind, P2CoreSimple | P2CoreSkipWs | P2CoreAtoi | P2MidParseNumber)
|
matches!(
|
||||||
|
cap.kind,
|
||||||
|
P2CoreSimple | P2CoreSkipWs | P2CoreAtoi | P2MidParseNumber | P3IfSum
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 44: Check if capability is supported by Normalized dev
|
/// Phase 44: Check if capability is supported by Normalized dev
|
||||||
@ -398,12 +419,34 @@ mod detectors {
|
|||||||
.iter()
|
.iter()
|
||||||
.any(|inst| matches!(inst, JoinInst::Call { k_next: None, .. }));
|
.any(|inst| matches!(inst, JoinInst::Call { k_next: None, .. }));
|
||||||
|
|
||||||
// P3 minimal has 2-4 params (i, sum, possibly n)
|
// P3 minimal/multi/json: typically 2-6 params (i + carriers + len/host)
|
||||||
let reasonable_param_count = (2..=4).contains(&loop_step.params.len());
|
let reasonable_param_count = (2..=6).contains(&loop_step.params.len());
|
||||||
|
|
||||||
has_compare && has_select && has_tail_call && reasonable_param_count
|
has_compare && has_select && has_tail_call && reasonable_param_count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 47-B: P3 if-sum (multi-carrier) shape detector
|
||||||
|
pub(crate) fn is_pattern3_if_sum_multi(module: &JoinModule) -> bool {
|
||||||
|
if !is_pattern3_if_sum_minimal(module) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
module
|
||||||
|
.functions
|
||||||
|
.values()
|
||||||
|
.any(|f| f.name == "pattern3_if_sum_multi_min")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Phase 47-B: P3 if-sum (JsonParser mini) shape detector
|
||||||
|
pub(crate) fn is_pattern3_if_sum_json(module: &JoinModule) -> bool {
|
||||||
|
if !is_pattern3_if_sum_minimal(module) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
module
|
||||||
|
.functions
|
||||||
|
.values()
|
||||||
|
.any(|f| f.name == "jsonparser_if_sum_min")
|
||||||
|
}
|
||||||
|
|
||||||
/// Phase 48-A: Check if module matches Pattern4 continue minimal shape
|
/// Phase 48-A: Check if module matches Pattern4 continue minimal shape
|
||||||
pub(crate) fn is_pattern4_continue_minimal(module: &JoinModule) -> bool {
|
pub(crate) fn is_pattern4_continue_minimal(module: &JoinModule) -> bool {
|
||||||
// Structure-based detection (avoid name-based heuristics)
|
// Structure-based detection (avoid name-based heuristics)
|
||||||
|
|||||||
@ -77,6 +77,15 @@ fn normalize_for_shape(
|
|||||||
crate::mir::join_ir::normalized::normalize_pattern3_if_sum_minimal(module)
|
crate::mir::join_ir::normalized::normalize_pattern3_if_sum_minimal(module)
|
||||||
.expect("P3 normalization failed")
|
.expect("P3 normalization failed")
|
||||||
})),
|
})),
|
||||||
|
// Phase 47-B: P3 extended normalization
|
||||||
|
NormalizedDevShape::Pattern3IfSumMulti => catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
crate::mir::join_ir::normalized::normalize_pattern3_if_sum_multi_minimal(module)
|
||||||
|
.expect("P3 multi normalization failed")
|
||||||
|
})),
|
||||||
|
NormalizedDevShape::Pattern3IfSumJson => catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
crate::mir::join_ir::normalized::normalize_pattern3_if_sum_json_minimal(module)
|
||||||
|
.expect("P3 json normalization failed")
|
||||||
|
})),
|
||||||
// Phase 48-A: P4 minimal normalization
|
// Phase 48-A: P4 minimal normalization
|
||||||
NormalizedDevShape::Pattern4ContinueMinimal => catch_unwind(AssertUnwindSafe(|| {
|
NormalizedDevShape::Pattern4ContinueMinimal => catch_unwind(AssertUnwindSafe(|| {
|
||||||
crate::mir::join_ir::normalized::normalize_pattern4_continue_minimal(module)
|
crate::mir::join_ir::normalized::normalize_pattern4_continue_minimal(module)
|
||||||
@ -186,9 +195,9 @@ pub(crate) fn bridge_joinir_to_mir_with_meta(
|
|||||||
{
|
{
|
||||||
let mode = current_joinir_mode();
|
let mode = current_joinir_mode();
|
||||||
|
|
||||||
// Phase 46: Canonical P2-Core + P2-Mid shapes always use Normalized→MIR(direct)
|
// Phase 47-C: Canonical set (P2-Core + P2-Mid + P3 if-sum) always uses Normalized→MIR(direct)
|
||||||
// Canonical set: Pattern2Mini, skip_ws mini/real, atoi mini/real, parse_number real
|
// Canonical set: Pattern2Mini, skip_ws mini/real, atoi mini/real, parse_number real,
|
||||||
// P3/P4 patterns are NOT canonical (deferred to NORM-P3/NORM-P4)
|
// P3 if-sum minimal/multi/json
|
||||||
let canonical_shapes = shape_guard::canonical_shapes(module);
|
let canonical_shapes = shape_guard::canonical_shapes(module);
|
||||||
if !canonical_shapes.is_empty() {
|
if !canonical_shapes.is_empty() {
|
||||||
match try_normalized_direct_bridge(module, meta, &canonical_shapes, false, false)? {
|
match try_normalized_direct_bridge(module, meta, &canonical_shapes, false, false)? {
|
||||||
|
|||||||
@ -53,5 +53,5 @@ mod helpers;
|
|||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
// Public re-exports
|
// Public re-exports
|
||||||
pub(crate) use analyzers::{analyze_captured_vars, analyze_captured_vars_v2};
|
pub(crate) use analyzers::analyze_captured_vars_v2;
|
||||||
pub use types::{CapturedEnv, CapturedVar};
|
pub use types::{CapturedEnv, CapturedVar};
|
||||||
|
|||||||
@ -17,6 +17,8 @@ use nyash_rust::mir::join_ir::normalized::fixtures::{
|
|||||||
build_jsonparser_skip_ws_structured_for_normalized_dev,
|
build_jsonparser_skip_ws_structured_for_normalized_dev,
|
||||||
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
|
build_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
|
||||||
build_pattern3_if_sum_min_structured_for_normalized_dev,
|
build_pattern3_if_sum_min_structured_for_normalized_dev,
|
||||||
|
build_pattern3_if_sum_multi_min_structured_for_normalized_dev,
|
||||||
|
build_pattern3_json_if_sum_min_structured_for_normalized_dev,
|
||||||
build_pattern4_continue_min_structured_for_normalized_dev,
|
build_pattern4_continue_min_structured_for_normalized_dev,
|
||||||
};
|
};
|
||||||
use nyash_rust::mir::join_ir_runner::run_joinir_function;
|
use nyash_rust::mir::join_ir_runner::run_joinir_function;
|
||||||
@ -530,6 +532,42 @@ fn normalized_pattern3_if_sum_minimal_runner_dev_switch_matches_structured() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalized_pattern3_if_sum_multi_vm_bridge_direct_matches_structured() {
|
||||||
|
let _ctx = normalized_dev_test_ctx();
|
||||||
|
let structured = build_pattern3_if_sum_multi_min_structured_for_normalized_dev();
|
||||||
|
let entry = structured.entry.expect("structured entry required");
|
||||||
|
let input = [JoinValue::Int(0)];
|
||||||
|
|
||||||
|
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
|
||||||
|
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
|
||||||
|
|
||||||
|
assert_eq!(base, dev, "vm bridge mismatch for P3 if-sum multi");
|
||||||
|
assert_eq!(
|
||||||
|
dev,
|
||||||
|
JoinValue::Int(2),
|
||||||
|
"unexpected result for P3 if-sum multi (expected sum=2)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalized_pattern3_json_if_sum_min_vm_bridge_direct_matches_structured() {
|
||||||
|
let _ctx = normalized_dev_test_ctx();
|
||||||
|
let structured = build_pattern3_json_if_sum_min_structured_for_normalized_dev();
|
||||||
|
let entry = structured.entry.expect("structured entry required");
|
||||||
|
let input = [JoinValue::Int(0)];
|
||||||
|
|
||||||
|
let base = run_joinir_vm_bridge(&structured, entry, &input, false);
|
||||||
|
let dev = run_joinir_vm_bridge(&structured, entry, &input, true);
|
||||||
|
|
||||||
|
assert_eq!(base, dev, "vm bridge mismatch for P3 json if-sum");
|
||||||
|
assert_eq!(
|
||||||
|
dev,
|
||||||
|
JoinValue::Int(10),
|
||||||
|
"unexpected result for P3 json if-sum (expected sum=10)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "normalized_dev")]
|
#[cfg(feature = "normalized_dev")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_phase46_canonical_set_includes_p2_mid() {
|
fn test_phase46_canonical_set_includes_p2_mid() {
|
||||||
@ -542,6 +580,15 @@ fn test_phase46_canonical_set_includes_p2_mid() {
|
|||||||
assert!(is_canonical_shape(
|
assert!(is_canonical_shape(
|
||||||
&NormalizedDevShape::JsonparserParseNumberReal
|
&NormalizedDevShape::JsonparserParseNumberReal
|
||||||
));
|
));
|
||||||
|
assert!(is_canonical_shape(
|
||||||
|
&NormalizedDevShape::Pattern3IfSumMinimal
|
||||||
|
));
|
||||||
|
assert!(is_canonical_shape(
|
||||||
|
&NormalizedDevShape::Pattern3IfSumMulti
|
||||||
|
));
|
||||||
|
assert!(is_canonical_shape(
|
||||||
|
&NormalizedDevShape::Pattern3IfSumJson
|
||||||
|
));
|
||||||
|
|
||||||
// Verify P2-Core patterns still canonical
|
// Verify P2-Core patterns still canonical
|
||||||
assert!(is_canonical_shape(&NormalizedDevShape::Pattern2Mini));
|
assert!(is_canonical_shape(&NormalizedDevShape::Pattern2Mini));
|
||||||
|
|||||||
Reference in New Issue
Block a user