提交记录 141224


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_v41f1017_agg4 mmmc4k. 测测你的8位整数矩阵乘法-4k Accepted 100 329.641 ms 56888 KB C++17 99.45 KB
提交时间 评测时间
2026-10-31 19:25:35 2026-10-31 19:25:38
/* ===== [seat15 mmmc4k 2026-10-31] mikro_u4: B chunk folded into both vpmaddubsw (base+disp) =====
 * EDITED copy of the priced sid 141203 body (work/mmmc4k/seat7/cand_a5t.cpp, sha256 94bd6aab...);
 * inherited notices below retained verbatim. ONE change, inside mikro_u4's hand-written k-loop:
 * the 32B B chunk was materialised by `vmovdqa OFF(%[bib],%[bidx]),%%ymm4` and used by the two
 * madds; the loads are deleted and both madds read the same chunk directly as base+displacement
 * memory operands `vpmaddubsw OFF(%[p]),%%ymm0/1,%%ymmD`. This replaces the base+index form
 * (indexed memory-ALU operands do not micro-fuse -- the priced FOLDLEAF +12% form) with a single
 * pointer bumped once per k-iteration, which does micro-fuse; the loop condition moves from the
 * index register to a dec counter. The 36 static sites, chunk addresses, offsets, arithmetic,
 * accumulator roles and stores are unchanged. Gates (seat15 dir): n=4096 oracle checked=30000
 * bad=0 FNV 2e9a2fdaf0565988; anchors 0662c9b59468b0cd / a30ee3f8b4732c61 / 9fa0d6a549e4a27f /
 * a8252d03d58c7321; 16MB dumps byte-identical to base at seeds 12345 and 999.
 */
/* ===== [seat5+seat7 mmmc4k 2026-10-31] 64B line-complete NT stores: cmb4/A5/B5 + A5t =====
 * EDITED copy of the adopted #139830 lineage (base_139845.cpp, sha256 7afed56b...); inherited
 * notices below retained verbatim. Donor: work/mmmc8k/seat6/cand_lc8k.cpp (public sid 141192,
 * official -0.472%): both 32B halves of each 64B NT line issued back to back.
 * [seat5, priced sid 141201 -0.325%] cmb4 (8 copies) + build_combsA5 + build_combsB5: j 32->64,
 * both halves loaded, stores paired. [seat7] build_combsA5t: same pairing (its halves were 5
 * store events apart, 1,146,880 stores/run; all other NT streams were gap 1). B=h>>2=256 at the
 * only call site, so j%64==0 lines stay aligned. Values, pointers, sizes, strides and all
 * non-store instructions unchanged. Gates: n=4096 FNV 2e9a2fdaf0565988, checked=30000 bad=0,
 * dump byte-identical; dynamic NT probe: 5,505,024 stores/run, all paired, bad=0.
 */
/* Adopted 2026-10-22 (agg4 main) from public duck.ac submission 139830 by saffah_codex_6a_agg3 (https://duck.ac/submission/139830): complete engine implementation; inherited notices retained; public submission, no separate license stated. */
/* References: saffah_v41f1017_agg4 https://duck.ac/submission/132723:
 * full4096 byte engine. saffah_codex_6a_agg3's1024 engine submissions:
 * https://duck.ac/submission/128634 (word-major A parity masks),
 * https://duck.ac/submission/129054 (cancel B/output lane permutations),
 * https://duck.ac/submission/129216 (single-instruction parity expansion).
 * Those three ideas are adapted to this engine's composed256 packers and
 * integrated output kernel. All inherited4096 notices retained below;
 * these public Duck sources declare no separate software license.
 */
// ===== 追加(本席,2026-10-17 晚)=====
// [A] 底盘 = #131373(saffah_cc_v41_agg1,mmmc4k 现 T)逐字节;上游链原样保留在下方。
// [B] 新增:A/B 两侧各 5 个和式融合为单次四象限遍历 + NT 流存储;组合缓冲零新增页
//     (A→MMS[0,1,4,5,6],B→MMS[2,3] 与 C 前 12MB;j 号组合在乘积 j 结束覆写前消费)。
//     判题机体验 1215.60M→1204.40M 拍(−0.92%);n=4096 seed=12345 FNV 逐位相同。
// ================
// [C] 二次下沉(本发):把同一 A 侧 5 和式融合下沉到 submm_s2 层(2048→1024):该层 7 个乘积原本
//   各做一次 blk 双源拷贝(A 侧共读 ~12MB/次);现改为先一次四象限遍历写 5 个 tiled 组合
//   (NT 流写;槽位 S2M[0,1,4,5,6],生命周期同根级:组合 j 在乘积 j 结束覆写前消费),
//   sum 类乘积把组合缓冲既作 Ap 又作 Cp 直传 submm_s4(免 S3A 拷贝);B 侧与纯块 case2/3 不变。
//   判题机体验 1193.8→1189.7M 拍(−0.34%);n=4096 seed=12345 FNV 逐位相同。
// ===== REFERENCES =====
// [1] duck.ac user saffah_codex_6a_agg3, submission #128565 <https://duck.ac/submission/128565>
//     -- rank 1 on `mmmc4k` at judge-raw 338.455773 ms (= current T). USED: the ENTIRE artifact
//     VERBATIM -- everything below this header is that submission byte-for-byte (all pointers,
//     constants, memory layout, inline asm and traversal order), with its own nested citation
//     chain left intact. That chain cites #128432 (fixed-address byte kernel + full recursive
//     engine), #128086 (independent-pitch immutable root quadrant views at size 8192, transferred
//     to the 2048 child driver), #128238 (second packed A row addressed by its fixed 512-byte
//     displacement -- deleting a live address register -- plus fixed 256/32-byte output/parity
//     displacements in the 4096 engine), #128167 (mixed four six-bit plus eight five-bit GF(2)
//     lookup partition) and our own public pieces #127997 / #127159 / #127986.
// [2] duck.ac user saffah_cc_v41_agg1 (this account), submission #127986
//     <https://duck.ac/submission/127986> at 342.010371 ms = this account's best on `mmmc4k`
//     before this file. Inherited through chain [1]; our own best is aligned to it here.
// LICENSE: both sides are public duck.ac submissions (site FAQ: 你的代码将会被公开);
//     neither carries a software license notice and neither comes from an external repository,
//     so both are reused with full attribution -- account, submission address and the exact
//     content used -- as stated above.
// ======================
/* References:
 * saffah_codex_6a_agg3 https://duck.ac/submission/128432: current fixed-address byte kernel and full recursive engine, all inherited citations retained below.
 * saffah_codex_6a_agg3 https://duck.ac/submission/128086: accepted independent-pitch immutable root quadrant views at size8192, transferred here to the 2048 child driver.
 * Idea: Pass the root's four plain 2048 input quadrants as immutable strided views instead of copying them to SA/SB. Give submm_s2 independent source pitches for its first materialization; all deeper products remain contiguous. This removes four complete 4-MiB copy passes without aliasing output or changing any byte arithmetic.
 * Purpose: Reduce root memory traffic while retaining the current leaf, correction tables and signed packers.
 */
/* References:
 * saffah_codex_6a_agg3 https://duck.ac/submission/128238: complete accepted byte matrix engine and full inherited attribution/license notices below.
 * Idea: The production recursion uses 256-square leaves. Express the second packed A row with its fixed 512-byte displacement from the first row, deleting a live address register and its setup/update. In the 4096 engine, also address the second output/parity rows by their fixed 256/32-byte displacements. Arithmetic, pack representation and traversal stay unchanged.
 * Purpose: Measure reduced address work for the problem's fixed-size production path; verify the complete official-size matrix over all signed-byte edge patterns.
 */
/* References:
 * saffah_codex_6a_agg3 https://duck.ac/submission/128167: accepted fixed initialized leaf loop and complete inherited engine/credit notices retained below.
 * saffah_cc_v41_agg1 https://duck.ac/submission/127997 and https://duck.ac/submission/127159: mixed four six-bit plus eight five-bit GF(2) lookup partition; the idea is adapted, with new generated builders and this engine's flat parity-source addressing.
 * These public submissions state no separate license; inherited notices are retained.
 * Idea: Combine a sixteen-KiB mixed-width correction slab with the initialized 256 leaf. Two fixed-width builder loops remove group-width branches, preserve register-only Gray generation, and index the unpadded 64-row B masks directly. Pair queries on two independent chains per row.
 * Purpose: Reduce table construction and cache occupation relative to the accepted uniform partition while preserving every modulo-256 product; only official judging determines speed.
 */
/* References:
- saffah_cc_v41_agg1, https://duck.ac/submission/127986: copied the current
  byte matrix engine and full original citation/license chain below.
Idea: The production engine always calls the forward microkernel on 256-square
  leaves. Remove its unreachable eight-element remainder and empty-loop guards.
  Initialize the eight accumulators directly with the first byte-pair product,
  then enter the existing unrolled ring at its second pair; later rings retain
  exactly the original order. This removes eight zeroes and eight adds per
  microcall without duplicating the full loop. Purpose: reduce real leaf work
  and hot code size while preserving all mod-256 products and parity correction.
*/
// ===== REFERENCES =====
// [1] duck.ac user saffah_codex_6a_agg3, submission #126001 <https://duck.ac/submission/126001> -- rank 1
//     on `mmmc4k` with judge-raw 345.290415 ms. USED: the ENTIRE artifact VERBATIM -- everything
//     below this header is problems/mmmc4k/ref2/rival_126001.cpp byte-for-byte (all pointers,
//     constants, memory layout, inline asm, loop and summation order), with the rival's
//     own nested citation chain left intact. That chain in turn cites its parents in
//     saffah_codex_6a_agg3's public series and our own public submissions, #123016,
//     which it states it copied and adapted; inherited notices retained below.
// [2] duck.ac user saffah_cc_v41_agg1 (this account), submission #123016
//     <https://duck.ac/submission/123016> at 348.938824 ms = this account's best on `mmmc4k` before
//     this file. Inherited through chain [1]; our own best is aligned to it here.
// LICENSE: both sides are public duck.ac submissions (site FAQ: 你的代码将会被公开);
//     neither carries a software license notice and neither comes from an external
//     repository, so both are reused with full attribution -- account, submission
//     address and the exact content used -- as stated above.
// [3] duck.ac user saffah_cc_v41_agg1 (this account), submissions #126876
//     <https://duck.ac/submission/126876> and #126888 <https://duck.ac/submission/126888>
//     on `mmmc1k` -- our own public pieces whose `corr4_256` carries the knife transplanted
//     here as (C): a 12-field-per-word table-index extraction written as a 64-bit ROTATION
//     `(w>>s)|(w<<(64-s))` under `target("avx2,bmi2")`, so gcc9 emits the 3-operand
//     `rorx $imm,src,dst` instead of the destructive `mov+shr+and` that x86's 2-operand
//     shifts force, with the table base kept as `char*` and the index pre-scaled to a byte
//     offset so the <<5 is folded into the shift immediate.  No code is copied from those
//     pieces -- only the mechanism, re-derived below for this chassis's 5-bit fields and
//     32-slot tables (mask 0x3e0).
// ======================
// ===== 思路 =====
// [r2m_/mmmc4k 横搬席 · 本发在在册件 #127029 之上再叠两把逐位等价的 ALU 刀(C)(D)】
// (C) **`gray12c4k`:表索引抽取改 3 操作数 rorx**(机理自本席在 `mmmc2k` 上兑现 −0.475%
//     板面的同族刀 #127082/#127093;源头是我方 `mmmc1k` 公开件 #126876/#126888,见 REFERENCES[3])。
//     `corr_six256` 的查询环每字取 12 个 **5 位** 字段(32 槽表,字节偏移 = idx*32 ⇒ 掩码 **0x3e0**):
//       `(const __m256i*)TB+OFF+((w>>5g)&31)`
//     ⇒ `(const __m256i*)(TBc+OFF*32+(R2M_ROR(w,r)&0x3e0))`,r = (5g−5) mod 64
//     (g=0 ⇒ r=59;g=1 ⇒ r=0,该式退化为恒等,直接写 `(w & 0x3e0)`);并只给 `corr_six256`
//     加 `target("avx2,bmi2")`(rorx 需 BMI2;判题机 i3-8100 = Coffee Lake 有)。旋转带入的位
//     全落在掩码外 ⇒ 逐位等价。
//     **判题机码流实证(godbolt gcc 9.3 -O2,唯一可信编译器)**:`corr_six256`
//     改前 **len=219 · shr=22 · rorx=0 · mov=29** ⇒ 改后 **len=197 · shr=2 · rorx=22 · mov=7**
//     (24 处抽取里 22 处变 rorx,剩 2 处是 r=0 的恒等位;−22 条指令、−22 条 mov)。
// (D) 〔本发**未含**〕**`and8c4k`:奇偶抽取的冗余 `and` 移除**(同族刀,机理来自对手自家 mmmc4k #126001 的公开思路,
//     我方 `mmmc1k` 件 #126876/#126888 的 (b) 段):`movemask(slli_epi16(and(v,one),7))` 里
//     `and(v,1)` 冗余 —— `v<<7` 后 16 位 lane 的 bit 7/15 恰是原 bit 0/8(movemask 读的两个符号位),
//     其余位落到非符号位 ⇒ 逐位等价。本底盘同形 **2 处**。
// **值闸门**:`r2m_vgate.py mmmc4k`(n=4096)对 (C)/(D) 各自 ⇒ **checked 8692, worst 0, bad=0** ✓。
// **本机 r0 定价**(`r2m_c4k.py`,单次冷调用 `__rdtsc` 包夹 = 板面同口径;轮转臂序):
//   base4k tot 1236895546 (+0.000%) · gray12c4k tot 1231668876 (**-0.423%**) · and8c4k tot 1237073408 (+0.014%)
// ⇒ **只叠 (C)**(本机 -0.423%);(D) 本机 +0.014%(非正)⇒ 按纪律不叠、仅留档。

