use vyre_debug::find_dangling_refs;
use vyre_debug::fixtures::loop_carry_smoke;
use vyre_lower::{KernelBody, KernelOp, KernelOpKind, LiteralValue};
#[test]
fn find_dangling_refs_clean_program_returns_empty() {
let prog = loop_carry_smoke();
let desc = vyre_lower::lower(&prog).unwrap();
let danglings = find_dangling_refs(&desc);
assert!(danglings.is_empty());
}
#[test]
fn find_dangling_refs_handcrafted_descriptor_finds_known_break() {
let mut desc = vyre_lower::lower(&loop_carry_smoke()).unwrap();
let id_in_child = 999;
let mut child_body = KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
};
child_body.literals.push(LiteralValue::U32(42));
child_body.ops.push(KernelOp {
result: Some(id_in_child),
kind: KernelOpKind::Literal,
operands: vec![0],
});
let parent_op_ref = KernelOp {
result: None,
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add), operands: vec![id_in_child, 0],
};
let child_body_idx = desc.body.child_bodies.len() as u32;
desc.body.child_bodies.push(child_body);
desc.body.ops.push(parent_op_ref);
desc.body.ops.push(KernelOp {
result: None,
kind: KernelOpKind::StructuredIfThen,
operands: vec![0, child_body_idx], });
let danglings = find_dangling_refs(&desc);
assert_eq!(danglings.len(), 1);
assert_eq!(danglings[0].ref_id, id_in_child);
}
#[test]
fn find_dangling_refs_matches_verifier_verdict() {
let mut desc = vyre_lower::lower(&loop_carry_smoke()).unwrap();
let id_in_child = 999;
let mut child_body = KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
};
child_body.literals.push(LiteralValue::U32(42));
child_body.ops.push(KernelOp {
result: Some(id_in_child),
kind: KernelOpKind::Literal,
operands: vec![0],
});
let parent_op_ref = KernelOp {
result: None,
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add),
operands: vec![id_in_child, id_in_child],
};
let child_body_idx = desc.body.child_bodies.len() as u32;
desc.body.child_bodies.push(child_body);
desc.body.ops.push(parent_op_ref);
desc.body.ops.push(KernelOp {
result: None,
kind: KernelOpKind::StructuredIfThen,
operands: vec![0, child_body_idx],
});
let danglings = find_dangling_refs(&desc);
let verify_errs = vyre_lower::verify::verify(&desc).unwrap_err();
let verify_dangling_ids: Vec<u32> = verify_errs
.iter()
.filter_map(|e| {
if let vyre_lower::VerifyErrorKind::DanglingResultRef { ref_id, .. } = &e.kind {
Some(*ref_id)
} else {
None
}
})
.collect();
assert!(verify_dangling_ids.contains(&id_in_child));
assert_eq!(danglings[0].ref_id, id_in_child);
}
#[test]
fn find_dangling_refs_handles_deep_nesting_six_levels() {
let mut desc = vyre_lower::lower(&loop_carry_smoke()).unwrap();
let mut level6 = KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
};
level6.literals.push(LiteralValue::U32(42));
level6.ops.push(KernelOp {
result: Some(999),
kind: KernelOpKind::Literal,
operands: vec![0],
});
let mut level5 = KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
};
level5.child_bodies.push(level6);
level5.ops.push(KernelOp {
result: None,
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add),
operands: vec![999, 0],
});
level5.ops.push(KernelOp {
result: None,
kind: KernelOpKind::StructuredIfThen,
operands: vec![0, 0],
});
let mut current_body = level5;
for _ in 1..5 {
let mut parent = KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
};
parent.child_bodies.push(current_body);
parent.ops.push(KernelOp {
result: None,
kind: KernelOpKind::StructuredIfThen,
operands: vec![0, 0],
});
current_body = parent;
}
let child_body_idx = desc.body.child_bodies.len() as u32;
desc.body.child_bodies.push(current_body);
desc.body.ops.push(KernelOp {
result: None,
kind: KernelOpKind::StructuredIfThen,
operands: vec![0, child_body_idx],
});
let danglings = find_dangling_refs(&desc);
assert_eq!(danglings.len(), 1);
assert_eq!(danglings[0].ref_id, 999);
}
#[test]
fn find_dangling_refs_does_not_flag_completed_child_results() {
let mut desc = vyre_lower::lower(&loop_carry_smoke()).unwrap();
let id_in_child = 999;
let mut child_body = KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
};
child_body.literals.push(LiteralValue::U32(42));
child_body.ops.push(KernelOp {
result: Some(id_in_child),
kind: KernelOpKind::Literal,
operands: vec![0],
});
let parent_op_ref = KernelOp {
result: None,
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add), operands: vec![id_in_child, id_in_child],
};
let child_body_idx = desc.body.child_bodies.len() as u32;
desc.body.child_bodies.push(child_body);
desc.body.ops.push(KernelOp {
result: None,
kind: KernelOpKind::StructuredIfThen,
operands: vec![0, child_body_idx],
});
desc.body.ops.push(parent_op_ref);
desc.body.ops.pop(); let danglings = find_dangling_refs(&desc);
assert!(danglings.is_empty());
}