[06/77] Make GET_MODE_WIDER return an opt_mode

Message ID 87fue0n317.fsf@linaro.org
State New
Headers show
Series
  • Add wrapper classes for machine_modes
Related show

Commit Message

Richard Sandiford July 13, 2017, 8:40 a.m.
GET_MODE_WIDER previously returned VOIDmode if no wider mode existed.
That would cause problems with stricter mode classes, since VOIDmode
isn't for example a valid scalar integer or floating-point mode.
This patch instead makes it return a new opt_mode<T> class, which
holds either a T or nothing.

2017-07-13  Richard Sandiford  <richard.sandiford@linaro.org>
	    Alan Hayward  <alan.hayward@arm.com>
	    David Sherwood  <david.sherwood@arm.com>

gcc/
	* coretypes.h (opt_mode): New class.
	* machmode.h (opt_mode): Likewise.
	(opt_mode::else_void): New function.
	(opt_mode::operator *): Likewise.
	(opt_mode::exists): Likewise.
	(GET_MODE_WIDER_MODE): Turn into a function and return an opt_mode.
	(GET_MODE_2XWIDER_MODE): Likewise.
	(mode_iterator::get_wider): Update accordingly.
	(mode_iterator::get_2xwider): Likewise.
	(mode_iterator::get_known_wider): Likewise, turning into a template.
	* combine.c (make_extraction): Update use of GET_MODE_WIDER_MODE,
	forcing a wider mode to exist.
	* config/cr16/cr16.h (LONG_REG_P): Likewise.
	* rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise.
	* config/c6x/c6x.c (c6x_rtx_costs): Update use of
	GET_MODE_2XWIDER_MODE, forcing a wider mode to exist.
	* lower-subreg.c (init_lower_subreg): Likewise.
	* optabs-libfuncs.c (init_sync_libfuncs_1): Likewise, but not
	on the final iteration.
	* config/i386/i386.c (ix86_expand_set_or_movmem): Check whether
	a wider mode exists before asking for a move pattern.
	(get_mode_wider_vector): Update use of GET_MODE_WIDER_MODE,
	forcing a wider mode to exist.
	(expand_vselect_vconcat): Update use of GET_MODE_2XWIDER_MODE,
	returning false if no such mode exists.
	* config/ia64/ia64.c (expand_vselect_vconcat): Likewise.
	* config/mips/mips.c (mips_expand_vselect_vconcat): Likewise.
	* expmed.c (init_expmed_one_mode): Update use of GET_MODE_WIDER_MODE.
	Avoid checking for a MODE_INT if we already know the mode is not a
	SCALAR_INT_MODE_P.
	(extract_high_half): Update use of GET_MODE_WIDER_MODE,
	forcing a wider mode to exist.
	(expmed_mult_highpart_optab): Likewise.
	(expmed_mult_highpart): Likewise.
	* expr.c (expand_expr_real_2): Update use of GET_MODE_WIDER_MODE,
	using else_void.
	* lto-streamer-in.c (lto_input_mode_table): Likewise.
	* optabs-query.c (find_widening_optab_handler_and_mode): Likewise.
	* stor-layout.c (bit_field_mode_iterator::next_mode): Likewise.
	* internal-fn.c (expand_mul_overflow): Update use of
	GET_MODE_2XWIDER_MODE.
	* omp-low.c (omp_clause_aligned_alignment): Likewise.
	* tree-ssa-math-opts.c (convert_mult_to_widen): Update use of
	GET_MODE_WIDER_MODE.
	(convert_plusminus_to_widen): Likewise.
	* tree-switch-conversion.c (array_value_type): Likewise.
	* var-tracking.c (emit_note_insn_var_location): Likewise.
	* tree-vrp.c (simplify_float_conversion_using_ranges): Likewise.
	Return false inside rather than outside the loop if no wider mode
	exists
	* optabs.c (expand_binop): Update use of GET_MODE_WIDER_MODE
	and GET_MODE_2XWIDER_MODE
	(can_compare_p): Use else_void.
	* gdbhooks.py (OptMachineModePrinter): New class.
	(build_pretty_printer): Use it for opt_mode.

gcc/ada/
	* gcc-interface/decl.c (validate_size): Update use of
	GET_MODE_WIDER_MODE, forcing a wider mode to exist.

Comments

Jeff Law Aug. 11, 2017, 6:05 p.m. | #1
On 07/13/2017 02:40 AM, Richard Sandiford wrote:
> GET_MODE_WIDER previously returned VOIDmode if no wider mode existed.

> That would cause problems with stricter mode classes, since VOIDmode

> isn't for example a valid scalar integer or floating-point mode.

> This patch instead makes it return a new opt_mode<T> class, which

> holds either a T or nothing.

> 

> 2017-07-13  Richard Sandiford  <richard.sandiford@linaro.org>

> 	    Alan Hayward  <alan.hayward@arm.com>

> 	    David Sherwood  <david.sherwood@arm.com>

> 

> gcc/

> 	* coretypes.h (opt_mode): New class.

> 	* machmode.h (opt_mode): Likewise.

> 	(opt_mode::else_void): New function.

> 	(opt_mode::operator *): Likewise.

> 	(opt_mode::exists): Likewise.

> 	(GET_MODE_WIDER_MODE): Turn into a function and return an opt_mode.

> 	(GET_MODE_2XWIDER_MODE): Likewise.

> 	(mode_iterator::get_wider): Update accordingly.

> 	(mode_iterator::get_2xwider): Likewise.

> 	(mode_iterator::get_known_wider): Likewise, turning into a template.

> 	* combine.c (make_extraction): Update use of GET_MODE_WIDER_MODE,

> 	forcing a wider mode to exist.

> 	* config/cr16/cr16.h (LONG_REG_P): Likewise.

> 	* rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise.

> 	* config/c6x/c6x.c (c6x_rtx_costs): Update use of

> 	GET_MODE_2XWIDER_MODE, forcing a wider mode to exist.

> 	* lower-subreg.c (init_lower_subreg): Likewise.

> 	* optabs-libfuncs.c (init_sync_libfuncs_1): Likewise, but not

> 	on the final iteration.

> 	* config/i386/i386.c (ix86_expand_set_or_movmem): Check whether

> 	a wider mode exists before asking for a move pattern.

> 	(get_mode_wider_vector): Update use of GET_MODE_WIDER_MODE,

> 	forcing a wider mode to exist.

> 	(expand_vselect_vconcat): Update use of GET_MODE_2XWIDER_MODE,

> 	returning false if no such mode exists.

> 	* config/ia64/ia64.c (expand_vselect_vconcat): Likewise.

> 	* config/mips/mips.c (mips_expand_vselect_vconcat): Likewise.

> 	* expmed.c (init_expmed_one_mode): Update use of GET_MODE_WIDER_MODE.

> 	Avoid checking for a MODE_INT if we already know the mode is not a

> 	SCALAR_INT_MODE_P.

> 	(extract_high_half): Update use of GET_MODE_WIDER_MODE,

> 	forcing a wider mode to exist.

> 	(expmed_mult_highpart_optab): Likewise.

> 	(expmed_mult_highpart): Likewise.

> 	* expr.c (expand_expr_real_2): Update use of GET_MODE_WIDER_MODE,

> 	using else_void.

> 	* lto-streamer-in.c (lto_input_mode_table): Likewise.

> 	* optabs-query.c (find_widening_optab_handler_and_mode): Likewise.

> 	* stor-layout.c (bit_field_mode_iterator::next_mode): Likewise.

> 	* internal-fn.c (expand_mul_overflow): Update use of

> 	GET_MODE_2XWIDER_MODE.

> 	* omp-low.c (omp_clause_aligned_alignment): Likewise.

> 	* tree-ssa-math-opts.c (convert_mult_to_widen): Update use of

> 	GET_MODE_WIDER_MODE.

> 	(convert_plusminus_to_widen): Likewise.

> 	* tree-switch-conversion.c (array_value_type): Likewise.

> 	* var-tracking.c (emit_note_insn_var_location): Likewise.

> 	* tree-vrp.c (simplify_float_conversion_using_ranges): Likewise.

> 	Return false inside rather than outside the loop if no wider mode

> 	exists

> 	* optabs.c (expand_binop): Update use of GET_MODE_WIDER_MODE

> 	and GET_MODE_2XWIDER_MODE

> 	(can_compare_p): Use else_void.

> 	* gdbhooks.py (OptMachineModePrinter): New class.

> 	(build_pretty_printer): Use it for opt_mode.

> 

> gcc/ada/

> 	* gcc-interface/decl.c (validate_size): Update use of

> 	GET_MODE_WIDER_MODE, forcing a wider mode to exist.

I'm not a big fan of the API here, particularly using operator* to
handle asserting the mode exists.  I'd prefer to just use a member
function rather than overloading operator*.

What's the rationale behind using operator* to imply the assertion?

THe changes themsleves look fine, it's really just a question of the API
we present.

jeff
Richard Sandiford Aug. 11, 2017, 6:24 p.m. | #2
Jeff Law <law@redhat.com> writes:
> On 07/13/2017 02:40 AM, Richard Sandiford wrote:

>> GET_MODE_WIDER previously returned VOIDmode if no wider mode existed.

>> That would cause problems with stricter mode classes, since VOIDmode

>> isn't for example a valid scalar integer or floating-point mode.

>> This patch instead makes it return a new opt_mode<T> class, which

>> holds either a T or nothing.

>> 

>> 2017-07-13  Richard Sandiford  <richard.sandiford@linaro.org>

>> 	    Alan Hayward  <alan.hayward@arm.com>

>> 	    David Sherwood  <david.sherwood@arm.com>

>> 

>> gcc/

>> 	* coretypes.h (opt_mode): New class.

>> 	* machmode.h (opt_mode): Likewise.

>> 	(opt_mode::else_void): New function.

>> 	(opt_mode::operator *): Likewise.

>> 	(opt_mode::exists): Likewise.

>> 	(GET_MODE_WIDER_MODE): Turn into a function and return an opt_mode.

>> 	(GET_MODE_2XWIDER_MODE): Likewise.

>> 	(mode_iterator::get_wider): Update accordingly.

>> 	(mode_iterator::get_2xwider): Likewise.

>> 	(mode_iterator::get_known_wider): Likewise, turning into a template.

>> 	* combine.c (make_extraction): Update use of GET_MODE_WIDER_MODE,

>> 	forcing a wider mode to exist.

>> 	* config/cr16/cr16.h (LONG_REG_P): Likewise.

>> 	* rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise.

>> 	* config/c6x/c6x.c (c6x_rtx_costs): Update use of

>> 	GET_MODE_2XWIDER_MODE, forcing a wider mode to exist.

>> 	* lower-subreg.c (init_lower_subreg): Likewise.

>> 	* optabs-libfuncs.c (init_sync_libfuncs_1): Likewise, but not

>> 	on the final iteration.

>> 	* config/i386/i386.c (ix86_expand_set_or_movmem): Check whether

>> 	a wider mode exists before asking for a move pattern.

>> 	(get_mode_wider_vector): Update use of GET_MODE_WIDER_MODE,

>> 	forcing a wider mode to exist.

>> 	(expand_vselect_vconcat): Update use of GET_MODE_2XWIDER_MODE,

>> 	returning false if no such mode exists.

>> 	* config/ia64/ia64.c (expand_vselect_vconcat): Likewise.

>> 	* config/mips/mips.c (mips_expand_vselect_vconcat): Likewise.

>> 	* expmed.c (init_expmed_one_mode): Update use of GET_MODE_WIDER_MODE.

>> 	Avoid checking for a MODE_INT if we already know the mode is not a

>> 	SCALAR_INT_MODE_P.

>> 	(extract_high_half): Update use of GET_MODE_WIDER_MODE,

>> 	forcing a wider mode to exist.

>> 	(expmed_mult_highpart_optab): Likewise.

>> 	(expmed_mult_highpart): Likewise.

>> 	* expr.c (expand_expr_real_2): Update use of GET_MODE_WIDER_MODE,

>> 	using else_void.

>> 	* lto-streamer-in.c (lto_input_mode_table): Likewise.

>> 	* optabs-query.c (find_widening_optab_handler_and_mode): Likewise.

>> 	* stor-layout.c (bit_field_mode_iterator::next_mode): Likewise.

