You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1217 lines
31 KiB

//! Interpreter tests.
use interp::Val;
use pulley_interpreter::{interp::Vm, *};
use std::{cell::UnsafeCell, fmt::Debug, ptr::NonNull};
fn encoded(ops: &[Op]) -> Vec<u8> {
let mut encoded = vec![];
for op in ops {
op.encode(&mut encoded);
}
log::trace!("encoded: {encoded:?}");
encoded
}
unsafe fn run(vm: &mut Vm, ops: &[Op]) -> Result<(), *mut u8> {
let _ = env_logger::try_init();
let ops = encoded(ops);
let _ = vm.call(NonNull::from(&ops[..]).cast(), &[], [])?;
Ok(())
}
unsafe fn assert_one<R0, R1, V>(
xs: impl IntoIterator<Item = (R0, V)>,
op: impl Into<Op> + Debug,
result: R1,
expected: u64,
) where
R0: Into<AnyReg>,
R1: Into<AnyReg>,
V: Into<Val>,
{
eprintln!("=======================================================");
let mut vm = Vm::new();
for (reg, val) in xs {
let reg = reg.into();
let val = val.into();
eprintln!("{reg} = {val:#018x}");
match (reg, val) {
(AnyReg::X(r), Val::XReg(v)) => vm.state_mut()[r] = v,
(AnyReg::F(r), Val::FReg(v)) => vm.state_mut()[r] = v,
(AnyReg::V(_), Val::VReg(_)) => todo!(),
(kind, val) => panic!("register kind and value mismatch: {kind:?} and {val:?}"),
}
}
eprintln!("op = {op:?}");
let op = op.into();
run(&mut vm, &[op, Op::Ret(Ret {})]).expect("should not trap");
eprintln!("expected = {expected:#018x}");
let actual = match result.into() {
AnyReg::X(r) => vm.state_mut()[r].get_u64(),
AnyReg::F(r) => vm.state_mut()[r].get_f64().to_bits(),
AnyReg::V(_) => todo!(),
};
eprintln!("actual = {actual:#018x}");
assert_eq!(expected, actual);
}
fn x(x: u8) -> XReg {
XReg::new(x).unwrap()
}
fn f(f: u8) -> FReg {
FReg::new(f).unwrap()
}
#[test]
fn xconst8() {
for (expected, imm) in [(42u64, 42i8), (u64::MAX, -1i8)] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678u64)],
Xconst8 { dst: x(0), imm },
x(0),
expected,
);
}
}
}
#[test]
fn xconst16() {
for (expected, imm) in [(42u64, 42i16), (u64::MAX, -1i16)] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678u64)],
Xconst16 { dst: x(0), imm },
x(0),
expected,
);
}
}
}
#[test]
fn xconst32() {
for (expected, imm) in [(42u64, 42i32), (u64::MAX, -1i32)] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678u64)],
Xconst32 { dst: x(0), imm },
x(0),
expected,
);
}
}
}
#[test]
fn xconst64() {
for (expected, imm) in [(42u64, 42i64), (u64::MAX, -1i64)] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678u64)],
Xconst64 { dst: x(0), imm },
x(0),
expected,
);
}
}
}
#[test]
fn xadd32() {
for (expected, a, b) in [
(42u64 | 0x1234567800000000, 10u64, 32u64),
(0x1234567800000000, u32::MAX as _, 1),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xadd32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xadd64() {
for (expected, a, b) in [(42u64, 10u64, 32u64), (0, u64::MAX, 1)] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xadd64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xeq64() {
for (expected, a, b) in [
(1u64, 0u64, 0u64),
(0, 0, 1),
(1, u64::MAX, u64::MAX),
(0, u64::MAX, u64::MAX - 1),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xeq64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xneq64() {
for (expected, a, b) in [
(0u64, 0u64, 0u64),
(1, 0, 1),
(0, u64::MAX, u64::MAX),
(1, u64::MAX, u64::MAX - 1),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xneq64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xslt64() {
for (expected, a, b) in [
(0u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, 0, -1 as _),
(1, -1 as _, 0),
(0, i64::MAX as u64, i64::MAX as u64),
(0, i64::MAX as u64, i64::MAX as u64 - 1),
(1, i64::MAX as u64 - 1, i64::MAX as u64),
(0, i64::MIN as u64, i64::MIN as u64),
(0, i64::MIN as u64 + 1, i64::MIN as u64),
(1, i64::MIN as u64, i64::MIN as u64 + 1),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xslt64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xslteq64() {
for (expected, a, b) in [
(1u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, 0, -1 as _),
(1, -1 as _, 0),
(1, i64::MAX as u64, i64::MAX as u64),
(0, i64::MAX as u64, i64::MAX as u64 - 1),
(1, i64::MAX as u64 - 1, i64::MAX as u64),
(1, i64::MIN as u64, i64::MIN as u64),
(0, i64::MIN as u64 + 1, i64::MIN as u64),
(1, i64::MIN as u64, i64::MIN as u64 + 1),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xslteq64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xult64() {
for (expected, a, b) in [
(0u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, u64::MAX, u64::MAX),
(0, u64::MAX, u64::MAX - 1),
(1, u64::MAX - 1, u64::MAX),
(0, i64::MIN as u64, 0),
(1, 0, i64::MIN as u64),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xult64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xulteq64() {
for (expected, a, b) in [
(1u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(1, u64::MAX, u64::MAX),
(0, u64::MAX, u64::MAX - 1),
(1, u64::MAX - 1, u64::MAX),
(0, i64::MIN as u64, 0),
(1, 0, i64::MIN as u64),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xulteq64 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xeq32() {
for (expected, a, b) in [
(1u64, 0u64, 0u64),
(0, 0, 1),
(1, u64::MAX, u64::MAX),
(0, u64::MAX, u64::MAX - 1),
(1, 0xffffffff00000001, 1),
(0, 0xffffffff00000000, 1),
(0, 0xffffffff00000001, 0),
(1, 0xffffffff00000000, 0),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xeq32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xneq32() {
for (expected, a, b) in [
(0u64, 0u64, 0u64),
(1, 0, 1),
(0, u64::MAX, u64::MAX),
(1, u64::MAX, u64::MAX - 1),
(0, 0xffffffff00000000, 0),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xneq32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xslt32() {
for (expected, a, b) in [
(0u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, 0, -1 as _),
(1, -1 as _, 0),
(0, i64::MAX as u64, i64::MAX as u64),
(0, i64::MAX as u64, i64::MAX as u64 - 1),
(1, i64::MAX as u64 - 1, i64::MAX as u64),
(0, i64::MIN as u64, i64::MIN as u64),
(0, i64::MIN as u64 + 1, i64::MIN as u64),
(1, i64::MIN as u64, i64::MIN as u64 + 1),
(1, 0x00000000ffffffff, 0),
(0, 0, 0x00000000ffffffff),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xslt32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xslteq32() {
for (expected, a, b) in [
(1u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, 0, -1 as _),
(1, -1 as _, 0),
(1, i64::MAX as u64, i64::MAX as u64),
(0, i64::MAX as u64, i64::MAX as u64 - 1),
(1, i64::MAX as u64 - 1, i64::MAX as u64),
(1, i64::MIN as u64, i64::MIN as u64),
(0, i64::MIN as u64 + 1, i64::MIN as u64),
(1, i64::MIN as u64, i64::MIN as u64 + 1),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xslteq32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xult32() {
for (expected, a, b) in [
(0u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, 0x00000000ffffffff, 0xfffffffffffffffe),
(1, 0xfffffffffffffffe, 0x00000000ffffffff),
(0, 0x00000000ffffffff, 0xffffffffffffffff),
(0, 0xfffffffffffffffe, 0x00000000fffffffe),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xult32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn xulteq32() {
for (expected, a, b) in [
(1u64, 0u64, 0u64),
(0, 1, 0),
(1, 0, 1),
(0, 0x00000000ffffffff, 0xfffffffffffffffe),
(1, 0xfffffffffffffffe, 0x00000000ffffffff),
(1, 0x00000000ffffffff, 0xffffffffffffffff),
(1, 0xfffffffffffffffe, 0x00000000fffffffe),
] {
unsafe {
assert_one(
[(x(0), 0x1234567812345678), (x(1), a), (x(2), b)],
Xulteq32 {
operands: BinaryOperands {
dst: x(0),
src1: x(1),
src2: x(2),
},
},
x(0),
expected,
);
}
}
}
#[test]
fn load32_u() {
let a = UnsafeCell::new(11u32);
let b = UnsafeCell::new(22u32);
let c = UnsafeCell::new(33u32);
let d = UnsafeCell::new(i32::MIN as u32);
for (expected, addr) in [
(11, a.get()),
(22, b.get()),
(33, c.get()),
(i32::MIN as u32 as u64, d.get()),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr.cast::<u8>())),
],
Load32U {
dst: x(0),
ptr: x(1),
},
x(0),
expected,
);
}
}
}
#[test]
fn load32_s() {
let a = UnsafeCell::new(11u32);
let b = UnsafeCell::new(22u32);
let c = UnsafeCell::new(33u32);
let d = UnsafeCell::new(-1i32 as u32);
for (expected, addr) in [
(11, a.get()),
(22, b.get()),
(33, c.get()),
(-1i64 as u64, d.get()),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr.cast::<u8>())),
],
Load32S {
dst: x(0),
ptr: x(1),
},
x(0),
expected,
);
}
}
}
#[test]
fn load64() {
let a = UnsafeCell::new(11u64);
let b = UnsafeCell::new(22u64);
let c = UnsafeCell::new(33u64);
let d = UnsafeCell::new(-1i64 as u64);
for (expected, addr) in [
(11, a.get()),
(22, b.get()),
(33, c.get()),
(-1i64 as u64, d.get()),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr)),
],
Load64 {
dst: x(0),
ptr: x(1),
},
x(0),
expected,
);
}
}
}
#[test]
fn load32_u_offset8() {
let a = UnsafeCell::new([11u32, 22]);
let b = UnsafeCell::new([33u32, 44]);
let c = UnsafeCell::new([55u32, 66]);
let d = UnsafeCell::new([i32::MIN as u32, i32::MAX as u32]);
for (expected, addr, offset) in [
(11, a.get(), 0),
(22, a.get(), 4),
(33, b.get(), 0),
(44, b.get(), 4),
(55, c.get(), 0),
(66, c.get(), 4),
(i32::MIN as u32 as u64, d.get(), 0),
(i32::MAX as u32 as u64, d.get(), 4),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr.cast::<u8>())),
],
Load32UOffset8 {
dst: x(0),
ptr: x(1),
offset,
},
x(0),
expected,
);
}
}
}
#[test]
fn load32_s_offset8() {
let a = UnsafeCell::new([11u32, 22]);
let b = UnsafeCell::new([33u32, 44]);
let c = UnsafeCell::new([55u32, 66]);
let d = UnsafeCell::new([-1i32 as u32, i32::MAX as u32]);
for (expected, addr, offset) in [
(11, a.get(), 0),
(22, a.get(), 4),
(33, b.get(), 0),
(44, b.get(), 4),
(55, c.get(), 0),
(55, unsafe { c.get().byte_add(4) }, -4),
(66, c.get(), 4),
(-1i64 as u64, d.get(), 0),
(i32::MAX as u32 as u64, d.get(), 4),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr.cast::<u8>())),
],
Load32SOffset8 {
dst: x(0),
ptr: x(1),
offset,
},
x(0),
expected,
);
}
}
}
#[test]
fn load64_offset8() {
let a = UnsafeCell::new([11u64, 22]);
let b = UnsafeCell::new([33u64, 44]);
let c = UnsafeCell::new([55u64, 66]);
let d = UnsafeCell::new([-1i64 as u64, i64::MAX as u64]);
for (expected, addr, offset) in [
(11, a.get(), 0),
(22, a.get(), 8),
(33, b.get(), 0),
(44, b.get(), 8),
(55, c.get(), 0),
(66, c.get(), 8),
(-1i64 as u64, d.get(), 0),
(i64::MAX as u64, d.get(), 8),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr)),
],
Load64Offset8 {
dst: x(0),
ptr: x(1),
offset,
},
x(0),
expected,
);
}
}
}
#[test]
fn load32_u_offset64() {
let a = UnsafeCell::new([11u32, 22]);
let b = UnsafeCell::new([33u32, 44]);
let c = UnsafeCell::new([55u32, 66]);
let d = UnsafeCell::new([i32::MIN as u32, i32::MAX as u32]);
for (expected, addr, offset) in [
(11, a.get(), 0),
(22, a.get(), 4),
(33, b.get(), 0),
(44, b.get(), 4),
(55, c.get(), 0),
(66, c.get(), 4),
(i32::MIN as u32 as u64, d.get(), 0),
(i32::MAX as u32 as u64, d.get(), 4),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr.cast::<u8>())),
],
Load32UOffset64 {
dst: x(0),
ptr: x(1),
offset,
},
x(0),
expected,
);
}
}
}
#[test]
fn load32_s_offset64() {
let a = UnsafeCell::new([11u32, 22]);
let b = UnsafeCell::new([33u32, 44]);
let c = UnsafeCell::new([55u32, 66]);
let d = UnsafeCell::new([-1i32 as u32, i32::MAX as u32]);
for (expected, addr, offset) in [
(11, a.get(), 0),
(22, a.get(), 4),
(33, b.get(), 0),
(44, b.get(), 4),
(55, c.get(), 0),
(55, unsafe { c.get().byte_add(4) }, -4),
(66, c.get(), 4),
(-1i64 as u64, d.get(), 0),
(i32::MAX as u32 as u64, d.get(), 4),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr.cast::<u8>())),
],
Load32SOffset64 {
dst: x(0),
ptr: x(1),
offset,
},
x(0),
expected,
);
}
}
}
#[test]
fn load64_offset64() {
let a = UnsafeCell::new([11u64, 22]);
let b = UnsafeCell::new([33u64, 44]);
let c = UnsafeCell::new([55u64, 66]);
let d = UnsafeCell::new([-1i64 as u64, i64::MAX as u64]);
for (expected, addr, offset) in [
(11, a.get(), 0),
(22, a.get(), 8),
(33, b.get(), 0),
(44, b.get(), 8),
(55, c.get(), 0),
(66, c.get(), 8),
(-1i64 as u64, d.get(), 0),
(i64::MAX as u64, d.get(), 8),
] {
unsafe {
assert_one(
[
(x(0), Val::from(0x1234567812345678u64)),
(x(1), Val::from(addr)),
],
Load64Offset64 {
dst: x(0),
ptr: x(1),
offset,
},
x(0),
expected,
);
}
}
}
#[test]
fn store32() {
let a = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
let b = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
let c = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
unsafe {
for (val, addr) in [
(0x11111111u32, a.get()),
(0x22222222, b.get().byte_add(4)),
(0x33333333, c.get().byte_add(2)),
] {
let val = val as u64;
assert_one(
[(x(0), Val::from(addr)), (x(1), Val::from(val))],
Store32 {
ptr: x(0),
src: x(1),
},
x(1),
val,
);
}
}
let a = u64::from_be_bytes(a.into_inner());
let expected = 0x1111111112345678u64;
eprintln!("expected(a) = {expected:#018x}");
eprintln!("actual(a) = {a:#018x}");
assert_eq!(a, expected);
let b = u64::from_be_bytes(b.into_inner());
let expected = 0x1234567822222222u64;
eprintln!("expected(b) = {expected:#018x}");
eprintln!("actual(b) = {b:#018x}");
assert_eq!(b, expected);
let c = u64::from_be_bytes(c.into_inner());
let expected = 0x1234333333335678u64;
eprintln!("expected(c) = {expected:#018x}");
eprintln!("actual(c) = {c:#018x}");
assert_eq!(c, expected);
}
#[test]
fn store64() {
let a = UnsafeCell::new(0x1234567812345678);
let b = UnsafeCell::new(0x1234567812345678);
let c = UnsafeCell::new(0x1234567812345678);
unsafe {
for (val, addr) in [
(0x1111111111111111u64, a.get()),
(0x2222222222222222, b.get()),
(0x3333333333333333, c.get()),
] {
assert_one(
[(x(0), Val::from(addr)), (x(1), Val::from(val))],
Store64 {
ptr: x(0),
src: x(1),
},
x(1),
val,
);
}
}
let a = a.into_inner();
let expected = 0x1111111111111111u64;
eprintln!("expected(a) = {expected:#018x}");
eprintln!("actual(a) = {a:#018x}");
assert_eq!(a, expected);
let b = b.into_inner();
let expected = 0x2222222222222222u64;
eprintln!("expected(b) = {expected:#018x}");
eprintln!("actual(b) = {b:#018x}");
assert_eq!(b, expected);
let c = c.into_inner();
let expected = 0x3333333333333333u64;
eprintln!("expected(c) = {expected:#018x}");
eprintln!("actual(c) = {c:#018x}");
assert_eq!(c, expected);
}
#[test]
fn store32_offset8() {
let a = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
let b = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
let c = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
unsafe {
for (val, addr, offset) in [
(0x11111111u32, a.get(), 0),
(0x22222222, b.get(), 4),
(0x33333333, c.get(), 2),
] {
let val = val as u64;
assert_one(
[(x(0), Val::from(addr)), (x(1), Val::from(val))],
Store32SOffset8 {
ptr: x(0),
src: x(1),
offset,
},
x(1),
val,
);
}
}
let a = u64::from_be_bytes(a.into_inner());
let expected = 0x1111111112345678u64;
eprintln!("expected(a) = {expected:#018x}");
eprintln!("actual(a) = {a:#018x}");
assert_eq!(a, expected);
let b = u64::from_be_bytes(b.into_inner());
let expected = 0x1234567822222222u64;
eprintln!("expected(b) = {expected:#018x}");
eprintln!("actual(b) = {b:#018x}");
assert_eq!(b, expected);
let c = u64::from_be_bytes(c.into_inner());
let expected = 0x1234333333335678u64;
eprintln!("expected(c) = {expected:#018x}");
eprintln!("actual(c) = {c:#018x}");
assert_eq!(c, expected);
}
#[test]
fn store64_offset8() {
let a = UnsafeCell::new([0x1234567812345678, 0x1234567812345678, 0x1234567812345678]);
unsafe {
for (val, addr, offset) in [
(0x1111111111111111u64, a.get(), 0),
(0x2222222222222222, a.get(), 8),
(0x3333333333333333, a.get(), 16),
] {
assert_one(
[(x(0), Val::from(addr)), (x(1), Val::from(val))],
Store64Offset8 {
ptr: x(0),
src: x(1),
offset,
},
x(1),
val,
);
}
}
let [a, b, c] = a.into_inner();
let expected = 0x1111111111111111u64;
eprintln!("expected(a) = {expected:#018x}");
eprintln!("actual(a) = {a:#018x}");
assert_eq!(a, expected);
let expected = 0x2222222222222222u64;
eprintln!("expected(b) = {expected:#018x}");
eprintln!("actual(b) = {b:#018x}");
assert_eq!(b, expected);
let expected = 0x3333333333333333u64;
eprintln!("expected(c) = {expected:#018x}");
eprintln!("actual(c) = {c:#018x}");
assert_eq!(c, expected);
}
#[test]
fn store32_offset64() {
let a = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
let b = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
let c = UnsafeCell::new([0x12u8, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78]);
unsafe {
for (val, addr, offset) in [
(0x11111111u32, a.get(), 0),
(0x22222222, b.get(), 4),
(0x33333333, c.get(), 2),
] {
let val = val as u64;
assert_one(
[(x(0), Val::from(addr)), (x(1), Val::from(val))],
Store32SOffset64 {
ptr: x(0),
src: x(1),
offset,
},
x(1),
val,
);
}
}
let a = u64::from_be_bytes(a.into_inner());
let expected = 0x1111111112345678u64;
eprintln!("expected(a) = {expected:#018x}");
eprintln!("actual(a) = {a:#018x}");
assert_eq!(a, expected);
let b = u64::from_be_bytes(b.into_inner());
let expected = 0x1234567822222222u64;
eprintln!("expected(b) = {expected:#018x}");
eprintln!("actual(b) = {b:#018x}");
assert_eq!(b, expected);
let c = u64::from_be_bytes(c.into_inner());
let expected = 0x1234333333335678u64;
eprintln!("expected(c) = {expected:#018x}");
eprintln!("actual(c) = {c:#018x}");
assert_eq!(c, expected);
}
#[test]
fn store64_offset64() {
let a = UnsafeCell::new([0x1234567812345678, 0x1234567812345678, 0x1234567812345678]);
unsafe {
for (val, addr, offset) in [
(0x1111111111111111u64, a.get(), 0),
(0x2222222222222222, a.get(), 8),
(0x3333333333333333, a.get(), 16),
] {
assert_one(
[(x(0), Val::from(addr)), (x(1), Val::from(val))],
Store64Offset64 {
ptr: x(0),
src: x(1),
offset,
},
x(1),
val,
);
}
}
let [a, b, c] = a.into_inner();
let expected = 0x1111111111111111u64;
eprintln!("expected(a) = {expected:#018x}");
eprintln!("actual(a) = {a:#018x}");
assert_eq!(a, expected);
let expected = 0x2222222222222222u64;
eprintln!("expected(b) = {expected:#018x}");
eprintln!("actual(b) = {b:#018x}");
assert_eq!(b, expected);
let expected = 0x3333333333333333u64;
eprintln!("expected(c) = {expected:#018x}");
eprintln!("actual(c) = {c:#018x}");
assert_eq!(c, expected);
}
#[test]
fn bitcast_int_from_float_32() {
for val in [
0.0,
1.0,
9.87654321,
f32::MAX,
f32::MIN,
f32::NAN,
f32::INFINITY,
f32::NEG_INFINITY,
f32::EPSILON,
f32::MIN_POSITIVE,
] {
unsafe {
assert_one(
[(f(0), val)],
BitcastIntFromFloat32 {
dst: x(0),
src: f(0),
},
x(0),
val.to_bits() as u64,
);
}
}
}
#[test]
fn bitcast_int_from_float_64() {
for val in [
0.0,
1.0,
9.87654321,
f64::MAX,
f64::MIN,
f64::NAN,
f64::INFINITY,
f64::NEG_INFINITY,
f64::EPSILON,
f64::MIN_POSITIVE,
] {
unsafe {
assert_one(
[(f(0), val)],
BitcastIntFromFloat64 {
dst: x(0),
src: f(0),
},
x(0),
val.to_bits(),
);
}
}
}
#[test]
fn bitcast_float_from_int_32() {
for val in [
0.0,
1.0,
9.87654321,
f32::MAX,
f32::MIN,
f32::NAN,
f32::INFINITY,
f32::NEG_INFINITY,
f32::EPSILON,
f32::MIN_POSITIVE,
] {
let val = val.to_bits() as u64;
unsafe {
assert_one(
[(x(0), val)],
BitcastFloatFromInt32 {
dst: f(0),
src: x(0),
},
f(0),
val,
);
}
}
}
#[test]
fn bitcast_float_from_int_64() {
for val in [
0.0,
1.0,
9.87654321,
f64::MAX,
f64::MIN,
f64::NAN,
f64::INFINITY,
f64::NEG_INFINITY,
f64::EPSILON,
f64::MIN_POSITIVE,
] {
let val = val.to_bits();
unsafe {
assert_one(
[(x(0), val)],
BitcastFloatFromInt64 {
dst: f(0),
src: x(0),
},
f(0),
val,
);
}
}
}
#[test]
fn trap() {
let mut vm = Vm::new();
let dst = XReg::new(0).unwrap();
unsafe {
run(
&mut vm,
&[
Op::Xconst16(Xconst16 { dst, imm: 1 }),
Op::ExtendedOp(ExtendedOp::Trap(Trap {})),
Op::Xconst16(Xconst16 { dst, imm: 2 }),
Op::Ret(Ret {}),
],
)
.unwrap_err();
}
// `dst` should not have been written to the second time.
assert_eq!(vm.state()[dst].get_u32(), 1);
}