From patchwork Thu Feb 21 21:35:14 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 222419 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 5D6922C0099 for ; Fri, 22 Feb 2013 08:36:03 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1362087364; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Date:From:To:Cc:Subject:Message-ID:Reply-To: MIME-Version:Content-Type:Content-Disposition:User-Agent: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=uSYt79nau+EYae0LSYHy lgWVz8M=; b=c+ESkS6YGDS8AInCgAwe5/0p1C4OU2RH6OT6L0gHcxe8OxROVqFm T5wr+DMG0SLD2eZcJZeRxgYsjEJ8Qp5lXmq1dhMXN1dErJbYmJwx93lLmBr8aiMQ K17vvJkm/PtGOQ1HAyJWVOe74IaO54oA5TPpvvojn+AWHX7bWeIl7qY= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Received:Date:From:To:Cc:Subject:Message-ID:Reply-To:MIME-Version:Content-Type:Content-Disposition:User-Agent:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=A7z/wCSRWtqhSHgCc9REgeqtqn2H/5WrfutefDddsUVjLy00HsJz3opxnasg08 6NEjLD5NOHuU3pdaAv0jaPZHFJERj3HaS0sUeuf4I2rLXrM6zIbZ1AOfstF3iyCd w5LLZAuk6/efJ/fj/OvdlCaeXcmaHft1zXJMwYT5HybPc=; Received: (qmail 10998 invoked by alias); 21 Feb 2013 21:35:54 -0000 Received: (qmail 10884 invoked by uid 22791); 21 Feb 2013 21:35:53 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, KHOP_RCVD_UNTRUST, KHOP_SPAMHAUS_DROP, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_IV 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; Thu, 21 Feb 2013 21:35:17 +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 r1LLZHd7012324 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 21 Feb 2013 16:35:17 -0500 Received: from zalov.redhat.com (vpn1-6-249.ams2.redhat.com [10.36.6.249]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r1LLZF4Q002057 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Thu, 21 Feb 2013 16:35:16 -0500 Received: from zalov.cz (localhost [127.0.0.1]) by zalov.redhat.com (8.14.5/8.14.5) with ESMTP id r1LLZEl6005910; Thu, 21 Feb 2013 22:35:14 +0100 Received: (from jakub@localhost) by zalov.cz (8.14.5/8.14.5/Submit) id r1LLZELM005909; Thu, 21 Feb 2013 22:35:14 +0100 Date: Thu, 21 Feb 2013 22:35:14 +0100 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Cc: Richard Henderson Subject: [committed] Fix expand_mult (PR middle-end/56420) Message-ID: <20130221213514.GH1215@tucnak.zalov.cz> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) 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! I've committed the following fix for the following testcase. When scalar_op1 is 0xffffffffffffffff8000000000000000 with 64-bit HWI, it matches EXACT_POWER_OF_2_OR_ZERO_P, but we should expand it as negation of the << 63 shift rather than the << 63 shift alone. The patch also improves multiplication by 0x8000000000000000 in TImode, which can be done as << 63 shift, and multiplication by -(((TImode)1) << N) for N 0 through 62, which can be also expanded as negation of left shift. Furthermore I've noticed several places where we could invoke signed integer overflows inside of the compiler and fixed them. Bootstrapped/regtested on x86_64-linux and i686-linux, acked by Richard on IRC, committed to trunk. 2013-02-21 Jakub Jelinek PR middle-end/56420 * expmed.c (EXACT_POWER_OF_2_OR_ZERO_P): Do subtraction in uhwi, to avoid signed wrapping. (expand_mult): Handle properly multiplication by ((dword_type) -1) << (BITS_PER_WORD - 1). Improve multiplication by ((dword_type) 1) << (BITS_PER_WORD - 1). Avoid undefined behavior in the compiler if coeff is HOST_WIDE_INT_MIN. (expand_divmod): Don't make ext_op1 static, change it's type to uhwi. Avoid undefined behavior in -INTVAL (op1). * gcc.dg/torture/pr56420.c: New test. Jakub --- gcc/expmed.c.jj 2013-02-13 21:46:52.000000000 +0100 +++ gcc/expmed.c 2013-02-21 19:25:05.692298011 +0100 @@ -64,7 +64,8 @@ static rtx expand_smod_pow2 (enum machin static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT); /* Test whether a value is zero of a power of two. */ -#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0) +#define EXACT_POWER_OF_2_OR_ZERO_P(x) \ + (((x) & ((x) - (unsigned HOST_WIDE_INT) 1)) == 0) struct init_expmed_rtl { @@ -3079,7 +3080,10 @@ expand_mult (enum machine_mode mode, rtx /* If we are multiplying in DImode, it may still be a win to try to work with shifts and adds. */ if (CONST_DOUBLE_HIGH (scalar_op1) == 0 - && CONST_DOUBLE_LOW (scalar_op1) > 0) + && (CONST_DOUBLE_LOW (scalar_op1) > 0 + || (CONST_DOUBLE_LOW (scalar_op1) < 0 + && EXACT_POWER_OF_2_OR_ZERO_P + (CONST_DOUBLE_LOW (scalar_op1))))) { coeff = CONST_DOUBLE_LOW (scalar_op1); is_neg = false; @@ -3109,7 +3113,8 @@ expand_mult (enum machine_mode mode, rtx use synth_mult. */ /* Special case powers of two. */ - if (EXACT_POWER_OF_2_OR_ZERO_P (coeff)) + if (EXACT_POWER_OF_2_OR_ZERO_P (coeff) + && !(is_neg && mode_bitsize > HOST_BITS_PER_WIDE_INT)) return expand_shift (LSHIFT_EXPR, mode, op0, floor_log2 (coeff), target, unsignedp); @@ -3124,13 +3129,24 @@ expand_mult (enum machine_mode mode, rtx result is interpreted as an unsigned coefficient. Exclude cost of op0 from max_cost to match the cost calculation of the synth_mult. */ + coeff = -(unsigned HOST_WIDE_INT) coeff; max_cost = (set_src_cost (gen_rtx_MULT (mode, fake_reg, op1), speed) - neg_cost(speed, mode)); - if (max_cost > 0 - && choose_mult_variant (mode, -coeff, &algorithm, - &variant, max_cost)) + if (max_cost <= 0) + goto skip_synth; + + /* Special case powers of two. */ + if (EXACT_POWER_OF_2_OR_ZERO_P (coeff)) + { + rtx temp = expand_shift (LSHIFT_EXPR, mode, op0, + floor_log2 (coeff), target, unsignedp); + return expand_unop (mode, neg_optab, temp, target, 0); + } + + if (choose_mult_variant (mode, coeff, &algorithm, &variant, + max_cost)) { - rtx temp = expand_mult_const (mode, op0, -coeff, NULL_RTX, + rtx temp = expand_mult_const (mode, op0, coeff, NULL_RTX, &algorithm, variant); return expand_unop (mode, neg_optab, temp, target, 0); } @@ -3813,13 +3829,12 @@ expand_divmod (int rem_flag, enum tree_c int op1_is_constant, op1_is_pow2 = 0; int max_cost, extra_cost; static HOST_WIDE_INT last_div_const = 0; - static HOST_WIDE_INT ext_op1; bool speed = optimize_insn_for_speed_p (); op1_is_constant = CONST_INT_P (op1); if (op1_is_constant) { - ext_op1 = INTVAL (op1); + unsigned HOST_WIDE_INT ext_op1 = UINTVAL (op1); if (unsignedp) ext_op1 &= GET_MODE_MASK (mode); op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1) @@ -3967,7 +3982,7 @@ expand_divmod (int rem_flag, enum tree_c op1_is_pow2 = (op1_is_constant && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)) || (! unsignedp - && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))) ; + && EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1)))))); } /* If one of the operands is a volatile MEM, copy it into a register. */ --- gcc/testsuite/gcc.dg/torture/pr56420.c.jj 2013-02-21 18:37:54.720565659 +0100 +++ gcc/testsuite/gcc.dg/torture/pr56420.c 2013-02-21 19:08:41.000000000 +0100 @@ -0,0 +1,37 @@ +/* PR middle-end/56420 */ +/* { dg-do run { target int128 } } */ + +extern void abort (void); + +__attribute__((noinline, noclone)) __uint128_t +foo (__uint128_t x) +{ + return x * (((__uint128_t) -1) << 63); +} + +__attribute__((noinline, noclone)) __uint128_t +bar (__uint128_t x) +{ + return x * (((__uint128_t) 1) << 63); +} + +__attribute__((noinline, noclone)) __uint128_t +baz (__uint128_t x) +{ + return x * -(((__uint128_t) 1) << 62); +} + +int +main () +{ + if (foo (1) != (((__uint128_t) -1) << 63) + || foo (8) != (((__uint128_t) -1) << 66)) + abort (); + if (bar (1) != (((__uint128_t) 1) << 63) + || bar (8) != (((__uint128_t) 1) << 66)) + abort (); + if (baz (1) != -(((__uint128_t) 1) << 62) + || baz (8) != ((-(((__uint128_t) 1) << 62)) << 3)) + abort (); + return 0; +}