Makefile.in (recog.o): Add insn-codes.h.
authorRichard Sandiford <rdsandiford@googlemail.com>
Sun, 18 Nov 2012 17:33:38 +0000 (17:33 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 18 Nov 2012 17:33:38 +0000 (17:33 +0000)
gcc/
* Makefile.in (recog.o): Add insn-codes.h.
* expr.h (extraction_pattern): Move to optabs.h.
(mode_for_extraction): Delete.
* optabs.h (extraction_insn): New structure.
(extraction_pattern): Moved from expr.h.
(get_best_reg_extraction_insn, get_best_mem_extraction_insn): Declare.
* optabs.c (HAVE_insv, CODE_FOR_insv, HAVE_extv, CODE_FOR_extv)
(HAVE_extzv, CODE_FOR_extzv): Provide defaults.
(extraction_type): New enum.
(get_traditional_extraction_insn, get_extraction_insn)
(get_best_reg_extraction_insn, get_best_mem_extraction_insn):
New functions.
* combine.c (make_extraction): Use get_best_reg_extraction_insn
instead of mode_for_extraction.
* expmed.c (HAVE_insv, CODE_FOR_insv, gen_insv, HAVE_extv)
(CODE_FOR_extv, gen_extv, HAVE_extzv, CODE_FOR_extzv, gen_extzv):
Remove fallback definitions.
(mode_for_extraction): Delete.
(adjust_bit_field_mem_for_reg): New function.
(store_bit_field_using_insv): Replace OP_MODE parameter with
an extraction_insn.  Pass struct_mode to narrow_bit_field_mem.
(extract_bit_field_using_extv): Likewise EXT_MODE.
(store_bit_field_1): Use get_best_reg_extraction_insn and
get_best_mem_extraction_insn instead of mode_for_extraction.
Use adjust_bit_field_mem_for_reg when forcing memory to a
register and doing a register insertion.  Update calls to
store_bit_field_using_insv.
(extract_bit_field_1): Likewise extractions and calls to
extract_bit_field_using_extv.
(store_Bit_field): When narrowing to a bitregion, don't use the
insv mode as a limit.
* recog.c: (HAVE_extv, CODE_FOR_extv, HAVE_extzv, CODE_FOR_extzv):
Provide defaults.
(simplify_while_replacing): Use insn_data instead of
mode_for_extraction.

From-SVN: r193605

gcc/ChangeLog
gcc/Makefile.in
gcc/combine.c
gcc/expmed.c
gcc/expr.h
gcc/optabs.c
gcc/optabs.h
gcc/recog.c

index c153f7320156a39f8eeac81653099634d372d465..9361e357aea2e98bcc9b099d9e628417d0d07311 100644 (file)
@@ -1,3 +1,41 @@
+2012-11-18  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * Makefile.in (recog.o): Add insn-codes.h.
+       * expr.h (extraction_pattern): Move to optabs.h.
+       (mode_for_extraction): Delete.
+       * optabs.h (extraction_insn): New structure.
+       (extraction_pattern): Moved from expr.h.
+       (get_best_reg_extraction_insn, get_best_mem_extraction_insn): Declare.
+       * optabs.c (HAVE_insv, CODE_FOR_insv, HAVE_extv, CODE_FOR_extv)
+       (HAVE_extzv, CODE_FOR_extzv): Provide defaults.
+       (extraction_type): New enum.
+       (get_traditional_extraction_insn, get_extraction_insn)
+       (get_best_reg_extraction_insn, get_best_mem_extraction_insn):
+       New functions.
+       * combine.c (make_extraction): Use get_best_reg_extraction_insn
+       instead of mode_for_extraction.
+       * expmed.c (HAVE_insv, CODE_FOR_insv, gen_insv, HAVE_extv)
+       (CODE_FOR_extv, gen_extv, HAVE_extzv, CODE_FOR_extzv, gen_extzv):
+       Remove fallback definitions.
+       (mode_for_extraction): Delete.
+       (adjust_bit_field_mem_for_reg): New function.
+       (store_bit_field_using_insv): Replace OP_MODE parameter with
+       an extraction_insn.  Pass struct_mode to narrow_bit_field_mem.
+       (extract_bit_field_using_extv): Likewise EXT_MODE.
+       (store_bit_field_1): Use get_best_reg_extraction_insn and
+       get_best_mem_extraction_insn instead of mode_for_extraction.
+       Use adjust_bit_field_mem_for_reg when forcing memory to a
+       register and doing a register insertion.  Update calls to
+       store_bit_field_using_insv.
+       (extract_bit_field_1): Likewise extractions and calls to
+       extract_bit_field_using_extv.
+       (store_Bit_field): When narrowing to a bitregion, don't use the
+       insv mode as a limit.
+       * recog.c: (HAVE_extv, CODE_FOR_extv, HAVE_extzv, CODE_FOR_extzv):
+       Provide defaults.
+       (simplify_while_replacing): Use insn_data instead of
+       mode_for_extraction.
+
 2012-11-18  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * stor-layout.c (bit_field_mode_iterator::bit_field_mode_iterator):
index 0a46425a4097fa0f47f8a3a7996feb6c50260206..d74e7b3c0dcd20c89c73fb8e8d48fed6ab145685 100644 (file)
@@ -3355,7 +3355,7 @@ recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \
    $(FUNCTION_H) $(BASIC_BLOCK_H) $(REGS_H) $(RECOG_H) $(EXPR_H) \
    $(FLAGS_H) insn-config.h $(INSN_ATTR_H) reload.h \
    addresses.h $(TM_P_H) $(TREE_PASS_H) hard-reg-set.h \
-   $(DF_H) $(DBGCNT_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H)
+   $(DF_H) $(DBGCNT_H) $(TARGET_H) $(DIAGNOSTIC_CORE_H) insn-codes.h
 reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(RTL_ERROR_H) $(TREE_H) $(RECOG_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
    insn-config.h reload.h $(FUNCTION_H) $(TM_P_H) $(GGC_H) \
index a3583e2013ad99b98be53e1d694952fecabe7a90..abd67e8ab9c7868085e3b46613dfc83a6473b690 100644 (file)
@@ -7179,29 +7179,24 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
          || (pos_rtx != 0 && len != 1)))
     return 0;
 
