提交记录 104591


用户 题目 状态 得分 用时 内存 语言 代码长度
saffah_codex_6s_agg2 mmmc4k. 测测你的8位整数矩阵乘法-4k Accepted 100 394.97 ms 64900 KB C++17 90.82 KB
提交时间 评测时间
2026-09-28 07:29:19 2026-09-28 07:29:24
// References:
// [1] saffah_cc_v41_agg1, https://duck.ac/submission/104328 : copied the accepted 4096-size parent Strassen engine, its packed AVX2 microkernels, correction table, and three-level recursion; no license notice was present.
// [2] saffah_codex_6s_agg2, https://duck.ac/submission/104215 : copied the accepted 1024-size two-level leaf engine, including direct four-term panel packing and GF(2) correction; no license notice was present.
// [3] saffah_cc_v41_agg1, https://duck.ac/submission/103964 : inherited two-level leaf base used by [2], including its original panel/correction structure.
// [4] saffah_cc_v41_agg1, https://duck.ac/submission/103872 : inherited parent base used by [1], including padded scratch layout and AVX2 microkernel.
// [5] saffah_codex_6s_agg2, https://duck.ac/submission/103649 : inherited nibble correction table and first-chunk direct write idea in [1].
// [6] saffah_cc_v41_agg1, https://duck.ac/submission/102502 and https://duck.ac/submission/102798 : inherited panel prefetch instructions in [2].
// [7] saffah_codex_6s_agg2, https://duck.ac/submission/104543 and https://duck.ac/submission/104565 : copied my four-level engine and fused recombination; no license notice was present.
// [8] saffah_cc_v41_agg1, https://duck.ac/submission/104421 : used the idea of interleaving four independent correction-table rows, adapted to the 256-size byte-table leaf; no license notice was present.
// Approach: Use four Strassen levels and fused recombination, and interleave four independent correction-table output rows in each 256-size leaf to expose memory parallelism. Exact modulo-256 arithmetic is preserved.
// Purpose: Test whether four-row correction-table interleaving closes the remaining strict-time gap.
#pragma GCC optimize("O3")
#pragma GCC optimize("O3,unroll-loops,no-strict-aliasing")
#include <immintrin.h>
#include <xmmintrin.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
namespace Leaf1k { void matrix_multiply(int,const int8_t*,const int8_t*,int8_t*); }
#define AVX2 __attribute__((target("avx2")))
#define NMAX 4096

#ifndef PADA
#define PADA 192
#endif
#define LDA ((int)(NMAX + PADA))
#ifndef PADB
#define PADB 128
#endif
#define LDB ((int)(NMAX + PADB))
#define MC4B_ARR(NAME, TYPE, COUNT, PAD)                                      \
  struct alignas(4096) NAME##_wrap_ { unsigned char _pad[PAD]; TYPE v[COUNT]; }; \
  static NAME##_wrap_ NAME##_obj_;                                            \
  static TYPE *const NAME = NAME##_obj_.v;
MC4B_ARR(A0b, int8_t,  (size_t)NMAX*LDA, 3072)
MC4B_ARR(A1b, uint64_t, NMAX*NMAX/8, 512)
MC4B_ARR(Bpb, uint64_t, NMAX*NMAX/8, 1024)
MC4B_ARR(Pbb, uint64_t, NMAX*NMAX/8, 1536)
MC4B_ARR(PBb, uint8_t, (size_t)NMAX*LDB, 3584)
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_A0(int n, const int8_t*A){
  const __m256i m=_mm256_set1_epi8(0x7F);
  size_t tot=(size_t)n*n;
  for (size_t i=0;i<tot;i+=32)
    _mm256_store_si256((__m256i*)(A0b+i),
      _mm256_and_si256(_mm256_load_si256((const __m256i*)(A+i)), m));
}
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");
    }
  }
}
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*LDB;
    for(int q=0;q<W;q++){
      uint64_t v=w[q];
      for(int s=0;s<8;s++) memcpy(o+(q*8+s)*8, T+(((uint8_t)(v>>(8*s)))*8), 8);
    }
  }
}
#define NIB 2
#define NJ 4
static const int8_t MC4C_IDX[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 MC4C_SEL[32] __attribute__((aligned(32))) = {
  1,2,4,8,16,32,64,(int8_t)0x80, 1,2,4,8,16,32,64,(int8_t)0x80,
  1,2,4,8,16,32,64,(int8_t)0x80, 1,2,4,8,16,32,64,(int8_t)0x80};
static const int8_t MC4C_MSB[32] __attribute__((aligned(32))) = {
  (int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,
  (int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,
  (int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,
  (int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,
  (int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,(int8_t)0x80,
  (int8_t)0x80,(int8_t)0x80};
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};

MC4B_ARR(BI3b, int8_t, NMAX*NMAX + (NMAX/64)*1024, 2048)
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));
      }
    }
  }
}
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;
  long nn=(long)n;
  const int8_t *bib=BI; const int8_t *bibend=BI+(long)(n>>3)*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"
    "1:\n\t"
    "vpbroadcastw 0(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda](%[x0]), %%ymm1\n\t"
    "vmovdqa 0(%[bib]), %%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]), %%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]), %%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]), %%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"
    "vpbroadcastw 2(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda]+2(%[x0]), %%ymm1\n\t"
    "vmovdqa 128(%[bib]), %%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]), %%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]), %%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]), %%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"
    "vpbroadcastw 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda]+4(%[x0]), %%ymm1\n\t"
    "vmovdqa 256(%[bib]), %%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]), %%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]), %%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]), %%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"
    "vpbroadcastw 6(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda]+6(%[x0]), %%ymm1\n\t"
    "vmovdqa 384(%[bib]), %%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]), %%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]), %%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]), %%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"
    "addq $8, %[x0]\n\t"
    "addq $512, %[bib]\n\t"
    "cmpq %[bibend], %[bib]\n\t"
    "jb 1b\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"
    "vpxor 0(%[PB0]), %%ymm2, %%ymm2\n\t"
    "vmovntdq %%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"
    "vpxor 32(%[PB0]), %%ymm2, %%ymm2\n\t"
    "vmovntdq %%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"
    "vpxor 0(%[PB1]), %%ymm2, %%ymm2\n\t"
    "vmovntdq %%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"
    "vpxor 32(%[PB1]), %%ymm2, %%ymm2\n\t"
    "vmovntdq %%ymm2, 32(%[C1])\n\t"
    : [x0]"+r"(x0), [bib]"+r"(bib)
    : [lda]"i"(lda), [C0]"r"(C0), [C1]"r"(C1), [PB0]"r"(PB0), [PB1]"r"(PB1), [nn]"r"(nn), [mask]"m"(W0FF), [bibend]"r"(bibend)
    : "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15","cc","memory");
}
AVX2 static void mikro_u4_pb(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 *bib=BI; const int8_t *bibend=BI+(long)(n>>3)*512;
  int8_t *C0=C+jb, *C1=C0+n;
  const uint8_t *PB0=PB, *PB1=PB+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"
    "1:\n\t"
    "vpbroadcastw 0(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda](%[x0]), %%ymm1\n\t"
    "vmovdqa 0(%[bib]), %%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]), %%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]), %%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]), %%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"
    "vpbroadcastw 2(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda]+2(%[x0]), %%ymm1\n\t"
    "vmovdqa 128(%[bib]), %%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]), %%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]), %%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]), %%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"
    "vpbroadcastw 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda]+4(%[x0]), %%ymm1\n\t"
    "vmovdqa 256(%[bib]), %%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]), %%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]), %%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]), %%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"
    "vpbroadcastw 6(%[x0]), %%ymm0\n\t"
    "vpbroadcastw %c[lda]+6(%[x0]), %%ymm1\n\t"
    "vmovdqa 384(%[bib]), %%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]), %%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]), %%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]), %%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"
    "addq $8, %[x0]\n\t"
    "addq $512, %[bib]\n\t"
    "cmpq %[bibend], %[bib]\n\t"
    "jb 1b\n\t"
    "vmovdqa %[IDX], %%ymm0\n\t"
    "vmovdqa %[SEL], %%ymm1\n\t"
    "vmovdqa %[MSB], %%ymm5\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]), %%ymm4\n\t"
	"vpshufb %%ymm0, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpcmpeqb %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm5, %%ymm4, %%ymm4\n\t"
	"vpxor %%ymm4, %%ymm2, %%ymm2\n\t"
    "vmovntdq %%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]), %%ymm4\n\t"
	"vpshufb %%ymm0, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpcmpeqb %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm5, %%ymm4, %%ymm4\n\t"
	"vpxor %%ymm4, %%ymm2, %%ymm2\n\t"
    "vmovntdq %%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]), %%ymm4\n\t"
	"vpshufb %%ymm0, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpcmpeqb %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm5, %%ymm4, %%ymm4\n\t"
	"vpxor %%ymm4, %%ymm2, %%ymm2\n\t"
    "vmovntdq %%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]), %%ymm4\n\t"
	"vpshufb %%ymm0, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpcmpeqb %%ymm1, %%ymm4, %%ymm4\n\t"
	"vpand %%ymm5, %%ymm4, %%ymm4\n\t"
	"vpxor %%ymm4, %%ymm2, %%ymm2\n\t"
    "vmovntdq %%ymm2, 32(%[C1])\n\t"
    : [x0]"+r"(x0), [bib]"+r"(bib)
    : [lda]"i"(lda), [C0]"r"(C0), [C1]"r"(C1), [PB0]"r"(PB0), [PB1]"r"(PB1),
    [IDX]"m"(MC4C_IDX), [SEL]"m"(MC4C_SEL), [MSB]"m"(MC4C_MSB), [nn]"r"(nn), [mask]"m"(W0FF), [bibend]"r"(bibend)
    : "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","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*LDA;
    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));
      _mm256_store_si256((__m256i*)(dst+k),    _mm256_and_si256(v0,m));
      _mm256_store_si256((__m256i*)(dst+k+32), _mm256_and_si256(v1,m));
      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;
      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(_mm256_and_si256(va,one),7));
        uint32_t m1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(_mm256_and_si256(vb,one),7));
        if(t==0)      { w0p[g]=(uint64_t)m0;      w1p[g]=(uint64_t)m1; }
        else          { w0p[g]|=(uint64_t)m0<<32; w1p[g]|=(uint64_t)m1<<32; }
      }
    }
  }
}


