📄 fold-const.c
字号:
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. */ 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_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; x = TREE_REAL_CST (arg1); l = real_value_from_int_cst (TYPE_MIN_VALUE (type)); u = real_value_from_int_cst (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))) return arg1; 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 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. */ if (TREE_CODE (arg0) == SAVE_EXPR && arg0 == arg1) return ! only_const; if (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)) return 0; if (TREE_CODE (arg0) == TREE_CODE (arg1) && TREE_CODE (arg0) == ADDR_EXPR && TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0)) return 1; if (TREE_CODE (arg0) == TREE_CODE (arg1) && TREE_CODE (arg0) == INTEGER_CST && TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1) && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1)) return 1; /* Detect when real constants are equal. */ if (TREE_CODE (arg0) == TREE_CODE (arg1) && TREE_CODE (arg0) == REAL_CST) return !bcmp ((char *) &TREE_REAL_CST (arg0), (char *) &TREE_REAL_CST (arg1), sizeof (REAL_VALUE_TYPE)); if (only_const) return 0; if (arg0 == arg1) return 1; if (TREE_CODE (arg0) != TREE_CODE (arg1)) return 0; /* This is needed for conversions and for COMPONENT_REF. Might as well play it safe and always test this. */ if (TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1))) 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; return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0); case '<': case '2': return (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0) && operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1), 0)); case 'r': switch (TREE_CODE (arg0)) { case INDIRECT_REF: return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0); case COMPONENT_REF: case ARRAY_REF: return (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0) && operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1), 0)); case BIT_FIELD_REF: return (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0) && operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1), 0) && operand_equal_p (TREE_OPERAND (arg0, 2), TREE_OPERAND (arg1, 2), 0)); } break; } return 0;}/* Similar to operand_equal_p, but see if ARG0 might have been made by shorten_compare from ARG1 when ARG1 was being compared with OTHER. When in doubt, return 0. */static int operand_equal_for_comparison_p (arg0, arg1, other) tree arg0, arg1; tree other;{ int unsignedp1, unsignedpo; tree primarg1, primother; unsigned correct_width; if (operand_equal_p (arg0, arg1, 0)) return 1; if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0)) || ! INTEGRAL_TYPE_P (TREE_TYPE (arg1))) return 0; /* Duplicate what shorten_compare does to ARG1 and see if that gives the actual comparison operand, ARG0. First throw away any conversions to wider types already present in the operands. */ primarg1 = get_narrower (arg1, &unsignedp1); primother = get_narrower (other, &unsignedpo); correct_width = TYPE_PRECISION (TREE_TYPE (arg1)); if (unsignedp1 == unsignedpo && TYPE_PRECISION (TREE_TYPE (primarg1)) < correct_width && TYPE_PRECISION (TREE_TYPE (primother)) < correct_width) { tree type = TREE_TYPE (arg0); /* Make sure shorter operand is extended the right way to match the longer operand. */ primarg1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primarg1)), primarg1); if (operand_equal_p (arg0, convert (type, primarg1), 0)) return 1; } return 0;}/* See if ARG is an expression that is either a comparison or is performing arithmetic on comparisons. The comparisons must only be comparing two different values, which will be stored in *CVAL1 and *CVAL2; if they are non-zero it means that some operands have already been found. No variables may be used anywhere else in the expression except in the comparisons. If SAVE_P is true it means we removed a SAVE_EXPR around the expression and save_expr needs to be called with CVAL1 and CVAL2. If this is true, return 1. Otherwise, return zero. */static inttwoval_comparison_p (arg, cval1, cval2, save_p) tree arg; tree *cval1, *cval2; int *save_p;{ enum tree_code code = TREE_CODE (arg); char class = TREE_CODE_CLASS (code); /* We can handle some of the 'e' cases here. */ if (class == 'e' && code == TRUTH_NOT_EXPR) class = '1'; else if (class == 'e' && (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR || code == COMPOUND_EXPR)) class = '2'; /* ??? Disable this since the SAVE_EXPR might already be in use outside the expression. There may be no way to make this work, but it needs to be looked at again for 2.6. */#if 0 else if (class == 'e' && code == SAVE_EXPR && SAVE_EXPR_RTL (arg) == 0) { /* If we've already found a CVAL1 or CVAL2, this expression is two complex to handle. */ if (*cval1 || *cval2) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -