diff options
Diffstat (limited to 'gcc/ada')
-rw-r--r-- | gcc/ada/ChangeLog | 38 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/decl.c | 26 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 264 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils.c | 8 | ||||
-rw-r--r-- | gcc/ada/gcc-interface/utils2.c | 4 |
5 files changed, 197 insertions, 143 deletions
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 20edf04ee22..930e86681ff 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,41 @@ +2016-06-13 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/decl.c (gnat_to_gnu_subprog_type): Build only a minimal + PARM_DECL when the parameter type is dummy. + * gcc-interface/trans.c (Call_to_gnu): Translate formal types before + formal objects. + +2016-06-13 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/decl.c (gnat_to_gnu_entity) <E_Variable>: Deal with + PLUS_EXPR in the expression of a renaming. + +2016-06-13 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/utils2.c (known_alignment) <CALL_EXPR>: Deal specially + with calls to malloc. + +2016-06-11 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/trans.c (build_binary_op_trapv): If no operand is a + constant, use the generic implementation of the middle-end; otherwise + turn the dynamic conditions into static conditions and simplify. + +2016-06-11 Eric Botcazou <ebotcazou@adacore.com> + + * gcc-interface/trans.c (Case_Statement_to_gnu): Deal with characters. + +2016-06-11 Pierre-Marie de Rodat <derodat@adacore.com> + + * gcc-interface/decl.c (gnat_to_gnu_entity): Do not clobber + gnat_entity_name with temporary names for XUP and XUT types. + +2016-06-10 Martin Sebor <msebor@redhat.com> + + PR c/71392 + * gcc/ada/gcc-interface/utils.c (handle_nonnull_attribute): Accept + the nonnull attribute in type-generic builtins. + 2016-06-06 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/decl.c (Gigi_Equivalent_Type): Make sure equivalent diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 45878a7c635..0ce2d47f195 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -1003,6 +1003,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) && !call_is_atomic_load (inner)) || TREE_CODE (inner) == ADDR_EXPR || TREE_CODE (inner) == NULL_EXPR + || TREE_CODE (inner) == PLUS_EXPR || TREE_CODE (inner) == CONSTRUCTOR || CONSTANT_CLASS_P (inner) /* We need to detect the case where a temporary is created to @@ -2335,10 +2336,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) gnat_name = Packed_Array_Impl_Type (gnat_entity); else gnat_name = gnat_entity; - if (gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL) - gnu_entity_name = create_concat_name (gnat_name, "XUP"); - create_type_decl (gnu_entity_name, gnu_fat_type, artificial_p, - debug_info_p, gnat_entity); + tree xup_name + = (gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + ? get_entity_name (gnat_name) + : create_concat_name (gnat_name, "XUP"); + create_type_decl (xup_name, gnu_fat_type, artificial_p, debug_info_p, + gnat_entity); /* Create the type to be designated by thin pointers: a record type for the array and its template. We used to shift the fields to have the @@ -2348,11 +2351,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) Note that GDB can handle standard DWARF information for them, so we don't have to name them as a GNAT encoding, except if specifically asked to. */ - if (gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL) - gnu_entity_name = create_concat_name (gnat_name, "XUT"); - else - gnu_entity_name = get_entity_name (gnat_name); - tem = build_unc_object_type (gnu_template_type, tem, gnu_entity_name, + tree xut_name + = (gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + ? get_entity_name (gnat_name) + : create_concat_name (gnat_name, "XUT"); + tem = build_unc_object_type (gnu_template_type, tem, xut_name, debug_info_p); SET_TYPE_UNCONSTRAINED_ARRAY (tem, gnu_type); @@ -5956,8 +5959,11 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition, else { + /* Build a minimal PARM_DECL without DECL_ARG_TYPE so that + Call_to_gnu will stop if it encounters the PARM_DECL. */ gnu_param - = create_param_decl (gnu_param_name, gnu_param_type); + = build_decl (input_location, PARM_DECL, gnu_param_name, + gnu_param_type); associate_subprog_with_dummy_type (gnat_subprog, gnu_param_type); incomplete_profile_p = true; diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index fb17cb2c381..f110e928b93 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -2472,13 +2472,15 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) static tree Case_Statement_to_gnu (Node_Id gnat_node) { - tree gnu_result, gnu_expr, gnu_label; + tree gnu_result, gnu_expr, gnu_type, gnu_label; Node_Id gnat_when; location_t end_locus; bool may_fallthru = false; gnu_expr = gnat_to_gnu (Expression (gnat_node)); gnu_expr = convert (get_base_type (TREE_TYPE (gnu_expr)), gnu_expr); + gnu_expr = maybe_character_value (gnu_expr); + gnu_type = TREE_TYPE (gnu_expr); /* We build a SWITCH_EXPR that contains the code with interspersed CASE_LABEL_EXPRs for each label. */ @@ -2548,6 +2550,11 @@ Case_Statement_to_gnu (Node_Id gnat_node) gcc_assert (!gnu_low || TREE_CODE (gnu_low) == INTEGER_CST); gcc_assert (!gnu_high || TREE_CODE (gnu_high) == INTEGER_CST); + if (gnu_low && TREE_TYPE (gnu_low) != gnu_type) + gnu_low = convert (gnu_type, gnu_low); + if (gnu_high && TREE_TYPE (gnu_high) != gnu_type) + gnu_high = convert (gnu_type, gnu_high); + add_stmt_with_node (build_case_label (gnu_low, gnu_high, label), gnat_choice); choices_added_p = true; @@ -2579,8 +2586,8 @@ Case_Statement_to_gnu (Node_Id gnat_node) /* Now emit a definition of the label the cases branch to, if any. */ if (may_fallthru) add_stmt (build1 (LABEL_EXPR, void_type_node, gnu_label)); - gnu_result = build3 (SWITCH_EXPR, TREE_TYPE (gnu_expr), gnu_expr, - end_stmt_group (), NULL_TREE); + gnu_result + = build3 (SWITCH_EXPR, gnu_type, gnu_expr, end_stmt_group (), NULL_TREE); return gnu_result; } @@ -4334,9 +4341,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, gnat_actual = Next_Actual (gnat_actual)) { Entity_Id gnat_formal_type = Etype (gnat_formal); + tree gnu_formal_type = gnat_to_gnu_type (gnat_formal_type); tree gnu_formal = present_gnu_tree (gnat_formal) ? get_gnu_tree (gnat_formal) : NULL_TREE; - tree gnu_formal_type = gnat_to_gnu_type (gnat_formal_type); const bool is_true_formal_parm = gnu_formal && TREE_CODE (gnu_formal) == PARM_DECL; const bool is_by_ref_formal_parm @@ -8868,19 +8875,16 @@ build_binary_op_trapv (enum tree_code code, tree gnu_type, tree left, tree rhs = gnat_protect_expr (right); tree type_max = TYPE_MAX_VALUE (gnu_type); tree type_min = TYPE_MIN_VALUE (gnu_type); - tree zero = build_int_cst (gnu_type, 0); - tree gnu_expr, rhs_lt_zero, tmp1, tmp2; - tree check_pos, check_neg, check; + tree gnu_expr, check; + int sgn; /* Assert that the precision is a power of 2. */ gcc_assert ((precision & (precision - 1)) == 0); - /* Prefer a constant or known-positive rhs to simplify checks. */ - if (!TREE_CONSTANT (rhs) - && commutative_tree_code (code) - && (TREE_CONSTANT (lhs) - || (!tree_expr_nonnegative_p (rhs) - && tree_expr_nonnegative_p (lhs)))) + /* Prefer a constant on the RHS to simplify checks. */ + if (TREE_CODE (rhs) != INTEGER_CST + && TREE_CODE (lhs) == INTEGER_CST + && (code == PLUS_EXPR || code == MULT_EXPR)) { tree tmp = lhs; lhs = rhs; @@ -8891,151 +8895,149 @@ build_binary_op_trapv (enum tree_code code, tree gnu_type, tree left, /* If we can fold the expression to a constant, just return it. The caller will deal with overflow, no need to generate a check. */ - if (TREE_CONSTANT (gnu_expr)) + if (TREE_CODE (gnu_expr) == INTEGER_CST) return gnu_expr; - rhs_lt_zero = tree_expr_nonnegative_p (rhs) - ? boolean_false_node - : build_binary_op (LT_EXPR, boolean_type_node, rhs, zero); - - /* ??? Should use more efficient check for operand_equal_p (lhs, rhs, 0) */ - - /* Try a few strategies that may be cheaper than the general - code at the end of the function, if the rhs is not known. - The strategies are: - - Call library function for 64-bit multiplication (complex) - - Widen, if input arguments are sufficiently small - - Determine overflow using wrapped result for addition/subtraction. */ - - if (!TREE_CONSTANT (rhs)) + /* If no operand is a constant, we use the generic implementation. */ + if (TREE_CODE (lhs) != INTEGER_CST && TREE_CODE (rhs) != INTEGER_CST) { - /* Even for add/subtract double size to get another base type. */ - const unsigned int needed_precision = precision * 2; - - if (code == MULT_EXPR && precision == 64) + /* Never inline a 64-bit mult for a 32-bit target, it's way too long. */ + if (code == MULT_EXPR && precision == 64 && BITS_PER_WORD < 64) { - tree int_64 = gnat_type_for_size (64, 0); - + tree int64 = gnat_type_for_size (64, 0); return convert (gnu_type, build_call_n_expr (mulv64_decl, 2, - convert (int_64, lhs), - convert (int_64, rhs))); + convert (int64, lhs), + convert (int64, rhs))); } - if (needed_precision <= BITS_PER_WORD - || (code == MULT_EXPR && needed_precision <= LONG_LONG_TYPE_SIZE)) - { - tree wide_type = gnat_type_for_size (needed_precision, 0); - tree wide_result = build_binary_op (code, wide_type, - convert (wide_type, lhs), - convert (wide_type, rhs)); - - check = build_binary_op - (TRUTH_ORIF_EXPR, boolean_type_node, - build_binary_op (LT_EXPR, boolean_type_node, wide_result, - convert (wide_type, type_min)), - build_binary_op (GT_EXPR, boolean_type_node, wide_result, - convert (wide_type, type_max))); - - return - emit_check (check, gnu_expr, CE_Overflow_Check_Failed, gnat_node); - } + enum internal_fn icode; - if (code == PLUS_EXPR || code == MINUS_EXPR) + switch (code) { - tree unsigned_type = gnat_type_for_size (precision, 1); - tree wrapped_expr - = convert (gnu_type, - build_binary_op (code, unsigned_type, - convert (unsigned_type, lhs), - convert (unsigned_type, rhs))); - - /* Overflow when (rhs < 0) ^ (wrapped_expr < lhs)), for addition - or when (rhs < 0) ^ (wrapped_expr > lhs) for subtraction. */ - check - = build_binary_op (TRUTH_XOR_EXPR, boolean_type_node, rhs_lt_zero, - build_binary_op (code == PLUS_EXPR - ? LT_EXPR : GT_EXPR, - boolean_type_node, - wrapped_expr, lhs)); - - return - emit_check (check, gnu_expr, CE_Overflow_Check_Failed, gnat_node); + case PLUS_EXPR: + icode = IFN_ADD_OVERFLOW; + break; + case MINUS_EXPR: + icode = IFN_SUB_OVERFLOW; + break; + case MULT_EXPR: + icode = IFN_MUL_OVERFLOW; + break; + default: + gcc_unreachable (); } + + tree gnu_ctype = build_complex_type (gnu_type); + tree call + = build_call_expr_internal_loc (UNKNOWN_LOCATION, icode, gnu_ctype, 2, + lhs, rhs); + tree tgt = save_expr (call); + gnu_expr = build1 (REALPART_EXPR, gnu_type, tgt); + check + = convert (boolean_type_node, build1 (IMAGPART_EXPR, gnu_type, tgt)); + return + emit_check (check, gnu_expr, CE_Overflow_Check_Failed, gnat_node); } + /* If one operand is a constant, we expose the overflow condition to enable + a subsequent simplication or even elimination. */ switch (code) { case PLUS_EXPR: - /* When rhs >= 0, overflow when lhs > type_max - rhs. */ - check_pos = build_binary_op (GT_EXPR, boolean_type_node, lhs, - build_binary_op (MINUS_EXPR, gnu_type, - type_max, rhs)), - - /* When rhs < 0, overflow when lhs < type_min - rhs. */ - check_neg = build_binary_op (LT_EXPR, boolean_type_node, lhs, - build_binary_op (MINUS_EXPR, gnu_type, - type_min, rhs)); + sgn = tree_int_cst_sgn (rhs); + if (sgn > 0) + /* When rhs > 0, overflow when lhs > type_max - rhs. */ + check = build_binary_op (GT_EXPR, boolean_type_node, lhs, + build_binary_op (MINUS_EXPR, gnu_type, + type_max, rhs)); + else if (sgn < 0) + /* When rhs < 0, overflow when lhs < type_min - rhs. */ + check = build_binary_op (LT_EXPR, boolean_type_node, lhs, + build_binary_op (MINUS_EXPR, gnu_type, + type_min, rhs)); + else + return gnu_expr; break; case MINUS_EXPR: - /* When rhs >= 0, overflow when lhs < type_min + rhs. */ - check_pos = build_binary_op (LT_EXPR, boolean_type_node, lhs, - build_binary_op (PLUS_EXPR, gnu_type, - type_min, rhs)), - - /* When rhs < 0, overflow when lhs > type_max + rhs. */ - check_neg = build_binary_op (GT_EXPR, boolean_type_node, lhs, - build_binary_op (PLUS_EXPR, gnu_type, - type_max, rhs)); + if (TREE_CODE (lhs) == INTEGER_CST) + { + sgn = tree_int_cst_sgn (lhs); + if (sgn > 0) + /* When lhs > 0, overflow when rhs < lhs - type_max. */ + check = build_binary_op (LT_EXPR, boolean_type_node, rhs, + build_binary_op (MINUS_EXPR, gnu_type, + lhs, type_max)); + else if (sgn < 0) + /* When lhs < 0, overflow when rhs > lhs - type_min. */ + check = build_binary_op (GT_EXPR, boolean_type_node, rhs, + build_binary_op (MINUS_EXPR, gnu_type, + lhs, type_min)); + else + return gnu_expr; + } + else + { + sgn = tree_int_cst_sgn (rhs); + if (sgn > 0) + /* When rhs > 0, overflow when lhs < type_min + rhs. */ + check = build_binary_op (LT_EXPR, boolean_type_node, lhs, + build_binary_op (PLUS_EXPR, gnu_type, + type_min, rhs)); + else if (sgn < 0) + /* When rhs < 0, overflow when lhs > type_max + rhs. */ + check = build_binary_op (GT_EXPR, boolean_type_node, lhs, + build_binary_op (PLUS_EXPR, gnu_type, + type_max, rhs)); + else + return gnu_expr; + } break; case MULT_EXPR: - /* The check here is designed to be efficient if the rhs is constant, - but it will work for any rhs by using integer division. - Four different check expressions determine whether X * C overflows, - depending on C. - C == 0 => false - C > 0 => X > type_max / C || X < type_min / C - C == -1 => X == type_min - C < -1 => X > type_min / C || X < type_max / C */ - - tmp1 = build_binary_op (TRUNC_DIV_EXPR, gnu_type, type_max, rhs); - tmp2 = build_binary_op (TRUNC_DIV_EXPR, gnu_type, type_min, rhs); - - check_pos - = build_binary_op (TRUTH_ANDIF_EXPR, boolean_type_node, - build_binary_op (NE_EXPR, boolean_type_node, zero, - rhs), - build_binary_op (TRUTH_ORIF_EXPR, boolean_type_node, - build_binary_op (GT_EXPR, - boolean_type_node, - lhs, tmp1), - build_binary_op (LT_EXPR, - boolean_type_node, - lhs, tmp2))); - - check_neg - = fold_build3 (COND_EXPR, boolean_type_node, - build_binary_op (EQ_EXPR, boolean_type_node, rhs, - build_int_cst (gnu_type, -1)), - build_binary_op (EQ_EXPR, boolean_type_node, lhs, - type_min), - build_binary_op (TRUTH_ORIF_EXPR, boolean_type_node, - build_binary_op (GT_EXPR, - boolean_type_node, - lhs, tmp2), - build_binary_op (LT_EXPR, - boolean_type_node, - lhs, tmp1))); + sgn = tree_int_cst_sgn (rhs); + if (sgn > 0) + { + if (integer_onep (rhs)) + return gnu_expr; + + tree lb = build_binary_op (TRUNC_DIV_EXPR, gnu_type, type_min, rhs); + tree ub = build_binary_op (TRUNC_DIV_EXPR, gnu_type, type_max, rhs); + + /* When rhs > 1, overflow outside [type_min/rhs; type_max/rhs]. */ + check + = build_binary_op (TRUTH_ORIF_EXPR, boolean_type_node, + build_binary_op (LT_EXPR, boolean_type_node, + lhs, lb), + build_binary_op (GT_EXPR, boolean_type_node, + lhs, ub)); + } + else if (sgn < 0) + { + tree lb = build_binary_op (TRUNC_DIV_EXPR, gnu_type, type_max, rhs); + tree ub = build_binary_op (TRUNC_DIV_EXPR, gnu_type, type_min, rhs); + + if (integer_minus_onep (rhs)) + /* When rhs == -1, overflow if lhs == type_min. */ + check + = build_binary_op (EQ_EXPR, boolean_type_node, lhs, type_min); + else + /* When rhs < -1, overflow outside [type_max/rhs; type_min/rhs]. */ + check + = build_binary_op (TRUTH_ORIF_EXPR, boolean_type_node, + build_binary_op (LT_EXPR, boolean_type_node, + lhs, lb), + build_binary_op (GT_EXPR, boolean_type_node, + lhs, ub)); + } + else + return gnu_expr; break; default: gcc_unreachable (); } - check = fold_build3 (COND_EXPR, boolean_type_node, rhs_lt_zero, check_neg, - check_pos); - return emit_check (check, gnu_expr, CE_Overflow_Check_Failed, gnat_node); } diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 831b6e035aa..1f1e4d3b814 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -5833,10 +5833,14 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), /* If no arguments are specified, all pointer arguments should be non-null. Verify a full prototype is given so that the arguments - will have the correct types when we actually check them later. */ + will have the correct types when we actually check them later. + Avoid diagnosing type-generic built-ins since those have no + prototype. */ if (!args) { - if (!prototype_p (type)) + if (!prototype_p (type) + && (!TYPE_ATTRIBUTES (type) + || !lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)))) { error ("nonnull attribute without arguments on a non-prototype"); *no_add_attrs = true; diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c index a0804e8e86d..aeb6cc3a3f7 100644 --- a/gcc/ada/gcc-interface/utils2.c +++ b/gcc/ada/gcc-interface/utils2.c @@ -171,6 +171,10 @@ known_alignment (tree exp) case CALL_EXPR: { + tree func = get_callee_fndecl (exp); + if (func && DECL_IS_MALLOC (func)) + return get_target_system_allocator_alignment () * BITS_PER_UNIT; + tree t = maybe_inline_call_in_expr (exp); if (t) return known_alignment (t); |