#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] __attribute__((aligned(64)));

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*LDA;
    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); } }
      _mm256_store_si256((__m256i*)(dst+k),    _mm256_and_si256(v0,mx));
      _mm256_store_si256((__m256i*)(dst+k+32), _mm256_and_si256(v1,mx));
      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++){
      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)*128+1024)+(size_t)p*128;
        _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 mm0=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(_mm256_and_si256(va,one),7));
        uint32_t mm1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(_mm256_and_si256(vb,one),7));
        if(t==0){ w0p[g]=(uint64_t)mm0;      w1p[g]=(uint64_t)mm1; }
        else    { w0p[g]|=(uint64_t)mm0<<32; w1p[g]|=(uint64_t)mm1<<32; }
      }
    }
  }
}

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

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<size_t 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+=32){
      size_t t=(size_t)i*h+j;
      __m256i m0=_mm256_load_si256((const __m256i*)(M[0]+t));
      __m256i m1=_mm256_load_si256((const __m256i*)(M[1]+t));
      __m256i m2=_mm256_load_si256((const __m256i*)(M[2]+t));
      __m256i m3=_mm256_load_si256((const __m256i*)(M[3]+t));
      __m256i m4=_mm256_load_si256((const __m256i*)(M[4]+t));
      __m256i m5=_mm256_load_si256((const __m256i*)(M[5]+t));
      __m256i m6=_mm256_load_si256((const __m256i*)(M[6]+t));
      __m256i c11=_mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(m0,m3),m4),m6);
      __m256i c12=_mm256_add_epi8(m2,m4);
      __m256i c21=_mm256_add_epi8(m1,m3);
      __m256i c22=_mm256_add_epi8(_mm256_sub_epi8(_mm256_add_epi8(m0,m2),m1),m5);
      _mm256_stream_si256((__m256i*)(r0+j),c11);
      _mm256_stream_si256((__m256i*)(r0+h+j),c12);
      _mm256_stream_si256((__m256i*)(r1+j),c21);
      _mm256_stream_si256((__m256i*)(r1+h+j),c22);
    }
  }
}


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){
  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_store_si256((__m256i*)(d+j),
                          _mm256_load_si256((const __m256i*)(xa+j)));
    else if (op==1) for(;j+32<=h;j+=32) _mm256_store_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_store_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]));
  }
}

static uint8_t Gtab[8*256*(NMAX/8)] __attribute__((aligned(64)));

#define LDU32(p) ({ __m256i _v; __asm__("vmovdqu %1, %0" : "=x"(_v) : "m"(*(const __m256i*)(p))); _v; })
#define XOR32(dst,p) __asm__("vpxor %1, %0, %0" : "+x"(dst) : "m"(*(const __m256i*)(p)))
#define STU32(p,v) __asm__ volatile("vmovdqu %1, %0" : "+m"(*(__m256i*)(p)) : "x"(v))

template<bool FIRST>
__attribute__((target("avx2"))) static void corr_rows64(int n,int W,int gb0,const uint8_t*A1){
  for(int i=0;i<n;i++){
    const uint8_t*a=A1+(size_t)i*64+gb0;
    uint64_t *po=Pbb+(size_t)i*W;
    uint64_t w; memcpy(&w,a,8);
    __m256i x0=_mm256_setzero_si256();
    __m256i x1=_mm256_setzero_si256();
#pragma GCC unroll 16
    for(int g=0;g<16;g++){
      unsigned off=(unsigned)(((w>>(4*g))&15u)<<6);
      const uint8_t*T=Gtab+off;
      XOR32(x0,T+(g<<10));
      XOR32(x1,T+(g<<10)+32);
    }
    if(FIRST){ STU32(po,x0); STU32(po+4,x1); }
    else { STU32(po,     _mm256_xor_si256(LDU32(po),x0));
           STU32(po+4,   _mm256_xor_si256(LDU32(po+4),x1)); }
  }
}
template<int NY, bool FIRST>
__attribute__((target("avx2"))) static void corr_rows(int n,int B,int W,int gb0,const uint8_t*A1){
  for(int i=0;i<n;i++){
    const uint8_t*a=A1+(size_t)i*B;
    uint64_t*po=Pbb+(size_t)i*W;
    __m256i acc[NY];
    for(int q=0;q<NY;q++) acc[q]=_mm256_setzero_si256();
    for(int g=0;g<16;g++){
      uint8_t bits=a[gb0+(g>>1)];
      uint8_t value=(g&1)?(bits>>4):(bits&15);
      const uint8_t*T=Gtab+((size_t)g*16+(size_t)value)*B;
      for(int q=0;q<NY;q++) XOR32(acc[q],T+(size_t)q*32);
    }
    for(int q=0;q<NY;q++){
      if (FIRST) STU32(po+4*(size_t)q, acc[q]);
      else {
        __m256i o=LDU32(po+4*(size_t)q);
        STU32(po+4*(size_t)q, _mm256_xor_si256(o,acc[q]));
      }
    }
  }
}
__attribute__((target("avx2"))) static void corr_rus(int n){
  const int W=n/64, B=n/8, NY=B/32;
  if(NY!=2 && NY!=4 && NY!=8 && NY!=16){ corr_pass3(n); return; }
  const uint8_t*A1=(const uint8_t*)A1b;
  const int NB=16;                       
  for(int kb=0;kb<n;kb+=NB*4){
    for(int g=0;g<NB;g++){
      const int k0=kb+g*4;
      uint8_t*T0=Gtab+(size_t)g*16*B;
      memset(T0,0,B);
      for(int v=1;v<16;v++){
        uint8_t*dst=T0+(size_t)v*B;
        const uint8_t*pr=T0+(size_t)(v&(v-1))*B;
        const uint8_t*bp=(const uint8_t*)(Bpb+(size_t)(k0+__builtin_ctz(v))*W);
        for(int q=0;q<B;q+=32){
          __m256i x=LDU32(pr+q);
          XOR32(x,bp+q);
          STU32(dst+q,x);
        }
      }
    }
    const int gb0=kb>>3;
    if (B==64) {                       
      if (kb==0) corr_rows64<true >(n,W,gb0,A1);
      else       corr_rows64<false>(n,W,gb0,A1);
    } else if (kb==0) {
      if(NY==16)    corr_rows<16,true>(n,B,W,gb0,A1);
      else if(NY==8)corr_rows<8,true>(n,B,W,gb0,A1);
      else if(NY==4)corr_rows<4,true>(n,B,W,gb0,A1);
      else          corr_rows<2,true>(n,B,W,gb0,A1);
    } else {
      if(NY==16)    corr_rows<16,false>(n,B,W,gb0,A1);
      else if(NY==8)corr_rows<8,false>(n,B,W,gb0,A1);
      else if(NY==4)corr_rows<4,false>(n,B,W,gb0,A1);
      else          corr_rows<2,false>(n,B,W,gb0,A1);
    }
  }
}

AVX2 static void submm_tail(int m,int8_t*Cp){
  corr_rus(m);
  const int PW=m/64;
  const int GB=256, IB=128;
  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+1024);
        for (int i=ib; i<ihi; i+=2)
          mikro_u4_pb(m, A0b+(size_t)i*LDA, bi,
                   Cp+(size_t)i*m+g, (const uint8_t*)(Pbb+(size_t)i*PW)+(g>>3), 0, LDA, PW*8);
      }
    }
  }
}

