bc6bc9c250
* Makefile: support Linux PowerPC (ppc64le) builds PowerPC GCC uses -mcpu instead of -march, so the Linux branch failed with unrecognized option -march=native on ppc64le. Detect ppc64le and ppc64 via uname -m and use -mcpu=$(ARCH) there. The x86-64 path is unchanged. Validated on an IBM POWER8 S824 (Ubuntu 20.04, gcc 9.4): make test-c passes, teacher forcing 32/32 positions and greedy 20/20 tokens against the transformers oracle, engine reports the scalar idot fallback. Signed-off-by: Scott <scottbphone12@gmail.com> * VSX integer-dot kernels for POWER8 (12.8x int8, 7.6x int4 over scalar) Adds a VSX path to dot_i8i8 and dot_i4i8 using vec_msum, which sums byte products directly into s32 lanes, so the 16-bit saturation bound of the AVX2 maddubs trick does not apply. abs(w) is built with a modulo-subtract select instead of vec_abs so w=-128 wraps to 128 unsigned instead of saturating to 127. Nibble unpack uses vec_mergeh/vec_mergel, which interleave like x86 unpacklo/unpackhi on ppc64le (verified on hardware). g_i4s=1 on VSX since the f32 fallback is plain scalar there: measured 5.5x for int4 IDOT at S=1. Measured on an IBM POWER8 S824 (gcc 9.4, Ubuntu 20.04 ppc64le), single thread, 1536x6144: dot_i8i8 1.48 -> 18.99 Gops/s (12.8x) dot_i4i8 2.33 -> 17.72 Gops/s (7.6x) S=1 int4 matmul path: 3.925 -> 0.505 ms/call (7.8x vs scalar build) Adds tests/test_idot.c: exactness test of the compiled idot kernels (any arch) against a plain-C reference, covering odd tails and the w=-128 edge. Passes on avx512-vnni (x86) and vsx (POWER8). The tiny oracle stays token-exact on the VSX build: TF 32/32, greedy 20/20. Signed-off-by: Scott <scottbphone12@gmail.com> --------- Signed-off-by: Scott <scottbphone12@gmail.com> Co-authored-by: Scott <scottbphone12@gmail.com>
45 lines
2.3 KiB
C
45 lines
2.3 KiB
C
/* Exactness test for the integer-dot kernels: dot_i8i8 and dot_i4i8 must return
|
||
* EXACTLY the same value as a plain-C reference, whatever SIMD path was compiled
|
||
* in (avx512-vnni / avx2 / neon / vsx / scalar). Integer arithmetic has no
|
||
* rounding, so any mismatch is a kernel bug, not noise.
|
||
*
|
||
* Covers: odd sizes (scalar tail), sizes below one vector, the w=-128 edge
|
||
* (sign-trick kernels must treat |−128| as 128 unsigned, not saturate to 127),
|
||
* and random data at qrow_i8's contract (|x| <= 127, w full int8 range). */
|
||
#define main coli_glm_main_unused
|
||
#include "../glm.c"
|
||
#undef main
|
||
|
||
static uint32_t rng_state=0x12345678u;
|
||
static uint32_t xr(void){ rng_state^=rng_state<<13; rng_state^=rng_state>>17; rng_state^=rng_state<<5; return rng_state; }
|
||
|
||
static int32_t ref_i8i8(const int8_t *w, const int8_t *x, int I){
|
||
int64_t s=0; for(int i=0;i<I;i++) s+=(int32_t)w[i]*x[i]; return (int32_t)s;
|
||
}
|
||
static int32_t ref_i4i8(const uint8_t *w4, const int8_t *x, int I){
|
||
int64_t s=0;
|
||
for(int i=0;i<I;i++){ uint8_t b=w4[i>>1]; int v=(i&1)?((int)(b>>4)-8):((int)(b&0xF)-8); s+=v*x[i]; }
|
||
return (int32_t)s;
|
||
}
|
||
|
||
int main(void){
|
||
static const int sizes[]={1,2,15,16,17,31,32,33,63,64,65,100,127,128,1408,4096,4097};
|
||
static int8_t w[8192], x[8192]; static uint8_t w4[4096];
|
||
for(unsigned t=0;t<sizeof(sizes)/sizeof(sizes[0]);t++){
|
||
int I=sizes[t];
|
||
for(int rep=0;rep<64;rep++){
|
||
for(int i=0;i<I;i++) x[i]=(int8_t)((int)(xr()%255)-127); /* [-127,127]: contratto di qrow_i8 */
|
||
for(int i=0;i<I;i++) w[i]=(int8_t)((int)(xr()%256)-128); /* [-128,127]: range pieno */
|
||
if(rep==0) for(int i=0;i<I;i++) w[i]=-128; /* caso limite del trucco del segno */
|
||
if(rep==1) for(int i=0;i<I;i++){ w[i]=127; x[i]=(int8_t)(i&1?-127:127); }
|
||
for(int i=0;i<(I+1)/2;i++) w4[i]=(uint8_t)(xr()&0xFF);
|
||
int32_t got=dot_i8i8(w,x,I), want=ref_i8i8(w,x,I);
|
||
if(got!=want){ fprintf(stderr,"FAIL dot_i8i8 I=%d rep=%d: %d != %d\n",I,rep,got,want); return 1; }
|
||
got=dot_i4i8(w4,x,I); want=ref_i4i8(w4,x,I);
|
||
if(got!=want){ fprintf(stderr,"FAIL dot_i4i8 I=%d rep=%d: %d != %d\n",I,rep,got,want); return 1; }
|
||
}
|
||
}
|
||
printf("idot kernel exactness (%s): ok\n", IDOT_KERNEL);
|
||
return 0;
|
||
}
|