use core::arch::asm;
#[path = "portable.rs"]
mod portable;
#[inline]
pub(super) unsafe fn submul_1(r: *mut u64, x: *const u64, n: usize, y: u64) -> u64 {
unsafe {
if std::is_x86_feature_detected!("bmi2") {
submul_1_bmi2(r, x, n, y)
} else {
portable::submul_1(r, x, n, y)
}
}
}
#[target_feature(enable = "bmi2")]
unsafe fn submul_1_bmi2(r: *mut u64, x: *const u64, n: usize, y: u64) -> u64 {
let borrow: u64;
unsafe {
asm!(
"mov {h3}, {n}",
"and {h3}, 3",
"inc {h3}",
"shr {n}, 2",
"inc {n}",
"xor {hp:e}, {hp:e}",
"jmp 3f",
"2:",
"mulx {h0}, {l0}, qword ptr [{xp}]",
"sbb qword ptr [{rp}], {l0}",
"adc {h0}, 0",
"sub qword ptr [{rp}], {hp}",
"mov {hp}, {h0}",
"lea {xp}, [{xp} + 8]",
"lea {rp}, [{rp} + 8]",
"3:",
"dec {h3}",
"jnz 2b",
"jmp 5f",
"4:",
"mulx {h0}, {l0}, qword ptr [{xp}]",
"mulx {h1}, {l1}, qword ptr [{xp} + 8]",
"mulx {h2}, {l2}, qword ptr [{xp} + 16]",
"mulx {h3}, {l3}, qword ptr [{xp} + 24]",
"sbb qword ptr [{rp}], {l0}",
"sbb qword ptr [{rp} + 8], {l1}",
"sbb qword ptr [{rp} + 16], {l2}",
"sbb qword ptr [{rp} + 24], {l3}",
"adc {h3}, 0",
"sub qword ptr [{rp}], {hp}",
"sbb qword ptr [{rp} + 8], {h0}",
"sbb qword ptr [{rp} + 16], {h1}",
"sbb qword ptr [{rp} + 24], {h2}",
"mov {hp}, {h3}",
"lea {xp}, [{xp} + 32]",
"lea {rp}, [{rp} + 32]",
"5:",
"dec {n}",
"jnz 4b",
"adc {hp}, 0",
rp = inout(reg) r => _, xp = inout(reg) x => _, n = inout(reg) n => _,
in("rdx") y,
hp = out(reg) borrow,
l0 = out(reg) _, l1 = out(reg) _, l2 = out(reg) _, l3 = out(reg) _,
h0 = out(reg) _, h1 = out(reg) _, h2 = out(reg) _, h3 = out(reg) _,
options(nostack),
);
}
borrow
}