help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-smalltalk] Make check on FreeBSD 10.x - Intel


From: Holger Freyther
Subject: Re: [Help-smalltalk] Make check on FreeBSD 10.x - Intel
Date: Thu, 21 May 2015 13:25:56 +0800

> On 16 Apr 2015, at 01:14, Holger Freyther <address@hidden> wrote:


> Our mul_with_check doesn’t properly detect the overflow on a multiplication
> like (380536542838076625 * 576687883419648000) printNl. The result is
> negative. I don’t have a fix yet but that is easy now. We need to review the
> other routines with an overflow check too. We run the tests on travis-ci so
> I wonder how intmax_t is different between  BSD and GNU.

the compiler optimizes the overflow check away. Shall we move to use a
routine like __builtin_mul_overflow (if it is available)?

The below is taken from GNU Smalltalk to see what is happening. With clang
from apple (Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn))
generates different output depending on -O0 vs. -O3.

result / b == a seems to be considered always true by the compiler. I don’t know
the C specification but I assume that “a * b” is assumed to never overflow so 
that
the result of “a * b / b” is certainly “a”. 


#include <stdint.h>
#include <stdio.h>

#define PTR void*

#define ST_INT_SIZE        ((sizeof (PTR) * 8) - 2)
#define MAX_ST_INT         ((1L << ST_INT_SIZE) - 1)
#define MIN_ST_INT         ( ~MAX_ST_INT)
#define INT_OVERFLOW(i)    (((i) ^ ((i) << 1)) < 0)

intptr_t mul_with_check(intptr_t a, intptr_t b, int *overflow)
{
  intmax_t result = (intmax_t)a * b;
  *overflow = 0;

  /* We define the largest int type in stdintx.h, but we can
     only use it if it is two times the width of an intptr_t.  */

  if (sizeof (intmax_t) >= 2 * sizeof (intptr_t))
    {
      if (result > MAX_ST_INT || result < MIN_ST_INT)
        *overflow = 1;
      else
        return (intptr_t) (result);
    }

  /* This fallback method uses a division to do overflow check */
  else
    {
      if  ((((uintptr_t) (a | b)) < (1L << (ST_INT_SIZE / 2))
                  || b == 0
                  || result / b == a)
                 && !INT_OVERFLOW (result))
        return  (result);
      else
        *overflow = 1;
    }

  return (0);
}

int main(int argc, char **argv)
{
        int overflow;

        mul_with_check(380536542838076625, 576687883419648000, &overflow);
        printf("overflow.. %d\n", overflow);
}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]