diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2015-11-18 21:55:11 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2015-11-18 21:55:11 +0000 |
commit | 642357660ae1f36651519fb41f81a997f5fdae53 (patch) | |
tree | 1b06a2606d86dae56336dcdd2fd3e60bee7c93db /gcc/ada/gcc-interface/utils2.c | |
parent | 5d306e55e09af218e1698a8e427638f717af4f3d (diff) | |
download | gcc-642357660ae1f36651519fb41f81a997f5fdae53.zip gcc-642357660ae1f36651519fb41f81a997f5fdae53.tar.gz gcc-642357660ae1f36651519fb41f81a997f5fdae53.tar.bz2 |
ada-tree.h (DECL_INVARIANT_P): New macro.
* gcc-interface/ada-tree.h (DECL_INVARIANT_P): New macro.
* gcc-interface/gigi.h (enum standard_datatypes): Remove
ADT_longjmp_decl and add ADT_not_handled_by_others_decl.
(longjmp_decl): Delete.
(not_handled_by_others_decl): New macro.
(build_simple_component_ref): Delete.
(build_component_ref): Adjust prototype.
* gcc-interface/decl.c (gnat_to_gnu_entity): Adjust calls to
build_component_ref.
(gnat_to_gnu_field): Set DECL_INVARIANT_P on discriminants
without default value.
* gcc-interface/trans.c (gigi): Reorder initialization sequence
and add not_handled_by_others_decl.
(Attribute_to_gnu): Adjust calls to build_component_ref.
(Subprogram_Body_to_gnu): Likewise.
(Call_to_gnu): Likewise.
(Exception_Handler_to_gnu_sjlj): Likewise.
(gnat_to_gnu): Likewise.
(range_check_info_d): Add inserted_cond field.
(Loop_Statement_to_gnu): Make two passes on the recorded range checks.
(build_noreturn_cond): New static function.
(Raise_Error_to_gnu): Record range checks in loops at -O1 and above.
(make_invariant): New static function.
(Loop_Statement_to_gnu): Use it to compute invariant expressions for
the loop bounds if possible, but do not require it if loop unswitching
is enabled.
* gcc-interface/utils.c (convert_to_fat_pointer): Likewise.
(convert): Likewise.
(maybe_unconstrained_array): Likewise. Call it instead of
build_simple_component_ref and add guard for CONSTRUCTORs.
(unchecked_convert): Likewise.
* gcc-interface/utils2.c (compare_fat_pointers): Likewise.
(build_simple_component_ref): Remove COMPONENT parameter, unify
code dealing with VIEW_CONVERT_EXPR and make it more general,
remove special treatment for CONSTRUCTORs of template types.
(build_component_ref): Remove COMPONENT parameter and adjust call
to build_simple_component_ref.
(maybe_wrap_malloc): Likewise.
(build_allocator): Likewise.
(gnat_invariant_expr): Look through overflow checks, deal with
addition and subtraction of constants and take into account
DECL_INVARIANT_P for the COMPONENT_REF case.
From-SVN: r230575
Diffstat (limited to 'gcc/ada/gcc-interface/utils2.c')
-rw-r--r-- | gcc/ada/gcc-interface/utils2.c | 225 |
1 files changed, 92 insertions, 133 deletions
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c index 73a9b10..79e9b2f 100644 --- a/gcc/ada/gcc-interface/utils2.c +++ b/gcc/ada/gcc-interface/utils2.c @@ -467,8 +467,7 @@ compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2) if (TREE_CODE (p1) == CONSTRUCTOR) p1_array = CONSTRUCTOR_ELT (p1, 0)->value; else - p1_array = build_component_ref (p1, NULL_TREE, - TYPE_FIELDS (TREE_TYPE (p1)), true); + p1_array = build_component_ref (p1, TYPE_FIELDS (TREE_TYPE (p1)), true); p1_array_is_null = fold_build2_loc (loc, EQ_EXPR, result_type, p1_array, @@ -478,8 +477,7 @@ compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2) if (TREE_CODE (p2) == CONSTRUCTOR) p2_array = CONSTRUCTOR_ELT (p2, 0)->value; else - p2_array = build_component_ref (p2, NULL_TREE, - TYPE_FIELDS (TREE_TYPE (p2)), true); + p2_array = build_component_ref (p2, TYPE_FIELDS (TREE_TYPE (p2)), true); p2_array_is_null = fold_build2_loc (loc, EQ_EXPR, result_type, p2_array, @@ -500,15 +498,15 @@ compare_fat_pointers (location_t loc, tree result_type, tree p1, tree p2) p1_bounds = CONSTRUCTOR_ELT (p1, 1)->value; else p1_bounds - = build_component_ref (p1, NULL_TREE, - DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p1))), true); + = build_component_ref (p1, DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p1))), + true); if (TREE_CODE (p2) == CONSTRUCTOR) p2_bounds = CONSTRUCTOR_ELT (p2, 1)->value; else p2_bounds - = build_component_ref (p2, NULL_TREE, - DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p2))), true); + = build_component_ref (p2, DECL_CHAIN (TYPE_FIELDS (TREE_TYPE (p2))), + true); same_bounds = fold_build2_loc (loc, EQ_EXPR, result_type, p1_bounds, p2_bounds); @@ -1942,80 +1940,65 @@ gnat_build_constructor (tree type, vec<constructor_elt, va_gc> *v) return result; } -/* Return a COMPONENT_REF to access a field that is given by COMPONENT, - an IDENTIFIER_NODE giving the name of the field, or FIELD, a FIELD_DECL, - for the field. Don't fold the result if NO_FOLD_P is true. +/* Return a COMPONENT_REF to access FIELD in RECORD, or NULL_TREE if the field + is not found in the record. Don't fold the result if NO_FOLD is true. */ - We also handle the fact that we might have been passed a pointer to the - actual record and know how to look for fields in variant parts. */ - -tree -build_simple_component_ref (tree record_variable, tree component, tree field, - bool no_fold_p) +static tree +build_simple_component_ref (tree record, tree field, bool no_fold) { - tree record_type = TYPE_MAIN_VARIANT (TREE_TYPE (record_variable)); - tree base, ref; + tree type = TYPE_MAIN_VARIANT (TREE_TYPE (record)); + tree ref; - gcc_assert (RECORD_OR_UNION_TYPE_P (record_type) - && COMPLETE_TYPE_P (record_type) - && (component == NULL_TREE) != (field == NULL_TREE)); - - /* If no field was specified, look for a field with the specified name in - the current record only. */ - if (!field) - for (field = TYPE_FIELDS (record_type); - field; - field = DECL_CHAIN (field)) - if (DECL_NAME (field) == component) - break; + gcc_assert (RECORD_OR_UNION_TYPE_P (type) && COMPLETE_TYPE_P (type)); - if (!field) - return NULL_TREE; + /* Try to fold a conversion from another record or union type unless the type + contains a placeholder as it might be needed for a later substitution. */ + if (TREE_CODE (record) == VIEW_CONVERT_EXPR + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (TREE_OPERAND (record, 0))) + && !type_contains_placeholder_p (type)) + { + tree op = TREE_OPERAND (record, 0); + + /* If this is an unpadding operation, convert the underlying object to + the unpadded type directly. */ + if (TYPE_IS_PADDING_P (type) && field == TYPE_FIELDS (type)) + return convert (TREE_TYPE (field), op); + + /* Otherwise try to access FIELD directly in the underlying type, but + make sure that the form of the reference doesn't change too much; + this can happen for an unconstrained bit-packed array type whose + constrained form can be an integer type. */ + ref = build_simple_component_ref (op, field, no_fold); + if (ref && TREE_CODE (TREE_TYPE (ref)) == TREE_CODE (TREE_TYPE (field))) + return ref; + } /* If this field is not in the specified record, see if we can find a field in the specified record whose original field is the same as this one. */ - if (DECL_CONTEXT (field) != record_type) + if (DECL_CONTEXT (field) != type) { tree new_field; /* First loop through normal components. */ - for (new_field = TYPE_FIELDS (record_type); + for (new_field = TYPE_FIELDS (type); new_field; new_field = DECL_CHAIN (new_field)) if (SAME_FIELD_P (field, new_field)) break; - /* Next, see if we're looking for an inherited component in an extension. - If so, look through the extension directly, unless the type contains - a placeholder, as it might be needed for a later substitution. */ - if (!new_field - && TREE_CODE (record_variable) == VIEW_CONVERT_EXPR - && TYPE_ALIGN_OK (record_type) - && !type_contains_placeholder_p (record_type) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (record_variable, 0))) - == RECORD_TYPE - && TYPE_ALIGN_OK (TREE_TYPE (TREE_OPERAND (record_variable, 0)))) - { - ref = build_simple_component_ref (TREE_OPERAND (record_variable, 0), - NULL_TREE, field, no_fold_p); - if (ref) - return ref; - } - /* Next, loop through DECL_INTERNAL_P components if we haven't found the component in the first search. Doing this search in two steps is required to avoid hidden homonymous fields in the _Parent field. */ if (!new_field) - for (new_field = TYPE_FIELDS (record_type); + for (new_field = TYPE_FIELDS (type); new_field; new_field = DECL_CHAIN (new_field)) - if (DECL_INTERNAL_P (new_field)) + if (DECL_INTERNAL_P (new_field) + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (new_field))) { tree field_ref - = build_simple_component_ref (record_variable, - NULL_TREE, new_field, no_fold_p); - ref = build_simple_component_ref (field_ref, NULL_TREE, field, - no_fold_p); + = build_simple_component_ref (record, new_field, no_fold); + ref = build_simple_component_ref (field_ref, field, no_fold); if (ref) return ref; } @@ -2033,95 +2016,49 @@ build_simple_component_ref (tree record_variable, tree component, tree field, && TREE_OVERFLOW (DECL_FIELD_OFFSET (field))) return NULL_TREE; - /* We have found a suitable field. Before building the COMPONENT_REF, get - the base object of the record variable if possible. */ - base = record_variable; - - if (TREE_CODE (record_variable) == VIEW_CONVERT_EXPR) - { - tree inner_variable = TREE_OPERAND (record_variable, 0); - tree inner_type = TYPE_MAIN_VARIANT (TREE_TYPE (inner_variable)); - - /* Look through a conversion between type variants. This is transparent - as far as the field is concerned. */ - if (inner_type == record_type) - base = inner_variable; - - /* Look through a conversion between original and packable version, but - the field needs to be adjusted in this case. */ - else if (RECORD_OR_UNION_TYPE_P (inner_type) - && TYPE_NAME (inner_type) == TYPE_NAME (record_type)) - { - tree new_field; - - for (new_field = TYPE_FIELDS (inner_type); - new_field; - new_field = DECL_CHAIN (new_field)) - if (SAME_FIELD_P (field, new_field)) - break; - if (new_field) - { - field = new_field; - base = inner_variable; - } - } - } - - ref = build3 (COMPONENT_REF, TREE_TYPE (field), base, field, NULL_TREE); + ref = build3 (COMPONENT_REF, TREE_TYPE (field), record, field, NULL_TREE); - if (TREE_READONLY (record_variable) + if (TREE_READONLY (record) || TREE_READONLY (field) - || TYPE_READONLY (record_type)) + || TYPE_READONLY (type)) TREE_READONLY (ref) = 1; - if (TREE_THIS_VOLATILE (record_variable) + if (TREE_THIS_VOLATILE (record) || TREE_THIS_VOLATILE (field) - || TYPE_VOLATILE (record_type)) + || TYPE_VOLATILE (type)) TREE_THIS_VOLATILE (ref) = 1; - if (no_fold_p) + if (no_fold) return ref; /* The generic folder may punt in this case because the inner array type can be self-referential, but folding is in fact not problematic. */ - if (TREE_CODE (base) == CONSTRUCTOR - && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (base))) + if (TREE_CODE (record) == CONSTRUCTOR + && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (record))) { - unsigned int len = CONSTRUCTOR_NELTS (base); - gcc_assert (len > 0); - - if (field == CONSTRUCTOR_ELT (base, 0)->index) - return CONSTRUCTOR_ELT (base, 0)->value; - - if (len > 1) - { - if (field == CONSTRUCTOR_ELT (base, 1)->index) - return CONSTRUCTOR_ELT (base, 1)->value; - } - else - return NULL_TREE; - + vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (record); + unsigned HOST_WIDE_INT idx; + tree index, value; + FOR_EACH_CONSTRUCTOR_ELT (elts, idx, index, value) + if (index == field) + return value; return ref; } return fold (ref); } -/* Likewise, but generate a Constraint_Error if the reference could not be - found. */ +/* Likewise, but return NULL_EXPR and generate a Constraint_Error if the + field is not found in the record. */ tree -build_component_ref (tree record_variable, tree component, tree field, - bool no_fold_p) +build_component_ref (tree record, tree field, bool no_fold) { - tree ref = build_simple_component_ref (record_variable, component, field, - no_fold_p); + tree ref = build_simple_component_ref (record, field, no_fold); if (ref) return ref; - /* If FIELD was specified, assume this is an invalid user field so raise - Constraint_Error. Otherwise, we have no type to return so abort. */ - gcc_assert (field); + /* Assume this is an invalid user field so raise Constraint_Error. */ return build1 (NULL_EXPR, TREE_TYPE (field), build_call_raise (CE_Discriminant_Check_Failed, Empty, N_Raise_Constraint_Error)); @@ -2230,8 +2167,8 @@ maybe_wrap_malloc (tree data_size, tree data_type, Node_Id gnat_node) = build_unary_op (INDIRECT_REF, NULL_TREE, aligning_record_addr); tree aligning_field - = build_component_ref (aligning_record, NULL_TREE, - TYPE_FIELDS (aligning_type), false); + = build_component_ref (aligning_record, TYPE_FIELDS (aligning_type), + false); tree aligning_field_addr = build_unary_op (ADDR_EXPR, NULL_TREE, aligning_field); @@ -2416,7 +2353,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, else storage_init = build_binary_op (INIT_EXPR, NULL_TREE, - build_component_ref (storage_deref, NULL_TREE, + build_component_ref (storage_deref, TYPE_FIELDS (storage_type), false), build_template (template_type, type, NULL_TREE)); @@ -2883,10 +2820,11 @@ done: tree gnat_invariant_expr (tree expr) { - tree type = TREE_TYPE (expr), t; + const tree type = TREE_TYPE (expr); expr = remove_conversions (expr, false); + /* Look through temporaries created to capture values. */ while ((TREE_CODE (expr) == CONST_DECL || (TREE_CODE (expr) == VAR_DECL && TREE_READONLY (expr))) && decl_function_context (expr) == current_function_decl @@ -2908,7 +2846,27 @@ gnat_invariant_expr (tree expr) if (TREE_CONSTANT (expr)) return fold_convert (type, expr); - t = expr; + /* Skip overflow checks since they don't change the invariantness. */ + if (TREE_CODE (expr) == COND_EXPR + && TREE_CODE (COND_EXPR_THEN (expr)) == COMPOUND_EXPR + && TREE_CODE (TREE_OPERAND (COND_EXPR_THEN (expr), 0)) == CALL_EXPR + && get_callee_fndecl (TREE_OPERAND (COND_EXPR_THEN (expr), 0)) + == gnat_raise_decls[CE_Overflow_Check_Failed]) + expr = COND_EXPR_ELSE (expr); + + /* Deal with addition or subtraction of constants. */ + if (TREE_CODE (expr) == PLUS_EXPR || TREE_CODE (expr) == MINUS_EXPR) + { + tree op0 = gnat_invariant_expr (TREE_OPERAND (expr, 0)); + tree op1 = TREE_OPERAND (expr, 1); + if (op0 && TREE_CONSTANT (op1)) + return fold_build2 (TREE_CODE (expr), type, op0, op1); + else + return NULL_TREE; + } + + bool invariant_p = false; + tree t = expr; while (true) { @@ -2917,6 +2875,7 @@ gnat_invariant_expr (tree expr) case COMPONENT_REF: if (TREE_OPERAND (t, 2) != NULL_TREE) return NULL_TREE; + invariant_p |= DECL_INVARIANT_P (TREE_OPERAND (t, 1)); break; case ARRAY_REF: @@ -2928,16 +2887,16 @@ gnat_invariant_expr (tree expr) break; case BIT_FIELD_REF: - case VIEW_CONVERT_EXPR: case REALPART_EXPR: case IMAGPART_EXPR: + case VIEW_CONVERT_EXPR: + CASE_CONVERT: break; case INDIRECT_REF: - if (!TREE_READONLY (t) - || TREE_SIDE_EFFECTS (t) - || !TREE_THIS_NOTRAP (t)) + if ((!invariant_p && !TREE_READONLY (t)) || TREE_SIDE_EFFECTS (t)) return NULL_TREE; + invariant_p = false; break; default: @@ -2956,7 +2915,7 @@ object: || decl_function_context (t) != current_function_decl)) return fold_convert (type, expr); - if (!TREE_READONLY (t)) + if (!invariant_p && !TREE_READONLY (t)) return NULL_TREE; if (TREE_CODE (t) == PARM_DECL) |