OSDN Git Service

* gcc-interface/trans.c (call_to_gnu): Open a nesting level if this is
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 15 Apr 2010 12:40:15 +0000 (12:40 +0000)
committerMasaki Muranaka <monaka@monami-software.com>
Sun, 23 May 2010 05:32:41 +0000 (14:32 +0900)
a statement.  Otherwise, if at top-level, push the processing of the
elaboration routine.  In the misaligned case, issue the error messages
again on entry and create the temporary explicitly.  Do not issue them
for CONSTRUCTORs.
For a function call, emit the range check if necessary.
In the copy-in copy-out case, create the temporary for the return
value explicitly.
Do not unnecessarily convert by-ref parameters to the formal's type.
Remove obsolete guards in conditions.
(gnat_to_gnu) <N_Assignment_Statement>: For a function call, pass the
target to call_to_gnu in all cases.
(gnat_gimplify_expr) <ADDR_EXPR>: Remove handling of SAVE_EXPR.
(addressable_p) <CONSTRUCTOR>: Return false if not static.
<COMPOUND_EXPR>: New case.
* gcc-interface/utils2.c (build_unary_op) <ADDR_EXPR>: Fold a compound
expression if it has unconstrained array type.
(gnat_mark_addressable) <COMPOUND_EXPR>: New case.
(gnat_stabilize_reference) <COMPOUND_EXPR>: Stabilize operands on an
individual basis.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158371 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ada/ChangeLog
gcc/ada/gcc-interface/trans.c
gcc/ada/gcc-interface/utils2.c

index 7c97b6c..3fad5a5 100644 (file)
@@ -1,5 +1,28 @@
 2010-04-15  Eric Botcazou  <ebotcazou@adacore.com>
 
+       * gcc-interface/trans.c (call_to_gnu): Open a nesting level if this is
+       a statement.  Otherwise, if at top-level, push the processing of the
+       elaboration routine.  In the misaligned case, issue the error messages
+       again on entry and create the temporary explicitly.  Do not issue them
+       for CONSTRUCTORs.
+       For a function call, emit the range check if necessary.
+       In the copy-in copy-out case, create the temporary for the return
+       value explicitly.
+       Do not unnecessarily convert by-ref parameters to the formal's type.
+       Remove obsolete guards in conditions.
+       (gnat_to_gnu) <N_Assignment_Statement>: For a function call, pass the
+       target to call_to_gnu in all cases.
+       (gnat_gimplify_expr) <ADDR_EXPR>: Remove handling of SAVE_EXPR.
+       (addressable_p) <CONSTRUCTOR>: Return false if not static.
+       <COMPOUND_EXPR>: New case.
+       * gcc-interface/utils2.c (build_unary_op) <ADDR_EXPR>: Fold a compound
+       expression if it has unconstrained array type.
+       (gnat_mark_addressable) <COMPOUND_EXPR>: New case.
+       (gnat_stabilize_reference) <COMPOUND_EXPR>: Stabilize operands on an
+       individual basis.
+
+2010-04-15  Eric Botcazou  <ebotcazou@adacore.com>
+
        * gcc-interface/trans.c (gigi): Do not start statement group.
        (Compilation_Unit_to_gnu): Set current_function_decl to NULL.
        Start statement group and push binding level here...
index c0c11bb..49dd0d7 100644 (file)
@@ -2619,6 +2619,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
   tree gnu_before_list = NULL_TREE;
   tree gnu_after_list = NULL_TREE;
   tree gnu_call;
+  bool went_into_elab_proc = false;
 
   gcc_assert (TREE_CODE (gnu_subprog_type) == FUNCTION_TYPE);
 
@@ -2655,6 +2656,22 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
   else
     gnat_formal = First_Formal_With_Extras (Entity (Name (gnat_node)));
 
