GS/arm64: fix MSVC C2995 in the __builtin_shufflevector shim

MSVC's arm64 <arm64_neon.h> defines int32x4_t, float32x4_t and int16x8_t
as typedefs of the same __n128 type, so the shim's separate int32x4_t and
float32x4_t gsneon_shuffle overloads collapsed to an identical signature
and cl.exe rejected the second as a redefinition (error C2995) -- the
first time the shim actually reached the MSVC compile.

Drop the float32x4_t overload (and its gsneon_pickf helper). A single
4-lane/32-bit overload now serves both int and float shuffles: a lane
copy is bit-preserving, so the s32 lane ops reproduce the exact float
result, and float32x4_t is literally the same __n128 type on MSVC. The
8-lane/16-bit overload is distinguished by arity and is unaffected.

clang/clang-cl keep __builtin_shufflevector, so the whole shim block is
#if'd out there -- this only changes the pure-MSVC path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Brian Degenhardt
2026-07-12 17:53:27 -07:00
co-authored by Claude Opus 4.8
parent 5cbcadaa1e
commit 7c48e1f939
+8 -18
View File
@@ -25,14 +25,6 @@ static __forceinline int32_t gsneon_pick(int32x4_t a, int32x4_t b)
return vgetq_lane_s32(b, I - 4);
}
template <int I>
static __forceinline float32_t gsneon_pickf(float32x4_t a, float32x4_t b)
{
if constexpr (I < 4)
return vgetq_lane_f32(a, I);
else
return vgetq_lane_f32(b, I - 4);
}
template <int I>
static __forceinline int16_t gsneon_pick16(int16x8_t a, int16x8_t b)
{
if constexpr (I < 8)
@@ -41,6 +33,14 @@ static __forceinline int16_t gsneon_pick16(int16x8_t a, int16x8_t b)
return vgetq_lane_s16(b, I - 8);
}
// MSVC's arm64 <arm64_neon.h> makes int32x4_t, float32x4_t and int16x8_t all
// typedefs of the same underlying __n128, so we can't provide distinct
// int32x4_t/float32x4_t overloads -- they'd have an identical signature and cl
// rejects the second as a redefinition (C2995). Keep a single 4-lane (32-bit)
// overload and a single 8-lane (16-bit) overload, distinguished only by arity.
// A lane copy is bit-preserving, so routing float32x4_t shuffles (the three
// GSVector4 call sites) through the s32 lane ops reproduces the exact float
// result -- float32x4_t is the very same __n128 type here.
template <int I0, int I1, int I2, int I3>
static __forceinline int32x4_t gsneon_shuffle(int32x4_t a, int32x4_t b)
{
@@ -51,16 +51,6 @@ static __forceinline int32x4_t gsneon_shuffle(int32x4_t a, int32x4_t b)
r = vsetq_lane_s32(gsneon_pick<I3>(a, b), r, 3);
return r;
}
template <int I0, int I1, int I2, int I3>
static __forceinline float32x4_t gsneon_shuffle(float32x4_t a, float32x4_t b)
{
float32x4_t r = vdupq_n_f32(0.0f);
r = vsetq_lane_f32(gsneon_pickf<I0>(a, b), r, 0);
r = vsetq_lane_f32(gsneon_pickf<I1>(a, b), r, 1);
r = vsetq_lane_f32(gsneon_pickf<I2>(a, b), r, 2);
r = vsetq_lane_f32(gsneon_pickf<I3>(a, b), r, 3);
return r;
}
template <int I0, int I1, int I2, int I3, int I4, int I5, int I6, int I7>
static __forceinline int16x8_t gsneon_shuffle(int16x8_t a, int16x8_t b)
{