diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-09-02 06:47:01 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-09-02 06:47:01 +0000 |
commit | 41dc12b443303c7422244ad83c673fc022a18aa9 (patch) | |
tree | 92274b998af0cc6f86fd45d1b53bb9d1eef8bed0 /gcc/calls.c | |
parent | 998d01227e4b1c1980db971f01db98195a7d4eaa (diff) | |
download | gcc-41dc12b443303c7422244ad83c673fc022a18aa9.tar.gz |
PR middle-end/17258
* calls.c (initialize_argument_information): Tighten pass-through
conditions for pass-by-reference. Remove dead TARGET_EXPR code.
Use build_fold_addr_expr.
(emit_library_call_value_1): Use build_fold_addr_expr. Remove code
that assumes ADDR_EXPR allocates stack space.
* fold-const.c (build_fold_addr_expr_with_type): Look through
WITH_SIZE_EXPR.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@86957 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 92 |
1 files changed, 30 insertions, 62 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index 2e500bd0044..e350a3fed14 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -970,54 +970,30 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, if (pass_by_reference (args_so_far, TYPE_MODE (type), type, argpos < n_named_args)) { - /* If we're compiling a thunk, pass through invisible - references instead of making a copy. */ + bool callee_copies; + tree base; + + callee_copies + = FUNCTION_ARG_CALLEE_COPIES (*args_so_far, TYPE_MODE (type), + type, argpos < n_named_args); + + /* If we're compiling a thunk, pass through invisible references + instead of making a copy. */ if (call_from_thunk_p - || (FUNCTION_ARG_CALLEE_COPIES (*args_so_far, TYPE_MODE (type), - type, argpos < n_named_args) - /* If it's in a register, we must make a copy of it too. */ - /* ??? Is this a sufficient test? Is there a better one? */ - && !(TREE_CODE (args[i].tree_value) == VAR_DECL - && REG_P (DECL_RTL (args[i].tree_value))) - && ! TREE_ADDRESSABLE (type)) - ) + || (callee_copies + && !TREE_ADDRESSABLE (type) + && (base = get_base_address (args[i].tree_value)) + && (!DECL_P (base) || MEM_P (DECL_RTL (base))))) { - /* C++ uses a TARGET_EXPR to indicate that we want to make a - new object from the argument. If we are passing by - invisible reference, the callee will do that for us, so we - can strip off the TARGET_EXPR. This is not always safe, - but it is safe in the only case where this is a useful - optimization; namely, when the argument is a plain object. - In that case, the frontend is just asking the backend to - make a bitwise copy of the argument. */ - - if (TREE_CODE (args[i].tree_value) == TARGET_EXPR - && (DECL_P (TREE_OPERAND (args[i].tree_value, 1))) - && ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1)))) - args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1); - - /* We can't use sibcalls if a callee-copied argument is stored - in the current function's frame. */ - if (!call_from_thunk_p - && (!DECL_P (args[i].tree_value) - || !TREE_STATIC (args[i].tree_value))) + /* We can't use sibcalls if a callee-copied argument is + stored in the current function's frame. */ + if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base)) *may_tailcall = false; - args[i].tree_value = build1 (ADDR_EXPR, - build_pointer_type (type), - args[i].tree_value); - type = build_pointer_type (type); - } - else if (TREE_CODE (args[i].tree_value) == TARGET_EXPR) - { - /* In the V3 C++ ABI, parameters are destroyed in the caller. - We implement this by passing the address of the temporary - rather than expanding it into another allocated slot. */ - args[i].tree_value = build1 (ADDR_EXPR, - build_pointer_type (type), - args[i].tree_value); - type = build_pointer_type (type); - *may_tailcall = false; + args[i].tree_value = build_fold_addr_expr (args[i].tree_value); + type = TREE_TYPE (args[i].tree_value); + + *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK); } else { @@ -1051,12 +1027,15 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, copy = assign_temp (type, 0, 1, 0); store_expr (args[i].tree_value, copy, 0); - *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); - args[i].tree_value = build1 (ADDR_EXPR, - build_pointer_type (type), - make_tree (type, copy)); - type = build_pointer_type (type); + if (callee_copies) + *ecf_flags &= ~(ECF_CONST | ECF_LIBCALL_BLOCK); + else + *ecf_flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); + + args[i].tree_value + = build_fold_addr_expr (make_tree (type, copy)); + type = TREE_TYPE (args[i].tree_value); *may_tailcall = false; } } @@ -3379,25 +3358,14 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, flags |= ECF_PURE; } - if (GET_MODE (val) == MEM && ! must_copy) + if (GET_MODE (val) == MEM && !must_copy) slot = val; - else if (must_copy) + else { slot = assign_temp (lang_hooks.types.type_for_mode (mode, 0), 0, 1, 1); emit_move_insn (slot, val); } - else - { - tree type = lang_hooks.types.type_for_mode (mode, 0); - - slot - = gen_rtx_MEM (mode, - expand_expr (build1 (ADDR_EXPR, - build_pointer_type (type), - make_tree (type, val)), - NULL_RTX, VOIDmode, 0)); - } call_fusage = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, slot), |