+  /* If we are translating a statement, open a new nesting level that will
+     surround it to declare the temporaries created for the call.  */
+  if (Nkind (gnat_node) == N_Procedure_Call_Statement || gnu_target)
+    {
+      start_stmt_group ();
+      gnat_pushlevel ();
+    }
+
+  /* The lifetime of the temporaries created for the call ends with the call
+     so we can give them the scope of the elaboration routine at top level.  */
+  else if (!current_function_decl)
+    {
+      current_function_decl = TREE_VALUE (gnu_elab_proc_stack);
+      went_into_elab_proc = true;
+    }
+
   /* Create the list of the actual parameters as GCC expects it, namely a
      chain of TREE_LIST nodes in which the TREE_VALUE field of each node
      is an expression and the TREE_PURPOSE field is null.  But skip Out
@@ -2704,7 +2721,34 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
          && (gnu_name_type = gnat_to_gnu_type (Etype (gnat_name)))
          && !addressable_p (gnu_name, gnu_name_type))
        {
-         tree gnu_copy = gnu_name;
+         tree gnu_orig = gnu_name, gnu_temp, gnu_stmt;
+
+         /* Do not issue warnings for CONSTRUCTORs since this is not a copy
+            but sort of an instantiation for them.  */
+         if (TREE_CODE (gnu_name) == CONSTRUCTOR)
+           ;
+
+         /* If the type is passed by reference, a copy is not allowed.  */
+         else if (TREE_ADDRESSABLE (gnu_formal_type))
+           post_error ("misaligned actual cannot be passed by reference",
+                       gnat_actual);
+
+         /* For users of Starlet we issue a warning because the interface
+            apparently assumes that by-ref parameters outlive the procedure
+            invocation.  The code still will not work as intended, but we
+            cannot do much better since low-level parts of the back-end
+            would allocate temporaries at will because of the misalignment
+            if we did not do so here.  */
+         else if (Is_Valued_Procedure (Entity (Name (gnat_node))))
+           {
+             post_error
+               ("?possible violation of implicit assumption", gnat_actual);
+             post_error_ne
+               ("?made by pragma Import_Valued_Procedure on &", gnat_actual,
+                Entity (Name (gnat_node)));
+             post_error_ne ("?because of misalignment of &", gnat_actual,
+                            gnat_formal);
+           }
 
          /* If the actual type of the object is already the nominal type,
             we have nothing to do, except if the size is self-referential
@@ -2736,38 +2780,23 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
                                               TREE_TYPE (gnu_name))))
            gnu_name = convert (gnu_name_type, gnu_name);
 
-         /* Make a SAVE_EXPR to force the creation of a temporary.  Special
-            code in gnat_gimplify_expr ensures that the same temporary is
-            used as the object and copied back after the call if needed.  */
-         gnu_name = build1 (SAVE_EXPR, TREE_TYPE (gnu_name), gnu_name);
-         TREE_SIDE_EFFECTS (gnu_name) = 1;
-
-         /* If the type is passed by reference, a copy is not allowed.  */
-         if (TREE_ADDRESSABLE (gnu_formal_type))
-           {
-             post_error ("misaligned actual cannot be passed by reference",
-                         gnat_actual);
+         /* Create an explicit temporary holding the copy.  This ensures that
+            its lifetime is as narrow as possible around a statement.  */
+         gnu_temp = create_var_decl (create_tmp_var_name ("A"), NULL_TREE,
+                                     TREE_TYPE (gnu_name), NULL_TREE, false,
+                                     false, false, false, NULL, Empty);
+         DECL_ARTIFICIAL (gnu_temp) = 1;
+         DECL_IGNORED_P (gnu_temp) = 1;
 
-             /* Avoid the back-end assertion on temporary creation.  */
-             gnu_name = TREE_OPERAND (gnu_name, 0);
-           }
+         /* But initialize it on the fly like for an implicit temporary as
+            we aren't necessarily dealing with a statement.  */
+         gnu_stmt
+           = build_binary_op (INIT_EXPR, NULL_TREE, gnu_temp, gnu_name);
+         set_expr_location_from_node (gnu_stmt, gnat_actual);
 
