mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-23 02:00:35 +02:00
Byte-exact, all four functions, whole object. Source was a pure skeleton with no code; status MISSING work now NonMatching -> Matching. An iterative quicksort for 2-byte and 4-byte elements with a 30-deep bounds stack and a selection-sort cutoff at 8. The two code_* symbols are the selection sorts and take hi in EAX under VC7's custom convention for statics. The comparator takes values, not pointers, and the zero-extension in the target pins the 2-byte element type to word rather than short. Five source-shape findings, each read off the disassembly: - the swap loads both elements then stores to *best first, which is temp = *best; *best = *hi; *hi = temp - the mirror of the natural form. That alone made both selection sorts exact. - element_count and size are unsigned: the target uses jb, ja and shr where signed types give jl, jg and sar. - the source writes lo+1 < j, not the algebraically identical lo < j-1, which reverses the lea and cmp operands. - the larger-partition test compares raw byte differences. On word pointers every element-count form makes MSVC emit two sars or cancel them and mask, costing 16 bytes; only an explicit byte-basis comparison gives the plain dec. j-1-lo >= hi-i, j-lo > hi-i and the byte form are integer-identical and only the last matches. - depth = 0 is assigned before hi; the reverse order swaps the two stores. Both qsort bodies went exact from the same five fixes, which is good evidence the shapes are right rather than coincidental. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
314 lines
4.0 KiB
C
314 lines
4.0 KiB
C
/*
|
|
SORT.C
|
|
|
|
symbols in this file:
|
|
00080360 0060:
|
|
_code_00080360 (0000)
|
|
000803C0 0050:
|
|
_code_000803c0 (0000)
|
|
00080410 0150:
|
|
_qsort_2byte (0000)
|
|
00080560 0140:
|
|
_qsort_4byte (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
QSORT_STACK_SIZE = 30,
|
|
QSORT_CUTOFF = 8
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static void code_00080360(
|
|
word *hi,
|
|
word *lo,
|
|
boolean (*compare)(word, word));
|
|
static void code_000803c0(
|
|
long *hi,
|
|
long *lo,
|
|
boolean (*compare)(long, long));
|
|
|
|
void qsort_2byte(
|
|
word *elements,
|
|
unsigned long element_count,
|
|
boolean (*compare)(word, word));
|
|
void qsort_4byte(
|
|
long *elements,
|
|
unsigned long element_count,
|
|
boolean (*compare)(long, long));
|
|
|
|
/* ---------- globals */
|
|
|
|
/* ---------- public code */
|
|
|
|
void qsort_2byte(
|
|
word *elements,
|
|
unsigned long element_count,
|
|
boolean (*compare)(word, word))
|
|
{
|
|
word *lo_stack[QSORT_STACK_SIZE];
|
|
word *hi_stack[QSORT_STACK_SIZE];
|
|
word *lo, *hi, *i, *j, *mid;
|
|
long depth;
|
|
unsigned long size;
|
|
word temp;
|
|
|
|
if (element_count<2)
|
|
return;
|
|
|
|
lo = elements;
|
|
depth = 0;
|
|
hi = elements+element_count-1;
|
|
|
|
for (;;)
|
|
{
|
|
size = hi-lo+1;
|
|
if (size<=QSORT_CUTOFF)
|
|
{
|
|
code_00080360(hi, lo, compare);
|
|
}
|
|
else
|
|
{
|
|
mid = lo+(size>>1);
|
|
temp = *mid;
|
|
*mid = *lo;
|
|
*lo = temp;
|
|
|
|
i = lo;
|
|
j = hi+1;
|
|
|
|
for (;;)
|
|
{
|
|
do
|
|
{
|
|
i++;
|
|
}
|
|
while (i<=hi && !compare(*i, *lo));
|
|
|
|
do
|
|
{
|
|
j--;
|
|
}
|
|
while (j>lo && compare(*j, *lo));
|
|
|
|
if (j<i)
|
|
break;
|
|
|
|
temp = *i;
|
|
*i = *j;
|
|
*j = temp;
|
|
}
|
|
|
|
temp = *lo;
|
|
*lo = *j;
|
|
*j = temp;
|
|
|
|
if ((char *)j-(char *)lo-1>=(char *)hi-(char *)i)
|
|
{
|
|
if (lo+1<j)
|
|
{
|
|
lo_stack[depth] = lo;
|
|
hi_stack[depth] = j-1;
|
|
depth++;
|
|
}
|
|
if (i<hi)
|
|
{
|
|
lo = i;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i<hi)
|
|
{
|
|
lo_stack[depth] = i;
|
|
hi_stack[depth] = hi;
|
|
depth++;
|
|
}
|
|
if (lo+1<j)
|
|
{
|
|
hi = j-1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (--depth<0)
|
|
break;
|
|
|
|
lo = lo_stack[depth];
|
|
hi = hi_stack[depth];
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void qsort_4byte(
|
|
long *elements,
|
|
unsigned long element_count,
|
|
boolean (*compare)(long, long))
|
|
{
|
|
long *lo_stack[QSORT_STACK_SIZE];
|
|
long *hi_stack[QSORT_STACK_SIZE];
|
|
long *lo, *hi, *i, *j, *mid;
|
|
long depth;
|
|
unsigned long size;
|
|
long temp;
|
|
|
|
if (element_count<2)
|
|
return;
|
|
|
|
lo = elements;
|
|
depth = 0;
|
|
hi = elements+element_count-1;
|
|
|
|
for (;;)
|
|
{
|
|
size = hi-lo+1;
|
|
if (size<=QSORT_CUTOFF)
|
|
{
|
|
code_000803c0(hi, lo, compare);
|
|
}
|
|
else
|
|
{
|
|
mid = lo+(size>>1);
|
|
temp = *mid;
|
|
*mid = *lo;
|
|
*lo = temp;
|
|
|
|
i = lo;
|
|
j = hi+1;
|
|
|
|
for (;;)
|
|
{
|
|
do
|
|
{
|
|
i++;
|
|
}
|
|
while (i<=hi && !compare(*i, *lo));
|
|
|
|
do
|
|
{
|
|
j--;
|
|
}
|
|
while (j>lo && compare(*j, *lo));
|
|
|
|
if (j<i)
|
|
break;
|
|
|
|
temp = *i;
|
|
*i = *j;
|
|
*j = temp;
|
|
}
|
|
|
|
temp = *lo;
|
|
*lo = *j;
|
|
*j = temp;
|
|
|
|
if ((char *)j-(char *)lo-1>=(char *)hi-(char *)i)
|
|
{
|
|
if (lo+1<j)
|
|
{
|
|
lo_stack[depth] = lo;
|
|
hi_stack[depth] = j-1;
|
|
depth++;
|
|
}
|
|
if (i<hi)
|
|
{
|
|
lo = i;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (i<hi)
|
|
{
|
|
lo_stack[depth] = i;
|
|
hi_stack[depth] = hi;
|
|
depth++;
|
|
}
|
|
if (lo+1<j)
|
|
{
|
|
hi = j-1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (--depth<0)
|
|
break;
|
|
|
|
lo = lo_stack[depth];
|
|
hi = hi_stack[depth];
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|
|
|
|
static void code_00080360(
|
|
word *hi,
|
|
word *lo,
|
|
boolean (*compare)(word, word))
|
|
{
|
|
word *best, *scan;
|
|
word temp;
|
|
|
|
while (hi>lo)
|
|
{
|
|
best = lo;
|
|
for (scan = lo+1; scan<=hi; scan++)
|
|
{
|
|
if (compare(*scan, *best))
|
|
best = scan;
|
|
}
|
|
|
|
temp = *best;
|
|
*best = *hi;
|
|
*hi = temp;
|
|
|
|
hi--;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void code_000803c0(
|
|
long *hi,
|
|
long *lo,
|
|
boolean (*compare)(long, long))
|
|
{
|
|
long *best, *scan;
|
|
long temp;
|
|
|
|
while (hi>lo)
|
|
{
|
|
best = lo;
|
|
for (scan = lo+1; scan<=hi; scan++)
|
|
{
|
|
if (compare(*scan, *best))
|
|
best = scan;
|
|
}
|
|
|
|
temp = *best;
|
|
*best = *hi;
|
|
*hi = temp;
|
|
|
|
hi--;
|
|
}
|
|
|
|
return;
|
|
}
|