fold-const.c
来自「GCC编译器源代码」· C语言 代码 · 共 2,288 行 · 第 1/5 页
C
2,288 行
const_binop (MULT_EXPR, r1, i2, notrunc), const_binop (MULT_EXPR, i1, r2, notrunc), notrunc)); break; case RDIV_EXPR: { register tree magsquared = const_binop (PLUS_EXPR, const_binop (MULT_EXPR, r2, r2, notrunc), const_binop (MULT_EXPR, i2, i2, notrunc), notrunc); t = build_complex (type, const_binop (INTEGRAL_TYPE_P (TREE_TYPE (r1)) ? TRUNC_DIV_EXPR : RDIV_EXPR, const_binop (PLUS_EXPR, const_binop (MULT_EXPR, r1, r2, notrunc), const_binop (MULT_EXPR, i1, i2, notrunc), notrunc), magsquared, notrunc), const_binop (INTEGRAL_TYPE_P (TREE_TYPE (r1)) ? TRUNC_DIV_EXPR : RDIV_EXPR, const_binop (MINUS_EXPR, const_binop (MULT_EXPR, i1, r2, notrunc), const_binop (MULT_EXPR, r1, i2, notrunc), notrunc), magsquared, notrunc)); } break; default: abort (); } return t; } return 0;}/* Return an INTEGER_CST with value V and type from `sizetype'. */treesize_int (number) unsigned HOST_WIDE_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 < 2*HOST_BITS_PER_WIDE_INT + 1 && size_table[number] != 0) return size_table[number]; if (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; TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0); } 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. */ if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) { /* And some specific cases even faster than that. */ if (code == PLUS_EXPR && integer_zerop (arg0)) return arg1; else if ((code == MINUS_EXPR || code == PLUS_EXPR) && integer_zerop (arg1)) return arg0; else if (code == MULT_EXPR && integer_onep (arg0)) return arg1; /* Handle general case of two integer constants. */ return int_const_binop (code, arg0, arg1, 0, 1); } if (arg0 == error_mark_node || arg1 == error_mark_node) return error_mark_node; return fold (build (code, sizetype, arg0, arg1));}/* Given T, a tree representing type conversion of ARG1, a constant, return a constant tree representing the result of conversion. */static treefold_convert (t, arg1) register tree t; register tree arg1;{ register tree type = TREE_TYPE (t); int overflow = 0; if (TREE_CODE (type) == POINTER_TYPE || INTEGRAL_TYPE_P (type)) { if (TREE_CODE (arg1) == INTEGER_CST) { /* If we would build a constant wider than GCC supports, leave the conversion unfolded. */ if (TYPE_PRECISION (type) > 2 * HOST_BITS_PER_WIDE_INT) return t; /* Given an integer constant, make new constant with new type, appropriately sign-extended or truncated. */ t = build_int_2 (TREE_INT_CST_LOW (arg1), TREE_INT_CST_HIGH (arg1)); TREE_TYPE (t) = type; /* Indicate an overflow if (1) ARG1 already overflowed, or (2) force_fit_type indicates an overflow. Tell force_fit_type that an overflow has already occurred if ARG1 is a too-large unsigned value and T is signed. But don't indicate an overflow if converting a pointer. */ TREE_OVERFLOW (t) = (TREE_OVERFLOW (arg1) || (force_fit_type (t, (TREE_INT_CST_HIGH (arg1) < 0 & (TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (arg1))))) && TREE_CODE (TREE_TYPE (arg1)) != POINTER_TYPE)); TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1); }#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) else if (TREE_CODE (arg1) == REAL_CST) { /* Don't initialize these, use assignments. Initialized local aggregates don't work on old compilers. */ REAL_VALUE_TYPE x; REAL_VALUE_TYPE l; REAL_VALUE_TYPE u; tree type1 = TREE_TYPE (arg1); x = TREE_REAL_CST (arg1); l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type)); u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type)); /* See if X will be in range after truncation towards 0. To compensate for truncation, move the bounds away from 0, but reject if X exactly equals the adjusted bounds. */#ifdef REAL_ARITHMETIC REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1); REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);#else l--; u++;#endif /* If X is a NaN, use zero instead and show we have an overflow. Otherwise, range check. */ if (REAL_VALUE_ISNAN (x)) overflow = 1, x = dconst0; else if (! (REAL_VALUES_LESS (l, x) && REAL_VALUES_LESS (x, u))) overflow = 1;#ifndef REAL_ARITHMETIC { HOST_WIDE_INT low, high; HOST_WIDE_INT half_word = (HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2); if (x < 0) x = -x; high = (HOST_WIDE_INT) (x / half_word / half_word); x -= (REAL_VALUE_TYPE) high * half_word * half_word; if (x >= (REAL_VALUE_TYPE) half_word * half_word / 2) { low = x - (REAL_VALUE_TYPE) half_word * half_word / 2; low |= (HOST_WIDE_INT) -1 << (HOST_BITS_PER_WIDE_INT - 1); } else low = (HOST_WIDE_INT) x; if (TREE_REAL_CST (arg1) < 0) neg_double (low, high, &low, &high); t = build_int_2 (low, high); }#else { HOST_WIDE_INT low, high; REAL_VALUE_TO_INT (&low, &high, x); t = build_int_2 (low, high); }#endif TREE_TYPE (t) = type; TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | force_fit_type (t, overflow); TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1); }#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ TREE_TYPE (t) = type; } else if (TREE_CODE (type) == REAL_TYPE) {#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) if (TREE_CODE (arg1) == INTEGER_CST) return build_real_from_int_cst (type, arg1);#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */ if (TREE_CODE (arg1) == REAL_CST) { if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1))) { t = arg1; TREE_TYPE (arg1) = type; return t; } else if (setjmp (float_error)) { overflow = 1; t = copy_node (arg1); goto got_it; } set_float_handler (float_error); t = build_real (type, real_value_truncate (TYPE_MODE (type), TREE_REAL_CST (arg1))); set_float_handler (NULL_PTR); got_it: TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | force_fit_type (t, overflow); TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1); return t; } } TREE_CONSTANT (t) = 1; return t;}/* Return an expr equal to X but certainly not valid as an lvalue. Also make sure it is not valid as an null pointer constant. */treenon_lvalue (x) tree x;{ tree result; /* These things are certainly not lvalues. */ if (TREE_CODE (x) == NON_LVALUE_EXPR || TREE_CODE (x) == INTEGER_CST || TREE_CODE (x) == REAL_CST || TREE_CODE (x) == STRING_CST || TREE_CODE (x) == ADDR_EXPR) { if (TREE_CODE (x) == INTEGER_CST && integer_zerop (x)) { /* Use NOP_EXPR instead of NON_LVALUE_EXPR so convert_for_assignment won't strip it. This is so this 0 won't be treated as a null pointer constant. */ result = build1 (NOP_EXPR, TREE_TYPE (x), x); TREE_CONSTANT (result) = TREE_CONSTANT (x); return result; } return x; } result = build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x); TREE_CONSTANT (result) = TREE_CONSTANT (x); return result;}/* Nonzero means lvalues are limited to those valid in pedantic ANSI C. Zero means allow extended lvalues. */int pedantic_lvalues;/* When pedantic, return an expr equal to X but certainly not valid as a pedantic lvalue. Otherwise, return X. */treepedantic_non_lvalue (x) tree x;{ if (pedantic_lvalues) return non_lvalue (x); else return x;}/* Given a tree comparison code, return the code that is the logical inverse of the given code. It is not safe to do this for floating-point comparisons, except for NE_EXPR and EQ_EXPR. */static enum tree_codeinvert_tree_comparison (code) enum tree_code code;{ switch (code) { case EQ_EXPR: return NE_EXPR; case NE_EXPR: return EQ_EXPR; case GT_EXPR: return LE_EXPR; case GE_EXPR: return LT_EXPR; case LT_EXPR: return GE_EXPR; case LE_EXPR: return GT_EXPR; default: abort (); }}/* Similar, but return the comparison that results if the operands are swapped. This is safe for floating-point. */static enum tree_codeswap_tree_comparison (code) enum tree_code code;{ switch (code) { case EQ_EXPR: case NE_EXPR: return code; case GT_EXPR: return LT_EXPR; case GE_EXPR: return LE_EXPR; case LT_EXPR: return GT_EXPR; case LE_EXPR: return GE_EXPR; default: abort (); }}/* Return nonzero if CODE is a tree code that represents a truth value. */static inttruth_value_p (code) enum tree_code code;{ return (TREE_CODE_CLASS (code) == '<' || code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR || code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR || code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR);}/* Return nonzero if two operands are necessarily equal. If ONLY_CONST is non-zero, only return non-zero for constants. This function tests whether the operands are indistinguishable; it does not test whether they are equal using C's == operation. The distinction is important for IEEE floating point, because (1) -0.0 and 0.0 are distinguishable, but -0.0==0.0, and (2) two NaNs may be indistinguishable, but NaN!=NaN. */intoperand_equal_p (arg0, arg1, only_const) tree arg0, arg1; int only_const;{ /* If both types don't have the same signedness, then we can't consider them equal. We must check this before the STRIP_NOPS calls because they may change the signedness of the arguments. */ if (TREE_UNSIGNED (TREE_TYPE (arg0)) != TREE_UNSIGNED (TREE_TYPE (arg1))) return 0; STRIP_NOPS (arg0); STRIP_NOPS (arg1); if (TREE_CODE (arg0) != TREE_CODE (arg1) /* This is needed for conversions and for COMPONENT_REF. Might as well play it safe and always test this. */ || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1))) return 0; /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal. We don't care about side effects in that case because the SAVE_EXPR takes care of that for us. In all other cases, two expressions are equal if they have no side effects. If we have two identical expressions with side effects that should be treated the same due to the only side effects being identical SAVE_EXPR's, that will be detected in the recursive calls below. */ if (arg0 == arg1 && ! only_const && (TREE_CODE (arg0) == SAVE_EXPR || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1)))) return 1; /* Next handle constant cases, those for which we can return 1 even if ONLY_CONST is set. */ if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1)) switch (TREE_CODE (arg0)) { case INTEGER_CST: return (! TREE_CONSTANT_OVERFLOW (arg0) && ! TREE_CONSTANT_OVERFLOW (arg1) && TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1) && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1)); case REAL_CST: return (! TREE_CONSTANT_OVERFLOW (arg0) && ! TREE_CONSTANT_OVERFLOW (arg1) && REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0), TREE_REAL_CST (arg1))); case COMPLEX_CST: return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1), only_const) && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1), only_const)); case STRING_CST: return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1) && ! strncmp (TREE_STRING_POINTER (arg0), TREE_STRING_POINTER (arg1), TREE_STRING_LENGTH (arg0))); case ADDR_EXPR: return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0); default: break; } if (only_const) return 0; switch (TREE_CODE_CLASS (TREE_CODE (arg0))) { case '1': /* Two conversions are equal only if signedness and modes match. */ if ((TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == CONVERT_EXPR) && (TREE_UNSIGNED (TREE_TYPE (arg0)) != TREE_UNSIGNED (TREE_TYPE (arg1)))) return 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?