-         /* For users of Starlet we issue a warning because the interface
-            apparently assumes that by-ref parameters outlive the procedure
-            invocation.  The code still will not work as intended, but we
-            cannot do much better since low-level parts of the back-end
-            would allocate temporaries at will because of the misalignment
-            if we did not do so here.  */
-         else if (Is_Valued_Procedure (Entity (Name (gnat_node))))
-           {
-             post_error
-               ("?possible violation of implicit assumption", gnat_actual);
-             post_error_ne
-               ("?made by pragma Import_Valued_Procedure on &", gnat_actual,
-                Entity (Name (gnat_node)));
-             post_error_ne ("?because of misalignment of &", gnat_actual,
-                            gnat_formal);
-           }
+         /* From now on, the real object is the temporary.  */
+         gnu_name = build2 (COMPOUND_EXPR, TREE_TYPE (gnu_name), gnu_stmt,
+                            gnu_temp);
 
          /* Set up to move the copy back to the original if needed.  */
          if (Ekind (gnat_formal) != E_In_Parameter)
@@ -2808,10 +2837,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
        gnu_actual
          = emit_range_check (gnu_actual, Etype (gnat_formal), gnat_actual);
 
-      /* And convert it to this type.  */
-      if (TREE_CODE (gnu_actual) != SAVE_EXPR)
-       gnu_actual = convert (gnu_formal_type, gnu_actual);
-
       /* Unless this is an In parameter, we must remove any justified modular
         building from GNU_NAME to get an lvalue.  */
       if (Ekind (gnat_formal) != E_In_Parameter
@@ -2823,7 +2848,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
 
       /* If we have not saved a GCC object for the formal, it means it is an
         Out parameter not passed by reference and that need not be copied in.
-        Otherwise, first see if the PARM_DECL is passed by reference.  */
+        Otherwise, first see if the parameter is passed by reference.  */
       if (gnu_formal
          && TREE_CODE (gnu_formal) == PARM_DECL
          && DECL_BY_REF_P (gnu_formal))
@@ -2891,6 +2916,8 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
               && TREE_CODE (gnu_formal) == PARM_DECL
               && DECL_BY_DESCRIPTOR_P (gnu_formal))
        {
+         gnu_actual = convert (gnu_formal_type, gnu_actual);
+
          /* If this is 'Null_Parameter, pass a zero descriptor.  */
          if ((TREE_CODE (gnu_actual) == INDIRECT_REF
               || TREE_CODE (gnu_actual) == UNCONSTRAINED_ARRAY_REF)
@@ -2918,6 +2945,8 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
              continue;
            }
 
+         gnu_actual = convert (gnu_formal_type, gnu_actual);
+
          /* If this is 'Null_Parameter, pass a zero even though we are
             dereferencing it.  */
          if (TREE_CODE (gnu_actual) == INDIRECT_REF
@@ -2948,7 +2977,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
   if (Nkind (gnat_node) == N_Function_Call)
     {
       tree gnu_result = gnu_call;
-      enum tree_code op_code;
 
       /* If the function returns an unconstrained array or by direct reference,
         we have to dereference the pointer.  */
@@ -2958,6 +2986,15 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
 
       if (gnu_target)
        {
+         Node_Id gnat_parent = Parent (gnat_node);
+         enum tree_code op_code;
+
+         /* If range check is needed, emit code to generate it.  */
+         if (Do_Range_Check (gnat_node))
+           gnu_result
+             = emit_range_check (gnu_result, Etype (Name (gnat_parent)),
+                                 gnat_parent);
+
          /* ??? If the return type has non-constant size, then force the
             return slot optimization as we would not be able to generate
             a temporary.  That's what has been done historically.  */
@@ -2968,6 +3005,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
 
          gnu_result
            = build_binary_op (op_code, NULL_TREE, gnu_target, gnu_result);
+         add_stmt_with_node (gnu_result, gnat_parent);
+         gnat_poplevel ();
+         gnu_result = end_stmt_group ();
        }
       else
        {
@@ -2984,17 +3024,31 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
      passing mechanism must be used.  */
   if (TYPE_CI_CO_LIST (gnu_subprog_type))
     {
-      /* List of FIELD_DECLs associated with the PARM_DECLs of the copy
-        in copy out parameters.  */
+      /* List of FIELD_DECLs associated with the PARM_DECLs of the copy-in/
+        copy-out parameters.  */
       tree gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
       const int length = list_length (gnu_cico_list);
 
       if (length > 1)
        {
+         tree gnu_temp, gnu_stmt;
+
          /* The call sequence must contain one and only one call, even though
-            the function is const or pure.  So force a SAVE_EXPR.  */
-         gnu_call = build1 (SAVE_EXPR, TREE_TYPE (gnu_call), gnu_call);
-         TREE_SIDE_EFFECTS (gnu_call) = 1;
+            the function is pure.  Save the result into a temporary.  */
+         gnu_temp = create_var_decl (create_tmp_var_name ("R"), NULL_TREE,
+                                     TREE_TYPE (gnu_call), NULL_TREE, false,
+                                     false, false, false, NULL, Empty);
+         DECL_ARTIFICIAL (gnu_temp) = 1;
+         DECL_IGNORED_P (gnu_temp) = 1;
+
+         gnu_stmt
+           = build_binary_op (INIT_EXPR, NULL_TREE, gnu_temp, gnu_call);
+         set_expr_location_from_node (gnu_stmt, gnat_node);
+
+         /* Add the call statement to the list and start from its result.  */
+         append_to_statement_list (gnu_stmt, &gnu_before_list);
+         gnu_call = gnu_temp;
+
          gnu_name_list = nreverse (gnu_name_list);
        }
 
@@ -3091,7 +3145,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
 
   append_to_statement_list (gnu_after_list, &gnu_before_list);
 
-  return gnu_before_list;
+  add_stmt (gnu_before_list);
+  gnat_poplevel ();
+  return end_stmt_group ();
 }
 \f
 /* Subroutine of gnat_to_gnu to translate gnat_node, an
@@ -5994,24 +6050,6 @@ gnat_gimplify_expr (tree *expr_p, gimple_seq *pre_p,
          return GS_ALL_DONE;
        }
 
-         /* Otherwise explicitly create the local temporary.  That's required
-            if the type is passed by reference.  */
-         else
-           {
-             tree mod, new_var = create_tmp_var_raw (TREE_TYPE (op), "C");
-             TREE_ADDRESSABLE (new_var) = 1;
-             gimple_add_tmp_var (new_var);
-
-             mod = build2 (INIT_EXPR, TREE_TYPE (new_var), new_var, op);
-             gimplify_and_add (mod, pre_p);
-
-             TREE_OPERAND (expr, 0) = new_var;
-             recompute_tree_invariant_for_addr_expr (expr);
-           }
-
-         return GS_ALL_DONE;
-       }
-
       return GS_UNHANDLED;
 
     case DECL_EXPR:
index 0f7f4e9..2aa8605 100644 (file)
@@ -2164,6 +2164,10 @@ gnat_mark_addressable (tree t)
        t = TREE_OPERAND (t, 0);
        break;
 
+      case COMPOUND_EXPR:
+       t = TREE_OPERAND (t, 1);
+       break;
+
       case CONSTRUCTOR:
        TREE_ADDRESSABLE (t) = 1;
        return true;
@@ -2422,10 +2426,17 @@ gnat_stabilize_reference (tree ref, bool force, bool *success)
       break;
 
     case CALL_EXPR:
-    case COMPOUND_EXPR:
       result = gnat_stabilize_reference_1 (ref, force);
       break;
 
+    case COMPOUND_EXPR:
+      result = build2 (COMPOUND_EXPR, type,
+                      gnat_stabilize_reference (TREE_OPERAND (ref, 0), force,
+                                                success),
+                      gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
+                                                  force));
+      break;
+
     case CONSTRUCTOR:
       /* Constructors with 1 element are used extensively to formally
         convert objects to special wrapping types.  */