AVX2 static void submm_plain(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  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

static int8_t S2A[1024*1024] __attribute__((aligned(64)));
static int8_t S2B[1024*1024] __attribute__((aligned(64)));
static int8_t S3M[7][512*512] __attribute__((aligned(64)));
AVX2 static void submm_s3(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  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,S3M[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,S3M[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,S3M[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,S3M[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,S3M[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,S3M[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,S3M[6]); break;
    }
  }
  _mm_sfence();
  cmb4(Cp,m,h,S3M);
  _mm_sfence();
}
AVX2 static void submm_s2(int m,const int8_t*Ap,const int8_t*Bp,int8_t*Cp){
  const int h=m>>1, o=h;
  for (int k=0;k<7;k++){
    switch(k){
      case 0: blk(S2A,Ap,m,0,0,h,Ap,o,o,1); blk(S2B,Bp,m,0,0,h,Bp,o,o,1); break;
      case 1: blk(S2A,Ap,m,o,0,h,Ap,o,o,1); blk(S2B,Bp,m,0,0,h,Bp,0,0,0); break;
      case 2: blk(S2A,Ap,m,0,0,h,Ap,0,0,0); blk(S2B,Bp,m,0,o,h,Bp,o,o,2); break;
      case 3: blk(S2A,Ap,m,o,o,h,Ap,o,o,0); blk(S2B,Bp,m,o,0,h,Bp,0,0,2); break;
      case 4: blk(S2A,Ap,m,0,0,h,Ap,0,o,1); blk(S2B,Bp,m,o,o,h,Bp,o,o,0); break;
      case 5: blk(S2A,Ap,m,o,0,h,Ap,0,0,2); blk(S2B,Bp,m,0,0,h,Bp,0,o,1); break;
      case 6: blk(S2A,Ap,m,0,o,h,Ap,o,o,2); blk(S2B,Bp,m,o,0,h,Bp,o,o,1); break;
    }
    Leaf1k::matrix_multiply(h,S2A,S2B,S2M[k]);
  }
  _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); return; }
  submm_plain(m,Ap,Bp,Cp);
}
AVX2 static void strassen1(int n,const int8_t*A,const int8_t*B,int8_t*C){
  const int m=n>>1, o=m;
  for (int k=0;k<7;k++){
    switch(k){
      case 0: blk(SA,A,n,0,0,m,A,o,o,1); blk(SB,B,n,0,0,m,B,o,o,1); break;
      case 1: blk(SA,A,n,o,0,m,A,o,o,1); blk(SB,B,n,0,0,m,B,0,0,0); break;
      case 2: blk(SA,A,n,0,0,m,A,0,0,0); blk(SB,B,n,0,o,m,B,o,o,2); break;
      case 3: blk(SA,A,n,o,o,m,A,o,o,0); blk(SB,B,n,o,0,m,B,0,0,2); break;
      case 4: blk(SA,A,n,0,0,m,A,0,o,1); blk(SB,B,n,o,o,m,B,o,o,0); break;
      case 5: blk(SA,A,n,o,0,m,A,0,0,2); blk(SB,B,n,0,0,m,B,0,o,1); break;
      case 6: blk(SA,A,n,0,o,m,A,o,o,2); blk(SB,B,n,o,0,m,B,o,o,1); break;
    }
    submm(m,SA,SB,MMS[k]);
  }
  _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; }
  
  build_A0A1(n,A); build_BI3Bp(n,B);
  if (n==4096) corr16(); else corr_pass3(n); expand_bits(n);
  for (int g=0; g<n; g+=64)
    for (int i=0; i<n; i+=2)
      mikro_u4(n, A0b+(size_t)i*LDA, BI3b+(size_t)(g>>6)*(n/2)*128,
               C+(size_t)i*n+g, PBb+(size_t)i*LDB+g, 0, LDA, LDB);
  _mm_sfence();
}

#undef AVX2
#undef AVX2BMI
#undef LDA
#undef LDB
#undef LDU32
#undef MC4B_ARR
#undef NIB
#undef NJ
#undef NMAX
#undef PADA
#undef PADB
#undef S2MIN
#undef SM
#undef STU32
#undef XOR32
namespace Leaf1k {
#define MC4_KNIVES_DE 1
#pragma GCC optimize("O3,unroll-loops,no-strict-aliasing,rename-registers")
#pragma GCC target("avx2,bmi,bmi2,popcnt,lzcnt")
#define AVX2 __attribute__((target("avx2")))
#define NMAX 4096
static int8_t   A0b[NMAX*NMAX]      __attribute__((aligned(64)));
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[NMAX*NMAX]      __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_A0(int n, const int8_t*A){
  const __m256i m=_mm256_set1_epi8(0x7F);
  size_t tot=(size_t)n*n;
  for (size_t i=0;i<tot;i+=32)
    _mm256_store_si256((__m256i*)(A0b+i),
      _mm256_and_si256(_mm256_load_si256((const __m256i*)(A+i)), m));
}
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]);
  }
}

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]));
      }
    }
  }
}

AVX2 static void corr16(void){
  const int n=4096, W=64;
  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+4;
    for (int i=0;i<n;i++){
      __m256i acc0,acc1,acc2,acc3,acc4,acc5,acc6,acc7,acc8,acc9,acc10,acc11,acc12,acc13,acc14,acc15;
      acc0=acc1=acc2=acc3=acc4=acc5=acc6=acc7=_mm256_setzero_si256();
      acc8=acc9=acc10=acc11=acc12=acc13=acc14=acc15=_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;
          acc0 =_mm256_xor_si256(acc0 ,_mm256_load_si256((const __m256i*)(br+0)));
          acc1 =_mm256_xor_si256(acc1 ,_mm256_load_si256((const __m256i*)(br+4)));
          acc2 =_mm256_xor_si256(acc2 ,_mm256_load_si256((const __m256i*)(br+8)));
          acc3 =_mm256_xor_si256(acc3 ,_mm256_load_si256((const __m256i*)(br+12)));
          acc4 =_mm256_xor_si256(acc4 ,_mm256_load_si256((const __m256i*)(br+16)));
          acc5 =_mm256_xor_si256(acc5 ,_mm256_load_si256((const __m256i*)(br+20)));
          acc6 =_mm256_xor_si256(acc6 ,_mm256_load_si256((const __m256i*)(br+24)));
          acc7 =_mm256_xor_si256(acc7 ,_mm256_load_si256((const __m256i*)(br+28)));
          acc8 =_mm256_xor_si256(acc8 ,_mm256_load_si256((const __m256i*)(br+32)));
          acc9 =_mm256_xor_si256(acc9 ,_mm256_load_si256((const __m256i*)(br+36)));
          acc10=_mm256_xor_si256(acc10,_mm256_load_si256((const __m256i*)(br+40)));
          acc11=_mm256_xor_si256(acc11,_mm256_load_si256((const __m256i*)(br+44)));
          acc12=_mm256_xor_si256(acc12,_mm256_load_si256((const __m256i*)(br+48)));
          acc13=_mm256_xor_si256(acc13,_mm256_load_si256((const __m256i*)(br+52)));
          acc14=_mm256_xor_si256(acc14,_mm256_load_si256((const __m256i*)(br+56)));
          acc15=_mm256_xor_si256(acc15,_mm256_load_si256((const __m256i*)(br+60)));
        }
      }
      uint64_t*o=Pbb+(size_t)i*W;
      #define RMW(q,a) { __m256i*po=(__m256i*)(o+4*(q)); _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),a)); }
      RMW(0,acc0) RMW(1,acc1) RMW(2,acc2) RMW(3,acc3) RMW(4,acc4) RMW(5,acc5) RMW(6,acc6) RMW(7,acc7)
      RMW(8,acc8) RMW(9,acc9) RMW(10,acc10) RMW(11,acc11) RMW(12,acc12) RMW(13,acc13) RMW(14,acc14) RMW(15,acc15)
      #undef RMW
    }
  }
}
AVX2 static void corr1k(void){
  const int n=1024, W=16;
  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+4;
    for (int i=0;i<n;i++){
      __m256i acc0,acc1,acc2,acc3;
      acc0=acc1=acc2=acc3=_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;
          acc0 =_mm256_xor_si256(acc0 ,_mm256_load_si256((const __m256i*)(br+0)));
          acc1 =_mm256_xor_si256(acc1 ,_mm256_load_si256((const __m256i*)(br+4)));
          acc2 =_mm256_xor_si256(acc2 ,_mm256_load_si256((const __m256i*)(br+8)));
          acc3 =_mm256_xor_si256(acc3 ,_mm256_load_si256((const __m256i*)(br+12)));
        }
      }
      uint64_t*o=Pbb+(size_t)i*W;
      #define RMW(q,a) { __m256i*po=(__m256i*)(o+4*(q)); _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),a)); }
      RMW(0,acc0) RMW(1,acc1) RMW(2,acc2) RMW(3,acc3)
      #undef RMW
    }
  }
}
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*n;
    for(int q=0;q<W;q++){
      uint64_t v=w[q];
      for(int s=0;s<8;s++) memcpy(o+(q*8+s)*8, T+(((uint8_t)(v>>(8*s)))*8), 8);
    }
  }
}
#define NIB 2
#define NJ 4
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));
      }
    }
  }
}
static int8_t mscr[256] __attribute__((aligned(64)));
static const uint8_t SHB8[256*8] __attribute__((aligned(64))) = {
  0,0,0,0,0,0,0,0,0x80,0,0,0,0,0,0,0,
  0,0x80,0,0,0,0,0,0,0x80,0x80,0,0,0,0,0,0,
  0,0,0x80,0,0,0,0,0,0x80,0,0x80,0,0,0,0,0,
  0,0x80,0x80,0,0,0,0,0,0x80,0x80,0x80,0,0,0,0,0,
  0,0,0,0x80,0,0,0,0,0x80,0,0,0x80,0,0,0,0,
  0,0x80,0,0x80,0,0,0,0,0x80,0x80,0,0x80,0,0,0,0,
  0,0,0x80,0x80,0,0,0,0,0x80,0,0x80,0x80,0,0,0,0,
  0,0x80,0x80,0x80,0,0,0,0,0x80,0x80,0x80,0x80,0,0,0,0,
  0,0,0,0,0x80,0,0,0,0x80,0,0,0,0x80,0,0,0,
  0,0x80,0,0,0x80,0,0,0,0x80,0x80,0,0,0x80,0,0,0,
  0,0,0x80,0,0x80,0,0,0,0x80,0,0x80,0,0x80,0,0,0,
  0,0x80,0x80,0,0x80,0,0,0,0x80,0x80,0x80,0,0x80,0,0,0,
  0,0,0,0x80,0x80,0,0,0,0x80,0,0,0x80,0x80,0,0,0,
  0,0x80,0,0x80,0x80,0,0,0,0x80,0x80,0,0x80,0x80,0,0,0,
  0,0,0x80,0x80,0x80,0,0,0,0x80,0,0x80,0x80,0x80,0,0,0,
  0,0x80,0x80,0x80,0x80,0,0,0,0x80,0x80,0x80,0x80,0x80,0,0,0,
  0,0,0,0,0,0x80,0,0,0x80,0,0,0,0,0x80,0,0,
  0,0x80,0,0,0,0x80,0,0,0x80,0x80,0,0,0,0x80,0,0,
  0,0,0x80,0,0,0x80,0,0,0x80,0,0x80,0,0,0x80,0,0,
  0,0x80,0x80,0,0,0x80,0,0,0x80,0x80,0x80,0,0,0x80,0,0,
  0,0,0,0x80,0,0x80,0,0,0x80,0,0,0x80,0,0x80,0,0,
  0,0x80,0,0x80,0,0x80,0,0,0x80,0x80,0,0x80,0,0x80,0,0,
  0,0,0x80,0x80,0,0x80,0,0,0x80,0,0x80,0x80,0,0x80,0,0,
  0,0x80,0x80,0x80,0,0x80,0,0,0x80,0x80,0x80,0x80,0,0x80,0,0,
  0,0,0,0,0x80,0x80,0,0,0x80,0,0,0,0x80,0x80,0,0,
  0,0x80,0,0,0x80,0x80,0,0,0x80,0x80,0,0,0x80,0x80,0,0,
  0,0,0x80,0,0x80,0x80,0,0,0x80,0,0x80,0,0x80,0x80,0,0,
  0,0x80,0x80,0,0x80,0x80,0,0,0x80,0x80,0x80,0,0x80,0x80,0,0,
  0,0,0,0x80,0x80,0x80,0,0,0x80,0,0,0x80,0x80,0x80,0,0,
  0,0x80,0,0x80,0x80,0x80,0,0,0x80,0x80,0,0x80,0x80,0x80,0,0,
  0,0,0x80,0x80,0x80,0x80,0,0,0x80,0,0x80,0x80,0x80,0x80,0,0,
  0,0x80,0x80,0x80,0x80,0x80,0,0,0x80,0x80,0x80,0x80,0x80,0x80,0,0,
  0,0,0,0,0,0,0x80,0,0x80,0,0,0,0,0,0x80,0,
  0,0x80,0,0,0,0,0x80,0,0x80,0x80,0,0,0,0,0x80,0,
  0,0,0x80,0,0,0,0x80,0,0x80,0,0x80,0,0,0,0x80,0,
  0,0x80,0x80,0,0,0,0x80,0,0x80,0x80,0x80,0,0,0,0x80,0,
  0,0,0,0x80,0,0,0x80,0,0x80,0,0,0x80,0,0,0x80,0,
  0,0x80,0,0x80,0,0,0x80,0,0x80,0x80,0,0x80,0,0,0x80,0,
  0,0,0x80,0x80,0,0,0x80,0,0x80,0,0x80,0x80,0,0,0x80,0,
  0,0x80,0x80,0x80,0,0,0x80,0,0x80,0x80,0x80,0x80,0,0,0x80,0,
  0,0,0,0,0x80,0,0x80,0,0x80,0,0,0,0x80,0,0x80,0,
  0,0x80,0,0,0x80,0,0x80,0,0x80,0x80,0,0,0x80,0,0x80,0,
  0,0,0x80,0,0x80,0,0x80,0,0x80,0,0x80,0,0x80,0,0x80,0,
  0,0x80,0x80,0,0x80,0,0x80,0,0x80,0x80,0x80,0,0x80,0,0x80,0,
  0,0,0,0x80,0x80,0,0x80,0,0x80,0,0,0x80,0x80,0,0x80,0,
  0,0x80,0,0x80,0x80,0,0x80,0,0x80,0x80,0,0x80,0x80,0,0x80,0,
  0,0,0x80,0x80,0x80,0,0x80,0,0x80,0,0x80,0x80,0x80,0,0x80,0,
  0,0x80,0x80,0x80,0x80,0,0x80,0,0x80,0x80,0x80,0x80,0x80,0,0x80,0,
  0,0,0,0,0,0x80,0x80,0,0x80,0,0,0,0,0x80,0x80,0,
  0,0x80,0,0,0,0x80,0x80,0,0x80,0x80,0,0,0,0x80,0x80,0,
  0,0,0x80,0,0,0x80,0x80,0,0x80,0,0x80,0,0,0x80,0x80,0,
  0,0x80,0x80,0,0,0x80,0x80,0,0x80,0x80,0x80,0,0,0x80,0x80,0,
  0,0,0,0x80,0,0x80,0x80,0,0x80,0,0,0x80,0,0x80,0x80,0,
  0,0x80,0,0x80,0,0x80,0x80,0,0x80,0x80,0,0x80,0,0x80,0x80,0,
  0,0,0x80,0x80,0,0x80,0x80,0,0x80,0,0x80,0x80,0,0x80,0x80,0,
  0,0x80,0x80,0x80,0,0x80,0x80,0,0x80,0x80,0x80,0x80,0,0x80,0x80,0,
  0,0,0,0,0x80,0x80,0x80,0,0x80,0,0,0,0x80,0x80,0x80,0,
  0,0x80,0,0,0x80,0x80,0x80,0,0x80,0x80,0,0,0x80,0x80,0x80,0,
  0,0,0x80,0,0x80,0x80,0x80,0,0x80,0,0x80,0,0x80,0x80,0x80,0,
  0,0x80,0x80,0,0x80,0x80,0x80,0,0x80,0x80,0x80,0,0x80,0x80,0x80,0,
  0,0,0,0x80,0x80,0x80,0x80,0,0x80,0,0,0x80,0x80,0x80,0x80,0,
  0,0x80,0,0x80,0x80,0x80,0x80,0,0x80,0x80,0,0x80,0x80,0x80,0x80,0,
  0,0,0x80,0x80,0x80,0x80,0x80,0,0x80,0,0x80,0x80,0x80,0x80,0x80,0,
  0,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,
  0,0,0,0,0,0,0,0x80,0x80,0,0,0,0,0,0,0x80,
  0,0x80,0,0,0,0,0,0x80,0x80,0x80,0,0,0,0,0,0x80,
  0,0,0x80,0,0,0,0,0x80,0x80,0,0x80,0,0,0,0,0x80,
  0,0x80,0x80,0,0,0,0,0x80,0x80,0x80,0x80,0,0,0,0,0x80,
  0,0,0,0x80,0,0,0,0x80,0x80,0,0,0x80,0,0,0,0x80,
  0,0x80,0,0x80,0,0,0,0x80,0x80,0x80,0,0x80,0,0,0,0x80,
  0,0,0x80,0x80,0,0,0,0x80,0x80,0,0x80,0x80,0,0,0,0x80,
  0,0x80,0x80,0x80,0,0,0,0x80,0x80,0x80,0x80,0x80,0,0,0,0x80,
  0,0,0,0,0x80,0,0,0x80,0x80,0,0,0,0x80,0,0,0x80,
  0,0x80,0,0,0x80,0,0,0x80,0x80,0x80,0,0,0x80,0,0,0x80,
  0,0,0x80,0,0x80,0,0,0x80,0x80,0,0x80,0,0x80,0,0,0x80,
  0,0x80,0x80,0,0x80,0,0,0x80,0x80,0x80,0x80,0,0x80,0,0,0x80,
  0,0,0,0x80,0x80,0,0,0x80,0x80,0,0,0x80,0x80,0,0,0x80,
  0,0x80,0,0x80,0x80,0,0,0x80,0x80,0x80,0,0x80,0x80,0,0,0x80,
  0,0,0x80,0x80,0x80,0,0,0x80,0x80,0,0x80,0x80,0x80,0,0,0x80,
  0,0x80,0x80,0x80,0x80,0,0,0x80,0x80,0x80,0x80,0x80,0x80,0,0,0x80,
  0,0,0,0,0,0x80,0,0x80,0x80,0,0,0,0,0x80,0,0x80,
  0,0x80,0,0,0,0x80,0,0x80,0x80,0x80,0,0,0,0x80,0,0x80,
  0,0,0x80,0,0,0x80,0,0x80,0x80,0,0x80,0,0,0x80,0,0x80,
  0,0x80,0x80,0,0,0x80,0,0x80,0x80,0x80,0x80,0,0,0x80,0,0x80,
  0,0,0,0x80,0,0x80,0,0x80,0x80,0,0,0x80,0,0x80,0,0x80,
  0,0x80,0,0x80,0,0x80,0,0x80,0x80,0x80,0,0x80,0,0x80,0,0x80,
  0,0,0x80,0x80,0,0x80,0,0x80,0x80,0,0x80,0x80,0,0x80,0,0x80,
  0,0x80,0x80,0x80,0,0x80,0,0x80,0x80,0x80,0x80,0x80,0,0x80,0,0x80,
  0,0,0,0,0x80,0x80,0,0x80,0x80,0,0,0,0x80,0x80,0,0x80,
  0,0x80,0,0,0x80,0x80,0,0x80,0x80,0x80,0,0,0x80,0x80,0,0x80,
  0,0,0x80,0,0x80,0x80,0,0x80,0x80,0,0x80,0,0x80,0x80,0,0x80,
  0,0x80,0x80,0,0x80,0x80,0,0x80,0x80,0x80,0x80,0,0x80,0x80,0,0x80,
  0,0,0,0x80,0x80,0x80,0,0x80,0x80,0,0,0x80,0x80,0x80,0,0x80,
  0,0x80,0,0x80,0x80,0x80,0,0x80,0x80,0x80,0,0x80,0x80,0x80,0,0x80,
  0,0,0x80,0x80,0x80,0x80,0,0x80,0x80,0,0x80,0x80,0x80,0x80,0,0x80,
  0,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,
  0,0,0,0,0,0,0x80,0x80,0x80,0,0,0,0,0,0x80,0x80,
  0,0x80,0,0,0,0,0x80,0x80,0x80,0x80,0,0,0,0,0x80,0x80,
  0,0,0x80,0,0,0,0x80,0x80,0x80,0,0x80,0,0,0,0x80,0x80,
  0,0x80,0x80,0,0,0,0x80,0x80,0x80,0x80,0x80,0,0,0,0x80,0x80,
  0,0,0,0x80,0,0,0x80,0x80,0x80,0,0,0x80,0,0,0x80,0x80,
  0,0x80,0,0x80,0,0,0x80,0x80,0x80,0x80,0,0x80,0,0,0x80,0x80,
  0,0,0x80,0x80,0,0,0x80,0x80,0x80,0,0x80,0x80,0,0,0x80,0x80,
  0,0x80,0x80,0x80,0,0,0x80,0x80,0x80,0x80,0x80,0x80,0,0,0x80,0x80,
  0,0,0,0,0x80,0,0x80,0x80,0x80,0,0,0,0x80,0,0x80,0x80,
  0,0x80,0,0,0x80,0,0x80,0x80,0x80,0x80,0,0,0x80,0,0x80,0x80,
  0,0,0x80,0,0x80,0,0x80,0x80,0x80,0,0x80,0,0x80,0,0x80,0x80,
  0,0x80,0x80,0,0x80,0,0x80,0x80,0x80,0x80,0x80,0,0x80,0,0x80,0x80,
  0,0,0,0x80,0x80,0,0x80,0x80,0x80,0,0,0x80,0x80,0,0x80,0x80,
  0,0x80,0,0x80,0x80,0,0x80,0x80,0x80,0x80,0,0x80,0x80,0,0x80,0x80,
  0,0,0x80,0x80,0x80,0,0x80,0x80,0x80,0,0x80,0x80,0x80,0,0x80,0x80,
  0,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,
  0,0,0,0,0,0x80,0x80,0x80,0x80,0,0,0,0,0x80,0x80,0x80,
  0,0x80,0,0,0,0x80,0x80,0x80,0x80,0x80,0,0,0,0x80,0x80,0x80,
  0,0,0x80,0,0,0x80,0x80,0x80,0x80,0,0x80,0,0,0x80,0x80,0x80,
  0,0x80,0x80,0,0,0x80,0x80,0x80,0x80,0x80,0x80,0,0,0x80,0x80,0x80,
  0,0,0,0x80,0,0x80,0x80,0x80,0x80,0,0,0x80,0,0x80,0x80,0x80,
  0,0x80,0,0x80,0,0x80,0x80,0x80,0x80,0x80,0,0x80,0,0x80,0x80,0x80,
  0,0,0x80,0x80,0,0x80,0x80,0x80,0x80,0,0x80,0x80,0,0x80,0x80,0x80,
  0,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,
  0,0,0,0,0x80,0x80,0x80,0x80,0x80,0,0,0,0x80,0x80,0x80,0x80,
  0,0x80,0,0,0x80,0x80,0x80,0x80,0x80,0x80,0,0,0x80,0x80,0x80,0x80,
  0,0,0x80,0,0x80,0x80,0x80,0x80,0x80,0,0x80,0,0x80,0x80,0x80,0x80,
  0,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,
  0,0,0,0x80,0x80,0x80,0x80,0x80,0x80,0,0,0x80,0x80,0x80,0x80,0x80,
  0,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,
  0,0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0,0x80,0x80,0x80,0x80,0x80,0x80,
  0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
};
AVX2 static void epilogue(int n, int8_t*C, const uint64_t*P, int jb, int i, int NCH){
  const __m128i bitm=_mm_setr_epi8(1,2,4,8,16,32,64,(char)0x80,1,2,4,8,16,32,64,(char)0x80);
  const __m128i hi=_mm_set1_epi8((char)0x80), zero=_mm_setzero_si128();
  const size_t bo=(size_t)jb>>3;
  const uint8_t*base=(const uint8_t*)P+(size_t)i*(n>>3);
  for(int r=0;r<2;r++){
    const uint8_t*qr=base+(size_t)r*(n>>3);
    for(int t=0;t<NCH;t++){
      size_t bi_=bo+4*(size_t)t;
      const uint8_t*wb=qr+bi_;
      __m256i v=_mm256_load_si256((const __m256i*)(mscr+(r*NCH+t)*32));
      __m128i z0=_mm_loadl_epi64((const __m128i*)(SHB8+(size_t)wb[0]*8));
      __m128i z1=_mm_loadl_epi64((const __m128i*)(SHB8+(size_t)wb[1]*8));
      __m128i z2=_mm_loadl_epi64((const __m128i*)(SHB8+(size_t)wb[2]*8));
      __m128i z3=_mm_loadl_epi64((const __m128i*)(SHB8+(size_t)wb[3]*8));
      __m256i msk=_mm256_set_m128i(_mm_unpacklo_epi64(z2,z3),_mm_unpacklo_epi64(z0,z1));
      int8_t*c=C+(size_t)(i+r)*n+jb+t*32;
      _mm256_storeu_si256((__m256i*)c,_mm256_xor_si256(v,msk));
    }
  }
}

