Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	2017-07-13 09:18:53.274650323 +0100
+++ gcc/optabs.c	2017-07-13 09:18:56.346425666 +0100
@@ -4635,6 +4635,7 @@ expand_float (rtx to, rtx from, int unsi
 {
   enum insn_code icode;
   rtx target = to;
+  scalar_mode from_mode, to_mode;
   machine_mode fmode, imode;
   bool can_do_signed = false;
 
@@ -4684,7 +4685,10 @@ expand_float (rtx to, rtx from, int unsi
 
   /* Unsigned integer, and no way to convert directly.  Convert as signed,
      then unconditionally adjust the result.  */
-  if (unsignedp && can_do_signed)
+  if (unsignedp
+      && can_do_signed
+      && is_a <scalar_mode> (GET_MODE (to), &to_mode)
+      && is_a <scalar_mode> (GET_MODE (from), &from_mode))
     {
       rtx_code_label *label = gen_label_rtx ();
       rtx temp;
@@ -4694,19 +4698,19 @@ expand_float (rtx to, rtx from, int unsi
 	 least as wide as the target.  Using FMODE will avoid rounding woes
 	 with unsigned values greater than the signed maximum value.  */
 
-      FOR_EACH_MODE_FROM (fmode, GET_MODE (to))
-	if (GET_MODE_PRECISION (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
-	    && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
+      FOR_EACH_MODE_FROM (fmode, to_mode)
+	if (GET_MODE_PRECISION (from_mode) < GET_MODE_BITSIZE (fmode)
+	    && can_float_p (fmode, from_mode, 0) != CODE_FOR_nothing)
 	  break;
 
       if (fmode == VOIDmode)
 	{
 	  /* There is no such mode.  Pretend the target is wide enough.  */
-	  fmode = GET_MODE (to);
+	  fmode = to_mode;
 
 	  /* Avoid double-rounding when TO is narrower than FROM.  */
 	  if ((significand_size (fmode) + 1)
-	      < GET_MODE_PRECISION (GET_MODE (from)))
+	      < GET_MODE_PRECISION (from_mode))
 	    {
 	      rtx temp1;
 	      rtx_code_label *neglabel = gen_label_rtx ();
@@ -4718,7 +4722,7 @@ expand_float (rtx to, rtx from, int unsi
 		  || GET_MODE (target) != fmode)
 		target = gen_reg_rtx (fmode);
 
-	      imode = GET_MODE (from);
+	      imode = from_mode;
 	      do_pending_stack_adjust ();
 
 	      /* Test whether the sign bit is set.  */
@@ -4758,7 +4762,7 @@ expand_float (rtx to, rtx from, int unsi
       /* If we are about to do some arithmetic to correct for an
 	 unsigned operand, do it in a pseudo-register.  */
 
-      if (GET_MODE (to) != fmode
+      if (to_mode != fmode
 	  || !REG_P (to) || REGNO (to) < FIRST_PSEUDO_REGISTER)
 	target = gen_reg_rtx (fmode);
 
@@ -4769,11 +4773,11 @@ expand_float (rtx to, rtx from, int unsi
 	 correct its value by 2**bitwidth.  */
 
       do_pending_stack_adjust ();
-      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
+      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, from_mode,
 			       0, label);
 
 
-      real_2expN (&offset, GET_MODE_PRECISION (GET_MODE (from)), fmode);
+      real_2expN (&offset, GET_MODE_PRECISION (from_mode), fmode);
       temp = expand_binop (fmode, add_optab, target,
 			   const_double_from_real_value (offset, fmode),
 			   target, 0, OPTAB_LIB_WIDEN);
@@ -4901,11 +4905,14 @@ expand_fix (rtx to, rtx from, int unsign
      2^63.  The subtraction of 2^63 should not generate any rounding as it
      simply clears out that bit.  The rest is trivial.  */
 
-  if (unsignedp && GET_MODE_PRECISION (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
+  scalar_int_mode to_mode;
+  if (unsignedp
+      && is_a <scalar_int_mode> (GET_MODE (to), &to_mode)
+      && HWI_COMPUTABLE_MODE_P (to_mode))
     FOR_EACH_MODE_FROM (fmode, GET_MODE (from))
-      if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0, &must_trunc)
+      if (CODE_FOR_nothing != can_fix_p (to_mode, fmode, 0, &must_trunc)
 	  && (!DECIMAL_FLOAT_MODE_P (fmode)
-	      || GET_MODE_BITSIZE (fmode) > GET_MODE_PRECISION (GET_MODE (to))))
+	      || GET_MODE_BITSIZE (fmode) > GET_MODE_PRECISION (to_mode)))
 	{
 	  int bitsize;
 	  REAL_VALUE_TYPE offset;
@@ -4913,7 +4920,7 @@ expand_fix (rtx to, rtx from, int unsign
 	  rtx_code_label *lab1, *lab2;
 	  rtx_insn *insn;
 
-	  bitsize = GET_MODE_PRECISION (GET_MODE (to));
+	  bitsize = GET_MODE_PRECISION (to_mode);
 	  real_2expN (&offset, bitsize - 1, fmode);
 	  limit = const_double_from_real_value (offset, fmode);
 	  lab1 = gen_label_rtx ();
@@ -4939,10 +4946,10 @@ expand_fix (rtx to, rtx from, int unsign
 	  target = expand_binop (GET_MODE (from), sub_optab, from, limit,
 				 NULL_RTX, 0, OPTAB_LIB_WIDEN);
 	  expand_fix (to, target, 0);
-	  target = expand_binop (GET_MODE (to), xor_optab, to,
+	  target = expand_binop (to_mode, xor_optab, to,
 				 gen_int_mode
 				 (HOST_WIDE_INT_1 << (bitsize - 1),
-				  GET_MODE (to)),
+				  to_mode),
 				 to, 1, OPTAB_LIB_WIDEN);
 
 	  if (target != to)
@@ -4950,12 +4957,12 @@ expand_fix (rtx to, rtx from, int unsign
 
 	  emit_label (lab2);
 
-	  if (optab_handler (mov_optab, GET_MODE (to)) != CODE_FOR_nothing)
+	  if (optab_handler (mov_optab, to_mode) != CODE_FOR_nothing)
 	    {
 	      /* Make a place for a REG_NOTE and add it.  */
 	      insn = emit_move_insn (to, to);
 	      set_dst_reg_note (insn, REG_EQUAL,
-				gen_rtx_fmt_e (UNSIGNED_FIX, GET_MODE (to),
+				gen_rtx_fmt_e (UNSIGNED_FIX, to_mode,
 					       copy_rtx (from)),
 				to);
 	    }
