Phase47-B/C: extend P3 normalized shapes and quiet dev warnings
This commit is contained in:
@ -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_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::JoinModule;
|
||||
use crate::mir::join_ir::{
|
||||
BinOpKind, CompareOp, ConstValue, JoinFuncId, JoinFunction, JoinInst, JoinModule, MirLikeInst,
|
||||
UnaryOp,
|
||||
};
|
||||
use crate::mir::{BasicBlockId, ValueId};
|
||||
use crate::{config::env::joinir_dev_enabled, config::env::joinir_test_debug_enabled};
|
||||
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 相当) をテスト用に生成するヘルパー。
|
||||
pub fn build_pattern2_minimal_structured() -> JoinModule {
|
||||
let loop_cond = ASTNode::BinaryOp {
|
||||
@ -163,6 +203,245 @@ pub fn build_jsonparser_parse_number_real_structured_for_normalized_dev() -> Joi
|
||||
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 で組み立てるヘルパー。
|
||||
///
|
||||
/// 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_pattern2_break_fixture_structured, build_pattern2_minimal_structured,
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
@ -19,6 +19,9 @@ pub enum ShapeCapabilityKind {
|
||||
/// P2 Mid: _parse_number real (p + num_str + result)
|
||||
P2MidParseNumber,
|
||||
|
||||
/// P3 If-Sum family (minimal/multi/json)
|
||||
P3IfSum,
|
||||
|
||||
// Future: Other P2 patterns
|
||||
// P2MidAtOfLoop,
|
||||
// P2HeavyString,
|
||||
@ -52,6 +55,9 @@ pub enum NormalizedDevShape {
|
||||
JsonparserParseNumberReal,
|
||||
// Phase 47-A: Pattern3 (if-sum) minimal
|
||||
Pattern3IfSumMinimal,
|
||||
// Phase 47-B: Pattern3 extended (multi/json)
|
||||
Pattern3IfSumMulti,
|
||||
Pattern3IfSumJson,
|
||||
// Phase 48-A: Pattern4 (continue) minimal
|
||||
Pattern4ContinueMinimal,
|
||||
}
|
||||
@ -86,6 +92,14 @@ const SHAPE_DETECTORS: &[(NormalizedDevShape, Detector)] = &[
|
||||
NormalizedDevShape::Pattern3IfSumMinimal,
|
||||
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
|
||||
(
|
||||
NormalizedDevShape::Pattern4ContinueMinimal,
|
||||
@ -118,8 +132,8 @@ pub fn capability_for_shape(shape: &NormalizedDevShape) -> ShapeCapability {
|
||||
JsonparserAtoiMini | JsonparserAtoiReal => P2CoreAtoi,
|
||||
JsonparserParseNumberReal => P2MidParseNumber,
|
||||
Pattern1Mini => P2CoreSimple, // Also core simple pattern
|
||||
// Phase 47-A: P3 minimal maps to P2CoreSimple for now (future: P3CoreSimple)
|
||||
Pattern3IfSumMinimal => P2CoreSimple,
|
||||
// Phase 47-B: P3 if-sum family
|
||||
Pattern3IfSumMinimal | Pattern3IfSumMulti | Pattern3IfSumJson => P3IfSum,
|
||||
// Phase 48-A: P4 minimal maps to P2CoreSimple for now (future: P4CoreSimple)
|
||||
Pattern4ContinueMinimal => P2CoreSimple,
|
||||
};
|
||||
@ -146,6 +160,10 @@ pub fn is_canonical_shape(shape: &NormalizedDevShape) -> bool {
|
||||
// Phase 46: Add P2-Mid patterns
|
||||
| JsonparserAtoiReal
|
||||
| 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.
|
||||
pub fn is_p2_core_capability(cap: &ShapeCapability) -> bool {
|
||||
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
|
||||
@ -398,12 +419,34 @@ mod detectors {
|
||||
.iter()
|
||||
.any(|inst| matches!(inst, JoinInst::Call { k_next: None, .. }));
|
||||
|
||||
// P3 minimal has 2-4 params (i, sum, possibly n)
|
||||
let reasonable_param_count = (2..=4).contains(&loop_step.params.len());
|
||||
// P3 minimal/multi/json: typically 2-6 params (i + carriers + len/host)
|
||||
let reasonable_param_count = (2..=6).contains(&loop_step.params.len());
|
||||
|
||||
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
|
||||
pub(crate) fn is_pattern4_continue_minimal(module: &JoinModule) -> bool {
|
||||
// Structure-based detection (avoid name-based heuristics)
|
||||
|
||||
Reference in New Issue
Block a user