static int8_t  BI9b[10*(NMAX/2)*192]  __attribute__((aligned(64)));

static uint64_t BP2[16*65*16] __attribute__((aligned(64)));
AVX2 static void build_BP2(int n, const int8_t*B){
  const int W=n>>6, STR=65*W;
  const __m256i one=_mm256_set1_epi8(1);
  for (int k=0;k<n;k++){
    const int8_t*row=B+(size_t)k*n; uint64_t*w=BP2+(size_t)(k>>6)*STR+(size_t)(k&63)*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);
    }
  }
  for (int g=0; g<(n>>6); g++) memset(BP2+(size_t)g*STR+64*W, 0, W*8);
}
AVX2 static void corr2k(int n){
  const int W=n>>6, STR=65*W;
  memset(Pbb,0,(size_t)n*W*8);
  for (int kb0=0; kb0<n; kb0+=256){
    int w0=kb0>>6;
    for (int i=0;i<n;i++){
      __m256i a0,a1,a2,a3; a0=a1=a2=a3=_mm256_setzero_si256();
      const uint64_t*row=A1b+(size_t)i*W;
      uint64_t b0=row[w0],b1=row[w0+1],b2=row[w0+2],b3=row[w0+3];
      const uint64_t*bw0=BP2+(size_t)w0*STR;
      const uint64_t*bw1=bw0+STR,*bw2=bw1+STR,*bw3=bw2+STR;
      while (b0|b1|b2|b3){
        long t0,t1,t2,t3; uint64_t nb;
        __asm__("tzcntq %2,%0\n\t" "blsrq %2,%1":"=r"(t0),"=r"(nb):"r"(b0)); b0=nb;
        __asm__("tzcntq %2,%0\n\t" "blsrq %2,%1":"=r"(t1),"=r"(nb):"r"(b1)); b1=nb;
        __asm__("tzcntq %2,%0\n\t" "blsrq %2,%1":"=r"(t2),"=r"(nb):"r"(b2)); b2=nb;
        __asm__("tzcntq %2,%0\n\t" "blsrq %2,%1":"=r"(t3),"=r"(nb):"r"(b3)); b3=nb;
        const uint64_t*r0=bw0+((size_t)t0<<4);
        const uint64_t*r1=bw1+((size_t)t1<<4);
        const uint64_t*r2=bw2+((size_t)t2<<4);
        const uint64_t*r3=bw3+((size_t)t3<<4);
        a0=_mm256_xor_si256(a0,_mm256_load_si256((const __m256i*)(r0+0)));
        a1=_mm256_xor_si256(a1,_mm256_load_si256((const __m256i*)(r0+4)));
        a2=_mm256_xor_si256(a2,_mm256_load_si256((const __m256i*)(r0+8)));
        a3=_mm256_xor_si256(a3,_mm256_load_si256((const __m256i*)(r0+12)));
        a0=_mm256_xor_si256(a0,_mm256_load_si256((const __m256i*)(r1+0)));
        a1=_mm256_xor_si256(a1,_mm256_load_si256((const __m256i*)(r1+4)));
        a2=_mm256_xor_si256(a2,_mm256_load_si256((const __m256i*)(r1+8)));
        a3=_mm256_xor_si256(a3,_mm256_load_si256((const __m256i*)(r1+12)));
        a0=_mm256_xor_si256(a0,_mm256_load_si256((const __m256i*)(r2+0)));
        a1=_mm256_xor_si256(a1,_mm256_load_si256((const __m256i*)(r2+4)));
        a2=_mm256_xor_si256(a2,_mm256_load_si256((const __m256i*)(r2+8)));
        a3=_mm256_xor_si256(a3,_mm256_load_si256((const __m256i*)(r2+12)));
        a0=_mm256_xor_si256(a0,_mm256_load_si256((const __m256i*)(r3+0)));
        a1=_mm256_xor_si256(a1,_mm256_load_si256((const __m256i*)(r3+4)));
        a2=_mm256_xor_si256(a2,_mm256_load_si256((const __m256i*)(r3+8)));
        a3=_mm256_xor_si256(a3,_mm256_load_si256((const __m256i*)(r3+12)));
      }
      uint64_t*o=Pbb+(size_t)i*W;
      { __m256i*po=(__m256i*)(o+0); _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),a0)); }
      { __m256i*po=(__m256i*)(o+4); _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),a1)); }
      { __m256i*po=(__m256i*)(o+8); _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),a2)); }
      { __m256i*po=(__m256i*)(o+12); _mm256_store_si256(po,_mm256_xor_si256(_mm256_load_si256((const __m256i*)po),a3)); }
    }
  }
}
AVX2 static void build_BI9(int n, const int8_t*B){
  const int half=n>>1, NC=96, NREC=192;
  for (int p=0;p<half;p++){
    const int8_t*r0b=B+(size_t)(2*p)*n, *r1b=r0b+n;
    for (int g=0; g<10; g++){
      const int8_t*r0=r0b+NC*g, *r1=r1b+NC*g;
      int8_t*o=BI9b+((size_t)g*half+p)*NREC;
      for (int t=0;t<NC;t+=32){
        __m256i va=_mm256_loadu_si256((const __m256i*)(r0+t));
        __m256i vb=_mm256_loadu_si256((const __m256i*)(r1+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));
      }
    }
  }
}
AVX2 static void build_A0_A1(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; uint64_t*w=A1b+(size_t)i*W;
    int8_t*o=A0b+(size_t)i*n;
    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));
      _mm256_store_si256((__m256i*)(o+k),    _mm256_and_si256(v0,m));
      _mm256_store_si256((__m256i*)(o+k+32), _mm256_and_si256(v1,m));
      uint32_t lo=(uint32_t)_mm256_movemask_epi8(v0);
      uint32_t hi=(uint32_t)_mm256_movemask_epi8(v1);
      w[k>>6]=(uint64_t)lo|((uint64_t)hi<<32);
    }
  }
}
AVX2 static void build_BI3_tail(int n, const int8_t*B){
  const int half=n>>1, c0=960;
  for (int p=0;p<half;p++){
    const int8_t*r0=B+(size_t)(2*p)*n+c0, *r1=r0+n;
    int8_t*o=BI3b+((size_t)p)*128;
    for (int t=0;t<64;t+=32){
      __m256i va=_mm256_loadu_si256((const __m256i*)(r0+t));
      __m256i vb=_mm256_loadu_si256((const __m256i*)(r1+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));
    }
  }
}
#define W0FFS {0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF,0x00FF}
static const int16_t M9[16] __attribute__((aligned(32))) = W0FFS;
AVX2 static void mk_s6(int n, const int8_t*A0, const int8_t*BI, uint8_t*scr){
  const int8_t *x0=A0, *x1=A0+n, *bi=BI; long cnt=n>>3;
  asm volatile(
    "vpxor %%xmm2,%%xmm2,%%xmm2\n\t"
    "vpxor %%xmm3,%%xmm3,%%xmm3\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"
    ".p2align 5\n" "1:\n"
    "prefetcht0 2304(%[bi])\n\t"
    "vpbroadcastw (%[x0]), %%ymm0\n\t"
    "vpbroadcastw (%[x1]), %%ymm1\n\t"
    "vmovdqa (%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 32(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vmovdqa 64(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm2, %%ymm2\n\t"
    "vmovdqa 96(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm3, %%ymm3\n\t"
    "vmovdqa 128(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm6, %%ymm6\n\t"
    "vmovdqa 160(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm7, %%ymm7\n\t"
    "vpbroadcastw 2(%[x0]), %%ymm0\n\t"
    "vpbroadcastw 2(%[x1]), %%ymm1\n\t"
    "vmovdqa 192(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 224(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vmovdqa 256(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm2, %%ymm2\n\t"
    "vmovdqa 288(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm3, %%ymm3\n\t"
    "vmovdqa 320(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm6, %%ymm6\n\t"
    "vmovdqa 352(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm7, %%ymm7\n\t"
    "vpbroadcastw 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastw 4(%[x1]), %%ymm1\n\t"
    "vmovdqa 384(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 416(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vmovdqa 448(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm2, %%ymm2\n\t"
    "vmovdqa 480(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm3, %%ymm3\n\t"
    "vmovdqa 512(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm6, %%ymm6\n\t"
    "vmovdqa 544(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm7, %%ymm7\n\t"
    "vpbroadcastw 6(%[x0]), %%ymm0\n\t"
    "vpbroadcastw 6(%[x1]), %%ymm1\n\t"
    "vmovdqa 576(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 608(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vmovdqa 640(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm2, %%ymm2\n\t"
    "vmovdqa 672(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm3, %%ymm3\n\t"
    "vmovdqa 704(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm6, %%ymm6\n\t"
    "vmovdqa 736(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm7, %%ymm7\n\t"
    "prefetcht0 800(%[bi])\n\t"
    "prefetcht0 1600(%[bi])\n\t"
    "addq $8, %[x0]\n\t"
    "addq $8, %[x1]\n\t"
    "addq $768, %[bi]\n\t"
    "decq %[cnt]\n\t"
    "jnz 1b\n\t"
    "vpand %[mask], %%ymm8, %%ymm0\n\t"
    "vpand %[mask], %%ymm9, %%ymm1\n\t"
    "vpackuswb %%ymm1, %%ymm0, %%ymm0\n\t"
    "vpermq $0xD8, %%ymm0, %%ymm0\n\t"
    "vmovdqu %%ymm0, 0(%[scr])\n\t"
    "vpand %[mask], %%ymm10, %%ymm0\n\t"
    "vpand %[mask], %%ymm11, %%ymm1\n\t"
    "vpackuswb %%ymm1, %%ymm0, %%ymm0\n\t"
    "vpermq $0xD8, %%ymm0, %%ymm0\n\t"
    "vmovdqu %%ymm0, 32(%[scr])\n\t"
    "vpand %[mask], %%ymm12, %%ymm0\n\t"
    "vpand %[mask], %%ymm13, %%ymm1\n\t"
    "vpackuswb %%ymm1, %%ymm0, %%ymm0\n\t"
    "vpermq $0xD8, %%ymm0, %%ymm0\n\t"
    "vmovdqu %%ymm0, 64(%[scr])\n\t"
    "vpand %[mask], %%ymm14, %%ymm0\n\t"
    "vpand %[mask], %%ymm15, %%ymm1\n\t"
    "vpackuswb %%ymm1, %%ymm0, %%ymm0\n\t"
    "vpermq $0xD8, %%ymm0, %%ymm0\n\t"
    "vmovdqu %%ymm0, 96(%[scr])\n\t"
    "vpand %[mask], %%ymm2, %%ymm0\n\t"
    "vpand %[mask], %%ymm3, %%ymm1\n\t"
    "vpackuswb %%ymm1, %%ymm0, %%ymm0\n\t"
    "vpermq $0xD8, %%ymm0, %%ymm0\n\t"
    "vmovdqu %%ymm0, 128(%[scr])\n\t"
    "vpand %[mask], %%ymm6, %%ymm0\n\t"
    "vpand %[mask], %%ymm7, %%ymm1\n\t"
    "vpackuswb %%ymm1, %%ymm0, %%ymm0\n\t"
    "vpermq $0xD8, %%ymm0, %%ymm0\n\t"
    "vmovdqu %%ymm0, 160(%[scr])\n\t"
    : [x0]"+r"(x0),[x1]"+r"(x1),[bi]"+r"(bi),[cnt]"+r"(cnt)
    : [mask]"m"(M9), [scr]"r"(scr)
    : "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15","cc","memory");
}
AVX2 static void mk_s(int n, const int8_t*A0, const int8_t*BI, int8_t*C, const uint8_t*PB, int jb){ (void)PB;
  const int8_t *x0=A0, *x1=A0+n, *bi=BI; long cnt=n>>3;
  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" "1:\n\t"
    "prefetcht0 1536(%[bi])\n\t"
    "vpbroadcastw (%[x0]), %%ymm0\n\t"
    "vpbroadcastw (%[x1]), %%ymm1\n\t"
    "vmovdqa 0(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vmovdqa 32(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vmovdqa 64(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 96(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vpbroadcastw 2(%[x0]), %%ymm0\n\t"
    "vpbroadcastw 2(%[x1]), %%ymm1\n\t"
    "vmovdqa 128(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vmovdqa 160(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vmovdqa 192(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 224(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vpbroadcastw 4(%[x0]), %%ymm0\n\t"
    "vpbroadcastw 4(%[x1]), %%ymm1\n\t"
    "vmovdqa 256(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vmovdqa 288(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vmovdqa 320(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 352(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "vpbroadcastw 6(%[x0]), %%ymm0\n\t"
    "vpbroadcastw 6(%[x1]), %%ymm1\n\t"
    "vmovdqa 384(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm8, %%ymm8\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm12, %%ymm12\n\t"
    "vmovdqa 416(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm9, %%ymm9\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm13, %%ymm13\n\t"
    "vmovdqa 448(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm10, %%ymm10\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm14, %%ymm14\n\t"
    "vmovdqa 480(%[bi]), %%ymm4\n\t"
    "vpmaddubsw %%ymm4, %%ymm0, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm11, %%ymm11\n\t"
    "vpmaddubsw %%ymm4, %%ymm1, %%ymm5\n\t"
    "vpaddw %%ymm5, %%ymm15, %%ymm15\n\t"
    "addq $8, %[x0]\n\t"
    "addq $8, %[x1]\n\t"
    "addq $512, %[bi]\n\t"
    "decq %[cnt]\n\t"
    "jnz 1b\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"
    "vmovdqu %%ymm2, 0(%[scr])\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"
    "vmovdqu %%ymm2, 32(%[scr])\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"
    "vmovdqu %%ymm2, 64(%[scr])\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"
    "vmovdqu %%ymm2, 96(%[scr])\n\t"
    : [x0]"+r"(x0),[x1]"+r"(x1),[bi]"+r"(bi),[cnt]"+r"(cnt)
    : [mask]"m"(W0FF), [scr]"r"(mscr)
    : "ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15","cc","memory");
}
static uint8_t Gtab[8*256*(NMAX/8)] __attribute__((aligned(64)));

#define LDU32(p) ({ __m256i _v; __asm__("vmovdqu %1, %0" : "=x"(_v) : "m"(*(const __m256i*)(p))); _v; })
#define XOR32(dst,p) __asm__("vpxor %1, %0, %0" : "+x"(dst) : "m"(*(const __m256i*)(p)))
#define STU32(p,v) __asm__ volatile("vmovdqu %1, %0" : "+m"(*(__m256i*)(p)) : "x"(v))
template<int NY>
__attribute__((target("avx2"))) static void corr_rows(int n,int B,int W,int gb0,const uint8_t*A1){
  for(int i=0;i<n;i++){
    const uint8_t*a=A1+(size_t)i*B;
    uint64_t*po=Pbb+(size_t)i*W;
    __m256i acc[NY];
    for(int q=0;q<NY;q++) acc[q]=_mm256_setzero_si256();
    for(int g=0;g<4;g++){
      const uint8_t*T=Gtab+((size_t)g*256+(size_t)a[gb0+g])*B;
      for(int q=0;q<NY;q++) XOR32(acc[q],T+(size_t)q*32);
    }
    for(int q=0;q<NY;q++){
      __m256i o=LDU32(po+4*(size_t)q);
      STU32(po+4*(size_t)q, _mm256_xor_si256(o,acc[q]));
    }
  }
}
__attribute__((target("avx2"))) static void corr_rus(int n){
  const int W=n/64, B=n/8, NY=B/32;
  if(NY!=1 && NY!=2 && NY!=4 && NY!=8 && NY!=16){ corr_pass3(n); return; }
  const uint8_t*A1=(const uint8_t*)A1b;
  memset(Pbb,0,(size_t)n*W*8);
  const int NB=4;                       
  for(int kb=0;kb<n;kb+=NB*8){
    for(int g=0;g<NB;g++){
      const int k0=kb+g*8;
      uint8_t*T0=Gtab+(size_t)g*256*B;
      memset(T0,0,B);
      for(int v=1;v<256;v++){
        uint8_t*dst=T0+(size_t)v*B;
        const uint8_t*pr=T0+(size_t)(v&(v-1))*B;
        const int k=k0+__builtin_ctz(v);
        const uint8_t*bp=(const uint8_t*)(BP2+(size_t)(k>>6)*(65*W)+(size_t)(k&63)*W);
        for(int q=0;q<B;q+=32){
          __m256i x=LDU32(pr+q);
          XOR32(x,bp+q);
          STU32(dst+q,x);
        }
      }
    }
    const int gb0=kb>>3;
    if(NY==16)    corr_rows<16>(n,B,W,gb0,A1);
    else if(NY==8)corr_rows<8>(n,B,W,gb0,A1);
    else if(NY==4)corr_rows<4>(n,B,W,gb0,A1);
    else if(NY==2)corr_rows<2>(n,B,W,gb0,A1);
    else          corr_rows<1>(n,B,W,gb0,A1);
  }
}

