Hello all,
Since GCC 7, a new function `__divmoddi4()` is added in libgcc. When GCC
performs division of two 64-bit integers on i686, a call to this
function is emitted, which could result in undefined references to this
function when we are building part of the CRT (winpthreads for example,
but I am not totally sure that our CRT is free of such issues). I
suggest we implement weak versions of these functions that are used only
by the CRT (strong ones from libgcc are used if whenever available).
Source attached. Any ideas on this?
--
Best regards,
LH_Mouse
#include <stdint.h>
static uint64_t udivmoddi4_unchecked(uint64_t dvnd, uint64_t dvsr, uint64_t *rem_ptr){
uint64_t quo, rem;
int lz_dvnd, lz_dvsr;
int scale, i;
uint64_t sub;
if(dvsr == 0){
/* Division by zero? */
__builtin_trap();
}
quo = 0;
rem = dvnd;
if(dvnd != 0){
lz_dvnd = __builtin_clzll(dvnd);
lz_dvsr = __builtin_clzll(dvsr);
scale = lz_dvsr - lz_dvnd;
if(scale < 0){
/* The divisor has fewer leading zeroes than the dividend.
This means the divisor is greater than the dividend.
There is nothing to do. */
} else {
/* Align the MSBs of the dividend and the divisor. */
sub = dvsr << scale;
i = 0;
for(;;){
/* Calculate the quotient bit by bit, as what we do in primary school. */
quo <<= 1;
if(rem >= sub){
quo += 1;
rem -= sub;
if(__builtin_expect(rem == 0, 0)){
/* Take the faster branch. */
quo <<= scale - i;
break;
}
}
if(i == scale){
break;
}
++i;
sub >>= 1;
}
}
}
*rem_ptr = rem;
return quo;
}
/* If we are linking against a real libgcc, use that implementation instead. */
#define ATTRIBUTE_WEAK __attribute__((__weak__))
ATTRIBUTE_WEAK uint64_t __udivmoddi4(uint64_t dvnd, uint64_t dvsr, uint64_t *rem_ptr){
uint64_t uquo, urem;
uquo = udivmoddi4_unchecked(dvnd, dvsr, &urem);
if(rem_ptr){
*rem_ptr = urem;
}
return uquo;
}
ATTRIBUTE_WEAK int64_t __divmoddi4(int64_t dvnd, int64_t dvsr, int64_t *rem_ptr){
int64_t quo, rem;
uint64_t uquo, urem;
if(dvnd >= 0){
if(dvsr >= 0){
uquo = udivmoddi4_unchecked((uint64_t)dvnd, (uint64_t)dvsr, &urem);
quo = (int64_t)uquo;
} else {
uquo = udivmoddi4_unchecked((uint64_t)dvnd, (uint64_t)-dvsr, &urem);
quo = -(int64_t)uquo;
}
rem = (int64_t)urem;
} else {
if(dvsr >= 0){
uquo = udivmoddi4_unchecked((uint64_t)-dvnd, (uint64_t)dvsr, &urem);
quo = -(int64_t)uquo;
} else {
uquo = udivmoddi4_unchecked((uint64_t)-dvnd, (uint64_t)-dvsr, &urem);
quo = (int64_t)uquo;
}
rem = -(int64_t)urem;
}
if(rem_ptr){
*rem_ptr = rem;
}
return quo;
}
#include <stdio.h>
int main(){
long long dvnd, dvsr, quo, rem;
dvnd = 1021;
dvsr = -25;
quo = __divmoddi4(dvnd, dvsr, &rem);
__mingw_printf("%lld / %lld = %lld ... %lld\n", dvnd, dvsr, quo, rem);
return 0;
}