summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2010-06-21 16:33:49 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2010-06-21 16:33:49 +0000
commit91dbed8930b2a28d1591436192d388f3e7fdb1a8 (patch)
tree3cacca416abef2d034b3c0f4fa0556c0b6a8e812 /gcc/config
parent38c3bb402491c5796ec32e36e83389c54221f8a9 (diff)
downloadgcc-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.c44
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;
}
}