expr.c (emit_block_move): Do not call memcpy as a libcall instead build up a CALL_EXP...
authorJeffrey A Law <law@cygnus.com>
Tue, 18 Aug 1998 17:49:28 +0000 (17:49 +0000)
committerJeff Law <law@gcc.gnu.org>
Tue, 18 Aug 1998 17:49:28 +0000 (11:49 -0600)
        * expr.c (emit_block_move): Do not call memcpy as a libcall
        instead build up a CALL_EXPR and call it like any other
        function.
        (clear_storage): Similarly for memset.

From-SVN: r21831

gcc/ChangeLog
gcc/expr.c

index c17374e726fbf4f5f75a4d3b0da941fc80024968..97dea44cce24cb42f282d1fc595a2c1c2936395c 100644 (file)
@@ -5,6 +5,11 @@ Tue Aug 18 12:40:27 1998  Richard Henderson  <rth@cygnus.com>
 
 Tue Aug 18 10:33:30 1998  Jeffrey A Law  (law@cygnus.com)
 
+       * expr.c (emit_block_move): Do not call memcpy as a libcall
+       instead build up a CALL_EXPR and call it like any other
+       function.
+       (clear_storage): Similarly for memset.
+
        * regmove.c (fixup_match_2): Do not call reg_overlap_mentioned_p
        on notes.
 
index cfea6304f270f55d0d058d7bcced81a7820bb322..e14517bf58c7beaebca120aee25309fcab8d0be3 100644 (file)
@@ -1616,6 +1616,10 @@ emit_block_move (x, y, size, align)
      int align;
 {
   rtx retval = 0;
+#ifdef TARGET_MEM_FUNCTIONS
+  static tree fn;
+  tree call_expr, arg_list;
+#endif
 
   if (GET_MODE (x) != BLKmode)
     abort ();
@@ -1689,13 +1693,60 @@ emit_block_move (x, y, size, align)
        }
 
 #ifdef TARGET_MEM_FUNCTIONS
-      retval
-       = emit_library_call_value (memcpy_libfunc, NULL_RTX, 0,
-                                  ptr_mode, 3, XEXP (x, 0), Pmode,
-                                  XEXP (y, 0), Pmode,
-                                  convert_to_mode (TYPE_MODE (sizetype), size,
-                                                   TREE_UNSIGNED (sizetype)),
-                                  TYPE_MODE (sizetype));
+      /* It is incorrect to use the libcall calling conventions to call
+        memcpy in this context.
+
+        This could be a user call to memcpy and the user may wish to
+        examine the return value from memcpy.
+
+        For targets where libcalls and normal calls have different conventions
+        for returning pointers, we could end up generating incorrect code. 
+
+        So instead of using a libcall sequence we build up a suitable
+        CALL_EXPR and expand the call in the normal fashion.  */
+      if (fn == NULL_TREE)
+       {
+         tree fntype;
+
+         /* This was copied from except.c, I don't know if all this is
+            necessary in this context or not.  */
+         fn = get_identifier ("memcpy");
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         fntype = build_pointer_type (void_type_node);
+         fntype = build_function_type (fntype, NULL_TREE);
+         fn = build_decl (FUNCTION_DECL, fn, fntype);
+         DECL_EXTERNAL (fn) = 1;
+         TREE_PUBLIC (fn) = 1;
+         DECL_ARTIFICIAL (fn) = 1;
+         make_decl_rtl (fn, NULL_PTR, 1);
+         assemble_external (fn);
+         pop_obstacks ();
+       }
+
+      /* We need to make an argument list for the function call. 
+
+        memcpy has three arguments, the first two are void * addresses and
+        the last is a size_t byte count for the copy.  */
+      arg_list
+       = build_tree_list (NULL_TREE,
+                           make_tree (build_pointer_type (void_type_node),
+                                      XEXP (x, 0)));
+      TREE_CHAIN (arg_list)
+       = build_tree_list (NULL_TREE,
+                          make_tree (build_pointer_type (void_type_node),
+                                     XEXP (y, 0)));
+      TREE_CHAIN (TREE_CHAIN (arg_list))
+        = build_tree_list (NULL_TREE, make_tree (sizetype, size));
+      TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
+
+      /* Now we have to build up the CALL_EXPR itself.  */
+      call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+                        call_expr, arg_list, NULL_TREE);
+      TREE_SIDE_EFFECTS (call_expr) = 1;
+
+      retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 #else
       emit_library_call (bcopy_libfunc, 0,
                         VOIDmode, 3, XEXP (y, 0), Pmode,
@@ -2211,6 +2262,10 @@ clear_storage (object, size, align)
      rtx size;
      int align;
 {
+#ifdef TARGET_MEM_FUNCTIONS
+  static tree fn;
+  tree call_expr, arg_list;
+#endif
   rtx retval = 0;
 
   if (GET_MODE (object) == BLKmode)
@@ -2275,16 +2330,60 @@ clear_storage (object, size, align)
 
 
 #ifdef TARGET_MEM_FUNCTIONS
-         retval
-           = emit_library_call_value (memset_libfunc, NULL_RTX, 0,
-                                      ptr_mode, 3,
-                                      XEXP (object, 0), Pmode,
-                                      const0_rtx,
-                                      TYPE_MODE (integer_type_node),
-                                      convert_to_mode
-                                      (TYPE_MODE (sizetype), size,
-                                       TREE_UNSIGNED (sizetype)),
-                                      TYPE_MODE (sizetype));
+      /* It is incorrect to use the libcall calling conventions to call
+        memset in this context.
+
+        This could be a user call to memset and the user may wish to
+        examine the return value from memset.
+
+        For targets where libcalls and normal calls have different conventions
+        for returning pointers, we could end up generating incorrect code. 
+
+        So instead of using a libcall sequence we build up a suitable
+        CALL_EXPR and expand the call in the normal fashion.  */
+      if (fn == NULL_TREE)
+       {
+         tree fntype;
+
+         /* This was copied from except.c, I don't know if all this is
+            necessary in this context or not.  */
+         fn = get_identifier ("memset");
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         fntype = build_pointer_type (void_type_node);
+         fntype = build_function_type (fntype, NULL_TREE);
+         fn = build_decl (FUNCTION_DECL, fn, fntype);
+         DECL_EXTERNAL (fn) = 1;
+         TREE_PUBLIC (fn) = 1;
+         DECL_ARTIFICIAL (fn) = 1;
+         make_decl_rtl (fn, NULL_PTR, 1);
+         assemble_external (fn);
+         pop_obstacks ();
+       }
+
+      /* We need to make an argument list for the function call. 
+
+        memset has three arguments, the first is a void * addresses, the
+        second a integer with the initialization value, the last is a size_t
+        byte count for the copy.  */
+      arg_list
+       = build_tree_list (NULL_TREE,
+                           make_tree (build_pointer_type (void_type_node),
+                                      XEXP (object, 0)));
+      TREE_CHAIN (arg_list)
+       = build_tree_list (NULL_TREE,
+                          make_tree (integer_type_node, const0_rtx));
+      TREE_CHAIN (TREE_CHAIN (arg_list))
+        = build_tree_list (NULL_TREE, make_tree (sizetype, size));
+      TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
+
+      /* Now we have to build up the CALL_EXPR itself.  */
+      call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+      call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+                        call_expr, arg_list, NULL_TREE);
+      TREE_SIDE_EFFECTS (call_expr) = 1;
+
+      retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
 #else
          emit_library_call (bzero_libfunc, 0,
                             VOIDmode, 2,