-  /* Get the mode to use should INNER not be a MEM, the mode for the position,
-     and the mode for the result.  */
-  if (in_dest && mode_for_extraction (EP_insv, -1) != MAX_MACHINE_MODE)
-    {
-      wanted_inner_reg_mode = mode_for_extraction (EP_insv, 0);
-      pos_mode = mode_for_extraction (EP_insv, 2);
-      extraction_mode = mode_for_extraction (EP_insv, 3);
-    }
+  enum extraction_pattern pattern = (in_dest ? EP_insv
+                                    : unsignedp ? EP_extzv : EP_extv);
 
-  if (! in_dest && unsignedp
-      && mode_for_extraction (EP_extzv, -1) != MAX_MACHINE_MODE)
-    {
-      wanted_inner_reg_mode = mode_for_extraction (EP_extzv, 1);
-      pos_mode = mode_for_extraction (EP_extzv, 3);
-      extraction_mode = mode_for_extraction (EP_extzv, 0);
-    }
+  /* If INNER is not from memory, we want it to have the mode of a register
+     extraction pattern's structure operand, or word_mode if there is no
+     such pattern.  The same applies to extraction_mode and pos_mode
+     and their respective operands.
 
-  if (! in_dest && ! unsignedp
-      && mode_for_extraction (EP_extv, -1) != MAX_MACHINE_MODE)
+     For memory, assume that the desired extraction_mode and pos_mode
+     are the same as for a register operation, since at present we don't
+     have named patterns for aligned memory structures.  */
+  struct extraction_insn insn;
+  if (get_best_reg_extraction_insn (&insn, pattern,
+                                   GET_MODE_BITSIZE (inner_mode), mode))
     {
-      wanted_inner_reg_mode = mode_for_extraction (EP_extv, 1);
-      pos_mode = mode_for_extraction (EP_extv, 3);
-      extraction_mode = mode_for_extraction (EP_extv, 0);
+      wanted_inner_reg_mode = insn.struct_mode;
+      pos_mode = insn.pos_mode;
+      extraction_mode = insn.field_mode;
     }
 
   /* Never narrow an object, since that might not be safe.  */
@@ -7210,9 +7205,6 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       && GET_MODE_SIZE (extraction_mode) < GET_MODE_SIZE (mode))
     extraction_mode = mode;
 
-  /* If this is not from memory, the desired mode is the preferred mode
-     for an extraction pattern's first input operand, or word_mode if there
-     is none.  */
   if (!MEM_P (inner))
     wanted_inner_mode = wanted_inner_reg_mode;
   else
index 106b78b7021b521d7bff116e3c9a6be47a72a062..752aecdaf17f9cc32cca297edf008001ed2ec089 100644 (file)
@@ -69,23 +69,6 @@ static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
 
-/* Reduce conditional compilation elsewhere.  */
-#ifndef HAVE_insv
-#define HAVE_insv      0
-#define CODE_FOR_insv  CODE_FOR_nothing
-#define gen_insv(a,b,c,d) NULL_RTX
-#endif
-#ifndef HAVE_extv
-#define HAVE_extv      0
-#define CODE_FOR_extv  CODE_FOR_nothing
-#define gen_extv(a,b,c,d) NULL_RTX
-#endif
-#ifndef HAVE_extzv
-#define HAVE_extzv     0
-#define CODE_FOR_extzv CODE_FOR_nothing
-#define gen_extzv(a,b,c,d) NULL_RTX
-#endif
-
 struct init_expmed_rtl
 {
   struct rtx_def reg;          rtunion reg_fld[2];
@@ -338,55 +321,6 @@ negate_rtx (enum machine_mode mode, rtx x)
   return result;
 }
 
