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