mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
Real numeric code walked straight into the parts of AdvSIMD that were
never decoded. A C matmul plus dot-product benchmark hit six distinct
families before it would run, so this fills in all of them.
- by-element (`fmla v0.4s, v1.4s, v2.s[3]`): the lane index is spread
over three fields and assembled differently per width. Once the lane
is splatted these are the three-same operations exactly, so
`three_same` was split to take a value for its second operand and the
lowerings are shared outright.
- three-different (`smull`, `uaddw`, `sabdl`, `smlal`): widen, then
operate at the wider size. `Q` picks which half of the sources to
read rather than the register width.
- the width-changing shifts (`sshll`/`sxtl`/`shrn`), which had been
decoding but falling out of the lifter as illegal.
- `fcvtl`/`fcvtn`, single <-> double across a vector.
- single-structure `ld1`/`st1`/`ld1r`, and `ld2`/`st2`, which are a
pair of shuffles in each direction.
- `fccmp`, which had an ISA variant and a lifter arm already and only
ever needed the decoder to reach them.
Two real bugs fell out. `fmov v0.2d, #0.5` was decoded as `mvni` and had
its bits inverted, because the inverting test admitted cmode 1111. And
`scvtf v0.2d, v0.2d` was emitting f64x2.convert_low_i32x4_s: wasm has no
i64x2 <-> f64x2 conversion at all, so the 64-bit arrangements now convert
lane by lane with the scalar instructions, and the opcode table panics
rather than substituting a wrong width again.
Corpus: 311 undecoded -> 116, operand-text diffs 473 -> 2, mnemonic
mismatches still 0, over 752k instructions. What is left undecoded is
ld3/ld4, the halving-narrow and saturating-doubling multiplies, half
precision and the fixed-point converts.
Validated against QEMU: a matmul/dot/classify benchmark and a NEON
structure-load test driven through ACLE intrinsics, both added to the
suite (35 comparisons), plus 2500 fuzz cases.
70 lines
2.2 KiB
C
70 lines
2.2 KiB
C
// Numeric kernels chosen so gcc -O3 emits fmla-by-element, fccmp and the
|
|
// scalar AdvSIMD forms: matmul and dot products index one operand's lane,
|
|
// and the min/max reductions compile to conditional compares.
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#define N 96
|
|
static float A[N][N], B[N][N], C[N][N];
|
|
|
|
static void matmul(void) {
|
|
memset(C, 0, sizeof C);
|
|
for (int i = 0; i < N; i++)
|
|
for (int k = 0; k < N; k++) {
|
|
float a = A[i][k];
|
|
for (int j = 0; j < N; j++) C[i][j] += a * B[k][j];
|
|
}
|
|
}
|
|
|
|
static double dotd(const double *x, const double *y, int n) {
|
|
double s = 0;
|
|
for (int i = 0; i < n; i++) s += x[i] * y[i];
|
|
return s;
|
|
}
|
|
|
|
// Conditional float compares: gcc turns the chained test into fccmp.
|
|
static int classify(double x, double lo, double hi) {
|
|
if (x > lo && x < hi) return 1;
|
|
if (x <= lo || isnan(x)) return 2;
|
|
return 3;
|
|
}
|
|
|
|
int main(void) {
|
|
unsigned s = 12345;
|
|
for (int i = 0; i < N; i++)
|
|
for (int j = 0; j < N; j++) {
|
|
s = s * 1103515245u + 12345u;
|
|
A[i][j] = (float)((s >> 16) % 1000) / 32.0f;
|
|
s = s * 1103515245u + 12345u;
|
|
B[i][j] = (float)((s >> 16) % 1000) / 32.0f;
|
|
}
|
|
matmul();
|
|
double sum = 0, mx = -1e30, mn = 1e30;
|
|
for (int i = 0; i < N; i++)
|
|
for (int j = 0; j < N; j++) {
|
|
sum += C[i][j];
|
|
if (C[i][j] > mx) mx = C[i][j];
|
|
if (C[i][j] < mn) mn = C[i][j];
|
|
}
|
|
printf("matmul sum=%.4f max=%.4f min=%.4f\n", sum, mx, mn);
|
|
|
|
static double x[1024], y[1024];
|
|
for (int i = 0; i < 1024; i++) { x[i] = i * 0.5 - 100.0; y[i] = 1.0 / (i + 1); }
|
|
printf("dot=%.9f\n", dotd(x, y, 1024));
|
|
|
|
int c[4] = {0};
|
|
for (int i = 0; i < 1000; i++) {
|
|
double v = (i % 7 == 0) ? nan("") : (double)i - 500.0;
|
|
c[classify(v, -200.0, 200.0)]++;
|
|
}
|
|
printf("classify %d %d %d\n", c[1], c[2], c[3]);
|
|
|
|
// Scalar AdvSIMD: gcc uses cmge/abs on d registers for 64-bit lanes.
|
|
long long acc = 0;
|
|
for (int i = 0; i < 4096; i++) { long long v = (i * 37) % 501 - 250; acc += llabs(v); }
|
|
printf("absacc=%lld\n", acc);
|
|
return 0;
|
|
}
|