From patchwork Wed Aug 5 14:14:22 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 504029 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 BFEE31402B8 for ; Thu, 6 Aug 2015 00:14:36 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=rBivOGC+; 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:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=MGPnyfuI7tmqdVz6 sc4014CPjFO5DsShyxxdUusg4giO8vrwh4zokIa2oR3xNCTeD9iX1ttt9PpvJn+V LbY5tnWvlFzxR9vuL66dkeGq6FUWPGSElv09gCWiSybRD6rZOE4srGpLVTHmK+rb cDoi6DeMqLeYE2/uNg3zjDroMOw= 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:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; s=default; bh=qdixVHrSu4Qv+kbQ/30QOj JeRdY=; b=rBivOGC+DEzICJKWSslA+k2GtMc80Erftfj5qpLWYgWsF9QmcOQhKU DNgc1MLdwvXYvtiGdsO3i6GFTXLlqQIScNDDsQ02iEEWOdoP1eBjBQsZ8zc4Z0+o 6jXYJzQCI48YbX1GNtEhuGLE+9G+r4KJ3RNZOIMPm8OeW1Wl+u8A0= Received: (qmail 46500 invoked by alias); 5 Aug 2015 14:14:30 -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 46489 invoked by uid 89); 5 Aug 2015 14:14:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL, BAYES_00, KAM_LOTSOFHASH, SPF_PASS autolearn=no version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (146.101.78.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 05 Aug 2015 14:14:27 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-11-LymHMfdrTzmWMUxR4zy8Hg-1; Wed, 05 Aug 2015 15:14:23 +0100 Received: from localhost ([10.1.2.79]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Wed, 5 Aug 2015 15:14:22 +0100 From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: PR66311: Fix extension in mpz->wide_int conversions Date: Wed, 05 Aug 2015 15:14:22 +0100 Message-ID: <87h9odkekh.fsf@e105548-lin.cambridge.arm.com> User-Agent: Gnus/5.130012 (Ma Gnus v0.12) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-MC-Unique: LymHMfdrTzmWMUxR4zy8Hg-1 wi::from_mpz reads the absolute value of the mpz and then negates the result if the mpz is negative. When the top bit of the most-significant HOST_WIDE_INT in the absolute value is set, we implicitly sign- rather than zero-extend it to full precision. For example, 1 << 63 gets mangled to (1 << prec) - (1 << 63). This patch fixes that by ensuring we zero-extend instead. The testcase is taken from comment 15 in bugzilla (thanks FX). Tested on x86_64-linux-gnu. OK to install? Thanks, Richard gcc/ PR middle-end/66311 * wide-int.cc (wi::from_mpz): Make sure that absolute mpz value is zero- rather than sign-extended. gcc/testsuite/ 2015-08-05 Francois-Xavier Coudert PR middle-end/66311 * gfortran.dg/pr66311.f90: New file. diff --git a/gcc/testsuite/gfortran.dg/pr66311.f90 b/gcc/testsuite/gfortran.dg/pr66311.f90 new file mode 100644 index 0000000..dc40cb6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr66311.f90 @@ -0,0 +1,60 @@ +! { dg-do run } +! { dg-additional-options "-fno-range-check -w" } +! +! Check that we can print large constants +! +! "-fno-range-check -w" is used so the testcase compiles even with targets +! that don't support large integer kinds. + +program test + use iso_fortran_env, only : ikinds => integer_kinds + implicit none + + ! Largest integer kind + integer, parameter :: k = ikinds(size(ikinds)) + integer, parameter :: hk = k / 2 + + if (k <= 8) stop + + call check(9000000000000000000_k, "9000000000000000000") + call check(90000000000000000000_k, "90000000000000000000") + call check(int(huge(1_hk), kind=k), "9223372036854775807") + call check(2_k**63, "9223372036854775808") + call check(10000000000000000000_k, "10000000000000000000") + call check(18446744065119617024_k, "18446744065119617024") + call check(2_k**64 - 1, "18446744073709551615") + call check(2_k**64, "18446744073709551616") + call check(20000000000000000000_k, "20000000000000000000") + call check(huge(0_k), "170141183460469231731687303715884105727") + call check(huge(0_k)-1, "170141183460469231731687303715884105726") + + call check(-9000000000000000000_k, "-9000000000000000000") + call check(-90000000000000000000_k, "-90000000000000000000") + call check(-int(huge(1_hk), kind=k), "-9223372036854775807") + call check(-2_k**63, "-9223372036854775808") + call check(-10000000000000000000_k, "-10000000000000000000") + call check(-18446744065119617024_k, "-18446744065119617024") + call check(-(2_k**64 - 1), "-18446744073709551615") + call check(-2_k**64, "-18446744073709551616") + call check(-20000000000000000000_k, "-20000000000000000000") + call check(-huge(0_k), "-170141183460469231731687303715884105727") + call check(-(huge(0_k)-1), "-170141183460469231731687303715884105726") + call check(-huge(0_k)-1, "-170141183460469231731687303715884105728") + + call check(2_k * huge(1_hk), "18446744073709551614") + call check((-2_k) * huge(1_hk), "-18446744073709551614") + +contains + + subroutine check (i, str) + implicit none + integer(kind=k), intent(in), value :: i + character(len=*), intent(in) :: str + + character(len=100) :: buffer + write(buffer,*) i + if (adjustl(buffer) /= adjustl(str)) call abort + end subroutine + +end + diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc index 13ba10c..9a93660 100644 --- a/gcc/wide-int.cc +++ b/gcc/wide-int.cc @@ -252,13 +252,15 @@ wi::from_mpz (const_tree type, mpz_t x, bool wrap) } /* Determine the number of unsigned HOST_WIDE_INTs that are required - for representing the value. The code to calculate count is + for representing the absolute value. The code to calculate count is extracted from the GMP manual, section "Integer Import and Export": http://gmplib.org/manual/Integer-Import-and-Export.html */ numb = CHAR_BIT * sizeof (HOST_WIDE_INT); count = (mpz_sizeinbase (x, 2) + numb - 1) / numb; HOST_WIDE_INT *val = res.write_val (); - /* Write directly to the wide_int storage if possible, otherwise leave + /* Read the absolute value. + + Write directly to the wide_int storage if possible, otherwise leave GMP to allocate the memory for us. It might be slightly more efficient to use mpz_tdiv_r_2exp for the latter case, but the situation is pathological and it seems safer to operate on the original mpz value @@ -276,7 +278,12 @@ wi::from_mpz (const_tree type, mpz_t x, bool wrap) memcpy (val, valres, count * sizeof (HOST_WIDE_INT)); free (valres); } - res.set_len (canonize (val, count, prec)); + /* Zero-extend the absolute value to PREC bits. */ + if (count < BLOCKS_NEEDED (prec) && val[count - 1] < 0) + val[count++] = 0; + else + count = canonize (val, count, prec); + res.set_len (count); if (mpz_sgn (x) < 0) res = -res;