a2223c7302
doesn't depend on the 'comp' set. ok espie@ deraadt@
1463 lines
38 KiB
C
1463 lines
38 KiB
C
/*
|
|
* Integer arithmetic evaluation.
|
|
*
|
|
* (c) Thomas Pornin 2002
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 4. The name of the authors may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include "arith.h"
|
|
|
|
#define ARITH_OCTAL(x) ((x) >= '0' && (x) <= '7')
|
|
#define ARITH_OVAL(x) ((x) - '0')
|
|
#define ARITH_DECIM(x) ((x) >= '0' && (x) <= '9')
|
|
#define ARITH_DVAL(x) ((x) - '0')
|
|
#define ARITH_HEXAD(x) (ARITH_DECIM(x) \
|
|
|| (x) == 'a' || (x) == 'A' \
|
|
|| (x) == 'b' || (x) == 'B' \
|
|
|| (x) == 'c' || (x) == 'C' \
|
|
|| (x) == 'd' || (x) == 'D' \
|
|
|| (x) == 'e' || (x) == 'E' \
|
|
|| (x) == 'f' || (x) == 'F')
|
|
#define ARITH_HVAL(x) (ARITH_DECIM(x) ? ARITH_DVAL(x) \
|
|
: (x) == 'a' || (x) == 'A' ? 10 \
|
|
: (x) == 'b' || (x) == 'B' ? 11 \
|
|
: (x) == 'c' || (x) == 'C' ? 12 \
|
|
: (x) == 'd' || (x) == 'D' ? 13 \
|
|
: (x) == 'e' || (x) == 'E' ? 14 : 15)
|
|
|
|
#ifdef NATIVE_SIGNED
|
|
/* ====================================================================== */
|
|
/* Arithmetics with native types */
|
|
/* ====================================================================== */
|
|
|
|
/*
|
|
* The following properties are imposed by the C standard:
|
|
*
|
|
* -- Arithmetics on the unsigned type should never overflow; every
|
|
* result is reduced modulo some power of 2. The macro NATIVE_UNSIGNED_BITS
|
|
* should have been defined to that specific exponent.
|
|
*
|
|
* -- The signed type should use either two's complement, one's complement
|
|
* or a sign bit and a magnitude. There should be an integer N such that
|
|
* the maximum signed value is (2^N)-1 and the minimum signed value is
|
|
* either -(2^N) or -((2^N)-1). -(2^N) is possible only for two's complement.
|
|
*
|
|
* -- The maximum signed value is at most equal to the maximum unsigned
|
|
* value.
|
|
*
|
|
* -- Trap representations can only be:
|
|
* ** In two's complement, 1 as sign bit and 0 for all value bits.
|
|
* This can happen only if the minimum signed value is -((2^N)-1).
|
|
* ** In one's complement, all bits set to 1.
|
|
* ** In mantissa + sign, sign bit to 1 and 0 for all value bits.
|
|
* Unsigned values have no trap representation achievable with numerical
|
|
* operators. Only signed values can have such representations, with
|
|
* operators &, |, ^, ~, << and >>. If trap representations are possible,
|
|
* such occurrences are reported as warnings.
|
|
*
|
|
* -- The operators +, -, * and << may overflow or underflow on signed
|
|
* quantities, which is potentially an error. A warning is emitted.
|
|
*
|
|
* -- The operator >> yields an implementation-defined result on
|
|
* signed negative quantities. Usually, the sign is extended, but this
|
|
* is not guaranteed. A warning is emitted.
|
|
*
|
|
* -- The operators / and % used with a second operand of 0 cannot work.
|
|
* An error is emitted when such a call is performed. Furthermore, in
|
|
* two's complemement representation, with NATIVE_SIGNED_MIN == -(2^N)
|
|
* for some N, the expression `NATIVE_SIGNED_MIN / (-1)' yields an
|
|
* unrepresentable result, which is also an error.
|
|
*
|
|
*
|
|
* For the value checks, we need to consider those different cases. So
|
|
* we calculate the following macros:
|
|
* -- TWOS_COMPLEMENT: is 1 if representation is two's complement, 0
|
|
* otherwise.
|
|
* -- ONES_COMPLEMENT: is 1 if representation is one's complement, 0
|
|
* otherwise.
|
|
* -- SIGNED_IS_BIGGER: 1 if the maximum signed value is equal to the
|
|
* maximum unsigned value, 0 otherwise. NATIVE_SIGNED_MAX cannot
|
|
* exceed the maximum unsigned value. If SIGNED_IS_BIGGER is 0, then
|
|
* the maximum unsigned value is strictly superior to twice the
|
|
* value of NATIVE_SIGNED_MAX (e.g. 65535 to 32767).
|
|
* -- TRAP_REPRESENTATION: 1 if a trap representation is possible, 0
|
|
* otherwise. The only way trap representations are guaranteed
|
|
* impossible is when TWOS_COMPLEMENT is set, and NATIVE_SIGNED_MIN
|
|
* is equal to -NATIVE_SIGNED_MAX - 1.
|
|
*
|
|
* Those macros are calculated by some preprocessor directives. This
|
|
* supposes that the implementation conforms to C99. Rules on preprocessing
|
|
* were quite looser in C90, and it could be that an old compiler, used
|
|
* for a cross-compiling task, does not get those right. Therefore, if
|
|
* ARCH_DEFINED is defined prior to the inclusion of this file, those
|
|
* four macros are supposed to be already defined. Otherwise they are
|
|
* (re)defined. The macro ARCH_TRAP_DEFINED has the same meaning, but
|
|
* is limited to the TRAP_REPRESENTATION macro (if ARCH_TRAP_DEFINED is
|
|
* defined, the macro TRAP_REPRESENTATION is supposed to be already
|
|
* defined; the three other macros are recalculated).
|
|
*
|
|
*
|
|
* To sum up:
|
|
* -- Whenever a division operator (/ or %) is invoked and would yield
|
|
* an unrepresentable result, ARITH_ERROR() is invoked.
|
|
* -- With ARITHMETIC_CHECKS undefined, ARITH_WARNING() is never invoked.
|
|
* -- With ARITHMETIC_CHECKS defined:
|
|
* ** If ARCH_DEFINED is defined, the including context must provide
|
|
* the macros TWOS_COMPLEMENT, ONES_COMPLEMENT, SIGNED_IS_BIGGER
|
|
* and TRAP_REPRESENTATION.
|
|
* ** Otherwise, if ARCH_TRAP_DEFINED is defined, the including context
|
|
* must provide the macro TRAP_REPRESENTATION.
|
|
* The code then detects all operator invokations that would yield an
|
|
* overflow, underflow, trap representation, or any implementation
|
|
* defined result or undefined behaviour. The macro ARITH_WARNING() is
|
|
* invoked for each detection.
|
|
* -- Trap representation detection code supposes that the operands are
|
|
* _not_ trap representation.
|
|
*/
|
|
|
|
#ifndef ARCH_DEFINED
|
|
|
|
#undef TWOS_COMPLEMENT
|
|
#undef ONES_COMPLEMENT
|
|
#undef SIGNED_IS_BIGGER
|
|
#ifndef ARCH_TRAP_DEFINED
|
|
#undef TRAP_REPRESENTATION
|
|
#endif
|
|
|
|
#if (-1) & 3 == 3
|
|
/*
|
|
* Two's complement.
|
|
*/
|
|
#define TWOS_COMPLEMENT 1
|
|
#define ONES_COMPLEMENT 0
|
|
#ifndef ARCH_TRAP_DEFINED
|
|
#if NATIVE_SIGNED_MIN < -NATIVE_SIGNED_MAX
|
|
#define TRAP_REPRESENTATION 0
|
|
#else
|
|
#define TRAP_REPRESENTATION 1
|
|
#endif
|
|
#endif
|
|
|
|
#elif (-1) & 3 == 2
|
|
/*
|
|
* One's complement.
|
|
*/
|
|
#define TWOS_COMPLEMENT 0
|
|
#define ONES_COMPLEMENT 1
|
|
#ifndef ARCH_TRAP_DEFINED
|
|
#define TRAP_REPRESENTATION 1
|
|
#endif
|
|
|
|
#else
|
|
/*
|
|
* Mantissa + sign.
|
|
*/
|
|
#define TWOS_COMPLEMENT 0
|
|
#define ONES_COMPLEMENT 0
|
|
#ifndef ARCH_TRAP_DEFINED
|
|
#define TRAP_REPRESENTATION 1
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Maximum native unsigned value. The first macro is for #if directives,
|
|
* the second macro is for use as constant expression in C code.
|
|
*/
|
|
#define NATIVE_UNSIGNED_MAX ((((1U << (NATIVE_UNSIGNED_BITS - 1)) - 1U) \
|
|
<< 1) + 1U)
|
|
#define NATIVE_UNSIGNED_MAX_A (((((arith_u)1 << (NATIVE_UNSIGNED_BITS - 1)) \
|
|
- (arith_u)1) << 1) + (arith_u)1)
|
|
|
|
#if NATIVE_SIGNED_MAX == NATIVE_UNSIGNED_MAX
|
|
#define SIGNED_IS_BIGGER 1
|
|
#else
|
|
#define SIGNED_IS_BIGGER 0
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#undef NEGATIVE_IS_BIGGER
|
|
#if NATIVE_SIGNED_MIN < -NATIVE_SIGNED_MAX
|
|
#define NEGATIVE_IS_BIGGER 1
|
|
#else
|
|
#define NEGATIVE_IS_BIGGER 0
|
|
#endif
|
|
|
|
/* sanity check: we cannot have a trap representation if we have
|
|
two's complement with NATIVE_SIGNED_MIN < -NATIVE_SIGNED_MAX */
|
|
#if TRAP_REPRESENTATION && NEGATIVE_IS_BIGGER
|
|
#error Impossible to get trap representations.
|
|
#endif
|
|
|
|
/* operations on the unsigned type */
|
|
|
|
ARITH_DECL_MONO_S_U(to_u) { return (arith_u)x; }
|
|
ARITH_DECL_MONO_I_U(fromint) { return (arith_u)x; }
|
|
ARITH_DECL_MONO_L_U(fromulong) { return (arith_u)x; }
|
|
|
|
ARITH_DECL_MONO_U_I(toint)
|
|
{
|
|
#if NATIVE_UNSIGNED_MAX > INT_MAX
|
|
if (x > (arith_u)INT_MAX) return INT_MAX;
|
|
#endif
|
|
return (int)x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_L(toulong)
|
|
{
|
|
#if NATIVE_UNSIGNED_MAX > LONG_MAX
|
|
if (x > (arith_u)LONG_MAX) return LONG_MAX;
|
|
#endif
|
|
return (long)x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_U(neg) { return -x; }
|
|
ARITH_DECL_MONO_U_U(not) { return ~x; }
|
|
ARITH_DECL_MONO_U_I(lnot) { return !x; }
|
|
ARITH_DECL_MONO_U_I(lval) { return x != 0; }
|
|
|
|
ARITH_DECL_BI_UU_U(plus) { return x + y; }
|
|
ARITH_DECL_BI_UU_U(minus) { return x - y; }
|
|
ARITH_DECL_BI_UU_I(lt) { return x < y; }
|
|
ARITH_DECL_BI_UU_I(leq) { return x <= y; }
|
|
ARITH_DECL_BI_UU_I(gt) { return x > y; }
|
|
ARITH_DECL_BI_UU_I(geq) { return x >= y; }
|
|
ARITH_DECL_BI_UU_I(same) { return x == y; }
|
|
ARITH_DECL_BI_UU_I(neq) { return x != y; }
|
|
ARITH_DECL_BI_UU_U(and) { return x & y; }
|
|
ARITH_DECL_BI_UU_U(xor) { return x ^ y; }
|
|
ARITH_DECL_BI_UU_U(or) { return x | y; }
|
|
ARITH_DECL_BI_UU_U(star) { return x * y; }
|
|
|
|
ARITH_DECL_BI_UI_U(lsh)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (y >= NATIVE_UNSIGNED_BITS)
|
|
ARITH_WARNING(ARITH_EXCEP_LSH_W);
|
|
else if (y < 0)
|
|
ARITH_WARNING(ARITH_EXCEP_LSH_C);
|
|
#endif
|
|
return x << y;
|
|
}
|
|
|
|
ARITH_DECL_BI_UI_U(rsh)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (y >= NATIVE_UNSIGNED_BITS)
|
|
ARITH_WARNING(ARITH_EXCEP_RSH_W);
|
|
else if (y < 0)
|
|
ARITH_WARNING(ARITH_EXCEP_RSH_C);
|
|
#endif
|
|
return x >> y;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(slash)
|
|
{
|
|
if (y == 0) ARITH_ERROR(ARITH_EXCEP_SLASH_D);
|
|
return x / y;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(pct)
|
|
{
|
|
if (y == 0) ARITH_ERROR(ARITH_EXCEP_PCT_D);
|
|
return x % y;
|
|
}
|
|
|
|
/* operations on the signed type */
|
|
|
|
ARITH_DECL_MONO_U_S(to_s)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
#if !SIGNED_IS_BIGGER
|
|
if (x > (arith_u)NATIVE_SIGNED_MAX)
|
|
ARITH_WARNING(ARITH_EXCEP_CONV_O);
|
|
#endif
|
|
#endif
|
|
return (arith_s)x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_I_S(fromint) { return (arith_s)x; }
|
|
ARITH_DECL_MONO_L_S(fromlong) { return (arith_s)x; }
|
|
|
|
ARITH_DECL_MONO_S_I(toint)
|
|
{
|
|
#if NATIVE_SIGNED_MIN < INT_MIN
|
|
if (x < (arith_s)INT_MIN) return INT_MIN;
|
|
#endif
|
|
#if NATIVE_SIGNED_MAX > INT_MAX
|
|
if (x > (arith_s)INT_MAX) return INT_MAX;
|
|
#endif
|
|
return (int)x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_L(tolong)
|
|
{
|
|
#if NATIVE_SIGNED_MIN < LONG_MIN
|
|
if (x < (arith_s)LONG_MIN) return LONG_MIN;
|
|
#endif
|
|
#if NATIVE_SIGNED_MAX > LONG_MAX
|
|
if (x > (arith_s)LONG_MAX) return LONG_MAX;
|
|
#endif
|
|
return (long)x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_S(neg)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
#if NEGATIVE_IS_BIGGER
|
|
if (x == NATIVE_SIGNED_MIN)
|
|
ARITH_WARNING(ARITH_EXCEP_NEG_O);
|
|
#endif
|
|
#endif
|
|
return -x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_S(not)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
#if TRAP_REPRESENTATION
|
|
if (
|
|
#if TWOS_COMPLEMENT
|
|
(x == NATIVE_SIGNED_MAX)
|
|
#elif ONES_COMPLEMENT
|
|
(x == 0)
|
|
#else
|
|
(x == NATIVE_SIGNED_MAX)
|
|
#endif
|
|
) ARITH_WARNING(ARITH_EXCEP_NOT_T);
|
|
#endif
|
|
#endif
|
|
return ~x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_I(lnot) { return !x; }
|
|
ARITH_DECL_MONO_S_I(lval) { return x != 0; }
|
|
|
|
/*
|
|
* Addition of signed values:
|
|
* -- overflows occur only when both operands are strictly positive
|
|
* -- underflows occur only when both operands are strictly negative
|
|
* -- overflow check (both operands > 0):
|
|
* ** if SIGNED_IS_BIGGER == 1, overflows are kept as such in the
|
|
* unsigned world (if the signed addition overflows, so does the
|
|
* unsigned, and vice versa)
|
|
* ** if SIGNED_IS_BIGGER == 0, no overflow can happen in the unsigned
|
|
* world
|
|
* -- underflow check (both operands < 0):
|
|
* ** if NEGATIVE_IS_BIGGER == 1 (must be two's complement)
|
|
* ++ we have a guaranteed underflow if one of the operand is equal
|
|
* to NATIVE_SIGNED_MIN; otherwise, -x and -y are valid integers,
|
|
* and we cast them into the unsigned world
|
|
* ++ if SIGNED_IS_BIGGER == 1, underflows become unsigned overflows
|
|
* with a non-zero result
|
|
* ++ if SIGNED_IS_BIGGER == 0, no overflow happens in the unsigned
|
|
* world; we use the fact that -NATIVE_SIGNED_MIN is then
|
|
* exaxctly 1 more than NATIVE_SIGNED_MAX
|
|
* ** if NEGATIVE_IS_BIGGER == 0, underflow check is identical to
|
|
* overflow check on (signed) -x and -y.
|
|
*/
|
|
ARITH_DECL_BI_SS_S(plus)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x > 0 && y > 0 && (
|
|
#if SIGNED_IS_BIGGER
|
|
((arith_u)((arith_u)x + (arith_u)y) < (arith_u)x)
|
|
#else
|
|
(((arith_u)x + (arith_u)y) > (arith_u)NATIVE_SIGNED_MAX)
|
|
#endif
|
|
)) ARITH_WARNING(ARITH_EXCEP_PLUS_O);
|
|
else if (x < 0 && y < 0 && (
|
|
#if NEGATIVE_IS_BIGGER
|
|
(x == NATIVE_SIGNED_MIN || y == NATIVE_SIGNED_MIN) ||
|
|
#if SIGNED_IS_BIGGER
|
|
(((arith_u)(-x) + (arith_u)(-y) != 0)
|
|
&& (arith_u)((arith_u)(-x) + (arith_u)(-y))
|
|
< (arith_u)(-x))
|
|
#else
|
|
(((arith_u)(-x) + (arith_u)(-y))
|
|
> ((arith_u)1 + (arith_u)NATIVE_SIGNED_MAX))
|
|
#endif
|
|
#else
|
|
#if SIGNED_IS_BIGGER
|
|
((arith_u)((arith_u)(-x) + (arith_u)(-y)) < (arith_u)(-x))
|
|
#else
|
|
(((arith_u)(-x) + (arith_u)(-y))
|
|
> (arith_u)NATIVE_SIGNED_MAX)
|
|
#endif
|
|
#endif
|
|
)) ARITH_WARNING(ARITH_EXCEP_PLUS_U);
|
|
#endif
|
|
return x + y;
|
|
}
|
|
|
|
/*
|
|
* Subtraction of signed values:
|
|
* -- overflow: only if x > 0 and y < 0
|
|
* ** if NEGATIVE_IS_BIGGER == 1 (must be two's complement) and
|
|
* y == NATIVE_SIGNED_MIN then overflow
|
|
* ** otherwise, cast x and -y to unsigned, then add and check
|
|
* for overflows
|
|
* -- underflow: only if x < 0 and y > 0
|
|
* ** if NEGATIVE_IS_BIGGER == 1 (must be two's complement):
|
|
* ++ if x == NATIVE_SIGNED_MIN then underflow
|
|
* ++ cast -x and y to unsigned, then add. If SIGNED_IS_BIGGER == 0,
|
|
* just check. Otherwise, check for overflow with non-zero result.
|
|
* ** if NEGATIVE_IS_BIGGER == 0: cast -x and y to unsigned, then
|
|
* add. Overflow check as in addition.
|
|
*/
|
|
ARITH_DECL_BI_SS_S(minus)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x > 0 && y < 0 && (
|
|
#if NEGATIVE_IS_BIGGER
|
|
(y == NATIVE_SIGNED_MIN) ||
|
|
#endif
|
|
#if SIGNED_IS_BIGGER
|
|
((arith_u)((arith_u)x + (arith_u)(-y)) < (arith_u)x)
|
|
#else
|
|
(((arith_u)x + (arith_u)(-y)) > (arith_u)NATIVE_SIGNED_MAX)
|
|
#endif
|
|
)) ARITH_WARNING(ARITH_EXCEP_MINUS_O);
|
|
else if (x < 0 && y > 0 && (
|
|
#if NEGATIVE_IS_BIGGER
|
|
(x == NATIVE_SIGNED_MIN) ||
|
|
#if SIGNED_IS_BIGGER
|
|
((((arith_u)(-x) + (arith_u)y) != 0) &&
|
|
((arith_u)((arith_u)(-x) + (arith_u)y) < (arith_u)(-x)))
|
|
#else
|
|
(((arith_u)(-x) + (arith_u)y) >
|
|
((arith_u)1 + (arith_u)NATIVE_SIGNED_MAX))
|
|
#endif
|
|
#else
|
|
#if SIGNED_IS_BIGGER
|
|
((arith_u)((arith_u)(-x) + (arith_u)y) < (arith_u)(-x))
|
|
#else
|
|
(((arith_u)(-x) + (arith_u)y) > (arith_u)NATIVE_SIGNED_MAX)
|
|
#endif
|
|
#endif
|
|
)) ARITH_WARNING(ARITH_EXCEP_MINUS_U);
|
|
#endif
|
|
return x - y;
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(lt) { return x < y; }
|
|
ARITH_DECL_BI_SS_I(leq) { return x <= y; }
|
|
ARITH_DECL_BI_SS_I(gt) { return x > y; }
|
|
ARITH_DECL_BI_SS_I(geq) { return x >= y; }
|
|
ARITH_DECL_BI_SS_I(same) { return x == y; }
|
|
ARITH_DECL_BI_SS_I(neq) { return x != y; }
|
|
|
|
/*
|
|
* Provided neither x nor y is a trap representation:
|
|
* -- one's complement: impossible to get a trap representation
|
|
* -- two's complement and sign + mantissa: trap representation if and
|
|
* only if x and y are strictly negative and (-x) & (-y) == 0
|
|
* (in two's complement, -x is safe because overflow would occur only
|
|
* if x was already a trap representation).
|
|
*/
|
|
ARITH_DECL_BI_SS_S(and)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
#if TRAP_REPRESENTATION && !ONES_COMPLEMENT
|
|
if (x < 0 && y < 0 && ((-x) & (-y)) == 0)
|
|
ARITH_WARNING(ARITH_EXCEP_AND_T);
|
|
#endif
|
|
#endif
|
|
return x & y;
|
|
}
|
|
|
|
/*
|
|
* Provided neither x nor y is a trap representation:
|
|
* -- two's complement: trap if and only if x != NATIVE_SIGNED_MAX && ~x == y
|
|
* -- one's complement: trap if and only if x != 0 && ~x == y
|
|
* -- mantissa + sign: trap if and only if x != 0 && -x == y
|
|
*/
|
|
ARITH_DECL_BI_SS_S(xor)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
#if TRAP_REPRESENTATION
|
|
if (
|
|
#if TWOS_COMPLEMENT
|
|
(x != NATIVE_SIGNED_MAX && ~x == y)
|
|
#elif ONES_COMPLEMENT
|
|
(x != 0 && ~x == y)
|
|
#else
|
|
(x != 0 && -x == y)
|
|
#endif
|
|
) ARITH_WARNING(ARITH_EXCEP_XOR_T);
|
|
#endif
|
|
#endif
|
|
return x ^ y;
|
|
}
|
|
|
|
/*
|
|
* Provided neither x nor y is a trap representation:
|
|
* -- two's complement: impossible to trap
|
|
* -- one's complement: trap if and only if x != 0 && y != 0 && (~x & ~y) == 0
|
|
* -- mantissa + sign: impossible to trap
|
|
*/
|
|
ARITH_DECL_BI_SS_S(or)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
#if TRAP_REPRESENTATION
|
|
#if ONES_COMPLEMENT
|
|
if (x != 0 && y != 0 && (~x & ~y) == 0)
|
|
ARITH_WARNING(ARITH_EXCEP_OR_T);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
return x | y;
|
|
}
|
|
|
|
/*
|
|
* Left-shifting by a negative or greater than type width count is
|
|
* forbidden. Left-shifting a negative value is forbidden (underflow).
|
|
* Left-shifting a positive value can trigger an overflow. We check it
|
|
* by casting into the unsigned world and simulating a truncation.
|
|
*
|
|
* If SIGNED_IS_BIGGER is set, then the signed type width is 1 more
|
|
* than the unsigned type width (the sign bit is included in the width);
|
|
* otherwise, if W is the signed type width, 1U << (W-1) is equal to
|
|
* NATIVE_SIGNED_MAX + 1.
|
|
*/
|
|
ARITH_DECL_BI_SI_S(lsh)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (y < 0) ARITH_WARNING(ARITH_EXCEP_LSH_C);
|
|
else if (
|
|
#if SIGNED_IS_BIGGER
|
|
y > NATIVE_UNSIGNED_BITS
|
|
#else
|
|
y >= NATIVE_UNSIGNED_BITS
|
|
|| (y > 0 && (((arith_u)1 << (y - 1))
|
|
> (arith_u)NATIVE_SIGNED_MAX))
|
|
#endif
|
|
) ARITH_WARNING(ARITH_EXCEP_LSH_W);
|
|
else if (x < 0) ARITH_WARNING(ARITH_EXCEP_LSH_U);
|
|
else if (x > 0 && ((((arith_u)x << y) & NATIVE_SIGNED_MAX) >> y)
|
|
!= (arith_u)x) ARITH_WARNING(ARITH_EXCEP_LSH_O);
|
|
#endif
|
|
return x << y;
|
|
}
|
|
|
|
/*
|
|
* Right-shifting is handled as left-shifting, except that the problem
|
|
* is somehow simpler: there is no possible overflow or underflow. Only
|
|
* right-shifting a negative value yields an implementation defined
|
|
* result (_not_ an undefined behaviour).
|
|
*/
|
|
ARITH_DECL_BI_SI_S(rsh)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (y < 0) ARITH_WARNING(ARITH_EXCEP_RSH_C);
|
|
else if (
|
|
#if SIGNED_IS_BIGGER
|
|
y > NATIVE_UNSIGNED_BITS
|
|
#else
|
|
y >= NATIVE_UNSIGNED_BITS
|
|
|| (y > 0 && (((arith_u)1 << (y - 1))
|
|
> (arith_u)NATIVE_SIGNED_MAX))
|
|
#endif
|
|
) ARITH_WARNING(ARITH_EXCEP_RSH_W);
|
|
else if (x < 0) ARITH_WARNING(ARITH_EXCEP_RSH_N);
|
|
#endif
|
|
return x >> y;
|
|
}
|
|
|
|
/*
|
|
* Overflow can happen only if both operands have the same sign.
|
|
* Underflow can happen only if both operands have opposite signs.
|
|
*
|
|
* Overflow checking: this is done quite inefficiently by performing
|
|
* a division on the result and check if it matches the initial operand.
|
|
*/
|
|
ARITH_DECL_BI_SS_S(star)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x == 0 || y == 0) return 0;
|
|
if (x > 0 && y > 0) {
|
|
if ((((arith_u)x * (arith_u)y) & (arith_u)NATIVE_SIGNED_MAX)
|
|
/ (arith_u)y != (arith_u)x)
|
|
ARITH_WARNING(ARITH_EXCEP_STAR_O);
|
|
} else if (x < 0 && y < 0) {
|
|
if (
|
|
#if NEGATIVE_IS_BIGGER
|
|
(x == NATIVE_SIGNED_MIN || y == NATIVE_SIGNED_MIN) ||
|
|
#endif
|
|
(((arith_u)(-x) * (arith_u)(-y))
|
|
& (arith_u)NATIVE_SIGNED_MAX) / (arith_u)(-y)
|
|
!= (arith_u)(-x))
|
|
ARITH_WARNING(ARITH_EXCEP_STAR_O);
|
|
} else if (x > 0 && y < 0) {
|
|
if ((arith_u)x > (arith_u)1 && (
|
|
#if NEGATIVE_IS_BIGGER
|
|
y == NATIVE_SIGNED_MIN ||
|
|
#endif
|
|
(((arith_u)x * (arith_u)(-y)) & (arith_u)NATIVE_SIGNED_MAX)
|
|
/ (arith_u)(-y) != (arith_u)x))
|
|
ARITH_WARNING(ARITH_EXCEP_STAR_U);
|
|
} else {
|
|
if ((arith_u)y > (arith_u)1 && (
|
|
#if NEGATIVE_IS_BIGGER
|
|
x == NATIVE_SIGNED_MIN ||
|
|
#endif
|
|
(((arith_u)y * (arith_u)(-x)) & (arith_u)NATIVE_SIGNED_MAX)
|
|
/ (arith_u)(-x) != (arith_u)y))
|
|
ARITH_WARNING(ARITH_EXCEP_STAR_U);
|
|
}
|
|
#endif
|
|
return x * y;
|
|
}
|
|
|
|
/*
|
|
* Division by 0 is an error. The only other possible problem is an
|
|
* overflow of the result. Such an overflow can only happen in two's
|
|
* complement representation, when NEGATIVE_IS_BIGGER is set, and
|
|
* one attempts to divide NATIVE_SIGNED_MIN by -1: the result is then
|
|
* -NATIVE_SIGNED_MIN, which is not representable by the type. This is
|
|
* considered as an error, not a warning, because it actually triggers
|
|
* an exception on modern Pentium-based PC.
|
|
*/
|
|
ARITH_DECL_BI_SS_S(slash)
|
|
{
|
|
if (y == 0) ARITH_ERROR(ARITH_EXCEP_SLASH_D);
|
|
#if NEGATIVE_IS_BIGGER
|
|
else if (x == NATIVE_SIGNED_MIN && y == (arith_s)(-1))
|
|
ARITH_ERROR(ARITH_EXCEP_SLASH_O);
|
|
#endif
|
|
return x / y;
|
|
}
|
|
|
|
/*
|
|
* Only division by 0 needs to be checked.
|
|
*/
|
|
ARITH_DECL_BI_SS_S(pct)
|
|
{
|
|
if (y == 0) ARITH_ERROR(ARITH_EXCEP_PCT_D);
|
|
return x % y;
|
|
}
|
|
|
|
ARITH_DECL_MONO_ST_US(octconst)
|
|
{
|
|
arith_u z = 0;
|
|
|
|
for (; ARITH_OCTAL(*c); c ++) {
|
|
arith_u w = ARITH_OVAL(*c);
|
|
if (z > (NATIVE_UNSIGNED_MAX_A / 8))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z *= 8;
|
|
#if 0
|
|
/* obsolete */
|
|
/* NATIVE_UNSIGNED_MAX_A is 2^N - 1, 0 <= w <= 7 and 8 divides z */
|
|
if (z > (NATIVE_UNSIGNED_MAX_A - w))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
#endif
|
|
z += w;
|
|
}
|
|
*ru = z;
|
|
#if SIGNED_IS_BIGGER
|
|
*rs = z;
|
|
*sp = 1;
|
|
#else
|
|
if (z > NATIVE_SIGNED_MAX) {
|
|
*sp = 0;
|
|
} else {
|
|
*rs = z;
|
|
*sp = 1;
|
|
}
|
|
#endif
|
|
return c;
|
|
}
|
|
|
|
ARITH_DECL_MONO_ST_US(decconst)
|
|
{
|
|
arith_u z = 0;
|
|
|
|
for (; ARITH_DECIM(*c); c ++) {
|
|
arith_u w = ARITH_DVAL(*c);
|
|
if (z > (NATIVE_UNSIGNED_MAX_A / 10))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z *= 10;
|
|
if (z > (NATIVE_UNSIGNED_MAX_A - w))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z += w;
|
|
}
|
|
*ru = z;
|
|
#if SIGNED_IS_BIGGER
|
|
*rs = z;
|
|
*sp = 1;
|
|
#else
|
|
if (z > NATIVE_SIGNED_MAX) {
|
|
*sp = 0;
|
|
} else {
|
|
*rs = z;
|
|
*sp = 1;
|
|
}
|
|
#endif
|
|
return c;
|
|
}
|
|
|
|
ARITH_DECL_MONO_ST_US(hexconst)
|
|
{
|
|
arith_u z = 0;
|
|
|
|
for (; ARITH_HEXAD(*c); c ++) {
|
|
arith_u w = ARITH_HVAL(*c);
|
|
if (z > (NATIVE_UNSIGNED_MAX_A / 16))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z *= 16;
|
|
#if 0
|
|
/* obsolete */
|
|
/* NATIVE_UNSIGNED_MAX_A is 2^N - 1, 0 <= w <= 15 and 16 divides z */
|
|
if (z > (NATIVE_UNSIGNED_MAX_A - w))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
#endif
|
|
z += w;
|
|
}
|
|
*ru = z;
|
|
#if SIGNED_IS_BIGGER
|
|
*rs = z;
|
|
*sp = 1;
|
|
#else
|
|
if (z > NATIVE_SIGNED_MAX) {
|
|
*sp = 0;
|
|
} else {
|
|
*rs = z;
|
|
*sp = 1;
|
|
}
|
|
#endif
|
|
return c;
|
|
}
|
|
|
|
#else
|
|
/* ====================================================================== */
|
|
/* Arithmetics with a simple simulated type */
|
|
/* ====================================================================== */
|
|
|
|
/*
|
|
* We simulate a type with the following characteristics:
|
|
* -- the signed type width is equal to the unsigned type width (which
|
|
* means that there is one less value bit in the signed type);
|
|
* -- the signed type uses two's complement representation;
|
|
* -- there is no trap representation;
|
|
* -- overflows and underflows are truncated (but a warning is emitted
|
|
* if ARITHMETIC_CHECKS is defined);
|
|
* -- overflow on integer division is still an error;
|
|
* -- right-shifting of a negative value extends the sign;
|
|
* -- the shift count value is first cast to unsigned, then reduced modulo
|
|
* the type size.
|
|
*
|
|
* These characteristics follow what is usually found on modern
|
|
* architectures.
|
|
*
|
|
* The maximum emulated type size is twice the size of the unsigned native
|
|
* type which is used to emulate the type.
|
|
*/
|
|
|
|
#undef SIMUL_ONE_TMP
|
|
#undef SIMUL_MSW_TMP1
|
|
#undef SIMUL_MSW_MASK
|
|
#undef SIMUL_LSW_TMP1
|
|
#undef SIMUL_LSW_MASK
|
|
|
|
#define SIMUL_ONE_TMP ((SIMUL_ARITH_SUBTYPE)1)
|
|
#define SIMUL_MSW_TMP1 (SIMUL_ONE_TMP << (SIMUL_MSW_WIDTH - 1))
|
|
#define SIMUL_MSW_MASK (SIMUL_MSW_TMP1 | (SIMUL_MSW_TMP1 - SIMUL_ONE_TMP))
|
|
#define SIMUL_LSW_TMP1 (SIMUL_ONE_TMP << (SIMUL_LSW_WIDTH - 1))
|
|
#define SIMUL_LSW_MASK (SIMUL_LSW_TMP1 | (SIMUL_LSW_TMP1 - SIMUL_ONE_TMP))
|
|
|
|
#undef TMSW
|
|
#undef TLSW
|
|
|
|
#define TMSW(x) ((x) & SIMUL_MSW_MASK)
|
|
#define TLSW(x) ((x) & SIMUL_LSW_MASK)
|
|
|
|
#undef SIMUL_ZERO
|
|
#undef SIMUL_ONE
|
|
|
|
#define SIMUL_ZERO arith_strc(ARITH_TYPENAME, _zero)
|
|
#define SIMUL_ONE arith_strc(ARITH_TYPENAME, _one)
|
|
|
|
static arith_u SIMUL_ZERO = { 0, 0 };
|
|
static arith_u SIMUL_ONE = { 0, 1 };
|
|
|
|
/*
|
|
* We use the fact that both the signed and unsigned type are the same
|
|
* structure. The difference between the signed and the unsigned type
|
|
* is a type information, and, as such, is considered compile-time and
|
|
* not maintained in the value structure itself. This is a job for
|
|
* the programmer / compiler.
|
|
*/
|
|
ARITH_DECL_MONO_S_U(to_u) { return x; }
|
|
|
|
ARITH_DECL_MONO_I_U(fromint)
|
|
{
|
|
arith_u z;
|
|
|
|
if (x < 0) return arith_op_u(neg)(arith_op_u(fromint)(-x));
|
|
/*
|
|
* This code works because types smaller than int are promoted
|
|
* by the C compiler before evaluating the >> operator.
|
|
*/
|
|
z.msw = TMSW(((SIMUL_ARITH_SUBTYPE)x >> (SIMUL_LSW_WIDTH - 1)) >> 1);
|
|
z.lsw = TLSW((SIMUL_ARITH_SUBTYPE)x);
|
|
return z;
|
|
}
|
|
|
|
ARITH_DECL_MONO_L_U(fromulong)
|
|
{
|
|
arith_u z;
|
|
|
|
#if (ULONG_MAX >> (SIMUL_LSW_WIDTH - 1)) >> 1 == 0
|
|
z.msw = 0;
|
|
z.lsw = x;
|
|
#else
|
|
z.msw = TMSW(x >> SIMUL_LSW_WIDTH);
|
|
z.lsw = TLSW((SIMUL_ARITH_SUBTYPE)x);
|
|
#endif
|
|
return z;
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_I(toint)
|
|
{
|
|
#if ((INT_MAX >> (SIMUL_LSW_WIDTH - 1)) >> 1) == 0
|
|
if (x.msw != 0 || x.lsw > (SIMUL_ARITH_SUBTYPE)INT_MAX)
|
|
return INT_MAX;
|
|
return (int)x.lsw;
|
|
#else
|
|
#if (INT_MAX >> (SIMUL_SUBTYPE_BITS - 1)) == 0
|
|
if (x.msw > (SIMUL_ARITH_SUBTYPE)(INT_MAX >> SIMUL_LSW_WIDTH))
|
|
return INT_MAX;
|
|
#endif
|
|
return ((int)x.msw << SIMUL_LSW_WIDTH) | (int)x.lsw;
|
|
#endif
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_L(toulong)
|
|
{
|
|
#if ((ULONG_MAX >> (SIMUL_LSW_WIDTH - 1)) >> 1) == 0
|
|
if (x.msw != 0 || x.lsw > (SIMUL_ARITH_SUBTYPE)ULONG_MAX)
|
|
return ULONG_MAX;
|
|
return (unsigned long)x.lsw;
|
|
#else
|
|
#if (ULONG_MAX >> (SIMUL_SUBTYPE_BITS - 1)) == 0
|
|
if (x.msw > (SIMUL_ARITH_SUBTYPE)(ULONG_MAX >> SIMUL_LSW_WIDTH))
|
|
return ULONG_MAX;
|
|
#endif
|
|
return ((unsigned long)x.msw << SIMUL_LSW_WIDTH) | (unsigned long)x.lsw;
|
|
#endif
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_U(neg)
|
|
{
|
|
x = arith_op_u(not)(x);
|
|
return arith_op_u(plus)(x, SIMUL_ONE);
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_U(not)
|
|
{
|
|
x.msw = TMSW(~x.msw);
|
|
x.lsw = TLSW(~x.lsw);
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_I(lnot)
|
|
{
|
|
return x.msw == 0 && x.lsw == 0;
|
|
}
|
|
|
|
ARITH_DECL_MONO_U_I(lval)
|
|
{
|
|
return x.msw != 0 || x.lsw != 0;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(plus)
|
|
{
|
|
x.lsw = TLSW(x.lsw + y.lsw);
|
|
x.msw = TMSW(x.msw + y.msw);
|
|
if (x.lsw < y.lsw) x.msw = TMSW(x.msw + 1);
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(minus)
|
|
{
|
|
return arith_op_u(plus)(x, arith_op_u(neg)(y));
|
|
}
|
|
|
|
ARITH_DECL_BI_UI_U(lsh)
|
|
{
|
|
if (y == 0) return x;
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (y < 0) ARITH_WARNING(ARITH_EXCEP_LSH_C);
|
|
else if (y >= SIMUL_NUMBITS) ARITH_WARNING(ARITH_EXCEP_LSH_W);
|
|
#endif
|
|
y = (unsigned)y % SIMUL_NUMBITS;
|
|
if (y >= SIMUL_LSW_WIDTH) {
|
|
/*
|
|
* We use here the fact that the LSW size is always
|
|
* equal to or greater than the MSW size.
|
|
*/
|
|
x.msw = TMSW(x.lsw << (y - SIMUL_LSW_WIDTH));
|
|
x.lsw = 0;
|
|
return x;
|
|
}
|
|
x.msw = TMSW((x.msw << y) | (x.lsw >> (SIMUL_LSW_WIDTH - y)));
|
|
x.lsw = TLSW(x.lsw << y);
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_BI_UI_U(rsh)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (y < 0) ARITH_WARNING(ARITH_EXCEP_RSH_C);
|
|
else if (y >= SIMUL_NUMBITS) ARITH_WARNING(ARITH_EXCEP_RSH_W);
|
|
#endif
|
|
y = (unsigned)y % SIMUL_NUMBITS;
|
|
if (y >= SIMUL_LSW_WIDTH) {
|
|
x.lsw = x.msw >> (y - SIMUL_LSW_WIDTH);
|
|
x.msw = 0;
|
|
return x;
|
|
}
|
|
x.lsw = TLSW((x.lsw >> y) | (x.msw << (SIMUL_LSW_WIDTH - y)));
|
|
x.msw >>= y;
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_I(lt)
|
|
{
|
|
return x.msw < y.msw || (x.msw == y.msw && x.lsw < y.lsw);
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_I(leq)
|
|
{
|
|
return x.msw < y.msw || (x.msw == y.msw && x.lsw <= y.lsw);
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_I(gt)
|
|
{
|
|
return arith_op_u(lt)(y, x);
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_I(geq)
|
|
{
|
|
return arith_op_u(leq)(y, x);
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_I(same)
|
|
{
|
|
return x.msw == y.msw && x.lsw == y.lsw;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_I(neq)
|
|
{
|
|
return !arith_op_u(same)(x, y);
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(and)
|
|
{
|
|
x.msw &= y.msw;
|
|
x.lsw &= y.lsw;
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(xor)
|
|
{
|
|
x.msw ^= y.msw;
|
|
x.lsw ^= y.lsw;
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(or)
|
|
{
|
|
x.msw |= y.msw;
|
|
x.lsw |= y.lsw;
|
|
return x;
|
|
}
|
|
|
|
#undef SIMUL_LSW_ODDLEN
|
|
#undef SIMUL_LSW_HALFLEN
|
|
#undef SIMUL_LSW_HALFMASK
|
|
|
|
#define SIMUL_LSW_ODDLEN (SIMUL_LSW_WIDTH & 1)
|
|
#define SIMUL_LSW_HALFLEN (SIMUL_LSW_WIDTH / 2)
|
|
#define SIMUL_LSW_HALFMASK (~(~(SIMUL_ARITH_SUBTYPE)0 << SIMUL_LSW_HALFLEN))
|
|
|
|
ARITH_DECL_BI_UU_U(star)
|
|
{
|
|
arith_u z;
|
|
SIMUL_ARITH_SUBTYPE a = x.lsw, b = y.lsw, t00, t01, t10, t11, c = 0, t;
|
|
#if SIMUL_LSW_ODDLEN
|
|
SIMUL_ARITH_SUBTYPE bms = b & (SIMUL_ONE_TMP << (SIMUL_LSW_WIDTH - 1));
|
|
|
|
b &= ~(SIMUL_ONE_TMP << (SIMUL_LSW_WIDTH - 1));
|
|
#endif
|
|
|
|
t00 = (a & SIMUL_LSW_HALFMASK) * (b & SIMUL_LSW_HALFMASK);
|
|
t01 = (a & SIMUL_LSW_HALFMASK) * (b >> SIMUL_LSW_HALFLEN);
|
|
t10 = (a >> SIMUL_LSW_HALFLEN) * (b & SIMUL_LSW_HALFMASK);
|
|
t11 = (a >> SIMUL_LSW_HALFLEN) * (b >> SIMUL_LSW_HALFLEN);
|
|
t = z.lsw = t00;
|
|
z.lsw = TLSW(z.lsw + (t01 << SIMUL_LSW_HALFLEN));
|
|
if (t > z.lsw) c ++;
|
|
t = z.lsw;
|
|
z.lsw = TLSW(z.lsw + (t10 << SIMUL_LSW_HALFLEN));
|
|
if (t > z.lsw) c ++;
|
|
#if SIMUL_LSW_ODDLEN
|
|
t = z.lsw;
|
|
z.lsw = TLSW(z.lsw + (t11 << (2 * SIMUL_LSW_HALFLEN)));
|
|
if (t > z.lsw) c ++;
|
|
if (bms && (a & SIMUL_ONE_TMP)) {
|
|
t = z.lsw;
|
|
z.lsw = TLSW(z.lsw + b);
|
|
if (t > z.lsw) c ++;
|
|
}
|
|
#endif
|
|
z.msw = TMSW(x.lsw * y.msw + x.msw * y.lsw + c
|
|
+ (t01 >> (SIMUL_LSW_WIDTH - SIMUL_LSW_HALFLEN))
|
|
+ (t10 >> (SIMUL_LSW_WIDTH - SIMUL_LSW_HALFLEN))
|
|
+ (t11 >> (SIMUL_LSW_WIDTH - (2 * SIMUL_LSW_HALFLEN))));
|
|
return z;
|
|
}
|
|
|
|
/*
|
|
* This function calculates the unsigned integer division, yielding
|
|
* both quotient and remainder. The divider (y) MUST be non-zero.
|
|
*/
|
|
static void arith_op_u(udiv)(arith_u x, arith_u y, arith_u *q, arith_u *r)
|
|
{
|
|
int i, j;
|
|
arith_u a;
|
|
|
|
*q = SIMUL_ZERO;
|
|
for (i = SIMUL_NUMBITS - 1; i >= 0; i --) {
|
|
if (i >= (int)SIMUL_LSW_WIDTH
|
|
&& (y.msw & (SIMUL_ONE_TMP << (i - SIMUL_LSW_WIDTH))))
|
|
break;
|
|
if (i < (int)SIMUL_LSW_WIDTH && (y.lsw & (SIMUL_ONE_TMP << i)))
|
|
break;
|
|
}
|
|
a = arith_op_u(lsh)(y, SIMUL_NUMBITS - 1 - i);
|
|
for (j = SIMUL_NUMBITS - 1 - i; j >= SIMUL_LSW_WIDTH; j --) {
|
|
if (arith_op_u(leq)(a, x)) {
|
|
x = arith_op_u(minus)(x, a);
|
|
q->msw |= SIMUL_ONE_TMP << (j - SIMUL_LSW_WIDTH);
|
|
}
|
|
a = arith_op_u(rsh)(a, 1);
|
|
}
|
|
for (; j >= 0; j --) {
|
|
if (arith_op_u(leq)(a, x)) {
|
|
x = arith_op_u(minus)(x, a);
|
|
q->lsw |= SIMUL_ONE_TMP << j;
|
|
}
|
|
a = arith_op_u(rsh)(a, 1);
|
|
}
|
|
*r = x;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(slash)
|
|
{
|
|
arith_u q, r;
|
|
|
|
if (arith_op_u(same)(y, SIMUL_ZERO))
|
|
ARITH_ERROR(ARITH_EXCEP_SLASH_D);
|
|
arith_op_u(udiv)(x, y, &q, &r);
|
|
return q;
|
|
}
|
|
|
|
ARITH_DECL_BI_UU_U(pct)
|
|
{
|
|
arith_u q, r;
|
|
|
|
if (arith_op_u(same)(y, SIMUL_ZERO))
|
|
ARITH_ERROR(ARITH_EXCEP_PCT_D);
|
|
arith_op_u(udiv)(x, y, &q, &r);
|
|
return r;
|
|
}
|
|
|
|
#undef SIMUL_TRAP
|
|
#undef SIMUL_TRAPL
|
|
#define SIMUL_TRAP (SIMUL_ONE_TMP << (SIMUL_MSW_WIDTH - 1))
|
|
#define SIMUL_TRAPL (SIMUL_ONE_TMP << (SIMUL_LSW_WIDTH - 1))
|
|
|
|
ARITH_DECL_MONO_U_S(to_s)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x.msw & SIMUL_TRAP) ARITH_WARNING(ARITH_EXCEP_CONV_O);
|
|
#endif
|
|
return x;
|
|
}
|
|
|
|
ARITH_DECL_MONO_I_S(fromint) { return arith_op_u(fromint)(x); }
|
|
ARITH_DECL_MONO_L_S(fromlong)
|
|
{
|
|
if (x < 0) return arith_op_u(neg)(
|
|
arith_op_u(fromulong)((unsigned long)(-x)));
|
|
return arith_op_u(fromulong)((unsigned long)x);
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_I(toint)
|
|
{
|
|
if (x.msw & SIMUL_TRAP) return -arith_op_u(toint)(arith_op_u(neg)(x));
|
|
return arith_op_u(toint)(x);
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_L(tolong)
|
|
{
|
|
if (x.msw & SIMUL_TRAP)
|
|
return -(long)arith_op_u(toulong)(arith_op_u(neg)(x));
|
|
return (long)arith_op_u(toulong)(x);
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_S(neg)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x.lsw == 0 && x.msw == SIMUL_TRAP)
|
|
ARITH_WARNING(ARITH_EXCEP_NEG_O);
|
|
#endif
|
|
return arith_op_u(neg)(x);
|
|
}
|
|
|
|
ARITH_DECL_MONO_S_S(not) { return arith_op_u(not)(x); }
|
|
ARITH_DECL_MONO_S_I(lnot) { return arith_op_u(lnot)(x); }
|
|
ARITH_DECL_MONO_S_I(lval) { return arith_op_u(lval)(x); }
|
|
|
|
ARITH_DECL_BI_SS_S(plus)
|
|
{
|
|
arith_u z = arith_op_u(plus)(x, y);
|
|
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x.msw & y.msw & ~z.msw & SIMUL_TRAP)
|
|
ARITH_WARNING(ARITH_EXCEP_PLUS_U);
|
|
else if (~x.msw & ~y.msw & z.msw & SIMUL_TRAP)
|
|
ARITH_WARNING(ARITH_EXCEP_PLUS_O);
|
|
#endif
|
|
return z;
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_S(minus)
|
|
{
|
|
arith_s z = arith_op_u(minus)(x, y);
|
|
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x.msw & ~y.msw & ~z.msw & SIMUL_TRAP)
|
|
ARITH_WARNING(ARITH_EXCEP_MINUS_U);
|
|
else if (~x.msw & y.msw & z.msw & SIMUL_TRAP)
|
|
ARITH_WARNING(ARITH_EXCEP_MINUS_O);
|
|
#endif
|
|
return z;
|
|
}
|
|
|
|
/*
|
|
* Since signed and unsigned widths are equal for the simulated type,
|
|
* we can use the unsigned left shift function, which performs the
|
|
* the checks on the type width.
|
|
*/
|
|
ARITH_DECL_BI_SI_S(lsh)
|
|
{
|
|
arith_s z = arith_op_u(lsh)(x, y);
|
|
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (x.msw & SIMUL_TRAP) ARITH_WARNING(ARITH_EXCEP_LSH_U);
|
|
else {
|
|
/*
|
|
* To check for possible overflow, we right shift the
|
|
* result. We need to make the shift count proper so that
|
|
* we do not emit a double-warning. Besides, the left shift
|
|
* could have been untruncated but yet affet the sign bit,
|
|
* so we must test this explicitly.
|
|
*/
|
|
arith_s w = arith_op_u(rsh)(z, (unsigned)y % SIMUL_NUMBITS);
|
|
|
|
if ((z.msw & SIMUL_TRAP) || w.msw != x.msw || w.lsw != x.lsw)
|
|
ARITH_WARNING(ARITH_EXCEP_LSH_O);
|
|
}
|
|
#endif
|
|
return z;
|
|
}
|
|
|
|
/*
|
|
* We define that right shifting a negative value, besides being worth a
|
|
* warning, duplicates the sign bit. This is the most useful and most
|
|
* usually encountered behaviour, and the standard allows it.
|
|
*/
|
|
ARITH_DECL_BI_SI_S(rsh)
|
|
{
|
|
int xn = (x.msw & SIMUL_TRAP) != 0;
|
|
arith_s z = arith_op_u(rsh)(x, y);
|
|
int gy = (unsigned)y % SIMUL_NUMBITS;
|
|
|
|
#ifdef ARITHMETIC_CHECKS
|
|
if (xn) ARITH_WARNING(ARITH_EXCEP_RSH_N);
|
|
#endif
|
|
if (xn && gy > 0) {
|
|
if (gy <= SIMUL_MSW_WIDTH) {
|
|
z.msw |= TMSW(~(SIMUL_MSW_MASK >> gy));
|
|
} else {
|
|
z.msw = SIMUL_MSW_MASK;
|
|
z.lsw |= TLSW(~(SIMUL_LSW_MASK
|
|
>> (gy - SIMUL_MSW_WIDTH)));
|
|
}
|
|
}
|
|
return z;
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(lt)
|
|
{
|
|
int xn = (x.msw & SIMUL_TRAP) != 0;
|
|
int yn = (y.msw & SIMUL_TRAP) != 0;
|
|
|
|
if (xn == yn) {
|
|
return x.msw < y.msw || (x.msw == y.msw && x.lsw < y.lsw);
|
|
} else {
|
|
return xn;
|
|
}
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(leq)
|
|
{
|
|
int xn = (x.msw & SIMUL_TRAP) != 0;
|
|
int yn = (y.msw & SIMUL_TRAP) != 0;
|
|
|
|
if (xn == yn) {
|
|
return x.msw < y.msw || (x.msw == y.msw && x.lsw <= y.lsw);
|
|
} else {
|
|
return xn;
|
|
}
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(gt)
|
|
{
|
|
return arith_op_s(lt)(y, x);
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(geq)
|
|
{
|
|
return arith_op_s(leq)(y, x);
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(same)
|
|
{
|
|
return x.msw == y.msw && x.lsw == y.lsw;
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_I(neq)
|
|
{
|
|
return !arith_op_s(same)(x, y);
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_S(and)
|
|
{
|
|
return arith_op_u(and)(x, y);
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_S(xor)
|
|
{
|
|
return arith_op_u(xor)(x, y);
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_S(or)
|
|
{
|
|
return arith_op_u(or)(x, y);
|
|
}
|
|
|
|
/*
|
|
* This function calculates the signed integer division, yielding
|
|
* both quotient and remainder. The divider (y) MUST be non-zero.
|
|
*/
|
|
static void arith_op_s(sdiv)(arith_s x, arith_s y, arith_s *q, arith_s *r)
|
|
{
|
|
arith_u a = x, b = y, c, d;
|
|
int xn = 0, yn = 0;
|
|
|
|
if (x.msw & SIMUL_TRAP) { a = arith_op_u(neg)(x); xn = 1; }
|
|
if (y.msw & SIMUL_TRAP) { b = arith_op_u(neg)(y); yn = 1; }
|
|
arith_op_u(udiv)(a, b, &c, &d);
|
|
if (xn != yn) *q = arith_op_u(neg)(c); else *q = c;
|
|
if (xn != yn) *r = arith_op_u(neg)(d); else *r = d;
|
|
}
|
|
|
|
/*
|
|
* Overflow/underflow check is done the following way: obvious cases
|
|
* are checked (both upper words non-null, both upper words null...)
|
|
* and border-line occurrences are verified with an unsigned division
|
|
* (which is quite computationaly expensive).
|
|
*/
|
|
ARITH_DECL_BI_SS_S(star)
|
|
{
|
|
#ifdef ARITHMETIC_CHECKS
|
|
arith_s z = arith_op_u(star)(x, y);
|
|
int warn = 0;
|
|
|
|
if (x.msw > 0) {
|
|
if (y.msw > 0
|
|
#if SIMUL_LSW_ODDLEN
|
|
|| (y.lsw & SIMUL_TRAPL)
|
|
#endif
|
|
) warn = 1;
|
|
}
|
|
#if SIMUL_LSW_ODDLEN
|
|
else if (y.msw > 0 && (x.lsw & SIMUL_TRAPL)) warn = 1;
|
|
#endif
|
|
if (!warn && (x.msw > 0 || y.msw > 0
|
|
#if SIMUL_LSW_ODDLEN
|
|
|| ((x.lsw | y.lsw) & SIMUL_TRAPL)
|
|
#endif
|
|
)) {
|
|
if (x.msw == SIMUL_MSW_MASK && x.lsw == SIMUL_LSW_MASK) {
|
|
if (y.msw == SIMUL_TRAP && y.lsw == 0) warn = 1;
|
|
} else if (!(x.msw == 0 && x.lsw == 0)
|
|
&& !arith_op_s(same)(arith_op_s(slash)(z, x), y)) {
|
|
} warn = 1;
|
|
}
|
|
if (warn) ARITH_WARNING(((x.msw ^ y.msw) & SIMUL_TRAP)
|
|
? ARITH_EXCEP_STAR_U : ARITH_EXCEP_STAR_O);
|
|
return z;
|
|
#else
|
|
return arith_op_u(star)(x, y);
|
|
#endif
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_S(slash)
|
|
{
|
|
arith_s q, r;
|
|
|
|
if (arith_op_s(same)(y, SIMUL_ZERO))
|
|
ARITH_ERROR(ARITH_EXCEP_SLASH_D);
|
|
else if (x.msw == SIMUL_TRAP && x.lsw == 0
|
|
&& y.msw == SIMUL_MSW_MASK && y.lsw == SIMUL_LSW_MASK)
|
|
ARITH_ERROR(ARITH_EXCEP_SLASH_O);
|
|
arith_op_s(sdiv)(x, y, &q, &r);
|
|
return q;
|
|
}
|
|
|
|
ARITH_DECL_BI_SS_S(pct)
|
|
{
|
|
arith_s q, r;
|
|
|
|
if (arith_op_s(same)(y, SIMUL_ZERO))
|
|
ARITH_ERROR(ARITH_EXCEP_PCT_D);
|
|
arith_op_s(sdiv)(x, y, &q, &r);
|
|
return r;
|
|
}
|
|
|
|
ARITH_DECL_MONO_ST_US(octconst)
|
|
{
|
|
arith_u z = { 0, 0 };
|
|
|
|
for (; ARITH_OCTAL(*c); c ++) {
|
|
unsigned w = ARITH_OVAL(*c);
|
|
if (z.msw > (SIMUL_MSW_MASK / 8))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z = arith_op_u(lsh)(z, 3);
|
|
z.lsw |= w;
|
|
}
|
|
*ru = z;
|
|
if (z.msw & SIMUL_TRAP) {
|
|
*sp = 0;
|
|
} else {
|
|
*rs = z;
|
|
*sp = 1;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ARITH_DECL_MONO_ST_US(decconst)
|
|
{
|
|
#define ARITH_ALPHA_TRAP (1U << (SIMUL_MSW_WIDTH - 1))
|
|
#define ARITH_ALPHA_MASK (ARITH_ALPHA_TRAP | (ARITH_ALPHA_TRAP - 1))
|
|
#define ARITH_ALPHA ((ARITH_ALPHA_MASK - 10 * (ARITH_ALPHA_TRAP / 5)) + 1)
|
|
#define ARITH_ALPHA_A ((SIMUL_MSW_MASK - 10 * (SIMUL_TRAP / 5)) + 1)
|
|
|
|
arith_u z = { 0, 0 };
|
|
|
|
for (; ARITH_DECIM(*c); c ++) {
|
|
unsigned w = ARITH_DVAL(*c);
|
|
SIMUL_ARITH_SUBTYPE t;
|
|
|
|
if (z.msw > (SIMUL_MSW_MASK / 10)
|
|
|| (z.msw == (SIMUL_MSW_MASK / 10) &&
|
|
/* ARITH_ALPHA is between 1 and 9, inclusive. */
|
|
#if ARITH_ALPHA == 5
|
|
z.lsw >= SIMUL_TRAPL
|
|
#else
|
|
z.lsw > ((SIMUL_TRAPL / 5) * ARITH_ALPHA_A
|
|
+ ((SIMUL_TRAPL % 5) * ARITH_ALPHA_A) / 5)
|
|
#endif
|
|
)) ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z = arith_op_u(plus)(arith_op_u(lsh)(z, 3),
|
|
arith_op_u(lsh)(z, 1));
|
|
t = TLSW(z.lsw + w);
|
|
if (t < z.lsw) z.msw ++;
|
|
z.lsw = t;
|
|
}
|
|
*ru = z;
|
|
if (z.msw & SIMUL_TRAP) {
|
|
*sp = 0;
|
|
} else {
|
|
*rs = z;
|
|
*sp = 1;
|
|
}
|
|
return c;
|
|
|
|
#undef ARITH_ALPHA_A
|
|
#undef ARITH_ALPHA
|
|
#undef ARITH_ALPHA_TRAP
|
|
#undef ARITH_ALPHA_MASK
|
|
}
|
|
|
|
ARITH_DECL_MONO_ST_US(hexconst)
|
|
{
|
|
arith_u z = { 0, 0 };
|
|
|
|
for (; ARITH_HEXAD(*c); c ++) {
|
|
unsigned w = ARITH_HVAL(*c);
|
|
if (z.msw > (SIMUL_MSW_MASK / 16))
|
|
ARITH_ERROR(ARITH_EXCEP_CONST_O);
|
|
z = arith_op_u(lsh)(z, 4);
|
|
z.lsw |= w;
|
|
}
|
|
*ru = z;
|
|
if (z.msw & SIMUL_TRAP) {
|
|
*sp = 0;
|
|
} else {
|
|
*rs = z;
|
|
*sp = 1;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
#endif
|
|
|
|
#undef ARITH_HVAL
|
|
#undef ARITH_HEXAD
|
|
#undef ARITH_DVAL
|
|
#undef ARITH_DECIM
|
|
#undef ARITH_OVAL
|
|
#undef ARITH_OCTAL
|