From a54351f98ce68999ed798a68c8ea58c5abb71467 Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Fri, 19 Sep 2025 07:08:13 -0700 Subject: ZJIT: Test disasm with insta (#14602) --- zjit/src/asm/arm64/mod.rs | 403 ++++++++++++++----- zjit/src/asm/mod.rs | 19 + zjit/src/asm/x86_64/tests.rs | 890 ++++++++++++++++++++++++++++++----------- zjit/src/assertions.rs | 21 - zjit/src/backend/arm64/mod.rs | 81 ++-- zjit/src/backend/x86_64/mod.rs | 206 ++++++---- zjit/src/lib.rs | 2 - 7 files changed, 1155 insertions(+), 467 deletions(-) delete mode 100644 zjit/src/assertions.rs diff --git a/zjit/src/asm/arm64/mod.rs b/zjit/src/asm/arm64/mod.rs index 63ac7823f1..d7e48d6c0c 100644 --- a/zjit/src/asm/arm64/mod.rs +++ b/zjit/src/asm/arm64/mod.rs @@ -1212,13 +1212,12 @@ fn cbz_cbnz(num_bits: u8, op: bool, offset: InstructionOffset, rt: u8) -> [u8; 4 #[cfg(test)] mod tests { use super::*; - use crate::assertions::assert_disasm; + use insta::assert_snapshot; - /// Check that the bytes for an instruction sequence match a hex string - fn check_bytes(bytes: &str, run: R) where R: FnOnce(&mut super::CodeBlock) { + fn compile(run: R) -> CodeBlock where R: FnOnce(&mut super::CodeBlock) { let mut cb = super::CodeBlock::new_dummy(); run(&mut cb); - assert_eq!(format!("{:x}", cb), bytes); + cb } #[test] @@ -1246,94 +1245,130 @@ mod tests { #[test] fn test_add_reg() { - check_bytes("2000028b", |cb| add(cb, X0, X1, X2)); + let cb = compile(|cb| add(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, x2"); + assert_snapshot!(cb.string(), @"2000028b"); } #[test] fn test_add_uimm() { - check_bytes("201c0091", |cb| add(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c0091"); } #[test] fn test_add_imm_positive() { - check_bytes("201c0091", |cb| add(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c0091"); } #[test] fn test_add_imm_negative() { - check_bytes("201c00d1", |cb| add(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| add(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00d1"); } #[test] fn test_adds_reg() { - check_bytes("200002ab", |cb| adds(cb, X0, X1, X2)); + let cb = compile(|cb| adds(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002ab"); } #[test] fn test_adds_uimm() { - check_bytes("201c00b1", |cb| adds(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00b1"); } #[test] fn test_adds_imm_positive() { - check_bytes("201c00b1", |cb| adds(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00b1"); } #[test] fn test_adds_imm_negative() { - check_bytes("201c00f1", |cb| adds(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| adds(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00f1"); } #[test] fn test_adr() { - check_bytes("aa000010", |cb| adr(cb, X10, A64Opnd::new_imm(20))); + let cb = compile(|cb| adr(cb, X10, A64Opnd::new_imm(20))); + assert_snapshot!(cb.disasm(), @" 0x0: adr x10, #0x14"); + assert_snapshot!(cb.string(), @"aa000010"); } #[test] fn test_adrp() { - check_bytes("4a000090", |cb| adrp(cb, X10, A64Opnd::new_imm(0x8000))); + let cb = compile(|cb| adrp(cb, X10, A64Opnd::new_imm(0x8000))); + assert_snapshot!(cb.disasm(), @" 0x0: adrp x10, #0x8000"); + assert_snapshot!(cb.string(), @"4a000090"); } #[test] fn test_and_register() { - check_bytes("2000028a", |cb| and(cb, X0, X1, X2)); + let cb = compile(|cb| and(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: and x0, x1, x2"); + assert_snapshot!(cb.string(), @"2000028a"); } #[test] fn test_and_immediate() { - check_bytes("20084092", |cb| and(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| and(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: and x0, x1, #7"); + assert_snapshot!(cb.string(), @"20084092"); } #[test] fn test_and_32b_immediate() { - check_bytes("404c0012", |cb| and(cb, W0, W2, A64Opnd::new_uimm(0xfffff))); + let cb = compile(|cb| and(cb, W0, W2, A64Opnd::new_uimm(0xfffff))); + assert_snapshot!(cb.disasm(), @" 0x0: and w0, w2, #0xfffff"); + assert_snapshot!(cb.string(), @"404c0012"); } #[test] fn test_ands_register() { - check_bytes("200002ea", |cb| ands(cb, X0, X1, X2)); + let cb = compile(|cb| ands(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: ands x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002ea"); } #[test] fn test_ands_immediate() { - check_bytes("200840f2", |cb| ands(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| ands(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: ands x0, x1, #7"); + assert_snapshot!(cb.string(), @"200840f2"); } #[test] fn test_asr() { - check_bytes("b4fe4a93", |cb| asr(cb, X20, X21, A64Opnd::new_uimm(10))); + let cb = compile(|cb| asr(cb, X20, X21, A64Opnd::new_uimm(10))); + assert_snapshot!(cb.disasm(), @" 0x0: asr x20, x21, #0xa"); + assert_snapshot!(cb.string(), @"b4fe4a93"); } #[test] fn test_bcond() { let offset = InstructionOffset::from_insns(0x100); - check_bytes("01200054", |cb| bcond(cb, Condition::NE, offset)); + let cb = compile(|cb| bcond(cb, Condition::NE, offset)); + assert_snapshot!(cb.disasm(), @" 0x0: b.ne #0x400"); + assert_snapshot!(cb.string(), @"01200054"); } #[test] fn test_b() { let offset = InstructionOffset::from_insns((1 << 25) - 1); - check_bytes("ffffff15", |cb| b(cb, offset)); + let cb = compile(|cb| b(cb, offset)); + assert_snapshot!(cb.disasm(), @" 0x0: b #0x7fffffc"); + assert_snapshot!(cb.string(), @"ffffff15"); } #[test] @@ -1341,7 +1376,7 @@ mod tests { fn test_b_too_big() { // There are 26 bits available let offset = InstructionOffset::from_insns(1 << 25); - check_bytes("", |cb| b(cb, offset)); + compile(|cb| b(cb, offset)); } #[test] @@ -1349,13 +1384,15 @@ mod tests { fn test_b_too_small() { // There are 26 bits available let offset = InstructionOffset::from_insns(-(1 << 25) - 1); - check_bytes("", |cb| b(cb, offset)); + compile(|cb| b(cb, offset)); } #[test] fn test_bl() { let offset = InstructionOffset::from_insns(-(1 << 25)); - check_bytes("00000096", |cb| bl(cb, offset)); + let cb = compile(|cb| bl(cb, offset)); + assert_snapshot!(cb.disasm(), @" 0x0: bl #0xfffffffff8000000"); + assert_snapshot!(cb.string(), @"00000096"); } #[test] @@ -1363,7 +1400,7 @@ mod tests { fn test_bl_too_big() { // There are 26 bits available let offset = InstructionOffset::from_insns(1 << 25); - check_bytes("", |cb| bl(cb, offset)); + compile(|cb| bl(cb, offset)); } #[test] @@ -1371,385 +1408,544 @@ mod tests { fn test_bl_too_small() { // There are 26 bits available let offset = InstructionOffset::from_insns(-(1 << 25) - 1); - check_bytes("", |cb| bl(cb, offset)); + compile(|cb| bl(cb, offset)); } #[test] fn test_blr() { - check_bytes("80023fd6", |cb| blr(cb, X20)); + let cb = compile(|cb| blr(cb, X20)); + assert_snapshot!(cb.disasm(), @" 0x0: blr x20"); + assert_snapshot!(cb.string(), @"80023fd6"); } #[test] fn test_br() { - check_bytes("80021fd6", |cb| br(cb, X20)); + let cb = compile(|cb| br(cb, X20)); + assert_snapshot!(cb.disasm(), @" 0x0: br x20"); + assert_snapshot!(cb.string(), @"80021fd6"); } #[test] fn test_cbz() { let offset = InstructionOffset::from_insns(-1); - check_bytes("e0ffffb4e0ffff34", |cb| { + let cb = compile(|cb| { cbz(cb, X0, offset); cbz(cb, W0, offset); }); + assert_snapshot!(cb.disasm(), @r" + 0x0: cbz x0, #0xfffffffffffffffc + 0x4: cbz w0, #0 + "); + assert_snapshot!(cb.string(), @"e0ffffb4e0ffff34"); } #[test] fn test_cbnz() { let offset = InstructionOffset::from_insns(2); - check_bytes("540000b554000035", |cb| { + let cb = compile(|cb| { cbnz(cb, X20, offset); cbnz(cb, W20, offset); }); + assert_snapshot!(cb.disasm(), @r" + 0x0: cbnz x20, #8 + 0x4: cbnz w20, #0xc + "); + assert_snapshot!(cb.string(), @"540000b554000035"); } #[test] fn test_brk_none() { - check_bytes("00003ed4", |cb| brk(cb, A64Opnd::None)); + let cb = compile(|cb| brk(cb, A64Opnd::None)); + assert_snapshot!(cb.disasm(), @" 0x0: brk #0xf000"); + assert_snapshot!(cb.string(), @"00003ed4"); } #[test] fn test_brk_uimm() { - check_bytes("c00120d4", |cb| brk(cb, A64Opnd::new_uimm(14))); + let cb = compile(|cb| brk(cb, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: brk #0xe"); + assert_snapshot!(cb.string(), @"c00120d4"); } #[test] fn test_cmp_register() { - check_bytes("5f010beb", |cb| cmp(cb, X10, X11)); + let cb = compile(|cb| cmp(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: cmp x10, x11"); + assert_snapshot!(cb.string(), @"5f010beb"); } #[test] fn test_cmp_immediate() { - check_bytes("5f3900f1", |cb| cmp(cb, X10, A64Opnd::new_uimm(14))); + let cb = compile(|cb| cmp(cb, X10, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: cmp x10, #0xe"); + assert_snapshot!(cb.string(), @"5f3900f1"); } #[test] fn test_csel() { - check_bytes("6a018c9a", |cb| csel(cb, X10, X11, X12, Condition::EQ)); + let cb = compile(|cb| csel(cb, X10, X11, X12, Condition::EQ)); + assert_snapshot!(cb.disasm(), @" 0x0: csel x10, x11, x12, eq"); + assert_snapshot!(cb.string(), @"6a018c9a"); } #[test] fn test_eor_register() { - check_bytes("6a010cca", |cb| eor(cb, X10, X11, X12)); + let cb = compile(|cb| eor(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: eor x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a010cca"); } #[test] fn test_eor_immediate() { - check_bytes("6a0940d2", |cb| eor(cb, X10, X11, A64Opnd::new_uimm(7))); + let cb = compile(|cb| eor(cb, X10, X11, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: eor x10, x11, #7"); + assert_snapshot!(cb.string(), @"6a0940d2"); } #[test] fn test_eor_32b_immediate() { - check_bytes("29040152", |cb| eor(cb, W9, W1, A64Opnd::new_uimm(0x80000001))); + let cb = compile(|cb| eor(cb, W9, W1, A64Opnd::new_uimm(0x80000001))); + assert_snapshot!(cb.disasm(), @" 0x0: eor w9, w1, #0x80000001"); + assert_snapshot!(cb.string(), @"29040152"); } #[test] fn test_ldaddal() { - check_bytes("8b01eaf8", |cb| ldaddal(cb, X10, X11, X12)); + let cb = compile(|cb| ldaddal(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: ldaddal x10, x11, [x12]"); + assert_snapshot!(cb.string(), @"8b01eaf8"); } #[test] fn test_ldaxr() { - check_bytes("6afd5fc8", |cb| ldaxr(cb, X10, X11)); + let cb = compile(|cb| ldaxr(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: ldaxr x10, [x11]"); + assert_snapshot!(cb.string(), @"6afd5fc8"); } #[test] fn test_ldp() { - check_bytes("8a2d4da9", |cb| ldp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| ldp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12, #0xd0]"); + assert_snapshot!(cb.string(), @"8a2d4da9"); } #[test] fn test_ldp_pre() { - check_bytes("8a2dcda9", |cb| ldp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| ldp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12, #0xd0]!"); + assert_snapshot!(cb.string(), @"8a2dcda9"); } #[test] fn test_ldp_post() { - check_bytes("8a2dcda8", |cb| ldp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| ldp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: ldp x10, x11, [x12], #0xd0"); + assert_snapshot!(cb.string(), @"8a2dcda8"); } #[test] fn test_ldr() { - check_bytes("6a696cf8", |cb| ldr(cb, X10, X11, X12)); + let cb = compile(|cb| ldr(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11, x12]"); + assert_snapshot!(cb.string(), @"6a696cf8"); } #[test] fn test_ldr_literal() { - check_bytes("40010058", |cb| ldr_literal(cb, X0, 10.into())); + let cb = compile(|cb| ldr_literal(cb, X0, 10.into())); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x0, #0x28"); + assert_snapshot!(cb.string(), @"40010058"); } #[test] fn test_ldr_post() { - check_bytes("6a0541f8", |cb| ldr_post(cb, X10, A64Opnd::new_mem(64, X11, 16))); + let cb = compile(|cb| ldr_post(cb, X10, A64Opnd::new_mem(64, X11, 16))); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11], #0x10"); + assert_snapshot!(cb.string(), @"6a0541f8"); } #[test] fn test_ldr_pre() { - check_bytes("6a0d41f8", |cb| ldr_pre(cb, X10, A64Opnd::new_mem(64, X11, 16))); + let cb = compile(|cb| ldr_pre(cb, X10, A64Opnd::new_mem(64, X11, 16))); + assert_snapshot!(cb.disasm(), @" 0x0: ldr x10, [x11, #0x10]!"); + assert_snapshot!(cb.string(), @"6a0d41f8"); } #[test] fn test_ldrh() { - check_bytes("6a194079", |cb| ldrh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| ldrh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11, #0xc]"); + assert_snapshot!(cb.string(), @"6a194079"); } #[test] fn test_ldrh_pre() { - check_bytes("6acd4078", |cb| ldrh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| ldrh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11, #0xc]!"); + assert_snapshot!(cb.string(), @"6acd4078"); } #[test] fn test_ldrh_post() { - check_bytes("6ac54078", |cb| ldrh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| ldrh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: ldrh w10, [x11], #0xc"); + assert_snapshot!(cb.string(), @"6ac54078"); } #[test] fn test_ldurh_memory() { - check_bytes("2a004078", |cb| ldurh(cb, W10, A64Opnd::new_mem(64, X1, 0))); - check_bytes("2ab04778", |cb| ldurh(cb, W10, A64Opnd::new_mem(64, X1, 123))); + let cb = compile(|cb| { + ldurh(cb, W10, A64Opnd::new_mem(64, X1, 0)); + ldurh(cb, W10, A64Opnd::new_mem(64, X1, 123)); + }); + assert_snapshot!(cb.disasm(), @r" + 0x0: ldurh w10, [x1] + 0x4: ldurh w10, [x1, #0x7b] + "); + assert_snapshot!(cb.string(), @"2a0040782ab04778"); } #[test] fn test_ldur_memory() { - check_bytes("20b047f8", |cb| ldur(cb, X0, A64Opnd::new_mem(64, X1, 123))); + let cb = compile(|cb| ldur(cb, X0, A64Opnd::new_mem(64, X1, 123))); + assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x1, #0x7b]"); + assert_snapshot!(cb.string(), @"20b047f8"); } #[test] fn test_ldur_register() { - check_bytes("200040f8", |cb| ldur(cb, X0, X1)); + let cb = compile(|cb| ldur(cb, X0, X1)); + assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x1]"); + assert_snapshot!(cb.string(), @"200040f8"); } #[test] fn test_ldursw() { - check_bytes("6ab187b8", |cb| ldursw(cb, X10, A64Opnd::new_mem(64, X11, 123))); + let cb = compile(|cb| ldursw(cb, X10, A64Opnd::new_mem(64, X11, 123))); + assert_snapshot!(cb.disasm(), @" 0x0: ldursw x10, [x11, #0x7b]"); + assert_snapshot!(cb.string(), @"6ab187b8"); } #[test] fn test_lsl() { - check_bytes("6ac572d3", |cb| lsl(cb, X10, X11, A64Opnd::new_uimm(14))); + let cb = compile(|cb| lsl(cb, X10, X11, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: lsl x10, x11, #0xe"); + assert_snapshot!(cb.string(), @"6ac572d3"); } #[test] fn test_lsr() { - check_bytes("6afd4ed3", |cb| lsr(cb, X10, X11, A64Opnd::new_uimm(14))); + let cb = compile(|cb| lsr(cb, X10, X11, A64Opnd::new_uimm(14))); + assert_snapshot!(cb.disasm(), @" 0x0: lsr x10, x11, #0xe"); + assert_snapshot!(cb.string(), @"6afd4ed3"); } #[test] fn test_mov_registers() { - check_bytes("ea030baa", |cb| mov(cb, X10, X11)); + let cb = compile(|cb| mov(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x10, x11"); + assert_snapshot!(cb.string(), @"ea030baa"); } #[test] fn test_mov_immediate() { - check_bytes("eaf300b2", |cb| mov(cb, X10, A64Opnd::new_uimm(0x5555555555555555))); + let cb = compile(|cb| mov(cb, X10, A64Opnd::new_uimm(0x5555555555555555))); + assert_snapshot!(cb.disasm(), @" 0x0: orr x10, xzr, #0x5555555555555555"); + assert_snapshot!(cb.string(), @"eaf300b2"); } #[test] fn test_mov_32b_immediate() { - check_bytes("ea070132", |cb| mov(cb, W10, A64Opnd::new_uimm(0x80000001))); + let cb = compile(|cb| mov(cb, W10, A64Opnd::new_uimm(0x80000001))); + assert_snapshot!(cb.disasm(), @" 0x0: mov w10, #-0x7fffffff"); + assert_snapshot!(cb.string(), @"ea070132"); } #[test] fn test_mov_into_sp() { - check_bytes("1f000091", |cb| mov(cb, X31, X0)); + let cb = compile(|cb| mov(cb, X31, X0)); + assert_snapshot!(cb.disasm(), @" 0x0: mov sp, x0"); + assert_snapshot!(cb.string(), @"1f000091"); } #[test] fn test_mov_from_sp() { - check_bytes("e0030091", |cb| mov(cb, X0, X31)); + let cb = compile(|cb| mov(cb, X0, X31)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, sp"); + assert_snapshot!(cb.string(), @"e0030091"); } #[test] fn test_movk() { - check_bytes("600fa0f2", |cb| movk(cb, X0, A64Opnd::new_uimm(123), 16)); + let cb = compile(|cb| movk(cb, X0, A64Opnd::new_uimm(123), 16)); + assert_snapshot!(cb.disasm(), @" 0x0: movk x0, #0x7b, lsl #16"); + assert_snapshot!(cb.string(), @"600fa0f2"); } #[test] fn test_movn() { - check_bytes("600fa092", |cb| movn(cb, X0, A64Opnd::new_uimm(123), 16)); + let cb = compile(|cb| movn(cb, X0, A64Opnd::new_uimm(123), 16)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #-0x7b0001"); + assert_snapshot!(cb.string(), @"600fa092"); } #[test] fn test_movz() { - check_bytes("600fa0d2", |cb| movz(cb, X0, A64Opnd::new_uimm(123), 16)); + let cb = compile(|cb| movz(cb, X0, A64Opnd::new_uimm(123), 16)); + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #0x7b0000"); + assert_snapshot!(cb.string(), @"600fa0d2"); } #[test] fn test_mrs() { - check_bytes("0a423bd5", |cb| mrs(cb, X10, SystemRegister::NZCV)); + let cb = compile(|cb| mrs(cb, X10, SystemRegister::NZCV)); + assert_snapshot!(cb.disasm(), @" 0x0: mrs x10, nzcv"); + assert_snapshot!(cb.string(), @"0a423bd5"); } #[test] fn test_msr() { - check_bytes("0a421bd5", |cb| msr(cb, SystemRegister::NZCV, X10)); + let cb = compile(|cb| msr(cb, SystemRegister::NZCV, X10)); + assert_snapshot!(cb.disasm(), @" 0x0: msr nzcv, x10"); + assert_snapshot!(cb.string(), @"0a421bd5"); } #[test] fn test_mul() { - check_bytes("6a7d0c9b", |cb| mul(cb, X10, X11, X12)); + let cb = compile(|cb| mul(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: mul x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a7d0c9b"); } #[test] fn test_mvn() { - check_bytes("ea032baa", |cb| mvn(cb, X10, X11)); + let cb = compile(|cb| mvn(cb, X10, X11)); + assert_snapshot!(cb.disasm(), @" 0x0: mvn x10, x11"); + assert_snapshot!(cb.string(), @"ea032baa"); } #[test] fn test_nop() { - check_bytes("1f2003d5", nop); + let cb = compile(nop); + assert_snapshot!(cb.disasm(), @" 0x0: nop"); + assert_snapshot!(cb.string(), @"1f2003d5"); } #[test] fn test_orn() { - check_bytes("6a012caa", |cb| orn(cb, X10, X11, X12)); + let cb = compile(|cb| orn(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: orn x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a012caa"); } #[test] fn test_orr_register() { - check_bytes("6a010caa", |cb| orr(cb, X10, X11, X12)); + let cb = compile(|cb| orr(cb, X10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: orr x10, x11, x12"); + assert_snapshot!(cb.string(), @"6a010caa"); } #[test] fn test_orr_immediate() { - check_bytes("6a0940b2", |cb| orr(cb, X10, X11, A64Opnd::new_uimm(7))); + let cb = compile(|cb| orr(cb, X10, X11, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: orr x10, x11, #7"); + assert_snapshot!(cb.string(), @"6a0940b2"); } #[test] fn test_orr_32b_immediate() { - check_bytes("6a010032", |cb| orr(cb, W10, W11, A64Opnd::new_uimm(1))); + let cb = compile(|cb| orr(cb, W10, W11, A64Opnd::new_uimm(1))); + assert_snapshot!(cb.disasm(), @" 0x0: orr w10, w11, #1"); + assert_snapshot!(cb.string(), @"6a010032"); } #[test] fn test_ret_none() { - check_bytes("c0035fd6", |cb| ret(cb, A64Opnd::None)); + let cb = compile(|cb| ret(cb, A64Opnd::None)); + assert_snapshot!(cb.disasm(), @" 0x0: ret"); + assert_snapshot!(cb.string(), @"c0035fd6"); } #[test] fn test_ret_register() { - check_bytes("80025fd6", |cb| ret(cb, X20)); + let cb = compile(|cb| ret(cb, X20)); + assert_snapshot!(cb.disasm(), @" 0x0: ret x20"); + assert_snapshot!(cb.string(), @"80025fd6"); } #[test] fn test_stlxr() { - check_bytes("8bfd0ac8", |cb| stlxr(cb, W10, X11, X12)); + let cb = compile(|cb| stlxr(cb, W10, X11, X12)); + assert_snapshot!(cb.disasm(), @" 0x0: stlxr w10, x11, [x12]"); + assert_snapshot!(cb.string(), @"8bfd0ac8"); } #[test] fn test_stp() { - check_bytes("8a2d0da9", |cb| stp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| stp(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12, #0xd0]"); + assert_snapshot!(cb.string(), @"8a2d0da9"); } #[test] fn test_stp_pre() { - check_bytes("8a2d8da9", |cb| stp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| stp_pre(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12, #0xd0]!"); + assert_snapshot!(cb.string(), @"8a2d8da9"); } #[test] fn test_stp_post() { - check_bytes("8a2d8da8", |cb| stp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + let cb = compile(|cb| stp_post(cb, X10, X11, A64Opnd::new_mem(64, X12, 208))); + assert_snapshot!(cb.disasm(), @" 0x0: stp x10, x11, [x12], #0xd0"); + assert_snapshot!(cb.string(), @"8a2d8da8"); } #[test] fn test_str_post() { - check_bytes("6a051ff8", |cb| str_post(cb, X10, A64Opnd::new_mem(64, X11, -16))); + let cb = compile(|cb| str_post(cb, X10, A64Opnd::new_mem(64, X11, -16))); + assert_snapshot!(cb.disasm(), @" 0x0: str x10, [x11], #0xfffffffffffffff0"); + assert_snapshot!(cb.string(), @"6a051ff8"); } #[test] fn test_str_pre() { - check_bytes("6a0d1ff8", |cb| str_pre(cb, X10, A64Opnd::new_mem(64, X11, -16))); + let cb = compile(|cb| str_pre(cb, X10, A64Opnd::new_mem(64, X11, -16))); + assert_snapshot!(cb.disasm(), @" 0x0: str x10, [x11, #-0x10]!"); + assert_snapshot!(cb.string(), @"6a0d1ff8"); } #[test] fn test_strh() { - check_bytes("6a190079", |cb| strh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| strh(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11, #0xc]"); + assert_snapshot!(cb.string(), @"6a190079"); } #[test] fn test_strh_pre() { - check_bytes("6acd0078", |cb| strh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| strh_pre(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11, #0xc]!"); + assert_snapshot!(cb.string(), @"6acd0078"); } #[test] fn test_strh_post() { - check_bytes("6ac50078", |cb| strh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + let cb = compile(|cb| strh_post(cb, W10, A64Opnd::new_mem(64, X11, 12))); + assert_snapshot!(cb.disasm(), @" 0x0: strh w10, [x11], #0xc"); + assert_snapshot!(cb.string(), @"6ac50078"); } #[test] fn test_stur_64_bits() { - check_bytes("6a0108f8", |cb| stur(cb, X10, A64Opnd::new_mem(64, X11, 128))); + let cb = compile(|cb| stur(cb, X10, A64Opnd::new_mem(64, X11, 128))); + assert_snapshot!(cb.disasm(), @" 0x0: stur x10, [x11, #0x80]"); + assert_snapshot!(cb.string(), @"6a0108f8"); } #[test] fn test_stur_32_bits() { - check_bytes("6a0108b8", |cb| stur(cb, X10, A64Opnd::new_mem(32, X11, 128))); + let cb = compile(|cb| stur(cb, X10, A64Opnd::new_mem(32, X11, 128))); + assert_snapshot!(cb.disasm(), @" 0x0: stur w10, [x11, #0x80]"); + assert_snapshot!(cb.string(), @"6a0108b8"); } #[test] fn test_sub_reg() { - check_bytes("200002cb", |cb| sub(cb, X0, X1, X2)); + let cb = compile(|cb| sub(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002cb"); } #[test] fn test_sub_uimm() { - check_bytes("201c00d1", |cb| sub(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00d1"); } #[test] fn test_sub_imm_positive() { - check_bytes("201c00d1", |cb| sub(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: sub x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00d1"); } #[test] fn test_sub_imm_negative() { - check_bytes("201c0091", |cb| sub(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| sub(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: add x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c0091"); } #[test] fn test_subs_reg() { - check_bytes("200002eb", |cb| subs(cb, X0, X1, X2)); + let cb = compile(|cb| subs(cb, X0, X1, X2)); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, x2"); + assert_snapshot!(cb.string(), @"200002eb"); } #[test] fn test_subs_imm_positive() { - check_bytes("201c00f1", |cb| subs(cb, X0, X1, A64Opnd::new_imm(7))); + let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_imm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00f1"); } #[test] fn test_subs_imm_negative() { - check_bytes("201c00b1", |cb| subs(cb, X0, X1, A64Opnd::new_imm(-7))); + let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_imm(-7))); + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00b1"); } #[test] fn test_subs_uimm() { - check_bytes("201c00f1", |cb| subs(cb, X0, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| subs(cb, X0, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: subs x0, x1, #7"); + assert_snapshot!(cb.string(), @"201c00f1"); } #[test] fn test_sxtw() { - check_bytes("6a7d4093", |cb| sxtw(cb, X10, W11)); + let cb = compile(|cb| sxtw(cb, X10, W11)); + assert_snapshot!(cb.disasm(), @" 0x0: sxtw x10, w11"); + assert_snapshot!(cb.string(), @"6a7d4093"); } #[test] fn test_tbnz() { - check_bytes("4a005037", |cb| tbnz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + let cb = compile(|cb| tbnz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + assert_snapshot!(cb.disasm(), @" 0x0: tbnz w10, #0xa, #8"); + assert_snapshot!(cb.string(), @"4a005037"); } #[test] fn test_tbz() { - check_bytes("4a005036", |cb| tbz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + let cb = compile(|cb| tbz(cb, X10, A64Opnd::UImm(10), A64Opnd::Imm(2))); + assert_snapshot!(cb.disasm(), @" 0x0: tbz w10, #0xa, #8"); + assert_snapshot!(cb.string(), @"4a005036"); } #[test] fn test_tst_register() { - check_bytes("1f0001ea", |cb| tst(cb, X0, X1)); + let cb = compile(|cb| tst(cb, X0, X1)); + assert_snapshot!(cb.disasm(), @" 0x0: tst x0, x1"); + assert_snapshot!(cb.string(), @"1f0001ea"); } #[test] fn test_tst_immediate() { - check_bytes("3f0840f2", |cb| tst(cb, X1, A64Opnd::new_uimm(7))); + let cb = compile(|cb| tst(cb, X1, A64Opnd::new_uimm(7))); + assert_snapshot!(cb.disasm(), @" 0x0: tst x1, #7"); + assert_snapshot!(cb.string(), @"3f0840f2"); } #[test] fn test_tst_32b_immediate() { - check_bytes("1f3c0072", |cb| tst(cb, W0, A64Opnd::new_uimm(0xffff))); + let cb = compile(|cb| tst(cb, W0, A64Opnd::new_uimm(0xffff))); + assert_snapshot!(cb.disasm(), @" 0x0: tst w0, #0xffff"); + assert_snapshot!(cb.string(), @"1f3c0072"); } #[test] @@ -1760,10 +1956,11 @@ mod tests { add_extended(&mut cb, X30, X30, X30); add_extended(&mut cb, X31, X31, X31); - assert_disasm!(cb, "6a61298bde633e8bff633f8b", " + assert_snapshot!(cb.disasm(), @" 0x0: add x10, x11, x9, uxtx 0x4: add x30, x30, x30, uxtx 0x8: add sp, sp, xzr "); + assert_snapshot!(cb.string(), @"6a61298bde633e8bff633f8b"); } } diff --git a/zjit/src/asm/mod.rs b/zjit/src/asm/mod.rs index e07ac0a48c..d866515c82 100644 --- a/zjit/src/asm/mod.rs +++ b/zjit/src/asm/mod.rs @@ -281,6 +281,25 @@ impl CodeBlock { pub fn mark_all_executable(&mut self) { self.mem_block.borrow_mut().mark_all_executable(); } + + /// Return the disasm of generated code for testing + #[cfg(test)] + pub fn disasm(&self) -> String { + #[cfg(feature = "disasm")] + { + let start_addr = self.get_ptr(0).raw_addr(self); + let end_addr = self.get_write_ptr().raw_addr(self); + crate::disasm::disasm_addr_range(self, start_addr, end_addr) + } + #[cfg(not(feature = "disasm"))] + unreachable!("zjit-test should enable disasm feature") + } + + /// Return the hex dump of generated code for testing + #[cfg(test)] + pub fn string(&self) -> String { + format!("{:x}", self) + } } /// Produce hex string output from the bytes in a code block diff --git a/zjit/src/asm/x86_64/tests.rs b/zjit/src/asm/x86_64/tests.rs index 0268846e10..aa8d31b215 100644 --- a/zjit/src/asm/x86_64/tests.rs +++ b/zjit/src/asm/x86_64/tests.rs @@ -1,5 +1,7 @@ #![cfg(test)] +use insta::assert_snapshot; + use crate::asm::x86_64::*; /// Check that the bytes for an instruction sequence match a hex string @@ -9,364 +11,745 @@ fn check_bytes(bytes: &str, run: R) where R: FnOnce(&mut super::CodeBlock) { assert_eq!(format!("{:x}", cb), bytes); } +fn compile(run: R) -> CodeBlock where R: FnOnce(&mut super::CodeBlock) { + let mut cb = super::CodeBlock::new_dummy(); + run(&mut cb); + cb +} + #[test] fn test_add() { - check_bytes("80c103", |cb| add(cb, CL, imm_opnd(3))); - check_bytes("00d9", |cb| add(cb, CL, BL)); - check_bytes("4000e1", |cb| add(cb, CL, SPL)); - check_bytes("6601d9", |cb| add(cb, CX, BX)); - check_bytes("4801d8", |cb| add(cb, RAX, RBX)); - check_bytes("01d1", |cb| add(cb, ECX, EDX)); - check_bytes("4c01f2", |cb| add(cb, RDX, R14)); - check_bytes("480110", |cb| add(cb, mem_opnd(64, RAX, 0), RDX)); - check_bytes("480310", |cb| add(cb, RDX, mem_opnd(64, RAX, 0))); - check_bytes("48035008", |cb| add(cb, RDX, mem_opnd(64, RAX, 8))); - check_bytes("480390ff000000", |cb| add(cb, RDX, mem_opnd(64, RAX, 255))); - check_bytes("4881407fff000000", |cb| add(cb, mem_opnd(64, RAX, 127), imm_opnd(255))); - check_bytes("0110", |cb| add(cb, mem_opnd(32, RAX, 0), EDX)); - check_bytes("4883c408", |cb| add(cb, RSP, imm_opnd(8))); - check_bytes("83c108", |cb| add(cb, ECX, imm_opnd(8))); - check_bytes("81c1ff000000", |cb| add(cb, ECX, imm_opnd(255))); + let cb01 = compile(|cb| add(cb, CL, imm_opnd(3))); + let cb02 = compile(|cb| add(cb, CL, BL)); + let cb03 = compile(|cb| add(cb, CL, SPL)); + let cb04 = compile(|cb| add(cb, CX, BX)); + let cb05 = compile(|cb| add(cb, RAX, RBX)); + let cb06 = compile(|cb| add(cb, ECX, EDX)); + let cb07 = compile(|cb| add(cb, RDX, R14)); + let cb08 = compile(|cb| add(cb, mem_opnd(64, RAX, 0), RDX)); + let cb09 = compile(|cb| add(cb, RDX, mem_opnd(64, RAX, 0))); + let cb10 = compile(|cb| add(cb, RDX, mem_opnd(64, RAX, 8))); + let cb11 = compile(|cb| add(cb, RDX, mem_opnd(64, RAX, 255))); + let cb12 = compile(|cb| add(cb, mem_opnd(64, RAX, 127), imm_opnd(255))); + let cb13 = compile(|cb| add(cb, mem_opnd(32, RAX, 0), EDX)); + let cb14 = compile(|cb| add(cb, RSP, imm_opnd(8))); + let cb15 = compile(|cb| add(cb, ECX, imm_opnd(8))); + let cb16 = compile(|cb| add(cb, ECX, imm_opnd(255))); + + assert_snapshot!(cb01.disasm(), @" 0x0: add cl, 3"); + assert_snapshot!(cb02.disasm(), @" 0x0: add cl, bl"); + assert_snapshot!(cb03.disasm(), @" 0x0: add cl, spl"); + assert_snapshot!(cb04.disasm(), @" 0x0: add cx, bx"); + assert_snapshot!(cb05.disasm(), @" 0x0: add rax, rbx"); + assert_snapshot!(cb06.disasm(), @" 0x0: add ecx, edx"); + assert_snapshot!(cb07.disasm(), @" 0x0: add rdx, r14"); + assert_snapshot!(cb08.disasm(), @" 0x0: add qword ptr [rax], rdx"); + assert_snapshot!(cb09.disasm(), @" 0x0: add rdx, qword ptr [rax]"); + assert_snapshot!(cb10.disasm(), @" 0x0: add rdx, qword ptr [rax + 8]"); + assert_snapshot!(cb11.disasm(), @" 0x0: add rdx, qword ptr [rax + 0xff]"); + assert_snapshot!(cb12.disasm(), @" 0x0: add qword ptr [rax + 0x7f], 0xff"); + assert_snapshot!(cb13.disasm(), @" 0x0: add dword ptr [rax], edx"); + assert_snapshot!(cb14.disasm(), @" 0x0: add rsp, 8"); + assert_snapshot!(cb15.disasm(), @" 0x0: add ecx, 8"); + assert_snapshot!(cb16.disasm(), @" 0x0: add ecx, 0xff"); + + assert_snapshot!(cb01.string(), @"80c103"); + assert_snapshot!(cb02.string(), @"00d9"); + assert_snapshot!(cb03.string(), @"4000e1"); + assert_snapshot!(cb04.string(), @"6601d9"); + assert_snapshot!(cb05.string(), @"4801d8"); + assert_snapshot!(cb06.string(), @"01d1"); + assert_snapshot!(cb07.string(), @"4c01f2"); + assert_snapshot!(cb08.string(), @"480110"); + assert_snapshot!(cb09.string(), @"480310"); + assert_snapshot!(cb10.string(), @"48035008"); + assert_snapshot!(cb11.string(), @"480390ff000000"); + assert_snapshot!(cb12.string(), @"4881407fff000000"); + assert_snapshot!(cb13.string(), @"0110"); + assert_snapshot!(cb14.string(), @"4883c408"); + assert_snapshot!(cb15.string(), @"83c108"); + assert_snapshot!(cb16.string(), @"81c1ff000000"); } #[test] fn test_add_unsigned() { // ADD r/m8, imm8 - check_bytes("4180c001", |cb| add(cb, R8B, uimm_opnd(1))); - check_bytes("4180c07f", |cb| add(cb, R8B, imm_opnd(i8::MAX.into()))); - + let cb1 = compile(|cb| add(cb, R8B, uimm_opnd(1))); + let cb2 = compile(|cb| add(cb, R8B, imm_opnd(i8::MAX.into()))); // ADD r/m16, imm16 - check_bytes("664183c001", |cb| add(cb, R8W, uimm_opnd(1))); - check_bytes("664181c0ff7f", |cb| add(cb, R8W, uimm_opnd(i16::MAX.try_into().unwrap()))); - + let cb3 = compile(|cb| add(cb, R8W, uimm_opnd(1))); + let cb4 = compile(|cb| add(cb, R8W, uimm_opnd(i16::MAX.try_into().unwrap()))); // ADD r/m32, imm32 - check_bytes("4183c001", |cb| add(cb, R8D, uimm_opnd(1))); - check_bytes("4181c0ffffff7f", |cb| add(cb, R8D, uimm_opnd(i32::MAX.try_into().unwrap()))); - + let cb5 = compile(|cb| add(cb, R8D, uimm_opnd(1))); + let cb6 = compile(|cb| add(cb, R8D, uimm_opnd(i32::MAX.try_into().unwrap()))); // ADD r/m64, imm32 - check_bytes("4983c001", |cb| add(cb, R8, uimm_opnd(1))); - check_bytes("4981c0ffffff7f", |cb| add(cb, R8, uimm_opnd(i32::MAX.try_into().unwrap()))); + let cb7 = compile(|cb| add(cb, R8, uimm_opnd(1))); + let cb8 = compile(|cb| add(cb, R8, uimm_opnd(i32::MAX.try_into().unwrap()))); + + assert_snapshot!(cb1.disasm(), @" 0x0: add r8b, 1"); + assert_snapshot!(cb2.disasm(), @" 0x0: add r8b, 0x7f"); + assert_snapshot!(cb3.disasm(), @" 0x0: add r8w, 1"); + assert_snapshot!(cb4.disasm(), @" 0x0: add r8w, 0x7fff"); + assert_snapshot!(cb5.disasm(), @" 0x0: add r8d, 1"); + assert_snapshot!(cb6.disasm(), @" 0x0: add r8d, 0x7fffffff"); + assert_snapshot!(cb7.disasm(), @" 0x0: add r8, 1"); + assert_snapshot!(cb8.disasm(), @" 0x0: add r8, 0x7fffffff"); + + assert_snapshot!(cb1.string(), @"4180c001"); + assert_snapshot!(cb2.string(), @"4180c07f"); + assert_snapshot!(cb3.string(), @"664183c001"); + assert_snapshot!(cb4.string(), @"664181c0ff7f"); + assert_snapshot!(cb5.string(), @"4183c001"); + assert_snapshot!(cb6.string(), @"4181c0ffffff7f"); + assert_snapshot!(cb7.string(), @"4983c001"); + assert_snapshot!(cb8.string(), @"4981c0ffffff7f"); } #[test] fn test_and() { - check_bytes("4421e5", |cb| and(cb, EBP, R12D)); - check_bytes("48832008", |cb| and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08))); + let cb1 = compile(|cb| and(cb, EBP, R12D)); + let cb2 = compile(|cb| and(cb, mem_opnd(64, RAX, 0), imm_opnd(0x08))); + + assert_snapshot!(cb1.disasm(), @" 0x0: and ebp, r12d"); + assert_snapshot!(cb2.disasm(), @" 0x0: and qword ptr [rax], 8"); + + assert_snapshot!(cb1.string(), @"4421e5"); + assert_snapshot!(cb2.string(), @"48832008"); } #[test] fn test_call_label() { - check_bytes("e8fbffffff", |cb| { + let cb = compile(|cb| { let label_idx = cb.new_label("fn".to_owned()); call_label(cb, label_idx); cb.link_labels(); }); + assert_snapshot!(cb.disasm(), @" 0x0: call 0"); + assert_snapshot!(cb.string(), @"e8fbffffff"); } #[test] fn test_call_ptr() { // calling a lower address - check_bytes("e8fbffffff", |cb| { + let cb = compile(|cb| { let ptr = cb.get_write_ptr(); call_ptr(cb, RAX, ptr.raw_ptr(cb)); }); + assert_snapshot!(cb.disasm(), @" 0x0: call 0"); + assert_snapshot!(cb.string(), @"e8fbffffff"); } #[test] fn test_call_reg() { - check_bytes("ffd0", |cb| call(cb, RAX)); + let cb = compile(|cb| call(cb, RAX)); + assert_snapshot!(cb.disasm(), @" 0x0: call rax"); + assert_snapshot!(cb.string(), @"ffd0"); } #[test] fn test_call_mem() { - check_bytes("ff542408", |cb| call(cb, mem_opnd(64, RSP, 8))); + let cb = compile(|cb| call(cb, mem_opnd(64, RSP, 8))); + assert_snapshot!(cb.disasm(), @" 0x0: call qword ptr [rsp + 8]"); + assert_snapshot!(cb.string(), @"ff542408"); } #[test] fn test_cmovcc() { - check_bytes("0f4ff7", |cb| cmovg(cb, ESI, EDI)); - check_bytes("0f4f750c", |cb| cmovg(cb, ESI, mem_opnd(32, RBP, 12))); - check_bytes("0f4cc1", |cb| cmovl(cb, EAX, ECX)); - check_bytes("480f4cdd", |cb| cmovl(cb, RBX, RBP)); - check_bytes("0f4e742404", |cb| cmovle(cb, ESI, mem_opnd(32, RSP, 4))); + let cb1 = compile(|cb| cmovg(cb, ESI, EDI)); + let cb2 = compile(|cb| cmovg(cb, ESI, mem_opnd(32, RBP, 12))); + let cb3 = compile(|cb| cmovl(cb, EAX, ECX)); + let cb4 = compile(|cb| cmovl(cb, RBX, RBP)); + let cb5 = compile(|cb| cmovle(cb, ESI, mem_opnd(32, RSP, 4))); + + assert_snapshot!(cb1.disasm(), @" 0x0: cmovg esi, edi"); + assert_snapshot!(cb2.disasm(), @" 0x0: cmovg esi, dword ptr [rbp + 0xc]"); + assert_snapshot!(cb3.disasm(), @" 0x0: cmovl eax, ecx"); + assert_snapshot!(cb4.disasm(), @" 0x0: cmovl rbx, rbp"); + assert_snapshot!(cb5.disasm(), @" 0x0: cmovle esi, dword ptr [rsp + 4]"); + + assert_snapshot!(cb1.string(), @"0f4ff7"); + assert_snapshot!(cb2.string(), @"0f4f750c"); + assert_snapshot!(cb3.string(), @"0f4cc1"); + assert_snapshot!(cb4.string(), @"480f4cdd"); + assert_snapshot!(cb5.string(), @"0f4e742404"); } #[test] fn test_cmp() { - check_bytes("38d1", |cb| cmp(cb, CL, DL)); - check_bytes("39f9", |cb| cmp(cb, ECX, EDI)); - check_bytes("493b1424", |cb| cmp(cb, RDX, mem_opnd(64, R12, 0))); - check_bytes("4883f802", |cb| cmp(cb, RAX, imm_opnd(2))); - check_bytes("81f900000080", |cb| cmp(cb, ECX, uimm_opnd(0x8000_0000))); + let cb1 = compile(|cb| cmp(cb, CL, DL)); + let cb2 = compile(|cb| cmp(cb, ECX, EDI)); + let cb3 = compile(|cb| cmp(cb, RDX, mem_opnd(64, R12, 0))); + let cb4 = compile(|cb| cmp(cb, RAX, imm_opnd(2))); + let cb5 = compile(|cb| cmp(cb, ECX, uimm_opnd(0x8000_0000))); + + assert_snapshot!(cb1.disasm(), @" 0x0: cmp cl, dl"); + assert_snapshot!(cb2.disasm(), @" 0x0: cmp ecx, edi"); + assert_snapshot!(cb3.disasm(), @" 0x0: cmp rdx, qword ptr [r12]"); + assert_snapshot!(cb4.disasm(), @" 0x0: cmp rax, 2"); + assert_snapshot!(cb5.disasm(), @" 0x0: cmp ecx, 0x80000000"); + + assert_snapshot!(cb1.string(), @"38d1"); + assert_snapshot!(cb2.string(), @"39f9"); + assert_snapshot!(cb3.string(), @"493b1424"); + assert_snapshot!(cb4.string(), @"4883f802"); + assert_snapshot!(cb5.string(), @"81f900000080"); } #[test] fn test_cqo() { - check_bytes("4899", cqo); + let cb = compile(cqo); + assert_snapshot!(cb.disasm(), @" 0x0: cqo"); + assert_snapshot!(cb.string(), @"4899"); } #[test] fn test_imul() { - check_bytes("480fafc3", |cb| imul(cb, RAX, RBX)); - check_bytes("480faf10", |cb| imul(cb, RDX, mem_opnd(64, RAX, 0))); - + let cb1 = compile(|cb| imul(cb, RAX, RBX)); + let cb2 = compile(|cb| imul(cb, RDX, mem_opnd(64, RAX, 0))); // Operands flipped for encoding since multiplication is commutative - check_bytes("480faf10", |cb| imul(cb, mem_opnd(64, RAX, 0), RDX)); + let cb3 = compile(|cb| imul(cb, mem_opnd(64, RAX, 0), RDX)); + + assert_snapshot!(cb1.disasm(), @" 0x0: imul rax, rbx"); + assert_snapshot!(cb2.disasm(), @" 0x0: imul rdx, qword ptr [rax]"); + assert_snapshot!(cb3.disasm(), @" 0x0: imul rdx, qword ptr [rax]"); + + assert_snapshot!(cb1.string(), @"480fafc3"); + assert_snapshot!(cb2.string(), @"480faf10"); + assert_snapshot!(cb3.string(), @"480faf10"); } #[test] fn test_jge_label() { - check_bytes("0f8dfaffffff", |cb| { + let cb = compile(|cb| { let label_idx = cb.new_label("loop".to_owned()); jge_label(cb, label_idx); cb.link_labels(); }); + assert_snapshot!(cb.disasm(), @" 0x0: jge 0"); + assert_snapshot!(cb.string(), @"0f8dfaffffff"); } #[test] fn test_jmp_label() { // Forward jump - check_bytes("e900000000", |cb| { + let cb1 = compile(|cb| { let label_idx = cb.new_label("next".to_owned()); jmp_label(cb, label_idx); cb.write_label(label_idx); cb.link_labels(); }); - // Backwards jump - check_bytes("e9fbffffff", |cb| { + let cb2 = compile(|cb| { let label_idx = cb.new_label("loop".to_owned()); cb.write_label(label_idx); jmp_label(cb, label_idx); cb.link_labels(); }); + + assert_snapshot!(cb1.disasm(), @" 0x0: jmp 5"); + assert_snapshot!(cb2.disasm(), @" 0x0: jmp 0"); + + assert_snapshot!(cb1.string(), @"e900000000"); + assert_snapshot!(cb2.string(), @"e9fbffffff"); } #[test] fn test_jmp_rm() { - check_bytes("41ffe4", |cb| jmp_rm(cb, R12)); + let cb = compile(|cb| jmp_rm(cb, R12)); + assert_snapshot!(cb.disasm(), @" 0x0: jmp r12"); + assert_snapshot!(cb.string(), @"41ffe4"); } #[test] fn test_jo_label() { - check_bytes("0f80faffffff", |cb| { + let cb = compile(|cb| { let label_idx = cb.new_label("loop".to_owned()); jo_label(cb, label_idx); cb.link_labels(); }); + assert_snapshot!(cb.disasm(), @" 0x0: jo 0"); + assert_snapshot!(cb.string(), @"0f80faffffff"); } #[test] fn test_lea() { - check_bytes("488d5108", |cb| lea(cb, RDX, mem_opnd(64, RCX, 8))); - check_bytes("488d0500000000", |cb| lea(cb, RAX, mem_opnd(8, RIP, 0))); - check_bytes("488d0505000000", |cb| lea(cb, RAX, mem_opnd(8, RIP, 5))); - check_bytes("488d3d05000000", |cb| lea(cb, RDI, mem_opnd(8, RIP, 5))); + let cb1 = compile(|cb| lea(cb, RDX, mem_opnd(64, RCX, 8))); + let cb2 = compile(|cb| lea(cb, RAX, mem_opnd(8, RIP, 0))); + let cb3 = compile(|cb| lea(cb, RAX, mem_opnd(8, RIP, 5))); + let cb4 = compile(|cb| lea(cb, RDI, mem_opnd(8, RIP, 5))); + + assert_snapshot!(cb1.disasm(), @" 0x0: lea rdx, [rcx + 8]"); + assert_snapshot!(cb2.disasm(), @" 0x0: lea rax, [rip]"); + assert_snapshot!(cb3.disasm(), @" 0x0: lea rax, [rip + 5]"); + assert_snapshot!(cb4.disasm(), @" 0x0: lea rdi, [rip + 5]"); + + assert_snapshot!(cb1.string(), @"488d5108"); + assert_snapshot!(cb2.string(), @"488d0500000000"); + assert_snapshot!(cb3.string(), @"488d0505000000"); + assert_snapshot!(cb4.string(), @"488d3d05000000"); } #[test] fn test_mov() { - check_bytes("b807000000", |cb| mov(cb, EAX, imm_opnd(7))); - check_bytes("b8fdffffff", |cb| mov(cb, EAX, imm_opnd(-3))); - check_bytes("41bf03000000", |cb| mov(cb, R15, imm_opnd(3))); - check_bytes("89d8", |cb| mov(cb, EAX, EBX)); - check_bytes("89c8", |cb| mov(cb, EAX, ECX)); - check_bytes("8b9380000000", |cb| mov(cb, EDX, mem_opnd(32, RBX, 128))); - check_bytes("488b442404", |cb| mov(cb, RAX, mem_opnd(64, RSP, 4))); - + let cb01 = compile(|cb| mov(cb, EAX, imm_opnd(7))); + let cb02 = compile(|cb| mov(cb, EAX, imm_opnd(-3))); + let cb03 = compile(|cb| mov(cb, R15, imm_opnd(3))); + let cb04 = compile(|cb| mov(cb, EAX, EBX)); + let cb05 = compile(|cb| mov(cb, EAX, ECX)); + let cb06 = compile(|cb| mov(cb, EDX, mem_opnd(32, RBX, 128))); + let cb07 = compile(|cb| mov(cb, RAX, mem_opnd(64, RSP, 4))); // Test `mov rax, 3` => `mov eax, 3` optimization - check_bytes("41b834000000", |cb| mov(cb, R8, imm_opnd(0x34))); - check_bytes("49b80000008000000000", |cb| mov(cb, R8, imm_opnd(0x80000000))); - check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, imm_opnd(-1))); - - check_bytes("b834000000", |cb| mov(cb, RAX, imm_opnd(0x34))); - check_bytes("48b8020000000000c0ff", |cb| mov(cb, RAX, imm_opnd(-18014398509481982))); - check_bytes("48b80000008000000000", |cb| mov(cb, RAX, imm_opnd(0x80000000))); - check_bytes("48b8ccffffffffffffff", |cb| mov(cb, RAX, imm_opnd(-52))); // yasm thinks this could use a dword immediate instead of qword - check_bytes("48b8ffffffffffffffff", |cb| mov(cb, RAX, imm_opnd(-1))); // yasm thinks this could use a dword immediate instead of qword - check_bytes("4488c9", |cb| mov(cb, CL, R9B)); - check_bytes("4889c3", |cb| mov(cb, RBX, RAX)); - check_bytes("4889df", |cb| mov(cb, RDI, RBX)); - check_bytes("40b60b", |cb| mov(cb, SIL, imm_opnd(11))); - - check_bytes("c60424fd", |cb| mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3))); - check_bytes("48c7470801000000", |cb| mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1))); - //check_bytes("67c7400411000000", |cb| mov(cb, mem_opnd(32, EAX, 4), imm_opnd(0x34))); // We don't distinguish between EAX and RAX here - that's probably fine? - check_bytes("c7400411000000", |cb| mov(cb, mem_opnd(32, RAX, 4), imm_opnd(17))); - check_bytes("c7400401000080", |cb| mov(cb, mem_opnd(32, RAX, 4), uimm_opnd(0x80000001))); - check_bytes("41895814", |cb| mov(cb, mem_opnd(32, R8, 20), EBX)); - check_bytes("4d8913", |cb| mov(cb, mem_opnd(64, R11, 0), R10)); - check_bytes("48c742f8f4ffffff", |cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12))); + let cb08 = compile(|cb| mov(cb, R8, imm_opnd(0x34))); + let cb09 = compile(|cb| mov(cb, R8, imm_opnd(0x80000000))); + let cb10 = compile(|cb| mov(cb, R8, imm_opnd(-1))); + let cb11 = compile(|cb| mov(cb, RAX, imm_opnd(0x34))); + let cb12 = compile(|cb| mov(cb, RAX, imm_opnd(-18014398509481982))); + let cb13 = compile(|cb| mov(cb, RAX, imm_opnd(0x80000000))); + let cb14 = compile(|cb| mov(cb, RAX, imm_opnd(-52))); // yasm thinks this could use a dword immediate instead of qword + let cb15 = compile(|cb| mov(cb, RAX, imm_opnd(-1))); // yasm thinks this could use a dword immediate instead of qword + let cb16 = compile(|cb| mov(cb, CL, R9B)); + let cb17 = compile(|cb| mov(cb, RBX, RAX)); + let cb18 = compile(|cb| mov(cb, RDI, RBX)); + let cb19 = compile(|cb| mov(cb, SIL, imm_opnd(11))); + let cb20 = compile(|cb| mov(cb, mem_opnd(8, RSP, 0), imm_opnd(-3))); + let cb21 = compile(|cb| mov(cb, mem_opnd(64, RDI, 8), imm_opnd(1))); + //let cb = compile(|cb| mov(cb, mem_opnd(32, EAX, 4), imm_opnd(0x34))); // We don't distinguish between EAX and RAX here - that's probably fine? + let cb22 = compile(|cb| mov(cb, mem_opnd(32, RAX, 4), imm_opnd(17))); + let cb23 = compile(|cb| mov(cb, mem_opnd(32, RAX, 4), uimm_opnd(0x80000001))); + let cb24 = compile(|cb| mov(cb, mem_opnd(32, R8, 20), EBX)); + let cb25 = compile(|cb| mov(cb, mem_opnd(64, R11, 0), R10)); + let cb26 = compile(|cb| mov(cb, mem_opnd(64, RDX, -8), imm_opnd(-12))); + + assert_snapshot!(cb01.disasm(), @" 0x0: mov eax, 7"); + assert_snapshot!(cb02.disasm(), @" 0x0: mov eax, 0xfffffffd"); + assert_snapshot!(cb03.disasm(), @" 0x0: mov r15d, 3"); + assert_snapshot!(cb04.disasm(), @" 0x0: mov eax, ebx"); + assert_snapshot!(cb05.disasm(), @" 0x0: mov eax, ecx"); + assert_snapshot!(cb06.disasm(), @" 0x0: mov edx, dword ptr [rbx + 0x80]"); + assert_snapshot!(cb07.disasm(), @" 0x0: mov rax, qword ptr [rsp + 4]"); + assert_snapshot!(cb08.disasm(), @" 0x0: mov r8d, 0x34"); + assert_snapshot!(cb09.disasm(), @" 0x0: movabs r8, 0x80000000"); + assert_snapshot!(cb10.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); + assert_snapshot!(cb11.disasm(), @" 0x0: mov eax, 0x34"); + assert_snapshot!(cb12.disasm(), @" 0x0: movabs rax, 0xffc0000000000002"); + assert_snapshot!(cb13.disasm(), @" 0x0: movabs rax, 0x80000000"); + assert_snapshot!(cb14.disasm(), @" 0x0: movabs rax, 0xffffffffffffffcc"); + assert_snapshot!(cb15.disasm(), @" 0x0: movabs rax, 0xffffffffffffffff"); + assert_snapshot!(cb16.disasm(), @" 0x0: mov cl, r9b"); + assert_snapshot!(cb17.disasm(), @" 0x0: mov rbx, rax"); + assert_snapshot!(cb18.disasm(), @" 0x0: mov rdi, rbx"); + assert_snapshot!(cb19.disasm(), @" 0x0: mov sil, 0xb"); + assert_snapshot!(cb20.disasm(), @" 0x0: mov byte ptr [rsp], 0xfd"); + assert_snapshot!(cb21.disasm(), @" 0x0: mov qword ptr [rdi + 8], 1"); + assert_snapshot!(cb22.disasm(), @" 0x0: mov dword ptr [rax + 4], 0x11"); + assert_snapshot!(cb23.disasm(), @" 0x0: mov dword ptr [rax + 4], 0x80000001"); + assert_snapshot!(cb24.disasm(), @" 0x0: mov dword ptr [r8 + 0x14], ebx"); + assert_snapshot!(cb25.disasm(), @" 0x0: mov qword ptr [r11], r10"); + assert_snapshot!(cb26.disasm(), @" 0x0: mov qword ptr [rdx - 8], 0xfffffffffffffff4"); + + assert_snapshot!(cb01.string(), @"b807000000"); + assert_snapshot!(cb02.string(), @"b8fdffffff"); + assert_snapshot!(cb03.string(), @"41bf03000000"); + assert_snapshot!(cb04.string(), @"89d8"); + assert_snapshot!(cb05.string(), @"89c8"); + assert_snapshot!(cb06.string(), @"8b9380000000"); + assert_snapshot!(cb07.string(), @"488b442404"); + assert_snapshot!(cb08.string(), @"41b834000000"); + assert_snapshot!(cb09.string(), @"49b80000008000000000"); + assert_snapshot!(cb10.string(), @"49b8ffffffffffffffff"); + assert_snapshot!(cb11.string(), @"b834000000"); + assert_snapshot!(cb12.string(), @"48b8020000000000c0ff"); + assert_snapshot!(cb13.string(), @"48b80000008000000000"); + assert_snapshot!(cb14.string(), @"48b8ccffffffffffffff"); + assert_snapshot!(cb15.string(), @"48b8ffffffffffffffff"); + assert_snapshot!(cb16.string(), @"4488c9"); + assert_snapshot!(cb17.string(), @"4889c3"); + assert_snapshot!(cb18.string(), @"4889df"); + assert_snapshot!(cb19.string(), @"40b60b"); + assert_snapshot!(cb20.string(), @"c60424fd"); + assert_snapshot!(cb21.string(), @"48c7470801000000"); + assert_snapshot!(cb22.string(), @"c7400411000000"); + assert_snapshot!(cb23.string(), @"c7400401000080"); + assert_snapshot!(cb24.string(), @"41895814"); + assert_snapshot!(cb25.string(), @"4d8913"); + assert_snapshot!(cb26.string(), @"48c742f8f4ffffff"); } #[test] fn test_movabs() { - check_bytes("49b83400000000000000", |cb| movabs(cb, R8, 0x34)); - check_bytes("49b80000008000000000", |cb| movabs(cb, R8, 0x80000000)); + let cb1 = compile(|cb| movabs(cb, R8, 0x34)); + let cb2 = compile(|cb| movabs(cb, R8, 0x80000000)); + + assert_snapshot!(cb1.disasm(), @" 0x0: movabs r8, 0x34"); + assert_snapshot!(cb2.disasm(), @" 0x0: movabs r8, 0x80000000"); + + assert_snapshot!(cb1.string(), @"49b83400000000000000"); + assert_snapshot!(cb2.string(), @"49b80000008000000000"); } #[test] fn test_mov_unsigned() { // MOV AL, imm8 - check_bytes("b001", |cb| mov(cb, AL, uimm_opnd(1))); - check_bytes("b0ff", |cb| mov(cb, AL, uimm_opnd(u8::MAX.into()))); - + let cb01 = compile(|cb| mov(cb, AL, uimm_opnd(1))); + let cb02 = compile(|cb| mov(cb, AL, uimm_opnd(u8::MAX.into()))); // MOV AX, imm16 - check_bytes("66b80100", |cb| mov(cb, AX, uimm_opnd(1))); - check_bytes("66b8ffff", |cb| mov(cb, AX, uimm_opnd(u16::MAX.into()))); - + let cb03 = compile(|cb| mov(cb, AX, uimm_opnd(1))); + let cb04 = compile(|cb| mov(cb, AX, uimm_opnd(u16::MAX.into()))); // MOV EAX, imm32 - check_bytes("b801000000", |cb| mov(cb, EAX, uimm_opnd(1))); - check_bytes("b8ffffffff", |cb| mov(cb, EAX, uimm_opnd(u32::MAX.into()))); - check_bytes("41b800000000", |cb| mov(cb, R8, uimm_opnd(0))); - check_bytes("41b8ffffffff", |cb| mov(cb, R8, uimm_opnd(0xFF_FF_FF_FF))); - + let cb05 = compile(|cb| mov(cb, EAX, uimm_opnd(1))); + let cb06 = compile(|cb| mov(cb, EAX, uimm_opnd(u32::MAX.into()))); + let cb07 = compile(|cb| mov(cb, R8, uimm_opnd(0))); + let cb08 = compile(|cb| mov(cb, R8, uimm_opnd(0xFF_FF_FF_FF))); // MOV RAX, imm64, will move down into EAX since it fits into 32 bits - check_bytes("b801000000", |cb| mov(cb, RAX, uimm_opnd(1))); - check_bytes("b8ffffffff", |cb| mov(cb, RAX, uimm_opnd(u32::MAX.into()))); - + let cb09 = compile(|cb| mov(cb, RAX, uimm_opnd(1))); + let cb10 = compile(|cb| mov(cb, RAX, uimm_opnd(u32::MAX.into()))); // MOV RAX, imm64, will not move down into EAX since it does not fit into 32 bits - check_bytes("48b80000000001000000", |cb| mov(cb, RAX, uimm_opnd(u32::MAX as u64 + 1))); - check_bytes("48b8ffffffffffffffff", |cb| mov(cb, RAX, uimm_opnd(u64::MAX))); - check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, uimm_opnd(u64::MAX))); - + let cb11 = compile(|cb| mov(cb, RAX, uimm_opnd(u32::MAX as u64 + 1))); + let cb12 = compile(|cb| mov(cb, RAX, uimm_opnd(u64::MAX))); + let cb13 = compile(|cb| mov(cb, R8, uimm_opnd(u64::MAX))); // MOV r8, imm8 - check_bytes("41b001", |cb| mov(cb, R8B, uimm_opnd(1))); - check_bytes("41b0ff", |cb| mov(cb, R8B, uimm_opnd(u8::MAX.into()))); - + let cb14 = compile(|cb| mov(cb, R8B, uimm_opnd(1))); + let cb15 = compile(|cb| mov(cb, R8B, uimm_opnd(u8::MAX.into()))); // MOV r16, imm16 - check_bytes("6641b80100", |cb| mov(cb, R8W, uimm_opnd(1))); - check_bytes("6641b8ffff", |cb| mov(cb, R8W, uimm_opnd(u16::MAX.into()))); - + let cb16 = compile(|cb| mov(cb, R8W, uimm_opnd(1))); + let cb17 = compile(|cb| mov(cb, R8W, uimm_opnd(u16::MAX.into()))); // MOV r32, imm32 - check_bytes("41b801000000", |cb| mov(cb, R8D, uimm_opnd(1))); - check_bytes("41b8ffffffff", |cb| mov(cb, R8D, uimm_opnd(u32::MAX.into()))); - + let cb18 = compile(|cb| mov(cb, R8D, uimm_opnd(1))); + let cb19 = compile(|cb| mov(cb, R8D, uimm_opnd(u32::MAX.into()))); // MOV r64, imm64, will move down into 32 bit since it fits into 32 bits - check_bytes("41b801000000", |cb| mov(cb, R8, uimm_opnd(1))); - + let cb20 = compile(|cb| mov(cb, R8, uimm_opnd(1))); // MOV r64, imm64, will not move down into 32 bit since it does not fit into 32 bits - check_bytes("49b8ffffffffffffffff", |cb| mov(cb, R8, uimm_opnd(u64::MAX))); + let cb21 = compile(|cb| mov(cb, R8, uimm_opnd(u64::MAX))); + + assert_snapshot!(cb01.disasm(), @" 0x0: mov al, 1"); + assert_snapshot!(cb02.disasm(), @" 0x0: mov al, 0xff"); + assert_snapshot!(cb03.disasm(), @" 0x0: mov ax, 1"); + assert_snapshot!(cb04.disasm(), @" 0x0: mov ax, 0xffff"); + assert_snapshot!(cb05.disasm(), @" 0x0: mov eax, 1"); + assert_snapshot!(cb06.disasm(), @" 0x0: mov eax, 0xffffffff"); + assert_snapshot!(cb07.disasm(), @" 0x0: mov r8d, 0"); + assert_snapshot!(cb08.disasm(), @" 0x0: mov r8d, 0xffffffff"); + assert_snapshot!(cb09.disasm(), @" 0x0: mov eax, 1"); + assert_snapshot!(cb10.disasm(), @" 0x0: mov eax, 0xffffffff"); + assert_snapshot!(cb11.disasm(), @" 0x0: movabs rax, 0x100000000"); + assert_snapshot!(cb12.disasm(), @" 0x0: movabs rax, 0xffffffffffffffff"); + assert_snapshot!(cb13.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); + assert_snapshot!(cb14.disasm(), @" 0x0: mov r8b, 1"); + assert_snapshot!(cb15.disasm(), @" 0x0: mov r8b, 0xff"); + assert_snapshot!(cb16.disasm(), @" 0x0: mov r8w, 1"); + assert_snapshot!(cb17.disasm(), @" 0x0: mov r8w, 0xffff"); + assert_snapshot!(cb18.disasm(), @" 0x0: mov r8d, 1"); + assert_snapshot!(cb19.disasm(), @" 0x0: mov r8d, 0xffffffff"); + assert_snapshot!(cb20.disasm(), @" 0x0: mov r8d, 1"); + assert_snapshot!(cb21.disasm(), @" 0x0: movabs r8, 0xffffffffffffffff"); + + assert_snapshot!(cb01.string(), @"b001"); + assert_snapshot!(cb02.string(), @"b0ff"); + assert_snapshot!(cb03.string(), @"66b80100"); + assert_snapshot!(cb04.string(), @"66b8ffff"); + assert_snapshot!(cb05.string(), @"b801000000"); + assert_snapshot!(cb06.string(), @"b8ffffffff"); + assert_snapshot!(cb07.string(), @"41b800000000"); + assert_snapshot!(cb08.string(), @"41b8ffffffff"); + assert_snapshot!(cb09.string(), @"b801000000"); + assert_snapshot!(cb10.string(), @"b8ffffffff"); + assert_snapshot!(cb11.string(), @"48b80000000001000000"); + assert_snapshot!(cb12.string(), @"48b8ffffffffffffffff"); + assert_snapshot!(cb13.string(), @"49b8ffffffffffffffff"); + assert_snapshot!(cb14.string(), @"41b001"); + assert_snapshot!(cb15.string(), @"41b0ff"); + assert_snapshot!(cb16.string(), @"6641b80100"); + assert_snapshot!(cb17.string(), @"6641b8ffff"); + assert_snapshot!(cb18.string(), @"41b801000000"); + assert_snapshot!(cb19.string(), @"41b8ffffffff"); + assert_snapshot!(cb20.string(), @"41b801000000"); + assert_snapshot!(cb21.string(), @"49b8ffffffffffffffff"); } #[test] fn test_mov_iprel() { - check_bytes("8b0500000000", |cb| mov(cb, EAX, mem_opnd(32, RIP, 0))); - check_bytes("8b0505000000", |cb| mov(cb, EAX, mem_opnd(32, RIP, 5))); + let cb1 = compile(|cb| mov(cb, EAX, mem_opnd(32, RIP, 0))); + let cb2 = compile(|cb| mov(cb, EAX, mem_opnd(32, RIP, 5))); + let cb3 = compile(|cb| mov(cb, RAX, mem_opnd(64, RIP, 0))); + let cb4 = compile(|cb| mov(cb, RAX, mem_opnd(64, RIP, 5))); + let cb5 = compile(|cb| mov(cb, RDI, mem_opnd(64, RIP, 5))); + + assert_snapshot!(cb1.disasm(), @" 0x0: mov eax, dword ptr [rip]"); + assert_snapshot!(cb2.disasm(), @" 0x0: mov eax, dword ptr [rip + 5]"); + assert_snapshot!(cb3.disasm(), @" 0x0: mov rax, qword ptr [rip]"); + assert_snapshot!(cb4.disasm(), @" 0x0: mov rax, qword ptr [rip + 5]"); + assert_snapshot!(cb5.disasm(), @" 0x0: mov rdi, qword ptr [rip + 5]"); - check_bytes("488b0500000000", |cb| mov(cb, RAX, mem_opnd(64, RIP, 0))); - check_bytes("488b0505000000", |cb| mov(cb, RAX, mem_opnd(64, RIP, 5))); - check_bytes("488b3d05000000", |cb| mov(cb, RDI, mem_opnd(64, RIP, 5))); + assert_snapshot!(cb1.string(), @"8b0500000000"); + assert_snapshot!(cb2.string(), @"8b0505000000"); + assert_snapshot!(cb3.string(), @"488b0500000000"); + assert_snapshot!(cb4.string(), @"488b0505000000"); + assert_snapshot!(cb5.string(), @"488b3d05000000"); } #[test] fn test_movsx() { - check_bytes("660fbec0", |cb| movsx(cb, AX, AL)); - check_bytes("0fbed0", |cb| movsx(cb, EDX, AL)); - check_bytes("480fbec3", |cb| movsx(cb, RAX, BL)); - check_bytes("0fbfc8", |cb| movsx(cb, ECX, AX)); - check_bytes("4c0fbed9", |cb| movsx(cb, R11, CL)); - check_bytes("4c6354240c", |cb| movsx(cb, R10, mem_opnd(32, RSP, 12))); - check_bytes("480fbe0424", |cb| movsx(cb, RAX, mem_opnd(8, RSP, 0))); - check_bytes("490fbf5504", |cb| movsx(cb, RDX, mem_opnd(16, R13, 4))); + let cb1 = compile(|cb| movsx(cb, AX, AL)); + let cb2 = compile(|cb| movsx(cb, EDX, AL)); + let cb3 = compile(|cb| movsx(cb, RAX, BL)); + let cb4 = compile(|cb| movsx(cb, ECX, AX)); + let cb5 = compile(|cb| movsx(cb, R11, CL)); + let cb6 = compile(|cb| movsx(cb, R10, mem_opnd(32, RSP, 12))); + let cb7 = compile(|cb| movsx(cb, RAX, mem_opnd(8, RSP, 0))); + let cb8 = compile(|cb| movsx(cb, RDX, mem_opnd(16, R13, 4))); + + assert_snapshot!(cb1.disasm(), @" 0x0: movsx ax, al"); + assert_snapshot!(cb2.disasm(), @" 0x0: movsx edx, al"); + assert_snapshot!(cb3.disasm(), @" 0x0: movsx rax, bl"); + assert_snapshot!(cb4.disasm(), @" 0x0: movsx ecx, ax"); + assert_snapshot!(cb5.disasm(), @" 0x0: movsx r11, cl"); + assert_snapshot!(cb6.disasm(), @" 0x0: movsxd r10, dword ptr [rsp + 0xc]"); + assert_snapshot!(cb7.disasm(), @" 0x0: movsx rax, byte ptr [rsp]"); + assert_snapshot!(cb8.disasm(), @" 0x0: movsx rdx, word ptr [r13 + 4]"); + + assert_snapshot!(cb1.string(), @"660fbec0"); + assert_snapshot!(cb2.string(), @"0fbed0"); + assert_snapshot!(cb3.string(), @"480fbec3"); + assert_snapshot!(cb4.string(), @"0fbfc8"); + assert_snapshot!(cb5.string(), @"4c0fbed9"); + assert_snapshot!(cb6.string(), @"4c6354240c"); + assert_snapshot!(cb7.string(), @"480fbe0424"); + assert_snapshot!(cb8.string(), @"490fbf5504"); } #[test] fn test_nop() { - check_bytes("90", |cb| nop(cb, 1)); - check_bytes("6690", |cb| nop(cb, 2)); - check_bytes("0f1f00", |cb| nop(cb, 3)); - check_bytes("0f1f4000", |cb| nop(cb, 4)); - check_bytes("0f1f440000", |cb| nop(cb, 5)); - check_bytes("660f1f440000", |cb| nop(cb, 6)); - check_bytes("0f1f8000000000", |cb| nop(cb, 7)); - check_bytes("0f1f840000000000", |cb| nop(cb, 8)); - check_bytes("660f1f840000000000", |cb| nop(cb, 9)); - check_bytes("660f1f84000000000090", |cb| nop(cb, 10)); - check_bytes("660f1f8400000000006690", |cb| nop(cb, 11)); - check_bytes("660f1f8400000000000f1f00", |cb| nop(cb, 12)); + let cb01 = compile(|cb| nop(cb, 1)); + let cb02 = compile(|cb| nop(cb, 2)); + let cb03 = compile(|cb| nop(cb, 3)); + let cb04 = compile(|cb| nop(cb, 4)); + let cb05 = compile(|cb| nop(cb, 5)); + let cb06 = compile(|cb| nop(cb, 6)); + let cb07 = compile(|cb| nop(cb, 7)); + let cb08 = compile(|cb| nop(cb, 8)); + let cb09 = compile(|cb| nop(cb, 9)); + let cb10 = compile(|cb| nop(cb, 10)); + let cb11 = compile(|cb| nop(cb, 11)); + let cb12 = compile(|cb| nop(cb, 12)); + + assert_snapshot!(cb01.disasm(), @" 0x0: nop"); + assert_snapshot!(cb02.disasm(), @" 0x0: nop"); + assert_snapshot!(cb03.disasm(), @" 0x0: nop dword ptr [rax]"); + assert_snapshot!(cb04.disasm(), @" 0x0: nop dword ptr [rax]"); + assert_snapshot!(cb05.disasm(), @" 0x0: nop dword ptr [rax + rax]"); + assert_snapshot!(cb06.disasm(), @" 0x0: nop word ptr [rax + rax]"); + assert_snapshot!(cb07.disasm(), @" 0x0: nop dword ptr [rax]"); + assert_snapshot!(cb08.disasm(), @" 0x0: nop dword ptr [rax + rax]"); + assert_snapshot!(cb09.disasm(), @" 0x0: nop word ptr [rax + rax]"); + assert_snapshot!(cb10.disasm(), @r" + 0x0: nop word ptr [rax + rax] + 0x9: nop + "); + assert_snapshot!(cb11.disasm(), @r" + 0x0: nop word ptr [rax + rax] + 0x9: nop + "); + assert_snapshot!(cb12.disasm(), @r" + 0x0: nop word ptr [rax + rax] + 0x9: nop dword ptr [rax] + "); + + assert_snapshot!(cb01.string(), @"90"); + assert_snapshot!(cb02.string(), @"6690"); + assert_snapshot!(cb03.string(), @"0f1f00"); + assert_snapshot!(cb04.string(), @"0f1f4000"); + assert_snapshot!(cb05.string(), @"0f1f440000"); + assert_snapshot!(cb06.string(), @"660f1f440000"); + assert_snapshot!(cb07.string(), @"0f1f8000000000"); + assert_snapshot!(cb08.string(), @"0f1f840000000000"); + assert_snapshot!(cb09.string(), @"660f1f840000000000"); + assert_snapshot!(cb10.string(), @"660f1f84000000000090"); + assert_snapshot!(cb11.string(), @"660f1f8400000000006690"); + assert_snapshot!(cb12.string(), @"660f1f8400000000000f1f00"); } #[test] fn test_not() { - check_bytes("66f7d0", |cb| not(cb, AX)); - check_bytes("f7d0", |cb| not(cb, EAX)); - check_bytes("49f71424", |cb| not(cb, mem_opnd(64, R12, 0))); - check_bytes("f794242d010000", |cb| not(cb, mem_opnd(32, RSP, 301))); - check_bytes("f71424", |cb| not(cb, mem_opnd(32, RSP, 0))); - check_bytes("f7542403", |cb| not(cb, mem_opnd(32, RSP, 3))); - check_bytes("f75500", |cb| not(cb, mem_opnd(32, RBP, 0))); - check_bytes("f7550d", |cb| not(cb, mem_opnd(32, RBP, 13))); - check_bytes("48f7d0", |cb| not(cb, RAX)); - check_bytes("49f7d3", |cb| not(cb, R11)); - check_bytes("f710", |cb| not(cb, mem_opnd(32, RAX, 0))); - check_bytes("f716", |cb| not(cb, mem_opnd(32, RSI, 0))); - check_bytes("f717", |cb| not(cb, mem_opnd(32, RDI, 0))); - check_bytes("f75237", |cb| not(cb, mem_opnd(32, RDX, 55))); - check_bytes("f79239050000", |cb| not(cb, mem_opnd(32, RDX, 1337))); - check_bytes("f752c9", |cb| not(cb, mem_opnd(32, RDX, -55))); - check_bytes("f792d5fdffff", |cb| not(cb, mem_opnd(32, RDX, -555))); + let cb01 = compile(|cb| not(cb, AX)); + let cb02 = compile(|cb| not(cb, EAX)); + let cb03 = compile(|cb| not(cb, mem_opnd(64, R12, 0))); + let cb04 = compile(|cb| not(cb, mem_opnd(32, RSP, 301))); + let cb05 = compile(|cb| not(cb, mem_opnd(32, RSP, 0))); + let cb06 = compile(|cb| not(cb, mem_opnd(32, RSP, 3))); + let cb07 = compile(|cb| not(cb, mem_opnd(32, RBP, 0))); + let cb08 = compile(|cb| not(cb, mem_opnd(32, RBP, 13))); + let cb09 = compile(|cb| not(cb, RAX)); + let cb10 = compile(|cb| not(cb, R11)); + let cb11 = compile(|cb| not(cb, mem_opnd(32, RAX, 0))); + let cb12 = compile(|cb| not(cb, mem_opnd(32, RSI, 0))); + let cb13 = compile(|cb| not(cb, mem_opnd(32, RDI, 0))); + let cb14 = compile(|cb| not(cb, mem_opnd(32, RDX, 55))); + let cb15 = compile(|cb| not(cb, mem_opnd(32, RDX, 1337))); + let cb16 = compile(|cb| not(cb, mem_opnd(32, RDX, -55))); + let cb17 = compile(|cb| not(cb, mem_opnd(32, RDX, -555))); + + assert_snapshot!(cb01.disasm(), @" 0x0: not ax"); + assert_snapshot!(cb02.disasm(), @" 0x0: not eax"); + assert_snapshot!(cb03.disasm(), @" 0x0: not qword ptr [r12]"); + assert_snapshot!(cb04.disasm(), @" 0x0: not dword ptr [rsp + 0x12d]"); + assert_snapshot!(cb05.disasm(), @" 0x0: not dword ptr [rsp]"); + assert_snapshot!(cb06.disasm(), @" 0x0: not dword ptr [rsp + 3]"); + assert_snapshot!(cb07.disasm(), @" 0x0: not dword ptr [rbp]"); + assert_snapshot!(cb08.disasm(), @" 0x0: not dword ptr [rbp + 0xd]"); + assert_snapshot!(cb09.disasm(), @" 0x0: not rax"); + assert_snapshot!(cb10.disasm(), @" 0x0: not r11"); + assert_snapshot!(cb11.disasm(), @" 0x0: not dword ptr [rax]"); + assert_snapshot!(cb12.disasm(), @" 0x0: not dword ptr [rsi]"); + assert_snapshot!(cb13.disasm(), @" 0x0: not dword ptr [rdi]"); + assert_snapshot!(cb14.disasm(), @" 0x0: not dword ptr [rdx + 0x37]"); + assert_snapshot!(cb15.disasm(), @" 0x0: not dword ptr [rdx + 0x539]"); + assert_snapshot!(cb16.disasm(), @" 0x0: not dword ptr [rdx - 0x37]"); + assert_snapshot!(cb17.disasm(), @" 0x0: not dword ptr [rdx - 0x22b]"); + + assert_snapshot!(cb01.string(), @"66f7d0"); + assert_snapshot!(cb02.string(), @"f7d0"); + assert_snapshot!(cb03.string(), @"49f71424"); + assert_snapshot!(cb04.string(), @"f794242d010000"); + assert_snapshot!(cb05.string(), @"f71424"); + assert_snapshot!(cb06.string(), @"f7542403"); + assert_snapshot!(cb07.string(), @"f75500"); + assert_snapshot!(cb08.string(), @"f7550d"); + assert_snapshot!(cb09.string(), @"48f7d0"); + assert_snapshot!(cb10.string(), @"49f7d3"); + assert_snapshot!(cb11.string(), @"f710"); + assert_snapshot!(cb12.string(), @"f716"); + assert_snapshot!(cb13.string(), @"f717"); + assert_snapshot!(cb14.string(), @"f75237"); + assert_snapshot!(cb15.string(), @"f79239050000"); + assert_snapshot!(cb16.string(), @"f752c9"); + assert_snapshot!(cb17.string(), @"f792d5fdffff"); } #[test] fn test_or() { - check_bytes("09f2", |cb| or(cb, EDX, ESI)); + let cb = compile(|cb| or(cb, EDX, ESI)); + assert_snapshot!(cb.disasm(), @" 0x0: or edx, esi"); + assert_snapshot!(cb.string(), @"09f2"); } #[test] fn test_pop() { - check_bytes("58", |cb| pop(cb, RAX)); - check_bytes("5b", |cb| pop(cb, RBX)); - check_bytes("5c", |cb| pop(cb, RSP)); - check_bytes("5d", |cb| pop(cb, RBP)); - check_bytes("415c", |cb| pop(cb, R12)); - check_bytes("8f00", |cb| pop(cb, mem_opnd(64, RAX, 0))); - check_bytes("418f00", |cb| pop(cb, mem_opnd(64, R8, 0))); - check_bytes("418f4003", |cb| pop(cb, mem_opnd(64, R8, 3))); - check_bytes("8f44c803", |cb| pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); - check_bytes("418f44c803", |cb| pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + let cb01 = compile(|cb| pop(cb, RAX)); + let cb02 = compile(|cb| pop(cb, RBX)); + let cb03 = compile(|cb| pop(cb, RSP)); + let cb04 = compile(|cb| pop(cb, RBP)); + let cb05 = compile(|cb| pop(cb, R12)); + let cb06 = compile(|cb| pop(cb, mem_opnd(64, RAX, 0))); + let cb07 = compile(|cb| pop(cb, mem_opnd(64, R8, 0))); + let cb08 = compile(|cb| pop(cb, mem_opnd(64, R8, 3))); + let cb09 = compile(|cb| pop(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); + let cb10 = compile(|cb| pop(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + + assert_snapshot!(cb01.disasm(), @" 0x0: pop rax"); + assert_snapshot!(cb02.disasm(), @" 0x0: pop rbx"); + assert_snapshot!(cb03.disasm(), @" 0x0: pop rsp"); + assert_snapshot!(cb04.disasm(), @" 0x0: pop rbp"); + assert_snapshot!(cb05.disasm(), @" 0x0: pop r12"); + assert_snapshot!(cb06.disasm(), @" 0x0: pop qword ptr [rax]"); + assert_snapshot!(cb07.disasm(), @" 0x0: pop qword ptr [r8]"); + assert_snapshot!(cb08.disasm(), @" 0x0: pop qword ptr [r8 + 3]"); + assert_snapshot!(cb09.disasm(), @" 0x0: pop qword ptr [rax + rcx*8 + 3]"); + assert_snapshot!(cb10.disasm(), @" 0x0: pop qword ptr [r8 + rcx*8 + 3]"); + + assert_snapshot!(cb01.string(), @"58"); + assert_snapshot!(cb02.string(), @"5b"); + assert_snapshot!(cb03.string(), @"5c"); + assert_snapshot!(cb04.string(), @"5d"); + assert_snapshot!(cb05.string(), @"415c"); + assert_snapshot!(cb06.string(), @"8f00"); + assert_snapshot!(cb07.string(), @"418f00"); + assert_snapshot!(cb08.string(), @"418f4003"); + assert_snapshot!(cb09.string(), @"8f44c803"); + assert_snapshot!(cb10.string(), @"418f44c803"); } #[test] fn test_push() { - check_bytes("50", |cb| push(cb, RAX)); - check_bytes("53", |cb| push(cb, RBX)); - check_bytes("4154", |cb| push(cb, R12)); - check_bytes("ff30", |cb| push(cb, mem_opnd(64, RAX, 0))); - check_bytes("41ff30", |cb| push(cb, mem_opnd(64, R8, 0))); - check_bytes("41ff7003", |cb| push(cb, mem_opnd(64, R8, 3))); - check_bytes("ff74c803", |cb| push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); - check_bytes("41ff74c803", |cb| push(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + let cb1 = compile(|cb| push(cb, RAX)); + let cb2 = compile(|cb| push(cb, RBX)); + let cb3 = compile(|cb| push(cb, R12)); + let cb4 = compile(|cb| push(cb, mem_opnd(64, RAX, 0))); + let cb5 = compile(|cb| push(cb, mem_opnd(64, R8, 0))); + let cb6 = compile(|cb| push(cb, mem_opnd(64, R8, 3))); + let cb7 = compile(|cb| push(cb, mem_opnd_sib(64, RAX, RCX, 8, 3))); + let cb8 = compile(|cb| push(cb, mem_opnd_sib(64, R8, RCX, 8, 3))); + + assert_snapshot!(cb1.disasm(), @" 0x0: push rax"); + assert_snapshot!(cb2.disasm(), @" 0x0: push rbx"); + assert_snapshot!(cb3.disasm(), @" 0x0: push r12"); + assert_snapshot!(cb4.disasm(), @" 0x0: push qword ptr [rax]"); + assert_snapshot!(cb5.disasm(), @" 0x0: push qword ptr [r8]"); + assert_snapshot!(cb6.disasm(), @" 0x0: push qword ptr [r8 + 3]"); + assert_snapshot!(cb7.disasm(), @" 0x0: push qword ptr [rax + rcx*8 + 3]"); + assert_snapshot!(cb8.disasm(), @" 0x0: push qword ptr [r8 + rcx*8 + 3]"); + + assert_snapshot!(cb1.string(), @"50"); + assert_snapshot!(cb2.string(), @"53"); + assert_snapshot!(cb3.string(), @"4154"); + assert_snapshot!(cb4.string(), @"ff30"); + assert_snapshot!(cb5.string(), @"41ff30"); + assert_snapshot!(cb6.string(), @"41ff7003"); + assert_snapshot!(cb7.string(), @"ff74c803"); + assert_snapshot!(cb8.string(), @"41ff74c803"); } #[test] fn test_ret() { - check_bytes("c3", ret); + let cb = compile(ret); + assert_snapshot!(cb.disasm(), @" 0x0: ret"); + assert_snapshot!(cb.string(), @"c3"); } #[test] fn test_sal() { - check_bytes("66d1e1", |cb| sal(cb, CX, uimm_opnd(1))); - check_bytes("d1e1", |cb| sal(cb, ECX, uimm_opnd(1))); - check_bytes("c1e505", |cb| sal(cb, EBP, uimm_opnd(5))); - check_bytes("d1642444", |cb| sal(cb, mem_opnd(32, RSP, 68), uimm_opnd(1))); - check_bytes("48d3e1", |cb| sal(cb, RCX, CL)); + let cb1 = compile(|cb| sal(cb, CX, uimm_opnd(1))); + let cb2 = compile(|cb| sal(cb, ECX, uimm_opnd(1))); + let cb3 = compile(|cb| sal(cb, EBP, uimm_opnd(5))); + let cb4 = compile(|cb| sal(cb, mem_opnd(32, RSP, 68), uimm_opnd(1))); + let cb5 = compile(|cb| sal(cb, RCX, CL)); + + assert_snapshot!(cb1.disasm(), @" 0x0: shl cx, 1"); + assert_snapshot!(cb2.disasm(), @" 0x0: shl ecx, 1"); + assert_snapshot!(cb3.disasm(), @" 0x0: shl ebp, 5"); + assert_snapshot!(cb4.disasm(), @" 0x0: shl dword ptr [rsp + 0x44], 1"); + assert_snapshot!(cb5.disasm(), @" 0x0: shl rcx, cl"); + + assert_snapshot!(cb1.string(), @"66d1e1"); + assert_snapshot!(cb2.string(), @"d1e1"); + assert_snapshot!(cb3.string(), @"c1e505"); + assert_snapshot!(cb4.string(), @"d1642444"); + assert_snapshot!(cb5.string(), @"48d3e1"); } #[test] fn test_sar() { - check_bytes("d1fa", |cb| sar(cb, EDX, uimm_opnd(1))); + let cb = compile(|cb| sar(cb, EDX, uimm_opnd(1))); + assert_snapshot!(cb.disasm(), @" 0x0: sar edx, 1"); + assert_snapshot!(cb.string(), @"d1fa"); } #[test] fn test_shr() { - check_bytes("49c1ee07", |cb| shr(cb, R14, uimm_opnd(7))); + let cb = compile(|cb| shr(cb, R14, uimm_opnd(7))); + assert_snapshot!(cb.disasm(), @" 0x0: shr r14, 7"); + assert_snapshot!(cb.string(), @"49c1ee07"); } #[test] fn test_sub() { - check_bytes("83e801", |cb| sub(cb, EAX, imm_opnd(1))); - check_bytes("4883e802", |cb| sub(cb, RAX, imm_opnd(2))); + let cb1 = compile(|cb| sub(cb, EAX, imm_opnd(1))); + let cb2 = compile(|cb| sub(cb, RAX, imm_opnd(2))); + + assert_snapshot!(cb1.disasm(), @" 0x0: sub eax, 1"); + assert_snapshot!(cb2.disasm(), @" 0x0: sub rax, 2"); + + assert_snapshot!(cb1.string(), @"83e801"); + assert_snapshot!(cb2.string(), @"4883e802"); } #[test] @@ -374,44 +757,95 @@ fn test_sub() { fn test_sub_uimm_too_large() { // This immediate becomes a different value after // sign extension, so not safe to encode. - check_bytes("ff", |cb| sub(cb, RCX, uimm_opnd(0x8000_0000))); + compile(|cb| sub(cb, RCX, uimm_opnd(0x8000_0000))); } #[test] fn test_test() { - check_bytes("84c0", |cb| test(cb, AL, AL)); - check_bytes("6685c0", |cb| test(cb, AX, AX)); - check_bytes("f6c108", |cb| test(cb, CL, uimm_opnd(8))); - check_bytes("f6c207", |cb| test(cb, DL, uimm_opnd(7))); - check_bytes("f6c108", |cb| test(cb, RCX, uimm_opnd(8))); - check_bytes("f6420808", |cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(8))); - check_bytes("f64208ff", |cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(255))); - check_bytes("66f7c2ffff", |cb| test(cb, DX, uimm_opnd(0xffff))); - check_bytes("66f74208ffff", |cb| test(cb, mem_opnd(16, RDX, 8), uimm_opnd(0xffff))); - check_bytes("f60601", |cb| test(cb, mem_opnd(8, RSI, 0), uimm_opnd(1))); - check_bytes("f6461001", |cb| test(cb, mem_opnd(8, RSI, 16), uimm_opnd(1))); - check_bytes("f646f001", |cb| test(cb, mem_opnd(8, RSI, -16), uimm_opnd(1))); - check_bytes("854640", |cb| test(cb, mem_opnd(32, RSI, 64), EAX)); - check_bytes("4885472a", |cb| test(cb, mem_opnd(64, RDI, 42), RAX)); - check_bytes("4885c0", |cb| test(cb, RAX, RAX)); - check_bytes("4885f0", |cb| test(cb, RAX, RSI)); - check_bytes("48f74640f7ffffff", |cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(!0x08))); - check_bytes("48f7464008000000", |cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(0x08))); - check_bytes("48f7c108000000", |cb| test(cb, RCX, imm_opnd(0x08))); - //check_bytes("48a9f7ffff0f", |cb| test(cb, RAX, imm_opnd(0x0FFFFFF7))); + let cb01 = compile(|cb| test(cb, AL, AL)); + let cb02 = compile(|cb| test(cb, AX, AX)); + let cb03 = compile(|cb| test(cb, CL, uimm_opnd(8))); + let cb04 = compile(|cb| test(cb, DL, uimm_opnd(7))); + let cb05 = compile(|cb| test(cb, RCX, uimm_opnd(8))); + let cb06 = compile(|cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(8))); + let cb07 = compile(|cb| test(cb, mem_opnd(8, RDX, 8), uimm_opnd(255))); + let cb08 = compile(|cb| test(cb, DX, uimm_opnd(0xffff))); + let cb09 = compile(|cb| test(cb, mem_opnd(16, RDX, 8), uimm_opnd(0xffff))); + let cb10 = compile(|cb| test(cb, mem_opnd(8, RSI, 0), uimm_opnd(1))); + let cb11 = compile(|cb| test(cb, mem_opnd(8, RSI, 16), uimm_opnd(1))); + let cb12 = compile(|cb| test(cb, mem_opnd(8, RSI, -16), uimm_opnd(1))); + let cb13 = compile(|cb| test(cb, mem_opnd(32, RSI, 64), EAX)); + let cb14 = compile(|cb| test(cb, mem_opnd(64, RDI, 42), RAX)); + let cb15 = compile(|cb| test(cb, RAX, RAX)); + let cb16 = compile(|cb| test(cb, RAX, RSI)); + let cb17 = compile(|cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(!0x08))); + let cb18 = compile(|cb| test(cb, mem_opnd(64, RSI, 64), imm_opnd(0x08))); + let cb19 = compile(|cb| test(cb, RCX, imm_opnd(0x08))); + + assert_snapshot!(cb01.disasm(), @" 0x0: test al, al"); + assert_snapshot!(cb02.disasm(), @" 0x0: test ax, ax"); + assert_snapshot!(cb03.disasm(), @" 0x0: test cl, 8"); + assert_snapshot!(cb04.disasm(), @" 0x0: test dl, 7"); + assert_snapshot!(cb05.disasm(), @" 0x0: test cl, 8"); + assert_snapshot!(cb06.disasm(), @" 0x0: test byte ptr [rdx + 8], 8"); + assert_snapshot!(cb07.disasm(), @" 0x0: test byte ptr [rdx + 8], 0xff"); + assert_snapshot!(cb08.disasm(), @" 0x0: test dx, 0xffff"); + assert_snapshot!(cb09.disasm(), @" 0x0: test word ptr [rdx + 8], 0xffff"); + assert_snapshot!(cb10.disasm(), @" 0x0: test byte ptr [rsi], 1"); + assert_snapshot!(cb11.disasm(), @" 0x0: test byte ptr [rsi + 0x10], 1"); + assert_snapshot!(cb12.disasm(), @" 0x0: test byte ptr [rsi - 0x10], 1"); + assert_snapshot!(cb13.disasm(), @" 0x0: test dword ptr [rsi + 0x40], eax"); + assert_snapshot!(cb14.disasm(), @" 0x0: test qword ptr [rdi + 0x2a], rax"); + assert_snapshot!(cb15.disasm(), @" 0x0: test rax, rax"); + assert_snapshot!(cb16.disasm(), @" 0x0: test rax, rsi"); + assert_snapshot!(cb17.disasm(), @" 0x0: test qword ptr [rsi + 0x40], -9"); + assert_snapshot!(cb18.disasm(), @" 0x0: test qword ptr [rsi + 0x40], 8"); + assert_snapshot!(cb19.disasm(), @" 0x0: test rcx, 8"); + + assert_snapshot!(cb01.string(), @"84c0"); + assert_snapshot!(cb02.string(), @"6685c0"); + assert_snapshot!(cb03.string(), @"f6c108"); + assert_snapshot!(cb04.string(), @"f6c207"); + assert_snapshot!(cb05.string(), @"f6c108"); + assert_snapshot!(cb06.string(), @"f6420808"); + assert_snapshot!(cb07.string(), @"f64208ff"); + assert_snapshot!(cb08.string(), @"66f7c2ffff"); + assert_snapshot!(cb09.string(), @"66f74208ffff"); + assert_snapshot!(cb10.string(), @"f60601"); + assert_snapshot!(cb11.string(), @"f6461001"); + assert_snapshot!(cb12.string(), @"f646f001"); + assert_snapshot!(cb13.string(), @"854640"); + assert_snapshot!(cb14.string(), @"4885472a"); + assert_snapshot!(cb15.string(), @"4885c0"); + assert_snapshot!(cb16.string(), @"4885f0"); + assert_snapshot!(cb17.string(), @"48f74640f7ffffff"); + assert_snapshot!(cb18.string(), @"48f7464008000000"); + assert_snapshot!(cb19.string(), @"48f7c108000000"); } #[test] fn test_xchg() { - check_bytes("4891", |cb| xchg(cb, RAX, RCX)); - check_bytes("4995", |cb| xchg(cb, RAX, R13)); - check_bytes("4887d9", |cb| xchg(cb, RCX, RBX)); - check_bytes("4d87f9", |cb| xchg(cb, R9, R15)); + let cb1 = compile(|cb| xchg(cb, RAX, RCX)); + let cb2 = compile(|cb| xchg(cb, RAX, R13)); + let cb3 = compile(|cb| xchg(cb, RCX, RBX)); + let cb4 = compile(|cb| xchg(cb, R9, R15)); + + assert_snapshot!(cb1.disasm(), @" 0x0: xchg rcx, rax"); + assert_snapshot!(cb2.disasm(), @" 0x0: xchg r13, rax"); + assert_snapshot!(cb3.disasm(), @" 0x0: xchg rcx, rbx"); + assert_snapshot!(cb4.disasm(), @" 0x0: xchg r9, r15"); + + assert_snapshot!(cb1.string(), @"4891"); + assert_snapshot!(cb2.string(), @"4995"); + assert_snapshot!(cb3.string(), @"4887d9"); + assert_snapshot!(cb4.string(), @"4d87f9"); } #[test] fn test_xor() { - check_bytes("31c0", |cb| xor(cb, EAX, EAX)); + let cb = compile(|cb| xor(cb, EAX, EAX)); + assert_snapshot!(cb.disasm(), @" 0x0: xor eax, eax"); + assert_snapshot!(cb.string(), @"31c0"); } #[test] @@ -437,25 +871,3 @@ fn basic_capstone_usage() -> std::result::Result<(), capstone::Error> { )), } } - -#[test] -#[ignore] -#[cfg(feature = "disasm")] -fn block_comments() { - let mut cb = super::CodeBlock::new_dummy(); - - let first_write_ptr = cb.get_write_ptr().raw_addr(&cb); - cb.add_comment("Beginning"); - xor(&mut cb, EAX, EAX); // 2 bytes long - let second_write_ptr = cb.get_write_ptr().raw_addr(&cb); - cb.add_comment("Two bytes in"); - cb.add_comment("Still two bytes in"); - cb.add_comment("Still two bytes in"); // Duplicate, should be ignored - test(&mut cb, mem_opnd(64, RSI, 64), imm_opnd(!0x08)); // 8 bytes long - let third_write_ptr = cb.get_write_ptr().raw_addr(&cb); - cb.add_comment("Ten bytes in"); - - assert_eq!(&vec!( "Beginning".to_string() ), cb.comments_at(first_write_ptr).unwrap()); - assert_eq!(&vec!( "Two bytes in".to_string(), "Still two bytes in".to_string() ), cb.comments_at(second_write_ptr).unwrap()); - assert_eq!(&vec!( "Ten bytes in".to_string() ), cb.comments_at(third_write_ptr).unwrap()); -} diff --git a/zjit/src/assertions.rs b/zjit/src/assertions.rs deleted file mode 100644 index 0dacc938fc..0000000000 --- a/zjit/src/assertions.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// Assert that CodeBlock has the code specified with hex. In addition, if tested with -/// `cargo test --all-features`, it also checks it generates the specified disasm. -#[cfg(test)] -macro_rules! assert_disasm { - ($cb:expr, $hex:expr, $disasm:expr) => { - #[cfg(feature = "disasm")] - { - use $crate::disasm::disasm_addr_range; - use $crate::cruby::unindent; - let disasm = disasm_addr_range( - &$cb, - $cb.get_ptr(0).raw_addr(&$cb), - $cb.get_write_ptr().raw_addr(&$cb), - ); - assert_eq!(unindent(&disasm, false), unindent(&$disasm, true)); - } - assert_eq!(format!("{:x}", $cb), $hex); - }; -} -#[cfg(test)] -pub(crate) use assert_disasm; diff --git a/zjit/src/backend/arm64/mod.rs b/zjit/src/backend/arm64/mod.rs index 50e7074de1..b1b898f38d 100644 --- a/zjit/src/backend/arm64/mod.rs +++ b/zjit/src/backend/arm64/mod.rs @@ -1425,7 +1425,7 @@ fn merge_three_reg_mov( #[cfg(test)] mod tests { use super::*; - use crate::assertions::assert_disasm; + use insta::assert_snapshot; static TEMP_REGS: [Reg; 5] = [X1_REG, X9_REG, X10_REG, X14_REG, X15_REG]; @@ -1441,11 +1441,12 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "600080d2207d009be10300aa", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #3 0x4: mul x0, x9, x0 0x8: mov x1, x0 - "}); + "); + assert_snapshot!(cb.string(), @"600080d2207d009be10300aa"); } #[test] @@ -1459,10 +1460,11 @@ mod tests { asm.mov(sp, new_sp); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "ff830091ff8300d1", " + assert_snapshot!(cb.disasm(), @" 0x0: add sp, sp, #0x20 0x4: sub sp, sp, #0x20 "); + assert_snapshot!(cb.string(), @"ff830091ff8300d1"); } #[test] @@ -1474,10 +1476,11 @@ mod tests { asm.add_into(Opnd::Reg(X20_REG), 0x20.into()); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "ff230091948200b1", " + assert_snapshot!(cb.disasm(), @" 0x0: add sp, sp, #8 0x4: adds x20, x20, #0x20 "); + assert_snapshot!(cb.string(), @"ff230091948200b1"); } #[test] @@ -1488,11 +1491,12 @@ mod tests { asm.load_into(Opnd::Reg(X1_REG), difference); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "000180d2000005ebe10300aa", " + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #8 0x4: subs x0, x0, x5 0x8: mov x1, x0 "); + assert_snapshot!(cb.string(), @"000180d2000005ebe10300aa"); } #[test] @@ -1503,10 +1507,11 @@ mod tests { asm.cret(ret_val); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "000040f8c0035fd6", " + assert_snapshot!(cb.disasm(), @" 0x0: ldur x0, [x0] 0x4: ret "); + assert_snapshot!(cb.string(), @"000040f8c0035fd6"); } #[test] @@ -1567,7 +1572,7 @@ mod tests { asm.frame_setup(THREE_REGS, 3); asm.frame_teardown(THREE_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "fd7bbfa9fd030091f44fbfa9f5831ff8ff8300d1b44f7fa9b5835ef8bf030091fd7bc1a8", " + assert_snapshot!(cb.disasm(), @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1578,6 +1583,7 @@ mod tests { 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 "); + assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ff8300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); } // Test 3 preserved regs (odd), even slot_count @@ -1586,7 +1592,7 @@ mod tests { asm.frame_setup(THREE_REGS, 4); asm.frame_teardown(THREE_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "fd7bbfa9fd030091f44fbfa9f5831ff8ffc300d1b44f7fa9b5835ef8bf030091fd7bc1a8", " + assert_snapshot!(cb.disasm(), @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1597,6 +1603,7 @@ mod tests { 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 "); + assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f5831ff8ffc300d1b44f7fa9b5835ef8bf030091fd7bc1a8"); } // Test 4 preserved regs (even), odd slot_count @@ -1606,7 +1613,7 @@ mod tests { asm.frame_setup(FOUR_REGS, 3); asm.frame_teardown(FOUR_REGS); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "fd7bbfa9fd030091f44fbfa9f657bfa9ff8300d1b44f7fa9b6577ea9bf030091fd7bc1a8", " + assert_snapshot!(cb.disasm(), @" 0x0: stp x29, x30, [sp, #-0x10]! 0x4: mov x29, sp 0x8: stp x20, x19, [sp, #-0x10]! @@ -1617,6 +1624,7 @@ mod tests { 0x1c: mov sp, x29 0x20: ldp x29, x30, [sp], #0x10 "); + assert_snapshot!(cb.string(), @"fd7bbfa9fd030091f44fbfa9f657bfa9ff8300d1b44f7fa9b6577ea9bf030091fd7bc1a8"); } } @@ -1656,7 +1664,7 @@ mod tests { } asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "e07b40b2e063208b000180d22000a0f2e063208b000083d2e063208be0230891e02308d1e0ff8292e063208b00ff9fd2c0ffbff2e0ffdff2e0fffff2e063208be08361b2e063208b", " + assert_snapshot!(cb.disasm(), @r" 0x0: orr x0, xzr, #0x7fffffff 0x4: add x0, sp, x0 0x8: mov x0, #8 @@ -1676,6 +1684,7 @@ mod tests { 0x40: orr x0, xzr, #0xffffffff80000000 0x44: add x0, sp, x0 "); + assert_snapshot!(cb.string(), @"e07b40b2e063208b000180d22000a0f2e063208b000083d2e063208be0230891e02308d1e0ff8292e063208b00ff9fd2c0ffbff2e0ffdff2e0fffff2e063208be08361b2e063208b"); } #[test] @@ -1690,7 +1699,7 @@ mod tests { asm.store(large_mem, large_mem); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8", " + assert_snapshot!(cb.disasm(), @" 0x0: sub x16, sp, #0x305 0x4: ldur x16, [x16] 0x8: stur x16, [x0] @@ -1702,6 +1711,7 @@ mod tests { 0x20: sub x17, sp, #0x305 0x24: stur x16, [x17] "); + assert_snapshot!(cb.string(), @"f0170cd1100240f8100000f8100040f8f1170cd1300200f8f0170cd1100240f8f1170cd1300200f8"); } #[test] @@ -1717,13 +1727,14 @@ mod tests { let gc_offsets = asm.arm64_emit(&mut cb).unwrap(); assert_eq!(1, gc_offsets.len(), "VALUE source operand should be reported as gc offset"); - assert_disasm!(cb, "50000058030000140010000000000000b00200f8", " + assert_snapshot!(cb.disasm(), @" 0x0: ldr x16, #8 0x4: b #0x10 0x8: .byte 0x00, 0x10, 0x00, 0x00 0xc: .byte 0x00, 0x00, 0x00, 0x00 0x10: stur x16, [x21] "); + assert_snapshot!(cb.string(), @"50000058030000140010000000000000b00200f8"); } #[test] @@ -1968,10 +1979,11 @@ mod tests { asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "000001ca400000f8", " + assert_snapshot!(cb.disasm(), @" 0x0: eor x0, x0, x1 0x4: stur x0, [x2] "); + assert_snapshot!(cb.string(), @"000001ca400000f8"); } #[test] @@ -2005,9 +2017,8 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), Opnd::mem(64, CFP, 8)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "618240f8", {" - 0x0: ldur x1, [x19, #8] - "}); + assert_snapshot!(cb.disasm(), @" 0x0: ldur x1, [x19, #8]"); + assert_snapshot!(cb.string(), @"618240f8"); } #[test] @@ -2018,10 +2029,11 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), Opnd::UImm(0x10000)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "e1ff9fd2e10370b2", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x1, #0xffff 0x4: orr x1, xzr, #0x10000 - "}); + "); + assert_snapshot!(cb.string(), @"e1ff9fd2e10370b2"); } #[test] @@ -2032,11 +2044,12 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "800280d2010080d201b0819a", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x0, #0x14 0x4: mov x1, #0 0x8: csel x1, x0, x1, lt - "}); + "); + assert_snapshot!(cb.string(), @"800280d2010080d201b0819a"); } #[test] @@ -2074,10 +2087,11 @@ mod tests { asm.mov(Opnd::Reg(TEMP_REGS[0]), out); asm.compile_with_num_regs(&mut cb, 2); - assert_disasm!(cb, "200500b1010400b1", {" + assert_snapshot!(cb.disasm(), @" 0x0: adds x0, x9, #1 0x4: adds x1, x0, #1 - "}); + "); + assert_snapshot!(cb.string(), @"200500b1010400b1"); } #[test] @@ -2091,10 +2105,11 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, #0 0x4: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"100080d200023fd6"); } #[test] @@ -2110,13 +2125,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "f00300aae00301aae10310aa100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, x0 0x4: mov x0, x1 0x8: mov x1, x16 0xc: mov x16, #0 0x10: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"f00300aae00301aae10310aa100080d200023fd6"); } #[test] @@ -2133,7 +2149,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "f00302aae20303aae30310aaf00300aae00301aae10310aa100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, x2 0x4: mov x2, x3 0x8: mov x3, x16 @@ -2142,7 +2158,8 @@ mod tests { 0x14: mov x1, x16 0x18: mov x16, #0 0x1c: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"f00302aae20303aae30310aaf00300aae00301aae10310aa100080d200023fd6"); } #[test] @@ -2158,14 +2175,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "f00300aae00301aae10302aae20310aa100080d200023fd6", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov x16, x0 0x4: mov x0, x1 0x8: mov x1, x2 0xc: mov x2, x16 0x10: mov x16, #0 0x14: blr x16 - "}); + "); + assert_snapshot!(cb.string(), @"f00300aae00301aae10302aae20310aa100080d200023fd6"); } - } diff --git a/zjit/src/backend/x86_64/mod.rs b/zjit/src/backend/x86_64/mod.rs index b18510c29a..0443095509 100644 --- a/zjit/src/backend/x86_64/mod.rs +++ b/zjit/src/backend/x86_64/mod.rs @@ -919,7 +919,7 @@ impl Assembler #[cfg(test)] mod tests { - use crate::assertions::assert_disasm; + use insta::assert_snapshot; use super::*; fn setup_asm() -> (Assembler, CodeBlock) { @@ -934,7 +934,11 @@ mod tests { let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881c0ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: add rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881c0ff000000"); } #[test] @@ -945,7 +949,12 @@ mod tests { let _ = asm.add(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c01d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: add rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c01d8"); } #[test] @@ -956,7 +965,11 @@ mod tests { let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881e0ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: and rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881e0ff000000"); } #[test] @@ -967,7 +980,12 @@ mod tests { let _ = asm.and(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c21d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: and rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c21d8"); } #[test] @@ -977,9 +995,8 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "4881f8ff000000", " - 0x0: cmp rax, 0xff - "); + assert_snapshot!(cb.disasm(), @" 0x0: cmp rax, 0xff"); + assert_snapshot!(cb.string(), @"4881f8ff000000"); } #[test] @@ -989,10 +1006,11 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "49bbffffffffffff00004c39d8", " - 0x0: movabs r11, 0xffffffffffff - 0xa: cmp rax, r11 + assert_snapshot!(cb.disasm(), @r" + 0x0: movabs r11, 0xffffffffffff + 0xa: cmp rax, r11 "); + assert_snapshot!(cb.string(), @"49bbffffffffffff00004c39d8"); } #[test] @@ -1002,9 +1020,8 @@ mod tests { asm.cmp(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "4883f8ff", " - 0x0: cmp rax, -1 - "); + assert_snapshot!(cb.disasm(), @" 0x0: cmp rax, -1"); + assert_snapshot!(cb.string(), @"4883f8ff"); } #[test] @@ -1016,7 +1033,8 @@ mod tests { asm.cmp(shape_opnd, Opnd::UImm(0xF000)); asm.compile_with_num_regs(&mut cb, 0); - assert_eq!(format!("{:x}", cb), "6681780600f0"); + assert_snapshot!(cb.disasm(), @" 0x0: cmp word ptr [rax + 6], 0xf000"); + assert_snapshot!(cb.string(), @"6681780600f0"); } #[test] @@ -1028,7 +1046,8 @@ mod tests { asm.cmp(shape_opnd, Opnd::UImm(0xF000_0000)); asm.compile_with_num_regs(&mut cb, 0); - assert_eq!(format!("{:x}", cb), "817804000000f0"); + assert_snapshot!(cb.disasm(), @" 0x0: cmp dword ptr [rax + 4], 0xf0000000"); + assert_snapshot!(cb.string(), @"817804000000f0"); } #[test] @@ -1039,7 +1058,11 @@ mod tests { let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881c8ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: or rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881c8ff000000"); } #[test] @@ -1050,7 +1073,12 @@ mod tests { let _ = asm.or(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c09d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: or rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c09d8"); } #[test] @@ -1061,7 +1089,11 @@ mod tests { let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881e8ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: sub rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881e8ff000000"); } #[test] @@ -1072,7 +1104,12 @@ mod tests { let _ = asm.sub(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c29d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: sub rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c29d8"); } #[test] @@ -1082,9 +1119,8 @@ mod tests { asm.test(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "48f7c0ff000000", " - 0x0: test rax, 0xff - "); + assert_snapshot!(cb.disasm(), @" 0x0: test rax, 0xff"); + assert_snapshot!(cb.string(), @"48f7c0ff000000"); } #[test] @@ -1094,7 +1130,11 @@ mod tests { asm.test(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 0); - assert_eq!(format!("{:x}", cb), "49bbffffffffffff00004c85d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: movabs r11, 0xffffffffffff + 0xa: test rax, r11 + "); + assert_snapshot!(cb.string(), @"49bbffffffffffff00004c85d8"); } #[test] @@ -1105,7 +1145,11 @@ mod tests { let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c04881f0ff000000"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: xor rax, 0xff + "); + assert_snapshot!(cb.string(), @"4889c04881f0ff000000"); } #[test] @@ -1116,7 +1160,12 @@ mod tests { let _ = asm.xor(Opnd::Reg(RAX_REG), Opnd::UImm(0xFFFF_FFFF_FFFF)); asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4889c049bbffffffffffff00004c31d8"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, rax + 0x3: movabs r11, 0xffffffffffff + 0xd: xor rax, r11 + "); + assert_snapshot!(cb.string(), @"4889c049bbffffffffffff00004c31d8"); } #[test] @@ -1127,9 +1176,8 @@ mod tests { asm.mov(SP, sp); // should be merged to lea asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "488d5b08", {" - 0x0: lea rbx, [rbx + 8] - "}); + assert_snapshot!(cb.disasm(), @" 0x0: lea rbx, [rbx + 8]"); + assert_snapshot!(cb.string(), @"488d5b08"); } #[test] @@ -1141,10 +1189,11 @@ mod tests { asm.mov(Opnd::mem(64, SP, 0), sp); // should NOT be merged to lea asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "488d4308488903", {" - 0x0: lea rax, [rbx + 8] - 0x4: mov qword ptr [rbx], rax - "}); + assert_snapshot!(cb.disasm(), @r" + 0x0: movabs r11, 0xffffffffffff + 0xa: cmp rax, r11 + "); + assert_snapshot!(cb.string(), @"49bbffffffffffff00004c39d8"); } #[test] @@ -1158,7 +1207,15 @@ mod tests { asm.mov(Opnd::Reg(RAX_REG), result); asm.compile_with_num_regs(&mut cb, 2); - assert_eq!(format!("{:x}", cb), "488b43084885c0b814000000b900000000480f45c14889c0"); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov rax, qword ptr [rbx + 8] + 0x4: test rax, rax + 0x7: mov eax, 0x14 + 0xc: mov ecx, 0 + 0x11: cmovne rax, rcx + 0x15: mov rax, rax + "); + assert_snapshot!(cb.string(), @"488b43084885c0b814000000b900000000480f45c14889c0"); } #[test] @@ -1169,9 +1226,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983c540", {" - 0x0: add r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); + assert_snapshot!(cb.string(), @"4983c540"); } #[test] @@ -1181,9 +1237,8 @@ mod tests { asm.add_into(CFP, Opnd::UImm(0x40)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983c540", {" - 0x0: add r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: add r13, 0x40"); + assert_snapshot!(cb.string(), @"4983c540"); } #[test] @@ -1194,9 +1249,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983ed40", {" - 0x0: sub r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); + assert_snapshot!(cb.string(), @"4983ed40"); } #[test] @@ -1206,9 +1260,8 @@ mod tests { asm.sub_into(CFP, Opnd::UImm(0x40)); asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "4983ed40", {" - 0x0: sub r13, 0x40 - "}); + assert_snapshot!(cb.disasm(), @" 0x0: sub r13, 0x40"); + assert_snapshot!(cb.string(), @"4983ed40"); } #[test] @@ -1219,7 +1272,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983e540"); + assert_snapshot!(cb.disasm(), @" 0x0: and r13, 0x40"); + assert_snapshot!(cb.string(), @"4983e540"); } #[test] @@ -1230,7 +1284,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983cd40"); + assert_snapshot!(cb.disasm(), @" 0x0: or r13, 0x40"); + assert_snapshot!(cb.string(), @"4983cd40"); } #[test] @@ -1241,7 +1296,8 @@ mod tests { asm.mov(CFP, sp); // should be merged to add asm.compile_with_num_regs(&mut cb, 1); - assert_eq!(format!("{:x}", cb), "4983f540"); + assert_snapshot!(cb.disasm(), @" 0x0: xor r13, 0x40"); + assert_snapshot!(cb.string(), @"4983f540"); } #[test] @@ -1255,10 +1311,11 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "b800000000ffd0", {" - 0x0: mov eax, 0 - 0x5: call rax - "}); + assert_snapshot!(cb.disasm(), @r" + 0x0: mov eax, 0 + 0x5: call rax + "); + assert_snapshot!(cb.string(), @"b800000000ffd0"); } #[test] @@ -1274,13 +1331,14 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "4989f34889fe4c89dfb800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov r11, rsi 0x3: mov rsi, rdi 0x6: mov rdi, r11 0x9: mov eax, 0 0xe: call rax - "}); + "); + assert_snapshot!(cb.string(), @"4989f34889fe4c89dfb800000000ffd0"); } #[test] @@ -1297,7 +1355,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "4989f34889fe4c89df4989cb4889d14c89dab800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov r11, rsi 0x3: mov rsi, rdi 0x6: mov rdi, r11 @@ -1306,7 +1364,8 @@ mod tests { 0xf: mov rdx, r11 0x12: mov eax, 0 0x17: call rax - "}); + "); + assert_snapshot!(cb.string(), @"4989f34889fe4c89df4989cb4889d14c89dab800000000ffd0"); } #[test] @@ -1322,14 +1381,15 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, ALLOC_REGS.len()); - assert_disasm!(cb, "4989f34889d64889fa4c89dfb800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov r11, rsi 0x3: mov rsi, rdx 0x6: mov rdx, rdi 0x9: mov rdi, r11 0xc: mov eax, 0 0x11: call rax - "}); + "); + assert_snapshot!(cb.string(), @"4989f34889d64889fa4c89dfb800000000ffd0"); } #[test] @@ -1349,7 +1409,7 @@ mod tests { ]); asm.compile_with_num_regs(&mut cb, 3); - assert_disasm!(cb, "b801000000b902000000ba030000004889c74889ce4989cb4889d14c89dab800000000ffd0", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov eax, 1 0x5: mov ecx, 2 0xa: mov edx, 3 @@ -1360,7 +1420,8 @@ mod tests { 0x1b: mov rdx, r11 0x1e: mov eax, 0 0x23: call rax - "}); + "); + assert_snapshot!(cb.string(), @"b801000000b902000000ba030000004889c74889ce4989cb4889d14c89dab800000000ffd0"); } #[test] @@ -1377,12 +1438,13 @@ mod tests { asm.compile_with_num_regs(&mut cb, 1); - assert_disasm!(cb, "48837b1001bf04000000480f4f3b48893b", {" + assert_snapshot!(cb.disasm(), @" 0x0: cmp qword ptr [rbx + 0x10], 1 0x5: mov edi, 4 0xa: cmovg rdi, qword ptr [rbx] 0xe: mov qword ptr [rbx], rdi - "}); + "); + assert_snapshot!(cb.string(), @"48837b1001bf04000000480f4f3b48893b"); } #[test] @@ -1396,12 +1458,13 @@ mod tests { asm.compile_with_num_regs(&mut cb, 3); - assert_disasm!(cb, "48b830198dc8227f0000b904000000480f44c1488903", {" + assert_snapshot!(cb.disasm(), @" 0x0: movabs rax, 0x7f22c88d1930 0xa: mov ecx, 4 0xf: cmove rax, rcx 0x13: mov qword ptr [rbx], rax - "}); + "); + assert_snapshot!(cb.string(), @"48b830198dc8227f0000b904000000480f44c1488903"); } #[test] @@ -1413,10 +1476,11 @@ mod tests { asm.mov(shape_opnd, Opnd::Imm(0x8000_0001)); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "c70001000080c70001000080", {" + assert_snapshot!(cb.disasm(), @" 0x0: mov dword ptr [rax], 0x80000001 0x6: mov dword ptr [rax], 0x80000001 - "}); + "); + assert_snapshot!(cb.string(), @"c70001000080c70001000080"); } #[test] @@ -1431,7 +1495,7 @@ mod tests { asm.frame_teardown(&[]); asm.compile_with_num_regs(&mut cb, 0); - assert_disasm!(cb, "554889e541555341544883ec084c8b6df8488b5df04c8b65e84889ec5dc3554889e54883ec304889ec5d", {" + assert_snapshot!(cb.disasm(), @" 0x0: push rbp 0x1: mov rbp, rsp 0x4: push r13 @@ -1449,7 +1513,8 @@ mod tests { 0x22: sub rsp, 0x30 0x26: mov rsp, rbp 0x29: pop rbp - "}); + "); + assert_snapshot!(cb.string(), @"554889e541555341544883ec084c8b6df8488b5df04c8b65e84889ec5dc3554889e54883ec304889ec5d"); } #[test] @@ -1463,9 +1528,10 @@ mod tests { let gc_offsets = asm.x86_emit(&mut cb).unwrap(); assert_eq!(1, gc_offsets.len(), "VALUE source operand should be reported as gc offset"); - assert_disasm!(cb, "49bb00100000000000004c891b", " + assert_snapshot!(cb.disasm(), @" 0x0: movabs r11, 0x1000 0xa: mov qword ptr [rbx], r11 "); + assert_snapshot!(cb.string(), @"49bb00100000000000004c891b"); } } diff --git a/zjit/src/lib.rs b/zjit/src/lib.rs index e6f743fa1e..e58cf2bec4 100644 --- a/zjit/src/lib.rs +++ b/zjit/src/lib.rs @@ -26,7 +26,5 @@ mod disasm; mod options; mod profile; mod invariants; -#[cfg(test)] -mod assertions; mod bitset; mod gc; -- cgit v1.2.3