// ===== REFERENCES =====
// [1] 本账号(saffah_cc_v41_agg1)提交 **#109281** <https://duck.ac/submission/109281>
// (270.067822 ms = 我方现役最好件)—— 本文件正文 = 该提交 + **单变量结构改写**(见思路)✓
// [2] duck.ac 题目页 <https://duck.ac/problem/mmmd2k>(n=2048 双精度矩阵乘法,接口 `matrix_multiply`)
// [3] 配方来源(本队在档):**A 面板 4× 复制消广播**(`mmmd1k` 已验,法律库 ㊴)—— 删 `vbroadcastsd`、
// FMA 改用 A 内存操作数(4× 复制 ⇒ 该 32 B 内存操作数天然就是广播)、地址 ×4、
// packA 用 `_mm256_permute4x64_pd(0x00/0x55/0xAA/0xFF)` 把一次 4 元素载入展成 4 条 32 B 向量 ✓
// ===== 思路 =====
// 【本席 d2z2_ · 单变量】把 mikro 环里的 **136 条 `vbroadcastsd` 全部消掉**:A 面板按元素 4× 复制
// (每元素占 32 B、4 份同值),于是 `vfmadd231pd mem, ymm, ymm` 的 32 B 内存操作数**本身就是广播**
// ⇒ 每环省 48 个发射槽(本席上一发代理臂判题机实测:48 个纯发射槽 = **+25.665 ms / +9.50%**
// ⇒ 该形态的"发射槽侧"上界 ≈ 9.5% ≫ 缺口 1.024%)✓
// 覆盖:4 个 asm 核(主核/plain/kernel2/tail16,含 tail16 的**异构角色互换**形态)· 3 处普通 pack ·
// 1 处 in-kernel 熔融 pack · `[oN]` 宏与 a 指针步进全部 ×4 ✓
// 【闸门】`md4_harness` n=2048 单 cell:`h = 5270272797787364638` = 判题机历史常数**逐位相同** ✓
// (首次实现曾因 tail16 的"两寄存器各自活跃"未分别跟踪而 h 错,已修 ✓)
// 【本机同量纲读数】base 953 M ↔ 本件 1500 M cyc ⇒ **本机 +57%**(A 侧 L1 载入字节每 FMA 8 B→32 B
// ⇒ 该形态的成本侧在本核超标)⇒ 本发 = **按协调者 ③ 走的"判题机定价"发**(本机 >5% 已被筛出,
// 但该题本机↔判题机换算率未标定,故仍取判题机真值收口)✓
// ================
#pragma GCC optimize("O3,unroll-loops,no-strict-aliasing")
#pragma GCC target("arch=skylake")
#include <immintrin.h>
#define MD9_T2BASE 1
#include <stddef.h>
#ifndef BASE
#define BASE 512
#endif
#ifndef MC
#define MC 30
#endif
#ifndef NTMIN
#define NTMIN 512
#endif
#ifndef UPPER_PAGE_PAD
#define UPPER_PAGE_PAD 15872
#endif
#ifndef LEAF_PAD
#define LEAF_PAD 1152
#endif
#ifndef SUMNT
#define SUMNT 1024
#endif
static constexpr int MR=6,NR=8;
alignas(4096) static double workspace[48*1024*1024];
alignas(64) static double ap[(MC+MR)*4*(BASE+24)],ap2[(MC+MR)*4*(BASE+24)],bp[BASE*(BASE+24)];
/* m2s/md5 fused-pack support: a zero row (for pad rows and for pure copies) and the
two sign masks (+0.0 / -0.0) used to apply Strassen's operand sign in-register. */
alignas(64) static double pk_zero[BASE+8];
alignas(64) static double pk_mp[4]={0.0,0.0,0.0,0.0}, pk_mn[4]={-0.0,-0.0,-0.0,-0.0};
struct Mat { const double *x; int ld; const double *y=nullptr; int ly=0; int sign=0; };
static inline __m256d ld(Mat a,int i,int j) {
__m256d x=_mm256_load_pd(a.x+(size_t)i*a.ld+j);
if(a.sign) {
__m256d y=_mm256_load_pd(a.y+(size_t)i*a.ly+j);
x=a.sign>0?_mm256_add_pd(x,y):_mm256_sub_pd(x,y);
}
return x;
}
static inline double scalar(Mat a,int i,int k) {
double x=a.x[(size_t)i*a.ld+k];
if(a.sign)x+=a.sign>0?a.y[(size_t)i*a.ly+k]:-a.y[(size_t)i*a.ly+k];
return x;
}
template<int SG> static __attribute__((always_inline)) inline void kernel(int n,const double *a,const double *b,double *c,int ldc,int rows,
const double *pks,const double *pky,double *pkd) {
double *out=c;
ptrdiff_t stride=(ptrdiff_t)ldc*8;
int k=n;
asm volatile (
"vxorpd %%ymm0, %%ymm0, %%ymm0\n\t"
"vxorpd %%ymm1, %%ymm1, %%ymm1\n\t"
"vxorpd %%ymm2, %%ymm2, %%ymm2\n\t"
"vxorpd %%ymm3, %%ymm3, %%ymm3\n\t"
"vxorpd %%ymm4, %%ymm4, %%ymm4\n\t"
"vxorpd %%ymm5, %%ymm5, %%ymm5\n\t"
"vxorpd %%ymm6, %%ymm6, %%ymm6\n\t"
"vxorpd %%ymm7, %%ymm7, %%ymm7\n\t"
"vxorpd %%ymm8, %%ymm8, %%ymm8\n\t"
"vxorpd %%ymm9, %%ymm9, %%ymm9\n\t"
"vxorpd %%ymm10, %%ymm10, %%ymm10\n\t"
"vxorpd %%ymm11, %%ymm11, %%ymm11\n\t"
".p2align 6\n\t"
"1:\n\t"
".if %c[sg] != 0\n\t"
"vmovapd 0(%[b]), %%ymm12\n\t"
"vmovapd 32(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 512(%[b])\n\t"
"vfmadd231pd %c[o2]+0(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+0(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+0(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+0(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+0(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+0(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+0(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+0(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 64(%[b]), %%ymm12\n\t"
"vmovapd 96(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 576(%[b])\n\t"
"vfmadd231pd %c[o2]+32(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+32(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+32(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+32(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+32(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+32(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+32(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+32(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 128(%[b]), %%ymm12\n\t"
"vmovapd 160(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 640(%[b])\n\t"
"vfmadd231pd %c[o2]+64(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+64(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+64(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+64(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+64(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+64(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+64(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+64(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 192(%[b]), %%ymm12\n\t"
"vmovapd 224(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 704(%[b])\n\t"
"vfmadd231pd %c[o2]+96(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+96(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+96(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+96(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+96(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+96(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+96(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+96(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 256(%[b]), %%ymm12\n\t"
"vmovapd 288(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+128(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+128(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+128(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+128(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 768(%[b])\n\t"
"vfmadd231pd %c[o2]+128(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+128(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+128(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+128(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+128(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+128(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+128(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+128(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 320(%[b]), %%ymm12\n\t"
"vmovapd 352(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+160(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+160(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+160(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+160(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 832(%[b])\n\t"
"vfmadd231pd %c[o2]+160(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+160(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+160(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+160(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+160(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+160(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+160(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+160(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 384(%[b]), %%ymm12\n\t"
"vmovapd 416(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+192(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+192(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+192(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+192(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 896(%[b])\n\t"
"vfmadd231pd %c[o2]+192(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+192(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+192(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+192(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+192(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+192(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+192(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+192(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 448(%[b]), %%ymm12\n\t"
"vmovapd 480(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+224(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+224(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+224(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+224(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 960(%[b])\n\t"
"vfmadd231pd %c[o2]+224(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+224(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+224(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+224(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+224(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+224(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+224(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+224(%[a]), %%ymm13, %%ymm11\n\t"
"vmovupd 0(%[pks]), %%ymm15\n\t"
".if %c[sg] == 1\n\t"
"vaddpd 0(%[pky]), %%ymm15, %%ymm15\n\t"
".elseif %c[sg] == -1\n\t"
"vsubpd 0(%[pky]), %%ymm15, %%ymm15\n\t"
".endif\n\t"
"vpermq $0x00, %%ymm15, %%ymm14\n\t"
"vmovupd %%ymm14, 0(%[pkd])\n\t"
"vpermq $0x55, %%ymm15, %%ymm14\n\t"
"vmovupd %%ymm14, 32(%[pkd])\n\t"
"vpermq $0xAA, %%ymm15, %%ymm14\n\t"
"vmovupd %%ymm14, 64(%[pkd])\n\t"
"vpermq $0xFF, %%ymm15, %%ymm14\n\t"
"vmovupd %%ymm14, 96(%[pkd])\n\t"
"add $32, %[pks]\n\t"
"add $32, %[pky]\n\t"
"add $128, %[pkd]\n\t"
"add $256, %[a]\n\t"
"add $512, %[b]\n\t"
"sub $8, %[k]\n\t"
".else\n\t"
"prefetcht0 512(%[b])\n\t"
"prefetcht0 576(%[b])\n\t"
"prefetcht0 640(%[b])\n\t"
"prefetcht0 704(%[b])\n\t"
"vmovapd 0(%[b]), %%ymm12\n\t"
"vmovapd 32(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm13, %%ymm3\n\t"
"vfmadd231pd %c[o2]+0(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+0(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+0(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+0(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+0(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+0(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+0(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+0(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 64(%[b]), %%ymm12\n\t"
"vmovapd 96(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm13, %%ymm3\n\t"
"vfmadd231pd %c[o2]+32(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+32(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+32(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+32(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+32(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+32(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+32(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+32(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 128(%[b]), %%ymm12\n\t"
"vmovapd 160(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm13, %%ymm3\n\t"
"vfmadd231pd %c[o2]+64(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+64(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+64(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+64(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+64(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+64(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+64(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+64(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 192(%[b]), %%ymm12\n\t"
"vmovapd 224(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm13, %%ymm3\n\t"
"vfmadd231pd %c[o2]+96(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+96(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+96(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+96(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+96(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+96(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+96(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+96(%[a]), %%ymm13, %%ymm11\n\t"
"add $128, %[a]\n\t"
"add $256, %[b]\n\t"
"sub $4, %[k]\n\t"
".endif\n\t"
"jnz 1b\n\t"
"vmovntpd %%ymm0, (%[out])\n\t"
"vmovntpd %%ymm1, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm2, (%[out])\n\t"
"vmovntpd %%ymm3, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm4, (%[out])\n\t"
"vmovntpd %%ymm5, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm6, (%[out])\n\t"
"vmovntpd %%ymm7, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm8, (%[out])\n\t"
"vmovntpd %%ymm9, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm10, (%[out])\n\t"
"vmovntpd %%ymm11, 32(%[out])\n\t"
: [a] "+&r"(a), [b] "+&r"(b), [out] "+&r"(out), [k] "+&r"(k),
[pks] "+&r"(pks), [pky] "+&r"(pky), [pkd] "+&r"(pkd)
: [stride] "r"(stride), [sg] "i"(SG), [o0] "i"(0*4*(BASE+24)*8), [o1] "i"(1*4*(BASE+24)*8), [o2] "i"(2*4*(BASE+24)*8), [o3] "i"(3*4*(BASE+24)*8), [o4] "i"(4*4*(BASE+24)*8), [o5] "i"(5*4*(BASE+24)*8)
: "memory", "cc", "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15");
}
static __attribute__((always_inline)) inline void kernel_plain(int n,const double *a,const double *b,double *c,int ldc,int rows) {
double *out=c;
ptrdiff_t stride=(ptrdiff_t)ldc*8;
int k=n;
asm volatile (
"vxorpd %%ymm0, %%ymm0, %%ymm0\n\t"
"vxorpd %%ymm1, %%ymm1, %%ymm1\n\t"
"vxorpd %%ymm2, %%ymm2, %%ymm2\n\t"
"vxorpd %%ymm3, %%ymm3, %%ymm3\n\t"
"vxorpd %%ymm4, %%ymm4, %%ymm4\n\t"
"vxorpd %%ymm5, %%ymm5, %%ymm5\n\t"
"vxorpd %%ymm6, %%ymm6, %%ymm6\n\t"
"vxorpd %%ymm7, %%ymm7, %%ymm7\n\t"
"vxorpd %%ymm8, %%ymm8, %%ymm8\n\t"
"vxorpd %%ymm9, %%ymm9, %%ymm9\n\t"
"vxorpd %%ymm10, %%ymm10, %%ymm10\n\t"
"vxorpd %%ymm11, %%ymm11, %%ymm11\n\t"
".p2align 6\n\t"
"1:\n\t"
"vmovapd 0(%[b]), %%ymm12\n\t"
"vmovapd 32(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 512(%[b])\n\t"
"vfmadd231pd %c[o2]+0(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+0(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+0(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+0(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+0(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+0(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+0(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+0(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 64(%[b]), %%ymm12\n\t"
"vmovapd 96(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 576(%[b])\n\t"
"vfmadd231pd %c[o2]+32(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+32(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+32(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+32(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+32(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+32(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+32(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+32(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 128(%[b]), %%ymm12\n\t"
"vmovapd 160(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 640(%[b])\n\t"
"vfmadd231pd %c[o2]+64(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+64(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+64(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+64(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+64(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+64(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+64(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+64(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 192(%[b]), %%ymm12\n\t"
"vmovapd 224(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 704(%[b])\n\t"
"vfmadd231pd %c[o2]+96(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+96(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+96(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+96(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+96(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+96(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+96(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+96(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 256(%[b]), %%ymm12\n\t"
"vmovapd 288(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+128(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+128(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+128(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+128(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 768(%[b])\n\t"
"vfmadd231pd %c[o2]+128(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+128(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+128(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+128(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+128(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+128(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+128(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+128(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 320(%[b]), %%ymm12\n\t"
"vmovapd 352(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+160(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+160(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+160(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+160(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 832(%[b])\n\t"
"vfmadd231pd %c[o2]+160(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+160(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+160(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+160(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+160(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+160(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+160(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+160(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 384(%[b]), %%ymm12\n\t"
"vmovapd 416(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+192(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+192(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+192(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+192(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 896(%[b])\n\t"
"vfmadd231pd %c[o2]+192(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+192(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+192(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+192(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+192(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+192(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+192(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+192(%[a]), %%ymm13, %%ymm11\n\t"
"vmovapd 448(%[b]), %%ymm12\n\t"
"vmovapd 480(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+224(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+224(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+224(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+224(%[a]), %%ymm13, %%ymm3\n\t"
"prefetcht0 960(%[b])\n\t"
"vfmadd231pd %c[o2]+224(%[a]), %%ymm12, %%ymm4\n\t"
"vfmadd231pd %c[o2]+224(%[a]), %%ymm13, %%ymm5\n\t"
"vfmadd231pd %c[o3]+224(%[a]), %%ymm12, %%ymm6\n\t"
"vfmadd231pd %c[o3]+224(%[a]), %%ymm13, %%ymm7\n\t"
"vfmadd231pd %c[o4]+224(%[a]), %%ymm12, %%ymm8\n\t"
"vfmadd231pd %c[o4]+224(%[a]), %%ymm13, %%ymm9\n\t"
"vfmadd231pd %c[o5]+224(%[a]), %%ymm12, %%ymm10\n\t"
"vfmadd231pd %c[o5]+224(%[a]), %%ymm13, %%ymm11\n\t"
"add $256, %[a]\n\t"
"add $512, %[b]\n\t"
"sub $8, %[k]\n\t"
"jnz 1b\n\t"
"vmovntpd %%ymm0, (%[out])\n\t"
"vmovntpd %%ymm1, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm2, (%[out])\n\t"
"vmovntpd %%ymm3, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm4, (%[out])\n\t"
"vmovntpd %%ymm5, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm6, (%[out])\n\t"
"vmovntpd %%ymm7, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm8, (%[out])\n\t"
"vmovntpd %%ymm9, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm10, (%[out])\n\t"
"vmovntpd %%ymm11, 32(%[out])\n\t"
: [a] "+&r"(a), [b] "+&r"(b), [out] "+&r"(out), [k] "+&r"(k)
: [stride] "r"(stride), [o0] "i"(0*4*(BASE+24)*8), [o1] "i"(1*4*(BASE+24)*8), [o2] "i"(2*4*(BASE+24)*8), [o3] "i"(3*4*(BASE+24)*8), [o4] "i"(4*4*(BASE+24)*8), [o5] "i"(5*4*(BASE+24)*8)
: "memory", "cc", "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15");
}
/* ===== mdA_dp2: deferred h=1024 combine (Winograd form, exact same arithmetic) ===== */
struct Pend2 { double *c; int ldc; const double *m; int h; int pz; int pos; bool active; int i, j; }; /* [m2w-NODIV] */
static Pend2 pend2={0,0,0,0,0,0,false,0,0};
static constexpr int STEP2=16;
static inline void pend2_prefetch(void){
if(!pend2.active)return;
const int i=pend2.i, j=pend2.j; /* [m2w-NODIV] */
const double *c=pend2.c+(size_t)i*pend2.ldc+j;
const double *m=pend2.m+pend2.pos;
for(int t=0;t<STEP2;t+=8) {
_mm_prefetch((const char*)(c+t),_MM_HINT_T1);
_mm_prefetch((const char*)(c+pend2.h+t),_MM_HINT_T1);
_mm_prefetch((const char*)(c+(size_t)pend2.h*pend2.ldc+t),_MM_HINT_T1);
_mm_prefetch((const char*)(c+(size_t)pend2.h*pend2.ldc+pend2.h+t),_MM_HINT_T1);
_mm_prefetch((const char*)(m+t),_MM_HINT_T1);
_mm_prefetch((const char*)(m+pend2.pz+t),_MM_HINT_T1);
_mm_prefetch((const char*)(m+2*pend2.pz+t),_MM_HINT_T1);
}
}
static inline void pend2_step(void){
const int i=pend2.i, j=pend2.j; /* [m2w-NODIV] */
for(int t=0;t<STEP2;t+=4) {
double *c11=pend2.c+(size_t)i*pend2.ldc+j+t,*c12=c11+pend2.h,
*c21=c11+(size_t)pend2.h*pend2.ldc,*c22=c21+pend2.h;
const double *m=pend2.m+pend2.pos+t;
__m256d m1=_mm256_load_pd(c11),m2=_mm256_load_pd(c21),
m3=_mm256_load_pd(c12),m4=_mm256_load_pd(c22),
m5=_mm256_load_pd(m),m6=_mm256_load_pd(m+pend2.pz),m7=_mm256_load_pd(m+2*pend2.pz);
__m256d u2=_mm256_add_pd(m1,m6),u3=_mm256_add_pd(u2,m7),u4=_mm256_add_pd(u2,m5);
__m256d r11=_mm256_add_pd(m1,m2),r12=_mm256_add_pd(u4,m3),
r21=_mm256_sub_pd(u3,m4),r22=_mm256_add_pd(u3,m5);
_mm256_store_pd(c11,r11);_mm256_store_pd(c12,r12);
_mm256_store_pd(c21,r21);_mm256_store_pd(c22,r22);
}
pend2.pos+=STEP2;
pend2.j+=STEP2; if(pend2.j>=pend2.h){pend2.j-=pend2.h;pend2.i++;}
if(pend2.pos>=pend2.h*pend2.h)pend2.active=false;
}
static void pend2_finish(void){ while(pend2.active)pend2_step(); }
struct Pending { double *c; int ldc; const double *m; int pos=0; bool active=false; int rowlim=0; bool prog=false; };
static Pending pending;
alignas(4096) static double pending_work[3*(BASE*BASE+LEAF_PAD)+LEAF_PAD];
static unsigned pending_tick=0;
static constexpr int STEP=32, PERIOD=1;
static inline void pending_prefetch() {
if(!pending.active)return;
if(pending.prog && pending.pos/BASE>=pending.rowlim)return;
int i=pending.pos/BASE,j=pending.pos%BASE;
const double *c=pending.c+(size_t)i*pending.ldc+j;
const double *m=pending.m+pending.pos;
for(int t=0;t<STEP;t+=8) {
_mm_prefetch((const char*)(c+t),_MM_HINT_T1);
_mm_prefetch((const char*)(c+BASE+t),_MM_HINT_T1);
_mm_prefetch((const char*)(c+(size_t)BASE*pending.ldc+t),_MM_HINT_T1);
_mm_prefetch((const char*)(c+(size_t)BASE*pending.ldc+BASE+t),_MM_HINT_T1);
_mm_prefetch((const char*)(m+t),_MM_HINT_T1);
_mm_prefetch((const char*)(m+(BASE*BASE+LEAF_PAD)+t),_MM_HINT_T1);
_mm_prefetch((const char*)(m+2*(BASE*BASE+LEAF_PAD)+t),_MM_HINT_T1);
}
}
static inline void pending_step() {
if(pending.prog && pending.pos/BASE>=pending.rowlim)return;
int i=pending.pos/BASE,j=pending.pos%BASE;
for(int t=0;t<STEP;t+=4) {
double *c11=pending.c+(size_t)i*pending.ldc+j+t,
*c12=c11+BASE,*c21=c11+(size_t)BASE*pending.ldc,*c22=c21+BASE;
const double *m=pending.m+pending.pos+t;
__m256d m1=_mm256_load_pd(c11),m2=_mm256_load_pd(c21),
m3=_mm256_load_pd(c12),m4=_mm256_load_pd(c22),
m5=_mm256_load_pd(m),m6=_mm256_load_pd(m+(BASE*BASE+LEAF_PAD)),m7=_mm256_load_pd(m+2*(BASE*BASE+LEAF_PAD));
__m256d r11=_mm256_add_pd(_mm256_sub_pd(_mm256_add_pd(m1,m4),m5),m7),
r12=_mm256_add_pd(m3,m5),r21=_mm256_add_pd(m2,m4),
r22=_mm256_add_pd(_mm256_add_pd(_mm256_sub_pd(m1,m2),m3),m6);
_mm256_store_pd(c11,r11);_mm256_store_pd(c12,r12);
_mm256_store_pd(c21,r21);_mm256_store_pd(c22,r22);
}
pending.pos+=STEP;
if(pending.pos==BASE*BASE)pending.active=false;
}
static void pending_finish() {
pending.prog=false;
while(pending.active)pending_step();
}
static __attribute__((always_inline)) inline void kernel2(int n,const double *a,const double *b,double *c,int ldc) {
int k=n;
double *out=c;
ptrdiff_t stride=(ptrdiff_t)ldc*8;
asm volatile (
"vxorpd %%ymm0, %%ymm0, %%ymm0\n\t"
"vxorpd %%ymm1, %%ymm1, %%ymm1\n\t"
"vxorpd %%ymm2, %%ymm2, %%ymm2\n\t"
"vxorpd %%ymm3, %%ymm3, %%ymm3\n\t"
".p2align 6\n\t" "1:\n\t"
"prefetcht0 512(%[b])\n\t"
"prefetcht0 576(%[b])\n\t"
"prefetcht0 640(%[b])\n\t"
"prefetcht0 704(%[b])\n\t"
"vmovapd 0(%[b]), %%ymm12\n\t"
"vmovapd 32(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm13, %%ymm3\n\t"
"vmovapd 64(%[b]), %%ymm12\n\t"
"vmovapd 96(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm13, %%ymm3\n\t"
"vmovapd 128(%[b]), %%ymm12\n\t"
"vmovapd 160(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm13, %%ymm3\n\t"
"vmovapd 192(%[b]), %%ymm12\n\t"
"vmovapd 224(%[b]), %%ymm13\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm12, %%ymm0\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm13, %%ymm1\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm12, %%ymm2\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm13, %%ymm3\n\t"
"add $128, %[a]\n\t"
"add $256, %[b]\n\t"
"sub $4, %[k]\n\t"
"jnz 1b\n\t"
"vmovntpd %%ymm0, (%[out])\n\t"
"vmovntpd %%ymm1, 32(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm2, (%[out])\n\t"
"vmovntpd %%ymm3, 32(%[out])\n\t"
: [a] "+&r"(a), [b] "+&r"(b), [out] "+&r"(out), [k] "+&r"(k)
: [stride] "r"(stride), [o0] "i"(0*4*(BASE+24)*8), [o1] "i"(1*4*(BASE+24)*8)
: "memory", "cc", "ymm0","ymm1","ymm2","ymm3","ymm12","ymm13","ymm14");
}
static __attribute__((noinline)) void kernel_tail16(int n,const double *a,const double *b,double *out,int ldc) {
const double *b1=b+8*(n+1);
ptrdiff_t stride=(ptrdiff_t)ldc*8;
int kk=n;
asm volatile (
"vxorpd %%ymm0, %%ymm0, %%ymm0\n\t"
"vxorpd %%ymm1, %%ymm1, %%ymm1\n\t"
"vxorpd %%ymm2, %%ymm2, %%ymm2\n\t"
"vxorpd %%ymm3, %%ymm3, %%ymm3\n\t"
"vxorpd %%ymm4, %%ymm4, %%ymm4\n\t"
"vxorpd %%ymm5, %%ymm5, %%ymm5\n\t"
"vxorpd %%ymm6, %%ymm6, %%ymm6\n\t"
"vxorpd %%ymm7, %%ymm7, %%ymm7\n\t"
".p2align 6\n\t"
"1:\n\t"
"prefetcht0 512(%[b])\n\t"
"prefetcht0 512(%[b1])\n\t"
"vmovapd 0(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm14, %%ymm0\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm14, %%ymm4\n\t"
"vmovapd 32(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm14, %%ymm1\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm14, %%ymm5\n\t"
"vmovapd 0(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm14, %%ymm2\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm14, %%ymm6\n\t"
"vmovapd 32(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+0(%[a]), %%ymm14, %%ymm3\n\t"
"vfmadd231pd %c[o1]+0(%[a]), %%ymm14, %%ymm7\n\t"
"prefetcht0 576(%[b])\n\t"
"prefetcht0 576(%[b1])\n\t"
"vmovapd 64(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm14, %%ymm0\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm14, %%ymm4\n\t"
"vmovapd 96(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm14, %%ymm1\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm14, %%ymm5\n\t"
"vmovapd 64(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm14, %%ymm2\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm14, %%ymm6\n\t"
"vmovapd 96(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+32(%[a]), %%ymm14, %%ymm3\n\t"
"vfmadd231pd %c[o1]+32(%[a]), %%ymm14, %%ymm7\n\t"
"prefetcht0 640(%[b])\n\t"
"prefetcht0 640(%[b1])\n\t"
"vmovapd 128(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm14, %%ymm0\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm14, %%ymm4\n\t"
"vmovapd 160(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm14, %%ymm1\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm14, %%ymm5\n\t"
"vmovapd 128(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm14, %%ymm2\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm14, %%ymm6\n\t"
"vmovapd 160(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+64(%[a]), %%ymm14, %%ymm3\n\t"
"vfmadd231pd %c[o1]+64(%[a]), %%ymm14, %%ymm7\n\t"
"prefetcht0 704(%[b])\n\t"
"prefetcht0 704(%[b1])\n\t"
"vmovapd 192(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm14, %%ymm0\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm14, %%ymm4\n\t"
"vmovapd 224(%[b]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm14, %%ymm1\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm14, %%ymm5\n\t"
"vmovapd 192(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm14, %%ymm2\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm14, %%ymm6\n\t"
"vmovapd 224(%[b1]), %%ymm14\n\t"
"vfmadd231pd %c[o0]+96(%[a]), %%ymm14, %%ymm3\n\t"
"vfmadd231pd %c[o1]+96(%[a]), %%ymm14, %%ymm7\n\t"
"add $128, %[a]\n\t"
"add $256, %[b]\n\t"
"add $256, %[b1]\n\t"
"sub $4, %[kk]\n\t"
"jnz 1b\n\t"
"vmovntpd %%ymm0, 0(%[out])\n\t"
"vmovntpd %%ymm1, 32(%[out])\n\t"
"vmovntpd %%ymm2, 64(%[out])\n\t"
"vmovntpd %%ymm3, 96(%[out])\n\t"
"add %[stride], %[out]\n\t"
"vmovntpd %%ymm4, 0(%[out])\n\t"
"vmovntpd %%ymm5, 32(%[out])\n\t"
"vmovntpd %%ymm6, 64(%[out])\n\t"
"vmovntpd %%ymm7, 96(%[out])\n\t"
: [a] "+&r"(a),[b] "+&r"(b),[b1] "+&r"(b1),[out] "+&r"(out),[kk] "+&r"(kk)
: [stride] "r"(stride),[o0] "i"(0),[o1] "i"(4*(BASE+24)*8)
: "memory","cc","ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15");
}
static void leaf(int n,Mat a,Mat b,double *c,int ldc) {
for(int k=0;k<n;k+=2)for(int j=0;j<n;j+=8) {
double *p=bp+(size_t)j*(n+1)+k*8;
_mm256_store_pd(p+0,ld(b,k+0,j));_mm256_store_pd(p+4,ld(b,k+0,j+4));
_mm256_store_pd(p+8,ld(b,k+1,j));_mm256_store_pd(p+12,ld(b,k+1,j+4));
}
pending_prefetch();
double *pkb[2]={ap,ap2};
int cur=0;
{ /* pack the first ic-block the ordinary way */
int mc0=n<MC?n:MC;
for(int r=0;r<mc0;r+=MR) {
int rows=mc0-r<MR?mc0-r:MR;
for(int i=0;i<rows;i++)for(int k=0;k<n;k+=4)
{ __m256d _v=ld(a,r+i,k); double *_p=pkb[0]+(size_t)(r+i)*4*(BASE+24)+4*k; _mm256_store_pd(_p,_mm256_permute4x64_pd(_v,0x00)); _mm256_store_pd(_p+4,_mm256_permute4x64_pd(_v,0x55)); _mm256_store_pd(_p+8,_mm256_permute4x64_pd(_v,0xAA)); _mm256_store_pd(_p+12,_mm256_permute4x64_pd(_v,0xFF)); }
for(int i=rows;i<MR;i++)for(int k=0;k<n;k+=4)
{ __m256d _z=_mm256_setzero_pd(); double *_p=pkb[0]+(size_t)(r+i)*4*(BASE+24)+4*k; _mm256_store_pd(_p,_z); _mm256_store_pd(_p+4,_z); _mm256_store_pd(_p+8,_z); _mm256_store_pd(_p+12,_z); }
}
}
for(int ic=0;ic<n;) {
int mc=n-ic<=MC+MR?n-ic:MC;
if(mc==MC+2) {
for(int j=0;j<n;j+=16) {
for(int jj=j;jj<j+16;jj+=NR)for(int r=0;r<MC;r+=MR) {
kernel_plain(n,pkb[cur]+(size_t)r*4*(BASE+24),bp+(size_t)jj*(n+1),c+(size_t)(ic+r)*ldc+jj,ldc,MR);
if(pending.active && (++pending_tick%PERIOD)==0) {pending_step();if(pending.prog)pending_step();pending_prefetch();}
if(pend2.active) {pend2_step();pend2_prefetch();}
}
kernel_tail16(n,pkb[cur]+(size_t)MC*4*(BASE+24),bp+(size_t)j*(n+1),c+(size_t)(ic+MC)*ldc+j,ldc);
}
ic+=mc;
if(pending.prog)pending.rowlim=ic;
continue;
}
/* ---- the NEXT ic-block's A panel is carried by this block's kernel calls ---- */
const int ic2=ic+mc;
const int nxt=(ic2<n)?(n-ic2<=MC+MR?n-ic2:MC):0;
const int rows2=((nxt+MR-1)/MR)*MR; /* rows incl. the zero pad rows */
const int nch=rows2*2; /* 2 chunks per row */
const int qd=n/2; /* doubles per chunk */
int ck=0; int skip=(n/NR)*((mc+MR-1)/MR)-nch;
for(int j=0;j<n;j+=NR)for(int r=0;r<mc;r+=MR) {
if(mc-r==2) { /* md9_t2: 2-row tail body (was 6-row body + tmp copy) */
kernel2(n,pkb[cur]+(size_t)r*4*(BASE+24),bp+(size_t)j*(n+1),c+(size_t)(ic+r)*ldc+j,ldc);
continue;
}
const double *pks=pk_zero,*pky=pk_zero,*pkm=pk_mp;
double *pkd=pk_zero;
int pkc=0;
if(ck<nch && --skip<0) {
const int row=ck/2, off=(ck%2)*qd;
if(row<nxt) {
pks=a.x+(size_t)(ic2+row)*a.ld+(size_t)off;
pky=a.sign?(a.y+(size_t)(ic2+row)*a.ly+(size_t)off):pk_zero;
pkm=a.sign>0?pk_mp:pk_mn;
}
pkd=pkb[cur^1]+(size_t)row*4*(BASE+24)+(size_t)off*4;
pkc=8;
ck++;
}
if(!pkc) kernel_plain(n,pkb[cur]+(size_t)r*4*(BASE+24),bp+(size_t)j*(n+1),c+(size_t)(ic+r)*ldc+j,ldc,mc-r<MR?mc-r:MR);
else if(a.sign==0) kernel<2>(n,pkb[cur]+(size_t)r*4*(BASE+24),bp+(size_t)j*(n+1),c+(size_t)(ic+r)*ldc+j,ldc,mc-r<MR?mc-r:MR,pks,pky,pkd);
else if(a.sign>0) kernel<1>(n,pkb[cur]+(size_t)r*4*(BASE+24),bp+(size_t)j*(n+1),c+(size_t)(ic+r)*ldc+j,ldc,mc-r<MR?mc-r:MR,pks,pky,pkd);
else kernel<-1>(n,pkb[cur]+(size_t)r*4*(BASE+24),bp+(size_t)j*(n+1),c+(size_t)(ic+r)*ldc+j,ldc,mc-r<MR?mc-r:MR,pks,pky,pkd);
if(pending.active && (++pending_tick%PERIOD)==0) {
pending_step(); if(pending.prog)pending_step(); pending_prefetch();
}
if(pend2.active) { pend2_step(); pend2_prefetch(); }
}
/* ---- finish whatever the kernel loop did not carry ---- */
for(int cc=ck;cc<nch;cc++) {
const int row=cc/2, off=(cc%2)*qd;
if(row<nxt) {
for(int k=off;k<off+qd;k+=4)
{ __m256d _v=ld(a,ic2+row,k); double *_p=pkb[cur^1]+(size_t)row*4*(BASE+24)+4*k; _mm256_store_pd(_p,_mm256_permute4x64_pd(_v,0x00)); _mm256_store_pd(_p+4,_mm256_permute4x64_pd(_v,0x55)); _mm256_store_pd(_p+8,_mm256_permute4x64_pd(_v,0xAA)); _mm256_store_pd(_p+12,_mm256_permute4x64_pd(_v,0xFF)); }
} else {
for(int k=off;k<off+qd;k+=4)
{ __m256d _z=_mm256_setzero_pd(); double *_p=pkb[cur^1]+(size_t)row*4*(BASE+24)+4*k; _mm256_store_pd(_p,_z); _mm256_store_pd(_p+4,_z); _mm256_store_pd(_p+8,_z); _mm256_store_pd(_p+12,_z); }
}
}
cur^=1;
ic+=mc;
if(pending.prog)pending.rowlim=ic;
}
if(n>=NTMIN)_mm_sfence();
}
static void sum(int h,double *dst,Mat a,Mat b,int sign) {
for(int i=0;i<h;i++)for(int j=0;j<h;j+=8) {
__m256d v=sign>0?_mm256_add_pd(ld(a,i,j),ld(b,i,j)):_mm256_sub_pd(ld(a,i,j),ld(b,i,j));
__m256d w=sign>0?_mm256_add_pd(ld(a,i,j+4),ld(b,i,j+4)):_mm256_sub_pd(ld(a,i,j+4),ld(b,i,j+4));
asm volatile("" : "+x"(v), "+x"(w) : : "memory");
if(h>=SUMNT) {
_mm256_stream_pd(dst+(size_t)i*h+j,v);_mm256_stream_pd(dst+(size_t)i*h+j+4,w);
} else {
_mm256_store_pd(dst+(size_t)i*h+j,v);_mm256_store_pd(dst+(size_t)i*h+j+4,w);
}
}
if(h>=SUMNT)_mm_sfence();
}
static void combine(int h,double *c,int ldc,const double *m,bool wino=false) {
size_t z=(size_t)h*h+(wino?UPPER_PAGE_PAD:0);
for(int i=0;i<h;i++)for(int j=0;j<h;j+=4) {
size_t t=(size_t)i*h+j;
double *c11=c+(size_t)i*ldc+j,*c12=c11+h,*c21=c+(size_t)(i+h)*ldc+j,*c22=c21+h;
__m256d m1=_mm256_load_pd(c11),m2=_mm256_load_pd(c21),m3=_mm256_load_pd(c12),m4=_mm256_load_pd(c22),
m5=_mm256_load_pd(m+t),m6=_mm256_load_pd(m+z+t),m7=_mm256_load_pd(m+2*z+t);
__m256d r11,r12,r21,r22;
if(wino) {
__m256d u2=_mm256_add_pd(m1,m6),u3=_mm256_add_pd(u2,m7),u4=_mm256_add_pd(u2,m5);
r11=_mm256_add_pd(m1,m2);r12=_mm256_add_pd(u4,m3);r21=_mm256_sub_pd(u3,m4);r22=_mm256_add_pd(u3,m5);
} else {
r11=_mm256_add_pd(_mm256_sub_pd(_mm256_add_pd(m1,m4),m5),m7);r12=_mm256_add_pd(m3,m5);r21=_mm256_add_pd(m2,m4);
r22=_mm256_add_pd(_mm256_add_pd(_mm256_sub_pd(m1,m2),m3),m6);
}
_mm256_store_pd(c11,r11);_mm256_store_pd(c12,r12);_mm256_store_pd(c21,r21);_mm256_store_pd(c22,r22);
}
}
static void pre(int h,Mat a,double *s1,double *s2,double *s4,double *s3,int ld3,bool right) {
for(int i=0;i<h;i++)for(int j=0;j<h;j+=8) {
__m256d a0=ld(a,i,j),a1=ld(a,i,j+4),b0=ld(a,i,j+h),b1=ld(a,i,j+h+4),
c0=ld(a,i+h,j),c1=ld(a,i+h,j+4),d0=ld(a,i+h,j+h),d1=ld(a,i+h,j+h+4);
__m256d p0,p1,q0,q1,r0,r1,t0,t1;
if(!right) {
p0=_mm256_add_pd(c0,d0);p1=_mm256_add_pd(c1,d1);
q0=_mm256_sub_pd(p0,a0);q1=_mm256_sub_pd(p1,a1);
r0=_mm256_sub_pd(b0,q0);r1=_mm256_sub_pd(b1,q1);
t0=_mm256_sub_pd(a0,c0);t1=_mm256_sub_pd(a1,c1);
}else {
p0=_mm256_sub_pd(b0,a0);p1=_mm256_sub_pd(b1,a1);
q0=_mm256_sub_pd(d0,p0);q1=_mm256_sub_pd(d1,p1);
r0=_mm256_sub_pd(q0,c0);r1=_mm256_sub_pd(q1,c1);
t0=_mm256_sub_pd(d0,b0);t1=_mm256_sub_pd(d1,b1);
}
size_t off=(size_t)i*h+j,off3=(size_t)i*ld3+j;
_mm256_stream_pd(s1+off,p0);_mm256_stream_pd(s1+off+4,p1);
_mm256_stream_pd(s2+off,q0);_mm256_stream_pd(s2+off+4,q1);
_mm256_stream_pd(s4+off,r0);_mm256_stream_pd(s4+off+4,r1);
_mm256_stream_pd(s3+off3,t0);_mm256_stream_pd(s3+off3+4,t1);
}
_mm_sfence();
}
static const int lperm[7]={3,1,2,0,5,4,6};
static void rec(int n,Mat a,Mat b,double *c,int ldc,double *work) {
if(n<=BASE){leaf(n,a,b,c,ldc);return;}
int h=n/2;size_t z=(size_t)h*h;
Mat aa[4]={{a.x,a.ld},{a.x+h,a.ld},{a.x+(size_t)h*a.ld,a.ld},{a.x+(size_t)h*a.ld+h,a.ld}};
Mat bb[4]={{b.x,b.ld},{b.x+h,b.ld},{b.x+(size_t)h*b.ld,b.ld},{b.x+(size_t)h*b.ld+h,b.ld}};
double *m=n==2*BASE?work+LEAF_PAD:work;
if(n==2*BASE && pending.active && pending.m==m)m=pending_work+LEAF_PAD;
size_t pz=z+(n==2*BASE?LEAF_PAD:UPPER_PAGE_PAD);
double *p=work+3*z,*q=p+z,*sub=q+z;
double *out[7]={c,c+(size_t)h*ldc,c+h,c+(size_t)h*ldc+h,m,m+pz,m+2*pz};
if(n>BASE*2) {
pending_finish();
double *pa0=m+3*pz,*pa1=pa0+pz,*pa2=pa1+pz,*pb0=pa2+pz,*pb1=pb0+pz,*pb2=pb1+pz;
sub=pb2+pz;
pre(h,a,pa0,pa1,pa2,c,ldc,false);
pre(h,b,pb0,pb1,pb2,c+h,ldc,true);
/* mdA_dp2: child order [1,3,4,5,6,0,2] -- constraint "6 before 0 and 2" is the only
hard one; this order puts the three m-panel writers (4,5,6) as late as possible,
which IS the deferral window for the previous sibling's deferred h=1024 combine. */
rec(h,aa[1],bb[2],out[1],ldc,sub);
rec(h,aa[3],{pb2,h},out[3],ldc,sub);
pend2_finish(); /* barrier: next call writes m, the deferred products */
rec(h,{pa0,h},{pb0,h},out[4],h,sub);
rec(h,{pa1,h},{pb1,h},out[5],h,sub);
rec(h,{c,ldc},{c+h,ldc},out[6],h,sub);
rec(h,aa[0],bb[0],out[0],ldc,sub);
rec(h,{pa2,h},bb[3],out[2],ldc,sub);
pending_finish();
pend2_finish(); /* finish an older deferred one */
pend2={c,ldc,m,h,(int)pz,0,true,0,0}; /* defer THIS combine (wino form);
m-plane stride = the engine's pz */
return;
}
const int ai[7]={0,2,0,3,0,2,1},aj[7]={3,3,-1,-1,1,0,3},as[7]={1,1,0,0,1,-1,-1};
const int bi[7]={0,0,1,2,3,0,2},bj[7]={3,-1,3,0,-1,1,3},bs[7]={1,0,-1,-1,0,1,1};
for(int r=0;r<7;r++) {
Mat x=aa[ai[r]],y=bb[bi[r]];
if(h<=BASE) {
/* mdE_perm: leaf-order permutation (outputs independent => bit-exact).
lperm = {2,4,5,1,3,6,0} A-adjacency 7 / B-adjacency 5 (natural order: 3/3). */
const int q=lperm[r];
Mat x=aa[ai[q]],y=bb[bi[q]];
if(as[q]){x.y=aa[aj[q]].x;x.ly=a.ld;x.sign=as[q];}
if(bs[q]){y.y=bb[bj[q]].x;y.ly=b.ld;y.sign=bs[q];}
if(r==6) {
pending_finish();
pending={c,ldc,m,0,true,0,true};
leaf(h,x,y,out[q],q<4?ldc:h);
pending.prog=false;
} else leaf(h,x,y,out[q],q<4?ldc:h);
} else {
if(as[r]){sum(h,p,x,aa[aj[r]],as[r]);x={p,h};}
if(bs[r]){sum(h,q,y,bb[bj[r]],bs[r]);y={q,h};}
rec(h,x,y,out[r],r<4?ldc:h,sub);
}
}
if(h==BASE) {
/* Keep any final portion deferred into the next sibling. */
} else {
pending_finish();
combine(h,c,ldc,m);
}
}
void matrix_multiply(int n,const double *a,const double *b,double *c) {
rec(n,{a,n},{b,n},c,n,workspace);
pending_finish();
pend2_finish();
_mm_sfence();
}
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 564.271 ms | 119 MB + 140 KB | Accepted | Score: 100 | 显示更多 |