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;
}
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to