/* References:
- saffah_codex_6a_agg3, https://duck.ac/submission/125993: retained the accepted byte engine and inherited attribution below.
No separate software license is declared by the cited public sources.
Idea: Accumulate both32-bit parity masks for each64-column B segment in local64-bit registers and store each completed parity word once. This removes the first partial store and later read/modify/write while preserving packed B stores and the exact GF(2) correction bits.
Purpose: Reduce parity staging traffic and memory alias dependencies in each composed B leaf.
*/



#pragma GCC optimize("O3")
#pragma GCC optimize("ira-loop-pressure")
#pragma GCC optimize("ira-region=mixed")
#pragma GCC optimize("no-ira-loop-pressure")
#pragma GCC optimize("no-tree-dominator-opts")

#include <immintrin.h>
#include <xmmintrin.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#ifndef PFMODE
#define PFMODE 1   
#endif
#if PFMODE==0
#define PF_STR "prefetcht0 512(%[bib],%[bidx])\n\t" "prefetcht0 1024(%[bib],%[bidx])\n\t"
#elif PFMODE==1
#define PF_STR ""
#elif PFMODE==2
#define PF_STR "prefetcht0 512(%[bib],%[bidx])\n\t"
#elif PFMODE==3
#define PF_STR "prefetcht0 256(%[bib],%[bidx])\n\t" "prefetcht0 512(%[bib],%[bidx])\n\t"
#elif PFMODE==4
#define PF_STR "prefetcht0 1024(%[bib],%[bidx])\n\t" "prefetcht0 2048(%[bib],%[bidx])\n\t"
#elif PFMODE==5
#define PF_STR "prefetchnta 512(%[bib],%[bidx])\n\t" "prefetchnta 1024(%[bib],%[bidx])\n\t"
#elif PFMODE==6
#define PF_STR "prefetcht0 512(%[bib],%[bidx])\n\t" "prefetcht0 1024(%[bib],%[bidx])\n\t" \
               "prefetcht0 1536(%[bib],%[bidx])\n\t" "prefetcht0 2048(%[bib],%[bidx])\n\t"
#endif
#define AVX2 __attribute__((target("avx2")))
#define NMAX 4096


#ifndef PADA
#define PADA 0
#endif
#define LDA ((int)(2*NMAX + PADA))
#ifndef PADB
#define PADB 0
#endif
#define LDB ((int)(NMAX + PADB))
static int8_t   A0b[(size_t)NMAX*LDA] __attribute__((aligned(64)));

static int GLDA = LDA, GLDB = LDB;

static uint64_t A1b[NMAX*NMAX/8]    __attribute__((aligned(64)));
static uint64_t Bpb[NMAX*NMAX/8]    __attribute__((aligned(64)));
static uint64_t Pbb[NMAX*NMAX/8]    __attribute__((aligned(64)));
static uint8_t  PBb[(size_t)NMAX*LDB] __attribute__((aligned(64)));

static void generic_mm(int n, const int8_t*A, const int8_t*B, int8_t*C){
  for (int i=0;i<n;i++) for (int j=0;j<n;j++){
    int s=0; for(int k=0;k<n;k++) s += (int)A[(size_t)i*n+k]*(int)B[(size_t)k*n+j];
    C[(size_t)i*n+j]=(int8_t)s;
  }
}

AVX2 static inline __m256i bcast16(const int8_t*p){
  __m256i v; __asm__("vpbroadcastw %1, %0" : "=x"(v) : "m"(*(const short*)p)); return v;
}
AVX2 static inline __m256i packlo8(__m256i a, __m256i b){
  const __m256i m=_mm256_set1_epi16(0x00FF);
  return _mm256_permute4x64_epi64(
    _mm256_packus_epi16(_mm256_and_si256(a,m), _mm256_and_si256(b,m)), 0XD8);
}


AVX2 static void build_A1bits(int n, const int8_t*A){
  int W=n/64;
  for (int i=0;i<n;i++){
    const int8_t*row=A+(size_t)i*n; uint64_t*w=A1b+(size_t)i*W;
    for (int k=0;k<n;k+=64){
      uint32_t lo=(uint32_t)_mm256_movemask_epi8(_mm256_load_si256((const __m256i*)(row+k)));
      uint32_t hi=(uint32_t)_mm256_movemask_epi8(_mm256_load_si256((const __m256i*)(row+k+32)));
      w[k>>6]=(uint64_t)lo|((uint64_t)hi<<32);
    }
  }
}
AVX2 static void build_Bpbits(int n, const int8_t*B){
  const __m256i one=_mm256_set1_epi8(1);
  int W=n/64;
  for (int k=0;k<n;k++){
    const int8_t*row=B+(size_t)k*n; uint64_t*w=Bpb+(size_t)k*W;
    for (int j=0;j<n;j+=64){
      __m256i a=_mm256_slli_epi16(_mm256_and_si256(_mm256_load_si256((const __m256i*)(row+j)),one),7);
      __m256i b=_mm256_slli_epi16(_mm256_and_si256(_mm256_load_si256((const __m256i*)(row+j+32)),one),7);
      uint32_t lo=(uint32_t)_mm256_movemask_epi8(a);
      uint32_t hi=(uint32_t)_mm256_movemask_epi8(b);
      w[j>>6]=(uint64_t)lo|((uint64_t)hi<<32);
    }
  }
}


AVX2 static void corr_bits(int n){
  int W=n/64, NY=W>>2;
  for (int i=0;i<n;i++){
    __m256i acc[16];
    for(int t=0;t<NY;t++) acc[t]=_mm256_setzero_si256();
    const uint64_t*row=A1b+(size_t)i*W;
    for(int w=0;w<W;w++){
      uint64_t b=row[w];
      while(b){
        int t=__builtin_ctzll(b); b&=b-1;
        const uint64_t*br=Bpb+(size_t)(w*64+t)*W;
        for(int q=0;q<NY;q++)
          acc[q]=_mm256_xor_si256(acc[q],_mm256_load_si256((const __m256i*)(br+4*q)));
      }
    }
    uint64_t*o=Pbb+(size_t)i*W;
    for(int q=0;q<NY;q++) _mm256_store_si256((__m256i*)(o+4*q),acc[q]);
  }
}

static uint64_t A1T[NMAX*NMAX/8] __attribute__((aligned(64)));
AVX2 static void transpose64(uint64_t *a){
  int j,k; uint64_t m,t;
  for (j=32,m=0xFFFFFFFF00000000ULL; j; j>>=1, m^=m>>j)
    for (k=0;k<64;k=(k+j+1)&~j){
      t=(a[k]^(a[k+j]<<j))&m;
      a[k]^=t; a[k+j]^=(t>>j);
    }
}
AVX2 static void build_A1T(int n){
  int W=n/64;
  for (int kb=0; kb<n; kb+=64)
    for (int ib=0; ib<n; ib+=64){
      uint64_t blk[64];
      for (int i=0;i<64;i++) blk[i]=A1b[(size_t)(ib+i)*W+(kb>>6)];
      transpose64(blk);
      for (int k=0;k<64;k++) A1T[(size_t)(kb+k)*W+(ib>>6)]=blk[k];
    }
}


AVX2 static void corr_pass3(int n){
  int W=n/64, NY=W>>2;
  memset(Pbb,0,(size_t)n*W*8);
  const int KB=256;
  for (int kb=0; kb<n; kb+=KB){
    int w0=kb>>6, w1=w0+(KB>>6);
    for (int i=0;i<n;i++){
      __m256i acc[16];
      for (int q=0;q<NY;q++) acc[q]=_mm256_setzero_si256();
      const uint64_t*row=A1b+(size_t)i*W;
      for (int w=w0;w<w1;w++){
        uint64_t b=row[w];
        while(b){
          int t=__builtin_ctzll(b); b&=b-1;
          const uint64_t*br=Bpb+(size_t)(w*64+t)*W;
          for (int q=0;q<NY;q++) acc[q]=_mm256_xor_si256(acc[q],_mm256_load_si256((const __m256i*)(br+4*q)));
        }
      }
      uint64_t*o=Pbb+(size_t)i*W;
      for (int q=0;q<NY;q++){
        __m256i*po=(__m256i*)(o+4*q);
        _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),acc[q]));
      }
    }
  }
}


#define AVX2BMI __attribute__((target("avx2,bmi")))

AVX2BMI static void corr16(void){
  const int n=4096, W=64;
  memset(Pbb,0,(size_t)n*W*8);
  const int KB=64;
  for (int kb=0; kb<n; kb+=KB){
    int w0=kb>>6;
    const char *bp0=(const char*)Bpb+(size_t)w0*32768;
    const char *bp1=bp0; (void)bp1;
    for (int i=0;i<n;i++){
      const uint64_t*row=A1b+(size_t)i*W+w0;
      uint64_t b0=row[0], b1=0;
      uint64_t *o=Pbb+(size_t)i*W;
      asm volatile(
        "vpxor %%xmm0,%%xmm0,%%xmm0\n\t"
        "vpxor %%xmm1,%%xmm1,%%xmm1\n\t"
        "vpxor %%xmm2,%%xmm2,%%xmm2\n\t"
        "vpxor %%xmm3,%%xmm3,%%xmm3\n\t"
        "vpxor %%xmm4,%%xmm4,%%xmm4\n\t"
        "vpxor %%xmm5,%%xmm5,%%xmm5\n\t"
        "vpxor %%xmm6,%%xmm6,%%xmm6\n\t"
        "vpxor %%xmm7,%%xmm7,%%xmm7\n\t"
        "vpxor %%xmm8,%%xmm8,%%xmm8\n\t"
        "vpxor %%xmm9,%%xmm9,%%xmm9\n\t"
        "vpxor %%xmm10,%%xmm10,%%xmm10\n\t"
        "vpxor %%xmm11,%%xmm11,%%xmm11\n\t"
        "vpxor %%xmm12,%%xmm12,%%xmm12\n\t"
        "vpxor %%xmm13,%%xmm13,%%xmm13\n\t"
        "vpxor %%xmm14,%%xmm14,%%xmm14\n\t"
        "vpxor %%xmm15,%%xmm15,%%xmm15\n\t"
        "testq %[b0], %[b0]\n\t"
        "jz 3%=f\n\t"
        "1%=:\n\t"
        "tzcntq %[b0], %%r11\n\t"
        "shlq $9, %%r11\n\t"
        "addq %[bp0], %%r11\n\t"
        "vpxor 0(%%r11), %%ymm0, %%ymm0\n\t"
        "vpxor 32(%%r11), %%ymm1, %%ymm1\n\t"
        "vpxor 64(%%r11), %%ymm2, %%ymm2\n\t"
        "vpxor 96(%%r11), %%ymm3, %%ymm3\n\t"
        "vpxor 128(%%r11), %%ymm4, %%ymm4\n\t"
        "vpxor 160(%%r11), %%ymm5, %%ymm5\n\t"
        "vpxor 192(%%r11), %%ymm6, %%ymm6\n\t"
        "vpxor 224(%%r11), %%ymm7, %%ymm7\n\t"
        "vpxor 256(%%r11), %%ymm8, %%ymm8\n\t"
        "vpxor 288(%%r11), %%ymm9, %%ymm9\n\t"
        "vpxor 320(%%r11), %%ymm10, %%ymm10\n\t"
        "vpxor 352(%%r11), %%ymm11, %%ymm11\n\t"
        "vpxor 384(%%r11), %%ymm12, %%ymm12\n\t"
        "vpxor 416(%%r11), %%ymm13, %%ymm13\n\t"
        "vpxor 448(%%r11), %%ymm14, %%ymm14\n\t"
        "vpxor 480(%%r11), %%ymm15, %%ymm15\n\t"
        "blsrq %[b0], %[b0]\n\t"
        "jnz 1%=b\n\t"
        "3%=:\n\t"
        "testq %[b1], %[b1]\n\t"
        "jz 4%=f\n\t"
        "2%=:\n\t"
        "tzcntq %[b1], %%r11\n\t"
        "shlq $9, %%r11\n\t"
        "addq %[bp1], %%r11\n\t"
        "vpxor 0(%%r11), %%ymm0, %%ymm0\n\t"
        "vpxor 32(%%r11), %%ymm1, %%ymm1\n\t"
        "vpxor 64(%%r11), %%ymm2, %%ymm2\n\t"
        "vpxor 96(%%r11), %%ymm3, %%ymm3\n\t"
        "vpxor 128(%%r11), %%ymm4, %%ymm4\n\t"
        "vpxor 160(%%r11), %%ymm5, %%ymm5\n\t"
        "vpxor 192(%%r11), %%ymm6, %%ymm6\n\t"
        "vpxor 224(%%r11), %%ymm7, %%ymm7\n\t"
        "vpxor 256(%%r11), %%ymm8, %%ymm8\n\t"
        "vpxor 288(%%r11), %%ymm9, %%ymm9\n\t"
        "vpxor 320(%%r11), %%ymm10, %%ymm10\n\t"
        "vpxor 352(%%r11), %%ymm11, %%ymm11\n\t"
        "vpxor 384(%%r11), %%ymm12, %%ymm12\n\t"
        "vpxor 416(%%r11), %%ymm13, %%ymm13\n\t"
        "vpxor 448(%%r11), %%ymm14, %%ymm14\n\t"
        "vpxor 480(%%r11), %%ymm15, %%ymm15\n\t"
        "blsrq %[b1], %[b1]\n\t"
        "jnz 2%=b\n\t"
        "4%=:\n\t"
        "vpxor   0(%[o]), %%ymm0, %%ymm0\n\t"
        "vmovdqu %%ymm0, 0(%[o])\n\t"
        "vpxor   32(%[o]), %%ymm1, %%ymm1\n\t"
        "vmovdqu %%ymm1, 32(%[o])\n\t"
        "vpxor   64(%[o]), %%ymm2, %%ymm2\n\t"
        "vmovdqu %%ymm2, 64(%[o])\n\t"
        "vpxor   96(%[o]), %%ymm3, %%ymm3\n\t"
        "vmovdqu %%ymm3, 96(%[o])\n\t"
        "vpxor   128(%[o]), %%ymm4, %%ymm4\n\t"
        "vmovdqu %%ymm4, 128(%[o])\n\t"
        "vpxor   160(%[o]), %%ymm5, %%ymm5\n\t"
        "vmovdqu %%ymm5, 160(%[o])\n\t"
        "vpxor   192(%[o]), %%ymm6, %%ymm6\n\t"
        "vmovdqu %%ymm6, 192(%[o])\n\t"
        "vpxor   224(%[o]), %%ymm7, %%ymm7\n\t"
        "vmovdqu %%ymm7, 224(%[o])\n\t"
        "vpxor   256(%[o]), %%ymm8, %%ymm8\n\t"
        "vmovdqu %%ymm8, 256(%[o])\n\t"
        "vpxor   288(%[o]), %%ymm9, %%ymm9\n\t"
        "vmovdqu %%ymm9, 288(%[o])\n\t"
        "vpxor   320(%[o]), %%ymm10, %%ymm10\n\t"
        "vmovdqu %%ymm10, 320(%[o])\n\t"
        "vpxor   352(%[o]), %%ymm11, %%ymm11\n\t"
        "vmovdqu %%ymm11, 352(%[o])\n\t"
        "vpxor   384(%[o]), %%ymm12, %%ymm12\n\t"
        "vmovdqu %%ymm12, 384(%[o])\n\t"
        "vpxor   416(%[o]), %%ymm13, %%ymm13\n\t"
        "vmovdqu %%ymm13, 416(%[o])\n\t"
        "vpxor   448(%[o]), %%ymm14, %%ymm14\n\t"
        "vmovdqu %%ymm14, 448(%[o])\n\t"
        "vpxor   480(%[o]), %%ymm15, %%ymm15\n\t"
        "vmovdqu %%ymm15, 480(%[o])\n\t"
        : [b0]"+r"(b0), [b1]"+r"(b1)
        : [bp0]"r"(bp0), [bp1]"r"(bp1), [o]"r"(o)
        : "r11","cc","memory","ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15");
    }
  }
}