>> 	* internal-fn.c (expand_mul_overflow): Update use of

>> 	GET_MODE_2XWIDER_MODE.

>> 	* omp-low.c (omp_clause_aligned_alignment): Likewise.

>> 	* tree-ssa-math-opts.c (convert_mult_to_widen): Update use of

>> 	GET_MODE_WIDER_MODE.

>> 	(convert_plusminus_to_widen): Likewise.

>> 	* tree-switch-conversion.c (array_value_type): Likewise.

>> 	* var-tracking.c (emit_note_insn_var_location): Likewise.

>> 	* tree-vrp.c (simplify_float_conversion_using_ranges): Likewise.

>> 	Return false inside rather than outside the loop if no wider mode

>> 	exists

>> 	* optabs.c (expand_binop): Update use of GET_MODE_WIDER_MODE

>> 	and GET_MODE_2XWIDER_MODE

>> 	(can_compare_p): Use else_void.

>> 	* gdbhooks.py (OptMachineModePrinter): New class.

>> 	(build_pretty_printer): Use it for opt_mode.

>> 

>> gcc/ada/

>> 	* gcc-interface/decl.c (validate_size): Update use of

>> 	GET_MODE_WIDER_MODE, forcing a wider mode to exist.

> I'm not a big fan of the API here, particularly using operator* to

> handle asserting the mode exists.  I'd prefer to just use a member

> function rather than overloading operator*.

>

> What's the rationale behind using operator* to imply the assertion?

>

> THe changes themsleves look fine, it's really just a question of the API

> we present.


The original idea was to make opt_mode look pointer-ish, so that
the dyn_cast <...> result could be used in the same way as for
dyn_cast <gassign *> etc.  The first cut therefore had operator bool ()
to test whether there was a mode and operator * to dereference it.

However, operator bool () created various subtle problems (as it always
seems to) so we dropped it in favour of exists ().  I was neutral
on whether we should keep '*' or switch to a function, so in the
end the status quo won out.  I'm happy to change it to a named
accessor though.

Any better ideas than "get ()" for the name?  Maybe something
to emphasis that it is asserting for non-nullness/non-emptiness
(which '*' does implicitly)?

Thanks,
Richard
Jeff Law Aug. 28, 2017, 5:57 p.m. | #3
On 08/11/2017 12:24 PM, Richard Sandiford wrote:
> Jeff Law <law@redhat.com> writes:

>> On 07/13/2017 02:40 AM, Richard Sandiford wrote:

>>> GET_MODE_WIDER previously returned VOIDmode if no wider mode existed.

>>> That would cause problems with stricter mode classes, since VOIDmode

>>> isn't for example a valid scalar integer or floating-point mode.

>>> This patch instead makes it return a new opt_mode<T> class, which

>>> holds either a T or nothing.

>>>

>>> 2017-07-13  Richard Sandiford  <richard.sandiford@linaro.org>

>>> 	    Alan Hayward  <alan.hayward@arm.com>

>>> 	    David Sherwood  <david.sherwood@arm.com>

>>>

>>> gcc/

>>> 	* coretypes.h (opt_mode): New class.

>>> 	* machmode.h (opt_mode): Likewise.

>>> 	(opt_mode::else_void): New function.

>>> 	(opt_mode::operator *): Likewise.

>>> 	(opt_mode::exists): Likewise.

>>> 	(GET_MODE_WIDER_MODE): Turn into a function and return an opt_mode.

>>> 	(GET_MODE_2XWIDER_MODE): Likewise.

>>> 	(mode_iterator::get_wider): Update accordingly.

>>> 	(mode_iterator::get_2xwider): Likewise.

>>> 	(mode_iterator::get_known_wider): Likewise, turning into a template.

>>> 	* combine.c (make_extraction): Update use of GET_MODE_WIDER_MODE,

>>> 	forcing a wider mode to exist.

>>> 	* config/cr16/cr16.h (LONG_REG_P): Likewise.

>>> 	* rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise.

>>> 	* config/c6x/c6x.c (c6x_rtx_costs): Update use of

>>> 	GET_MODE_2XWIDER_MODE, forcing a wider mode to exist.

>>> 	* lower-subreg.c (init_lower_subreg): Likewise.

>>> 	* optabs-libfuncs.c (init_sync_libfuncs_1): Likewise, but not

>>> 	on the final iteration.

>>> 	* config/i386/i386.c (ix86_expand_set_or_movmem): Check whether

>>> 	a wider mode exists before asking for a move pattern.

>>> 	(get_mode_wider_vector): Update use of GET_MODE_WIDER_MODE,

>>> 	forcing a wider mode to exist.

>>> 	(expand_vselect_vconcat): Update use of GET_MODE_2XWIDER_MODE,

>>> 	returning false if no such mode exists.

>>> 	* config/ia64/ia64.c (expand_vselect_vconcat): Likewise.

>>> 	* config/mips/mips.c (mips_expand_vselect_vconcat): Likewise.

>>> 	* expmed.c (init_expmed_one_mode): Update use of GET_MODE_WIDER_MODE.

>>> 	Avoid checking for a MODE_INT if we already know the mode is not a

>>> 	SCALAR_INT_MODE_P.

>>> 	(extract_high_half): Update use of GET_MODE_WIDER_MODE,

>>> 	forcing a wider mode to exist.

>>> 	(expmed_mult_highpart_optab): Likewise.

>>> 	(expmed_mult_highpart): Likewise.

>>> 	* expr.c (expand_expr_real_2): Update use of GET_MODE_WIDER_MODE,

>>> 	using else_void.

>>> 	* lto-streamer-in.c (lto_input_mode_table): Likewise.

>>> 	* optabs-query.c (find_widening_optab_handler_and_mode): Likewise.

>>> 	* stor-layout.c (bit_field_mode_iterator::next_mode): Likewise.

>>> 	* internal-fn.c (expand_mul_overflow): Update use of

>>> 	GET_MODE_2XWIDER_MODE.

>>> 	* omp-low.c (omp_clause_aligned_alignment): Likewise.

>>> 	* tree-ssa-math-opts.c (convert_mult_to_widen): Update use of

>>> 	GET_MODE_WIDER_MODE.

>>> 	(convert_plusminus_to_widen): Likewise.

>>> 	* tree-switch-conversion.c (array_value_type): Likewise.

>>> 	* var-tracking.c (emit_note_insn_var_location): Likewise.

>>> 	* tree-vrp.c (simplify_float_conversion_using_ranges): Likewise.

>>> 	Return false inside rather than outside the loop if no wider mode

>>> 	exists

>>> 	* optabs.c (expand_binop): Update use of GET_MODE_WIDER_MODE

>>> 	and GET_MODE_2XWIDER_MODE

>>> 	(can_compare_p): Use else_void.

>>> 	* gdbhooks.py (OptMachineModePrinter): New class.

>>> 	(build_pretty_printer): Use it for opt_mode.

>>>

>>> gcc/ada/

>>> 	* gcc-interface/decl.c (validate_size): Update use of

>>> 	GET_MODE_WIDER_MODE, forcing a wider mode to exist.

>> I'm not a big fan of the API here, particularly using operator* to

>> handle asserting the mode exists.  I'd prefer to just use a member

>> function rather than overloading operator*.

>>

>> What's the rationale behind using operator* to imply the assertion?

>>

>> THe changes themsleves look fine, it's really just a question of the API

>> we present.

> 

> The original idea was to make opt_mode look pointer-ish, so that

> the dyn_cast <...> result could be used in the same way as for

> dyn_cast <gassign *> etc.  The first cut therefore had operator bool ()

> to test whether there was a mode and operator * to dereference it.

> 

> However, operator bool () created various subtle problems (as it always

> seems to) so we dropped it in favour of exists ().  I was neutral

> on whether we should keep '*' or switch to a function, so in the

> end the status quo won out.  I'm happy to change it to a named

> accessor though.

> 

> Any better ideas than "get ()" for the name?  Maybe something

> to emphasis that it is asserting for non-nullness/non-emptiness

> (which '*' does implicitly)?Yea, when I was reading the first few patches it felt like you trying to

do a pointer-ish API.

I think we should avoid the operator overload.  It's not real obvious
what's going on and I think our guidelines generally discourage operator
overloading.  Sadly I think it's going to require a lot of mechanical
changes, but better to do it now than go back later and do it.

As for the name, get_nonvoid?  Ugh.  Not sure.  Open to suggestions.

jeff
Richard Sandiford Aug. 28, 2017, 7:05 p.m. | #4
Jeff Law <law@redhat.com> writes:
> On 08/11/2017 12:24 PM, Richard Sandiford wrote:

>> Jeff Law <law@redhat.com> writes:

>>> On 07/13/2017 02:40 AM, Richard Sandiford wrote:

>>>> GET_MODE_WIDER previously returned VOIDmode if no wider mode existed.

>>>> That would cause problems with stricter mode classes, since VOIDmode

>>>> isn't for example a valid scalar integer or floating-point mode.

>>>> This patch instead makes it return a new opt_mode<T> class, which

>>>> holds either a T or nothing.

>>>>

>>>> 2017-07-13  Richard Sandiford  <richard.sandiford@linaro.org>

>>>> 	    Alan Hayward  <alan.hayward@arm.com>

>>>> 	    David Sherwood  <david.sherwood@arm.com>

>>>>

>>>> gcc/

>>>> 	* coretypes.h (opt_mode): New class.

>>>> 	* machmode.h (opt_mode): Likewise.

>>>> 	(opt_mode::else_void): New function.

>>>> 	(opt_mode::operator *): Likewise.

>>>> 	(opt_mode::exists): Likewise.

>>>> 	(GET_MODE_WIDER_MODE): Turn into a function and return an opt_mode.

>>>> 	(GET_MODE_2XWIDER_MODE): Likewise.

>>>> 	(mode_iterator::get_wider): Update accordingly.

>>>> 	(mode_iterator::get_2xwider): Likewise.

>>>> 	(mode_iterator::get_known_wider): Likewise, turning into a template.

>>>> 	* combine.c (make_extraction): Update use of GET_MODE_WIDER_MODE,

>>>> 	forcing a wider mode to exist.

>>>> 	* config/cr16/cr16.h (LONG_REG_P): Likewise.

>>>> 	* rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise.

>>>> 	* config/c6x/c6x.c (c6x_rtx_costs): Update use of

>>>> 	GET_MODE_2XWIDER_MODE, forcing a wider mode to exist.

>>>> 	* lower-subreg.c (init_lower_subreg): Likewise.

>>>> 	* optabs-libfuncs.c (init_sync_libfuncs_1): Likewise, but not

>>>> 	on the final iteration.

>>>> 	* config/i386/i386.c (ix86_expand_set_or_movmem): Check whether

>>>> 	a wider mode exists before asking for a move pattern.

>>>> 	(get_mode_wider_vector): Update use of GET_MODE_WIDER_MODE,

>>>> 	forcing a wider mode to exist.

>>>> 	(expand_vselect_vconcat): Update use of GET_MODE_2XWIDER_MODE,

>>>> 	returning false if no such mode exists.

>>>> 	* config/ia64/ia64.c (expand_vselect_vconcat): Likewise.

>>>> 	* config/mips/mips.c (mips_expand_vselect_vconcat): Likewise.

>>>> 	* expmed.c (init_expmed_one_mode): Update use of GET_MODE_WIDER_MODE.

>>>> 	Avoid checking for a MODE_INT if we already know the mode is not a

>>>> 	SCALAR_INT_MODE_P.

>>>> 	(extract_high_half): Update use of GET_MODE_WIDER_MODE,

>>>> 	forcing a wider mode to exist.

>>>> 	(expmed_mult_highpart_optab): Likewise.

>>>> 	(expmed_mult_highpart): Likewise.

>>>> 	* expr.c (expand_expr_real_2): Update use of GET_MODE_WIDER_MODE,

>>>> 	using else_void.

>>>> 	* lto-streamer-in.c (lto_input_mode_table): Likewise.

>>>> 	* optabs-query.c (find_widening_optab_handler_and_mode): Likewise.

>>>> 	* stor-layout.c (bit_field_mode_iterator::next_mode): Likewise.

>>>> 	* internal-fn.c (expand_mul_overflow): Update use of

>>>> 	GET_MODE_2XWIDER_MODE.

