diff options
author | law <law@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-08-18 17:49:28 +0000 |
---|---|---|
committer | law <law@138bc75d-0d04-0410-961f-82ee72b054a4> | 1998-08-18 17:49:28 +0000 |
commit | f708f8fd7b3f028eb8bd3ea06048a94a8ae6d9b3 (patch) | |
tree | 204fa56dd26f617dfbc77b6524547796e4392cb0 /gcc/expr.c | |
parent | d1b1832e666b64ac34ae4a9e6dd01c7b085252d3 (diff) | |
download | gcc-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
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 133 |
1 files changed, 116 insertions, 17 deletions
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, |