-/* Report on the availability of insv/extv/extzv and the desired mode
-   of each of their operands.  Returns MAX_MACHINE_MODE if HAVE_foo
-   is false; else the mode of the specified operand.  If OPNO is -1,
-   all the caller cares about is whether the insn is available.  */
-enum machine_mode
-mode_for_extraction (enum extraction_pattern pattern, int opno)
-{
-  const struct insn_data_d *data;
-
-  switch (pattern)
-    {
-    case EP_insv:
-      if (HAVE_insv)
-       {
-         data = &insn_data[CODE_FOR_insv];
-         break;
-       }
-      return MAX_MACHINE_MODE;
-
-    case EP_extv:
-      if (HAVE_extv)
-       {
-         data = &insn_data[CODE_FOR_extv];
-         break;
-       }
-      return MAX_MACHINE_MODE;
-
-    case EP_extzv:
-      if (HAVE_extzv)
-       {
-         data = &insn_data[CODE_FOR_extzv];
-         break;
-       }
-      return MAX_MACHINE_MODE;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  if (opno == -1)
-    return VOIDmode;
-
-  /* Everyone who uses this function used to follow it with
-     if (result == VOIDmode) result = word_mode; */
-  if (data->operand[opno].mode == VOIDmode)
-    return word_mode;
-  return data->operand[opno].mode;
-}
-
 /* Adjust bitfield memory MEM so that it points to the first unit of mode
    MODE that contains a bitfield of size BITSIZE at bit position BITNUM.
    If MODE is BLKmode, return a reference to every byte in the bitfield.
@@ -415,6 +349,57 @@ narrow_bit_field_mem (rtx mem, enum machine_mode mode,
     }
 }
 
+/* The caller wants to perform insertion or extraction PATTERN on a
+   bitfield of size BITSIZE at BITNUM bits into memory operand OP0.
+   BITREGION_START and BITREGION_END are as for store_bit_field
+   and FIELDMODE is the natural mode of the field.
+
+   Search for a mode that is compatible with the memory access
+   restrictions and (where applicable) with a register insertion or
+   extraction.  Return the new memory on success, storing the adjusted
+   bit position in *NEW_BITNUM.  Return null otherwise.  */
+
+static rtx
+adjust_bit_field_mem_for_reg (enum extraction_pattern pattern,
+                             rtx op0, HOST_WIDE_INT bitsize,
+                             HOST_WIDE_INT bitnum,
+                             unsigned HOST_WIDE_INT bitregion_start,
+                             unsigned HOST_WIDE_INT bitregion_end,
+                             enum machine_mode fieldmode,
+                             unsigned HOST_WIDE_INT *new_bitnum)
+{
+  bit_field_mode_iterator iter (bitsize, bitnum, bitregion_start,
+                               bitregion_end, MEM_ALIGN (op0),
+                               MEM_VOLATILE_P (op0));
+  enum machine_mode best_mode;
+  if (iter.next_mode (&best_mode))
+    {
+      /* We can use a memory in BEST_MODE.  See whether this is true for
+        any wider modes.  All other things being equal, we prefer to
+        use the widest mode possible because it tends to expose more
+        CSE opportunities.  */
+      if (!iter.prefer_smaller_modes ())
+       {
+         /* Limit the search to the mode required by the corresponding
+            register insertion or extraction instruction, if any.  */
+         enum machine_mode limit_mode = word_mode;
+         extraction_insn insn;
+         if (get_best_reg_extraction_insn (&insn, pattern,
+                                           GET_MODE_BITSIZE (best_mode),
+                                           fieldmode))
+           limit_mode = insn.field_mode;
+
+         enum machine_mode wider_mode;
+         while (iter.next_mode (&wider_mode)
+                && GET_MODE_SIZE (wider_mode) <= GET_MODE_SIZE (limit_mode))
+           best_mode = wider_mode;
+       }
+      return narrow_bit_field_mem (op0, best_mode, bitsize, bitnum,
+                                  new_bitnum);
+    }
+  return NULL_RTX;
+}
+
 /* Return true if a bitfield of size BITSIZE at bit number BITNUM within
    a structure of mode STRUCT_MODE represents a lowpart subreg.   The subreg
    offset is then BITNUM / BITS_PER_UNIT.  */
@@ -432,14 +417,13 @@ lowpart_bit_field_p (unsigned HOST_WIDE_INT bitnum,
     return bitnum % BITS_PER_WORD == 0;
 }
 \f
-/* Try to use an insv pattern to store VALUE into a field of OP0.
-   OP_MODE is the mode of the insertion and BITSIZE and BITNUM are
-   as for store_bit_field.  */
+/* Try to use instruction INSV to store VALUE into a field of OP0.
+   BITSIZE and BITNUM are as for store_bit_field.  */
 
 static bool
-store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize,
-                           unsigned HOST_WIDE_INT bitnum, rtx value,
-                           enum machine_mode op_mode)
+store_bit_field_using_insv (const extraction_insn *insv, rtx op0,
+                           unsigned HOST_WIDE_INT bitsize,
+                           unsigned HOST_WIDE_INT bitnum, rtx value)
 {
   struct expand_operand ops[4];
   rtx value1;
@@ -447,13 +431,15 @@ store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize,
   rtx last = get_last_insn ();
   bool copy_back = false;
 
+  enum machine_mode op_mode = insv->field_mode;
   unsigned int unit = GET_MODE_BITSIZE (op_mode);
   if (bitsize == 0 || bitsize > unit)
     return false;
 
   if (MEM_P (xop0))
     /* Get a reference to the first byte of the field.  */
-    xop0 = narrow_bit_field_mem (xop0, byte_mode, bitsize, bitnum, &bitnum);
+    xop0 = narrow_bit_field_mem (xop0, insv->struct_mode, bitsize, bitnum,
+                                &bitnum);
   else
     {
       /* Convert from counting within OP0 to counting in OP_MODE.  */
@@ -533,7 +519,7 @@ store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize,
   create_integer_operand (&ops[1], bitsize);
   create_integer_operand (&ops[2], bitnum);
   create_input_operand (&ops[3], value1, op_mode);
-  if (maybe_expand_insn (CODE_FOR_insv, 4, ops))
+  if (maybe_expand_insn (insv->icode, 4, ops))
     {
       if (copy_back)
        convert_move (op0, xop0, true);
@@ -807,68 +793,38 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      within a word.  If the destination is a register, it too fits
      in a word.  */
 
-  enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
-  if (op_mode != MAX_MACHINE_MODE
-      && !MEM_P (op0)
-      && store_bit_field_using_insv (op0, bitsize, bitnum, value, op_mode))
+  extraction_insn insv;
+  if (!MEM_P (op0)
+      && get_best_reg_extraction_insn (&insv, EP_insv,
+                                      GET_MODE_BITSIZE (GET_MODE (op0)),
+                                      fieldmode)
+      && store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value))
     return true;
 
   /* If OP0 is a memory, try copying it to a register and seeing if a
      cheap register alternative is available.  */
-  if (op_mode != MAX_MACHINE_MODE && MEM_P (op0))
+  if (MEM_P (op0))
     {
-      enum machine_mode bestmode;
-      unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
-
-      /* Do not use insv for volatile bitfields when
-         -fstrict-volatile-bitfields is in effect.  */
-      if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0)
-         /* Do not use insv if the bit region is restricted and
-            an op_mode integer doesn't fit into the restricted region.  */
-         && !(bitregion_end
-              && (bitnum - (bitnum % BITS_PER_UNIT)
-                  + GET_MODE_BITSIZE (op_mode)
-                  > bitregion_end + 1))
-         && store_bit_field_using_insv (op0, bitsize, bitnum, value, op_mode))
+      /* Do not use unaligned memory insvs for volatile bitfields when
+        -fstrict-volatile-bitfields is in effect.  */
+      if (!(MEM_VOLATILE_P (op0)
+           && flag_strict_volatile_bitfields > 0)
+         && get_best_mem_extraction_insn (&insv, EP_insv, bitsize, bitnum,
+                                          fieldmode)
+         && store_bit_field_using_insv (&insv, op0, bitsize, bitnum, value))
        return true;
 
-      if (bitregion_end)
-       maxbits = bitregion_end - bitregion_start + 1;
-
-      /* Get the mode to use for inserting into this field.  If OP0 is
-        BLKmode, get the smallest mode consistent with the alignment. If
-        OP0 is a non-BLKmode object that is no wider than OP_MODE, use its
-        mode. Otherwise, use the smallest mode containing the field.  */
-
-      if (GET_MODE (op0) == BLKmode
-         || GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits
-         || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode))
-       bestmode = get_best_mode (bitsize, bitnum,
-                                 bitregion_start, bitregion_end,
-                                 MEM_ALIGN (op0), op_mode,
-                                 MEM_VOLATILE_P (op0));
-      else
-       bestmode = GET_MODE (op0);
+      rtx last = get_last_insn ();
 
-      if (bestmode != VOIDmode
-         && GET_MODE_SIZE (bestmode) >= GET_MODE_SIZE (fieldmode)
-         && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0))
-              && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
+      /* Try loading part of OP0 into a register, inserting the bitfield
+        into that, and then copying the result back to OP0.  */
+      unsigned HOST_WIDE_INT bitpos;
+      rtx xop0 = adjust_bit_field_mem_for_reg (EP_insv, op0, bitsize, bitnum,
+                                              bitregion_start, bitregion_end,
+                                              fieldmode, &bitpos);
+      if (xop0)
        {
-         rtx last, tempreg, xop0;
-         unsigned HOST_WIDE_INT bitpos;
-
-         last = get_last_insn ();
-
-         /* Adjust address to point to the containing unit of
-            that mode.  Compute the offset as a multiple of this unit,
-            counting in bytes.  */
-         xop0 = narrow_bit_field_mem (op0, bestmode, bitsize, bitnum,
-                                      &bitpos);
-
-         /* Fetch that unit, store the bitfield in it, then store
-            the unit.  */
-         tempreg = copy_to_reg (xop0);
+         rtx tempreg = copy_to_reg (xop0);
          if (store_bit_field_1 (tempreg, bitsize, bitpos,
                                 bitregion_start, bitregion_end,
                                 fieldmode, orig_value, false))
@@ -913,13 +869,8 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (MEM_P (str_rtx) && bitregion_start > 0)
     {
       enum machine_mode bestmode;
-      enum machine_mode op_mode;
       unsigned HOST_WIDE_INT offset;
 
-      op_mode = mode_for_extraction (EP_insv, 3);
-      if (op_mode == MAX_MACHINE_MODE)
-       op_mode = VOIDmode;
-
       gcc_assert ((bitregion_start % BITS_PER_UNIT) == 0);
 
       offset = bitregion_start / BITS_PER_UNIT;
@@ -928,8 +879,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       bitregion_start = 0;
       bestmode = get_best_mode (bitsize, bitnum,
                                bitregion_start, bitregion_end,
-                               MEM_ALIGN (str_rtx),
-                               op_mode,
+                               MEM_ALIGN (str_rtx), VOIDmode,
                                MEM_VOLATILE_P (str_rtx));
       str_rtx = adjust_address (str_rtx, bestmode, offset);
     }
@@ -1251,15 +1201,16 @@ convert_extracted_bit_field (rtx x, enum machine_mode mode,
    are as for extract_bit_field.  */
 
 static rtx
-extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize,
+extract_bit_field_using_extv (const extraction_insn *extv, rtx op0,
+                             unsigned HOST_WIDE_INT bitsize,
                              unsigned HOST_WIDE_INT bitnum,
                              int unsignedp, rtx target,
-                             enum machine_mode mode, enum machine_mode tmode,
-                             enum machine_mode ext_mode)
+                             enum machine_mode mode, enum machine_mode tmode)
 {
   struct expand_operand ops[4];
   rtx spec_target = target;
   rtx spec_target_subreg = 0;
+  enum machine_mode ext_mode = extv->field_mode;
   unsigned unit = GET_MODE_BITSIZE (ext_mode);
 
   if (bitsize == 0 || unit < bitsize)
@@ -1267,7 +1218,8 @@ extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize,
 
   if (MEM_P (op0))
     /* Get a reference to the first byte of the field.  */
-    op0 = narrow_bit_field_mem (op0, byte_mode, bitsize, bitnum, &bitnum);
+    op0 = narrow_bit_field_mem (op0, extv->struct_mode, bitsize, bitnum,
+                               &bitnum);
   else
     {
       /* Convert from counting within OP0 to counting in EXT_MODE.  */
@@ -1315,7 +1267,7 @@ extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize,
   create_fixed_operand (&ops[1], op0);
   create_integer_operand (&ops[2], bitsize);
   create_integer_operand (&ops[3], bitnum);
-  if (maybe_expand_insn (unsignedp ? CODE_FOR_extzv : CODE_FOR_extv, 4, ops))
+  if (maybe_expand_insn (extv->icode, 4, ops))
     {
       target = ops[0].value;
       if (target == spec_target)
@@ -1341,7 +1293,6 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 {
   rtx op0 = str_rtx;
   enum machine_mode int_mode;
-  enum machine_mode ext_mode;
   enum machine_mode mode1;
 
   if (tmode == VOIDmode)
@@ -1612,74 +1563,53 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
   /* From here on we know the desired field is smaller than a word.
      If OP0 is a register, it too fits within a word.  */
-
-  ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0);
-  if (ext_mode != MAX_MACHINE_MODE && !MEM_P (op0))
+  enum extraction_pattern pattern = unsignedp ? EP_extzv : EP_extv;
+  extraction_insn extv;
+  if (!MEM_P (op0)
+      && get_best_reg_extraction_insn (&extv, pattern, bitnum + bitsize,
+                                      tmode))
     {
-      rtx result = extract_bit_field_using_extv (op0, bitsize, bitnum,
+      rtx result = extract_bit_field_using_extv (&extv, op0, bitsize, bitnum,
                                                 unsignedp, target, mode,
-                                                tmode, ext_mode);
+                                                tmode);
       if (result)
        return result;
     }
 
   /* If OP0 is a memory, try copying it to a register and seeing if a
      cheap register alternative is available.  */
-  if (ext_mode != MAX_MACHINE_MODE && MEM_P (op0))
+  if (MEM_P (op0))
     {
-      enum machine_mode bestmode;
-
       /* Do not use extv/extzv for volatile bitfields when
          -fstrict-volatile-bitfields is in effect.  */
-      if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0))
+      if (!(MEM_VOLATILE_P (op0) && flag_strict_volatile_bitfields > 0)
+         && get_best_mem_extraction_insn (&extv, pattern, bitsize, bitnum,
+                                          tmode))
        {
-         rtx result = extract_bit_field_using_extv (op0, bitsize, bitnum,
-                                                    unsignedp, target, mode,
-                                                    tmode, ext_mode);
+         rtx result = extract_bit_field_using_extv (&extv, op0, bitsize,
+                                                    bitnum, unsignedp,
+                                                    target, mode,
+                                                    tmode);
          if (result)
            return result;
        }
 
-      /* Get the mode to use for inserting into this field.  If
-        OP0 is BLKmode, get the smallest mode consistent with the
-        alignment. If OP0 is a non-BLKmode object that is no
-        wider than EXT_MODE, use its mode. Otherwise, use the
-        smallest mode containing the field.  */
-
-      if (GET_MODE (op0) == BLKmode
-         || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode))
-       bestmode = get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0),
-                                 ext_mode, MEM_VOLATILE_P (op0));
-      else
-       bestmode = GET_MODE (op0);
+      rtx last = get_last_insn ();
 
