Repository navigation
Conversation
Signed-off-by: 潘彦茜 <627875273@qq.com>
is this AVX2 specific? Sounds like this should be true on AVX-512 as well, right? |
|
Yes, I reproduced the signed-zero count issue on AVX-512 as well. I tested AVX2 on a Ryzen 7 5800H and AVX-512 under Intel SDE 9.58 using the Skylake-X model. In the AVX-512 run, the original code changed the zero counts for both float and double. With the patch, the same cases preserved the counts. |
| { | ||
| for (size_t size : {5, 17}) { | ||
| for (bool descending : {false, true}) { | ||
| std::vector<double> values(size, 0.0); |
There was a problem hiding this comment.
This problem exists for all 3 floating point types: _Float16, float and double. Can you extend these tests for these types too?
There was a problem hiding this comment.
Thanks for pointing this out. In 00d7c7c I extended the regression test to _Float16, float, and double in both sort directions. I added a 33-element case because the original lengths (5 and 17) passed for _Float16 even with the old code. Under Intel SDE on the Sapphire Rapids model, all three typed tests failed against the original library and passed with the fix.
Signed-off-by: LittlePyx <627875273@qq.com>
Include 33 elements so the half-precision case crosses an AVX-512 register boundary and reproduces the original failure. Signed-off-by: LittlePyx <627875273@qq.com>
| X86_SIMD_SORT_FINLINE void COEX(reg_t &a, reg_t &b) | ||
| { | ||
| if constexpr (descend) { ::COEX<vtype, reg_t>(b, a); } | ||
| if constexpr (!mirrored && xss::fp::is_floating_point_v<type_t>) { |
There was a problem hiding this comment.
Can we move this logic into the original COEX definition? You would have to pass mirrored template argument in there but that should be easy. It keeps tie-breaking logic in one place.
There was a problem hiding this comment.
Moved the floating-point tie handling into the original COEX in 23419ef. The comparator now forwards the policy and swaps the arguments for descending order. The signed-zero tests for _Float16, float, and double passed under Sapphire Rapids emulation.
| } | ||
| } | ||
|
|
||
| template <bool mirrored = false> |
There was a problem hiding this comment.
Suggest renaming mirrored to keep_lane_on_tie?
There was a problem hiding this comment.
Renamed it to keep_lane_on_tie in 23419ef. It defaults to true for independent registers, including pivot sampling. Only the reverse-and-merge and swap-and-merge calls pass false: those compare each pair in both lane orders before blending.
| double>; | ||
| TYPED_TEST_SUITE(FloatingPointQSort, FloatingPointTypes); | ||
|
|
||
| TYPED_TEST(FloatingPointQSort, preserves_signed_zeros) |
There was a problem hiding this comment.
We dont need a new class, you can use the existing simdsort class and run the test conditional on floating point:
| TYPED_TEST(FloatingPointQSort, preserves_signed_zeros) | |
| TYPED_TEST_P(simdsort, preserves_signed_zeros) | |
| { | |
| if constexpr (xss::fp::is_floating_point_v<TypeParam>) { |
There was a problem hiding this comment.
Thanks for the suggestion. In d9b4824 I moved the test into the existing simdsort suite, guarded it with if constexpr (xss::fp::is_floating_point_v<TypeParam>), and removed the separate fixture and type list. Under Sapphire Rapids emulation, all three floating-point cases still fail against the original library and pass with the fix.
Keep independent lanes on ties by default. Mirrored reverse and swap merges compare each pair in both orders and opt out before blending the results. Signed-off-by: LittlePyx <627875273@qq.com>
Signed-off-by: LittlePyx <627875273@qq.com>
On AVX2, sorting
{+0.0, +0.0, +0.0, +0.0, -0.0}withx86simdsort::qsortproduces four negative zeros in ascending order and none in descending order. Both results should contain exactly one negative zero. This addresses the x86 case reported in numpy/numpy#33286.When two lanes compare equal, x86 floating-point min and max both select their second operand. For independent registers, the sorting network now uses
min(a, b)andmax(b, a)so each input contributes once. A mirrored merge already compares each pair in both lane orders and takes one lane from each result, so it keeps the original operand order. The change applies only to native floating-point comparisons.Validation
qsortAPI in both directions at lengths 5 and 17. All four cases failed on the original code and passed with the fix. The full GoogleTest suite passed (394 tests, zero skips).int32values, median runtime differed from upstream by −0.63% to +0.97% across three input seeds and two library load orders.AI disclosure
Codex assisted with writing and testing the patch and drafting this PR description.