OSDN Git Service

Fix typo
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index 8f71b8b..632f24f 100644 (file)
@@ -430,14 +430,11 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
             || (offset * BITS_PER_UNIT % bitsize == 0
                 && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
     {
-      if (GET_MODE (op0) != fieldmode)
-       {
-         if (MEM_P (op0))
-           op0 = adjust_address (op0, fieldmode, offset);
-         else
-           op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
-                                      byte_offset);
-       }
+      if (MEM_P (op0))
+       op0 = adjust_address (op0, fieldmode, offset);
+      else if (GET_MODE (op0) != fieldmode)
+       op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
+                                  byte_offset);
       emit_move_insn (op0, value);
       return value;
     }
@@ -608,8 +605,8 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (HAVE_insv
       && GET_MODE (value) != BLKmode
       && !(bitsize == 1 && GET_CODE (value) == CONST_INT)
-      /* Ensure insv's size is wide enough for this field.  */
-      && (GET_MODE_BITSIZE (op_mode) >= bitsize)
+      && bitsize > 0
+      && GET_MODE_BITSIZE (op_mode) >= bitsize
       && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
            && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
     {
@@ -1356,7 +1353,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (unsignedp)
     {
       if (HAVE_extzv
-         && (GET_MODE_BITSIZE (extzv_mode) >= bitsize)
+         && bitsize > 0
+         && GET_MODE_BITSIZE (extzv_mode) >= bitsize
          && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
                && (bitsize + bitpos > GET_MODE_BITSIZE (extzv_mode))))
        {
@@ -1409,6 +1407,11 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                  xbitpos = bitnum % unit;
                  xop0 = adjust_address (xop0, bestmode, xoffset);
 
+                 /* Make sure register is big enough for the whole field. */
+                 if (xoffset * BITS_PER_UNIT + unit 
+                     < offset * BITS_PER_UNIT + bitsize)
+                   goto extzv_loses;
+
                  /* Fetch it to a register in that size.  */
                  xop0 = force_reg (bestmode, xop0);
 
@@ -1488,7 +1491,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   else
     {
       if (HAVE_extv
-         && (GET_MODE_BITSIZE (extv_mode) >= bitsize)
+         && bitsize > 0
+         && GET_MODE_BITSIZE (extv_mode) >= bitsize
          && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
                && (bitsize + bitpos > GET_MODE_BITSIZE (extv_mode))))
        {
@@ -1537,6 +1541,11 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                  xbitpos = bitnum % unit;
                  xop0 = adjust_address (xop0, bestmode, xoffset);
 
+                 /* Make sure register is big enough for the whole field. */
+                 if (xoffset * BITS_PER_UNIT + unit 
+                     < offset * BITS_PER_UNIT + bitsize)
+                   goto extv_loses;
+
                  /* Fetch it to a register in that size.  */
                  xop0 = force_reg (bestmode, xop0);
 
@@ -2227,9 +2236,9 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
              shifted = force_reg (mode, shifted);
 
              temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
-                                  mode, shifted, new_amount, subtarget, 1);
+                                  mode, shifted, new_amount, 0, 1);
              temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
-                                   mode, shifted, other_amount, 0, 1);
+                                   mode, shifted, other_amount, subtarget, 1);
              return expand_binop (mode, ior_optab, temp, temp1, target,
                                   unsignedp, methods);
            }
@@ -2237,19 +2246,6 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
          temp = expand_binop (mode,
                               left ? rotl_optab : rotr_optab,
                               shifted, op1, target, unsignedp, methods);
-
-         /* If we don't have the rotate, but we are rotating by a constant
-            that is in range, try a rotate in the opposite direction.  */
-
-         if (temp == 0 && GET_CODE (op1) == CONST_INT
-             && INTVAL (op1) > 0
-             && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
-           temp = expand_binop (mode,
-                                left ? rotr_optab : rotl_optab,
-                                shifted,
-                                GEN_INT (GET_MODE_BITSIZE (mode)
-                                         - INTVAL (op1)),
-                                target, unsignedp, methods);
        }
       else if (unsignedp)
        temp = expand_binop (mode,
@@ -2286,10 +2282,18 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
   return temp;
 }
 \f