struct SBLK { const int8_t *X, *Y; int r0, c0, r1, c1, op; };
AVX2 static inline __m256i sblk_cmb(__m256i v, const int8_t *ya, int op){
  if (!op) return v;
  __m256i u = _mm256_load_si256((const __m256i*)ya);
  return (op==1) ? _mm256_add_epi8(v,u) : _mm256_sub_epi8(v,u);
}

AVX2 static void bld_A(int m, int nn, const SBLK*b){
  const __m256i msk=_mm256_set1_epi8(0x7F);
  int W=m/64;
  for (int i=0;i<m;i++){
    const int8_t*xa=b->X+(size_t)(b->r0+i)*nn+b->c0;
    const int8_t*ya=b->Y+(size_t)(b->r1+i)*nn+b->c1;
    int8_t*dst=A0b+(size_t)i*m;
    uint64_t*w1=A1b+(size_t)i*W;
    for (int k=0;k<m;k+=64){
      __m256i v0=_mm256_load_si256((const __m256i*)(xa+k));
      __m256i v1=_mm256_load_si256((const __m256i*)(xa+k+32));
      v0=sblk_cmb(v0,ya+k,   b->op);
      v1=sblk_cmb(v1,ya+k+32,b->op);
      _mm256_store_si256((__m256i*)(dst+k),    _mm256_and_si256(v0,msk));
      _mm256_store_si256((__m256i*)(dst+k+32), _mm256_and_si256(v1,msk));
      w1[k>>6]=(uint64_t)(uint32_t)_mm256_movemask_epi8(v0)
              |((uint64_t)(uint32_t)_mm256_movemask_epi8(v1)<<32);
    }
  }
}

AVX2 static void bld_B(int m, int nn, const SBLK*b){
  const __m256i one=_mm256_set1_epi8(1);
  int ng=m/64, W=m/64;
  for (int p=0;p<m/2;p++){
    const int8_t *ax=b->X+(size_t)(b->r0+2*p)*nn+b->c0;
    const int8_t *bx=ax+nn;
    const int8_t *ay=b->Y+(size_t)(b->r1+2*p)*nn+b->c1;
    const int8_t *by=ay+nn;
    uint64_t *w0p=BP2+(size_t)((2*p)>>6)*(size_t)(65*W)+(size_t)((2*p)&63)*W;
    uint64_t *w1p=BP2+(size_t)((2*p+1)>>6)*(size_t)(65*W)+(size_t)((2*p+1)&63)*W;
    for (int g=0;g<ng;g++){
      const int8_t *a=ax+64*g, *c=bx+64*g;
      const int8_t *d=ay+64*g, *e=by+64*g;
      int8_t *o=BI3b+((size_t)g*(m/2)+p)*128;
      for (int t=0;t<64;t+=32){
        __m256i va=sblk_cmb(_mm256_load_si256((const __m256i*)(a+t)), d+t, b->op);
        __m256i vb=sblk_cmb(_mm256_load_si256((const __m256i*)(c+t)), e+t, b->op);
        __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(_mm256_and_si256(va,one),7));
        uint32_t m1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(_mm256_and_si256(vb,one),7));
        if(t==0)      { w0p[g]=(uint64_t)m0;      w1p[g]=(uint64_t)m1; }
        else          { w0p[g]|=(uint64_t)m0<<32; w1p[g]|=(uint64_t)m1<<32; }
      }
    }
  }
}
static const int SAB_T[7][5] = {
  {0,0, 1,1, 1},   
  {1,0, 1,1, 1},   
  {0,0, 0,0, 0},   
  {1,1, 1,1, 0},   
  {0,0, 0,1, 1},   
  {1,0, 0,0, 2},   
  {0,1, 1,1, 2},   
};
static const int SBB_T[7][5] = {
  {0,0, 1,1, 1},   
  {0,0, 0,0, 0},   
  {0,1, 1,1, 2},   
  {1,0, 0,0, 2},   
  {1,1, 1,1, 0},   
  {0,0, 0,1, 1},   
  {1,0, 1,1, 1},   
};
static int8_t MMS[7][512*512] __attribute__((aligned(64)));
static int8_t M2[7][256*256] __attribute__((aligned(64)));

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_store_si256((__m256i*)(d+j), v);
    }
  }
}

static __m256i XT4_256[16][16] __attribute__((aligned(64)));
AVX2 static void corr4_256(void){
  const int n=256,W=4;
  for(int kb=0;kb<n;kb+=64){
    const int w0=kb>>6;
    for(int g=0;g<16;g++){
      XT4_256[g][0]=_mm256_setzero_si256();
      for(int v=1;v<16;v++){
        const int lb=__builtin_ctz(v),t2=v&(v-1),k=kb+4*g+lb;
        const uint64_t*bp=BP2+(size_t)(k>>6)*(65*W)+(size_t)(k&63)*W;
        XT4_256[g][v]=_mm256_xor_si256(XT4_256[g][t2],_mm256_load_si256((const __m256i*)bp));
      }
    }
    for(int i=0;i<n;i+=4){
      uint64_t bits[4]; __m256i acc[4];
      for(int r=0;r<4;r++){
        bits[r]=A1b[(size_t)(i+r)*W+w0];
        acc[r]=XT4_256[0][(int)(bits[r]&15)];
      }
      for(int g=1;g<16;g++)
        for(int r=0;r<4;r++)
          acc[r]=_mm256_xor_si256(acc[r],XT4_256[g][(int)((bits[r]>>(4*g))&15)]);
      for(int r=0;r<4;r++){
        __m256i*dst=(__m256i*)(Pbb+(size_t)(i+r)*W);
        if (kb == 0) _mm256_store_si256(dst,acc[r]);
        else _mm256_store_si256(dst,_mm256_xor_si256(_mm256_load_si256(dst),acc[r]));
      }
    }
  }
}

static inline int sgn_of(int op){ return op==0 ? 0 : (op==1 ? 1 : -1); }

