[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);
}
- Re: [Help-smalltalk] Make check on FreeBSD 10.x - Intel,
Holger Freyther <=