AVX2 static void expand_bits(int n){
  static uint8_t T[256*8]; static int ti=0;
  if(!ti){ for(int v=0;v<256;v++) for(int b=0;b<8;b++) T[v*8+b]=((v>>b)&1)?0x80:0x00; ti=1; }
  int W=n/64;
  
  for(int i=0;i<n;i++){
    const uint64_t*w=Pbb+(size_t)i*W; uint8_t*o=PBb+(size_t)i*GLDB;
    for(int q=0;q<W;q++){
      uint64_t v=w[q];
      __m128i a0=_mm_loadl_epi64((const __m128i*)(T+((v>> 0)&0xFF)*8));
      __m128i a1=_mm_loadl_epi64((const __m128i*)(T+((v>> 8)&0xFF)*8));
      __m128i a2=_mm_loadl_epi64((const __m128i*)(T+((v>>16)&0xFF)*8));
      __m128i a3=_mm_loadl_epi64((const __m128i*)(T+((v>>24)&0xFF)*8));
      __m128i a4=_mm_loadl_epi64((const __m128i*)(T+((v>>32)&0xFF)*8));
      __m128i a5=_mm_loadl_epi64((const __m128i*)(T+((v>>40)&0xFF)*8));
      __m128i a6=_mm_loadl_epi64((const __m128i*)(T+((v>>48)&0xFF)*8));
      __m128i a7=_mm_loadl_epi64((const __m128i*)(T+((v>>56)&0xFF)*8));
      __m128i l01=_mm_unpacklo_epi64(a0,a1), l23=_mm_unpacklo_epi64(a2,a3);
      __m128i l45=_mm_unpacklo_epi64(a4,a5), l67=_mm_unpacklo_epi64(a6,a7);
      _mm256_storeu_si256((__m256i*)(o+q*64),    _mm256_set_m128i(l23,l01));
      _mm256_storeu_si256((__m256i*)(o+q*64+32), _mm256_set_m128i(l67,l45));
    }
  }
}

#define NIB 2
#define NJ 4

static const int8_t PSCTRL[32] __attribute__((aligned(32))) =
  {0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3};
static const int8_t PSBIT[32] __attribute__((aligned(32))) =
  {1,2,4,8,16,32,64,(int8_t)128, 1,2,4,8,16,32,64,(int8_t)128,
   1,2,4,8,16,32,64,(int8_t)128, 1,2,4,8,16,32,64,(int8_t)128};
static const int8_t PS80[32] __attribute__((aligned(32))) =
  {(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,
   (int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,
   (int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,
   (int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128,(int8_t)128};
static const int16_t W0FF[16] __attribute__((aligned(32))) =
  {0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,
   0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF};


static int8_t BI3b[NMAX*NMAX] __attribute__((aligned(64)));
AVX2 static void build_BI3(int n, const int8_t*B){
  int ng=n/64;
  for (int p=0;p<n/2;p++){
    const int8_t *r0=B+(size_t)(2*p)*n, *r1=r0+n;
    for (int g=0;g<ng;g++){
      const int8_t *a=r0+64*g, *b=r1+64*g;
      int8_t *o=BI3b+((size_t)g*(n/2)+p)*128;
      for (int t=0;t<64;t+=32){
        __m256i va=_mm256_load_si256((const __m256i*)(a+t));
        __m256i vb=_mm256_load_si256((const __m256i*)(b+t));
        __m256i lo=_mm256_unpacklo_epi8(va,vb), hi=_mm256_unpackhi_epi8(va,vb);
        _mm256_store_si256((__m256i*)(o+2*t),    _mm256_permute2x128_si256(lo,hi,0x20));
        _mm256_store_si256((__m256i*)(o+2*t+32), _mm256_permute2x128_si256(lo,hi,0x31));
      }
    }
  }
}
template<bool NativeLane=false>
AVX2 static void mikro_u4(int n,const int8_t*A0,const int8_t*BI,int8_t*C,const uint8_t*PB,int jb,int lda,int ldb){
  const int8_t *x0=A0;
  
  const int8_t *x1=A0+lda;
  const int8_t *p=BI; long cnt=n>>4;
  int8_t *C0=C+jb, *C1=C0+n;
  const uint8_t *PB0=PB+jb, *PB1=PB0+ldb;
  asm volatile(
    "vpbroadcastd 0(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 512(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 0(%[p]), %%ymm0, %%ymm8\n\t"
    "vpmaddubsw 0(%[p]), %%ymm1, %%ymm12\n\t"
    "vpmaddubsw 32(%[p]), %%ymm0, %%ymm9\n\t"
    "vpmaddubsw 32(%[p]), %%ymm1, %%ymm13\n\t"
    "vpmaddubsw 64(%[p]), %%ymm0, %%ymm10\n\t"
    "vpmaddubsw 64(%[p]), %%ymm1, %%ymm14\n\t"
    "vpmaddubsw 96(%[p]), %%ymm0, %%ymm11\n\t"
    "vpmaddubsw 96(%[p]), %%ymm1, %%ymm15\n\t"
    "jmp 4f\n\t"
    ".p2align 6\n\t"
    "2:\n\t"
    "vpbroadcastd 0(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 512(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 0(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 0(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 32(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 32(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 64(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 64(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 96(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 96(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "4:\n\t"
    "vpbroadcastd 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 516(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 128(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 128(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 160(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 160(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 192(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 192(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 224(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 224(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 8(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 520(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 256(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 256(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 288(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 288(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 320(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 320(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 352(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 352(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 12(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 524(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 384(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 384(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 416(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 416(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 448(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 448(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 480(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 480(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 16(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 528(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 512(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 512(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 544(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 544(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 576(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 576(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 608(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 608(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 20(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 532(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 640(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 640(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 672(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 672(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 704(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 704(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 736(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 736(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 24(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 536(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 768(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 768(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 800(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 800(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 832(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 832(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 864(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 864(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 28(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 540(%[x0]), %%ymm1\n\t"
    "vpmaddubsw 896(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 896(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw 928(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 928(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw 960(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 960(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vpmaddubsw 992(%[p]), %%ymm0, %%ymm5\n\t"
    "vpmaddubsw 992(%[p]), %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    PF_STR
    "addq $32, %[x0]\n\t"
        "addq $1024, %[p]\n\t"
    "decq %[cnt]\n\t"
    "jnz 2b\n\t"
    "9:\n\t"
    "vpand %[mask], %%ymm8, %%ymm2\n\t"
    "vpand %[mask], %%ymm9, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    ".if %c[native] == 0\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    ".endif\n\t"
    "vmovdqa %[ps80], %%ymm7\n\t"
    "vpbroadcastd 0(%[PB0]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpsignb %%ymm0, %%ymm7, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 0(%[C0])\n\t"
    "vpand %[mask], %%ymm10, %%ymm2\n\t"
    "vpand %[mask], %%ymm11, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    ".if %c[native] == 0\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    ".endif\n\t"
    "vpbroadcastd 4(%[PB0]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpsignb %%ymm0, %%ymm7, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 32(%[C0])\n\t"
    "vpand %[mask], %%ymm12, %%ymm2\n\t"
    "vpand %[mask], %%ymm13, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    ".if %c[native] == 0\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    ".endif\n\t"
    "vpbroadcastd 32(%[PB0]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpsignb %%ymm0, %%ymm7, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 256(%[C0])\n\t"
    "vpand %[mask], %%ymm14, %%ymm2\n\t"
    "vpand %[mask], %%ymm15, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    ".if %c[native] == 0\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    ".endif\n\t"
    "vpbroadcastd 36(%[PB0]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpsignb %%ymm0, %%ymm7, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 288(%[C0])\n\t"
    : [x0]"+r"(x0), [p]"+r"(p), [cnt]"+r"(cnt)
    : [native]"i"(NativeLane), [C0]"r"(C0), [PB0]"r"(PB0), [mask]"m"(W0FF), [psctrl]"m"(PSCTRL), [psbit]"m"(PSBIT), [ps80]"m"(PS80)
    : "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15","cc","memory");
}

AVX2 static void mikro_u4r(int n,const int8_t*A0,const int8_t*BI,int8_t*C,const uint8_t*PB,int jb,int lda,int ldb){
  const int8_t *x0=A0;
  long nn=(long)n;
  const int8_t *x1=A0+lda;
  const int8_t *bib=BI;   long bidx=((long)(n>>3)*512)-512;  
  int8_t *C0=C+jb, *C1=C0+n;
  const uint8_t *PB0=PB+jb, *PB1=PB0+ldb;
  asm volatile(
    "vpxor %%xmm8,%%xmm8,%%xmm8\n\t"
    "vpxor %%xmm9,%%xmm9,%%xmm9\n\t"
    "vpxor %%xmm10,%%xmm10,%%xmm10\n\t"
    "vpxor %%xmm11,%%xmm11,%%xmm11\n\t"
    "vpxor %%xmm12,%%xmm12,%%xmm12\n\t"
    "vpxor %%xmm13,%%xmm13,%%xmm13\n\t"
    "vpxor %%xmm14,%%xmm14,%%xmm14\n\t"
    "vpxor %%xmm15,%%xmm15,%%xmm15\n\t"
    ".p2align 5\n\t"
    "testq $8, %[nn]\n\t"
    "jz 5f\n\t"
    "vpbroadcastd 0(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 0(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 0(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 32(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 64(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 96(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 4(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 128(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 160(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 192(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 224(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 8(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 8(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 256(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 288(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 320(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 352(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 12(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 12(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 384(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 416(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 448(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 480(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    PF_STR
    "subq $16, %[x0]\n\t"
        "subq $512, %[bidx]\n\t"
    "5:\n\t"
    "testq %[bidx], %[bidx]\n\t"
    "jz 9f\n\t"
    ".p2align 5\n\t"
    "2:\n\t"
    "vpbroadcastd 0(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 0(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 0(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 32(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 64(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 96(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 4(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 128(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 160(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 192(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 224(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 8(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 8(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 256(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 288(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 320(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 352(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd 12(%[x0]), %%ymm0\n\t"
    "vpbroadcastd 12(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa 384(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa 416(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa 448(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa 480(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd -16(%[x0]), %%ymm0\n\t"
    "vpbroadcastd -16(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa -512(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa -480(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa -448(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa -416(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd -12(%[x0]), %%ymm0\n\t"
    "vpbroadcastd -12(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa -384(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa -352(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa -320(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa -288(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd -8(%[x0]), %%ymm0\n\t"
    "vpbroadcastd -8(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa -256(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa -224(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa -192(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa -160(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    "vpbroadcastd -4(%[x0]), %%ymm0\n\t"
    "vpbroadcastd -4(%[x0],%[glda]), %%ymm1\n\t"
    "vmovdqa -128(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpaddw %%ymm6, %%ymm12, %%ymm12\n\t"
    "vmovdqa -96(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpaddw %%ymm6, %%ymm13, %%ymm13\n\t"
    "vmovdqa -64(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpaddw %%ymm6, %%ymm14, %%ymm14\n\t"
    "vmovdqa -32(%[bib],%[bidx]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm6\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpaddw %%ymm6, %%ymm15, %%ymm15\n\t"
    PF_STR
    "subq $32, %[x0]\n\t"
        "subq $1024, %[bidx]\n\t"
    "jns 2b\n\t"
    "9:\n\t"
    "vpand %[mask], %%ymm8, %%ymm2\n\t"
    "vpand %[mask], %%ymm9, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    "vpbroadcastd 0(%[PB0]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpcmpeqb %%ymm7, %%ymm0, %%ymm0\n\t"
    "vpandn %[ps80], %%ymm0, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vpxor %%xmm7, %%xmm7, %%xmm7\n\t"
    "vmovdqu %%ymm2, 0(%[C0])\n\t"
    "vpand %[mask], %%ymm10, %%ymm2\n\t"
    "vpand %[mask], %%ymm11, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    "vpbroadcastd 4(%[PB0]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpcmpeqb %%ymm7, %%ymm0, %%ymm0\n\t"
    "vpandn %[ps80], %%ymm0, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 32(%[C0])\n\t"
    "vpand %[mask], %%ymm12, %%ymm2\n\t"
    "vpand %[mask], %%ymm13, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    "vpbroadcastd 0(%[PB1]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpcmpeqb %%ymm7, %%ymm0, %%ymm0\n\t"
    "vpandn %[ps80], %%ymm0, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 0(%[C1])\n\t"
    "vpand %[mask], %%ymm14, %%ymm2\n\t"
    "vpand %[mask], %%ymm15, %%ymm3\n\t"
    "vpackuswb %%ymm3, %%ymm2, %%ymm2\n\t"
    "vpermq $0xD8, %%ymm2, %%ymm2\n\t"
    "vpbroadcastd 4(%[PB1]), %%ymm0\n\t"
    "vpshufb %[psctrl], %%ymm0, %%ymm0\n\t"
    "vpand %[psbit], %%ymm0, %%ymm0\n\t"
    "vpcmpeqb %%ymm7, %%ymm0, %%ymm0\n\t"
    "vpandn %[ps80], %%ymm0, %%ymm0\n\t"
    "vpxor %%ymm0, %%ymm2, %%ymm2\n\t"
    "vmovdqu %%ymm2, 32(%[C1])\n\t"
    : [x0]"+r"(x0), [bidx]"+r"(bidx)
    : [C0]"r"(C0), [C1]"r"(C1), [PB0]"r"(PB0), [PB1]"r"(PB1), [nn]"r"(nn), [mask]"m"(W0FF), [bib]"r"(bib), [psctrl]"m"(PSCTRL), [psbit]"m"(PSBIT), [ps80]"m"(PS80), [glda]"r"((long)lda)
    : "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15","cc","memory");
}


AVX2 static void build_A0A1(int n, const int8_t*A){
  const __m256i m=_mm256_set1_epi8(0x7F);
  int W=n/64;
  for (int i=0;i<n;i++){
    const int8_t*row=A+(size_t)i*n;
    int8_t*dst=A0b+(size_t)i*GLDA;
    uint64_t*w1=A1b+(size_t)i*W;
    for (int k=0;k<n;k+=64){
      __m256i v0=_mm256_load_si256((const __m256i*)(row+k));
      __m256i v1=_mm256_load_si256((const __m256i*)(row+k+32));
      { __m256i _w0=_mm256_and_si256(v0,m), _w1=_mm256_and_si256(v1,m);
        __m256i _l0=_mm256_unpacklo_epi16(_w0,_w0), _h0=_mm256_unpackhi_epi16(_w0,_w0);
        __m256i _l1=_mm256_unpacklo_epi16(_w1,_w1), _h1=_mm256_unpackhi_epi16(_w1,_w1);
        _mm256_store_si256((__m256i*)(dst+2*k),    _mm256_permute2x128_si256(_l0,_h0,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+32), _mm256_permute2x128_si256(_l0,_h0,0x31));
        _mm256_store_si256((__m256i*)(dst+2*k+64), _mm256_permute2x128_si256(_l1,_h1,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+96), _mm256_permute2x128_si256(_l1,_h1,0x31)); }
      w1[k>>6]=(uint64_t)(uint32_t)_mm256_movemask_epi8(v0)
              |((uint64_t)(uint32_t)_mm256_movemask_epi8(v1)<<32);
    }
  }
}

AVX2 static void build_BI3Bp(int n, const int8_t*B){
  const __m256i one=_mm256_set1_epi8(1);
  int ng=n/64, W=n/64;
  for (int p=0;p<n/2;p++){
    const int8_t *r0=B+(size_t)(2*p)*n, *r1=r0+n;
    uint64_t *w0p=Bpb+(size_t)(2*p)*W, *w1p=Bpb+(size_t)(2*p+1)*W;
    for (int g=0;g<ng;g++){
      const int8_t *a=r0+64*g, *b=r1+64*g;
      int8_t *o=BI3b+((size_t)g*(n/2)+p)*128;
      uint64_t parity0=0,parity1=0;
      for (int t=0;t<64;t+=32){
        __m256i va=_mm256_load_si256((const __m256i*)(a+t));
        __m256i vb=_mm256_load_si256((const __m256i*)(b+t));
        __m256i lo=_mm256_unpacklo_epi8(va,vb), hi=_mm256_unpackhi_epi8(va,vb);
        _mm256_store_si256((__m256i*)(o+2*t),    _mm256_permute2x128_si256(lo,hi,0x20));
        _mm256_store_si256((__m256i*)(o+2*t+32), _mm256_permute2x128_si256(lo,hi,0x31));
        uint32_t m0=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(va,7));
        uint32_t m1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(vb,7));
        parity0 |= (uint64_t)m0<<t; parity1 |= (uint64_t)m1<<t;
      }
      w0p[g]=parity0; w1p[g]=parity1;
    }
  }
}


#define SM 2048
static int8_t SA[SM*SM]     __attribute__((aligned(64)));
static int8_t SB[SM*SM]     __attribute__((aligned(64)));
static int8_t MMS[7][SM*SM+24576] __attribute__((aligned(64)));


#define AQT(J,S) if (S){ __m256i _u0=_mm256_load_si256((const __m256i*)(p##J+k));           \
                         __m256i _u1=_mm256_load_si256((const __m256i*)(p##J+k+32));       \
                         if ((S)>0){ v0=_mm256_add_epi8(v0,_u0); v1=_mm256_add_epi8(v1,_u1); } \
                         else      { v0=_mm256_sub_epi8(v0,_u0); v1=_mm256_sub_epi8(v1,_u1); } }
#define BQT(J,S) if (S){ __m256i _x=_mm256_load_si256((const __m256i*)(q##J##a+64*g+t));    \
                         __m256i _y=_mm256_load_si256((const __m256i*)(q##J##b+64*g+t));    \
                         if ((S)>0){ va=_mm256_add_epi8(va,_x); vb=_mm256_add_epi8(vb,_y); } \
                         else      { va=_mm256_sub_epi8(va,_x); vb=_mm256_sub_epi8(vb,_y); } }

template<int S1,int S2,int S3>
AVX2 static void buildA_q4t(int h,int n,const int8_t*P,
                            int r0,int c0,int r1,int c1,int r2,int c2,int r3,int c3){
  const __m256i mx=_mm256_set1_epi8(0x7F);
  int W=h/64;
  for (int i=0;i<h;i++){
    const int8_t*p0=P+(size_t)(r0+i)*n+c0, *p1=P+(size_t)(r1+i)*n+c1,
                 *p2=P+(size_t)(r2+i)*n+c2, *p3=P+(size_t)(r3+i)*n+c3;
    int8_t*dst=A0b+(size_t)i*GLDA;
    uint64_t*w1=A1b+(size_t)i*W;
    for (int k=0;k<h;k+=64){
      _mm_prefetch((const char*)(p0+4*n+k), _MM_HINT_T0);
      _mm_prefetch((const char*)(p1+4*n+k), _MM_HINT_T0);
      _mm_prefetch((const char*)(p2+4*n+k), _MM_HINT_T0);
      _mm_prefetch((const char*)(p3+4*n+k), _MM_HINT_T0);
      __m256i v0=_mm256_load_si256((const __m256i*)(p0+k));
      __m256i v1=_mm256_load_si256((const __m256i*)(p0+k+32));
      AQT(1,S1); AQT(2,S2); AQT(3,S3);
      __asm__ volatile("prefetchw %0" :: "m"(*(char*)(dst+2*k+256)));
      __asm__ volatile("prefetchw %0" :: "m"(*(char*)(dst+2*k+320)));
      { __m256i _w0=_mm256_and_si256(v0,mx), _w1=_mm256_and_si256(v1,mx);
        __m256i _l0=_mm256_unpacklo_epi16(_w0,_w0), _h0=_mm256_unpackhi_epi16(_w0,_w0);
        __m256i _l1=_mm256_unpacklo_epi16(_w1,_w1), _h1=_mm256_unpackhi_epi16(_w1,_w1);
        _mm256_store_si256((__m256i*)(dst+2*k),    _mm256_permute2x128_si256(_l0,_h0,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+32), _mm256_permute2x128_si256(_l0,_h0,0x31));
        _mm256_store_si256((__m256i*)(dst+2*k+64), _mm256_permute2x128_si256(_l1,_h1,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+96), _mm256_permute2x128_si256(_l1,_h1,0x31)); }
      (h==256?A1b[(size_t)(k>>6)*h+i]:w1[k>>6])=(uint64_t)(uint32_t)_mm256_movemask_epi8(v0)
              |((uint64_t)(uint32_t)_mm256_movemask_epi8(v1)<<32);
    }
  }
}
template<int S1,int S2,int S3>
AVX2 static void buildB_q4t(int h,int n,const int8_t*P,
                            int r0,int c0,int r1,int c1,int r2,int c2,int r3,int c3){
  const __m256i one=_mm256_set1_epi8(1);
  int ng=h/64, W=h/64;
  for (int p=0;p<h/2;p++){
    const int8_t *a0=P+(size_t)(r0+2*p)*n+c0,   *a1=P+(size_t)(r0+2*p+1)*n+c0;
    const int8_t *q1a=P+(size_t)(r1+2*p)*n+c1,  *q1b=P+(size_t)(r1+2*p+1)*n+c1;
    const int8_t *q2a=P+(size_t)(r2+2*p)*n+c2,  *q2b=P+(size_t)(r2+2*p+1)*n+c2;
    const int8_t *q3a=P+(size_t)(r3+2*p)*n+c3,  *q3b=P+(size_t)(r3+2*p+1)*n+c3;
    uint64_t *w0p=Bpb+(size_t)(2*p)*W, *w1p=Bpb+(size_t)(2*p+1)*W;
    for (int g=0;g<ng;g++){
      _mm_prefetch((const char*)(a0+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(a1+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(q1a+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(q1b+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(q2a+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(q2b+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(q3a+64*g+1024), _MM_HINT_T0);
      _mm_prefetch((const char*)(q3b+64*g+1024), _MM_HINT_T0);
      uint64_t parity0=0,parity1=0;
      for (int t=0;t<64;t+=32){
        __asm__ volatile("prefetchw %0" :: "m"(*(char*)(BI3b+((size_t)g*(h/2)+p)*128+2*t+256)));
        __asm__ volatile("prefetchw %0" :: "m"(*(char*)(BI3b+((size_t)g*(h/2)+p)*128+2*t+320)));
        __m256i va=_mm256_load_si256((const __m256i*)(a0+64*g+t));
        __m256i vb=_mm256_load_si256((const __m256i*)(a1+64*g+t));
        BQT(1,S1); BQT(2,S2); BQT(3,S3);
        __m256i lo=_mm256_unpacklo_epi8(va,vb), hi=_mm256_unpackhi_epi8(va,vb);
        int8_t *o=BI3b+((size_t)g*(h/2)+p)*128;
        _mm256_store_si256((__m256i*)(o+2*t),    (h==256?lo:_mm256_permute2x128_si256(lo,hi,0x20)));
        _mm256_store_si256((__m256i*)(o+2*t+32), (h==256?hi:_mm256_permute2x128_si256(lo,hi,0x31)));
        uint32_t mm0=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(va,7));
        uint32_t mm1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(vb,7));
        parity0 |= (uint64_t)mm0<<t; parity1 |= (uint64_t)mm1<<t;
      }
      w0p[g]=parity0; w1p[g]=parity1;
    }
  }
}

#define AQ_TERM(J) if (s##J){ __m256i _u0=_mm256_load_si256((const __m256i*)(p##J+k));          \
                              __m256i _u1=_mm256_load_si256((const __m256i*)(p##J+k+32));      \
                              if (s##J>0){ v0=_mm256_add_epi8(v0,_u0); v1=_mm256_add_epi8(v1,_u1); } \
                              else       { v0=_mm256_sub_epi8(v0,_u0); v1=_mm256_sub_epi8(v1,_u1); } }
#define BQ_TERM(J) if (s##J){ __m256i _x=_mm256_load_si256((const __m256i*)(q##J##a+64*g+t));   \
                              __m256i _y=_mm256_load_si256((const __m256i*)(q##J##b+64*g+t));   \
                              if (s##J>0){ va=_mm256_add_epi8(va,_x); vb=_mm256_add_epi8(vb,_y); } \
                              else       { va=_mm256_sub_epi8(va,_x); vb=_mm256_sub_epi8(vb,_y); } }

AVX2 static void buildA_q(int h,int n,const int8_t*X,int r0,int c0,
                          const int8_t*Y,int r1,int c1,int op){
  const __m256i mx=_mm256_set1_epi8(0x7F);
  int W=h/64;
  for (int i=0;i<h;i++){
    const int8_t*xa=X+(size_t)(r0+i)*n+c0, *ya=Y+(size_t)(r1+i)*n+c1;
    int8_t*dst=A0b+(size_t)i*GLDA;
    uint64_t*w1=A1b+(size_t)i*W;
    for (int k=0;k<h;k+=64){
      __m256i v0=_mm256_load_si256((const __m256i*)(xa+k));
      __m256i v1=_mm256_load_si256((const __m256i*)(xa+k+32));
      if (op){ __m256i u0=_mm256_load_si256((const __m256i*)(ya+k));
               __m256i u1=_mm256_load_si256((const __m256i*)(ya+k+32));
               if(op==1){ v0=_mm256_add_epi8(v0,u0); v1=_mm256_add_epi8(v1,u1); }
               else     { v0=_mm256_sub_epi8(v0,u0); v1=_mm256_sub_epi8(v1,u1); } }
      { __m256i _w0=_mm256_and_si256(v0,mx), _w1=_mm256_and_si256(v1,mx);
        __m256i _l0=_mm256_unpacklo_epi16(_w0,_w0), _h0=_mm256_unpackhi_epi16(_w0,_w0);
        __m256i _l1=_mm256_unpacklo_epi16(_w1,_w1), _h1=_mm256_unpackhi_epi16(_w1,_w1);
        _mm256_store_si256((__m256i*)(dst+2*k),    _mm256_permute2x128_si256(_l0,_h0,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+32), _mm256_permute2x128_si256(_l0,_h0,0x31));
        _mm256_store_si256((__m256i*)(dst+2*k+64), _mm256_permute2x128_si256(_l1,_h1,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+96), _mm256_permute2x128_si256(_l1,_h1,0x31)); }
      (h==256?A1b[(size_t)(k>>6)*h+i]:w1[k>>6])=(uint64_t)(uint32_t)_mm256_movemask_epi8(v0)
              |((uint64_t)(uint32_t)_mm256_movemask_epi8(v1)<<32);
    }
  }
}
AVX2 static void buildB_q(int h,int n,const int8_t*X,int r0,int c0,
                          const int8_t*Y,int r1,int c1,int op){
  const __m256i one=_mm256_set1_epi8(1);
  int ng=h/64, W=h/64;
  for (int p=0;p<h/2;p++){
    const int8_t *ra=X+(size_t)(r0+2*p)*n+c0,   *rb=X+(size_t)(r0+2*p+1)*n+c0;
    const int8_t *sa=Y+(size_t)(r1+2*p)*n+c1,   *sb=Y+(size_t)(r1+2*p+1)*n+c1;
    uint64_t *w0p=Bpb+(size_t)(2*p)*W, *w1p=Bpb+(size_t)(2*p+1)*W;
    for (int g=0;g<ng;g++){
      uint64_t parity0=0,parity1=0;
      for (int t=0;t<64;t+=32){
        __m256i va=_mm256_load_si256((const __m256i*)(ra+64*g+t));
        __m256i vb=_mm256_load_si256((const __m256i*)(rb+64*g+t));
        if (op){ __m256i pa=_mm256_load_si256((const __m256i*)(sa+64*g+t));
                 __m256i pb=_mm256_load_si256((const __m256i*)(sb+64*g+t));
                 if(op==1){ va=_mm256_add_epi8(va,pa); vb=_mm256_add_epi8(vb,pb); }
                 else     { va=_mm256_sub_epi8(va,pa); vb=_mm256_sub_epi8(vb,pb); } }
        __m256i lo=_mm256_unpacklo_epi8(va,vb), hi=_mm256_unpackhi_epi8(va,vb);
        int8_t *o=BI3b+((size_t)g*(h/2)+p)*128;
        _mm256_store_si256((__m256i*)(o+2*t),    (h==256?lo:_mm256_permute2x128_si256(lo,hi,0x20)));
        _mm256_store_si256((__m256i*)(o+2*t+32), (h==256?hi:_mm256_permute2x128_si256(lo,hi,0x31)));
        uint32_t mm0=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(va,7));
        uint32_t mm1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(vb,7));
        parity0 |= (uint64_t)mm0<<t; parity1 |= (uint64_t)mm1<<t;
      }
      w0p[g]=parity0; w1p[g]=parity1;
    }
  }
}


static int8_t S2M[7][1024*1024+24576]  __attribute__((aligned(64)));

static int8_t S3A[1024*1024]        __attribute__((aligned(64)));
static int8_t S3B[1024*1024]        __attribute__((aligned(64)));
static int8_t S3M[7][512*512+24576]    __attribute__((aligned(64)));

static int8_t S4A[512*512]          __attribute__((aligned(64)));
static int8_t S4B[512*512]          __attribute__((aligned(64)));
static int8_t S4M[7][256*256+24576]    __attribute__((aligned(64)));


AVX2 static void buildA_q4g(int h,int n,const int8_t*P,
                           int r0,int c0,int r1,int c1,int s1,
                           int r2,int c2,int s2, int r3,int c3,int s3){
  const __m256i mx=_mm256_set1_epi8(0x7F);
  int W=h/64;
  for (int i=0;i<h;i++){
    const int8_t*p0=P+(size_t)(r0+i)*n+c0, *p1=P+(size_t)(r1+i)*n+c1,
                 *p2=P+(size_t)(r2+i)*n+c2, *p3=P+(size_t)(r3+i)*n+c3;
    int8_t*dst=A0b+(size_t)i*GLDA;
    uint64_t*w1=A1b+(size_t)i*W;
    for (int k=0;k<h;k+=64){
      __m256i v0=_mm256_load_si256((const __m256i*)(p0+k));
      __m256i v1=_mm256_load_si256((const __m256i*)(p0+k+32));
      AQ_TERM(1); AQ_TERM(2); AQ_TERM(3);
      { __m256i _w0=_mm256_and_si256(v0,mx), _w1=_mm256_and_si256(v1,mx);
        __m256i _l0=_mm256_unpacklo_epi16(_w0,_w0), _h0=_mm256_unpackhi_epi16(_w0,_w0);
        __m256i _l1=_mm256_unpacklo_epi16(_w1,_w1), _h1=_mm256_unpackhi_epi16(_w1,_w1);
        _mm256_store_si256((__m256i*)(dst+2*k),    _mm256_permute2x128_si256(_l0,_h0,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+32), _mm256_permute2x128_si256(_l0,_h0,0x31));
        _mm256_store_si256((__m256i*)(dst+2*k+64), _mm256_permute2x128_si256(_l1,_h1,0x20));
        _mm256_store_si256((__m256i*)(dst+2*k+96), _mm256_permute2x128_si256(_l1,_h1,0x31)); }
      (h==256?A1b[(size_t)(k>>6)*h+i]:w1[k>>6])=(uint64_t)(uint32_t)_mm256_movemask_epi8(v0)
              |((uint64_t)(uint32_t)_mm256_movemask_epi8(v1)<<32);
    }
  }
}
AVX2 static void buildA_q4(int h,int n,const int8_t*P,
                           int r0,int c0,int r1,int c1,int s1,
                           int r2,int c2,int s2, int r3,int c3,int s3){
#define PACKA(S1,S2,S3) return buildA_q4t<S1,S2,S3>(h,n,P,r0,c0,r1,c1,r2,c2,r3,c3)
  if (s1==-1&&s2==-1&&s3== 1){ PACKA(-1,-1, 1); }
  if (s1==-1&&s2== 0&&s3== 0){ PACKA(-1, 0, 0); }
  if (s1==-1&&s2== 1&&s3==-1){ PACKA(-1, 1,-1); }
  if (s1== 0&&s2==-1&&s3== 0){ PACKA( 0,-1, 0); }
  if (s1== 0&&s2== 0&&s3== 0){ PACKA( 0, 0, 0); }
  if (s1== 0&&s2== 1&&s3== 0){ PACKA( 0, 1, 0); }
  if (s1== 1&&s2==-1&&s3==-1){ PACKA( 1,-1,-1); }
  if (s1== 1&&s2== 0&&s3== 0){ PACKA( 1, 0, 0); }
  if (s1== 1&&s2== 1&&s3== 1){ PACKA( 1, 1, 1); }

  buildA_q4g(h,n,P,r0,c0,r1,c1,s1,r2,c2,s2,r3,c3,s3);
}

AVX2 static void buildB_q4g(int h,int n,const int8_t*P,
                           int r0,int c0,int r1,int c1,int s1,
                           int r2,int c2,int s2, int r3,int c3,int s3){
  const __m256i one=_mm256_set1_epi8(1);
  int ng=h/64, W=h/64;
  for (int p=0;p<h/2;p++){
    const int8_t *a0=P+(size_t)(r0+2*p)*n+c0,   *a1=P+(size_t)(r0+2*p+1)*n+c0;
    const int8_t *q1a=P+(size_t)(r1+2*p)*n+c1,  *q1b=P+(size_t)(r1+2*p+1)*n+c1;
    const int8_t *q2a=P+(size_t)(r2+2*p)*n+c2,  *q2b=P+(size_t)(r2+2*p+1)*n+c2;
    const int8_t *q3a=P+(size_t)(r3+2*p)*n+c3,  *q3b=P+(size_t)(r3+2*p+1)*n+c3;
    uint64_t *w0p=Bpb+(size_t)(2*p)*W, *w1p=Bpb+(size_t)(2*p+1)*W;
    for (int g=0;g<ng;g++){
      uint64_t parity0=0,parity1=0;
      for (int t=0;t<64;t+=32){
        __m256i va=_mm256_load_si256((const __m256i*)(a0+64*g+t));
        __m256i vb=_mm256_load_si256((const __m256i*)(a1+64*g+t));
        BQ_TERM(1); BQ_TERM(2); BQ_TERM(3);
        __m256i lo=_mm256_unpacklo_epi8(va,vb), hi=_mm256_unpackhi_epi8(va,vb);
        int8_t *o=BI3b+((size_t)g*(h/2)+p)*128;
        _mm256_store_si256((__m256i*)(o+2*t),    (h==256?lo:_mm256_permute2x128_si256(lo,hi,0x20)));
        _mm256_store_si256((__m256i*)(o+2*t+32), (h==256?hi:_mm256_permute2x128_si256(lo,hi,0x31)));
        uint32_t mm0=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(va,7));
        uint32_t mm1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(vb,7));
        parity0 |= (uint64_t)mm0<<t; parity1 |= (uint64_t)mm1<<t;
      }
      w0p[g]=parity0; w1p[g]=parity1;
    }
  }
}

AVX2 static void buildB_q4(int h,int n,const int8_t*P,
                           int r0,int c0,int r1,int c1,int s1,
                           int r2,int c2,int s2, int r3,int c3,int s3){
#define PACKB(S1,S2,S3) return buildB_q4t<S1,S2,S3>(h,n,P,r0,c0,r1,c1,r2,c2,r3,c3)
  if (s1==-1&&s2==-1&&s3== 1){ PACKB(-1,-1, 1); }
  if (s1==-1&&s2== 0&&s3== 0){ PACKB(-1, 0, 0); }
  if (s1==-1&&s2== 1&&s3==-1){ PACKB(-1, 1,-1); }
  if (s1== 0&&s2==-1&&s3== 0){ PACKB( 0,-1, 0); }
  if (s1== 0&&s2== 0&&s3== 0){ PACKB( 0, 0, 0); }
  if (s1== 0&&s2== 1&&s3== 0){ PACKB( 0, 1, 0); }
  if (s1== 1&&s2==-1&&s3==-1){ PACKB( 1,-1,-1); }
  if (s1== 1&&s2== 0&&s3== 0){ PACKB( 1, 0, 0); }
  if (s1== 1&&s2== 1&&s3== 1){ PACKB( 1, 1, 1); }

  buildB_q4g(h,n,P,r0,c0,r1,c1,s1,r2,c2,s2,r3,c3,s3);
}


template<int Q>
AVX2 static void cmb4(int8_t *C,int n,int h,const int8_t (&M)[7][Q]){
  for(int i=0;i<h;i++){
    int8_t *r0=C+(size_t)i*n, *r1=C+(size_t)(i+h)*n;
    for(int j=0;j<h;j+=64){
      size_t t=(size_t)i*h+j;
      const __m256i a0=_mm256_load_si256((const __m256i*)(M[0]+t)), b0=_mm256_load_si256((const __m256i*)(M[0]+t+32));
      const __m256i a1=_mm256_load_si256((const __m256i*)(M[1]+t)), b1=_mm256_load_si256((const __m256i*)(M[1]+t+32));
      const __m256i a2=_mm256_load_si256((const __m256i*)(M[2]+t)), b2=_mm256_load_si256((const __m256i*)(M[2]+t+32));
      const __m256i a3=_mm256_load_si256((const __m256i*)(M[3]+t)), b3=_mm256_load_si256((const __m256i*)(M[3]+t+32));
      const __m256i a4=_mm256_load_si256((const __m256i*)(M[4]+t)), b4=_mm256_load_si256((const __m256i*)(M[4]+t+32));
      const __m256i a5=_mm256_load_si256((const __m256i*)(M[5]+t)), b5=_mm256_load_si256((const __m256i*)(M[5]+t+32));
      const __m256i a6=_mm256_load_si256((const __m256i*)(M[6]+t)), b6=_mm256_load_si256((const __m256i*)(M[6]+t+32));
      _mm256_stream_si256((__m256i*)(r0+j),
          _mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(a0,a3),a4),a6));
      _mm256_stream_si256((__m256i*)(r0+j+32),
          _mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(b0,b3),b4),b6));
      _mm256_stream_si256((__m256i*)(r0+h+j), _mm256_add_epi8(a2,a4));
      _mm256_stream_si256((__m256i*)(r0+h+j+32), _mm256_add_epi8(b2,b4));
      _mm256_stream_si256((__m256i*)(r1+j),   _mm256_add_epi8(a1,a3));
      _mm256_stream_si256((__m256i*)(r1+j+32), _mm256_add_epi8(b1,b3));
      _mm256_stream_si256((__m256i*)(r1+h+j),
          _mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(a0,a2),a1),a5));
      _mm256_stream_si256((__m256i*)(r1+h+j+32),
          _mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(b0,b2),b1),b5));
    }
  }
}

template<int Q>
AVX2 static void cmb4wb(int8_t *C,int n,int h,const int8_t (&M)[7][Q]){
  for(int i=0;i<h;i++){
    int8_t *r0=C+(size_t)i*n, *r1=C+(size_t)(i+h)*n;
    for(int j=0;j<h;j+=32){
      size_t t=(size_t)i*h+j;
      const __m256i m0=_mm256_load_si256((const __m256i*)(M[0]+t));
      const __m256i m1=_mm256_load_si256((const __m256i*)(M[1]+t));
      const __m256i m2=_mm256_load_si256((const __m256i*)(M[2]+t));
      const __m256i m3=_mm256_load_si256((const __m256i*)(M[3]+t));
      const __m256i m4=_mm256_load_si256((const __m256i*)(M[4]+t));
      const __m256i m5=_mm256_load_si256((const __m256i*)(M[5]+t));
      const __m256i m6=_mm256_load_si256((const __m256i*)(M[6]+t));
      _mm256_store_si256((__m256i*)(r0+j),
          _mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(m0,m3),m4),m6));
      _mm256_store_si256((__m256i*)(r0+h+j), _mm256_add_epi8(m2,m4));
      _mm256_store_si256((__m256i*)(r1+j),   _mm256_add_epi8(m1,m3));
      _mm256_store_si256((__m256i*)(r1+h+j),
          _mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(m0,m2),m1),m5));
    }
  }
}

