PR ada/19419
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 6 Nov 2008 11:28:07 +0000 (11:28 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 6 Nov 2008 11:28:07 +0000 (11:28 +0000)
* gcc-interface/trans.c (gnat_to_gnu) <N_Assignment_Statement>:
Generate a call to memmove for an assignment between overlapping
array slices.

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

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

index ba94a5e..6730093 100644 (file)
@@ -1,3 +1,10 @@
+2008-11-06  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR ada/19419
+       * gcc-interface/trans.c (gnat_to_gnu) <N_Assignment_Statement>:
+       Generate a call to memmove for an assignment between overlapping
+       array slices.
+
 2008-11-02  Andreas Krebbel  <Andreas.Krebbel@de.ibm.com>
 
        PR target/37977
index 6ade568..9f050bd 100644 (file)
@@ -4159,12 +4159,33 @@ gnat_to_gnu (Node_Id gnat_node)
          gnu_rhs
            = maybe_unconstrained_array (gnat_to_gnu (Expression (gnat_node)));
 
-         /* If range check is needed, emit code to generate it */
+         /* If range check is needed, emit code to generate it */
          if (Do_Range_Check (Expression (gnat_node)))
            gnu_rhs = emit_range_check (gnu_rhs, Etype (Name (gnat_node)));
 
          gnu_result
            = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_lhs, gnu_rhs);
+
+         /* If the type being assigned is an array type and the two sides
+            are not completely disjoint, play safe and use memmove.  */
+         if (TREE_CODE (gnu_result) == MODIFY_EXPR
+             && Is_Array_Type (Etype (Name (gnat_node)))
+             && !(Forwards_OK (gnat_node) && Backwards_OK (gnat_node)))
+           {
+             tree to, from, size, to_ptr, from_ptr, t;
+
+             to = TREE_OPERAND (gnu_result, 0);
+             from = TREE_OPERAND (gnu_result, 1);
+
+             size = TYPE_SIZE_UNIT (TREE_TYPE (from));
+             size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, from);
+
+             to_ptr = build_fold_addr_expr (to);
+             from_ptr = build_fold_addr_expr (from);
+
+             t = implicit_built_in_decls[BUILT_IN_MEMMOVE];
+             gnu_result = build_call_expr (t, 3, to_ptr, from_ptr, size);
+          }
        }
       break;