// ===== REFERENCES =====
// [1] duck.ac 用户 saffah_codex_6s_agg2,提交 #105778
// <https://duck.ac/submission/105778>(11.864668 ms)—— 本文件正文的基座:
// 本文件 = 该提交正文**只改 B 微块预取指令的 hint/位置**(一处 token 级改动)。
// [2] 本账号(saffah_cc_v41_agg1),提交 #105545
// <https://duck.ac/submission/105545>(11.927623 ms)—— [1] 的正文基座(我方 B 侧 k 步长 4),
// 其谱系引用(#104306 / #103100 / pdoom #86352)随 [1] 一并保留在正文注释里。
// [3] 本账号(saffah_cc_v41_agg1),提交 #105818 <https://duck.ac/submission/105818>
// (11.855965 ms,`work/fs_rv778.cpp`)—— 本账号已落地的换基座件;其正文与 [1] **逐字节相同**
// (本发文末相同、只多本刀的 2 处 token),是本刀落地的**当前最好件**。
// [4] 本工作区非提交工件 `problems/mmms1k/work/fs2_ms1_pfsweep.py`(本刀的候选选择台,5 臂 × 4 轮交错)。
// ======================
// ===== 思路 =====
// 【试验性提交】单变量:微块内层循环的 **预取语义**。
// 现状:[1] 在 `micro24` 的入口与内层循环头部各有一条 `prefetchnta 384(%[b])`
// (384 B = 恰好一次循环迭代的 b 前进量 `add $384, %[b]`)。
// ★ 本发唯一改动:`prefetchnta` → `prefetcht0`(两条同改),其余一字不动。
// 机理(为什么预期为正):mikro 是**每个 4 行 i-block 被调一次、j 面板复用**——
// 同一条 B 微块行会在**后续 i-block 里再次被读**。`prefetchnta` 的语义是"该行即将失效、
// 尽早驱逐"(non-temporal),也就是把**马上要发生的复用**提前扔掉;
// `prefetcht0` 保留正常 LRU 语义 ⇒ 复用时命中 L1/L2。
// 【定价】判题机 in-situ:本刀的局部读数在**加载很重的本机**上为 −3.3%(`a64` 臂 −1.0%),
// 但按 `§2.18.906`(内存/落位类轴的本地读数**不能定符号**),**符号与幅度以本发判题机读数为准**。
// 正确性:只改预取 hint,不触碰任何数据路径;`mx_chk` n=256/512/1024 三查全 0、
// FNV 与 #105545 逐位相同(`5996794521752134075`),`tools/gcc93check.py` COMPILE OK。
// ================
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2")
#include <immintrin.h>
#include <stdint.h>
#include <string.h>
#ifndef BASE
#define BASE 64
#endif
using U = uint16_t;
alignas(32) static const unsigned char single_shuffle_mask[32] = {0,1,4,5,8,9,12,13,128,128,128,128,128,128,128,128,0,1,4,5,8,9,12,13,128,128,128,128,128,128,128,128};
static constexpr int MAXN = 1024;
alignas(4096) static U pa_[MAXN * MAXN + 8192], pb_[MAXN * MAXN + 8192];
alignas(4096) static U pc_[MAXN * MAXN + 8192], ws_[MAXN * MAXN + 8192];
static U *pa = pa_ + 0, *pb = pb_ + 0, *pc = pc_ + 0, *ws = ws_ + 1024;
static inline __m256i ld(const U *p) {
return _mm256_load_si256((const __m256i *)p);
}
static inline void st(U *p, __m256i x) {
_mm256_store_si256((__m256i *)p, x);
}
// The recursive quadrant layout makes every Strassen addition contiguous.
static void pack(U *d, const U *s, int n, int stride, bool right) {
if (n > BASE) {
int h = n / 2, q = h * h;
pack(d, s, h, stride, right);
pack(d + q, s + h, h, stride, right);
pack(d + 2*q, s + h*stride, h, stride, right);
pack(d + 3*q, s + h*stride + h, h, stride, right);
} else if (!right) {
/* 每次读 8 字节 = 4 个 k(2 个 k-pair),两个 k-pair 的输出都由这一组 load 得到:
低 64 位 = k-pair p;高 64 位 = k-pair p+1 ⇒ 每 2 个 k-pair 只付 4 条 load、2 条 unpacklo_epi32。 */
for(int i=0;i<n;i+=4) for(int k=0;k<n;k+=4) {
__m128i a0=_mm_loadl_epi64((const __m128i*)(s+(i+0)*stride+k));
__m128i a1=_mm_loadl_epi64((const __m128i*)(s+(i+1)*stride+k));
__m128i a2=_mm_loadl_epi64((const __m128i*)(s+(i+2)*stride+k));
__m128i a3=_mm_loadl_epi64((const __m128i*)(s+(i+3)*stride+k));
__m128i t01=_mm_unpacklo_epi32(a0,a1), t23=_mm_unpacklo_epi32(a2,a3);
_mm_stream_si128((__m128i*)d, _mm_unpacklo_epi64(t01,t23));
_mm_stream_si128((__m128i*)(d+8),_mm_unpackhi_epi64(t01,t23));
d+=16;
}
} else {
/* B 侧叶:一次处理 4 行(k 步长 2→4)⇒ 每趟 4 条 16 B 载入同时在飞(原来只有 2 条)。
输出寻址推导:某 (k,t) 对的输出块在 `((k/2)*(w/8) + t/8)*16` 元素处;
故行 k,k+1 的块在 `db`、行 k+2,k+3 的块在 `db + (w/8)*16`,两者每 t 步各 +16。 */
for(int j=0;j<n;) {
int w=n-j>=24?24:n-j;
U *db=d;
for(int k=0;k<n;k+=4) {
U *dp=db, *dp2=db+(size_t)(w/8)*16;
for(int t=0;t<w;t+=8) {
__m128i x=_mm_load_si128((const __m128i*)(s+(size_t)k*stride+j+t));
__m128i y=_mm_load_si128((const __m128i*)(s+(size_t)(k+1)*stride+j+t));
__m128i z=_mm_load_si128((const __m128i*)(s+(size_t)(k+2)*stride+j+t));
__m128i u=_mm_load_si128((const __m128i*)(s+(size_t)(k+3)*stride+j+t));
__m128i lo=_mm_unpacklo_epi16(x,y),hi=_mm_unpackhi_epi16(x,y);
__m128i lo2=_mm_unpacklo_epi16(z,u),hi2=_mm_unpackhi_epi16(z,u);
_mm_stream_si128((__m128i*)dp,lo);
_mm_stream_si128((__m128i*)(dp+8),hi);
_mm_stream_si128((__m128i*)dp2,lo2);
_mm_stream_si128((__m128i*)(dp2+8),hi2);
dp+=16; dp2+=16;
}
db+=(size_t)(w/8)*32;
}
d+=(size_t)(w/8)*16*(size_t)(n/2); /* 本 j 组共 n/2 个 k-pair 组 × (w/8) 块 × 16 元素 */
j+=w;
}
}
}
static void unpack(U *d, const U *s, int n, int stride) {
if (n > BASE) {
int h = n/2, q = h*h;
unpack(d,s,h,stride);
unpack(d+h,s+q,h,stride);
unpack(d+h*stride,s+2*q,h,stride);
unpack(d+h*stride+h,s+3*q,h,stride);
} else {
for (int i=0;i<n;++i) {
U *dp = d + (size_t)i*stride; const U *sp = s + (size_t)i*n;
int k=0;
for (;k+32<=n;k+=32) {
_mm256_stream_si256((__m256i*)(dp+k), _mm256_load_si256((const __m256i*)(sp+k)));
_mm256_stream_si256((__m256i*)(dp+k+16), _mm256_load_si256((const __m256i*)(sp+k+16)));
}
for (;k<n;k+=16) _mm256_storeu_si256((__m256i*)(dp+k), _mm256_loadu_si256((const __m256i*)(sp+k)));
}
}
}
static inline void micro24(const U *a,const U *b,U *c,int n) {
const U *end=a+4*n; U *c3=c+3*n; intptr_t stride=2*n;
asm volatile(
"prefetcht0 384(%[b])\n\t"
"vmovdqa 0(%[b]), %%ymm12\n\t"
"vmovdqa 32(%[b]), %%ymm13\n\t"
"vpbroadcastd 0(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm1\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm2\n\t"
"vpbroadcastd 4(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm4\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm5\n\t"
"vpbroadcastd 8(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm7\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm8\n\t"
"vpbroadcastd 12(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm10\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm11\n\t"
"vmovdqa 96(%[b]), %%ymm12\n\t"
"vmovdqa 128(%[b]), %%ymm13\n\t"
"vpbroadcastd 16(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 20(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 24(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 28(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqa 192(%[b]), %%ymm12\n\t"
"vmovdqa 224(%[b]), %%ymm13\n\t"
"vpbroadcastd 32(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 36(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 40(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 44(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqa 288(%[b]), %%ymm12\n\t"
"vmovdqa 320(%[b]), %%ymm13\n\t"
"vpbroadcastd 48(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 52(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 56(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 60(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"add $64, %[a]\n\t"
"add $384, %[b]\n\t"
"cmp %[end], %[a]\n\t"
"jae 2f\n\t"
".p2align 4\n\t"
"1:\n\t"
"prefetcht0 384(%[b])\n\t"
"vmovdqa 0(%[b]), %%ymm12\n\t"
"vmovdqa 32(%[b]), %%ymm13\n\t"
"vpbroadcastd 0(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 4(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 8(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 12(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 64(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqa 96(%[b]), %%ymm12\n\t"
"vmovdqa 128(%[b]), %%ymm13\n\t"
"vpbroadcastd 16(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 20(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 24(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 28(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 160(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqa 192(%[b]), %%ymm12\n\t"
"vmovdqa 224(%[b]), %%ymm13\n\t"
"vpbroadcastd 32(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 36(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 40(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 44(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 256(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"vmovdqa 288(%[b]), %%ymm12\n\t"
"vmovdqa 320(%[b]), %%ymm13\n\t"
"vpbroadcastd 48(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpaddd %%ymm14, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 52(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 56(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm7, %%ymm7\n\t"
"vpaddd %%ymm14, %%ymm8, %%ymm8\n\t"
"vpbroadcastd 60(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm9, %%ymm9\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm15\n\t"
"vpmaddwd 352(%[b]), %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm10, %%ymm10\n\t"
"vpaddd %%ymm14, %%ymm11, %%ymm11\n\t"
"add $64, %[a]\n\t"
"add $384, %[b]\n\t"
"cmp %[end], %[a]\n\t"
"jb 1b\n\t"
"2:\n\t"
"vpcmpeqd %%ymm13, %%ymm13, %%ymm13\n\t"
"vpsrld $16, %%ymm13, %%ymm13\n\t"
"vmovdqa %[shuf], %%ymm12\n\t"
"vpand %%ymm13, %%ymm0, %%ymm0\n\t"
"vpand %%ymm13, %%ymm1, %%ymm1\n\t"
"vpackusdw %%ymm1, %%ymm0, %%ymm0\n\t"
"vpermq $216, %%ymm0, %%ymm0\n\t"
"vmovdqu %%ymm0, 0(%[c])\n\t"
"vpshufb %%ymm12, %%ymm2, %%ymm2\n\t"
"vpermq $216, %%ymm2, %%ymm2\n\t"
"vmovdqu %%xmm2, 32(%[c])\n\t"
"vpand %%ymm13, %%ymm3, %%ymm3\n\t"
"vpand %%ymm13, %%ymm4, %%ymm4\n\t"
"vpackusdw %%ymm4, %%ymm3, %%ymm3\n\t"
"vpermq $216, %%ymm3, %%ymm3\n\t"
"vmovdqu %%ymm3, 0(%[c],%[s],1)\n\t"
"vpshufb %%ymm12, %%ymm5, %%ymm5\n\t"
"vpermq $216, %%ymm5, %%ymm5\n\t"
"vmovdqu %%xmm5, 32(%[c],%[s],1)\n\t"
"vpand %%ymm13, %%ymm6, %%ymm6\n\t"
"vpand %%ymm13, %%ymm7, %%ymm7\n\t"
"vpackusdw %%ymm7, %%ymm6, %%ymm6\n\t"
"vpermq $216, %%ymm6, %%ymm6\n\t"
"vmovdqu %%ymm6, 0(%[c],%[s],2)\n\t"
"vpshufb %%ymm12, %%ymm8, %%ymm8\n\t"
"vpermq $216, %%ymm8, %%ymm8\n\t"
"vmovdqu %%xmm8, 32(%[c],%[s],2)\n\t"
"vpand %%ymm13, %%ymm9, %%ymm9\n\t"
"vpand %%ymm13, %%ymm10, %%ymm10\n\t"
"vpackusdw %%ymm10, %%ymm9, %%ymm9\n\t"
"vpermq $216, %%ymm9, %%ymm9\n\t"
"vmovdqu %%ymm9, 0(%[c3])\n\t"
"vpshufb %%ymm12, %%ymm11, %%ymm11\n\t"
"vpermq $216, %%ymm11, %%ymm11\n\t"
"vmovdqu %%xmm11, 32(%[c3])\n\t"
: [a] "+&r"(a), [b] "+&r"(b)
: [c] "r"(c), [c3] "r"(c3), [s] "r"(stride), [end] "r"(end), [shuf] "m"(single_shuffle_mask)
: "cc", "memory", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15");
}
static inline void micro16(const U *a,const U *b,U *c,int n) {
const U *end=a+4*n; U *c3=c+3*n; intptr_t stride=2*n;
asm volatile(
"vmovdqa 0(%[b]), %%ymm12\n\t"
"vmovdqa 32(%[b]), %%ymm13\n\t"
"vpbroadcastd 0(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm0\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm1\n\t"
"vpbroadcastd 4(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm2\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm3\n\t"
"vpbroadcastd 8(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm4\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm5\n\t"
"vpbroadcastd 12(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm6\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm7\n\t"
"vmovdqa 64(%[b]), %%ymm12\n\t"
"vmovdqa 96(%[b]), %%ymm13\n\t"
"vpbroadcastd 16(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 20(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 24(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 28(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqa 128(%[b]), %%ymm12\n\t"
"vmovdqa 160(%[b]), %%ymm13\n\t"
"vpbroadcastd 32(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 36(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 40(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 44(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqa 192(%[b]), %%ymm12\n\t"
"vmovdqa 224(%[b]), %%ymm13\n\t"
"vpbroadcastd 48(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 52(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 56(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 60(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"add $64, %[a]\n\t"
"add $256, %[b]\n\t"
"cmp %[end], %[a]\n\t"
"jae 2f\n\t"
".p2align 3\n\t"
"1:\n\t"
"vmovdqa 0(%[b]), %%ymm12\n\t"
"vmovdqa 32(%[b]), %%ymm13\n\t"
"vpbroadcastd 0(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 4(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 8(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 12(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqa 64(%[b]), %%ymm12\n\t"
"vmovdqa 96(%[b]), %%ymm13\n\t"
"vpbroadcastd 16(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 20(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 24(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 28(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqa 128(%[b]), %%ymm12\n\t"
"vmovdqa 160(%[b]), %%ymm13\n\t"
"vpbroadcastd 32(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 36(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 40(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 44(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"vmovdqa 192(%[b]), %%ymm12\n\t"
"vmovdqa 224(%[b]), %%ymm13\n\t"
"vpbroadcastd 48(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpaddd %%ymm14, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 52(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpaddd %%ymm14, %%ymm3, %%ymm3\n\t"
"vpbroadcastd 56(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm4, %%ymm4\n\t"
"vpaddd %%ymm14, %%ymm5, %%ymm5\n\t"
"vpbroadcastd 60(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpmaddwd %%ymm13, %%ymm14, %%ymm14\n\t"
"vpaddd %%ymm15, %%ymm6, %%ymm6\n\t"
"vpaddd %%ymm14, %%ymm7, %%ymm7\n\t"
"add $64, %[a]\n\t"
"add $256, %[b]\n\t"
"cmp %[end], %[a]\n\t"
"jb 1b\n\t"
"2:\n\t"
"vpcmpeqd %%ymm13, %%ymm13, %%ymm13\n\t"
"vpsrld $16, %%ymm13, %%ymm13\n\t"
"vpand %%ymm13, %%ymm0, %%ymm0\n\t"
"vpand %%ymm13, %%ymm1, %%ymm1\n\t"
"vpackusdw %%ymm1, %%ymm0, %%ymm0\n\t"
"vpermq $216, %%ymm0, %%ymm0\n\t"
"vmovdqu %%ymm0, 0(%[c])\n\t"
"vpand %%ymm13, %%ymm2, %%ymm2\n\t"
"vpand %%ymm13, %%ymm3, %%ymm3\n\t"
"vpackusdw %%ymm3, %%ymm2, %%ymm2\n\t"
"vpermq $216, %%ymm2, %%ymm2\n\t"
"vmovdqu %%ymm2, 0(%[c],%[s],1)\n\t"
"vpand %%ymm13, %%ymm4, %%ymm4\n\t"
"vpand %%ymm13, %%ymm5, %%ymm5\n\t"
"vpackusdw %%ymm5, %%ymm4, %%ymm4\n\t"
"vpermq $216, %%ymm4, %%ymm4\n\t"
"vmovdqu %%ymm4, 0(%[c],%[s],2)\n\t"
"vpand %%ymm13, %%ymm6, %%ymm6\n\t"
"vpand %%ymm13, %%ymm7, %%ymm7\n\t"
"vpackusdw %%ymm7, %%ymm6, %%ymm6\n\t"
"vpermq $216, %%ymm6, %%ymm6\n\t"
"vmovdqu %%ymm6, 0(%[c3])\n\t"
: [a] "+&r"(a), [b] "+&r"(b)
: [c] "r"(c), [c3] "r"(c3), [s] "r"(stride), [end] "r"(end)
: "cc", "memory", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15");
}
static inline void micro8(const U *a,const U *b,U *c,int n) {
const U *end=a+4*n; U *c3=c+3*n; intptr_t stride=2*n;
asm volatile(
"vmovdqa 0(%[b]), %%ymm12\n\t"
"vpbroadcastd 0(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm0\n\t"
"vpbroadcastd 4(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm1\n\t"
"vpbroadcastd 8(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm2\n\t"
"vpbroadcastd 12(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm3\n\t"
"vmovdqa 32(%[b]), %%ymm12\n\t"
"vpbroadcastd 16(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 20(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 24(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 28(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vmovdqa 64(%[b]), %%ymm12\n\t"
"vpbroadcastd 32(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 36(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 40(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 44(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vmovdqa 96(%[b]), %%ymm12\n\t"
"vpbroadcastd 48(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 52(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 56(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 60(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"add $64, %[a]\n\t"
"add $128, %[b]\n\t"
"cmp %[end], %[a]\n\t"
"jae 2f\n\t"
".p2align 5\n\t"
"1:\n\t"
"vmovdqa 0(%[b]), %%ymm12\n\t"
"vpbroadcastd 0(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 4(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 8(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 12(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vmovdqa 32(%[b]), %%ymm12\n\t"
"vpbroadcastd 16(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 20(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 24(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 28(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vmovdqa 64(%[b]), %%ymm12\n\t"
"vpbroadcastd 32(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 36(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 40(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 44(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"vmovdqa 96(%[b]), %%ymm12\n\t"
"vpbroadcastd 48(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm0, %%ymm0\n\t"
"vpbroadcastd 52(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm1, %%ymm1\n\t"
"vpbroadcastd 56(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm2, %%ymm2\n\t"
"vpbroadcastd 60(%[a]), %%ymm14\n\t"
"vpmaddwd %%ymm12, %%ymm14, %%ymm15\n\t"
"vpaddd %%ymm15, %%ymm3, %%ymm3\n\t"
"add $64, %[a]\n\t"
"add $128, %[b]\n\t"
"cmp %[end], %[a]\n\t"
"jb 1b\n\t"
"2:\n\t"
"vpcmpeqd %%ymm13, %%ymm13, %%ymm13\n\t"
"vpsrld $16, %%ymm13, %%ymm13\n\t"
"vpand %%ymm13, %%ymm0, %%ymm0\n\t"
"vpackusdw %%ymm0, %%ymm0, %%ymm0\n\t"
"vpermq $216, %%ymm0, %%ymm0\n\t"
"vmovdqu %%xmm0, 0(%[c])\n\t"
"vpand %%ymm13, %%ymm1, %%ymm1\n\t"
"vpackusdw %%ymm1, %%ymm1, %%ymm1\n\t"
"vpermq $216, %%ymm1, %%ymm1\n\t"
"vmovdqu %%xmm1, 0(%[c],%[s],1)\n\t"
"vpand %%ymm13, %%ymm2, %%ymm2\n\t"
"vpackusdw %%ymm2, %%ymm2, %%ymm2\n\t"
"vpermq $216, %%ymm2, %%ymm2\n\t"
"vmovdqu %%xmm2, 0(%[c],%[s],2)\n\t"
"vpand %%ymm13, %%ymm3, %%ymm3\n\t"
"vpackusdw %%ymm3, %%ymm3, %%ymm3\n\t"
"vpermq $216, %%ymm3, %%ymm3\n\t"
"vmovdqu %%xmm3, 0(%[c3])\n\t"
: [a] "+&r"(a), [b] "+&r"(b)
: [c] "r"(c), [c3] "r"(c3), [s] "r"(stride), [end] "r"(end)
: "cc", "memory", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15");
}
static void base(const U *a,const U *b,U *c,int n) {
int j=0;
for(;j+24<=n;j+=24)
for(int i=0;i<n;i+=4) micro24(a+i*n,b+j*n,c+i*n+j,n);
if(n-j==16)
for(int i=0;i<n;i+=4) micro16(a+i*n,b+j*n,c+i*n+j,n);
if(n-j==8)
for(int i=0;i<n;i+=4) micro8(a+i*n,b+j*n,c+i*n+j,n);
}
template<bool Sub>
static inline void combine(U *d,const U *a,const U *b,int len) {
for(int i=0;i<len;i+=16) {
__m256i x=ld(a+i),y=ld(b+i);
st(d+i,Sub?_mm256_sub_epi16(x,y):_mm256_add_epi16(x,y));
}
}
// Strassen-Winograd: seven products, fifteen additions, two temporaries.
// All operations are in Z/(2^16); truncation never changes the answer.
static void mul_sub(const U *a,const U *b,U *c,int n,U *work,const U *ysub);
static void mul(const U *a,const U *b,U *c,int n,U *work) {
if(n<=BASE) { base(a,b,c,n); return; }
int h=n/2,q=h*h;
const U *a11=a,*a12=a+q,*a21=a+2*q,*a22=a+3*q;
const U *b11=b,*b12=b+q,*b21=b+2*q,*b22=b+3*q;
U *c11=c,*c12=c+q,*c21=c+2*q,*c22=c+3*q;
U *x=work,*y=work+q,*next=work+2*q;
combine<true>(x,a11,a21,q);
combine<true>(y,b22,b12,q);
mul(x,y,c21,h,next); // P7
combine<false>(x,a21,a22,q);
combine<true>(y,b12,b11,q);
mul(x,y,c22,h,next); // P5
combine<true>(x,x,a11,q);
combine<true>(y,b22,y,q);
mul(x,y,c12,h,next); // P6
combine<true>(x,a12,x,q);
mul(x,b22,c11,h,next); // P3
combine<true>(y,y,b21,q);
mul(a22,y,x,h,next); // P4
mul(a11,b11,y,h,next); // P1
for(int i=0;i<q;i+=16) {
__m256i u2=_mm256_add_epi16(ld(y+i),ld(c12+i));
__m256i u3=_mm256_add_epi16(u2,ld(c21+i));
__m256i p5=ld(c22+i);
st(c12+i,_mm256_add_epi16(_mm256_add_epi16(u2,p5),ld(c11+i)));
st(c21+i,_mm256_sub_epi16(u3,ld(x+i)));
st(c22+i,_mm256_add_epi16(u3,p5));
}
{ if (h>BASE) mul_sub(a12,b21,c11,h,next,y);
else { mul(a12,b21,c11,h,next); combine<false>(c11,c11,y,q); } }
}
static void mul_sub(const U *a,const U *b,U *c,int n,U *work,const U *ysub) {
int h=n/2,q=h*h;
const U *a11=a,*a12=a+q,*a21=a+2*q,*a22=a+3*q;
const U *b11=b,*b12=b+q,*b21=b+2*q,*b22=b+3*q;
U *c11=c,*c12=c+q,*c21=c+2*q,*c22=c+3*q;
U *x=work,*y=work+q,*next=work+2*q;
combine<true>(x,a11,a21,q);
combine<true>(y,b22,b12,q);
mul(x,y,c21,h,next); // P7
combine<false>(x,a21,a22,q);
combine<true>(y,b12,b11,q);
mul(x,y,c22,h,next); // P5
combine<true>(x,x,a11,q);
combine<true>(y,b22,y,q);
mul(x,y,c12,h,next); // P6
combine<true>(x,a12,x,q);
mul(x,b22,c11,h,next); // P3
combine<true>(y,y,b21,q);
mul(a22,y,x,h,next); // P4
mul(a11,b11,y,h,next); // P1
{
const U *s12=ysub+q,*s21=ysub+2*q,*s22=ysub+3*q;
for(int i=0;i<q;i+=16) {
__m256i u2=_mm256_add_epi16(ld(y+i),ld(c12+i));
__m256i u3=_mm256_add_epi16(u2,ld(c21+i));
__m256i p5=ld(c22+i);
st(c12+i,_mm256_add_epi16(_mm256_add_epi16(_mm256_add_epi16(u2,p5),ld(c11+i)),ld(s12+i)));
st(c21+i,_mm256_add_epi16(_mm256_sub_epi16(u3,ld(x+i)),ld(s21+i)));
st(c22+i,_mm256_add_epi16(_mm256_add_epi16(u3,p5),ld(s22+i)));
}
}
mul(a12,b21,c11,h,next); // P2
for(int i=0;i<q;i+=16)
st(c11+i,_mm256_add_epi16(_mm256_add_epi16(ld(c11+i),ld(y+i)),ld(ysub+i)));
}
void matrix_multiply(int n,const short *A,const short *B,short *C) {
pack(pa,(const U *)A,n,n,false);
pack(pb,(const U *)B,n,n,true);
_mm_sfence();
mul(pa,pb,pc,n,(U*)C + 1024); /* ★ 工作区搬进 C 的缓冲区(unpack 会整块覆写 C) */
unpack((U *)C,pc,n,n);
_mm_sfence();
}
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 11.859 ms | 8 MB + 12 KB | Accepted | Score: 100 | 显示更多 |