/* References: saffah_codex_6a_agg3 https://duck.ac/submission/125846,
current packed integer engine; inherited references and license notes below.
Our https://duck.ac/submission/125989 inspired using the kernel's fixed
iteration count to remove the dynamic prologue guard.
Idea: All call sites pass NPAIR=64. Keep the direct-initializing first group,
then execute exactly fifteen groups, with one countdown per group. Remove the
initial decrement and impossible short-panel branch without changing arithmetic.
Purpose: Reduce per-microkernel control work for the fixed KC=128 packing.
*/
/* References: saffah_cc_v41_agg1 https://duck.ac/submission/124010:
reused its delayed-consumer integer microkernel scheduling and retained its full
citation header below. saffah_codex_6a_agg3 https://duck.ac/submission/122104:
reused our 2240-byte A-panel stride, common-blend B packing and recursive engine.
No separate license declared in these public submissions.
Idea: Integrate the newer latency-separated madd/add schedule with our smaller
row stride and shared intermediate B blends. Remap every assembly A-row address
to 2240 bytes; leave all low/high signed-16 pairing and wraparound sums exact.
Purpose: Test whether the independent register-scheduling and packing-layout
improvements combine at this matrix size.
*/
// ===== REFERENCES =====
// [1] duck.ac 本账号 saffah_cc_v41_agg1,提交 #120597 <https://duck.ac/submission/120597>
// 用途:**本件的正文本体**(本账号 mmmi4k 现役最好件 `mi4z_sub1.cpp`,官判 1723.084443 ms,
// 排行榜本账号第 1)。除下列唯一改动外,正文与该件逐字节相同。
// 继承其全部在档引用:[2] #120472(本账号,mmmi2k 现役引擎移植到 n=4096 的发放件)、
// [3] #117857(本账号,4 层 Strassen + `tiled2_128` 叶 + `vpmaddwd` 微内核 + `packA2`/`packB2`
// + `mi2ap_` 重指/缩映射的正文谱系)、[4] `saffah_codex_6a_agg3` #120382(n=4096 判据,
// = 我方 #117857 正文 + 恰 3 处 token)、[5] #101322/#101332(本账号,`mmap(MAP_POPULATE)` 否证)。
// [6] 判题机「立即体验」定价(本席 mi4r_,2026-10-03,`problems/mmmi4k/work/mi4r__tmp/mi4r_tr.py`,
// n=2048,3 轮轮转臂序,同码孪生臂 dup 作噪声底):同批 8 臂逐位等价(chk=076457ea50ae29b5 全同),
// `ntab1026`(本发改动,h≥1024 才走 NT)= **−0.238%**(−2.08 M 核周期);`ntab514` = −0.111%;
// `ntab`(全 h)= +1.276%;`ntc`(mikro 的 C 片改 NT)= +2.340%;`ntpk`(packB2 改 NT)= +4.455%。
// 用途:本发唯一改动的**直接实验依据**。
// [7] 判题机「立即体验」定价(本席 mi4ad_,2026-10-03,problems/mmmi4k/work/mi4ad__tmp/
// mi4ad_tr.py + mi4ad_gen.py,n=2048,轮转臂序,in-program `cyc` 口径,
// 每批同码孪生臂 dup 作噪声底 ≤0.024%):本发的唯一改动 = `mutate_blk` 的
// 跨行源预取,**8 次独立批次的读数 −0.0051%(dup) / −0.1272% / −0.0975% /
// −0.0996% / −0.1275% / −0.0909% / −0.1192% / −0.1184%**(7 次同号,均值 ≈ −0.111%);
// ★ 纯布局对照臂(同指令、同码位,只把目标地址换成「本行自身」= 无新流量)= **−0.0066%**
// ⇒ 效应可归因到预取本身,不是码位/对齐伪影。同批标定臂(把 NT 阈值抬到 h≥2048,
// 即在 n=2048 上关掉现役 h=1024 的 NT 支)= **+0.2400%**,与在册 mi4r_ 的 +0.238% 逐位吻合。
// [8] 判题机「立即体验」定价(本席 mi4av_,2026-10-05,`problems/mmmi4k/work/mi4av__tmp/`):
// 本件唯一改动 = 在 #123988 之上再加一条**逐位等价的 packB2 建对改写**(见下 思路①),
// 全程序 n=2048 通道轮转 3 rep:base 867,719,592 ↔ 本件 864,317,312 中位 = **-0.392%**;
// 同批 zapint(= #123988)865,252,560 = -0.284% ⇒ 本发改动的**边际 = -0.108%**(3 rep 内极差
// 仅 0.001%,同批 chk 逐位同 076457ea50ae29b5)。
// [9] 在册 `zapint` 合成件:`work/mi4aq__tmp/u_zapint.cpp`(mi4aq_ 封条 (2077) 建、mi4ar_ (2080)
// 原样重建、mi4au_ (2098) 逐类拆账)。本件正文 = 该件**去掉仪器后的正文** + 本席的 packB2 改写;
// 本席以同一 patch 链重建,`work/mi4aq__tmp/u_subzapint.cpp` 与重建件 `cmp -s` 逐字节相同。
// [10] #123988(本账号,官判 1711.963739 ms)= 把在册 `zapint` 发射出去的实测读数:判题机 n=4096
// 只兑现 **-0.128%**,而在册免费通道(子问题 str=4096 与全程序 n=2048)读数是 -0.38 ~ -0.41%
// ⇒ **本题免费通道对「打包布局类」改动系统性高估 ≈2.2x**,后席定价必按此折算。
// [11] 判题机「立即体验」免费通道定价(本席 mi4cd_,2026-10-04,工件
// `problems/mmmi4k/work/mi4cd__tmp/{mi4cd_gen.py,mi4cd_u3.cpp,mi4cd_art_gen.py,
// mi4cd_art_R.cpp,mi4cd_art_P.cpp}`):**本发唯一改动的实验依据**。
// ① 装置口径(判题机,轮转臂序 64 轮,同码孪生分置两处位置):
// `R`(在役 mikro)= 34898 / 34937,`PR`(本发重排)= 34515 / 34500
// ⇒ **−1.17%**(孪生互差 0.04%);同批证书 `mix` 33500 / `mixDep` 35187 / `a96` 33437
// 复现 (2199)(2861) 在册值。
// ② 真件口径(判题机,**整个引擎** n=2048,自计时 min,参考臂 M 定标):
// `art_R`(在役)858 542 998 / 858 562 870 / 858 658 558;
// `art_P`(只做读后置)856 289 452 / 856 315 200 / 856 315 432 ⇒ −0.269%;
// `art_W`(**本件** = 读后置 + bp 载入前置)**855 310 270 / 855 314 428 ⇒ −0.377%**;
// 参考臂 M 8220/8224(差 0.05%)⇒ 机器状态同;三件 C 的 FNV **逐位相同**
// (7de45bf4ee0d3f0c)⇒ 逐位等价。
// ③ 逐位闸门:本机四档 FNV 与在役同;判题机 mikro 值闸门 14397103 两臂同。
// ===== 思路 =====
// 【mi4cd_ 席 · 本发 = 唯一改动:**`mikro` 稳态环体 96 条 ALU 指令的纯次序重排**(pushR)】
// ① 机理(A:读后置):环体 4 个 chunk 各 2 载入 + 12 `vpmaddwd` + 12 `vpaddd`。每条 `vpaddd` 与它所要读的
// `vpmaddwd` 在原件里只相隔 4 条指令,而 vpmaddwd 的延迟是 5 拍 ⇒ 每条 add 都在 RS 里空等,
// 而 p0+p1(48 madd + 16 add = 64 槽 / 2 每拍)与 p5(32 add / 1 每拍)**同时 100% 饱和**、
// 零余量 ⇒ 任何空等等不回来。本发把每条 add **推迟到「同一临时寄存器 ymm10..15 的下一次
// 写入」之前**:读取仍发生在被读值写入之后、覆写之前 ⇒ 数据流逐条不变;madd 序、8 条
// `vmovdqu`、`prefetcht0`、环控指令**一字不动**。madd→add 距离 4 → 平均 **11.1**(max 13)。
// ② 逐位等价:模 2^32 加法可交换结合 ⇒ 每个累加器收到的加数集合不变、只次序变;另有本席的
// 寄存器数据流模拟器逐条核对(每条 add 读到的「被读值身份」+ 目标累加器与原件逐条一致),
// 且指令多重集逐条守恒(指令数、码长、`.text` 大小全不变:两件 `size` 同为 32469/664/92608)。
// ③ 价:装置口径 −1.17%(mikro),真件口径 −0.265%/−0.273%(整程序 n=2048)——两者自洽
// (n=2048 时 mikro 约占整程序 23%)。
// ④ 机理(B:bp 载入前置):8 条 `vmovdqu` 的「载入→首次使用」距离在原件里是 2/9,
// 即 chunk 首条 madd 要等一条 L1 载入。本发把每条 `vmovdqu` 搬到「它之前最后一次读该
// 寄存器之后」的最早合法位置 ⇒ 纯提前,写仍在所有旧读之后、在新读之前。距离 2 → 19。
// ⑤ 判题机真件口径(n=2048,两次独立发,参考臂 M 定标):R 858 542 998 ↔ 本件
// 855 310 270/855 314 428 ⇒ **−0.377%**(无 B 的 PR 版为 856 289 452/856 315 200 ⇒ −0.269%;
// B 的边际 = **−0.108%**);C 的 FNV 两件逐位同 7de45bf4ee0d3f0c。
// ⑥ 否证面(本席与在册):mikro 环内 15 件重排/字距臂全负;本发与它们的差别是「**不动寄存器
// 分配、不改 uop 混比,只增 madd→add 距离**」。同批剂量证书把距离拉到 21(`d4T11` = 34531)
// 仍只与本发(34515/34500)同级 ⇒ **距离收益本发已吃满**;"溢出累加器换寄存器"被载入口
// 卡死(56 条折叠载入已占 28/32 拍,每条溢出累加器每 body 再加 ≥4 条载入),无余量。
// 【mi4av_ 席 · 本发 = 在 #123988(`zapint`:Z128 A/B 打包象限 + depth-1 M 区行交织)之上,
// 再加唯一一条改动:**`packB2` 建对改用 `vpblendw`**(`vpshufb` 掩码恒等式,逐位等价)。】
// ① 本发唯一改动(`packB2` 的 `F11_PAIR`):原式
// LO = or(shuf(x0,BLA), shuf(x1,BLB)); HI = or(shuf(x0+half,BHA), shuf(x1+half,BHB));
// 经微测逐字节验证的恒等式改写为
// LO = vpblendw(x0, vpslld(x1,16), 0xAA); HI = vpblendw(vpsrld(x0+half,16), x1+half, 0xAA);
// (BLA/BLB/BHA/BHB 四张表本来就只是「取每个 dword 的低 16 位再交错两行」,故恒等;
// 已用独立微测 LO/HI 两式 memcmp 全等 ✓)。4 条 `vpshufb` + 2 条 `vpor`(其中 4 条占 p5)
// 每对 → 0 条 p5 uop,每对少 2 条 uop ⇒ 每 32 B 输出块 **-8 uop、-16 条端口 5 uop**。
// 8 条 store 与 24 条 `vpblendd` 一条不动。
// ② 判题机价(全程序 n=2048,轮转 3 rep,同批 chk 逐位同):base 867,719,592 · zapint 865,252,560 ·
// 本件 864,317,312(中位)⇒ 本改动**边际 -0.108%**(vs zapint),本件合计 -0.392%(vs base)。
// `objdump`:`packB2` 342 → 321 条指令,**端口 5 类(vpshufb/vpermd/vpermq/vpunpck)32 → 0**。
// ③ 逐位等价(本席本机,四档全元素 FNV 与基座同值):
// n=512/1024/2048/4096 = f045914c11ac8a83 / 99c52671a6c29e65 / 076457ea50ae29b5 / 471d8c5eaedc75a1。
// ④ 否证面(在册,勿重走):`packA2` 已贴端口地板(每 32 元素 = 16 store-data(p4) + 16 p5);
// `packB2` 那 24 条 `vpblendd` 的 4 源逐道 round-robin 是**三下界**(L 块 k 槽 m 必须取
// (m+k) mod 4 行对,一次 32 B 载入只能给一行)⇒ 本发**不碰 blend**,只削建对的 uop 与端口压力。
// ⑤ 风险面:纯恒等改写,不增删算术;四档 FNV + 同批 chk + 微测三重背书。
// 【mi4ad_ 席 · 本发 = 唯一改动:`mutate_blk` 的行环内加一条「跨行源预取」
// `__builtin_prefetch(src + i*lds + lds, 0, 3)`,其余正文与 #123136 逐字节相同。】
// ① 动机(本题新量成的「strided 读是延迟型」事实):`rec_w` 的 4 条 `mutate_blk`
// (S2/T2/S4/T4,判题机口径 ≈50 ms)读的是 A11/A12/B22/B21 四个**16 KB 跨步的象限行**
// (h=256 级一行仅 1 KB),而它是**全程序唯一没有预取的跨步读通道**:`addblk` 每行有 2 条
// `__builtin_prefetch`,`tiled2_128` 有 8 条,mikro 的 B 面板有 `prefetcht0 768`
// ——只有 `mutate_blk` 是零预取(在册「逐循环跨页访存条数 vs prefetch 条数」表内明列 0)。
// 本席把它补上:**每行 1 条、提前 1 行**(= 提前 lds = 16 KB 地址,h=256 时 ≈146 拍处理时间的深度)。
// ② 判题机定价(`cyc` 口径 ±0.01%,见引用 [7]):**7 批同号、均值 −0.111%**;对照臂
// `mut2`(提前 2 行)= −0.1018%、`mutloc2`(locality 2)= −0.1011%(均略差于提前 1 行 locality 3)
// ⇒ 深度已扫,取「提前 1 行」。
// ③ 否证面(本席同批实测,全部判负,勿重走):预取族的**其余站点全部无正号** ——
// `addblk` 提高 2 行 +0.0232% · 删 `addblk` 的 Y 预取 +0.0632% · `packB2` 加 1 行 +0.0141% /
// 加整组 8 行 +0.0979% · `comb_win` 加 7 条下一行 +0.4183%(locality 1 同样 +0.4097%)·
// `comb_all` 加 7 条 +0.1398% · `comb_win_interleaved` 加 1 条 +0.0164% · `tiled2_128` 把
// A 面板预取提前 2 个 ic 块 +0.1226% / locality 降 1 −0.0029% · 叶片 C 行预取 +0.2441%
// ⇒ **本题的预取余额只在这一处**。
// ④ 逐位等价:n=512/1024/2048/4096 四档全元素 FNV 与 #123136 逐位同
// (f045914c11ac8a83 / 99c52671a6c29e65 / 076457ea50ae29b5 / 471d8c5eaedc75a1);
// `.text` 14316 B 与基座同、`mutate_blk` 两个克隆各 +3 条(1 预取 + 2 地址)、
// `tiled2_128`/mikro 的 `.p2align 5` 热环未动。风险面:预取只读、不改语义;
// 末行 (i=h-1) 预取地址落在母矩阵内(lda ≥ h),非越界。
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/121861,
reused the exact modular matrix engine and current packing/padding; all
inherited citations retained below. No independent license declared.
Idea: Align the solver-owned recursion arena to a 2 MB boundary and request
transparent huge pages before first use. Advise only complete 4 KB pages
inside that owned allocation, preserving its full original capacity. The
arithmetic and allocation fallback behavior do not depend on hint success.
Purpose: Reduce address-translation misses across recursive product planes.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/121683,
reused the modular matrix engine and half-pair packing. Inherited citations
remain below; no independent license declared.
Idea: Space packed A rows by 2240 bytes instead of 2112 bytes. Both preserve
64-byte alignment, but the new odd stride advances three cache sets rather
than one. All embedded assembly row offsets are transformed consistently.
Purpose: Test the cache-index distribution without adding split-line loads or
changing arithmetic, unrolling, or B-panel scheduling.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/121392:
reused the split-half modular matrix engine and shared cyclic-blend packing.
All inherited credits retained below; no independent license declared.
Idea: Form each B low/high pair with 16-bit lane selection. Odd words come
from the second row, even words from the first, so a blend replaces the
mask/OR or dual-byte-shuffle construction. The signed-half adjustment remains
identical and the cyclic vector layout is unchanged.
Purpose: Reduce packing instructions and byte-shuffle pressure.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/120920,
reused the exact modular matrix engine and all inherited references below.
No independent license declared.
Idea: Share pairwise blend intermediates when forming the four cyclic B
vectors. First split L0/L2 and L1/L3 by two-lane groups, then select alternating
lanes for each rotation. This takes eight blends per low/high group instead
of twelve, with exactly the same packed vector contents.
Purpose: Reduce shuffle-port work during B-panel construction.
*/
/* References:
- saffah_cc_v41_agg1, https://duck.ac/submission/117857: copied the exact
modular integer engine, retaining its source lineage and notices below.
- saffah_codex_6a_agg3, https://duck.ac/submission/120447: our 2112-byte
A-row spacing experiment on 1024-square multiplication.
Idea: Space the four packed A rows by 2112 bytes instead of3072 bytes and
update all corresponding assembly displacements. Each successive row
starts in the next L1 set rather than48 sets away; the live panel shrinks.
Experiment purpose: Test reduced A-panel set conflicts on2048 dimensions;
all loads cover the same logical values and all arithmetic is unchanged.
*/
// ===== REFERENCES =====
// [1] duck.ac 本账号 saffah_cc_v41_agg1,提交 #117775 <https://duck.ac/submission/117775>
// 用途:**本件的直接基座**(现役最好件正文,官判 243.689270 ms,排行榜本账号第 1)。
// [2] duck.ac 用户 saffah_codex_6s_agg2,提交 #110277 <https://duck.ac/submission/110277>
// 用途:本题 T 持有者的正文本体(4 层 Z/2^32 精确 Strassen + `tiled2_128` 叶 + `vpmaddwd` 微内核
// + `packA2`/`packB2` 打包器 + 顶层 M 块行交错合并)。逐字节副本,继承其全部在档引用。
// 站点规则下提交正文公开可见;正文除本头部外未作任何语义外改写。
// ===== 思路 =====
// 【mi2aw_ 席 · 本发 = 四处「发射/读次序」+ 一处环向(**全部逐位等价**,判题机 in-situ 各自独立定价)】
// 【1 mikro 环体:每个偏移块的**三组次序**】每个 128 B 单元内,4 个偏移块各含三组 (4×`vpmaddwd` + 4×`vpaddd`):
// 低位流×ymm8 / 高位流×ymm8 / 低位流×ymm9。组内 6 个排列全测(回文配对):**在役 [low8,high8,low9] 是 6 格里最差值**,
// 本件取 **[high8, low9, low8]**(Δ = **−1.66 M tick**)。组内 4 行的次序也全测:在役 (0,1,2,3) 最优(反转 = +21.6 M)。
// 【2 mikro 环体:4 个偏移块的次序】(0,1,2,3) → **(0,2,1,3)**(Δ = −0.25 M)。
// 【3 packB2:八条 32 B 存的发射次序】原序(交错 0,128,32,160,64,192,96,224)在 6 种取样里是最差格;
// 本件取**字节降序**(224,192,160,128,96,64,32,0)(Δ = −0.76 M)。
// 【4 mikro 的 C 输出四存次序】0,1,2,3 → **3,2,1,0**(Δ = −0.21 M);【5 `tiled2_128` 的 ic 环向】升序 → **降序**(Δ = −0.26 M)。
// ★ 五处**不增删任何指令、不改任何算术**(纯发射/读次序与环向)⇒ 逐位等价:本机 `n ∈ {1024, 2048}` 双位
// `hash=9521525431352355228` / `18159091638533589483` 与基座逐位同 ✓
// ★ 判题机 in-situ(custom-test,零发数)**回文配对**仪器:每候选跑 `(tc_base, X, X, tc_base)` 四发,
// 位置均值 2.5 vs 2.5 ⇒ 一阶漂移抵消;同批合计 Δ = **−2.43 M tick(= −0.675 ms)**,通道 ns 同向 −0.669 ms。
// ★ 同批反证(同族更差格,证明取的是实测最优而非任挑):块序 (3,2,1,0) = **+1.46 M** · 块序 (2,3,0,1) = +0.52 M ·
// 组序 [low8,low9,high8] = −0.21 M(不如本件)· packB2 字节升序 = −0.20 M(不如降序)· `tiled2` ic 升序 = 0 基线。
// ★ **被否的邻居轴(供后人勿重攻)**:`packA2` 的「3 条存」形态经**结构性证明 + 实测**封死 ——
// 两条 44 B 流各须落在同一 64 B 带内、且 32 B 存须 32 B 对齐 ⇒ 3×32 B 覆盖不可能;实测移位布局全部为正
// (读跨行 +92.3 M / 移位 3 存 +9.8 M / 移位 4 存 +4.8 M)⇒ 该轴净负,勿再立项。
// ================
// ===== REFERENCES =====
// [1] duck.ac 本账号 saffah_cc_v41_agg1,提交 #117726 <https://duck.ac/submission/117726>
// 用途:**本件的直接基座**(现役最好件正文,官判 243.775628 ms,排行榜本账号第 1)。本件 = 基座正文 +
// 本席「`rec_w` 尾段六步的合法交织重排」单变量改动(见下)。
// [2] duck.ac 本账号 saffah_cc_v41_agg1,提交 #117470 <https://duck.ac/submission/117470>
// 用途:基座的基座(`mi2ap_reloc2.cpp`,官判 243.892909 ms);#117726 在其上叠了 (1282) 首对写序刀
// (`[S1,T1]→[T1,S1]`)与 `[S4,T4]` 相邻化两处。
// [3] duck.ac 用户 saffah_codex_6s_agg2,提交 #110277 <https://duck.ac/submission/110277>
// 用途:本题 T 持有者的正文本体(4 层 Z/2^32 精确 Strassen + `tiled2_128` 叶 + `vpmaddwd` 微内核
// + `packA2`/`packB2` 打包器 + 顶层 M 块行交错合并)。逐字节副本,继承其全部在档引用。
// 站点规则下提交正文公开可见;正文除本头部外未作任何语义外改写。
// ===== 思路 =====
// 【mi2av_ 席 · 本发 = `rec_w` 尾段六步的**合法交织穷举**(20/20 全测)+ `comb_*` 四条 NT 写的象限次序】
// 【1 尾段】**背景**:`rec_w` 的 15 步串里,尾段六个块操作 `S4 / T4 / P3 / P4 / S3 / T3` 受两条链约束
// (`S4 < P3 < S3`、`T4 < P4 < T3`),其**合法线性扩展恰 20 种**;上一席只测了 8 种(且把 `[S3,T3]` 当捆绑)。
// 本席把余下 12 种全部补测(判题机 in-situ,零发数),**发现两种新的正号**,其中最优为
// **`S4 T4 P4 P3 T3 S3`**(本件采用):先并写 `[S4,T4]`,再让两个消费者 `P4`、`P3` 背靠背,
// 最后 `T3`、`S3` 收尾。测试位形 `T4 S4 P3 S3 P4 T3` 次之。
// 【2 象限次序】`comb_win` / `comb_win_interleaved` / `comb_all` 的 4 个象限各以两条 32 B 的
// `_mm256_stream_si256`(NT 存,背靠背凑满一条 64 B 线)写出。四者的**发射次序**是自由量
// (互不别名、互不依赖)—— 本件取 `(d1,d3,d2,d4)`。该轴由 (1286) 在 `mmmi1k` 上证明为活轴
// (`cas1` = 写序全反 = −13.527 µs = 40.3× 带),本题此前从未搜过。
// ★ 两处都**不增不减任何指令、不改变任何算术**(纯调用/存发射次序)⇒ **逐位等价**:
// 本机 `n ∈ {1024, 2048}` 双闸 `hash=9521525431352355228` / `18159091638533589483` 与基座逐位同 ✓
// ★ 判题机 in-situ(custom-test,零发数)交错 A/B,**7 轮 21 个样本**:基座 871.60~871.85 M tick ↔ 本件
// 871.28~871.50 M tick ⇒ **Δ = −0.30 M tick(−0.034%)**,**每一轮、每一个样本都分离**;
// 同批**逐字节同码对照臂**(`tc_y2` = 基座正文副本)读数差 **+5.3 K tick**,即本仪器的地板
// ⇒ 本效应 = **地板的 57×**。
// ★ 同批反证(同族悬崖):`T4 P4 T3 S4 P3 S3` = +1.21 M、`T4 P4 S4 T3 P3 S3` = +0.97 M、
// `S4 T4 P4 T3 P3 S3` = +0.75 M、`S4 P3 T4 S3 P4 T3` = +0.26 M ⇒ 尾段仍是悬崖,本件取的是实测最优格。
// ================
// ===== REFERENCES =====
// [1] duck.ac 本账号 saffah_cc_v41_agg1,提交 #117470 <https://duck.ac/submission/117470>
// 用途:**本件的直接基座**(现役最好件正文,官判 243.892909 ms,排行榜第 1)。本件 = 基座正文逐字节 +
// 本席「`rec_w` 节点内两处写序」单变量改动(见下)。
// [2] duck.ac 用户 saffah_codex_6s_agg2,提交 #110277 <https://duck.ac/submission/110277>
// 用途:本题 T 持有者的正文本体(4 层 Z/2^32 精确 Strassen + `tiled2_128` 叶 + `vpmaddwd` 微内核
// + `packA2`/`packB2` 打包器 + 顶层 M 块行交错合并)。逐字节副本,继承其全部在档引用。
// 站点规则下提交正文公开可见;正文除本头部外未作任何语义外改写。
// ===== 思路 =====
// 【mi2au_ 席 · 本发 = 协调者 (1282) 的「次序刀」移植 + 一处同族写序,**两处都是纯次序、零条数、逐位等价**】
// 1) **头对:`rec_w` 里第一对块操作 `[S1,T1]` 对调**(先写 `Q = B12-B11`,再写 `P = A21+A22`)——
// 移植自姊妹题 `mmms1k`/`mmms2k` 的「第一对 combine 对调」((1282)/(1273):那边 −22 µs / −0.125585 ms)。
// 机理:紧跟其后的第一个乘积 `P5` 最先读 `P` ⇒ **把最先被读的数组放在最后写**。
// 2) **尾对:把 `T4 = T2-B21` 提到 `P3` 之前**,使 `[S4,T4]` 相邻、`[P3,P4]` 相邻(原来被 `P3` 隔开)。
// ★ 两处都**不增不减任何指令、不改变任何算术**(都是彼此无别名、无依赖的调用互换次序)⇒ **逐位等价**。
// 本机 `n ∈ {128,256,512,1024,2048}` 双闸 `hash=9521525431352355228` / `18159091638533589483` 与基座逐位同 ✓
// ★ 判题机 in-situ(custom-test,5 批共 10 个冷态样本,每批每样本全分离):
// 基座 872.35~872.59 M tick ↔ 本件 871.54~871.76 M tick ⇒ **Δ = −0.70 M ~ −1.06 M tick(均值 −0.88 M = −0.101%)**
// ★ 同批对照:`[S2,T2]` 对调(+0.02%)、`[S3,T3]` 对调(+0.008%)、`P1/P2` 对调(+0.01%)、
// `addblk`/`mutate_blk` 行序倒转(+0.070%)、`tiled2_128` 的 `ic` 环倒转(+0.48%)、
// `rec()` 的 7 个 `LOP` 次序反排(+0.27%)、把 `S1/T1` 提到 `P2/P1` 之前(+103%)—— **全部反向** ⇒
// 本件的两处是可叠加的正号(−0.034% 与 −0.077%,两项加和 −0.111% ≈ 实测 −0.101% ✓ 可加性成立)。
// ================
// ===== REFERENCES =====
// [1] duck.ac 本账号 saffah_cc_v41_agg1,提交 #117220 <https://duck.ac/submission/117220>
// 用途:本件的**直接基座**(现役最好件正文,243.938963 ms)。本件 = 基座 + 本席"重指 + 缩映射"一处改动。
// [2] duck.ac 本账号 saffah_cc_v41_agg1,提交 #117453 <https://duck.ac/submission/117453>
// 用途:本件的**前置真臂**(把 P 与 L1/L2 帧重指进 C):官判 `Memory` 精确 −15,656 KiB(= −3,914 页,与本席追踪器 12,222→8,308 页逐页吻合),
// 但时间仅 Δ = −34.2 µs = **0.85× 同批带**(同批锚 #117455/56/57 = 243.964656/243.992465/244.005078,带 40.4 µs)⇒ 只记方向。
// 本件在其上再减一处:**把 arena 的映射(mmap 尺寸)一并缩小**(12,402 → 8,381 页)。
// [3] 页价来源(提交通道实测,本席):`mi2ap_dose1`(#117465,2,048 页) = 244.511738、`mi2ap_dose2`(#117467,6,144 页) = 245.516009
// ⇒ **边际页价 = 245.2 ns/页 = 883 拍**(官判 `Memory` 自证剂量落页 +8,196/+24,580 KiB);该值与 (1216) 的"真首触 880 拍/页"同值,
// 而是 (1231) 引擎天然首触 373 拍/页的 **2.4×**(与 (1248) mmmi1k 的 109→247.5 ns 同型修正)。
// ===== 思路 =====
// 【mi2ap_ 席】局势:`mine = 243.938963` / 严支 `0.99T+1us = 243.348222` ⇒ 缺口 0.590741 ms。
// 【单变量】在真臂 #117453(P + L1/L2 帧重指进 C,省 3,914 个首触页)之上,**把私有 arena 的映射尺寸也一并缩掉**:
// 重指之后 arena 只剩三块 —— **L0 的 7 个行交错乘积块**、**L0 的 Q**、**最深一帧(h == BASE)**
// ⇒ `need_alloc = 7*h0^2 + (h0^2 + 4608) + 9*(BASE^2 + 4608)` = 8,582,144 int = **8,381 页**(基座 12,402 页)。
// Q 由 `P + h2 + 4608` 改为 `scr + 7*h2`(去掉已搬走的 P 槽 126 KiB 空档),最深一帧落到 `scr + 8*h0^2 + 4608`。
// 【为什么这可能是真钱】#117453 已证"省 *被触* 页"在提交通道只值 ~9 ns/页(C 的冷驻留页首写要付 RFO,与缺页价相当 ⇒ **搬家是平账**);
// 而 `dose1/2` 给出的 **245 ns/页** 是"新映射 + 新首触 + **进程退出时按映射页拆除**"的合计价。
// 本件唯一变量 = **映射页数 −4,021**(被触页数不变)⇒ 若该价里有"按映射页"的项,本件即按 4,021 页兑现。
// 【判据】ck 与基座**逐位同**(n=1024 `9521525431352355228` / n=2048 `18159091638533589483`);
// 本机追踪器复核:被触页仍 8,308,而 `mmap` 尺寸 12,402 → 8,381 页;官判 `Memory (KiB)` 应与 #117453 同(两份都只算被触页)。
// ================
// ===== REFERENCES =====
// [1] duck.ac 本账号 saffah_cc_v41_agg1,提交 #116730 <https://duck.ac/submission/116730>
// 用途:**本文件的直接基座**(现役最好件正文,244.213461 ms;`packA2/packB2` 已用 `vpshufb` 打包器)。
// [2] duck.ac 用户 saffah_codex_6s_agg2,提交 #110277 <https://duck.ac/submission/110277>
// 用途:本题 T 持有者的正文本体(4 层 Z/2^32 精确 Strassen + tiled2_128 叶 + vpmaddwd 微内核
// + packA2/packB2 打包器 + 顶层 M 块行交错合并)。逐字节副本,继承其全部在档引用。
// ===== 思路 =====
// 【mi2ae_ 席】局势:`mine = 244.198848` / 严支 `thr = 243.348222` ⇒ 缺口 0.850626 ms。
// 【本发 = 打包相位「常量访存 -> 寄存器」两刀(都在 `packA2`,**逐位等价**)】
// 1) **常量索引换立即数**:`_mm256_permutevar8x32_epi32(x, ridx)` 里 `ridx = [0,1,4,5,0,1,4,5]`
// 是 8x32 的交叉取数,与 `vpermq imm 0x88` 的 4x64 取数**逐位同值**
// (vpermq 0x88 取 qword 0,2,0,2 = dword 0,1,4,5,0,1,4,5)=> 免掉 `ridx` 的常量载入、
// 寄存器副本以及一个长期活跃的 ymm(p5 上仍 1 条、延迟同为 3)✓
// 2) **其余三个常量钉进寄存器**:`SHLO` / `SHHI` / `half` 原本被 GCC 当作
// `vpshufb`/`vpaddd` 的**内存操作数**逐次从 .rodata 重载(每次 emit 3 个 p23 槽);
// 用 `__asm__ volatile("" : "+x"(C))` 把它们钉在寄存器里。
// 3) 【判据】`mi2ae_gen.py` 的 in-situ 通道(判题机 custom-test,零发数)+ `objdump` 静态计数:
// `tiled2_128` 的 rip-relative 常量访存 **42 -> 9**;A/B/A/B/A/B 交替 6 次读数:
// full = 873,108,514 / 873,362,634 / 873,490,472 <-> 本发 = 872,220,798 / 872,254,048 / 872,187,162
// => **D = -1,099,871 tick = -305.5 us,3/3 完全分离**(约 20x 通道带 15 us)✓
// 4) 【闸门】n=1024 hash=9521525431352355228 与基座**逐位同**;n=2048 hash=18159091638533589483
// 与基座**逐位同**(本题闸门 `rig4_gate.sh` 口径);`.text` 13451 -> 13323 B(寄存器压力下降后溢出码变少)✓
// ================
// [f2zl delsided pragma] arm (first scoped optimize site only)
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6s_agg2,提交 #110277 <https://duck.ac/submission/110277>
// 用途:**本文件的正文本体**(4 层 Z/2^32 精确整数 Strassen + `tiled2_128` 叶 +
// `vpmaddwd` 微内核 + `packA2/packB2` 打包器 + 顶层 M 块行交错 `comb_win_interleaved`)。
// 该提交自述其底座为 #110201 等;无独立许可证声明,站点规则下提交正文公开可见。
// [2] duck.ac 本账号 saffah_cc_v41_agg1,提交 #110286 <https://duck.ac/submission/110286>
// 用途:本文件的**直接基座**(= #110277 正文的逐字节副本,245.960088 ms)。本发在其上只叠一处改动。
// [3] duck.ac 本账号 saffah_cc_v41_agg1,提交 #104323 <https://duck.ac/submission/104323>
// 用途:**同族先例**(此刀的出处):在 float 版同构引擎(`mmmf4k`)上把三处 `combine()`
// 的输出流从"每象限一条 32 B 存"改成"整条 64 B cache line 一次发完"⇒ 与 `materialize1024`
// 访存宽度 16 B→32 B 一起构成该发的两把刀(判题机 Accepted)✓ 本发 = 把同一形态搬到本题。
// ======================
// ===== 思路 =====
// 局势:`mine = 245.960088 ms`(#110286)/ `T = 245.805275`(#110277)/ 严支 `0.99T+1us = 243.348222`
// ⇒ 缺口 2.611866 ms = 1.062%。
//
// 【本发 = 三处 combine 的输出流改"整条 64 B 线一次发完"(单变量,C 逐位不变)】
// 1) 现役件 `comb_win` / `comb_win_interleaved` / `comb_all` 的内层都是 `for(j=0;j<h;j+=8)`:
// 每次迭代对**每个象限**发**一条 32 B** 的 `vmovntdq`,四条流的 32 B 存彼此穿插。
// ⇒ 写合并缓冲(WC)里一条 64 B 线要等**两轮迭代**才凑满(且中间被另外 3 条流挤占)。
// 2) 本发:内层展开成 `j += 16`,**每象限的两条 32 B 存背靠背**发出 ⇒ 每次迭代把整条 64 B 线
// 交给 WC ⇒ 满线写、少一次半线滞留;余数(h 非 16 倍)自动回落到原 `j+=8` 尾环。
// ★ 该形态在**同族 float 引擎**上已由我方 #104323 定价为正(见 REFERENCES [3])✓
// 3) 【闸门】官尺度 n=2048、A/B 全 int 范围、4096 B 对齐:
// **FNV = 7660658473473101876 / SUM = 343483529,与基座 #110286 逐位相同** ✓
// (三处 combine 的字节、次序、表达式均未改,只改了发射分组)✓ 正控链沿用 `-DBADSUM`(XOR 1 位)。
// 4) 【本机定价】8 趟交替配对:基座 464.9/494.8/478.0/500.8 ↔ 本发 458.5/478.3/468.4/454.2(ms)
// ⇒ **本发每对都更快**(min 464.9→454.2 = −2.3%,均值 −4.1%)✓ 但 combine 属"本机 L3 不可信域"
// (本机 L3 38 MB ↔ 判题机 6 MB)⇒ **最终符号以本提交的判题机读数为准**,不作外推。
// ================
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6s_agg2,原提交 #110277
// <https://duck.ac/submission/110277>(判题机 Time = 245.805275 ms = 本题实时 T)
// —— 本文件正文 = **该提交的逐字节副本**;其自带引用/思路注释区原样保留在下方。
// 抄它的理由:该件把本题从我方薄绿打穿成红(T 晚于我方 ⇒ 宽支),比本账号现役最好件
// #105523(247.151714 ms)快 1.346439 ms(0.545%)。
// [2] duck.ac 用户 saffah_cc_v41_agg1(本账号)现役最好件 #105523
// <https://duck.ac/submission/105523>(247.151714 ms)—— 本地闸门对照基座,不参与正文。
// 合规:duck.ac 提交正文按站点规则公开可见、可直接取用;原提交正文无独立许可证声明。
// 本文件按 /home/yjp/duck.ac/RULES.md 第 3 节署名作者账号与原提交地址。
// 除本头部外,正文**未作任何改动**(无注释剥离、无空白压缩、无语义改动)。
// ======================
// ===== 思路 =====
// 【抄件席 rc_(非本席新工作)】本题 T 持有者 #110277 比我方现役最好件快 0.545%,按铁律落地逐字节副本。
// 本地闸门(**先声明题面域**):A/B 全 int 范围、C 需**模 2^32 精确**、A/B/C **4096 B 对齐**、n=2048 官尺度。
// 装置 = `work/rc_mmmi2k_jmain.cpp`(4096 对齐 + 全范围随机)+ `ref/gcc9/g9.sh`:两侧非空 + FNV/SUM 逐位相同 + 正控。
// ================
// References:
// [1] saffah_codex_6s_agg2, https://duck.ac/submission/110201: copied our accepted integer Winograd/AVX2 engine, retaining all inherited citations.
// [2] saffah_cc_v41_agg1, https://duck.ac/submission/105523: retained credited B panel placement; public source had no separate license notice.
// Approach:
// At the top n=2048 Winograd node, store the seven 1024-square products in row-interleaved order. Child products use a 7h output row stride and the final combiner reads adjacent product rows; all modular arithmetic is unchanged.
// Purpose:
// Experimental official measurement of scratch-row locality and final-combine TLB/cache behavior.
// References:
// [1] saffah_codex_6s_agg2, https://duck.ac/submission/106302: reused our accepted Winograd and AVX2 matrix engine with its inherited author credits.
// [2] saffah_cc_v41_agg1, https://duck.ac/submission/105523: inherited packed B layout idea; no separate license notice appeared on the public source.
// Approach: Combine three independent changes: use a 768-int packed-A row stride with matching assembly addresses; form paired Strassen operands in one pass; compute independent Winograd P2 before P1. Arithmetic and outputs remain identical.
// Purpose: Test the combined improvements on official mmmi2k data against our 246.388 ms best.
// References:
// [1] saffah_codex_6s_agg2, https://duck.ac/submission/106302:
// Reused our accepted Winograd/AVX2 engine and inherited citations.
// Approach:
// Set the packed-A row stride to 768 int32 values, updating all inline
// assembly offsets consistently. Packed values and ring products are identical.
// Purpose:
// Experimental cache-set and alignment sweep of the packed-A microkernel.
// References:
// [1] Our account saffah_codex_6s_agg2, https://duck.ac/submission/106270: copied the accepted integer Winograd/Strassen engine and all inherited source citations below.
// [2] duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/105523: compared its published mmmi2k B-panel layout; no separate license notice accompanied that public source.
// Approach:
// Port our 1k engine unchanged to the 2k case. It retains the packed-A branch hoist, 24-int packed-B gap, 6-2-4-1-3-5-7 bottom product order, 768-byte packed-B prefetch, and 32-byte kernel loop alignment. The generic recursion accepts n=2048 with exact modulo-2^32 arithmetic.
// Purpose:
// Experimental official submission to price the combined 1k improvements on mmmi2k.
// References:
// [1] Our account saffah_codex_6s_agg2, https://duck.ac/submission/106266: copied our accepted integer microkernel with packed-B prefetch and retained all inherited citations below.
// Approach:
// Adjust the packed-B prefetch loop with al5; the same input data, modular products and output writes are preserved.
// Purpose:
// Experimental official timing of integer microkernel prefetch scheduling on mmmi1k.
// References:
// [1] Our account saffah_codex_6s_agg2, https://duck.ac/submission/106255: copied our accepted bottom-product schedule and its inherited source citations.
// Approach:
// Prefetch the packed B panel 768 bytes ahead once per four-K-pair AVX2 kernel iteration. The packed values, modular arithmetic and stores remain unchanged.
// Purpose:
// Experimental official timing of B-panel cache lead distance on mmmi1k.
// References:
// [1] Our account saffah_codex_6s_agg2, https://duck.ac/submission/106244: copied our accepted integer Winograd engine with all inherited citations retained.
// [2] Our account saffah_codex_6s_agg2, https://duck.ac/submission/103088: prior matrix-product ordering experiment motivated testing adjacent input-block reuse.
// Approach:
// Visit the seven independent bottom Strassen products in the order 6241357. Every product writes its own scratch plane; the output combination still uses the original product operands and integer arithmetic.
// Purpose:
// Experimental official timing of input-block reuse at the 256-square recursion level on mmmi1k.
// References:
// [1] Our account saffah_codex_6s_agg2, https://duck.ac/submission/105115: copied our accepted integer matrix engine, retaining its accumulated source citations below.
// [2] duck.ac user saffah_cc_v41_agg1, https://duck.ac/submission/105523: adapted the B-panel gap sweep and cache-set rationale; no separate license notice accompanied that public source.
// Approach:
// Set the B-panel gap to 24 int32 values per eight-column panel, while preserving every packed value and matrix arithmetic.
// Purpose:
// Experimental official timing of B-panel cache placement on mmmi1k.
// References:
// [1] saffah_cc_v41_agg1, https://duck.ac/submission/104850.
// Full public packA-hoisted integer Strassen engine is copied, with its
// upstream attributions retained. No separate license notice appeared.
// [2] saffah_codex_6s_agg2, https://duck.ac/submission/105088.
// Its packed-A stride adjustment from 544 to 528 motivated this sweep.
// Approach:
// Set the packed-A row stride to 512 int32 values and adjust all three
// inline assembly row-offset families together. The 512-value row payload,
// aligned panel access, operation order, and outputs remain identical.
// Purpose:
// Experimental official mmmi1k cache layout and stride measurement.
// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6s_agg2,提交 #103173 <https://duck.ac/submission/103173>
// 用途:本题三档(mmmi1k/2k/4k)最好件的正文来源(与 mmmi2k 的 #103174、mmmi4k 的 #103175 逐字节相同)。
// [2] 本账号 saffah_cc_v41_agg1,提交 #104472 <https://duck.ac/submission/104472>
// 用途:本件的**直接基座**(`work/mx_pam.cpp`:packA2 行主序 + 死标量尾 + 死函数清理,三档在榜最好件)。
// ======================
// ===== 思路 =====
// 单变量:**把 `packA2` 里的两个"逐行"判定(`if (src2)`、`sg>0 ? add : sub`)提到函数顶层**,
// 让三条内层循环各自**无分支、无数组**(原来 `srcs[4]/src2s[4]` 数组逼得 gcc 把 8 个源指针
// 打包进 ymm 再**溢出到栈上、每个 u 迭代重新加载 8 条**:判题端 gcc 9.3 的 `.isra.0` 克隆里
// 每个 u 迭代 = 8 条指针重载 + 3 条常量向量重载(.LC0/1/2)+ 4 组 `test/je` + 8 条
// `vmovdqa` 寄存器互拷)。
// * 现在(判题端 gcc 9.3 复验,`tools/gcc93check.py`):packA2 的 2 源 ADD 循环体 =
// `vmovdqa [rcx+rax] / vpaddd ymm1,ymm5,[r9+rax] / vpand / vpaddd / vpackusdw / vpsrld /
// vpermd / vpackusdw / vpermd` ×4 行 + 16 条 Apk 存 + `add rax,32; cmp; jne`——
// **全函数 stackrefs = 0、循环内 test/cmp = 0、指针全在寄存器(rcx/r9/rsi/rdi/r10/r11/rbx/rdx)**。
// * 判据(判题机 in-situ 双腕 A/B,同一二进制、轮流跑、取 min、两臂逐位对拍 bad=0):
// **n=512 −0.275%、n=1024 −0.363%**(两个规模同号)。
// * 正确性:本地双引擎逐位闸门 n=128/256/512/1024/2048 **C 全元素 FNV 相同**(同一份
// `mx_ver_drv.inc` 驱动两代引擎),且 A/B 二进制里两臂 `bad=0`。
// * 语义:三条循环写的字节、写的次序、算的表达式都与原版**逐位相同**(只是把判定搬家)。
// * 同一轮试过的同类改动(**判题机中性或负,未采纳**):`packB2` 同样解分支(+0.11%/+0.02%)、
// `tiled2_128` 里把 `first` 固化成常量 1(+0.07%/−0.03%)、`packB2` 源行前瞻预取(+0.40%/+0.55%)。
// ================
#include <immintrin.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
#define MR 4
#define NCG 1
#define KC 128
#define MC 4
#define NC 128
#define NPAIR (KC / 2)
#define APSTR 560 /* 2048 B per row = 16 units x 128 B */
#define NR (8 * NCG)
#define BASE 128
typedef int32_t T;
#define AVX2 __attribute__((target("avx2")))
#define LD(p) _mm256_load_si256((const __m256i *)(p))
#define LDA(p) _mm256_load_si256((const __m256i *)(p))
#define STA(p, v) _mm256_store_si256((__m256i *)(p), (v))
#define ST(p, v) _mm256_store_si256((__m256i *)(p), (v))
static int32_t Apk[(MC + 4) * APSTR + 64] __attribute__((aligned(64)));
static int32_t Bpk[16896] __attribute__((aligned(64))); /* [jg][m][B0|B1] */
/* ===== mi2ap_:P 与前两级递归帧重指到调用方输出缓冲 C,并把私有 arena 的映射一并缩小 ===== */
static T *g_pool = 0; /* == C:深度-0 的重指池 */
static T *g_deep = 0; /* 最深一帧(h == BASE),留在 scr 内 */
static int g_rel = 0; /* 1 iff 本次调用启用重指与缩映射(仅顶层 n == 2048) */
/* MIKRO-BEGIN */
#define AVX2 __attribute__((target("avx2")))
AVX2 static inline __attribute__((always_inline)) void mikro(int npair, const int32_t *ap, const int32_t *bp,
int32_t *c, int ldc, int first) {
(void)npair;
static_assert(KC==128, "fixed packing kernel");
int groups=KC/8-1;
__m256i q0, q1, q2, q3;
__asm__ volatile(
"vmovdqu 0(%[bp]), %%ymm8\n\t" "vmovdqu 128(%[bp]), %%ymm9\n\t" "vpmaddwd 0(%[ap]), %%ymm8, %%ymm0\n\t" "vpmaddwd 2240(%[ap]), %%ymm8, %%ymm1\n\t" "vpmaddwd 4480(%[ap]), %%ymm8, %%ymm2\n\t" "vpmaddwd 6720(%[ap]), %%ymm8, %%ymm3\n\t" "vpmaddwd 64(%[ap]), %%ymm8, %%ymm4\n\t" "vpmaddwd 2304(%[ap]), %%ymm8, %%ymm5\n\t" "vpmaddwd 4544(%[ap]), %%ymm8, %%ymm6\n\t" "vpmaddwd 6784(%[ap]), %%ymm8, %%ymm7\n\t" "vpmaddwd 0(%[ap]), %%ymm9, %%ymm10\n\t" "vpmaddwd 2240(%[ap]), %%ymm9, %%ymm11\n\t" "vpmaddwd 4480(%[ap]), %%ymm9, %%ymm12\n\t" "vpmaddwd 6720(%[ap]), %%ymm9, %%ymm13\n\t" "vpaddd %%ymm10, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm11, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm12, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm13, %%ymm7, %%ymm7\n\t" "vmovdqu 32(%[bp]), %%ymm8\n\t" "vmovdqu 160(%[bp]), %%ymm9\n\t" "vpmaddwd 4(%[ap]), %%ymm8, %%ymm10\n\t" "vpmaddwd 2244(%[ap]), %%ymm8, %%ymm11\n\t" "vpmaddwd 4484(%[ap]), %%ymm8, %%ymm12\n\t" "vpmaddwd 6724(%[ap]), %%ymm8, %%ymm13\n\t" "vpaddd %%ymm10, %%ymm0, %%ymm0\n\t" "vpaddd %%ymm11, %%ymm1, %%ymm1\n\t" "vpaddd %%ymm12, %%ymm2, %%ymm2\n\t" "vpaddd %%ymm13, %%ymm3, %%ymm3\n\t" "vpmaddwd 68(%[ap]), %%ymm8, %%ymm14\n\t" "vpmaddwd 2308(%[ap]), %%ymm8, %%ymm15\n\t" "vpmaddwd 4548(%[ap]), %%ymm8, %%ymm10\n\t" "vpmaddwd 6788(%[ap]), %%ymm8, %%ymm11\n\t" "vpaddd %%ymm14, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm15, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm10, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm11, %%ymm7, %%ymm7\n\t" "vpmaddwd 4(%[ap]), %%ymm9, %%ymm12\n\t" "vpmaddwd 2244(%[ap]), %%ymm9, %%ymm13\n\t" "vpmaddwd 4484(%[ap]), %%ymm9, %%ymm14\n\t" "vpmaddwd 6724(%[ap]), %%ymm9, %%ymm15\n\t" "vpaddd %%ymm12, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm13, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm14, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm15, %%ymm7, %%ymm7\n\t" "vmovdqu 64(%[bp]), %%ymm8\n\t" "vmovdqu 192(%[bp]), %%ymm9\n\t" "vpmaddwd 8(%[ap]), %%ymm8, %%ymm10\n\t" "vpmaddwd 2248(%[ap]), %%ymm8, %%ymm11\n\t" "vpmaddwd 4488(%[ap]), %%ymm8, %%ymm12\n\t" "vpmaddwd 6728(%[ap]), %%ymm8, %%ymm13\n\t" "vpaddd %%ymm10, %%ymm0, %%ymm0\n\t" "vpaddd %%ymm11, %%ymm1, %%ymm1\n\t" "vpaddd %%ymm12, %%ymm2, %%ymm2\n\t" "vpaddd %%ymm13, %%ymm3, %%ymm3\n\t" "vpmaddwd 72(%[ap]), %%ymm8, %%ymm14\n\t" "vpmaddwd 2312(%[ap]), %%ymm8, %%ymm15\n\t" "vpmaddwd 4552(%[ap]), %%ymm8, %%ymm10\n\t" "vpmaddwd 6792(%[ap]), %%ymm8, %%ymm11\n\t" "vpaddd %%ymm14, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm15, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm10, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm11, %%ymm7, %%ymm7\n\t" "vpmaddwd 8(%[ap]), %%ymm9, %%ymm12\n\t" "vpmaddwd 2248(%[ap]), %%ymm9, %%ymm13\n\t" "vpmaddwd 4488(%[ap]), %%ymm9, %%ymm14\n\t" "vpmaddwd 6728(%[ap]), %%ymm9, %%ymm15\n\t" "vpaddd %%ymm12, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm13, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm14, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm15, %%ymm7, %%ymm7\n\t" "vmovdqu 96(%[bp]), %%ymm8\n\t" "vmovdqu 224(%[bp]), %%ymm9\n\t" "vpmaddwd 12(%[ap]), %%ymm8, %%ymm10\n\t" "vpmaddwd 2252(%[ap]), %%ymm8, %%ymm11\n\t" "vpmaddwd 4492(%[ap]), %%ymm8, %%ymm12\n\t" "vpmaddwd 6732(%[ap]), %%ymm8, %%ymm13\n\t" "vpaddd %%ymm10, %%ymm0, %%ymm0\n\t" "vpaddd %%ymm11, %%ymm1, %%ymm1\n\t" "vpaddd %%ymm12, %%ymm2, %%ymm2\n\t" "vpaddd %%ymm13, %%ymm3, %%ymm3\n\t" "vpmaddwd 76(%[ap]), %%ymm8, %%ymm14\n\t" "vpmaddwd 2316(%[ap]), %%ymm8, %%ymm15\n\t" "vpmaddwd 4556(%[ap]), %%ymm8, %%ymm10\n\t" "vpmaddwd 6796(%[ap]), %%ymm8, %%ymm11\n\t" "vpaddd %%ymm14, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm15, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm10, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm11, %%ymm7, %%ymm7\n\t" "vpmaddwd 12(%[ap]), %%ymm9, %%ymm12\n\t" "vpmaddwd 2252(%[ap]), %%ymm9, %%ymm13\n\t" "vpmaddwd 4492(%[ap]), %%ymm9, %%ymm14\n\t" "vpmaddwd 6732(%[ap]), %%ymm9, %%ymm15\n\t" "vpaddd %%ymm12, %%ymm4, %%ymm4\n\t" "vpaddd %%ymm13, %%ymm5, %%ymm5\n\t" "vpaddd %%ymm14, %%ymm6, %%ymm6\n\t" "vpaddd %%ymm15, %%ymm7, %%ymm7\n\t" "add $128, %[ap]\n\t"
"add $256, %[bp]\n\t"
".p2align 5\n\t"
"1:\n\t" "prefetcht0 768(%[bp])\n\t"
"vmovdqu 0(%[bp]), %%ymm8\n\t"
"vmovdqu 128(%[bp]), %%ymm9\n\t"
"vpmaddwd 64(%[ap]), %%ymm8, %%ymm14\n\t"
"vpmaddwd 2304(%[ap]), %%ymm8, %%ymm15\n\t"
"vpmaddwd 4544(%[ap]), %%ymm8, %%ymm10\n\t"
"vpmaddwd 6784(%[ap]), %%ymm8, %%ymm11\n\t"
"vpmaddwd 0(%[ap]), %%ymm9, %%ymm12\n\t"
"vpmaddwd 2240(%[ap]), %%ymm9, %%ymm13\n\t"
"vpaddd %%ymm14, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4480(%[ap]), %%ymm9, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6720(%[ap]), %%ymm9, %%ymm15\n\t"
"vmovdqu 192(%[bp]), %%ymm9\n\t"
"vpaddd %%ymm10, %%ymm6, %%ymm6\n\t"
"vpmaddwd 0(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2240(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4480(%[ap]), %%ymm8, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6720(%[ap]), %%ymm8, %%ymm13\n\t"
"vmovdqu 64(%[bp]), %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm6, %%ymm6\n\t"
"vpmaddwd 72(%[ap]), %%ymm8, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2312(%[ap]), %%ymm8, %%ymm15\n\t"
"vpaddd %%ymm10, %%ymm0, %%ymm0\n\t"
"vpmaddwd 4552(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm1, %%ymm1\n\t"
"vpmaddwd 6792(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm2, %%ymm2\n\t"
"vpmaddwd 8(%[ap]), %%ymm9, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm3, %%ymm3\n\t"
"vpmaddwd 2248(%[ap]), %%ymm9, %%ymm13\n\t"
"vpaddd %%ymm14, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4488(%[ap]), %%ymm9, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6728(%[ap]), %%ymm9, %%ymm15\n\t"
"vmovdqu 160(%[bp]), %%ymm9\n\t"
"vpaddd %%ymm10, %%ymm6, %%ymm6\n\t"
"vpmaddwd 8(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2248(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4488(%[ap]), %%ymm8, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6728(%[ap]), %%ymm8, %%ymm13\n\t"
"vmovdqu 32(%[bp]), %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm6, %%ymm6\n\t"
"vpmaddwd 68(%[ap]), %%ymm8, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2308(%[ap]), %%ymm8, %%ymm15\n\t"
"vpaddd %%ymm10, %%ymm0, %%ymm0\n\t"
"vpmaddwd 4548(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm1, %%ymm1\n\t"
"vpmaddwd 6788(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm2, %%ymm2\n\t"
"vpmaddwd 4(%[ap]), %%ymm9, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm3, %%ymm3\n\t"
"vpmaddwd 2244(%[ap]), %%ymm9, %%ymm13\n\t"
"vpaddd %%ymm14, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4484(%[ap]), %%ymm9, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6724(%[ap]), %%ymm9, %%ymm15\n\t"
"vmovdqu 224(%[bp]), %%ymm9\n\t"
"vpaddd %%ymm10, %%ymm6, %%ymm6\n\t"
"vpmaddwd 4(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2244(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4484(%[ap]), %%ymm8, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6724(%[ap]), %%ymm8, %%ymm13\n\t"
"vmovdqu 96(%[bp]), %%ymm8\n\t"
"vpaddd %%ymm14, %%ymm6, %%ymm6\n\t"
"vpmaddwd 76(%[ap]), %%ymm8, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2316(%[ap]), %%ymm8, %%ymm15\n\t"
"vpaddd %%ymm10, %%ymm0, %%ymm0\n\t"
"vpmaddwd 4556(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm1, %%ymm1\n\t"
"vpmaddwd 6796(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm2, %%ymm2\n\t"
"vpmaddwd 12(%[ap]), %%ymm9, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm3, %%ymm3\n\t"
"vpmaddwd 2252(%[ap]), %%ymm9, %%ymm13\n\t"
"vpaddd %%ymm14, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4492(%[ap]), %%ymm9, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6732(%[ap]), %%ymm9, %%ymm15\n\t"
"vpaddd %%ymm10, %%ymm6, %%ymm6\n\t"
"vpmaddwd 12(%[ap]), %%ymm8, %%ymm10\n\t"
"vpaddd %%ymm11, %%ymm7, %%ymm7\n\t"
"vpmaddwd 2252(%[ap]), %%ymm8, %%ymm11\n\t"
"vpaddd %%ymm12, %%ymm4, %%ymm4\n\t"
"vpmaddwd 4492(%[ap]), %%ymm8, %%ymm12\n\t"
"vpaddd %%ymm13, %%ymm5, %%ymm5\n\t"
"vpmaddwd 6732(%[ap]), %%ymm8, %%ymm13\n\t"
"vpaddd %%ymm14, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm10, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm11, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm12, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm13, %%ymm3, %%ymm3\n\t"
"add $128, %[ap]\n\t"
"add $256, %[bp]\n\t"
"sub $1, %[cnt]\n\t"
"jnz 1b\n\t"
"2:\n\t"
"vpslld $16, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm4, %%ymm0, %[q0]\n\t"
"vpslld $16, %%ymm5, %%ymm5\n\t"
"vpaddd %%ymm5, %%ymm1, %[q1]\n\t"
"vpslld $16, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm6, %%ymm2, %[q2]\n\t"
"vpslld $16, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm7, %%ymm3, %[q3]\n\t"
: [ap] "+r" (ap), [bp] "+r" (bp), [cnt] "+r" (groups),
[q0] "=x" (q0), [q1] "=x" (q1), [q2] "=x" (q2), [q3] "=x" (q3)
:
: "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm15", "memory"); /* ymm15 kept DECLARED on purpose -- see notes */
{ int32_t *cp = c;
if (first) {
_mm256_store_si256((__m256i *)(cp + (size_t)3 * ldc), q3);
_mm256_store_si256((__m256i *)(cp + (size_t)2 * ldc), q2);
_mm256_store_si256((__m256i *)(cp + (size_t)1 * ldc), q1);
_mm256_store_si256((__m256i *)(cp + (size_t)0 * ldc), q0);
} else {
int32_t *cpr3 = cp + (size_t)3 * ldc;
_mm256_store_si256((__m256i *)cpr3, _mm256_add_epi32(_mm256_load_si256((const __m256i *)cpr3), q3));
int32_t *cpr2 = cp + (size_t)2 * ldc;
_mm256_store_si256((__m256i *)cpr2, _mm256_add_epi32(_mm256_load_si256((const __m256i *)cpr2), q2));
int32_t *cpr1 = cp + (size_t)1 * ldc;
_mm256_store_si256((__m256i *)cpr1, _mm256_add_epi32(_mm256_load_si256((const __m256i *)cpr1), q1));
int32_t *cpr0 = cp + (size_t)0 * ldc;
_mm256_store_si256((__m256i *)cpr0, _mm256_add_epi32(_mm256_load_si256((const __m256i *)cpr0), q0));
} }
}
/* MIKRO-END */
/* ---- ld-aware packing + tiled macro-kernel (base case) ---- */
#pragma GCC push_options
#pragma GCC optimize("O2")
AVX2 static inline void packA2(int ic, int kk, int n, int lda, const T * __restrict A, int sg, const T * __restrict A2) {
const __m256i m16 = _mm256_set1_epi32(0xFFFF);
__m256i half = _mm256_set1_epi32(0x8000);
__asm__ volatile("" : "+x"(half));
/* 常量索引 -> vpermq 立即数 0x88 */
__m256i SHLO = _mm256_setr_epi8(0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13,0,1,4,5,8,9,12,13);
__m256i SHHI = _mm256_setr_epi8(2,3,6,7,10,11,14,15,2,3,6,7,10,11,14,15,2,3,6,7,10,11,14,15,2,3,6,7,10,11,14,15);
__asm__ volatile("" : "+x"(SHLO));
__asm__ volatile("" : "+x"(SHHI));
(void)n;
/* UNSWITCHED: the (A2!=0) and (sg>0) decisions are hoisted to the top so each
inner loop is branch-free and no source pointer has to live in an array.
Same stores, same order of arithmetic -> bit-identical panels. */
const size_t st = (size_t)lda;
const T *s0 = A + (size_t)ic * st + kk, *s1 = s0 + st, *s2 = s1 + st, *s3 = s2 + st;
#define PA_EMIT(RO, XV) \
do { __m256i rl = _mm256_permute4x64_epi64(_mm256_shuffle_epi8((XV), SHLO), 0x88); \
__m256i rh = _mm256_permute4x64_epi64( \
_mm256_shuffle_epi8(_mm256_add_epi32((XV), half), SHHI), 0x88); \
T *d = Apk + (size_t)(RO) * APSTR + 32 * u; \
ST(d + 0, rl); _mm_store_si128((__m128i *)(d + 8), _mm256_castsi256_si128(rl)); \
ST(d + 16, rh); _mm_store_si128((__m128i *)(d + 24), _mm256_castsi256_si128(rh)); } while (0)
if (A2) {
const T *t0 = A2 + (size_t)ic * st + kk, *t1 = t0 + st, *t2 = t1 + st, *t3 = t2 + st;
if (sg > 0) {
for (int u = 0; u < KC / 8; u++) {
PA_EMIT(0, _mm256_add_epi32(LD(s0 + 8 * u), LD(t0 + 8 * u)));
PA_EMIT(1, _mm256_add_epi32(LD(s1 + 8 * u), LD(t1 + 8 * u)));
PA_EMIT(2, _mm256_add_epi32(LD(s2 + 8 * u), LD(t2 + 8 * u)));
PA_EMIT(3, _mm256_add_epi32(LD(s3 + 8 * u), LD(t3 + 8 * u)));
}
} else {
for (int u = 0; u < KC / 8; u++) {
PA_EMIT(0, _mm256_sub_epi32(LD(s0 + 8 * u), LD(t0 + 8 * u)));
PA_EMIT(1, _mm256_sub_epi32(LD(s1 + 8 * u), LD(t1 + 8 * u)));
PA_EMIT(2, _mm256_sub_epi32(LD(s2 + 8 * u), LD(t2 + 8 * u)));
PA_EMIT(3, _mm256_sub_epi32(LD(s3 + 8 * u), LD(t3 + 8 * u)));
}
}
} else {
for (int u = 0; u < KC / 8; u++) {
PA_EMIT(0, LD(s0 + 8 * u)); PA_EMIT(1, LD(s1 + 8 * u));
PA_EMIT(2, LD(s2 + 8 * u)); PA_EMIT(3, LD(s3 + 8 * u));
}
}
#undef PA_EMIT
}
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize("O3")
AVX2 static inline void packB2(int jc, int kk, int n, int ldb, const T * __restrict B, int sg, const T * __restrict B2) {
const __m256i m16 = _mm256_set1_epi32(0xFFFF);
const __m256i half = _mm256_set1_epi32(0x8000);
(void)n;
const __m256i BLA = _mm256_setr_epi8(0,1,(char)0x80,(char)0x80,4,5,(char)0x80,(char)0x80,8,9,(char)0x80,(char)0x80,12,13,(char)0x80,(char)0x80,0,1,(char)0x80,(char)0x80,4,5,(char)0x80,(char)0x80,8,9,(char)0x80,(char)0x80,12,13,(char)0x80,(char)0x80);
const __m256i BLB = _mm256_setr_epi8((char)0x80,(char)0x80,0,1,(char)0x80,(char)0x80,4,5,(char)0x80,(char)0x80,8,9,(char)0x80,(char)0x80,12,13,(char)0x80,(char)0x80,0,1,(char)0x80,(char)0x80,4,5,(char)0x80,(char)0x80,8,9,(char)0x80,(char)0x80,12,13);
const __m256i BHA = _mm256_setr_epi8(2,3,(char)0x80,(char)0x80,6,7,(char)0x80,(char)0x80,10,11,(char)0x80,(char)0x80,14,15,(char)0x80,(char)0x80,2,3,(char)0x80,(char)0x80,6,7,(char)0x80,(char)0x80,10,11,(char)0x80,(char)0x80,14,15,(char)0x80,(char)0x80);
const __m256i BHB = _mm256_setr_epi8((char)0x80,(char)0x80,2,3,(char)0x80,(char)0x80,6,7,(char)0x80,(char)0x80,10,11,(char)0x80,(char)0x80,14,15,(char)0x80,(char)0x80,2,3,(char)0x80,(char)0x80,6,7,(char)0x80,(char)0x80,10,11,(char)0x80,(char)0x80,14,15);
for (int u = 0; u < NPAIR / 4; u++) {
const T *s = B + (size_t)(kk + 8 * u) * ldb + jc;
const T *t = B2 ? (B2 + (size_t)(kk + 8 * u) * ldb + jc) : 0;
for (int j = 0; j < NC; j += 8) {
T *d = Bpk + (size_t)(j / 8) * (NPAIR * 16 + 24) + (size_t)u * 64;
__m256i L0, L1, L2, L3, H0, H1, H2, H3;
#define F11_PAIR(P, LO, HI) \
{ const T *sp = s + (size_t)(2 * P) * ldb + j; \
__m256i x0 = LD(sp), x1 = LD(sp + ldb); \
if (t) { const T *tp = t + (size_t)(2 * P) * ldb + j; \
__m256i y0 = LD(tp), y1 = LD(tp + ldb); \
if (sg > 0) { x0 = _mm256_add_epi32(x0, y0); x1 = _mm256_add_epi32(x1, y1); } \
else { x0 = _mm256_sub_epi32(x0, y0); x1 = _mm256_sub_epi32(x1, y1); } } \
LO = _mm256_blend_epi16(x0,_mm256_slli_epi32(x1,16),0xaa); \
HI = _mm256_blend_epi16(_mm256_srli_epi32(_mm256_add_epi32(x0,half),16), \
_mm256_add_epi32(x1,half),0xaa); }
F11_PAIR(0, L0, H0)
F11_PAIR(1, L1, H1)
F11_PAIR(2, L2, H2)
F11_PAIR(3, L3, H3)
#undef F11_PAIR
{
__m256i a=_mm256_blend_epi32(H0,H2,0xcc),b=_mm256_blend_epi32(H0,H2,0x33);
__m256i c=_mm256_blend_epi32(H1,H3,0xcc),e=_mm256_blend_epi32(H1,H3,0x33);
ST(d+56,_mm256_blend_epi32(e,a,0xaa));
ST(d+48,_mm256_blend_epi32(b,e,0xaa));
ST(d+40,_mm256_blend_epi32(c,b,0xaa));
ST(d+32,_mm256_blend_epi32(a,c,0xaa));
}
{
__m256i a=_mm256_blend_epi32(L0,L2,0xcc),b=_mm256_blend_epi32(L0,L2,0x33);
__m256i c=_mm256_blend_epi32(L1,L3,0xcc),e=_mm256_blend_epi32(L1,L3,0x33);
ST(d+24,_mm256_blend_epi32(e,a,0xaa));
ST(d+16,_mm256_blend_epi32(b,e,0xaa));
ST(d+8,_mm256_blend_epi32(c,b,0xaa));
ST(d+0,_mm256_blend_epi32(a,c,0xaa));
}
}
}
}
#pragma GCC pop_options
AVX2 static inline __attribute__((always_inline)) void block_mikro(int ic, int jc, int n, int ldc, T *C, int first) {
T *cp0 = C + (size_t)ic * ldc + jc;
for (int r = 0; r < MC; r += MR) {
const int32_t *ap = Apk + (size_t)r * APSTR;
T *cp = cp0 + (size_t)r * ldc;
const int32_t *bp = Bpk;
for (int jg = 0; jg < NC; jg += NR) {
mikro(NPAIR, ap, bp, cp + jg, ldc, first);
bp += (NPAIR * 16 + 24);
}
}
}
/* LEAF SPECIALISED: with BASE==KC==NC==128 every tiled2 leaf call has h==128 and
ldc==h==128, so both become compile-time constants -> the jc/kk/ic loops fully fold. */
AVX2 static void tiled2_128(const T *A1, const T *A2, int sgA, int lda,
const T *B1, const T *B2, int sgB, int ldb, T *C) {
const int n = 128;
const int ldc = 128;
for (int jc = 0; jc < n; jc += NC) {
for (int kk = 0; kk < n; kk += KC) {
packB2(jc, kk, n, ldb, B1, sgB, B2);
for (int ic = n - MC; ic >= 0; ic -= MC) {
packA2(ic, kk, n, lda, A1, sgA, A2);
if (ic - MC >= 0) {
const T *n1 = A1 + (size_t)(ic - MC) * lda + kk;
const T *n2 = A2 ? (A2 + (size_t)(ic - MC) * lda + kk) : 0;
for (int r = 0; r < MC; r++) {
const T *p1 = n1 + (size_t)r * lda;
const T *p2 = n2 ? (n2 + (size_t)r * lda) : 0;
__builtin_prefetch(p1, 0, 2);
if (p2) __builtin_prefetch(p2, 0, 2);
}
}
block_mikro(ic, jc, n, ldc, C, kk == 0);
}
}
}
}
/* correct for any n, just slow */
AVX2 static void generic(int n, const T *A, int lda, const T *B, int ldb, T *C, int ldc) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
uint32_t s = 0;
for (int k = 0; k < n; k++)
s += (uint32_t)A[(size_t)i * lda + k] * (uint32_t)B[(size_t)k * ldb + j];
C[(size_t)i * ldc + j] = (T)s;
}
}
/* tiled base case: requires n % NC == 0, n % KC == 0, n >= MC */
AVX2 static void tiled(int n, const T *A, int lda, const T *B, int ldb, T *C, int ldc) {
/* C is fully written by the kk==0 pass (micro stores instead of RMWs) */
for (int jc = 0; jc < n; jc += NC) {
for (int kk = 0; kk < n; kk += KC) {
packB2(jc, kk, n, ldb, B, 1, (const T *)0);
for (int ic = 0; ic < n; ic += MC) {
packA2(ic, kk, n, lda, A, 1, (const T *)0);
block_mikro(ic, jc, n, ldc, C, kk == 0);
}
}
}
}
AVX2 static int ok_tiled(int n) {
return (n % NC) == 0 && (n % KC) == 0 && (n % MC) == 0 && (MC % MR) == 0 && (NC % NR) == 0;
}
/* ---- Strassen over Z/2^32. Exact: all ops are ring ops of Z/2^32. ---- */
#define STR_DEPTH 6
/* P = X + s*Y in ONE pass over h x h (replaces copyblk + axpy: one write instead of two) */
#pragma GCC push_options
#pragma GCC optimize("O3")
AVX2 static void addblk(int h, T * __restrict P, const T * __restrict X, int ldx, const T * __restrict Y, int ldy, int s) {
for (int i = 0; i < h; i++) {
const T *xp = X + (size_t)i * ldx, *yp = Y + (size_t)i * ldy;
T *pp = P + (size_t)i * h;
__builtin_prefetch(X + (size_t)(i+1)*ldx, 0, 3); __builtin_prefetch(Y + (size_t)(i+1)*ldy, 0, 3);
int j = 0;
if (s > 0) for (; j + 8 <= h; j += 8) STA(pp + j, _mm256_add_epi32(LDA(xp + j), LDA(yp + j)));
else for (; j + 8 <= h; j += 8) STA(pp + j, _mm256_sub_epi32(LDA(xp + j), LDA(yp + j)));
/* scalar tail removed: h is always a multiple of 8 (h = n/2, n a power of two >= 256);
mutate_blk in this engine already relies on the same invariant. */
}
}
#pragma GCC pop_options
#pragma GCC push_options
#pragma GCC optimize("O3")
template<int SA, int SB>
AVX2 static void addblk_pair(int h, T * __restrict P,
const T * __restrict A, int lda, const T * __restrict A2,
T * __restrict Q,
const T * __restrict B, int ldb, const T * __restrict B2) {
for (int i=0;i<h;i++) {
const T *a=A+(size_t)i*lda,*a2=A2+(size_t)i*lda;
const T *b=B+(size_t)i*ldb,*b2=B2+(size_t)i*ldb;
T *p=P+(size_t)i*h,*q=Q+(size_t)i*h;
__builtin_prefetch(a+lda,0,3); __builtin_prefetch(a2+lda,0,3);
__builtin_prefetch(b+ldb,0,3); __builtin_prefetch(b2+ldb,0,3);
for(int j=0;j<h;j+=8) {
__m256i x=LD(a+j), y=LD(a2+j), z=LD(b+j), w=LD(b2+j);
STA(p+j,SA>0?_mm256_add_epi32(x,y):_mm256_sub_epi32(x,y));
STA(q+j,SB>0?_mm256_add_epi32(z,w):_mm256_sub_epi32(z,w));
}
}
}
#pragma GCC pop_options
/* dst = s1*m1 + s2*m2 , ONE pass (M blocks are contiguous, row stride h) */
/* dst = s1*m1 + s2*m2 + s3*m3 + s4*m4 , ONE pass */
#define B11 (A)
#define B12 (A + h)
#define B21 (A + (size_t)h * lda)
#define B22 (A + (size_t)h * lda + h)
#define D11 (B)
#define D12 (B + h)
#define D21 (B + (size_t)h * ldb)
#define D22 (B + (size_t)h * ldb + h)
/* ---- FUSED combine: one pass instead of four (l_sub1pct) --------------------
The shipped rec() makes FOUR passes over the seven M blocks (12 block-reads
for 4 outputs: M1..M5 are each read twice). Holding the seven row vectors in
registers lets all four quadrants be formed from 7 loads, so the combine's
issue cost per 8 outputs goes 24 -> 19 uops and its read volume 12h^2 -> 7h^2.
Same stores, same NT form, byte-exact. */
#pragma GCC push_options
#pragma GCC optimize("O3")
AVX2 static void comb_all(int h, T * __restrict C, int ldc,
const T * __restrict M1, const T * __restrict M2, const T * __restrict M3, const T * __restrict M4,
const T * __restrict M5, const T * __restrict M6, const T * __restrict M7) {
for (int i = 0; i < h; i++) {
const T *a = M1 + (size_t)i * h, *b = M2 + (size_t)i * h, *c = M3 + (size_t)i * h,
*d = M4 + (size_t)i * h, *e = M5 + (size_t)i * h, *f = M6 + (size_t)i * h,
*g = M7 + (size_t)i * h;
T *d1 = C + (size_t)i * ldc, *d2 = d1 + h,
*d3 = d1 + (size_t)h * ldc, *d4 = d3 + h;
int j = 0;
for (; j + 16 <= h; j += 16) { /* [i2y_] 同上 */
{ const int jj = j;
__m256i m1=LDA(a+jj),m2=LDA(b+jj),m3=LDA(c+jj),m4=LDA(d+jj),
m5=LDA(e+jj),m6=LDA(f+jj),m7=LDA(g+jj);
__m256i r1=LDA(a+jj+8),r2=LDA(b+jj+8),r3=LDA(c+jj+8),r4=LDA(d+jj+8),
r5=LDA(e+jj+8),r6=LDA(f+jj+8),r7=LDA(g+jj+8);
_mm256_stream_si256((__m256i *)(d1+jj), _mm256_add_epi32(_mm256_sub_epi32(_mm256_add_epi32(m1,m4),m5),m7));
_mm256_stream_si256((__m256i *)(d1+jj+8), _mm256_add_epi32(_mm256_sub_epi32(_mm256_add_epi32(r1,r4),r5),r7));
_mm256_stream_si256((__m256i *)(d3+jj), _mm256_add_epi32(m2,m4));
_mm256_stream_si256((__m256i *)(d3+jj+8), _mm256_add_epi32(r2,r4));
_mm256_stream_si256((__m256i *)(d2+jj), _mm256_add_epi32(m3,m5));
_mm256_stream_si256((__m256i *)(d2+jj+8), _mm256_add_epi32(r3,r5));
_mm256_stream_si256((__m256i *)(d4+jj), _mm256_add_epi32(_mm256_sub_epi32(_mm256_add_epi32(m1,m3),m2),m6));
_mm256_stream_si256((__m256i *)(d4+jj+8), _mm256_add_epi32(_mm256_sub_epi32(_mm256_add_epi32(r1,r3),r2),r6));
}
}
for (; j + 8 <= h; j += 8) {
__m256i m1 = LDA(a + j), m2 = LDA(b + j), m3 = LDA(c + j), m4 = LDA(d + j),
m5 = LDA(e + j), m6 = LDA(f + j), m7 = LDA(g + j);
_mm256_stream_si256((__m256i *)(d1 + j),
_mm256_add_epi32(_mm256_sub_epi32(_mm256_add_epi32(m1, m4), m5), m7));
_mm256_stream_si256((__m256i *)(d2 + j), _mm256_add_epi32(m3, m5));
_mm256_stream_si256((__m256i *)(d3 + j), _mm256_add_epi32(m2, m4));
_mm256_stream_si256((__m256i *)(d4 + j),
_mm256_add_epi32(_mm256_sub_epi32(_mm256_add_epi32(m1, m3), m2), m6));
}
/* scalar tail removed: same invariant as above. */
}
}
#pragma GCC pop_options
AVX2 static void rec(int n, const T *A, int lda, const T *B, int ldb, T *C, int ldc,
T *scr, int depth) {
if (depth >= STR_DEPTH || (n & 1) || n <= BASE || !ok_tiled(n)) {
if (ok_tiled(n)) tiled(n, A, lda, B, ldb, C, ldc);
else generic(n, A, lda, B, ldb, C, ldc);
return;
}
const int h = n / 2;
const size_t h2 = (size_t)h * h;
T *S = scr; /* 7 result blocks M1..M7 then 2 scratch S blocks */
T *M1 = S, *M2 = M1 + h2 + 4608, *M3 = M2 + h2 + 4608, *M4 = M3 + h2 + 4608,
*M5 = M4 + h2 + 4608, *M6 = M5 + h2 + 4608, *M7 = M6 + h2 + 4608;
T *P = M7 + h2 + 4608; /* operand scratch block 1 (h x h, ldp = h) */
T *Q = P + h2 + 4608; /* operand scratch block 2 */
T *sub = Q + h2 + 4608; /* recursion arena */
/* Each of the 7 products uses an operand that is A1 (+/- A2) on the A side and
B1 (+/- B2) on the B side. When the children are LEAVES (h <= BASE) the summed
operand is consumed only by the packers, so we fuse the sum INTO the packer and
never materialise P/Q: that removes 2 of every 4 accesses per summed operand
element (addblk's write + the packer's read of it, replaced by a second load of
the original block, which is exactly what addblk did anyway). */
#define LOP(a1, a2, sgA, b1, b2, sgB, Mi) \
do { \
if (h <= BASE) { \
tiled2_128((a1), (a2), (sgA), lda, \
(b1), (b2), (sgB), ldb, (Mi)); \
} else { \
const T *pa = (a1); int la = lda; \
const T *pb = (b1); int lb = ldb; \
if ((a2) && (b2)) { \
addblk_pair<(sgA),(sgB)>(h,P,(a1),lda,(a2),Q,(b1),ldb,(b2)); \
pa=P; la=h; pb=Q; lb=h; \
} else { \
if (a2) { addblk(h,P,(a1),lda,(a2),lda,(sgA)); pa=P; la=h; } \
if (b2) { addblk(h,Q,(b1),ldb,(b2),ldb,(sgB)); pb=Q; lb=h; } \
} \
rec(h, pa, la, pb, lb, (Mi), h, sub, depth + 1); \
} \
} while (0)
LOP(B21, B11, -1, D11, D12, +1, M6); /* M6 = (A21-A11)(B11+B12) */
LOP(B21, B22, +1, D11, 0, +1, M2); /* M2 = (A21+A22) B11 */
LOP(B22, 0, +1, D21, D11, -1, M4); /* M4 = A22 (B21-B11) */
LOP(B11, B22, +1, D11, D22, +1, M1); /* M1 = (A11+A22)(B11+B22) */
LOP(B11, 0, +1, D12, D22, -1, M3); /* M3 = A11 (B12-B22) */
LOP(B11, B12, +1, D22, 0, +1, M5); /* M5 = (A11+A12) B22 */
LOP(B12, B22, -1, D21, D22, +1, M7); /* M7 = (A12-A22)(B21+B22) */
#undef LOP
/* C11 = M1 + M4 - M5 + M7 ; C12 = M3 + M5 ; C21 = M2 + M4 ; C22 = M1 - M2 + M3 + M6 */
comb_all(h, C, ldc, M1, M2, M3, M4, M5, M6, M7);
}
#undef B11
#undef B12
#undef B21
#undef B22
#undef D11
#undef D12
#undef D21
#undef D22
/* Update an already materialized S or T block without a separate copy.
[7] verbatim. */
#pragma GCC push_options
#pragma GCC optimize("O3")
AVX2 static void mutate_blk(int h, T *dst, const T *src, int lds, int reverse) {
for (int i=0;i<h;i++) {
T *d=dst+(size_t)i*h; const T *s=src+(size_t)i*lds;
if (reverse) {
for(int j=0;j<h;j+=8) STA(d+j,_mm256_sub_epi32(LDA(s+j),LDA(d+j)));
} else {
for(int j=0;j<h;j+=8) STA(d+j,_mm256_sub_epi32(LDA(d+j),LDA(s+j)));
}
}
}
AVX2 static void comb_win(int h, T *C, int ldc, const T *M1, const T *M2,
const T *M3, const T *M4, const T *M5,
const T *M6, const T *M7) {
for(int i=0;i<h;i++) {
const T *a=M1+(size_t)i*h,*b=M2+(size_t)i*h,*c=M3+(size_t)i*h,
*d=M4+(size_t)i*h,*e=M5+(size_t)i*h,*f=M6+(size_t)i*h,*g=M7+(size_t)i*h;
T *o11=C+(size_t)i*ldc,*o12=o11+h,*o21=o11+(size_t)h*ldc,*o22=o21+h;
int j=0;
for(;j+16<=h;j+=16) { /* [i2y_] 整条 64 B 线一次发完(每象限两条 32 B 存背靠背) */
{ const int jj=j;
__m256i p1=LDA(a+jj),p2=LDA(b+jj),p3=LDA(c+jj),p4=LDA(d+jj),
p5=LDA(e+jj),p6=LDA(f+jj),p7=LDA(g+jj);
__m256i q1=LDA(a+jj+8),q2=LDA(b+jj+8),q3=LDA(c+jj+8),q4=LDA(d+jj+8),
q5=LDA(e+jj+8),q6=LDA(f+jj+8),q7=LDA(g+jj+8);
__m256i u2=_mm256_add_epi32(p1,p6), u3=_mm256_add_epi32(u2,p7), u4=_mm256_add_epi32(u2,p5);
__m256i v2=_mm256_add_epi32(q1,q6), v3=_mm256_add_epi32(v2,q7), v4=_mm256_add_epi32(v2,q5);
_mm256_stream_si256((__m256i*)(o11+jj),_mm256_add_epi32(p1,p2));
_mm256_stream_si256((__m256i*)(o11+jj+8),_mm256_add_epi32(q1,q2));
_mm256_stream_si256((__m256i*)(o21+jj),_mm256_sub_epi32(u3,p4));
_mm256_stream_si256((__m256i*)(o21+jj+8),_mm256_sub_epi32(v3,q4));
_mm256_stream_si256((__m256i*)(o12+jj),_mm256_add_epi32(u4,p3));
_mm256_stream_si256((__m256i*)(o12+jj+8),_mm256_add_epi32(v4,q3));
_mm256_stream_si256((__m256i*)(o22+jj),_mm256_add_epi32(u3,p5));
_mm256_stream_si256((__m256i*)(o22+jj+8),_mm256_add_epi32(v3,q5));
}
}
for(;j<h;j+=8) {
__m256i p1=LDA(a+j),p2=LDA(b+j),p3=LDA(c+j),p4=LDA(d+j),
p5=LDA(e+j),p6=LDA(f+j),p7=LDA(g+j);
__m256i u2=_mm256_add_epi32(p1,p6);
__m256i u3=_mm256_add_epi32(u2,p7);
__m256i u4=_mm256_add_epi32(u2,p5);
_mm256_stream_si256((__m256i*)(o11+j),_mm256_add_epi32(p1,p2));
_mm256_stream_si256((__m256i*)(o12+j),_mm256_add_epi32(u4,p3));
_mm256_stream_si256((__m256i*)(o21+j),_mm256_sub_epi32(u3,p4));
_mm256_stream_si256((__m256i*)(o22+j),_mm256_add_epi32(u3,p5));
}
}
}
AVX2 static void comb_win_interleaved(int h, T *C, int ldc, const T *M1, const T *M2,
const T *M3, const T *M4, const T *M5,
const T *M6, const T *M7) {
for(int i=0;i<h;i++) {
const T *a=M1+(size_t)i*(7*h),*b=M2+(size_t)i*(7*h),*c=M3+(size_t)i*(7*h),
*d=M4+(size_t)i*(7*h),*e=M5+(size_t)i*(7*h),*f=M6+(size_t)i*(7*h),*g=M7+(size_t)i*(7*h);
T *o11=C+(size_t)i*ldc,*o12=o11+h,*o21=o11+(size_t)h*ldc,*o22=o21+h;
int j=0;
for(;j+16<=h;j+=16) { /* [i2y_] 整条 64 B 线一次发完(每象限两条 32 B 存背靠背) */
{ const int jj=j;
__m256i p1=LDA(a+jj),p2=LDA(b+jj),p3=LDA(c+jj),p4=LDA(d+jj),
p5=LDA(e+jj),p6=LDA(f+jj),p7=LDA(g+jj);
__m256i q1=LDA(a+jj+8),q2=LDA(b+jj+8),q3=LDA(c+jj+8),q4=LDA(d+jj+8),
q5=LDA(e+jj+8),q6=LDA(f+jj+8),q7=LDA(g+jj+8);
__m256i u2=_mm256_add_epi32(p1,p6), u3=_mm256_add_epi32(u2,p7), u4=_mm256_add_epi32(u2,p5);
__m256i v2=_mm256_add_epi32(q1,q6), v3=_mm256_add_epi32(v2,q7), v4=_mm256_add_epi32(v2,q5);
_mm256_stream_si256((__m256i*)(o11+jj),_mm256_add_epi32(p1,p2));
_mm256_stream_si256((__m256i*)(o11+jj+8),_mm256_add_epi32(q1,q2));
_mm256_stream_si256((__m256i*)(o21+jj),_mm256_sub_epi32(u3,p4));
_mm256_stream_si256((__m256i*)(o21+jj+8),_mm256_sub_epi32(v3,q4));
_mm256_stream_si256((__m256i*)(o12+jj),_mm256_add_epi32(u4,p3));
_mm256_stream_si256((__m256i*)(o12+jj+8),_mm256_add_epi32(v4,q3));
_mm256_stream_si256((__m256i*)(o22+jj),_mm256_add_epi32(u3,p5));
_mm256_stream_si256((__m256i*)(o22+jj+8),_mm256_add_epi32(v3,q5));
}
}
for(;j<h;j+=8) {
__m256i p1=LDA(a+j),p2=LDA(b+j),p3=LDA(c+j),p4=LDA(d+j),
p5=LDA(e+j),p6=LDA(f+j),p7=LDA(g+j);
__m256i u2=_mm256_add_epi32(p1,p6);
__m256i u3=_mm256_add_epi32(u2,p7);
__m256i u4=_mm256_add_epi32(u2,p5);
_mm256_stream_si256((__m256i*)(o11+j),_mm256_add_epi32(p1,p2));
_mm256_stream_si256((__m256i*)(o12+j),_mm256_add_epi32(u4,p3));
_mm256_stream_si256((__m256i*)(o21+j),_mm256_sub_epi32(u3,p4));
_mm256_stream_si256((__m256i*)(o22+j),_mm256_add_epi32(u3,p5));
}
}
}
#pragma GCC pop_options
AVX2 static void rec_w(int n, const T *A, int lda, const T *B, int ldb,
T *C, int ldc, T *scr, int depth) {
if (n<=256 || depth>=STR_DEPTH || (n&1) || !ok_tiled(n)) {
rec(n,A,lda,B,ldb,C,ldc,scr,depth); return;
}
const int h=n/2; const size_t h2=(size_t)h*h;
T *M1=scr,*M2=M1+h2+4608,*M3=M2+h2+4608,*M4=M3+h2+4608,
*M5=M4+h2+4608,*M6=M5+h2+4608,*M7=M6+h2+4608;
T *P=M7+h2+4608,*Q=P+h2+4608,*sub=Q+h2+4608;
const bool interleaved = (depth == 0 && n == 2048);
if (interleaved) {
M1=scr; M2=M1+h; M3=M2+h; M4=M3+h; M5=M4+h; M6=M5+h; M7=M6+h;
P=scr+7*h2+7*4608; Q=P+h2+4608; sub=Q+h2+4608;
if (g_rel) { /* mi2ap_: P 与 L1/L2 帧进池;Q 紧跟 M 区;最深一帧在 g_deep */
P = g_pool; Q = scr + 7*h2; sub = g_pool + h2;
}
} else if (g_rel && depth == 2) {
sub = g_deep;
}
const int mld=interleaved?7*h:h;
const T *A11=A,*A12=A+h,*A21=A+(size_t)h*lda,*A22=A21+h;
const T *B11=B,*B12=B+h,*B21=B+(size_t)h*ldb,*B22=B21+h;
rec_w(h,A12,lda,B21,ldb,M2,mld,sub,depth+1); // P2
rec_w(h,A11,lda,B11,ldb,M1,mld,sub,depth+1); // P1
addblk(h,Q,B12,ldb,B11,ldb,-1); // T1 [mi2au_ ord-1: 第一对对调]
addblk(h,P,A21,lda,A22,lda,+1); // S1
rec_w(h,P,h,Q,h,M5,mld,sub,depth+1); // P5
mutate_blk(h,P,A11,lda,0); // S2 = S1-A11
mutate_blk(h,Q,B22,ldb,1); // T2 = B22-T1
rec_w(h,P,h,Q,h,M6,mld,sub,depth+1); // P6
mutate_blk(h,P,A12,lda,1); // S4 = A12-S2
mutate_blk(h,Q,B21,ldb,0); // T4 = T2-B21
rec_w(h,A22,lda,Q,h,M4,mld,sub,depth+1); // P4
rec_w(h,P,h,B22,ldb,M3,mld,sub,depth+1); // P3
addblk(h,Q,B22,ldb,B12,ldb,-1); // T3
addblk(h,P,A11,lda,A21,lda,-1); // S3
rec_w(h,P,h,Q,h,M7,mld,sub,depth+1); // P7
if(interleaved) comb_win_interleaved(h,C,ldc,M1,M2,M3,M4,M5,M6,M7);
else comb_win(h,C,ldc,M1,M2,M3,M4,M5,M6,M7);
}
AVX2 void matrix_multiply(int n, const T *A, const T *B, T *C) {
unsigned long long al = (unsigned long long)(size_t)A | (unsigned long long)(size_t)B | (unsigned long long)(size_t)C;
if (n <= BASE || !ok_tiled(n) || (al & 31)) {
if (ok_tiled(n) && !(al & 31)) tiled(n, A, n, B, n, C, n);
else generic(n, A, n, B, n, C, n);
return;
}
/* depth-first arena: 9 h^2 blocks at each level along the path */
size_t need = 0, h = (size_t)n;
while (h > (size_t)BASE) { h /= 2; need += 9 * (h * h + 4608); }
const int rel = (n == 2048);
size_t need_alloc = need;
if (rel) { /* mi2ap_: [7h^2][Q][最深一帧] */
const size_t h0 = (size_t)n / 2;
need_alloc = 7*h0*h0 + (h0*h0 + 4608) + 9*((size_t)BASE*BASE + 4608);
}
static T *scr = 0; static size_t cap = 0;
if (need_alloc > cap) { if (scr) free(scr); cap = need_alloc + 1;
void *pv = 0; if (posix_memalign(&pv, 2097152, cap * sizeof(T))) return; scr = (T *)pv; (void)madvise(scr,(cap*sizeof(T))&~size_t(4095),MADV_HUGEPAGE); }
g_rel = rel;
if (rel) {
const size_t h0 = (size_t)n / 2;
g_pool = C;
g_deep = scr + 7*h0*h0 + (h0*h0 + 4608);
}
rec_w(n, A, n, B, n, C, n, scr, 0);
}
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 241.733 ms | 48 MB + 564 KB | Accepted | Score: 100 | 显示更多 |