diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2014-04-15 09:23:21 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2014-04-15 09:23:21 +0000 |
commit | e297e2eaa6e39126dd216a09dc47458824eb5d52 (patch) | |
tree | 017986e6c0b887f1af51a9d79ce4f4dce42907d4 /gcc/ada/gcc-interface/trans.c | |
parent | e63b36bda5085924a07cb2c57788e0e7e72c6272 (diff) | |
download | gcc-e297e2eaa6e39126dd216a09dc47458824eb5d52.zip gcc-e297e2eaa6e39126dd216a09dc47458824eb5d52.tar.gz gcc-e297e2eaa6e39126dd216a09dc47458824eb5d52.tar.bz2 |
decl.c (gnat_to_gnu_entity): Create a mere scalar constant instead of a reference for renaming of scalar literal.
* gcc-interface/decl.c (gnat_to_gnu_entity) <object>: Create a mere
scalar constant instead of a reference for renaming of scalar literal.
Do not create a new object for constant renaming except for a function
call. Make sure a VAR_DECL is created for the renaming pointer.
* gcc-interface/trans.c (constant_decl_with_initializer_p): New.
(fold_constant_decl_in_expr): New function.
(Identifier_to_gnu): Use constant_decl_with_initializer_p.
For a constant renaming, try to fold a constant DECL in the result.
(lvalue_required_p) <N_Object_Renaming_Declaration>: Always return 1.
(Identifier_to_gnu): Reference the renamed object of constant renaming
pointers directly.
(Case_Statement_to_gnu): Do not re-fold the bounds of integer types.
Assert that the case values are constant.
* gcc-interface/utils.c (invalidate_global_renaming_pointers): Do not
invalidate constant renaming pointers.
Co-Authored-By: Pierre-Marie de Rodat <derodat@adacore.com>
From-SVN: r209411
Diffstat (limited to 'gcc/ada/gcc-interface/trans.c')
-rw-r--r-- | gcc/ada/gcc-interface/trans.c | 150 |
1 files changed, 109 insertions, 41 deletions
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index 3b6d5bd..ae7a2ef 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -898,17 +898,8 @@ lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant, address_of_constant, aliased); case N_Object_Renaming_Declaration: - /* We need to make a real renaming only if the constant object is - aliased or if we may use a renaming pointer; otherwise we can - optimize and return the rvalue. We make an exception if the object - is an identifier since in this case the rvalue can be propagated - attached to the CONST_DECL. */ - return (!constant - || aliased - /* This should match the constant case of the renaming code. */ - || Is_Composite_Type - (Underlying_Type (Etype (Name (gnat_parent)))) - || Nkind (Name (gnat_parent)) == N_Identifier); + /* We need to preserve addresses through a renaming. */ + return 1; case N_Object_Declaration: /* We cannot use a constructor if this is an atomic object because @@ -968,6 +959,77 @@ lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant, gcc_unreachable (); } +/* Return true if T is a constant DECL node that can be safely replaced + by its initializer. */ + +static bool +constant_decl_with_initializer_p (tree t) +{ + if (!TREE_CONSTANT (t) || !DECL_P (t) || !DECL_INITIAL (t)) + return false; + + /* Return false for aggregate types that contain a placeholder since + their initializers cannot be manipulated easily. */ + if (AGGREGATE_TYPE_P (TREE_TYPE (t)) + && !TYPE_IS_FAT_POINTER_P (TREE_TYPE (t)) + && type_contains_placeholder_p (TREE_TYPE (t))) + return false; + + return true; +} + +/* Return an expression equivalent to EXP but where constant DECL nodes + have been replaced by their initializer. */ + +static tree +fold_constant_decl_in_expr (tree exp) +{ + enum tree_code code = TREE_CODE (exp); + tree op0; + + switch (code) + { + case CONST_DECL: + case VAR_DECL: + if (!constant_decl_with_initializer_p (exp)) + return exp; + + return DECL_INITIAL (exp); + + case BIT_FIELD_REF: + case COMPONENT_REF: + op0 = fold_constant_decl_in_expr (TREE_OPERAND (exp, 0)); + if (op0 == TREE_OPERAND (exp, 0)) + return exp; + + return fold_build3 (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1), + TREE_OPERAND (exp, 2)); + + case ARRAY_REF: + case ARRAY_RANGE_REF: + op0 = fold_constant_decl_in_expr (TREE_OPERAND (exp, 0)); + if (op0 == TREE_OPERAND (exp, 0)) + return exp; + + return fold (build4 (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1), + TREE_OPERAND (exp, 2), TREE_OPERAND (exp, 3))); + + case VIEW_CONVERT_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + op0 = fold_constant_decl_in_expr (TREE_OPERAND (exp, 0)); + if (op0 == TREE_OPERAND (exp, 0)) + return exp; + + return fold_build1 (code, TREE_TYPE (exp), op0); + + default: + return exp; + } + + gcc_unreachable (); +} + /* Subroutine of gnat_to_gnu to translate gnat_node, an N_Identifier, to a GCC tree, which is returned. GNU_RESULT_TYPE_P is a pointer to where we should place the result type. */ @@ -1112,13 +1174,16 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) true, false))) gnu_result = DECL_INITIAL (gnu_result); - /* If it's a renaming pointer and we are at the right binding level, - we can reference the renamed object directly, since the renamed - expression has been protected against multiple evaluations. */ + /* If it's a renaming pointer and, either the renamed object is constant + or we are at the right binding level, we can reference the renamed + object directly, since it is constant or has been protected against + multiple evaluations. */ if (TREE_CODE (gnu_result) == VAR_DECL && !DECL_LOOP_PARM_P (gnu_result) && DECL_RENAMED_OBJECT (gnu_result) - && (!DECL_RENAMING_GLOBAL_P (gnu_result) || global_bindings_p ())) + && (TREE_CONSTANT (DECL_RENAMED_OBJECT (gnu_result)) + || !DECL_RENAMING_GLOBAL_P (gnu_result) + || global_bindings_p ())) gnu_result = DECL_RENAMED_OBJECT (gnu_result); /* Otherwise, do the final dereference. */ @@ -1138,15 +1203,8 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) /* If we have a constant declaration and its initializer, try to return the latter to avoid the need to call fold in lots of places and the need for - elaboration code if this identifier is used as an initializer itself. - Don't do it for aggregate types that contain a placeholder since their - initializers cannot be manipulated easily. */ - if (TREE_CONSTANT (gnu_result) - && DECL_P (gnu_result) - && DECL_INITIAL (gnu_result) - && !(AGGREGATE_TYPE_P (TREE_TYPE (gnu_result)) - && !TYPE_IS_FAT_POINTER_P (TREE_TYPE (gnu_result)) - && type_contains_placeholder_p (TREE_TYPE (gnu_result)))) + elaboration code if this identifier is used as an initializer itself. */ + if (constant_decl_with_initializer_p (gnu_result)) { bool constant_only = (TREE_CODE (gnu_result) == CONST_DECL && !DECL_CONST_CORRESPONDING_VAR (gnu_result)); @@ -1166,6 +1224,21 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) gnu_result = DECL_INITIAL (gnu_result); } + /* But for a constant renaming we couldn't do that incrementally for its + definition because of the need to return an lvalue so, if the present + context doesn't itself require an lvalue, we try again here. */ + else if (Ekind (gnat_temp) == E_Constant + && Is_Elementary_Type (gnat_temp_type) + && Present (Renamed_Object (gnat_temp))) + { + if (require_lvalue < 0) + require_lvalue + = lvalue_required_p (gnat_node, gnu_result_type, true, false, + Is_Aliased (gnat_temp)); + if (!require_lvalue) + gnu_result = fold_constant_decl_in_expr (gnu_result); + } + /* The GNAT tree has the type of a function set to its result type, so we adjust here. Also use the type of the result if the Etype is a subtype that is nominally unconstrained. Likewise if this is a deferred constant @@ -2327,9 +2400,11 @@ Case_Statement_to_gnu (Node_Id gnat_node) /* First compile all the different case choices for the current WHEN alternative. */ for (gnat_choice = First (Discrete_Choices (gnat_when)); - Present (gnat_choice); gnat_choice = Next (gnat_choice)) + Present (gnat_choice); + gnat_choice = Next (gnat_choice)) { tree gnu_low = NULL_TREE, gnu_high = NULL_TREE; + tree label = create_artificial_label (input_location); switch (Nkind (gnat_choice)) { @@ -2353,8 +2428,8 @@ Case_Statement_to_gnu (Node_Id gnat_node) { tree gnu_type = get_unpadded_type (Entity (gnat_choice)); - gnu_low = fold (TYPE_MIN_VALUE (gnu_type)); - gnu_high = fold (TYPE_MAX_VALUE (gnu_type)); + gnu_low = TYPE_MIN_VALUE (gnu_type); + gnu_high = TYPE_MAX_VALUE (gnu_type); break; } @@ -2372,20 +2447,13 @@ Case_Statement_to_gnu (Node_Id gnat_node) gcc_unreachable (); } - /* If the case value is a subtype that raises Constraint_Error at - run time because of a wrong bound, then gnu_low or gnu_high is - not translated into an INTEGER_CST. In such a case, we need - to ensure that the when statement is not added in the tree, - otherwise it will crash the gimplifier. */ - if ((!gnu_low || TREE_CODE (gnu_low) == INTEGER_CST) - && (!gnu_high || TREE_CODE (gnu_high) == INTEGER_CST)) - { - add_stmt_with_node (build_case_label - (gnu_low, gnu_high, - create_artificial_label (input_location)), - gnat_choice); - choices_added_p = true; - } + /* Everything should be folded into constants at this point. */ + gcc_assert (!gnu_low || TREE_CODE (gnu_low) == INTEGER_CST); + gcc_assert (!gnu_high || TREE_CODE (gnu_high) == INTEGER_CST); + + add_stmt_with_node (build_case_label (gnu_low, gnu_high, label), + gnat_choice); + choices_added_p = true; } /* This construct doesn't define a scope so we shouldn't push a binding |