From patchwork Wed Sep 13 19:19:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 112488 Delivered-To: patch@linaro.org Received: by 10.140.106.117 with SMTP id d108csp1302369qgf; Wed, 13 Sep 2017 12:20:47 -0700 (PDT) X-Received: by 10.99.173.4 with SMTP id g4mr18273313pgf.87.1505330447541; Wed, 13 Sep 2017 12:20:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1505330447; cv=none; d=google.com; s=arc-20160816; b=yVPC3XnXaoqQkLz8rfDTR8Izx6F/toBK1LmZcUw9VfUKPSJ9intqzl1ppnNbj5HsoE Ac1GHz8FsQR/dmpLC1K3Mm5E/2SJ0NiFuTGmsApqxR8fNgqDs96baIshTkv0F9t8TagG 11cftFjXtYhRVCzqp9M9AxEmB+IyD0+HEwn81UMBL/+XmM5JrJyynfV/3lw+YJ7jM6W6 fGAyJir6AZx5iWXJnzkDZR/ZaCEjSJj+NA5E1C6YrJK5MGG1r/BvBGy/vYxO8vJ6h84o 5TfHrWOU6Z7zVD3+NKyo8r8miHs9M1R25xCNdd9c3tFmExWzxUFoHrJnD+KVXDqR1MWb LAzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=mime-version:user-agent:message-id:date:subject:mail-followup-to:to :from:delivered-to:sender:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mailing-list:dkim-signature :domainkey-signature:arc-authentication-results; bh=J366we27qX53ZxXqoRZWh+ZzhC7rKoQVGo4KP/0Oto0=; b=Zczl87CUhzGk0z42UgKWDBHkkT+kPelwn/N8v13LjtZtaCjlERMXcmzxzVPYxv/pU3 QAz+AESDLG76k50nBrTVZevZ1UrRAyFiPzy2NFzCYgoWOgyF/uw3g7OLilbiNbS0wjED 4GEHAVUBFOwQrwkye0z7pcbCWYKGXrkxyRGls7kQWVJNP+gqpWu5ClJliXplVr3W5e5y JUseuRMVAEX1fRBEcX3WSfw9IusCBjpcrG/WnRTRrITqejp59sWu9+FLfNHqcl8d8xsB WiWh4UVso8BB+rMp6btq9JMNEA8taGOffhpBla0CMst55jrK8fDDYbjMniFvq0u/s5SV gXyg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cmJ0JHgB; spf=pass (google.com: domain of gcc-patches-return-462073-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-462073-patch=linaro.org@gcc.gnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id 11si10947274plc.450.2017.09.13.12.20.47 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 13 Sep 2017 12:20:47 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-462073-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=cmJ0JHgB; spf=pass (google.com: domain of gcc-patches-return-462073-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-462073-patch=linaro.org@gcc.gnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org 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; q=dns; s= default; b=wlZmDyd+U+MLDm0t4n4hTDguArwMKvXP0LP0kc9x9usRlb0OgdofC SrSep66/aH7jwRyWmQTFds9K7d1gV+jPmlQQc24nKb5SZEpX3+F8b2hf3rhtaMUw AUB2rXe1YXNNsFaIy4UDFb3++BkAScwPDcFoYqgZTYAEF7oRs5z56E= 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; s= default; bh=eOJ2gvXx/TmyOQU1fiFpIqZcbIs=; b=cmJ0JHgBdgPpJg7HWiC8 9T9jgGlcHiFuxeb4B7HfEZ5h6WqElWas1H7g2sTuAGvPSa2h8oQQbaZELa6w/KYO HIIsYBUYG35tudUOqXHHaAAFOq2QP0Ky7mVQzCZP50YfGHbtKtnb5iV/nlWaXszd fDh/HhyToyBMVptPZKxhLtg= Received: (qmail 47906 invoked by alias); 13 Sep 2017 19:20:17 -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 47095 invoked by uid 89); 13 Sep 2017 19:20:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-15.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=ham version=3.3.2 spammy=Six, som X-HELO: mail-wr0-f171.google.com Received: from mail-wr0-f171.google.com (HELO mail-wr0-f171.google.com) (209.85.128.171) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 13 Sep 2017 19:20:06 +0000 Received: by mail-wr0-f171.google.com with SMTP id m18so2471546wrm.2 for ; Wed, 13 Sep 2017 12:20:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:mail-followup-to:subject:date:message-id :user-agent:mime-version; bh=J366we27qX53ZxXqoRZWh+ZzhC7rKoQVGo4KP/0Oto0=; b=XUevO+NEQ/GPmla3QpezPC6c7FoHzzAH0rM3ifW1hr+WiGqKO9tq44GcChun17Kztk BDoh271zoHT52CvqGTpsecjP45kZYd3RV99q9npeS8PzyE8klw1QdCLOTakjl0lAECeK iBwFqLpbeq9/8/bF4rrP/OkflniOe6IXF6hYcPqRB+5K6dUa3Pa0LuE2ZCSWZXpe0jKV hj7evlStx/ufqFHsGIYBiwzRlpIOk5SbFz25dImE+z3KplkmeYnP21vV4E5x09Tl5zqC jSZhCFXYrNXauMlrf+fdsrTPh+g0rhQpSMycBpG+4tBQAP7n9jSJtTmQFjVNd/AVoRFY TeHQ== X-Gm-Message-State: AHPjjUhB1QW8WuzRHAUFiMjxOe4Za8DTptYzt4fRbPepUtiHWIVNJZwa IKShjin74LxcaimUkLxG5Q== X-Google-Smtp-Source: ADKCNb6peVfzDKR2I0iT3E22nM0kHQ9shhl7nKhZ4UdIf4jHoyxMtp6mHMt+ZDqfi8NipWeAsiKsQQ== X-Received: by 10.223.133.244 with SMTP id 49mr15525898wru.153.1505330401472; Wed, 13 Sep 2017 12:20:01 -0700 (PDT) Received: from localhost ([2.25.234.0]) by smtp.gmail.com with ESMTPSA id g70sm11600321wrd.7.2017.09.13.12.19.57 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 13 Sep 2017 12:20:00 -0700 (PDT) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@linaro.org Subject: Turn CANNOT_CHANGE_MODE_CLASS into a hook Date: Wed, 13 Sep 2017 20:19:57 +0100 Message-ID: <87bmmebe3m.fsf@linaro.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux) MIME-Version: 1.0 This also seemed like a good opportunity to reverse the sense of the hook to "can", to avoid the awkward double negative in !CANNOT. Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64le-linux-gnu. Also tested by comparing the testsuite assembly output on at least one target per CPU directory. OK to install? Richard 2017-09-13 Richard Sandiford Alan Hayard David Sherwood gcc/ * target.def (can_change_mode_class): New hook. (mode_rep_extended): Refer to it instead of CANNOT_CHANGE_MODE_CLASS. (hard_regno_nregs): Likewise. * hooks.h (hook_bool_mode_mode_reg_class_t_true): Declare. * hooks.c (hook_bool_mode_mode_reg_class_t_true): New function. * doc/tm.texi.in (CANNOT_CHANGE_MODE_CLASS): Replace with... (TARGET_CAN_CHANGE_MODE_CLASS): ...this. (LOAD_EXTEND_OP): Update accordingly. * doc/tm.texi: Regenerate. * doc/rtl.texi: Refer to TARGET_CAN_CHANGE_MODE_CLASS instead of CANNOT_CHANGE_MODE_CLASS. * hard-reg-set.h (REG_CANNOT_CHANGE_MODE_P): Replace with... (REG_CAN_CHANGE_MODE_P): ...this new macro. * combine.c (simplify_set): Update accordingly. * emit-rtl.c (validate_subreg): Likewise. * recog.c (general_operand): Likewise. * regcprop.c (mode_change_ok): Likewise. * reload1.c (choose_reload_regs): Likewise. (inherit_piecemeal_p): Likewise. * rtlanal.c (simplify_subreg_regno): Likewise. * postreload.c (reload_cse_simplify_set): Use REG_CAN_CHANGE_MODE_P instead of CANNOT_CHANGE_MODE_CLASS. (reload_cse_simplify_operands): Likewise. * reload.c (push_reload): Use targetm.can_change_mode_class instead of CANNOT_CHANGE_MODE_CLASS. (push_reload): Likewise. Also use REG_CAN_CHANGE_MODE_P instead of REG_CANNOT_CHANGE_MODE_P. * config/alpha/alpha.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/alpha/alpha.c (alpha_can_change_mode_class): New function. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/arm/arm.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/arm/arm.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (arm_can_change_mode_class): New function. * config/arm/neon.md: Refer to TARGET_CAN_CHANGE_MODE_CLASS rather than CANNOT_CHANGE_MODE_CLASS in comments. * config/i386/i386.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/i386/i386-protos.h (ix86_cannot_change_mode_class): Delete. * config/i386/i386.c (ix86_cannot_change_mode_class): Replace with... (ix86_can_change_mode_class): ...this new function, inverting the sense of the return value. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/ia64/ia64.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/ia64/ia64.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (ia64_can_change_mode_class): New function. * config/m32c/m32c.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/m32c/m32c-protos.h (m32c_cannot_change_mode_class): Delete. * config/m32c/m32c.c (m32c_cannot_change_mode_class): Replace with... (m32c_can_change_mode_class): ...this new function, inverting the sense of the return value. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/mips/mips.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/mips/mips-protos.h (mips_cannot_change_mode_class): Delete. * config/mips/mips.c (mips_cannot_change_mode_class): Replace with... (mips_can_change_mode_class): ...this new function, inverting the sense of the return value. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/msp430/msp430.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/msp430/msp430.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (msp430_can_change_mode_class): New function. * config/nvptx/nvptx.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/nvptx/nvptx.c (nvptx_can_change_mode_class): New function. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/pa/pa32-regs.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/pa/pa64-regs.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/pa/pa-protos.h (pa_cannot_change_mode_class): Delete. * config/pa/pa.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (pa_cannot_change_mode_class): Replace with... (pa_can_change_mode_class): ...this new function, inverting the sense of the return value. (pa_modes_tieable_p): Refer to TARGET_CAN_CHANGE_MODE_CLASS rather than CANNOT_CHANGE_MODE_CLASS in comments. * config/pdp11/pdp11.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/pdp11/pdp11-protos.h (pdp11_cannot_change_mode_class): Delete. * config/pdp11/pdp11.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (pdp11_cannot_change_mode_class): Replace with... (pdp11_can_change_mode_class): ...this new function, inverting the sense of the return value. * config/powerpcspe/powerpcspe.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/powerpcspe/powerpcspe-protos.h (rs6000_cannot_change_mode_class_ptr): Delete. * config/powerpcspe/powerpcspe.c (rs6000_cannot_change_mode_class_ptr): Delete. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (rs6000_option_override_internal): Assign to targetm.can_change_mode_class instead of rs6000_cannot_change_mode_class_ptr. (rs6000_cannot_change_mode_class): Replace with... (rs6000_can_change_mode_class): ...this new function, inverting the sense of the return value. (rs6000_debug_cannot_change_mode_class): Replace with... (rs6000_debug_can_change_mode_class): ...this new function. * config/riscv/riscv.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/riscv/riscv.c (riscv_can_change_mode_class): New function. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/rs6000/rs6000.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/rs6000/rs6000-protos.h (rs6000_cannot_change_mode_class_ptr): Delete. * config/rs6000/rs6000.c (rs6000_cannot_change_mode_class_ptr): Delete. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (rs6000_option_override_internal): Assign to targetm.can_change_mode_class instead of rs6000_cannot_change_mode_class_ptr. (rs6000_cannot_change_mode_class): Replace with... (rs6000_can_change_mode_class): ...this new function, inverting the sense of the return value. (rs6000_debug_cannot_change_mode_class): Replace with... (rs6000_debug_can_change_mode_class): ...this new function. * config/s390/s390.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/s390/s390-protos.h (s390_cannot_change_mode_class): Delete. * config/s390/s390.c (s390_cannot_change_mode_class): Replace with... (s390_can_change_mode_class): ...this new function, inverting the sense of the return value. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/sh/sh.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/sh/sh-protos.h (sh_cannot_change_mode_class): Delete. * config/sh/sh.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (sh_cannot_change_mode_class): Replace with... (sh_can_change_mode_class): ...this new function, inverting the sense of the return value. * config/sparc/sparc.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/sparc/sparc.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (sparc_can_change_mode_class): New function. * config/spu/spu.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/spu/spu.c (spu_can_change_mode_class): New function. (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. * config/visium/visium.h (CANNOT_CHANGE_MODE_CLASS): Delete. * config/visium/visium.c (TARGET_CAN_CHANGE_MODE_CLASS): Redefine. (visium_can_change_mode_class): New function. * system.h (CANNOT_CHANGE_MODE_CLASS): Poison. Index: gcc/target.def =================================================================== --- gcc/target.def 2017-09-13 20:11:42.906469581 +0100 +++ gcc/target.def 2017-09-13 20:12:03.830543207 +0100 @@ -3151,7 +3151,7 @@ widest integral mode and currently we ta Similarly to @code{LOAD_EXTEND_OP} you may return a non-@code{UNKNOWN}\n\ value even if the extension is not performed on certain hard registers\n\ as long as for the @code{REGNO_REG_CLASS} of these hard registers\n\ -@code{CANNOT_CHANGE_MODE_CLASS} returns nonzero.\n\ +@code{TARGET_CAN_CHANGE_MODE_CLASS} returns false.\n\ \n\ Note that @code{TARGET_MODE_REP_EXTENDED} and @code{LOAD_EXTEND_OP}\n\ describe two related properties. If you define\n\ @@ -5043,6 +5043,38 @@ This is currently used only by the C and tree, (tree type, tree expr), hook_tree_tree_tree_null) +DEFHOOK +(can_change_mode_class, + "This hook returns true if it is possible to bitcast values held in\n\ +registers of class @var{rclass} from mode @var{from} to mode @var{to}\n\ +and if doing so preserves the low-order bits that are common to both modes.\n\ +The result is only meaningful if @var{rclass} has registers that can hold\n\ +both @code{from} and @code{to}. The default implementation returns true.\n\ +\n\ +As an example of when such bitcasting is invalid, loading 32-bit integer or\n\ +floating-point objects into floating-point registers on Alpha extends them\n\ +to 64 bits. Therefore loading a 64-bit object and then storing it as a\n\ +32-bit object does not store the low-order 32 bits, as would be the case\n\ +for a normal register. Therefore, @file{alpha.h} defines\n\ +@code{TARGET_CAN_CHANGE_MODE_CLASS} to return:\n\ +\n\ +@smallexample\n\ +(GET_MODE_SIZE (from) == GET_MODE_SIZE (to)\n\ + || !reg_classes_intersect_p (FLOAT_REGS, rclass))\n\ +@end smallexample\n\ +\n\ +Even if storing from a register in mode @var{to} would be valid,\n\ +if both @var{from} and @code{raw_reg_mode} for @var{rclass} are wider\n\ +than @code{word_mode}, then we must prevent @var{to} narrowing the\n\ +mode. This happens when the middle-end assumes that it can load\n\ +or store pieces of an @var{N}-word pseudo, and that the pseudo will\n\ +eventually be allocated to @var{N} @code{word_mode} hard registers.\n\ +Failure to prevent this kind of mode change will result in the\n\ +entire @code{raw_reg_mode} being modified instead of the partial\n\ +value that the middle-end intended.", + bool, (machine_mode from, machine_mode to, reg_class_t rclass), + hook_bool_mode_mode_reg_class_t_true) + /* Change pseudo allocno class calculated by IRA. */ DEFHOOK (ira_change_pseudo_allocno_class, @@ -5466,8 +5498,8 @@ DEFHOOK at register number @var{regno}, required to hold a value of mode\n\ @var{mode}. This hook must never return zero, even if a register\n\ cannot hold the requested mode - indicate that with\n\ -@code{TARGET_HARD_REGNO_MODE_OK} and/or @code{CANNOT_CHANGE_MODE_CLASS}\n\ -instead.\n\ +@code{TARGET_HARD_REGNO_MODE_OK} and/or\n\ +@code{TARGET_CAN_CHANGE_MODE_CLASS} instead.\n\ \n\ The default definition returns the number of words in @var{mode}.", unsigned int, (unsigned int regno, machine_mode mode), Index: gcc/hooks.h =================================================================== --- gcc/hooks.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/hooks.h 2017-09-13 20:12:03.821479281 +0100 @@ -59,6 +59,8 @@ extern bool hook_bool_rtx_false (rtx); extern bool hook_bool_rtx_insn_int_false (rtx_insn *, int); extern bool hook_bool_uintp_uintp_false (unsigned int *, unsigned int *); extern bool hook_bool_reg_class_t_false (reg_class_t regclass); +extern bool hook_bool_mode_mode_reg_class_t_true (machine_mode, machine_mode, + reg_class_t); extern bool hook_bool_mode_reg_class_t_reg_class_t_false (machine_mode, reg_class_t, reg_class_t); Index: gcc/hooks.c =================================================================== --- gcc/hooks.c 2017-09-13 20:11:42.906469581 +0100 +++ gcc/hooks.c 2017-09-13 20:12:03.820572889 +0100 @@ -495,6 +495,14 @@ hook_bool_reg_class_t_false (reg_class_t return false; } +/* Generic hook that takes 2 machine_modes and a register class and + returns true. */ +bool +hook_bool_mode_mode_reg_class_t_true (machine_mode, machine_mode, reg_class_t) +{ + return true; +} + /* Generic hook that takes a machine_mode and 2 register classes and returns false. */ bool Index: gcc/doc/tm.texi.in =================================================================== --- gcc/doc/tm.texi.in 2017-09-13 20:11:42.906469581 +0100 +++ gcc/doc/tm.texi.in 2017-09-13 20:12:03.819666496 +0100 @@ -2334,34 +2334,7 @@ This macro helps control the handling of in the reload pass. @end defmac -@defmac CANNOT_CHANGE_MODE_CLASS (@var{from}, @var{to}, @var{class}) -If defined, a C expression that returns nonzero for a @var{class} for which -a change from mode @var{from} to mode @var{to} is invalid. - -For example, loading 32-bit integer or floating-point objects into -floating-point registers on Alpha extends them to 64 bits. -Therefore loading a 64-bit object and then storing it as a 32-bit object -does not store the low-order 32 bits, as would be the case for a normal -register. Therefore, @file{alpha.h} defines @code{CANNOT_CHANGE_MODE_CLASS} -as below: - -@smallexample -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ - ? reg_classes_intersect_p (FLOAT_REGS, (CLASS)) : 0) -@end smallexample - -Even if storing from a register in mode @var{to} would be valid, -if both @var{from} and @code{raw_reg_mode} for @var{class} are wider -than @code{word_mode}, then we must prevent @var{to} narrowing the -mode. This happens when the middle-end assumes that it can load -or store pieces of an @var{N}-word pseudo, and that the pseudo will -eventually be allocated to @var{N} @code{word_mode} hard registers. -Failure to prevent this kind of mode change will result in the -entire @code{raw_reg_mode} being modified instead of the partial -value that the middle-end intended. - -@end defmac +@hook TARGET_CAN_CHANGE_MODE_CLASS @hook TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS @@ -7451,12 +7424,12 @@ define it as the constant @code{SIGN_EXT You may return a non-@code{UNKNOWN} value even if for some hard registers the sign extension is not performed, if for the @code{REGNO_REG_CLASS} -of these hard registers @code{CANNOT_CHANGE_MODE_CLASS} returns nonzero +of these hard registers @code{TARGET_CAN_CHANGE_MODE_CLASS} returns false when the @var{from} mode is @var{mem_mode} and the @var{to} mode is any integral mode larger than this but not larger than @code{word_mode}. You must return @code{UNKNOWN} if for some hard registers that allow this -mode, @code{CANNOT_CHANGE_MODE_CLASS} says that they cannot change to +mode, @code{TARGET_CAN_CHANGE_MODE_CLASS} says that they cannot change to @code{word_mode}, but that they can change to another integral mode that is larger then @var{mem_mode} but still smaller than @code{word_mode}. @end defmac Index: gcc/doc/tm.texi =================================================================== --- gcc/doc/tm.texi 2017-09-13 20:11:42.906469581 +0100 +++ gcc/doc/tm.texi 2017-09-13 20:12:03.816040925 +0100 @@ -2018,8 +2018,8 @@ This hook returns the number of consecut at register number @var{regno}, required to hold a value of mode @var{mode}. This hook must never return zero, even if a register cannot hold the requested mode - indicate that with -@code{TARGET_HARD_REGNO_MODE_OK} and/or @code{CANNOT_CHANGE_MODE_CLASS} -instead. +@code{TARGET_HARD_REGNO_MODE_OK} and/or +@code{TARGET_CAN_CHANGE_MODE_CLASS} instead. The default definition returns the number of words in @var{mode}. @end deftypefn @@ -2814,25 +2814,27 @@ This macro helps control the handling of in the reload pass. @end defmac -@defmac CANNOT_CHANGE_MODE_CLASS (@var{from}, @var{to}, @var{class}) -If defined, a C expression that returns nonzero for a @var{class} for which -a change from mode @var{from} to mode @var{to} is invalid. - -For example, loading 32-bit integer or floating-point objects into -floating-point registers on Alpha extends them to 64 bits. -Therefore loading a 64-bit object and then storing it as a 32-bit object -does not store the low-order 32 bits, as would be the case for a normal -register. Therefore, @file{alpha.h} defines @code{CANNOT_CHANGE_MODE_CLASS} -as below: +@deftypefn {Target Hook} bool TARGET_CAN_CHANGE_MODE_CLASS (machine_mode @var{from}, machine_mode @var{to}, reg_class_t @var{rclass}) +This hook returns true if it is possible to bitcast values held in +registers of class @var{rclass} from mode @var{from} to mode @var{to} +and if doing so preserves the low-order bits that are common to both modes. +The result is only meaningful if @var{rclass} has registers that can hold +both @code{from} and @code{to}. The default implementation returns true. + +As an example of when such bitcasting is invalid, loading 32-bit integer or +floating-point objects into floating-point registers on Alpha extends them +to 64 bits. Therefore loading a 64-bit object and then storing it as a +32-bit object does not store the low-order 32 bits, as would be the case +for a normal register. Therefore, @file{alpha.h} defines +@code{TARGET_CAN_CHANGE_MODE_CLASS} to return: @smallexample -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ - ? reg_classes_intersect_p (FLOAT_REGS, (CLASS)) : 0) +(GET_MODE_SIZE (from) == GET_MODE_SIZE (to) + || !reg_classes_intersect_p (FLOAT_REGS, rclass)) @end smallexample Even if storing from a register in mode @var{to} would be valid, -if both @var{from} and @code{raw_reg_mode} for @var{class} are wider +if both @var{from} and @code{raw_reg_mode} for @var{rclass} are wider than @code{word_mode}, then we must prevent @var{to} narrowing the mode. This happens when the middle-end assumes that it can load or store pieces of an @var{N}-word pseudo, and that the pseudo will @@ -2840,8 +2842,7 @@ eventually be allocated to @var{N} @code Failure to prevent this kind of mode change will result in the entire @code{raw_reg_mode} being modified instead of the partial value that the middle-end intended. - -@end defmac +@end deftypefn @deftypefn {Target Hook} reg_class_t TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS (int, @var{reg_class_t}, @var{reg_class_t}) A target hook which can change allocno class for given pseudo from @@ -10695,12 +10696,12 @@ define it as the constant @code{SIGN_EXT You may return a non-@code{UNKNOWN} value even if for some hard registers the sign extension is not performed, if for the @code{REGNO_REG_CLASS} -of these hard registers @code{CANNOT_CHANGE_MODE_CLASS} returns nonzero +of these hard registers @code{TARGET_CAN_CHANGE_MODE_CLASS} returns false when the @var{from} mode is @var{mem_mode} and the @var{to} mode is any integral mode larger than this but not larger than @code{word_mode}. You must return @code{UNKNOWN} if for some hard registers that allow this -mode, @code{CANNOT_CHANGE_MODE_CLASS} says that they cannot change to +mode, @code{TARGET_CAN_CHANGE_MODE_CLASS} says that they cannot change to @code{word_mode}, but that they can change to another integral mode that is larger then @var{mem_mode} but still smaller than @code{word_mode}. @end defmac @@ -10813,7 +10814,7 @@ widest integral mode and currently we ta Similarly to @code{LOAD_EXTEND_OP} you may return a non-@code{UNKNOWN} value even if the extension is not performed on certain hard registers as long as for the @code{REGNO_REG_CLASS} of these hard registers -@code{CANNOT_CHANGE_MODE_CLASS} returns nonzero. +@code{TARGET_CAN_CHANGE_MODE_CLASS} returns false. Note that @code{TARGET_MODE_REP_EXTENDED} and @code{LOAD_EXTEND_OP} describe two related properties. If you define Index: gcc/doc/rtl.texi =================================================================== --- gcc/doc/rtl.texi 2017-08-31 10:40:00.485258650 +0100 +++ gcc/doc/rtl.texi 2017-09-13 20:12:03.813321748 +0100 @@ -2024,17 +2024,17 @@ has an unknown number of undefined bits, does not guarantee that @samp{(subreg:HI (reg:PSI 0) 0)} has the value @samp{(reg:HI 4)}. -@cindex @code{CANNOT_CHANGE_MODE_CLASS} and subreg semantics +@cindex @code{TARGET_CAN_CHANGE_MODE_CLASS} and subreg semantics The rules above apply to both pseudo @var{reg}s and hard @var{reg}s. If the semantics are not correct for particular combinations of @var{m1}, @var{m2} and hard @var{reg}, the target-specific code must ensure that those combinations are never used. For example: @smallexample -CANNOT_CHANGE_MODE_CLASS (@var{m2}, @var{m1}, @var{class}) +TARGET_CAN_CHANGE_MODE_CLASS (@var{m2}, @var{m1}, @var{class}) @end smallexample -must be true for every class @var{class} that includes @var{reg}. +must be false for every class @var{class} that includes @var{reg}. @findex SUBREG_REG @findex SUBREG_BYTE Index: gcc/hard-reg-set.h =================================================================== --- gcc/hard-reg-set.h 2017-02-23 19:54:12.000000000 +0000 +++ gcc/hard-reg-set.h 2017-09-13 20:12:03.820572889 +0100 @@ -765,9 +765,9 @@ #define reg_names \ extern const char * reg_class_names[]; -/* Given a hard REGN a FROM mode and a TO mode, return nonzero if - REGN cannot change modes between the specified modes. */ -#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, TO) \ - CANNOT_CHANGE_MODE_CLASS (FROM, TO, REGNO_REG_CLASS (REGN)) +/* Given a hard REGN a FROM mode and a TO mode, return true if + REGN can change from mode FROM to mode TO. */ +#define REG_CAN_CHANGE_MODE_P(REGN, FROM, TO) \ + (targetm.can_change_mode_class (FROM, TO, REGNO_REG_CLASS (REGN))) #endif /* ! GCC_HARD_REG_SET_H */ Index: gcc/combine.c =================================================================== --- gcc/combine.c 2017-09-13 20:11:42.906469581 +0100 +++ gcc/combine.c 2017-09-13 20:12:03.733559197 +0100 @@ -6869,12 +6869,10 @@ simplify_set (rtx x) == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)) && (WORD_REGISTER_OPERATIONS || !paradoxical_subreg_p (src)) -#ifdef CANNOT_CHANGE_MODE_CLASS && ! (REG_P (dest) && REGNO (dest) < FIRST_PSEUDO_REGISTER - && REG_CANNOT_CHANGE_MODE_P (REGNO (dest), - GET_MODE (SUBREG_REG (src)), - GET_MODE (src))) -#endif + && !REG_CAN_CHANGE_MODE_P (REGNO (dest), + GET_MODE (SUBREG_REG (src)), + GET_MODE (src))) && (REG_P (dest) || (GET_CODE (dest) == SUBREG && REG_P (SUBREG_REG (dest))))) Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c 2017-09-12 14:28:56.393825195 +0100 +++ gcc/emit-rtl.c 2017-09-13 20:12:03.820572889 +0100 @@ -866,13 +866,11 @@ validate_subreg (machine_mode omode, mac { unsigned int regno = REGNO (reg); -#ifdef CANNOT_CHANGE_MODE_CLASS if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode)) && GET_MODE_INNER (imode) == omode) ; - else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode)) + else if (!REG_CAN_CHANGE_MODE_P (regno, imode, omode)) return false; -#endif return subreg_offset_representable_p (regno, imode, offset, omode); } Index: gcc/recog.c =================================================================== --- gcc/recog.c 2017-09-12 14:28:56.397825010 +0100 +++ gcc/recog.c 2017-09-13 20:12:03.822385674 +0100 @@ -1009,10 +1009,9 @@ general_operand (rtx op, machine_mode mo && MEM_P (sub)) return 0; -#ifdef CANNOT_CHANGE_MODE_CLASS if (REG_P (sub) && REGNO (sub) < FIRST_PSEUDO_REGISTER - && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode) + && !REG_CAN_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode) && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT /* LRA can generate some invalid SUBREGS just for matched @@ -1020,7 +1019,6 @@ general_operand (rtx op, machine_mode mo valid. */ && ! LRA_SUBREG_P (op)) return 0; -#endif /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally create such rtl, and we must reject it. */ Index: gcc/regcprop.c =================================================================== --- gcc/regcprop.c 2017-09-12 14:28:56.397825010 +0100 +++ gcc/regcprop.c 2017-09-13 20:12:03.823292066 +0100 @@ -376,11 +376,7 @@ mode_change_ok (machine_mode orig_mode, if (partial_subreg_p (orig_mode, new_mode)) return false; -#ifdef CANNOT_CHANGE_MODE_CLASS - return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode); -#endif - - return true; + return REG_CAN_CHANGE_MODE_P (regno, orig_mode, new_mode); } /* Register REGNO was originally set in ORIG_MODE. It - or a copy of it - Index: gcc/reload1.c =================================================================== --- gcc/reload1.c 2017-09-13 18:05:06.002435306 +0100 +++ gcc/reload1.c 2017-09-13 20:12:03.826011244 +0100 @@ -6557,14 +6557,12 @@ choose_reload_regs (struct insn_chain *c && reg_last_reload_reg[regno] != 0 && (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno])) >= GET_MODE_SIZE (mode) + byte) -#ifdef CANNOT_CHANGE_MODE_CLASS /* Verify that the register it's in can be used in mode MODE. */ - && !REG_CANNOT_CHANGE_MODE_P (REGNO (reg_last_reload_reg[regno]), - GET_MODE (reg_last_reload_reg[regno]), - mode) -#endif - ) + && (REG_CAN_CHANGE_MODE_P + (REGNO (reg_last_reload_reg[regno]), + GET_MODE (reg_last_reload_reg[regno]), + mode))) { enum reg_class rclass = rld[r].rclass, last_class; rtx last_reg = reg_last_reload_reg[regno]; @@ -8035,12 +8033,8 @@ inherit_piecemeal_p (int dest ATTRIBUTE_ int src ATTRIBUTE_UNUSED, machine_mode mode ATTRIBUTE_UNUSED) { -#ifdef CANNOT_CHANGE_MODE_CLASS - return (!REG_CANNOT_CHANGE_MODE_P (dest, mode, reg_raw_mode[dest]) - && !REG_CANNOT_CHANGE_MODE_P (src, mode, reg_raw_mode[src])); -#else - return true; -#endif + return (REG_CAN_CHANGE_MODE_P (dest, mode, reg_raw_mode[dest]) + && REG_CAN_CHANGE_MODE_P (src, mode, reg_raw_mode[src])); } /* Output insns to reload values in and out of the chosen reload regs. */ Index: gcc/rtlanal.c =================================================================== --- gcc/rtlanal.c 2017-09-12 14:28:56.399824918 +0100 +++ gcc/rtlanal.c 2017-09-13 20:12:03.827824030 +0100 @@ -3861,15 +3861,13 @@ simplify_subreg_regno (unsigned int xreg struct subreg_info info; unsigned int yregno; -#ifdef CANNOT_CHANGE_MODE_CLASS /* Give the backend a chance to disallow the mode change. */ if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT && GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT - && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode) + && !REG_CAN_CHANGE_MODE_P (xregno, xmode, ymode) /* We can use mode change in LRA for some transformations. */ && ! lra_in_progress) return -1; -#endif /* We shouldn't simplify stack-related registers. */ if ((!reload_completed || frame_pointer_needed) Index: gcc/postreload.c =================================================================== --- gcc/postreload.c 2017-09-12 14:28:56.396825056 +0100 +++ gcc/postreload.c 2017-09-13 20:12:03.821479281 +0100 @@ -335,12 +335,8 @@ reload_cse_simplify_set (rtx set, rtx_in && !REG_P (SET_SRC (set)))) { if (extend_op != UNKNOWN -#ifdef CANNOT_CHANGE_MODE_CLASS - && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)), - word_mode, - REGNO_REG_CLASS (REGNO (SET_DEST (set)))) -#endif - ) + && REG_CAN_CHANGE_MODE_P (REGNO (SET_DEST (set)), + GET_MODE (SET_DEST (set)), word_mode)) { rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set))); ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set)); @@ -434,15 +430,13 @@ reload_cse_simplify_operands (rtx_insn * || GET_CODE (SET_SRC (set)) == ZERO_EXTEND || GET_CODE (SET_SRC (set)) == SIGN_EXTEND) ; /* Continue ordinary processing. */ -#ifdef CANNOT_CHANGE_MODE_CLASS /* If the register cannot change mode to word_mode, it follows that it cannot have been used in word_mode. */ else if (REG_P (SET_DEST (set)) - && CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)), - word_mode, - REGNO_REG_CLASS (REGNO (SET_DEST (set))))) + && !REG_CAN_CHANGE_MODE_P (REGNO (SET_DEST (set)), + GET_MODE (SET_DEST (set)), + word_mode)) ; /* Continue ordinary processing. */ -#endif /* If this is a straight load, make the extension explicit. */ else if (REG_P (SET_DEST (set)) && recog_data.n_operands == 2 Index: gcc/reload.c =================================================================== --- gcc/reload.c 2017-09-13 18:05:06.000622850 +0100 +++ gcc/reload.c 2017-09-13 20:12:03.824198459 +0100 @@ -1038,9 +1038,8 @@ push_reload (rtx in, rtx out, rtx *inloc scalar_int_mode inner_mode; if (in != 0 && GET_CODE (in) == SUBREG && (subreg_lowpart_p (in) || strict_low) -#ifdef CANNOT_CHANGE_MODE_CLASS - && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), inmode, rclass) -#endif + && targetm.can_change_mode_class (GET_MODE (SUBREG_REG (in)), + inmode, rclass) && contains_allocatable_reg_of_mode[rclass][GET_MODE (SUBREG_REG (in))] && (CONSTANT_P (SUBREG_REG (in)) || GET_CODE (SUBREG_REG (in)) == PLUS @@ -1076,13 +1075,10 @@ push_reload (rtx in, rtx out, rtx *inloc && (secondary_reload_class (1, rclass, GET_MODE (SUBREG_REG (in)), SUBREG_REG (in)) == NO_REGS)) -#ifdef CANNOT_CHANGE_MODE_CLASS || (REG_P (SUBREG_REG (in)) && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER - && REG_CANNOT_CHANGE_MODE_P - (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode)) -#endif - )) + && !REG_CAN_CHANGE_MODE_P (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in)), inmode)))) { #ifdef LIMIT_RELOAD_CLASS in_subreg_loc = inloc; @@ -1143,9 +1139,8 @@ push_reload (rtx in, rtx out, rtx *inloc label it input-output.) */ if (out != 0 && GET_CODE (out) == SUBREG && (subreg_lowpart_p (out) || strict_low) -#ifdef CANNOT_CHANGE_MODE_CLASS - && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), outmode, rclass) -#endif + && targetm.can_change_mode_class (GET_MODE (SUBREG_REG (out)), + outmode, rclass) && contains_allocatable_reg_of_mode[rclass][GET_MODE (SUBREG_REG (out))] && (CONSTANT_P (SUBREG_REG (out)) || strict_low @@ -1170,14 +1165,11 @@ push_reload (rtx in, rtx out, rtx *inloc && (secondary_reload_class (0, rclass, GET_MODE (SUBREG_REG (out)), SUBREG_REG (out)) == NO_REGS)) -#ifdef CANNOT_CHANGE_MODE_CLASS || (REG_P (SUBREG_REG (out)) && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER - && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), - GET_MODE (SUBREG_REG (out)), - outmode)) -#endif - )) + && !REG_CAN_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + outmode)))) { #ifdef LIMIT_RELOAD_CLASS out_subreg_loc = outloc; Index: gcc/config/alpha/alpha.h =================================================================== --- gcc/config/alpha/alpha.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/alpha/alpha.h 2017-09-13 20:12:03.735371982 +0100 @@ -479,12 +479,6 @@ #define BASE_REG_CLASS GENERAL_REGS #define PREFERRED_RELOAD_CLASS alpha_preferred_reload_class -/* Return the class of registers that cannot change mode from FROM to TO. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ - ? reg_classes_intersect_p (FLOAT_REGS, CLASS) : 0) - /* Provide the cost of a branch. Exact meaning under development. */ #define BRANCH_COST(speed_p, predictable_p) 5 Index: gcc/config/alpha/alpha.c =================================================================== --- gcc/config/alpha/alpha.c 2017-09-13 18:05:05.966186196 +0100 +++ gcc/config/alpha/alpha.c 2017-09-13 20:12:03.734465590 +0100 @@ -9936,6 +9936,16 @@ alpha_modes_tieable_p (machine_mode mode ? alpha_hard_regno_mode_ok (32, mode2) : true); } + +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ + +static bool +alpha_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) +{ + return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to) + || !reg_classes_intersect_p (FLOAT_REGS, rclass)); +} /* Initialize the GCC target structure. */ #if TARGET_ABI_OPEN_VMS @@ -10140,6 +10150,9 @@ #define TARGET_HARD_REGNO_MODE_OK alpha_ #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P alpha_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS alpha_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; Index: gcc/config/arm/arm.h =================================================================== --- gcc/config/arm/arm.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/arm/arm.h 2017-09-13 20:12:03.745342301 +0100 @@ -1152,23 +1152,6 @@ #define IS_VFP_CLASS(X) \ or could index an array. */ #define REGNO_REG_CLASS(REGNO) arm_regno_class (REGNO) -/* In VFPv1, VFP registers could only be accessed in the mode they - were set, so subregs would be invalid there. However, we don't - support VFPv1 at the moment, and the restriction was lifted in - VFPv2. - In big-endian mode, modes greater than word size (i.e. DFmode) are stored in - VFP registers in little-endian order. We can't describe that accurately to - GCC, so avoid taking subregs of such values. - The only exception is going from a 128-bit to a 64-bit type. In that case - the data layout happens to be consistent for big-endian, so we explicitly allow - that case. */ -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (TARGET_BIG_END \ - && !(GET_MODE_SIZE (FROM) == 16 && GET_MODE_SIZE (TO) == 8) \ - && (GET_MODE_SIZE (FROM) > UNITS_PER_WORD \ - || GET_MODE_SIZE (TO) > UNITS_PER_WORD) \ - && reg_classes_intersect_p (VFP_REGS, (CLASS))) - /* The class value for index registers, and the one for base regs. */ #define INDEX_REG_CLASS (TARGET_THUMB1 ? LO_REGS : GENERAL_REGS) #define BASE_REG_CLASS (TARGET_THUMB1 ? LO_REGS : CORE_REGS) Index: gcc/config/arm/arm.c =================================================================== --- gcc/config/arm/arm.c 2017-09-13 18:03:47.580649117 +0100 +++ gcc/config/arm/arm.c 2017-09-13 20:12:03.745342301 +0100 @@ -793,6 +793,9 @@ #define TARGET_HARD_REGNO_MODE_OK arm_ha #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P arm_modes_tieable_p + +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS arm_can_change_mode_class /* Obstack for minipool constant handling. */ static struct obstack minipool_obstack; @@ -31243,6 +31246,33 @@ arm_coproc_ldc_stc_legitimate_address (r return false; } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. + + In VFPv1, VFP registers could only be accessed in the mode they were + set, so subregs would be invalid there. However, we don't support + VFPv1 at the moment, and the restriction was lifted in VFPv2. + + In big-endian mode, modes greater than word size (i.e. DFmode) are stored in + VFP registers in little-endian order. We can't describe that accurately to + GCC, so avoid taking subregs of such values. + + The only exception is going from a 128-bit to a 64-bit type. In that + case the data layout happens to be consistent for big-endian, so we + explicitly allow that case. */ + +static bool +arm_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) +{ + if (TARGET_BIG_END + && !(GET_MODE_SIZE (from) == 16 && GET_MODE_SIZE (to) == 8) + && (GET_MODE_SIZE (from) > UNITS_PER_WORD + || GET_MODE_SIZE (to) > UNITS_PER_WORD) + && reg_classes_intersect_p (VFP_REGS, rclass)) + return false; + return true; +} + #if CHECKING_P namespace selftest { Index: gcc/config/arm/neon.md =================================================================== --- gcc/config/arm/neon.md 2017-08-30 12:08:15.976667513 +0100 +++ gcc/config/arm/neon.md 2017-09-13 20:12:03.745342301 +0100 @@ -142,7 +142,7 @@ (define_expand "movv4hf" (match_operand:V4HF 1 "s_register_operand"))] "TARGET_NEON && TARGET_FP16" { - /* We need to use force_reg to avoid CANNOT_CHANGE_MODE_CLASS + /* We need to use force_reg to avoid TARGET_CAN_CHANGE_MODE_CLASS causing an ICE on big-endian because it cannot extract subregs in this case. */ if (can_create_pseudo_p ()) @@ -157,7 +157,7 @@ (define_expand "movv8hf" (match_operand:V8HF 1 ""))] "TARGET_NEON && TARGET_FP16" { - /* We need to use force_reg to avoid CANNOT_CHANGE_MODE_CLASS + /* We need to use force_reg to avoid TARGET_CAN_CHANGE_MODE_CLASS causing an ICE on big-endian because it cannot extract subregs in this case. */ if (can_create_pseudo_p ()) Index: gcc/config/i386/i386.h =================================================================== --- gcc/config/i386/i386.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/i386/i386.h 2017-09-13 20:12:03.761657368 +0100 @@ -1518,11 +1518,6 @@ #define SSE_REGNO(N) \ #define INDEX_REG_CLASS INDEX_REGS #define BASE_REG_CLASS GENERAL_REGS - -/* Return a class of registers that cannot change FROM mode to TO mode. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - ix86_cannot_change_mode_class (FROM, TO, CLASS) /* Stack layout; function entry, exit and calling. */ Index: gcc/config/i386/i386-protos.h =================================================================== --- gcc/config/i386/i386-protos.h 2017-09-13 18:05:05.968904879 +0100 +++ gcc/config/i386/i386-protos.h 2017-09-13 20:12:03.746248694 +0100 @@ -167,8 +167,6 @@ extern int ix86_reg_parm_stack_space (co extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx, rtx, rtx, rtx); -extern bool ix86_cannot_change_mode_class (machine_mode, - machine_mode, enum reg_class); extern bool ix86_libc_has_function (enum function_class fn_class); Index: gcc/config/i386/i386.c =================================================================== --- gcc/config/i386/i386.c 2017-09-13 18:05:05.972529790 +0100 +++ gcc/config/i386/i386.c 2017-09-13 20:12:03.761657368 +0100 @@ -41204,20 +41204,19 @@ ix86_class_max_nregs (reg_class_t rclass } } -/* Return true if the registers in CLASS cannot represent the change from - modes FROM to TO. */ +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ -bool -ix86_cannot_change_mode_class (machine_mode from, machine_mode to, - enum reg_class regclass) +static bool +ix86_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t regclass) { if (from == to) - return false; + return true; /* x87 registers can't do subreg at all, as all values are reformatted to extended precision. */ if (MAYBE_FLOAT_CLASS_P (regclass)) - return true; + return false; if (MAYBE_SSE_CLASS_P (regclass) || MAYBE_MMX_CLASS_P (regclass)) { @@ -41226,10 +41225,10 @@ ix86_cannot_change_mode_class (machine_m drop the subreg from (subreg:SI (reg:HI 100) 0). This affects the vec_dupv4hi pattern. */ if (GET_MODE_SIZE (from) < 4) - return true; + return false; } - return false; + return true; } /* Return the cost of moving data of mode M between a @@ -53434,6 +53433,9 @@ #define TARGET_MODES_TIEABLE_P ix86_mode #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \ ix86_hard_regno_call_part_clobbered +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS ix86_can_change_mode_class + #if CHECKING_P #undef TARGET_RUN_TARGET_SELFTESTS #define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests Index: gcc/config/ia64/ia64.h =================================================================== --- gcc/config/ia64/ia64.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/ia64/ia64.h 2017-09-13 20:12:03.762563761 +0100 @@ -777,17 +777,6 @@ #define CLASS_MAX_NREGS(CLASS, MODE) \ : (((CLASS) == FR_REGS || (CLASS) == FP_REGS) && (MODE) == RFmode) ? 1 \ : (((CLASS) == FR_REGS || (CLASS) == FP_REGS) && (MODE) == XCmode) ? 2 \ : (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* In BR regs, we can't change the DImode at all. - In FP regs, we can't change FP values to integer values and vice versa, - but we can change e.g. DImode to SImode, and V2SFmode into DImode. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (reg_classes_intersect_p (CLASS, BR_REGS) \ - ? (FROM) != (TO) \ - : (SCALAR_FLOAT_MODE_P (FROM) != SCALAR_FLOAT_MODE_P (TO) \ - ? reg_classes_intersect_p (CLASS, FR_REGS) \ - : 0)) /* Basic Stack Layout */ Index: gcc/config/ia64/ia64.c =================================================================== --- gcc/config/ia64/ia64.c 2017-09-13 18:05:05.975248473 +0100 +++ gcc/config/ia64/ia64.c 2017-09-13 20:12:03.762563761 +0100 @@ -339,6 +339,8 @@ static bool ia64_vectorize_vec_perm_cons static unsigned int ia64_hard_regno_nregs (unsigned int, machine_mode); static bool ia64_hard_regno_mode_ok (unsigned int, machine_mode); static bool ia64_modes_tieable_p (machine_mode, machine_mode); +static bool ia64_can_change_mode_class (machine_mode, machine_mode, + reg_class_t); #define MAX_VECT_LEN 8 @@ -668,6 +670,9 @@ #define TARGET_HARD_REGNO_MODE_OK ia64_h #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P ia64_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS ia64_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; /* Returns TRUE iff the target attribute indicated by ATTR_ID takes a plain @@ -11908,4 +11913,21 @@ ia64_expand_vec_perm_even_odd (rtx targe gcc_assert (ok); } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. + + In BR regs, we can't change the DImode at all. + In FP regs, we can't change FP values to integer values and vice versa, + but we can change e.g. DImode to SImode, and V2SFmode into DImode. */ + +static bool +ia64_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) +{ + if (reg_classes_intersect_p (rclass, BR_REGS)) + return from == to; + if (SCALAR_FLOAT_MODE_P (from) != SCALAR_FLOAT_MODE_P (to)) + return !reg_classes_intersect_p (rclass, FR_REGS); + return true; +} + #include "gt-ia64.h" Index: gcc/config/m32c/m32c.h =================================================================== --- gcc/config/m32c/m32c.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/m32c/m32c.h 2017-09-13 20:12:03.763470154 +0100 @@ -411,8 +411,6 @@ #define SECONDARY_RELOAD_CLASS(CLASS,MOD #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true -#define CANNOT_CHANGE_MODE_CLASS(F,T,C) m32c_cannot_change_mode_class(F,T,C) - /* STACK AND CALLING */ /* Frame Layout */ Index: gcc/config/m32c/m32c-protos.h =================================================================== --- gcc/config/m32c/m32c-protos.h 2017-09-12 14:29:25.238530499 +0100 +++ gcc/config/m32c/m32c-protos.h 2017-09-13 20:12:03.763470154 +0100 @@ -38,7 +38,6 @@ int m32c_trampoline_size (void); #ifdef RTX_CODE -int m32c_cannot_change_mode_class (machine_mode, machine_mode, int); rtx m32c_eh_return_stackadj_rtx (void); void m32c_emit_eh_epilogue (rtx); int m32c_expand_cmpstr (rtx *); Index: gcc/config/m32c/m32c.c =================================================================== --- gcc/config/m32c/m32c.c 2017-09-12 14:29:25.239530456 +0100 +++ gcc/config/m32c/m32c.c 2017-09-13 20:12:03.763470154 +0100 @@ -799,17 +799,17 @@ m32c_class_max_nregs (reg_class_t regcla return max; } -/* Implements CANNOT_CHANGE_MODE_CLASS. Only r0 and r1 can change to +/* Implements TARGET_CAN_CHANGE_MODE_CLASS. Only r0 and r1 can change to QI (r0l, r1l) because the chip doesn't support QI ops on other registers (well, it does on a0/a1 but if we let gcc do that, reload suffers). Otherwise, we allow changes to larger modes. */ -int -m32c_cannot_change_mode_class (machine_mode from, - machine_mode to, int rclass) +static bool +m32c_can_change_mode_class (machine_mode from, + machine_mode to, reg_class_t rclass) { int rn; #if DEBUG0 - fprintf (stderr, "cannot change from %s to %s in %s\n", + fprintf (stderr, "can change from %s to %s in %s\n", mode_name[from], mode_name[to], class_names[rclass]); #endif @@ -818,18 +818,18 @@ m32c_cannot_change_mode_class (machine_m for (rn = 0; rn < FIRST_PSEUDO_REGISTER; rn++) if (class_contents[rclass][0] & (1 << rn)) if (! m32c_hard_regno_mode_ok (rn, to)) - return 1; + return false; if (to == QImode) - return (class_contents[rclass][0] & 0x1ffa); + return (class_contents[rclass][0] & 0x1ffa) == 0; if (class_contents[rclass][0] & 0x0005 /* r0, r1 */ && GET_MODE_SIZE (from) > 1) - return 0; + return true; if (GET_MODE_SIZE (from) > 2) /* all other regs */ - return 0; + return true; - return 1; + return false; } /* Helpers for the rest of the file. */ @@ -4496,6 +4496,9 @@ #define TARGET_HARD_REGNO_MODE_OK m32c_h #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P m32c_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS m32c_can_change_mode_class + /* The Global `targetm' Variable. */ struct gcc_target targetm = TARGET_INITIALIZER; Index: gcc/config/mips/mips.h =================================================================== --- gcc/config/mips/mips.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/mips/mips.h 2017-09-13 20:12:03.767095724 +0100 @@ -2302,9 +2302,6 @@ #define SECONDARY_OUTPUT_RELOAD_CLASS(CL needed to represent mode MODE in a register of class CLASS. */ #define CLASS_MAX_NREGS(CLASS, MODE) mips_class_max_nregs (CLASS, MODE) - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - mips_cannot_change_mode_class (FROM, TO, CLASS) /* Stack layout; function entry, exit and calling. */ Index: gcc/config/mips/mips-protos.h =================================================================== --- gcc/config/mips/mips-protos.h 2017-09-13 18:05:05.977967157 +0100 +++ gcc/config/mips/mips-protos.h 2017-09-13 20:12:03.763470154 +0100 @@ -294,8 +294,6 @@ extern bool mips_const_vector_bitimm_set extern bool mips_const_vector_bitimm_clr_p (rtx, machine_mode); extern rtx mips_msa_vec_parallel_const_half (machine_mode, bool); extern rtx mips_gen_const_int_vector (machine_mode, HOST_WIDE_INT); -extern bool mips_cannot_change_mode_class (machine_mode, - machine_mode, enum reg_class); extern bool mips_dangerous_for_la25_p (rtx); extern enum reg_class mips_secondary_reload_class (enum reg_class, machine_mode, Index: gcc/config/mips/mips.c =================================================================== --- gcc/config/mips/mips.c 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/mips/mips.c 2017-09-13 20:12:03.767095724 +0100 @@ -12945,22 +12945,21 @@ mips_class_max_nregs (enum reg_class rcl return (GET_MODE_SIZE (mode) + size - 1) / size; } -/* Implement CANNOT_CHANGE_MODE_CLASS. */ +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ -bool -mips_cannot_change_mode_class (machine_mode from, - machine_mode to, - enum reg_class rclass) +static bool +mips_can_change_mode_class (machine_mode from, + machine_mode to, reg_class_t rclass) { /* Allow conversions between different Loongson integer vectors, and between those vectors and DImode. */ if (GET_MODE_SIZE (from) == 8 && GET_MODE_SIZE (to) == 8 && INTEGRAL_MODE_P (from) && INTEGRAL_MODE_P (to)) - return false; + return true; /* Allow conversions between different MSA vector modes. */ if (MSA_SUPPORTED_MODE_P (from) && MSA_SUPPORTED_MODE_P (to)) - return false; + return true; /* Otherwise, there are several problems with changing the modes of values in floating-point registers: @@ -12985,7 +12984,7 @@ mips_cannot_change_mode_class (machine_m We therefore disallow all mode changes involving FPRs. */ - return reg_classes_intersect_p (FP_REGS, rclass); + return !reg_classes_intersect_p (FP_REGS, rclass); } /* Implement target hook small_register_classes_for_mode_p. */ @@ -22621,6 +22620,9 @@ #define TARGET_CUSTOM_FUNCTION_DESCRIPTO #undef TARGET_SECONDARY_MEMORY_NEEDED #define TARGET_SECONDARY_MEMORY_NEEDED mips_secondary_memory_needed +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS mips_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-mips.h" Index: gcc/config/msp430/msp430.h =================================================================== --- gcc/config/msp430/msp430.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/msp430/msp430.h 2017-09-13 20:12:03.768002117 +0100 @@ -407,14 +407,6 @@ #define DWARF2_ASM_LINE_DEBUG_INFO 1 #define HARD_REGNO_CALLER_SAVE_MODE(REGNO,NREGS,MODE) \ ((TARGET_LARGE && ((NREGS) <= 2)) ? PSImode : choose_hard_reg_mode ((REGNO), (NREGS), false)) -/* Also stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ -#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \ - ( ((TO) == PSImode && (FROM) == SImode) \ - || ((TO) == SImode && (FROM) == PSImode) \ - || ((TO) == DImode && (FROM) == PSImode) \ - || ((TO) == PSImode && (FROM) == DImode) \ - ) - #define ACCUMULATE_OUTGOING_ARGS 1 #undef ASM_DECLARE_FUNCTION_NAME Index: gcc/config/msp430/msp430.c =================================================================== --- gcc/config/msp430/msp430.c 2017-09-12 14:29:25.243530280 +0100 +++ gcc/config/msp430/msp430.c 2017-09-13 20:12:03.768002117 +0100 @@ -3812,6 +3812,22 @@ msp430x_logical_shift_right (rtx amount) right shift instruction to perform the rest of the shift. */ return "rrum.w\t#1, %0 { rpt\t%Z2 { rrax.w\t%0"; /* Six bytes. */ } + +/* Stop GCC from thinking that it can eliminate (SUBREG:PSI (SI)). */ + +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS msp430_can_change_mode_class + +static bool +msp430_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t) +{ + if ((to == PSImode && from == SImode) + || (to == SImode && from == PSImode) + || (to == DImode && from == PSImode) + || (to == PSImode && from == DImode)) + return false; + return true; +} struct gcc_target targetm = TARGET_INITIALIZER; Index: gcc/config/nvptx/nvptx.h =================================================================== --- gcc/config/nvptx/nvptx.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/nvptx/nvptx.h 2017-09-13 20:12:03.769814902 +0100 @@ -95,9 +95,6 @@ #define FIRST_PSEUDO_REGISTER 16 #define FIXED_REGISTERS { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define CALL_USED_REGISTERS { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } -#define CANNOT_CHANGE_MODE_CLASS(M1, M2, CLS) \ - ((void)(M1), (void)(M2), (void)(CLS), true) - /* Register Classes. */ enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES }; #define REG_CLASS_NAMES { "NO_REGS", "ALL_REGS" } Index: gcc/config/nvptx/nvptx.c =================================================================== --- gcc/config/nvptx/nvptx.c 2017-09-12 14:29:25.246530148 +0100 +++ gcc/config/nvptx/nvptx.c 2017-09-13 20:12:03.768908509 +0100 @@ -5529,6 +5529,14 @@ nvptx_hard_regno_nregs (unsigned int, ma return 1; } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ + +static bool +nvptx_can_change_mode_class (machine_mode, machine_mode, reg_class_t) +{ + return false; +} + #undef TARGET_OPTION_OVERRIDE #define TARGET_OPTION_OVERRIDE nvptx_option_override @@ -5659,6 +5667,9 @@ #define TARGET_MODES_TIEABLE_P nvptx_mod #undef TARGET_HARD_REGNO_NREGS #define TARGET_HARD_REGNO_NREGS nvptx_hard_regno_nregs +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS nvptx_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-nvptx.h" Index: gcc/config/pa/pa32-regs.h =================================================================== --- gcc/config/pa/pa32-regs.h 2017-09-12 14:29:25.246530148 +0100 +++ gcc/config/pa/pa32-regs.h 2017-09-13 20:12:03.773440472 +0100 @@ -294,11 +294,6 @@ #define REG_CLASS_CONTENTS \ {0x00000000, 0x00000000, 0x01000000}, /* SHIFT_REGS */ \ {0xfffffffe, 0xffffffff, 0x03ffffff}} /* ALL_REGS */ -/* Defines invalid mode changes. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - pa_cannot_change_mode_class (FROM, TO, CLASS) - /* Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ Index: gcc/config/pa/pa64-regs.h =================================================================== --- gcc/config/pa/pa64-regs.h 2017-09-12 14:29:25.246530148 +0100 +++ gcc/config/pa/pa64-regs.h 2017-09-13 20:12:03.773440472 +0100 @@ -230,11 +230,6 @@ #define REG_CLASS_CONTENTS \ {0x00000000, 0x10000000}, /* SHIFT_REGS */ \ {0xfffffffe, 0x3fffffff}} /* ALL_REGS */ -/* Defines invalid mode changes. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - pa_cannot_change_mode_class (FROM, TO, CLASS) - /* Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ Index: gcc/config/pa/pa-protos.h =================================================================== --- gcc/config/pa/pa-protos.h 2017-09-04 11:50:24.551667467 +0100 +++ gcc/config/pa/pa-protos.h 2017-09-13 20:12:03.769814902 +0100 @@ -106,8 +106,6 @@ extern void pa_asm_output_aligned_local unsigned HOST_WIDE_INT, unsigned int); extern void pa_hpux_asm_output_external (FILE *, tree, const char *); -extern bool pa_cannot_change_mode_class (machine_mode, machine_mode, - enum reg_class); extern HOST_WIDE_INT pa_initial_elimination_offset (int, int); extern const int pa_magic_milli[]; Index: gcc/config/pa/pa.c =================================================================== --- gcc/config/pa/pa.c 2017-09-13 18:05:05.985216979 +0100 +++ gcc/config/pa/pa.c 2017-09-13 20:12:03.772534080 +0100 @@ -204,6 +204,7 @@ static bool pa_callee_copies (cumulative static unsigned int pa_hard_regno_nregs (unsigned int, machine_mode); static bool pa_hard_regno_mode_ok (unsigned int, machine_mode); static bool pa_modes_tieable_p (machine_mode, machine_mode); +static bool pa_can_change_mode_class (machine_mode, machine_mode, reg_class_t); /* The following extra sections are only used for SOM. */ static GTY(()) section *som_readonly_data_section; @@ -421,6 +422,9 @@ #define TARGET_HARD_REGNO_MODE_OK pa_har #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P pa_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS pa_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; /* Parse the -mfixed-range= option string. */ @@ -10001,27 +10005,26 @@ pa_hpux_file_end (void) } #endif -/* Return true if a change from mode FROM to mode TO for a register - in register class RCLASS is invalid. */ +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ -bool -pa_cannot_change_mode_class (machine_mode from, machine_mode to, - enum reg_class rclass) +static bool +pa_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) { if (from == to) - return false; + return true; if (GET_MODE_SIZE (from) == GET_MODE_SIZE (to)) - return false; + return true; /* Reject changes to/from modes with zero size. */ if (!GET_MODE_SIZE (from) || !GET_MODE_SIZE (to)) - return true; + return false; /* Reject changes to/from complex and vector modes. */ if (COMPLEX_MODE_P (from) || VECTOR_MODE_P (from) || COMPLEX_MODE_P (to) || VECTOR_MODE_P (to)) - return true; + return false; /* There is no way to load QImode or HImode values directly from memory to a FP register. SImode loads to the FP registers are not zero @@ -10029,16 +10032,16 @@ pa_cannot_change_mode_class (machine_mod of LOAD_EXTEND_OP. Thus, we can't allow changing between modes with different sizes in the floating-point registers. */ if (MAYBE_FP_REG_CLASS_P (rclass)) - return true; + return false; /* TARGET_HARD_REGNO_MODE_OK places modes with sizes larger than a word in specific sets of registers. Thus, we cannot allow changing to a larger mode when it's larger than a word. */ if (GET_MODE_SIZE (to) > UNITS_PER_WORD && GET_MODE_SIZE (to) > GET_MODE_SIZE (from)) - return true; + return false; - return false; + return true; } /* Implement TARGET_MODES_TIEABLE_P. @@ -10047,7 +10050,7 @@ pa_cannot_change_mode_class (machine_mod are not ok in the floating-point registers. However, this prevents tieing these modes to SImode and DImode in the general registers. So, this isn't a good idea. We rely on TARGET_HARD_REGNO_MODE_OK and - CANNOT_CHANGE_MODE_CLASS to prevent these modes from being used + TARGET_CAN_CHANGE_MODE_CLASS to prevent these modes from being used in the floating-point registers. */ static bool Index: gcc/config/pdp11/pdp11.h =================================================================== --- gcc/config/pdp11/pdp11.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/pdp11/pdp11.h 2017-09-13 20:12:03.774346865 +0100 @@ -243,9 +243,6 @@ #define CLASS_MAX_NREGS(CLASS, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD): \ 1 \ ) - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - pdp11_cannot_change_mode_class (FROM, TO, CLASS) /* Stack layout; function entry, exit and calling. */ Index: gcc/config/pdp11/pdp11-protos.h =================================================================== --- gcc/config/pdp11/pdp11-protos.h 2017-09-13 18:05:05.985216979 +0100 +++ gcc/config/pdp11/pdp11-protos.h 2017-09-13 20:12:03.773440472 +0100 @@ -29,8 +29,6 @@ extern const char *output_move_multiple extern const char *output_block_move (rtx *); extern const char *output_jump (enum rtx_code, int, int); extern void print_operand_address (FILE *, rtx); -extern bool pdp11_cannot_change_mode_class (machine_mode, - machine_mode, enum reg_class); typedef enum { no_action, dec_before, inc_after } pdp11_action; typedef enum { little, either, big } pdp11_partorder; extern bool pdp11_expand_operands (rtx *, rtx [][2], int, Index: gcc/config/pdp11/pdp11.c =================================================================== --- gcc/config/pdp11/pdp11.c 2017-09-13 18:05:05.986123206 +0100 +++ gcc/config/pdp11/pdp11.c 2017-09-13 20:12:03.773440472 +0100 @@ -246,6 +246,9 @@ #define TARGET_MODES_TIEABLE_P pdp11_mod #undef TARGET_SECONDARY_MEMORY_NEEDED #define TARGET_SECONDARY_MEMORY_NEEDED pdp11_secondary_memory_needed + +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS pdp11_can_change_mode_class /* A helper function to determine if REGNO should be saved in the current function's stack frame. */ @@ -1372,20 +1375,20 @@ legitimate_const_double_p (rtx address) return 0; } -/* Implement CANNOT_CHANGE_MODE_CLASS. */ -bool -pdp11_cannot_change_mode_class (machine_mode from, - machine_mode to, - enum reg_class rclass) +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ +static bool +pdp11_can_change_mode_class (machine_mode from, + machine_mode to, + reg_class_t rclass) { /* Also, FPU registers contain a whole float value and the parts of it are not separately accessible. So we disallow all mode changes involving FPRs. */ if (FLOAT_MODE_P (from) != FLOAT_MODE_P (to)) - return true; + return false; - return reg_classes_intersect_p (FPU_REGS, rclass); + return !reg_classes_intersect_p (FPU_REGS, rclass); } /* TARGET_PREFERRED_RELOAD_CLASS Index: gcc/config/powerpcspe/powerpcspe.h =================================================================== --- gcc/config/powerpcspe/powerpcspe.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/powerpcspe/powerpcspe.h 2017-09-13 20:12:03.787036362 +0100 @@ -1611,11 +1611,6 @@ #define SECONDARY_MEMORY_NEEDED_RTX(MODE registers can hold 128 bits. */ #define CLASS_MAX_NREGS(CLASS, MODE) rs6000_class_max_nregs[(MODE)][(CLASS)] -/* Return nonzero if for CLASS a mode change from FROM to TO is invalid. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - rs6000_cannot_change_mode_class_ptr (FROM, TO, CLASS) - /* Stack layout; function entry, exit and calling. */ /* Define this if pushing a word on the stack Index: gcc/config/powerpcspe/powerpcspe-protos.h =================================================================== --- gcc/config/powerpcspe/powerpcspe-protos.h 2017-09-13 18:05:05.986123206 +0100 +++ gcc/config/powerpcspe/powerpcspe-protos.h 2017-09-13 20:12:03.774346865 +0100 @@ -109,9 +109,6 @@ extern enum reg_class (*rs6000_preferred extern enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class, machine_mode, rtx); -extern bool (*rs6000_cannot_change_mode_class_ptr) (machine_mode, - machine_mode, - enum reg_class); extern void rs6000_secondary_reload_inner (rtx, rtx, rtx, bool); extern void rs6000_secondary_reload_gpr (rtx, rtx, rtx, bool); extern int paired_emit_vector_cond_expr (rtx, rtx, rtx, Index: gcc/config/powerpcspe/powerpcspe.c =================================================================== --- gcc/config/powerpcspe/powerpcspe.c 2017-09-13 18:05:05.989748117 +0100 +++ gcc/config/powerpcspe/powerpcspe.c 2017-09-13 20:12:03.786129969 +0100 @@ -1387,12 +1387,9 @@ static enum reg_class rs6000_debug_prefe static bool rs6000_debug_secondary_memory_needed (machine_mode, reg_class_t, reg_class_t); -static bool rs6000_cannot_change_mode_class (machine_mode, - machine_mode, - enum reg_class); -static bool rs6000_debug_cannot_change_mode_class (machine_mode, - machine_mode, - enum reg_class); +static bool rs6000_debug_can_change_mode_class (machine_mode, + machine_mode, + reg_class_t); static bool rs6000_save_toc_in_prologue_p (void); static rtx rs6000_internal_arg_pointer (void); @@ -1410,11 +1407,6 @@ enum reg_class (*rs6000_secondary_reload enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx, enum reg_class) = rs6000_preferred_reload_class; -bool (*rs6000_cannot_change_mode_class_ptr) (machine_mode, - machine_mode, - enum reg_class) - = rs6000_cannot_change_mode_class; - const int INSN_NOT_AVAILABLE = -1; static void rs6000_print_isa_options (FILE *, int, const char *, @@ -1989,6 +1981,9 @@ #define TARGET_HARD_REGNO_CALL_PART_CLOB #undef TARGET_SLOW_UNALIGNED_ACCESS #define TARGET_SLOW_UNALIGNED_ACCESS rs6000_slow_unaligned_access + +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS rs6000_can_change_mode_class /* Processor table. */ @@ -5096,8 +5091,8 @@ rs6000_option_override_internal (bool gl = rs6000_debug_secondary_reload_class; targetm.secondary_memory_needed = rs6000_debug_secondary_memory_needed; - rs6000_cannot_change_mode_class_ptr - = rs6000_debug_cannot_change_mode_class; + targetm.can_change_mode_class + = rs6000_debug_can_change_mode_class; rs6000_preferred_reload_class_ptr = rs6000_debug_preferred_reload_class; rs6000_legitimize_reload_address_ptr @@ -23297,12 +23292,12 @@ rs6000_debug_secondary_reload_class (enu return ret; } -/* Return nonzero if for CLASS a mode change from FROM to TO is invalid. */ +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ static bool -rs6000_cannot_change_mode_class (machine_mode from, - machine_mode to, - enum reg_class rclass) +rs6000_can_change_mode_class (machine_mode from, + machine_mode to, + reg_class_t rclass) { unsigned from_size = GET_MODE_SIZE (from); unsigned to_size = GET_MODE_SIZE (to); @@ -23326,31 +23321,31 @@ rs6000_cannot_change_mode_class (machine values. */ if (to_float128_vector_p && from_float128_vector_p) - return false; + return true; else if (to_float128_vector_p || from_float128_vector_p) - return true; + return false; /* TDmode in floating-mode registers must always go into a register pair with the most significant word in the even-numbered register to match ISA requirements. In little-endian mode, this does not match subreg numbering, so we cannot allow subregs. */ if (!BYTES_BIG_ENDIAN && (to == TDmode || from == TDmode)) - return true; + return false; if (from_size < 8 || to_size < 8) - return true; + return false; if (from_size == 8 && (8 * to_nregs) != to_size) - return true; + return false; if (to_size == 8 && (8 * from_nregs) != from_size) - return true; + return false; - return false; + return true; } else - return false; + return true; } if (TARGET_E500_DOUBLE @@ -23361,7 +23356,7 @@ rs6000_cannot_change_mode_class (machine || (((to) == DDmode) + ((from) == DDmode)) == 1 || (((to) == TDmode) + ((from) == TDmode)) == 1 || (((to) == DImode) + ((from) == DImode)) == 1)) - return true; + return false; /* Since the VSX register set includes traditional floating point registers and altivec registers, just check for the size being different instead of @@ -23374,32 +23369,32 @@ rs6000_cannot_change_mode_class (machine unsigned num_regs = (from_size + 15) / 16; if (hard_regno_nregs (FIRST_FPR_REGNO, to) > num_regs || hard_regno_nregs (FIRST_FPR_REGNO, from) > num_regs) - return true; + return false; - return (from_size != 8 && from_size != 16); + return (from_size == 8 || from_size == 16); } if (TARGET_ALTIVEC && rclass == ALTIVEC_REGS && (ALTIVEC_VECTOR_MODE (from) + ALTIVEC_VECTOR_MODE (to)) == 1) - return true; + return false; if (TARGET_SPE && (SPE_VECTOR_MODE (from) + SPE_VECTOR_MODE (to)) == 1 && reg_classes_intersect_p (GENERAL_REGS, rclass)) - return true; + return false; - return false; + return true; } -/* Debug version of rs6000_cannot_change_mode_class. */ +/* Debug version of rs6000_can_change_mode_class. */ static bool -rs6000_debug_cannot_change_mode_class (machine_mode from, - machine_mode to, - enum reg_class rclass) +rs6000_debug_can_change_mode_class (machine_mode from, + machine_mode to, + reg_class_t rclass) { - bool ret = rs6000_cannot_change_mode_class (from, to, rclass); + bool ret = rs6000_can_change_mode_class (from, to, rclass); fprintf (stderr, - "rs6000_cannot_change_mode_class, return %s, from = %s, " + "rs6000_can_change_mode_class, return %s, from = %s, " "to = %s, rclass = %s\n", ret ? "true" : "false", GET_MODE_NAME (from), GET_MODE_NAME (to), Index: gcc/config/riscv/riscv.h =================================================================== --- gcc/config/riscv/riscv.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/riscv/riscv.h 2017-09-13 20:12:03.787942754 +0100 @@ -456,9 +456,6 @@ #define LUI_OPERAND(VALUE) \ (((VALUE) | ((1UL<<31) - IMM_REACH)) == ((1UL<<31) - IMM_REACH) \ || ((VALUE) | ((1UL<<31) - IMM_REACH)) + IMM_REACH == 0) -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - reg_classes_intersect_p (FP_REGS, CLASS) - /* Stack layout; function entry, exit and calling. */ #define STACK_GROWS_DOWNWARD 1 Index: gcc/config/riscv/riscv.c =================================================================== --- gcc/config/riscv/riscv.c 2017-09-13 18:05:05.990654345 +0100 +++ gcc/config/riscv/riscv.c 2017-09-13 20:12:03.787942754 +0100 @@ -3987,6 +3987,14 @@ riscv_slow_unaligned_access (machine_mod return riscv_slow_unaligned_access_p; } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ + +static bool +riscv_can_change_mode_class (machine_mode, machine_mode, reg_class_t rclass) +{ + return !reg_classes_intersect_p (FP_REGS, rclass); +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" @@ -4131,6 +4139,9 @@ #define TARGET_SLOW_UNALIGNED_ACCESS ris #undef TARGET_SECONDARY_MEMORY_NEEDED #define TARGET_SECONDARY_MEMORY_NEEDED riscv_secondary_memory_needed +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS riscv_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-riscv.h" Index: gcc/config/rs6000/rs6000.h =================================================================== --- gcc/config/rs6000/rs6000.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/rs6000/rs6000.h 2017-09-13 20:12:03.797913073 +0100 @@ -1514,11 +1514,6 @@ #define SECONDARY_RELOAD_CLASS(CLASS,MOD registers can hold 128 bits. */ #define CLASS_MAX_NREGS(CLASS, MODE) rs6000_class_max_nregs[(MODE)][(CLASS)] -/* Return nonzero if for CLASS a mode change from FROM to TO is invalid. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - rs6000_cannot_change_mode_class_ptr (FROM, TO, CLASS) - /* Stack layout; function entry, exit and calling. */ /* Define this if pushing a word on the stack Index: gcc/config/rs6000/rs6000-protos.h =================================================================== --- gcc/config/rs6000/rs6000-protos.h 2017-09-13 18:05:05.991560573 +0100 +++ gcc/config/rs6000/rs6000-protos.h 2017-09-13 20:12:03.787942754 +0100 @@ -110,9 +110,6 @@ extern enum reg_class (*rs6000_preferred extern enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class, machine_mode, rtx); -extern bool (*rs6000_cannot_change_mode_class_ptr) (machine_mode, - machine_mode, - enum reg_class); extern void rs6000_secondary_reload_inner (rtx, rtx, rtx, bool); extern void rs6000_secondary_reload_gpr (rtx, rtx, rtx, bool); extern int paired_emit_vector_cond_expr (rtx, rtx, rtx, Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c 2017-09-13 18:05:05.995185484 +0100 +++ gcc/config/rs6000/rs6000.c 2017-09-13 20:12:03.796100288 +0100 @@ -1392,12 +1392,9 @@ static enum reg_class rs6000_debug_prefe static bool rs6000_debug_secondary_memory_needed (machine_mode, reg_class_t, reg_class_t); -static bool rs6000_cannot_change_mode_class (machine_mode, - machine_mode, - enum reg_class); -static bool rs6000_debug_cannot_change_mode_class (machine_mode, - machine_mode, - enum reg_class); +static bool rs6000_debug_can_change_mode_class (machine_mode, + machine_mode, + reg_class_t); static bool rs6000_save_toc_in_prologue_p (void); static rtx rs6000_internal_arg_pointer (void); @@ -1415,11 +1412,6 @@ enum reg_class (*rs6000_secondary_reload enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx, enum reg_class) = rs6000_preferred_reload_class; -bool (*rs6000_cannot_change_mode_class_ptr) (machine_mode, - machine_mode, - enum reg_class) - = rs6000_cannot_change_mode_class; - const int INSN_NOT_AVAILABLE = -1; static void rs6000_print_isa_options (FILE *, int, const char *, @@ -1979,6 +1971,9 @@ #define TARGET_HARD_REGNO_CALL_PART_CLOB #undef TARGET_SLOW_UNALIGNED_ACCESS #define TARGET_SLOW_UNALIGNED_ACCESS rs6000_slow_unaligned_access + +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS rs6000_can_change_mode_class /* Processor table. */ @@ -4714,8 +4709,8 @@ rs6000_option_override_internal (bool gl = rs6000_debug_secondary_reload_class; targetm.secondary_memory_needed = rs6000_debug_secondary_memory_needed; - rs6000_cannot_change_mode_class_ptr - = rs6000_debug_cannot_change_mode_class; + targetm.can_change_mode_class + = rs6000_debug_can_change_mode_class; rs6000_preferred_reload_class_ptr = rs6000_debug_preferred_reload_class; rs6000_legitimize_reload_address_ptr @@ -20639,12 +20634,12 @@ rs6000_debug_secondary_reload_class (enu return ret; } -/* Return nonzero if for CLASS a mode change from FROM to TO is invalid. */ +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ static bool -rs6000_cannot_change_mode_class (machine_mode from, - machine_mode to, - enum reg_class rclass) +rs6000_can_change_mode_class (machine_mode from, + machine_mode to, + reg_class_t rclass) { unsigned from_size = GET_MODE_SIZE (from); unsigned to_size = GET_MODE_SIZE (to); @@ -20668,31 +20663,31 @@ rs6000_cannot_change_mode_class (machine values. */ if (to_float128_vector_p && from_float128_vector_p) - return false; + return true; else if (to_float128_vector_p || from_float128_vector_p) - return true; + return false; /* TDmode in floating-mode registers must always go into a register pair with the most significant word in the even-numbered register to match ISA requirements. In little-endian mode, this does not match subreg numbering, so we cannot allow subregs. */ if (!BYTES_BIG_ENDIAN && (to == TDmode || from == TDmode)) - return true; + return false; if (from_size < 8 || to_size < 8) - return true; + return false; if (from_size == 8 && (8 * to_nregs) != to_size) - return true; + return false; if (to_size == 8 && (8 * from_nregs) != from_size) - return true; + return false; - return false; + return true; } else - return false; + return true; } /* Since the VSX register set includes traditional floating point registers @@ -20706,28 +20701,28 @@ rs6000_cannot_change_mode_class (machine unsigned num_regs = (from_size + 15) / 16; if (hard_regno_nregs (FIRST_FPR_REGNO, to) > num_regs || hard_regno_nregs (FIRST_FPR_REGNO, from) > num_regs) - return true; + return false; - return (from_size != 8 && from_size != 16); + return (from_size == 8 || from_size == 16); } if (TARGET_ALTIVEC && rclass == ALTIVEC_REGS && (ALTIVEC_VECTOR_MODE (from) + ALTIVEC_VECTOR_MODE (to)) == 1) - return true; + return false; - return false; + return true; } -/* Debug version of rs6000_cannot_change_mode_class. */ +/* Debug version of rs6000_can_change_mode_class. */ static bool -rs6000_debug_cannot_change_mode_class (machine_mode from, - machine_mode to, - enum reg_class rclass) +rs6000_debug_can_change_mode_class (machine_mode from, + machine_mode to, + reg_class_t rclass) { - bool ret = rs6000_cannot_change_mode_class (from, to, rclass); + bool ret = rs6000_can_change_mode_class (from, to, rclass); fprintf (stderr, - "rs6000_cannot_change_mode_class, return %s, from = %s, " + "rs6000_can_change_mode_class, return %s, from = %s, " "to = %s, rclass = %s\n", ret ? "true" : "false", GET_MODE_NAME (from), GET_MODE_NAME (to), Index: gcc/config/s390/s390.h =================================================================== --- gcc/config/s390/s390.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/s390/s390.h 2017-09-13 20:12:03.801538644 +0100 @@ -477,9 +477,6 @@ #define HARD_REGNO_RENAME_OK(FROM, TO) #define CLASS_MAX_NREGS(CLASS, MODE) \ s390_class_max_nregs ((CLASS), (MODE)) -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - s390_cannot_change_mode_class ((FROM), (TO), (CLASS)) - /* We can reverse a CC mode safely if we know whether it comes from a floating point compare or not. With the vector modes it is encoded as part of the mode. Index: gcc/config/s390/s390-protos.h =================================================================== --- gcc/config/s390/s390-protos.h 2017-09-04 11:49:42.926500723 +0100 +++ gcc/config/s390/s390-protos.h 2017-09-13 20:12:03.797913073 +0100 @@ -49,8 +49,6 @@ extern void s390_function_profiler (FILE extern void s390_set_has_landing_pad_p (bool); extern bool s390_hard_regno_rename_ok (unsigned int, unsigned int); extern int s390_class_max_nregs (enum reg_class, machine_mode); -extern int s390_cannot_change_mode_class (machine_mode, machine_mode, - enum reg_class); extern bool s390_function_arg_vector (machine_mode, const_tree); #if S390_USE_TARGET_ATTRIBUTE extern tree s390_valid_target_attribute_tree (tree args, Index: gcc/config/s390/s390.c =================================================================== --- gcc/config/s390/s390.c 2017-09-13 18:05:05.996091712 +0100 +++ gcc/config/s390/s390.c 2017-09-13 20:12:03.801538644 +0100 @@ -10630,13 +10630,12 @@ s390_class_max_nregs (enum reg_class rcl return (GET_MODE_SIZE (mode) + reg_size - 1) / reg_size; } -/* Return TRUE if changing mode from FROM to TO should not be allowed - for register class CLASS. */ +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ -int -s390_cannot_change_mode_class (machine_mode from_mode, - machine_mode to_mode, - enum reg_class rclass) +static bool +s390_can_change_mode_class (machine_mode from_mode, + machine_mode to_mode, + reg_class_t rclass) { machine_mode small_mode; machine_mode big_mode; @@ -10646,10 +10645,10 @@ s390_cannot_change_mode_class (machine_m if (reg_classes_intersect_p (VEC_REGS, rclass) && ((from_mode == V1TFmode && to_mode == TFmode) || (from_mode == TFmode && to_mode == V1TFmode))) - return 1; + return false; if (GET_MODE_SIZE (from_mode) == GET_MODE_SIZE (to_mode)) - return 0; + return true; if (GET_MODE_SIZE (from_mode) < GET_MODE_SIZE (to_mode)) { @@ -10672,14 +10671,14 @@ s390_cannot_change_mode_class (machine_m if (reg_classes_intersect_p (VEC_REGS, rclass) && (GET_MODE_SIZE (small_mode) < 8 || s390_class_max_nregs (VEC_REGS, big_mode) == 1)) - return 1; + return false; /* Likewise for access registers, since they have only half the word size on 64-bit. */ if (reg_classes_intersect_p (ACCESS_REGS, rclass)) - return 1; + return false; - return 0; + return true; } /* Return true if we use LRA instead of reload pass. */ @@ -16115,6 +16114,9 @@ #define TARGET_CAN_INLINE_P s390_can_inl #undef TARGET_OPTION_RESTORE #define TARGET_OPTION_RESTORE s390_function_specific_restore +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS s390_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-s390.h" Index: gcc/config/sh/sh.h =================================================================== --- gcc/config/sh/sh.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/sh/sh.h 2017-09-13 20:12:03.805164214 +0100 @@ -1087,13 +1087,6 @@ #define ZERO_EXTRACT_ANDMASK(EXTRACT_SZ_ Otherwise we will need at most one register per word. */ #define CLASS_MAX_NREGS(CLASS, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) - -/* If defined, gives a class of registers that cannot be used as the - operand of a SUBREG that changes the mode of the object illegally. - ??? We need to renumber the internal numbers for the frnn registers - when in little endian in order to allow mode size changes. */ -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - sh_cannot_change_mode_class (FROM, TO, CLASS) /* Stack layout; function entry, exit and calling. */ Index: gcc/config/sh/sh-protos.h =================================================================== --- gcc/config/sh/sh-protos.h 2017-09-04 11:49:42.928500723 +0100 +++ gcc/config/sh/sh-protos.h 2017-09-13 20:12:03.802445036 +0100 @@ -324,8 +324,6 @@ extern bool sh_cfun_interrupt_handler_p extern bool sh_cfun_resbank_handler_p (void); extern bool sh_attr_renesas_p (const_tree); extern bool sh_cfun_attr_renesas_p (void); -extern bool sh_cannot_change_mode_class - (machine_mode, machine_mode, enum reg_class); extern bool sh_small_register_classes_for_mode_p (machine_mode); extern void sh_mark_label (rtx, int); extern bool check_use_sfunc_addr (rtx_insn *, rtx); Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c 2017-09-12 14:29:25.258529622 +0100 +++ gcc/config/sh/sh.c 2017-09-13 20:12:03.804257821 +0100 @@ -325,6 +325,7 @@ static void sh_init_sync_libfuncs (void) static unsigned int sh_hard_regno_nregs (unsigned int, machine_mode); static bool sh_hard_regno_mode_ok (unsigned int, machine_mode); static bool sh_modes_tieable_p (machine_mode, machine_mode); +static bool sh_can_change_mode_class (machine_mode, machine_mode, reg_class_t); static const struct attribute_spec sh_attribute_table[] = { @@ -653,6 +654,9 @@ #define TARGET_HARD_REGNO_MODE_OK sh_har #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P sh_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS sh_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; @@ -10628,11 +10632,10 @@ sh_hard_regno_caller_save_mode (unsigned return choose_hard_reg_mode (regno, nregs, false); } -/* Return the class of registers for which a mode change from FROM to TO - is invalid. */ -bool -sh_cannot_change_mode_class (machine_mode from, machine_mode to, - enum reg_class rclass) +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */ +static bool +sh_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) { /* We want to enable the use of SUBREGs as a means to VEC_SELECT a single element of a vector. */ @@ -10642,22 +10645,22 @@ sh_cannot_change_mode_class (machine_mod on the stack with displacement addressing, as it happens with -O0. Thus we disallow the mode change for -O0. */ if (to == SFmode && VECTOR_MODE_P (from) && GET_MODE_INNER (from) == SFmode) - return optimize ? (reg_classes_intersect_p (GENERAL_REGS, rclass)) : false; + return optimize ? !reg_classes_intersect_p (GENERAL_REGS, rclass) : true; if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to)) { if (TARGET_LITTLE_ENDIAN) { if (GET_MODE_SIZE (to) < 8 || GET_MODE_SIZE (from) < 8) - return reg_classes_intersect_p (DF_REGS, rclass); + return !reg_classes_intersect_p (DF_REGS, rclass); } else { if (GET_MODE_SIZE (from) < 8) - return reg_classes_intersect_p (DF_REGS, rclass); + return !reg_classes_intersect_p (DF_REGS, rclass); } } - return false; + return true; } /* Return true if registers in machine mode MODE will likely be Index: gcc/config/sparc/sparc.h =================================================================== --- gcc/config/sparc/sparc.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/sparc/sparc.h 2017-09-13 20:12:03.807883392 +0100 @@ -907,23 +907,6 @@ #define REG_CLASS_CONTENTS \ #define REGNO_REG_CLASS(REGNO) sparc_regno_reg_class[(REGNO)] -/* Defines invalid mode changes. Borrowed from the PA port. - - SImode loads to floating-point registers are not zero-extended. - The definition for LOAD_EXTEND_OP specifies that integer loads - narrower than BITS_PER_WORD will be zero-extended. As a result, - we inhibit changes from SImode unless they are to a mode that is - identical in size. - - Likewise for SFmode, since word-mode paradoxical subregs are - problematic on big-endian architectures. */ - -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - (TARGET_ARCH64 \ - && GET_MODE_SIZE (FROM) == 4 \ - && GET_MODE_SIZE (TO) != 4 \ - ? reg_classes_intersect_p (CLASS, FP_REGS) : 0) - /* This is the order in which to allocate registers normally. We put %f0-%f7 last among the float registers, so as to make it more Index: gcc/config/sparc/sparc.c =================================================================== --- gcc/config/sparc/sparc.c 2017-09-13 18:05:05.996997939 +0100 +++ gcc/config/sparc/sparc.c 2017-09-13 20:12:03.807883392 +0100 @@ -682,7 +682,8 @@ static unsigned int sparc_min_arithmetic static unsigned int sparc_hard_regno_nregs (unsigned int, machine_mode); static bool sparc_hard_regno_mode_ok (unsigned int, machine_mode); static bool sparc_modes_tieable_p (machine_mode, machine_mode); - +static bool sparc_can_change_mode_class (machine_mode, machine_mode, + reg_class_t); #ifdef SUBTARGET_ATTRIBUTE_TABLE /* Table of valid machine attributes. */ @@ -921,6 +922,9 @@ #define TARGET_HARD_REGNO_MODE_OK sparc_ #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P sparc_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS sparc_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; /* Return the memory reference contained in X if any, zero otherwise. */ @@ -13400,4 +13404,26 @@ sparc_atomic_assign_expand_fenv (tree *h = compound_expr (compound_expr (update_stfsr, update_ldfsr), update_call); } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. Borrowed from the PA port. + + SImode loads to floating-point registers are not zero-extended. + The definition for LOAD_EXTEND_OP specifies that integer loads + narrower than BITS_PER_WORD will be zero-extended. As a result, + we inhibit changes from SImode unless they are to a mode that is + identical in size. + + Likewise for SFmode, since word-mode paradoxical subregs are + problematic on big-endian architectures. */ + +static bool +sparc_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) +{ + if (TARGET_ARCH64 + && GET_MODE_SIZE (from) == 4 + && GET_MODE_SIZE (to) != 4) + return !reg_classes_intersect_p (rclass, FP_REGS); + return true; +} + #include "gt-sparc.h" Index: gcc/config/spu/spu.h =================================================================== --- gcc/config/spu/spu.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/spu/spu.h 2017-09-13 20:12:03.810602570 +0100 @@ -211,13 +211,6 @@ #define INT_REG_OK_FOR_INDEX_P(X,STRICT) #define INT_REG_OK_FOR_BASE_P(X,STRICT) \ ((!(STRICT) || REGNO_OK_FOR_BASE_P (REGNO (X)))) -/* GCC assumes that modes are in the lowpart of a register, which is - only true for SPU. */ -#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ - ((GET_MODE_SIZE (FROM) > 4 || GET_MODE_SIZE (TO) > 4) \ - && (GET_MODE_SIZE (FROM) < 16 || GET_MODE_SIZE (TO) < 16) \ - && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) - #define REGISTER_TARGET_PRAGMAS() do { \ c_register_addr_space ("__ea", ADDR_SPACE_EA); \ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \ Index: gcc/config/spu/spu.c =================================================================== --- gcc/config/spu/spu.c 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/spu/spu.c 2017-09-13 20:12:03.810602570 +0100 @@ -7162,6 +7162,17 @@ spu_modes_tieable_p (machine_mode mode1, return (GET_MODE_BITSIZE (mode1) <= MAX_FIXED_MODE_SIZE && GET_MODE_BITSIZE (mode2) <= MAX_FIXED_MODE_SIZE); } + +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. GCC assumes that modes are + in the lowpart of a register, which is only true for SPU. */ + +static bool +spu_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t) +{ + return (GET_MODE_SIZE (from) == GET_MODE_SIZE (to) + || (GET_MODE_SIZE (from) <= 4 && GET_MODE_SIZE (to) <= 4) + || (GET_MODE_SIZE (from) >= 16 && GET_MODE_SIZE (to) >= 16)); +} /* Table of machine attributes. */ static const struct attribute_spec spu_attribute_table[] = @@ -7393,6 +7404,9 @@ #define TARGET_MODES_TIEABLE_P spu_modes #undef TARGET_HARD_REGNO_NREGS #define TARGET_HARD_REGNO_NREGS spu_hard_regno_nregs +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS spu_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-spu.h" Index: gcc/config/visium/visium.h =================================================================== --- gcc/config/visium/visium.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/config/visium/visium.h 2017-09-13 20:12:03.812415355 +0100 @@ -723,24 +723,6 @@ #define REGNO_OK_FOR_INDEX_P(REGNO) 0 registers. */ #define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS -/* `CANNOT_CHANGE_MODE_CLASS (from, to, class) - - If defined, a C expression that returns nonzero for a `class' for - which a change from mode `from' to mode `to' is invalid. - - It's not obvious from the above that MDB cannot change mode. However - difficulties arise from expressions of the form - - (subreg:SI (reg:DI R_MDB) 0) - - There is no way to convert that reference to a single machine - register and, without the following definition, reload will quietly - convert it to - - (reg:SI R_MDB) */ -#define CANNOT_CHANGE_MODE_CLASS(FROM,TO,CLASS) \ - (CLASS == MDB ? (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) : 0) - #define CLASS_MAX_NREGS(CLASS, MODE) \ ((CLASS) == MDB ? \ ((GET_MODE_SIZE (MODE) + 2 * UNITS_PER_WORD - 1) / (2 * UNITS_PER_WORD)) \ Index: gcc/config/visium/visium.c =================================================================== --- gcc/config/visium/visium.c 2017-09-12 14:29:25.261529490 +0100 +++ gcc/config/visium/visium.c 2017-09-13 20:12:03.811508962 +0100 @@ -234,6 +234,9 @@ static bool visium_hard_regno_mode_ok (u static bool visium_modes_tieable_p (machine_mode, machine_mode); +static bool visium_can_change_mode_class (machine_mode, machine_mode, + reg_class_t); + /* Setup the global target hooks structure. */ #undef TARGET_MAX_ANCHOR_OFFSET @@ -354,6 +357,9 @@ #define TARGET_HARD_REGNO_MODE_OK visium #undef TARGET_MODES_TIEABLE_P #define TARGET_MODES_TIEABLE_P visium_modes_tieable_p +#undef TARGET_CAN_CHANGE_MODE_CLASS +#define TARGET_CAN_CHANGE_MODE_CLASS visium_can_change_mode_class + struct gcc_target targetm = TARGET_INITIALIZER; namespace { @@ -4293,4 +4299,24 @@ reg_or_subreg_regno (rtx op) return regno; } +/* Implement TARGET_CAN_CHANGE_MODE_CLASS. + + It's not obvious from the documentation of the hook that MDB cannot + change mode. However difficulties arise from expressions of the form + + (subreg:SI (reg:DI R_MDB) 0) + + There is no way to convert that reference to a single machine + register and, without the following definition, reload will quietly + convert it to + + (reg:SI R_MDB). */ + +static bool +visium_can_change_mode_class (machine_mode from, machine_mode to, + reg_class_t rclass) +{ + return (rclass != MDB || GET_MODE_SIZE (from) == GET_MODE_SIZE (to)); +} + #include "gt-visium.h" Index: gcc/system.h =================================================================== --- gcc/system.h 2017-09-13 20:11:42.906469581 +0100 +++ gcc/system.h 2017-09-13 20:12:03.827824030 +0100 @@ -914,7 +914,7 @@ #define realloc xrealloc HARD_REGNO_CALL_PART_CLOBBERED HARD_REGNO_MODE_OK \ MODES_TIEABLE_P FUNCTION_ARG_PADDING SLOW_UNALIGNED_ACCESS \ HARD_REGNO_NREGS SECONDARY_MEMORY_NEEDED_MODE \ - SECONDARY_MEMORY_NEEDED + SECONDARY_MEMORY_NEEDED CANNOT_CHANGE_MODE_CLASS /* Target macros only used for code built for the target, that have moved to libgcc-tm.h or have never been present elsewhere. */