static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT mask;
+  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
 
       if (signmask)
        {
          signmask = force_reg (mode, signmask);
-         mask = ((HOST_WIDE_INT) 1 << logd) - 1;
+         masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
          shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
          /* Use the rtx_cost of a LSHIFTRT instruction to determine
             which instruction sequence to use.  If logical right shifts
             are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
             use a LSHIFTRT, 1 ADD, 1 SUB and an AND.  */
-            
+
          temp = gen_rtx_LSHIFTRT (mode, result, shift);
          if (lshr_optab->handlers[mode].insn_code == CODE_FOR_nothing
              || rtx_cost (temp, SET) > COSTS_N_INSNS (2))
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, sub_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+             temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, xor_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
              temp = expand_binop (mode, add_optab, op0, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+             temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, sub_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
      can avoid an explicit compare operation in the following comparison
      against zero.  */
 
-  mask = (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1)
-        | (((HOST_WIDE_INT) 1 << logd) - 1);
+  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
+  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+    {
+      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
+      maskhigh = -1;
+    }
+  else
+    maskhigh = (HOST_WIDE_INT) -1
+                << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
 
-  temp = expand_binop (mode, and_optab, op0, GEN_INT (mask), result,
-                      1, OPTAB_LIB_WIDEN);
+  temp = expand_binop (mode, and_optab, op0,
+                      immed_double_const (masklow, maskhigh, mode),
+                      result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
 
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
-  mask = (HOST_WIDE_INT) -1 << logd;
-  temp = expand_binop (mode, ior_optab, temp, GEN_INT (mask), result,
-                      1, OPTAB_LIB_WIDEN);
+  masklow = (HOST_WIDE_INT) -1 << logd;
+  maskhigh = -1;
+  temp = expand_binop (mode, ior_optab, temp,
+                      immed_double_const (masklow, maskhigh, mode),
+                      result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
   if (temp != result)