Files
parallel-ps2/tests/gsvec/gs_vector_codegen.cpp
LibretroAdmin 7e5e6c7b9c GS: add gs_vector, the 128-bit integer vector as C89
gs_vec4i is the machine vector itself rather than a class holding one, so
an operation is its intrinsic: operators become named functions, and the
template parameters carrying an immediate become macros, which the
instructions require since pslld and pshufd take a literal.

Carries a tier GSVector4i cannot express. The class reaches for pminsd,
pmaxsd, pminud, pmaxud, pblendvb, pblendw, packusdw, ptest, pmovzx and the
pinsr/pextr family with no fallback, which is what makes SSE4.1 a hard
floor for the whole GS; the SSE2 forms are here, alongside SSE4.1, AVX and
NEON.

tests/gsvec checks every entry point against a written-out scalar model of
what the operation means -- the only reference available on SSE2, where
the class will not build -- and against the class itself from SSE4.1 up,
at both compilers and every tier. A third lane counts instructions per
operation: the two are identical everywhere, values in and value out, so
nothing is paid for the shape.
2026-09-21 16:55:15 +02:00

45 lines
2.2 KiB
C++

/* Instruction counts per operation, GSVector4i beside gs_vector.
*
* Compiled to assembly rather than run: the harness counts the instructions
* in each pair and reports any that differ. Values in and value out, so
* neither side can fold a load or a store the other cannot -- measured the
* other way round, the two sides fold differently and the difference looks
* like a win or a loss that is not in the operation at all.
*/
#include "GS/GSVector.h"
extern "C" {
#include "GS/gs_vector.h"
}
/* Values in, value out: no load or store for either side to fold, so the
* comparison is the operation and nothing else. */
#define P(n, cppe, ce) \
extern "C" __m128i cpp_##n(__m128i x,__m128i y){ GSVector4i A(x),B(y); (void)B; return (cppe); } \
extern "C" __m128i c89_##n(__m128i x,__m128i y){ gs_vec4i a=x,b=y; (void)b; return (ce); }
P(add32, A+B, gs_v4i_add32(a,b))
P(sub32, A-B, gs_v4i_sub32(a,b))
P(and_, A&B, gs_v4i_and(a,b))
P(min_i32, A.min_i32(B), gs_v4i_min_i32(a,b))
P(max_i32, A.max_i32(B), gs_v4i_max_i32(a,b))
P(min_u32, A.min_u32(B), gs_v4i_min_u32(a,b))
P(max_u32, A.max_u32(B), gs_v4i_max_u32(a,b))
P(upl16, A.upl16(), gs_v4i_upl16(a))
P(uph16, A.uph16(), gs_v4i_uph16(a))
P(upl16v, A.upl16(B), gs_v4i_upl16v(a,b))
P(upl32, A.upl32(), gs_v4i_upl32(a))
P(ps32, A.ps32(B), gs_v4i_ps32(a,b))
P(pu32, A.pu32(B), gs_v4i_pu32(a,b))
P(blend8, A.blend8(B,B), gs_v4i_blend8(a,b,b))
P(blend32, A.blend32<12>(B), GS_V4I_BLEND32(a,b,12))
P(sll32, A.sll32<7>(), GS_V4I_SLL32(a,7))
P(srl32, A.srl32<11>(), GS_V4I_SRL32(a,11))
P(sra32, A.sra32<4>(), GS_V4I_SRA32(a,4))
P(srl16, A.srl16<5>(), GS_V4I_SRL16(a,5))
P(srl_, A.srl<8>(), GS_V4I_SRL(a,8))
P(xyxy, A.xyxy(), GS_V4I_SHUFFLE32(a,0x44))
P(rinter, A.rintersect(B), gs_v4i_rintersect(a,b))
P(runion_, A.runion(B), gs_v4i_runion(a,b))
P(insert32,A.insert32<1>(9), GS_V4I_INSERT32(a,9,1))
P(insert8, A.insert8<5>(9), GS_V4I_INSERT8(a,9,5))
P(zero, GSVector4i::zero(), gs_v4i_zero())
P(ones, GSVector4i::xffffffff(), gs_v4i_ones())