>>>> 	* omp-low.c (omp_clause_aligned_alignment): Likewise.

>>>> 	* tree-ssa-math-opts.c (convert_mult_to_widen): Update use of

>>>> 	GET_MODE_WIDER_MODE.

>>>> 	(convert_plusminus_to_widen): Likewise.

>>>> 	* tree-switch-conversion.c (array_value_type): Likewise.

>>>> 	* var-tracking.c (emit_note_insn_var_location): Likewise.

>>>> 	* tree-vrp.c (simplify_float_conversion_using_ranges): Likewise.

>>>> 	Return false inside rather than outside the loop if no wider mode

>>>> 	exists

>>>> 	* optabs.c (expand_binop): Update use of GET_MODE_WIDER_MODE

>>>> 	and GET_MODE_2XWIDER_MODE

>>>> 	(can_compare_p): Use else_void.

>>>> 	* gdbhooks.py (OptMachineModePrinter): New class.

>>>> 	(build_pretty_printer): Use it for opt_mode.

>>>>

>>>> gcc/ada/

>>>> 	* gcc-interface/decl.c (validate_size): Update use of

>>>> 	GET_MODE_WIDER_MODE, forcing a wider mode to exist.

>>> I'm not a big fan of the API here, particularly using operator* to

>>> handle asserting the mode exists.  I'd prefer to just use a member

>>> function rather than overloading operator*.

>>>

>>> What's the rationale behind using operator* to imply the assertion?

>>>

>>> THe changes themsleves look fine, it's really just a question of the API

>>> we present.

>> 

>> The original idea was to make opt_mode look pointer-ish, so that

>> the dyn_cast <...> result could be used in the same way as for

>> dyn_cast <gassign *> etc.  The first cut therefore had operator bool ()

>> to test whether there was a mode and operator * to dereference it.

>> 

>> However, operator bool () created various subtle problems (as it always

>> seems to) so we dropped it in favour of exists ().  I was neutral

>> on whether we should keep '*' or switch to a function, so in the

>> end the status quo won out.  I'm happy to change it to a named

>> accessor though.

>> 

>> Any better ideas than "get ()" for the name?  Maybe something

>> to emphasis that it is asserting for non-nullness/non-emptiness

>> (which '*' does implicitly)?

>

> Yea, when I was reading the first few patches it felt like you trying

>to do a pointer-ish API.

>

> I think we should avoid the operator overload.  It's not real obvious

> what's going on and I think our guidelines generally discourage operator

> overloading.  Sadly I think it's going to require a lot of mechanical

> changes, but better to do it now than go back later and do it.


That's OK, it should be a trivial update.

> As for the name, get_nonvoid?  Ugh.  Not sure.  Open to suggestions.


I'd rather avoid "nonvoid", since the use of VOIDmode for "no mode" is
really an implementation detail in things like opt_mode <scalar_int_mode>.
Other possiblities might be:

  - require
  - demand
  - mode
  - get_mode
  - require_mode
  - demand_mode
  - else_fail (to go with else_void and else_blk)
  - noelse

Thanks,
Richard
Jeff Law Aug. 28, 2017, 7:11 p.m. | #5
On 08/28/2017 01:05 PM, Richard Sandiford wrote:
> 

>> As for the name, get_nonvoid?  Ugh.  Not sure.  Open to suggestions.

> 

> I'd rather avoid "nonvoid", since the use of VOIDmode for "no mode" is

> really an implementation detail in things like opt_mode <scalar_int_mode>.

> Other possiblities might be:

Yea, good point on encoding the implementation detail not being a good idea.

> 

>   - require

>   - demand

>   - mode

>   - get_mode

>   - require_mode

>   - demand_mode

>   - else_fail (to go with else_void and else_blk)

>   - noelse

require, demand with or without the _mode suffix seem good to me.

jeff
Richard Sandiford Aug. 29, 2017, 3:01 p.m. | #6
Jeff Law <law@redhat.com> writes:
> On 08/28/2017 01:05 PM, Richard Sandiford wrote:

>> 

>>> As for the name, get_nonvoid?  Ugh.  Not sure.  Open to suggestions.

>> 

>> I'd rather avoid "nonvoid", since the use of VOIDmode for "no mode" is

>> really an implementation detail in things like opt_mode <scalar_int_mode>.

>> Other possiblities might be:

> Yea, good point on encoding the implementation detail not being a good idea.

>

>> 

>>   - require

>>   - demand

>>   - mode

>>   - get_mode

>>   - require_mode

>>   - demand_mode

>>   - else_fail (to go with else_void and else_blk)

>>   - noelse

> require, demand with or without the _mode suffix seem good to me.


OK, here's a patch that uses require ().  I've updated the following
patches in the obvious way.

This does make me want to reconsider another decision though.
Using opt_mode for iterators leads to things like:

  opt_scalar_int_mode wider_mode_iter;
  FOR_EACH_WIDER_MODE (wider_mode_iter, mode)
    {
      scalar_int_mode wider_mode = wider_mode_iter.require ();
      if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
        ...

which isn't pretty.  It would be easy to support:

  scalar_int_mode wider_mode;
  FOR_EACH_WIDER_MODE (wider_mode, mode)
    if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
      ...

*but* this would mean that "wider_mode" is accessible but undefined
after the loop (unlike the first loop, where wider_mode_iter is
guaranteed to be empty if the loop runs to completion).  Is that OK?
Or is it too suprising?

Another alternative would be:

  opt_scalar_int_mode wider_mode_iter;
  scalar_int_mode wider_mode;
  FOR_EACH_WIDER_MODE (wider_mode_iter, wider_mode, mode)
    if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)
      ...

which gives both.  But perhaps this would be odd for plain machine_mode
iterators, where there's no obvious distinction between the first and
second arguments.

Thanks,
Richard


2017-08-29  Richard Sandiford  <richard.sandiford@linaro.org>
	    Alan Hayward  <alan.hayward@arm.com>
	    David Sherwood  <david.sherwood@arm.com>

gcc/
	* coretypes.h (opt_mode): New class.
	* machmode.h (opt_mode): Likewise.
	(opt_mode::else_void): New function.
	(opt_mode::require): Likewise.
	(opt_mode::exists): Likewise.
	(GET_MODE_WIDER_MODE): Turn into a function and return an opt_mode.
	(GET_MODE_2XWIDER_MODE): Likewise.
	(mode_iterator::get_wider): Update accordingly.
	(mode_iterator::get_2xwider): Likewise.
	(mode_iterator::get_known_wider): Likewise, turning into a template.
	* combine.c (make_extraction): Update use of GET_MODE_WIDER_MODE,
	forcing a wider mode to exist.
	* config/cr16/cr16.h (LONG_REG_P): Likewise.
	* rtlanal.c (init_num_sign_bit_copies_in_rep): Likewise.
	* config/c6x/c6x.c (c6x_rtx_costs): Update use of
	GET_MODE_2XWIDER_MODE, forcing a wider mode to exist.
	* lower-subreg.c (init_lower_subreg): Likewise.
	* optabs-libfuncs.c (init_sync_libfuncs_1): Likewise, but not
	on the final iteration.
	* config/i386/i386.c (ix86_expand_set_or_movmem): Check whether
	a wider mode exists before asking for a move pattern.
	(get_mode_wider_vector): Update use of GET_MODE_WIDER_MODE,
	forcing a wider mode to exist.
	(expand_vselect_vconcat): Update use of GET_MODE_2XWIDER_MODE,
	returning false if no such mode exists.
	* config/ia64/ia64.c (expand_vselect_vconcat): Likewise.
	* config/mips/mips.c (mips_expand_vselect_vconcat): Likewise.
	* expmed.c (init_expmed_one_mode): Update use of GET_MODE_WIDER_MODE.
	Avoid checking for a MODE_INT if we already know the mode is not a
	SCALAR_INT_MODE_P.
	(extract_high_half): Update use of GET_MODE_WIDER_MODE,
	forcing a wider mode to exist.
	(expmed_mult_highpart_optab): Likewise.
	(expmed_mult_highpart): Likewise.
	* expr.c (expand_expr_real_2): Update use of GET_MODE_WIDER_MODE,
	using else_void.
	* lto-streamer-in.c (lto_input_mode_table): Likewise.
	* optabs-query.c (find_widening_optab_handler_and_mode): Likewise.
	* stor-layout.c (bit_field_mode_iterator::next_mode): Likewise.
	* internal-fn.c (expand_mul_overflow): Update use of
	GET_MODE_2XWIDER_MODE.
	* omp-low.c (omp_clause_aligned_alignment): Likewise.
	* tree-ssa-math-opts.c (convert_mult_to_widen): Update use of
	GET_MODE_WIDER_MODE.
	(convert_plusminus_to_widen): Likewise.
	* tree-switch-conversion.c (array_value_type): Likewise.
	* var-tracking.c (emit_note_insn_var_location): Likewise.
	* tree-vrp.c (simplify_float_conversion_using_ranges): Likewise.
	Return false inside rather than outside the loop if no wider mode
	exists
	* optabs.c (expand_binop): Update use of GET_MODE_WIDER_MODE
	and GET_MODE_2XWIDER_MODE
	(can_compare_p): Use else_void.
	* gdbhooks.py (OptMachineModePrinter): New class.
	(build_pretty_printer): Use it for opt_mode.

gcc/ada/
	* gcc-interface/decl.c (validate_size): Update use of
	GET_MODE_WIDER_MODE, forcing a wider mode to exist.

Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	2017-08-29 15:51:59.126986401 +0100
+++ gcc/coretypes.h	2017-08-29 15:52:16.793375425 +0100
@@ -55,6 +55,7 @@ typedef const struct simple_bitmap_def *
 struct rtx_def;
 typedef struct rtx_def *rtx;
 typedef const struct rtx_def *const_rtx;
+template<typename> class opt_mode;
 
 /* Subclasses of rtx_def, using indentation to show the class
    hierarchy, along with the relevant invariant.
Index: gcc/machmode.h
===================================================================
--- gcc/machmode.h	2017-08-29 15:51:59.315986390 +0100
+++ gcc/machmode.h	2017-08-29 15:52:16.797005080 +0100
@@ -221,6 +221,71 @@ #define CLASS_HAS_WIDER_MODES_P(CLASS)
 #define POINTER_BOUNDS_MODE_P(MODE)      \
   (GET_MODE_CLASS (MODE) == MODE_POINTER_BOUNDS)
 
+/* An optional T (i.e. a T or nothing), where T is some form of mode class.  */
+template<typename T>
+class opt_mode
+{
+public:
+  enum from_int { dummy = MAX_MACHINE_MODE };
+
+  ALWAYS_INLINE opt_mode () : m_mode (E_VOIDmode) {}
+  ALWAYS_INLINE opt_mode (const T &m) : m_mode (m) {}
+  ALWAYS_INLINE opt_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+  machine_mode else_void () const;
+  T require () const;
+
+  bool exists () const;
+  template<typename U> bool exists (U *) const;
+
+private:
+  machine_mode m_mode;
+};
+
+/* If the object contains a T, return its enum value, otherwise return
+   E_VOIDmode.  */
+
+template<typename T>
+ALWAYS_INLINE machine_mode
+opt_mode<T>::else_void () const
+{
+  return m_mode;
+}
+
+/* Assert that the object contains a T and return it.  */
+
+template<typename T>
+inline T
+opt_mode<T>::require () const
+{
+  gcc_checking_assert (m_mode != E_VOIDmode);
+  return typename mode_traits<T>::from_int (m_mode);
+}
+
+/* Return true if the object contains a T rather than nothing.  */
+
+template<typename T>
+ALWAYS_INLINE bool
+opt_mode<T>::exists () const
+{
+  return m_mode != E_VOIDmode;
+}
+
+/* Return true if the object contains a T, storing it in *MODE if so.  */
+
+template<typename T>
+template<typename U>
+inline bool
+opt_mode<T>::exists (U *mode) const
+{
+  if (m_mode != E_VOIDmode)
+    {
+      *mode = T (typename mode_traits<T>::from_int (m_mode));
+      return true;
+    }
+  return false;
+}
+
 /* Return the base GET_MODE_SIZE value for MODE.  */
 
 ALWAYS_INLINE unsigned short
