diff -rup gcc-20120418-orig/gcc/expmed.c gcc-20120418/gcc/expmed.c
--- gcc-20120418-orig/gcc/expmed.c	2012-04-20 14:00:49.125256428 +0400
+++ gcc-20120418/gcc/expmed.c	2012-04-20 16:15:08.305042269 +0400
@@ -3523,6 +3523,68 @@ expand_mult_highpart_optab (enum machine
 	}
     }
 
+  if (size - 1 > BITS_PER_WORD
+      && BITS_PER_WORD == 32 && mode == DImode)
+    {
+      unsigned HOST_WIDE_INT d;
+      rtx x1, x0, y1, y0, z2, z0, tmp, tmp1, u0, u0tmp, u1, c, c1, ccst, cres, result, seq;
+
+      d = (INTVAL (op1) & GET_MODE_MASK (DImode));
+      start_sequence ();
+      x1 = gen_highpart (SImode, op0);
+      x1 = force_reg (SImode, x1);
+      x0 = gen_lowpart (SImode, op0);
+      x0 = force_reg (SImode, x0);
+
+      x1 = convert_to_mode (DImode, x1, 0);
+      x0 = convert_to_mode (DImode, x0, 0);
+
+      y0 = gen_rtx_CONST_INT (DImode, d&UINT_MAX);
+      y1 = gen_rtx_CONST_INT (DImode, d>>32);
+
+      z2 = gen_reg_rtx (DImode);
+      u0 = gen_reg_rtx (DImode);
+
+      z2 = expand_mult(DImode, x1, y1, z2, 0);
+      u0 = expand_mult(DImode, x0, y1, u0, 0);
+
+      z0 = gen_reg_rtx (DImode);
+      u1 = gen_reg_rtx (DImode);
+      z0 = expand_mult(DImode, x0, y0, z0, 0);
+      u1 = expand_mult(DImode, x1, y0, u1, 0);
+
+      u0tmp = gen_reg_rtx (DImode);
+      u0tmp = expand_shift (RSHIFT_EXPR, DImode, z0, 32, u0tmp, 1);
+      expand_inc (u0, u0tmp);
+      tmp = gen_reg_rtx (DImode);
+      tmp = expand_binop (DImode, add_optab, u0, u1, tmp, 1, OPTAB_LIB_WIDEN);
+      if (!tmp)
+             return 0;
+
+      c = gen_reg_rtx (DImode);
+      c1 = gen_reg_rtx (DImode);
+      cres = gen_reg_rtx (DImode);
+      emit_store_flag_force (c, GT, u0, tmp, DImode, 1, -1);
+      emit_store_flag_force (c1, GT, u1, tmp, DImode, 1, -1);
+      result = expand_binop (DImode, ior_optab, c, c1, cres, 1, OPTAB_LIB_WIDEN);
+      if (!result)
+           return 0;
+
+      ccst = gen_reg_rtx (DImode);
+      ccst = expand_shift (LSHIFT_EXPR, DImode, cres, 32, ccst, 1);
+
+      expand_inc (z2, ccst);
+
+      tmp1 = gen_reg_rtx (DImode);
+      tmp1 = expand_shift (RSHIFT_EXPR, DImode, tmp, 32, NULL_RTX, 1);
+      expand_inc (z2, tmp1);
+      seq = get_insns ();
+      end_sequence ();
+      emit_insn (seq);
+      return z2;
+
+    }
+
   /* Try widening multiplication of opposite signedness, and adjust.  */
   moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
   if (widening_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
