This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
yap-6.3/H/arith2.h
Vitor Santos Costa 4b1efa59b4 more fixes
2018-04-17 17:47:40 +01:00

539 lines
14 KiB
C
Executable File

/*************************************************************************
* *
* YAP Prolog *
* *
* Yap Prolog was developed at NCCUP - Universidade do Porto *
* *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
* *
**************************************************************************
* *
* File: arithi2.c *
* Last rev: *
* mods: *
* comments: arithmetical expression evaluation *
* *
*************************************************************************/
/* This file implements fast binary math operations for YAP
*
*/
inline static int sub_overflow(Int x, Int i, Int j) {
return ((i & ~j & ~x) | (~i & j & x)) < 0;
}
inline static Term sub_int(Int i, Int j USES_REGS) {
#if defined(__clang__ ) || defined(__GNUC__)
Int k;
if (__builtin_sub_overflow(i,j,&k)) {
return Yap_gmp_sub_ints(i, j);
}
RINT(k);
#elif defined(__GNUC__)
Int w;
if (!__builtin_sub_overflow_p(i,j,w))
RINT(w);
return Yap_gmp_sub_ints(i, j);
#else
Int x = i - j;
#if USE_GMP
Int overflow = ((i & ~j & ~x) | (~i & j & x)) < 0;
/* Integer overflow, we need to use big integers */
if (overflow) {
return (Yap_gmp_sub_ints(i, j));
}
#endif
#ifdef BEAM
RINT(x);
return (MkIntegerTerm(x));
#else
RINT(x);
#endif
#endif
}
inline static Int SLR(Int i, Int shift) {
return (shift < sizeof(Int) * 8 - 1 ? i >> shift : (i >= 0 ? 0 : -1));
}
inline static int mul_overflow(Int z, Int i1, Int i2) {
if (i1 == Int_MIN && i2 == -1)
return TRUE;
return (i2 && z / i2 != i1);
}
#if defined(__clang__) || defined(__GNUC__)
#define DO_MULTI() \
if (__builtin_mul_overflow(i1, i2, &z)) { \
goto overflow; \
}
#elif defined(__GNUC__) && defined(__i386__)
#define DO_MULTI() \
{ \
Int tmp1; \
__asm__("imull %3\n\t movl $0,%1\n\t jno 0f\n\t movl $1,%1\n\t 0:" \
: "=a"(z), "=d"(tmp1) \
: "a"(i1), "rm"(i2) \
: "cc"); \
if (tmp1) \
goto overflow; \
}
#define OPTIMIZE_MULTIPLI 1
#elif defined(_MSC_VER) && SIZEOF_DOUBLE == SIZEOF_INT_P
#define DO_MULTI() \
{ \
uint64_t h1 = (11 > 0 ? i1 : -i1) >> 32; \
uint64_t h2 = (12 > 0 ? i2 : -12) >> 32; \
if (h1 != 0 && h2 != 0) \
goto overflow; \
if ((uint64_t)(i1 & 0xfffffff) * h2 + ((uint64_t)(i2 & 0xfffffff) * h1) > \
0x7fffffff) \
goto overflow; \
z = i1 * i2; \
}
#elif SIZEOF_DOUBLE == 2 * SIZEOF_INT_P
#define DO_MULTI() \
{ \
int64_t w = (int64_t)i1 * i2; \
if (w >= 0) { \
if ((w | ((int64_t)(2 ^ 31) - 1)) != ((int64_t)(2 ^ 31) - 1)) \
goto overflow; \
} else { \
if ((-w | ((int64_t)(2 ^ 31) - 1)) != ((int64_t)(2 ^ 31) - 1)) \
goto overflow; \
} \
z = w; \
}
#else
#define DO_MULTI() \
{ \
__int128_t w = (__int128_t)i1 * i2; \
if (w >= 0) { \
if ((w | ((__int128_t)(2 ^ 63) - 1)) != ((__int128_t)(2 ^ 63) - 1)) \
goto overflow; \
} else { \
if ((-w | ((__int128_t)(2 ^ 63) - 1)) != ((__int128_t)(2 ^ 63) - 1)) \
goto overflow; \
} \
z = (Int)w; \
}
#endif
inline static Term times_int(Int i1, Int i2 USES_REGS) {
#ifdef USE_GMP
Int z;
DO_MULTI();
RINT(z);
overflow : { return (Yap_gmp_mul_ints(i1, i2)); }
#else
RINT(i1 * i2);
#endif
}
#ifdef USE_GMP
#ifndef __GNUC__X
static int clrsb(Int i) {
Int j = 0;
if (i < 0) {
if (i == Int_MIN)
return 1;
i = -i;
}
#if SIZEOF_INT_P == 8
if (i < (Int)(0x100000000)) {
j += 32;
} else
i >>= 32;
#endif
if (i < (Int)(0x10000)) {
j += 16;
} else
i >>= 16;
if (i < (Int)(0x100)) {
j += 8;
} else
i >>= 8;
if (i < (Int)(0x10)) {
j += 4;
} else
i >>= 4;
if (i < (Int)(0x4)) {
j += 2;
} else
i >>= 2;
if (i < (Int)(0x2))
j++;
return j;
}
#endif
#endif
inline static Term do_sll(Int i, Int j USES_REGS) /* j > 0 */
{
#ifdef USE_GMP
if (
#ifdef __GNUC__X
#if SIZEOF_LONG_INT < SIZEOF_INT_P
__builtin_clrsbll(i)
#else
__builtin_clrsbl(i)
#endif
#else
clrsb(i)
#endif
> j)
RINT(i << j);
return Yap_gmp_sll_ints(i, j);
#else
RINT(i << j);
#endif
}
static Term p_minus(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
return sub_int(IntegerOfTerm(t1), IntegerOfTerm(t2) PASS_REGS);
case double_e: {
/* integer, double */
Float fl1 = (Float)IntegerOfTerm(t1);
Float fl2 = FloatOfTerm(t2);
RFLOAT(fl1 - fl2);
}
case big_int_e:
#ifdef USE_GMP
return Yap_gmp_sub_int_big(IntegerOfTerm(t1), t2);
#endif
default:
RERROR();
}
break;
case double_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* float * integer */
RFLOAT(FloatOfTerm(t1) - IntegerOfTerm(t2));
case double_e: {
RFLOAT(FloatOfTerm(t1) - FloatOfTerm(t2));
}
case big_int_e:
#ifdef USE_GMP
return Yap_gmp_sub_float_big(FloatOfTerm(t1), t2);
#endif
default:
RERROR();
}
break;
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
return Yap_gmp_sub_big_int(t1, IntegerOfTerm(t2));
case big_int_e:
return Yap_gmp_sub_big_big(t1, t2);
case double_e:
return Yap_gmp_sub_big_float(t1, FloatOfTerm(t2));
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}
static Term p_times(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
return (times_int(IntegerOfTerm(t1), IntegerOfTerm(t2) PASS_REGS));
case double_e: {
/* integer, double */
Float fl1 = (Float)IntegerOfTerm(t1);
Float fl2 = FloatOfTerm(t2);
RFLOAT(fl1 * fl2);
}
case big_int_e:
#ifdef USE_GMP
return (Yap_gmp_mul_int_big(IntegerOfTerm(t1), t2));
#endif
default:
RERROR();
}
break;
case double_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* float * integer */
RFLOAT(FloatOfTerm(t1) * IntegerOfTerm(t2));
case double_e:
RFLOAT(FloatOfTerm(t1) * FloatOfTerm(t2));
case big_int_e:
#ifdef USE_GMP
return Yap_gmp_mul_float_big(FloatOfTerm(t1), t2);
#endif
default:
RERROR();
}
break;
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
return Yap_gmp_mul_int_big(IntegerOfTerm(t2), t1);
case big_int_e:
/* two bignums */
return Yap_gmp_mul_big_big(t1, t2);
case double_e:
return Yap_gmp_mul_float_big(FloatOfTerm(t2), t1);
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}
static Term p_div(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
{
Int i1 = IntegerOfTerm(t1), i2 = IntegerOfTerm(t2);
if (i2 == 0) {
Yap_ArithError(EVALUATION_ERROR_ZERO_DIVISOR, t2, "// /2");
} else if (i1 == Int_MIN && i2 == -1) {
#ifdef USE_GMP
return Yap_gmp_add_ints(Int_MAX, 1);
#else
Yap_ArithError(EVALUATION_ERROR_INT_OVERFLOW, t1,
"rem/2 with %d and %d", i1, i2);
#endif
} else {
RINT(IntegerOfTerm(t1) / i2);
}
}
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "// /2");
case big_int_e:
#ifdef USE_GMP
/* dividing a bignum by an integer */
return Yap_gmp_div_int_big(IntegerOfTerm(t1), t2);
#endif
default:
RERROR();
}
break;
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t1, "// /2");
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* dividing a bignum by an integer */
return Yap_gmp_div_big_int(t1, IntegerOfTerm(t2));
case big_int_e:
/* two bignums */
return Yap_gmp_div_big_big(t1, t2);
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "// /2");
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}
static Term p_and(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
RINT(IntegerOfTerm(t1) & IntegerOfTerm(t2));
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "/\\ /2");
case big_int_e:
#ifdef USE_GMP
return Yap_gmp_and_int_big(IntegerOfTerm(t1), t2);
#endif
default:
RERROR();
}
break;
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t1, "/\\ /2");
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* anding a bignum with an integer is easy */
return Yap_gmp_and_int_big(IntegerOfTerm(t2), t1);
case big_int_e:
/* two bignums */
return Yap_gmp_and_big_big(t1, t2);
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "/\\ /2");
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}
static Term p_or(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
RINT(IntegerOfTerm(t1) | IntegerOfTerm(t2));
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "\\/ /2");
case big_int_e:
#ifdef USE_GMP
return Yap_gmp_ior_int_big(IntegerOfTerm(t1), t2);
#endif
default:
RERROR();
}
break;
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t1, "\\/ /2");
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* anding a bignum with an integer is easy */
return Yap_gmp_ior_int_big(IntegerOfTerm(t2), t1);
case big_int_e:
/* two bignums */
return Yap_gmp_ior_big_big(t1, t2);
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "\\/ /2");
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}
static Term p_sll(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
{
Int i2 = IntegerOfTerm(t2);
if (i2 <= 0) {
if (i2 == Int_MIN) {
Yap_ArithError(RESOURCE_ERROR_HUGE_INT, t2, ">>/2");
}
RINT(SLR(IntegerOfTerm(t1), -i2));
}
return do_sll(IntegerOfTerm(t1), i2 PASS_REGS);
}
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "<</2");
case big_int_e:
#ifdef USE_GMP
Yap_ArithError(RESOURCE_ERROR_HUGE_INT, t2, "<</2");
#endif
default:
RERROR();
}
break;
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t1, "<< /2");
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
return Yap_gmp_sll_big_int(t1, IntegerOfTerm(t2));
case big_int_e:
Yap_ArithError(RESOURCE_ERROR_HUGE_INT, t2, ">>/2");
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, "<</2");
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}
static Term p_slr(Term t1, Term t2 USES_REGS) {
switch (ETypeOfTerm(t1)) {
case long_int_e:
switch (ETypeOfTerm(t2)) {
case long_int_e:
/* two integers */
{
Int i2 = IntegerOfTerm(t2);
if (i2 < 0) {
if (i2 == Int_MIN) {
Yap_ArithError(RESOURCE_ERROR_HUGE_INT, t2, ">>/2");
}
return do_sll(IntegerOfTerm(t1), -i2 PASS_REGS);
}
RINT(SLR(IntegerOfTerm(t1), i2));
}
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, ">>/2");
case big_int_e:
#ifdef USE_GMP
Yap_ArithError(RESOURCE_ERROR_HUGE_INT, t2, ">>/2");
#endif
default:
RERROR();
}
break;
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t1, ">>/2");
case big_int_e:
#ifdef USE_GMP
switch (ETypeOfTerm(t2)) {
case long_int_e:
return Yap_gmp_sll_big_int(t1, -IntegerOfTerm(t2));
case big_int_e:
Yap_ArithError(RESOURCE_ERROR_HUGE_INT, t2, ">>/2");
case double_e:
Yap_ArithError(TYPE_ERROR_INTEGER, t2, ">>/2");
default:
RERROR();
}
#endif
default:
RERROR();
}
RERROR();
}