long mach_long_sign; /* sign bit of the machine long */
int mach_long_size; /* size of long on this machine == sizeof(long) */
long full_mask[MAXSIZE];/* full_mask[1] == 0xFF, full_mask[2] == 0xFFFF, .. */
-long int_mask[MAXSIZE]; /* int_mask[1] == 0x7F, int_mask[2] == 0x7FFF, .. */
-arith max_int; /* maximum integer on target machine */
+long max_int[MAXSIZE]; /* max_int[1] == 0x7F, max_int[2] == 0x7FFF, .. */
+long min_int[MAXSIZE]; /* min_int[1] == 0xFFFFFF80, min_int[2] = 0xFFFF8000,
+ ...
+ */
unsigned int wrd_bits; /* number of bits in a word */
extern char options[];
-static char ovflow[] = "overflow in constant expression";
+overflow(expp)
+ t_node *expp;
+{
+ node_warning(expp, W_ORDINARY, "overflow in constant expression");
+}
+
+arith
+ar_abs(i)
+ arith i;
+{
+
+ return i < 0 ? -i : i;
+}
cstunary(expp)
register t_node *expp;
*/
case '-':
- if (right->nd_INT < -int_mask[(int)(right->nd_type->tp_size)])
- node_warning(expp, W_ORDINARY, ovflow);
+ if (right->nd_INT == min_int[(int)(right->nd_type->tp_size)])
+ overflow(expp);
expp->nd_INT = -right->nd_INT;
break;
}
STATIC
-divide(pdiv, prem, uns)
+divide(pdiv, prem)
arith *pdiv, *prem;
{
- /* Divide *pdiv by *prem, and store result in *pdiv,
+ /* Unsigned divide *pdiv by *prem, and store result in *pdiv,
remainder in *prem
*/
register arith o1 = *pdiv;
register arith o2 = *prem;
- if (uns) {
- /* this is more of a problem than you might
- think on C compilers which do not have
- unsigned long.
- */
- if (o2 & mach_long_sign) {/* o2 > max_long */
- if (! (o1 >= 0 || o1 < o2)) {
- /* this is the unsigned test
- o1 < o2 for o2 > max_long
- */
- *prem = o2 - o1;
- *pdiv = 1;
- }
- else {
- *pdiv = 0;
- }
+ /* this is more of a problem than you might
+ think on C compilers which do not have
+ unsigned long.
+ */
+ if (o2 & mach_long_sign) {/* o2 > max_long */
+ if (! (o1 >= 0 || o1 < o2)) {
+ /* this is the unsigned test
+ o1 < o2 for o2 > max_long
+ */
+ *prem = o2 - o1;
+ *pdiv = 1;
}
- else { /* o2 <= max_long */
- long half, bit, hdiv, hrem, rem;
-
- half = (o1 >> 1) & ~mach_long_sign;
- bit = o1 & 01;
- /* now o1 == 2 * half + bit
- and half <= max_long
- and bit <= max_long
+ else {
+ *pdiv = 0;
+ }
+ }
+ else { /* o2 <= max_long */
+ long half, bit, hdiv, hrem, rem;
+
+ half = (o1 >> 1) & ~mach_long_sign;
+ bit = o1 & 01;
+ /* now o1 == 2 * half + bit
+ and half <= max_long
+ and bit <= max_long
+ */
+ hdiv = half / o2;
+ hrem = half % o2;
+ rem = 2 * hrem + bit;
+ *pdiv = 2*hdiv;
+ *prem = rem;
+ if (rem < 0 || rem >= o2) {
+ /* that is the unsigned compare
+ rem >= o2 for o2 <= max_long
*/
- hdiv = half / o2;
- hrem = half % o2;
- rem = 2 * hrem + bit;
- *pdiv = 2*hdiv;
- *prem = rem;
- if (rem < 0 || rem >= o2) {
- /* that is the unsigned compare
- rem >= o2 for o2 <= max_long
- */
- *pdiv += 1;
- *prem -= o2;
- }
+ *pdiv += 1;
+ *prem -= o2;
}
}
- else {
- *pdiv = o1 / o2; /* ??? */
- *prem = o1 - *pdiv * o2;
+}
+
+cstibin(expp)
+ register t_node *expp;
+{
+ /* The binary operation in "expp" is performed on the constant
+ expressions below it, and the result restored in expp.
+ This version is for INTEGER expressions.
+ */
+ arith o1 = expp->nd_left->nd_INT;
+ arith o2 = expp->nd_right->nd_INT;
+ register int sz = expp->nd_type->tp_size;
+
+ assert(expp->nd_class == Oper);
+ assert(expp->nd_left->nd_class == Value);
+ assert(expp->nd_right->nd_class == Value);
+
+ switch (expp->nd_symb) {
+ case '*':
+ if (o1 == 0 || o2 == 0) {
+ o1 = 0;
+ break;
+ }
+ if ((o1 > 0 && o2 > 0) || (o1 < 0 && o2 < 0)) {
+ if (o1 == min_int[sz] ||
+ o2 == min_int[sz] ||
+ max_int[sz] / ar_abs(o1) < ar_abs(o2)) overflow(expp);
+ }
+ else if (o1 > 0) {
+ if (min_int[sz] / o1 > o2) overflow(expp);
+ }
+ else if (min_int[sz] / o2 > o1) overflow(expp);
+ o1 *= o2;
+ break;
+
+ case DIV:
+ if (o2 == 0) {
+ node_error(expp, "division by 0");
+ return;
+ }
+ o1 /= o2; /* ??? */
+ break;
+
+ case MOD:
+ if (o2 == 0) {
+ node_error(expp, "modulo by 0");
+ return;
+ }
+ o1 %= o2; /* ??? */
+ break;
+
+ case '+':
+ if (o1 > 0 && o2 > 0) {
+ if (max_int[sz] - o1 < o2) overflow(expp);
+ }
+ else if (o1 < 0 && o2 < 0) {
+ if (min_int[sz] - o1 > o2) overflow(expp);
+ }
+ o1 += o2;
+ break;
+
+ case '-':
+ if (o1 >= 0 && o2 < 0) {
+ if (max_int[sz] + o2 < o1) overflow(expp);
+ }
+ else if (o1 < 0 && o2 >= 0) {
+ if (min_int[sz] + o2 > o1) overflow(expp);
+ }
+ o1 -= o2;
+ break;
+
+ case '<':
+ { arith tmp = o1;
+
+ o1 = o2;
+ o2 = tmp;
+ }
+ /* Fall through */
+
+ case '>':
+ o1 = (o1 > o2);
+ break;
+
+ case LESSEQUAL:
+ { arith tmp = o1;
+
+ o1 = o2;
+ o2 = tmp;
+ }
+ /* Fall through */
+
+ case GREATEREQUAL:
+ o1 = chk_bounds(o2, o1, T_INTEGER);
+ break;
+
+ case '=':
+ o1 = (o1 == o2);
+ break;
+
+ case '#':
+ o1 = (o1 != o2);
+ break;
+
+ default:
+ crash("(cstibin)");
}
+
+ expp->nd_class = Value;
+ expp->nd_token = expp->nd_right->nd_token;
+ expp->nd_INT = o1;
+ CutSize(expp);
+ FreeNode(expp->nd_left);
+ FreeNode(expp->nd_right);
+ expp->nd_left = expp->nd_right = 0;
}
-cstbin(expp)
+cstubin(expp)
register t_node *expp;
{
/* The binary operation in "expp" is performed on the constant
*/
arith o1 = expp->nd_left->nd_INT;
arith o2 = expp->nd_right->nd_INT;
- register int uns = expp->nd_left->nd_type != int_type;
+ register int sz = expp->nd_type->tp_size;
+ arith tmp1, tmp2;
assert(expp->nd_class == Oper);
assert(expp->nd_left->nd_class == Value);
switch (expp->nd_symb) {
case '*':
+ if (o1 == 0 || o2 == 0) {
+ o1 = 0;
+ break;
+ }
+ tmp1 = full_mask[sz];
+ tmp2 = o2;
+ divide(&tmp1, &tmp2);
+ if (! chk_bounds(o1, tmp1, T_CARDINAL)) overflow(expp);
o1 *= o2;
break;
node_error(expp, "division by 0");
return;
}
- divide(&o1, &o2, uns);
+ divide(&o1, &o2);
break;
case MOD:
node_error(expp, "modulo by 0");
return;
}
- divide(&o1, &o2, uns);
+ divide(&o1, &o2);
o1 = o2;
break;
case '+':
+ if (! chk_bounds(o2, full_mask[sz] - o1, T_CARDINAL)) {
+ overflow(expp);
+ }
o1 += o2;
break;
case '-':
- o1 -= o2;
- if (expp->nd_type->tp_fund == T_INTORCARD) {
- if (o1 < 0) expp->nd_type = int_type;
+ if (! chk_bounds(o2, o1, T_CARDINAL)) {
+ if (expp->nd_type->tp_fund == T_INTORCARD) {
+ expp->nd_type = int_type;
+ if (! chk_bounds(min_int[sz], o1 - o2, T_CARDINAL)) {
+ overflow();
+ }
+ }
+ else overflow();
}
+ o1 -= o2;
break;
case '<':
/* Fall through */
case '>':
- if (uns) {
- o1 = (o1 & mach_long_sign ?
- (o2 & mach_long_sign ? o1 > o2 : 1) :
- (o2 & mach_long_sign ? 0 : o1 > o2)
- );
- }
- else
- o1 = (o1 > o2);
+ o1 = ! chk_bounds(o1, o2, T_CARDINAL);
break;
case LESSEQUAL:
/* Fall through */
case GREATEREQUAL:
- o1 = chk_bounds(o2, o1, uns ? T_CARDINAL : T_INTEGER);
+ o1 = chk_bounds(o2, o1, T_CARDINAL);
break;
case '=':
break;
default:
- crash("(cstbin)");
+ crash("(cstubin)");
}
expp->nd_class = Value;
expp->nd_symb = INTEGER;
switch(call) {
case S_ABS:
- if (expr->nd_INT < 0) expp->nd_INT = - expr->nd_INT;
+ if (expr->nd_INT < 0) {
+ if (expr->nd_INT <= min_int[(int)(tp->tp_size)]) {
+ overflow(expr);
+ }
+ expp->nd_INT = - expr->nd_INT;
+ }
else expp->nd_INT = expr->nd_INT;
CutSize(expp);
break;
case S_MAX:
if (tp->tp_fund == T_INTEGER) {
- expp->nd_INT = int_mask[(int)(tp->tp_size)];
+ expp->nd_INT = max_int[(int)(tp->tp_size)];
}
else if (tp == card_type) {
expp->nd_INT = full_mask[(int)(int_size)];
case S_MIN:
if (tp->tp_fund == T_INTEGER) {
- expp->nd_INT = -int_mask[(int)(tp->tp_size)];
- if (! options['s']) expp->nd_INT--;
+ expp->nd_INT = min_int[(int)(tp->tp_size)];
}
else if (tp->tp_fund == T_SUBRANGE) {
expp->nd_INT = tp->sub_lb;
/* The constant value of the expression expr is made to
conform to the size of the type of the expression.
*/
- register arith o1 = expr->nd_INT;
register t_type *tp = BaseType(expr->nd_type);
- int uns;
- int size = tp->tp_size;
assert(expr->nd_class == Value);
- uns = (tp->tp_fund & (T_CARDINAL|T_CHAR));
- if (uns) {
- if (o1 & ~full_mask[size]) {
- node_warning(expr, W_ORDINARY, ovflow);
- o1 &= full_mask[size];
- }
+ if (tp->tp_fund != T_INTEGER) {
+ expr->nd_INT &= full_mask[tp->tp_size];
}
else {
- int nbits = (int) (mach_long_size - size) * 8;
- long remainder = o1 & ~int_mask[size];
+ int nbits = (int) (mach_long_size - tp->tp_size) * 8;
- if (remainder != 0 && remainder != ~int_mask[size]) {
- node_warning(expr, W_ORDINARY, ovflow);
- o1 <<= nbits;
- o1 >>= nbits;
- }
+ expr->nd_INT <<= nbits;
+ expr->nd_INT >>= nbits;
}
- expr->nd_INT = o1;
}
InitCst()
if (i == MAXSIZE)
fatal("array full_mask too small for this machine");
full_mask[i] = bt;
- int_mask[i] = bt & ~(1L << ((i << 3) - 1));
+ max_int[i] = bt & ~(1L << ((i << 3) - 1));
+ min_int[i] = - max_int[i];
+ if (! options['s']) min_int[i]--;
}
mach_long_size = i;
mach_long_sign = 1L << (mach_long_size * 8 - 1);
fatal("sizeof (long) insufficient on this machine");
}
- max_int = int_mask[(int)int_size];
wrd_bits = 8 * (unsigned) word_size;
}