-      if (bestmode != VOIDmode
-         && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0))
-              && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0)))
+      /* Try loading part of OP0 into a register and extracting the
+        bitfield from that.  */
+      unsigned HOST_WIDE_INT bitpos;
+      rtx xop0 = adjust_bit_field_mem_for_reg (pattern, op0, bitsize, bitnum,
+                                              0, 0, tmode, &bitpos);
+      if (xop0)
        {
-         unsigned HOST_WIDE_INT bitpos;
-         rtx xop0 = narrow_bit_field_mem (op0, bestmode, bitsize, bitnum,
-                                          &bitpos);
-
-         /* Make sure the register is big enough for the whole field.
-            (It might not be if bestmode == GET_MODE (op0) and the input
-            code was invalid.)  */
-         if (bitpos + bitsize <= GET_MODE_BITSIZE (bestmode))
-           {
-             rtx last, result;
-
-             last = get_last_insn ();
-
-             /* Fetch it to a register in that size.  */
-             xop0 = force_reg (bestmode, xop0);
-             result = extract_bit_field_1 (xop0, bitsize, bitpos,
+         xop0 = copy_to_reg (xop0);
+         rtx result = extract_bit_field_1 (xop0, bitsize, bitpos,
                                            unsignedp, packedp, target,
                                            mode, tmode, false);
-             if (result)
-               return result;
-
-             delete_insns_since (last);
-           }
+         if (result)
+           return result;
+         delete_insns_since (last);
        }
     }
 
