aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada')
-rw-r--r--gcc/ada/ChangeLog38
-rw-r--r--gcc/ada/gcc-interface/decl.c26
-rw-r--r--gcc/ada/gcc-interface/trans.c264
-rw-r--r--gcc/ada/gcc-interface/utils.c8
-rw-r--r--gcc/ada/gcc-interface/utils2.c4
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);