From 19032e296f0c1cf5f7003e262f17036092899d56 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 29 Sep 2026 13:59:07 +0100 Subject: [PATCH] IA32: Add __divmoddi4/__divdi3/__moddi3 gcc intrinsics replacements * When carrying out signed int64 division, GCC on IA32 automatically generates the intrinsics calls above because it expects linking with libgcc, which we obviously don't link against. * This results in undefined reference errors when linking code that carries out long divisions. * Fix this by adding these missing calls in ia32/math.c. * Note that, for the time being, and to avoid potential conflicts with existing workflows, we limit this to MinGW compiler usage, as this is where we are seeing the issue. But we can easily remove the MinGW guard if regular gcc users report that they need those as well. * Also, with respect to AI usage disclosure, the assembly code was generated by Claude. --- lib/ia32/math.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/lib/ia32/math.c b/lib/ia32/math.c index b6b2217..5771f09 100644 --- a/lib/ia32/math.c +++ b/lib/ia32/math.c @@ -180,3 +180,115 @@ DivU64x32 ( return Dividend; #endif } + +// gcc on IA32 emits these calls on i64 division, as it expects linking with libgcc +// NB: The assembly code was generated by Claude. +#if defined(__GNUC__) && defined(__MINGW32__) +__attribute__ ((__used__)) +long long +__divmoddi4( + long long dividend, + long long divisor, + long long *remainder + ) +{ + long long quot, rem; + int cnt; + + __asm__ ( + // eax/edx = |dividend| (becomes quotient), ecx/ebx = |divisor| + "movl %[n], %%eax \n\t" + "movl %H[n], %%edx \n\t" + "movl %[d], %%ecx \n\t" + "movl %H[d], %%ebx \n\t" + + "testl %%edx, %%edx \n\t" + "jns 1f \n\t" + "negl %%edx \n\t" + "negl %%eax \n\t" + "sbbl $0, %%edx \n\t" + "1: \n\t" + "testl %%ebx, %%ebx \n\t" + "jns 2f \n\t" + "negl %%ebx \n\t" + "negl %%ecx \n\t" + "sbbl $0, %%ebx \n\t" + "2: \n\t" + + // edi:esi = running remainder = 0 + "xorl %%esi, %%esi \n\t" + "xorl %%edi, %%edi \n\t" + "movl $64, %[c] \n\t" + + // shift-subtract loop + "3: \n\t" + "shll $1, %%eax \n\t" + "rcll $1, %%edx \n\t" + "rcll $1, %%esi \n\t" + "rcll $1, %%edi \n\t" + "cmpl %%ebx, %%edi \n\t" // remainder >= divisor? + "jb 4f \n\t" + "ja 5f \n\t" + "cmpl %%ecx, %%esi \n\t" + "jb 4f \n\t" + "5: \n\t" + "subl %%ecx, %%esi \n\t" + "sbbl %%ebx, %%edi \n\t" + "orl $1, %%eax \n\t" + "4: \n\t" + "decl %[c] \n\t" + "jnz 3b \n\t" + + // sign fixup: quotient negative if signs differ, + // remainder takes the sign of the dividend + "movl %H[n], %%ebx \n\t" + "movl %H[d], %%ecx \n\t" + "xorl %%ebx, %%ecx \n\t" + "jns 6f \n\t" + "negl %%edx \n\t" + "negl %%eax \n\t" + "sbbl $0, %%edx \n\t" + "6: \n\t" + "testl %%ebx, %%ebx \n\t" + "jns 7f \n\t" + "negl %%edi \n\t" + "negl %%esi \n\t" + "sbbl $0, %%edi \n\t" + "7: \n\t" + + // store results + "movl %%eax, %[q] \n\t" + "movl %%edx, %H[q] \n\t" + "movl %%esi, %[r] \n\t" + "movl %%edi, %H[r] \n\t" + : [q] "=&m" (quot), [r] "=&m" (rem), [c] "=&m" (cnt) + : [n] "m" (dividend), [d] "m" (divisor) + : "eax", "ebx", "ecx", "edx", "esi", "edi", "cc" + ); + + if (remainder) + *remainder = rem; + return quot; +} + +__attribute__ ((__used__)) +long long +__divdi3( + long long dividend, + long long divisor + ) +{ + return __divmoddi4(dividend, divisor, 0); +} + +long long +__moddi3( + long long dividend, + long long divisor + ) +{ + long long rem; + __divmoddi4(dividend, divisor, &rem); + return rem; +} +#endif \ No newline at end of file