a2223c7302
doesn't depend on the 'comp' set. ok espie@ deraadt@
256 lines
10 KiB
C
256 lines
10 KiB
C
/*
|
|
* Integer arithmetic evaluation, header file.
|
|
*
|
|
* (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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This arithmetic evaluator uses two files: this header file (arith.h)
|
|
* and the source file (arith.c). To use this code, the source file should
|
|
* be included from another .c file which defines some macros (see below).
|
|
* Then the functions defined in the arith.c file become available to the
|
|
* including source file. If those functions are defined with external
|
|
* linkage (that is, `ARITH_FUNCTION_HEADER' does not contain `static'),
|
|
* it is possible for other source files to use the arithmetic functions
|
|
* by including the arith.h header only. The source file which includes
|
|
* arith.c should *not* include arith.h.
|
|
*
|
|
* If the #include is for arith.h, the following macros should be
|
|
* defined:
|
|
*
|
|
* -- If the evaluator is supposed to use a native type:
|
|
* NATIVE_SIGNED the native signed integer type
|
|
* NATIVE_UNSIGNED the native unsigned integer type
|
|
*
|
|
* -- If the evaluator is supposed to use an emulated type:
|
|
* SIMUL_ARITH_SUBTYPE the native unsigned type used for the simulation
|
|
* SIMUL_SUBTYPE_BITS the native unsigned type size
|
|
* SIMUL_NUMBITS the emulated type size
|
|
*
|
|
* -- For both cases:
|
|
* ARITH_TYPENAME the central arithmetic type name
|
|
* ARITH_FUNCTION_HEADER the qualifiers to add to function definitions
|
|
*
|
|
* The presence (respectively absence) of the NATIVE_SIGNED macro triggers
|
|
* the use of the native type evaluator (respectively simulated type
|
|
* evaluator).
|
|
*
|
|
* If the #include is for arith.c, the macros for arith.h should be defined,
|
|
* and the following should be defined as well:
|
|
*
|
|
* -- If the evaluator is supposed to use a native type:
|
|
* NATIVE_UNSIGNED_BITS the native unsigned type size
|
|
* NATIVE_SIGNED_MIN the native signed minimum value
|
|
* NATIVE_SIGNED_MAX the native signed maximum value
|
|
* (the last two macros must evaluate to signed constant expressions)
|
|
*
|
|
* -- For both cases:
|
|
* ARITH_WARNING(type) code to perform on warning
|
|
* ARITH_ERROR(type) code to perform on error
|
|
*
|
|
* The macro ARITH_WARNING() and ARITH_ERROR() are invoked with a
|
|
* numerical argument which is one of the enumeration constants
|
|
* defined below (ARITH_EXCEP_*) that identifies the specific problem.
|
|
*
|
|
* If the #include is for arith.c, the macro ARITHMETIC_CHECKS may be
|
|
* defined. When this macro is defined, checks are performed so that all
|
|
* operation which would lead to undefined or implementation-defined
|
|
* behaviour are first reported through ARITH_WARNING(). Code is smaller
|
|
* and faster without these checks, of course. Regardless of the status
|
|
* of that macro, divisions by 0 and overflows on signed division are
|
|
* reported as errors through ARITH_ERROR().
|
|
*
|
|
*/
|
|
|
|
#ifndef ARITH_H__
|
|
#define ARITH_H__
|
|
|
|
enum {
|
|
/* Warnings */
|
|
ARITH_EXCEP_CONV_O, /* overflow on conversion */
|
|
ARITH_EXCEP_NEG_O, /* overflow on unary minus */
|
|
ARITH_EXCEP_NOT_T, /* trap representation on bitwise inversion */
|
|
ARITH_EXCEP_PLUS_O, /* overflow on addition */
|
|
ARITH_EXCEP_PLUS_U, /* underflow on addition */
|
|
ARITH_EXCEP_MINUS_O, /* overflow on subtraction */
|
|
ARITH_EXCEP_MINUS_U, /* underflow on subtraction */
|
|
ARITH_EXCEP_AND_T, /* trap representation on bitwise and */
|
|
ARITH_EXCEP_XOR_T, /* trap representation on bitwise xor */
|
|
ARITH_EXCEP_OR_T, /* trap representation on bitwise or */
|
|
ARITH_EXCEP_LSH_W, /* left shift by type width or more */
|
|
ARITH_EXCEP_LSH_C, /* left shift by negative count */
|
|
ARITH_EXCEP_LSH_O, /* overflow on left shift */
|
|
ARITH_EXCEP_LSH_U, /* underflow on left shift */
|
|
ARITH_EXCEP_RSH_W, /* right shift by type width or more */
|
|
ARITH_EXCEP_RSH_C, /* right shift by negative count */
|
|
ARITH_EXCEP_RSH_N, /* right shift of negative value */
|
|
ARITH_EXCEP_STAR_O, /* overflow on multiplication */
|
|
ARITH_EXCEP_STAR_U, /* underflow on multiplication */
|
|
|
|
/* Errors */
|
|
ARITH_EXCEP_SLASH_D, /* division by 0 */
|
|
ARITH_EXCEP_SLASH_O, /* overflow on division */
|
|
ARITH_EXCEP_PCT_D, /* division by 0 on modulus operator */
|
|
ARITH_EXCEP_CONST_O /* constant too large */
|
|
};
|
|
|
|
#define arith_strc_(x, y) x ## y
|
|
#define arith_strc(x, y) arith_strc_(x, y)
|
|
|
|
#define arith_u arith_strc(u_, ARITH_TYPENAME)
|
|
#define arith_s arith_strc(s_, ARITH_TYPENAME)
|
|
#define arith_op_u(op) arith_strc(ARITH_TYPENAME, arith_strc(_u_, op))
|
|
#define arith_op_s(op) arith_strc(ARITH_TYPENAME, arith_strc(_s_, op))
|
|
|
|
#define ARITH_DECL_MONO_U_U(op) ARITH_FUNCTION_HEADER arith_u \
|
|
arith_op_u(op)(arith_u x)
|
|
#define ARITH_DECL_MONO_U_S(op) ARITH_FUNCTION_HEADER arith_s \
|
|
arith_op_u(op)(arith_u x)
|
|
#define ARITH_DECL_MONO_U_I(op) ARITH_FUNCTION_HEADER int \
|
|
arith_op_u(op)(arith_u x)
|
|
#define ARITH_DECL_MONO_U_L(op) ARITH_FUNCTION_HEADER unsigned long \
|
|
arith_op_u(op)(arith_u x)
|
|
#define ARITH_DECL_MONO_S_U(op) ARITH_FUNCTION_HEADER arith_u \
|
|
arith_op_s(op)(arith_s x)
|
|
#define ARITH_DECL_MONO_S_S(op) ARITH_FUNCTION_HEADER arith_s \
|
|
arith_op_s(op)(arith_s x)
|
|
#define ARITH_DECL_MONO_S_I(op) ARITH_FUNCTION_HEADER int \
|
|
arith_op_s(op)(arith_s x)
|
|
#define ARITH_DECL_MONO_S_L(op) ARITH_FUNCTION_HEADER long \
|
|
arith_op_s(op)(arith_s x)
|
|
#define ARITH_DECL_MONO_I_U(op) ARITH_FUNCTION_HEADER arith_u \
|
|
arith_op_u(op)(int x)
|
|
#define ARITH_DECL_MONO_L_U(op) ARITH_FUNCTION_HEADER arith_u \
|
|
arith_op_u(op)(unsigned long x)
|
|
#define ARITH_DECL_MONO_I_S(op) ARITH_FUNCTION_HEADER arith_s \
|
|
arith_op_s(op)(int x)
|
|
#define ARITH_DECL_MONO_L_S(op) ARITH_FUNCTION_HEADER arith_s \
|
|
arith_op_s(op)(long x)
|
|
#define ARITH_DECL_MONO_ST_US(op) ARITH_FUNCTION_HEADER char *arith_op_u(op) \
|
|
(char *c, arith_u *ru, arith_s *rs, int *sp)
|
|
|
|
#define ARITH_DECL_BI_UU_U(op) ARITH_FUNCTION_HEADER arith_u \
|
|
arith_op_u(op)(arith_u x, arith_u y)
|
|
#define ARITH_DECL_BI_UI_U(op) ARITH_FUNCTION_HEADER arith_u \
|
|
arith_op_u(op)(arith_u x, int y)
|
|
#define ARITH_DECL_BI_UU_I(op) ARITH_FUNCTION_HEADER int \
|
|
arith_op_u(op)(arith_u x, arith_u y)
|
|
#define ARITH_DECL_BI_SS_S(op) ARITH_FUNCTION_HEADER arith_s \
|
|
arith_op_s(op)(arith_s x, arith_s y)
|
|
#define ARITH_DECL_BI_SI_S(op) ARITH_FUNCTION_HEADER arith_s \
|
|
arith_op_s(op)(arith_s x, int y)
|
|
#define ARITH_DECL_BI_SS_I(op) ARITH_FUNCTION_HEADER int \
|
|
arith_op_s(op)(arith_s x, arith_s y)
|
|
|
|
#endif
|
|
|
|
#ifdef NATIVE_SIGNED
|
|
|
|
typedef NATIVE_SIGNED arith_s;
|
|
typedef NATIVE_UNSIGNED arith_u;
|
|
|
|
#else
|
|
|
|
#if SIMUL_NUMBITS > (2 * SIMUL_SUBTYPE_BITS)
|
|
#error Native subtype too small for arithmetic simulation.
|
|
#endif
|
|
|
|
#define SIMUL_MSW_WIDTH (SIMUL_NUMBITS / 2)
|
|
#define SIMUL_LSW_WIDTH ((SIMUL_NUMBITS + 1) / 2)
|
|
|
|
typedef struct {
|
|
SIMUL_ARITH_SUBTYPE msw, lsw;
|
|
} arith_u, arith_s;
|
|
|
|
#endif
|
|
|
|
/* functions with the unsigned type */
|
|
|
|
ARITH_DECL_MONO_S_U(to_u);
|
|
ARITH_DECL_MONO_I_U(fromint);
|
|
ARITH_DECL_MONO_L_U(fromulong);
|
|
ARITH_DECL_MONO_U_I(toint);
|
|
ARITH_DECL_MONO_U_L(toulong);
|
|
|
|
ARITH_DECL_MONO_U_U(neg);
|
|
ARITH_DECL_MONO_U_U(not);
|
|
ARITH_DECL_MONO_U_I(lnot);
|
|
ARITH_DECL_MONO_U_I(lval);
|
|
|
|
ARITH_DECL_BI_UU_U(plus);
|
|
ARITH_DECL_BI_UU_U(minus);
|
|
ARITH_DECL_BI_UI_U(lsh);
|
|
ARITH_DECL_BI_UI_U(rsh);
|
|
ARITH_DECL_BI_UU_I(lt);
|
|
ARITH_DECL_BI_UU_I(leq);
|
|
ARITH_DECL_BI_UU_I(gt);
|
|
ARITH_DECL_BI_UU_I(geq);
|
|
ARITH_DECL_BI_UU_I(same);
|
|
ARITH_DECL_BI_UU_I(neq);
|
|
ARITH_DECL_BI_UU_U(and);
|
|
ARITH_DECL_BI_UU_U(xor);
|
|
ARITH_DECL_BI_UU_U(or);
|
|
ARITH_DECL_BI_UU_U(star);
|
|
ARITH_DECL_BI_UU_U(slash);
|
|
ARITH_DECL_BI_UU_U(pct);
|
|
|
|
/* functions with the signed type */
|
|
|
|
ARITH_DECL_MONO_U_S(to_s);
|
|
ARITH_DECL_MONO_I_S(fromint);
|
|
ARITH_DECL_MONO_L_S(fromlong);
|
|
ARITH_DECL_MONO_S_I(toint);
|
|
ARITH_DECL_MONO_S_L(tolong);
|
|
|
|
ARITH_DECL_MONO_S_S(neg);
|
|
ARITH_DECL_MONO_S_S(not);
|
|
ARITH_DECL_MONO_S_I(lnot);
|
|
ARITH_DECL_MONO_S_I(lval);
|
|
|
|
ARITH_DECL_BI_SS_S(plus);
|
|
ARITH_DECL_BI_SS_S(minus);
|
|
ARITH_DECL_BI_SI_S(lsh);
|
|
ARITH_DECL_BI_SI_S(rsh);
|
|
ARITH_DECL_BI_SS_I(lt);
|
|
ARITH_DECL_BI_SS_I(leq);
|
|
ARITH_DECL_BI_SS_I(gt);
|
|
ARITH_DECL_BI_SS_I(geq);
|
|
ARITH_DECL_BI_SS_I(same);
|
|
ARITH_DECL_BI_SS_I(neq);
|
|
ARITH_DECL_BI_SS_S(and);
|
|
ARITH_DECL_BI_SS_S(xor);
|
|
ARITH_DECL_BI_SS_S(or);
|
|
ARITH_DECL_BI_SS_S(star);
|
|
ARITH_DECL_BI_SS_S(slash);
|
|
ARITH_DECL_BI_SS_S(pct);
|
|
|
|
/* conversions from string */
|
|
ARITH_DECL_MONO_ST_US(octconst);
|
|
ARITH_DECL_MONO_ST_US(hexconst);
|
|
ARITH_DECL_MONO_ST_US(decconst);
|