index f94f1db2224f87cb8e5d7f72089f7d77a9f8dd03..c2168287cff080647684b8c77ffbccf9dde50816 100644 (file)
@@ -698,14 +698,6 @@ extern void probe_stack_range (HOST_WIDE_INT, rtx);
    in its original home.  This becomes invalid if any more code is emitted.  */
 extern rtx hard_libcall_value (enum machine_mode, rtx);
 
-/* Return the mode desired by operand N of a particular bitfield
-   insert/extract insn, or MAX_MACHINE_MODE if no such insn is
-   available.  */
-
-enum extraction_pattern { EP_insv, EP_extv, EP_extzv };
-extern enum machine_mode
-mode_for_extraction (enum extraction_pattern, int);
-
 extern void store_bit_field (rtx, unsigned HOST_WIDE_INT,
                             unsigned HOST_WIDE_INT,
                             unsigned HOST_WIDE_INT,
index bba93c2d5618d1fdcc85a6a89ddc6258476a260d..66c0337b0fd7f9a9b371f3888b9f161456b75e7f 100644 (file)
@@ -8239,4 +8239,177 @@ expand_jump_insn (enum insn_code icode, unsigned int nops,
     gcc_unreachable ();
 }
 
+/* Reduce conditional compilation elsewhere.  */
+#ifndef HAVE_insv
+#define HAVE_insv      0
+#define CODE_FOR_insv  CODE_FOR_nothing
+#endif
+#ifndef HAVE_extv
+#define HAVE_extv      0
+#define CODE_FOR_extv  CODE_FOR_nothing
+#endif
+#ifndef HAVE_extzv
+#define HAVE_extzv     0
+#define CODE_FOR_extzv CODE_FOR_nothing
+#endif
+
+/* Enumerates the possible types of structure operand to an
+   extraction_insn.  */
+enum extraction_type { ET_unaligned_mem, ET_reg };
+
+/* Check whether insv, extv or extzv pattern ICODE can be used for an
+   insertion or extraction of type TYPE on a structure of mode MODE.
+   Return true if so and fill in *INSN accordingly.  STRUCT_OP is the
+   operand number of the structure (the first sign_extract or zero_extract
+   operand) and FIELD_OP is the operand number of the field (the other
+   side of the set from the sign_extract or zero_extract).  */
+
+static bool
+get_traditional_extraction_insn (extraction_insn *insn,
+                                enum extraction_type type,
+                                enum machine_mode mode,
+                                enum insn_code icode,
+                                int struct_op, int field_op)
+{
+  const struct insn_data_d *data = &insn_data[icode];
+
+  enum machine_mode struct_mode = data->operand[struct_op].mode;
+  if (struct_mode == VOIDmode)
+    struct_mode = word_mode;
+  if (mode != struct_mode)
+    return false;
+
+  enum machine_mode field_mode = data->operand[field_op].mode;
+  if (field_mode == VOIDmode)
+    field_mode = word_mode;
+
+  enum machine_mode pos_mode = data->operand[struct_op + 2].mode;
+  if (pos_mode == VOIDmode)
+    pos_mode = word_mode;
+
+  insn->icode = icode;
+  insn->field_mode = field_mode;
+  insn->struct_mode = (type == ET_unaligned_mem ? byte_mode : struct_mode);
+  insn->pos_mode = pos_mode;
+  return true;
+}
+
+/* Return true if an instruction exists to perform an insertion or
+   extraction (PATTERN says which) of type TYPE in mode MODE.
+   Describe the instruction in *INSN if so.  */
+
+static bool
+get_extraction_insn (extraction_insn *insn,
+                    enum extraction_pattern pattern,
+                    enum extraction_type type,
+                    enum machine_mode mode)
+{
+  switch (pattern)
+    {
+    case EP_insv:
+      if (HAVE_insv
+         && get_traditional_extraction_insn (insn, type, mode,
+                                             CODE_FOR_insv, 0, 3))
+       return true;
+      return false;
+
+    case EP_extv:
+      if (HAVE_extv
+         && get_traditional_extraction_insn (insn, type, mode,
+                                             CODE_FOR_extv, 1, 0))
+       return true;
+      return false;
+
+    case EP_extzv:
+      if (HAVE_extzv
+         && get_traditional_extraction_insn (insn, type, mode,
+                                             CODE_FOR_extzv, 1, 0))
+       return true;
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return true if an instruction exists to access a field of mode
+   FIELDMODE in a structure that has STRUCT_BITS significant bits.
+   Describe the "best" such instruction in *INSN if so.  PATTERN and
+   TYPE describe the type of insertion or extraction we want to perform.
+
+   For an insertion, the number of significant structure bits includes
+   all bits of the target.  For an extraction, it need only include the
+   most significant bit of the field.  Larger widths are acceptable
+   in both cases.  */
+
+static bool
+get_best_extraction_insn (extraction_insn *insn,
+                         enum extraction_pattern pattern,
+                         enum extraction_type type,
+                         unsigned HOST_WIDE_INT struct_bits,
+                         enum machine_mode field_mode)
+{
+  enum machine_mode mode = smallest_mode_for_size (struct_bits, MODE_INT);
+  while (mode != VOIDmode)
+    {
+      if (get_extraction_insn (insn, pattern, type, mode))
+       {
+         while (mode != VOIDmode
+                && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (field_mode)
+                && !TRULY_NOOP_TRUNCATION_MODES_P (insn->field_mode,
+                                                   field_mode))
+           {
+             get_extraction_insn (insn, pattern, type, mode);
+             mode = GET_MODE_WIDER_MODE (mode);
+           }
+         return true;
+       }
+      mode = GET_MODE_WIDER_MODE (mode);
+    }
+  return false;
+}
+
+/* Return true if an instruction exists to access a field of mode
+   FIELDMODE in a register structure that has STRUCT_BITS significant bits.
+   Describe the "best" such instruction in *INSN if so.  PATTERN describes
+   the type of insertion or extraction we want to perform.
+
+   For an insertion, the number of significant structure bits includes
+   all bits of the target.  For an extraction, it need only include the
+   most significant bit of the field.  Larger widths are acceptable
+   in both cases.  */
+
+bool
+get_best_reg_extraction_insn (extraction_insn *insn,
+                             enum extraction_pattern pattern,
+                             unsigned HOST_WIDE_INT struct_bits,
+                             enum machine_mode field_mode)
+{
+  return get_best_extraction_insn (insn, pattern, ET_reg, struct_bits,
+                                  field_mode);
+}
+
+/* Return true if an instruction exists to access a field of BITSIZE
+   bits starting BITNUM bits into a memory structure.  Describe the
+   "best" such instruction in *INSN if so.  PATTERN describes the type
+   of insertion or extraction we want to perform and FIELDMODE is the
+   natural mode of the extracted field.
+
+   The instructions considered here only access bytes that overlap
+   the bitfield; they do not touch any surrounding bytes.  */
+
+bool
+get_best_mem_extraction_insn (extraction_insn *insn,
+                             enum extraction_pattern pattern,
+                             HOST_WIDE_INT bitsize, HOST_WIDE_INT bitnum,
+                             enum machine_mode field_mode)
+{
+  unsigned HOST_WIDE_INT struct_bits = (bitnum % BITS_PER_UNIT
+                                       + bitsize
+                                       + BITS_PER_UNIT - 1);
+  struct_bits -= struct_bits % BITS_PER_UNIT;
+  return get_best_extraction_insn (insn, pattern, ET_unaligned_mem,
+                                  struct_bits, field_mode);
+}
+
 #include "gt-optabs.h"
index e0be2bac4fd44ee6775c5b543d47dacb2462c4eb..81aa1d049dca29b1043108c37535c43a88967141 100644 (file)
@@ -323,6 +323,38 @@ extern rtx optab_libfunc (optab optab, enum machine_mode mode);
 extern rtx convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
                                  enum machine_mode mode2);
 
+/* Describes an instruction that inserts or extracts a bitfield.  */
+struct extraction_insn
+{
+  /* The code of the instruction.  */
+  enum insn_code icode;
+
+  /* The mode that the structure operand should have.  This is byte_mode
+     when using the legacy insv, extv and extzv patterns to access memory.  */
+  enum machine_mode struct_mode;
+
+  /* The mode of the field to be inserted or extracted, and by extension
+     the mode of the insertion or extraction itself.  */
+  enum machine_mode field_mode;
+
+  /* The mode of the field's bit position.  This is only important
+     when the position is variable rather than constant.  */
+  enum machine_mode pos_mode;
+};
+
+/* Enumerates the possible extraction_insn operations.  */
+enum extraction_pattern { EP_insv, EP_extv, EP_extzv };
+
+extern bool get_best_reg_extraction_insn (extraction_insn *,
+                                         enum extraction_pattern,
+                                         unsigned HOST_WIDE_INT,
+                                         enum machine_mode);
+
+extern bool get_best_mem_extraction_insn (extraction_insn *,
+                                         enum extraction_pattern,
+                                         HOST_WIDE_INT, HOST_WIDE_INT,
+                                         enum machine_mode);
+
 extern bool insn_operand_matches (enum insn_code icode, unsigned int opno,
                                  rtx operand);
 
index 47e7f75e1dd7a5d4d78d33ebb78ba63264bcf789..3c56703b1f534ae1496a3776c2a9c04a9213a502 100644 (file)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "tree-pass.h"
 #include "df.h"
+#include "insn-codes.h"
 
 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
@@ -542,6 +543,16 @@ cancel_changes (int num)
   num_changes = num;
 }
 
+/* Reduce conditional compilation elsewhere.  */
+#ifndef HAVE_extv
+#define HAVE_extv      0
+#define CODE_FOR_extv  CODE_FOR_nothing
+#endif
+#ifndef HAVE_extzv
+#define HAVE_extzv     0
+#define CODE_FOR_extzv CODE_FOR_nothing
+#endif
+
 /* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting
    rtx.  */
 
@@ -628,19 +639,17 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
          enum machine_mode is_mode = GET_MODE (XEXP (x, 0));
          int pos = INTVAL (XEXP (x, 2));
 
-         if (GET_CODE (x) == ZERO_EXTRACT)
+         if (GET_CODE (x) == ZERO_EXTRACT && HAVE_extzv)
            {
-             enum machine_mode new_mode
-               = mode_for_extraction (EP_extzv, 1);
-             if (new_mode != MAX_MACHINE_MODE)
-               wanted_mode = new_mode;
+             wanted_mode = insn_data[CODE_FOR_extzv].operand[1].mode;
+             if (wanted_mode == VOIDmode)
+               wanted_mode = word_mode;
            }
-         else if (GET_CODE (x) == SIGN_EXTRACT)
+         else if (GET_CODE (x) == SIGN_EXTRACT && HAVE_extv)
            {
-             enum machine_mode new_mode
-               = mode_for_extraction (EP_extv, 1);
-             if (new_mode != MAX_MACHINE_MODE)
-               wanted_mode = new_mode;
+             wanted_mode = insn_data[CODE_FOR_extv].operand[1].mode;
+             if (wanted_mode == VOIDmode)
+               wanted_mode = word_mode;
            }
 
          /* If we have a narrower mode, we can do something.  */