summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>1998-08-18 17:49:28 +0000
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>1998-08-18 17:49:28 +0000
commitf708f8fd7b3f028eb8bd3ea06048a94a8ae6d9b3 (patch)
tree204fa56dd26f617dfbc77b6524547796e4392cb0
parentd1b1832e666b64ac34ae4a9e6dd01c7b085252d3 (diff)
downloadgcc-f708f8fd7b3f028eb8bd3ea06048a94a8ae6d9b3.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@21831 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/expr.c133
2 files changed, 121 insertions, 17 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c17374e726f..97dea44cce2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/expr.c b/gcc/expr.c
index cfea6304f27..e14517bf58c 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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,