* [PATCH] H8/300: sim: Fix simulator hang caused by qsort on Windows/MinGW. @ 2026-08-22 11:02 Jan Dubiec 2026-08-23 20:50 ` Jan Dubiec 0 siblings, 1 reply; 4+ messages in thread From: Jan Dubiec @ 2026-08-22 11:02 UTC (permalink / raw) To: gdb-patches; +Cc: Jan Dubiec, Jeffrey Law See the comment below. I don't know why qsort behaves so strangely. It could be a bug, or simply a consequence of its being an unstable sort. Unfortunately, I don't have time to investigate the root cause. Signed-off-by: Jan Dubiec <jdx@o2.pl> --- sim/h8300/compile.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/sim/h8300/compile.c b/sim/h8300/compile.c index 06988095228..c08f7704ef3 100644 --- a/sim/h8300/compile.c +++ b/sim/h8300/compile.c @@ -1568,6 +1568,41 @@ store2 (SIM_DESC sd, ea_type *arg, int n) return store_1 (sd, arg, n, 1); } +#ifdef __MINGW32__ +/* On Windows/MinGW, qsort for some reason produces a "shuffled" opcode +table instead of a sorted one, causing the entire simulator to hang. + +This is a simple insertion sort implementation, but it has virtually +no impact on simulator performance. */ + +#define qsort opcode_insertion_sort + +static void +opcode_insertion_sort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) +{ + unsigned char *a = base; + struct h8_opcode tmp; + size_t i, j; + + if (nmemb < 2 || size == 0) + return; + + for (i = 1; i < nmemb; ++i) { + memcpy(&tmp, a + i * size, size); + + j = i; + while (j > 0 && compar(&tmp, a + (j - 1) * size) < 0) { + memcpy(a + j * size, a + (j - 1) * size, size); + --j; + } + + memcpy(a + j * size, &tmp, size); + } + +} +#endif /* #ifdef __MINGW32__ */ + /* Callback for qsort. We sort first based on availability (available instructions sort lower). When availability state is the same, then we use the first 4 bit nibble as a secondary -- 2.55.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] H8/300: sim: Fix simulator hang caused by qsort on Windows/MinGW. 2026-08-22 11:02 [PATCH] H8/300: sim: Fix simulator hang caused by qsort on Windows/MinGW Jan Dubiec @ 2026-08-23 20:50 ` Jan Dubiec 2026-08-27 15:19 ` Tom Tromey 0 siblings, 1 reply; 4+ messages in thread From: Jan Dubiec @ 2026-08-23 20:50 UTC (permalink / raw) To: gdb-patches; +Cc: Jeffrey Law [-- Attachment #1: Type: text/plain, Size: 1326 bytes --] On 22.08.2026 13:02, Jan Dubiec wrote: > See the comment below. I don't know why qsort behaves so strangely. It > could be a bug, or simply a consequence of its being an unstable sort. > Unfortunately, I don't have time to investigate the root cause. OK, I did some testing that shows that Microsoft's implementation of qsort() uses an unstable sorting algorithm, i.e. the order of equal elements may change. See the attached program. It compares insertion sort, which is a stable algorithm, with qsort(). The test fails on Windows and passes on Linux. The compiler is irrelevant — both Microsoft's compiler and GCC from MinGW produce the same result. It's worth noting that although the test passes on Linux, this is not guaranteed. According to AI, the qsort() implementation in glibc generally uses merge sort (stable), but may fall back to heapsort (unstable), depending on the size of the data. The glibc documentation seems to confirm this — it clearly states that "If two elements compare equal, their order after sorting is unpredictable": https://sourceware.org/glibc/manual/2.44/html_node/Array-Sort-Function.html So I think the best solution is to use a sorting algorithm known to be stable on every host, e.g. the insertion sort implementation from my previous message. What do you think? /J.D. [-- Attachment #2: qsort_test.c --] [-- Type: text/plain, Size: 2299 bytes --] /* * Compile commad: gcc -O2 -s -o qsort_test.exe qsort_test.c * or cl /O2 /Fe:qsort_test.exe qsort_test.c * Usage: qsort_test.exe [-d] * -d - dump tables to stdout */ #include <stdio.h> #include <string.h> #include <stdlib.h> #define TABLESIZE 5 typedef struct { int f1; int f2; int f3; } element_type; static int element_comparator (const void *el1, const void *el2) { element_type *p1 = (element_type*) el1; element_type *p2 = (element_type*) el2; /* Only f1 and f2 are used as sort keys; f3 is irrelevant. */ if (p1->f1 != p2->f1) return (p1->f1 > p2->f1) - (p1->f1 < p2->f1); if (p1->f2 != p2->f2) return (p1->f2 > p2->f2) - (p1->f2 < p2->f2); return 0; } static void insertion_sort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { unsigned char *a = base; unsigned char *tmp; size_t i, j; if (nmemb < 2 || size == 0) return; tmp = malloc(size); if (tmp == NULL) return; for (i = 1; i < nmemb; ++i) { memcpy(tmp, a + i * size, size); j = i; while (j > 0 && compar(tmp, a + (j - 1) * size) < 0) { memcpy(a + j * size, a + (j - 1) * size, size); --j; } memcpy(a + j * size, tmp, size); } free(tmp); } int main (int argc, char *argv[]) { element_type t0[TABLESIZE] = { {0, 0, 10}, {7, 7, 10}, {5, 5, 10}, {7, 7, 5}, {0, 0, 11} }; element_type t1[TABLESIZE], t2[TABLESIZE]; size_t i; memcpy(t1, t0, TABLESIZE*sizeof(element_type)); memcpy(t2, t0, TABLESIZE*sizeof(element_type)); insertion_sort(t1, TABLESIZE, sizeof(element_type), element_comparator); qsort(t2, TABLESIZE, sizeof(element_type), element_comparator); /* Dump tables to stdout */ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'd') { for (i = 0; i < TABLESIZE; ++i) { printf("t0[%zu]:\t%d\t%d\t%d\n", i, t0[i].f1, t0[i].f2, t0[i].f3); printf("t1[%zu]:\t%d\t%d\t%d\n", i, t1[i].f1, t1[i].f2, t1[i].f3); printf("t2[%zu]:\t%d\t%d\t%d\n\n", i, t2[i].f1, t2[i].f2, t2[i].f3); } } for (i = 0; i < TABLESIZE; ++i) { if ( memcmp(&t1[i], &t2[i], sizeof(element_type)) ) { printf("First fail at element %zu\n", i); printf("FAIL\n"); return -1; } } printf("PASS\n"); return 0; } ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] H8/300: sim: Fix simulator hang caused by qsort on Windows/MinGW. 2026-08-23 20:50 ` Jan Dubiec @ 2026-08-27 15:19 ` Tom Tromey 2026-08-30 1:40 ` Jan Dubiec 0 siblings, 1 reply; 4+ messages in thread From: Tom Tromey @ 2026-08-27 15:19 UTC (permalink / raw) To: Jan Dubiec; +Cc: gdb-patches, Jeffrey Law >>>>> "Jan" == Jan Dubiec <jdx@o2.pl> writes: Jan> So I think the best solution is to use a sorting algorithm known to be Jan> stable on every host, e.g. the insertion sort implementation from my Jan> previous message. Would it be possible to change the comparison function to be stable? I think it would be somewhat nicer not to have a separate sort implementation. If that's too hard, though, I think your approach is fine. Tom ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] H8/300: sim: Fix simulator hang caused by qsort on Windows/MinGW. 2026-08-27 15:19 ` Tom Tromey @ 2026-08-30 1:40 ` Jan Dubiec 0 siblings, 0 replies; 4+ messages in thread From: Jan Dubiec @ 2026-08-30 1:40 UTC (permalink / raw) To: Tom Tromey; +Cc: gdb-patches, Jeffrey Law [-- Attachment #1: Type: text/plain, Size: 1470 bytes --] On 27.08.2026 17:19, Tom Tromey wrote: >>>>>> "Jan" == Jan Dubiec <jdx@o2.pl> writes: > > Jan> So I think the best solution is to use a sorting algorithm known to be > Jan> stable on every host, e.g. the insertion sort implementation from my > Jan> previous message. > > Would it be possible to change the comparison function to be stable? It is impossible by definition, because stability is a property of the sorting algorithm, not the comparator. However, the comparator can be modified in such a way that an unstable sorting algorithm produces a “good enough” result. That said, the following simple patch is sufficient: /* Secondarily sort based on the first opcode nibble. */ - return p1->data.nib[0] - p2->data.nib[0]; + if (p1->data.nib[0] != p2->data.nib[0]) + return p1->data.nib[0] - p2->data.nib[0]; + + /* The 3rd sort key */ + return strcmp(p1->name, p2->name); However, I decided to take the longer route (see the attached patch) in order to make the opcode table as close as possible to the one that would be produced by a stable sorting algorithm. > I think it would be somewhat nicer not to have a separate sort > implementation. > > If that's too hard, though, I think your approach is fine. It wasn't difficult, but I’m still inclined to favor a stable, predictable sorting algorithm. That said, it’s not a big deal to me. Let me know what you think about it, and then I’ll post a new version of the patch. /J.D. [-- Attachment #2: instruction_comparator.patch --] [-- Type: text/plain, Size: 1868 bytes --] sim/h8300/compile.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/sim/h8300/compile.c b/sim/h8300/compile.c index 06988095228..3cca69730b0 100644 --- a/sim/h8300/compile.c +++ b/sim/h8300/compile.c @@ -1586,6 +1586,7 @@ instruction_comparator (const void *p1_, const void *p2_) { struct h8_opcode *p1 = (struct h8_opcode *)p1_; struct h8_opcode *p2 = (struct h8_opcode *)p2_; + int cmp; /* The 1st sort key is based on whether or not the instruction is even available. This reduces the @@ -1605,7 +1606,43 @@ instruction_comparator (const void *p1_, const void *p2_) return p2_available - p1_available; /* Secondarily sort based on the first opcode nibble. */ - return p1->data.nib[0] - p2->data.nib[0]; + if (p1->data.nib[0] != p2->data.nib[0]) + return p1->data.nib[0] - p2->data.nib[0]; + + /* The 3rd sort key */ + cmp = strcmp(p1->name, p2->name); + if (cmp) + { + /* Two different opcodes */ + size_t l1 = strlen(p1->name); + size_t l2 = strlen(p2->name); + ptrdiff_t i1 = strchr(p1->name, '.') - p1->name; + ptrdiff_t i2 = strchr(p2->name, '.') - p2->name; + char c1, c2; + + if ((l1 == l2) && (i1 == i2) && (i1 > 0)) + { + /* Check for different mnemonics, e.g. add.w vs. and.b */ + cmp = strncmp(p1->name, p2->name, i1); + if (cmp) + return cmp; + + /* At this point we expect only b, w or l suffix, + where b < w < l */ + c1 = p1->name[i1+1]; + c2 = p2->name[i2+1]; + if (c1 == 'b') + return -1; + else if (c1 == 'w') + return (c2 == 'b') ? 1 : -1; + else + return 1; + } + return cmp; + } + + /* The 4th sort key */ + return p1->how - p2->how; } ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-30 1:40 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-08-22 11:02 [PATCH] H8/300: sim: Fix simulator hang caused by qsort on Windows/MinGW Jan Dubiec 2026-08-23 20:50 ` Jan Dubiec 2026-08-27 15:19 ` Tom Tromey 2026-08-30 1:40 ` Jan Dubiec
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox