diff options
Diffstat (limited to 'gcc/ada/gcc-interface/utils.c')
-rw-r--r-- | gcc/ada/gcc-interface/utils.c | 164 |
1 files changed, 114 insertions, 50 deletions
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 9bbb46f..2ff664b 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -2260,7 +2260,7 @@ merge_sizes (tree last_size, tree first_bit, tree size, bool special, 1, has_rep)); /* We don't need any NON_VALUE_EXPRs and they can confuse us (especially - when fed through substitute_in_expr) into thinking that a constant + when fed through SUBSTITUTE_IN_EXPR) into thinking that a constant size is not constant. */ while (TREE_CODE (new_size) == NON_LVALUE_EXPR) new_size = TREE_OPERAND (new_size, 0); @@ -2429,6 +2429,24 @@ create_range_type (tree type, tree min, tree max) return range_type; } +/* Return an extra subtype of TYPE with range MIN to MAX. */ + +tree +create_extra_subtype (tree type, tree min, tree max) +{ + const bool uns = TYPE_UNSIGNED (type); + const unsigned prec = TYPE_PRECISION (type); + tree subtype = uns ? make_unsigned_type (prec) : make_signed_type (prec); + + TREE_TYPE (subtype) = type; + TYPE_EXTRA_SUBTYPE_P (subtype) = 1; + + SET_TYPE_RM_MIN_VALUE (subtype, min); + SET_TYPE_RM_MAX_VALUE (subtype, max); + + return subtype; +} + /* Return a TYPE_DECL node suitable for the TYPE_STUB_DECL field of TYPE. NAME gives the name of the type to be used in the declaration. */ @@ -2811,8 +2829,8 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, layout_decl (field_decl, known_align); SET_DECL_OFFSET_ALIGN (field_decl, - tree_fits_uhwi_p (pos) ? BIGGEST_ALIGNMENT - : BITS_PER_UNIT); + tree_fits_uhwi_p (pos) + ? BIGGEST_ALIGNMENT : BITS_PER_UNIT); pos_from_bit (&DECL_FIELD_OFFSET (field_decl), &DECL_FIELD_BIT_OFFSET (field_decl), DECL_OFFSET_ALIGN (field_decl), pos); @@ -2829,6 +2847,15 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, if (!addressable && !type_for_nonaliased_component_p (type)) addressable = 1; + /* Note that there is a trade-off in making a field nonaddressable because + this will cause type-based alias analysis to use the same alias set for + accesses to the field as for accesses to the whole record: while doing + so will make it more likely to disambiguate accesses to other objects + and accesses to the field, it will make it less likely to disambiguate + accesses to the other fields of the record and accesses to the field. + If the record is fully static, then the trade-off is irrelevant since + the fields of the record can always be disambiguated by their offsets + but, if the record is dynamic, then it can become problematic. */ DECL_NONADDRESSABLE_P (field_decl) = !addressable; return field_decl; @@ -3658,11 +3685,27 @@ max_size (tree exp, bool max_p) modify. Otherwise, we treat it like a variable. */ if (CONTAINS_PLACEHOLDER_P (exp)) { - tree val_type = TREE_TYPE (TREE_OPERAND (exp, 1)); - tree val = (max_p ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type)); - return - convert (type, - max_size (convert (get_base_type (val_type), val), true)); + tree base_type = get_base_type (TREE_TYPE (TREE_OPERAND (exp, 1))); + tree val + = fold_convert (base_type, + max_p + ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type)); + + /* Walk down the extra subtypes to get more restrictive bounds. */ + while (TYPE_IS_EXTRA_SUBTYPE_P (type)) + { + type = TREE_TYPE (type); + if (max_p) + val = fold_build2 (MIN_EXPR, base_type, val, + fold_convert (base_type, + TYPE_MAX_VALUE (type))); + else + val = fold_build2 (MAX_EXPR, base_type, val, + fold_convert (base_type, + TYPE_MIN_VALUE (type))); + } + + return fold_convert (type, max_size (val, max_p)); } return exp; @@ -3683,49 +3726,57 @@ max_size (tree exp, bool max_p) return fold_build1 (code, type, op0); case tcc_binary: - { - tree lhs = max_size (TREE_OPERAND (exp, 0), max_p); - tree rhs = max_size (TREE_OPERAND (exp, 1), - code == MINUS_EXPR ? !max_p : max_p); + op0 = TREE_OPERAND (exp, 0); + op1 = TREE_OPERAND (exp, 1); + + /* If we have a multiply-add with a "negative" value in an unsigned + type, do a multiply-subtract with the negated value, in order to + avoid creating a spurious overflow below. */ + if (code == PLUS_EXPR + && TREE_CODE (op0) == MULT_EXPR + && TYPE_UNSIGNED (type) + && TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST + && !TREE_OVERFLOW (TREE_OPERAND (op0, 1)) + && tree_int_cst_sign_bit (TREE_OPERAND (op0, 1))) + { + tree tmp = op1; + op1 = build2 (MULT_EXPR, type, TREE_OPERAND (op0, 0), + fold_build1 (NEGATE_EXPR, type, + TREE_OPERAND (op0, 1))); + op0 = tmp; + code = MINUS_EXPR; + } - /* Special-case wanting the maximum value of a MIN_EXPR. - In that case, if one side overflows, return the other. */ - if (max_p && code == MIN_EXPR) - { - if (TREE_CODE (rhs) == INTEGER_CST && TREE_OVERFLOW (rhs)) - return lhs; + op0 = max_size (op0, max_p); + op1 = max_size (op1, code == MINUS_EXPR ? !max_p : max_p); - if (TREE_CODE (lhs) == INTEGER_CST && TREE_OVERFLOW (lhs)) - return rhs; - } - - /* Likewise, handle a MINUS_EXPR or PLUS_EXPR with the LHS - overflowing and the RHS a variable. */ - if ((code == MINUS_EXPR || code == PLUS_EXPR) - && TREE_CODE (lhs) == INTEGER_CST - && TREE_OVERFLOW (lhs) - && TREE_CODE (rhs) != INTEGER_CST) - return lhs; - - /* If we are going to subtract a "negative" value in an unsigned type, - do the operation as an addition of the negated value, in order to - avoid creating a spurious overflow below. */ - if (code == MINUS_EXPR - && TYPE_UNSIGNED (type) - && TREE_CODE (rhs) == INTEGER_CST - && !TREE_OVERFLOW (rhs) - && tree_int_cst_sign_bit (rhs) != 0) - { - rhs = fold_build1 (NEGATE_EXPR, type, rhs); - code = PLUS_EXPR; - } + if ((code == MINUS_EXPR || code == PLUS_EXPR)) + { + /* If the op0 has overflowed and the op1 is a variable, + propagate the overflow by returning the op0. */ + if (TREE_CODE (op0) == INTEGER_CST + && TREE_OVERFLOW (op0) + && TREE_CODE (op1) != INTEGER_CST) + return op0; + + /* If we have a "negative" value in an unsigned type, do the + opposite operation on the negated value, in order to avoid + creating a spurious overflow below. */ + if (TYPE_UNSIGNED (type) + && TREE_CODE (op1) == INTEGER_CST + && !TREE_OVERFLOW (op1) + && tree_int_cst_sign_bit (op1)) + { + op1 = fold_build1 (NEGATE_EXPR, type, op1); + code = (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR); + } + } - if (lhs == TREE_OPERAND (exp, 0) && rhs == TREE_OPERAND (exp, 1)) - return exp; + if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)) + return exp; - /* We need to detect overflows so we call size_binop here. */ - return size_binop (code, lhs, rhs); - } + /* We need to detect overflows so we call size_binop here. */ + return size_binop (code, op0, op1); case tcc_expression: switch (TREE_CODE_LENGTH (code)) @@ -3757,15 +3808,28 @@ max_size (tree exp, bool max_p) case 3: if (code == COND_EXPR) { + op0 = TREE_OPERAND (exp, 0); op1 = TREE_OPERAND (exp, 1); op2 = TREE_OPERAND (exp, 2); if (!op1 || !op2) return exp; - return - fold_build2 (max_p ? MAX_EXPR : MIN_EXPR, type, - max_size (op1, max_p), max_size (op2, max_p)); + op1 = max_size (op1, max_p); + op2 = max_size (op2, max_p); + + /* If we have the MAX of a "negative" value in an unsigned type + and zero for a length expression, just return zero. */ + if (max_p + && TREE_CODE (op0) == LE_EXPR + && TYPE_UNSIGNED (type) + && TREE_CODE (op1) == INTEGER_CST + && !TREE_OVERFLOW (op1) + && tree_int_cst_sign_bit (op1) + && integer_zerop (op2)) + return op2; + + return fold_build2 (max_p ? MAX_EXPR : MIN_EXPR, type, op1, op2); } break; |