mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
Covers the three-same, two-register-misc, across-lanes, permute, extract, table-lookup, copy and shift-by-immediate groups. Undecoded instructions across the corpus drop from 2,442 to 317 (0.05%), still with zero mnemonic mismatches. The lever that made this tractable is i8x16.shuffle: trn, uzp, zip, ext, the rev family and element dup/ins are all fixed byte permutations, so one IR node covers eight instruction families. bitselect covers bsl/bit/bif, and swizzle is tbl with a single table register. Two decoder bugs the corpus found: ins (general) has op == 0, not 1, so "mov v20.s[1], w16" never decoded; and bit 23 is part of the size field for the integer two-register-misc forms, so testing it alone sent "rev64 v0.4s" down the floating-point path. Where wasm has no equivalent the lowering is spelled out rather than skipped: horizontal reductions fold in log2(lanes) shuffle-and-combine steps, pairwise add deinterleaves first, absolute difference is max-minus-min so it cannot overflow at the extremes, and multi-register tbl biases each swizzle. A -O3 vectorised program is now part of the integration ladder, so the corpus tracks what gcc's vectoriser emits rather than what we thought to test. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01KcidnrZ5aLqKoBJBqdjx9d
29 lines
1.8 KiB
C
29 lines
1.8 KiB
C
/* Auto-vectorising loops, for the NEON path (PLAN §5.7).
|
|
*
|
|
* Compiled at -O3 these become NEON: lane-wise arithmetic, horizontal
|
|
* reductions, shuffles and the load/store forms. The point is not the
|
|
* arithmetic but that gcc's vectoriser picks the instructions, so the corpus
|
|
* tracks what real compilers emit rather than what we thought to test.
|
|
*/
|
|
__attribute__((noinline)) static int isum(const int *a, int n){ int s=0; for(int i=0;i<n;i++) s+=a[i]; return s; }
|
|
__attribute__((noinline)) static float fsum(const float *a, int n){ float s=0; for(int i=0;i<n;i++) s+=a[i]*a[i]; return s; }
|
|
__attribute__((noinline)) static void saxpy(float *y,const float *x,float a,int n){ for(int i=0;i<n;i++) y[i]=a*x[i]+y[i]; }
|
|
__attribute__((noinline)) static int imax(const int *a,int n){ int m=a[0]; for(int i=1;i<n;i++) if(a[i]>m) m=a[i]; return m; }
|
|
__attribute__((noinline)) static int cnt(const unsigned char *a,int n){ int c=0; for(int i=0;i<n;i++) c+=__builtin_popcount(a[i]); return c; }
|
|
__attribute__((noinline)) static void rev(unsigned *d,const unsigned *s,int n){ for(int i=0;i<n;i++) d[i]=__builtin_bswap32(s[i]); }
|
|
int main(void){
|
|
enum { N = 1024 };
|
|
static int ia[N]; static float fa[N], fb[N]; static unsigned char ba[N]; static unsigned ua[N], ub[N];
|
|
unsigned seed=7;
|
|
for (int i=0;i<N;i++){ seed=seed*1103515245u+12345u; ia[i]=(int)(seed>>17)-16384; fa[i]=(float)((seed>>20)%1000)/7.0f; fb[i]=1.0f; ba[i]=(unsigned char)(seed>>8); ua[i]=seed; }
|
|
printf("isum=%d\n", isum(ia,N));
|
|
printf("fsum=%.4f\n", fsum(fa,N));
|
|
saxpy(fb,fa,2.5f,N); printf("saxpy=%.4f %.4f\n", fb[0], fb[N-1]);
|
|
printf("imax=%d\n", imax(ia,N));
|
|
printf("popcount=%d\n", cnt(ba,N));
|
|
rev(ub,ua,N); printf("bswap=%08x %08x\n", ub[0], ub[N-1]);
|
|
double d=0; for(int i=0;i<N;i++) d += (double)fa[i]/(1.0+i);
|
|
printf("dsum=%.8f\n", d);
|
|
return 0;
|
|
}
|