AVX2 static void cmb(int8_t*C,int n,int r0,int c0,int m,
                     const int8_t*M0,int s0,const int8_t*M1,int s1,
                     const int8_t*M2,int s2,const int8_t*M3,int s3){
  for (int i=0;i<m;i++){
    int8_t *d=C+(size_t)(r0+i)*n+c0;
    const int8_t *p0=M0?M0+(size_t)i*m:0, *p1=M1?M1+(size_t)i*m:0;
    const int8_t *p2=M2?M2+(size_t)i*m:0, *p3=M3?M3+(size_t)i*m:0;
    for (int j=0;j<m;j+=32){
      __m256i v;
      if (p0){ __m256i t=_mm256_load_si256((const __m256i*)(p0+j));
               v = s0>0?t:_mm256_sub_epi8(_mm256_setzero_si256(),t); }
      else    v = _mm256_setzero_si256();
      if (p1){ __m256i t=_mm256_load_si256((const __m256i*)(p1+j));
               v = _mm256_add_epi8(v, s1>0?t:_mm256_sub_epi8(_mm256_setzero_si256(),t)); }
      if (p2){ __m256i t=_mm256_load_si256((const __m256i*)(p2+j));
               v = _mm256_add_epi8(v, s2>0?t:_mm256_sub_epi8(_mm256_setzero_si256(),t)); }
      if (p3){ __m256i t=_mm256_load_si256((const __m256i*)(p3+j));
               v = _mm256_add_epi8(v, s3>0?t:_mm256_sub_epi8(_mm256_setzero_si256(),t)); }
      _mm256_stream_si256((__m256i*)(d+j), v);
    }
  }
}


