From patchwork Sat Mar 14 08:57:18 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 450169 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D925114017B for ; Sat, 14 Mar 2015 19:57:34 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass reason="1024-bit key; unprotected key" header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=Jcz/e7w8; dkim-adsp=none (unprotected policy); dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; q=dns; s=default; b=SkzCcQS4Rc3wrn2bObhBq2SsvNnCN kOLwPc8wP6v5M+SkipMuE/39xC0bh4NmY2ovjYI7EXdfbm1dZkBaq66NDtcsDSSx BWOcNV3wjh9Ahxx9hwtuaKJDEdg4Nq1hnS/ydZ9HnnXLsuVy+l3XOiVltXxgNx6N Ku3oMmQbCfLSvg= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:mime-version :content-type; s=default; bh=BtvDWOd0A+b3W5TjGFuPWM/AXf0=; b=Jcz /e7w87sI/Fb9gVgoBCz+0Y+iOEJVxe6D5kD+C0J8icUdU6bIkJya1I95hwa1RZ5H +qeQRegXwFEvTiwIp/f04vPac+1dWCu5vSPYOTo2qAxS85q4FAH+7qT3zCncllbv oWCnYzBO3lBVkqU1dIr8Dik8yMHWFrj8T2zRIRzI= Received: (qmail 82999 invoked by alias); 14 Mar 2015 08:57:27 -0000 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 Received: (qmail 82984 invoked by uid 89); 14 Mar 2015 08:57:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.5 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Sat, 14 Mar 2015 08:57:25 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t2E8vNKo010743 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Sat, 14 Mar 2015 04:57:23 -0400 Received: from tucnak.zalov.cz (ovpn-116-63.ams2.redhat.com [10.36.116.63]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t2E8vKrZ019609 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NO); Sat, 14 Mar 2015 04:57:23 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.14.9/8.14.9) with ESMTP id t2E8vIIj016892; Sat, 14 Mar 2015 09:57:19 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.14.9/8.14.9/Submit) id t2E8vIaP016891; Sat, 14 Mar 2015 09:57:18 +0100 Date: Sat, 14 Mar 2015 09:57:18 +0100 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Cc: Jeff Law Subject: [committed] Fix make_field_assignment on big endian (PR rtl-optimization/65401) Message-ID: <20150314085718.GI1746@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) X-IsSubscribed: yes Hi! The following testcase is miscompiled on s390x-linux, because make_field_assignment considers the actual byte swap as a field assignment. The problem is in the widening of the MEM mode, in the testcase from original QI to HI, that only works for little-endian, for big endian we need to adjust the offset. Bootstrapped/regtested on {x86_64,i686,aarch64,powerpc64{,le},s390{,x}}-linux, preapproved by Jeff on IRC, committed to trunk. 2015-03-14 Jakub Jelinek PR rtl-optimization/65401 * combine.c (rtx_equal_for_field_assignment_p): Add widen_x argument. If true, adjust_address_nv of x with big-endian correction for the mode widening to GET_MODE (y). (make_field_assignment): Don't do MEM mode widening here. Use MEM_P instead of GET_CODE == MEM. * gcc.c-torture/execute/pr65401.c: New test. Jakub --- gcc/combine.c.jj 2015-02-03 10:38:46.000000000 +0100 +++ gcc/combine.c 2015-03-13 18:46:45.710940306 +0100 @@ -475,7 +475,7 @@ static rtx force_to_mode (rtx, machine_m unsigned HOST_WIDE_INT, int); static rtx if_then_else_cond (rtx, rtx *, rtx *); static rtx known_cond (rtx, enum rtx_code, rtx, rtx); -static int rtx_equal_for_field_assignment_p (rtx, rtx); +static int rtx_equal_for_field_assignment_p (rtx, rtx, bool = false); static rtx make_field_assignment (rtx); static rtx apply_distributive_law (rtx); static rtx distribute_and_simplify_rtx (rtx, int); @@ -9184,8 +9184,23 @@ known_cond (rtx x, enum rtx_code cond, r assignment as a field assignment. */ static int -rtx_equal_for_field_assignment_p (rtx x, rtx y) +rtx_equal_for_field_assignment_p (rtx x, rtx y, bool widen_x) { + if (widen_x && GET_MODE (x) != GET_MODE (y)) + { + if (GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (y))) + return 0; + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN) + return 0; + /* For big endian, adjust the memory offset. */ + if (BYTES_BIG_ENDIAN) + x = adjust_address_nv (x, GET_MODE (y), + -subreg_lowpart_offset (GET_MODE (x), + GET_MODE (y))); + else + x = adjust_address_nv (x, GET_MODE (y), 0); + } + if (x == y || rtx_equal_p (x, y)) return 1; @@ -9339,16 +9354,15 @@ make_field_assignment (rtx x) /* The second SUBREG that might get in the way is a paradoxical SUBREG around the first operand of the AND. We want to pretend the operand is as wide as the destination here. We - do this by creating a new MEM in the wider mode for the sole + do this by adjusting the MEM to wider mode for the sole purpose of the call to rtx_equal_for_field_assignment_p. Also note this trick only works for MEMs. */ else if (GET_CODE (rhs) == AND && paradoxical_subreg_p (XEXP (rhs, 0)) - && GET_CODE (SUBREG_REG (XEXP (rhs, 0))) == MEM + && MEM_P (SUBREG_REG (XEXP (rhs, 0))) && CONST_INT_P (XEXP (rhs, 1)) - && rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), - XEXP (SUBREG_REG (XEXP (rhs, 0)), 0)), - dest)) + && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (rhs, 0)), + dest, true)) c1 = INTVAL (XEXP (rhs, 1)), other = lhs; else if (GET_CODE (lhs) == AND && CONST_INT_P (XEXP (lhs, 1)) @@ -9357,16 +9371,15 @@ make_field_assignment (rtx x) /* The second SUBREG that might get in the way is a paradoxical SUBREG around the first operand of the AND. We want to pretend the operand is as wide as the destination here. We - do this by creating a new MEM in the wider mode for the sole + do this by adjusting the MEM to wider mode for the sole purpose of the call to rtx_equal_for_field_assignment_p. Also note this trick only works for MEMs. */ else if (GET_CODE (lhs) == AND && paradoxical_subreg_p (XEXP (lhs, 0)) - && GET_CODE (SUBREG_REG (XEXP (lhs, 0))) == MEM + && MEM_P (SUBREG_REG (XEXP (lhs, 0))) && CONST_INT_P (XEXP (lhs, 1)) - && rtx_equal_for_field_assignment_p (gen_rtx_MEM (GET_MODE (dest), - XEXP (SUBREG_REG (XEXP (lhs, 0)), 0)), - dest)) + && rtx_equal_for_field_assignment_p (SUBREG_REG (XEXP (lhs, 0)), + dest, true)) c1 = INTVAL (XEXP (lhs, 1)), other = rhs; else return x; --- gcc/testsuite/gcc.c-torture/execute/pr65401.c.jj 2015-03-13 18:36:30.639817393 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr65401.c 2015-03-13 18:42:02.693485127 +0100 @@ -0,0 +1,59 @@ +/* PR rtl-optimization/65401 */ + +struct S { unsigned short s[64]; }; + +__attribute__((noinline, noclone)) void +foo (struct S *x) +{ + unsigned int i; + unsigned char *s; + + s = (unsigned char *) x->s; + for (i = 0; i < 64; i++) + x->s[i] = s[i * 2] | (s[i * 2 + 1] << 8); +} + +__attribute__((noinline, noclone)) void +bar (struct S *x) +{ + unsigned int i; + unsigned char *s; + + s = (unsigned char *) x->s; + for (i = 0; i < 64; i++) + x->s[i] = (s[i * 2] << 8) | s[i * 2 + 1]; +} + +int +main () +{ + unsigned int i; + struct S s; + if (sizeof (unsigned short) != 2) + return 0; + for (i = 0; i < 64; i++) + s.s[i] = i + ((64 - i) << 8); + foo (&s); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != (64 - i) + (i << 8)) + __builtin_abort (); +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != i + ((64 - i) << 8)) + __builtin_abort (); +#endif + for (i = 0; i < 64; i++) + s.s[i] = i + ((64 - i) << 8); + bar (&s); +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != (64 - i) + (i << 8)) + __builtin_abort (); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + for (i = 0; i < 64; i++) + if (s.s[i] != i + ((64 - i) << 8)) + __builtin_abort (); +#endif + return 0; +}