#![cfg(all(feature = "z3-solver", feature = "arm"))]
use synth_synthesis::{ArmOp, Operand2, Pattern, Reg, Replacement, SynthesisRule, WasmOp};
use synth_verify::{
ArmSemantics, ArmState, TranslationValidator, ValidationResult, WasmSemantics, with_z3_context,
};
use z3::ast::{Ast, BV};
fn create_rule(name: &str, wasm_op: WasmOp, arm_op: ArmOp) -> SynthesisRule {
SynthesisRule {
name: name.to_string(),
priority: 0,
pattern: Pattern::WasmInstr(wasm_op),
replacement: Replacement::ArmInstr(arm_op),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 2,
},
}
}
#[test]
fn verify_i32_add() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.add",
WasmOp::I32Add,
ArmOp::Add {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_sub() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.sub",
WasmOp::I32Sub,
ArmOp::Sub {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn verify_i32_mul() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.mul",
WasmOp::I32Mul,
ArmOp::Mul {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn verify_i32_div_s() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.div_s",
WasmOp::I32DivS,
ArmOp::Sdiv {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn verify_i32_div_u() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.div_u",
WasmOp::I32DivU,
ArmOp::Udiv {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn test_remainder_sequences_concrete() {
with_z3_context(|| {
let wasm_encoder = WasmSemantics::new();
let arm_encoder = ArmSemantics::new();
let dividend = BV::from_i64(17, 32);
let divisor = BV::from_i64(5, 32);
let wasm_result =
wasm_encoder.encode_op(&WasmOp::I32RemU, &[dividend.clone(), divisor.clone()]);
assert_eq!(
wasm_result.simplify().as_i64(),
Some(2),
"WASM rem_u(17, 5) = 2"
);
let mut state = ArmState::new_symbolic();
state.set_reg(&Reg::R0, dividend.clone());
state.set_reg(&Reg::R1, divisor.clone());
arm_encoder.encode_op(
&ArmOp::Udiv {
rd: Reg::R2,
rn: Reg::R0,
rm: Reg::R1,
},
&mut state,
);
assert_eq!(
state.get_reg(&Reg::R2).simplify().as_i64(),
Some(3),
"Quotient = 3"
);
arm_encoder.encode_op(
&ArmOp::Mls {
rd: Reg::R0,
rn: Reg::R2,
rm: Reg::R1,
ra: Reg::R0,
},
&mut state,
);
let arm_result = state.get_reg(&Reg::R0);
assert_eq!(
arm_result.simplify().as_i64(),
Some(2),
"ARM rem_u(17, 5) = 2"
);
let neg_dividend = BV::from_i64(-17, 32);
let pos_divisor = BV::from_i64(5, 32);
let wasm_result_signed = wasm_encoder.encode_op(
&WasmOp::I32RemS,
&[neg_dividend.clone(), pos_divisor.clone()],
);
let mut state2 = ArmState::new_symbolic();
state2.set_reg(&Reg::R0, neg_dividend);
state2.set_reg(&Reg::R1, pos_divisor);
arm_encoder.encode_op(
&ArmOp::Sdiv {
rd: Reg::R2,
rn: Reg::R0,
rm: Reg::R1,
},
&mut state2,
);
arm_encoder.encode_op(
&ArmOp::Mls {
rd: Reg::R0,
rn: Reg::R2,
rm: Reg::R1,
ra: Reg::R0,
},
&mut state2,
);
let arm_result_signed = state2.get_reg(&Reg::R0);
assert_eq!(
wasm_result_signed.as_i64(),
arm_result_signed.as_i64(),
"Signed remainder matches"
);
println!("✓ Remainder sequences work correctly with concrete values");
});
}
#[test]
fn verify_i32_rem_s() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.rem_s".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32RemS),
replacement: Replacement::ArmSequence(vec![
ArmOp::Sdiv {
rd: Reg::R2, rn: Reg::R0, rm: Reg::R1, },
ArmOp::Mls {
rd: Reg::R0, rn: Reg::R2, rm: Reg::R1, ra: Reg::R0, },
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 3,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32RemS sequence verified: rem_s(a,b) = a - (a/b)*b");
}
Ok(ValidationResult::Unknown { reason }) => {
println!(
"⚠ I32RemS verification unknown (complex formula): {}",
reason
);
}
other => panic!(
"Expected Verified or Unknown for REM_S sequence, got {:?}",
other
),
}
});
}
#[test]
fn verify_i32_rem_u() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.rem_u".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32RemU),
replacement: Replacement::ArmSequence(vec![
ArmOp::Udiv {
rd: Reg::R2, rn: Reg::R0, rm: Reg::R1, },
ArmOp::Mls {
rd: Reg::R0, rn: Reg::R2, rm: Reg::R1, ra: Reg::R0, },
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 3,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32RemU sequence verified: rem_u(a,b) = a - (a/b)*b");
}
Ok(ValidationResult::Unknown { reason }) => {
println!(
"⚠ I32RemU verification unknown (complex formula): {}",
reason
);
}
other => panic!(
"Expected Verified or Unknown for REM_U sequence, got {:?}",
other
),
}
});
}
#[test]
fn verify_i32_and() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.and",
WasmOp::I32And,
ArmOp::And {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn verify_i32_or() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.or",
WasmOp::I32Or,
ArmOp::Orr {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn verify_i32_xor() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.xor",
WasmOp::I32Xor,
ArmOp::Eor {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
);
assert!(matches!(
validator.verify_rule(&rule),
Ok(ValidationResult::Verified)
));
});
}
#[test]
fn verify_i32_shl_parameterized() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let result = validator.verify_parameterized_range(
&WasmOp::I32Shl,
|shift_amount| {
vec![ArmOp::Lsl {
rd: Reg::R0,
rn: Reg::R0,
shift: shift_amount as u32,
}]
},
1, 0..32,
);
match result {
Ok(ValidationResult::Verified) => {
println!("✓ I32Shl verified for all shift amounts 0-31");
}
other => panic!(
"Expected Verified for all SHL constant shifts, got {:?}",
other
),
}
});
}
#[test]
fn verify_i32_shr_u_parameterized() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let result = validator.verify_parameterized_range(
&WasmOp::I32ShrU,
|shift_amount| {
vec![ArmOp::Lsr {
rd: Reg::R0,
rn: Reg::R0,
shift: shift_amount as u32,
}]
},
1, 0..32,
);
match result {
Ok(ValidationResult::Verified) => {
println!("✓ I32ShrU verified for all shift amounts 0-31");
}
other => panic!(
"Expected Verified for all SHR_U constant shifts, got {:?}",
other
),
}
});
}
#[test]
fn verify_i32_shr_s_parameterized() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let result = validator.verify_parameterized_range(
&WasmOp::I32ShrS,
|shift_amount| {
vec![ArmOp::Asr {
rd: Reg::R0,
rn: Reg::R0,
shift: shift_amount as u32,
}]
},
1, 0..32,
);
match result {
Ok(ValidationResult::Verified) => {
println!("✓ I32ShrS verified for all shift amounts 0-31");
}
other => panic!(
"Expected Verified for all SHR_S constant shifts, got {:?}",
other
),
}
});
}
#[test]
fn test_arm_ror_semantics() {
with_z3_context(|| {
let encoder = ArmSemantics::new();
let mut state = ArmState::new_symbolic();
state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
let ror_op = ArmOp::Ror {
rd: Reg::R0,
rn: Reg::R1,
shift: 8,
};
encoder.encode_op(&ror_op, &mut state);
assert_eq!(
state.get_reg(&Reg::R0).simplify().as_i64(),
Some(0x78123456)
);
state.set_reg(&Reg::R1, BV::from_u64(0x12345678, 32));
let ror_24 = ArmOp::Ror {
rd: Reg::R0,
rn: Reg::R1,
shift: 24, };
encoder.encode_op(&ror_24, &mut state);
assert_eq!(
state.get_reg(&Reg::R0).simplify().as_i64(),
Some(0x34567812)
);
});
}
#[test]
fn verify_i32_rotr_parameterized() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let result = validator.verify_parameterized_range(
&WasmOp::I32Rotr,
|shift_amount| {
vec![ArmOp::Ror {
rd: Reg::R0,
rn: Reg::R0,
shift: shift_amount as u32,
}]
},
1, 0..32,
);
match result {
Ok(ValidationResult::Verified) => {
println!("✓ I32Rotr verified for all shift amounts 0-31");
}
other => panic!(
"Expected Verified for all ROTR constant shifts, got {:?}",
other
),
}
});
}
#[test]
fn verify_i32_rotl_transformation() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let result = validator.verify_parameterized_range(
&WasmOp::I32Rotl,
|shift_amount| {
let ror_amount = (32 - shift_amount) % 32;
vec![ArmOp::Ror {
rd: Reg::R0,
rn: Reg::R0,
shift: ror_amount as u32,
}]
},
1, 0..32,
);
match result {
Ok(ValidationResult::Verified) => {
println!("✓ I32Rotl transformation verified: ROTL(x,n) = ROR(x, 32-n) for all n");
}
other => panic!("Expected Verified for ROTL transformation, got {:?}", other),
}
});
}
#[test]
fn verify_i32_clz() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.clz",
WasmOp::I32Clz,
ArmOp::Clz {
rd: Reg::R0,
rm: Reg::R0,
},
);
if let Ok(ValidationResult::Unknown { .. }) = validator.verify_rule(&rule) {}
});
}
#[test]
fn test_ctz_sequence_concrete() {
with_z3_context(|| {
let wasm_encoder = WasmSemantics::new();
let arm_encoder = ArmSemantics::new();
let value = BV::from_i64(12, 32);
let wasm_result = wasm_encoder.encode_op(&WasmOp::I32Ctz, std::slice::from_ref(&value));
assert_eq!(
wasm_result.simplify().as_i64(),
Some(2),
"WASM CTZ(12) should be 2"
);
let mut state = ArmState::new_symbolic();
state.set_reg(&Reg::R0, value);
arm_encoder.encode_op(
&ArmOp::Rbit {
rd: Reg::R1,
rm: Reg::R0,
},
&mut state,
);
arm_encoder.encode_op(
&ArmOp::Clz {
rd: Reg::R0,
rm: Reg::R1,
},
&mut state,
);
let arm_result = state.get_reg(&Reg::R0);
assert_eq!(
arm_result.simplify().as_i64(),
Some(2),
"ARM CTZ(12) should be 2"
);
let value2 = BV::from_i64(8, 32);
let wasm_result2 = wasm_encoder.encode_op(&WasmOp::I32Ctz, std::slice::from_ref(&value2));
assert_eq!(
wasm_result2.simplify().as_i64(),
Some(3),
"WASM CTZ(8) should be 3"
);
let mut state2 = ArmState::new_symbolic();
state2.set_reg(&Reg::R0, value2);
arm_encoder.encode_op(
&ArmOp::Rbit {
rd: Reg::R1,
rm: Reg::R0,
},
&mut state2,
);
arm_encoder.encode_op(
&ArmOp::Clz {
rd: Reg::R0,
rm: Reg::R1,
},
&mut state2,
);
let arm_result2 = state2.get_reg(&Reg::R0);
assert_eq!(
arm_result2.simplify().as_i64(),
Some(3),
"ARM CTZ(8) should be 3"
);
println!("✓ CTZ sequence concrete tests passed");
});
}
#[test]
fn verify_i32_ctz() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.ctz".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32Ctz),
replacement: Replacement::ArmSequence(vec![
ArmOp::Rbit {
rd: Reg::R1,
rm: Reg::R0,
},
ArmOp::Clz {
rd: Reg::R0,
rm: Reg::R1,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ CTZ sequence verified: I32Ctz ≡ [RBIT + CLZ]");
}
other => panic!("Expected Verified for CTZ sequence, got {:?}", other),
}
});
}
#[test]
fn verify_i32_eq() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.eq".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32Eq),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::EQ,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32Eq verified (CMP + SetCond EQ)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_ne() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.ne".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32Ne),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::NE,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32Ne verified (CMP + SetCond NE)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_lt_s() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.lt_s".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32LtS),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::LT,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32LtS verified (CMP + SetCond LT)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_le_s() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.le_s".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32LeS),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::LE,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32LeS verified (CMP + SetCond LE)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_gt_s() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.gt_s".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32GtS),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::GT,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32GtS verified (CMP + SetCond GT)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_ge_s() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.ge_s".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32GeS),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::GE,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32GeS verified (CMP + SetCond GE)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_lt_u() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.lt_u".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32LtU),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::LO,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32LtU verified (CMP + SetCond LO)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_le_u() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.le_u".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32LeU),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::LS,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32LeU verified (CMP + SetCond LS)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_gt_u() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.gt_u".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32GtU),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::HI,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32GtU verified (CMP + SetCond HI)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_ge_u() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.ge_u".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32GeU),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::HS,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 2,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32GeU verified (CMP + SetCond HS)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_eqz() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "i32.eqz".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::I32Eqz),
replacement: Replacement::ArmSequence(vec![
ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Imm(0),
},
ArmOp::SetCond {
rd: Reg::R0,
cond: synth_synthesis::rules::Condition::EQ,
},
]),
cost: synth_synthesis::Cost {
cycles: 2,
code_size: 8,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32Eqz verified (CMP #0 + SetCond EQ)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_i32_popcnt() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"i32.popcnt",
WasmOp::I32Popcnt,
ArmOp::Popcnt {
rd: Reg::R0,
rm: Reg::R0,
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32Popcnt verified (Hamming weight algorithm)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_select() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "select".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::Select),
replacement: Replacement::ArmInstr(ArmOp::Select {
rd: Reg::R0,
rval1: Reg::R0,
rval2: Reg::R1,
rcond: Reg::R2,
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 3,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Select verified (conditional selection)");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_local_get() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "local.get".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::LocalGet(0)),
replacement: Replacement::ArmInstr(ArmOp::LocalGet {
rd: Reg::R0,
index: 0,
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ LocalGet verified");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_local_set() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "local.set".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::LocalSet(0)),
replacement: Replacement::ArmInstr(ArmOp::LocalSet {
rs: Reg::R0,
index: 0,
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ LocalSet verified");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_local_tee() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "local.tee".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::LocalTee(0)),
replacement: Replacement::ArmInstr(ArmOp::LocalTee {
rd: Reg::R0,
rs: Reg::R0,
index: 0,
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ LocalTee verified");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_global_get() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "global.get".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::GlobalGet(0)),
replacement: Replacement::ArmInstr(ArmOp::GlobalGet {
rd: Reg::R0,
index: 0,
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ GlobalGet verified");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_global_set() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "global.set".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::GlobalSet(0)),
replacement: Replacement::ArmInstr(ArmOp::GlobalSet {
rs: Reg::R0,
index: 0,
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ GlobalSet verified");
}
other => panic!("Expected Verified, got {:?}", other),
}
});
}
#[test]
fn verify_nop() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule("nop", WasmOp::Nop, ArmOp::Nop);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Nop verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ Nop handled (structural operation)");
}
other => panic!("Unexpected verification result for Nop: {:?}", other),
}
});
}
#[test]
fn verify_block() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule("block", WasmOp::Block, ArmOp::Nop);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Block verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ Block handled (structural operation)");
}
other => panic!("Unexpected verification result for Block: {:?}", other),
}
});
}
#[test]
fn verify_loop() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule("loop", WasmOp::Loop, ArmOp::Nop);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Loop verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ Loop handled (structural operation)");
}
other => panic!("Unexpected verification result for Loop: {:?}", other),
}
});
}
#[test]
fn verify_end() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule("end", WasmOp::End, ArmOp::Nop);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ End verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ End handled (structural operation)");
}
other => panic!("Unexpected verification result for End: {:?}", other),
}
});
}
#[test]
fn verify_if() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = SynthesisRule {
name: "if".to_string(),
priority: 0,
pattern: Pattern::WasmInstr(WasmOp::If),
replacement: Replacement::ArmInstr(ArmOp::Cmp {
rn: Reg::R0,
op2: Operand2::Imm(0),
}),
cost: synth_synthesis::Cost {
cycles: 1,
code_size: 4,
registers: 1,
},
};
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ If verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ If handled (structural operation)");
}
other => panic!("Unexpected verification result for If: {:?}", other),
}
});
}
#[test]
fn verify_else() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule("else", WasmOp::Else, ArmOp::Nop);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Else verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ Else handled (structural operation)");
}
other => panic!("Unexpected verification result for Else: {:?}", other),
}
});
}
#[test]
fn batch_verify_all_arithmetic() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rules = vec![
create_rule(
"i32.add",
WasmOp::I32Add,
ArmOp::Add {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
create_rule(
"i32.sub",
WasmOp::I32Sub,
ArmOp::Sub {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
create_rule(
"i32.mul",
WasmOp::I32Mul,
ArmOp::Mul {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
),
create_rule(
"i32.div_s",
WasmOp::I32DivS,
ArmOp::Sdiv {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
),
create_rule(
"i32.div_u",
WasmOp::I32DivU,
ArmOp::Udiv {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
),
];
let results = validator.verify_rules(&rules);
let verified_count = results
.iter()
.filter(|(_, r)| matches!(r, Ok(ValidationResult::Verified)))
.count();
assert_eq!(
verified_count, 5,
"All 5 arithmetic operations should verify"
);
});
}
#[test]
fn batch_verify_all_bitwise() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rules = vec![
create_rule(
"i32.and",
WasmOp::I32And,
ArmOp::And {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
create_rule(
"i32.or",
WasmOp::I32Or,
ArmOp::Orr {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
create_rule(
"i32.xor",
WasmOp::I32Xor,
ArmOp::Eor {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
];
let results = validator.verify_rules(&rules);
let verified_count = results
.iter()
.filter(|(_, r)| matches!(r, Ok(ValidationResult::Verified)))
.count();
assert_eq!(verified_count, 3, "All 3 bitwise operations should verify");
});
}
#[test]
fn generate_verification_report() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let test_cases = vec![
(
"i32.add → ADD",
WasmOp::I32Add,
ArmOp::Add {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
(
"i32.sub → SUB",
WasmOp::I32Sub,
ArmOp::Sub {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
(
"i32.mul → MUL",
WasmOp::I32Mul,
ArmOp::Mul {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
),
(
"i32.div_s → SDIV",
WasmOp::I32DivS,
ArmOp::Sdiv {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
),
(
"i32.div_u → UDIV",
WasmOp::I32DivU,
ArmOp::Udiv {
rd: Reg::R0,
rn: Reg::R0,
rm: Reg::R1,
},
),
(
"i32.and → AND",
WasmOp::I32And,
ArmOp::And {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
(
"i32.or → ORR",
WasmOp::I32Or,
ArmOp::Orr {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
(
"i32.xor → EOR",
WasmOp::I32Xor,
ArmOp::Eor {
rd: Reg::R0,
rn: Reg::R0,
op2: Operand2::Reg(Reg::R1),
},
),
];
println!("\n╔══════════════════════════════════════════════════════════════════════╗");
println!("║ FORMAL VERIFICATION REPORT ║");
println!("╠══════════════════════════════════════════════════════════════════════╣");
println!("║ WebAssembly → ARM Synthesis Rule Verification ║");
println!("╚══════════════════════════════════════════════════════════════════════╝\n");
let mut verified = 0;
let mut invalid = 0;
let mut unknown = 0;
for (name, wasm_op, arm_op) in test_cases {
let rule = create_rule(name, wasm_op, arm_op);
let result = validator.verify_rule(&rule);
let status = match &result {
Ok(ValidationResult::Verified) => {
verified += 1;
"✓ PROVEN"
}
Ok(ValidationResult::Invalid { .. }) => {
invalid += 1;
"✗ INVALID"
}
Ok(ValidationResult::Unknown { .. }) => {
unknown += 1;
"? UNKNOWN"
}
Err(_) => {
unknown += 1;
"⚠ ERROR"
}
};
println!("{:40} {}", name, status);
}
println!("\n");
println!("Summary:");
println!(" ✓ Proven: {}/8", verified);
println!(" ✗ Invalid: {}/8", invalid);
println!(" ? Unknown: {}/8", unknown);
println!();
assert_eq!(verified, 8, "Expected 8 operations to be proven correct");
});
}
#[test]
fn verify_i32_const() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let test_values = vec![
(0, "zero"),
(1, "one"),
(42, "positive"),
(-1, "negative_one"),
(-42, "negative"),
(127, "max_signed_byte"),
(-128, "min_signed_byte"),
(255, "max_unsigned_byte"),
(32767, "max_signed_short"),
(-32768, "min_signed_short"),
(i32::MAX, "max_i32"),
(i32::MIN, "min_i32"),
];
for (value, name) in test_values {
let rule = create_rule(
&format!("i32.const({})", value),
WasmOp::I32Const(value),
ArmOp::Mov {
rd: Reg::R0,
op2: Operand2::Imm(value),
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ I32Const({}) verified ({})", value, name);
}
other => panic!(
"Expected Verified for i32.const({}), got {:?}",
value, other
),
}
}
});
}
#[test]
fn verify_br_table() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let test_cases = vec![
(vec![0], 1, "single_target"),
(vec![0, 1], 2, "two_targets"),
(vec![0, 1, 2], 3, "three_targets"),
(vec![0, 1, 2, 3, 4], 5, "five_targets"),
(vec![0, 0, 0], 1, "same_target"),
(vec![5, 4, 3, 2, 1, 0], 10, "reverse_targets"),
];
for (targets, default, name) in test_cases {
let rule = create_rule(
&format!("br_table_{}", name),
WasmOp::BrTable {
targets: targets.clone(),
default,
},
ArmOp::BrTable {
rd: Reg::R0,
index_reg: Reg::R1,
targets: targets.clone(),
default,
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ BrTable verified ({}, {} targets)", name, targets.len());
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!(
"✓ BrTable handled ({}, {} targets - structural operation)",
name,
targets.len()
);
}
other => panic!(
"Unexpected verification result for br_table ({}): {:?}",
name, other
),
}
}
});
}
#[test]
fn verify_br_table_empty() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"br_table_empty",
WasmOp::BrTable {
targets: vec![],
default: 0,
},
ArmOp::BrTable {
rd: Reg::R0,
index_reg: Reg::R1,
targets: vec![],
default: 0,
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ BrTable empty targets verified");
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!("✓ BrTable empty targets handled (structural operation)");
}
other => panic!(
"Unexpected verification result for br_table_empty: {:?}",
other
),
}
});
}
#[test]
fn verify_call() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let test_indices = vec![0, 1, 5, 10, 42, 100, 255, 1000];
for func_idx in test_indices {
let rule = create_rule(
&format!("call({})", func_idx),
WasmOp::Call(func_idx),
ArmOp::Call {
rd: Reg::R0,
func_idx,
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Call({}) verified", func_idx);
}
other => panic!("Expected Verified for call({}), got {:?}", func_idx, other),
}
}
});
}
#[test]
fn verify_call_indirect() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let test_types = vec![0, 1, 2, 5, 10, 15, 31];
for type_idx in test_types {
let rule = create_rule(
&format!("call_indirect({})", type_idx),
WasmOp::CallIndirect {
type_index: type_idx,
table_index: 0,
},
ArmOp::CallIndirect {
rd: Reg::R0,
type_idx,
table_index_reg: Reg::R1,
},
);
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ CallIndirect({}) verified", type_idx);
}
Ok(ValidationResult::Invalid { .. }) | Ok(ValidationResult::Unknown { .. }) => {
println!(
"✓ CallIndirect({}) handled (structural operation)",
type_idx
);
}
other => panic!(
"Unexpected verification result for call_indirect({}): {:?}",
type_idx, other
),
}
}
});
}
#[test]
fn verify_unreachable() {
with_z3_context(|| {
let validator = TranslationValidator::new();
let rule = create_rule(
"unreachable",
WasmOp::Unreachable,
ArmOp::Nop, );
match validator.verify_rule(&rule) {
Ok(ValidationResult::Verified) => {
println!("✓ Unreachable verified");
}
Ok(ValidationResult::Unknown { reason }) => {
println!("⚠ Unreachable verification unknown: {}", reason);
}
other => {
println!("Note: Unreachable result: {:?}", other);
}
}
});
}