Phase 33 NORM canon test: enforce normalized dev route for P1/P2/JP mini
This commit is contained in:
114
src/mir/join_ir/normalized/fixtures.rs
Normal file
114
src/mir/join_ir/normalized/fixtures.rs
Normal file
@ -0,0 +1,114 @@
|
||||
#![cfg(feature = "normalized_dev")]
|
||||
|
||||
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
|
||||
use crate::mir::join_ir::frontend::AstToJoinIrLowerer;
|
||||
use crate::mir::join_ir::lowering::condition_env::ConditionEnv;
|
||||
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
|
||||
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::JoinModule;
|
||||
use crate::mir::{BasicBlockId, ValueId};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
/// Structured Pattern2 (joinir_min_loop 相当) をテスト用に生成するヘルパー。
|
||||
pub fn build_pattern2_minimal_structured() -> JoinModule {
|
||||
let loop_cond = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::Less,
|
||||
left: Box::new(ASTNode::Variable {
|
||||
name: "i".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(3),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
let break_cond = ASTNode::BinaryOp {
|
||||
operator: BinaryOperator::GreaterEqual,
|
||||
left: Box::new(ASTNode::Variable {
|
||||
name: "i".to_string(),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
right: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(2),
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
let mut scope = LoopScopeShape {
|
||||
header: BasicBlockId(0),
|
||||
body: BasicBlockId(1),
|
||||
latch: BasicBlockId(2),
|
||||
exit: BasicBlockId(3),
|
||||
pinned: BTreeSet::new(),
|
||||
carriers: BTreeSet::new(),
|
||||
body_locals: BTreeSet::new(),
|
||||
exit_live: BTreeSet::new(),
|
||||
progress_carrier: None,
|
||||
variable_definitions: BTreeMap::new(),
|
||||
};
|
||||
scope.pinned.insert("i".to_string());
|
||||
|
||||
let mut condition_env = ConditionEnv::new();
|
||||
condition_env.insert("i".to_string(), ValueId(100));
|
||||
|
||||
let carrier_info = crate::mir::join_ir::lowering::carrier_info::CarrierInfo {
|
||||
loop_var_name: "i".to_string(),
|
||||
loop_var_id: ValueId(1),
|
||||
carriers: vec![],
|
||||
trim_helper: None,
|
||||
promoted_loopbodylocals: vec![],
|
||||
};
|
||||
|
||||
let carrier_updates: BTreeMap<String, UpdateExpr> = BTreeMap::new();
|
||||
let mut join_value_space = JoinValueSpace::new();
|
||||
|
||||
let (module, _) = lower_loop_with_break_minimal(
|
||||
scope,
|
||||
&loop_cond,
|
||||
&break_cond,
|
||||
&condition_env,
|
||||
&carrier_info,
|
||||
&carrier_updates,
|
||||
&[],
|
||||
None,
|
||||
&mut join_value_space,
|
||||
)
|
||||
.expect("pattern2 minimal lowering should succeed");
|
||||
|
||||
module
|
||||
}
|
||||
|
||||
/// Pattern2 ブレークループ(fixture ベース)を Structured で組み立てるヘルパー。
|
||||
///
|
||||
/// Fixture: docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/loop_frontend_break.program.json
|
||||
pub fn build_pattern2_break_fixture_structured() -> JoinModule {
|
||||
const FIXTURE: &str = include_str!(
|
||||
"../../../../docs/private/roadmap2/phases/phase-34-joinir-frontend/fixtures/loop_frontend_break.program.json"
|
||||
);
|
||||
|
||||
let program_json: serde_json::Value =
|
||||
serde_json::from_str(FIXTURE).expect("fixture JSON should be valid");
|
||||
|
||||
let mut lowerer = AstToJoinIrLowerer::new();
|
||||
lowerer.lower_program_json(&program_json)
|
||||
}
|
||||
|
||||
/// JsonParser 由来のミニ P2 ループ(空白スキップ相当)を Structured で組み立てるヘルパー。
|
||||
///
|
||||
/// Fixture: docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_mini.program.json
|
||||
pub fn build_jsonparser_skip_ws_structured_for_normalized_dev() -> JoinModule {
|
||||
const FIXTURE: &str = include_str!(
|
||||
"../../../../docs/private/roadmap2/phases/normalized_dev/fixtures/jsonparser_skip_ws_mini.program.json"
|
||||
);
|
||||
|
||||
let program_json: serde_json::Value =
|
||||
serde_json::from_str(FIXTURE).expect("jsonparser skip_ws fixture should be valid JSON");
|
||||
|
||||
let mut lowerer = AstToJoinIrLowerer::new();
|
||||
lowerer.lower_program_json(&program_json)
|
||||
}
|
||||
68
src/mir/join_ir/normalized/shape_guard.rs
Normal file
68
src/mir/join_ir/normalized/shape_guard.rs
Normal file
@ -0,0 +1,68 @@
|
||||
#![cfg(feature = "normalized_dev")]
|
||||
|
||||
use crate::mir::join_ir::{JoinFuncId, JoinFunction, JoinInst, JoinModule};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum NormalizedDevShape {
|
||||
Pattern1Mini,
|
||||
Pattern2Mini,
|
||||
JsonparserSkipWsMini,
|
||||
}
|
||||
|
||||
pub(crate) fn supported_shapes(module: &JoinModule) -> Vec<NormalizedDevShape> {
|
||||
let mut shapes = Vec::new();
|
||||
if is_jsonparser_skip_ws_mini(module) {
|
||||
shapes.push(NormalizedDevShape::JsonparserSkipWsMini);
|
||||
}
|
||||
if is_pattern2_mini(module) {
|
||||
shapes.push(NormalizedDevShape::Pattern2Mini);
|
||||
}
|
||||
if is_pattern1_mini(module) {
|
||||
shapes.push(NormalizedDevShape::Pattern1Mini);
|
||||
}
|
||||
shapes
|
||||
}
|
||||
|
||||
pub(crate) fn is_pattern1_mini(module: &JoinModule) -> bool {
|
||||
module.is_structured() && find_loop_step(module).is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn is_pattern2_mini(module: &JoinModule) -> bool {
|
||||
if !module.is_structured() || module.functions.len() != 3 {
|
||||
return false;
|
||||
}
|
||||
let loop_func = match find_loop_step(module) {
|
||||
Some(f) => f,
|
||||
None => return false,
|
||||
};
|
||||
if !(1..=3).contains(&loop_func.params.len()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let has_cond_jump = loop_func
|
||||
.body
|
||||
.iter()
|
||||
.any(|inst| matches!(inst, JoinInst::Jump { cond: Some(_), .. }));
|
||||
let has_tail_call = loop_func
|
||||
.body
|
||||
.iter()
|
||||
.any(|inst| matches!(inst, JoinInst::Call { k_next: None, .. }));
|
||||
|
||||
has_cond_jump && has_tail_call
|
||||
}
|
||||
|
||||
pub(crate) fn is_jsonparser_skip_ws_mini(module: &JoinModule) -> bool {
|
||||
is_pattern2_mini(module)
|
||||
&& module
|
||||
.functions
|
||||
.values()
|
||||
.any(|f| f.name == "jsonparser_skip_ws_mini")
|
||||
}
|
||||
|
||||
fn find_loop_step(module: &JoinModule) -> Option<&JoinFunction> {
|
||||
module
|
||||
.functions
|
||||
.values()
|
||||
.find(|f| f.name == "loop_step")
|
||||
.or_else(|| module.functions.get(&JoinFuncId::new(1)))
|
||||
}
|
||||
Reference in New Issue
Block a user