AVX2 static void buildA4(int h, int n, const int8_t*A, int k1, int k2){
  const __m256i msk=_mm256_set1_epi8(0x7F);
  const int o1 = 512;
  const int *t1=SAB_T[k1], *t2=SAB_T[k2];
  const int s1=sgn_of(t1[4]), s2=sgn_of(t2[4]), s12=s1*s2;
  const size_t R1=(size_t)(t1[0]*o1+t2[0]*h)*n + t1[1]*o1+t2[1]*h;
  const size_t R2=(size_t)(t1[2]*o1+t2[0]*h)*n + t1[3]*o1+t2[1]*h;
  const size_t R3=(size_t)(t1[0]*o1+t2[2]*h)*n + t1[1]*o1+t2[3]*h;
  const size_t R4=(size_t)(t1[2]*o1+t2[2]*h)*n + t1[3]*o1+t2[3]*h;
  int W=h/64;
  for (int i=0;i<h;i++){
    const int8_t*p1=A+R1+(size_t)i*n;
    const int8_t*p2=A+R2+(size_t)i*n;
    const int8_t*p3=A+R3+(size_t)i*n;
    const int8_t*p4=A+R4+(size_t)i*n;
    int8_t*dst=A0b+(size_t)i*h;
    uint64_t*w1=A1b+(size_t)i*W;
    for (int k=0;k<h;k+=64){
      _mm_prefetch((const char*)(p1+k+4096), _MM_HINT_T0);
      _mm_prefetch((const char*)(p1+k+32+4096), _MM_HINT_T0);
      _mm_prefetch((const char*)(p2+k+4096), _MM_HINT_T0);
      _mm_prefetch((const char*)(p3+k+4096), _MM_HINT_T0);
      _mm_prefetch((const char*)(p4+k+4096), _MM_HINT_T0);
      __m256i v0=_mm256_load_si256((const __m256i*)(p1+k));
      __m256i v1=_mm256_load_si256((const __m256i*)(p1+k+32));
      if(s1){ __m256i u0=_mm256_load_si256((const __m256i*)(p2+k));
              __m256i u1=_mm256_load_si256((const __m256i*)(p2+k+32));
              if(s1>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);} }
      if(s2){ __m256i u0=_mm256_load_si256((const __m256i*)(p3+k));
              __m256i u1=_mm256_load_si256((const __m256i*)(p3+k+32));
              if(s2>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);} }
      if(s12){__m256i u0=_mm256_load_si256((const __m256i*)(p4+k));
              __m256i u1=_mm256_load_si256((const __m256i*)(p4+k+32));
              if(s12>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);} }
      _mm256_store_si256((__m256i*)(dst+k),    _mm256_and_si256(v0,msk));
      _mm256_store_si256((__m256i*)(dst+k+32), _mm256_and_si256(v1,msk));
      w1[k>>6]=(uint64_t)(uint32_t)_mm256_movemask_epi8(v0)
              |((uint64_t)(uint32_t)_mm256_movemask_epi8(v1)<<32);
    }
  }
}

AVX2 static void buildB4(int h, int n, const int8_t*B, int k1, int k2){
  const __m256i one=_mm256_set1_epi8(1);
  const int o1 = 512;
  const int *t1=SBB_T[k1], *t2=SBB_T[k2];
  const int s1=sgn_of(t1[4]), s2=sgn_of(t2[4]), s12=s1*s2;
  const size_t R1=(size_t)(t1[0]*o1+t2[0]*h)*n + t1[1]*o1+t2[1]*h;
  const size_t R2=(size_t)(t1[2]*o1+t2[0]*h)*n + t1[3]*o1+t2[1]*h;
  const size_t R3=(size_t)(t1[0]*o1+t2[2]*h)*n + t1[1]*o1+t2[3]*h;
  const size_t R4=(size_t)(t1[2]*o1+t2[2]*h)*n + t1[3]*o1+t2[3]*h;
  int ng=h/64, W=h/64;
  for (int p=0;p<h/2;p++){
    const int8_t *a1=B+R1+(size_t)(2*p)*n, *b1=B+R1+(size_t)(2*p+1)*n;
    const int8_t *a2=B+R2+(size_t)(2*p)*n, *b2=B+R2+(size_t)(2*p+1)*n;
    const int8_t *a3=B+R3+(size_t)(2*p)*n, *b3=B+R3+(size_t)(2*p+1)*n;
    const int8_t *a4=B+R4+(size_t)(2*p)*n, *b4=B+R4+(size_t)(2*p+1)*n;
    uint64_t *w0p=BP2+(size_t)((2*p)>>6)*(size_t)(65*W)+(size_t)((2*p)&63)*W;
    uint64_t *w1p=BP2+(size_t)((2*p+1)>>6)*(size_t)(65*W)+(size_t)((2*p+1)&63)*W;
    for (int g=0;g<ng;g++){
      const int8_t *a=a1+64*g, *c=b1+64*g;
      const int8_t *d=a2+64*g, *e=b2+64*g;
      const int8_t *f=a3+64*g, *h3=b3+64*g;
      const int8_t *m4=a4+64*g, *n4=b4+64*g;
      int8_t *o=BI3b+((size_t)g*(h/2)+p)*128;
      for (int t=0;t<64;t+=32){
        _mm_prefetch((const char*)(a +t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(c +t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(d +t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(e +t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(f +t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(h3+t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(m4+t+4096), _MM_HINT_T0);
        _mm_prefetch((const char*)(n4+t+4096), _MM_HINT_T0);
        __m256i va=_mm256_load_si256((const __m256i*)(a+t));
        __m256i vb=_mm256_load_si256((const __m256i*)(c+t));
        if(s1){ __m256i u0=_mm256_load_si256((const __m256i*)(d+t));
                __m256i u1=_mm256_load_si256((const __m256i*)(e+t));
                if(s1>0){va=_mm256_add_epi8(va,u0);vb=_mm256_add_epi8(vb,u1);}
                else    {va=_mm256_sub_epi8(va,u0);vb=_mm256_sub_epi8(vb,u1);} }
        if(s2){ __m256i u0=_mm256_load_si256((const __m256i*)(f+t));
                __m256i u1=_mm256_load_si256((const __m256i*)(h3+t));
                if(s2>0){va=_mm256_add_epi8(va,u0);vb=_mm256_add_epi8(vb,u1);}
                else    {va=_mm256_sub_epi8(va,u0);vb=_mm256_sub_epi8(vb,u1);} }
        if(s12){__m256i u0=_mm256_load_si256((const __m256i*)(m4+t));
                __m256i u1=_mm256_load_si256((const __m256i*)(n4+t));
                if(s12>0){va=_mm256_add_epi8(va,u0);vb=_mm256_add_epi8(vb,u1);}
                else     {va=_mm256_sub_epi8(va,u0);vb=_mm256_sub_epi8(vb,u1);} }
        __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(_mm256_and_si256(va,one),7));
        uint32_t m1=(uint32_t)_mm256_movemask_epi8(_mm256_slli_epi16(_mm256_and_si256(vb,one),7));
        if(t==0)      { w0p[g]=(uint64_t)m0;      w1p[g]=(uint64_t)m1; }
        else          { w0p[g]|=(uint64_t)m0<<32; w1p[g]|=(uint64_t)m1<<32; }
      }
    }
  }
}

AVX2 static void submm512_4(int m, int n, const int8_t*A, const int8_t*B, int k1, int k2,
                            int8_t*Cp){
  buildA4(m,n,A,k1,k2); buildB4(m,n,B,k1,k2);
  { const int W=m>>6; for (int g=0; g<(m>>6); g++) memset(BP2+(size_t)g*65*W+64*W, 0, (size_t)W*8); }
  if(m==256) corr4_256(); else corr_rus(m);
  for (int g=0; g<m; g+=64)
    for (int i=0; i<m; i+=2){
      mk_s(m, A0b+(size_t)i*m, BI3b+(size_t)(g>>6)*(m/2)*128, Cp, PBb, g);
      epilogue(m, Cp, (const uint64_t*)Pbb, g, i, 2);
    }
}

AVX2 static void strassen2_512(int8_t*Cp, const int8_t*A, const int8_t*B, int n, int k1){
  const int m=512,h=256;
  for(int k=0;k<7;k++){
    submm512_4(h,n,A,B,k1,k,M2[k]);
  }
  cmb4(Cp,m,h,M2);
}
AVX2 static void strassen1(int n, const int8_t*A, const int8_t*B, int8_t*C){
  const int m = n>>1;                       
  const int o = m;
  for (int k=0;k<7;k++){
    strassen2_512(MMS[k], A, B, n, k);
  }
  cmb4(C,n,m,MMS);
}
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==1024) { strassen1(n,A,B,C); return; }
  build_A0_A1(n,A);
  if(n==1024){
    build_BI9(n,B); build_BI3_tail(n,B); build_BP2(n,B); corr_rus(n);
    for (int g=0; g<10; g++)
      for (int i=0; i<n; i+=2){
        mk_s6(n, A0b+(size_t)i*n, BI9b+(size_t)g*(n/2)*192, (uint8_t*)mscr);
        epilogue(n, C, (const uint64_t*)Pbb, g*96, i, 3);
      }
    for (int i=0; i<n; i+=2){
      mk_s(n, A0b+(size_t)i*n, BI3b, C, PBb, 0);
      epilogue(n, C, (const uint64_t*)Pbb, 960, i, 2);
    }
    return;
  }
  build_BI3(n,B); build_Bpbits(n,B);
  if(n==4096) corr16(); else corr_pass3(n);
  for (int g=0, jbg=0; g<n; g+=64, jbg=g)
    for (int i=0; i<n; i+=2)
      { mk_s(n, A0b+(size_t)i*n, BI3b+(size_t)(g>>6)*(n/2)*128, C, PBb, g);
        epilogue(n, C, (const uint64_t*)Pbb, g, i, 2); }
}
}

CompilationN/AN/ACompile OKScore: N/A

Testcase #1394.97 ms63 MB + 388 KBAcceptedScore: 100


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