Fix #3863: Correct _mm_shuffle_pd immediate decoding and add tests

- Fixed _mm_shuffle_pd to use 1-bit selector fields instead of 2-bit fields
- The intrinsic now correctly interprets the immediate as two 1-bit selectors
  (one for each output lane) instead of treating it like _mm_shuffle_ps
- Added LIT test covering all four shuffle masks: (0,0), (0,1), (1,0), (1,1)
- Added functional test to verify runtime correctness
- Updated copyright year to 2026

Co-authored-by: aneshlya <aneshlya@users.noreply.github.com>
This commit is contained in:
claude[bot]
2026-06-22 10:53:20 -07:00
committed by aneshlya
co-authored by aneshlya
parent f6fed70a43
commit 122ade2f96
3 changed files with 118 additions and 3 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2010-2025, Intel Corporation
Copyright (c) 2010-2026, Intel Corporation
SPDX-License-Identifier: BSD-3-Clause
*/
@@ -569,8 +569,8 @@ static inline unmasked uniform int _mm_movemask_pd(uniform __m128d _A) {
static inline unmasked uniform __m128d _mm_shuffle_pd(uniform __m128d _A, uniform __m128d _B, uniform unsigned int _I) {
uniform double<2> _R;
_R[0] = _A.m128d_f64[_I & 0x3];
_R[1] = _B.m128d_f64[(_I >> 2) & 0x3];
_R[0] = _A.m128d_f64[_I & 0x1];
_R[1] = _B.m128d_f64[(_I >> 1) & 0x1];
return *((uniform __m128d * uniform) & _R);
}
+58
View File
@@ -0,0 +1,58 @@
// Copyright (c) 2026, Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
// Test for _mm_shuffle_pd SSE2 intrinsic correctness (#3863)
// This runtime test verifies that _mm_shuffle_pd correctly uses 1-bit selector
// fields for each output lane, not 2-bit fields like _mm_shuffle_ps.
//
// RUN: %{ispc} %s -o %t.o
// RUN: %{cc} %S/../test_static.c %t.o -o %t.exe
// RUN: %t.exe
//
// REQUIRES: X86_ENABLED
#include "../test_static.isph"
#include "intrinsics/emmintrin.isph"
// Test all four possible shuffle masks: (0,0), (0,1), (1,0), (1,1)
// _MM_SHUFFLE2(x, y) produces ((x << 1) | y)
// Expected behavior:
// result[0] = A[y]
// result[1] = B[x]
task void f_v(uniform float RET[]) {
uniform __m128d a = _mm_setr_pd(1.0, 2.0);
uniform __m128d b = _mm_setr_pd(3.0, 4.0);
// Test 1: _MM_SHUFFLE2(0, 0) = 0: select A[0], B[0] -> {1.0, 3.0}
uniform __m128d r0 = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(0, 0));
uniform double result0[2];
*((uniform __m128d * uniform)result0) = r0;
RET[0] = (result0[0] == 1.0 && result0[1] == 3.0) ? 1.0 : 0.0;
// Test 2: _MM_SHUFFLE2(0, 1) = 1: select A[1], B[0] -> {2.0, 3.0}
uniform __m128d r1 = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(0, 1));
uniform double result1[2];
*((uniform __m128d * uniform)result1) = r1;
RET[1] = (result1[0] == 2.0 && result1[1] == 3.0) ? 1.0 : 0.0;
// Test 3: _MM_SHUFFLE2(1, 0) = 2: select A[0], B[1] -> {1.0, 4.0}
uniform __m128d r2 = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(1, 0));
uniform double result2[2];
*((uniform __m128d * uniform)result2) = r2;
RET[2] = (result2[0] == 1.0 && result2[1] == 4.0) ? 1.0 : 0.0;
// Test 4: _MM_SHUFFLE2(1, 1) = 3: select A[1], B[1] -> {2.0, 4.0}
uniform __m128d r3 = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(1, 1));
uniform double result3[2];
*((uniform __m128d * uniform)result3) = r3;
RET[3] = (result3[0] == 2.0 && result3[1] == 4.0) ? 1.0 : 0.0;
}
task void result(uniform float RET[]) {
// All tests should pass (return 1.0)
RET[0] = 1.0;
RET[1] = 1.0;
RET[2] = 1.0;
RET[3] = 1.0;
}
+57
View File
@@ -0,0 +1,57 @@
// Copyright (c) 2026, Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
// Test for _mm_shuffle_pd SSE2 intrinsic correctness (#3863)
// This test verifies that _mm_shuffle_pd correctly uses 1-bit selector fields
// for each output lane, not 2-bit fields like _mm_shuffle_ps.
//
// RUN: %{ispc} %s --target=sse2-i32x4 --emit-llvm-text --nostdlib -o - | FileCheck %s
// RUN: %{ispc} %s --target=sse4-i32x4 --emit-llvm-text --nostdlib -o - | FileCheck %s
// RUN: %{ispc} %s --target=avx1-i32x4 --emit-llvm-text --nostdlib -o - | FileCheck %s
// RUN: %{ispc} %s --target=avx2-i32x8 --emit-llvm-text --nostdlib -o - | FileCheck %s
// REQUIRES: X86_ENABLED
#include "intrinsics/emmintrin.isph"
// Test all four possible shuffle masks: (0,0), (0,1), (1,0), (1,1)
// _MM_SHUFFLE2(x, y) produces ((x << 1) | y)
// Expected behavior:
// result[0] = A[y]
// result[1] = B[x]
export void test_shuffle_pd_00() {
uniform __m128d a = _mm_setr_pd(1.0, 2.0);
uniform __m128d b = _mm_setr_pd(3.0, 4.0);
// _MM_SHUFFLE2(0, 0) = 0: select A[0], B[0] -> {1.0, 3.0}
uniform __m128d r = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(0, 0));
// CHECK-LABEL: @test_shuffle_pd_00
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 0, i32 2>
}
export void test_shuffle_pd_01() {
uniform __m128d a = _mm_setr_pd(1.0, 2.0);
uniform __m128d b = _mm_setr_pd(3.0, 4.0);
// _MM_SHUFFLE2(0, 1) = 1: select A[1], B[0] -> {2.0, 3.0}
uniform __m128d r = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(0, 1));
// CHECK-LABEL: @test_shuffle_pd_01
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 1, i32 2>
}
export void test_shuffle_pd_10() {
uniform __m128d a = _mm_setr_pd(1.0, 2.0);
uniform __m128d b = _mm_setr_pd(3.0, 4.0);
// _MM_SHUFFLE2(1, 0) = 2: select A[0], B[1] -> {1.0, 4.0}
uniform __m128d r = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(1, 0));
// CHECK-LABEL: @test_shuffle_pd_10
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 0, i32 3>
}
export void test_shuffle_pd_11() {
uniform __m128d a = _mm_setr_pd(1.0, 2.0);
uniform __m128d b = _mm_setr_pd(3.0, 4.0);
// _MM_SHUFFLE2(1, 1) = 3: select A[1], B[1] -> {2.0, 4.0}
uniform __m128d r = _mm_shuffle_pd(a, b, _MM_SHUFFLE2(1, 1));
// CHECK-LABEL: @test_shuffle_pd_11
// CHECK: shufflevector <2 x double> %{{.*}}, <2 x double> %{{.*}}, <2 x i32> <i32 1, i32 3>
}