From patchwork Tue Aug 18 15:10:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 508350 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 62E7A14032B for ; Wed, 19 Aug 2015 01:10:46 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=d8bA0RjL; 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=IB7lmqbN+UdMVwnv zSAMsfWMD7JgYFxKiWeCN0aaDri1ww+ld2xz9VIEyrMdykNcPwNZhZ8FM9UbmoDy kYzDwHEZmy7W39MShHhS3o5QcKCEZ9g1OQUrdkoY7u1UURCGWQ2FNtTGmV32fPi9 vkk2OUdQPw7yPSHln3SuHh4Ob7k= 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=PsBurQs/csFP+Y55JAUcIY Nplf8=; b=d8bA0RjLZFnQZCkB0OoruOKiNSLB3XPmYThEc5573Cc+ThLiWszi+6 4WKaOYmMtoHBJaprR8m5+CdPpPozjSZDGC6VoHU7dp17DysVE9hRfw35NMSuVVXG 9gtHAbbU55mj+AXtQadqC+Rlwe/ueQUCFiRT0fWkZ23tudorkBuSk= Received: (qmail 96648 invoked by alias); 18 Aug 2015 15:10:39 -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 96638 invoked by uid 89); 18 Aug 2015 15:10:38 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL, BAYES_00, SPF_PASS autolearn=ham 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; Tue, 18 Aug 2015 15:10:36 +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-7-GcS-W3wLRdi6JlqdCp43kw-1; Tue, 18 Aug 2015 16:10:31 +0100 Received: from localhost ([10.1.2.79]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 18 Aug 2015 16:10:31 +0100 From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: PR67218: Fix invalid removal of FP cast Date: Tue, 18 Aug 2015 16:10:31 +0100 Message-ID: <87bne4bpjs.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: GcS-W3wLRdi6JlqdCp43kw-1 simplify_unary_operation_1 has: /* (float_truncate (float x)) is (float x) */ if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT) && (flag_unsafe_math_optimizations || (SCALAR_FLOAT_MODE_P (GET_MODE (op)) && ((unsigned)significand_size (GET_MODE (op)) >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))) - num_sign_bit_copies (XEXP (op, 0), GET_MODE (XEXP (op, 0)))))))) return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0), GET_MODE (XEXP (op, 0))); where the !flag_unsafe_math_optimizations alternative is trying to check that the int->float conversion is exact. Using num_sign_bit_copies is only correct for signed inputs though; for UNSIGNED_FLOAT we need to check whether the upper bits are zero. Also, for both cases we can discount known trailing zeros. It might not be a particularly exciting thing to check on its own, but since we're calling nonzero_bits for UNSIGNED_FLOAT anyway... It does mean calling nonzero_bits as well as num_sign_bit_copies for FLOAT, but this is very rarely executed code. I noticed this while trying to generalise some of the simplify-rtx.c patterns so that they applied to vectors as well as scalars. (Dave's recent GET_MODE_INNER changes make this easier and cheaper to do.) The patch does that here too for completeness. I think any code in simplify-rtx.c that handles GET_MODE_PRECISION for scalars only is suspect. Tested on x86_64-linux-gnu and aarch64-linux-gnu. OK to install? This is a gcc 6 regression so no backport is needed. Thanks, Richard gcc/ PR rtl-optimization/67218 * simplify-rtx.c (exact_int_to_float_conversion_p): New function. (simplify_unary_operation_1): Use it. gcc/testsuite/ PR rtl-optimization/67218 * gcc.c-torture/execute/ieee/pr67218.c, gcc.target/aarch64/fcvt_int_float_double1.c, gcc.target/aarch64/fcvt_int_float_double2.c, gcc.target/aarch64/fcvt_int_float_double3.c, gcc.target/aarch64/fcvt_int_float_double4.c, gcc.target/aarch64/fcvt_uint_float_double1.c, gcc.target/aarch64/fcvt_uint_float_double2.c, gcc.target/aarch64/fcvt_uint_float_double3.c, gcc.target/aarch64/fcvt_uint_float_double4.c: New tests. diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index f9352a1..8d86e57 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -829,6 +829,32 @@ simplify_unary_operation (enum rtx_code code, machine_mode mode, return simplify_unary_operation_1 (code, mode, op); } +/* Return true if FLOAT or UNSIGNED_FLOAT operation OP is known + to be exact. */ + +static bool +exact_int_to_float_conversion_p (const_rtx op) +{ + int out_bits = significand_size (GET_MODE_INNER (GET_MODE (op))); + machine_mode op0_mode = GET_MODE (XEXP (op, 0)); + /* Constants shouldn't reach here. */ + gcc_assert (op0_mode != VOIDmode); + int in_prec = GET_MODE_UNIT_PRECISION (op0_mode); + int in_bits = in_prec; + if (HWI_COMPUTABLE_MODE_P (op0_mode)) + { + unsigned HOST_WIDE_INT nonzero = nonzero_bits (XEXP (op, 0), op0_mode); + if (GET_CODE (op) == FLOAT) + in_bits -= num_sign_bit_copies (XEXP (op, 0), op0_mode); + else if (GET_CODE (op) == UNSIGNED_FLOAT) + in_bits = wi::min_precision (wi::uhwi (nonzero, in_prec), UNSIGNED); + else + gcc_unreachable (); + in_bits -= wi::ctz (wi::uhwi (nonzero, in_prec)); + } + return in_bits <= out_bits; +} + /* Perform some simplifications we can do even if the operands aren't constant. */ static rtx @@ -1190,11 +1216,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op) /* (float_truncate (float x)) is (float x) */ if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT) && (flag_unsafe_math_optimizations - || (SCALAR_FLOAT_MODE_P (GET_MODE (op)) - && ((unsigned)significand_size (GET_MODE (op)) - >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))) - - num_sign_bit_copies (XEXP (op, 0), - GET_MODE (XEXP (op, 0)))))))) + || exact_int_to_float_conversion_p (op))) return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0), GET_MODE (XEXP (op, 0))); @@ -1227,11 +1249,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op) */ if (GET_CODE (op) == FLOAT_EXTEND || ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT) - && SCALAR_FLOAT_MODE_P (GET_MODE (op)) - && ((unsigned)significand_size (GET_MODE (op)) - >= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0))) - - num_sign_bit_copies (XEXP (op, 0), - GET_MODE (XEXP (op, 0))))))) + && exact_int_to_float_conversion_p (op))) return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0), GET_MODE (XEXP (op, 0))); diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/pr67218.c b/gcc/testsuite/gcc.c-torture/execute/ieee/pr67218.c new file mode 100644 index 0000000..2a1260a --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/ieee/pr67218.c @@ -0,0 +1,15 @@ +extern void abort (void) __attribute__ ((noreturn)); + +double __attribute__ ((noinline, noclone)) +foo (unsigned int x) +{ + return (double) (float) (x | 0xffff0000); +} + +int +main () +{ + if (foo (1) != 0x1.fffep31) + abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double1.c b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double1.c new file mode 100644 index 0000000..e555b2c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (int x) +{ + return (double) (float) (x | (int) 0xff000000); +} + +/* { dg-final { scan-assembler {\tscvtf\td0, w[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double2.c b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double2.c new file mode 100644 index 0000000..7791b22 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (int x) +{ + return (double) (float) (x | (int) 0xfe000000); +} + +/* { dg-final { scan-assembler {\tscvtf\ts[0-9]*, w[0-9]*} } } */ +/* { dg-final { scan-assembler {\tfcvt\td0, s[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double3.c b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double3.c new file mode 100644 index 0000000..c647742 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (int x) +{ + return (double) (float) ((x & -16) | (int) 0xf0000000); +} + +/* { dg-final { scan-assembler {\tscvtf\td0, w[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double4.c b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double4.c new file mode 100644 index 0000000..88a5242 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_int_float_double4.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (int x) +{ + return (double) (float) ((x & -16) | (int) 0xfe00000); +} + +/* { dg-final { scan-assembler {\tscvtf\ts[0-9]*, w[0-9]*} } } */ +/* { dg-final { scan-assembler {\tfcvt\td0, s[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double1.c b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double1.c new file mode 100644 index 0000000..c1c4920 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double1.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (unsigned int x) +{ + return (double) (float) (x & 0xffffff); +} + +/* { dg-final { scan-assembler {\t[su]cvtf\td0, w[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double2.c b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double2.c new file mode 100644 index 0000000..334aae8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double2.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (unsigned int x) +{ + return (double) (float) (x & 0x1ffffff); +} + +/* { dg-final { scan-assembler {\t[su]cvtf\ts[0-9]*, w[0-9]*} } } */ +/* { dg-final { scan-assembler {\tfcvt\td0, s[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double3.c b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double3.c new file mode 100644 index 0000000..deb4578 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double3.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (unsigned int x) +{ + return (double) (float) (x & 0xffffff00); +} + +/* { dg-final { scan-assembler {\tucvtf\td0, w[0-9]*} } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double4.c b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double4.c new file mode 100644 index 0000000..8f0955c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fcvt_uint_float_double4.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +double +foo (unsigned int x) +{ + return (double) (float) (x & 0xffffff80); +} + +/* { dg-final { scan-assembler {\tucvtf\ts[0-9]*, w[0-9]*} } } */ +/* { dg-final { scan-assembler {\tfcvt\td0, s[0-9]*} } } */