📄 fold-const.c
字号:
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 || (TREE_CODE (TREE_TYPE (in)) != REAL_TYPE /* 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 constants NUM 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. */static treeconst_binop (code, arg1, arg2) enum tree_code code; register tree arg1, arg2;{ if (TREE_CODE (arg1) == INTEGER_CST) { register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1); register HOST_WIDE_INT int1h = TREE_INT_CST_HIGH (arg1); HOST_WIDE_INT int2l = TREE_INT_CST_LOW (arg2); HOST_WIDE_INT int2h = TREE_INT_CST_HIGH (arg2); HOST_WIDE_INT low, hi; HOST_WIDE_INT garbagel, garbageh; register tree t; int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); /* Propagate overflow flags from operands; also record new overflow. */ int overflow = TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2); switch (code) { case BIT_IOR_EXPR: t = build_int_2 (int1l | int2l, int1h | int2h); break; case BIT_XOR_EXPR: t = build_int_2 (int1l ^ int2l, int1h ^ int2h); break; case BIT_AND_EXPR: t = build_int_2 (int1l & int2l, int1h & int2h); break; case BIT_ANDTC_EXPR: t = build_int_2 (int1l & ~int2l, int1h & ~int2h); break; case RSHIFT_EXPR: int2l = - int2l; case LSHIFT_EXPR: overflow = lshift_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)), &low, &hi, !uns); t = build_int_2 (low, hi); break; case RROTATE_EXPR: int2l = - int2l; case LROTATE_EXPR: lrotate_double (int1l, int1h, int2l, TYPE_PRECISION (TREE_TYPE (arg1)), &low, &hi); t = build_int_2 (low, hi); break; case PLUS_EXPR: if (int1h == 0) { int2l += int1l; if ((unsigned HOST_WIDE_INT) int2l < int1l) { hi = int2h++; overflow = ! same_sign (hi, int2h); } t = build_int_2 (int2l, int2h); break; } if (int2h == 0) { int1l += int2l; if ((unsigned HOST_WIDE_INT) int1l < int2l) { hi = int1h++; overflow = ! same_sign (hi, int1h); } t = build_int_2 (int1l, int1h); break; } overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); t = build_int_2 (low, hi); break; case MINUS_EXPR: if (int2h == 0 && int2l == 0) { t = build_int_2 (int1l, int1h); break; } neg_double (int2l, int2h, &low, &hi); add_double (int1l, int1h, low, hi, &low, &hi); overflow = overflow_sum_sign (hi, int2h, int1h); t = build_int_2 (low, hi); break; case MULT_EXPR: /* Optimize simple cases. */ if (int1h == 0) { unsigned HOST_WIDE_INT temp; switch (int1l) { case 0: t = build_int_2 (0, 0); goto got_it; case 1: t = build_int_2 (int2l, int2h); goto got_it; case 2: overflow = left_shift_overflows (int2h, 1); temp = int2l + int2l; int2h = (int2h << 1) + (temp < int2l); t = build_int_2 (temp, int2h); goto got_it;#if 0 /* This code can lose carries. */ case 3: temp = int2l + int2l + int2l; int2h = int2h * 3 + (temp < int2l); t = build_int_2 (temp, int2h); goto got_it;#endif case 4: overflow = left_shift_overflows (int2h, 2); temp = int2l + int2l; int2h = (int2h << 2) + ((temp < int2l) << 1); int2l = temp; temp += temp; int2h += (temp < int2l); t = build_int_2 (temp, int2h); goto got_it; case 8: overflow = left_shift_overflows (int2h, 3); temp = int2l + int2l; int2h = (int2h << 3) + ((temp < int2l) << 2); int2l = temp; temp += temp; int2h += (temp < int2l) << 1; int2l = temp; temp += temp; int2h += (temp < int2l); t = build_int_2 (temp, int2h); goto got_it; default: break; } } if (int2h == 0) { if (int2l == 0) { t = build_int_2 (0, 0); break; } if (int2l == 1) { t = build_int_2 (int1l, int1h); break; } } overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); t = build_int_2 (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. It reduces the number of tree nodes generated and saves time. */ if (int2h == 0 && int2l > 0 && TREE_TYPE (arg1) == sizetype && int1h == 0 && int1l >= 0) { if (code == CEIL_DIV_EXPR) int1l += int2l-1; return size_int (int1l / int2l); } case ROUND_DIV_EXPR: if (int2h == 0 && int2l == 1) { t = build_int_2 (int1l, int1h); break; } if (int1l == int2l && int1h == int2h) { if ((int1l | int1h) == 0) abort (); t = build_int_2 (1, 0); break; } overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h, &low, &hi, &garbagel, &garbageh); t = build_int_2 (low, hi); break; case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR: case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: overflow = div_and_round_double (code, uns, int1l, int1h, int2l, int2h, &garbagel, &garbageh, &low, &hi); t = build_int_2 (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)) t = build_int_2 (int1l, int1h); else t = build_int_2 (int2l, int2h); break; default: abort (); } got_it: TREE_TYPE (t) = TREE_TYPE (arg1); force_fit_type (t); TREE_CONSTANT_OVERFLOW (t) = overflow; return t; }#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) if (TREE_CODE (arg1) == REAL_CST) { register REAL_VALUE_TYPE d1; register REAL_VALUE_TYPE d2; register REAL_VALUE_TYPE value; tree t; d1 = TREE_REAL_CST (arg1); d2 = TREE_REAL_CST (arg2); if (setjmp (float_error)) { pedwarn ("floating overflow in constant expression"); return build (code, TREE_TYPE (arg1), arg1, arg2); } 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)); set_float_handler (NULL_PTR); return t; }#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ if (TREE_CODE (arg1) == COMPLEX_CST) { 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 (const_binop (PLUS_EXPR, r1, r2), const_binop (PLUS_EXPR, i1, i2)); break; case MINUS_EXPR: t = build_complex (const_binop (MINUS_EXPR, r1, r2), const_binop (MINUS_EXPR, i1, i2)); break; case MULT_EXPR: t = build_complex (const_binop (MINUS_EXPR, const_binop (MULT_EXPR, r1, r2), const_binop (MULT_EXPR, i1, i2)), const_binop (PLUS_EXPR, const_binop (MULT_EXPR, r1, i2), const_binop (MULT_EXPR, i1, r2))); break; case RDIV_EXPR: { register tree magsquared = const_binop (PLUS_EXPR, const_binop (MULT_EXPR, r2, r2), const_binop (MULT_EXPR, i2, i2)); t = build_complex (const_binop (RDIV_EXPR, const_binop (PLUS_EXPR, const_binop (MULT_EXPR, r1, r2), const_binop (MULT_EXPR, i1, i2)), magsquared), const_binop (RDIV_EXPR, const_binop (MINUS_EXPR, const_binop (MULT_EXPR, i1, r2), const_binop (MULT_EXPR, r1, i2)), magsquared)); } break; default: abort (); } TREE_TYPE (t) = TREE_TYPE (arg1); return t; } return 0;}/* Return an INTEGER_CST with value V and type from `sizetype'. */treesize_int (number) unsigned int number;{ register tree t; /* Type-size nodes already made for small sizes. */ static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1]; if (number >= 0 && number < 2*HOST_BITS_PER_WIDE_INT + 1 && size_table[number] != 0) return size_table[number]; if (number >= 0 && number < 2*HOST_BITS_PER_WIDE_INT + 1) { push_obstacks_nochange (); /* Make this a permanent node. */ end_temporary_allocation (); t = build_int_2 (number, 0); TREE_TYPE (t) = sizetype; size_table[number] = t; pop_obstacks (); } else { t = build_int_2 (number, 0); TREE_TYPE (t) = sizetype; } return t;}/* Combine operands OP1 and OP2 with arithmetic operation CODE. CODE is a tree code. Data type is taken from `sizetype', If the operands are constant, so is the result. */treesize_binop (code, arg0, arg1) enum tree_code code; tree arg0, arg1;{ /* Handle the special case of two integer constants faster. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -