From patchwork Mon Jun 21 16:14:16 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 56331 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id CF10FB6F0D for ; Tue, 22 Jun 2010 02:14:03 +1000 (EST) Received: (qmail 20398 invoked by alias); 21 Jun 2010 16:13:59 -0000 Received: (qmail 20383 invoked by uid 22791); 21 Jun 2010 16:13:57 -0000 X-SWARE-Spam-Status: No, hits=-6.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 21 Jun 2010 16:13:52 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o5LGDoxC016270 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 21 Jun 2010 12:13:50 -0400 Received: from tyan-ft48-01.lab.bos.redhat.com (tyan-ft48-01.lab.bos.redhat.com [10.16.42.4]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o5LGDnrJ031719 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 21 Jun 2010 12:13:50 -0400 Received: from tyan-ft48-01.lab.bos.redhat.com (tyan-ft48-01.lab.bos.redhat.com [127.0.0.1]) by tyan-ft48-01.lab.bos.redhat.com (8.14.4/8.14.4) with ESMTP id o5LGEJIV032699; Mon, 21 Jun 2010 18:14:19 +0200 Received: (from jakub@localhost) by tyan-ft48-01.lab.bos.redhat.com (8.14.4/8.14.4/Submit) id o5LGEH91032697; Mon, 21 Jun 2010 18:14:17 +0200 Date: Mon, 21 Jun 2010 18:14:16 +0200 From: Jakub Jelinek To: Uros Bizjak , Jan Hubicka Cc: gcc-patches@gcc.gnu.org Subject: [PATCH] Fix x86_64 va_arg gimplification (PR target/44575) Message-ID: <20100621161416.GQ7811@tyan-ft48-01.lab.bos.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi! While emit_store_group/emit_load_group* at the RTL level properly handle stores or loads from PARALLEL of registers where the sum of sizes is larger than the type being copied by doing convert_modes etc., ix86_gimplify_va_arg uses the modes without considering it and thus in some cases stores to the temporary more than it should. Following patch fixes it by handling the case of the last word copy using smaller mode, or if there is no such mode (hear I mean say 3 bytes), using memcpy. Bootstrapped/regtested on x86_64-linux and i686-linux. Ok for trunk? 2010-06-21 Jakub Jelinek 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. Jakub --- gcc/config/i386/i386.c.jj 2010-06-14 07:44:22.000000000 +0200 +++ gcc/config/i386/i386.c 2010-06-21 14:34:17.000000000 +0200 @@ -7267,7 +7267,7 @@ ix86_gimplify_va_arg (tree valist, tree } 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 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 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; } } --- gcc/testsuite/gcc.c-torture/execute/pr44575.c.jj 2010-06-21 14:43:19.000000000 +0200 +++ gcc/testsuite/gcc.c-torture/execute/pr44575.c 2010-06-21 14:44:20.000000000 +0200 @@ -0,0 +1,49 @@ +/* PR target/44575 */ + +#include + +int fails = 0; +struct S { float a[3]; }; +struct S a[5]; + +void +check (int z, ...) +{ + struct S arg, *p; + va_list ap; + int j = 0, k = 0; + int i; + va_start (ap, z); + for (i = 2; i < 4; ++i) + { + p = 0; + j++; + k += 2; + switch ((z << 4) | i) + { + case 0x12: + case 0x13: + p = &a[2]; + arg = va_arg (ap, struct S); + break; + default: + ++fails; + break; + } + if (p && p->a[2] != arg.a[2]) + ++fails; + if (fails) + break; + } + va_end (ap); +} + +int +main () +{ + a[2].a[2] = -49026; + check (1, a[2], a[2]); + if (fails) + abort (); + return 0; +}