diff mbox series

Turn CANNOT_CHANGE_MODE_CLASS into a hook

Message ID 87bmmebe3m.fsf@linaro.org
State New
Headers show
Series Turn CANNOT_CHANGE_MODE_CLASS into a hook | expand

Commit Message

Richard Sandiford Sept. 13, 2017, 7:19 p.m. UTC
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  <richard.sandiford@linaro.org>
	    Alan Hayard  <alan.hayward@arm.com>
	    David Sherwood  <david.sherwood@arm.com>

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.

Comments

Jeff Law Sept. 14, 2017, 5:05 p.m. UTC | #1
On 09/13/2017 01:19 PM, Richard Sandiford wrote:
> This also seemed like a good opportunity to reverse the sense of the
> hook to "can", to avoid the awkward double negative in !CANNOT.
Yea.  The double-negatives can sometimes make code hard to read.


> 
> 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  <richard.sandiford@linaro.org>
> 	    Alan Hayard  <alan.hayward@arm.com>
> 	    David Sherwood  <david.sherwood@arm.com>
> 
> 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.
OK.

I don't know how many more conversions to hooks are in your queue, but
if you've got more and they're semantic preserving, then the review step
is not adding much value.  Consider them pre-approved.  Post for the
archives and commit.


Jeff
Richard Sandiford Sept. 15, 2017, 12:02 p.m. UTC | #2
Jeff Law <law@redhat.com> writes:
> On 09/13/2017 01:19 PM, Richard Sandiford wrote:
>> 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  <richard.sandiford@linaro.org>
>> 	    Alan Hayard  <alan.hayward@arm.com>
>> 	    David Sherwood  <david.sherwood@arm.com>
>> 
>> 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.
> OK.
>
> I don't know how many more conversions to hooks are in your queue, but
> if you've got more and they're semantic preserving, then the review step
> is not adding much value.  Consider them pre-approved.  Post for the
> archives and commit.

Thanks, and thanks for reviewing such dull patches :-)  This was actually
the last of the target hook conversions we had, but it's possible that
we might end up needing more before SVE lands, depending on what changes
happen to other ports.

(We also have patches to change the interface of some existing target hooks,
but that's much easier than converting from a target macro.)

Richard
diff mbox series

Patch

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.  */