From patchwork Sun Nov 25 12:19:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Modra X-Patchwork-Id: 1002791 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-490832-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="WdtYTX2j"; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="I+7zPpWm"; dkim-atps=neutral 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 432pyB0rjKz9s1c for ; Sun, 25 Nov 2018 23:19:29 +1100 (AEDT) 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:mime-version:content-type; q=dns; s=default; b=kOTW0XEmOKwa/WpidFGwwiSFe9Eb7oO8uA2epLfFTLSynve+D0 /c6PPhVGjEtmyfzuR1CRr/rQEMPEvWIIFnd1NG/dzbN0SMZpxeK4lPjQa9n+NVwm arnq3odfOARnYIPuFWMOa1Pc0DX0U2sO9ThP/0i9untjs6on/ZS6Zrwog= 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:mime-version:content-type; s= default; bh=peCbpOZsPOMnqBbEFCGU7o87m6c=; b=WdtYTX2jtbapVSltAt/i XCdl1tSRKxIvAYioQ4TkePhFzbevFbeK7RZJwdgAcWv6xpqr+A9WRBYZL7e1ekma VriGXgPhonxD/zHFK2ddb+NsjZUd7wpdc10roIRB+ubIHHga5nmPNMt73NZumRf1 J+H6S40lc8soZTn8T4tFb0U= Received: (qmail 68665 invoked by alias); 25 Nov 2018 12:19:22 -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 68645 invoked by uid 89); 25 Nov 2018 12:19:22 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.7 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=combinations, interpret, ori, loadable X-HELO: mail-pg1-f173.google.com Received: from mail-pg1-f173.google.com (HELO mail-pg1-f173.google.com) (209.85.215.173) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 25 Nov 2018 12:19:18 +0000 Received: by mail-pg1-f173.google.com with SMTP id z11so4881503pgu.0 for ; Sun, 25 Nov 2018 04:19:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=QUyvgGluUOBJnFyCZsHniaDADOBPw4eBQSmMfeRRyJA=; b=I+7zPpWmL6YSx+nmnZjIN3XPYUX6eQTbTBsa/5DiVK/12E1PfCSZ3bixcxUw3nd0V1 TD6QohjSTQ334Pn2+LF6bxSKzWUcZwj9OjinXz3crqXf6p/Vlk3LrnzTJucHtAZROt6U aNQj75McHq3LMKFm6jswBPPOl/4jHn+W3J1VaCbl4P4uFMpM1KofuwjdvufbX3pYem2c +u5q9lyYWNoDsV6XOr/a9AeeZZWKF3WvhksRW2efZuc2IucOqHBOaCTmoM3DKeWtZ6x9 DxBw6swUuWt21V/4ygMwyx9jdoJP77RnvTCui4SIEn2wp3AG/O0luYSBZayiTVgkMsiA bI3w== Received: from bubble.grove.modra.org ([58.175.241.133]) by smtp.gmail.com with ESMTPSA id 64sm38226496pff.101.2018.11.25.04.19.15 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 25 Nov 2018 04:19:15 -0800 (PST) Received: by bubble.grove.modra.org (Postfix, from userid 1000) id 5ED2A8077C; Sun, 25 Nov 2018 22:49:12 +1030 (ACDT) Date: Sun, 25 Nov 2018 22:49:12 +1030 From: Alan Modra To: gcc-patches@gcc.gnu.org Cc: Segher Boessenkool Subject: [RS6000] num_insns_constant ICE Message-ID: <20181125121912.GO21617@bubble.grove.modra.org> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.4 (2018-02-28) X-IsSubscribed: yes This patch came about from investigating an ICE that appeared when I was retesting an old half-baked patch of mine to rs6000_rtx_costs. If a const_double is fed to rs6000_is_valid_and_mask and from there to rs6000_is_valid_mask where INTVAL is used, gcc will ICE. The num_insns_constant ICE was introduced with git commit f337168d97. However, the code was buggy before that. There was no point in testing for a mask since the mask predicates only handle const_int. In fact, I don't think the function ever handled floating point constants that might match a load of minus one and mask. It does now. I've added a few comments regarding splitters so the next person looking at this code can see how this works. The patch also extracts code out of num_insns_constant that needed to handle multiple gprs for DFmode constants in 32-bit mode, to a function that handles multiple gprs a little more generally. I don't think there is any need for anything but the 32-bit DFmode case currently, but this allows for possible future uses. The CONST_WIDE_INT case is also not used currently, and needed fixing. Adding CONST_WIDE_INT_NUNITS - 1 only makes sense if the elements of the array were being shifted into a register of size larger than the element size (which is 64-bits). Boostrapped etc. powerpc64le-linux and powerpc64-linux. * config/rs6000/rs6000.c (num_insns_constant_gpr): Renamed from num_insns_constant_wide. Make static. Revise comment. (num_insns_constant_multi): New function. (num_insns_constant): Formatting. Correct CONST_WIDE_INT calculation. Simplify and extract code common to both CONST_INT and CONST_DOUBLE. Add gcc_unreachable for unhandled const_double modes. * config/rs6000/rs6000-protos.h (num_insns_const_wide): Delete. diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 1dfe7995ff1..dfee1f28aa9 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -36,7 +36,6 @@ extern int vspltis_shifted (rtx); extern HOST_WIDE_INT const_vector_elt_as_int (rtx, unsigned int); extern bool macho_lo_sum_memory_operand (rtx, machine_mode); extern int num_insns_constant (rtx, machine_mode); -extern int num_insns_constant_wide (HOST_WIDE_INT); extern int small_data_operand (rtx, machine_mode); extern bool mem_operand_gpr (rtx, machine_mode); extern bool mem_operand_ds_form (rtx, machine_mode); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 42dcb61904c..3364068d976 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -5815,11 +5815,12 @@ direct_return (void) return 0; } -/* Return the number of instructions it takes to form a constant in an - integer register. */ +/* Helper for num_insn_constant. Calculate number of instructions to + load VALUE to a single gpr using combinations of addi, addis, ori, + oris and sldi instructions. */ -int -num_insns_constant_wide (HOST_WIDE_INT value) +static int +num_insns_constant_gpr (HOST_WIDE_INT value) { /* signed constant loadable with addi */ if (((unsigned HOST_WIDE_INT) value + 0x8000) < 0x10000) @@ -5841,85 +5842,108 @@ num_insns_constant_wide (HOST_WIDE_INT value) high >>= 1; if (low == 0) - return num_insns_constant_wide (high) + 1; + return num_insns_constant_gpr (high) + 1; else if (high == 0) - return num_insns_constant_wide (low) + 1; + return num_insns_constant_gpr (low) + 1; else - return (num_insns_constant_wide (high) - + num_insns_constant_wide (low) + 1); + return (num_insns_constant_gpr (high) + + num_insns_constant_gpr (low) + 1); } else return 2; } +/* Helper for num_insn_constant. Allow constants formed by the + num_insns_constant_gpr sequences, plus li -1, rldicl/rldicr/rlwinm, + and handle modes that require multiple gprs. */ + +static int +num_insns_constant_multi (HOST_WIDE_INT value, machine_mode mode) +{ + int nregs = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + int total = 0; + while (nregs-- > 0) + { + int ins = num_insns_constant_gpr (value); + if (ins > 2 + /* We won't get more than 2 from num_insns_constant_gpr + except when TARGET_POWERPC64 and mode is DImode or + wider, so the register mode must be DImode. */ + && rs6000_is_valid_and_mask (GEN_INT (value), DImode)) + ins = 2; + total += ins; + value >>= 32; + if (TARGET_POWERPC64) + value >>= 32; + } + return total; +} + +/* Return the number of instructions it takes to form a constant in as + many gprs are needed for MODE. */ + int num_insns_constant (rtx op, machine_mode mode) { - HOST_WIDE_INT low, high; + HOST_WIDE_INT val; switch (GET_CODE (op)) { case CONST_INT: - if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1 - && rs6000_is_valid_and_mask (op, mode)) - return 2; - else - return num_insns_constant_wide (INTVAL (op)); + val = INTVAL (op); + break; case CONST_WIDE_INT: { - int i; - int ins = CONST_WIDE_INT_NUNITS (op) - 1; - for (i = 0; i < CONST_WIDE_INT_NUNITS (op); i++) - ins += num_insns_constant_wide (CONST_WIDE_INT_ELT (op, i)); + int ins = 0; + for (int i = 0; i < CONST_WIDE_INT_NUNITS (op); i++) + ins += num_insns_constant_multi (CONST_WIDE_INT_ELT (op, i), DImode); return ins; } - case CONST_DOUBLE: + case CONST_DOUBLE: + { + const struct real_value *rv = CONST_DOUBLE_REAL_VALUE (op); + if (mode == SFmode || mode == SDmode) { long l; - if (DECIMAL_FLOAT_MODE_P (mode)) - REAL_VALUE_TO_TARGET_DECIMAL32 - (*CONST_DOUBLE_REAL_VALUE (op), l); + if (mode == SDmode) + REAL_VALUE_TO_TARGET_DECIMAL32 (*rv, l); else - REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op), l); - return num_insns_constant_wide ((HOST_WIDE_INT) l); + REAL_VALUE_TO_TARGET_SINGLE (*rv, l); + /* See the first define_split in rs6000.md handling a + const_double_operand. */ + val = l; + mode = SImode; } - - long l[2]; - if (DECIMAL_FLOAT_MODE_P (mode)) - REAL_VALUE_TO_TARGET_DECIMAL64 (*CONST_DOUBLE_REAL_VALUE (op), l); - else - REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), l); - high = l[WORDS_BIG_ENDIAN == 0]; - low = l[WORDS_BIG_ENDIAN != 0]; - - if (TARGET_32BIT) - return (num_insns_constant_wide (low) - + num_insns_constant_wide (high)); - else + else if (mode == DFmode || mode == DDmode) { - if ((high == 0 && low >= 0) - || (high == -1 && low < 0)) - return num_insns_constant_wide (low); - - else if (rs6000_is_valid_and_mask (op, mode)) - return 2; - - else if (low == 0) - return num_insns_constant_wide (high) + 1; + long l[2]; + if (mode == DDmode) + REAL_VALUE_TO_TARGET_DECIMAL64 (*rv, l); else - return (num_insns_constant_wide (high) - + num_insns_constant_wide (low) + 1); + REAL_VALUE_TO_TARGET_DOUBLE (*rv, l); + + /* See the second (32-bit) and third (64-bit) define_split + in rs6000.md handling a const_double_operand. */ + val = l[WORDS_BIG_ENDIAN ? 0 : 1] << 32; + val |= l[WORDS_BIG_ENDIAN ? 1 : 0] & 0xffffffffUL; + mode = DImode; } + else + gcc_unreachable (); + } + break; default: gcc_unreachable (); } + + return num_insns_constant_multi (val, mode); } /* Interpret element ELT of the CONST_VECTOR OP as an integer value.