📄 fold-const.c
字号:
HOST_WIDE_INT lnum_orig, hnum_orig; /* num == numerator == dividend */ HOST_WIDE_INT lden_orig, hden_orig; /* den == denominator == divisor */ HOST_WIDE_INT *lquo, *hquo, *lrem, *hrem;{ int quo_neg = 0; HOST_WIDE_INT num[4 + 1]; /* extra element for scaling. */ HOST_WIDE_INT den[4], quo[4]; register int i, j; unsigned HOST_WIDE_INT work; register unsigned HOST_WIDE_INT carry = 0; HOST_WIDE_INT lnum = lnum_orig; HOST_WIDE_INT hnum = hnum_orig; HOST_WIDE_INT lden = lden_orig; HOST_WIDE_INT hden = hden_orig; int overflow = 0; if ((hden == 0) && (lden == 0)) abort (); /* calculate quotient sign and convert operands to unsigned. */ if (!uns) { if (hnum < 0) { quo_neg = ~ quo_neg; /* (minimum integer) / (-1) is the only overflow case. */ if (neg_double (lnum, hnum, &lnum, &hnum) && (lden & hden) == -1) overflow = 1; } if (hden < 0) { quo_neg = ~ quo_neg; neg_double (lden, hden, &lden, &hden); } } if (hnum == 0 && hden == 0) { /* single precision */ *hquo = *hrem = 0; /* This unsigned division rounds toward zero. */ *lquo = lnum / (unsigned HOST_WIDE_INT) lden; goto finish_up; } if (hnum == 0) { /* trivial case: dividend < divisor */ /* hden != 0 already checked. */ *hquo = *lquo = 0; *hrem = hnum; *lrem = lnum; goto finish_up; } bzero ((char *) quo, sizeof quo); bzero ((char *) num, sizeof num); /* to zero 9th element */ bzero ((char *) den, sizeof den); encode (num, lnum, hnum); encode (den, lden, hden); /* Special code for when the divisor < BASE. */ if (hden == 0 && lden < BASE) { /* hnum != 0 already checked. */ for (i = 4 - 1; i >= 0; i--) { work = num[i] + carry * BASE; quo[i] = work / (unsigned HOST_WIDE_INT) lden; carry = work % (unsigned HOST_WIDE_INT) lden; } } else { /* Full double precision division, with thanks to Don Knuth's "Seminumerical Algorithms". */ int num_hi_sig, den_hi_sig; unsigned HOST_WIDE_INT quo_est, scale; /* Find the highest non-zero divisor digit. */ for (i = 4 - 1; ; i--) if (den[i] != 0) { den_hi_sig = i; break; } /* Insure that the first digit of the divisor is at least BASE/2. This is required by the quotient digit estimation algorithm. */ scale = BASE / (den[den_hi_sig] + 1); if (scale > 1) { /* scale divisor and dividend */ carry = 0; for (i = 0; i <= 4 - 1; i++) { work = (num[i] * scale) + carry; num[i] = LOWPART (work); carry = HIGHPART (work); } num[4] = carry; carry = 0; for (i = 0; i <= 4 - 1; i++) { work = (den[i] * scale) + carry; den[i] = LOWPART (work); carry = HIGHPART (work); if (den[i] != 0) den_hi_sig = i; } } num_hi_sig = 4; /* Main loop */ for (i = num_hi_sig - den_hi_sig - 1; i >= 0; i--) { /* guess the next quotient digit, quo_est, by dividing the first two remaining dividend digits by the high order quotient digit. quo_est is never low and is at most 2 high. */ unsigned HOST_WIDE_INT tmp; num_hi_sig = i + den_hi_sig + 1; work = num[num_hi_sig] * BASE + num[num_hi_sig - 1]; if (num[num_hi_sig] != den[den_hi_sig]) quo_est = work / den[den_hi_sig]; else quo_est = BASE - 1; /* refine quo_est so it's usually correct, and at most one high. */ tmp = work - quo_est * den[den_hi_sig]; if (tmp < BASE && den[den_hi_sig - 1] * quo_est > (tmp * BASE + num[num_hi_sig - 2])) quo_est--; /* Try QUO_EST as the quotient digit, by multiplying the divisor by QUO_EST and subtracting from the remaining dividend. Keep in mind that QUO_EST is the I - 1st digit. */ carry = 0; for (j = 0; j <= den_hi_sig; j++) { work = quo_est * den[j] + carry; carry = HIGHPART (work); work = num[i + j] - LOWPART (work); num[i + j] = LOWPART (work); carry += HIGHPART (work) != 0; } /* if quo_est was high by one, then num[i] went negative and we need to correct things. */ if (num[num_hi_sig] < carry) { quo_est--; carry = 0; /* add divisor back in */ for (j = 0; j <= den_hi_sig; j++) { work = num[i + j] + den[j] + carry; carry = HIGHPART (work); num[i + j] = LOWPART (work); } num [num_hi_sig] += carry; } /* store the quotient digit. */ quo[i] = quo_est; } } decode (quo, lquo, hquo); finish_up: /* if result is negative, make it so. */ if (quo_neg) neg_double (*lquo, *hquo, lquo, hquo); /* compute trial remainder: rem = num - (quo * den) */ mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem); neg_double (*lrem, *hrem, lrem, hrem); add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem); switch (code) { case TRUNC_DIV_EXPR: case TRUNC_MOD_EXPR: /* round toward zero */ case EXACT_DIV_EXPR: /* for this one, it shouldn't matter */ return overflow; case FLOOR_DIV_EXPR: case FLOOR_MOD_EXPR: /* round toward negative infinity */ if (quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio < 0 && rem != 0 */ { /* quo = quo - 1; */ add_double (*lquo, *hquo, (HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, lquo, hquo); } else return overflow; break; case CEIL_DIV_EXPR: case CEIL_MOD_EXPR: /* round toward positive infinity */ if (!quo_neg && (*lrem != 0 || *hrem != 0)) /* ratio > 0 && rem != 0 */ { add_double (*lquo, *hquo, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0, lquo, hquo); } else return overflow; break; case ROUND_DIV_EXPR: case ROUND_MOD_EXPR: /* round to closest integer */ { HOST_WIDE_INT labs_rem = *lrem, habs_rem = *hrem; HOST_WIDE_INT labs_den = lden, habs_den = hden, ltwice, htwice; /* get absolute values */ if (*hrem < 0) neg_double (*lrem, *hrem, &labs_rem, &habs_rem); if (hden < 0) neg_double (lden, hden, &labs_den, &habs_den); /* if (2 * abs (lrem) >= abs (lden)) */ mul_double ((HOST_WIDE_INT) 2, (HOST_WIDE_INT) 0, labs_rem, habs_rem, <wice, &htwice); if (((unsigned HOST_WIDE_INT) habs_den < (unsigned HOST_WIDE_INT) htwice) || (((unsigned HOST_WIDE_INT) habs_den == (unsigned HOST_WIDE_INT) htwice) && ((HOST_WIDE_INT unsigned) labs_den < (unsigned HOST_WIDE_INT) ltwice))) { if (*hquo < 0) /* quo = quo - 1; */ add_double (*lquo, *hquo, (HOST_WIDE_INT) -1, (HOST_WIDE_INT) -1, lquo, hquo); else /* quo = quo + 1; */ add_double (*lquo, *hquo, (HOST_WIDE_INT) 1, (HOST_WIDE_INT) 0, lquo, hquo); } else return overflow; } break; default: abort (); } /* compute true remainder: rem = num - (quo * den) */ mul_double (*lquo, *hquo, lden_orig, hden_orig, lrem, hrem); neg_double (*lrem, *hrem, lrem, hrem); add_double (lnum_orig, hnum_orig, *lrem, *hrem, lrem, hrem); return overflow;}#ifndef REAL_ARITHMETIC/* Effectively truncate a real value to represent the nearest possible value in a narrower mode. The result is actually represented in the same data type as the argument, but its value is usually different. A trap may occur during the FP operations and it is the responsibility of the calling function to have a handler established. */REAL_VALUE_TYPEreal_value_truncate (mode, arg) enum machine_mode mode; REAL_VALUE_TYPE arg;{ return REAL_VALUE_TRUNCATE (mode, arg);}#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT/* Check for infinity in an IEEE double precision number. */inttarget_isinf (x) REAL_VALUE_TYPE x;{ /* The IEEE 64-bit double format. */ union { REAL_VALUE_TYPE d; struct { unsigned sign : 1; unsigned exponent : 11; unsigned mantissa1 : 20; unsigned mantissa2; } little_endian; struct { unsigned mantissa2; unsigned mantissa1 : 20; unsigned exponent : 11; unsigned sign : 1; } big_endian; } u; u.d = dconstm1; if (u.big_endian.sign == 1) { u.d = x; return (u.big_endian.exponent == 2047 && u.big_endian.mantissa1 == 0 && u.big_endian.mantissa2 == 0); } else { u.d = x; return (u.little_endian.exponent == 2047 && u.little_endian.mantissa1 == 0 && u.little_endian.mantissa2 == 0); }}/* Check whether an IEEE double precision number is a NaN. */inttarget_isnan (x) REAL_VALUE_TYPE x;{ /* The IEEE 64-bit double format. */ union { REAL_VALUE_TYPE d; struct { unsigned sign : 1; unsigned exponent : 11; unsigned mantissa1 : 20; unsigned mantissa2; } little_endian; struct { unsigned mantissa2; unsigned mantissa1 : 20; unsigned exponent : 11; unsigned sign : 1; } big_endian; } u; u.d = dconstm1; if (u.big_endian.sign == 1) { u.d = x; return (u.big_endian.exponent == 2047 && (u.big_endian.mantissa1 != 0 || u.big_endian.mantissa2 != 0)); } else { u.d = x; return (u.little_endian.exponent == 2047 && (u.little_endian.mantissa1 != 0 || u.little_endian.mantissa2 != 0)); }}/* Check for a negative IEEE double precision number. */inttarget_negative (x) REAL_VALUE_TYPE x;{ /* The IEEE 64-bit double format. */ union { REAL_VALUE_TYPE d; struct { unsigned sign : 1; unsigned exponent : 11; unsigned mantissa1 : 20; unsigned mantissa2; } little_endian; struct { unsigned mantissa2; unsigned mantissa1 : 20; unsigned exponent : 11; unsigned sign : 1; } big_endian; } u; u.d = dconstm1; if (u.big_endian.sign == 1) { u.d = x; return u.big_endian.sign; } else { u.d = x; return u.little_endian.sign; }}#else /* Target not IEEE *//* Let's assume other float formats don't have infinity. (This can be overridden by redefining REAL_VALUE_ISINF.) */target_isinf (x) REAL_VALUE_TYPE x;{ return 0;}/* Let's assume other float formats don't have NaNs. (This can be overridden by redefining REAL_VALUE_ISNAN.) */target_isnan (x) REAL_VALUE_TYPE x;{ return 0;}/* Let's assume other float formats don't have minus zero. (This can be overridden by redefining REAL_VALUE_NEGATIVE.) */target_negative (x) REAL_VALUE_TYPE x;{ return x < 0;}#endif /* Target not IEEE */#endif /* no REAL_ARITHMETIC *//* Split a tree IN into a constant and a variable part that could be combined with CODE to make IN. CODE must be a commutative arithmetic operation. Store the constant part into *CONP and the variable in &VARP. Return 1 if this was done; zero means the tree IN did not decompose this way. If CODE is PLUS_EXPR we also split trees that use MINUS_EXPR. Therefore, we must tell the caller whether the variable part was subtracted. We do this by storing 1 or -1 into *VARSIGNP. The value stored is the coefficient for the variable term. The constant term we return should always be added; we negate it if necessary. */static intsplit_tree (in, code, varp, conp, varsignp) tree in; enum tree_code code; tree *varp, *conp; int *varsignp;{ register tree outtype = TREE_TYPE (in); *varp = 0; *conp = 0; /* Strip any conversions that don't change the machine mode. */ while ((TREE_CODE (in) == NOP_EXPR || TREE_CODE (in) == CONVERT_EXPR) && (TYPE_MODE (TREE_TYPE (in)) == TYPE_MODE (TREE_TYPE (TREE_OPERAND (in, 0))))) in = TREE_OPERAND (in, 0); if (TREE_CODE (in) == code || (! FLOAT_TYPE_P (TREE_TYPE (in)) /* We can associate addition and subtraction together (even though the C standard doesn't say so) for integers because the value is not affected. For reals, the value might be affected, so we can't. */ && ((code == PLUS_EXPR && TREE_CODE (in) == MINUS_EXPR) || (code == MINUS_EXPR && TREE_CODE (in) == PLUS_EXPR)))) { enum tree_code code = TREE_CODE (TREE_OPERAND (in, 0)); if (code == INTEGER_CST) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -