diff --git a/gcc/expmed.c b/gcc/expmed.c
index 1fe0034..d91d8f1 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -101,7 +101,6 @@ struct init_expmed_rtl
   struct rtx_def mult;	rtunion mult_fld1;
   struct rtx_def sdiv;	rtunion sdiv_fld1;
   struct rtx_def udiv;	rtunion udiv_fld1;
-  struct rtx_def zext;
   struct rtx_def sdiv_32;	rtunion sdiv_32_fld1;
   struct rtx_def smod_32;	rtunion smod_32_fld1;
   struct rtx_def wide_mult;	rtunion wide_mult_fld1;
@@ -112,13 +111,36 @@ struct init_expmed_rtl
   struct rtx_def shift_add;	rtunion shift_add_fld1;
   struct rtx_def shift_sub0;	rtunion shift_sub0_fld1;
   struct rtx_def shift_sub1;	rtunion shift_sub1_fld1;
-  struct rtx_def convert;
+  struct rtx_def zext;
+  struct rtx_def trunc;
 
   rtx pow2[MAX_BITS_PER_WORD];
   rtx cint[MAX_BITS_PER_WORD];
 };
 
 static void
+init_expmed_one_conv (struct init_expmed_rtl *all, enum machine_mode to_mode,
+		      enum machine_mode from_mode, bool speed)
+{
+  int to_size, from_size;
+  rtx which;
+
+  /* We're given no information about the true size of a partial integer,
+     only the size of the "full" integer it requires for storage.  For
+     comparison purposes here, reduce the bit size by one in that case.  */
+  to_size = (GET_MODE_BITSIZE (to_mode)
+	     - (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT));
+  from_size = (GET_MODE_BITSIZE (from_mode)
+	       - (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT));
+  
+  /* Assume cost of zero-extend and sign-extend is the same.  */
+  which = (to_size < from_size ? &all->trunc : &all->zext);
+
+  PUT_MODE (&all->reg, from_mode);
+  set_convert_cost (to_mode, from_mode, speed, set_src_cost (which, speed));
+}
+
+static void
 init_expmed_one_mode (struct init_expmed_rtl *all,
 		      enum machine_mode mode, int speed)
 {
@@ -141,7 +163,8 @@ init_expmed_one_mode (struct init_expmed_rtl *all,
   PUT_MODE (&all->shift_add, mode);
   PUT_MODE (&all->shift_sub0, mode);
   PUT_MODE (&all->shift_sub1, mode);
-  PUT_MODE (&all->convert, mode);
+  PUT_MODE (&all->zext, mode);
+  PUT_MODE (&all->trunc, mode);
 
   set_add_cost (speed, mode, set_src_cost (&all->plus, speed));
   set_neg_cost (speed, mode, set_src_cost (&all->neg, speed));
@@ -176,8 +199,13 @@ init_expmed_one_mode (struct init_expmed_rtl *all,
 
   if (SCALAR_INT_MODE_P (mode))
     {
-      enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
-
+      for (mode_from = MIN_MODE_INT; mode_from <= MAX_MODE_INT;
+	   mode_from = (enum machine_mode)(mode_from + 1))
+	init_expmed_one_conv (all, mode, mode_from, speed);
+    }
+  if (GET_MODE_CLASS (mode) == MODE_INT)
+    {
+      enum machine_mode  wider_mode = GET_MODE_WIDER_MODE (mode);
       if (wider_mode != VOIDmode)
 	{
 	  PUT_MODE (&all->zext, wider_mode);
@@ -185,33 +213,11 @@ init_expmed_one_mode (struct init_expmed_rtl *all,
 	  PUT_MODE (&all->wide_lshr, wider_mode);
 	  XEXP (&all->wide_lshr, 1) = GEN_INT (mode_bitsize);
 
-	  set_mul_widen_cost (speed, wider_mode, set_src_cost (&all->wide_mult, speed));
-	  set_mul_highpart_cost (speed, mode, set_src_cost (&all->wide_trunc, speed));
+	  set_mul_widen_cost (speed, wider_mode,
+			      set_src_cost (&all->wide_mult, speed));
+	  set_mul_highpart_cost (speed, mode,
+				 set_src_cost (&all->wide_trunc, speed));
 	}
-
-      for (mode_from = GET_CLASS_NARROWEST_MODE (MODE_INT);
-	   mode_from != VOIDmode;
-	   mode_from = GET_MODE_WIDER_MODE (mode_from))
-	if (mode != mode_from)
-	  {
-	    unsigned short size_to = GET_MODE_SIZE (mode);
-	    unsigned short size_from = GET_MODE_SIZE (mode_from);
-	    if (size_to < size_from)
-	      {
-		PUT_CODE (&all->convert, TRUNCATE);
-		PUT_MODE (&all->reg, mode_from);
-		set_convert_cost (mode, mode_from, speed,
-				  set_src_cost (&all->convert, speed));
-	      }
-	    else if (size_from < size_to)
-	      {
-		/* Assume cost of zero-extend and sign-extend is the same.  */
-		PUT_CODE (&all->convert, ZERO_EXTEND);
-		PUT_MODE (&all->reg, mode_from);
-		set_convert_cost (mode, mode_from, speed,
-				  set_src_cost (&all->convert, speed));
-	      }
-	  }
     }
 }
 
@@ -291,23 +297,27 @@ init_expmed (void)
   XEXP (&all.shift_sub1, 0) = &all.reg;
   XEXP (&all.shift_sub1, 1) = &all.shift_mult;
 
-  PUT_CODE (&all.convert, TRUNCATE);
-  XEXP (&all.convert, 0) = &all.reg;
+  PUT_CODE (&all.trunc, TRUNCATE);
+  XEXP (&all.trunc, 0) = &all.reg;
 
   for (speed = 0; speed < 2; speed++)
     {
       crtl->maybe_hot_insn_p = speed;
       set_zero_cost (speed, set_src_cost (const0_rtx, speed));
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-	   mode != VOIDmode;
-	   mode = GET_MODE_WIDER_MODE (mode))
+      for (mode = MIN_MODE_INT; mode <= MAX_MODE_INT;
+	   mode = (enum machine_mode)(mode + 1))
 	init_expmed_one_mode (&all, mode, speed);
 
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
-	   mode != VOIDmode;
-	   mode = GET_MODE_WIDER_MODE (mode))
-	init_expmed_one_mode (&all, mode, speed);
+      if (MIN_MODE_PARTIAL_INT != VOIDmode)
+	for (mode = MIN_MODE_PARTIAL_INT; mode <= MAX_MODE_PARTIAL_INT;
+	     mode = (enum machine_mode)(mode + 1))
+	  init_expmed_one_mode (&all, mode, speed);
+
+      if (MIN_MODE_VECTOR_INT != VOIDmode)
+	for (mode = MIN_MODE_VECTOR_INT; mode <= MAX_MODE_VECTOR_INT;
+	     mode = (enum machine_mode)(mode + 1))
+	  init_expmed_one_mode (&all, mode, speed);
     }
 
   if (alg_hash_used_p ())
diff --git a/gcc/expmed.h b/gcc/expmed.h
index bde5cae..05d0c15 100644
--- a/gcc/expmed.h
+++ b/gcc/expmed.h
@@ -124,23 +124,24 @@ struct alg_hash_entry {
 #define NUM_ALG_HASH_ENTRIES 307
 #endif
 
-#define NUM_MODE_INT (MAX_MODE_INT - MIN_MODE_INT + 1)
-#define NUM_MODE_VECTOR_INT (MAX_MODE_VECTOR_INT - MIN_MODE_VECTOR_INT + 1)
+#define NUM_MODE_INT \
+  (MAX_MODE_INT - MIN_MODE_INT + 1)
+#define NUM_MODE_PARTIAL_INT \
+  (MIN_MODE_PARTIAL_INT == VOIDmode ? 0 \
+   : MAX_MODE_PARTIAL_INT - MIN_MODE_PARTIAL_INT + 1)
+#define NUM_MODE_VECTOR_INT \
+  (MIN_MODE_VECTOR_INT == VOIDmode ? 0 \
+   : MAX_MODE_VECTOR_INT - MIN_MODE_VECTOR_INT + 1)
+
+#define NUM_MODE_IP_INT (NUM_MODE_INT + NUM_MODE_PARTIAL_INT)
+#define NUM_MODE_IPV_INT (NUM_MODE_IP_INT + NUM_MODE_VECTOR_INT)
 
 struct expmed_op_cheap {
-  /* Whether an operation is cheap in a given integer mode.  */
-  bool cheap_int[2][NUM_MODE_INT];
-
-  /* Whether an operation is cheap in a given vector integer mode.  */
-  bool cheap_vector_int[2][NUM_MODE_VECTOR_INT];
+  bool cheap[2][NUM_MODE_IPV_INT];
 };
 
 struct expmed_op_costs {
-  /* The cost of an operation in a given integer mode.  */
-  int int_cost[2][NUM_MODE_INT];
-
-  /* The cost of an operation in a given vector integer mode.  */
-  int vector_int_cost[2][NUM_MODE_VECTOR_INT];
+  int cost[2][NUM_MODE_IPV_INT];
 };
 
 /* Target-dependent globals.  */
@@ -178,7 +179,7 @@ struct target_expmed {
   /* Conversion costs are only defined between two scalar integer modes
      of different sizes.  The first machine mode is the destination mode,
      and the second is the source mode.  */
-  int x_convert_cost[2][NUM_MODE_INT][NUM_MODE_INT];
+  int x_convert_cost[2][NUM_MODE_IP_INT][NUM_MODE_IP_INT];
 };
 
 extern struct target_expmed default_target_expmed;
@@ -212,6 +213,24 @@ set_alg_hash_used_p (bool usedp)
   this_target_expmed->x_alg_hash_used_p = usedp;
 }
 
+/* Compute an index into the cost arrays by mode class.  */
+
+static inline int
+expmed_mode_index (enum machine_mode mode)
+{
+  switch (GET_MODE_CLASS (mode))
+    {
+    case MODE_INT:
+      return mode - MIN_MODE_INT;
+    case MODE_PARTIAL_INT:
+      return mode - MIN_MODE_PARTIAL_INT + NUM_MODE_INT;
+    case MODE_VECTOR_INT:
+      return mode - MIN_MODE_VECTOR_INT + NUM_MODE_IP_INT;
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Return a pointer to a boolean contained in EOC indicating whether
    a particular operation performed in MODE is cheap when optimizing
    for SPEED.  */
@@ -220,19 +239,8 @@ static inline bool *
 expmed_op_cheap_ptr (struct expmed_op_cheap *eoc, bool speed,
 		     enum machine_mode mode)
 {
-  gcc_assert (GET_MODE_CLASS (mode) == MODE_INT
-	      || GET_MODE_CLASS (mode) == MODE_VECTOR_INT);
-
-  if (GET_MODE_CLASS (mode) == MODE_INT)
-    {
-      int idx = mode - MIN_MODE_INT;
-      return &eoc->cheap_int[speed][idx];
-    }
-  else
-    {
-      int idx = mode - MIN_MODE_VECTOR_INT;
-      return &eoc->cheap_vector_int[speed][idx];
-    }
+  int idx = expmed_mode_index (mode);
+  return &eoc->cheap[speed][idx];
 }
 
 /* Return a pointer to a cost contained in COSTS when a particular
@@ -242,19 +250,8 @@ static inline int *
 expmed_op_cost_ptr (struct expmed_op_costs *costs, bool speed,
 		    enum machine_mode mode)
 {
-  gcc_assert (GET_MODE_CLASS (mode) == MODE_INT
-	      || GET_MODE_CLASS (mode) == MODE_VECTOR_INT);
-
-  if (GET_MODE_CLASS (mode) == MODE_INT)
-    {
-      int idx = mode - MIN_MODE_INT;
-      return &costs->int_cost[speed][idx];
-    }
-  else
-    {
-      int idx = mode - MIN_MODE_VECTOR_INT;
-      return &costs->vector_int_cost[speed][idx];
-    }
+  int idx = expmed_mode_index (mode);
+  return &costs->cost[speed][idx];
 }
 
 /* Subroutine of {set_,}sdiv_pow2_cheap.  Not to be used otherwise.  */
@@ -631,15 +628,12 @@ static inline int *
 convert_cost_ptr (enum machine_mode to_mode, enum machine_mode from_mode,
 		  bool speed)
 {
-  int to_idx, from_idx;
+  int to_idx = expmed_mode_index (to_mode);
+  int from_idx = expmed_mode_index (from_mode);
 
-  gcc_assert (to_mode >= MIN_MODE_INT
-	      && to_mode <= MAX_MODE_INT
-	      && from_mode >= MIN_MODE_INT
-	      && from_mode <= MAX_MODE_INT);
+  gcc_assert (IN_RANGE (to_idx, 0, NUM_MODE_IP_INT - 1));
+  gcc_assert (IN_RANGE (from_idx, 0, NUM_MODE_IP_INT - 1));
 
-  to_idx = to_mode - MIN_MODE_INT;
-  from_idx = from_mode - MIN_MODE_INT;
   return &this_target_expmed->x_convert_cost[speed][to_idx][from_idx];
 }
 
