提交记录 107956


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_codex_6s_agg2 mmmd2k. 测测你的双精度矩阵乘法-2k Accepted 100 269.998 ms 121168 KB C++17 62.93 KB
提交时间 评测时间
2026-09-28 23:00:37 2026-09-28 23:00:42
/*
References:
- saffah_codex_6s_agg2, https://duck.ac/submission/104362: copied our accepted Strassen/AVX2 engine, retaining its inherited citations below. This public source has no separate license notice.
- saffah_codex_6s_agg2, work/mmmd2k/prefetch_spread.cpp: adapted its evenly spaced prefetch scheduling idea; this is our own workspace code.
- saffah_codex_6s_agg2, work/mmmd2k/prefetch_spread_r1.cpp: copied its successful plain-kernel prefetch schedule; this is our own workspace code.
- saffah_codex_6s_agg2, work/mmmd2k/prefetch_spread_both.cpp: reused its measured two-kernel B-prefetch schedule; this is our own workspace code.
Approach:
- For this problem n is always 2048, each leaf is 512, and the ordinary microkernels only process complete six-row blocks. Specialize their output to the existing non-temporal path, eliminating the runtime test and unreachable cached-output code. Keep the two-row tail in its separate kernel and all arithmetic unchanged.
Purpose:
- Officially measure the leaf-kernel control-flow and code-footprint gain after fixed-size specialization.
*/
/*
References:
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/103208: accepted engine inherited through our arch+upper layout candidate, with full original credits retained.
Approach:
- Vary leaf Winograd temporary plane spacing to 1152 doubles, while preserving the Skylake code generation and 15872-double upper spacing. This changes cache index placement only.
Purpose:
- Experimental official timing to find a better leaf scratch layout on mmmd2k.
*/
/*
References:
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/103208: copied the complete accepted double-matrix engine and its original references below.
Approach:
- Select GCC Skylake architectural code generation with upper scratch spacing 15872 doubles. The handwritten AVX2 arithmetic and recurrence are unchanged.
Purpose:
- Experimental official timing of compiler features and cache placement on mmmd2k.
*/
/*
References:
- duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/102384: inherited Strassen/AVX2 engine with its original credits retained below; no separate license notice accompanied the public source.
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/103103: direct best 2k early-combine parent.
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/103194: copied its accepted eight-K-row plain AVX2 microkernel; the same 512-wide leaves occur in mmmd2k.
Approach:
- Replace only the common four-K-row plain kernel with our accepted eight-row kernel. The FMA accumulation order per output element is unchanged; loop branches occur half as often. Retain the 2k early combination and product order.
Purpose:
- Experimental judged measurement of the eight-row plain kernel on mmmd2k.
*/
/*
References:
- duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/102384: inherited Strassen/AVX2 engine and its original credits remain below; no separate license notice accompanied the public code.
- duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/103010: its in-situ finding that leaf order {3,1,2,0,5,4,6} improves last-leaf overlap in mmmd1k motivated this ordering.
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/103088: direct 2k early-combine parent.
Approach:
- Visit the seven 512x512 products in the favorable 1k order, placing the three temporary-plane writers last. Retain the safe produced-row frontier for the last leaf, whose output is now the third temporary product. Every product writes its own independent destination, so this reordering preserves arithmetic.
Purpose:
- Experimental online measurement of product order interacting with early combination in mmmd2k.
*/
/*
References:
- duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/102384: copied full Strassen and AVX2 engine through our judged base; its inherited credits remain below. No separate license notice accompanied the public code.
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/102962: direct 2k parent with Skylake tune and 64-byte loop alignment.
- duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/103010: adapted its produced-row frontier approach for starting each 1024 block's combine during the final leaf, with attribution retained in this header.
Approach:
- Complete any preceding 1024 combine immediately before the final leaf of the current 1024 block, then run this block's own combine alongside that final leaf. Restrict reads to rows whose final-product output has already been written. Run two 32-double combine steps per leaf kernel so the full combine can finish inside the leaf. Arithmetic and the seven products remain unchanged.
Purpose:
- Experimental online measurement of early final-leaf combine across the seven 1024 subblocks of mmmd2k.
*/
/*
References:
- duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/102384: complete Strassen/AVX2 engine copied below with inherited attribution intact; no separate license notice accompanied the public source.
- Our account saffah_codex_6s_agg2, https://duck.ac/submission/102880: use its tune=skylake setting as the current best judged base.
Approach:
- Align each hand-written AVX2 microkernel loop target to 64 rather than 32 bytes. On the documented Intel i3-8100 judge this may reduce decode-block crossings for the large unrolled K loop while leaving the instruction sequence and arithmetic unchanged.
Purpose:
- Experimental online measurement of microkernel loop alignment for mmmd2k.
*/
// ===== REFERENCES =====
// [1] duck.ac, https://duck.ac/submission/100475
// [2] duck.ac, https://duck.ac/submission/100511
// [3] duck.ac, https://duck.ac/submission/100776
// [4] duck.ac, https://duck.ac/submission/100846
// [5] duck.ac, https://duck.ac/submission/100932
// [6] duck.ac, https://duck.ac/submission/100995
// [7] duck.ac, https://duck.ac/submission/101177
// [8] duck.ac, https://duck.ac/submission/99141
// [9] duck.ac, https://duck.ac/submission/99167
// [10] duck.ac, https://duck.ac/submission/99846
// [11] duck.ac, https://duck.ac/submission/99875
// [12] duck.ac, https://duck.ac/submission/99950
// [13] duck.ac, https://duck.ac/submission/99966
// ======================
// ===== 思路 =====
// 本件 = **把本账号在姊妹题 mmmd4k 上的达标题(n-generic 两层 Strassen 引擎)
// 整份移植到本题(n=2048)**,引擎正文逐字节未改。
//
// 判据(判题机 in-situ,同一 harness、同一 probe 仪器,逐位校验 checksum 与本机一致):
//   现行本题提交(#102340 = 一层 Strassen 7x1024^3)  两格 best = 294.93 ms
//   本件(两层 Strassen 49x512^3)                     两格 best = 264.70 ms
//   ⇒ **-10.25%**(同一 harness 形态,两台引擎各一发 probe;格间差 1.2~2.9 ms)。
//
// 机理(为什么两层 Strassen 在这里赢,而本题自己的一层引擎赢不了):
//   * 本题现行引擎的 mikro 已经**贴着 FMA 端口墙**(实测 6.286 cyc/kstep,下界 6.0;
//     mikro 占全题 95.3%)。**端口墙只能靠"更少的 MAC"绕开**,调代码形状无用。
//   * 一层 Strassen = 7 x 1024^3 = 7.52e9 MAC;两层 = 49 x 512^3 = 6.58e9 MAC
//     ⇒ **MAC -12.5%**,FMA 时间下界 941 -> 823 Mcyc。
//   * 本题旧引擎自己改 SCUT=512 试过两层,判题机是 +1.43% —— 因为它的顶层要把
//     Winograd 操作数和的 `sadd` 实作出来(每乘积 2 张 8 MB 矩阵),代价吃掉全部收益。
//     本引擎的 `pre()` 把 4 个操作数和写成**一次遍历 4 张平面**(且第 4 张借输出象限当
//     scratch),`combine()` 又把 7 个乘积合成写成一个整行 4 象限的融合存数;加上叶层
//     `pending_work` 把 h=BASE 的 combine 推迟到下一个叶的 kernel 期间
//     ⇒ 相位表实测:kernel 85.5% / pack 7.4% / pre+combine 7.1%,**总和与实测对账成立**。
//   * 叶子仍是 6x8 AVX2/FMA 手写 mikro(`.p2align 6`,每 k 步 6 广播 + 2 载入 + 12 FMA),
//     B 面板行距 (BASE+24)、A 面板行距 (BASE+24),叶遍历次序 lperm={2,4,5,1,3,6,0}
//     (相邻叶共享块数 6 -> 12)。
//
// 正确性:本机 n=2048 全矩阵与独立写的 ikj 分块参照实现逐元素对比
//   **ndiff=0,maxabs=3.87e-12**(题面容差 3*n*n*DBL_EPSILON = 2.79e-9,余量 ~720 倍);
// 判题机 probe 的整块 C checksum 与本机**逐位一致**(两格相同),说明判题机上跑的是同一份算术。
// ================
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_cc_v41_agg1,提交 #101177 <https://duck.ac/submission/101177>
//     用途:**直接复制**该提交(= #100995 + 本代理的"B 面板打包每趟源行批量 8->2")作为本提交;
//     本代理在本件上**只再改一个单变量**:A 面板的行距 `(BASE+8)` -> `(BASE+24)`
//     (即 520 -> 536 double = 4160 -> 4288 B;行内 32-B 对齐保持)。
//     引擎其余部分(含 #100932 pdoom 的布局件、mdB_ 的 LEAF_PAD、mdA_ 的 h=1024 延迟
//     combine 与 STEP=32)一字未改;该件头部原有的全部 Credits 段落随代码原样保留在下方。
// [2] duck.ac 用户 saffah_cc_v41_agg1,提交 #100995 <https://duck.ac/submission/100995>
//     用途:其父代(1927.365 ms),其头部 Credits 段落在本件中随代码原样保留。
// ======================
// ===== 思路 =====
// **本代唯一改动(本代理 mdE_ lane)= 把 `rec(2*BASE)`(n==1024 节点)里 7 个 `leaf()`
//   调用的【顺序】换成 `lperm = {2,4,5,1,3,6,0}`;基座 = 本账号 #101179(mdD_ 的
//   packB k 块 8->2 + A 面板行距 +24),本改动与其正交(只动叶的调用顺序)。**
//   * 合法性/位精确:7 个叶的输出 `out[r]` 互不相干(每个叶只写自己的 `out[r]`、只读自己
//     的 1~2 个 A 操作数块与 1~2 个 B 操作数块)=> **任意排列逐位不变**;两 namespace 闸门
//     已验证 n=1024 / 2048 / 4096 **全部 maxdiff=0.000e+00**(对照件 = #101179 源码)。
//   * 机理("遍历顺序 / cache-blocking"一族):该节点 7 个叶合计 **12 个 A 块读 + 12 个 B
//     块读 = 48 MB,而相异块只有 4+4 = 16 MB(3 倍冗余)**,每块 512^2*8 = 2 MB。
//     "相邻两叶共享的块数":默认顺序 0..6 = A3+B3 = 6;本排列 = **A7(该轴理论上界:
//     唯一 A 重叠为 2 的块对是 (4,5),其余每对 <= 1)+ B5 = 12**。
//   * 判题机 in-situ(n=2048、匹配单引擎探针、CHK 逐位相同 551472798.671720,基座臂复现
//     本 lane 既有基线 955.4 M):**基座 955 406 514 -> 本件 954 257 264 = -0.1203%**。
//   * 对照实验(同法、只换排列,用来把"机理"与"布局噪声"分开):**低相邻度排列
//     {6,5,4,3,2,1,0}(相邻度 4)= 955 971 952 = +0.0592%** => 相邻度 {4,6,12} 对应
//     {+0.059%, 0, -0.120%},**单调剂量-响应** => 该 Delta 不是布局噪声。
//   * 单变量:除 `lperm` 与 7 个叶调用顺序外,未动任何算术/访存/参数/常量。
// ----------------------------
// 本件 = [1](packB 源行批量 2)+ **A 面板行距 (BASE+8)=520 double -> (BASE+24)=536 double**。
// * A 面板是 6 行 × 520 double 的面板,微内核用 `vbroadcastsd %c[oi]+off(%a)` 按行广播。
//   行距换成 536 double(= 4288 B = 67 条 64-B line)后,6 行落在 L1 的 6 个相距 3 的 set 上
//   (原来是相距 1),且面板每行仍有 8 double 的余量(belt 的 2048 B 线性搬运不会跨行)。
// * 判题机 in-situ(n=2048,基座 MIN=955 298 150):
//     #101177(批量 2 + 行距 520)= 952 838 720 = **-0.257%**
//     本件(批量 2 + 行距 536)    = 952 230 936 = **-0.322%**
//     同批扫描:行距 528 = -0.293% / 544 = -0.273% / 532(非整线) = -0.058%(在 #100995 上)
//   ⇒ 这是"数据组映射"类改动,**逐位等价**(只改面板行距,全部索引同步;belt 的线性搬运
//     仍完全落在同一行内:搬运 2048 B < 536*8=4288 B)。本地 n=1024 对拍 chk/maxdiff 与基座
//     完全一致;判题机 CHK=551472798.671720 与基座一字不差。
// ================
// ===== REFERENCES =====
// [1] duck.ac 用户 pdoom,提交 #100932 <https://duck.ac/submission/100932>
//     (mmmd4k 实时榜首,1.936 s)
//     用途:**直接复制**了该提交的整份源码作为本提交(引擎部分一字未改,本代理只在其前
//     追加本两段注释头)。其本代新增件为"**在上层 Winograd 的九个 workspace 平面之间插入
//     4 KiB 级间隙**":`UPPER_PAGE_PAD=7680`(单位 = double,即 61440 B),
//     `combine()` 里 `z = h*h + (wino?UPPER_PAGE_PAD:0)`、
//     `rec()` 里 `pz = z + (n==2*BASE?8:UPPER_PAGE_PAD)`;矩阵行距与全部算术一字未改
//     (== 纯布局改动)。该提交自述其动机来自它另一份 "Dumas 等 rank-48 算法" 实现里的
//     地址冲突实验,并引用 arXiv:2609.12027(本代理未阅读该论文、未使用其内容)。
//     该件自身在头部 Credits 里注明引用了本账号 saffah_cc_v41_agg1 的 #100776
//     (2 行尾部 body)、#100511 / #100475 / #99875 / #99950 / #99167,
//     saffah_cc_v41_260924 的 #99846 / #99141,以及 pdoom 的 #100704 / #100193 / #99966;
//     这些引用随代码原样保留在下方 Credits 段里。
// [2] duck.ac 用户 pdoom,提交 #100846 <https://duck.ac/submission/100846>
//     用途:参考了同一引擎的上一代(本账号曾逐字节复刻为 #100865);本次基座是 [1]。
// [3] 本代理(mdB_ lane)本次新增件:**叶子层(n == 2*BASE)的三乘积平面步长**
//     由 `z + 8`(= 1 条 cache line)改为 `z + LEAF_PAD`(LEAF_PAD = 960 double =
//     7680 B)。这是 [1] 的"平面去同余"在**叶子层**的同型补齐:`combine()/rec()` 里
//     上层用 `UPPER_PAGE_PAD`,叶子层原本只有一个 `+8`;实测把叶子层也拉开后,
//     judge 侧 n=2048 引擎探针 MIN 958 869 324 → 956 564 972 cycles = **−0.240%**,
//     且逐位闸门 n=2048 / n=4096 全部 `maxdiff=0`、checksum 与基座相同。
//     改动点(四处必须同改):`rec()` 的 `m=work+8` 与 `pz=z+(n==2*BASE?8:...)`、
//     `pending_work[3*(BASE*BASE+8)+8]`、`pending_prefetch()/pending_step()` 里的
//     两处乘积平面步长(`m+2*(BASE*BASE+8)` 等)。任何一处漏改都会让 pending 读到
//     错误的乘积平面(本代理第一版即因此算错,checksum 立刻变化 ⇒ 该 checksum 是有效哨兵)。
//     机理同 [1]:`BASE^2*8 = 2 097 152 B ≡ 0 (mod 65536/524288)` ⇒ 三个乘积平面原本
//     全部落在同一个 L2 组 / L3 组;`+8` 只把它们错开 1 条 line,`+960` 错开到
//     120/240 条 line。n=2048 上逐值扫描:320 → −0.209%、512 → −0.029%、
//     960 → −0.240%(最好)、1024 → −0.027%、1536 → −0.132%、2048 → −0.161%、
//     2560 → −0.146%(同一探针,重复性 0.001%)。
// ======================
// ===== 思路 =====
// **本文件 = 本代理 mdA 的"h=1024 层延迟 combine"(提交 #100991 = 1930.013594 ms,我方当时最好)
//   + 本轮的单一变量:把 `pending`(对手 #100704 的延迟 combine 机制)的 `STEP` 8 → 32。**
//   (其下的引擎 = mdB_ 分支的 `mdB_sub_lp960.cpp` = 提交 #100962,含对手 #100932 的逐字节复刻
//    与两组"数据组映射"pad:`UPPER_PAGE_PAD` 7680 / `LEAF_PAD` 960。)
//
// 【为什么加大 STEP 会变快(机理,两个数都是判题机实测)】
//   * 延迟 combine 的每一步要读 7 个流(C 四象限 + m 三平面);这些行即使被 `pending_prefetch`
//     提前一次调用(≈3000 cycle)拉进 L2,**每步仍有 ~100 cycle 的固定延迟暴露**(本代理在
//     "把 pre 搬进 kernel" 的实验里量过同型数:l1 常驻 0.52 cycle/武装步 vs DRAM 流 8.8)。
//   * 因此**加大 STEP(每调用多推几列)能摊薄这个固定代价**:同样的总 uop 数,往返次数更少。
//   * 判题机 in-situ(n=2048,匹配单引擎探针,warm-up + 2 次计时取 min;同二进制重复性 ~0.005%):
//     基座(本文件去掉 STEP 改动,MIN=957,774,906)/ **STEP=16: 956,350,986(−0.149%)** /
//     **STEP=32: 955,417,836(−0.247%)** / STEP=64: 956,364,804(−0.147%)/ STEP=128: 958,685,698(+0.095%)
//     ⇒ 最优点在 32 附近(16~64 是平台),故取 32。
//   * 容量:h=512 的 combine 需 `512²/STEP` 步(STEP=32 ⇒ 8192 步),而其窗口 = 下一个 rec(1024)
//     节点的全部叶调用(38304 次)⇒ 利用率 21%,远不会落到串行补齐;且 `BASE²=2^18` 被任何 2 的幂
//     STEP 整除、STEP 也整除行宽 512 ⇒ **行列分解与边界条件完全不变**。
//   * 正确性:`mdA_gc32/mdA_g64` 逐位闸门(本文件 vs 上一发 `#100991` 的源码,两 namespace 同进程)
//     n=2048 全部 `maxdiff=0.000e+00` ✓(算式、操作数顺序、缓冲布局一字未动,只改每次调用推进几列)。
// ================
/*
Credit: inherited algorithm and microkernel sources are listed below.
New layout: add a 4 KiB gap between each of the nine upper Winograd
workspace planes; keep matrix row strides and all arithmetic unchanged.
This layout was motivated by address-conflict experiments in our separate
implementation of Dumas et al.'s rank-48 algorithm (arXiv:2609.12027).
*/
/*
Credit: saffah_cc_v41_agg1, https://duck.ac/submission/100776,
for specializing the final two rows instead of computing six padded rows.
This version starts from that submission; all earlier engine credits follow.

New scheduling and kernel:
- Merge the final two rows into the preceding 30-row block.
- Process the resulting 32-row block in pairs of B panels: ten 6x8
  kernels followed by one 2x16 kernel while both panels remain in L2.
- The 2x16 tail uses eight independent accumulators, retaining the
  original per-element double-precision FMA order along K.
*/
/*
Credits: inherited engine credits are retained immediately below.
New scheduling: defer a completed last-level Strassen combination and
prefetch/combine small pieces between the following sibling's kernels.
A second three-product buffer prevents overwriting pending operands.
*/
/*
Credits:
- saffah_cc_v41_agg1, https://duck.ac/submission/100511 and
  https://duck.ac/submission/100475: carry next A packing inside the FMA
  loop, double-buffer A, and pack B in groups of eight K rows. This code
  starts from #100511, itself based on pdoom #100193.
- Earlier credits from pdoom #100193 are retained below.
Changes in this version:
- Specialize copy/add/subtract A carry at compile time; move one 32-byte
  vector per eight K steps, without a gating branch or sign mask.
- Carry two half-row chunks per next A row, during the final kernel calls
  of the current block. Use MC=30 to limit cache pressure.
- Give calls without packing their own plain four-step kernel, avoiding
  unused packing pointer operands and their register constraints.
*/
/*
Credits:
- saffah_cc_v41_260924, https://duck.ac/submission/99846:
  fused leaf operand sums/packing, one-pass operand-sum generation, and
  one-pass four-quadrant Strassen combine.
- saffah_cc_v41_agg1, https://duck.ac/submission/99875 and
  https://duck.ac/submission/99950: non-temporal intermediate/output stores.
- saffah_cc_v41_260924, https://duck.ac/submission/99141, and
  saffah_cc_v41_agg1, https://duck.ac/submission/99167:
  double-precision 6x8 blocking, B-panel prefetch, explicit 256-bit memory instructions, and
  row-contiguous A packing and row-first B packing were consulted for this problem's baseline.
- pdoom, https://duck.ac/submission/99966: preceding packing/assembly framework.
The double microkernel, output-backed temporary placement, and hybrid
Strassen/Winograd recursion below were implemented here.
New scheduling: precompute all Winograd operand sums in one traversal.
The third sum of each operand temporarily occupies an output quadrant;
M7 is evaluated first to free those quadrants before the other products.
No quantization is used: arithmetic remains binary64.
*/
#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)*(BASE+24)],ap2[(MC+MR)*(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"
        "vbroadcastsd %c[o0]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 512(%[b])\n\t"
        "vbroadcastsd %c[o2]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 64(%[b]), %%ymm12\n\t"
        "vmovapd 96(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 576(%[b])\n\t"
        "vbroadcastsd %c[o2]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 128(%[b]), %%ymm12\n\t"
        "vmovapd 160(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 640(%[b])\n\t"
        "vbroadcastsd %c[o2]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 192(%[b]), %%ymm12\n\t"
        "vmovapd 224(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 704(%[b])\n\t"
        "vbroadcastsd %c[o2]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 256(%[b]), %%ymm12\n\t"
        "vmovapd 288(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 768(%[b])\n\t"
        "vbroadcastsd %c[o2]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 320(%[b]), %%ymm12\n\t"
        "vmovapd 352(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 832(%[b])\n\t"
        "vbroadcastsd %c[o2]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 384(%[b]), %%ymm12\n\t"
        "vmovapd 416(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 896(%[b])\n\t"
        "vbroadcastsd %c[o2]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 448(%[b]), %%ymm12\n\t"
        "vmovapd 480(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 960(%[b])\n\t"
        "vbroadcastsd %c[o2]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%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"
        "vmovupd %%ymm15, 0(%[pkd])\n\t"
        "add $32, %[pks]\n\t"
        "add $32, %[pky]\n\t"
        "add $32, %[pkd]\n\t"
        "add $64, %[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"
        "vbroadcastsd %c[o0]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vbroadcastsd %c[o2]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 64(%[b]), %%ymm12\n\t"
        "vmovapd 96(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vbroadcastsd %c[o2]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 128(%[b]), %%ymm12\n\t"
        "vmovapd 160(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vbroadcastsd %c[o2]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 192(%[b]), %%ymm12\n\t"
        "vmovapd 224(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vbroadcastsd %c[o2]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "add $32, %[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*(BASE+24)*8), [o1] "i"(1*(BASE+24)*8), [o2] "i"(2*(BASE+24)*8), [o3] "i"(3*(BASE+24)*8), [o4] "i"(4*(BASE+24)*8), [o5] "i"(5*(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"
        "vbroadcastsd %c[o0]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 512(%[b])\n\t"
        "vbroadcastsd %c[o2]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 64(%[b]), %%ymm12\n\t"
        "vmovapd 96(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 576(%[b])\n\t"
        "vbroadcastsd %c[o2]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 128(%[b]), %%ymm12\n\t"
        "vmovapd 160(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 640(%[b])\n\t"
        "vbroadcastsd %c[o2]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 192(%[b]), %%ymm12\n\t"
        "vmovapd 224(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 704(%[b])\n\t"
        "vbroadcastsd %c[o2]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 256(%[b]), %%ymm12\n\t"
        "vmovapd 288(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 768(%[b])\n\t"
        "vbroadcastsd %c[o2]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+32(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 320(%[b]), %%ymm12\n\t"
        "vmovapd 352(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 832(%[b])\n\t"
        "vbroadcastsd %c[o2]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+40(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 384(%[b]), %%ymm12\n\t"
        "vmovapd 416(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 896(%[b])\n\t"
        "vbroadcastsd %c[o2]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+48(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "vmovapd 448(%[b]), %%ymm12\n\t"
        "vmovapd 480(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "prefetcht0 960(%[b])\n\t"
        "vbroadcastsd %c[o2]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm4\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm5\n\t"
        "vbroadcastsd %c[o3]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm6\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm7\n\t"
        "vbroadcastsd %c[o4]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm8\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm9\n\t"
        "vbroadcastsd %c[o5]+56(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm10\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm11\n\t"
        "add $64, %[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*(BASE+24)*8), [o1] "i"(1*(BASE+24)*8), [o2] "i"(2*(BASE+24)*8), [o3] "i"(3*(BASE+24)*8), [o4] "i"(4*(BASE+24)*8), [o5] "i"(5*(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; };
static Pend2 pend2={0,0,0,0,0,0,false};
static constexpr int STEP2=16;
static inline void pend2_prefetch(void){
 if(!pend2.active)return;
 int i=pend2.pos/pend2.h, j=pend2.pos%pend2.h;
 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){
 int i=pend2.pos/pend2.h, j=pend2.pos%pend2.h;
 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;
 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"
        "vbroadcastsd %c[o0]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+0(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vmovapd 64(%[b]), %%ymm12\n\t"
        "vmovapd 96(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+8(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vmovapd 128(%[b]), %%ymm12\n\t"
        "vmovapd 160(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+16(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "vmovapd 192(%[b]), %%ymm12\n\t"
        "vmovapd 224(%[b]), %%ymm13\n\t"
        "vbroadcastsd %c[o0]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm0\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm1\n\t"
        "vbroadcastsd %c[o1]+24(%[a]), %%ymm14\n\t"
        "vfmadd231pd %%ymm12, %%ymm14, %%ymm2\n\t"
        "vfmadd231pd %%ymm13, %%ymm14, %%ymm3\n\t"
        "add $32, %[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*(BASE+24)*8), [o1] "i"(1*(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"
        "vbroadcastsd %c[o0]+0(%[a]), %%ymm12\n\t"
        "vbroadcastsd %c[o1]+0(%[a]), %%ymm13\n\t"
        "vmovapd 0(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm0\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm4\n\t"
        "vmovapd 32(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm1\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm5\n\t"
        "vmovapd 0(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm2\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm6\n\t"
        "vmovapd 32(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm3\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm7\n\t"
        "prefetcht0 576(%[b])\n\t"
        "prefetcht0 576(%[b1])\n\t"
        "vbroadcastsd %c[o0]+8(%[a]), %%ymm12\n\t"
        "vbroadcastsd %c[o1]+8(%[a]), %%ymm13\n\t"
        "vmovapd 64(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm0\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm4\n\t"
        "vmovapd 96(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm1\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm5\n\t"
        "vmovapd 64(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm2\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm6\n\t"
        "vmovapd 96(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm3\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm7\n\t"
        "prefetcht0 640(%[b])\n\t"
        "prefetcht0 640(%[b1])\n\t"
        "vbroadcastsd %c[o0]+16(%[a]), %%ymm12\n\t"
        "vbroadcastsd %c[o1]+16(%[a]), %%ymm13\n\t"
        "vmovapd 128(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm0\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm4\n\t"
        "vmovapd 160(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm1\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm5\n\t"
        "vmovapd 128(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm2\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm6\n\t"
        "vmovapd 160(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm3\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm7\n\t"
        "prefetcht0 704(%[b])\n\t"
        "prefetcht0 704(%[b1])\n\t"
        "vbroadcastsd %c[o0]+24(%[a]), %%ymm12\n\t"
        "vbroadcastsd %c[o1]+24(%[a]), %%ymm13\n\t"
        "vmovapd 192(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm0\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm4\n\t"
        "vmovapd 224(%[b]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm1\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm5\n\t"
        "vmovapd 192(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm2\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm6\n\t"
        "vmovapd 224(%[b1]), %%ymm14\n\t"
        "vfmadd231pd %%ymm14, %%ymm12, %%ymm3\n\t"
        "vfmadd231pd %%ymm14, %%ymm13, %%ymm7\n\t"
        "add $32, %[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"((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)
                _mm256_store_pd(pkb[0]+(size_t)(r+i)*(BASE+24)+k,ld(a,r+i,k));
            for(int i=rows;i<MR;i++)for(int k=0;k<n;k+=4)
                _mm256_store_pd(pkb[0]+(size_t)(r+i)*(BASE+24)+k,_mm256_setzero_pd());
        }
    }
    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*(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*(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*(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*(BASE+24)+(size_t)off;
                pkc=8;
                ck++;
            }
            if(!pkc) kernel_plain(n,pkb[cur]+(size_t)r*(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*(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*(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*(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)
                    _mm256_store_pd(pkb[cur^1]+(size_t)row*(BASE+24)+k, ld(a,ic2+row,k));
            } else {
                for(int k=off;k<off+qd;k+=4)
                    _mm256_store_pd(pkb[cur^1]+(size_t)row*(BASE+24)+k, _mm256_setzero_pd());
            }
        }
        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};                 /* 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();
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #1269.998 ms118 MB + 336 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-10-16 04:35:47 | Loaded in 1 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