diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-06-21 16:33:49 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-06-21 16:33:49 +0000 |
commit | 91dbed8930b2a28d1591436192d388f3e7fdb1a8 (patch) | |
tree | 3cacca416abef2d034b3c0f4fa0556c0b6a8e812 /gcc/config | |
parent | 38c3bb402491c5796ec32e36e83389c54221f8a9 (diff) | |
download | gcc-91dbed8930b2a28d1591436192d388f3e7fdb1a8.tar.gz |
PR target/44575
* config/i386/i386.c (ix86_gimplify_va_arg): When copying
va_arg from a set of register save slots into a temporary,
if the container is bigger than type size, do the copying
using smaller mode or using memcpy.
* gcc.c-torture/execute/pr44575.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@161097 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/i386/i386.c | 44 |
1 files changed, 36 insertions, 8 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index f9c0718e391..7d97a6a0061 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -7267,7 +7267,7 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, } if (need_temp) { - int i; + int i, prev_size = 0; tree temp = create_tmp_var (type, "va_arg_tmp"); /* addr = &temp; */ @@ -7279,13 +7279,29 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, rtx slot = XVECEXP (container, 0, i); rtx reg = XEXP (slot, 0); enum machine_mode mode = GET_MODE (reg); - tree piece_type = lang_hooks.types.type_for_mode (mode, 1); - tree addr_type = build_pointer_type (piece_type); - tree daddr_type = build_pointer_type_for_mode (piece_type, - ptr_mode, true); + tree piece_type; + tree addr_type; + tree daddr_type; tree src_addr, src; int src_offset; tree dest_addr, dest; + int cur_size = GET_MODE_SIZE (mode); + + if (prev_size + cur_size > size) + { + cur_size = size - prev_size; + mode = mode_for_size (cur_size * BITS_PER_UNIT, MODE_INT, 1); + if (mode == BLKmode) + mode = QImode; + } + piece_type = lang_hooks.types.type_for_mode (mode, 1); + if (mode == GET_MODE (reg)) + addr_type = build_pointer_type (piece_type); + else + addr_type = build_pointer_type_for_mode (piece_type, ptr_mode, + true); + daddr_type = build_pointer_type_for_mode (piece_type, ptr_mode, + true); if (SSE_REGNO_P (REGNO (reg))) { @@ -7300,14 +7316,26 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, src_addr = fold_convert (addr_type, src_addr); src_addr = fold_build2 (POINTER_PLUS_EXPR, addr_type, src_addr, size_int (src_offset)); - src = build_va_arg_indirect_ref (src_addr); dest_addr = fold_convert (daddr_type, addr); dest_addr = fold_build2 (POINTER_PLUS_EXPR, daddr_type, dest_addr, size_int (INTVAL (XEXP (slot, 1)))); - dest = build_va_arg_indirect_ref (dest_addr); + if (cur_size == GET_MODE_SIZE (mode)) + { + src = build_va_arg_indirect_ref (src_addr); + dest = build_va_arg_indirect_ref (dest_addr); - gimplify_assign (dest, src, pre_p); + gimplify_assign (dest, src, pre_p); + } + else + { + tree copy + = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], + 3, dest_addr, src_addr, + size_int (cur_size)); + gimplify_and_add (copy, pre_p); + } + prev_size += cur_size; } } |