📄 c-typeck.c
字号:
The resulting tree has type int. */static treepointer_diff (op0, op1) register tree op0, op1;{ tree dt0 = datatype (op0); enum tree_code resultcode; register tree result, folded; tree restype = type_for_size (POINTER_SIZE, 0); if (pedantic) { if (TREE_CODE (TREE_TYPE (dt0)) == VOID_TYPE) warning ("pointer of type `void *' used in subtraction"); if (TREE_CODE (TREE_TYPE (dt0)) == FUNCTION_TYPE) warning ("pointer to a function used in subtraction"); } /* First do the subtraction as integers; then drop through to build the divide operator. */ op0 = build_binary_op (MINUS_EXPR, convert (restype, op0), convert (restype, op1)); op1 = c_sizeof_nowarn (TREE_TYPE (dt0)); /* Create the sum or difference. */ result = build (EXACT_DIV_EXPR, restype, op0, op1); folded = fold (result); if (folded == result) TREE_LITERAL (folded) = TREE_LITERAL (op0) & TREE_LITERAL (op1); return folded;}/* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */static voidbinary_op_error (code) enum tree_code code;{ register char *opname; switch (code) { case NOP_EXPR: error ("invalid truth-value expression"); return; case PLUS_EXPR: opname = "+"; break; case MINUS_EXPR: opname = "-"; break; case MULT_EXPR: opname = "*"; break; case MAX_EXPR: opname = "max"; break; case MIN_EXPR: opname = "min"; break; case EQ_EXPR: opname = "=="; break; case NE_EXPR: opname = "!="; break; case LE_EXPR: opname = "<="; break; case GE_EXPR: opname = ">="; break; case LT_EXPR: opname = "<"; break; case GT_EXPR: opname = ">"; break; case LSHIFT_EXPR: opname = "<<"; break; case RSHIFT_EXPR: opname = ">>"; break; case TRUNC_MOD_EXPR: opname = "%"; break; case TRUNC_DIV_EXPR: opname = "/"; break; case BIT_AND_EXPR: opname = "&"; break; case BIT_IOR_EXPR: opname = "|"; break; case TRUTH_ANDIF_EXPR: opname = "&&"; break; case TRUTH_ORIF_EXPR: opname = "||"; break; case BIT_XOR_EXPR: opname = "^"; break; } error ("invalid operands to binary %s", opname);}/* Subroutine of build_binary_op_nodefault, used for comparison operations. See if the operands have both been converted from subword integer types and, if so, perhaps change them both back to their original type. The arguments of this function are all pointers to local variables of build_binary_op_nodefault: OP0_PTR is &OP0, OP1_PTR is &OP1, RESTYPE_PTR is &RESULT_TYPE and RESCODE_PTR is &RESULTCODE. If this function returns nonzero, it means that the comparison has a constant value. What this function returns is an expression for that value. */static treeshorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr) tree *op0_ptr, *op1_ptr; tree *restype_ptr; enum tree_code *rescode_ptr;{ register tree type; tree op0 = *op0_ptr; tree op1 = *op1_ptr; int unsignedp0, unsignedp1; int real1, real2; tree primop0, primop1; enum tree_code code = *rescode_ptr; /* Throw away any conversions to wider types already present in the operands. */ primop0 = get_narrower (op0, &unsignedp0); primop1 = get_narrower (op1, &unsignedp1); /* Handle the case that OP0 does not *contain* a conversion but it *requires* conversion to FINAL_TYPE. */ if (op0 == primop0 && TREE_TYPE (op0) != *restype_ptr) unsignedp0 = TREE_UNSIGNED (TREE_TYPE (op0)); if (op1 == primop1 && TREE_TYPE (op1) != *restype_ptr) unsignedp1 = TREE_UNSIGNED (TREE_TYPE (op1)); /* If one of the operands must be floated, we cannot optimize. */ real1 = TREE_CODE (TREE_TYPE (primop0)) == REAL_TYPE; real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE; /* If first arg is constant, swap the args (changing operation so value is preserved), for canonicalization. */ if (TREE_LITERAL (primop0)) { register tree tem = primop0; register int temi = unsignedp0; primop0 = primop1; primop1 = tem; tem = op0; op0 = op1; op1 = tem; *op0_ptr = op0; *op1_ptr = op1; unsignedp0 = unsignedp1; unsignedp1 = temi; temi = real1; real1 = real2; real2 = temi; switch (code) { case LT_EXPR: code = GT_EXPR; break; case GT_EXPR: code = LT_EXPR; break; case LE_EXPR: code = GE_EXPR; break; case GE_EXPR: code = LE_EXPR; break; } *rescode_ptr = code; } /* If comparing an integer against a constant more bits wide, maybe we can deduce a value of 1 or 0 independent of the data. Or else truncate the constant now rather than extend the variable at run time. This is only interesting if the constant is the wider arg. Also, it is not safe if the constant is unsigned and the variable arg is signed, since in this case the variable would be sign-extended and then regarded as unsigned. Our technique fails in this case because the lowest/highest possible unsigned results don't follow naturally from the lowest/highest possible values of the variable operand. For just EQ_EXPR and NE_EXPR there is another technique that could be used: see if the constant can be faithfully represented in the other operand's type, by truncating it and reextending it and see if that preserves the constant's value. */ if (!real1 && !real2 && TREE_CODE (primop1) == INTEGER_CST && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr)) { int min_gt, max_gt, min_lt, max_lt; tree maxval, minval; /* 1 if comparison is nominally unsigned. */ int unsignedp = TREE_UNSIGNED (*restype_ptr); tree val; type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)); maxval = TYPE_MAX_VALUE (type); minval = TYPE_MIN_VALUE (type); if (unsignedp && !unsignedp0) *restype_ptr = signed_type (*restype_ptr); if (TREE_TYPE (primop1) != *restype_ptr) primop1 = convert (*restype_ptr, primop1); if (type != *restype_ptr) { minval = convert (*restype_ptr, minval); maxval = convert (*restype_ptr, maxval); } if (unsignedp && unsignedp0) { min_gt = INT_CST_LT_UNSIGNED (primop1, minval); max_gt = INT_CST_LT_UNSIGNED (primop1, maxval); min_lt = INT_CST_LT_UNSIGNED (minval, primop1); max_lt = INT_CST_LT_UNSIGNED (maxval, primop1); } else { min_gt = INT_CST_LT (primop1, minval); max_gt = INT_CST_LT (primop1, maxval); min_lt = INT_CST_LT (minval, primop1); max_lt = INT_CST_LT (maxval, primop1); } val = 0; /* This used to be a switch, but Genix compiler can't handle that. */ if (code == NE_EXPR) { if (max_lt || min_gt) val = integer_one_node; } else if (code == EQ_EXPR) { if (max_lt || min_gt) val = integer_zero_node; } else if (code == LT_EXPR) { if (max_lt) val = integer_one_node; if (!min_lt) val = integer_zero_node; } else if (code == GT_EXPR) { if (min_gt) val = integer_one_node; if (!max_gt) val = integer_zero_node; } else if (code == LE_EXPR) { if (!max_gt) val = integer_one_node; if (min_gt) val = integer_zero_node; } else if (code == GE_EXPR) { if (!min_lt) val = integer_one_node; if (max_lt) val = integer_zero_node; } /* If primop0 was sign-extended and unsigned comparison specd, we did a signed comparison above using the signed type bounds. But the comparison we output must be unsigned. Also, for inequalities, VAL is no good; but if the signed comparison had *any* fixed result, it follows that the unsigned comparison just tests the sign in reverse (positive values are LE, negative ones GE). So we can generate an unsigned comparison against an extreme value of the signed type. */ if (unsignedp && !unsignedp0) { if (val != 0) switch (code) { case LT_EXPR: case GE_EXPR: primop1 = TYPE_MIN_VALUE (type); val = 0; break; case LE_EXPR: case GT_EXPR: primop1 = TYPE_MAX_VALUE (type); val = 0; break; } type = unsigned_type (type); } if (max_lt && !unsignedp0) { /* This is the case of (char)x >?< 0x80, which people used to use expecting old C compilers to change the 0x80 into -0x80. */ if (val == integer_zero_node) warning ("comparison is always 0 due to limited range of data type"); if (val == integer_one_node) warning ("comparison is always 1 due to limited range of data type"); } if (val != 0) { /* Don't forget to evaluate PRIMOP0 if it has side effects. */ if (TREE_VOLATILE (primop0)) return build (COMPOUND_EXPR, TREE_TYPE (val), primop0, val); return val; } /* Value is not predetermined, but do the comparison in the type of the operand that is not constant. TYPE is already properly set. */ } else if (real1 && real2 && TYPE_PRECISION (TREE_TYPE (primop0)) == TYPE_PRECISION (TREE_TYPE (primop1))) type = TREE_TYPE (primop0); /* If args' natural types are both narrower than nominal type and both extend in the same manner, compare them in the type of the wider arg. Otherwise must actually extend both to the nominal common type lest different ways of extending alter the result. (eg, (short)-1 == (unsigned short)-1 should be 0.) */ else if (unsignedp0 == unsignedp1 && real1 == real2 && TYPE_PRECISION (TREE_TYPE (primop0)) < TYPE_PRECISION (*restype_ptr) && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr)) { type = commontype (TREE_TYPE (primop0), TREE_TYPE (primop1)); type = signed_or_unsigned_type (unsignedp0 || TREE_UNSIGNED (*restype_ptr), type); /* Make sure shorter operand is extended the right way to match the longer operand. */ primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)), primop0); primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)), primop1); } else { /* Here we must do the comparison on the nominal type using the args exactly as we received them. */ type = *restype_ptr; primop0 = op0; primop1 = op1; } *op0_ptr = convert (type, primop0); *op1_ptr = convert (type, primop1); *restype_ptr = integer_type_node; return 0;}/* Construct and perhaps optimize a tree representation for a unary operation. CODE, a tree_code, specifies the operation and XARG is the operand. NOCONVERT nonzero suppresses the default promotions (such as from short to int). */treebuild_unary_op (code, xarg, noconvert) enum tree_code code; tree xarg; int noconvert;{ /* No default_conversion here. It causes trouble for ADDR_EXPR. */ register tree arg = xarg; register tree argtype = 0; register enum tree_code typecode = TREE_CODE (TREE_TYPE (arg)); char *errstring = NULL; tree val; if (typecode == ERROR_MARK) return error_mark_node; if (typecode == ENUMERAL_TYPE) typecode = INTEGER_TYPE; switch (code) { case CONVERT_EXPR: /* This is used for unary plus, because a CONVERT_EXPR is enough to prevent anybody from looking inside for associativity, but won't generate any code. */ if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) errstring = "wrong type argument to unary plus"; else if (!noconvert) arg = default_conversion (arg); break; case NEGATE_EXPR: if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) errstring = "wrong type argument to unary minus"; else if (!noconvert) arg = default_conversion (arg); break; case BIT_NOT_EXPR: if (typecode != INTEGER_TYPE) errstring = "wrong type argument to bit-complement"; else if (!noconvert) arg = default_conversion (arg); break; case ABS_EXPR: if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE)) errstring = "wrong type argument to abs"; else if (!noconvert) arg = default_conversion (arg); break; case TRUTH_NOT_EXPR: if (typecode != INTEGER_TYPE && typecode != REAL_TYPE && typecode != POIN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -