use synth_backend::{
ArmEncoder, ElfBuilder, ElfSectionType, Section, SectionFlags, Symbol, SymbolBinding,
SymbolType,
};
use synth_synthesis::{InstructionSelector, RuleDatabase, WasmOp};
#[test]
fn test_end_to_end_pipeline() {
let wasm_ops = vec![WasmOp::I32Const(42), WasmOp::I32Const(10), WasmOp::I32Add];
let db = RuleDatabase::with_standard_rules();
let mut selector = InstructionSelector::new(db.rules().to_vec());
let arm_instrs = selector
.select(&wasm_ops)
.expect("Failed to select instructions");
assert!(!arm_instrs.is_empty());
let encoder = ArmEncoder::new_arm32();
let mut code = Vec::new();
for arm_instr in &arm_instrs {
let encoded = encoder
.encode(&arm_instr.op)
.expect("Failed to encode instruction");
code.extend_from_slice(&encoded);
}
assert!(!code.is_empty());
assert_eq!(code.len() % 4, 0);
let mut elf_builder = ElfBuilder::new_arm32().with_entry(0x8000);
let text_section = Section::new(".text", ElfSectionType::ProgBits)
.with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
.with_addr(0x8000)
.with_align(4)
.with_data(code.clone());
elf_builder.add_section(text_section);
let main_sym = Symbol::new("_start")
.with_value(0x8000)
.with_size(code.len() as u32)
.with_binding(SymbolBinding::Global)
.with_type(SymbolType::Func)
.with_section(4);
elf_builder.add_symbol(main_sym);
let elf_data = elf_builder.build().expect("Failed to build ELF");
assert!(elf_data.len() > 52); assert_eq!(&elf_data[0..4], &[0x7f, b'E', b'L', b'F']); assert_eq!(elf_data[4], 1); assert_eq!(elf_data[5], 1);
let entry_bytes = &elf_data[24..28];
let entry = u32::from_le_bytes([
entry_bytes[0],
entry_bytes[1],
entry_bytes[2],
entry_bytes[3],
]);
assert_eq!(entry, 0x8001);
println!("✓ End-to-end pipeline test passed!");
println!(" - Generated {} WASM ops", wasm_ops.len());
println!(" - Selected {} ARM instructions", arm_instrs.len());
println!(" - Encoded {} bytes of code", code.len());
println!(" - Built {} byte ELF file", elf_data.len());
}
#[test]
fn test_wasm_arithmetic_to_elf() {
let wasm_ops = vec![
WasmOp::I32Const(5),
WasmOp::I32Const(3),
WasmOp::I32Mul,
WasmOp::I32Const(2),
WasmOp::I32Add,
];
let db = RuleDatabase::with_standard_rules();
let mut selector = InstructionSelector::new(db.rules().to_vec());
let arm_instrs = selector.select(&wasm_ops).expect("Failed to select");
let encoder = ArmEncoder::new_arm32();
let mut code = Vec::new();
for instr in &arm_instrs {
let encoded = encoder.encode(&instr.op).expect("Failed to encode");
code.extend_from_slice(&encoded);
}
let mut elf_builder = ElfBuilder::new_arm32().with_entry(0x8000);
let text = Section::new(".text", ElfSectionType::ProgBits)
.with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
.with_addr(0x8000)
.with_align(4)
.with_data(code);
elf_builder.add_section(text);
let elf_data = elf_builder.build().expect("Failed to build");
assert!(elf_data.len() > 52);
assert_eq!(&elf_data[0..4], &[0x7f, b'E', b'L', b'F']);
}
#[test]
fn test_wasm_memory_operations_to_elf() {
let wasm_ops = vec![
WasmOp::I32Const(100),
WasmOp::I32Store {
offset: 0,
align: 4,
},
WasmOp::I32Load {
offset: 0,
align: 4,
},
];
let db = RuleDatabase::with_standard_rules();
let mut selector = InstructionSelector::new(db.rules().to_vec());
let arm_instrs = selector.select(&wasm_ops).expect("Failed to select");
let encoder = ArmEncoder::new_arm32();
let mut code = Vec::new();
for instr in &arm_instrs {
let encoded = encoder.encode(&instr.op).expect("Failed to encode");
code.extend_from_slice(&encoded);
}
assert!(!code.is_empty());
assert_eq!(code.len() % 4, 0);
let mut elf_builder = ElfBuilder::new_arm32().with_entry(0x8000);
let text = Section::new(".text", ElfSectionType::ProgBits)
.with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
.with_addr(0x8000)
.with_align(4)
.with_data(code.clone());
elf_builder.add_section(text);
let data = Section::new(".data", ElfSectionType::ProgBits)
.with_flags(SectionFlags::ALLOC | SectionFlags::WRITE)
.with_addr(0x8100)
.with_align(4)
.with_data(vec![0u8; 64]);
elf_builder.add_section(data);
let elf_data = elf_builder.build().expect("Failed to build");
assert!(elf_data.len() > 52);
assert_eq!(&elf_data[0..4], &[0x7f, b'E', b'L', b'F']);
println!("✓ Memory operations test passed!");
println!(" - Generated {} bytes of code", code.len());
println!(" - ELF size: {} bytes", elf_data.len());
}
#[test]
fn test_complete_function_to_elf() {
let wasm_ops = vec![
WasmOp::LocalGet(0), WasmOp::LocalGet(1), WasmOp::I32Add, ];
let db = RuleDatabase::with_standard_rules();
let mut selector = InstructionSelector::new(db.rules().to_vec());
let arm_instrs = selector.select(&wasm_ops).expect("Failed to select");
let encoder = ArmEncoder::new_arm32();
let mut code = Vec::new();
for instr in &arm_instrs {
let encoded = encoder.encode(&instr.op).expect("Failed to encode");
code.extend_from_slice(&encoded);
}
let mut elf_builder = ElfBuilder::new_arm32().with_entry(0x8000);
let text = Section::new(".text", ElfSectionType::ProgBits)
.with_flags(SectionFlags::ALLOC | SectionFlags::EXEC)
.with_addr(0x8000)
.with_align(4)
.with_data(code.clone());
elf_builder.add_section(text);
let add_func = Symbol::new("add")
.with_value(0x8000)
.with_size(code.len() as u32)
.with_binding(SymbolBinding::Global)
.with_type(SymbolType::Func)
.with_section(4);
elf_builder.add_symbol(add_func);
let elf_data = elf_builder.build().expect("Failed to build");
assert!(elf_data.len() > 52);
assert_eq!(&elf_data[0..4], &[0x7f, b'E', b'L', b'F']);
println!("✓ Complete function test passed!");
println!(" - Function 'add' compiled successfully");
println!(" - Code size: {} bytes", code.len());
}
#[test]
fn test_selector_stats() {
let wasm_ops = vec![
WasmOp::I32Const(1),
WasmOp::I32Const(2),
WasmOp::I32Add,
WasmOp::I32Const(3),
WasmOp::I32Mul,
];
let db = RuleDatabase::with_standard_rules();
let mut selector = InstructionSelector::new(db.rules().to_vec());
let _arm_instrs = selector.select(&wasm_ops).expect("Failed to select");
let stats = selector.get_stats();
println!("Selection stats:");
println!(" - Registers used: {}", stats.total_registers_used);
println!(" - Variables mapped: {}", stats.variables_mapped);
assert!(stats.total_registers_used > 0);
}