Skip to content

sort()/rsort(): exact zend_sort + native zend_compare + int radix path (O(n²) → faster than Zend) - #37725

Merged
PurHur merged 1 commit into
masterfrom
claude/zend-sort
Oct 24, 2026
Merged

PurHur merged 1 commit into
masterfrom
claude/zend-sort

Conversation

@PurHur

@PurHur PurHur commented Oct 24, 2026

Copy link
Copy Markdown
Owner

See commit message for details. Gates: make check OK; parallel AOT differential sweep (386 cases ×3 runs) identical failing set to master (374 ok / 8 fail); new Zend-oracle cases added. Not run: compliance suites.

🤖 Generated with Claude Code

… int radix path

sort()/rsort() (SORT_REGULAR, SORT_STRING|SORT_FLAG_CASE) were a bubble sort
— O(n²), sorting 1.5M ints never finished — comparing strings with plain
strcmp (SORT_REGULAR compares numeric strings numerically) and mixed types
through a spaceship runtime that ranks every int below every string.

- ZendSortLlvm: php-src Zend/zend_sort.c (8.2) reproduced exactly —
  zend_insert_sort (networks for 2..5, guarded insertion with 2-step probe)
  and the median-of-3/5 hybrid quicksort, recursion as an explicit
  smaller-part-first stack — over an index permutation, plus
  RETURN_STABLE_SORT's tiebreak on original position. Same algorithm =>
  same output for non-transitive mixed comparisons and the same comparator
  call sequence. Comparator is its own internal function (a shared
  comparator block with a continuation switch crashed LLVM 9's RA).
- ZendCompareLlvm (__phpc_zend_compare): zend_compare for every pair of
  null/bool/int/float/string — compare_long_to_string,
  compare_double_to_string, zendi_smart_strcmp with php-src's overflow
  rules, ZEND_NORMALIZE_BOOL NaN behaviour; arrays/objects keep the old
  runtime.
- NumericStringLlvm: php-src's first-byte fast reject; NUMERIC_OFLOW_POS/
  NEG statuses (is_numeric_string's oflow) for smart_strcmp.
- Fast paths where zend_compare is a consistent total order, so any
  correct stable sort equals zend_sort's result exactly:
  all ints -> LSD radix sort (IntRadixSortLlvm, O(n), no comparator calls);
  all non-numeric strings -> stable merge sort (MergeSortLlvm) over
  contiguous {big-endian 8-byte prefix, index} keys, memcmp only on ties.

Lab timings (1.5M elements incl. array build, Zend 8.2 pinned image, best of
3, output identical): ints 0.147s vs Zend 0.283s; non-numeric strings 0.49s
vs 0.50s; benchmarks/v2 sort-mixed scaled 0.51s vs 0.69s (was: no result).

New differential cases (Zend oracle): sort_zend_parity (ints, strings,
numeric strings, 40-element non-transitive mixed arrays, sort/rsort, flag
case), pow_int_overflow_parity, numeric_string_arith_parity,
operand_typeerror_runtime_names — from the previous commits' work.

Gates: make check OK; parallel AOT differential sweep (386 cases, 3 runs):
374 ok / 8 fail, identical failing set to current master; sort_zend_parity
20/20 runs identical (an uninitialized parse box caused intermittent
corruption during development — scratch boxes are now IS_NULL-initialized).

Not converted yet: usort/uasort/uksort, asort/arsort, ksort/krsort,
array_multisort still bubble-sort (next).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PurHur
PurHur merged commit 1cfa76c into master Oct 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant