use core::arch::asm;
macro_rules! le_kernel {
($(#[$attr:meta])* $name:ident, $op:literal, $carry:ident) => {
$(#[$attr])*
#[inline]
pub(super) unsafe fn $name(
r: *mut u8,
x: *const u8,
y: *const u8,
n: usize,
$carry: bool,
) -> bool {
let carry_out: u8;
unsafe {
asm!(
"mov {rem:e}, {cnt:e}",
"and {rem:e}, 3",
"inc {rem:e}",
"shr {cnt}, 2",
"inc {cnt}",
"neg {cf}",
"jmp 3f",
".p2align 5",
"2:",
"mov {a}, qword ptr [{x}]",
concat!($op, " {a}, qword ptr [{y}]"),
"mov qword ptr [{r}], {a}",
"mov {b}, qword ptr [{x} + 8]",
concat!($op, " {b}, qword ptr [{y} + 8]"),
"mov qword ptr [{r} + 8], {b}",
"mov {a}, qword ptr [{x} + 16]",
concat!($op, " {a}, qword ptr [{y} + 16]"),
"mov qword ptr [{r} + 16], {a}",
"mov {b}, qword ptr [{x} + 24]",
concat!($op, " {b}, qword ptr [{y} + 24]"),
"mov qword ptr [{r} + 24], {b}",
"lea {x}, [{x} + 32]",
"lea {y}, [{y} + 32]",
"lea {r}, [{r} + 32]",
"3:",
"dec {cnt}",
"jnz 2b",
"jmp 5f",
"4:",
"mov {a}, qword ptr [{x}]",
concat!($op, " {a}, qword ptr [{y}]"),
"mov qword ptr [{r}], {a}",
"lea {x}, [{x} + 8]",
"lea {y}, [{y} + 8]",
"lea {r}, [{r} + 8]",
"5:",
"dec {rem:e}",
"jnz 4b",
"setc {cf}",
r = inout(reg) r as u64 => _,
x = inout(reg) x as u64 => _,
y = inout(reg) y as u64 => _,
cnt = inout(reg) n as u64 => _,
rem = out(reg) _,
cf = inout(reg_byte) u8::from($carry) => carry_out,
a = out(reg) _,
b = out(reg) _,
options(nostack),
);
}
carry_out != 0
}
};
}
macro_rules! be_kernel {
($(#[$attr:meta])* $name:ident, $op:literal, $carry:ident) => {
$(#[$attr])*
#[inline]
pub(super) unsafe fn $name(
r_end: *mut u8,
x_end: *const u8,
y_end: *const u8,
n: usize,
$carry: bool,
) -> bool {
let carry_out: u8;
unsafe {
asm!(
"mov {rem:e}, {cnt:e}",
"and {rem:e}, 3",
"inc {rem:e}",
"shr {cnt}, 2",
"inc {cnt}",
"neg {cf}",
"jmp 3f",
".p2align 5",
"2:",
"mov {a}, qword ptr [{x} - 8]",
"mov {b}, qword ptr [{y} - 8]",
"bswap {a}",
"bswap {b}",
concat!($op, " {a}, {b}"),
"bswap {a}",
"mov qword ptr [{r} - 8], {a}",
"mov {a}, qword ptr [{x} - 16]",
"mov {b}, qword ptr [{y} - 16]",
"bswap {a}",
"bswap {b}",
concat!($op, " {a}, {b}"),
"bswap {a}",
"mov qword ptr [{r} - 16], {a}",
"mov {a}, qword ptr [{x} - 24]",
"mov {b}, qword ptr [{y} - 24]",
"bswap {a}",
"bswap {b}",
concat!($op, " {a}, {b}"),
"bswap {a}",
"mov qword ptr [{r} - 24], {a}",
"mov {a}, qword ptr [{x} - 32]",
"mov {b}, qword ptr [{y} - 32]",
"bswap {a}",
"bswap {b}",
concat!($op, " {a}, {b}"),
"bswap {a}",
"mov qword ptr [{r} - 32], {a}",
"lea {x}, [{x} - 32]",
"lea {y}, [{y} - 32]",
"lea {r}, [{r} - 32]",
"3:",
"dec {cnt}",
"jnz 2b",
"jmp 5f",
"4:",
"mov {a}, qword ptr [{x} - 8]",
"mov {b}, qword ptr [{y} - 8]",
"bswap {a}",
"bswap {b}",
concat!($op, " {a}, {b}"),
"bswap {a}",
"mov qword ptr [{r} - 8], {a}",
"lea {x}, [{x} - 8]",
"lea {y}, [{y} - 8]",
"lea {r}, [{r} - 8]",
"5:",
"dec {rem:e}",
"jnz 4b",
"setc {cf}",
r = inout(reg) r_end as u64 => _,
x = inout(reg) x_end as u64 => _,
y = inout(reg) y_end as u64 => _,
cnt = inout(reg) n as u64 => _,
rem = out(reg) _,
cf = inout(reg_byte) u8::from($carry) => carry_out,
a = out(reg) _,
b = out(reg) _,
options(nostack),
);
}
carry_out != 0
}
};
}
le_kernel!(
add_n_le,
"adc",
carry
);
le_kernel!(
sub_n_le,
"sbb",
borrow
);
be_kernel!(
add_n_be,
"adc",
carry
);
be_kernel!(
sub_n_be,
"sbb",
borrow
);