template<int OP>
AVX2 static void blk_t(int8_t*dst,const int8_t*X,int n,int r0,int c0,int h,
                     const int8_t*Y,int r1,int c1){
  const int B = h>>2, NB = 4;
  const size_t BB = (size_t)B*(size_t)B;
  for (int i=0;i<h;i++){
    const int8_t *xa=X+(size_t)(r0+i)*n+c0, *ya=Y+(size_t)(r1+i)*n+c1;
    int8_t *d0 = dst + (size_t)((i/B)*NB)*BB + (size_t)(i%B)*B;
    for (int J=0;J<NB;J++){
    int8_t *d = d0 + (size_t)J*BB;
    const int8_t *xaj = xa + J*B, *yaj = ya + J*B;
    int j=0;
    if (OP==0)      for(;j+32<=B;j+=32) _mm256_store_si256((__m256i*)(d+j),
                          _mm256_load_si256((const __m256i*)(xaj+j)));
    else if (OP==1) for(;j+32<=B;j+=32) _mm256_store_si256((__m256i*)(d+j),
                          _mm256_add_epi8(_mm256_load_si256((const __m256i*)(xaj+j)),
                                          _mm256_load_si256((const __m256i*)(yaj+j))));
    else            for(;j+32<=B;j+=32) _mm256_store_si256((__m256i*)(d+j),
                          _mm256_sub_epi8(_mm256_load_si256((const __m256i*)(xaj+j)),
                                          _mm256_load_si256((const __m256i*)(yaj+j))));
    if (OP) for(;j<B;j++) d[j]=(int8_t)(xaj[j]+(OP==1?yaj[j]:-yaj[j]));
    }
  }
}
AVX2 static void blk(int8_t*dst,const int8_t*X,int n,int r0,int c0,int h,
                     const int8_t*Y,int r1,int c1,int op){
  if (op==0)      blk_t<0>(dst,X,n,r0,c0,h,Y,r1,c1);
  else if (op==1) blk_t<1>(dst,X,n,r0,c0,h,Y,r1,c1);
  else            blk_t<2>(dst,X,n,r0,c0,h,Y,r1,c1);
}


template<int OP>
AVX2 static void blk_nt_t(int8_t*dst,const int8_t*X,int n,int r0,int c0,int h,
                     const int8_t*Y,int r1,int c1){
  for (int i=0;i<h;i++){
    const int8_t *xa=X+(size_t)(r0+i)*n+c0, *ya=Y+(size_t)(r1+i)*n+c1;
    int8_t *d=dst+(size_t)i*h;
    int j=0;
    if (OP==0)      for(;j+32<=h;j+=32) _mm256_stream_si256((__m256i*)(d+j),
                          _mm256_load_si256((const __m256i*)(xa+j)));
    else if (OP==1) for(;j+32<=h;j+=32) _mm256_stream_si256((__m256i*)(d+j),
                          _mm256_add_epi8(_mm256_load_si256((const __m256i*)(xa+j)),
                                          _mm256_load_si256((const __m256i*)(ya+j))));
    else            for(;j+32<=h;j+=32) _mm256_stream_si256((__m256i*)(d+j),
                          _mm256_sub_epi8(_mm256_load_si256((const __m256i*)(xa+j)),
                                          _mm256_load_si256((const __m256i*)(ya+j))));
    if (OP) for(;j<h;j++) d[j]=(int8_t)(xa[j]+(OP==1?ya[j]:-ya[j]));
  }
}
AVX2 static void blk_nt(int8_t*dst,const int8_t*X,int n,int r0,int c0,int h,
                     const int8_t*Y,int r1,int c1,int op){
  if (op==0)      blk_nt_t<0>(dst,X,n,r0,c0,h,Y,r1,c1);
  else if (op==1) blk_nt_t<1>(dst,X,n,r0,c0,h,Y,r1,c1);
  else            blk_nt_t<2>(dst,X,n,r0,c0,h,Y,r1,c1);
}



AVX2BMI static void corr1024(void);

AVX2BMI static void corr1024(void){
  const int n=1024, W=16;
  memset(Pbb,0,(size_t)n*W*8);
  const int KB=64;
  for (int kb=0; kb<n; kb+=KB){
    int w0=kb>>6;
    const char *bp0=(const char*)Bpb+(size_t)w0*8192;
    for (int i=0;i<n;i++){
      const uint64_t*row=A1b+(size_t)i*W+w0;
      uint64_t b0=row[0], b1=0;
      uint64_t *o=Pbb+(size_t)i*W;
      asm volatile(
        "vpxor %%xmm0,%%xmm0,%%xmm0\n\t"
        "vpxor %%xmm1,%%xmm1,%%xmm1\n\t"
        "vpxor %%xmm2,%%xmm2,%%xmm2\n\t"
        "vpxor %%xmm3,%%xmm3,%%xmm3\n\t"
        "testq %[b0], %[b0]\n\t"
        "jz 3%=f\n\t"
        "1%=:\n\t"
        "tzcntq %[b0], %%r11\n\t"
        "shlq $7, %%r11\n\t"
        "addq %[bp0], %%r11\n\t"
        "vpxor 0(%%r11), %%ymm0, %%ymm0\n\t"
        "vpxor 32(%%r11), %%ymm1, %%ymm1\n\t"
        "vpxor 64(%%r11), %%ymm2, %%ymm2\n\t"
        "vpxor 96(%%r11), %%ymm3, %%ymm3\n\t"
        "blsrq %[b0], %[b0]\n\t"
        "jnz 1%=b\n\t"
        "3%=:\n\t"
        "testq %[b1], %[b1]\n\t"
        "jz 4%=f\n\t"
        "2%=:\n\t"
        "tzcntq %[b1], %%r11\n\t"
        "shlq $7, %%r11\n\t"
        "addq %[bp0], %%r11\n\t"
        "vpxor 0(%%r11), %%ymm0, %%ymm0\n\t"
        "vpxor 32(%%r11), %%ymm1, %%ymm1\n\t"
        "vpxor 64(%%r11), %%ymm2, %%ymm2\n\t"
        "vpxor 96(%%r11), %%ymm3, %%ymm3\n\t"
        "blsrq %[b1], %[b1]\n\t"
        "jnz 2%=b\n\t"
        "4%=:\n\t"
        "vpxor   0(%[o]), %%ymm0, %%ymm0\n\t"
        "vmovdqu %%ymm0, 0(%[o])\n\t"
        "vpxor   32(%[o]), %%ymm1, %%ymm1\n\t"
        "vmovdqu %%ymm1, 32(%[o])\n\t"
        "vpxor   64(%[o]), %%ymm2, %%ymm2\n\t"
        "vmovdqu %%ymm2, 64(%[o])\n\t"
        "vpxor   96(%[o]), %%ymm3, %%ymm3\n\t"
        "vmovdqu %%ymm3, 96(%[o])\n\t"
        : [b0]"+r"(b0), [b1]"+r"(b1)
        : [bp0]"r"(bp0), [o]"r"(o)
        : "r11","cc","memory","ymm0","ymm1","ymm2","ymm3");
    }
  }
}


#define R2M_BMI2 __attribute__((target("avx2,bmi2")))
#define R2M_ROR(w,r) ((uint64_t)(((w)>>(r))|((w)<<(64-(r)))))
static uint64_t TB[((size_t)NMAX/64)*256] __attribute__((aligned(64)));


AVX2BMI static void nibtab_build(const uint64_t *__restrict r, uint64_t *__restrict T, int W){
  const int U = W>>2;                       
  const __m256i *rp = (const __m256i*)r;
  __m256i *tp = (__m256i*)T;
  for (int q=0;q<U;q++){
    const __m256i a1=rp[q], a2=rp[U+q], a4=rp[2*U+q], a8=rp[3*U+q];
    const __m256i x12=_mm256_xor_si256(a1,a2), x14=_mm256_xor_si256(a1,a4),
                  x18=_mm256_xor_si256(a1,a8);
    __m256i *o = tp+q;                      
    o[ 0*U]=_mm256_setzero_si256();
    o[ 1*U]=a1;      o[ 2*U]=a2;      o[ 4*U]=a4;      o[ 8*U]=a8;
    o[ 3*U]=x12;     o[ 5*U]=x14;
    o[ 6*U]=_mm256_xor_si256(a2,a4);   o[ 7*U]=_mm256_xor_si256(x12,a4);
    o[ 9*U]=x18;     o[10*U]=_mm256_xor_si256(a2,a8);
    o[12*U]=_mm256_xor_si256(a4,a8);
    o[11*U]=_mm256_xor_si256(a2,x18);  o[13*U]=_mm256_xor_si256(a4,x18);
    o[14*U]=_mm256_xor_si256(_mm256_xor_si256(a2,a4),a8);
    o[15*U]=_mm256_xor_si256(_mm256_xor_si256(x12,a4),a8);
  }
}

#define DEF_NIBCORR(TAG, M)                                                    \
AVX2BMI static void nibcorr##TAG(void){                                        \
  const int n=M, W=n/64, G=n>>2, GB=16, NY=W>>2;                               \
  memset(Pbb,0,(size_t)n*W*8);                                                 \
  for (int g0=0; g0<G; g0+=GB){                                                \
    for (int t=0;t<GB;t++){                                                    \
      const int g=g0+t;                                                        \
      uint64_t *T=TB+(size_t)t*16*W;                                           \
      const uint64_t *r=Bpb+(size_t)(g*4)*W;                                   \
            nibtab_build(r,T,W);                                                     \
                                                                        \
    }                                                                          \
    for (int i=0;i<n;i++){                                                     \
      const uint64_t *arow=A1b+(size_t)i*W+(g0>>4);                            \
      __m256i acc[NY];                                                         \
      for (int q=0;q<NY;q++) acc[q]=_mm256_setzero_si256();                    \
      const uint64_t *T=TB;                                                    \
      for (int wb=0; wb<(GB>>4); wb++){                                        \
        const uint64_t word=arow[wb];                                          \
        _Pragma("GCC unroll 16")                                               \
        for (int b=0;b<16;b++, T+=(size_t)16*W){                               \
          const uint64_t *e=T+(size_t)(((word>>(4*b))&15u)*W);                 \
          for (int q=0;q<NY;q++)                                               \
            acc[q]=_mm256_xor_si256(acc[q],_mm256_load_si256((const __m256i*)(e+4*q))); \
        }                                                                      \
      }                                                                        \
      uint64_t *o=Pbb+(size_t)i*W;                                             \
      for (int q=0;q<NY;q++){                                                  \
        __m256i *po=(__m256i*)(o+4*q);                                         \
        _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),acc[q])); \
      }                                                                        \
    }                                                                          \
  }                                                                            \
}
DEF_NIBCORR(512,512)

DEF_NIBCORR(256,256)
DEF_NIBCORR(1024,1024)

