// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6a_agg3,提交 #122210 <https://duck.ac/submission/122210>
// 用途:本文件引擎正文的最上游祖先(经 #124001 / #124045 / #124075 / #124135 / #124195 逐字节传递)。
// [2] duck.ac 用户 saffah_cc_v41_agg1(本账号),提交 #117203 <https://duck.ac/submission/117203>
// 用途:#122210 正文自述的上游("original engine")。
// [3] duck.ac 用户 saffah_codex_6a_agg3,提交 #120448 / #122147 / #122175 / #122193
// <https://duck.ac/submission/120448> 等:精确内存操作数 / 定长打包器 / 64 级专用驱动器。
// [4] 本账号提交 #124045(参数搜索席 ml4cc_ 的 Apanel 行距 pad=0)· #124075(环内审计席 ml4cd_ 的
// ×2 展开 + 预取去冗余)。
// [5] 本账号提交 #124135(md5 12df2ff9…)与 #124195(md5 **56a5486163e807ece40a1dd2cbd5353b**,
// = 当前在役最快件,板面 5242.338080 ms)= **本发母本**。
// 本发正文 = #124195 的逐字节完整源码,**唯一差异 = 按 §新思路 在 mikro 的 rows==6 汇编块里插入
// `.space N,0x90` 对齐填充的若干处机械插入**;被引用正文一个语义字节未改、未删。
// [6] 本账号提交 #124187 / #124194 / #124196 / #124198 / #124204 / #124206(攻坚席 ml4cj_ 的
// **aoff 机理判决**:#124198/#124194/#124196 是 `packA()` 体首 32/48/8 B 填充的**代码刚性平移**
// 梯,读数为 5243.887 / 5247.552 / 5247.747(对照 #124135 的 5243.362)⇒ 全局 +16 B 平移值
// **−4.385 ms**、+32 B 平移值 **−0.525 ms**。本席的全部设计直接建立在这三行读数上。
// 许可证合规:duck.ac 题面明示「你提交的代码将会被公开,所有人都可见」;逐条标注原作者账号与
// 原提交地址。本席改动全部以 [ml4cm_] 注释标出。
// ===== 历史臂读数(压缩自历次提交的长叙述;原文见 .cache/seat_template.md 律 415/416/421/423/432/433 与各席交付单)=====
// · 布局族:`main` 槽 mod64 0→16 = +10.8 ms(律 415);预测器 rr×m32 留一法 97.5%(律 416);
// 在役格 rr=(50,24,24,48) × m32=0 是 40+ 臂最优格;绝对地址项 ≈0(律 427,判题机 non-PIE)。
// · 足迹族:在役件已执行热码 56.7 KB(L1I 1.77×);压到 20.75/25.25 KB 的三臂读数 +20.23/+14.99/+18.79 ms,
// 差全由 +0.26~0.37% 指令数解释(回归 0.1082 ns/条,散布 0.2%)⇒ 足迹轴关闭(律 432),指令数可本地预测(律 433)。
// · 热四环 = `leaf64<0>/<+1>/<-1>/<+1>.constprop.0` 的 mikro rows==6 主环(380 B/69 条,含 prefetcht0 与 sub $0x2,)。
// · 环体族关闭:环体字节数不增(律 ml4j_),5 次删 uop/挪端口全 ≤0;`ic` 环内剂量位置族关闭(律 423)。
// · 本席(ml4df_)对在役件的指令账改正:callgrind 转储的位置增量是【十进制】;按十六进制解析会整体错位
// (`fp_an.py` 口径),本席改按十进制后总 Ir 与判题同款复现逐位一致(48 192 410 389),已执行 L1I 行 907(≈56.7 KB)。
// ===== 新思路(ml4df_ · 第 20 席)=====
// 【口径改正】ml4de_ 的 callgrind 解析把位置增量当十六进制(转储实为十进制)⇒ 逐地址归属整体错位;
// 本席改按十进制后:总 Ir = 48 192 410 389(与判题同款复现逐位一致)、唯一已执行指令 10 609、
// L1I 行 907(56.7 KB)。据此重算【非 leaf 包装层】= 2 299 485 101 条(4.771%):
// vec-mov 1 267 773 224 · vec-alu 667 443 200 · **LEA 168 725 759 · 标量 ALU/mov 140 888 200 · 分支 51 596 464**
// ⇒ 簿记合计 362 616 828 条(包装层的 15.77%)≈ 39.2 ms 当量(×0.1082 ns/条)。
// 【本发的刀】包装层逐元素算子(wg_add / wg_sub2 / wg_mutate / wg_combine)的内环里,GCC 用「多基址指针
// 各自 LEA 前移」:wg_combine 每 16 元素付 8 条 LEA + 2 add + cmp/jne(共 11 条簿记 / 83 条 = 13.3%)。
// 本发改为【基址寄存器固定 + 单一字节索引】:11 个流各占一个基址寄存器,索引每 16 元素只 `add $128` 一次
// ⇒ 每 16 元素簿记 11 → 3 条(−9.6%),且环体字节 432 → 406(满足"环体字节数不增")。asm 用 GAS
// `.set/.rept` 写一遍展开四份(字符预算),ASCII 单行指令序列与母本逐条对应。
// 值中性:整数 mod 2^64 加减,逐元素次序、操作数次序、访存次序全部与母本相同(隔离件 h∈{16,48,64,128,200,272}
// × wg_add(sg=±1)/wg_sub2/wg_mutate(reverse=0/1)/wg_combine 全逐位相同)。四档 CK 见收工报告。
// 【为什么不是别处】leaf 族 45.9e9 条(95.2%)的主环 69 条/迭代里标量+分支只有 4 条,且该轴已被
// 律 ml4j_(环体字节数不增)与本席上表的历史读数关闭;包装层里 packB_fixed64 的标量占比 11.7%(ml4de_ 已排除)。
// 【头部压缩声明】为满足判题源码长度闸,本席把历次提交累积的长叙述压缩为上面 6 行要点(引用区 [1]-[6]
// 与许可证合规行逐字未动);全部被压缩内容都在 .cache/seat_template.md 与各席交付单中有原文。
/* References:
- saffah_codex_6a_agg3, https://duck.ac/submission/122193: specialized store-only
64 driver, fixed packers and complete inherited engine/reference notices.
Idea: Resolve the A operand sign once per64 leaf and inline its small fixed
packing loop into the corresponding driver. This removes eleven indirect
packing calls per leaf and allows constant full/tail row counts in packing.
Keep one specialized driver per A sign and the existing shared B packers.
Experiment purpose: Eliminate remaining frequent call setup in the improved
bottom-level driver while preserving all panel layouts and products.
*/
/* References:
- saffah_codex_6a_agg3, https://duck.ac/submission/122175: fixed64 packers,
exact memory wrappers and modular64 engine; inherited references retained.
Idea: Specialize the bottom64 product driver to its actual store-only output.
Resolve B packing and the A packing function once per leaf, process ten full
six-row tiles plus the four-row tail, and give the microkernel constant K64,
row counts and output mode. Skip generic NC/KC/MC and dual-output dispatch.
Experiment purpose: Remove repeated generic driver setup and branches while
sharing one microkernel body for all seven bottom Strassen products.
*/
/* References:
- saffah_codex_6a_agg3, https://duck.ac/submission/122147: exact memory operands
and padded-panel modular64 engine; complete inherited references below.
Idea: Specialize packing for the actual64-by64 leaves and one/two signed
operands. Resolve operand count and sign before the loop, use fixed vector
bounds with no scalar remainder, and walk source rows directly. Dispatch
other sizes or more operands to the unchanged general packers.
Experiment purpose: Remove general-size packing setup, repeated branches and
remainder handling from the frequent bottom-level calls without changing
panel layouts, multiplication instructions or arithmetic results.
*/
/* References:
- saffah_codex_6a_agg3, https://duck.ac/submission/120448: complete exact
modular64 engine, inline vector memory operations and inherited references.
- saffah_cc_v41_agg1, https://duck.ac/submission/117203: original engine;
no separate license declaration, full inherited attribution retained.
Idea: Declare the vector store as a write-only memory output and the vector
load as its precise32-byte input. Remove global compiler memory clobbers
from these single-access wrappers while preserving their one-instruction
unaligned vmovdqu implementation. The compiler can schedule independent
panel loads and arithmetic across stores without changing true dependencies.
Experiment purpose: Improve packing and reconstruction instruction scheduling
with exact memory operands instead of treating every access as a full barrier.
*/
/* References:
- saffah_cc_v41_agg1, https://duck.ac/submission/117203: copied the accepted exact modular Strassen implementation, retaining its inherited attributions and license notices.
Idea: Change the private A-panel row stride from 2048 to 2112 bytes and update every assembly row displacement. Consecutive rows then differ by 33 cache lines rather than 32, avoiding repeated L1 set overlap for four/six-row tiles. Purpose: evaluate conflict reduction with identical values and arithmetic.
*/
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_cc_v41_agg1(本账号),提交 #109358 <https://duck.ac/submission/109358>
// (5377.160444 ms,本账号现役最好件)= `work/l4q_sub3_pack81.cpp`(`l4q_` 席的 `[l4q-PACK81]` 刀)。
// 本发正文 = 该件正文(含其全部上游刀)+ **且仅 + 一处纯摆放扰动**(语义逐位不变,见思路)。
// [2] 正文内部保留的完整上游引用链(逐 hunk 继承、未删改):
// #109353 → #107857 → #107212 → ...(详见正文头注)
// 许可证合规:duck.ac 题面明示「你提交的代码将会被公开,所有人都可见」,即站上提交按站点规则公开;
// 本文件逐条标注原作者账号、原提交地址与用途,未改动其正文一个字节。
// ======================
// ===== 思路 =====
// 【ml4h_ 席 · K2 刀:把环内置换搬到「写侧成形」(零额外字节)】
// 前席 ml4g_ 关掉了「σ 列置换轴」,判词是「载体不存在 ⇒ 构造性不可折进任何 store」。本席复核该判词:
// 其证明(ml4g_plan.md §3.2 四组合穷举)只覆盖「**整面板二选一的字节序**(raw/swap)× 单次**对齐**载入」,
// **不覆盖**「写侧按交换形落字节 + 环内对同一块面板做 +4B **错位**载入」。后者正是姊妹题 mmml1k 的 K2 刀
// (agent.md (1127):`#116708` 翻绿、舒适档 +1025.3 µs),其构造恰恰绕开了四组合表:表的每一行都假定
// `vpmuludq` 吃的是**对齐**载入的那一支;K2 让主项吃**同一个 32B 窗口的 +4B 错位载入**。
//
// 数学(本席逐位复核,dword 编号为 256 位寄存器内 0..7,每 64 位 lane = 2 个 dword):
// 存 S=[b_hi,b_lo] ⇒ 32B 窗口 dwords = [b0_hi,b0_lo, b1_hi,b1_lo, ...]
// · 0B 载入 = S 形:lane_i dwords = (b_i_hi, b_i_lo)
// · +4B 载入:dwords = [b0_lo, b1_hi, b1_lo, b2_hi, b2_lo, b3_hi, b3_lo, X]
// ⇒ **偶 dword = (b0_lo, b1_lo, b2_lo, b3_lo)**,与 lane 对齐(dword 0/2/4/6 ↔ lane 0/1/2/3)✓
// A 广播 = [a_lo, a_hi](不动):
// · vpmuludq(A, 错位载入) 取偶 dword ⇒ 每 lane = a_lo·b_lo(满 64 位)= **与原式主项逐位同** ✓
// · vpmulld(A, S 载入) 逐 dword ⇒ lane_i = (a_lo·b_i_hi, a_hi·b_i_lo) = **与原式交叉项逐位同** ✓
// ⇒ 归并式 `y=hi+(hi>>32); res=lo+(y<<32)` 未动 ⇒ 输出逐位相同。
//
// 【本臂相对在档三件负读数的区别(不许当重复件)】
// `#106567`(A 侧双子面板, +5.71%) · `#106591`(B 面板**×2** 存 [raw32|swap32], step 32→64, 预取 1024→2048, +1.16%)
// · `#111453`(2 MiB 偏移处 twin,触犯 l4x 自己的「镜像禁放 2 的幂偏移」律, +0.84%)
// —— 三件**都另写了一份拷贝**(面板加倍 / 多一个 2 MiB 镜像),代价里含**字节数、footprint、预取落点**。
// 本臂**一块面板、字节数不变、stride 不变(32B/轮)、预取距离不变(1024)**;只把 1 条 p5 shuffle uop
// 换成 1 条**同 32B 窗口**的错位载入(uop 数 / 指令数 / 前端地板全不变,纯 p5→p23 迁移)。形态**从未在本题发过**。
//
// 【代价的可信上界(在档两条独立读数)】`noshuf` 消融(删掉那条 shuffle,故意错算)= −2.3%;
// 「环内 +1 条载入 uop」= +0.95%~1.35%(#106567/#106591 反推)⇒ 净 ≈ −1.0%~−1.3% ≈ 54~70 ms > 缺口 40.07 ms。
// ⚠ 两者非同批相加,真实符号只能由真榜面裁决(探针上限 1000 ms ≪ 本题 5374 ms,(1150)/(1189) 律)。
// 【闸门】rig4_gate.sh:n=4096 ck 必须 = 基座 `13093758586119956379`(逐位同);正控 `17758171817276779410`。
// ================
// ===== 思路 =====
// 【本发 = 「mover 配方」纯摆放臂(语义逐位不变)】把 `1008e8` 上刚量出的**位移带**结论搬到本题:
// 那里 14 发逐位不变的摆放臂给出实测带 = [−13.26, +32.53] ms(同码地板仅 0.387 ms),
// 且**代码摆放的好带 −11~−13 ms 可白赚**(最好件 3639.499 → 3626.629)✓
// 本题缺口 = 42.723293 ms(0.795%)⇒ 若摆放能白赚 ≥5 ms 就值得全做 ✓
// 【本臂的唯一扰动】:Apanel `aligned(64)` → `aligned(8192)`(Apanel 对齐扫描:D1=4096 的邻档)
// 【闸门】`work/l4q_drv.cpp` 驱动(n=4096):`CK=3fcc2160d0cb6c34` 必须与基座**逐位相同**;
// 且**每个函数的字节数与基座一致**(= 只动位置/对齐、不动指令)✓
// ★ 本题生产 5377 ms ≫ probe 上限 1000 ms ⇒ 本地/探针**不可定价**,只有正式提交可信(本题既有律)✓
// ================
#include <immintrin.h>
/* Single-instruction 256-bit unaligned access, NO alignment precondition.
g++-9 -O2 with no -march expands the unaligned 256-bit intrinsics into 2-3 uops, one
of them a p5-only vinsertf128/vextractf128; these emit the single instruction the
intrinsic is named for. AT&T order is `vmovdqu src,dst`: the STORE is %0,%1 (ymm
first, memory second). A REVERSED store operand silently emits a LOAD instead --
that is how this was first written and it produced wrong output with no diagnostic.
volatile + "memory" is REQUIRED: a non-volatile asm with only an "m" input is pure
and gets eliminated. */
#define LDQ(p) ({ __m256i v; __asm__("vmovdqu %1,%0" : "=x"(v) : "m"(*(const __m256i *)(p))); v; })
#define STQ(p,v) __asm__ volatile("vmovdqu %1,%0" : "=m"(*(__m256i*)(p)) : "x"(v))
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>
#pragma GCC optimize("O3","unroll-loops")
#pragma GCC push_options
#pragma GCC target("avx2")
typedef long long TE;
#define MR (6) /* [ml4cg_] 同场锚:纯拼写,零语义/零机器码改动 */
#define KC 256
#define MC 6
#define NC 1024
#define UU 1
/* [ml4cw_] 本族 = 只动 leaf64 的 ic 瓦片次序;wg_combine 与在役逐字节相同。 */
/* ===================== [ml4cw_] 访问次序旋钮(本席唯一自变量) =====================
两个 `static volatile` 数组(.data 静态初值)承载次序选择:
ml4cz_ic1wN152p[0] : leaf64 ic 瓦片序 0=正 1=逆 ml4cz_ic1wN152p[1] : 4 行尾瓦片 0=后 1=前
且 volatile 语义下编译器必须逐次取真值 ⇒ 各臂 .text 逐字节相同(唯一差异 = .data 初值)。
★方向**不进循环体**:只用「增量寄存器 + 终止值」表达 ⇒ 与在役的立即数增量同为 1 条
add / 1 条 cmp,内环 uop 数不变(本族零指令代价)。 */
static volatile int ml4cz_ic1wN152p[3] = {0, 1, -1};
/* =================== [ml4cw_] 旋钮结束 =================== */
#define CUTL 256
/* A-panel row stride PADDED by 8 uint64 (64 B). With the natural stride KC*8 = 4096 B
every one of the 6 rows of a micro-tile maps to the SAME L1 set (4096/64 = 64 sets
apart, 64 sets in the cache) -- a textbook conflict. +8 uint64 makes the stride
4160 B = 65 lines, so consecutive rows land in consecutive sets. */
#define KCP (KC + 0) /* [ml4cc_] */
static TE Apanel[(size_t)MC * KCP + 64] __attribute__((aligned(8192))); // [x14f-D4]
static TE Bpanel[(size_t)2 * (NC / 4 + 1) * KC * 8 + 64] __attribute__((aligned(2097152)));
/* op: 0 = store, 1 = add, 2 = sub; c2 may be 0 (single destination) */
static inline void mikro(long cnt, const long long *ap, const long long *bp,
long long *c1, int ldc1, int op1,
long long *c2, int ldc2, int op2, int rows) {
register __m256i v0 asm("ymm0");
register __m256i v1 asm("ymm1");
register __m256i v2 asm("ymm2");
register __m256i v3 asm("ymm3");
register __m256i v4 asm("ymm4");
register __m256i v5 asm("ymm5");
register __m256i v6 asm("ymm6");
register __m256i v7 asm("ymm7");
register __m256i v8 asm("ymm8");
register __m256i v9 asm("ymm9");
register __m256i v10 asm("ymm10");
register __m256i v11 asm("ymm11");
if (rows == 4) {
__asm__ volatile(
"test %[cnt], %[cnt]\n\t"
"jle 2f\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm0\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm2\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm4\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm6\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm7\n\t"
"prefetcht0 256(%[bp])\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"test $1, %[cnt]\n\t"
"jz 3f\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"3:\n\t"
"1:\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"vmovdqu 36(%[bp]), %%ymm13\n\t"
"vbroadcastsd 8(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2056(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4104(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6152(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqu 64(%[bp]), %%ymm12\n\t"
"prefetcht0 256(%[bp])\n\t"
"add $16, %[ap]\n\t"
"add $64, %[bp]\n\t"
"sub $2, %[cnt]\n\t"
"jg 1b\n\t"
"2:\n\t"
""
: [ap] "+r"(ap), [bp] "+r"(bp), [cnt] "+r"(cnt), [v0] "=x"(v0), [v1] "=x"(v1), [v2] "=x"(v2), [v3] "=x"(v3), [v4] "=x"(v4), [v5] "=x"(v5), [v6] "=x"(v6), [v7] "=x"(v7)
:
: "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "cc", "memory");
} else
if (rows == 2) {
__asm__ volatile(
"test %[cnt], %[cnt]\n\t"
"jle 2f\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm0\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm2\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm3\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"1:\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jnz 1b\n\t"
"2:\n\t"
""
: [ap] "+r"(ap), [bp] "+r"(bp), [cnt] "+r"(cnt), [v0] "=x"(v0), [v1] "=x"(v1), [v2] "=x"(v2), [v3] "=x"(v3)
:
: "ymm4", "ymm5", "ymm6", "ymm7",
"ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "cc", "memory");
} else {
__asm__ volatile(
"test %[cnt], %[cnt]\n\t"
"jle 2f\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm0\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm2\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm4\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm6\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm7\n\t"
"vbroadcastsd 8192(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm8\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm9\n\t"
"vbroadcastsd 10240(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm10\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm11\n\t"
"prefetcht0 256(%[bp])\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"test $1, %[cnt]\n\t"
"jz 3f\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vbroadcastsd 8192(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm8, %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm9, %%ymm9\n\t"
"vbroadcastsd 10240(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"3:\n\t"
"1:\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vbroadcastsd 8192(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm8, %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm9, %%ymm9\n\t"
"vbroadcastsd 10240(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"vmovdqu 36(%[bp]), %%ymm13\n\t"
"vbroadcastsd 8(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2056(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4104(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6152(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vbroadcastsd 8200(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm8, %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm9, %%ymm9\n\t"
"vbroadcastsd 10248(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"prefetcht0 256(%[bp])\n\t"
"vmovdqu 64(%[bp]), %%ymm12\n\t"
"add $16, %[ap]\n\t"
"add $64, %[bp]\n\t"
"sub $2, %[cnt]\n\t"
"jg 1b\n\t"
"2:\n\t"
""
: [ap] "+r"(ap), [bp] "+r"(bp), [cnt] "+r"(cnt), [v0] "=x"(v0), [v1] "=x"(v1), [v2] "=x"(v2), [v3] "=x"(v3), [v4] "=x"(v4), [v5] "=x"(v5), [v6] "=x"(v6), [v7] "=x"(v7), [v8] "=x"(v8), [v9] "=x"(v9), [v10] "=x"(v10), [v11] "=x"(v11)
:
: "ymm12", "ymm13", "ymm14", "ymm15", "cc", "memory");
}
if (rows > 0) {
__m256i lo = v0, hi = v1;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)0 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)0 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 1) {
__m256i lo = v2, hi = v3;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)1 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)1 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 2) {
__m256i lo = v4, hi = v5;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)2 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)2 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 3) {
__m256i lo = v6, hi = v7;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)3 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)3 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 4) {
__m256i lo = v8, hi = v9;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)4 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)4 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 5) {
__m256i lo = v10, hi = v11;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)5 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)5 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
}
static __attribute__((always_inline)) inline void mikro_i(long cnt, const long long *ap, const long long *bp,
long long *c1, int ldc1, int op1,
long long *c2, int ldc2, int op2, int rows) {
register __m256i v0 asm("ymm0");
register __m256i v1 asm("ymm1");
register __m256i v2 asm("ymm2");
register __m256i v3 asm("ymm3");
register __m256i v4 asm("ymm4");
register __m256i v5 asm("ymm5");
register __m256i v6 asm("ymm6");
register __m256i v7 asm("ymm7");
register __m256i v8 asm("ymm8");
register __m256i v9 asm("ymm9");
register __m256i v10 asm("ymm10");
register __m256i v11 asm("ymm11");
if (rows == 4) {
__asm__ volatile(
"test %[cnt], %[cnt]\n\t"
"jle 2f\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm0\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm2\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm4\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm6\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm7\n\t"
"prefetcht0 256(%[bp])\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"test $1, %[cnt]\n\t"
"jz 3f\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"3:\n\t"
"1:\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"vmovdqu 36(%[bp]), %%ymm13\n\t"
"vbroadcastsd 8(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2056(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4104(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6152(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqu 64(%[bp]), %%ymm12\n\t"
"prefetcht0 256(%[bp])\n\t"
"add $16, %[ap]\n\t"
"add $64, %[bp]\n\t"
"sub $2, %[cnt]\n\t"
"jg 1b\n\t"
"2:\n\t"
""
: [ap] "+r"(ap), [bp] "+r"(bp), [cnt] "+r"(cnt), [v0] "=x"(v0), [v1] "=x"(v1), [v2] "=x"(v2), [v3] "=x"(v3), [v4] "=x"(v4), [v5] "=x"(v5), [v6] "=x"(v6), [v7] "=x"(v7)
:
: "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "cc", "memory");
} else
if (rows == 2) {
__asm__ volatile(
"test %[cnt], %[cnt]\n\t"
"jle 2f\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm0\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm2\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm3\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"1:\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jnz 1b\n\t"
"2:\n\t"
""
: [ap] "+r"(ap), [bp] "+r"(bp), [cnt] "+r"(cnt), [v0] "=x"(v0), [v1] "=x"(v1), [v2] "=x"(v2), [v3] "=x"(v3)
:
: "ymm4", "ymm5", "ymm6", "ymm7",
"ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "cc", "memory");
} else {
__asm__ volatile(
"test %[cnt], %[cnt]\n\t"
"jle 2f\n\t"
"vmovdqu 0(%[bp]), %%ymm12\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm0\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm2\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm4\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm6\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm7\n\t"
"vbroadcastsd 8192(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm8\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm9\n\t"
"vbroadcastsd 10240(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm10\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm11\n\t"
"prefetcht0 256(%[bp])\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"test $1, %[cnt]\n\t"
"jz 3f\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vbroadcastsd 8192(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm8, %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm9, %%ymm9\n\t"
"vbroadcastsd 10240(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"add $8, %[ap]\n\t"
"add $32, %[bp]\n\t"
"dec %[cnt]\n\t"
"jle 2f\n\t"
"3:\n\t"
"1:\n\t"
"vmovdqu 4(%[bp]), %%ymm13\n\t"
"vbroadcastsd 0(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2048(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4096(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6144(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vbroadcastsd 8192(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm8, %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm9, %%ymm9\n\t"
"vbroadcastsd 10240(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqu 32(%[bp]), %%ymm12\n\t"
"vmovdqu 36(%[bp]), %%ymm13\n\t"
"vbroadcastsd 8(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vbroadcastsd 2056(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vbroadcastsd 4104(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vbroadcastsd 6152(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vbroadcastsd 8200(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm8, %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm9, %%ymm9\n\t"
"vbroadcastsd 10248(%[ap]), %%ymm14\n\t"
"vpmuludq %%ymm14, %%ymm13, %%ymm15\n\t"
"vpmulld %%ymm12, %%ymm14, %%ymm14\n\t"
"vpaddq %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"prefetcht0 256(%[bp])\n\t"
"vmovdqu 64(%[bp]), %%ymm12\n\t"
"add $16, %[ap]\n\t"
"add $64, %[bp]\n\t"
"sub $2, %[cnt]\n\t"
"jg 1b\n\t"
"2:\n\t"
""
: [ap] "+r"(ap), [bp] "+r"(bp), [cnt] "+r"(cnt), [v0] "=x"(v0), [v1] "=x"(v1), [v2] "=x"(v2), [v3] "=x"(v3), [v4] "=x"(v4), [v5] "=x"(v5), [v6] "=x"(v6), [v7] "=x"(v7), [v8] "=x"(v8), [v9] "=x"(v9), [v10] "=x"(v10), [v11] "=x"(v11)
:
: "ymm12", "ymm13", "ymm14", "ymm15", "cc", "memory");
}
if (rows > 0) {
__m256i lo = v0, hi = v1;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)0 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)0 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 1) {
__m256i lo = v2, hi = v3;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)1 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)1 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 2) {
__m256i lo = v4, hi = v5;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)2 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)2 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 3) {
__m256i lo = v6, hi = v7;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)3 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)3 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 4) {
__m256i lo = v8, hi = v9;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)4 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)4 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
if (rows > 5) {
__m256i lo = v10, hi = v11;
__m256i y = _mm256_add_epi32(hi, _mm256_srli_epi64(hi, 32));
__m256i res = _mm256_add_epi64(lo, _mm256_slli_epi64(y, 32));
long long *cp = c1 + (size_t)5 * ldc1;
if (op1 == 0) STQ((__m256i *)cp, res);
else if (op1 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res));
if (c2) { cp = c2 + (size_t)5 * ldc2;
if (op2 == 0) STQ((__m256i *)cp, res);
else if (op2 == 1) STQ((__m256i *)cp, _mm256_add_epi64(LDQ((const __m256i *)cp), res));
else STQ((__m256i *)cp, _mm256_sub_epi64(LDQ((const __m256i *)cp), res)); } }
}
struct Opd { /* value(i,j) = sum_t s[t]*p[(r[t]+i)*ld + c[t]+j] (nt <= 4) */
const long long *p; int ld; int nt; int r[4], c[4], s[4];
};
static inline Opd oq(const Opd *o, int qi, int qj, int h) {
Opd d = *o;
for (int t = 0; t < o->nt; t++) { d.r[t] += qi * h; d.c[t] += qj * h; }
return d;
}
static inline Opd oadd(const Opd *a, const Opd *b, int sgn) {
Opd d = *a;
for (int t = 0; t < b->nt; t++) { d.r[d.nt] = b->r[t]; d.c[d.nt] = b->c[t]; d.s[d.nt] = b->s[t] < 0 ? -sgn : sgn; d.nt++; }
return d;
}
static inline Opd o1(const long long *p, int ld) {
Opd d; d.p = p; d.ld = ld; d.nt = 1; d.r[0] = 0; d.c[0] = 0; d.s[0] = 1; return d;
}
/* A panel: rows [ic, ic+mc), k in [pc, pc+kc) of the operand */
static void packA_general(const Opd *o, int ic, int mc, int pc, int kc) {
const int nt = o->nt;
const long long *P = o->p; const int ld = o->ld;
for (int r = 0; r < MC; r++) {
long long *p = (Apanel + 8) + (size_t)r * KCP; /* [ml4cg_] */
int k = 0;
if (r < mc) {
const long long *s0 = P + (size_t)(o->r[0] + ic + r) * ld + o->c[0] + pc;
if (nt == 1 || nt == 2) {
const long long *s1 = (nt == 2) ? P + (size_t)(o->r[1] + ic + r) * ld + o->c[1] + pc : 0;
int sgn1 = (nt == 2) ? o->s[1] : 1;
for (; k + 4 <= kc; k += 4) {
__m256i v = LDQ((const __m256i *)(s0 + k));
if (nt == 2) {
__m256i w = LDQ((const __m256i *)(s1 + k));
v = (sgn1 > 0) ? _mm256_add_epi64(v, w) : _mm256_sub_epi64(v, w);
}
STQ((__m256i *)p, v);
p += 4;
}
for (; k < kc; k++) { long long v = s0[k];
if (nt == 2) v = (sgn1 > 0) ? v + s1[k] : v - s1[k];
*p++ = (v); }
} else {
for (; k + 4 <= kc; k += 4) {
__m256i v = _mm256_setzero_si256();
for (int t = 0; t < nt; t++) {
__m256i w = LDQ((const __m256i *)(P + (size_t)(o->r[t] + ic + r) * ld + o->c[t] + pc + k));
v = (o->s[t] < 0) ? _mm256_sub_epi64(v, w) : _mm256_add_epi64(v, w);
}
STQ((__m256i *)p, v);
p += 4;
}
for (; k < kc; k++) {
long long v = 0;
for (int t = 0; t < nt; t++)
v += o->s[t] < 0 ? -P[(size_t)(o->r[t] + ic + r) * ld + o->c[t] + pc + k]
: P[(size_t)(o->r[t] + ic + r) * ld + o->c[t] + pc + k];
*p++ = (v);
}
}
}
p += KC - k; /* k >= kc is never read: mikro runs kc steps */
}
}
static void packB_general(const Opd *o, int jc, int nc, int pc, int kc) {
const int nt = o->nt;
const long long *P = o->p; const int ld = o->ld;
const int jbn = (nc + 3) & ~3; /* mikro reads only jg < nc, step 4 */
int jb = 0;
/* ---- 8-column pass: the two 4-column groups jb and jb+4 share ONE 64-byte
source line (the row stride is ld*8 bytes, so a 4-column load uses exactly
half a line). The 4-column loop walks all kc rows before returning to the
neighbouring group, i.e. after kc strided accesses, so that line is long
evicted and gets fetched a second time. Taking both groups in one pass
reads a full line per row per visit: source line fetches are halved.
Panel layout is byte-identical (group jb sits at (jb/4)*KC). ---- */
for (; jb + 16 <= nc; jb += 16) {
long long *q0 = Bpanel + (size_t)(jb / 4) * kc * 4;
long long *q1 = q0 + (size_t)kc * 4;
long long *q2 = q1 + (size_t)kc * 4;
long long *q3 = q2 + (size_t)kc * 4;
if (nt <= 2) {
const long long *s0 = P + (size_t)o->r[0] * ld + o->c[0] + jc + jb;
const long long *s1 = (nt == 2) ? P + (size_t)o->r[1] * ld + o->c[1] + jc + jb : 0;
const int sg1 = (nt == 2) ? o->s[1] : 1;
for (int k = 0; k < kc; k++) {
const long long *r0 = s0 + (size_t)(pc + k) * ld;
__m256i v0 = LDQ((const __m256i *)(r0));
__m256i v1 = LDQ((const __m256i *)(r0 + 4));
__m256i v2 = LDQ((const __m256i *)(r0 + 8));
__m256i v3 = LDQ((const __m256i *)(r0 + 12));
if (nt == 2) {
const long long *r1 = s1 + (size_t)(pc + k) * ld;
__m256i w0 = LDQ((const __m256i *)(r1));
__m256i w1 = LDQ((const __m256i *)(r1 + 4));
__m256i w2 = LDQ((const __m256i *)(r1 + 8));
__m256i w3 = LDQ((const __m256i *)(r1 + 12));
if (sg1 > 0) { v0 = _mm256_add_epi64(v0, w0); v1 = _mm256_add_epi64(v1, w1);
v2 = _mm256_add_epi64(v2, w2); v3 = _mm256_add_epi64(v3, w3); }
else { v0 = _mm256_sub_epi64(v0, w0); v1 = _mm256_sub_epi64(v1, w1);
v2 = _mm256_sub_epi64(v2, w2); v3 = _mm256_sub_epi64(v3, w3); }
}
_mm256_store_si256((__m256i *)(q0 + (size_t)k * 4), _mm256_shuffle_epi32(v0, 0xB1));
_mm256_store_si256((__m256i *)(q1 + (size_t)k * 4), _mm256_shuffle_epi32(v1, 0xB1));
_mm256_store_si256((__m256i *)(q2 + (size_t)k * 4), _mm256_shuffle_epi32(v2, 0xB1));
_mm256_store_si256((__m256i *)(q3 + (size_t)k * 4), _mm256_shuffle_epi32(v3, 0xB1));
}
} else {
for (int k = 0; k < kc; k++) {
__m256i v0 = _mm256_setzero_si256(), v1 = _mm256_setzero_si256();
__m256i v2 = _mm256_setzero_si256(), v3 = _mm256_setzero_si256();
for (int tt = 0; tt < nt; tt++) {
const long long *r0 = P + (size_t)(o->r[tt] + pc + k) * ld + o->c[tt] + jc + jb;
__m256i w0 = LDQ((const __m256i *)r0);
__m256i w1 = LDQ((const __m256i *)(r0 + 4));
__m256i w2 = LDQ((const __m256i *)(r0 + 8));
__m256i w3 = LDQ((const __m256i *)(r0 + 12));
if (o->s[tt] < 0) { v0 = _mm256_sub_epi64(v0, w0); v1 = _mm256_sub_epi64(v1, w1);
v2 = _mm256_sub_epi64(v2, w2); v3 = _mm256_sub_epi64(v3, w3); }
else { v0 = _mm256_add_epi64(v0, w0); v1 = _mm256_add_epi64(v1, w1);
v2 = _mm256_add_epi64(v2, w2); v3 = _mm256_add_epi64(v3, w3); }
}
_mm256_store_si256((__m256i *)(q0 + (size_t)k * 4), _mm256_shuffle_epi32(v0, 0xB1));
_mm256_store_si256((__m256i *)(q1 + (size_t)k * 4), _mm256_shuffle_epi32(v1, 0xB1));
_mm256_store_si256((__m256i *)(q2 + (size_t)k * 4), _mm256_shuffle_epi32(v2, 0xB1));
_mm256_store_si256((__m256i *)(q3 + (size_t)k * 4), _mm256_shuffle_epi32(v3, 0xB1));
}
}
}
for (; jb < jbn; jb += 4) {
long long *q = Bpanel + (size_t)(jb / 4) * kc * 4;
int full = (jb + 4 <= nc);
int lim = nc - jb; if (lim > 4) lim = 4; if (lim < 0) lim = 0;
const long long *sq = P + (size_t)o->r[0] * ld + o->c[0] + jc + jb;
const long long *sq1 = (nt >= 2) ? P + (size_t)o->r[1] * ld + o->c[1] + jc + jb : 0;
if (full && nt <= 2) {
for (int k = 0; k < kc; k++) {
__m256i v = LDQ((const __m256i *)(sq + (size_t)(pc + k) * ld));
if (nt == 2) {
__m256i w = LDQ((const __m256i *)(sq1 + (size_t)(pc + k) * ld));
v = (o->s[1] > 0) ? _mm256_add_epi64(v, w) : _mm256_sub_epi64(v, w);
}
_mm256_store_si256((__m256i *)(q + (size_t)k * 4), _mm256_shuffle_epi32(v, 0xB1));
}
} else if (full) {
for (int k = 0; k < kc; k++) {
__m256i v = _mm256_setzero_si256();
for (int tt = 0; tt < nt; tt++) {
__m256i w = LDQ((const __m256i *)(P + (size_t)(o->r[tt] + pc + k) * ld + o->c[tt] + jc + jb));
v = (o->s[tt] < 0) ? _mm256_sub_epi64(v, w) : _mm256_add_epi64(v, w);
}
_mm256_store_si256((__m256i *)(q + (size_t)k * 4), _mm256_shuffle_epi32(v, 0xB1));
}
} else {
for (int k = 0; k < KC; k++) {
long long t[4] = {0, 0, 0, 0};
if (k < kc) {
int ncol = full ? 4 : lim;
for (int c = 0; c < ncol; c++) {
long long v = 0;
for (int tt = 0; tt < nt; tt++)
v += o->s[tt] < 0 ? -P[(size_t)(o->r[tt] + pc + k) * ld + o->c[tt] + jc + jb + c]
: P[(size_t)(o->r[tt] + pc + k) * ld + o->c[tt] + jc + jb + c];
t[c] = v;
}
}
__m256i v = LDQ((const __m256i *)t);
_mm256_store_si256((__m256i *)(q + (size_t)k * 4), _mm256_shuffle_epi32(v, 0xB1));
}
}
}
}
template<int Sign>
static __attribute__((always_inline)) inline void packA_fixed64(const long long*s0,const long long*s1,int ld,int mc){
long long*d=(Apanel + 8); /* [ml4cg_] */
for(int r=0;r<mc;r++){
#pragma GCC unroll 4
for(int k=0;k<64;k+=4){
__m256i v=LDQ((const __m256i*)(s0+k));
if constexpr(Sign) { __m256i w=LDQ((const __m256i*)(s1+k));v=Sign>0?_mm256_add_epi64(v,w):_mm256_sub_epi64(v,w); }
STQ((__m256i*)(d+k),v);
}
s0+=ld;if constexpr(Sign)s1+=ld;d+=KCP;
}
}
static void packA(const Opd*o,int ic,int mc,int pc,int kc){
if(kc==64 && pc==0 && o->nt<=2){
const long long*s0=o->p+(size_t)(o->r[0]+ic)*o->ld+o->c[0];
if(o->nt==1)packA_fixed64<0>(s0,nullptr,o->ld,mc);
else {const long long*s1=o->p+(size_t)(o->r[1]+ic)*o->ld+o->c[1];
if(o->s[1]>0)packA_fixed64<1>(s0,s1,o->ld,mc);else packA_fixed64<-1>(s0,s1,o->ld,mc);}
return;
}
packA_general(o,ic,mc,pc,kc);
}
/* [ml4cy_] 本函数 = 在役 `packB_fixed64` 正文的**直接式(无旋钮)改写**,唯一改动 = 内层 k 环
×1 -> ×2 且**四个相距 2048 B 的写流由「32 B 交错」改成「按象限 64 B 连续突发」**
(q0+0,q0+4 -> q1+0,q1+4 -> q2 -> q3)。值、地址、算式一字不改,只有**写入次序**不同。
注:第一发以运行期旋钮形态量到本改动 **−5.39 ms**(pd1 5236.916 vs pd0 5242.305,相邻 47 s);
本件去掉旋钮与二选一分支 ⇒ 去掉族固有代价 +8.2 ms 后,真效应应留下。 */
template<int Sign>
static __attribute__((noinline)) void packB_fixed64(const long long*s0,const long long*s1,int ld){
for(int jb=0;jb<64;jb+=16){
long long*q0=Bpanel+(jb/4)*64*4,*q1=q0+256,*q2=q1+256,*q3=q2+256;
const long long*r0=s0+jb,*r1=s1;
if constexpr(Sign)r1+=jb;
#pragma GCC unroll 1
for(int k=0;k<64;k+=2){
__m256i t0,t1,t2,t3,t4,t5,t6,t7;
{
__m256i v0=LDQ((const __m256i*)r0),v1=LDQ((const __m256i*)(r0+4)),v2=LDQ((const __m256i*)(r0+8)),v3=LDQ((const __m256i*)(r0+12));
if constexpr(Sign){
__m256i w0=LDQ((const __m256i*)r1),w1=LDQ((const __m256i*)(r1+4)),w2=LDQ((const __m256i*)(r1+8)),w3=LDQ((const __m256i*)(r1+12));
if constexpr(Sign>0){v0=_mm256_add_epi64(v0,w0);v1=_mm256_add_epi64(v1,w1);v2=_mm256_add_epi64(v2,w2);v3=_mm256_add_epi64(v3,w3);}
else {v0=_mm256_sub_epi64(v0,w0);v1=_mm256_sub_epi64(v1,w1);v2=_mm256_sub_epi64(v2,w2);v3=_mm256_sub_epi64(v3,w3);}
}
t0=_mm256_shuffle_epi32(v0,0xB1);t1=_mm256_shuffle_epi32(v1,0xB1);
t2=_mm256_shuffle_epi32(v2,0xB1);t3=_mm256_shuffle_epi32(v3,0xB1);
}
{
const long long*r2=r0+ld,*r3=r1; if constexpr(Sign) r3+=ld;
__m256i v0=LDQ((const __m256i*)r2),v1=LDQ((const __m256i*)(r2+4)),v2=LDQ((const __m256i*)(r2+8)),v3=LDQ((const __m256i*)(r2+12));
if constexpr(Sign){
__m256i w0=LDQ((const __m256i*)r3),w1=LDQ((const __m256i*)(r3+4)),w2=LDQ((const __m256i*)(r3+8)),w3=LDQ((const __m256i*)(r3+12));
if constexpr(Sign>0){v0=_mm256_add_epi64(v0,w0);v1=_mm256_add_epi64(v1,w1);v2=_mm256_add_epi64(v2,w2);v3=_mm256_add_epi64(v3,w3);}
else {v0=_mm256_sub_epi64(v0,w0);v1=_mm256_sub_epi64(v1,w1);v2=_mm256_sub_epi64(v2,w2);v3=_mm256_sub_epi64(v3,w3);}
}
t4=_mm256_shuffle_epi32(v0,0xB1);t5=_mm256_shuffle_epi32(v1,0xB1);
t6=_mm256_shuffle_epi32(v2,0xB1);t7=_mm256_shuffle_epi32(v3,0xB1);
}
_mm256_store_si256((__m256i*)q0,t0);_mm256_store_si256((__m256i*)(q0+4),t4);
_mm256_store_si256((__m256i*)q1,t1);_mm256_store_si256((__m256i*)(q1+4),t5);
_mm256_store_si256((__m256i*)q2,t2);_mm256_store_si256((__m256i*)(q2+4),t6);
_mm256_store_si256((__m256i*)q3,t3);_mm256_store_si256((__m256i*)(q3+4),t7);
q0+=8;q1+=8;q2+=8;q3+=8;r0+=(size_t)2*ld;if constexpr(Sign)r1+=(size_t)2*ld;
}
}
}
static void packB(const Opd*o,int jc,int nc,int pc,int kc){
if(kc==64 && nc==64 && pc==0 && o->nt<=2){
const long long*s0=o->p+(size_t)o->r[0]*o->ld+o->c[0]+jc;
if(o->nt==1)packB_fixed64<0>(s0,nullptr,o->ld);
else {const long long*s1=o->p+(size_t)o->r[1]*o->ld+o->c[1]+jc;
if(o->s[1]>0)packB_fixed64<1>(s0,s1,o->ld);else packB_fixed64<-1>(s0,s1,o->ld);}
return;
}
packB_general(o,jc,nc,pc,kc);
}
static inline int effop(int base, int term) { /* term: 1 = +M, 2 = -M ; result: 0 store 1 add 2 sub */
if (base == 0) return term == 1 ? 0 : 2;
if (base == 1) return term == 2 ? 2 : 1;
return term == 2 ? 1 : 2;
}
/* C1 op1 (+- second destination C2 op2, either may be absent) = Ao * Bo, block size n */
static __attribute__((always_inline)) inline void leaf(int n, const Opd *Ao, const Opd *Bo,
long long *C1, int ldc1, int op1, long long *C2, int ldc2, int op2) {
int nb4 = n - (n & 3);
for (int jc = 0; jc < nb4; jc += NC) {
int nc = (nb4 - jc < NC) ? (nb4 - jc) : NC;
for (int pc = 0; pc < n; pc += KC) {
int kc = (n - pc < KC) ? (n - pc) : KC;
packB(Bo, jc, nc, pc, kc);
int e1 = (pc == 0) ? op1 : (op1 == 2 ? 2 : 1);
int e2 = (pc == 0) ? op2 : (op2 == 2 ? 2 : 1);
for (int ic = 0; ic < n; ic += MC) {
int mc = (n - ic < MC) ? (n - ic) : MC;
packA(Ao, ic, mc, pc, kc);
for (int ir = 0; ir < mc; ir += MR) {
int rows = (mc - ir < MR) ? (mc - ir) : MR;
const long long *ap = (Apanel + 8) + (size_t)ir * KCP * 1; /* [ml4cg_] */
for (int jg = 0; jg < nc; jg += 4) {
const long long *bp = Bpanel + (size_t)(jg / 4) * kc * 4;
mikro(kc / UU, ap, bp, C1 + (size_t)(ic + ir) * ldc1 + jc + jg, ldc1, e1,
C2 ? C2 + (size_t)(ic + ir) * ldc2 + jc + jg : 0, ldc2, e2, rows);
}
}
}
}
}
for (int j = nb4; j < n; j++)
for (int i = 0; i < n; i++) {
unsigned long long acc = 0;
for (int k = 0; k < n; k++) {
long long av = 0, bv = 0;
for (int t = 0; t < Ao->nt; t++)
av += Ao->s[t] < 0 ? -Ao->p[(size_t)(Ao->r[t] + i) * Ao->ld + Ao->c[t] + k]
: Ao->p[(size_t)(Ao->r[t] + i) * Ao->ld + Ao->c[t] + k];
for (int t = 0; t < Bo->nt; t++)
bv += Bo->s[t] < 0 ? -Bo->p[(size_t)(Bo->r[t] + k) * Bo->ld + Bo->c[t] + j]
: Bo->p[(size_t)(Bo->r[t] + k) * Bo->ld + Bo->c[t] + j];
acc += (unsigned long long)av * (unsigned long long)bv;
}
long long *cp = C1 + (size_t)i * ldc1 + j;
if (op1 == 0) *cp = (long long)acc;
else if (op1 == 1) *cp += (long long)acc;
else *cp -= (long long)acc;
if (C2) {
long long *cq = C2 + (size_t)i * ldc2 + j;
if (op2 == 0) *cq = (long long)acc;
else if (op2 == 1) *cq += (long long)acc;
else *cq -= (long long)acc;
}
}
}
template<int ASign>
static __attribute__((noinline)) void leaf64_by_sign(const Opd*ao,const Opd*bo,long long*c,int ldc){
const long long *a0=ao->p+(size_t)ao->r[0]*ao->ld+ao->c[0];
const long long *a1=ao->nt==2?ao->p+(size_t)ao->r[1]*ao->ld+ao->c[1]:a0;
const long long *b0=bo->p+(size_t)bo->r[0]*bo->ld+bo->c[0];
const long long *b1=bo->nt==2?bo->p+(size_t)bo->r[1]*bo->ld+bo->c[1]:b0;
if(bo->nt==1)packB_fixed64<0>(b0,b1,bo->ld);
else if(bo->s[1]>0)packB_fixed64<1>(b0,b1,bo->ld);else packB_fixed64<-1>(b0,b1,bo->ld);
/* [ml4cw_] 本 11 瓦片循环 = 在役正文逐字节拷贝,**唯一改动 = 瓦片拜访次序由运行期
旋钮给出**(`ic += id` / 尾瓦片前/后)。packA→mikro 的 WAR 依赖链(Apanel)不变 ⇒ 每瓦片
仍是「打包-消费」串行对;改的只是 11 对的**先后**(C 写流序 / A 读流序 / 生产者-消费者
重近性)。11! 只取 4 个有结构理由者(正/逆 × 尾瓦片前/后)。 */
{
const int id = ml4cz_ic1wN152p[0] ? -6 : 6;
const int icend = id > 0 ? 60 : -6;
if (ml4cz_ic1wN152p[1]) {
packA_fixed64<ASign>(a0+(size_t)60*ao->ld,a1+(size_t)60*ao->ld,ao->ld,4);
for(int j=0;j<64;j+=4) mikro_i(64,(Apanel + 8),Bpanel+(size_t)j*64,c+(size_t)60*ldc+j,ldc,0,nullptr,0,0,4);
}
for(int ic = id > 0 ? 0 : 54; ic != icend; ic += id){
packA_fixed64<ASign>(a0+(size_t)ic*ao->ld,a1+(size_t)ic*ao->ld,ao->ld,6);
if(ASign==0) __asm__ volatile(".space 16,0x90"); for(int j=0;j<64;j+=4) mikro_i(64,(Apanel + 8),Bpanel+(size_t)j*64,c+(size_t)ic*ldc+j,ldc,0,nullptr,0,0,6);
}
if (!ml4cz_ic1wN152p[1]) {
packA_fixed64<ASign>(a0+(size_t)60*ao->ld,a1+(size_t)60*ao->ld,ao->ld,4);
for(int j=0;j<64;j+=4) mikro_i(64,(Apanel + 8),Bpanel+(size_t)j*64,c+(size_t)60*ldc+j,ldc,0,nullptr,0,0,4);
}
}
}
static void fixed_leaf64_product(const Opd*ao,const Opd*bo,long long*c,int ldc){
if(ao->nt==1)leaf64_by_sign<0>(ao,bo,c,ldc);
else if(ao->s[1]>0)leaf64_by_sign<1>(ao,bo,c,ldc);
else leaf64_by_sign<-1>(ao,bo,c,ldc);
}
/* recursive Strassen: C1 op1 op= Ao*Bo and C2 op2 op= Ao*Bo */
/* Scratch: one h*h product block per recursion level, carved from the tail of the
buffer. Only the levels that actually recurse consume space, so a walk of the
recursion computes exactly the bytes matrix_multiply() hands us below. */
static long long g_scratch[6u * 1024u * 1024u] __attribute__((aligned(2097152)));
/* dst op= sign * T (op: 0 store, 1 add, 2 sub) */
static void cmb(long long *dst, int ldd, const long long *T, int ldt, int h, int sign, int op) {
__m256i sgn = _mm256_set1_epi64x(sign < 0 ? -1 : 0);
for (int i = 0; i < h; i++) {
const long long *t = T + (size_t)i * ldt;
long long *c = dst + (size_t)i * ldd;
int j = 0;
if (op == 0) {
for (; j + 4 <= h; j += 4) {
__m256i v = LDQ((const __m256i *)(t + j));
if (sign < 0) v = _mm256_sub_epi64(_mm256_setzero_si256(), v);
STQ((__m256i *)(c + j), v);
}
for (; j < h; j++) c[j] = sign < 0 ? -t[j] : t[j];
} else {
for (; j + 4 <= h; j += 4) {
__m256i v = LDQ((const __m256i *)(t + j));
__m256i w = LDQ((const __m256i *)(c + j));
if ((op == 1) != (sign < 0)) STQ((__m256i *)(c + j), _mm256_add_epi64(w, v));
else STQ((__m256i *)(c + j), _mm256_sub_epi64(w, v));
}
for (; j < h; j++) { if ((op == 1) != (sign < 0)) c[j] += t[j]; else c[j] -= t[j]; }
}
}
}
/* Reuse one pair of temporary 1024-square operands across depth-first leaves. */
static long long material_A[1024u * 1024u] __attribute__((aligned(2097152)));
static long long material_B[1024u * 1024u] __attribute__((aligned(2097152)));
/* 512 级物化的目的地:必须与 material_A/B 分开 —— 1024 级钩子的递归仍在读 material_A/B。 */
static long long material_C[512u * 512u] __attribute__((aligned(2097152)));
static long long material_D[512u * 512u] __attribute__((aligned(2097152)));
static void materializeN(const Opd *o, long long *dst, const int n) {
for (int i = 0; i < n; i++) {
long long *out = dst + (size_t)i * n;
int j = 0;
for (; j + 4 <= n; j += 4) {
__m256i value = _mm256_setzero_si256();
for (int t = 0; t < o->nt; t++) {
const long long *src = o->p + (size_t)(o->r[t] + i) * o->ld + o->c[t] + j;
__m256i part = LDQ((const __m256i *)src);
value = o->s[t] < 0 ? _mm256_sub_epi64(value, part) : _mm256_add_epi64(value, part);
}
STQ((__m256i *)(out + j), value);
}
for (; j < n; j++) {
unsigned long long value = 0;
for (int t = 0; t < o->nt; t++) {
unsigned long long part = (unsigned long long)o->p[(size_t)(o->r[t] + i) * o->ld + o->c[t] + j];
value = o->s[t] < 0 ? value - part : value + part;
}
out[j] = (long long)value;
}
}
}
/* single-destination recursive Strassen: d op= Ao*Bo, with T a scratch block of h*h */
static void mmxR(int n, const Opd *Ao, const Opd *Bo, long long *d, int ld, int op,
long long *T) {
if (n == 1024 && (Ao->nt > 1 || Bo->nt > 1)) {
Opd am, bm; const Opd *a = Ao, *b = Bo;
if (Ao->nt > 1) { materializeN(Ao, material_A, 1024); am = o1(material_A, n); a = &am; }
if (Bo->nt > 1) { materializeN(Bo, material_B, 1024); bm = o1(material_B, n); b = &bm; }
mmxR(n, a, b, d, ld, op, T);
return;
}
if (n <= CUTL || (n & 1) || Ao->nt > 2 || Bo->nt > 2) {
leaf(n, Ao, Bo, d, ld, op, 0, 0, 0); return; }
/* n == 512 且本次**本来就会递归**(守卫已过 ⇒ nt <= 2、n > CUTL)时,先把惰性操作数
物化成 512^2 连续矩阵再递归。语义恒等(mod 2^64 下加法可结合),但 h=256 那一层的描述符
nt 从 {2,4} 掉到 {2} ⇒ **每个 256 叶的 pack 源读项数减半**(pack 流量 ≈ −2 MB/叶)。 */
if (n == 512 && (Ao->nt > 1 || Bo->nt > 1)) {
Opd am, bm; const Opd *a = Ao, *b = Bo;
if (Ao->nt > 1) { materializeN(Ao, material_C, 512); am = o1(material_C, 512); a = &am; }
if (Bo->nt > 1) { materializeN(Bo, material_D, 512); bm = o1(material_D, 512); b = &bm; }
mmxR(n, a, b, d, ld, op, T);
return;
}
const int h = n >> 1;
Opd A11 = oq(Ao, 0, 0, h), A12 = oq(Ao, 0, 1, h), A21 = oq(Ao, 1, 0, h), A22 = oq(Ao, 1, 1, h);
Opd B11 = oq(Bo, 0, 0, h), B12 = oq(Bo, 0, 1, h), B21 = oq(Bo, 1, 0, h), B22 = oq(Bo, 1, 1, h);
long long *Q[4];
Q[0] = d; Q[1] = d + h; Q[2] = d + (size_t)h * ld; Q[3] = Q[2] + h;
long long *T2 = T + (size_t)h * h;
int wr[4] = {0, 0, 0, 0};
#define MK(qi, si, qj, sj, Ma, Mb) do { \
int oa = wr[qi] ? effop(1, (si)) : effop(op, (si)); \
int ob = wr[qj] ? effop(1, (sj)) : effop(op, (sj)); \
wr[qi] = 1; wr[qj] = 1; \
if (oa == 0) { \
mmxR(h, &(Ma), &(Mb), Q[qi], ld, 0, T); \
cmb(Q[qj], ld, Q[qi], ld, h, (sj), ob); \
} else { \
mmxR(h, &(Ma), &(Mb), T, h, 0, T2); \
cmb(Q[qi], ld, T, h, h, (si), oa); \
cmb(Q[qj], ld, T, h, h, (sj), ob); \
} \
} while (0) \
#define MK1(qi, si, Ma, Mb) do { \
int oa = wr[qi] ? effop(1, (si)) : effop(op, (si)); \
wr[qi] = 1; \
mmxR(h, &(Ma), &(Mb), Q[qi], ld, oa, T); \
} while (0)
{ /* M1 = (A11+A22)(B11+B22) -> +C11, +C22 */
Opd Ma = oadd(&A11, &A22, 1), Mb = oadd(&B11, &B22, 1);
MK(0, 1, 3, 1, Ma, Mb);
}
{ /* M2 = (A21+A22)B11 -> +C21, -C22 */
Opd Ma = oadd(&A21, &A22, 1), Mb = B11;
MK(2, 1, 3, 2, Ma, Mb);
}
{ /* M3 = A11(B12-B22) -> +C12, +C22 */
Opd Ma = A11, Mb = oadd(&B12, &B22, -1);
MK(1, 1, 3, 1, Ma, Mb);
}
{ /* M4 = A22(B21-B11) -> +C11, +C21 */
Opd Ma = A22, Mb = oadd(&B21, &B11, -1);
MK(0, 1, 2, 1, Ma, Mb);
}
{ /* M5 = (A11+A12)B22 -> -C11, +C12 */
Opd Ma = oadd(&A11, &A12, 1), Mb = B22;
MK(0, 2, 1, 1, Ma, Mb);
}
{ /* M6 = (A21-A11)(B11+B12) -> +C22 */
Opd Ma = oadd(&A21, &A11, -1), Mb = oadd(&B11, &B12, 1);
MK1(3, 1, Ma, Mb);
}
{ /* M7 = (A12-A22)(B21+B22) -> +C11 */
Opd Ma = oadd(&A12, &A22, -1), Mb = oadd(&B21, &B22, 1);
MK1(0, 1, Ma, Mb);
}
#undef MK
#undef MK1
}
static inline __m256i wg_load(const long long *p) { return LDQ((const __m256i *)p); }
static inline void wg_store(long long *p, __m256i v) { STQ((__m256i *)p, v); }
static long long wg_buf[5 * (size_t)(2048 * (2048 + 8)) + 4 * 512] __attribute__((aligned(2097152)));
static void wg_add(int h, long long *dst, const long long *a, int lda,
const long long *b, int ldb, int sg) {
/* [ml4df_] 基址固定 + 单索引内环(每 16 元素 1 条 add),值与母本逐位相同 */
for (int i = 0; i < h; i++) {
long long *d = dst + (size_t)i*h;
const long long *x = a + (size_t)i*lda, *y = b + (size_t)i*ldb;
size_t jb=0; const size_t nb=(size_t)(h/16)*128;
if (sg > 0) {
#pragma GCC unroll 1
for (; jb<nb; jb+=128)
__asm__ __volatile__(".set o,0\n.rept 4\nvmovdqu o(%[x],%[j],1),%%ymm0;vmovdqu o(%[y],%[j],1),%%ymm1;vpaddq %%ymm1,%%ymm0,%%ymm2;vmovdqu %%ymm2,o(%[d],%[j],1)\n.set o,o+32\n.endr\n"
: : [x]"r"(x),[y]"r"(y),[d]"r"(d),[j]"r"(jb) : "ymm0","ymm1","ymm2","memory");
} else {
#pragma GCC unroll 1
for (; jb<nb; jb+=128)
__asm__ __volatile__(".set o,0\n.rept 4\nvmovdqu o(%[x],%[j],1),%%ymm0;vmovdqu o(%[y],%[j],1),%%ymm1;vpsubq %%ymm1,%%ymm0,%%ymm2;vmovdqu %%ymm2,o(%[d],%[j],1)\n.set o,o+32\n.endr\n"
: : [x]"r"(x),[y]"r"(y),[d]"r"(d),[j]"r"(jb) : "ymm0","ymm1","ymm2","memory");
}
for (int j=(int)(jb/8); j<h; j+=4) {
__m256i vx=wg_load(x+j), vy=wg_load(y+j);
wg_store(d+j, sg > 0 ? _mm256_add_epi64(vx,vy) : _mm256_sub_epi64(vx,vy));
}
}
}
/* [SCHAIN] d1 = A21+A22, d2 = A21+A22-A11, d3 = A11-A21, one pass (mod 2^64, exact). */
static void wg_schain3(int h, long long *d1, long long *d2, long long *d3,
const long long *a11, int ld11, const long long *a21, int ld21,
const long long *a22, int ld22) {
for (int i = 0; i < h; i++) {
long long *p1 = d1 + (size_t)i*h, *p2 = d2 + (size_t)i*h, *p3 = d3 + (size_t)i*h;
const long long *x11 = a11 + (size_t)i*ld11, *x21 = a21 + (size_t)i*ld21, *x22 = a22 + (size_t)i*ld22;
for (int j = 0; j < h; j += 4) {
__m256i v11 = wg_load(x11+j), v21 = wg_load(x21+j), v22 = wg_load(x22+j);
__m256i s1 = _mm256_add_epi64(v21, v22);
wg_store(p1+j, s1);
wg_store(p2+j, _mm256_sub_epi64(s1, v11));
wg_store(p3+j, _mm256_sub_epi64(v11, v21));
}
}
}
/* d = a - b (mod 2^64) */
static void wg_sub2(int h, long long *d, const long long *a, int lda, const long long *b, int ldb) {
/* [ml4df_] 同上 */
for (int i = 0; i < h; i++) {
long long *dd = d + (size_t)i*h;
const long long *x = a + (size_t)i*lda, *y = b + (size_t)i*ldb;
size_t jb=0; const size_t nb=(size_t)(h/16)*128;
#pragma GCC unroll 1
for (; jb<nb; jb+=128)
__asm__ __volatile__(".set o,0\n.rept 4\nvmovdqu o(%[x],%[j],1),%%ymm0;vmovdqu o(%[y],%[j],1),%%ymm1;vpsubq %%ymm1,%%ymm0,%%ymm2;vmovdqu %%ymm2,o(%[d],%[j],1)\n.set o,o+32\n.endr\n"
: : [x]"r"(x),[y]"r"(y),[d]"r"(dd),[j]"r"(jb) : "ymm0","ymm1","ymm2","memory");
for (int j=(int)(jb/8); j<h; j+=4)
wg_store(dd+j, _mm256_sub_epi64(wg_load(x+j), wg_load(y+j)));
}
}
static void wg_mutate(int h, long long *dst, const long long *b, int ldb, int reverse) {
/* [ml4df_] 同上 */
for (int i = 0; i < h; i++) {
long long *d = dst + (size_t)i*h; const long long *y=b+(size_t)i*ldb;
size_t jb=0; const size_t nb=(size_t)(h/16)*128;
if (!reverse) {
#pragma GCC unroll 1
for (; jb<nb; jb+=128)
__asm__ __volatile__(".set o,0\n.rept 4\nvmovdqu o(%[d],%[j],1),%%ymm0;vmovdqu o(%[y],%[j],1),%%ymm1;vpsubq %%ymm1,%%ymm0,%%ymm2;vmovdqu %%ymm2,o(%[d],%[j],1)\n.set o,o+32\n.endr\n"
: : [d]"r"(d),[y]"r"(y),[j]"r"(jb) : "ymm0","ymm1","ymm2","memory");
} else {
#pragma GCC unroll 1
for (; jb<nb; jb+=128)
__asm__ __volatile__(".set o,0\n.rept 4\nvmovdqu o(%[d],%[j],1),%%ymm0;vmovdqu o(%[y],%[j],1),%%ymm1;vpsubq %%ymm0,%%ymm1,%%ymm2;vmovdqu %%ymm2,o(%[d],%[j],1)\n.set o,o+32\n.endr\n"
: : [d]"r"(d),[y]"r"(y),[j]"r"(jb) : "ymm0","ymm1","ymm2","memory");
}
for (int j=(int)(jb/8); j<h; j+=4) {
__m256i vd=wg_load(d+j),vy=wg_load(y+j);
wg_store(d+j, reverse ? _mm256_sub_epi64(vy,vd) : _mm256_sub_epi64(vd,vy));
}
}
}
static void wg_combine(int h, long long *C, int ldc, const long long *M1,
const long long *M2, const long long *M3, const long long *M4,
const long long *M5, const long long *M6, const long long *M7) {
/* [ml4df_] 基址固定 + 单索引内环(11 流各一基址,索引每 16 元素 1 条 add),与母本逐位相同 */
const size_t sh=(size_t)h;
for (int i=0; i<h; i++) {
const long long *a=M1+(size_t)i*ldc,*b=M2+(size_t)i*ldc,*c=M3+(size_t)i*ldc;
const long long *d=M4+(size_t)i*ldc,*e=M5+(size_t)i*sh,*f=M6+(size_t)i*sh,*g=M7+(size_t)i*sh;
long long *c11=C+(size_t)i*ldc,*c12=c11+sh,*c21=c11+(size_t)sh*ldc,*c22=c21+sh;
size_t jb=0; const size_t nb=(size_t)(h/16)*128;
#pragma GCC unroll 1
for (; jb<nb; jb+=128)
__asm__ __volatile__(".set o,0\n.rept 4\nvmovdqu o(%[a],%[j],1),%%ymm0;vmovdqu o(%[b],%[j],1),%%ymm1;vmovdqu o(%[c],%[j],1),%%ymm2;vmovdqu o(%[d],%[j],1),%%ymm3;vmovdqu o(%[e],%[j],1),%%ymm4;vmovdqu o(%[f],%[j],1),%%ymm5;vmovdqu o(%[g],%[j],1),%%ymm6;vpaddq %%ymm5,%%ymm0,%%ymm7;vpaddq %%ymm6,%%ymm7,%%ymm8;vpaddq %%ymm4,%%ymm7,%%ymm7;vpaddq %%ymm1,%%ymm0,%%ymm9;vmovdqu %%ymm9,o(%[q1],%[j],1);vpaddq %%ymm2,%%ymm7,%%ymm9;vmovdqu %%ymm9,o(%[q2],%[j],1);vpsubq %%ymm3,%%ymm8,%%ymm9;vmovdqu %%ymm9,o(%[q3],%[j],1);vpaddq %%ymm4,%%ymm8,%%ymm9;vmovdqu %%ymm9,o(%[q4],%[j],1)\n.set o,o+32\n.endr\n"
: : [a]"r"(a),[b]"r"(b),[c]"r"(c),[d]"r"(d),[e]"r"(e),[f]"r"(f),[g]"r"(g),
[q1]"r"(c11),[q2]"r"(c12),[q3]"r"(c21),[q4]"r"(c22),[j]"r"(jb)
: "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","memory");
for (int j=(int)(jb/8); j<h; j+=4) {
__m256i p1=wg_load(a+j),p2=wg_load(b+j),p3=wg_load(c+j),p4=wg_load(d+j);
__m256i p5=wg_load(e+j),p6=wg_load(f+j),p7=wg_load(g+j);
__m256i u2=_mm256_add_epi64(p1,p6),u3=_mm256_add_epi64(u2,p7);
__m256i u4=_mm256_add_epi64(u2,p5);
wg_store(c11+j,_mm256_add_epi64(p1,p2));
wg_store(c12+j,_mm256_add_epi64(u4,p3));
wg_store(c21+j,_mm256_sub_epi64(u3,p4));
wg_store(c22+j,_mm256_add_epi64(u3,p5));
}
}
}
static long long wg_buf_mini[5 * 64 * 64 + 4 * 512] __attribute__((aligned(2097152)));
static void winograd_prod128(int n, const long long *A, int lda, const long long *B,
int ldb, long long *C, int ldc) {
const int h=n/2; const size_t sz=(size_t)h*h; const size_t sg=(size_t)h*(size_t)(h+8); /* [ml4cn_] 面板间距 */
long long *M1=C,*M2=C+h,*M3=C+(size_t)h*ldc,*M4=M3+h;
long long *M5=wg_buf_mini,*M6=M5+sg+512,*M7=M6+sg+512;
Opd A0=o1(A,lda), B0=o1(B,ldb);
Opd A11=oq(&A0,0,0,h), A12=oq(&A0,0,1,h), A21=oq(&A0,1,0,h), A22=oq(&A0,1,1,h);
Opd B11=oq(&B0,0,0,h), B12=oq(&B0,0,1,h), B21=oq(&B0,1,0,h), B22=oq(&B0,1,1,h);
Opd P1=oadd(&A11,&A22,1), Q1=oadd(&B11,&B22,1); /* M1=(A11+A22)(B11+B22) */
Opd P2=oadd(&A21,&A22,1), Q2=B11; /* M2=(A21+A22)B11 */
Opd P3=A11, Q3=oadd(&B12,&B22,-1); /* M3=A11(B12-B22) */
Opd P4=A22, Q4=oadd(&B21,&B11,-1); /* M4=A22(B21-B11) */
Opd P5=oadd(&A11,&A12,1), Q5=B22; /* M5=(A11+A12)B22 */
Opd P6=oadd(&A21,&A11,-1),Q6=oadd(&B11,&B12,1); /* M6=(A21-A11)(B11+B12) */
Opd P7=oadd(&A12,&A22,-1),Q7=oadd(&B21,&B22,1); /* M7=(A12-A22)(B21+B22) */
#define PRODO(AO,BO,Z,LZ) do { Opd a_=(AO),b_=(BO); \
fixed_leaf64_product(&a_,&b_,(Z),(LZ)); } while(0)
PRODO(P6,Q6,M6,h); PRODO(P5,Q5,M5,h); PRODO(P7,Q7,M7,h); PRODO(P2,Q2,M2,ldc); PRODO(P1,Q1,M1,ldc); PRODO(P4,Q4,M4,ldc); PRODO(P3,Q3,M3,ldc);
#undef PRODO
for (int i=0;i<h;i++) {
const long long *m1=M1+(size_t)i*ldc,*m2=M2+(size_t)i*ldc,*m3=M3+(size_t)i*ldc,*m4=M4+(size_t)i*ldc;
const long long *m5=M5+(size_t)i*h,*m6=M6+(size_t)i*h,*m7=M7+(size_t)i*h;
long long *c11=C+(size_t)i*ldc,*c12=c11+h,*c21=c11+(size_t)h*ldc,*c22=c21+h;
for (int j=0;j<h;j+=4) {
__m256i p1=wg_load(m1+j),p2=wg_load(m2+j),p3=wg_load(m3+j),p4=wg_load(m4+j);
__m256i p5=wg_load(m5+j),p6=wg_load(m6+j),p7=wg_load(m7+j);
wg_store(c11+j,_mm256_add_epi64(_mm256_sub_epi64(_mm256_add_epi64(p1,p4),p5),p7));
wg_store(c12+j,_mm256_add_epi64(p3,p5));
wg_store(c21+j,_mm256_add_epi64(p2,p4));
wg_store(c22+j,_mm256_add_epi64(_mm256_add_epi64(_mm256_sub_epi64(p1,p2),p3),p6));
}
}
}
/* ---- materialised 256-square Winograd product level ----------------------------
Each 256-square product is split into seven 128-square ones (M1..M4 in the
destination's own quadrants, M5..M7/P/Q in scratch carved from the head of
g_scratch). The seven 128-square products are plain leaf(128) mikro calls.
g_scratch is dead storage at n=4096: the only other users are mmxR's T argument
(never read on the leaf path, and 128 <= CUTL always takes it) and
matrix_multiply's n != 4096 fallback, which the judge's n=4096 never reaches. */
#define WG256_SZ (128*128)
/* [l4q-PACK-81] Minimal-viable measurement (approved scope = ONLY lda==4096, 81 calls) of the "relayout A" lead.
Rationale (BRIEF 2.19.1176): the shape arm contrasted stride 4096 vs 256 on ALL blocks, but the
live engine already runs 56.24% of winograd_prod256's time at stride 256 (via the existing
materializeN/material_C machinery); only 3.50% is still at 4096. This wrapper densifies A for
EXACTLY those calls: winograd_prod256(n) only ever reads its own 2h x 2h (= n x n) operand block,
so copying that block into a dense n-stride scratch is value-identical (hence BIT-EXACT) and the
four quadrants then form correctly with lda = n. B is deliberately left alone (single variable). */
static void winograd_prod256_inner(int n, const long long *A, int lda, const long long *B,
int ldb, long long *C, int ldc);
static long long l4q_apack[256 * 256] __attribute__((aligned(4096)));
static void winograd_prod256(int n, const long long *A, int lda, const long long *B,
int ldb, long long *C, int ldc) {
if (lda != 4096) { /* [l4q-PACK-81] EXACT approved scope: only the 81 calls with lda==4096 */
winograd_prod256_inner(n, A, lda, B, ldb, C, ldc);
return;
}
for (int i = 0; i < n; i++) {
const long long *src = A + (size_t)i * lda; long long *dst = l4q_apack + (size_t)i * n;
for (int j = 0; j < n; j++) dst[j] = src[j];
}
winograd_prod256_inner(n, l4q_apack, n, B, ldb, C, ldc);
}
static void winograd_prod256_inner(int n, const long long *A, int lda, const long long *B,
int ldb, long long *C, int ldc) {
const int h=n/2; const size_t sz=(size_t)h*h; const size_t sg=(size_t)h*(size_t)(h+8); /* [ml4cn_] 面板间距 */
long long *M1=C,*M2=C+h,*M3=C+(size_t)h*ldc,*M4=M3+h;
long long *M5=g_scratch,*M6=M5+sg+512,*M7=M6+sg+512,*P=M7+sg+512,*Q=P+sg+512;
const long long *A11=A,*A12=A+h,*A21=A+(size_t)h*lda,*A22=A21+h;
const long long *B11=B,*B12=B+h,*B21=B+(size_t)h*ldb,*B22=B21+h;
#define PROD4(X,Y,Z,LX,LY,LZ) do { Opd ao=o1((X),(LX)),bo=o1((Y),(LY)); \
winograd_prod128(h,(X),(LX),(Y),(LY),(Z),(LZ)); } while(0)
PROD4(A11,B11,M1,lda,ldb,ldc);
PROD4(A12,B21,M2,lda,ldb,ldc);
wg_add(h,P,A21,lda,A22,lda,+1);
wg_add(h,Q,B12,ldb,B11,ldb,-1);
PROD4(P,Q,M5,h,h,h);
wg_mutate(h,P,A11,lda,0);
wg_mutate(h,Q,B22,ldb,1);
PROD4(P,Q,M6,h,h,h);
wg_mutate(h,P,A12,lda,1);
PROD4(P,B22,M3,h,ldb,ldc);
wg_mutate(h,Q,B21,ldb,0);
PROD4(A22,Q,M4,lda,h,ldc);
wg_add(h,P,A11,lda,A21,lda,-1);
wg_add(h,Q,B22,ldb,B12,ldb,-1);
PROD4(P,Q,M7,h,h,h);
#undef PROD4
wg_combine(h,C,ldc,M1,M2,M3,M4,M5,M6,M7);
}
static long long wg_buf2[5 * (size_t)(1024 * (1024 + 8)) + 4 * 512] __attribute__((aligned(2097152)));
static long long wg_buf_s2[2 * 2048 * 2048 + 2 * 512] __attribute__((aligned(2097152)));
static long long wg_buf2_s2[2 * (size_t)(1024 * (1024 + 8)) + 1 * 512] __attribute__((aligned(2097152)));
static long long wg_buf1[5 * (size_t)(512 * (512 + 8)) + 4 * 256] __attribute__((aligned(2097152)));
static long long wg_buf0[5 * (size_t)(256 * (256 + 8)) + 4 * 512] __attribute__((aligned(2097152)));
static void winograd_leaf512(int n, const long long *A, int lda, const long long *B, int ldb,
long long *C, int ldc) {
const int h=n/2; const size_t sz=(size_t)h*h; const size_t sg=(size_t)h*(size_t)(h+8); /* [ml4cn_] 面板间距 */
long long *M1=C,*M2=C+h,*M3=C+(size_t)h*ldc,*M4=M3+h;
long long *M5=wg_buf0,*M6=M5+sg+512,*M7=M6+sg+512,*P=M7+sg+512,*Q=P+sg+512;
const long long *A11=A,*A12=A+h,*A21=A+(size_t)h*lda,*A22=A21+h;
const long long *B11=B,*B12=B+h,*B21=B+(size_t)h*ldb,*B22=B21+h;
#define PROD3(X,Y,Z,LX,LY,LZ) do { winograd_prod256(h,(X),(LX),(Y),(LY),(Z),(LZ)); } while(0)
PROD3(A11,B11,M1,lda,ldb,ldc);
PROD3(A12,B21,M2,lda,ldb,ldc);
wg_add(h,P,A21,lda,A22,lda,+1);
wg_add(h,Q,B12,ldb,B11,ldb,-1);
PROD3(P,Q,M5,h,h,h);
wg_mutate(h,P,A11,lda,0);
wg_mutate(h,Q,B22,ldb,1);
PROD3(P,Q,M6,h,h,h);
wg_mutate(h,P,A12,lda,1);
PROD3(P,B22,M3,h,ldb,ldc);
wg_mutate(h,Q,B21,ldb,0);
PROD3(A22,Q,M4,lda,h,ldc);
wg_add(h,P,A11,lda,A21,lda,-1);
wg_add(h,Q,B22,ldb,B12,ldb,-1);
PROD3(P,Q,M7,h,h,h);
#undef PROD3
wg_combine(h,C,ldc,M1,M2,M3,M4,M5,M6,M7);
}
static void winograd_grandchild(int n, const long long *A, int lda, const long long *B, int ldb,
long long *C, int ldc) {
const int h=n/2; const size_t sz=(size_t)h*h; const size_t sg=(size_t)h*(size_t)(h+8); /* [ml4cn_] 面板间距 */
long long *M1=C,*M2=C+h,*M3=C+(size_t)h*ldc,*M4=M3+h;
long long *M5=wg_buf1,*M6=M5+sg+256,*M7=M6+sg+256,*P=M7+sg+256,*Q=P+sg+256;
const long long *A11=A,*A12=A+h,*A21=A+(size_t)h*lda,*A22=A21+h;
const long long *B11=B,*B12=B+h,*B21=B+(size_t)h*ldb,*B22=B21+h;
#define PROD3(X,Y,Z,LX,LY,LZ) do { winograd_leaf512(h,(X),(LX),(Y),(LY),(Z),(LZ)); } while(0)
PROD3(A11,B11,M1,lda,ldb,ldc);
PROD3(A12,B21,M2,lda,ldb,ldc);
wg_add(h,P,A21,lda,A22,lda,+1);
wg_add(h,Q,B12,ldb,B11,ldb,-1);
PROD3(P,Q,M5,h,h,h);
wg_mutate(h,P,A11,lda,0);
wg_mutate(h,Q,B22,ldb,1);
PROD3(P,Q,M6,h,h,h);
wg_mutate(h,P,A12,lda,1);
PROD3(P,B22,M3,h,ldb,ldc);
wg_mutate(h,Q,B21,ldb,0);
PROD3(A22,Q,M4,lda,h,ldc);
wg_add(h,P,A11,lda,A21,lda,-1);
wg_add(h,Q,B22,ldb,B12,ldb,-1);
PROD3(P,Q,M7,h,h,h);
#undef PROD3
wg_combine(h,C,ldc,M1,M2,M3,M4,M5,M6,M7);
}
static void winograd_child(int n, const long long *A, int lda, const long long *B, int ldb,
long long *C, int ldc) {
const int h=n/2; const size_t sz=(size_t)h*h; const size_t sg=(size_t)h*(size_t)(h+8); /* [ml4cn_] 面板间距 */
long long *M1=C,*M2=C+h,*M3=C+(size_t)h*ldc,*M4=M3+h;
long long *M5=wg_buf2,*M6=M5+sg+512,*M7=M6+sg+512,*P=M7+sg+512,*Q=P+sg+512;
long long *P2=wg_buf2_s2,*P3=P2+sg+512;
const long long *A11=A,*A12=A+h,*A21=A+(size_t)h*lda,*A22=A21+h;
const long long *B11=B,*B12=B+h,*B21=B+(size_t)h*ldb,*B22=B21+h;
#define PROD2(X,Y,Z,LX,LY,LZ) do { winograd_grandchild(h,(X),(LX),(Y),(LY),(Z),(LZ)); } while(0)
PROD2(A11,B11,M1,lda,ldb,ldc);
PROD2(A12,B21,M2,lda,ldb,ldc);
wg_schain3(h,P,P2,P3,A11,lda,A21,lda,A22,lda);
wg_add(h,Q,B12,ldb,B11,ldb,-1);
PROD2(P,Q,M5,h,h,h);
wg_mutate(h,Q,B22,ldb,1);
PROD2(P2,Q,M6,h,h,h);
wg_sub2(h,P,A12,lda,P2,h); /* P2 is a contiguous h x h block */
PROD2(P,B22,M3,h,ldb,ldc);
wg_mutate(h,Q,B21,ldb,0);
PROD2(A22,Q,M4,lda,h,ldc);
wg_add(h,Q,B22,ldb,B12,ldb,-1);
PROD2(P3,Q,M7,h,h,h);
#undef PROD2
wg_combine(h,C,ldc,M1,M2,M3,M4,M5,M6,M7);
}
static void winograd_top(int n, const long long *A, const long long *B, long long *C) {
const int h=n/2; const size_t sz=(size_t)h*h; const size_t sg=(size_t)h*(size_t)(h+8); /* [ml4cn_] 面板间距 */
long long *M1=C,*M2=C+h,*M3=C+(size_t)h*n,*M4=M3+h;
long long *M5=wg_buf,*M6=M5+sg+512,*M7=M6+sg+512,*P=M7+sg+512,*Q=P+sg+512;
const long long *A11=A,*A12=A+h,*A21=A+(size_t)h*n,*A22=A21+h;
const long long *B11=B,*B12=B+h,*B21=B+(size_t)h*n,*B22=B21+h;
#define PROD(X,Y,Z,LX,LY,LZ) do { winograd_child(h,(X),(LX),(Y),(LY),(Z),(LZ)); } while(0)
PROD(A11,B11,M1,n,n,n);
PROD(A12,B21,M2,n,n,n);
wg_add(h,P,A21,n,A22,n,+1); // S1
wg_add(h,Q,B12,n,B11,n,-1); // T1
PROD(P,Q,M5,h,h,h);
wg_mutate(h,P,A11,n,0); // S2 = S1 - A11
wg_mutate(h,Q,B22,n,1); // T2 = B22 - T1
PROD(P,Q,M6,h,h,h);
wg_mutate(h,P,A12,n,1); // S4 = A12 - S2
PROD(P,B22,M3,h,n,n);
wg_mutate(h,Q,B21,n,0); // T4 = T2 - B21
PROD(A22,Q,M4,n,h,n);
wg_add(h,P,A11,n,A21,n,-1); // S3
wg_add(h,Q,B22,n,B12,n,-1); // T3
PROD(P,Q,M7,h,h,h);
#undef PROD
wg_combine(h,C,n,M1,M2,M3,M4,M5,M6,M7);
}
static inline void advise_huge(void *p,size_t bytes){
uintptr_t a=(uintptr_t)p,e=a+bytes;
uintptr_t h0=(a+2097151u)&~(uintptr_t)2097151u;
uintptr_t h1=e&~(uintptr_t)2097151u;
if(h1>h0) madvise((void*)h0,(size_t)(h1-h0),MADV_HUGEPAGE);
}
__attribute__((constructor)) static void setup_huge_scratch(){
__asm__ volatile(".space 152,0x90"); /* [ml4d1_] */
advise_huge(wg_buf,sizeof(wg_buf));
advise_huge(wg_buf2,sizeof(wg_buf2));
advise_huge(wg_buf1,sizeof(wg_buf1));
advise_huge(wg_buf0,sizeof(wg_buf0));
advise_huge(g_scratch,sizeof(g_scratch));
advise_huge(material_A,sizeof(material_A));
advise_huge(material_B,sizeof(material_B));
advise_huge(material_C,sizeof(material_C));
advise_huge(material_D,sizeof(material_D));
advise_huge(Bpanel,sizeof(Bpanel));
}
static_assert(sizeof(long long)==8,"l4z3a4");
void matrix_multiply(int n, const long long *A, const long long *B, long long *C) {
Opd Ao = o1(A, n), Bo = o1(B, n);
if (n <= CUTL || (n & 1)) { leaf(n, &Ao, &Bo, C, n, 0, 0, 0, 0); return; }
if (n == 4096) winograd_top(n, A, B, C);
else mmxR(n, &Ao, &Bo, C, n, 0, g_scratch);
}
#pragma GCC pop_options
/* ml4be_ 席 · 全局布局对照块: 死 .bss, 一行代码不改, 只把程序映像的尾端推后 8 MiB。
(不可删: used; 不可读: 无任何代码引用 ⇒ 语义零扰动, 闸门按构造成立。) */
static unsigned char ml4be_layout_pad[8u << 20] __attribute__((used, aligned(2097152)));
__attribute__((weak)) int main() { return 0; }
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 5.218 s | 357 MB + 800 KB | Accepted | Score: 100 | 显示更多 |