#[cfg(target_arch = "riscv64")]
#[cfg(target_feature = "f")]
mod inner {
use core::arch::asm;
pub const PS_SCRATCH_DEFAULT: u8 = 28;
#[rustfmt::skip] macro_rules! fmul2 {
($lo:literal, $hi:literal, $s:literal) => {
asm!(
concat!(
".insn r 0x7b, 0, 8, f", $lo, ", f", $lo, ", f", $s, "\n",
".insn r 0x7b, 0, 8, f", $hi, ", f", $hi, ", f", $s
),
options(nostack, preserves_flags)
)
};
}
#[rustfmt::skip] macro_rules! scale_row {
(($lo:literal, $hi:literal), $s:expr) => {
match $s {
0 => { fmul2!($lo, $hi, 0) },
1 => { fmul2!($lo, $hi, 1) },
2 => { fmul2!($lo, $hi, 2) },
3 => { fmul2!($lo, $hi, 3) },
4 => { fmul2!($lo, $hi, 4) },
5 => { fmul2!($lo, $hi, 5) },
6 => { fmul2!($lo, $hi, 6) },
7 => { fmul2!($lo, $hi, 7) },
8 => { fmul2!($lo, $hi, 8) },
9 => { fmul2!($lo, $hi, 9) },
10 => { fmul2!($lo, $hi, 10) },
11 => { fmul2!($lo, $hi, 11) },
12 => { fmul2!($lo, $hi, 12) },
13 => { fmul2!($lo, $hi, 13) },
14 => { fmul2!($lo, $hi, 14) },
15 => { fmul2!($lo, $hi, 15) },
16 => { fmul2!($lo, $hi, 16) },
17 => { fmul2!($lo, $hi, 17) },
18 => { fmul2!($lo, $hi, 18) },
19 => { fmul2!($lo, $hi, 19) },
20 => { fmul2!($lo, $hi, 20) },
21 => { fmul2!($lo, $hi, 21) },
22 => { fmul2!($lo, $hi, 22) },
23 => { fmul2!($lo, $hi, 23) },
24 => { fmul2!($lo, $hi, 24) },
25 => { fmul2!($lo, $hi, 25) },
26 => { fmul2!($lo, $hi, 26) },
27 => { fmul2!($lo, $hi, 27) },
28 => { fmul2!($lo, $hi, 28) },
29 => { fmul2!($lo, $hi, 29) },
30 => { fmul2!($lo, $hi, 30) },
31 => { fmul2!($lo, $hi, 31) },
_ => {}
}
};
}
#[inline(always)]
#[rustfmt::skip] pub unsafe fn broadcast_ps(scalar: f32, dest: u8) {
let tmp: u64;
asm!(
"fmv.x.w {tmp}, {x}",
x = in(freg) scalar,
tmp = out(reg) tmp,
options(nostack, preserves_flags),
);
match dest {
0 => asm!(".insn i 0x0b, 3, f0, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
1 => asm!(".insn i 0x0b, 3, f1, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
2 => asm!(".insn i 0x0b, 3, f2, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
3 => asm!(".insn i 0x0b, 3, f3, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
4 => asm!(".insn i 0x0b, 3, f4, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
5 => asm!(".insn i 0x0b, 3, f5, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
6 => asm!(".insn i 0x0b, 3, f6, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
7 => asm!(".insn i 0x0b, 3, f7, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
8 => asm!(".insn i 0x0b, 3, f8, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
9 => asm!(".insn i 0x0b, 3, f9, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
10 => asm!(".insn i 0x0b, 3, f10, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
11 => asm!(".insn i 0x0b, 3, f11, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
12 => asm!(".insn i 0x0b, 3, f12, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
13 => asm!(".insn i 0x0b, 3, f13, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
14 => asm!(".insn i 0x0b, 3, f14, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
15 => asm!(".insn i 0x0b, 3, f15, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
16 => asm!(".insn i 0x0b, 3, f16, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
17 => asm!(".insn i 0x0b, 3, f17, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
18 => asm!(".insn i 0x0b, 3, f18, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
19 => asm!(".insn i 0x0b, 3, f19, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
20 => asm!(".insn i 0x0b, 3, f20, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
21 => asm!(".insn i 0x0b, 3, f21, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
22 => asm!(".insn i 0x0b, 3, f22, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
23 => asm!(".insn i 0x0b, 3, f23, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
24 => asm!(".insn i 0x0b, 3, f24, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
25 => asm!(".insn i 0x0b, 3, f25, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
26 => asm!(".insn i 0x0b, 3, f26, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
27 => asm!(".insn i 0x0b, 3, f27, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
28 => asm!(".insn i 0x0b, 3, f28, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
29 => asm!(".insn i 0x0b, 3, f29, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
30 => asm!(".insn i 0x0b, 3, f30, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
31 => asm!(".insn i 0x0b, 3, f31, {t}, 0", t = in(reg) tmp, options(nostack, preserves_flags)),
_ => {}
}
}
#[inline(always)]
#[rustfmt::skip] pub unsafe fn fmul_ps_row(row: u32, scratch: u8) {
debug_assert!(
scratch != 2 * row as u8 && scratch != 2 * row as u8 + 1,
"fmul_ps_row: scratch f{} conflicts with C-tile row {} (f{} and f{})",
scratch,
row,
2 * row,
2 * row + 1,
);
match row {
0 => scale_row!((0, 1), scratch),
1 => scale_row!((2, 3), scratch),
2 => scale_row!((4, 5), scratch),
3 => scale_row!((6, 7), scratch),
4 => scale_row!((8, 9), scratch),
5 => scale_row!((10, 11), scratch),
6 => scale_row!((12, 13), scratch),
7 => scale_row!((14, 15), scratch),
8 => scale_row!((16, 17), scratch),
9 => scale_row!((18, 19), scratch),
10 => scale_row!((20, 21), scratch),
11 => scale_row!((22, 23), scratch),
12 => scale_row!((24, 25), scratch),
13 => scale_row!((26, 27), scratch),
14 => scale_row!((28, 29), scratch),
15 => scale_row!((30, 31), scratch),
_ => {}
}
}
#[inline(always)]
pub unsafe fn scale_c_row(row: u32, alpha: f32, scratch: u8) {
broadcast_ps(alpha, scratch);
fmul_ps_row(row, scratch);
}
}
#[cfg(target_arch = "riscv64")]
#[cfg(target_feature = "f")]
pub use inner::*;