AVX2 static inline __attribute__((always_inline)) void mixed_build5(const uint64_t*r,__m256i*T){
 const __m256i r0=_mm256_load_si256((const __m256i*)(r+0));
 const __m256i r1=_mm256_load_si256((const __m256i*)(r+4));
 const __m256i r2=_mm256_load_si256((const __m256i*)(r+8));
 const __m256i r3=_mm256_load_si256((const __m256i*)(r+12));
 const __m256i r4=_mm256_load_si256((const __m256i*)(r+16));
 __m256i v=_mm256_setzero_si256();_mm256_store_si256(T,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+1,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+3,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+2,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+6,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+7,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+5,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+4,v);
 v=_mm256_xor_si256(v,r3);_mm256_store_si256(T+12,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+13,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+15,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+14,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+10,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+11,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+9,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+8,v);
 v=_mm256_xor_si256(v,r4);_mm256_store_si256(T+24,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+25,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+27,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+26,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+30,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+31,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+29,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+28,v);
 v=_mm256_xor_si256(v,r3);_mm256_store_si256(T+20,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+21,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+23,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+22,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+18,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+19,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+17,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+16,v);
}
AVX2 static inline __attribute__((always_inline)) void mixed_build6(const uint64_t*r,__m256i*T){
 const __m256i r0=_mm256_load_si256((const __m256i*)(r+0));
 const __m256i r1=_mm256_load_si256((const __m256i*)(r+4));
 const __m256i r2=_mm256_load_si256((const __m256i*)(r+8));
 const __m256i r3=_mm256_load_si256((const __m256i*)(r+12));
 const __m256i r4=_mm256_load_si256((const __m256i*)(r+16));
 const __m256i r5=_mm256_load_si256((const __m256i*)(r+20));
 __m256i v=_mm256_setzero_si256();_mm256_store_si256(T,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+1,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+3,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+2,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+6,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+7,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+5,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+4,v);
 v=_mm256_xor_si256(v,r3);_mm256_store_si256(T+12,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+13,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+15,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+14,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+10,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+11,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+9,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+8,v);
 v=_mm256_xor_si256(v,r4);_mm256_store_si256(T+24,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+25,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+27,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+26,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+30,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+31,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+29,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+28,v);
 v=_mm256_xor_si256(v,r3);_mm256_store_si256(T+20,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+21,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+23,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+22,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+18,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+19,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+17,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+16,v);
 v=_mm256_xor_si256(v,r5);_mm256_store_si256(T+48,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+49,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+51,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+50,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+54,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+55,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+53,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+52,v);
 v=_mm256_xor_si256(v,r3);_mm256_store_si256(T+60,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+61,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+63,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+62,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+58,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+59,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+57,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+56,v);
 v=_mm256_xor_si256(v,r4);_mm256_store_si256(T+40,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+41,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+43,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+42,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+46,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+47,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+45,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+44,v);
 v=_mm256_xor_si256(v,r3);_mm256_store_si256(T+36,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+37,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+39,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+38,v);
 v=_mm256_xor_si256(v,r2);_mm256_store_si256(T+34,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+35,v);
 v=_mm256_xor_si256(v,r1);_mm256_store_si256(T+33,v);
 v=_mm256_xor_si256(v,r0);_mm256_store_si256(T+32,v);
}
R2M_BMI2 static void corr_six256(){
 const char*tb=(const char*)TB;
 for(int wb=0;wb<4;wb++){
  for(int g=0;g<4;g++)mixed_build6(Bpb+(wb*64+g*6)*4,(__m256i*)TB+g*64);
  for(int g=0;g<8;g++)mixed_build5(Bpb+(wb*64+24+g*5)*4,(__m256i*)TB+256+g*32);
  for(int i=0;i<256;i+=2){
   uint64_t w0=A1b[wb*256+i],w1=A1b[wb*256+i+1];
   __m256i x0=wb?_mm256_load_si256((const __m256i*)(Pbb+i*4)):_mm256_setzero_si256();
   __m256i y0=wb?_mm256_load_si256((const __m256i*)(Pbb+(i+1)*4)):_mm256_setzero_si256();
   __m256i x1=_mm256_setzero_si256(),y1=x1;
   x0=_mm256_xor_si256(x0,_mm256_load_si256((const __m256i*)(tb+0+(R2M_ROR(w0,59)&2016))));
   y0=_mm256_xor_si256(y0,_mm256_load_si256((const __m256i*)(tb+0+(R2M_ROR(w1,59)&2016))));
   x1=_mm256_xor_si256(x1,_mm256_load_si256((const __m256i*)(tb+2048+(R2M_ROR(w0,1)&2016))));
   y1=_mm256_xor_si256(y1,_mm256_load_si256((const __m256i*)(tb+2048+(R2M_ROR(w1,1)&2016))));
   x0=_mm256_xor_si256(x0,_mm256_load_si256((const __m256i*)(tb+4096+(R2M_ROR(w0,7)&2016))));
   y0=_mm256_xor_si256(y0,_mm256_load_si256((const __m256i*)(tb+4096+(R2M_ROR(w1,7)&2016))));
   x1=_mm256_xor_si256(x1,_mm256_load_si256((const __m256i*)(tb+6144+(R2M_ROR(w0,13)&2016))));
   y1=_mm256_xor_si256(y1,_mm256_load_si256((const __m256i*)(tb+6144+(R2M_ROR(w1,13)&2016))));
   x0=_mm256_xor_si256(x0,_mm256_load_si256((const __m256i*)(tb+8192+(R2M_ROR(w0,19)&992))));
   y0=_mm256_xor_si256(y0,_mm256_load_si256((const __m256i*)(tb+8192+(R2M_ROR(w1,19)&992))));
   x1=_mm256_xor_si256(x1,_mm256_load_si256((const __m256i*)(tb+9216+(R2M_ROR(w0,24)&992))));
   y1=_mm256_xor_si256(y1,_mm256_load_si256((const __m256i*)(tb+9216+(R2M_ROR(w1,24)&992))));
   x0=_mm256_xor_si256(x0,_mm256_load_si256((const __m256i*)(tb+10240+(R2M_ROR(w0,29)&992))));
   y0=_mm256_xor_si256(y0,_mm256_load_si256((const __m256i*)(tb+10240+(R2M_ROR(w1,29)&992))));
   x1=_mm256_xor_si256(x1,_mm256_load_si256((const __m256i*)(tb+11264+(R2M_ROR(w0,34)&992))));
   y1=_mm256_xor_si256(y1,_mm256_load_si256((const __m256i*)(tb+11264+(R2M_ROR(w1,34)&992))));
   x0=_mm256_xor_si256(x0,_mm256_load_si256((const __m256i*)(tb+12288+(R2M_ROR(w0,39)&992))));
   y0=_mm256_xor_si256(y0,_mm256_load_si256((const __m256i*)(tb+12288+(R2M_ROR(w1,39)&992))));
   x1=_mm256_xor_si256(x1,_mm256_load_si256((const __m256i*)(tb+13312+(R2M_ROR(w0,44)&992))));
   y1=_mm256_xor_si256(y1,_mm256_load_si256((const __m256i*)(tb+13312+(R2M_ROR(w1,44)&992))));
   x0=_mm256_xor_si256(x0,_mm256_load_si256((const __m256i*)(tb+14336+(R2M_ROR(w0,49)&992))));
   y0=_mm256_xor_si256(y0,_mm256_load_si256((const __m256i*)(tb+14336+(R2M_ROR(w1,49)&992))));
   x1=_mm256_xor_si256(x1,_mm256_load_si256((const __m256i*)(tb+15360+(R2M_ROR(w0,54)&992))));
   y1=_mm256_xor_si256(y1,_mm256_load_si256((const __m256i*)(tb+15360+(R2M_ROR(w1,54)&992))));
   _mm256_store_si256((__m256i*)(Pbb+i*4),_mm256_xor_si256(x0,x1));
   _mm256_store_si256((__m256i*)(Pbb+(i+1)*4),_mm256_xor_si256(y0,y1));
  }
 }
}

AVX2 static void submm_tail(int m,int8_t*Cp){
  GLDA = 2*(m) + PADA; GLDB = m + PADB;
  
  
  if (m==1024) nibcorr1024(); else if (m==512) nibcorr512();
  else if (m==256) corr_six256(); else corr_pass3(m);
  const int GB=1024, IB=1024;
  for (int ib=0; ib<m; ib+=IB){
    const int ihi = (ib+IB<m)? ib+IB : m;
    for (int gb=0; gb<m; gb+=GB){
      const int ghi = (gb+GB<m)? gb+GB : m;
      for (int g=gb; g<ghi; g+=64){
        const int8_t *bi = BI3b+(size_t)(g>>6)*(m/2)*128;
        { int rev=0;
        for (int i=ib; i<ihi; i+=2){
          
          const int8_t *ap=A0b+(size_t)i*GLDA;
          
          const uint8_t *pw = (const uint8_t*)(Pbb+(size_t)i*(m>>6)+(g>>6));
          if(m==256) mikro_u4<true>(m,ap,bi,Cp+(size_t)i*m+g,pw,0,GLDA,(m>>6)*8);
          else mikro_u4<false>(m,ap,bi,Cp+(size_t)i*m+g,pw,0,GLDA,(m>>6)*8);
          rev^=1; }
        }
      }
    }
  }
}


AVX2 static void submm_plain(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  GLDA = 2*(m) + PADA; GLDB = m + PADB;
  build_A0A1(m,Ap); build_BI3Bp(m,Bp); submm_tail(m,Cp);
}

AVX2 static void submm(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp);
#define S2MIN 1024


AVX2 static void submm_s4(int m,const int8_t*X,const int8_t*Y,int8_t*dst);


AVX2 static void submm_s5f(int M,const int8_t*Ap,int Aa0,int Aa1,int Aa2,int Aa3,int Aop,
                           const int8_t*Bp,int Ba0,int Ba1,int Ba2,int Ba3,int Bop,int8_t*Cp);
AVX2 static void submm_s5f(int M,const int8_t*Ap,int Aa0,int Aa1,int Aa2,int Aa3,int Aop,
                           const int8_t*Bp,int Ba0,int Ba1,int Ba2,int Ba3,int Bop,int8_t*Cp){
  const int h=M>>2, o=h;
  
  #define NRB(rr,cc) ((((rr)/h)*4 + ((cc)/h))*(h))                       
  const int SQA=(Aop==1)?1:((Aop==2)?-1:0);    
  const int SQB=(Bop==1)?1:((Bop==2)?-1:0);
  const int dz=M>>1;                           
  GLDA = 2*h + PADA; GLDB = h + PADB;
  for (int k=0;k<7;k++){
    switch(k){
      case 0: buildA_q4(h,h,Ap,NRB(Aa0,Aa1),0, NRB(Aa2,Aa3),0,SQA, NRB(Aa0+o,Aa1+o),0,+1, NRB(Aa2+o,Aa3+o),0,(SQA)*(+1));
              buildB_q4(h,h,Bp,NRB(Ba0,Ba1),0, NRB(Ba2,Ba3),0,SQB, NRB(Ba0+o,Ba1+o),0,+1, NRB(Ba2+o,Ba3+o),0,(SQB)*(+1));
              submm_tail(h,S4M[0]); break;
      case 1: buildA_q4(h,h,Ap,NRB(Aa0+o,Aa1),0, NRB(Aa2+o,Aa3),0,SQA, NRB(Aa0+o,Aa1+o),0,+1, NRB(Aa2+o,Aa3+o),0,(SQA)*(+1));
              buildB_q4(h,h,Bp,NRB(Ba0,Ba1),0, NRB(Ba2,Ba3),0,SQB, NRB(Ba0,Ba1),0,+0, NRB(Ba2,Ba3),0,(SQB)*(+0));
              submm_tail(h,S4M[1]); break;
      case 2: buildA_q4(h,h,Ap,NRB(Aa0,Aa1),0, NRB(Aa2,Aa3),0,SQA, NRB(Aa0,Aa1),0,+0, NRB(Aa2,Aa3),0,(SQA)*(+0));
              buildB_q4(h,h,Bp,NRB(Ba0,Ba1+o),0, NRB(Ba2,Ba3+o),0,SQB, NRB(Ba0+o,Ba1+o),0,-1, NRB(Ba2+o,Ba3+o),0,(SQB)*(-1));
              submm_tail(h,S4M[2]); break;
      case 3: buildA_q4(h,h,Ap,NRB(Aa0+o,Aa1+o),0, NRB(Aa2+o,Aa3+o),0,SQA, NRB(Aa0+o,Aa1+o),0,+0, NRB(Aa2+o,Aa3+o),0,(SQA)*(+0));
              buildB_q4(h,h,Bp,NRB(Ba0+o,Ba1),0, NRB(Ba2+o,Ba3),0,SQB, NRB(Ba0,Ba1),0,-1, NRB(Ba2,Ba3),0,(SQB)*(-1));
              submm_tail(h,S4M[3]); break;
      case 4: buildA_q4(h,h,Ap,NRB(Aa0,Aa1),0, NRB(Aa2,Aa3),0,SQA, NRB(Aa0,Aa1+o),0,+1, NRB(Aa2,Aa3+o),0,(SQA)*(+1));
              buildB_q4(h,h,Bp,NRB(Ba0+o,Ba1+o),0, NRB(Ba2+o,Ba3+o),0,SQB, NRB(Ba0+o,Ba1+o),0,+0, NRB(Ba2+o,Ba3+o),0,(SQB)*(+0));
              submm_tail(h,S4M[4]); break;
      case 5: buildA_q4(h,h,Ap,NRB(Aa0+o,Aa1),0, NRB(Aa2+o,Aa3),0,SQA, NRB(Aa0,Aa1),0,-1, NRB(Aa2,Aa3),0,(SQA)*(-1));
              buildB_q4(h,h,Bp,NRB(Ba0,Ba1),0, NRB(Ba2,Ba3),0,SQB, NRB(Ba0,Ba1+o),0,+1, NRB(Ba2,Ba3+o),0,(SQB)*(+1));
              submm_tail(h,S4M[5]); break;
      case 6: buildA_q4(h,h,Ap,NRB(Aa0,Aa1+o),0, NRB(Aa2,Aa3+o),0,SQA, NRB(Aa0+o,Aa1+o),0,-1, NRB(Aa2+o,Aa3+o),0,(SQA)*(-1));
              buildB_q4(h,h,Bp,NRB(Ba0+o,Ba1),0, NRB(Ba2+o,Ba3),0,SQB, NRB(Ba0+o,Ba1+o),0,+1, NRB(Ba2+o,Ba3+o),0,(SQB)*(+1));
              submm_tail(h,S4M[6]); break;
    }
  }
  #undef NRB
  _mm_sfence();
  cmb4wb(Cp,dz,h,S4M);   
  _mm_sfence();
}

