Add dev normalized→MIR bridge for P1/P2 mini and JP _atoi
This commit is contained in:
@ -10,7 +10,7 @@ use crate::mir::join_ir::{
|
||||
JoinModule, MirLikeInst, UnaryOp,
|
||||
};
|
||||
use crate::mir::ValueId;
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
|
||||
@ -90,6 +90,7 @@ pub enum JpOp {
|
||||
BinOp(BinOpKind),
|
||||
Unary(UnaryOp),
|
||||
Compare(CompareOp),
|
||||
BoxCall { box_name: String, method: String },
|
||||
}
|
||||
|
||||
/// Normalized JoinIR モジュール(テスト専用)。
|
||||
@ -180,7 +181,10 @@ pub fn normalized_pattern1_to_structured(norm: &NormalizedModule) -> JoinModule
|
||||
let mut module = JoinModule::new();
|
||||
|
||||
for (jp_id, jp_fn) in &norm.functions {
|
||||
let params: Vec<ValueId> = env_layout
|
||||
let params: Vec<ValueId> = jp_fn
|
||||
.env_layout
|
||||
.and_then(|id| norm.env_layouts.iter().find(|layout| layout.id == id))
|
||||
.unwrap_or(env_layout)
|
||||
.fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
@ -196,6 +200,14 @@ pub fn normalized_pattern1_to_structured(norm: &NormalizedModule) -> JoinModule
|
||||
dst: *dst,
|
||||
value: v.clone(),
|
||||
})),
|
||||
JpOp::BoxCall { box_name, method } => {
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(*dst),
|
||||
box_name: box_name.clone(),
|
||||
method: method.clone(),
|
||||
args: args.clone(),
|
||||
}))
|
||||
}
|
||||
JpOp::BinOp(op) => func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: *dst,
|
||||
op: *op,
|
||||
@ -282,9 +294,20 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
||||
"normalize_pattern2_minimal: expected 3 functions (entry/loop_step/k_exit) but got {}",
|
||||
func_count
|
||||
);
|
||||
let param_max = {
|
||||
let mut max = 3;
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
{
|
||||
if shape_guard::is_jsonparser_atoi_mini(structured) {
|
||||
max = 8;
|
||||
}
|
||||
}
|
||||
max
|
||||
};
|
||||
assert!(
|
||||
(1..=3).contains(&loop_func.params.len()),
|
||||
"normalize_pattern2_minimal: expected 1..=3 params (loop var + optional acc + optional host)"
|
||||
(1..=param_max).contains(&loop_func.params.len()),
|
||||
"normalize_pattern2_minimal: expected 1..={} params (loop var + carriers + optional host)",
|
||||
param_max
|
||||
);
|
||||
|
||||
let jump_conds = loop_func
|
||||
@ -302,27 +325,28 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
||||
"normalize_pattern2_minimal: expected at least one conditional jump and one tail call"
|
||||
);
|
||||
|
||||
let env_layout = EnvLayout {
|
||||
id: 0,
|
||||
fields: loop_func
|
||||
.params
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, vid)| EnvField {
|
||||
name: format!("field{}", idx),
|
||||
ty: None,
|
||||
value_id: Some(*vid),
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let mut functions = BTreeMap::new();
|
||||
let mut env_layouts = Vec::new();
|
||||
|
||||
for (fid, func) in &structured.functions {
|
||||
let env_layout_id = if func.params.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(env_layout.id)
|
||||
let id = env_layouts.len() as u32;
|
||||
env_layouts.push(EnvLayout {
|
||||
id,
|
||||
fields: func
|
||||
.params
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, vid)| EnvField {
|
||||
name: format!("field{}", idx),
|
||||
ty: None,
|
||||
value_id: Some(*vid),
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
Some(id)
|
||||
};
|
||||
|
||||
let mut body = Vec::new();
|
||||
@ -333,6 +357,23 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
||||
op: JpOp::Const(value.clone()),
|
||||
args: vec![],
|
||||
}),
|
||||
JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst,
|
||||
box_name,
|
||||
method,
|
||||
args,
|
||||
}) => {
|
||||
if let Some(dst) = dst {
|
||||
body.push(JpInst::Let {
|
||||
dst: *dst,
|
||||
op: JpOp::BoxCall {
|
||||
box_name: box_name.clone(),
|
||||
method: method.clone(),
|
||||
},
|
||||
args: args.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
JoinInst::Compute(MirLikeInst::BinOp { dst, op, lhs, rhs }) => {
|
||||
body.push(JpInst::Let {
|
||||
dst: *dst,
|
||||
@ -377,6 +418,25 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
||||
});
|
||||
}
|
||||
}
|
||||
JoinInst::MethodCall {
|
||||
dst,
|
||||
receiver,
|
||||
method,
|
||||
args,
|
||||
..
|
||||
} => {
|
||||
let mut call_args = Vec::with_capacity(args.len() + 1);
|
||||
call_args.push(*receiver);
|
||||
call_args.extend(args.iter().copied());
|
||||
body.push(JpInst::Let {
|
||||
dst: *dst,
|
||||
op: JpOp::BoxCall {
|
||||
box_name: "unknown".to_string(),
|
||||
method: method.clone(),
|
||||
},
|
||||
args: call_args,
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
// Ret / other instructions are ignored in this minimal prototype
|
||||
}
|
||||
@ -398,14 +458,14 @@ pub fn normalize_pattern2_minimal(structured: &JoinModule) -> NormalizedModule {
|
||||
let norm = NormalizedModule {
|
||||
functions,
|
||||
entry: structured.entry.map(|e| JpFuncId(e.0)),
|
||||
env_layouts: vec![env_layout],
|
||||
env_layouts,
|
||||
phase: JoinIrPhase::Normalized,
|
||||
structured_backup: Some(structured.clone()),
|
||||
};
|
||||
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
{
|
||||
verify_normalized_pattern2(&norm).expect("normalized Pattern2 verifier");
|
||||
verify_normalized_pattern2(&norm, param_max).expect("normalized Pattern2 verifier");
|
||||
}
|
||||
|
||||
norm
|
||||
@ -417,14 +477,12 @@ pub fn normalized_pattern2_to_structured(norm: &NormalizedModule) -> JoinModule
|
||||
return backup;
|
||||
}
|
||||
|
||||
let env_layout = norm.env_layouts.get(0);
|
||||
|
||||
let mut module = JoinModule::new();
|
||||
|
||||
for (jp_id, jp_fn) in &norm.functions {
|
||||
let params: Vec<ValueId> = jp_fn
|
||||
.env_layout
|
||||
.and_then(|id| env_layout.filter(|layout| layout.id == id))
|
||||
.and_then(|id| norm.env_layouts.iter().find(|layout| layout.id == id))
|
||||
.map(|layout| {
|
||||
layout
|
||||
.fields
|
||||
@ -444,6 +502,14 @@ pub fn normalized_pattern2_to_structured(norm: &NormalizedModule) -> JoinModule
|
||||
dst: *dst,
|
||||
value: v.clone(),
|
||||
})),
|
||||
JpOp::BoxCall { box_name, method } => {
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(*dst),
|
||||
box_name: box_name.clone(),
|
||||
method: method.clone(),
|
||||
args: args.clone(),
|
||||
}))
|
||||
}
|
||||
JpOp::BinOp(op) => func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: *dst,
|
||||
op: *op,
|
||||
@ -505,23 +571,32 @@ pub fn normalized_pattern2_to_structured(norm: &NormalizedModule) -> JoinModule
|
||||
}
|
||||
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn verify_normalized_pattern2(module: &NormalizedModule) -> Result<(), String> {
|
||||
fn verify_normalized_pattern2(
|
||||
module: &NormalizedModule,
|
||||
max_env_fields: usize,
|
||||
) -> Result<(), String> {
|
||||
if module.phase != JoinIrPhase::Normalized {
|
||||
return Err("Normalized verifier (Pattern2): phase must be Normalized".to_string());
|
||||
}
|
||||
|
||||
let field_count = module.env_layouts.get(0).map(|e| e.fields.len());
|
||||
|
||||
if let Some(field_count) = field_count {
|
||||
if !(1..=3).contains(&field_count) {
|
||||
let mut layout_sizes: HashMap<u32, usize> = HashMap::new();
|
||||
for layout in &module.env_layouts {
|
||||
let size = layout.fields.len();
|
||||
if !(1..=max_env_fields).contains(&size) {
|
||||
return Err(format!(
|
||||
"Normalized Pattern2 expects 1..=3 env fields, got {}",
|
||||
field_count
|
||||
"Normalized Pattern2 expects 1..={} env fields, got {}",
|
||||
max_env_fields, size
|
||||
));
|
||||
}
|
||||
layout_sizes.insert(layout.id, size);
|
||||
}
|
||||
|
||||
for func in module.functions.values() {
|
||||
let expected_env_len = func
|
||||
.env_layout
|
||||
.and_then(|id| layout_sizes.get(&id))
|
||||
.copied();
|
||||
|
||||
for inst in &func.body {
|
||||
match inst {
|
||||
JpInst::Let { .. }
|
||||
@ -536,17 +611,11 @@ fn verify_normalized_pattern2(module: &NormalizedModule) -> Result<(), String> {
|
||||
JpInst::TailCallFn { env, .. }
|
||||
| JpInst::TailCallKont { env, .. }
|
||||
| JpInst::If { env, .. } => {
|
||||
if env.is_empty() {
|
||||
return Err("Normalized Pattern2 env must not be empty".to_string());
|
||||
}
|
||||
if let Some(expected) = field_count {
|
||||
if env.len() > expected {
|
||||
return Err(format!(
|
||||
"Normalized Pattern2 env size exceeds layout: env={}, layout={}",
|
||||
env.len(),
|
||||
expected
|
||||
));
|
||||
if let Some(expected) = expected_env_len {
|
||||
if env.is_empty() {
|
||||
return Err("Normalized Pattern2 env must not be empty".to_string());
|
||||
}
|
||||
let _ = expected;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@ -615,6 +684,23 @@ pub fn normalize_pattern1_minimal(structured: &JoinModule) -> NormalizedModule {
|
||||
op: JpOp::Const(value.clone()),
|
||||
args: vec![],
|
||||
}),
|
||||
JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst,
|
||||
box_name,
|
||||
method,
|
||||
args,
|
||||
}) => {
|
||||
if let Some(dst) = dst {
|
||||
jp_body.push(JpInst::Let {
|
||||
dst: *dst,
|
||||
op: JpOp::BoxCall {
|
||||
box_name: box_name.clone(),
|
||||
method: method.clone(),
|
||||
},
|
||||
args: args.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
JoinInst::Compute(MirLikeInst::BinOp { dst, op, lhs, rhs }) => {
|
||||
jp_body.push(JpInst::Let {
|
||||
dst: *dst,
|
||||
@ -737,12 +823,12 @@ pub(crate) fn normalized_dev_roundtrip_structured(
|
||||
let norm = normalize_pattern1_minimal(module);
|
||||
normalized_pattern1_to_structured(&norm)
|
||||
})),
|
||||
NormalizedDevShape::Pattern2Mini | NormalizedDevShape::JsonparserSkipWsMini => {
|
||||
catch_unwind(AssertUnwindSafe(|| {
|
||||
let norm = normalize_pattern2_minimal(module);
|
||||
normalized_pattern2_to_structured(&norm)
|
||||
}))
|
||||
}
|
||||
NormalizedDevShape::Pattern2Mini
|
||||
| NormalizedDevShape::JsonparserSkipWsMini
|
||||
| NormalizedDevShape::JsonparserAtoiMini => catch_unwind(AssertUnwindSafe(|| {
|
||||
let norm = normalize_pattern2_minimal(module);
|
||||
normalized_pattern2_to_structured(&norm)
|
||||
})),
|
||||
};
|
||||
|
||||
match attempt {
|
||||
|
||||
Reference in New Issue
Block a user