46#ifdef NUMERICAL_AMX_COMPILED
48 enum class amx_op :
unsigned
64 inline void amx(std::uint64_t operand)
noexcept
66 __asm__
volatile (
".word (0x201000 + (%0 << 5) + 0%1 - ((0%1 >> 4) * 6))"
68 :
"i" (
static_cast<unsigned>(Op)),
"r" (operand)
77 inline void amx_switch()
noexcept
79 __asm__
volatile (
"nop\nnop\nnop\n.word (0x201000 + (17 << 5) + %0)"
81 :
"i" (
static_cast<unsigned>(Off))
90 amx_session()
noexcept
95 amx_session(
const amx_session&) =
delete;
96 amx_session& operator=(
const amx_session&) =
delete;
97 amx_session(amx_session&&) =
delete;
98 amx_session& operator=(amx_session&&) =
delete;
107 [[nodiscard]]
inline std::uint64_t amx_address(
const void * at,
108 std::uint64_t index)
noexcept
110 return (index << 56U) |
reinterpret_cast<std::uintptr_t
>(at);
114 inline constexpr std::size_t amx_dot_group {8};
124 inline void amx_dot_rows_f64(
const double* m,
129 double* out)
noexcept
131 alignas(64)
static constexpr std::array<double, 8> zero {};
132 alignas(64) std::array<std::array<double, 8>, amx_dot_group> lanes {};
133 const std::size_t whole {count - (count % 8)};
134 for (std::size_t r0 {0}; r0 < rows; r0 += amx_dot_group) {
135 const std::size_t group {std::min(amx_dot_group, rows - r0)};
136 for (std::size_t r {0}; r < group; ++r) {
139 for (std::size_t j {0}; j <
whole; j += 8) {
141 for (std::size_t r {0}; r <
group; ++r) {
143 amx<amx_op::fma64>((std::uint64_t {1} << 63U) | (std::uint64_t {r} << 20U) | (std::uint64_t {r} *64U));
146 for (std::size_t r {0}; r <
group; ++r) {
149 for (std::size_t r {0}; r <
group; ++r) {
150 for (std::size_t j {
whole}; j < count; ++j) {
151 lanes[r][j % 8] = std::fma(m[((
r0 + r) * ld) + j], x[j],
lanes[r][j % 8]);
154 for (std::size_t
l {1};
l < 8; ++
l) {
163 inline constexpr std::size_t
amx_mr {32};
166 inline constexpr std::size_t
amx_nr {16};
177 inline constexpr std::size_t
amx_least_work {std::size_t {1} << 16U};
182 std::size_t k)
noexcept
204 std::size_t k)
noexcept
227 [[gnu::noinline, gnu::aligned(64)]]
inline void amx_depth_f64(std::size_t
kc,
230 std::size_t
ldb)
noexcept
232 for (std::size_t p {0}; p <
kc; ++p) {
233 const double*
const a {
ap + (p *
amx_mr)};
234 const double*
const b {
bp + (p *
ldb)};
235 for (std::uint64_t
ya {0};
ya < 4; ++
ya) {
240 for (std::uint64_t
ya {0};
ya < 4; ++
ya) {
241 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
268 std::size_t ld)
noexcept
270 for (std::uint64_t
ya {0};
ya < 4; ++
ya) {
271 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
272 for (std::uint64_t j {0}; j < 8; ++j) {
278 for (std::uint64_t
ya {0};
ya < 4; ++
ya) {
279 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
280 for (std::uint64_t j {0}; j < 8; ++j) {
289 [[gnu::noinline, gnu::aligned(64)]]
inline void amx_depth_f32(std::size_t
kc,
292 std::size_t
ldb)
noexcept
294 for (std::size_t p {0}; p <
kc; ++p) {
296 const float*
const b {
bp + (p *
ldb)};
301 for (std::uint64_t
ya {0};
ya < 2; ++
ya) {
302 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
313 std::size_t
ldb)
noexcept
322 std::size_t
ldb)
noexcept
328 template <
typename T>
342 template <
typename T,
348 std::size_t
ldb)
noexcept
350 constexpr std::size_t
lanes {64 /
sizeof(
T)};
351 for (std::size_t p {0}; p <
kc; ++p) {
353 const T*
const b {
bp + (p *
ldb)};
369 template <
typename T,
375 std::uint64_t
halves)
noexcept
392 std::uint64_t
halves)
noexcept
397 else if (
bands == 2) {
400 else if (
bands == 3) {
414 std::uint64_t
halves)
noexcept
439 template <
typename T>
447 std::size_t cols)
noexcept
450 constexpr std::size_t
lanes {64 /
sizeof(
T)};
452 alignas(64) std::array<T, amx_mr * lanes>
cut {};
457 for (std::uint64_t j {0}; j <
lanes; ++j) {
462 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
463 const std::uint64_t
z {(j * 2 *
bands) + (
ya * 2) +
xb};
475 for (std::size_t
row {0};
row < rows; ++
row) {
476 for (std::size_t e {0}; e <
cut_width; ++e) {
492 for (std::size_t
row {0};
row < rows; ++
row) {
493 for (std::size_t e {0}; e <
cut_width; ++e) {
507 std::size_t ld)
noexcept
509 for (std::uint64_t
ya {0};
ya < 2; ++
ya) {
510 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
511 for (std::uint64_t j {0}; j < 16; ++j) {
517 for (std::uint64_t
ya {0};
ya < 2; ++
ya) {
518 for (std::uint64_t
xb {0};
xb < 2; ++
xb) {
519 for (std::uint64_t j {0}; j < 16; ++j) {
539 std::size_t cols)
noexcept
567 std::size_t cols)
noexcept
569 if ((rows <
amx_mr || cols <
amx_nr) && (cols < 8 || cols % 8 == 0)) {
573 through_edge<amx_mr, amx_nr>(c, ldc, rows, cols, [&](
double* tile, std::size_t ld)
noexcept {
amx_full_tile_f64(
kc,
ap,
bp,
ldb, tile, ld); });
593 double*
out)
noexcept
600 for (; p + 2 <=
kc; p += 2) {
601 for (std::size_t i {0}; i <
amx_mr; i += 4) {
602 std::array<pair, 4>
row {};
603 for (std::size_t r {0}; r < 4; ++r) {
604 std::memcpy(&
row.at(r), a + ((
ir + i + r) * lda) + p,
sizeof(
pair));
610 __asm__ volatile (
"stnp %q0, %q1, [%2]"
614 __asm__ volatile (
"stnp %q0, %q1, [%2]"
620 for (; p <
kc; ++p) {
621 for (std::size_t i {0}; i <
amx_mr; i += 2) {
622 const double first {a[((
ir + i) * lda) + p]};
623 const double second {a[((
ir + i + 1) * lda) + p]};
624 __asm__ volatile (
"stnp %d0, %d1, [%2]"
626 :
"w" (first),
"w" (second),
"r" (
sliver + (p *
amx_mr) + i)
634 for (; p + 2 <=
kc; p += 2) {
635 for (std::size_t i {0}; i <
amx_mr; i += 2) {
638 std::memcpy(&first, a + ((
ir + i) * lda) + p,
sizeof(
pair));
639 std::memcpy(&second, a + ((
ir + i + 1) * lda) + p,
sizeof(
pair));
646 for (; p <
kc; ++p) {
647 for (std::size_t i {0}; i <
amx_mr; ++i) {
654 for (std::size_t p {0}; p <
kc; ++p) {
655 for (std::size_t i {0}; i <
amx_mr; ++i) {
682 return std::array<quad, 4> {
__builtin_shufflevector(
low01,
low23, 0, 1, 4, 5),
__builtin_shufflevector(
low01,
low23, 2, 3, 6, 7),
683 __builtin_shufflevector(
high01,
high23, 0, 1, 4, 5),
__builtin_shufflevector(
high01,
high23, 2, 3, 6, 7)};
687 __asm__ volatile (
"stnp %q0, %q1, [%2]"
689 :
"w" (
upper),
"w" (lower),
"r" (at)
696 for (; p + 4 <=
kc; p += 4) {
698 std::array<quad, 8>
row {};
699 for (std::size_t r {0}; r < 8; ++r) {
700 std::memcpy(&
row.at(r), a + ((
ir + i + r) * lda) + p,
sizeof(
quad));
711 for (; p <
kc; ++p) {
713 const float first {a[((
ir + i) * lda) + p]};
714 const float second {a[((
ir + i + 1) * lda) + p]};
715 __asm__ volatile (
"stnp %s0, %s1, [%2]"
725 for (std::size_t p {0}; p <
kc; ++p) {
754 std::size_t size {
sizeof family};
765 constexpr std::size_t rows {11};
766 constexpr std::size_t count {21};
767 std::array<double, rows * count> m {};
768 std::array<double, count> x {};
769 std::array<double, rows>
got {};
770 std::array<double, rows>
want {};
771 for (std::size_t i {0}; i < m.size(); ++i) {
772 m[i] = std::ldexp(
static_cast<double>((i * 37) % 101) - 50.0, -
static_cast<int>(i % 9));
774 for (std::size_t j {0}; j < count; ++j) {
775 x[j] = 1.0 /
static_cast<double>((j % 13) + 3);
777 for (std::size_t r {0}; r < rows; ++r) {
778 std::array<double, 8>
lane {};
779 for (std::size_t j {0}; j < count; ++j) {
780 lane[j % 8] = std::fma(m[(r * count) + j], x[j],
lane[j % 8]);
783 for (std::size_t
l {1};
l < 8; ++
l) {
799 constexpr std::size_t depth {7};
801 std::array<float, depth * side> a {};
802 std::array<float, depth * side> b {};
803 std::array<float, side * side> c {};
804 std::array<float, side * side>
want {};
805 for (std::size_t i {0}; i < depth *
side; ++i) {
806 a[i] = std::ldexp(
static_cast<float>((i * 37) % 101) - 50.0F, -
static_cast<int>(i % 9));
807 b[i] = 1.0F /
static_cast<float>((i % 13) + 3);
809 for (std::size_t i {0}; i <
side *
side; ++i) {
810 c[i] =
static_cast<float>(i % 17) * 0.1F;
813 for (
const std::size_t rows : {
side, std::size_t {19}}) {
814 const std::size_t cols {rows ==
side ?
side : std::size_t {11}};
815 for (std::size_t i {0}; i < rows; ++i) {
816 for (std::size_t j {0}; j < cols; ++j) {
817 for (std::size_t p {0}; p < depth; ++p) {
838 constexpr std::size_t depth {7};
839 std::array<double, depth * amx_mr> a {};
840 std::array<double, depth * amx_nr> b {};
841 std::array<double, amx_mr * amx_nr> c {};
842 std::array<double, amx_mr * amx_nr>
want {};
843 for (std::size_t i {0}; i < depth *
amx_mr; ++i) {
844 a[i] = std::ldexp(
static_cast<double>((i * 37) % 101) - 50.0, -
static_cast<int>(i % 9));
846 for (std::size_t i {0}; i < depth *
amx_nr; ++i) {
847 b[i] = 1.0 /
static_cast<double>((i % 13) + 3);
850 c[i] =
static_cast<double>(i % 17) * 0.1;
853 for (
const std::size_t rows : {
amx_mr, std::size_t {19}}) {
854 const std::size_t cols {rows ==
amx_mr ?
amx_nr : std::size_t {11}};
855 for (std::size_t i {0}; i < rows; ++i) {
856 for (std::size_t j {0}; j < cols; ++j) {
857 for (std::size_t p {0}; p < depth; ++p) {
868 return std::count(
passed.begin(),
passed.end(),
true) == 3;
875 std::size_t size {
sizeof present};
883 static std::atomic<bool>
probed {
false};
904#ifdef NUMERICAL_AMX_COMPILED