/* seat14_fresh_20261031 agg4 2026-10-31 0submit: base cand_twdel_agg4.cpp (sha256 8b8c7813, 101919cp, sid141141) + ONE change: dh4's fused S=4 level, four horizontal final_dif4_vec calls -> transposed vertical radix-4 (two 4x4 lane transposes, one vS, same mod-p math); inherited notices below unchanged. Full 80000004B output identical: mode0 FNV fb206c93723a3583 C0=10, all-9 77fffe38ccc593f7 C0=81, unaligned-c fallback identical. */
/* agg4 ADOPT of saffah_codex_6a_agg3 #140076 <https://duck.ac/submission/140076> (283,842.545us, 2026-10-23 00:51:39):
body adopted in full with attribution (their header below intact; their chain = our #139932 <https://duck.ac/submission/139932>
+ their #139747/#140059 lazy inverse boundaries). Nothing of ours removed.
Gates: full 80,000,004-byte output byte-identical to #139932, random and all-9 inputs.
*/
/* References: saffah_codex_6a_agg3 https://duck.ac/submission/140059: pointer-hoisted engine with three lazy middle inverse boundaries, all prior attribution below.
Idea: Extend the range proof across the padded16384-coefficient slab boundary. In the known even,L4 path, only child slabs1/2/3 feed Montgomery in merge4_dit_s3, so their H4096 outputs can remain below2P. Child0 stays canonical and every other geometry retains its original path. No padding element becomes data. Shorten private names solely for source size.
Purpose: Delete canonicalization before the next Montgomery consumer. Verify padded groups, modular ranges and complete20M outputs at three alignments.
*/
/* References: saffah_v41f1017_agg4 https://duck.ac/submission/139932: pointer-hoisted engine below; saffah_codex_6a_agg3 https://duck.ac/submission/139747: our three proven lazy inverse boundaries.
Idea: Combine those independent improvements. Keep canonical unmultiplied children, but omit normalization for fused64 and middle H64/H256/H1024 outputs consumed only by Montgomery. Bounds a<2P,b<P and unchanged canonical consumers still apply. Shorten three private helper names solely for source size.
Purpose: Validate stage residues/bounds and every full output on the new pointer layout.
*/
/* 1002e7: ac4 FUSE-IM (inv->merge; ours #139464<https://duck.ac/submission/139464>) + agg4 H1FUSE (h1->h4 DIT). Sources per RULES sec.3 (no license; acct+URL+content): saffah_codex_6a_agg3 #139373 <https://duck.ac/submission/139373> base; #139367 <https://duck.ac/submission/139367> merge5; #139358 <https://duck.ac/submission/139358>; #139353 <https://duck.ac/submission/139353>; #133546 <https://duck.ac/submission/133546> slabs; #128549 <https://duck.ac/submission/128549> changes; #125868 <https://duck.ac/submission/125868>; #121456 <https://duck.ac/submission/121456>; #121443 <https://duck.ac/submission/121443>; #121420 <https://duck.ac/submission/121420>; #120684 <https://duck.ac/submission/120684>; #120621 <https://duck.ac/submission/120621>; saffah_cc_v41_agg1 #130191 <https://duck.ac/submission/130191> base; #127195 <https://duck.ac/submission/127195>; #121257 <https://duck.ac/submission/121257>; #122356 <https://duck.ac/submission/122356>; #122333 <https://duck.ac/submission/122333>; #122392 <https://duck.ac/submission/122392>; #126906 <https://duck.ac/submission/126906>; #111674 <https://duck.ac/submission/111674>.
agg4 chain: H1FUSE = ours #139571 <https://duck.ac/submission/139571> (inverse h1->h4 DIT ring fusion).
agg4 additions on that base (all value-preserving; full 80,000,004-byte outputs byte-identical):
(1) S64FUSE: inverse S=16 -> S=64 ring levels fused in registers (removes one 64KB-slab store/load round trip);
(2) DISPHOIST: loop-invariant switch(S) dispatch hoisted out of the ring block loops in fwd_sb_ring and ntt_inv_tail;
(3) PADGATE: PADJUMP/PADJUMP_S four boundary compares replaced by one nearest-boundary gate (min counter), sync at crossings;
(4) PMSPLIT: dh4 g_pmdelta branch split into norm/pm loop variants with delta folded into the base pointer;
(5) S64 kernel always_inline into ntt_inv_tail.
(6) PTRHOIST: ds2/s3 and merge4_dit_s2/s3 tails, stage16_dif_top_batch, and the H16 ring level use raw incremented data/twiddle pointers instead of gcc9 per-iteration pointer-chain reloads; byte-exact, Ir -38.90M vs cand_disp.
(7) PTRHOIST2: single-base table/data addressing from build_tabs layout (MP=H+TPAD) for stage4_dif_h, merge4_dit_h, ds2/s3, merge4_dit_s2/s3, fused inverse l-tables and bodyC; H4 pointer loops; H16 noinline single-base loop with its four prefetches removed. Ir -66.45M vs cand_disp (additional -27.56M vs PTRHOIST).
Gates rand sha1 4bc5ad88828cf2aefc06810ad4032ec5c2ef1677, all-9 9276aacf2a6b58674a5d65128fd2908318e308f0.
*/
#define NTT_MAXN 8500000u
#pragma GCC optimize("O3,rename-registers")
#include <immintrin.h>
#include <cstdint>
#include <cstring>
#include <cstdlib>
__attribute__((target("avx2")))static inline __m256i ldu256(const void*p){__m256i r;__asm__("vmovdqu %1, %0":"=x"(r):"m"(*(const __m256i*)p));return r;}__attribute__((target("avx2")))static inline void stu256(void*p,__m256i v){__asm__("vmovdqu %1, %0":"=m"(*(__m256i*)p):"x"(v));}typedef uint32_t u32;typedef uint64_t u64;
#define PF_DIST 192
static inline void pf5(const void*p){_mm_prefetch((const char*)p,_MM_HINT_T0);}
#define NTP 2013265921u
#define TPAD 704u
#define TOPPAD 128u
static inline u32 padpos(u32 i){return i+TOPPAD*((i>>20)+(i>>18)+(i>>16)+(i>>14));}
#define PADJUMP() if (j >= nxt) { if (j >= nxt0) { bp += TOPPAD; nxt0 += (1u << 20); } \
if (j >= nxt1) { bp += TOPPAD; nxt1 += (1u << 18); } \
if (j >= nxt2) { bp += TOPPAD; nxt2 += (1u << 16); } \
if (j >= nxt3) { bp += TOPPAD; nxt3 += (1u << 14); } \
nxt = nxt0; if (nxt1 < nxt) nxt = nxt1; if (nxt2 < nxt) nxt = nxt2; if (nxt3 < nxt) nxt = nxt3; }
#define PADJUMP_S() if (s >= nxt) { if (s >= nxt0) { bp += TOPPAD; nxt0 += (1u << 20); } \
if (s >= nxt1) { bp += TOPPAD; nxt1 += (1u << 18); } \
if (s >= nxt2) { bp += TOPPAD; nxt2 += (1u << 16); } \
if (s >= nxt3) { bp += TOPPAD; nxt3 += (1u << 14); } \
nxt = nxt0; if (nxt1 < nxt) nxt = nxt1; if (nxt2 < nxt) nxt = nxt2; if (nxt3 < nxt) nxt = nxt3; }
#define TGT __attribute__((target("avx2")))
static u32 g_scale_digit[10];static u32 g_scale_lo[8]__attribute__((aligned(32)));static u32 g_scale_hi[8]__attribute__((aligned(32)));template<bool SCALE>TGT static inline __m256i lds256(const void*p){__m256i v=ldu256(p);if constexpr(SCALE){__m256i lo=ldu256(g_scale_lo),hi=ldu256(g_scale_hi);__m256i a=_mm256_permutevar8x32_epi32(lo,v);__m256i b=_mm256_permutevar8x32_epi32(hi,v);return _mm256_blendv_epi8(a,b,_mm256_cmpgt_epi32(v,_mm256_set1_epi32(7)));}return v;}
#ifndef NTT_MAXN
#define NTT_MAXN (1u << 25)
#endif
static u32 g_n,g_Sb;static u32 g_pinv;static int g_log2n,g_L,g_odd,g_nb,g_BT=13;static u32 g_ciF,g_cisF,g_ciI,g_cisI;static u32 g_tabF[5*NTT_MAXN/2+4096]__attribute__((aligned(64)));
#define Q_T5OFF (5 * NTT_MAXN / 2 + 4096 - 4 * (1u << 22))
#define Q_SCF (g_tabF + Q_T5OFF + (1u << 22))
#define Q_SCI (g_tabI + Q_T5OFF + (1u << 22))
static u32 g_tabI[5*NTT_MAXN/2+4096]__attribute__((aligned(64)));struct Tabs{const u32*l1[40],*l2[40],*l3[40],*m1[40],*m2[40],*m3[40];const u32*b2,*b2s;const u32*h1[40],*h2[40],*h3[40],*q1[40],*q2[40],*q3[40];};static Tabs g_TF,g_TI;static inline u32 mulmod(u32 a,u32 b){return(u32)((u64)a*b%NTP);}static u32 powmod(u32 a,u32 e){u32 r=1;while(e){if(e&1)r=mulmod(r,a);a=mulmod(a,a);e>>=1;}return r;}
#define RRW ((u32)((1ull<<32)%NTP))
static u32 g_wf,g_wif;static void tw16(u32*d,u32 x,u32 r){for(int i=0;i<16;i++){d[i]=x;x=mulmod(x,r);}}static inline u32 shoup1s(u32 a,u32 w,u32 ws){u32 t=(u32)((u64)a*w);u32 q=(u32)(((u64)a*ws)>>32);u32 r=t-(u32)((u64)q*NTP);return r>=NTP?r-NTP:r;}static inline u32 shoup_c(u32 w){return(u32)(((u64)w<<32)/NTP);}TGT static inline __m256i vmulhi(__m256i a,__m256i b){__m256i e=_mm256_mul_epu32(a,b);__m256i o=_mm256_mul_epu32(_mm256_bsrli_epi128(a,4),_mm256_bsrli_epi128(b,4));e=_mm256_bsrli_epi128(e,4);return _mm256_blend_epi32(e,o,0xAA);}TGT static inline __m256i vmont(__m256i a,__m256i b,__m256i pv){const __m256i pinv=_mm256_set1_epi32((int)g_pinv);__m256i tlo=_mm256_mullo_epi32(a,b);__m256i thi=vmulhi(a,b);__m256i m=_mm256_mullo_epi32(tlo,pinv);__m256i mhi=vmulhi(m,pv);__m256i nz=_mm256_andnot_si256(_mm256_cmpeq_epi32(tlo,_mm256_setzero_si256()),_mm256_set1_epi32(1));__m256i u=_mm256_add_epi32(_mm256_add_epi32(thi,mhi),nz);return _mm256_min_epu32(u,_mm256_sub_epi32(u,pv));}TGT static inline __m256i mpa(__m256i a,__m256i b,__m256i pv){const __m256i np=_mm256_set1_epi64x((long long)g_pinv);const __m256i p64=_mm256_set1_epi64x((long long)NTP);__m256i ae=_mm256_mul_epu32(a,b);__m256i ao=_mm256_mul_epu32(_mm256_bsrli_epi128(a,4),_mm256_bsrli_epi128(b,4));__m256i me=_mm256_mul_epu32(ae,np),mo=_mm256_mul_epu32(ao,np);ae=_mm256_add_epi64(ae,_mm256_mul_epu32(me,p64));ao=_mm256_add_epi64(ao,_mm256_mul_epu32(mo,p64));__m256i value=_mm256_or_si256(_mm256_bsrli_epi128(ae,4),ao);return _mm256_min_epu32(value,_mm256_sub_epi32(value,pv));}TGT static inline __m256i mpb(__m256i a,__m256i b,__m256i bpi,__m256i pv){const __m256i p64=_mm256_set1_epi64x((long long)NTP);__m256i ae=_mm256_mul_epu32(a,b);__m256i ao=_mm256_mul_epu32(_mm256_bsrli_epi128(a,4),_mm256_bsrli_epi128(b,4));__m256i me=_mm256_mul_epu32(a,bpi),mo=_mm256_mul_epu32(_mm256_bsrli_epi128(a,4),_mm256_bsrli_epi128(bpi,4));ae=_mm256_add_epi64(ae,_mm256_mul_epu32(me,p64));ao=_mm256_add_epi64(ao,_mm256_mul_epu32(mo,p64));__m256i value=_mm256_or_si256(_mm256_bsrli_epi128(ae,4),ao);return _mm256_min_epu32(value,_mm256_sub_epi32(value,pv));}TGT static inline __m128i mpc(__m128i a,__m128i b,__m128i bpi,__m128i pv){const __m128i p64=_mm_set1_epi64x((long long)NTP);__m128i ae=_mm_mul_epu32(a,b);__m128i ao=_mm_mul_epu32(_mm_bsrli_si128(a,4),_mm_bsrli_si128(b,4));__m128i me=_mm_mul_epu32(a,bpi),mo=_mm_mul_epu32(_mm_bsrli_si128(a,4),_mm_bsrli_si128(bpi,4));ae=_mm_add_epi64(ae,_mm_mul_epu32(me,p64));ao=_mm_add_epi64(ao,_mm_mul_epu32(mo,p64));__m128i value=_mm_or_si128(_mm_bsrli_si128(ae,4),ao);return _mm_min_epu32(value,_mm_sub_epi32(value,pv));}TGT static inline __m128i mont_prepared4(__m128i a,__m128i b,__m128i pv){const __m128i np=_mm_set1_epi64x((long long)g_pinv);const __m128i p64=_mm_set1_epi64x((long long)NTP);__m128i ae=_mm_mul_epu32(a,b);__m128i ao=_mm_mul_epu32(_mm_bsrli_si128(a,4),_mm_bsrli_si128(b,4));__m128i me=_mm_mul_epu32(ae,np),mo=_mm_mul_epu32(ao,np);ae=_mm_add_epi64(ae,_mm_mul_epu32(me,p64));ao=_mm_add_epi64(ao,_mm_mul_epu32(mo,p64));__m128i value=_mm_or_si128(_mm_bsrli_si128(ae,4),ao);return _mm_min_epu32(value,_mm_sub_epi32(value,pv));}
#define MLO_V 572662301u
TGT static inline __m256i der_ws(__m256i w){__m256i mlo=_mm256_set1_epi32((int)MLO_V);return _mm256_add_epi32(_mm256_add_epi32(w,w),vmulhi(w,mlo));}TGT static inline __m256i vS(__m256i a,__m256i w,__m256i ws,__m256i pv){__m256i t=_mm256_mullo_epi32(a,w);__m256i q=vmulhi(a,ws);__m256i r=_mm256_sub_epi32(t,_mm256_add_epi32(q,_mm256_sub_epi32(_mm256_slli_epi32(q,31),_mm256_slli_epi32(q,27))));return _mm256_min_epu32(r,_mm256_sub_epi32(r,pv));}TGT static inline __m256i vaddm(__m256i a,__m256i b,__m256i pv){__m256i s=_mm256_add_epi32(a,b);return _mm256_min_epu32(s,_mm256_sub_epi32(s,pv));}TGT static inline __m256i vsubm(__m256i a,__m256i b,__m256i pv){__m256i d=_mm256_sub_epi32(a,b);return _mm256_min_epu32(d,_mm256_add_epi32(d,pv));}TGT static inline __m128i vmulhi4(__m128i a,__m128i b){__m128i e=_mm_mul_epu32(a,b);__m128i o=_mm_mul_epu32(_mm_bsrli_si128(a,4),_mm_bsrli_si128(b,4));e=_mm_bsrli_si128(e,4);return _mm_blend_epi32(e,o,0xAA);}TGT static inline __m128i sh4(__m128i a,__m128i w,__m128i ws,__m128i pv){__m128i t=_mm_mullo_epi32(a,w);__m128i q=vmulhi4(a,ws);__m128i r=_mm_sub_epi32(t,_mm_add_epi32(q,_mm_sub_epi32(_mm_slli_epi32(q,31),_mm_slli_epi32(q,27))));return _mm_min_epu32(r,_mm_sub_epi32(r,pv));}TGT static inline __m128i add4(__m128i a,__m128i b,__m128i pv){__m128i s=_mm_add_epi32(a,b);return _mm_min_epu32(s,_mm_sub_epi32(s,pv));}TGT static inline __m128i sub4(__m128i a,__m128i b,__m128i pv){__m128i d=_mm_sub_epi32(a,b);return _mm_min_epu32(d,_mm_add_epi32(d,pv));}TGT static inline __m256i ld2(const __m128i*lo,const __m128i*hi){return _mm256_inserti128_si256(_mm256_castsi128_si256(_mm_loadu_si128(lo)),_mm_loadu_si128(hi),1);}TGT static inline void st2(__m128i*lo,__m128i*hi,__m256i v){_mm_storeu_si128(lo,_mm256_castsi256_si128(v));_mm_storeu_si128(hi,_mm256_extracti128_si256(v,1));}TGT static inline __m256i bc128(__m128i v){return _mm256_inserti128_si256(_mm256_castsi128_si256(v),v,1);}TGT static inline __m256i vL(__m256i a,__m256i b,__m256i pv){return _mm256_add_epi32(_mm256_sub_epi32(a,b),pv);}TGT static inline __m128i sub_lazy4(__m128i a,__m128i b,__m128i pv){return _mm_add_epi32(_mm_sub_epi32(a,b),pv);}TGT static void stage0_dif_src(u32*a,const u32*src,u32 len,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const __m256i zero=_mm256_setzero_si256();u32 j=0;u32 lim1=len-h;for(;j+8<=lim1+1;j+=8){__builtin_prefetch(src+j+192);__builtin_prefetch(src+j+h+192);__builtin_prefetch(a+j+192);__builtin_prefetch(a+j+h+192);__builtin_prefetch(a+j+2*h+192);__builtin_prefetch(a+j+3*h+192);__builtin_prefetch(t1+j+192);__m256i x0=ldu256((src+j));__m256i x1=ldu256((src+j+h));__m256i u0=vaddm(x0,x1,pv),u2=vL(x0,x1,pv);__m256i E=vS(x1,cI,cIs,pv);__m256i u1=_mm256_add_epi32(x0,E),u3=vL(x0,E,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}stu256((a+j),u0);stu256((a+j+h),u1);stu256((a+j+2*h),u2);stu256((a+j+3*h),u3);}for(;j<=lim1&&j<h;j++){u32 x0=(j<=len)?src[j]:0,x1=(j+h<=len)?src[j+h]:0;u32 u0=(u32)(((u64)x0+x1)%NTP);u32 u2=(u32)(((u64)x0+NTP-x1)%NTP);u32 E=mulmod(x1,ci);u32 u1=(u32)(((u64)x0+E)%NTP),u3=(u32)(((u64)x0+NTP-E)%NTP);u1=shoup1s(u1,t1[j],shoup_c(t1[j]));u2=shoup1s(u2,t2[j],shoup_c(t2[j]));u3=shoup1s(u3,t3[j],shoup_c(t3[j]));a[j]=u0;a[j+h]=u1;a[j+2*h]=u2;a[j+3*h]=u3;}for(;j+8<=h;j+=8){__m256i x0=(j+8<=len+1)?ldu256((src+j)):zero;__m256i u0=x0,u1=x0,u2=x0,u3=x0;{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}stu256((a+j),u0);stu256((a+j+h),u1);stu256((a+j+2*h),u2);stu256((a+j+3*h),u3);}for(;j<h;j++){u32 x0=(j<=len)?src[j]:0;u32 u1=shoup1s(x0,t1[j],shoup_c(t1[j]));u32 u2=shoup1s(x0,t2[j],shoup_c(t2[j]));u32 u3=shoup1s(x0,t3[j],shoup_c(t3[j]));a[j]=x0;a[j+h]=u1;a[j+2*h]=u2;a[j+3*h]=u3;}}TGT static void stage4_dif_s0(u32*a,u32 blk,u32 h,u32 s,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*s){u32*p=a+i;u32 poff=0,nxt18=1u<<18,nxt16=1u<<16;for(u32 cb=0;cb<h;cb+=16384u){u32*pc=p+poff;u32 j=cb,jr=0;for(;j+16<=cb+16384u;j+=16,jr+=16){__builtin_prefetch(pc+jr+192);__builtin_prefetch(pc+jr+s+192);__builtin_prefetch(pc+jr+2*s+192);__builtin_prefetch(pc+jr+3*s+192);__builtin_prefetch(t1+j+192);__builtin_prefetch(t2+j+192);__builtin_prefetch(t3+j+192);__m256i x0=ldu256((pc+jr));__m256i x1=ldu256((pc+jr+s));__m256i x2=ldu256((pc+jr+2*s));__m256i x3=ldu256((pc+jr+3*s));__m256i y0=ldu256((pc+jr+8));__m256i y1=ldu256((pc+jr+s+8));__m256i y2=ldu256((pc+jr+2*s+8));__m256i y3=ldu256((pc+jr+3*s+8));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv);__m256i F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}{v1=mpa(v1,ldu256((t1+j+8)),pv);}{v2=mpa(v2,ldu256((t2+j+8)),pv);}{v3=mpa(v3,ldu256((t3+j+8)),pv);}stu256((pc+jr),u0);stu256((pc+jr+s),u1);stu256((pc+jr+2*s),u2);stu256((pc+jr+3*s),u3);stu256((pc+jr+8),v0);stu256((pc+jr+s+8),v1);stu256((pc+jr+2*s+8),v2);stu256((pc+jr+3*s+8),v3);}for(;j+8<=cb+16384u;j+=8,jr+=8){__builtin_prefetch(pc+jr+192);__builtin_prefetch(pc+jr+s+192);__builtin_prefetch(pc+jr+2*s+192);__builtin_prefetch(pc+jr+3*s+192);__m256i x0=ldu256((pc+jr));__m256i x1=ldu256((pc+jr+s));__m256i x2=ldu256((pc+jr+2*s));__m256i x3=ldu256((pc+jr+3*s));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}stu256((pc+jr),u0);stu256((pc+jr+s),u1);stu256((pc+jr+2*s),u2);stu256((pc+jr+3*s),u3);}poff+=16384u+TOPPAD;if(cb+16384u>=nxt18){poff+=TOPPAD;nxt18+=(1u<<18);}if(cb+16384u>=nxt16){poff+=TOPPAD;nxt16+=(1u<<16);}}}}TGT static void stage4_dif_s1(u32*a,u32 blk,u32 h,u32 s,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*s){u32*p=a+i;u32 poff=0,nxt16=1u<<16;for(u32 cb=0;cb<h;cb+=16384u){u32*pc=p+poff;u32 j=cb,jr=0;for(;j+16<=cb+16384u;j+=16,jr+=16){__builtin_prefetch(pc+jr+192);__builtin_prefetch(pc+jr+s+192);__builtin_prefetch(pc+jr+2*s+192);__builtin_prefetch(pc+jr+3*s+192);__builtin_prefetch(t1+j+192);__builtin_prefetch(t2+j+192);__builtin_prefetch(t3+j+192);__m256i x0=ldu256((pc+jr));__m256i x1=ldu256((pc+jr+s));__m256i x2=ldu256((pc+jr+2*s));__m256i x3=ldu256((pc+jr+3*s));__m256i y0=ldu256((pc+jr+8));__m256i y1=ldu256((pc+jr+s+8));__m256i y2=ldu256((pc+jr+2*s+8));__m256i y3=ldu256((pc+jr+3*s+8));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv);__m256i F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}{v1=mpa(v1,ldu256((t1+j+8)),pv);}{v2=mpa(v2,ldu256((t2+j+8)),pv);}{v3=mpa(v3,ldu256((t3+j+8)),pv);}stu256((pc+jr),u0);stu256((pc+jr+s),u1);stu256((pc+jr+2*s),u2);stu256((pc+jr+3*s),u3);stu256((pc+jr+8),v0);stu256((pc+jr+s+8),v1);stu256((pc+jr+2*s+8),v2);stu256((pc+jr+3*s+8),v3);}for(;j+8<=cb+16384u;j+=8,jr+=8){__builtin_prefetch(pc+jr+192);__builtin_prefetch(pc+jr+s+192);__builtin_prefetch(pc+jr+2*s+192);__builtin_prefetch(pc+jr+3*s+192);__m256i x0=ldu256((pc+jr));__m256i x1=ldu256((pc+jr+s));__m256i x2=ldu256((pc+jr+2*s));__m256i x3=ldu256((pc+jr+3*s));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}stu256((pc+jr),u0);stu256((pc+jr+s),u1);stu256((pc+jr+2*s),u2);stu256((pc+jr+3*s),u3);}poff+=16384u+TOPPAD;if(cb+16384u>=nxt16){poff+=TOPPAD;nxt16+=(1u<<16);}}}}TGT static void ds2(u32*a,u32 blk,u32 h,u32 s,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const u32 MP=h+TPAD;for(u32 i=0;i<blk;i+=4*s){u32*p=a+i;u32 poff=0;for(u32 cb=0;cb<h;cb+=16384u){u32*q0=p+poff,*q1=q0+s,*q2=q1+s,*q3=q2+s;const u32*w=t1+cb;u32 jr=0;for(;jr+16<=16384u;jr+=16,q0+=16,q1+=16,q2+=16,q3+=16,w+=16){__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__builtin_prefetch(w+192);__builtin_prefetch(w+MP+192);__builtin_prefetch(w+2*MP+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);__m256i y0=ldu256(q0+8),y1=ldu256(q1+8),y2=ldu256(q2+8),y3=ldu256(q3+8);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);u1=mpa(u1,ldu256(w),pv);u2=mpa(u2,ldu256(w+MP),pv);u3=mpa(u3,ldu256(w+2*MP),pv);v1=mpa(v1,ldu256(w+8),pv);v2=mpa(v2,ldu256(w+MP+8),pv);v3=mpa(v3,ldu256(w+2*MP+8),pv);stu256(q0,u0);stu256(q1,u1);stu256(q2,u2);stu256(q3,u3);stu256(q0+8,v0);stu256(q1+8,v1);stu256(q2+8,v2);stu256(q3+8,v3);}for(;jr+8<=16384u;jr+=8,q0+=8,q1+=8,q2+=8,q3+=8,w+=8){__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);u1=mpa(u1,ldu256(w),pv);u2=mpa(u2,ldu256(w+MP),pv);u3=mpa(u3,ldu256(w+2*MP),pv);stu256(q0,u0);stu256(q1,u1);stu256(q2,u2);stu256(q3,u3);}poff+=16384u+TOPPAD;}}}TGT static void ds3(u32*a,u32 blk,u32 h,u32 s,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const u32 MP=h+TPAD;for(u32 i=0;i<blk;i+=4*s){u32*q0=a+i,*q1=q0+s,*q2=q1+s,*q3=q2+s;const u32*w=t1;u32 j=0;for(;j+16<=h;j+=16,q0+=16,q1+=16,q2+=16,q3+=16,w+=16){__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__builtin_prefetch(w+192);__builtin_prefetch(w+MP+192);__builtin_prefetch(w+2*MP+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);__m256i y0=ldu256(q0+8),y1=ldu256(q1+8),y2=ldu256(q2+8),y3=ldu256(q3+8);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);u1=mpa(u1,ldu256(w),pv);u2=mpa(u2,ldu256(w+MP),pv);u3=mpa(u3,ldu256(w+2*MP),pv);v1=mpa(v1,ldu256(w+8),pv);v2=mpa(v2,ldu256(w+MP+8),pv);v3=mpa(v3,ldu256(w+2*MP+8),pv);stu256(q0,u0);stu256(q1,u1);stu256(q2,u2);stu256(q3,u3);stu256(q0+8,v0);stu256(q1+8,v1);stu256(q2+8,v2);stu256(q3+8,v3);}for(;j+8<=h;j+=8,q0+=8,q1+=8,q2+=8,q3+=8,w+=8){__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);u1=mpa(u1,ldu256(w),pv);u2=mpa(u2,ldu256(w+MP),pv);u3=mpa(u3,ldu256(w+2*MP),pv);stu256(q0,u0);stu256(q1,u1);stu256(q2,u2);stu256(q3,u3);}}}TGT static void stage4_dif(u32*a,u32 blk,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*h){u32*p=a+i;u32 j=0;for(;j+16<=h;j+=16){__builtin_prefetch(p+j+192);__builtin_prefetch(p+j+h+192);__builtin_prefetch(p+j+2*h+192);__builtin_prefetch(p+j+3*h+192);__builtin_prefetch(t1+j+192);__builtin_prefetch(t2+j+192);__builtin_prefetch(t3+j+192);__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));__m256i y0=ldu256((p+j+8));__m256i y1=ldu256((p+j+h+8));__m256i y2=ldu256((p+j+2*h+8));__m256i y3=ldu256((p+j+3*h+8));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv);__m256i F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}{v1=mpa(v1,ldu256((t1+j+8)),pv);}{v2=mpa(v2,ldu256((t2+j+8)),pv);}{v3=mpa(v3,ldu256((t3+j+8)),pv);}stu256((p+j),u0);stu256((p+j+h),u1);stu256((p+j+2*h),u2);stu256((p+j+3*h),u3);stu256((p+j+8),v0);stu256((p+j+h+8),v1);stu256((p+j+2*h+8),v2);stu256((p+j+3*h+8),v3);}for(;j+8<=h;j+=8){__builtin_prefetch(p+j+192);__builtin_prefetch(p+j+h+192);__builtin_prefetch(p+j+2*h+192);__builtin_prefetch(p+j+3*h+192);__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}stu256((p+j),u0);stu256((p+j+h),u1);stu256((p+j+2*h),u2);stu256((p+j+3*h),u3);}}}TGT static void stage4_dif_t(u32*a,u32 blk,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*h){u32*p=a+i;u32 j=0;for(;j+16<=h;j+=16){__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));__m256i y0=ldu256((p+j+8));__m256i y1=ldu256((p+j+h+8));__m256i y2=ldu256((p+j+2*h+8));__m256i y3=ldu256((p+j+3*h+8));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv);__m256i F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}{v1=mpa(v1,ldu256((t1+j+8)),pv);}{v2=mpa(v2,ldu256((t2+j+8)),pv);}{v3=mpa(v3,ldu256((t3+j+8)),pv);}stu256((p+j),u0);stu256((p+j+h),u1);stu256((p+j+2*h),u2);stu256((p+j+3*h),u3);stu256((p+j+8),v0);stu256((p+j+h+8),v1);stu256((p+j+2*h+8),v2);stu256((p+j+3*h+8),v3);}for(;j+8<=h;j+=8){__builtin_prefetch(p+j+192);__builtin_prefetch(p+j+h+192);__builtin_prefetch(p+j+2*h+192);__builtin_prefetch(p+j+3*h+192);__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);{u1=mpa(u1,ldu256((t1+j)),pv);}{u2=mpa(u2,ldu256((t2+j)),pv);}{u3=mpa(u3,ldu256((t3+j)),pv);}stu256((p+j),u0);stu256((p+j+h),u1);stu256((p+j+2*h),u2);stu256((p+j+3*h),u3);}}}template<int H>TGT static void stage4_dif_h(u32*a,u32 blk,u32 _h,const u32*tb,u32 ci,u32 cis){const u32 MP=H+TPAD;const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*H){u32*q0=a+i;const u32*w=tb;u32 j=0;for(;j+16<=H;j+=16,q0+=16,w+=16){__builtin_prefetch(q0+192);__builtin_prefetch(q0+H+192);__builtin_prefetch(q0+2*H+192);__builtin_prefetch(q0+3*H+192);__m256i x0=ldu256(q0),x1=ldu256(q0+H),x2=ldu256(q0+2*H),x3=ldu256(q0+3*H);__m256i y0=ldu256(q0+8),y1=ldu256(q0+H+8),y2=ldu256(q0+2*H+8),y3=ldu256(q0+3*H+8);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);u1=mpb(u1,ldu256(w),ldu256(w+3*MP),pv);u2=mpb(u2,ldu256(w+MP),ldu256(w+4*MP),pv);u3=mpb(u3,ldu256(w+2*MP),ldu256(w+5*MP),pv);v1=mpb(v1,ldu256(w+8),ldu256(w+3*MP+8),pv);v2=mpb(v2,ldu256(w+MP+8),ldu256(w+4*MP+8),pv);v3=mpb(v3,ldu256(w+2*MP+8),ldu256(w+5*MP+8),pv);stu256(q0,u0);stu256(q0+H,u1);stu256(q0+2*H,u2);stu256(q0+3*H,u3);stu256(q0+8,v0);stu256(q0+H+8,v1);stu256(q0+2*H+8,v2);stu256(q0+3*H+8,v3);}for(;j+8<=H;j+=8,q0+=8,w+=8){__builtin_prefetch(q0+192);__builtin_prefetch(q0+H+192);__builtin_prefetch(q0+2*H+192);__builtin_prefetch(q0+3*H+192);__m256i x0=ldu256(q0),x1=ldu256(q0+H),x2=ldu256(q0+2*H),x3=ldu256(q0+3*H);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);u1=mpb(u1,ldu256(w),ldu256(w+3*MP),pv);u2=mpb(u2,ldu256(w+MP),ldu256(w+4*MP),pv);u3=mpb(u3,ldu256(w+2*MP),ldu256(w+5*MP),pv);stu256(q0,u0);stu256(q0+H,u1);stu256(q0+2*H,u2);stu256(q0+3*H,u3);}}}TGT static void stage4_dif_nt(u32*a,u32 blk,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*h){u32*p=a+i;u32 j=0;for(;j+16<=h;j+=16){__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));__m256i y0=ldu256((p+j+8));__m256i y1=ldu256((p+j+h+8));__m256i y2=ldu256((p+j+2*h+8));__m256i y3=ldu256((p+j+3*h+8));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv);__m256i F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);u1=vS(u1,ldu256((t1+j)),der_ws(ldu256((t1+j))),pv);u2=vS(u2,ldu256((t2+j)),der_ws(ldu256((t2+j))),pv);u3=vS(u3,ldu256((t3+j)),der_ws(ldu256((t3+j))),pv);v1=vS(v1,ldu256((t1+j+8)),der_ws(ldu256((t1+j+8))),pv);v2=vS(v2,ldu256((t2+j+8)),der_ws(ldu256((t2+j+8))),pv);v3=vS(v3,ldu256((t3+j+8)),der_ws(ldu256((t3+j+8))),pv);_mm256_stream_si256((__m256i*)(p+j),u0);_mm256_stream_si256((__m256i*)(p+j+h),u1);_mm256_stream_si256((__m256i*)(p+j+2*h),u2);_mm256_stream_si256((__m256i*)(p+j+3*h),u3);_mm256_stream_si256((__m256i*)(p+j+8),v0);_mm256_stream_si256((__m256i*)(p+j+h+8),v1);_mm256_stream_si256((__m256i*)(p+j+2*h+8),v2);_mm256_stream_si256((__m256i*)(p+j+3*h+8),v3);}for(;j+8<=h;j+=8){__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);u1=vS(u1,ldu256((t1+j)),der_ws(ldu256((t1+j))),pv);u2=vS(u2,ldu256((t2+j)),der_ws(ldu256((t2+j))),pv);u3=vS(u3,ldu256((t3+j)),der_ws(ldu256((t3+j))),pv);_mm256_stream_si256((__m256i*)(p+j),u0);_mm256_stream_si256((__m256i*)(p+j+h),u1);_mm256_stream_si256((__m256i*)(p+j+2*h),u2);_mm256_stream_si256((__m256i*)(p+j+3*h),u3);}}}TGT static inline void transpose4(__m256i&a,__m256i&b,__m256i&c,__m256i&d){__m256i t0=_mm256_unpacklo_epi32(a,b),t1=_mm256_unpackhi_epi32(a,b),t2=_mm256_unpacklo_epi32(c,d),t3=_mm256_unpackhi_epi32(c,d);a=_mm256_unpacklo_epi64(t0,t2);b=_mm256_unpackhi_epi64(t0,t2);c=_mm256_unpacklo_epi64(t1,t3);d=_mm256_unpackhi_epi64(t1,t3);}TGT static void dh1(u32*a,u32 blk,u32 ci,u32 cis);static long g_pmdelta=0;
#define E7Z3_PM_ON() (g_pmdelta != 0)
TGT static inline __m256i e7z3_pmul(__m256i u,const u32*p,__m256i pv){if(g_pmdelta==0)return _mm256_min_epu32(u,_mm256_sub_epi32(u,pv));const __m128i*lo=(const __m128i*)((const char*)p+g_pmdelta);const __m128i*hi=(const __m128i*)((const char*)(p+16)+g_pmdelta);__m256i w=ld2(lo,hi);return mpa(w,u,pv);}TGT static inline void e7z3_st(void*p,__m256i v){if(g_pmdelta==0)stu256(p,v);else stu256((void*)((char*)p+g_pmdelta),v);}TGT static inline void e7z3_st2(__m128i*lo,__m128i*hi,__m256i v){if(g_pmdelta==0)st2(lo,hi,v);else st2((__m128i*)((char*)lo+g_pmdelta),(__m128i*)((char*)hi+g_pmdelta),v);}TGT static inline __m256i e7z3_minn(__m256i u,__m256i pv){return _mm256_min_epu32(u,_mm256_sub_epi32(u,pv));}TGT static inline __m256i e7z3_pmn(__m256i u,const u32*p,__m256i pv){return mpa(ld2((const __m128i*)(p),(const __m128i*)(p+16)),u,pv);}TGT __attribute__((always_inline))static inline void dh4(u32*a,u32 nsub,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);if(nsub<32){const __m128i pv4=_mm256_castsi256_si128(pv),cI4=_mm256_castsi256_si128(cI),cIs4=_mm256_castsi256_si128(cIs);__m128i W1=_mm_loadu_si128((const __m128i*)t1);__m128i WS1=_mm_loadu_si128((const __m128i*)s1);__m128i W2=_mm_loadu_si128((const __m128i*)t2);__m128i WS2=_mm_loadu_si128((const __m128i*)s2);__m128i W3=_mm_loadu_si128((const __m128i*)t3);__m128i WS3=_mm_loadu_si128((const __m128i*)s3);for(u32 i=0;i<nsub;i+=16){u32*p=a+i;__m128i x0=_mm_loadu_si128((const __m128i*)(p));__m128i x1=_mm_loadu_si128((const __m128i*)(p+4));__m128i x2=_mm_loadu_si128((const __m128i*)(p+8));__m128i x3=_mm_loadu_si128((const __m128i*)(p+12));__m128i A=add4(x0,x2,pv4),B=sub4(x0,x2,pv4);__m128i C=add4(x1,x3,pv4),D=sub_lazy4(x1,x3,pv4);__m128i u0=add4(A,C,pv4),u2=sub_lazy4(A,C,pv4);__m128i E=sh4(D,cI4,cIs4,pv4);__m128i u1=_mm_add_epi32(B,E),u3=sub_lazy4(B,E,pv4);u1=mpc(u1,W1,WS1,pv4);u2=mpc(u2,W2,WS2,pv4);u3=mpc(u3,W3,WS3,pv4);_mm_storeu_si128((__m128i*)(p),u0);_mm_storeu_si128((__m128i*)(p+4),u1);_mm_storeu_si128((__m128i*)(p+8),u2);_mm_storeu_si128((__m128i*)(p+12),u3);}dh1(a,nsub,ci,cis);return;}__m256i W1=bc128(_mm_loadu_si128((const __m128i*)t1));__m256i WS1=bc128(_mm_loadu_si128((const __m128i*)s1));__m256i W2=bc128(_mm_loadu_si128((const __m128i*)t2));__m256i WS2=bc128(_mm_loadu_si128((const __m128i*)s2));__m256i W3=bc128(_mm_loadu_si128((const __m128i*)t3));__m256i WS3=bc128(_mm_loadu_si128((const __m128i*)s3));if(g_pmdelta==0){
#pragma GCC unroll 2
for(u32 i=0,*p=a;i<nsub;i+=32,p+=32){__m256i x0=ld2((const __m128i*)(p),(const __m128i*)(p+16));__m256i x1=ld2((const __m128i*)(p+4),(const __m128i*)(p+20));__m256i x2=ld2((const __m128i*)(p+8),(const __m128i*)(p+24));__m256i x3=ld2((const __m128i*)(p+12),(const __m128i*)(p+28));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);u1=mpb(u1,W1,WS1,pv);u2=mpb(u2,W2,WS2,pv);u3=mpb(u3,W3,WS3,pv);transpose4(u0,u1,u2,u3);{__m256i A4=vaddm(u0,u2,pv),B4=vsubm(u0,u2,pv),C4=vaddm(u1,u3,pv),D4=vL(u1,u3,pv),E4=vS(D4,cI,cIs,pv);u0=vaddm(A4,C4,pv);u2=vL(A4,C4,pv);u1=_mm256_add_epi32(B4,E4);u3=vL(B4,E4,pv);transpose4(u0,u1,u2,u3);}u0=e7z3_minn(u0,pv);u1=e7z3_minn(u1,pv);u2=e7z3_minn(u2,pv);u3=e7z3_minn(u3,pv);st2((__m128i*)(p),(__m128i*)(p+16),u0);st2((__m128i*)(p+4),(__m128i*)(p+20),u1);st2((__m128i*)(p+8),(__m128i*)(p+24),u2);st2((__m128i*)(p+12),(__m128i*)(p+28),u3);}}else{
#pragma GCC unroll 2
for(u32 i=0,*p=a,*pd=(u32*)((char*)a+g_pmdelta);i<nsub;i+=32,p+=32,pd+=32){__m256i x0=ld2((const __m128i*)(p),(const __m128i*)(p+16));__m256i x1=ld2((const __m128i*)(p+4),(const __m128i*)(p+20));__m256i x2=ld2((const __m128i*)(p+8),(const __m128i*)(p+24));__m256i x3=ld2((const __m128i*)(p+12),(const __m128i*)(p+28));__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i E=vS(D,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);u1=mpb(u1,W1,WS1,pv);u2=mpb(u2,W2,WS2,pv);u3=mpb(u3,W3,WS3,pv);transpose4(u0,u1,u2,u3);{__m256i A4=vaddm(u0,u2,pv),B4=vsubm(u0,u2,pv),C4=vaddm(u1,u3,pv),D4=vL(u1,u3,pv),E4=vS(D4,cI,cIs,pv);u0=vaddm(A4,C4,pv);u2=vL(A4,C4,pv);u1=_mm256_add_epi32(B4,E4);u3=vL(B4,E4,pv);transpose4(u0,u1,u2,u3);}u0=e7z3_pmn(u0,pd,pv);u1=e7z3_pmn(u1,pd+4,pv);u2=e7z3_pmn(u2,pd+8,pv);u3=e7z3_pmn(u3,pd+12,pv);st2((__m128i*)(pd),(__m128i*)(pd+16),u0);st2((__m128i*)(pd+4),(__m128i*)(pd+20),u1);st2((__m128i*)(pd+8),(__m128i*)(pd+24),u2);st2((__m128i*)(pd+12),(__m128i*)(pd+28),u3);}}}TGT static void dh1(u32*a,u32 blk,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=8){u32*p=a+i;__m256i x=ldu256(p);__m256i t=_mm256_shuffle_epi32(x,_MM_SHUFFLE(1,0,3,2));__m256i s=vaddm(x,t,pv);__m256i d=vsubm(x,t,pv);__m256i Z=_mm256_shuffle_epi32(d,0x00);__m256i P=_mm256_blend_epi32(s,Z,0xAA);__m256i E=vS(d,cI,cIs,pv);__m256i E2=_mm256_shuffle_epi32(E,0x55);__m256i W=_mm256_shuffle_epi32(s,0x55);__m256i Q=_mm256_blend_epi32(W,E2,0xAA);__m256i sum=vaddm(P,Q,pv);__m256i dif=vsubm(P,Q,pv);stu256(p,_mm256_blend_epi32(sum,dif,0xCC));}}TGT static void stage2_dif(u32*a,u32 blk,const u32*t,const u32*s){const __m256i pv=_mm256_set1_epi32((int)NTP);u32 h=blk>>1;for(u32 j=0;j<h;j+=8){__m256i x0=ldu256((a+j));__m256i x1=ldu256((a+j+h));__m256i u0=vaddm(x0,x1,pv);__m256i u1=mpa(vsubm(x0,x1,pv),ldu256((t+j)),pv);stu256((a+j),u0);stu256((a+j+h),u1);}}TGT static void merge4_dit_s2(u32*a,u32 blk,u32 h,u32 s,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const u32 MP=h+TPAD;for(u32 i=0;i<blk;i+=4*s){u32*p=a+i;u32 poff=0;for(u32 cb=0;cb<h;cb+=16384u){u32*q0=p+poff,*q1=q0+s,*q2=q1+s,*q3=q2+s;const u32*w=t1+cb;for(u32 jr=0;jr<16384u;jr+=8,q0+=8,q1+=8,q2+=8,q3+=8,w+=8){__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__builtin_prefetch(w+192);__builtin_prefetch(w+MP+192);__builtin_prefetch(w+2*MP+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);x1=mpa(x1,ldu256(w),pv);x2=mpa(x2,ldu256(w+MP),pv);x3=mpa(x3,ldu256(w+2*MP),pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);stu256(q0,vaddm(A,C,pv));stu256(q1,vaddm(B,E,pv));stu256(q2,vsubm(A,C,pv));stu256(q3,vsubm(B,E,pv));}poff+=16384u+TOPPAD;}}}TGT static void merge4_dit_s3(u32*a,u32 blk,u32 h,u32 s,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const u32 MP=h+TPAD;for(u32 i=0;i<blk;i+=4*s){u32*q0=a+i,*q1=q0+s,*q2=q1+s,*q3=q2+s;const u32*w=t1;for(u32 j=0;j<h;j+=8,q0+=8,q1+=8,q2+=8,q3+=8,w+=8){__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__builtin_prefetch(w+192);__builtin_prefetch(w+MP+192);__builtin_prefetch(w+2*MP+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);x1=mpa(x1,ldu256(w),pv);x2=mpa(x2,ldu256(w+MP),pv);x3=mpa(x3,ldu256(w+2*MP),pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);stu256(q0,vaddm(A,C,pv));stu256(q1,vaddm(B,E,pv));stu256(q2,vsubm(A,C,pv));stu256(q3,vsubm(B,E,pv));}}}TGT static void merge4_dit(u32*a,u32 blk,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*h){u32*p=a+i;for(u32 j=0;j<h;j+=8){__builtin_prefetch(p+j+192);__builtin_prefetch(p+j+h+192);__builtin_prefetch(p+j+2*h+192);__builtin_prefetch(p+j+3*h+192);__builtin_prefetch(t1+j+192);__builtin_prefetch(t2+j+192);__builtin_prefetch(t3+j+192);__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));{x1=mpa(x1,ldu256((t1+j)),pv);}{x2=mpa(x2,ldu256((t2+j)),pv);}{x3=mpa(x3,ldu256((t3+j)),pv);}__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);stu256((p+j),vaddm(A,C,pv));stu256((p+j+h),vaddm(B,E,pv));stu256((p+j+2*h),vsubm(A,C,pv));stu256((p+j+3*h),vsubm(B,E,pv));}}}TGT static void merge4_dit_t(u32*a,u32 blk,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*h){u32*p=a+i;for(u32 j=0;j<h;j+=8){__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));{x1=mpa(x1,ldu256((t1+j)),pv);}{x2=mpa(x2,ldu256((t2+j)),pv);}{x3=mpa(x3,ldu256((t3+j)),pv);}__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);stu256((p+j),vaddm(A,C,pv));stu256((p+j+h),vaddm(B,E,pv));stu256((p+j+2*h),vsubm(A,C,pv));stu256((p+j+3*h),vsubm(B,E,pv));}}}template<int H,bool LazyOutput=false>TGT static void merge4_dit_h(u32*a,u32 blk,u32 _h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const u32 MP=H+TPAD;const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);(void)t2;(void)t3;(void)s1;(void)s2;(void)s3;for(u32 i=0;i<blk;i+=4*H){u32*q0=a+i;const u32*w=t1;u32 j=0;for(;j<H;j+=16,q0+=16,w+=16){__builtin_prefetch(q0+192);__builtin_prefetch(q0+H+192);__builtin_prefetch(q0+2*H+192);__builtin_prefetch(q0+3*H+192);__m256i x0=ldu256(q0),y0=ldu256(q0+8);__m256i x1=ldu256(q0+H),y1=ldu256(q0+H+8);__m256i x2=ldu256(q0+2*H),y2=ldu256(q0+2*H+8);__m256i x3=ldu256(q0+3*H),y3=ldu256(q0+3*H+8);x1=mpb(x1,ldu256(w),ldu256(w+3*MP),pv);y1=mpb(y1,ldu256(w+8),ldu256(w+3*MP+8),pv);x2=mpb(x2,ldu256(w+MP),ldu256(w+4*MP),pv);y2=mpb(y2,ldu256(w+MP+8),ldu256(w+4*MP+8),pv);x3=mpb(x3,ldu256(w+2*MP),ldu256(w+5*MP),pv);y3=mpb(y3,ldu256(w+2*MP+8),ldu256(w+5*MP+8),pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);stu256(q0,(LazyOutput?_mm256_add_epi32(A,C):vaddm(A,C,pv)));stu256(q0+8,(LazyOutput?_mm256_add_epi32(A2,C2):vaddm(A2,C2,pv)));stu256(q0+H,(LazyOutput?_mm256_add_epi32(B,E):vaddm(B,E,pv)));stu256(q0+H+8,(LazyOutput?_mm256_add_epi32(B2,F):vaddm(B2,F,pv)));stu256(q0+2*H,(LazyOutput?vL(A,C,pv):vsubm(A,C,pv)));stu256(q0+2*H+8,(LazyOutput?vL(A2,C2,pv):vsubm(A2,C2,pv)));stu256(q0+3*H,(LazyOutput?vL(B,E,pv):vsubm(B,E,pv)));stu256(q0+3*H+8,(LazyOutput?vL(B2,F,pv):vsubm(B2,F,pv)));}for(;j<H;j+=8,q0+=8,w+=8){__m256i x0=ldu256(q0),x1=ldu256(q0+H),x2=ldu256(q0+2*H),x3=ldu256(q0+3*H);x1=mpb(x1,ldu256(w),ldu256(w+3*MP),pv);x2=mpb(x2,ldu256(w+MP),ldu256(w+4*MP),pv);x3=mpb(x3,ldu256(w+2*MP),ldu256(w+5*MP),pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);stu256(q0,(LazyOutput?_mm256_add_epi32(A,C):vaddm(A,C,pv)));stu256(q0+H,(LazyOutput?_mm256_add_epi32(B,E):vaddm(B,E,pv)));stu256(q0+2*H,(LazyOutput?vL(A,C,pv):vsubm(A,C,pv)));stu256(q0+3*H,(LazyOutput?vL(B,E,pv):vsubm(B,E,pv)));}}}TGT static void merge4_dit_nt(u32*a,u32 blk,u32 h,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=4*h){u32*p=a+i;for(u32 j=0;j<h;j+=8){__m256i x0=ldu256((p+j));__m256i x1=ldu256((p+j+h));__m256i x2=ldu256((p+j+2*h));__m256i x3=ldu256((p+j+3*h));x1=vS(x1,ldu256((t1+j)),der_ws(ldu256((t1+j))),pv);x2=vS(x2,ldu256((t2+j)),der_ws(ldu256((t2+j))),pv);x3=vS(x3,ldu256((t3+j)),der_ws(ldu256((t3+j))),pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);_mm256_stream_si256((__m256i*)(p+j),vaddm(A,C,pv));_mm256_stream_si256((__m256i*)(p+j+h),vaddm(B,E,pv));_mm256_stream_si256((__m256i*)(p+j+2*h),vsubm(A,C,pv));_mm256_stream_si256((__m256i*)(p+j+3*h),vsubm(B,E,pv));}}}TGT static void merge4_dit_h4(u32*a,u32 nsub,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);if(nsub<32){const __m128i pv4=_mm256_castsi256_si128(pv),cI4=_mm256_castsi256_si128(cI),cIs4=_mm256_castsi256_si128(cIs);__m128i W1=_mm_loadu_si128((const __m128i*)t1);__m128i WS1=_mm_loadu_si128((const __m128i*)s1);__m128i W2=_mm_loadu_si128((const __m128i*)t2);__m128i WS2=_mm_loadu_si128((const __m128i*)s2);__m128i W3=_mm_loadu_si128((const __m128i*)t3);__m128i WS3=_mm_loadu_si128((const __m128i*)s3);for(u32 i=0;i<nsub;i+=16){u32*p=a+i;__m128i x0=_mm_loadu_si128((const __m128i*)(p));__m128i x1=mpc(_mm_loadu_si128((const __m128i*)(p+4)),W1,WS1,pv4);__m128i x2=mpc(_mm_loadu_si128((const __m128i*)(p+8)),W2,WS2,pv4);__m128i x3=mpc(_mm_loadu_si128((const __m128i*)(p+12)),W3,WS3,pv4);__m128i A=add4(x0,x2,pv4),B=sub4(x0,x2,pv4);__m128i C=add4(x1,x3,pv4),D=sub4(x1,x3,pv4);__m128i E=sh4(D,cI4,cIs4,pv4);_mm_storeu_si128((__m128i*)(p),add4(A,C,pv4));_mm_storeu_si128((__m128i*)(p+4),add4(B,E,pv4));_mm_storeu_si128((__m128i*)(p+8),sub4(A,C,pv4));_mm_storeu_si128((__m128i*)(p+12),sub4(B,E,pv4));}return;}__m256i W1=bc128(_mm_loadu_si128((const __m128i*)t1));__m256i WS1=bc128(_mm_loadu_si128((const __m128i*)s1));__m256i W2=bc128(_mm_loadu_si128((const __m128i*)t2));__m256i WS2=bc128(_mm_loadu_si128((const __m128i*)s2));__m256i W3=bc128(_mm_loadu_si128((const __m128i*)t3));__m256i WS3=bc128(_mm_loadu_si128((const __m128i*)s3));for(u32 i=0;i<nsub;i+=32){u32*p=a+i;__m256i x0=ld2((const __m128i*)(p),(const __m128i*)(p+16));__m256i x1=ld2((const __m128i*)(p+4),(const __m128i*)(p+20));__m256i x2=ld2((const __m128i*)(p+8),(const __m128i*)(p+24));__m256i x3=ld2((const __m128i*)(p+12),(const __m128i*)(p+28));x1=mpb(x1,W1,WS1,pv);x2=mpb(x2,W2,WS2,pv);x3=mpb(x3,W3,WS3,pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);st2((__m128i*)(p),(__m128i*)(p+16),vaddm(A,C,pv));st2((__m128i*)(p+4),(__m128i*)(p+20),vaddm(B,E,pv));st2((__m128i*)(p+8),(__m128i*)(p+24),vsubm(A,C,pv));st2((__m128i*)(p+12),(__m128i*)(p+28),vsubm(B,E,pv));}}TGT static inline __m256i merge4_h1v(__m256i x,__m256i pv,__m256i cI,__m256i cIs){__m256i t=_mm256_shuffle_epi32(x,_MM_SHUFFLE(1,0,3,2)),sv=vaddm(x,t,pv),d=vsubm(x,t,pv),Z=_mm256_shuffle_epi32(d,0x00),P=_mm256_blend_epi32(sv,Z,0xAA),E=vS(d,cI,cIs,pv),E2=_mm256_shuffle_epi32(E,0x55),W=_mm256_shuffle_epi32(sv,0x55),Q=_mm256_blend_epi32(W,E2,0xAA),sum=vaddm(P,Q,pv),dif=vsubm(P,Q,pv);return _mm256_blend_epi32(sum,dif,0xCC);}TGT static inline __m256i merge4_h1v_lazy(__m256i x,__m256i pv,__m256i cI,__m256i cIs){__m256i t=_mm256_shuffle_epi32(x,_MM_SHUFFLE(1,0,3,2)),sv=vaddm(x,t,pv),d=vsubm(x,t,pv),Z=_mm256_shuffle_epi32(d,0x00),P=_mm256_blend_epi32(sv,Z,0xAA),E=vS(d,cI,cIs,pv),E2=_mm256_shuffle_epi32(E,0x55),W=_mm256_shuffle_epi32(sv,0x55),Q=_mm256_blend_epi32(W,E2,0xAA),sum=_mm256_add_epi32(P,Q),dif=vL(P,Q,pv);return _mm256_blend_epi32(sum,dif,0xCC);}TGT static void mhh(u32*a,u32 nsub,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP),cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);__m256i W1=bc128(_mm_loadu_si128((const __m128i*)t1)),WS1=bc128(_mm_loadu_si128((const __m128i*)s1)),W2=bc128(_mm_loadu_si128((const __m128i*)t2)),WS2=bc128(_mm_loadu_si128((const __m128i*)s2)),W3=bc128(_mm_loadu_si128((const __m128i*)t3)),WS3=bc128(_mm_loadu_si128((const __m128i*)s3));for(u32 i=0;i+32<=nsub;i+=32){u32*p=a+i;__m256i g0=merge4_h1v(ldu256((const void*)(p)),pv,cI,cIs),g1=merge4_h1v(ldu256((const void*)(p+8)),pv,cI,cIs),g2=merge4_h1v(ldu256((const void*)(p+16)),pv,cI,cIs),g3=merge4_h1v(ldu256((const void*)(p+24)),pv,cI,cIs);__m256i x0=_mm256_permute2x128_si256(g0,g2,0x20),x1=_mm256_permute2x128_si256(g0,g2,0x31),x2=_mm256_permute2x128_si256(g1,g3,0x20),x3=_mm256_permute2x128_si256(g1,g3,0x31);x1=mpb(x1,W1,WS1,pv);x2=mpb(x2,W2,WS2,pv);x3=mpb(x3,W3,WS3,pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv),C=vaddm(x1,x3,pv),D=vL(x1,x3,pv),E=vS(D,cI,cIs,pv);st2((__m128i*)(p),(__m128i*)(p+16),vaddm(A,C,pv));st2((__m128i*)(p+4),(__m128i*)(p+20),vaddm(B,E,pv));st2((__m128i*)(p+8),(__m128i*)(p+24),vsubm(A,C,pv));st2((__m128i*)(p+12),(__m128i*)(p+28),vsubm(B,E,pv));}for(u32 i=(nsub&~31u);i<nsub;i+=8){u32*p=a+i;stu256((void*)p,merge4_h1v(ldu256((const void*)p),pv,cI,cIs));}}
#define H4B32(Q,R1,R2,R3,R4,LAZY) {const u32*q=(Q);__m256i g0=merge4_h1v(ldu256((const void*)(q)),pv,cI,cIs),g1=merge4_h1v_lazy(ldu256((const void*)(q+8)),pv,cI,cIs),g2=merge4_h1v(ldu256((const void*)(q+16)),pv,cI,cIs),g3=merge4_h1v_lazy(ldu256((const void*)(q+24)),pv,cI,cIs);__m256i e0=_mm256_permute2x128_si256(g0,g2,0x20),e1=_mm256_permute2x128_si256(g0,g2,0x31),e2=_mm256_permute2x128_si256(g1,g3,0x20),e3=_mm256_permute2x128_si256(g1,g3,0x31);e1=mpb(e1,W1,WS1,pv);e2=mpb(e2,W2,WS2,pv);e3=mpb(e3,W3,WS3,pv);__m256i a1=vaddm(e0,e2,pv),b1=vsubm(e0,e2,pv),c1=vaddm(e1,e3,pv),d1=vL(e1,e3,pv),f1=vS(d1,cI,cIs,pv);if constexpr(LAZY){R1=_mm256_add_epi32(a1,c1);R2=_mm256_add_epi32(b1,f1);R3=vL(a1,c1,pv);R4=vL(b1,f1,pv);}else{R1=vaddm(a1,c1,pv);R2=vaddm(b1,f1,pv);R3=vsubm(a1,c1,pv);R4=vsubm(b1,f1,pv);}}
TGT __attribute__((always_inline))static inline void mhh64(u32*a,u32 nsub,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis,const u32*u1,const u32*u2,const u32*u3,const u32*v1,const u32*v2,const u32*v3){const __m256i pv=_mm256_set1_epi32((int)NTP),cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const __m256i W1=bc128(_mm_loadu_si128((const __m128i*)t1)),WS1=bc128(_mm_loadu_si128((const __m128i*)s1)),W2=bc128(_mm_loadu_si128((const __m128i*)t2)),WS2=bc128(_mm_loadu_si128((const __m128i*)s2)),W3=bc128(_mm_loadu_si128((const __m128i*)t3)),WS3=bc128(_mm_loadu_si128((const __m128i*)s3));for(u32 i=0,*p=a;i+64<=nsub;i+=64,p+=64){__m256i R1,R2,R3,R4,R1b,R2b,R3b,R4b;H4B32(p,R1,R2,R3,R4,false)H4B32(p+32,R1b,R2b,R3b,R4b,true)__m256i x0=_mm256_permute2x128_si256(R1,R2,0x20),y0=_mm256_permute2x128_si256(R3,R4,0x20),x1=_mm256_permute2x128_si256(R1,R2,0x31),y1=_mm256_permute2x128_si256(R3,R4,0x31),x2=_mm256_permute2x128_si256(R1b,R2b,0x20),y2=_mm256_permute2x128_si256(R3b,R4b,0x20),x3=_mm256_permute2x128_si256(R1b,R2b,0x31),y3=_mm256_permute2x128_si256(R3b,R4b,0x31);x1=mpb(x1,ldu256((const void*)(u1)),ldu256((const void*)(v1)),pv);y1=mpb(y1,ldu256((const void*)(u1+8)),ldu256((const void*)(v1+8)),pv);x2=mpb(x2,ldu256((const void*)(u2)),ldu256((const void*)(v2)),pv);y2=mpb(y2,ldu256((const void*)(u2+8)),ldu256((const void*)(v2+8)),pv);x3=mpb(x3,ldu256((const void*)(u3)),ldu256((const void*)(v3)),pv);y3=mpb(y3,ldu256((const void*)(u3+8)),ldu256((const void*)(v3+8)),pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv),A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv),C=vaddm(x1,x3,pv),D=vL(x1,x3,pv),C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv),E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);if(nsub>=256u && (nsub&255u)==0u && (i&192u)!=0u){stu256((void*)(p),_mm256_add_epi32(A,C));stu256((void*)(p+8),_mm256_add_epi32(A2,C2));stu256((void*)(p+16),_mm256_add_epi32(B,E));stu256((void*)(p+24),_mm256_add_epi32(B2,F));stu256((void*)(p+32),vL(A,C,pv));stu256((void*)(p+40),vL(A2,C2,pv));stu256((void*)(p+48),vL(B,E,pv));stu256((void*)(p+56),vL(B2,F,pv));}else{stu256((void*)(p),vaddm(A,C,pv));stu256((void*)(p+8),vaddm(A2,C2,pv));stu256((void*)(p+16),vaddm(B,E,pv));stu256((void*)(p+24),vaddm(B2,F,pv));stu256((void*)(p+32),vsubm(A,C,pv));stu256((void*)(p+40),vsubm(A2,C2,pv));stu256((void*)(p+48),vsubm(B,E,pv));stu256((void*)(p+56),vsubm(B2,F,pv));}}for(u32 i=(nsub&~63u);i<nsub;i+=8){u32*p=a+i;stu256((void*)p,merge4_h1v(ldu256((const void*)p),pv,cI,cIs));}}TGT static void mh1(u32*a,u32 blk,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<blk;i+=8){u32*p=a+i;__m256i x=ldu256(p);__m256i t=_mm256_shuffle_epi32(x,_MM_SHUFFLE(1,0,3,2));__m256i s=vaddm(x,t,pv);__m256i d=vsubm(x,t,pv);__m256i Z=_mm256_shuffle_epi32(d,0x00);__m256i P=_mm256_blend_epi32(s,Z,0xAA);__m256i E=vS(d,cI,cIs,pv);__m256i E2=_mm256_shuffle_epi32(E,0x55);__m256i W=_mm256_shuffle_epi32(s,0x55);__m256i Q=_mm256_blend_epi32(W,E2,0xAA);__m256i sum=vaddm(P,Q,pv);__m256i dif=vsubm(P,Q,pv);stu256(p,_mm256_blend_epi32(sum,dif,0xCC));}}TGT static void merge2_dit(u32*a,u32 blk,const u32*t,const u32*s){const __m256i pv=_mm256_set1_epi32((int)NTP);u32 h=blk>>1;for(u32 j=0;j<h;j+=8){__m256i x0=ldu256((a+j));__m256i x1=vS(ldu256((a+j+h)),ldu256((t+j)),ldu256((s+j)),pv);stu256((a+j),vaddm(x0,x1,pv));stu256((a+j+h),vsubm(x0,x1,pv));}}TGT static inline void ntst256(void*p,__m256i v){if(((uintptr_t)p&31u)==0)_mm256_stream_si256((__m256i*)p,v);else stu256(p,v);}TGT static void gen_geo_val(u32*dst,u32 cnt,u32 v0,u32 r);TGT static void gen_geo(u32*dst,u32*sc,u32 cnt,u32 v0,u32 r){if(!sc){gen_geo_val(dst,cnt,v0,r);return;}if(!cnt)return;if(cnt<32){u32 x=v0%NTP;for(u32 i=0;i<cnt;i++){dst[i]=x;sc[i]=shoup_c(x);x=mulmod(x,r);}return;}const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i mlo=_mm256_set1_epi32(572662301u);u32 seq[32],cur=v0%NTP;for(int i=0;i<32;i++){seq[i]=cur;cur=mulmod(cur,r);}u32 rs=shoup_c(cur);const __m256i rv=_mm256_set1_epi32((int)cur);const __m256i rsv=_mm256_set1_epi32((int)rs);__m256i a=ldu256(seq),b=ldu256(seq+8),c=ldu256(seq+16),d=ldu256(seq+24);u32 i=0;for(;i+32<=cnt;i+=32){ntst256(dst+i,a);ntst256(dst+i+8,b);ntst256(dst+i+16,c);ntst256(dst+i+24,d);ntst256(sc+i,_mm256_add_epi32(_mm256_add_epi32(a,a),vmulhi(a,mlo)));ntst256(sc+i+8,_mm256_add_epi32(_mm256_add_epi32(b,b),vmulhi(b,mlo)));ntst256(sc+i+16,_mm256_add_epi32(_mm256_add_epi32(c,c),vmulhi(c,mlo)));ntst256(sc+i+24,_mm256_add_epi32(_mm256_add_epi32(d,d),vmulhi(d,mlo)));a=vS(a,rv,rsv,pv);b=vS(b,rv,rsv,pv);c=vS(c,rv,rsv,pv);d=vS(d,rv,rsv,pv);}if(i<cnt){u32 x=mulmod(v0,powmod(r,i));for(;i<cnt;i++){dst[i]=x;sc[i]=shoup_c(x);x=mulmod(x,r);}}}TGT static void gen_geo_val(u32*dst,u32 cnt,u32 v0,u32 r){if(!cnt)return;if(cnt<32){u32 x=v0%NTP;for(u32 i=0;i<cnt;i++){dst[i]=x;x=mulmod(x,r);}return;}const __m256i pv=_mm256_set1_epi32((int)NTP);u32 seq[32],cur=v0%NTP;for(int i=0;i<32;i++){seq[i]=cur;cur=mulmod(cur,r);}if(v0!=1u)cur=powmod(r,32);u32 rs=shoup_c(cur);const __m256i rv=_mm256_set1_epi32((int)cur);const __m256i rsv=_mm256_set1_epi32((int)rs);__m256i a=ldu256(seq),b=ldu256(seq+8),c=ldu256(seq+16),d=ldu256(seq+24);u32 i=0;for(;i+32<=cnt;i+=32){ntst256(dst+i,a);ntst256(dst+i+8,b);ntst256(dst+i+16,c);ntst256(dst+i+24,d);a=vS(a,rv,rsv,pv);b=vS(b,rv,rsv,pv);c=vS(c,rv,rsv,pv);d=vS(d,rv,rsv,pv);}if(i<cnt){u32 x=mulmod(v0,powmod(r,i));for(;i<cnt;i++){dst[i]=x;x=mulmod(x,r);}}}static void build_tabs(Tabs&T,u32*tab,u32 n,u32 Sb,int L,int odd,u32 root,u32*scbase,u32 skipsc){u32*p=tab;u32*sp=scbase;u32 S=n;for(int l=0;l<L;l++){u32 M=S>>2;const u32 MPr=M+TPAD;T .l1[l]=p;T .l2[l]=p+MPr;T .l3[l]=p+2*MPr;T .m1[l]=sp;T .m2[l]=sp+MPr;T .m3[l]=sp+2*MPr;u32 base=powmod(root,n/S);u32 b1=base,b2=mulmod(base,base),b3=mulmod(b2,base);{const bool nosc=((skipsc>>l)&1u)!=0;const u32 unit=(u32)((1ull<<32)%NTP);gen_geo(p,nosc?0:sp,M,unit,b1);gen_geo(p+MPr,nosc?0:sp+MPr,M,unit,b2);gen_geo(p+2*MPr,nosc?0:sp+2*MPr,M,unit,b3);}p+=3*MPr;sp+=3*MPr;S>>=2;}T .b2=0;T .b2s=0;if(odd){u32 M=Sb>>1;T .b2=p;T .b2s=p+M;gen_geo(p,0,M,(u32)((1ull<<32)%NTP),powmod(root,n/Sb));p+=2*M;}int s=0;u32 S2v=4;while(s<g_nb){u32 M=S2v>>2;if(M>=32)p=(u32*)(((uintptr_t)p+31u)&~(uintptr_t)31u);const u32 MP=M+TPAD;T .h1[s]=p;T .h2[s]=p+MP;T .h3[s]=p+2*MP;T .q1[s]=p+3*MP;T .q2[s]=p+4*MP;T .q3[s]=p+5*MP;u32 base=powmod(root,n/S2v);u32 b1=base,b2=mulmod(base,base),b3=mulmod(b2,base);gen_geo(p,0,M,(u32)((1ull<<32)%NTP),b1);gen_geo(p+MP,0,M,(u32)((1ull<<32)%NTP),b2);gen_geo(p+2*MP,0,M,(u32)((1ull<<32)%NTP),b3);for(u32 i2=0;i2<M;i2++){p[3*MP+i2]=(u32)((u64)p[i2]*(u64)g_pinv);p[4*MP+i2]=(u32)((u64)p[MP+i2]*(u64)g_pinv);p[5*MP+i2]=(u32)((u64)p[2*MP+i2]*(u64)g_pinv);}p+=6*MP;S2v<<=2;s++;}}static void ntt_init(u32 n){{u32 iv=1;for(int q=0;q<5;q++)iv*=2u-NTP*iv;g_pinv=0u-iv;}g_n=n;int lg=0;while((1u<<lg)<n)lg++;g_log2n=lg;const int BT=g_BT;int L=0;while(lg-2*(L+1)>=BT)L++;g_L=L;g_Sb=n>>(2*L);g_odd=((lg-2*L)&1)?1:0;u32 S2=g_Sb;if(g_odd)S2>>=1;g_nb=0;while(S2>=4){S2>>=2;g_nb++;}u32 w=powmod(31u,(NTP-1)/n);u32 wi=powmod(w,NTP-2);u32 iF=powmod(w,n>>2),iI=powmod(wi,n>>2);g_ciF=iF;g_cisF=shoup_c(iF);g_ciI=iI;g_cisI=shoup_c(iI);build_tabs(g_TF,g_tabF,n,g_Sb,L,g_odd,w,Q_SCF,~0u);build_tabs(g_TI,g_tabI,n,g_Sb,L,g_odd,wi,Q_SCI,~0u);}int g_fuse16=1;
#define E7_TILE 512u
static u32 g_scrA[16*E7_TILE]__attribute__((aligned(64)));TGT static void stage16_dif_top_batch(u32**blocks,int nb,u32 S,const u32*tA1,const u32*tA2,const u32*tA3,const u32*tB1,const u32*tB2,const u32*tB3,const u32*sB1,const u32*sB2,const u32*sB3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);const u32 h=S>>2,h4=S>>4;for(u32 cb=0;cb<h4;cb+=4096u){for(int qi=0;qi<nb;qi++){u32*a=blocks[qi];const u32 b=0;const u32 bb=padpos(b);u32*P[16];for(int p=0;p<4;p++)for(int q=0;q<4;q++)P[p*4+q]=a+(padpos(b+cb+(u32)p*h4+(u32)q*h)-bb);for(u32 jj0=0;jj0<4096u;jj0+=E7_TILE){for(int p=0;p<4;p++){u32*r0=P[p*4+0]+jj0,*r1=P[p*4+1]+jj0,*r2=P[p*4+2]+jj0,*r3=P[p*4+3]+jj0;const u32*a1=tA1+(u32)p*h4+cb+jj0,*a2=tA2+(u32)p*h4+cb+jj0,*a3=tA3+(u32)p*h4+cb+jj0;u32*z0=g_scrA+(p*4+0)*E7_TILE,*z1=g_scrA+(p*4+1)*E7_TILE,*z2=g_scrA+(p*4+2)*E7_TILE,*z3=g_scrA+(p*4+3)*E7_TILE;for(u32 t=0;t<E7_TILE;t+=8){__builtin_prefetch(r0+t+192);__builtin_prefetch(r1+t+192);__builtin_prefetch(r2+t+192);__builtin_prefetch(r3+t+192);__m256i x0=ldu256(r0+t),x1=ldu256(r1+t),x2=ldu256(r2+t),x3=ldu256(r3+t);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i E=vS(D,cI,cIs,pv);__m256i w1=ldu256(a1+t),w2=ldu256(a2+t),w3=ldu256(a3+t);stu256(z1+t,mpa(_mm256_add_epi32(B,E),w1,pv));stu256(z2+t,mpa(vL(A,C,pv),w2,pv));stu256(z3+t,mpa(vL(B,E,pv),w3,pv));stu256(z0+t,vaddm(A,C,pv));}}for(int i=0;i<4;i++){const u32*b1=tB1+cb+jj0,*b2=tB2+cb+jj0,*b3=tB3+cb+jj0;const u32*s0=g_scrA+(0*4+i)*E7_TILE,*s1=g_scrA+(1*4+i)*E7_TILE,*s2=g_scrA+(2*4+i)*E7_TILE,*s3=g_scrA+(3*4+i)*E7_TILE;u32*o0=P[0*4+i]+jj0,*o1=P[1*4+i]+jj0,*o2=P[2*4+i]+jj0,*o3=P[3*4+i]+jj0;for(u32 t=0;t<E7_TILE;t+=8){__m256i wB1=ldu256(b1+t),wB2=ldu256(b2+t),wB3=ldu256(b3+t);__m256i y0=ldu256(s0+t),y1=ldu256(s1+t),y2=ldu256(s2+t),y3=ldu256(s3+t);__m256i A=vaddm(y0,y2,pv),B=vsubm(y0,y2,pv);__m256i C=vaddm(y1,y3,pv),D=vL(y1,y3,pv);__m256i E=vS(D,cI,cIs,pv);stu256(o0+t,vaddm(A,C,pv));stu256(o1+t,mpa(_mm256_add_epi32(B,E),wB1,pv));stu256(o2+t,mpa(vL(A,C,pv),wB2,pv));stu256(o3+t,mpa(vL(B,E,pv),wB3,pv));}}}}}}
#ifndef E7Z_SBFUSE
#define E7Z_SBFUSE 1
#endif
#ifndef E7Z_IVFUSE
#define E7Z_IVFUSE 1
#endif
TGT static void stage4_dif_h16_loop(u32*a,u32 total,const u32*t1,const u32*t2,const u32*t3,const u32*s1,const u32*s2,const u32*s3,u32 ci,u32 cis){const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<total;i+=64){u32*q0=a+i,*q1=q0+16,*q2=q0+32,*q3=q0+48;__builtin_prefetch(q0+192);__builtin_prefetch(q1+192);__builtin_prefetch(q2+192);__builtin_prefetch(q3+192);__m256i x0=ldu256(q0),x1=ldu256(q1),x2=ldu256(q2),x3=ldu256(q3);__m256i y0=ldu256(q0+8),y1=ldu256(q1+8),y2=ldu256(q2+8),y3=ldu256(q3+8);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);u1=mpb(u1,ldu256(t1),ldu256(s1),pv);u2=mpb(u2,ldu256(t2),ldu256(s2),pv);u3=mpb(u3,ldu256(t3),ldu256(s3),pv);v1=mpb(v1,ldu256(t1+8),ldu256(s1+8),pv);v2=mpb(v2,ldu256(t2+8),ldu256(s2+8),pv);v3=mpb(v3,ldu256(t3+8),ldu256(s3+8),pv);stu256(q0,u0);stu256(q1,u1);stu256(q2,u2);stu256(q3,u3);stu256(q0+8,v0);stu256(q1+8,v1);stu256(q2+8,v2);stu256(q3+8,v3);}}TGT __attribute__((always_inline))static inline void stage4_h16_loop(u32*a,u32 total,const u32*tb,u32 ci,u32 cis){const u32 MP=16+TPAD;const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cI=_mm256_set1_epi32((int)ci),cIs=_mm256_set1_epi32((int)cis);for(u32 i=0;i<total;i+=64){u32*q0=a+i;const u32*w=tb;u32 j=0;for(;j+16<=16;j+=16,q0+=16,w+=16){__m256i x0=ldu256(q0),x1=ldu256(q0+16),x2=ldu256(q0+32),x3=ldu256(q0+48);__m256i y0=ldu256(q0+8),y1=ldu256(q0+24),y2=ldu256(q0+40),y3=ldu256(q0+56);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv);__m256i C=vaddm(x1,x3,pv),D=vL(x1,x3,pv);__m256i A2=vaddm(y0,y2,pv),B2=vsubm(y0,y2,pv);__m256i C2=vaddm(y1,y3,pv),D2=vL(y1,y3,pv);__m256i u0=vaddm(A,C,pv),u2=vL(A,C,pv);__m256i v0=vaddm(A2,C2,pv),v2=vL(A2,C2,pv);__m256i E=vS(D,cI,cIs,pv),F=vS(D2,cI,cIs,pv);__m256i u1=_mm256_add_epi32(B,E),u3=vL(B,E,pv);__m256i v1=_mm256_add_epi32(B2,F),v3=vL(B2,F,pv);u1=mpb(u1,ldu256(w),ldu256(w+3*MP),pv);u2=mpb(u2,ldu256(w+MP),ldu256(w+4*MP),pv);u3=mpb(u3,ldu256(w+2*MP),ldu256(w+5*MP),pv);v1=mpb(v1,ldu256(w+8),ldu256(w+3*MP+8),pv);v2=mpb(v2,ldu256(w+MP+8),ldu256(w+4*MP+8),pv);v3=mpb(v3,ldu256(w+2*MP+8),ldu256(w+5*MP+8),pv);stu256(q0,u0);stu256(q0+16,u1);stu256(q0+32,u2);stu256(q0+48,u3);stu256(q0+8,v0);stu256(q0+24,v1);stu256(q0+40,v2);stu256(q0+56,v3);}}}TGT static void fwd_sb_ring(u32*a,u32 b){u32*p=a+padpos(b);if(g_odd)stage2_dif(p,g_Sb,g_TF .b2,g_TF .b2s);for(int s=g_nb-1;s>=0;s--){u32 S2=4u<<(2*s);if(S2>=32){if(S2==16384){for(u32 i=0;i<g_Sb;i+=S2)stage4_dif_h<4096>(p+i,16384,4096,g_TF .h1[s],g_ciF,g_cisF);}else if(S2==4096){for(u32 i=0;i<g_Sb;i+=S2)stage4_dif_h<1024>(p+i,4096,1024,g_TF .h1[s],g_ciF,g_cisF);}else if(S2==1024){for(u32 i=0;i<g_Sb;i+=S2)stage4_dif_h<256>(p+i,1024,256,g_TF .h1[s],g_ciF,g_cisF);}else if(S2==256){for(u32 i=0;i<g_Sb;i+=S2)stage4_dif_h<64>(p+i,256,64,g_TF .h1[s],g_ciF,g_cisF);}else if(S2==64){stage4_h16_loop(p,g_Sb,g_TF .h1[s],g_ciF,g_cisF);}else{for(u32 i=0;i<g_Sb;i+=S2)stage4_dif_t(p+i,S2,S2>>2,g_TF .h1[s],g_TF .h2[s],g_TF .h3[s],g_TF .q1[s],g_TF .q2[s],g_TF .q3[s],g_ciF,g_cisF);}}else if(S2==16){dh4(p,g_Sb,g_TF .h1[s],g_TF .h2[s],g_TF .h3[s],g_TF .q1[s],g_TF .q2[s],g_TF .q3[s],g_ciF,g_cisF);}else{}}}TGT static void ntt_fwd_tail(u32*a,u32 S,int lstart,int l0);TGT static void ntt_fwd(u32*a,const u32*src=0,u32 len=0){u32 S=g_n;int l0=0;if(src&&len>=(g_n>>2)&&len<=(g_n>>1)){stage0_dif_src(a,src,len,g_n>>2,g_TF .l1[0],g_TF .l2[0],g_TF .l3[0],g_TF .m1[0],g_TF .m2[0],g_TF .m3[0],g_ciF,g_cisF);S=g_n>>2;l0=1;}int lstart=l0;if(g_fuse16&&l0==0&&S>=(1u<<22)&&((S>>4)%16384u)==0u){u32*bl1[1]={a};stage16_dif_top_batch(bl1,1,S,g_TF .l1[0],g_TF .l2[0],g_TF .l3[0],g_TF .l1[1],g_TF .l2[1],g_TF .l3[1],g_TF .m1[1],g_TF .m2[1],g_TF .m3[1],g_ciF,g_cisF);_mm_sfence();S>>=4;lstart=2;}ntt_fwd_tail(a,S,lstart,l0);}TGT static void ntt_fwd_pair_batch(u32**ablocks,u32**bblocks,int nb,const long*deltas){u32 S=g_n;const int n2=nb*2;u32*all[10];for(int q=0;q<nb;q++){all[q]=ablocks[q];all[nb+q]=bblocks[q];}if(g_fuse16&&S>=(1u<<22)&&((S>>4)%16384u)==0u){stage16_dif_top_batch(all,n2,S,g_TF .l1[0],g_TF .l2[0],g_TF .l3[0],g_TF .l1[1],g_TF .l2[1],g_TF .l3[1],g_TF .m1[1],g_TF .m2[1],g_TF .m3[1],g_ciF,g_cisF);_mm_sfence();S>>=4;g_pmdelta=0;for(int q=0;q<nb;q++)ntt_fwd_tail(ablocks[q],S,2,0);for(int q=0;q<nb;q++){g_pmdelta=deltas?deltas[q]:0;ntt_fwd_tail(bblocks[q],S,2,0);}g_pmdelta=0;}else{for(int q=0;q<nb;q++){ntt_fwd(ablocks[q],0,0);g_pmdelta=deltas?deltas[q]:0;ntt_fwd(bblocks[q],0,0);}g_pmdelta=0;}}TGT static void ntt_fwd_tail(u32*a,u32 S,int lstart,int l0){int sb_done=0;if(lstart==2&&g_L==4&&E7Z_SBFUSE){for(u32 b=0;b<g_n;b+=262144u){ds2(a+padpos(b),262144u,65536u,65536u+5*TOPPAD,g_TF .l1[2],g_TF .l2[2],g_TF .l3[2],g_TF .m1[2],g_TF .m2[2],g_TF .m3[2],g_ciF,g_cisF);for(u32 bb=0;bb<262144u;bb+=65536u){ds3(a+padpos(b+bb),65536u,16384u,16384u+TOPPAD,g_TF .l1[3],g_TF .l2[3],g_TF .l3[3],g_TF .m1[3],g_TF .m2[3],g_TF .m3[3],g_ciF,g_cisF);for(u32 rr=0;rr<65536u;rr+=g_Sb)fwd_sb_ring(a,b+bb+rr);}_mm_sfence();}return;}for(int l=lstart;l<g_L;l++){u32 h=S>>2;if(l0+0==l)for(u32 b=0;b<g_n;b+=S)stage4_dif_s0(a+padpos(b),S,h,h+85*TOPPAD,g_TF .l1[l],g_TF .l2[l],g_TF .l3[l],g_TF .m1[l],g_TF .m2[l],g_TF .m3[l],g_ciF,g_cisF);else if(l0+1==l)for(u32 b=0;b<g_n;b+=S)stage4_dif_s1(a+padpos(b),S,h,h+21*TOPPAD,g_TF .l1[l],g_TF .l2[l],g_TF .l3[l],g_TF .m1[l],g_TF .m2[l],g_TF .m3[l],g_ciF,g_cisF);else if(l0+2==l)for(u32 b=0;b<g_n;b+=S)ds2(a+padpos(b),S,h,h+5*TOPPAD,g_TF .l1[l],g_TF .l2[l],g_TF .l3[l],g_TF .m1[l],g_TF .m2[l],g_TF .m3[l],g_ciF,g_cisF);else if(l0+3==l){if(E7Z_SBFUSE&&l==g_L-1){for(u32 b=0;b<g_n;b+=S){ds3(a+padpos(b),S,h,h+1*TOPPAD,g_TF .l1[l],g_TF .l2[l],g_TF .l3[l],g_TF .m1[l],g_TF .m2[l],g_TF .m3[l],g_ciF,g_cisF);for(u32 bb=0;bb<S;bb+=g_Sb)fwd_sb_ring(a,b+bb);}sb_done=1;}else for(u32 b=0;b<g_n;b+=S)ds3(a+padpos(b),S,h,h+1*TOPPAD,g_TF .l1[l],g_TF .l2[l],g_TF .l3[l],g_TF .m1[l],g_TF .m2[l],g_TF .m3[l],g_ciF,g_cisF);}else for(u32 b=0;b<g_n;b+=S)stage4_dif(a+padpos(b),S,h,g_TF .l1[l],g_TF .l2[l],g_TF .l3[l],g_TF .m1[l],g_TF .m2[l],g_TF .m3[l],g_ciF,g_cisF);_mm_sfence();S=h;}if(!sb_done){for(u32 b=0;b<g_n;b+=g_Sb)fwd_sb_ring(a,b);}}
#define I44 512u
TGT static void fib(u32**blocks,int nb){const u32 h1=1u<<18,h0=1u<<20,sh1=h1+21*TOPPAD,sh0=h0+85*TOPPAD;const u32*u11=g_TI .l1[1],*u12=g_TI .l2[1],*u13=g_TI .l3[1];const u32*s11=g_TI .m1[1],*s12=g_TI .m2[1],*s13=g_TI .m3[1];const u32*u01=g_TI .l1[0],*u02=g_TI .l2[0],*u03=g_TI .l3[0];const __m256i pv=_mm256_set1_epi32((int)NTP),ci=_mm256_set1_epi32((int)g_ciI),cis=_mm256_set1_epi32((int)g_cisI);alignas(64)static u32 z[4][4][I44+8];for(u32 j0=0;j0<h1;j0+=I44){for(int qi=0;qi<nb;qi++){u32*a=blocks[qi];for(u32 r=0;r<4;r++)for(u32 t=0;t<I44;t+=8){u32 j=j0+t;u32*p=a+r*sh0+padpos(j0)+t;__builtin_prefetch(p+128);__builtin_prefetch(p+sh1+128);__builtin_prefetch(p+2*sh1+128);__builtin_prefetch(p+3*sh1+128);__m256i w1=ldu256(u11+j),w2=ldu256(u12+j),w3=ldu256(u13+j);__m256i x0=ldu256(p),x1=mpa(ldu256(p+sh1),w1,pv),x2=mpa(ldu256(p+2*sh1),w2,pv),x3=mpa(ldu256(p+3*sh1),w3,pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv),C=vaddm(x1,x3,pv),D=vL(x1,x3,pv),E=vS(D,ci,cis,pv);if(r==0){stu256(z[r][0]+t,vaddm(A,C,pv));stu256(z[r][1]+t,vaddm(B,E,pv));stu256(z[r][2]+t,vsubm(A,C,pv));stu256(z[r][3]+t,vsubm(B,E,pv));}else{stu256(z[r][0]+t,_mm256_add_epi32(A,C));stu256(z[r][1]+t,_mm256_add_epi32(B,E));stu256(z[r][2]+t,vL(A,C,pv));stu256(z[r][3]+t,vL(B,E,pv));}}for(u32 k=0;k<4;k++)for(u32 t=0;t<I44;t+=8){u32 j=k*h1+j0+t;u32*p=a+padpos(k*h1+j0)+t;__builtin_prefetch(p+0*sh0+256,1,3);__builtin_prefetch(p+1*sh0+288,1,3);__builtin_prefetch(p+2*sh0+320,1,3);__builtin_prefetch(p+3*sh0+352,1,3);__builtin_prefetch(u01+j+128);__builtin_prefetch(u02+j+128);__builtin_prefetch(u03+j+128);__m256i w1=ldu256(u01+j),w2=ldu256(u02+j),w3=ldu256(u03+j);__m256i x0=ldu256(z[0][k]+t),x1=mpa(ldu256(z[1][k]+t),w1,pv),x2=mpa(ldu256(z[2][k]+t),w2,pv),x3=mpa(ldu256(z[3][k]+t),w3,pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv),C=vaddm(x1,x3,pv),D=vL(x1,x3,pv),E=vS(D,ci,cis,pv);if(qi==0){stu256(p,vaddm(A,C,pv));stu256(p+sh0,vaddm(B,E,pv));stu256(p+2*sh0,vsubm(A,C,pv));stu256(p+3*sh0,vsubm(B,E,pv));}else{stu256(p,_mm256_add_epi32(A,C));stu256(p+sh0,_mm256_add_epi32(B,E));stu256(p+2*sh0,vL(A,C,pv));stu256(p+3*sh0,vL(B,E,pv));}}}}}TGT static void ntt_inv_tail(u32*a,const u32*Bmul){for(u32 b=0;b<g_n;b+=g_Sb){u32*p=a+padpos(b);if(Bmul&&!E7Z3_PM_ON()){const __m256i pv=_mm256_set1_epi32((int)NTP);const u32*q=Bmul+padpos(b);for(u32 i=0;i<g_Sb;i+=8){__m256i x=ldu256((p+i));__m256i y=ldu256((q+i));stu256((p+i),vS(x,y,der_ws(y),pv));}}const int h1fused=(g_nb>=2&&g_Sb>=32u&&(g_Sb%32u)==0u);const int s64fused=(h1fused&&g_nb>=3&&g_Sb>=64u&&(g_Sb%64u)==0u);for(int s=0;s<g_nb;s++){u32 S=4u<<(2*s);if(S>=32){if(S==16384){for(u32 i=0;i<g_Sb;i+=S){if(g_Sb==16384&&!g_odd&&g_L==4&&(b&(3*g_Sb)))merge4_dit_h<4096,true>(p+i,16384,4096,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);else merge4_dit_h<4096>(p+i,16384,4096,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}}else if(S==4096){for(u32 i=0;i<g_Sb;i+=S){if(g_Sb>=4*S&&(i&(3*S))!=0)merge4_dit_h<1024,true>(p+i,4096,1024,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);else merge4_dit_h<1024>(p+i,4096,1024,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}}else if(S==1024){for(u32 i=0;i<g_Sb;i+=S){if(g_Sb>=4*S&&(i&(3*S))!=0)merge4_dit_h<256,true>(p+i,1024,256,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);else merge4_dit_h<256>(p+i,1024,256,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}}else if(S==256){for(u32 i=0;i<g_Sb;i+=S){if(g_Sb>=4*S&&(i&(3*S))!=0)merge4_dit_h<64,true>(p+i,256,64,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);else merge4_dit_h<64>(p+i,256,64,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}}else if(S==64){if(!s64fused){for(u32 i=0;i<g_Sb;i+=S)merge4_dit_h<16>(p+i,64,16,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}}else{for(u32 i=0;i<g_Sb;i+=S)merge4_dit_t(p+i,S,S>>2,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}}else if(S==16){if(s64fused)mhh64(p,g_Sb,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI,g_TI .h1[s+1],g_TI .h2[s+1],g_TI .h3[s+1],g_TI .q1[s+1],g_TI .q2[s+1],g_TI .q3[s+1]);else if(h1fused)mhh(p,g_Sb,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);else merge4_dit_h4(p,g_Sb,g_TI .h1[s],g_TI .h2[s],g_TI .h3[s],g_TI .q1[s],g_TI .q2[s],g_TI .q3[s],g_ciI,g_cisI);}else{if(!h1fused)mh1(p,g_Sb,g_ciI,g_cisI);}}if(g_odd)merge2_dit(p,g_Sb,g_TI .b2,g_TI .b2s);if(E7Z_IVFUSE&&g_L==4){if((b+g_Sb)%(g_n>>6)==0){u32 SB=g_n>>6,h=SB>>2;merge4_dit_s3(a+padpos(b+g_Sb-SB),SB,h,h+TOPPAD,g_TI .l1[3],g_TI .l2[3],g_TI .l3[3],g_TI .m1[3],g_TI .m2[3],g_TI .m3[3],g_ciI,g_cisI);}if((b+g_Sb)%(g_n>>4)==0){u32 SB=g_n>>4,h=SB>>2;merge4_dit_s2(a+padpos(b+g_Sb-SB),SB,h,h+5*TOPPAD,g_TI .l1[2],g_TI .l2[2],g_TI .l3[2],g_TI .m1[2],g_TI .m2[2],g_TI .m3[2],g_ciI,g_cisI);}}}for(int l=g_L-1;l>=2;l--){if(E7Z_IVFUSE&&g_L==4&&(l==2||l==3)){_mm_sfence();continue;}u32 SB=g_n>>(2*l),h=SB>>2;if(l==2)for(u32 b=0;b<g_n;b+=SB)merge4_dit_s2(a+padpos(b),SB,h,h+5*TOPPAD,g_TI .l1[l],g_TI .l2[l],g_TI .l3[l],g_TI .m1[l],g_TI .m2[l],g_TI .m3[l],g_ciI,g_cisI);else if(l==3)for(u32 b=0;b<g_n;b+=SB)merge4_dit_s3(a+padpos(b),SB,h,h+TOPPAD,g_TI .l1[l],g_TI .l2[l],g_TI .l3[l],g_TI .m1[l],g_TI .m2[l],g_TI .m3[l],g_ciI,g_cisI);else for(u32 b=0;b<g_n;b+=SB)merge4_dit(a+padpos(b),SB,h,g_TI .l1[l],g_TI .l2[l],g_TI .l3[l],g_TI .m1[l],g_TI .m2[l],g_TI .m3[l],g_ciI,g_cisI);_mm_sfence();}}TGT static void ntt_inv_batch(u32**blocks,int nb){g_pmdelta=0;for(int q=0;q<nb;q++)ntt_inv_tail(blocks[q],0);fib(blocks,nb);}static u32 g_M5,g_M5L;static u32*g_outC=0;static u32 g_ninvS=0,g_limS=0;static int g_fuse=0,g_nt=0;static u32*g_t5[4],*g_u5[4];static u32 g_c5a,g_c5b,g_c5c,g_c5d,g_c5ci,g_c5di,g_inv2;static u32 g_c5k,g_c5dc,g_c5sc,g_c5dci,g_c5sci;static u32 g_c5a_s,g_c5b_s,g_c5c_s,g_c5d_s,g_c5ci_s,g_c5di_s,g_inv2_s;static u32 g_c5k_s,g_c5dc_s,g_c5sc_s,g_c5dci_s,g_c5sci_s;static void init_r5(u32 N){u32 M=N/5;g_M5=M+448*TOPPAD+896;g_M5L=M;u32 w=powmod(31u,(NTP-1)/N);u32 wi=powmod(w,NTP-2);g_wf=w;g_wif=wi;u32 rho=powmod(w,M);u32 rho2=mulmod(rho,rho),rho3=mulmod(rho2,rho),rho4=mulmod(rho3,rho);g_c5a=(u32)(((u64)rho+rho4)%NTP);g_c5b=(u32)(((u64)rho2+rho3)%NTP);g_c5c=(u32)(((u64)rho+NTP-rho4)%NTP);g_c5d=(u32)(((u64)rho2+NTP-rho3)%NTP);g_c5ci=(u32)((NTP-(u64)g_c5c)%NTP);g_c5di=(u32)((NTP-(u64)g_c5d)%NTP);g_inv2=(u32)(((u64)NTP+1)/2);g_c5a=mulmod(g_c5a,g_inv2);g_c5b=mulmod(g_c5b,g_inv2);g_c5c=mulmod(g_c5c,g_inv2);g_c5d=mulmod(g_c5d,g_inv2);g_c5ci=mulmod(g_c5ci,g_inv2);g_c5di=mulmod(g_c5di,g_inv2);g_c5k=mulmod((g_c5a+NTP-g_c5b)%NTP,g_inv2);g_c5dc=(g_c5d+NTP-g_c5c)%NTP;g_c5sc=(g_c5c+g_c5d)%NTP;g_c5dci=(g_c5di+NTP-g_c5ci)%NTP;g_c5sci=(g_c5ci+g_c5di)%NTP;g_c5k_s=shoup_c(g_c5k);g_c5dc_s=shoup_c(g_c5dc);g_c5sc_s=shoup_c(g_c5sc);g_c5dci_s=shoup_c(g_c5dci);g_c5sci_s=shoup_c(g_c5sci);g_c5a_s=shoup_c(g_c5a);g_c5b_s=shoup_c(g_c5b);g_c5c_s=shoup_c(g_c5c);g_c5d_s=shoup_c(g_c5d);g_c5ci_s=shoup_c(g_c5ci);g_c5di_s=shoup_c(g_c5di);g_inv2_s=shoup_c(g_inv2);u32*pf=g_tabF+(5*NTT_MAXN/2+4096)-4*M;u32*pi=g_tabI+(5*NTT_MAXN/2+4096)-4*M;for(int q=0;q<4;q++){g_t5[q]=pf+(size_t)q*M;g_u5[q]=pi+(size_t)q*M;}for(int q=1;q<4;q++){g_t5[q]=g_t5[0];g_u5[q]=g_u5[0];}}TGT static inline void dft5v(__m256i x0,__m256i x1,__m256i x2,__m256i x3,__m256i x4,__m256i&Y0,__m256i&Y1,__m256i&Y2,__m256i&Y3,__m256i&Y4,__m256i pv,__m256i cK,__m256i cKs,__m256i cC,__m256i cCs,__m256i cDiff,__m256i cDiffS,__m256i cSum,__m256i cSumS,__m256i iv2,__m256i iv2s){(void)iv2;(void)iv2s;__m256i P1=vaddm(x1,x4,pv),M1=vsubm(x1,x4,pv);__m256i P2=vaddm(x2,x3,pv),M2=vsubm(x2,x3,pv);__m256i S=vaddm(P1,P2,pv),D=vL(P1,P2,pv);const __m256i negQuarterBase=_mm256_setr_epi32(2013265921,503316480,1006632960,1509949440,2013265921,503316480,1006632960,1509949440);__m256i rem4=_mm256_and_si256(S,_mm256_set1_epi32(3));__m256i U=_mm256_sub_epi32(_mm256_permutevar8x32_epi32(negQuarterBase,rem4),_mm256_srli_epi32(S,2));U=_mm256_min_epu32(U,_mm256_sub_epi32(U,pv));__m256i V=vS(D,cK,cKs,pv);__m256i A=vaddm(U,V,pv),B=vsubm(U,V,pv);__m256i T1=vS(_mm256_add_epi32(M1,M2),cC,cCs,pv);__m256i T2=vS(M2,cDiff,cDiffS,pv);__m256i T3=vS(M1,cSum,cSumS,pv);__m256i R=vaddm(T1,T2,pv),I=vsubm(T3,T1,pv);Y0=vaddm(x0,S,pv);Y1=vaddm(x0,vaddm(A,R,pv),pv);Y2=vaddm(x0,vaddm(B,I,pv),pv);Y3=vaddm(x0,vsubm(B,I,pv),pv);Y4=vaddm(x0,vsubm(A,R,pv),pv);}TGT static inline void dft5v3(__m256i x0,__m256i x1,__m256i x2,__m256i,__m256i,__m256i&Y0,__m256i&Y1,__m256i&Y2,__m256i&Y3,__m256i&Y4,__m256i p,__m256i K,__m256i Ks,__m256i C,__m256i Cs,__m256i Dif,__m256i Difs,__m256i Sum,__m256i Sums,__m256i,__m256i){__m256i S=vaddm(x1,x2,p),D=vL(x1,x2,p);const __m256i tab=_mm256_setr_epi32(2013265921,503316480,1006632960,1509949440,2013265921,503316480,1006632960,1509949440);__m256i U=_mm256_sub_epi32(_mm256_permutevar8x32_epi32(tab,_mm256_and_si256(S,_mm256_set1_epi32(3))),_mm256_srli_epi32(S,2));U=_mm256_min_epu32(U,_mm256_sub_epi32(U,p));__m256i V=vS(D,K,Ks,p),A=vaddm(U,V,p),B=vsubm(U,V,p);__m256i T=vS(S,C,Cs,p),R=vaddm(T,vS(x2,Dif,Difs,p),p),I=vsubm(vS(x1,Sum,Sums,p),T,p);Y0=vaddm(x0,S,p);Y1=_mm256_add_epi32(x0,vaddm(A,R,p));Y2=_mm256_add_epi32(x0,vaddm(B,I,p));Y3=_mm256_add_epi32(x0,vsubm(B,I,p));Y4=_mm256_add_epi32(x0,vsubm(A,R,p));}TGT static inline void dft5v2(__m256i a,__m256i b,__m256i&z0,__m256i&z1,__m256i&z2,__m256i&z3,__m256i&z4,__m256i p){z0=vaddm(a,b,p);z1=_mm256_add_epi32(a,vS(b,_mm256_set1_epi32(645581151),_mm256_set1_epi32(1377239788),p));z2=_mm256_add_epi32(a,vS(b,_mm256_set1_epi32(1956349769),_mm256_set1_epi32((int)4173546171u),p));z3=_mm256_add_epi32(a,vS(b,_mm256_set1_epi32(609564788),_mm256_set1_epi32(1300404880),p));z4=_mm256_add_epi32(a,vS(b,_mm256_set1_epi32(815036133),_mm256_set1_epi32(1738743749),p));}TGT static inline void stnfwd(void*p,__m256i v){stu256(p,v);}
#define ST5_FWD2(a, j, Ya0, Ya1, Ya2, Ya3, Ya4, Yb0, Yb1, Yb2, Yb3, Yb4) \
{ stnfwd(((a) + (j)), (Ya0)); stnfwd(((a) + (j) + 8), (Yb0)); \
__m256i w1 = ldu256((tw0 + (j))); __m256i s1 = der_ws(w1); \
__m256i w1b = ldu256((tw0 + (j) + 8)); __m256i s1b = der_ws(w1b); \
__m256i w2 = mpa(w1, w1, pv5); __m256i w2b = mpa(w1b, w1b, pv5); \
__m256i w3 = mpa(w2, w1, pv5); __m256i w3b = mpa(w2b, w1b, pv5); \
__m256i w4 = mpa(w2, w2, pv5); __m256i w4b = mpa(w2b, w2b, pv5); \
stnfwd(((a) + (j) + (size_t)strideM5), mpa((Ya1), w1, pv5)); \
stnfwd(((a) + (j) + 8 + (size_t)strideM5), mpa((Yb1), w1b, pv5)); \
stnfwd(((a) + (j) + (size_t)2 * strideM5), mpa((Ya2), w2, pv5)); \
stnfwd(((a) + (j) + 8 + (size_t)2 * strideM5), mpa((Yb2), w2b, pv5)); \
stnfwd(((a) + (j) + (size_t)3 * strideM5), mpa((Ya3), w3, pv5)); \
stnfwd(((a) + (j) + 8 + (size_t)3 * strideM5), mpa((Yb3), w3b, pv5)); \
stnfwd(((a) + (j) + (size_t)4 * strideM5), mpa((Ya4), w4, pv5)); \
stnfwd(((a) + (j) + 8 + (size_t)4 * strideM5), mpa((Yb4), w4b, pv5)); \
}
#define ST5_FWD(a, j, Y0, Y1, Y2, Y3, Y4) \
{ stnfwd(((a) + (j)), (Y0)); \
__m256i w1 = ldu256((tw0 + (j))); \
__m256i s1 = der_ws(w1); \
__m256i w2 = mpa(w1, w1, pv5); \
__m256i w3 = mpa(w2, w1, pv5); \
__m256i w4 = mpa(w2, w2, pv5); \
stnfwd(((a) + (j) + (size_t)strideM5), mpa((Y1), w1, pv5)); \
stnfwd(((a) + (j) + (size_t)2 * strideM5), mpa((Y2), w2, pv5)); \
stnfwd(((a) + (j) + (size_t)3 * strideM5), mpa((Y3), w3, pv5)); \
stnfwd(((a) + (j) + (size_t)4 * strideM5), mpa((Y4), w4, pv5)); \
}
template<bool SCALE>static inline void st5_scalar(u32*a,const u32 x[5],u32 u,u32 M){u32 scaled[5];const u32*input=x;if constexpr(SCALE){for(int q=0;q<5;q++)scaled[q]=g_scale_digit[x[q]];input=scaled;}u32 P1=(u32)(((u64)input[1]+input[4])%NTP),M1=(u32)(((u64)input[1]+NTP-input[4])%NTP);u32 P2=(u32)(((u64)input[2]+input[3])%NTP),M2=(u32)(((u64)input[2]+NTP-input[3])%NTP);u32 aP1=shoup1s(P1,g_c5a,g_c5a_s),cM1=shoup1s(M1,g_c5c,g_c5c_s);u32 bP2=shoup1s(P2,g_c5b,g_c5b_s),dM2=shoup1s(M2,g_c5d,g_c5d_s);u32 bP1=shoup1s(P1,g_c5b,g_c5b_s),dM1=shoup1s(M1,g_c5d,g_c5d_s);u32 aP2=shoup1s(P2,g_c5a,g_c5a_s),cM2=shoup1s(M2,g_c5c,g_c5c_s);u32 Y[5];Y[0]=(u32)(((u64)input[0]+P1+P2)%NTP);Y[1]=(u32)(((u64)input[0]+(u32)(((u64)aP1+cM1+bP2+dM2)%NTP))%NTP);Y[2]=(u32)(((u64)input[0]+(u32)(((u64)bP1+dM1+aP2+NTP-cM2)%NTP))%NTP);Y[3]=(u32)(((u64)input[0]+(u32)(((u64)bP1+NTP-dM1+aP2+cM2)%NTP))%NTP);Y[4]=(u32)(((u64)input[0]+(u32)(((u64)aP1+NTP-cM1+bP2+NTP-dM2)%NTP))%NTP);a[u]=Y[0];{u32 w1=mulmod(g_t5[0][u],943718400u),w2=mulmod(w1,w1),w3=mulmod(w2,w1),w4=mulmod(w3,w1);a[u+(size_t)g_M5]=shoup1s(Y[1],w1,shoup_c(w1));a[u+(size_t)2*g_M5]=shoup1s(Y[2],w2,shoup_c(w2));a[u+(size_t)3*g_M5]=shoup1s(Y[3],w3,shoup_c(w3));a[u+(size_t)4*g_M5]=shoup1s(Y[4],w4,shoup_c(w4));}}static int g_s5skip=1;TGT __attribute__((always_inline))static inline void st5_pair_out(u32*pa,u32*pb,u32 st,__m256i w1,__m256i w2,__m256i w3,__m256i w4,__m256i u1,__m256i u2,__m256i u3,__m256i u4,__m256i Y0,__m256i Y1,__m256i Y2,__m256i Y3,__m256i Y4,__m256i Z0,__m256i Z1,__m256i Z2,__m256i Z3,__m256i Z4,__m256i Q0,__m256i Q1,__m256i Q2,__m256i Q3,__m256i Q4,__m256i R0,__m256i R1,__m256i R2,__m256i R3,__m256i R4,__m256i pv){stnfwd(pa,Y0);stnfwd(pa+8,Z0);stnfwd(pa+st,mpa(Y1,w1,pv));stnfwd(pa+st+8,mpa(Z1,u1,pv));stnfwd(pa+2*st,mpa(Y2,w2,pv));stnfwd(pa+2*st+8,mpa(Z2,u2,pv));stnfwd(pa+3*st,mpa(Y3,w3,pv));stnfwd(pa+3*st+8,mpa(Z3,u3,pv));stnfwd(pa+4*st,mpa(Y4,w4,pv));stnfwd(pa+4*st+8,mpa(Z4,u4,pv));stnfwd(pb,Q0);stnfwd(pb+8,R0);stnfwd(pb+st,mpa(Q1,w1,pv));stnfwd(pb+st+8,mpa(R1,u1,pv));stnfwd(pb+2*st,mpa(Q2,w2,pv));stnfwd(pb+2*st+8,mpa(R2,u2,pv));stnfwd(pb+3*st,mpa(Q3,w3,pv));stnfwd(pb+3*st+8,mpa(R3,u3,pv));stnfwd(pb+4*st,mpa(Q4,w4,pv));stnfwd(pb+4*st+8,mpa(R4,u4,pv));}TGT static void stage5_pair(u32*da,u32*db,const u32*sa,const u32*sb,u32 len,u32 M){const u32 st=g_M5;const __m256i pv=_mm256_set1_epi32((int)NTP);const __m256i cK=_mm256_set1_epi32((int)g_c5k),cKs=_mm256_set1_epi32((int)g_c5k_s),cC=_mm256_set1_epi32((int)g_c5c),cCs=_mm256_set1_epi32((int)g_c5c_s),cD=_mm256_set1_epi32((int)g_c5d),cDs=_mm256_set1_epi32((int)g_c5d_s),cF=_mm256_set1_epi32((int)g_c5dc),cFS=_mm256_set1_epi32((int)g_c5dc_s),cS=_mm256_set1_epi32((int)g_c5sc),cSS=_mm256_set1_epi32((int)g_c5sc_s),ivv=_mm256_set1_epi32((int)g_inv2),ivs=_mm256_set1_epi32((int)g_inv2_s),zz=_mm256_setzero_si256();u32 l2=len-2*M+1;if(l2>M)l2=M;u32 tws[16];__m256i twS=_mm256_set1_epi32((int)mulmod(RRW,powmod(g_wf,16))),W0,W1;tw16(tws,RRW,g_wf);W0=ldu256(tws);W1=ldu256(tws+8);for(u32 j=0;j+16<=l2;j+=16){__m256i x0=lds256<false>(sa+j),x1=lds256<false>(sa+j+M),x2=lds256<false>(sa+j+2*M),y0=lds256<false>(sa+j+8),y1=lds256<false>(sa+j+M+8),y2=lds256<false>(sa+j+2*M+8);__m256i Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4;dft5v3(x0,x1,x2,zz,zz,Y0,Y1,Y2,Y3,Y4,pv,cK,cKs,cC,cCs,cF,cFS,cS,cSS,ivv,ivs);dft5v3(y0,y1,y2,zz,zz,Z0,Z1,Z2,Z3,Z4,pv,cK,cKs,cC,cCs,cF,cFS,cS,cSS,ivv,ivs);__m256i a0=lds256<true>(sb+j),a1=lds256<true>(sb+j+M),a2=lds256<true>(sb+j+2*M),b0=lds256<true>(sb+j+8),b1=lds256<true>(sb+j+M+8),b2=lds256<true>(sb+j+2*M+8);__m256i Q0,Q1,Q2,Q3,Q4,R0,R1,R2,R3,R4;dft5v3(a0,a1,a2,zz,zz,Q0,Q1,Q2,Q3,Q4,pv,cK,cKs,cC,cCs,cF,cFS,cS,cSS,ivv,ivs);dft5v3(b0,b1,b2,zz,zz,R0,R1,R2,R3,R4,pv,cK,cKs,cC,cCs,cF,cFS,cS,cSS,ivv,ivs);__m256i w1=W0,w1b=W1;W0=mpa(W0,twS,pv);W1=mpa(W1,twS,pv);__m256i w2=mpa(w1,w1,pv),w3=mpa(w2,w1,pv),w4=mpa(w2,w2,pv);__m256i v1=w1b,v2=mpa(w1b,w1b,pv),v3=mpa(v2,w1b,pv),v4=mpa(v2,v2,pv);st5_pair_out(da+padpos(j),db+padpos(j),st,w1,w2,w3,w4,v1,v2,v3,v4,Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4,Q0,Q1,Q2,Q3,Q4,R0,R1,R2,R3,R4,pv);}tw16(tws,mulmod(RRW,powmod(g_wf,l2+15)),g_wf);W0=ldu256(tws);W1=ldu256(tws+8);u32 j=l2+15;for(;j+16<=M;j+=16){__m256i x0=lds256<false>(sa+j),x1=lds256<false>(sa+j+M),y0=lds256<false>(sa+j+8),y1=lds256<false>(sa+j+M+8);__m256i Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4;dft5v2(x0,x1,Y0,Y1,Y2,Y3,Y4,pv);dft5v2(y0,y1,Z0,Z1,Z2,Z3,Z4,pv);__m256i a0=lds256<true>(sb+j),a1=lds256<true>(sb+j+M),b0=lds256<true>(sb+j+8),b1=lds256<true>(sb+j+M+8);__m256i Q0,Q1,Q2,Q3,Q4,R0,R1,R2,R3,R4;dft5v2(a0,a1,Q0,Q1,Q2,Q3,Q4,pv);dft5v2(b0,b1,R0,R1,R2,R3,R4,pv);__m256i w1=W0,w1b=W1;W0=mpa(W0,twS,pv);W1=mpa(W1,twS,pv);__m256i w2=mpa(w1,w1,pv),w3=mpa(w2,w1,pv),w4=mpa(w2,w2,pv);__m256i v1=w1b,v2=mpa(w1b,w1b,pv),v3=mpa(v2,w1b,pv),v4=mpa(v2,v2,pv);st5_pair_out(da+padpos(j),db+padpos(j),st,w1,w2,w3,w4,v1,v2,v3,v4,Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4,Q0,Q1,Q2,Q3,Q4,R0,R1,R2,R3,R4,pv);}}template<bool SCALE>TGT static void stage5_dif_src(u32*a,const u32*src,u32 len,u32 M){const u32*const tw0=g_t5[0];const u32 strideM5=g_M5;u32*bp=a;u32 nxt0=1u<<20;u32 nxt1=1u<<18;u32 nxt2=1u<<16;u32 nxt3=1u<<14;u32 nxt=nxt3;const __m256i pv5=_mm256_set1_epi32((int)NTP);const __m256i cA=_mm256_set1_epi32((int)g_c5a),cAs=_mm256_set1_epi32((int)g_c5a_s);const __m256i cB=_mm256_set1_epi32((int)g_c5b),cBs=_mm256_set1_epi32((int)g_c5b_s);const __m256i cC=_mm256_set1_epi32((int)g_c5c),cCs=_mm256_set1_epi32((int)g_c5c_s);const __m256i cD=_mm256_set1_epi32((int)g_c5d),cDs=_mm256_set1_epi32((int)g_c5d_s);const __m256i cK=_mm256_set1_epi32((int)g_c5k),cKs=_mm256_set1_epi32((int)g_c5k_s);const __m256i cDiff=_mm256_set1_epi32((int)g_c5dc),cDiffS=_mm256_set1_epi32((int)g_c5dc_s);const __m256i cSum=_mm256_set1_epi32((int)g_c5sc),cSumS=_mm256_set1_epi32((int)g_c5sc_s);const __m256i iv2=_mm256_set1_epi32((int)g_inv2),iv2s=_mm256_set1_epi32((int)g_inv2_s);const __m256i zz=_mm256_setzero_si256();u32 l4=(len>=4*M)?(len-4*M+1):0;if(l4>M)l4=M;u32 l3=(len>=3*M)?(len-3*M+1):0;if(l3>M)l3=M;u32 l2=(len>=2*M)?(len-2*M+1):0;if(l2>M)l2=M;u32 l1=(len>=M)?(len-M+1):0;if(l1>M)l1=M;{u32 lo=l2>64?l2-64:0,x=mulmod(RRW,powmod(g_wf,lo));for(u32 jj=lo;jj<l2+64;jj++){g_t5[0][jj]=x;x=mulmod(x,g_wf);}}{u32 lo=M>64?M-64:0,x=mulmod(RRW,powmod(g_wf,lo));for(u32 jj=lo;jj<M;jj++){g_t5[0][jj]=x;x=mulmod(x,g_wf);}}u32 j=0;for(;(j&7)&&j<l4;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=src[j+(size_t)t*M];st5_scalar<SCALE>(bp,xx,j,M);}for(;j+8<=l4;j+=8){PADJUMP()pf5(src+j+PF_DIST);pf5(src+j+M+PF_DIST);pf5(src+j+2*M+PF_DIST);pf5(src+j+3*M+PF_DIST);pf5(src+j+4*M+PF_DIST);pf5(tw0+j+PF_DIST);__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i x2=lds256<SCALE>((src+j+2*M));__m256i x3=lds256<SCALE>((src+j+3*M));__m256i x4=lds256<SCALE>((src+j+4*M));__m256i Y0,Y1,Y2,Y3,Y4;dft5v(x0,x1,x2,x3,x4,Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cC,cCs,cDiff,cDiffS,cSum,cSumS,iv2,iv2s);ST5_FWD(bp,j,Y0,Y1,Y2,Y3,Y4);}for(;j<l4;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=src[j+(size_t)t*M];st5_scalar<SCALE>(bp,xx,j,M);}for(;(j&7)&&j<l3;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=(t<4&&j+(size_t)t*M<=len)?src[j+(size_t)t*M]:0;st5_scalar<SCALE>(bp,xx,j,M);}for(;j+8<=l3;j+=8){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i x2=lds256<SCALE>((src+j+2*M));__m256i x3=lds256<SCALE>((src+j+3*M));__m256i Y0,Y1,Y2,Y3,Y4;dft5v(x0,x1,x2,x3,zz,Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cC,cCs,cDiff,cDiffS,cSum,cSumS,iv2,iv2s);ST5_FWD(bp,j,Y0,Y1,Y2,Y3,Y4);}for(;j<l3;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=(t<4&&j+(size_t)t*M<=len)?src[j+(size_t)t*M]:0;st5_scalar<SCALE>(bp,xx,j,M);}for(;(j&7)&&j<l2;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=(t<3&&j+(size_t)t*M<=len)?src[j+(size_t)t*M]:0;st5_scalar<SCALE>(bp,xx,j,M);}for(;(j&15)&&j+8<=l2;j+=8){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i x2=lds256<SCALE>((src+j+2*M));__m256i Y0,Y1,Y2,Y3,Y4;dft5v3(x0,x1,x2,zz,zz,Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cC,cCs,cDiff,cDiffS,cSum,cSumS,iv2,iv2s);ST5_FWD(bp,j,Y0,Y1,Y2,Y3,Y4);}if(g_s5skip){for(;j+16<=l2;j+=16){PADJUMP()}}else for(;j+16<=l2;j+=16){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i x2=lds256<SCALE>((src+j+2*M));__m256i y0=lds256<SCALE>((src+j+8));__m256i y1=lds256<SCALE>((src+j+M+8));__m256i y2=lds256<SCALE>((src+j+2*M+8));__m256i Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4;dft5v3(x0,x1,x2,zz,zz,Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cC,cCs,cDiff,cDiffS,cSum,cSumS,iv2,iv2s);dft5v3(y0,y1,y2,zz,zz,Z0,Z1,Z2,Z3,Z4,pv5,cK,cKs,cC,cCs,cDiff,cDiffS,cSum,cSumS,iv2,iv2s);ST5_FWD2(bp,j,Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4);}for(;j+8<=l2;j+=8){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i x2=lds256<SCALE>((src+j+2*M));__m256i Y0,Y1,Y2,Y3,Y4;dft5v3(x0,x1,x2,zz,zz,Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cC,cCs,cDiff,cDiffS,cSum,cSumS,iv2,iv2s);ST5_FWD(bp,j,Y0,Y1,Y2,Y3,Y4);}for(;j<l2;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=(t<3&&j+(size_t)t*M<=len)?src[j+(size_t)t*M]:0;st5_scalar<SCALE>(bp,xx,j,M);}for(;(j&7)&&j<l1;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=(t<2&&j+(size_t)t*M<=len)?src[j+(size_t)t*M]:0;st5_scalar<SCALE>(bp,xx,j,M);}for(;(j&15)&&j+8<=l1;j+=8){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i Y0,Y1,Y2,Y3,Y4;dft5v2(x0,x1,Y0,Y1,Y2,Y3,Y4,pv5);ST5_FWD(bp,j,Y0,Y1,Y2,Y3,Y4);}if(g_s5skip){for(;j+16<=l1;j+=16){PADJUMP()}}else for(;j+16<=l1;j+=16){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i y0=lds256<SCALE>((src+j+8));__m256i y1=lds256<SCALE>((src+j+M+8));__m256i Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4;dft5v2(x0,x1,Y0,Y1,Y2,Y3,Y4,pv5);dft5v2(y0,y1,Z0,Z1,Z2,Z3,Z4,pv5);ST5_FWD2(bp,j,Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4);}for(;j+8<=l1;j+=8){PADJUMP()__m256i x0=lds256<SCALE>((src+j));__m256i x1=lds256<SCALE>((src+j+M));__m256i Y0,Y1,Y2,Y3,Y4;dft5v2(x0,x1,Y0,Y1,Y2,Y3,Y4,pv5);ST5_FWD(bp,j,Y0,Y1,Y2,Y3,Y4);}for(;j<l1;j++){PADJUMP()u32 xx[5];for(int t=0;t<5;t++)xx[t]=(t<2&&j+(size_t)t*M<=len)?src[j+(size_t)t*M]:0;st5_scalar<SCALE>(bp,xx,j,M);}for(;(j&7)&&j<M;j++){PADJUMP()u32 x0=(j<=len)?src[j]:0;bp[j]=x0;u32 w1=mulmod(g_t5[0][j],943718400u),w2=mulmod(w1,w1),w3=mulmod(w2,w1),w4=mulmod(w3,w1);bp[j+(size_t)g_M5]=shoup1s(x0,w1,shoup_c(w1));bp[j+(size_t)2*g_M5]=shoup1s(x0,w2,shoup_c(w2));bp[j+(size_t)3*g_M5]=shoup1s(x0,w3,shoup_c(w3));bp[j+(size_t)4*g_M5]=shoup1s(x0,w4,shoup_c(w4));}for(;j+8<=M;j+=8){PADJUMP()__m256i x0=(j+8<=len+1)?lds256<SCALE>((src+j)):zz;stnfwd((bp+j),x0);{__m256i w1=ldu256((g_t5[0]+j));__m256i s1=der_ws(w1);__m256i w2=mpa(w1,w1,pv5),w3=mpa(w2,w1,pv5),w4=mpa(w2,w2,pv5);stnfwd((bp+j+(size_t)g_M5),mpa(x0,w1,pv5));stnfwd((bp+j+(size_t)2*g_M5),mpa(x0,w2,pv5));stnfwd((bp+j+(size_t)3*g_M5),mpa(x0,w3,pv5));stnfwd((bp+j+(size_t)4*g_M5),mpa(x0,w4,pv5));}}for(;j<M;j++){PADJUMP()u32 x0=(j<=len)?src[j]:0;bp[j]=x0;u32 w1=mulmod(g_t5[0][j],943718400u),w2=mulmod(w1,w1),w3=mulmod(w2,w1),w4=mulmod(w3,w1);bp[j+(size_t)g_M5]=shoup1s(x0,w1,shoup_c(w1));bp[j+(size_t)2*g_M5]=shoup1s(x0,w2,shoup_c(w2));bp[j+(size_t)3*g_M5]=shoup1s(x0,w3,shoup_c(w3));bp[j+(size_t)4*g_M5]=shoup1s(x0,w4,shoup_c(w4));}}TGT static void fimb(u32**blocks,int nb){const u32 h1=1u<<18,h0=1u<<20,sh1=h1+21*TOPPAD,sh0=h0+85*TOPPAD;const u32 MP1=h1+TPAD,MP0=h0+TPAD;const u32*u11=g_TI .l1[1],*u12=g_TI .l2[1],*u13=g_TI .l3[1];const u32*u01=g_TI .l1[0],*u02=g_TI .l2[0],*u03=g_TI .l3[0];const __m256i pv=_mm256_set1_epi32((int)NTP),ci=_mm256_set1_epi32((int)g_ciI),cis=_mm256_set1_epi32((int)g_cisI);const __m256i twS=_mm256_set1_epi32((int)mulmod(RRW,powmod(g_wif,16)));u32 wib[16],tws[16];__m256i W0,W1;for(int rk_=0;rk_<16;rk_++)wib[rk_]=powmod(g_wif,(rk_>>2)*h0+(rk_&3)*h1);u32*const outC=g_outC;const u32 limit=g_limS;const u32 M=h0*4;const __m256i cK=_mm256_set1_epi32((int)g_c5k),cKs=_mm256_set1_epi32((int)g_c5k_s);const __m256i cCi=_mm256_set1_epi32((int)g_c5ci),cCis=_mm256_set1_epi32((int)g_c5ci_s);const __m256i cDiffI=_mm256_set1_epi32((int)g_c5dci),cDiffIs=_mm256_set1_epi32((int)g_c5dci_s);const __m256i cSumI=_mm256_set1_epi32((int)g_c5sci),cSumIs=_mm256_set1_epi32((int)g_c5sci_s);const __m256i iv2=_mm256_set1_epi32((int)g_inv2),iv2s=_mm256_set1_epi32((int)g_inv2_s);alignas(64)static u32 z[4][4][I44+8];alignas(64)static u32 cap[5][4][4][I44+8];for(u32 j0=0;j0<h1;j0+=I44){const u32 wj0=powmod(g_wif,j0);for(int qi=0;qi<nb;qi++){u32*a=blocks[qi];const u32*u1base=u11+j0,*u0base=u01+j0;for(u32 r=0;r<4;r++)for(u32 t=0;t<I44;t+=8){u32 j=j0+t;u32*p=a+r*sh0+padpos(j0)+t;__builtin_prefetch(p+128);__builtin_prefetch(p+sh1+128);__builtin_prefetch(p+2*sh1+128);__builtin_prefetch(p+3*sh1+128);__m256i w1=ldu256(u1base+t),w2=ldu256(u1base+MP1+t),w3=ldu256(u1base+2*MP1+t);__m256i x0=ldu256(p),x1=mpa(ldu256(p+sh1),w1,pv),x2=mpa(ldu256(p+2*sh1),w2,pv),x3=mpa(ldu256(p+3*sh1),w3,pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv),C=vaddm(x1,x3,pv),D=vL(x1,x3,pv),E=vS(D,ci,cis,pv);if(r==0){stu256(z[r][0]+t,vaddm(A,C,pv));stu256(z[r][1]+t,vaddm(B,E,pv));stu256(z[r][2]+t,vsubm(A,C,pv));stu256(z[r][3]+t,vsubm(B,E,pv));}else{stu256(z[r][0]+t,_mm256_add_epi32(A,C));stu256(z[r][1]+t,_mm256_add_epi32(B,E));stu256(z[r][2]+t,vL(A,C,pv));stu256(z[r][3]+t,vL(B,E,pv));}}for(u32 k=0;k<4;k++)for(u32 t=0;t<I44;t+=8){u32 j=k*h1+j0+t;const u32*u0k=u0base+k*h1;__builtin_prefetch(u0k+t+128);__builtin_prefetch(u0k+MP0+t+128);__builtin_prefetch(u0k+2*MP0+t+128);__m256i w1=ldu256(u0k+t),w2=ldu256(u0k+MP0+t),w3=ldu256(u0k+2*MP0+t);__m256i x0=ldu256(z[0][k]+t),x1=mpa(ldu256(z[1][k]+t),w1,pv),x2=mpa(ldu256(z[2][k]+t),w2,pv),x3=mpa(ldu256(z[3][k]+t),w3,pv);__m256i A=vaddm(x0,x2,pv),B=vsubm(x0,x2,pv),C=vaddm(x1,x3,pv),D=vL(x1,x3,pv),E=vS(D,ci,cis,pv);if(qi==0){stu256(cap[qi][0][k]+t,vaddm(A,C,pv));stu256(cap[qi][1][k]+t,vaddm(B,E,pv));stu256(cap[qi][2][k]+t,vsubm(A,C,pv));stu256(cap[qi][3][k]+t,vsubm(B,E,pv));}else{stu256(cap[qi][0][k]+t,_mm256_add_epi32(A,C));stu256(cap[qi][1][k]+t,_mm256_add_epi32(B,E));stu256(cap[qi][2][k]+t,vL(A,C,pv));stu256(cap[qi][3][k]+t,vL(B,E,pv));}}}for(u32 r=0;r<4;r++)for(u32 k=0;k<4;k++){const u32 CS=16*(I44+8);u32 base=r*h0+k*h1+j0;const u32*cp=cap[0][r][k];u32*C=outC+base;tw16(tws,mulmod(RRW,mulmod(wib[r*4+k],wj0)),g_wif);W0=ldu256(tws);W1=ldu256(tws+8);for(u32 t0=0;t0<I44;t0+=16,cp+=16,C+=16){u32 s=base+t0;__m256i ta[5],tb[5];ta[0]=ldu256(cp);tb[0]=ldu256(cp+8);{__m256i w1=W0;__m256i s1=der_ws(w1);__m256i w2=mpa(w1,w1,pv),w3=mpa(w2,w1,pv),w4=mpa(w2,w2,pv);__m256i w1b=W1;W0=mpa(W0,twS,pv);W1=mpa(W1,twS,pv);__m256i s1b=der_ws(w1b);__m256i w2b=mpa(w1b,w1b,pv),w3b=mpa(w2b,w1b,pv),w4b=mpa(w2b,w2b,pv);ta[1]=mpa(ldu256(cp+CS),w1,pv);tb[1]=mpa(ldu256(cp+CS+8),w1b,pv);ta[2]=mpa(ldu256(cp+2*CS),w2,pv);tb[2]=mpa(ldu256(cp+2*CS+8),w2b,pv);ta[3]=mpa(ldu256(cp+3*CS),w3,pv);tb[3]=mpa(ldu256(cp+3*CS+8),w3b,pv);ta[4]=mpa(ldu256(cp+4*CS),w4,pv);tb[4]=mpa(ldu256(cp+4*CS+8),w4b,pv);}__m256i Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4;dft5v(ta[0],ta[1],ta[2],ta[3],ta[4],Y0,Y1,Y2,Y3,Y4,pv,cK,cKs,cCi,cCis,cDiffI,cDiffIs,cSumI,cSumIs,iv2,iv2s);dft5v(tb[0],tb[1],tb[2],tb[3],tb[4],Z0,Z1,Z2,Z3,Z4,pv,cK,cKs,cCi,cCis,cDiffI,cDiffIs,cSumI,cSumIs,iv2,iv2s);_mm256_stream_si256((__m256i*)(C),Y0);_mm256_stream_si256((__m256i*)(C+8),Z0);_mm256_stream_si256((__m256i*)(C+M),Y1);_mm256_stream_si256((__m256i*)(C+M+8),Z1);_mm256_stream_si256((__m256i*)(C+2*M),Y2);_mm256_stream_si256((__m256i*)(C+2*M+8),Z2);_mm256_stream_si256((__m256i*)(C+3*M),Y3);_mm256_stream_si256((__m256i*)(C+3*M+8),Z3);if(s+16<=limit-4*M){_mm256_stream_si256((__m256i*)(C+4*M),Y4);_mm256_stream_si256((__m256i*)(C+4*M+8),Z4);}else if(s<limit-4*M){u32 tail[16];stu256(tail,Y4);stu256(tail+8,Z4);for(u32 kk=0;kk<limit-4*M-s;++kk)C[4*M+kk]=tail[kk];}}}}}TGT static void merge5_dit(u32*a,u32 M){const u32 strideM5=g_M5;const u32*const tw0=g_u5[0];const int fuse=1,nt=g_nt;u32*const outC=g_outC;const u32 limit=g_limS;u32*bp=a;u32 nxt0=1u<<20;u32 nxt1=1u<<18;u32 nxt2=1u<<16;u32 nxt3=1u<<14;u32 nxt=nxt3;const __m256i pv5=_mm256_set1_epi32((int)NTP);const u32 final_scale=g_ninvS;const u32 final_scale_shoup=shoup_c(final_scale);const __m256i nv=_mm256_set1_epi32((int)final_scale);const __m256i ns=_mm256_set1_epi32((int)final_scale_shoup);const __m256i cA=_mm256_set1_epi32((int)g_c5a),cAs=_mm256_set1_epi32((int)g_c5a_s);const __m256i cB=_mm256_set1_epi32((int)g_c5b),cBs=_mm256_set1_epi32((int)g_c5b_s);const __m256i cCi=_mm256_set1_epi32((int)g_c5ci),cCis=_mm256_set1_epi32((int)g_c5ci_s);const __m256i cDi=_mm256_set1_epi32((int)g_c5di),cDis=_mm256_set1_epi32((int)g_c5di_s);const __m256i cK=_mm256_set1_epi32((int)g_c5k),cKs=_mm256_set1_epi32((int)g_c5k_s);const __m256i cDiffI=_mm256_set1_epi32((int)g_c5dci),cDiffIs=_mm256_set1_epi32((int)g_c5dci_s);const __m256i cSumI=_mm256_set1_epi32((int)g_c5sci),cSumIs=_mm256_set1_epi32((int)g_c5sci_s);const __m256i iv2=_mm256_set1_epi32((int)g_inv2),iv2s=_mm256_set1_epi32((int)g_inv2_s);__m128i carry5[5];const int shiftnt=fuse&&!nt&&(((uintptr_t)outC&31)==16);u32 s=0;for(;s+16<=M;){const u32 full=M&~15u,boundary=(s|16383u)+1u;const u32 stop=full<boundary?full:boundary;PADJUMP_S()for(;s<stop;s+=16){pf5(bp+s+PF_DIST);pf5(bp+s+(size_t)strideM5+PF_DIST);pf5(bp+s+(size_t)2*strideM5+PF_DIST);pf5(bp+s+(size_t)3*strideM5+PF_DIST);pf5(bp+s+(size_t)4*strideM5+PF_DIST);pf5(tw0+s+PF_DIST);__m256i ta[5],tb[5];ta[0]=ldu256((bp+s));tb[0]=ldu256((bp+s+8));{__m256i w1=ldu256((tw0+s));__m256i s1=der_ws(w1);__m256i w2=mpa(w1,w1,pv5),w3=mpa(w2,w1,pv5),w4=mpa(w2,w2,pv5);__m256i w1b=ldu256((tw0+s+8));__m256i s1b=der_ws(w1b);__m256i w2b=mpa(w1b,w1b,pv5),w3b=mpa(w2b,w1b,pv5),w4b=mpa(w2b,w2b,pv5);ta[1]=mpa(ldu256((bp+s+(size_t)strideM5)),w1,pv5);tb[1]=mpa(ldu256((bp+s+8+(size_t)strideM5)),w1b,pv5);ta[2]=mpa(ldu256((bp+s+(size_t)2*strideM5)),w2,pv5);tb[2]=mpa(ldu256((bp+s+8+(size_t)2*strideM5)),w2b,pv5);ta[3]=mpa(ldu256((bp+s+(size_t)3*strideM5)),w3,pv5);tb[3]=mpa(ldu256((bp+s+8+(size_t)3*strideM5)),w3b,pv5);ta[4]=mpa(ldu256((bp+s+(size_t)4*strideM5)),w4,pv5);tb[4]=mpa(ldu256((bp+s+8+(size_t)4*strideM5)),w4b,pv5);}__m256i Y0,Y1,Y2,Y3,Y4,Z0,Z1,Z2,Z3,Z4;dft5v(ta[0],ta[1],ta[2],ta[3],ta[4],Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cCi,cCis,cDiffI,cDiffIs,cSumI,cSumIs,iv2,iv2s);dft5v(tb[0],tb[1],tb[2],tb[3],tb[4],Z0,Z1,Z2,Z3,Z4,pv5,cK,cKs,cCi,cCis,cDiffI,cDiffIs,cSumI,cSumIs,iv2,iv2s);if(fuse){u32*C=outC+s;if(nt){_mm256_stream_si256((__m256i*)(C),Y0);_mm256_stream_si256((__m256i*)(C+8),Z0);_mm256_stream_si256((__m256i*)(C+M),Y1);_mm256_stream_si256((__m256i*)(C+M+8),Z1);_mm256_stream_si256((__m256i*)(C+2*M),Y2);_mm256_stream_si256((__m256i*)(C+2*M+8),Z2);_mm256_stream_si256((__m256i*)(C+3*M),Y3);_mm256_stream_si256((__m256i*)(C+3*M+8),Z3);if(s+16<=limit-4*M){_mm256_stream_si256((__m256i*)(C+4*M),Y4);_mm256_stream_si256((__m256i*)(C+4*M+8),Z4);}else if(s<limit-4*M){u32 tail[16];stu256(tail,Y4);stu256(tail+8,Z4);for(u32 k=0;k<limit-4*M-s;++k)C[4*M+k]=tail[k];}}else if(shiftnt){
#define SH5(q,Y,Z) { u32 *D=C+(q)*M; if(s) _mm256_stream_si256((__m256i*)(D-4),_mm256_inserti128_si256(_mm256_castsi128_si256(carry5[q]),_mm256_castsi256_si128(Y),1)); else _mm_storeu_si128((__m128i*)D,_mm256_castsi256_si128(Y)); _mm256_stream_si256((__m256i*)(D+4),_mm256_permute2x128_si256(Y,Z,0x21)); carry5[q]=_mm256_extracti128_si256(Z,1); if(s+16==M || ((q)==4 && s+16>=limit-4*M)) _mm_storeu_si128((__m128i*)(D+12),carry5[q]); }
SH5(0,Y0,Z0)SH5(1,Y1,Z1)SH5(2,Y2,Z2)SH5(3,Y3,Z3)if(s+16<=limit-4*M){SH5(4,Y4,Z4)}else if(s<limit-4*M){u32*D=C+4*M;if(s)_mm_storeu_si128((__m128i*)(D-4),carry5[4]);u32 tail[16];stu256(tail,Y4);stu256(tail+8,Z4);for(u32 k=0;k<limit-4*M-s;++k)D[k]=tail[k];}
#undef SH5
}else{stu256((C),Y0);stu256((C+8),Z0);stu256((C+M),Y1);stu256((C+M+8),Z1);stu256((C+2*M),Y2);stu256((C+2*M+8),Z2);stu256((C+3*M),Y3);stu256((C+3*M+8),Z3);if(s+16<=limit-4*M){stu256((C+4*M),Y4);stu256((C+4*M+8),Z4);}else if(s<limit-4*M){u32 tail[16];stu256(tail,Y4);stu256(tail+8,Z4);for(u32 k=0;k<limit-4*M-s;++k)C[4*M+k]=tail[k];}}}else{stu256((bp+s),Y0);stu256((bp+s+8),Z0);stu256((bp+s+(size_t)strideM5),Y1);stu256((bp+s+8+(size_t)strideM5),Z1);stu256((bp+s+(size_t)2*strideM5),Y2);stu256((bp+s+8+(size_t)2*strideM5),Z2);stu256((bp+s+(size_t)3*strideM5),Y3);stu256((bp+s+8+(size_t)3*strideM5),Z3);stu256((bp+s+(size_t)4*strideM5),Y4);stu256((bp+s+8+(size_t)4*strideM5),Z4);}}}for(;s+8<=M;s+=8){PADJUMP_S()pf5(bp+s+PF_DIST);pf5(bp+s+(size_t)strideM5+PF_DIST);pf5(bp+s+(size_t)2*strideM5+PF_DIST);pf5(bp+s+(size_t)3*strideM5+PF_DIST);pf5(bp+s+(size_t)4*strideM5+PF_DIST);pf5(tw0+s+PF_DIST);__m256i t0=ldu256((bp+s));__m256i t[5];t[0]=t0;{__m256i w1=ldu256((tw0+s));__m256i s1=der_ws(w1);__m256i w2=mpa(w1,w1,pv5),w3=mpa(w2,w1,pv5),w4=mpa(w2,w2,pv5);t[1]=mpa(ldu256((bp+s+(size_t)strideM5)),w1,pv5);t[2]=mpa(ldu256((bp+s+(size_t)2*strideM5)),w2,pv5);t[3]=mpa(ldu256((bp+s+(size_t)3*strideM5)),w3,pv5);t[4]=mpa(ldu256((bp+s+(size_t)4*strideM5)),w4,pv5);}__m256i Y0,Y1,Y2,Y3,Y4;dft5v(t[0],t[1],t[2],t[3],t[4],Y0,Y1,Y2,Y3,Y4,pv5,cK,cKs,cCi,cCis,cDiffI,cDiffIs,cSumI,cSumIs,iv2,iv2s);if(fuse){u32*C=outC+s;if(nt){_mm256_stream_si256((__m256i*)(C),Y0);_mm256_stream_si256((__m256i*)(C+M),Y1);_mm256_stream_si256((__m256i*)(C+2*M),Y2);_mm256_stream_si256((__m256i*)(C+3*M),Y3);if(s+8<=limit-4*M)_mm256_stream_si256((__m256i*)(C+4*M),Y4);else if(s<limit-4*M){u32 tail[8];stu256(tail,Y4);for(u32 k=0;k<limit-4*M-s;++k)C[4*M+k]=tail[k];}}else{stu256((C),Y0);stu256((C+M),Y1);stu256((C+2*M),Y2);stu256((C+3*M),Y3);if(s+8<=limit-4*M)stu256((C+4*M),Y4);else if(s<limit-4*M){u32 tail[8];stu256(tail,Y4);for(u32 k=0;k<limit-4*M-s;++k)C[4*M+k]=tail[k];}}}else{stu256((bp+s),Y0);stu256((bp+s+strideM5),Y1);stu256((bp+s+2*strideM5),Y2);stu256((bp+s+3*strideM5),Y3);stu256((bp+s+4*strideM5),Y4);}}for(;s<M;s++){PADJUMP_S()u32 t[5];t[0]=bp[s];{u32 w1=mulmod(tw0[s],943718400u),w2=mulmod(w1,w1),w3=mulmod(w2,w1),w4=mulmod(w3,w1);t[1]=shoup1s(bp[s+(size_t)strideM5],w1,shoup_c(w1));t[2]=shoup1s(bp[s+(size_t)2*strideM5],w2,shoup_c(w2));t[3]=shoup1s(bp[s+(size_t)3*strideM5],w3,shoup_c(w3));t[4]=shoup1s(bp[s+(size_t)4*strideM5],w4,shoup_c(w4));}u32 P1=(u32)(((u64)t[1]+t[4])%NTP),M1=(u32)(((u64)t[1]+NTP-t[4])%NTP);u32 P2=(u32)(((u64)t[2]+t[3])%NTP),M2=(u32)(((u64)t[2]+NTP-t[3])%NTP);u32 Y[5];Y[0]=(u32)(((u64)t[0]+P1+P2)%NTP);Y[1]=(u32)(((u64)t[0]+(u32)(((u64)mulmod(g_c5a,P1)+mulmod(g_c5ci,M1))%NTP)+(u32)(((u64)mulmod(g_c5b,P2)+mulmod(g_c5di,M2))%NTP))%NTP);Y[2]=(u32)(((u64)t[0]+(u32)(((u64)mulmod(g_c5b,P1)+mulmod(g_c5di,M1))%NTP)+(u32)(((u64)mulmod(g_c5a,P2)+NTP-mulmod(g_c5ci,M2))%NTP))%NTP);Y[3]=(u32)(((u64)t[0]+(u32)(((u64)mulmod(g_c5b,P1)+NTP-mulmod(g_c5di,M1))%NTP)+(u32)(((u64)mulmod(g_c5a,P2)+mulmod(g_c5ci,M2))%NTP))%NTP);Y[4]=(u32)(((u64)t[0]+(u32)(((u64)mulmod(g_c5a,P1)+NTP-mulmod(g_c5ci,M1))%NTP)+(u32)(((u64)mulmod(g_c5b,P2)+NTP-mulmod(g_c5di,M2))%NTP))%NTP);if(fuse){u32*C=outC+s;C[0]=Y[0];C[M]=Y[1];C[2*M]=Y[2];C[3*M]=Y[3];if(s<limit-4*M)C[4*M]=Y[4];}else{bp[s]=Y[0];bp[s+strideM5]=Y[1];bp[s+2*strideM5]=Y[2];bp[s+3*strideM5]=Y[3];bp[s+4*strideM5]=Y[4];}}}static u32 g_dataA[5*((1u<<22)+448*TOPPAD+896)]__attribute__((aligned(64)));static u32 g_dataB[5*((1u<<22)+448*TOPPAD+896)]__attribute__((aligned(64)));static int g_ready=0;__attribute__((target("avx2")))void poly_multiply(unsigned*a,int n,unsigned*b,int m,unsigned*c){const u32 M=1u<<22;const u32 N=5u*M;if(!g_ready){ntt_init(M);init_r5(N);_mm_sfence();g_ready=1;}u32*A=g_dataA,*B=g_dataB;(void)n;(void)m;u32 na=10000000u,nb=10000000u;u32 ninv=powmod(N%NTP,NTP-2);g_scale_digit[0]=0;for(int d=1;d<10;d++){u64 v=(u64)g_scale_digit[d-1]+mulmod(ninv,(u32)((1ull<<32)%NTP));g_scale_digit[d]=(u32)(v>=NTP?v-NTP:v);}for(int d=0;d<8;d++){g_scale_lo[d]=g_scale_digit[d];g_scale_hi[d]=d<2?g_scale_digit[d+8]:0;}stage5_dif_src<false>(A,a,na,g_M5L);stage5_dif_src<true>(B,b,nb,g_M5L);stage5_pair(A,B,a,b,na,g_M5L);_mm_sfence();{g_ninvS=ninv;g_limS=na+nb+1;g_outC=c;g_nt=(((uintptr_t)c&31)==0);g_fuse=1;}{u32*bblocks[5],*ablocks[5];long deltas[5];for(int q=0;q<5;q++){ablocks[q]=A+(size_t)q*g_M5;bblocks[q]=B+(size_t)q*g_M5;}for(int q=0;q<5;q++)deltas[q]=(long)((char*)ablocks[q]-(char*)bblocks[q]);ntt_fwd_pair_batch(ablocks,bblocks,5,deltas);if(g_nt){g_pmdelta=0;for(int q=0;q<5;q++)ntt_inv_tail(ablocks[q],0);fimb(ablocks,5);}else{gen_geo_val(g_u5[0],g_M5L,RRW,g_wif);ntt_inv_batch(ablocks,5);merge5_dit(A,g_M5L);}}_mm_sfence();}
| Compilation | N/A | N/A | Compile OK | Score: N/A | 显示更多 |
| Testcase #1 | 278.495 ms | 270 MB + 656 KB | Accepted | Score: 100 | 显示更多 |