Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions crates/synth-backend/src/arm_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8949,6 +8949,36 @@ mod tests {
assert_eq!(code.len(), 4, "MVE VABS.F32 should be 4 bytes");
}

/// VCR-RA-001 / immediate-folding precondition: pins the Thumb-2 `AND`
/// immediate encoding for the byte range and documents its bound.
///
/// The `And { Operand2::Imm }` encoder packs the low 12 bits straight into
/// the `i:imm3:imm8` field WITHOUT applying ThumbExpandImm (the modified-
/// immediate expansion). For `imm <= 0xFF` (e.g. gale's int8 clamps
/// `#0x7e` / `#0x7f`) that is correct — `i:imm3 = 0000` means "imm8
/// zero-extended". So `and r2, r0, #0x7e` encodes to the canonical
/// `00 f0 7e 02`. For `imm >= 0x100` the field would need a true
/// ThumbExpandImm pattern (rotation / replication), which is NOT
/// implemented here — so **immediate folding must gate on `imm <= 0xFF`**
/// until the encoder is hardened to ThumbExpandImm/Ok-or-Err (the
/// "encoder must be Ok-or-Err, never silently wrong" principle, #180/#185).
/// This bound covers the measured `flat_flight` waste (#209).
#[test]
fn and_immediate_encodes_correctly_in_byte_range_documents_fold_bound() {
let encoder = ArmEncoder::new_thumb2();
let op = ArmOp::And {
rd: Reg::R2,
rn: Reg::R0,
op2: Operand2::Imm(0x7e),
};
let code = encoder.encode(&op).unwrap();
assert_eq!(
code,
vec![0x00, 0xf0, 0x7e, 0x02],
"and r2, r0, #0x7e must encode to the canonical AND.W T1 (imm8=0x7e)"
);
}

#[test]
fn test_encode_mve_different_qregs() {
let encoder = ArmEncoder::new_thumb2();
Expand Down
Loading