AVX2 static void submm_s5(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp);
AVX2 static void submm_s5(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  GLDA = 2*((m>>1)) + PADA; GLDB = (m>>1) + PADB;
  const int h=m>>1, o=h;
  for (int k=0;k<7;k++){
    switch(k){
      case 0: buildA_q(h,m,Ap,0,0,Ap,o,o,1); buildB_q(h,m,Bp,0,0,Bp,o,o,1);  submm_tail(h,S4M[0]); break;
      case 1: buildA_q(h,m,Ap,o,0,Ap,o,o,1); buildB_q(h,m,Bp,0,0,Bp,0,0,0);  submm_tail(h,S4M[1]); break;
      case 2: buildA_q(h,m,Ap,0,0,Ap,0,0,0); buildB_q(h,m,Bp,0,o,Bp,o,o,2);  submm_tail(h,S4M[2]); break;
      case 3: buildA_q(h,m,Ap,o,o,Ap,o,o,0); buildB_q(h,m,Bp,o,0,Bp,0,0,2);  submm_tail(h,S4M[3]); break;
      case 4: buildA_q(h,m,Ap,0,0,Ap,0,o,1); buildB_q(h,m,Bp,o,o,Bp,o,o,0);  submm_tail(h,S4M[4]); break;
      case 5: buildA_q(h,m,Ap,o,0,Ap,0,0,2); buildB_q(h,m,Bp,0,0,Bp,0,o,1);  submm_tail(h,S4M[5]); break;
      case 6: buildA_q(h,m,Ap,0,o,Ap,o,o,2); buildB_q(h,m,Bp,o,0,Bp,o,o,1);  submm_tail(h,S4M[6]); break;
    }
  }
  _mm_sfence();
  cmb(Cp,m,0,0,h, S4M[0],1,S4M[3],1,S4M[4],-1,S4M[6],1);
  cmb(Cp,m,0,o,h, S4M[2],1,S4M[4],1,0,0,0,0);
  cmb(Cp,m,o,0,h, S4M[1],1,S4M[3],1,0,0,0,0);
  cmb(Cp,m,o,o,h, S4M[0],1,S4M[2],1,S4M[1],-1,S4M[5],1);
  _mm_sfence();
}
AVX2 static void submm_s4(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  GLDA = 2*((m>>1)) + PADA; GLDB = (m>>1) + PADB;
  const int h=m>>1, o=h;
  for (int k=0;k<7;k++){
    switch(k){
      case 0: submm_s5f(m,Ap,0,0,o,o,1, Bp,0,0,o,o,1, S3M[0]); break;
      case 1: submm_s5f(m,Ap,o,0,o,o,1, Bp,0,0,0,0,0, S3M[1]); break;
      case 2: submm_s5f(m,Ap,0,0,0,0,0, Bp,0,o,o,o,2, S3M[2]); break;
      case 3: submm_s5f(m,Ap,o,o,o,o,0, Bp,o,0,0,0,2, S3M[3]); break;
      case 4: submm_s5f(m,Ap,0,0,0,o,1, Bp,o,o,o,o,0, S3M[4]); break;
      case 5: submm_s5f(m,Ap,o,0,0,0,2, Bp,0,0,0,o,1, S3M[5]); break;
      case 6: submm_s5f(m,Ap,0,o,o,o,2, Bp,o,0,o,o,1, S3M[6]); break;
    }
  }
  _mm_sfence();
  cmb4(Cp,m,h,S3M);
  _mm_sfence();
}
AVX2 static void build_combsA5t(const int8_t*X,int n,int h,int8_t*o0,int8_t*o1,int8_t*o4,int8_t*o5,int8_t*o6){
  const int B=h>>2, BB=B*B;
  for(int i=0;i<h;i++){
    const int8_t*p00=X+(size_t)i*n, *p01=p00+h, *p10=p00+(size_t)h*n, *p11=p10+h;
    const size_t base=(size_t)((i/B)*4)*BB+(size_t)(i%B)*B;
    for(int J=0;J<4;J++){
      const int8_t*x00=p00+J*B,*x01=p01+J*B,*x10=p10+J*B,*x11=p11+J*B;
      const size_t o=base+(size_t)J*BB;
      for(int j=0;j<B;j+=64){
        __m256i v00=_mm256_load_si256((const __m256i*)(x00+j)), w00=_mm256_load_si256((const __m256i*)(x00+j+32));
        __m256i v01=_mm256_load_si256((const __m256i*)(x01+j)), w01=_mm256_load_si256((const __m256i*)(x01+j+32));
        __m256i v10=_mm256_load_si256((const __m256i*)(x10+j)), w10=_mm256_load_si256((const __m256i*)(x10+j+32));
        __m256i v11=_mm256_load_si256((const __m256i*)(x11+j)), w11=_mm256_load_si256((const __m256i*)(x11+j+32));
        _mm256_stream_si256((__m256i*)(o0+o+j),_mm256_add_epi8(v00,v11));
        _mm256_stream_si256((__m256i*)(o0+o+j+32),_mm256_add_epi8(w00,w11));
        _mm256_stream_si256((__m256i*)(o1+o+j),_mm256_add_epi8(v10,v11));
        _mm256_stream_si256((__m256i*)(o1+o+j+32),_mm256_add_epi8(w10,w11));
        _mm256_stream_si256((__m256i*)(o4+o+j),_mm256_add_epi8(v00,v01));
        _mm256_stream_si256((__m256i*)(o4+o+j+32),_mm256_add_epi8(w00,w01));
        _mm256_stream_si256((__m256i*)(o5+o+j),_mm256_sub_epi8(v10,v00));
        _mm256_stream_si256((__m256i*)(o5+o+j+32),_mm256_sub_epi8(w10,w00));
        _mm256_stream_si256((__m256i*)(o6+o+j),_mm256_sub_epi8(v01,v11));
        _mm256_stream_si256((__m256i*)(o6+o+j+32),_mm256_sub_epi8(w01,w11));
      }
    }
  }
  _mm_sfence();
}
AVX2 static void submm_s2(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp,int la,int lb){
  GLDA = 2*((m>>1)) + PADA; GLDB = (m>>1) + PADB;
  const int h=m>>1, o=h;
  build_combsA5t(Ap,la,h,S2M[0],S2M[1],S2M[4],S2M[5],S2M[6]);
  for (int k=0;k<7;k++){
    switch(k){
      case 0: blk(S3B,Bp,lb,0,0,h,Bp,o,o,1); submm_s4(h,S2M[0],S3B,S2M[0]); break;
      case 1: blk(S3B,Bp,lb,0,0,h,Bp,0,0,0); submm_s4(h,S2M[1],S3B,S2M[1]); break;
      case 2: blk(S3A,Ap,la,0,0,h,Ap,0,0,0); blk(S3B,Bp,lb,0,o,h,Bp,o,o,2); submm_s4(h,S3A,S3B,S2M[2]); break;
      case 3: blk(S3A,Ap,la,o,o,h,Ap,o,o,0); blk(S3B,Bp,lb,o,0,h,Bp,0,0,2); submm_s4(h,S3A,S3B,S2M[3]); break;
      case 4: blk(S3B,Bp,lb,o,o,h,Bp,o,o,0); submm_s4(h,S2M[4],S3B,S2M[4]); break;
      case 5: blk(S3B,Bp,lb,0,0,h,Bp,0,o,1); submm_s4(h,S2M[5],S3B,S2M[5]); break;
      case 6: blk(S3B,Bp,lb,o,0,h,Bp,o,o,1); submm_s4(h,S2M[6],S3B,S2M[6]); break;
    }
  }
  _mm_sfence();
  cmb4(Cp,m,h,S2M);
  _mm_sfence();
}
AVX2 static void submm(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  if (m>=S2MIN) { submm_s2(m,Ap,Bp,Cp,m,m); return; }
  submm_plain(m,Ap,Bp,Cp);
}


static volatile char r9c4k_pad64[312] __attribute__((used));

AVX2 static void build_combsA5(const int8_t*X,int n,int m,int8_t*o0,int8_t*o1,int8_t*o4,int8_t*o5,int8_t*o6){
  for(int i=0;i<m;i++){
    const int8_t*p00=X+(size_t)i*n, *p01=p00+m, *p10=p00+(size_t)m*n, *p11=p10+m;
    int8_t*d0=o0+(size_t)i*m,*d1=o1+(size_t)i*m,*d4=o4+(size_t)i*m,*d5=o5+(size_t)i*m,*d6=o6+(size_t)i*m;
    for(int j=0;j<m;j+=64){
      __m256i v00=_mm256_loadu_si256((const __m256i*)(p00+j)), w00=_mm256_loadu_si256((const __m256i*)(p00+j+32));
      __m256i v01=_mm256_loadu_si256((const __m256i*)(p01+j)), w01=_mm256_loadu_si256((const __m256i*)(p01+j+32));
      __m256i v10=_mm256_loadu_si256((const __m256i*)(p10+j)), w10=_mm256_loadu_si256((const __m256i*)(p10+j+32));
      __m256i v11=_mm256_loadu_si256((const __m256i*)(p11+j)), w11=_mm256_loadu_si256((const __m256i*)(p11+j+32));
      _mm256_stream_si256((__m256i*)(d0+j),_mm256_add_epi8(v00,v11));
      _mm256_stream_si256((__m256i*)(d0+j+32),_mm256_add_epi8(w00,w11));
      _mm256_stream_si256((__m256i*)(d1+j),_mm256_add_epi8(v10,v11));
      _mm256_stream_si256((__m256i*)(d1+j+32),_mm256_add_epi8(w10,w11));
      _mm256_stream_si256((__m256i*)(d4+j),_mm256_add_epi8(v00,v01));
      _mm256_stream_si256((__m256i*)(d4+j+32),_mm256_add_epi8(w00,w01));
      _mm256_stream_si256((__m256i*)(d5+j),_mm256_sub_epi8(v10,v00));
      _mm256_stream_si256((__m256i*)(d5+j+32),_mm256_sub_epi8(w10,w00));
      _mm256_stream_si256((__m256i*)(d6+j),_mm256_sub_epi8(v01,v11));
      _mm256_stream_si256((__m256i*)(d6+j+32),_mm256_sub_epi8(w01,w11));
    }
  }

  _mm_sfence();
}
AVX2 static void build_combsB5(const int8_t*X,int n,int m,int8_t*o0,int8_t*o2,int8_t*o3,int8_t*o5,int8_t*o6){
  for(int i=0;i<m;i++){
    const int8_t*p00=X+(size_t)i*n, *p01=p00+m, *p10=p00+(size_t)m*n, *p11=p10+m;
    int8_t*d0=o0+(size_t)i*m,*d2=o2+(size_t)i*m,*d3=o3+(size_t)i*m,*d5=o5+(size_t)i*m,*d6=o6+(size_t)i*m;
    for(int j=0;j<m;j+=64){
      __m256i v00=_mm256_loadu_si256((const __m256i*)(p00+j)), w00=_mm256_loadu_si256((const __m256i*)(p00+j+32));
      __m256i v01=_mm256_loadu_si256((const __m256i*)(p01+j)), w01=_mm256_loadu_si256((const __m256i*)(p01+j+32));
      __m256i v10=_mm256_loadu_si256((const __m256i*)(p10+j)), w10=_mm256_loadu_si256((const __m256i*)(p10+j+32));
      __m256i v11=_mm256_loadu_si256((const __m256i*)(p11+j)), w11=_mm256_loadu_si256((const __m256i*)(p11+j+32));
      _mm256_stream_si256((__m256i*)(d0+j),_mm256_add_epi8(v00,v11));
      _mm256_stream_si256((__m256i*)(d0+j+32),_mm256_add_epi8(w00,w11));
      _mm256_stream_si256((__m256i*)(d2+j),_mm256_sub_epi8(v01,v11));
      _mm256_stream_si256((__m256i*)(d2+j+32),_mm256_sub_epi8(w01,w11));
      _mm256_stream_si256((__m256i*)(d3+j),_mm256_sub_epi8(v10,v00));
      _mm256_stream_si256((__m256i*)(d3+j+32),_mm256_sub_epi8(w10,w00));
      _mm256_stream_si256((__m256i*)(d5+j),_mm256_add_epi8(v00,v01));
      _mm256_stream_si256((__m256i*)(d5+j+32),_mm256_add_epi8(w00,w01));
      _mm256_stream_si256((__m256i*)(d6+j),_mm256_add_epi8(v10,v11));
      _mm256_stream_si256((__m256i*)(d6+j+32),_mm256_add_epi8(w10,w11));
    }
  }
  _mm_sfence();
}
AVX2 static void strassen1(int n,const int8_t*A,const int8_t*B,int8_t*C){
  const int m=n>>1, o=m;
  int8_t*a0=MMS[0],*a1=MMS[1],*a4=MMS[4],*a5=MMS[5],*a6=MMS[6];
  build_combsA5(A,n,m,a0,a1,a4,a5,a6);
  const size_t SZ=(size_t)m*m;
  int8_t*b2=MMS[2],*b3=MMS[3],*b0=C,*b5=C+SZ,*b6=C+2*SZ;
  build_combsB5(B,n,m,b0,b2,b3,b5,b6);
  for (int k=0;k<7;k++){
    const int8_t*pa=a0;int la=m;const int8_t*pb=b2;int lb=m;
    switch(k){
      case 0: pb=b0; break;
      case 1: pa=a1; pb=B; lb=n; break;
      case 2: pa=A; la=n; pb=b2; break;
      case 3: pa=A+(size_t)o*n+o; la=n; pb=b3; break;
      case 4: pa=a4; pb=B+(size_t)o*n+o; lb=n; break;
      case 5: pa=a5; pb=b5; break;
      case 6: pa=a6; pb=b6; break;
    }
    submm_s2(m,pa,pb,MMS[k],la,lb);
  }
  _mm_sfence();
  cmb4(C,n,m,MMS);
  _mm_sfence();
}
AVX2 void matrix_multiply(int n, const int8_t *A, const int8_t *B, int8_t *C){
  if (n<=0 || (n&255) || n>NMAX) { generic_mm(n,A,B,C); return; }
  if (n==4096) { strassen1(n,A,B,C); return; }
  
  
  GLDA = 2*(n) + PADA; GLDB = n + PADB;
  build_A0A1(n,A); build_BI3Bp(n,B);
  if (n==4096) corr16(); else corr_pass3(n);
  
  {
    const int GB=128, IB=64;
    for (int ib=0; ib<n; ib+=IB){
      const int ihi = (ib+IB<n)? ib+IB : n;
      for (int gb=0; gb<n; gb+=GB){
        const int ghi = (gb+GB<n)? gb+GB : n;
        for (int g=gb; g<ghi; g+=64){
          const int8_t *bi = BI3b+(size_t)(g>>6)*(n/2)*128;
          int rev=0;
          for (int i=ib; i<ihi; i+=2){
            const int8_t *ap = A0b+(size_t)i*GLDA;
            const uint8_t *pw = (const uint8_t*)(Pbb+(size_t)i*(n>>6)+(g>>6));
            if (rev) mikro_u4r(n, ap+(2*n)-16, bi,
                               C+(size_t)i*n+g, pw, 0, GLDA, (n>>6)*8);
            else     mikro_u4 (n, ap, bi,
                               C+(size_t)i*n+g, pw, 0, GLDA, (n>>6)*8);
            rev^=1;
          }
        }
      }
    }
  }
  _mm_sfence();
  __asm__ __volatile__(".space 16, 0x90");   /* r9c4k_ state-vs-placement test */
}


CompilationN/AN/ACompile OKScore: N/A

Testcase #1329.641 ms55 MB + 568 KBAcceptedScore: 100


Judge Duck Online | 评测鸭在线
Server Time: 2026-11-02 02:01:28 | Loaded in 2 ms | Server Status
个人娱乐项目,仅供学习交流使用 | 捐赠