2025-11-18 06:39:45 +09:00
|
|
|
/*!
|
|
|
|
|
* Test for MIR locals SSA form with Copy instructions
|
|
|
|
|
*
|
|
|
|
|
* This test verifies that local variable declarations emit Copy instructions
|
|
|
|
|
* to establish proper SSA form.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use crate::ast::ASTNode;
|
|
|
|
|
use crate::mir::printer::MirPrinter;
|
2025-12-08 23:43:26 +09:00
|
|
|
use crate::mir::MirCompiler;
|
2025-11-18 06:39:45 +09:00
|
|
|
use crate::parser::NyashParser;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn mir_locals_copy_instructions_emitted() {
|
2025-12-02 12:36:28 +09:00
|
|
|
std::env::set_var("NYASH_FEATURES", "stage3");
|
2025-11-18 06:39:45 +09:00
|
|
|
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
|
|
|
|
|
|
|
|
|
let src = r#"
|
|
|
|
|
static box TestLocals {
|
|
|
|
|
main() {
|
|
|
|
|
local a = 1
|
|
|
|
|
local b = 2
|
|
|
|
|
local c = new ArrayBox()
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#;
|
|
|
|
|
|
|
|
|
|
eprintln!("=== Parsing source ===");
|
|
|
|
|
let ast: ASTNode = NyashParser::parse_from_string(src).expect("parse ok");
|
|
|
|
|
|
|
|
|
|
eprintln!("=== AST Debug ===");
|
|
|
|
|
eprintln!("{:#?}", ast);
|
|
|
|
|
|
|
|
|
|
eprintln!("=== Compiling to MIR ===");
|
|
|
|
|
let mut mc = MirCompiler::with_options(false);
|
|
|
|
|
let cr = mc.compile(ast).expect("compile");
|
|
|
|
|
|
|
|
|
|
let printer = MirPrinter::verbose();
|
|
|
|
|
let mir_output = printer.print_module(&cr.module);
|
|
|
|
|
|
|
|
|
|
eprintln!("=== MIR Dump ===");
|
|
|
|
|
eprintln!("{}", mir_output);
|
|
|
|
|
|
|
|
|
|
// Check if Copy instructions are present
|
|
|
|
|
let has_copy = mir_output.contains("copy");
|
|
|
|
|
eprintln!("=== Copy instruction check: {} ===", has_copy);
|
|
|
|
|
|
|
|
|
|
// Count the number of "copy" occurrences
|
|
|
|
|
let copy_count = mir_output.matches("copy").count();
|
|
|
|
|
eprintln!("=== Number of copy instructions: {} ===", copy_count);
|
|
|
|
|
|
|
|
|
|
// Check for SSA violations (multiple definitions of same register)
|
|
|
|
|
let lines: Vec<&str> = mir_output.lines().collect();
|
|
|
|
|
let mut defined_regs = std::collections::HashSet::new();
|
|
|
|
|
let mut violations = Vec::new();
|
|
|
|
|
|
|
|
|
|
for line in &lines {
|
|
|
|
|
// Look for register definitions: %N =
|
|
|
|
|
if let Some(pos) = line.find('%') {
|
|
|
|
|
if let Some(eq_pos) = line.find('=') {
|
|
|
|
|
if eq_pos > pos {
|
|
|
|
|
let reg_part = &line[pos..eq_pos].trim();
|
|
|
|
|
if let Some(space_pos) = reg_part.find(' ') {
|
|
|
|
|
let reg = ®_part[..space_pos].trim();
|
|
|
|
|
if !defined_regs.insert(reg.to_string()) {
|
|
|
|
|
violations.push(format!("Register {} defined multiple times", reg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !violations.is_empty() {
|
|
|
|
|
eprintln!("=== SSA Violations Found ===");
|
|
|
|
|
for v in &violations {
|
|
|
|
|
eprintln!(" {}", v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Assert Copy instructions are present
|
2025-11-21 06:25:17 +09:00
|
|
|
assert!(
|
|
|
|
|
has_copy,
|
|
|
|
|
"MIR should contain Copy instructions for local variable initializations"
|
|
|
|
|
);
|
2025-11-18 06:39:45 +09:00
|
|
|
|
|
|
|
|
// Assert no SSA violations
|
2025-11-21 06:25:17 +09:00
|
|
|
assert!(
|
|
|
|
|
violations.is_empty(),
|
|
|
|
|
"MIR should not have SSA violations: {:?}",
|
|
|
|
|
violations
|
|
|
|
|
);
|
2025-11-18 06:39:45 +09:00
|
|
|
|
|
|
|
|
// We expect at least 3 copy instructions (for a, b, c)
|
2025-11-21 06:25:17 +09:00
|
|
|
assert!(
|
|
|
|
|
copy_count >= 3,
|
|
|
|
|
"Expected at least 3 copy instructions, found {}",
|
|
|
|
|
copy_count
|
|
|
|
|
);
|
2025-11-18 06:39:45 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn mir_locals_uninitialized() {
|
2025-12-02 12:36:28 +09:00
|
|
|
std::env::set_var("NYASH_FEATURES", "stage3");
|
2025-11-18 06:39:45 +09:00
|
|
|
std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1");
|
|
|
|
|
|
|
|
|
|
let src = r#"
|
|
|
|
|
static box TestUninit {
|
|
|
|
|
main() {
|
|
|
|
|
local x
|
|
|
|
|
local y
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"#;
|
|
|
|
|
|
|
|
|
|
let ast: ASTNode = NyashParser::parse_from_string(src).expect("parse ok");
|
|
|
|
|
let mut mc = MirCompiler::with_options(false);
|
|
|
|
|
let cr = mc.compile(ast).expect("compile");
|
|
|
|
|
|
|
|
|
|
let printer = MirPrinter::verbose();
|
|
|
|
|
let mir_output = printer.print_module(&cr.module);
|
|
|
|
|
|
|
|
|
|
eprintln!("=== MIR for uninitialized locals ===");
|
|
|
|
|
eprintln!("{}", mir_output);
|
|
|
|
|
|
|
|
|
|
// Uninitialized locals should have void constants, not copy
|
2025-11-21 06:25:17 +09:00
|
|
|
assert!(
|
|
|
|
|
mir_output.contains("const void"),
|
|
|
|
|
"Uninitialized locals should have void constants"
|
|
|
|
|
);
|
2025-11-18 06:39:45 +09:00
|
|
|
}
|