fold-const.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,288 行 · 第 1/5 页
C
2,288 行
return 0; } set_float_handler (float_error); /* Domain check the argument. */ x.d = *r; if (x.d == 0.0) goto fail;#ifdef REAL_INFINITY if (REAL_VALUE_ISINF (x.d) || REAL_VALUE_ISNAN (x.d)) goto fail;#endif /* Compute the reciprocal and check for numerical exactness. It is unnecessary to check all the significand bits to determine whether X is a power of 2. If X is not, then it is impossible for the bottom half significand of both X and 1/X to be all zero bits. Hence we ignore the data structure of the top half and examine only the low order bits of the two significands. */ t.d = 1.0 / x.d; if (x.i[K] != 0 || x.i[K + 1] != 0 || t.i[K] != 0 || t.i[K + 1] != 0) goto fail; /* Truncate to the required mode and range-check the result. */ y.d = REAL_VALUE_TRUNCATE (mode, t.d);#ifdef CHECK_FLOAT_VALUE i = 0; if (CHECK_FLOAT_VALUE (mode, y.d, i)) goto fail;#endif /* Fail if truncation changed the value. */ if (y.d != t.d || y.d == 0.0) goto fail;#ifdef REAL_INFINITY if (REAL_VALUE_ISINF (y.d) || REAL_VALUE_ISNAN (y.d)) goto fail;#endif /* Output the reciprocal and return success flag. */ set_float_handler (NULL_PTR); *r = y.d; return 1;}#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) { *conp = TREE_OPERAND (in, 0); *varp = TREE_OPERAND (in, 1); if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) && TREE_TYPE (*varp) != outtype) *varp = convert (outtype, *varp); *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; return 1; } if (TREE_CONSTANT (TREE_OPERAND (in, 1))) { *conp = TREE_OPERAND (in, 1); *varp = TREE_OPERAND (in, 0); *varsignp = 1; if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) && TREE_TYPE (*varp) != outtype) *varp = convert (outtype, *varp); if (TREE_CODE (in) == MINUS_EXPR) { /* If operation is subtraction and constant is second, must negate it to get an additive constant. And this cannot be done unless it is a manifest constant. It could also be the address of a static variable. We cannot negate that, so give up. */ if (TREE_CODE (*conp) == INTEGER_CST) /* Subtracting from integer_zero_node loses for long long. */ *conp = fold (build1 (NEGATE_EXPR, TREE_TYPE (*conp), *conp)); else return 0; } return 1; } if (TREE_CONSTANT (TREE_OPERAND (in, 0))) { *conp = TREE_OPERAND (in, 0); *varp = TREE_OPERAND (in, 1); if (TYPE_MODE (TREE_TYPE (*varp)) != TYPE_MODE (outtype) && TREE_TYPE (*varp) != outtype) *varp = convert (outtype, *varp); *varsignp = (TREE_CODE (in) == MINUS_EXPR) ? -1 : 1; return 1; } } return 0;}/* Combine two integer constants ARG1 and ARG2 under operation CODE to produce a new constant. If NOTRUNC is nonzero, do not truncate the result to fit the data type. If FORSIZE is nonzero, compute overflow for unsigned types. */static treeint_const_binop (code, arg1, arg2, notrunc, forsize) enum tree_code code; register tree arg1, arg2; int notrunc, forsize;{ HOST_WIDE_INT int1l, int1h, int2l, int2h; HOST_WIDE_INT low, hi; HOST_WIDE_INT garbagel, garbageh; register tree t; int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); int overflow = 0; int no_overflow = 0; int1l = TREE_INT_CST_LOW (arg1); int1h = TREE_INT_CST_HIGH (arg1); int2l = TREE_INT_CST_LOW (arg2); int2h = TREE_INT_CST_HIGH (arg2); switch (code) { case BIT_IOR_EXPR: low = int1l | int2l, hi = int1h | int2h; break; case BIT_XOR_EXPR: low = int1l ^ int2l, hi = int1h ^ int2h; break; case BIT_AND_EXPR: low = int1l & int2l, hi = int1h & int2h; break; case BIT_ANDTC_EXPR: low = int1l & ~int2l, hi = int1h & ~int2h; break; case RSHIFT_EXPR: int2l = - int2l; case LSHIFT_EXPR: /* It's unclear from the C standard whether shifts can overflow. The following code ignores overflow; perhaps a C standard interpretation ruling is needed. */ lshift_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)), &low, &hi, !uns); no_overflow = 1; break; case RROTATE_EXPR: int2l = - int2l; case LROTATE_EXPR: lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)), &low, &hi); break; case PLUS_EXPR: overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); break; case MINUS_EXPR: neg_double (int2l, int2h, &low, &hi); add_double (int1l, int1h, low, hi, &low, &hi); overflow = overflow_sum_sign (hi, int2h, int1h); break; case MULT_EXPR: overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); break; case TRUNC_DIV_EXPR: case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: case EXACT_DIV_EXPR: /* This is a shortcut for a common special case. */ if (int2h == 0 && int2l > 0 && ! TREE_CONSTANT_OVERFLOW (arg1) && ! TREE_CONSTANT_OVERFLOW (arg2) && int1h == 0 && int1l >= 0) { if (code == CEIL_DIV_EXPR) int1l += int2l - 1; low = int1l / int2l, hi = 0; break; } /* ... fall through ... */ case ROUND_DIV_EXPR: if (int2h == 0 && int2l == 1) { low = int1l, hi = int1h; break; } if (int1l == int2l && int1h == int2h && ! (int1l == 0 && int1h == 0)) { low = 1, hi = 0; break; } overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h, &low, &hi, &garbagel, &garbageh); break; case TRUNC_MOD_EXPR: case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: /* This is a shortcut for a common special case. */ if (int2h == 0 && int2l > 0 && ! TREE_CONSTANT_OVERFLOW (arg1) && ! TREE_CONSTANT_OVERFLOW (arg2) && int1h == 0 && int1l >= 0) { if (code == CEIL_MOD_EXPR) int1l += int2l - 1; low = int1l % int2l, hi = 0; break; } /* ... fall through ... */ case ROUND_MOD_EXPR: overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h, &garbagel, &garbageh, &low, &hi); break; case MIN_EXPR: case MAX_EXPR: if (uns) { low = (((unsigned HOST_WIDE_INT) int1h < (unsigned HOST_WIDE_INT) int2h) || (((unsigned HOST_WIDE_INT) int1h == (unsigned HOST_WIDE_INT) int2h) && ((unsigned HOST_WIDE_INT) int1l < (unsigned HOST_WIDE_INT) int2l))); } else { low = ((int1h < int2h) || ((int1h == int2h) && ((unsigned HOST_WIDE_INT) int1l < (unsigned HOST_WIDE_INT) int2l))); } if (low == (code == MIN_EXPR)) low = int1l, hi = int1h; else low = int2l, hi = int2h; break; default: abort (); } if (TREE_TYPE (arg1) == sizetype && hi == 0 && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)) && ! overflow && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2)) t = size_int (low); else { t = build_int_2 (low, hi); TREE_TYPE (t) = TREE_TYPE (arg1); } TREE_OVERFLOW (t) = ((notrunc ? (!uns || forsize) && overflow : force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow) | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)); /* If we're doing a size calculation, unsigned arithmetic does overflow. So check if force_fit_type truncated the value. */ if (forsize && ! TREE_OVERFLOW (t) && (TREE_INT_CST_HIGH (t) != hi || TREE_INT_CST_LOW (t) != low)) TREE_OVERFLOW (t) = 1; TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2)); return t;}/* Combine two constants ARG1 and ARG2 under operation CODE to produce a new constant. We assume ARG1 and ARG2 have the same data type, or at least are the same kind of constant and the same machine mode. If NOTRUNC is nonzero, do not truncate the result to fit the data type. */static treeconst_binop (code, arg1, arg2, notrunc) enum tree_code code; register tree arg1, arg2; int notrunc;{ STRIP_NOPS (arg1); STRIP_NOPS (arg2); if (TREE_CODE (arg1) == INTEGER_CST) return int_const_binop (code, arg1, arg2, notrunc, 0);#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) if (TREE_CODE (arg1) == REAL_CST) { REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d2; int overflow = 0; REAL_VALUE_TYPE value; tree t; d1 = TREE_REAL_CST (arg1); d2 = TREE_REAL_CST (arg2); /* If either operand is a NaN, just return it. Otherwise, set up for floating-point trap; we return an overflow. */ if (REAL_VALUE_ISNAN (d1)) return arg1; else if (REAL_VALUE_ISNAN (d2)) return arg2; else if (setjmp (float_error)) { t = copy_node (arg1); overflow = 1; goto got_float; } set_float_handler (float_error);#ifdef REAL_ARITHMETIC REAL_ARITHMETIC (value, code, d1, d2);#else switch (code) { case PLUS_EXPR: value = d1 + d2; break; case MINUS_EXPR: value = d1 - d2; break; case MULT_EXPR: value = d1 * d2; break; case RDIV_EXPR:#ifndef REAL_INFINITY if (d2 == 0) abort ();#endif value = d1 / d2; break; case MIN_EXPR: value = MIN (d1, d2); break; case MAX_EXPR: value = MAX (d1, d2); break; default: abort (); }#endif /* no REAL_ARITHMETIC */ t = build_real (TREE_TYPE (arg1), real_value_truncate (TYPE_MODE (TREE_TYPE (arg1)), value)); got_float: set_float_handler (NULL_PTR); TREE_OVERFLOW (t) = (force_fit_type (t, overflow) | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2)); TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2); return t; }#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ if (TREE_CODE (arg1) == COMPLEX_CST) { register tree type = TREE_TYPE (arg1); register tree r1 = TREE_REALPART (arg1); register tree i1 = TREE_IMAGPART (arg1); register tree r2 = TREE_REALPART (arg2); register tree i2 = TREE_IMAGPART (arg2); register tree t; switch (code) { case PLUS_EXPR: t = build_complex (type, const_binop (PLUS_EXPR, r1, r2, notrunc), const_binop (PLUS_EXPR, i1, i2, notrunc)); break; case MINUS_EXPR: t = build_complex (type, const_binop (MINUS_EXPR, r1, r2, notrunc), const_binop (MINUS_EXPR, i1, i2, notrunc)); break; case MULT_EXPR: t = build_complex (type, const_binop (MINUS_EXPR, const_binop (MULT_EXPR, r1, r2, notrunc), const_binop (MULT_EXPR, i1, i2, notrunc), notrunc), const_binop (PLUS_EXPR,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?