@@ -352,13 +417,22 @@ #define GET_MODE_NUNITS(MODE) (mode_to_n
 
 /* Get the next wider natural mode (eg, QI -> HI -> SI -> DI -> TI).  */
 
-extern const unsigned char mode_wider[NUM_MACHINE_MODES];
-#define GET_MODE_WIDER_MODE(MODE) ((machine_mode) mode_wider[MODE])
+template<typename T>
+ALWAYS_INLINE opt_mode<T>
+GET_MODE_WIDER_MODE (const T &m)
+{
+  return typename opt_mode<T>::from_int (mode_wider[m]);
+}
 
 /* For scalars, this is a mode with twice the precision.  For vectors,
    this is a mode with the same inner mode but with twice the elements.  */
-extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
-#define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
+
+template<typename T>
+ALWAYS_INLINE opt_mode<T>
+GET_MODE_2XWIDER_MODE (const T &m)
+{
+  return typename opt_mode<T>::from_int (mode_2xwider[m]);
+}
 
 /* Get the complex mode from the component mode.  */
 extern const unsigned char mode_complex[NUM_MACHINE_MODES];
@@ -497,17 +571,17 @@ struct int_n_data_t {
   inline void
   get_wider (machine_mode *iter)
   {
-    *iter = GET_MODE_WIDER_MODE (*iter);
+    *iter = GET_MODE_WIDER_MODE (*iter).else_void ();
   }
 
   /* Set mode iterator *ITER to the next widest mode in the same class.
      Such a mode is known to exist.  */
 
+  template<typename T>
   inline void
-  get_known_wider (machine_mode *iter)
+  get_known_wider (T *iter)
   {
-    *iter = GET_MODE_WIDER_MODE (*iter);
-    gcc_checking_assert (*iter != VOIDmode);
+    *iter = GET_MODE_WIDER_MODE (*iter).require ();
   }
 
   /* Set mode iterator *ITER to the mode that is two times wider than the
@@ -516,7 +590,7 @@ struct int_n_data_t {
   inline void
   get_2xwider (machine_mode *iter)
   {
-    *iter = GET_MODE_2XWIDER_MODE (*iter);
+    *iter = GET_MODE_2XWIDER_MODE (*iter).else_void ();
   }
 }
 
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	2017-08-29 15:51:59.308986390 +0100
+++ gcc/combine.c	2017-08-29 15:52:16.787023529 +0100
@@ -7596,10 +7596,7 @@ make_extraction (machine_mode mode, rtx
       wanted_inner_mode = smallest_mode_for_size (len, MODE_INT);
       while (pos % GET_MODE_BITSIZE (wanted_inner_mode) + len
 	     > GET_MODE_BITSIZE (wanted_inner_mode))

-	{
-	  wanted_inner_mode = GET_MODE_WIDER_MODE (wanted_inner_mode);
-	  gcc_assert (wanted_inner_mode != VOIDmode);
-	}
+	wanted_inner_mode = GET_MODE_WIDER_MODE (wanted_inner_mode).require ();
     }
 
   orig_pos = pos;
Index: gcc/config/cr16/cr16.h
===================================================================
--- gcc/config/cr16/cr16.h	2017-08-29 15:51:59.055986405 +0100
+++ gcc/config/cr16/cr16.h	2017-08-29 15:52:16.787023529 +0100
@@ -197,9 +197,7 @@ #define CALL_USED_REGISTERS
 
 /* Returns 1 if the register is longer than word size, 0 otherwise.  */
 #define LONG_REG_P(REGNO)                                                    \
-  (HARD_REGNO_NREGS (REGNO,                                                  \
-		     GET_MODE_WIDER_MODE (smallest_mode_for_size	     \
-					 (BITS_PER_WORD, MODE_INT))) == 1)
+  (HARD_REGNO_NREGS (REGNO, GET_MODE_WIDER_MODE (word_mode).require ()) == 1)
 
 #define HARD_REGNO_NREGS(REGNO, MODE)                                         \
  ((REGNO >= CR16_FIRST_DWORD_REGISTER)                                        \
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	2017-08-29 15:51:59.318986390 +0100
+++ gcc/rtlanal.c	2017-08-29 15:52:16.798819908 +0100
@@ -5680,13 +5680,15 @@ init_num_sign_bit_copies_in_rep (void)
 	/* Currently, it is assumed that TARGET_MODE_REP_EXTENDED
 	   extends to the next widest mode.  */
 	gcc_assert (targetm.mode_rep_extended (mode, in_mode) == UNKNOWN
-		    || GET_MODE_WIDER_MODE (mode) == in_mode);
+		    || GET_MODE_WIDER_MODE (mode).require () == in_mode);
 
 	/* We are in in_mode.  Count how many bits outside of mode
 	   have to be copies of the sign-bit.  */
 	FOR_EACH_MODE (i, mode, in_mode)
 	  {
-	    machine_mode wider = GET_MODE_WIDER_MODE (i);
+	    /* This must always exist (for the last iteration it will be
+	       IN_MODE).  */
+	    machine_mode wider = GET_MODE_WIDER_MODE (i).require ();
 
 	    if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
 		/* We can only check sign-bit copies starting from the
Index: gcc/config/c6x/c6x.c
===================================================================
--- gcc/config/c6x/c6x.c	2017-08-29 15:51:59.252986394 +0100
+++ gcc/config/c6x/c6x.c	2017-08-29 15:52:16.787023529 +0100
@@ -6066,7 +6066,7 @@ c6x_rtx_costs (rtx x, machine_mode mode,
       /* Recognize a mult_highpart operation.  */
       if ((mode == HImode || mode == SImode)
 	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
-	  && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (mode)
+	  && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (mode).require ()
 	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
 	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
 	  && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode))
Index: gcc/lower-subreg.c
===================================================================
--- gcc/lower-subreg.c	2017-08-29 15:51:59.094986403 +0100
+++ gcc/lower-subreg.c	2017-08-29 15:52:16.796097666 +0100
@@ -267,7 +267,7 @@ init_lower_subreg (void)
 
   memset (this_target_lower_subreg, 0, sizeof (*this_target_lower_subreg));
 
-  twice_word_mode = GET_MODE_2XWIDER_MODE (word_mode);
+  twice_word_mode = GET_MODE_2XWIDER_MODE (word_mode).require ();
 
   rtxes.target = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
   rtxes.source = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 2);
Index: gcc/optabs-libfuncs.c
===================================================================
--- gcc/optabs-libfuncs.c	2017-07-13 09:25:13.387236070 +0100
+++ gcc/optabs-libfuncs.c	2017-08-29 15:52:16.797912494 +0100
@@ -918,9 +918,10 @@ init_sync_libfuncs_1 (optab tab, const c
   mode = QImode;
   for (i = 1; i <= max; i *= 2)
     {
+      if (i > 1)
+	mode = GET_MODE_2XWIDER_MODE (mode).require ();
       buf[len + 1] = '0' + i;
       set_optab_libfunc (tab, mode, buf);
-      mode = GET_MODE_2XWIDER_MODE (mode);
     }
 }
 
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	2017-08-29 15:51:59.312986390 +0100
+++ gcc/config/i386/i386.c	2017-08-29 15:52:16.790653184 +0100
@@ -28543,6 +28543,7 @@ ix86_expand_set_or_movmem (rtx dst, rtx
   bool need_zero_guard = false;
   bool noalign;
   machine_mode move_mode = VOIDmode;
+  machine_mode wider_mode;
   int unroll_factor = 1;
   /* TODO: Once value ranges are available, fill in proper data.  */
   unsigned HOST_WIDE_INT min_size = 0;
@@ -28636,9 +28637,9 @@ ix86_expand_set_or_movmem (rtx dst, rtx
       unroll_factor = 4;
       /* Find the widest supported mode.  */
       move_mode = word_mode;
-      while (optab_handler (mov_optab, GET_MODE_WIDER_MODE (move_mode))
-	     != CODE_FOR_nothing)
-	  move_mode = GET_MODE_WIDER_MODE (move_mode);
+      while (GET_MODE_WIDER_MODE (move_mode).exists (&wider_mode)
+	     && optab_handler (mov_optab, wider_mode) != CODE_FOR_nothing)
+	move_mode = wider_mode;
 
       /* Find the corresponding vector mode with the same size as MOVE_MODE.
 	 MOVE_MODE is an integer mode at the moment (SI, DI, TI, etc.).  */
@@ -43523,7 +43524,7 @@ static bool expand_vec_perm_palignr (str
 get_mode_wider_vector (machine_mode o)
 {
   /* ??? Rely on the ordering that genmodes.c gives to vectors.  */
-  machine_mode n = GET_MODE_WIDER_MODE (o);
+  machine_mode n = GET_MODE_WIDER_MODE (o).require ();
   gcc_assert (GET_MODE_NUNITS (o) == GET_MODE_NUNITS (n) * 2);
   gcc_assert (GET_MODE_SIZE (o) == GET_MODE_SIZE (n));
   return n;
@@ -46886,7 +46887,8 @@ expand_vselect_vconcat (rtx target, rtx
   if (vselect_insn == NULL_RTX)
     init_vselect_insn ();
 
-  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+    return false;
   x = XEXP (SET_SRC (PATTERN (vselect_insn)), 0);
   PUT_MODE (x, v2mode);
   XEXP (x, 0) = op0;
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c	2017-08-29 15:51:59.261986393 +0100
+++ gcc/config/ia64/ia64.c	2017-08-29 15:52:16.791560598 +0100
@@ -11353,7 +11353,8 @@ expand_vselect_vconcat (rtx target, rtx
   machine_mode v2mode;
   rtx x;
 
-  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+    return false;
   x = gen_rtx_VEC_CONCAT (v2mode, op0, op1);
   return expand_vselect (target, x, perm, nelt);
 }
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2017-08-29 15:51:59.265986393 +0100
+++ gcc/config/mips/mips.c	2017-08-29 15:52:16.793375425 +0100
@@ -21134,7 +21134,8 @@ mips_expand_vselect_vconcat (rtx target,
   machine_mode v2mode;
   rtx x;
 
-  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+    return false;
   x = gen_rtx_VEC_CONCAT (v2mode, op0, op1);
   return mips_expand_vselect (target, x, perm, nelt);
 }
Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c	2017-08-29 15:52:16.456724920 +0100
+++ gcc/expmed.c	2017-08-29 15:52:16.793375425 +0100
@@ -207,11 +207,10 @@ init_expmed_one_mode (struct init_expmed
       for (mode_from = MIN_MODE_INT; mode_from <= MAX_MODE_INT;
 	   mode_from = (machine_mode)(mode_from + 1))
 	init_expmed_one_conv (all, mode, mode_from, speed);
-    }
-  if (GET_MODE_CLASS (mode) == MODE_INT)
-    {
-      machine_mode  wider_mode = GET_MODE_WIDER_MODE (mode);
-      if (wider_mode != VOIDmode)
+
+      machine_mode wider_mode;
+      if (GET_MODE_CLASS (mode) == MODE_INT
+	  && GET_MODE_WIDER_MODE (mode).exists (&wider_mode))
 	{
 	  PUT_MODE (all->zext, wider_mode);
 	  PUT_MODE (all->wide_mult, wider_mode);
@@ -3618,7 +3617,7 @@ extract_high_half (machine_mode mode, rt
 
   gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
 
-  wider_mode = GET_MODE_WIDER_MODE (mode);
+  wider_mode = GET_MODE_WIDER_MODE (mode).require ();
   op = expand_shift (RSHIFT_EXPR, wider_mode, op,
 		     GET_MODE_BITSIZE (mode), 0, 1);
   return convert_modes (mode, wider_mode, op, 0);
@@ -3640,7 +3639,7 @@ expmed_mult_highpart_optab (machine_mode
 
   gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
 
-  wider_mode = GET_MODE_WIDER_MODE (mode);
+  wider_mode = GET_MODE_WIDER_MODE (mode).require ();
   size = GET_MODE_BITSIZE (mode);
 
   /* Firstly, try using a multiplication insn that only generates the needed
@@ -3746,7 +3745,7 @@ expmed_mult_highpart_optab (machine_mode
 expmed_mult_highpart (machine_mode mode, rtx op0, rtx op1,
 		      rtx target, int unsignedp, int max_cost)
 {
-  machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+  machine_mode wider_mode = GET_MODE_WIDER_MODE (mode).require ();
   unsigned HOST_WIDE_INT cnst1;
   int extra_cost;
   bool sign_adjust = false;
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	2017-08-29 15:51:59.315986390 +0100
+++ gcc/expr.c	2017-08-29 15:52:16.794282839 +0100
@@ -9142,7 +9142,7 @@ #define REDUCE_BIT_FIELD(expr)	(reduce_b
 	if (code == LSHIFT_EXPR
 	    && target
 	    && REG_P (target)
-	    && mode == GET_MODE_WIDER_MODE (word_mode)
+	    && mode == GET_MODE_WIDER_MODE (word_mode).else_void ()
 	    && GET_MODE_SIZE (mode) == 2 * GET_MODE_SIZE (word_mode)
 	    && TREE_CONSTANT (treeop1)
 	    && TREE_CODE (treeop0) == SSA_NAME)
Index: gcc/lto-streamer-in.c
===================================================================
--- gcc/lto-streamer-in.c	2017-08-21 12:14:39.684583630 +0100
+++ gcc/lto-streamer-in.c	2017-08-29 15:52:16.796097666 +0100
@@ -1636,7 +1636,7 @@ lto_input_mode_table (struct lto_file_de
 				    : GET_CLASS_NARROWEST_MODE (mclass);
 	     pass ? mr < MAX_MACHINE_MODE : mr != VOIDmode;
 	     pass ? mr = (machine_mode) (mr + 1)
-		  : mr = GET_MODE_WIDER_MODE (mr))
+		  : mr = GET_MODE_WIDER_MODE (mr).else_void ())
 	  if (GET_MODE_CLASS (mr) != mclass
 	      || GET_MODE_SIZE (mr) != size
 	      || GET_MODE_PRECISION (mr) != prec
Index: gcc/optabs-query.c
===================================================================
--- gcc/optabs-query.c	2017-08-29 15:51:59.316986390 +0100
+++ gcc/optabs-query.c	2017-08-29 15:52:16.797912494 +0100
@@ -425,7 +425,7 @@ find_widening_optab_handler_and_mode (op
   for (; (permit_non_widening || from_mode != to_mode)
 	 && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
 	 && from_mode != VOIDmode;
-       from_mode = GET_MODE_WIDER_MODE (from_mode))
+       from_mode = GET_MODE_WIDER_MODE (from_mode).else_void ())
     {
       enum insn_code handler = widening_optab_handler (op, to_mode,
 						       from_mode);
Index: gcc/stor-layout.c
===================================================================
--- gcc/stor-layout.c	2017-08-29 15:51:59.319986390 +0100
+++ gcc/stor-layout.c	2017-08-29 15:52:16.799727321 +0100
@@ -2745,7 +2745,8 @@ fixup_unsigned_type (tree type)
 bool
 bit_field_mode_iterator::next_mode (machine_mode *out_mode)
 {
-  for (; m_mode != VOIDmode; m_mode = GET_MODE_WIDER_MODE (m_mode))
+  for (; m_mode != VOIDmode;
+       m_mode = GET_MODE_WIDER_MODE (m_mode).else_void ())
     {
       unsigned int unit = GET_MODE_BITSIZE (m_mode);
 
@@ -2782,7 +2783,7 @@ bit_field_mode_iterator::next_mode (mach
 	break;
 
       *out_mode = m_mode;
-      m_mode = GET_MODE_WIDER_MODE (m_mode);
+      m_mode = GET_MODE_WIDER_MODE (m_mode).else_void ();
       m_count++;
       return true;
     }
Index: gcc/internal-fn.c
===================================================================
--- gcc/internal-fn.c	2017-08-17 09:05:42.895968489 +0100
+++ gcc/internal-fn.c	2017-08-29 15:52:16.796097666 +0100
@@ -1460,14 +1460,14 @@ expand_mul_overflow (location_t loc, tre
       struct separate_ops ops;
       int prec = GET_MODE_PRECISION (mode);
       machine_mode hmode = mode_for_size (prec / 2, MODE_INT, 1);
+      machine_mode wmode;
       ops.op0 = make_tree (type, op0);
       ops.op1 = make_tree (type, op1);
       ops.op2 = NULL_TREE;
       ops.location = loc;
-      if (GET_MODE_2XWIDER_MODE (mode) != VOIDmode
-	  && targetm.scalar_mode_supported_p (GET_MODE_2XWIDER_MODE (mode)))
+      if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
+	  && targetm.scalar_mode_supported_p (wmode))
 	{
-	  machine_mode wmode = GET_MODE_2XWIDER_MODE (mode);
 	  ops.code = WIDEN_MULT_EXPR;
 	  ops.type
 	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
Index: gcc/omp-low.c
===================================================================
--- gcc/omp-low.c	2017-08-29 15:51:59.316986390 +0100
+++ gcc/omp-low.c	2017-08-29 15:52:16.797005080 +0100
@@ -3456,8 +3456,8 @@ omp_clause_aligned_alignment (tree claus
 	  continue;
 	while (vs
 	       && GET_MODE_SIZE (vmode) < vs
-	       && GET_MODE_2XWIDER_MODE (vmode) != VOIDmode)
-	  vmode = GET_MODE_2XWIDER_MODE (vmode);
+	       && GET_MODE_2XWIDER_MODE (vmode).exists ())
+	  vmode = GET_MODE_2XWIDER_MODE (vmode).require ();
 
 	tree type = lang_hooks.types.type_for_mode (mode, 1);
 	if (type == NULL_TREE || TYPE_MODE (type) != mode)
Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c	2017-08-29 15:51:59.319986390 +0100
+++ gcc/tree-ssa-math-opts.c	2017-08-29 15:52:16.799727321 +0100
@@ -3283,8 +3283,8 @@ convert_mult_to_widen (gimple *stmt, gim
 	      || (TYPE_UNSIGNED (type2)
 		  && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
 	    {
-	      from_mode = GET_MODE_WIDER_MODE (from_mode);
-	      if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
+	      if (!GET_MODE_WIDER_MODE (from_mode).exists (&from_mode)
+		  || GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
 		return false;
 	    }
 
@@ -3465,8 +3465,8 @@ convert_plusminus_to_widen (gimple_stmt_
 	  || (from_unsigned2
 	      && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
 	{
-	  from_mode = GET_MODE_WIDER_MODE (from_mode);
-	  if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
+	  if (!GET_MODE_WIDER_MODE (from_mode).exists (&from_mode)
+	      || GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
 	    return false;
 	}
 
Index: gcc/tree-switch-conversion.c
===================================================================
--- gcc/tree-switch-conversion.c	2017-08-29 15:51:59.329986389 +0100
+++ gcc/tree-switch-conversion.c	2017-08-29 15:52:16.799727321 +0100
@@ -1085,8 +1085,7 @@ array_value_type (gswitch *swtch, tree t
 	  if (sign == 1)
 	    sign = 0;
 
-	  mode = GET_MODE_WIDER_MODE (mode);
-	  if (mode == VOIDmode
+	  if (!GET_MODE_WIDER_MODE (mode).exists (&mode)
 	      || GET_MODE_SIZE (mode) >= GET_MODE_SIZE (type_mode))
 	    return type;
 	}
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	2017-08-29 15:51:59.321986390 +0100
+++ gcc/var-tracking.c	2017-08-29 15:52:16.801542149 +0100
@@ -8706,12 +8706,11 @@ emit_note_insn_var_location (variable **
       last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
 
       /* Attempt to merge adjacent registers or memory.  */
-      wider_mode = GET_MODE_WIDER_MODE (mode);
       for (j = i + 1; j < var->n_var_parts; j++)
 	if (last_limit <= VAR_PART_OFFSET (var, j))
 	  break;
       if (j < var->n_var_parts
-	  && wider_mode != VOIDmode
+	  && GET_MODE_WIDER_MODE (mode).exists (&wider_mode)
 	  && var->var_part[j].cur_loc
 	  && mode == GET_MODE (var->var_part[j].cur_loc)
 	  && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	2017-08-21 15:50:48.665709938 +0100
+++ gcc/tree-vrp.c	2017-08-29 15:52:16.800634735 +0100
@@ -10120,7 +10120,7 @@ simplify_float_conversion_using_ranges (
   else
     {
       mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-      do
+      for (;;)
 	{
 	  /* If we cannot do a signed conversion to float from mode
 	     or if the value-range does not fit in the signed type
@@ -10129,15 +10129,12 @@ simplify_float_conversion_using_ranges (
 	      && range_fits_type_p (vr, GET_MODE_PRECISION (mode), SIGNED))
 	    break;
 
-	  mode = GET_MODE_WIDER_MODE (mode);
 	  /* But do not widen the input.  Instead leave that to the
 	     optabs expansion code.  */
-	  if (GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
+	  if (!GET_MODE_WIDER_MODE (mode).exists (&mode)
+	      || GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
 	    return false;
 	}
-      while (mode != VOIDmode);
-      if (mode == VOIDmode)
-	return false;
     }
 
   /* It works, insert a truncation or sign-change before the
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	2017-08-29 15:51:59.317986390 +0100
+++ gcc/optabs.c	2017-08-29 15:52:16.798819908 +0100
@@ -1186,13 +1186,13 @@ expand_binop (machine_mode mode, optab b
      takes operands of this mode and makes a wider mode.  */
 
   if (binoptab == smul_optab
-      && GET_MODE_2XWIDER_MODE (mode) != VOIDmode
-      && (widening_optab_handler ((unsignedp ? umul_widen_optab
-					     : smul_widen_optab),
-				  GET_MODE_2XWIDER_MODE (mode), mode)
-	  != CODE_FOR_nothing))
+      && GET_MODE_2XWIDER_MODE (mode).exists (&wider_mode)
+      && (convert_optab_handler ((unsignedp
+				  ? umul_widen_optab
+				  : smul_widen_optab),
+				 wider_mode, mode) != CODE_FOR_nothing))
     {
-      temp = expand_binop (GET_MODE_2XWIDER_MODE (mode),
+      temp = expand_binop (wider_mode,
 			   unsignedp ? umul_widen_optab : smul_widen_optab,
 			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
 
@@ -1253,14 +1253,14 @@ expand_binop (machine_mode mode, optab b
       && methods != OPTAB_DIRECT && methods != OPTAB_LIB)
     FOR_EACH_WIDER_MODE (wider_mode, mode)
       {
+	machine_mode next_mode;
 	if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
 	    || (binoptab == smul_optab
-		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
+		&& GET_MODE_WIDER_MODE (wider_mode).exists (&next_mode)
 		&& (find_widening_optab_handler ((unsignedp
 						  ? umul_widen_optab
 						  : smul_widen_optab),
-						 GET_MODE_WIDER_MODE (wider_mode),
-						 mode, 0)
+						 next_mode, mode, 0)
 		    != CODE_FOR_nothing)))
 	  {
 	    rtx xop0 = op0, xop1 = op1;
@@ -3702,7 +3702,7 @@ can_compare_p (enum rtx_code code, machi
 	  && optab_handler (cmov_optab, mode) != CODE_FOR_nothing)
 	return 1;
 
-      mode = GET_MODE_WIDER_MODE (mode);
+      mode = GET_MODE_WIDER_MODE (mode).else_void ();
       PUT_MODE (test, mode);
     }
   while (mode != VOIDmode);
Index: gcc/gdbhooks.py
===================================================================
--- gcc/gdbhooks.py	2017-07-13 09:25:13.387236070 +0100
+++ gcc/gdbhooks.py	2017-08-29 15:52:16.796097666 +0100
@@ -422,6 +422,18 @@ class VecPrinter:
 
 ######################################################################
 
+class OptMachineModePrinter:
+    def __init__(self, gdbval):
+        self.gdbval = gdbval
+
+    def to_string (self):
+        name = str(self.gdbval['m_mode'])
+	if name == 'E_VOIDmode':
+	    return '<None>'
+        return name[2:] if name.startswith('E_') else name
+
+######################################################################
+
 # TODO:
 #   * hashtab
 #   * location_t
@@ -518,6 +530,9 @@ def build_pretty_printer():
                              'vec',
                              VecPrinter)
 
+    pp.add_printer_for_regex(r'opt_mode<(\S+)>',
+                             'opt_mode', OptMachineModePrinter)
+
     return pp
 
 gdb.printing.register_pretty_printer(
Index: gcc/ada/gcc-interface/decl.c
===================================================================
--- gcc/ada/gcc-interface/decl.c	2017-07-13 09:25:13.387236070 +0100
+++ gcc/ada/gcc-interface/decl.c	2017-08-29 15:52:16.784301288 +0100
@@ -8576,7 +8576,7 @@ validate_size (Uint uint_size, tree gnu_
     {
       machine_mode p_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
       while (!targetm.valid_pointer_mode (p_mode))
-	p_mode = GET_MODE_WIDER_MODE (p_mode);
+	p_mode = GET_MODE_WIDER_MODE (p_mode).require ();
       type_size = bitsize_int (GET_MODE_BITSIZE (p_mode));
     }
Jeff Law Aug. 29, 2017, 3:15 p.m. | #7
On 08/29/2017 09:01 AM, Richard Sandiford wrote:
> Jeff Law <law@redhat.com> writes:

> 

> OK, here's a patch that uses require ().  I've updated the following

> patches in the obvious way.

Thanks.

> 

> This does make me want to reconsider another decision though.

> Using opt_mode for iterators leads to things like:

> 

>   opt_scalar_int_mode wider_mode_iter;

>   FOR_EACH_WIDER_MODE (wider_mode_iter, mode)

>     {

>       scalar_int_mode wider_mode = wider_mode_iter.require ();

>       if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>         ...

> 

> which isn't pretty.  It would be easy to support:

No ideal, but it's reasonably explicit in what it does, so I wouldn't
expect anyone to be surprised.


> 

>   scalar_int_mode wider_mode;

>   FOR_EACH_WIDER_MODE (wider_mode, mode)

>     if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>       ...

> 

> *but* this would mean that "wider_mode" is accessible but undefined

> after the loop (unlike the first loop, where wider_mode_iter is

> guaranteed to be empty if the loop runs to completion).  Is that OK?

> Or is it too suprising?

I think most folks would be surprised that they can't look at wider_mode
in a meaningful way after the loop.

> 

> Another alternative would be:

> 

>   opt_scalar_int_mode wider_mode_iter;

>   scalar_int_mode wider_mode;

>   FOR_EACH_WIDER_MODE (wider_mode_iter, wider_mode, mode)

>     if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>       ...

> 

> which gives both.  But perhaps this would be odd for plain machine_mode

> iterators, where there's no obvious distinction between the first and

> second arguments.

Well, this is like the first to me, except we've separated the iterator
from the mode.

I slightly prefer the first and think the second is probably too
different from the traditional way we think about the state of loop
variables after the loop has terminated.

Jeff
Richard Sandiford Aug. 29, 2017, 3:36 p.m. | #8
Jeff Law <law@redhat.com> writes:
> On 08/29/2017 09:01 AM, Richard Sandiford wrote:

>> Jeff Law <law@redhat.com> writes:

>> 

>> OK, here's a patch that uses require ().  I've updated the following

>> patches in the obvious way.

> Thanks.

>

>> 

>> This does make me want to reconsider another decision though.

>> Using opt_mode for iterators leads to things like:

>> 

>>   opt_scalar_int_mode wider_mode_iter;

>>   FOR_EACH_WIDER_MODE (wider_mode_iter, mode)

>>     {

>>       scalar_int_mode wider_mode = wider_mode_iter.require ();

>>       if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>>         ...

>> 

>> which isn't pretty.  It would be easy to support:

> No ideal, but it's reasonably explicit in what it does, so I wouldn't

> expect anyone to be surprised.

>

>

>> 

>>   scalar_int_mode wider_mode;

>>   FOR_EACH_WIDER_MODE (wider_mode, mode)

>>     if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>>       ...

>> 

>> *but* this would mean that "wider_mode" is accessible but undefined

>> after the loop (unlike the first loop, where wider_mode_iter is

>> guaranteed to be empty if the loop runs to completion).  Is that OK?

>> Or is it too suprising?

> I think most folks would be surprised that they can't look at wider_mode

> in a meaningful way after the loop.

>

>> 

>> Another alternative would be:

>> 

>>   opt_scalar_int_mode wider_mode_iter;

>>   scalar_int_mode wider_mode;

>>   FOR_EACH_WIDER_MODE (wider_mode_iter, wider_mode, mode)

>>     if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>>       ...

>> 

>> which gives both.  But perhaps this would be odd for plain machine_mode

>> iterators, where there's no obvious distinction between the first and

>> second arguments.

> Well, this is like the first to me, except we've separated the iterator

> from the mode.

>

> I slightly prefer the first and think the second is probably too

> different from the traditional way we think about the state of loop

> variables after the loop has terminated.


OK, that's easy then :-)  Is OK to apply the approved parts of the
series with the "require" change then?  If the consensus ends up
being that we should handle the iterators a different way, I'll
volunteer to do a bulk update.

Thanks again for all the reviews.

Richard
Jeff Law Aug. 29, 2017, 3:40 p.m. | #9
On 08/29/2017 09:36 AM, Richard Sandiford wrote:
> Jeff Law <law@redhat.com> writes:

>> On 08/29/2017 09:01 AM, Richard Sandiford wrote:

>>> Jeff Law <law@redhat.com> writes:

>>>

>>> OK, here's a patch that uses require ().  I've updated the following

>>> patches in the obvious way.

>> Thanks.

>>

>>>

>>> This does make me want to reconsider another decision though.

>>> Using opt_mode for iterators leads to things like:

>>>

>>>   opt_scalar_int_mode wider_mode_iter;

>>>   FOR_EACH_WIDER_MODE (wider_mode_iter, mode)

>>>     {

>>>       scalar_int_mode wider_mode = wider_mode_iter.require ();

>>>       if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>>>         ...

>>>

>>> which isn't pretty.  It would be easy to support:

>> No ideal, but it's reasonably explicit in what it does, so I wouldn't

>> expect anyone to be surprised.

>>

>>

>>>

>>>   scalar_int_mode wider_mode;

>>>   FOR_EACH_WIDER_MODE (wider_mode, mode)

>>>     if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>>>       ...

>>>

>>> *but* this would mean that "wider_mode" is accessible but undefined

>>> after the loop (unlike the first loop, where wider_mode_iter is

>>> guaranteed to be empty if the loop runs to completion).  Is that OK?

>>> Or is it too suprising?

>> I think most folks would be surprised that they can't look at wider_mode

>> in a meaningful way after the loop.

>>

>>>

>>> Another alternative would be:

>>>

>>>   opt_scalar_int_mode wider_mode_iter;

>>>   scalar_int_mode wider_mode;

>>>   FOR_EACH_WIDER_MODE (wider_mode_iter, wider_mode, mode)

>>>     if (optab_handler (unoptab, wider_mode) != CODE_FOR_nothing)

>>>       ...

>>>

>>> which gives both.  But perhaps this would be odd for plain machine_mode

>>> iterators, where there's no obvious distinction between the first and

>>> second arguments.

>> Well, this is like the first to me, except we've separated the iterator

>> from the mode.

>>

>> I slightly prefer the first and think the second is probably too

>> different from the traditional way we think about the state of loop

>> variables after the loop has terminated.

> 

> OK, that's easy then :-)  Is OK to apply the approved parts of the

> series with the "require" change then?  If the consensus ends up

> being that we should handle the iterators a different way, I'll

> volunteer to do a bulk update.

Yea, I think the approved parts are good to go for the trunk.  I think
that covers the whole series, except the aarch64 backend bits which I
left to the ARM folks.

> 

> Thanks again for all the reviews.

No problem.  Sorry it took so long.

jeff

Patch

Index: gcc/coretypes.h
===================================================================
--- gcc/coretypes.h	2017-07-02 10:05:20.995639436 +0100
+++ gcc/coretypes.h	2017-07-13 09:18:22.924279021 +0100
@@ -55,6 +55,7 @@  typedef const struct simple_bitmap_def *
 struct rtx_def;
 typedef struct rtx_def *rtx;
 typedef const struct rtx_def *const_rtx;
+template<typename> class opt_mode;
 
 /* Subclasses of rtx_def, using indentation to show the class
    hierarchy, along with the relevant invariant.
Index: gcc/machmode.h
===================================================================
--- gcc/machmode.h	2017-07-13 09:18:21.533429040 +0100
+++ gcc/machmode.h	2017-07-13 09:18:22.930278376 +0100
@@ -221,6 +221,72 @@  #define CLASS_HAS_WIDER_MODES_P(CLASS)
 #define POINTER_BOUNDS_MODE_P(MODE)      \
   (GET_MODE_CLASS (MODE) == MODE_POINTER_BOUNDS)
 
+/* An optional T (i.e. a T or nothing), where T is some form of mode class.
+   operator * gives the T value.  */
+template<typename T>
+class opt_mode
+{
+public:
+  enum from_int { dummy = MAX_MACHINE_MODE };
+
+  ALWAYS_INLINE opt_mode () : m_mode (E_VOIDmode) {}
+  ALWAYS_INLINE opt_mode (const T &m) : m_mode (m) {}
+  ALWAYS_INLINE opt_mode (from_int m) : m_mode (machine_mode (m)) {}
+
+  machine_mode else_void () const;
+  T operator * () const;
+
+  bool exists () const;
+  template<typename U> bool exists (U *) const;
+
+private:
+  machine_mode m_mode;
+};
+
+/* If the object contains a T, return its enum value, otherwise return
+   E_VOIDmode.  */
+
+template<typename T>
+ALWAYS_INLINE machine_mode
+opt_mode<T>::else_void () const
+{
+  return m_mode;
+}
+
+/* Assert that the object contains a T and return it.  */
+
+template<typename T>
+inline T
+opt_mode<T>::operator * () const
+{
+  gcc_checking_assert (m_mode != E_VOIDmode);
+  return typename mode_traits<T>::from_int (m_mode);
+}
+
+/* Return true if the object contains a T rather than nothing.  */
+
+template<typename T>
+ALWAYS_INLINE bool
+opt_mode<T>::exists () const
+{
+  return m_mode != E_VOIDmode;
+}
+
+/* Return true if the object contains a T, storing it in *MODE if so.  */
+
+template<typename T>
+template<typename U>
+inline bool
+opt_mode<T>::exists (U *mode) const
+{
+  if (m_mode != E_VOIDmode)
+    {
+      *mode = T (typename mode_traits<T>::from_int (m_mode));
+      return true;
+    }
+  return false;
+}
+
 /* Return the base GET_MODE_SIZE value for MODE.  */
 
 ALWAYS_INLINE unsigned short
@@ -352,13 +418,22 @@  #define GET_MODE_NUNITS(MODE) (mode_to_n
 
 /* Get the next wider natural mode (eg, QI -> HI -> SI -> DI -> TI).  */
 
-extern const unsigned char mode_wider[NUM_MACHINE_MODES];
-#define GET_MODE_WIDER_MODE(MODE) ((machine_mode) mode_wider[MODE])
+template<typename T>
+ALWAYS_INLINE opt_mode<T>
+GET_MODE_WIDER_MODE (const T &m)
+{
+  return typename opt_mode<T>::from_int (mode_wider[m]);
+}
 
 /* For scalars, this is a mode with twice the precision.  For vectors,
    this is a mode with the same inner mode but with twice the elements.  */
-extern const unsigned char mode_2xwider[NUM_MACHINE_MODES];
-#define GET_MODE_2XWIDER_MODE(MODE) ((machine_mode) mode_2xwider[MODE])
+
+template<typename T>
+ALWAYS_INLINE opt_mode<T>
+GET_MODE_2XWIDER_MODE (const T &m)
+{
+  return typename opt_mode<T>::from_int (mode_2xwider[m]);
+}
 
 /* Get the complex mode from the component mode.  */
 extern const unsigned char mode_complex[NUM_MACHINE_MODES];
@@ -497,17 +572,17 @@  struct int_n_data_t {
   inline void
   get_wider (machine_mode *iter)
   {
-    *iter = GET_MODE_WIDER_MODE (*iter);
+    *iter = GET_MODE_WIDER_MODE (*iter).else_void ();
   }
 
   /* Set mode iterator *ITER to the next widest mode in the same class.
      Such a mode is known to exist.  */
 
+  template<typename T>
   inline void
-  get_known_wider (machine_mode *iter)
+  get_known_wider (T *iter)
   {
-    *iter = GET_MODE_WIDER_MODE (*iter);
-    gcc_checking_assert (*iter != VOIDmode);
+    *iter = *GET_MODE_WIDER_MODE (*iter);
   }
 
   /* Set mode iterator *ITER to the mode that is two times wider than the
@@ -516,7 +591,7 @@  struct int_n_data_t {
   inline void
   get_2xwider (machine_mode *iter)
   {
-    *iter = GET_MODE_2XWIDER_MODE (*iter);
+    *iter = GET_MODE_2XWIDER_MODE (*iter).else_void ();
   }
 }
 
Index: gcc/combine.c
===================================================================
--- gcc/combine.c	2017-07-13 09:18:21.524430018 +0100
+++ gcc/combine.c	2017-07-13 09:18:22.914280096 +0100
@@ -7617,10 +7617,7 @@  make_extraction (machine_mode mode, rtx
       wanted_inner_mode = smallest_mode_for_size (len, MODE_INT);
       while (pos % GET_MODE_BITSIZE (wanted_inner_mode) + len
 	     > GET_MODE_BITSIZE (wanted_inner_mode))
-	{
-	  wanted_inner_mode = GET_MODE_WIDER_MODE (wanted_inner_mode);
-	  gcc_assert (wanted_inner_mode != VOIDmode);
-	}
+	wanted_inner_mode = *GET_MODE_WIDER_MODE (wanted_inner_mode);
     }
 
   orig_pos = pos;
Index: gcc/config/cr16/cr16.h
===================================================================
--- gcc/config/cr16/cr16.h	2017-04-18 19:52:36.663792154 +0100
+++ gcc/config/cr16/cr16.h	2017-07-13 09:18:22.915279989 +0100
@@ -197,9 +197,7 @@  #define CALL_USED_REGISTERS
 
 /* Returns 1 if the register is longer than word size, 0 otherwise.  */
 #define LONG_REG_P(REGNO)                                                    \
-  (HARD_REGNO_NREGS (REGNO,                                                  \
-		     GET_MODE_WIDER_MODE (smallest_mode_for_size	     \
-					 (BITS_PER_WORD, MODE_INT))) == 1)
+  (HARD_REGNO_NREGS (REGNO, *GET_MODE_WIDER_MODE (word_mode)) == 1)
 
 #define HARD_REGNO_NREGS(REGNO, MODE)                                         \
  ((REGNO >= CR16_FIRST_DWORD_REGISTER)                                        \
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c	2017-07-13 09:18:21.536428715 +0100
+++ gcc/rtlanal.c	2017-07-13 09:18:22.937277624 +0100
@@ -5671,13 +5671,15 @@  init_num_sign_bit_copies_in_rep (void)
 	/* Currently, it is assumed that TARGET_MODE_REP_EXTENDED
 	   extends to the next widest mode.  */
 	gcc_assert (targetm.mode_rep_extended (mode, in_mode) == UNKNOWN
-		    || GET_MODE_WIDER_MODE (mode) == in_mode);
+		    || *GET_MODE_WIDER_MODE (mode) == in_mode);
 
 	/* We are in in_mode.  Count how many bits outside of mode
 	   have to be copies of the sign-bit.  */
 	FOR_EACH_MODE (i, mode, in_mode)
 	  {
-	    machine_mode wider = GET_MODE_WIDER_MODE (i);
+	    /* This must always exist (for the last iteration it will be
+	       IN_MODE).  */
+	    machine_mode wider = *GET_MODE_WIDER_MODE (i);
 
 	    if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
 		/* We can only check sign-bit copies starting from the
Index: gcc/config/c6x/c6x.c
===================================================================
--- gcc/config/c6x/c6x.c	2017-07-13 09:18:19.037703403 +0100
+++ gcc/config/c6x/c6x.c	2017-07-13 09:18:22.915279989 +0100
@@ -6065,7 +6065,7 @@  c6x_rtx_costs (rtx x, machine_mode mode,
       /* Recognize a mult_highpart operation.  */
       if ((mode == HImode || mode == SImode)
 	  && GET_CODE (XEXP (x, 0)) == LSHIFTRT
-	  && GET_MODE (XEXP (x, 0)) == GET_MODE_2XWIDER_MODE (mode)
+	  && GET_MODE (XEXP (x, 0)) == *GET_MODE_2XWIDER_MODE (mode)
 	  && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
 	  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
 	  && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode))
Index: gcc/lower-subreg.c
===================================================================
--- gcc/lower-subreg.c	2017-05-18 07:51:11.882801135 +0100
+++ gcc/lower-subreg.c	2017-07-13 09:18:22.929278484 +0100
@@ -266,7 +266,7 @@  init_lower_subreg (void)
 
   memset (this_target_lower_subreg, 0, sizeof (*this_target_lower_subreg));
 
-  twice_word_mode = GET_MODE_2XWIDER_MODE (word_mode);
+  twice_word_mode = *GET_MODE_2XWIDER_MODE (word_mode);
 
   rtxes.target = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
   rtxes.source = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 2);
Index: gcc/optabs-libfuncs.c
===================================================================
--- gcc/optabs-libfuncs.c	2017-02-23 19:54:04.000000000 +0000
+++ gcc/optabs-libfuncs.c	2017-07-13 09:18:22.933278054 +0100
@@ -918,9 +918,10 @@  init_sync_libfuncs_1 (optab tab, const c
   mode = QImode;
   for (i = 1; i <= max; i *= 2)
     {
+      if (i > 1)
+	mode = *GET_MODE_2XWIDER_MODE (mode);
       buf[len + 1] = '0' + i;
       set_optab_libfunc (tab, mode, buf);
-      mode = GET_MODE_2XWIDER_MODE (mode);
     }
 }
 
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	2017-07-13 09:18:21.528429583 +0100
+++ gcc/config/i386/i386.c	2017-07-13 09:18:22.921279344 +0100
@@ -28388,6 +28388,7 @@  ix86_expand_set_or_movmem (rtx dst, rtx
   bool need_zero_guard = false;
   bool noalign;
   machine_mode move_mode = VOIDmode;
+  machine_mode wider_mode;
   int unroll_factor = 1;
   /* TODO: Once value ranges are available, fill in proper data.  */
   unsigned HOST_WIDE_INT min_size = 0;
@@ -28481,9 +28482,9 @@  ix86_expand_set_or_movmem (rtx dst, rtx
       unroll_factor = 4;
       /* Find the widest supported mode.  */
       move_mode = word_mode;
-      while (optab_handler (mov_optab, GET_MODE_WIDER_MODE (move_mode))
-	     != CODE_FOR_nothing)
-	  move_mode = GET_MODE_WIDER_MODE (move_mode);
+      while (GET_MODE_WIDER_MODE (move_mode).exists (&wider_mode)
+	     && optab_handler (mov_optab, wider_mode) != CODE_FOR_nothing)
+	move_mode = wider_mode;
 
       /* Find the corresponding vector mode with the same size as MOVE_MODE.
 	 MOVE_MODE is an integer mode at the moment (SI, DI, TI, etc.).  */
@@ -43337,7 +43338,7 @@  static bool expand_vec_perm_palignr (str
 get_mode_wider_vector (machine_mode o)
 {
   /* ??? Rely on the ordering that genmodes.c gives to vectors.  */
-  machine_mode n = GET_MODE_WIDER_MODE (o);
+  machine_mode n = *GET_MODE_WIDER_MODE (o);
   gcc_assert (GET_MODE_NUNITS (o) == GET_MODE_NUNITS (n) * 2);
   gcc_assert (GET_MODE_SIZE (o) == GET_MODE_SIZE (n));
   return n;
@@ -46605,7 +46606,8 @@  expand_vselect_vconcat (rtx target, rtx
   if (vselect_insn == NULL_RTX)
     init_vselect_insn ();
 
-  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+    return false;
   x = XEXP (SET_SRC (PATTERN (vselect_insn)), 0);
   PUT_MODE (x, v2mode);
   XEXP (x, 0) = op0;
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc/config/ia64/ia64.c	2017-07-13 09:18:19.067700078 +0100
+++ gcc/config/ia64/ia64.c	2017-07-13 09:18:22.922279236 +0100
@@ -11297,7 +11297,8 @@  expand_vselect_vconcat (rtx target, rtx
   machine_mode v2mode;
   rtx x;
 
-  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+    return false;
   x = gen_rtx_VEC_CONCAT (v2mode, op0, op1);
   return expand_vselect (target, x, perm, nelt);
 }
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2017-07-13 09:18:19.076699080 +0100
+++ gcc/config/mips/mips.c	2017-07-13 09:18:22.924279021 +0100
@@ -21105,7 +21105,8 @@  mips_expand_vselect_vconcat (rtx target,
   machine_mode v2mode;
   rtx x;
 
-  v2mode = GET_MODE_2XWIDER_MODE (GET_MODE (op0));
+  if (!GET_MODE_2XWIDER_MODE (GET_MODE (op0)).exists (&v2mode))
+    return false;
   x = gen_rtx_VEC_CONCAT (v2mode, op0, op1);
   return mips_expand_vselect (target, x, perm, nelt);
 }
Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c	2017-07-13 09:18:21.531429258 +0100
+++ gcc/expmed.c	2017-07-13 09:18:22.925278914 +0100
@@ -206,11 +206,10 @@  init_expmed_one_mode (struct init_expmed
     {
       FOR_EACH_MODE_IN_CLASS (mode_from, MODE_INT)
 	init_expmed_one_conv (all, mode, mode_from, speed);
-    }
-  if (GET_MODE_CLASS (mode) == MODE_INT)
-    {
-      machine_mode  wider_mode = GET_MODE_WIDER_MODE (mode);
-      if (wider_mode != VOIDmode)
+
+      machine_mode wider_mode;
+      if (GET_MODE_CLASS (mode) == MODE_INT
+	  && GET_MODE_WIDER_MODE (mode).exists (&wider_mode))
 	{
 	  PUT_MODE (all->zext, wider_mode);
 	  PUT_MODE (all->wide_mult, wider_mode);
@@ -3588,7 +3587,7 @@  extract_high_half (machine_mode mode, rt
 
   gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
 
-  wider_mode = GET_MODE_WIDER_MODE (mode);
+  wider_mode = *GET_MODE_WIDER_MODE (mode);
   op = expand_shift (RSHIFT_EXPR, wider_mode, op,
 		     GET_MODE_BITSIZE (mode), 0, 1);
   return convert_modes (mode, wider_mode, op, 0);
@@ -3610,7 +3609,7 @@  expmed_mult_highpart_optab (machine_mode
 
   gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
 
-  wider_mode = GET_MODE_WIDER_MODE (mode);
+  wider_mode = *GET_MODE_WIDER_MODE (mode);
   size = GET_MODE_BITSIZE (mode);
 
   /* Firstly, try using a multiplication insn that only generates the needed
@@ -3716,7 +3715,7 @@  expmed_mult_highpart_optab (machine_mode
 expmed_mult_highpart (machine_mode mode, rtx op0, rtx op1,
 		      rtx target, int unsignedp, int max_cost)
 {
-  machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+  machine_mode wider_mode = *GET_MODE_WIDER_MODE (mode);
   unsigned HOST_WIDE_INT cnst1;
   int extra_cost;
   bool sign_adjust = false;
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	2017-07-13 09:18:21.532429149 +0100
+++ gcc/expr.c	2017-07-13 09:18:22.928278591 +0100
@@ -9153,7 +9153,7 @@  #define REDUCE_BIT_FIELD(expr)	(reduce_b
 	if (code == LSHIFT_EXPR
 	    && target
 	    && REG_P (target)
-	    && mode == GET_MODE_WIDER_MODE (word_mode)
+	    && mode == GET_MODE_WIDER_MODE (word_mode).else_void ()
 	    && GET_MODE_SIZE (mode) == 2 * GET_MODE_SIZE (word_mode)
 	    && TREE_CONSTANT (treeop1)
 	    && TREE_CODE (treeop0) == SSA_NAME)
Index: gcc/lto-streamer-in.c
===================================================================
--- gcc/lto-streamer-in.c	2017-06-30 12:50:38.331658620 +0100
+++ gcc/lto-streamer-in.c	2017-07-13 09:18:22.930278376 +0100
@@ -1593,7 +1593,7 @@  lto_input_mode_table (struct lto_file_de
 				    : GET_CLASS_NARROWEST_MODE (mclass);
 	     pass ? mr < MAX_MACHINE_MODE : mr != VOIDmode;
 	     pass ? mr = (machine_mode) (mr + 1)
-		  : mr = GET_MODE_WIDER_MODE (mr))
+		  : mr = GET_MODE_WIDER_MODE (mr).else_void ())
 	  if (GET_MODE_CLASS (mr) != mclass
 	      || GET_MODE_SIZE (mr) != size
 	      || GET_MODE_PRECISION (mr) != prec
Index: gcc/optabs-query.c
===================================================================
--- gcc/optabs-query.c	2017-07-13 09:18:21.534428932 +0100
+++ gcc/optabs-query.c	2017-07-13 09:18:22.934277946 +0100
@@ -425,7 +425,7 @@  find_widening_optab_handler_and_mode (op
   for (; (permit_non_widening || from_mode != to_mode)
 	 && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
 	 && from_mode != VOIDmode;
-       from_mode = GET_MODE_WIDER_MODE (from_mode))
+       from_mode = GET_MODE_WIDER_MODE (from_mode).else_void ())
     {
       enum insn_code handler = widening_optab_handler (op, to_mode,
 						       from_mode);
Index: gcc/stor-layout.c
===================================================================
--- gcc/stor-layout.c	2017-07-13 09:18:21.536428715 +0100
+++ gcc/stor-layout.c	2017-07-13 09:18:22.938277517 +0100
@@ -2719,7 +2719,8 @@  fixup_unsigned_type (tree type)
 bool
 bit_field_mode_iterator::next_mode (machine_mode *out_mode)
 {
-  for (; m_mode != VOIDmode; m_mode = GET_MODE_WIDER_MODE (m_mode))
+  for (; m_mode != VOIDmode;
+       m_mode = GET_MODE_WIDER_MODE (m_mode).else_void ())
     {
       unsigned int unit = GET_MODE_BITSIZE (m_mode);
 
@@ -2756,7 +2757,7 @@  bit_field_mode_iterator::next_mode (mach
 	break;
 
       *out_mode = m_mode;
-      m_mode = GET_MODE_WIDER_MODE (m_mode);
+      m_mode = GET_MODE_WIDER_MODE (m_mode).else_void ();
       m_count++;
       return true;
     }
Index: gcc/internal-fn.c
===================================================================
--- gcc/internal-fn.c	2017-07-08 11:37:46.037390715 +0100
+++ gcc/internal-fn.c	2017-07-13 09:18:22.929278484 +0100
@@ -1446,14 +1446,14 @@  expand_mul_overflow (location_t loc, tre
       struct separate_ops ops;
       int prec = GET_MODE_PRECISION (mode);
       machine_mode hmode = mode_for_size (prec / 2, MODE_INT, 1);
+      machine_mode wmode;
       ops.op0 = make_tree (type, op0);
       ops.op1 = make_tree (type, op1);
       ops.op2 = NULL_TREE;
       ops.location = loc;
-      if (GET_MODE_2XWIDER_MODE (mode) != VOIDmode
-	  && targetm.scalar_mode_supported_p (GET_MODE_2XWIDER_MODE (mode)))
+      if (GET_MODE_2XWIDER_MODE (mode).exists (&wmode)
+	  && targetm.scalar_mode_supported_p (wmode))
 	{
-	  machine_mode wmode = GET_MODE_2XWIDER_MODE (mode);
 	  ops.code = WIDEN_MULT_EXPR;
 	  ops.type
 	    = build_nonstandard_integer_type (GET_MODE_PRECISION (wmode), uns);
Index: gcc/omp-low.c
===================================================================
--- gcc/omp-low.c	2017-07-13 09:18:21.533429040 +0100
+++ gcc/omp-low.c	2017-07-13 09:18:22.933278054 +0100
@@ -3452,8 +3452,8 @@  omp_clause_aligned_alignment (tree claus
 	  continue;
 	while (vs
 	       && GET_MODE_SIZE (vmode) < vs
-	       && GET_MODE_2XWIDER_MODE (vmode) != VOIDmode)
-	  vmode = GET_MODE_2XWIDER_MODE (vmode);
+	       && GET_MODE_2XWIDER_MODE (vmode).exists ())
+	  vmode = *GET_MODE_2XWIDER_MODE (vmode);
 
 	tree type = lang_hooks.types.type_for_mode (mode, 1);
 	if (type == NULL_TREE || TYPE_MODE (type) != mode)
Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c	2017-07-13 09:18:21.537428606 +0100
+++ gcc/tree-ssa-math-opts.c	2017-07-13 09:18:22.939277409 +0100
@@ -3160,8 +3160,8 @@  convert_mult_to_widen (gimple *stmt, gim
 	      || (TYPE_UNSIGNED (type2)
 		  && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
 	    {
-	      from_mode = GET_MODE_WIDER_MODE (from_mode);
-	      if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
+	      if (!GET_MODE_WIDER_MODE (from_mode).exists (&from_mode)
+		  || GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode))
 		return false;
 	    }
 
@@ -3342,8 +3342,8 @@  convert_plusminus_to_widen (gimple_stmt_
 	  || (from_unsigned2
 	      && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode)))
 	{
-	  from_mode = GET_MODE_WIDER_MODE (from_mode);
-	  if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
+	  if (!GET_MODE_WIDER_MODE (from_mode).exists (&from_mode)
+	      || GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode))
 	    return false;
 	}
 
Index: gcc/tree-switch-conversion.c
===================================================================
--- gcc/tree-switch-conversion.c	2017-07-13 09:18:22.307345334 +0100
+++ gcc/tree-switch-conversion.c	2017-07-13 09:18:22.939277409 +0100
@@ -1085,8 +1085,7 @@  array_value_type (gswitch *swtch, tree t
 	  if (sign == 1)
 	    sign = 0;
 
-	  mode = GET_MODE_WIDER_MODE (mode);
-	  if (mode == VOIDmode
+	  if (!GET_MODE_WIDER_MODE (mode).exists (&mode)
 	      || GET_MODE_SIZE (mode) >= GET_MODE_SIZE (type_mode))
 	    return type;
 	}
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	2017-07-13 09:18:21.539428389 +0100
+++ gcc/var-tracking.c	2017-07-13 09:18:22.945276764 +0100
@@ -8706,12 +8706,11 @@  emit_note_insn_var_location (variable **
       last_limit = offsets[n_var_parts] + GET_MODE_SIZE (mode);
 
       /* Attempt to merge adjacent registers or memory.  */
-      wider_mode = GET_MODE_WIDER_MODE (mode);
       for (j = i + 1; j < var->n_var_parts; j++)
 	if (last_limit <= VAR_PART_OFFSET (var, j))
 	  break;
       if (j < var->n_var_parts
-	  && wider_mode != VOIDmode
+	  && GET_MODE_WIDER_MODE (mode).exists (&wider_mode)
 	  && var->var_part[j].cur_loc
 	  && mode == GET_MODE (var->var_part[j].cur_loc)
 	  && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	2017-07-05 16:25:08.469709143 +0100
+++ gcc/tree-vrp.c	2017-07-13 09:18:22.943276979 +0100
@@ -10115,7 +10115,7 @@  simplify_float_conversion_using_ranges (
   else
     {
       mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-      do
+      for (;;)
 	{
 	  /* If we cannot do a signed conversion to float from mode
 	     or if the value-range does not fit in the signed type
@@ -10124,15 +10124,12 @@  simplify_float_conversion_using_ranges (
 	      && range_fits_type_p (vr, GET_MODE_PRECISION (mode), SIGNED))
 	    break;
 
-	  mode = GET_MODE_WIDER_MODE (mode);
 	  /* But do not widen the input.  Instead leave that to the
 	     optabs expansion code.  */
-	  if (GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
+	  if (!GET_MODE_WIDER_MODE (mode).exists (&mode)
+	      || GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
 	    return false;
 	}
-      while (mode != VOIDmode);
-      if (mode == VOIDmode)
-	return false;
     }
 
   /* It works, insert a truncation or sign-change before the
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	2017-07-13 09:18:21.534428932 +0100
+++ gcc/optabs.c	2017-07-13 09:18:22.935277839 +0100
@@ -1185,13 +1185,13 @@  expand_binop (machine_mode mode, optab b
      takes operands of this mode and makes a wider mode.  */
 
   if (binoptab == smul_optab
-      && GET_MODE_2XWIDER_MODE (mode) != VOIDmode
-      && (widening_optab_handler ((unsignedp ? umul_widen_optab
-					     : smul_widen_optab),
-				  GET_MODE_2XWIDER_MODE (mode), mode)
-	  != CODE_FOR_nothing))
+      && GET_MODE_2XWIDER_MODE (mode).exists (&wider_mode)
+      && (convert_optab_handler ((unsignedp
+				  ? umul_widen_optab
+				  : smul_widen_optab),
+				 wider_mode, mode) != CODE_FOR_nothing))
     {
-      temp = expand_binop (GET_MODE_2XWIDER_MODE (mode),
+      temp = expand_binop (wider_mode,
 			   unsignedp ? umul_widen_optab : smul_widen_optab,
 			   op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
 
@@ -1252,14 +1252,14 @@  expand_binop (machine_mode mode, optab b
       && methods != OPTAB_DIRECT && methods != OPTAB_LIB)
     FOR_EACH_WIDER_MODE (wider_mode, mode)
       {
+	machine_mode next_mode;
 	if (optab_handler (binoptab, wider_mode) != CODE_FOR_nothing
 	    || (binoptab == smul_optab
-		&& GET_MODE_WIDER_MODE (wider_mode) != VOIDmode
+		&& GET_MODE_WIDER_MODE (wider_mode).exists (&next_mode)
 		&& (find_widening_optab_handler ((unsignedp
 						  ? umul_widen_optab
 						  : smul_widen_optab),
-						 GET_MODE_WIDER_MODE (wider_mode),
-						 mode, 0)
+						 next_mode, mode, 0)
 		    != CODE_FOR_nothing)))
 	  {
 	    rtx xop0 = op0, xop1 = op1;
@@ -3701,7 +3701,7 @@  can_compare_p (enum rtx_code code, machi
 	  && optab_handler (cmov_optab, mode) != CODE_FOR_nothing)
 	return 1;
 
-      mode = GET_MODE_WIDER_MODE (mode);
+      mode = GET_MODE_WIDER_MODE (mode).else_void ();
       PUT_MODE (test, mode);
     }
   while (mode != VOIDmode);
Index: gcc/gdbhooks.py
===================================================================
--- gcc/gdbhooks.py	2017-02-23 19:54:12.000000000 +0000
+++ gcc/gdbhooks.py	2017-07-13 09:18:22.928278591 +0100
@@ -422,6 +422,18 @@  class VecPrinter:
 
 ######################################################################
 
+class OptMachineModePrinter:
+    def __init__(self, gdbval):
+        self.gdbval = gdbval
+
+    def to_string (self):
+        name = str(self.gdbval['m_mode'])
+	if name == 'E_VOIDmode':
+	    return '<None>'
+        return name[2:] if name.startswith('E_') else name
+
+######################################################################
+
 # TODO:
 #   * hashtab
 #   * location_t
@@ -518,6 +530,9 @@  def build_pretty_printer():
                              'vec',
                              VecPrinter)
 
+    pp.add_printer_for_regex(r'opt_mode<(\S+)>',
+                             'opt_mode', OptMachineModePrinter)
+
     return pp
 
 gdb.printing.register_pretty_printer(
Index: gcc/ada/gcc-interface/decl.c
===================================================================
--- gcc/ada/gcc-interface/decl.c	2017-06-22 12:22:56.063377521 +0100
+++ gcc/ada/gcc-interface/decl.c	2017-07-13 09:18:22.913280204 +0100
@@ -8576,7 +8576,7 @@  validate_size (Uint uint_size, tree gnu_
     {
       machine_mode p_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
       while (!targetm.valid_pointer_mode (p_mode))
-	p_mode = GET_MODE_WIDER_MODE (p_mode);
+	p_mode = *GET_MODE_WIDER_MODE (p_mode);
       type_size = bitsize_int (GET_MODE_BITSIZE (p_mode));
     }