-enum alg_code { alg_unknown, alg_zero, alg_m, alg_shift,
-                 alg_add_t_m2, alg_sub_t_m2,
-                 alg_add_factor, alg_sub_factor,
-                 alg_add_t2_m, alg_sub_t2_m };
+enum alg_code {
+  alg_unknown,
+  alg_zero,
+  alg_m, alg_shift,
+  alg_add_t_m2,
+  alg_sub_t_m2,
+  alg_add_factor,
+  alg_sub_factor,
+  alg_add_t2_m,
+  alg_sub_t2_m,
+  alg_impossible
+};
 
 /* This structure holds the "cost" of a multiply sequence.  The
    "cost" field holds the total rtx_cost of every operator in the
@@ -2363,6 +2367,11 @@ struct alg_hash_entry {
 
   /* The best multiplication algorithm for t.  */
   enum alg_code alg;
+
+  /* The cost of multiplication if ALG_CODE is not alg_impossible.
+     Otherwise, the cost within which multiplication by T is
+     impossible.  */
+  struct mult_cost cost;
 };
 
 /* The number of cache/hash entries.  */
@@ -2465,29 +2474,57 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       && alg_hash[hash_index].mode == mode
       && alg_hash[hash_index].alg != alg_unknown)
     {
-      cache_hit = true;
       cache_alg = alg_hash[hash_index].alg;
-      switch (cache_alg)
+
+      if (cache_alg == alg_impossible)
        {
-       case alg_shift:
-         goto do_alg_shift;
+         /* The cache tells us that it's impossible to synthesize
+            multiplication by T within alg_hash[hash_index].cost.  */
+         if (!CHEAPER_MULT_COST (&alg_hash[hash_index].cost, cost_limit))
+           /* COST_LIMIT is at least as restrictive as the one
+              recorded in the hash table, in which case we have no
+              hope of synthesizing a multiplication.  Just
+              return.  */
+           return;
+
+         /* If we get here, COST_LIMIT is less restrictive than the
+            one recorded in the hash table, so we may be able to
+            synthesize a multiplication.  Proceed as if we didn't
+            have the cache entry.  */
+       }
+      else
+       {
+         if (CHEAPER_MULT_COST (cost_limit, &alg_hash[hash_index].cost))
+           /* The cached algorithm shows that this multiplication
+              requires more cost than COST_LIMIT.  Just return.  This
+              way, we don't clobber this cache entry with
+              alg_impossible but retain useful information.  */
+           return;
 
-       case alg_add_t_m2:
-       case alg_sub_t_m2:
-         goto do_alg_addsub_t_m2;
+         cache_hit = true;
 
-       case alg_add_factor:
-       case alg_sub_factor:
-         goto do_alg_addsub_factor;
+         switch (cache_alg)
+           {
+           case alg_shift:
+             goto do_alg_shift;
 
-       case alg_add_t2_m:
-         goto do_alg_add_t2_m;
+           case alg_add_t_m2:
+           case alg_sub_t_m2:
+             goto do_alg_addsub_t_m2;
 
-       case alg_sub_t2_m:
-         goto do_alg_sub_t2_m;
+           case alg_add_factor:
+           case alg_sub_factor:
+             goto do_alg_addsub_factor;
 
-       default:
-         gcc_unreachable ();
+           case alg_add_t2_m:
+             goto do_alg_add_t2_m;
+
+           case alg_sub_t2_m:
+             goto do_alg_sub_t2_m;
+
+           default:
+             gcc_unreachable ();
+           }
        }
     }
 
@@ -2740,7 +2777,18 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
  done:
   /* If best_cost has not decreased, we have not found any algorithm.  */
   if (!CHEAPER_MULT_COST (&best_cost, cost_limit))
-    return;
+    {
+      /* We failed to find an algorithm.  Record alg_impossible for
+        this case (that is, <T, MODE, COST_LIMIT>) so that next time
+        we are asked to find an algorithm for T within the same or
+        lower COST_LIMIT, we can immediately return to the
+        caller.  */
+      alg_hash[hash_index].t = t;
+      alg_hash[hash_index].mode = mode;
+      alg_hash[hash_index].alg = alg_impossible;
+      alg_hash[hash_index].cost = *cost_limit;
+      return;
+    }
 
   /* Cache the result.  */
   if (!cache_hit)
@@ -2748,6 +2796,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       alg_hash[hash_index].t = t;
       alg_hash[hash_index].mode = mode;
       alg_hash[hash_index].alg = best_alg->op[best_alg->ops];
+      alg_hash[hash_index].cost.cost = best_cost.cost;
+      alg_hash[hash_index].cost.latency = best_cost.latency;
     }
 
   /* If we are getting a too long sequence for `struct algorithm'