summaryrefslogtreecommitdiff
path: root/gcc/ada/trans.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ada/trans.c')
-rw-r--r--gcc/ada/trans.c240
1 files changed, 129 insertions, 111 deletions
diff --git a/gcc/ada/trans.c b/gcc/ada/trans.c
index f45783e9986..91b051882c6 100644
--- a/gcc/ada/trans.c
+++ b/gcc/ada/trans.c
@@ -82,17 +82,30 @@ bool type_annotate_only;
struct stmt_group GTY((chain_next ("%h.previous"))) {
struct stmt_group *previous; /* Previous code group. */
+ struct stmt_group *global; /* Global code group from the level. */
tree stmt_list; /* List of statements for this code group. */
tree block; /* BLOCK for this code group, if any. */
tree cleanups; /* Cleanups for this code group, if any. */
};
static GTY(()) struct stmt_group *current_stmt_group;
-static struct stmt_group *global_stmt_group;
/* List of unused struct stmt_group nodes. */
static GTY((deletable)) struct stmt_group *stmt_group_free_list;
+/* A structure used to record information on elaboration procedures
+ we've made and need to process.
+
+ ??? gnat_node should be Node_Id, but gengtype gets confused. */
+
+struct elab_info GTY((chain_next ("%h.next"))) {
+ struct elab_info *next; /* Pointer to next in chain. */
+ tree elab_proc; /* Elaboration procedure. */
+ int gnat_node; /* The N_Compilation_Unit. */
+};
+
+static GTY(()) struct elab_info *elab_info_list;
+
/* Free list of TREE_LIST nodes used for stacks. */
static GTY((deletable)) tree gnu_stack_free_list;
@@ -102,6 +115,10 @@ static GTY((deletable)) tree gnu_stack_free_list;
handler. Not used in the zero-cost case. */
static GTY(()) tree gnu_except_ptr_stack;
+/* List of TREE_LIST nodes used to store the current elaboration procedure
+ decl. TREE_VALUE is the decl. */
+static GTY(()) tree gnu_elab_proc_stack;
+
/* Variable that stores a list of labels to be used as a goto target instead of
a return in some functions. See processing for N_Subprogram_Body. */
static GTY(()) tree gnu_return_label_stack;
@@ -114,15 +131,13 @@ static GTY(()) tree gnu_loop_label_stack;
TREE_VALUE of each entry is the label at the end of the switch. */
static GTY(()) tree gnu_switch_label_stack;
-/* The FUNCTION_DECL for the elaboration procedure for the main unit. */
-static GTY(()) tree gnu_elab_proc_decl;
-
/* Map GNAT tree codes to GCC tree codes for simple expressions. */
static enum tree_code gnu_codes[Number_Node_Kinds];
/* Current node being treated, in case abort called. */
Node_Id error_gnat_node;
+static void Compilation_Unit_to_gnu (Node_Id);
static void record_code_position (Node_Id);
static void insert_code_for (Node_Id);
static void start_stmt_group (void);
@@ -149,7 +164,6 @@ static tree extract_values (tree, tree);
static tree pos_to_constructor (Node_Id, tree, Entity_Id);
static tree maybe_implicit_deref (tree);
static tree gnat_stabilize_reference_1 (tree, bool);
-static bool build_unit_elab (void);
static void annotate_with_node (tree, Node_Id);
/* Constants for +0.5 and -0.5 for float-to-integer rounding. */
@@ -169,10 +183,9 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
Entity_Id standard_long_long_float, Entity_Id standard_exception_type,
Int gigi_operating_mode)
{
- bool body_p;
- Entity_Id gnat_unit_entity;
tree gnu_standard_long_long_float;
tree gnu_standard_exception_type;
+ struct elab_info *info;
max_gnat_nodes = max_gnat_node;
number_names = number_name;
@@ -226,53 +239,42 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name,
if (Exception_Mechanism == GCC_ZCX)
gnat_init_gcc_eh ();
- /* Make the decl for the elaboration procedure. */
- body_p = (Defining_Entity (Unit (gnat_root)),
- Nkind (Unit (gnat_root)) == N_Package_Body
- || Nkind (Unit (gnat_root)) == N_Subprogram_Body);
- gnat_unit_entity = Defining_Entity (Unit (gnat_root));
-
- gnu_elab_proc_decl
- = create_subprog_decl
- (create_concat_name (gnat_unit_entity,
- body_p ? "elabb" : "elabs"),
- NULL_TREE, void_ftype, NULL_TREE, false, true, false, NULL,
- gnat_unit_entity);
-
- DECL_ELABORATION_PROC_P (gnu_elab_proc_decl) = 1;
- allocate_struct_function (gnu_elab_proc_decl);
- Sloc_to_locus (Sloc (gnat_unit_entity), &cfun->function_end_locus);
- cfun = 0;
-
- /* For a body, first process the spec if there is one. */
- if (Nkind (Unit (gnat_root)) == N_Package_Body
- || (Nkind (Unit (gnat_root)) == N_Subprogram_Body
- && !Acts_As_Spec (gnat_root)))
- add_stmt (gnat_to_gnu (Library_Unit (gnat_root)));
+ if (Nkind (gnat_root) != N_Compilation_Unit)
+ abort ();
- process_inlined_subprograms (gnat_root);
+ Compilation_Unit_to_gnu (gnat_root);
- if (type_annotate_only)
+ /* Now see if we have any elaboration procedures to deal with. */
+ for (info = elab_info_list; info; info = info->next)
{
- elaborate_all_entities (gnat_root);
-
- if (Nkind (Unit (gnat_root)) == N_Subprogram_Declaration
- || Nkind (Unit (gnat_root)) == N_Generic_Package_Declaration
- || Nkind (Unit (gnat_root)) == N_Generic_Subprogram_Declaration)
- return;
+ tree gnu_body = DECL_SAVED_TREE (info->elab_proc);
+ tree gnu_stmts;
+
+ /* Mark everything we have as not visited. */
+ walk_tree_without_duplicates (&gnu_body, mark_unvisited, NULL);
+
+ /* Set the current function to be the elaboration procedure and gimplify
+ what we have. */
+ current_function_decl = info->elab_proc;
+ gimplify_body (&gnu_body, info->elab_proc);
+
+ /* We should have a BIND_EXPR, but it may or may not have any statements
+ in it. If it doesn't have any, we have nothing to do. */
+ gnu_stmts = gnu_body;
+ if (TREE_CODE (gnu_stmts) == BIND_EXPR)
+ gnu_stmts = BIND_EXPR_BODY (gnu_stmts);
+
+ /* If there are no statements, there is no elaboration code. */
+ if (!gnu_stmts || !STATEMENT_LIST_HEAD (gnu_stmts))
+ Set_Has_No_Elaboration_Code (info->gnat_node, 1);
+ else
+ {
+ /* Otherwise, compile the function. Note that we'll be gimplifying
+ it twice, but that's fine for the nodes we use. */
+ begin_subprog_body (info->elab_proc);
+ end_subprog_body (gnu_body);
+ }
}
-
- process_decls (Declarations (Aux_Decls_Node (gnat_root)), Empty, Empty,
- true, true);
- add_stmt (gnat_to_gnu (Unit (gnat_root)));
-
- /* Process any pragmas and actions following the unit. */
- add_stmt_list (Pragmas_After (Aux_Decls_Node (gnat_root)));
- add_stmt_list (Actions (Aux_Decls_Node (gnat_root)));
-
- /* Generate elaboration code for this unit, if necessary, and say whether
- we did or not. */
- Set_Has_No_Elaboration_Code (gnat_root, build_unit_elab ());
}
/* Perform initializations for this module. */
@@ -284,7 +286,7 @@ gnat_init_stmt_group ()
init_code_table ();
start_stmt_group ();
- global_stmt_group = current_stmt_group;
+ current_stmt_group->global = current_stmt_group;
/* Enable GNAT stack checking method if needed */
if (!Stack_Check_Probes_On_Target)
@@ -2331,6 +2333,73 @@ Exception_Handler_to_gnu_zcx (Node_Id gnat_node)
end_stmt_group ());
}
+/* Subroutine of gnat_to_gnu to generate code for an N_Compilation unit. */
+
+static void
+Compilation_Unit_to_gnu (Node_Id gnat_node)
+{
+ /* Make the decl for the elaboration procedure. */
+ bool body_p = (Defining_Entity (Unit (gnat_node)),
+ Nkind (Unit (gnat_node)) == N_Package_Body
+ || Nkind (Unit (gnat_node)) == N_Subprogram_Body);
+ Entity_Id gnat_unit_entity = Defining_Entity (Unit (gnat_node));
+ tree gnu_elab_proc_decl
+ = create_subprog_decl
+ (create_concat_name (gnat_unit_entity,
+ body_p ? "elabb" : "elabs"),
+ NULL_TREE, void_ftype, NULL_TREE, false, true, false, NULL,
+ gnat_unit_entity);
+ struct elab_info *info;
+
+ push_stack (&gnu_elab_proc_stack, NULL_TREE, gnu_elab_proc_decl);
+
+ DECL_ELABORATION_PROC_P (gnu_elab_proc_decl) = 1;
+ allocate_struct_function (gnu_elab_proc_decl);
+ Sloc_to_locus (Sloc (gnat_unit_entity), &cfun->function_end_locus);
+ cfun = 0;
+
+ /* For a body, first process the spec if there is one. */
+ if (Nkind (Unit (gnat_node)) == N_Package_Body
+ || (Nkind (Unit (gnat_node)) == N_Subprogram_Body
+ && !Acts_As_Spec (gnat_node)))
+ add_stmt (gnat_to_gnu (Library_Unit (gnat_node)));
+
+ process_inlined_subprograms (gnat_node);
+
+ if (type_annotate_only)
+ {
+ elaborate_all_entities (gnat_node);
+
+ if (Nkind (Unit (gnat_node)) == N_Subprogram_Declaration
+ || Nkind (Unit (gnat_node)) == N_Generic_Package_Declaration
+ || Nkind (Unit (gnat_node)) == N_Generic_Subprogram_Declaration)
+ return;
+ }
+
+ process_decls (Declarations (Aux_Decls_Node (gnat_node)), Empty, Empty,
+ true, true);
+ add_stmt (gnat_to_gnu (Unit (gnat_node)));
+
+ /* Process any pragmas and actions following the unit. */
+ add_stmt_list (Pragmas_After (Aux_Decls_Node (gnat_node)));
+ add_stmt_list (Actions (Aux_Decls_Node (gnat_node)));
+
+ /* Save away what we've made so far and record this potential elaboration
+ procedure. */
+ info = (struct elab_info *) ggc_alloc (sizeof (struct elab_info));
+ set_current_block_context (gnu_elab_proc_decl);
+ gnat_poplevel ();
+ DECL_SAVED_TREE (gnu_elab_proc_decl) = end_stmt_group ();
+ info->next = elab_info_list;
+ info->elab_proc = gnu_elab_proc_decl;
+ info->gnat_node = gnat_node;
+ elab_info_list = info;
+
+ /* Generate elaboration code for this unit, if necessary, and say whether
+ we did or not. */
+ pop_stack (&gnu_elab_proc_stack);
+}
+
/* This function is the driver of the GNAT to GCC tree transformation
process. It is the entry point of the tree transformer. GNAT_NODE is the
root of some GNAT tree. Return the root of the corresponding GCC tree.
@@ -2382,7 +2451,7 @@ gnat_to_gnu (Node_Id gnat_node)
|| Nkind (gnat_node) == N_Raise_Program_Error)
&& (Ekind (Etype (gnat_node)) == E_Void))))
{
- current_function_decl = gnu_elab_proc_decl;
+ current_function_decl = TREE_VALUE (gnu_elab_proc_stack);
start_stmt_group ();
gnat_pushlevel ();
went_into_elab_proc = true;
@@ -3587,24 +3656,11 @@ gnat_to_gnu (Node_Id gnat_node)
/* This is not called for the main unit, which is handled in function
gigi above. */
start_stmt_group ();
+ current_stmt_group->global = current_stmt_group;
+ gnat_pushlevel ();
- /* For a body, first process the spec if there is one. */
- if (Nkind (Unit (gnat_node)) == N_Package_Body
- || (Nkind (Unit (gnat_node)) == N_Subprogram_Body
- && !Acts_As_Spec (gnat_node)))
- add_stmt (gnat_to_gnu (Library_Unit (gnat_node)));
-
- process_inlined_subprograms (gnat_node);
- process_decls (Declarations (Aux_Decls_Node (gnat_node)),
- Empty, Empty, true, true);
- add_stmt (gnat_to_gnu (Unit (gnat_node)));
-
- /* Process any pragmas and actions following the unit. */
- add_stmt_list (Pragmas_After (Aux_Decls_Node (gnat_node)));
- add_stmt_list (Actions (Aux_Decls_Node (gnat_node)));
-
- Set_Has_No_Elaboration_Code (gnat_node, 1);
- gnu_result = end_stmt_group ();
+ Compilation_Unit_to_gnu (gnat_node);
+ gnu_result = alloc_stmt_list ();
break;
case N_Subprogram_Body_Stub:
@@ -4057,6 +4113,7 @@ start_stmt_group ()
group->previous = current_stmt_group;
group->stmt_list = group->block = group->cleanups = NULL_TREE;
+ group->global = current_stmt_group ? current_stmt_group->global : NULL;
current_stmt_group = group;
}
@@ -4117,7 +4174,7 @@ add_decl_expr (tree gnu_decl, Entity_Id gnat_entity)
return;
if (global_bindings_p ())
- current_stmt_group = global_stmt_group;
+ current_stmt_group = current_stmt_group->global;
add_stmt_with_node (build (DECL_EXPR, void_type_node, gnu_decl),
gnat_entity);
@@ -4339,7 +4396,7 @@ gnat_expand_stmt (tree gnu_stmt)
/* Generate GIMPLE in place for the expression at *EXPR_P. */
int
-gnat_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, tree *post_p)
+gnat_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
{
tree expr = *expr_p;
@@ -4362,7 +4419,7 @@ gnat_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, tree *post_p)
TREE_NO_WARNING (*expr_p) = 1;
}
- append_to_statement_list (TREE_OPERAND (expr, 0), post_p);
+ append_to_statement_list (TREE_OPERAND (expr, 0), pre_p);
return GS_OK;
case UNCONSTRAINED_ARRAY_REF:
@@ -5614,45 +5671,6 @@ gnat_stabilize_reference_1 (tree e, bool force)
return result;
}
-/* Take care of building the elaboration procedure for the main unit.
-
- Return true if we didn't need an elaboration function, false otherwise. */
-
-static bool
-build_unit_elab ()
-{
- tree body, stmts;
-
- /* Mark everything we have as not visited. */
- walk_tree_without_duplicates (&current_stmt_group->stmt_list,
- mark_unvisited, NULL);
-
- /* Set the current function to be the elaboration procedure, pop our
- binding level, end our statement group, and gimplify what we have. */
- set_current_block_context (gnu_elab_proc_decl);
- gnat_poplevel ();
- body = end_stmt_group ();
- current_function_decl = gnu_elab_proc_decl;
- gimplify_body (&body, gnu_elab_proc_decl);
-
- /* We should have a BIND_EXPR, but it may or may not have any statements
- in it. If it doesn't have any, we have nothing to do. */
- stmts = body;
- if (TREE_CODE (stmts) == BIND_EXPR)
- stmts = BIND_EXPR_BODY (stmts);
-
- /* If there are no statements, we have nothing to do. */
- if (!stmts || !STATEMENT_LIST_HEAD (stmts))
- return true;
-
- /* Otherwise, compile the function. Note that we'll be gimplifying
- it twice, but that's fine for the nodes we use. */
- begin_subprog_body (gnu_elab_proc_decl);
- end_subprog_body (body);
-
- return false;
-}
-
extern char *__gnat_to_canonical_file_spec (char *);
/* Convert Sloc into *LOCUS (a location_t). Return true if this Sloc