loopform(hints): detect up to 2 assigned vars in loop body (no break/continue) and emit LoopCarrier hint; add smoke for two-vars case
This commit is contained in:
@ -182,6 +182,10 @@ impl MirBuilder {
|
|||||||
pub(crate) fn hint_scope_leave(&mut self, id: u32) { self.hint_sink.scope_leave(id); }
|
pub(crate) fn hint_scope_leave(&mut self, id: u32) { self.hint_sink.scope_leave(id); }
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) { self.hint_sink.join_result(var.into()); }
|
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) { self.hint_sink.join_result(var.into()); }
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn hint_loop_carrier<S: Into<String>>(&mut self, vars: impl IntoIterator<Item = S>) {
|
||||||
|
self.hint_sink.loop_carrier(vars.into_iter().map(|s| s.into()).collect::<Vec<_>>());
|
||||||
|
}
|
||||||
|
|
||||||
// moved to builder_calls.rs: lower_method_as_function
|
// moved to builder_calls.rs: lower_method_as_function
|
||||||
|
|
||||||
|
|||||||
@ -143,6 +143,39 @@ impl<'a> LoopBuilder<'a> {
|
|||||||
condition: ASTNode,
|
condition: ASTNode,
|
||||||
body: Vec<ASTNode>,
|
body: Vec<ASTNode>,
|
||||||
) -> Result<ValueId, String> {
|
) -> Result<ValueId, String> {
|
||||||
|
// Pre-scan body for simple carrier pattern (up to 2 assigned variables, no break/continue)
|
||||||
|
fn collect_assigns(n: &ASTNode, vars: &mut Vec<String>, has_ctrl: &mut bool) {
|
||||||
|
match n {
|
||||||
|
ASTNode::Assignment { target, .. } => {
|
||||||
|
if let ASTNode::Variable { name, .. } = target.as_ref() {
|
||||||
|
if !vars.iter().any(|v| v == name) {
|
||||||
|
vars.push(name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASTNode::Break { .. } | ASTNode::Continue { .. } => { *has_ctrl = true; }
|
||||||
|
ASTNode::If { then_body, else_body, .. } => {
|
||||||
|
let tp = ASTNode::Program { statements: then_body.clone(), span: crate::ast::Span::unknown() };
|
||||||
|
collect_assigns(&tp, vars, has_ctrl);
|
||||||
|
if let Some(eb) = else_body {
|
||||||
|
let ep = ASTNode::Program { statements: eb.clone(), span: crate::ast::Span::unknown() };
|
||||||
|
collect_assigns(&ep, vars, has_ctrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASTNode::Program { statements, .. } => {
|
||||||
|
for s in statements { collect_assigns(s, vars, has_ctrl); }
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut assigned_vars: Vec<String> = Vec::new();
|
||||||
|
let mut has_ctrl = false;
|
||||||
|
for st in &body { collect_assigns(st, &mut assigned_vars, &mut has_ctrl); }
|
||||||
|
if !has_ctrl && !assigned_vars.is_empty() && assigned_vars.len() <= 2 {
|
||||||
|
// Emit a carrier hint (no-op sink by default; visible with NYASH_MIR_TRACE_HINTS=1)
|
||||||
|
self.parent_builder.hint_loop_carrier(assigned_vars.clone());
|
||||||
|
}
|
||||||
|
|
||||||
// 1. ブロックの準備
|
// 1. ブロックの準備
|
||||||
let preheader_id = self.current_block()?;
|
let preheader_id = self.current_block()?;
|
||||||
let (header_id, body_id, after_loop_id) =
|
let (header_id, body_id, after_loop_id) =
|
||||||
|
|||||||
25
tools/test/smoke/mir/hints_loop_carrier_two_vars_smoke.sh
Normal file
25
tools/test/smoke/mir/hints_loop_carrier_two_vars_smoke.sh
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
root=$(cd "$(dirname "$0")"/../../../.. && pwd)
|
||||||
|
bin="$root/target/release/nyash"
|
||||||
|
src="apps/tests/macro/loopform/two_vars.nyash"
|
||||||
|
|
||||||
|
if [ ! -x "$bin" ]; then
|
||||||
|
echo "nyash binary not found at $bin; build first (cargo build --release)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export NYASH_MIR_TRACE_HINTS=1
|
||||||
|
|
||||||
|
out=$({ "$bin" --backend vm "$src" 1>/dev/null; } 2>&1 || true)
|
||||||
|
|
||||||
|
# Check the LoopCarrier hint contains both variable names (order-agnostic)
|
||||||
|
echo "$out" | rg -q "\[mir\]\[hint\] LoopCarrier\((i,sum|sum,i)\)" || {
|
||||||
|
echo "[FAIL] missing LoopCarrier(i,sum) hint" >&2
|
||||||
|
printf '%s\n' "$out" | tail -n 80 >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "[OK] MIR hints LoopCarrier(two vars) trace smoke passed"
|
||||||
|
|
||||||
Reference in New Issue
Block a user