]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
md.texi: Document "preferred_for_size" and "preferred_for_speed" attributes.
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 22 Oct 2014 12:02:11 +0000 (12:02 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 22 Oct 2014 12:02:11 +0000 (12:02 +0000)
gcc/
* doc/md.texi: Document "preferred_for_size" and "preferred_for_speed"
attributes.
* genattr.c (main): Handle "preferred_for_size" and
"preferred_for_speed" in the same way as "enabled".
* recog.h (bool_attr): New enum.
(target_recog): Replace x_enabled_alternatives with x_bool_attr_masks.
(get_preferred_alternatives, check_bool_attrs): Declare.
* recog.c (have_bool_attr, get_bool_attr, get_bool_attr_mask_uncached)
(get_bool_attr_mask, get_preferred_alternatives, check_bool_attrs):
New functions.
(get_enabled_alternatives): Use get_bool_attr_mask.
* ira-costs.c (record_reg_classes): Use get_preferred_alternatives
instead of recog_data.enabled_alternatives.
* ira.c (ira_setup_alts): Likewise.
* postreload.c (reload_cse_simplify_operands): Likewise.
* config/i386/i386.c (ix86_legitimate_combined_insn): Likewise.
* ira-lives.c (preferred_alternatives): New variable.
(process_bb_node_lives): Set it.
(check_and_make_def_conflict, make_early_clobber_and_input_conflicts)
(single_reg_class, ira_implicitly_set_insn_hard_regs): Use it instead
of recog_data.enabled_alternatives.
* lra-int.h (lra_insn_recog_data): Replace enabled_alternatives
to preferred_alternatives.
* lra-constraints.c (process_alt_operands): Update accordingly.
* lra.c (lra_set_insn_recog_data): Likewise.
(lra_update_insn_recog_data): Assert check_bool_attrs.

From-SVN: r216554

13 files changed:
gcc/ChangeLog
gcc/config/i386/i386.c
gcc/doc/md.texi
gcc/genattr.c
gcc/ira-costs.c
gcc/ira-lives.c
gcc/ira.c
gcc/lra-constraints.c
gcc/lra-int.h
gcc/lra.c
gcc/postreload.c
gcc/recog.c
gcc/recog.h

index 5de3d9f58b1dba6fe395102c6a57def2f0e553d2..c3d8f810741956a101ebdfcc083cf425d01ff93c 100644 (file)
@@ -1,3 +1,32 @@
+2014-10-22  Richard Sandiford  <richard.sandiford@arm.com>
+
+       * doc/md.texi: Document "preferred_for_size" and "preferred_for_speed"
+       attributes.
+       * genattr.c (main): Handle "preferred_for_size" and
+       "preferred_for_speed" in the same way as "enabled".
+       * recog.h (bool_attr): New enum.
+       (target_recog): Replace x_enabled_alternatives with x_bool_attr_masks.
+       (get_preferred_alternatives, check_bool_attrs): Declare.
+       * recog.c (have_bool_attr, get_bool_attr, get_bool_attr_mask_uncached)
+       (get_bool_attr_mask, get_preferred_alternatives, check_bool_attrs):
+       New functions.
+       (get_enabled_alternatives): Use get_bool_attr_mask.
+       * ira-costs.c (record_reg_classes): Use get_preferred_alternatives
+       instead of recog_data.enabled_alternatives.
+       * ira.c (ira_setup_alts): Likewise.
+       * postreload.c (reload_cse_simplify_operands): Likewise.
+       * config/i386/i386.c (ix86_legitimate_combined_insn): Likewise.
+       * ira-lives.c (preferred_alternatives): New variable.
+       (process_bb_node_lives): Set it.
+       (check_and_make_def_conflict, make_early_clobber_and_input_conflicts)
+       (single_reg_class, ira_implicitly_set_insn_hard_regs): Use it instead
+       of recog_data.enabled_alternatives.
+       * lra-int.h (lra_insn_recog_data): Replace enabled_alternatives
+       to preferred_alternatives.
+       * lra-constraints.c (process_alt_operands): Update accordingly.
+       * lra.c (lra_set_insn_recog_data): Likewise.
+       (lra_update_insn_recog_data): Assert check_bool_attrs.
+
 2014-10-22  Richard Sandiford  <richard.sandiford@arm.com>
 
        * recog.h (extract_constrain_insn): Declare.
index 94b7f798b9e5a2f3ca0349da34a775751695705f..65b31734d39ce0977ff970aea72eab306b584202 100644 (file)
@@ -5905,10 +5905,10 @@ ix86_legitimate_combined_insn (rtx_insn *insn)
          /* Operand has no constraints, anything is OK.  */
          win = !n_alternatives;
 
-         alternative_mask enabled = recog_data.enabled_alternatives;
+         alternative_mask preferred = get_preferred_alternatives (insn);
          for (j = 0; j < n_alternatives; j++, op_alt += n_operands)
            {
-             if (!TEST_BIT (enabled, j))
+             if (!TEST_BIT (preferred, j))
                continue;
              if (op_alt[i].anything_ok
                  || (op_alt[i].matches != -1
index 2f2325e907a805ab87d1c853428b4d57bb25545c..1d16e2947114a9bcc4b46c9e84c1cb5ac9045e9c 100644 (file)
@@ -1080,7 +1080,7 @@ the addressing register.
 * Class Preferences::   Constraints guide which hard register to put things in.
 * Modifiers::           More precise control over effects of constraints.
 * Machine Constraints:: Existing constraints for some particular machines.
-* Disable Insn Alternatives:: Disable insn alternatives using the @code{enabled} attribute.
+* Disable Insn Alternatives:: Disable insn alternatives using attributes.
 * Define Constraints::  How to define machine-specific constraints.
 * C Constraint Interface:: How to test constraints from C code.
 @end menu
@@ -4006,42 +4006,49 @@ Unsigned constant valid for BccUI instructions
 @subsection Disable insn alternatives using the @code{enabled} attribute
 @cindex enabled
 
-The @code{enabled} insn attribute may be used to disable insn
-alternatives that are not available for the current subtarget.
-This is useful when adding new instructions to an existing pattern
-which are only available for certain cpu architecture levels as
-specified with the @code{-march=} option.
+There are three insn attributes that may be used to selectively disable
+instruction alternatives:
 
-If an insn alternative is disabled, then it will never be used.  The
-compiler treats the constraints for the disabled alternative as
-unsatisfiable.
+@table @code
+@item enabled
+Says whether an alternative is available on the current subtarget.
 
-In order to make use of the @code{enabled} attribute a back end has to add
-in the machine description files:
+@item preferred_for_size
+Says whether an enabled alternative should be used in code that is
+optimized for size.
 
-@enumerate
-@item
-A definition of the @code{enabled} insn attribute.  The attribute is
-defined as usual using the @code{define_attr} command.  This
-definition should be based on other insn attributes and/or target flags.
-The attribute must be a static property of the subtarget; that is, it
-must not depend on the current operands or any other dynamic context
-(for example, the location of the insn within the body of a loop).
-
-The @code{enabled} attribute is a numeric attribute and should evaluate to
-@code{(const_int 1)} for an enabled alternative and to
-@code{(const_int 0)} otherwise.
-@item
-A definition of another insn attribute used to describe for what
-reason an insn alternative might be available or
-not.  E.g. @code{cpu_facility} as in the example below.
-@item
-An assignment for the second attribute to each insn definition
-combining instructions which are not all available under the same
-circumstances.  (Note: It obviously only makes sense for definitions
-with more than one alternative.  Otherwise the insn pattern should be
-disabled or enabled using the insn condition.)
-@end enumerate
+@item preferred_for_speed
+Says whether an enabled alternative should be used in code that is
+optimized for speed.
+@end table
+
+All these attributes should use @code{(const_int 1)} to allow an alternative
+or @code{(const_int 0)} to disallow it.  The attributes must be a static
+property of the subtarget; they cannot for example depend on the
+current operands, on the current optimization level, on the location
+of the insn within the body of a loop, on whether register allocation
+has finished, or on the current compiler pass.
+
+The @code{enabled} attribute is a correctness property.  It tells GCC to act
+as though the disabled alternatives were never defined in the first place.
+This is useful when adding new instructions to an existing pattern in
+cases where the new instructions are only available for certain cpu
+architecture levels (typically mapped to the @code{-march=} command-line
+option).
+
+In contrast, the @code{preferred_for_size} and @code{preferred_for_speed}
+attributes are strong optimization hints rather than correctness properties.
+@code{preferred_for_size} tells GCC which alternatives to consider when
+adding or modifying an instruction that GCC wants to optimize for size.
+@code{preferred_for_speed} does the same thing for speed.  Note that things
+like code motion can lead to cases where code optimized for size uses
+alternatives that are not preferred for size, and similarly for speed.
+
+Although @code{define_insn}s can in principle specify the @code{enabled}
+attribute directly, it is often clearer to have subsiduary attributes
+for each architectural feature of interest.  The @code{define_insn}s
+can then use these subsiduary attributes to say which alternatives
+require which features.  The example below does this for @code{cpu_facility}.
 
 E.g. the following two patterns could easily be merged using the @code{enabled}
 attribute:
index 699590e9fbedeec9f11b881dc606ec05311c9393..8c45979bb49323ba461ee7215159fad8304e61d5 100644 (file)
@@ -338,7 +338,9 @@ main (int argc, char **argv)
     }
 
   /* Special-purpose attributes should be tested with if, not #ifdef.  */
-  const char * const special_attrs[] = { "length", "enabled", 0 };
+  const char * const special_attrs[] = { "length", "enabled",
+                                        "preferred_for_size",
+                                        "preferred_for_speed", 0 };
   for (const char * const *p = special_attrs; *p; p++)
     {
       printf ("#ifndef HAVE_ATTR_%s\n"
@@ -355,9 +357,15 @@ main (int argc, char **argv)
        "#define insn_current_length hook_int_rtx_insn_unreachable\n"
        "#include \"insn-addr.h\"\n"
        "#endif\n"
-       "#if !HAVE_ATTR_enabled\n"
        "extern int hook_int_rtx_1 (rtx);\n"
+       "#if !HAVE_ATTR_enabled\n"
        "#define get_attr_enabled hook_int_rtx_1\n"
+       "#endif\n"
+       "#if !HAVE_ATTR_preferred_for_size\n"
+       "#define get_attr_preferred_for_size hook_int_rtx_1\n"
+       "#endif\n"
+       "#if !HAVE_ATTR_preferred_for_speed\n"
+       "#define get_attr_preferred_for_speed hook_int_rtx_1\n"
        "#endif\n");
 
   /* Output flag masks for use by reorg.
index 0a930deec95f7d74eb968c44cf37d6776f83218b..8b6c9f9047d999306670b068d34089ddcb15439f 100644 (file)
@@ -416,6 +416,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 
   /* Process each alternative, each time minimizing an operand's cost
      with the cost for each operand in that alternative.  */
+  alternative_mask preferred = get_preferred_alternatives (insn);
   for (alt = 0; alt < n_alts; alt++)
     {
       enum reg_class classes[MAX_RECOG_OPERANDS];
@@ -424,7 +425,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
       int alt_fail = 0;
       int alt_cost = 0, op_cost_add;
 
-      if (!TEST_BIT (recog_data.enabled_alternatives, alt))
+      if (!TEST_BIT (preferred, alt))
        {
          for (i = 0; i < recog_data.n_operands; i++)
            constraints[i] = skip_alternative (constraints[i]);
index 1d410538d16388c40a91d5f2b8952375ba18e511..1c9f8841dfeb474f2372f3b54a7a5cd14efaab9d 100644 (file)
@@ -85,6 +85,10 @@ static int last_call_num;
 /* The number of last call at which given allocno was saved.  */
 static int *allocno_saved_at_call;
 
+/* The value of get_preferred_alternatives for the current instruction,
+   supplemental to recog_data.  */
+static alternative_mask preferred_alternatives;
+
 /* Record the birth of hard register REGNO, updating hard_regs_live and
    hard reg conflict information for living allocnos.  */
 static void
@@ -641,10 +645,9 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
       /* If there's any alternative that allows USE to match DEF, do not
         record a conflict.  If that causes us to create an invalid
         instruction due to the earlyclobber, reload must fix it up.  */
-      alternative_mask enabled = recog_data.enabled_alternatives;
       for (alt1 = 0; alt1 < recog_data.n_alternatives; alt1++)
        {
-         if (!TEST_BIT (enabled, alt1))
+         if (!TEST_BIT (preferred_alternatives, alt1))
            continue;
          const operand_alternative *op_alt1
            = &recog_op_alt[alt1 * n_operands];
@@ -692,10 +695,9 @@ make_early_clobber_and_input_conflicts (void)
 
   int n_alternatives = recog_data.n_alternatives;
   int n_operands = recog_data.n_operands;
-  alternative_mask enabled = recog_data.enabled_alternatives;
   const operand_alternative *op_alt = recog_op_alt;
   for (alt = 0; alt < n_alternatives; alt++, op_alt += n_operands)
-    if (TEST_BIT (enabled, alt))
+    if (TEST_BIT (preferred_alternatives, alt))
       for (def = 0; def < n_operands; def++)
        {
          def_cl = NO_REGS;
@@ -762,13 +764,13 @@ single_reg_class (const char *constraints, rtx op, rtx equiv_const)
   enum constraint_num cn;
 
   cl = NO_REGS;
-  alternative_mask enabled = recog_data.enabled_alternatives;
+  alternative_mask preferred = preferred_alternatives;
   for (; (c = *constraints); constraints += CONSTRAINT_LEN (c, constraints))
     if (c == '#')
-      enabled &= ~ALTERNATIVE_BIT (0);
+      preferred &= ~ALTERNATIVE_BIT (0);
     else if (c == ',')
-      enabled >>= 1;
-    else if (enabled & 1)
+      preferred >>= 1;
+    else if (preferred & 1)
       switch (c)
        {
        case 'g':
@@ -851,13 +853,13 @@ ira_implicitly_set_insn_hard_regs (HARD_REG_SET *set)
          mode = (GET_CODE (op) == SCRATCH
                  ? GET_MODE (op) : PSEUDO_REGNO_MODE (regno));
          cl = NO_REGS;
-         alternative_mask enabled = recog_data.enabled_alternatives;
+         alternative_mask preferred = preferred_alternatives;
          for (; (c = *p); p += CONSTRAINT_LEN (c, p))
            if (c == '#')
-             enabled &= ~ALTERNATIVE_BIT (0);
+             preferred &= ~ALTERNATIVE_BIT (0);
            else if (c == ',')
-             enabled >>= 1;
-           else if (enabled & 1)
+             preferred >>= 1;
+           else if (preferred & 1)
              {
                cl = reg_class_for_constraint (lookup_constraint (p));
                if (cl != NO_REGS)
@@ -1174,6 +1176,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
              }
 
          extract_insn (insn);
+         preferred_alternatives = get_preferred_alternatives (insn);
          preprocess_constraints (insn);
          process_single_reg_class_operands (false, freq);
 
index 3f4405eca08570d690d581668029149394c05b31..1bdc44612dbb75e7bffda60038d02682a9872fb7 100644 (file)
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1788,6 +1788,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG_SET &alts)
   int commutative = -1;
 
   extract_insn (insn);
+  alternative_mask preferred = get_preferred_alternatives (insn);
   CLEAR_HARD_REG_SET (alts);
   insn_constraints.release ();
   insn_constraints.safe_grow_cleared (recog_data.n_operands
@@ -1817,7 +1818,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG_SET &alts)
        }
       for (nalt = 0; nalt < recog_data.n_alternatives; nalt++)
        {
-         if (!TEST_BIT (recog_data.enabled_alternatives, nalt)
+         if (!TEST_BIT (preferred, nalt)
              || TEST_HARD_REG_BIT (alts, nalt))
            continue;
 
index 6ee99a29312c96903903ff02db9af1e4aa9f3972..7f9f3178507a2a3139f0a8306fac6c50367b42a6 100644 (file)
@@ -1685,14 +1685,14 @@ process_alt_operands (int only_alternative)
      together, the second alternatives go together, etc.
 
      First loop over alternatives.  */
-  alternative_mask enabled = curr_id->enabled_alternatives;
+  alternative_mask preferred = curr_id->preferred_alternatives;
   if (only_alternative >= 0)
-    enabled &= ALTERNATIVE_BIT (only_alternative);
+    preferred &= ALTERNATIVE_BIT (only_alternative);
 
   for (nalt = 0; nalt < n_alternatives; nalt++)
     {
       /* Loop over operands for one constraint alternative.  */
-      if (!TEST_BIT (enabled, nalt))
+      if (!TEST_BIT (preferred, nalt))
        continue;
 
       overall = losers = reject = reload_nregs = reload_sum = 0;
index 1337acad0d024227585f7f1d98edad3710dc9029..8bd45b207b54ae219006e6969af1cfe499e41005 100644 (file)
@@ -233,8 +233,8 @@ struct lra_insn_recog_data
      value can be NULL or points to array of the hard register numbers
      ending with a negative value.  */
   int *arg_hard_regs;
-  /* Alternative enabled for the insn. NULL for debug insns.  */
-  alternative_mask enabled_alternatives;
+  /* Cached value of get_preferred_alternatives.  */
+  alternative_mask preferred_alternatives;
   /* The following member value is always NULL for a debug insn.  */
   struct lra_insn_reg *regs;
 };
index 6326131d8c36573d00b9109003819d4628f6874b..22226361e64a3e1c8a56501d3eef8cf936fc0a7b 100644 (file)
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -921,7 +921,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
       data->insn_static_data = &debug_insn_static_data;
       data->dup_loc = NULL;
       data->arg_hard_regs = NULL;
-      data->enabled_alternatives = ALL_ALTERNATIVES;
+      data->preferred_alternatives = ALL_ALTERNATIVES;
       data->operand_loc = XNEWVEC (rtx *, 1);
       data->operand_loc[0] = &INSN_VAR_LOCATION_LOC (insn);
       return data;
@@ -981,7 +981,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
          = (insn_static_data->operand[i].constraint[0] == '=' ? OP_OUT
             : insn_static_data->operand[i].constraint[0] == '+' ? OP_INOUT
             : OP_IN);
-      data->enabled_alternatives = ALL_ALTERNATIVES;
+      data->preferred_alternatives = ALL_ALTERNATIVES;
       if (nop > 0)
        {
          operand_alternative *op_alt = XCNEWVEC (operand_alternative,
@@ -1015,7 +1015,7 @@ lra_set_insn_recog_data (rtx_insn *insn)
          memcpy (locs, recog_data.dup_loc, n * sizeof (rtx *));
        }
       data->dup_loc = locs;
-      data->enabled_alternatives = get_enabled_alternatives (insn);
+      data->preferred_alternatives = get_preferred_alternatives (insn);
       const operand_alternative *op_alt = preprocess_insn_constraints (icode);
       if (!insn_static_data->operand_alternative)
        setup_operand_alternative (data, op_alt);
@@ -1206,27 +1206,7 @@ lra_update_insn_recog_data (rtx_insn *insn)
       n = insn_static_data->n_dups;
       if (n != 0)
        memcpy (data->dup_loc, recog_data.dup_loc, n * sizeof (rtx *));
-#if HAVE_ATTR_enabled
-#ifdef ENABLE_CHECKING
-      {
-       int i;
-       alternative_mask enabled;
-
-       n = insn_static_data->n_alternatives;
-       enabled = data->enabled_alternatives;
-       lra_assert (n >= 0);
-       /* Cache the insn to prevent extract_insn call from
-          get_attr_enabled.  */
-       recog_data.insn = insn;
-       for (i = 0; i < n; i++)
-         {
-           which_alternative = i;
-           lra_assert (TEST_BIT (enabled, i)
-                       == (bool) get_attr_enabled (insn));
-         }
-      }
-#endif
-#endif
+      lra_assert (check_bool_attrs (insn));
     }
   return data;
 }
index f460bf3a3a4a5279f8fc031be026bcbd09bf6f38..dcdfedfd920b399b417ccd519402ef88020c15e9 100644 (file)
@@ -497,6 +497,7 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
          SET_HARD_REG_BIT (equiv_regs[i], REGNO (l->loc));
     }
 
+  alternative_mask preferred = get_preferred_alternatives (insn);
   for (i = 0; i < recog_data.n_operands; i++)
     {
       enum machine_mode mode;
@@ -570,7 +571,7 @@ reload_cse_simplify_operands (rtx_insn *insn, rtx testreg)
                     alternative yet and the operand being replaced is not
                     a cheap CONST_INT.  */
                  if (op_alt_regno[i][j] == -1
-                     && TEST_BIT (recog_data.enabled_alternatives, j)
+                     && TEST_BIT (preferred, j)
                      && reg_fits_class_p (testreg, rclass, 0, mode)
                      && (!CONST_INT_P (recog_data.operand[i])
                          || (set_src_cost (recog_data.operand[i],
index 199c7debbf8343b16a0088381fc3a28854a7837d..afcab998124d9f60b377ac581643d775bbed585d 100644 (file)
@@ -2060,25 +2060,46 @@ mode_dependent_address_p (rtx addr, addr_space_t addrspace)
   return targetm.mode_dependent_address_p (addr, addrspace);
 }
 \f
-/* Return the mask of operand alternatives that are allowed for INSN.
-   This mask depends only on INSN and on the current target; it does not
-   depend on things like the values of operands.  */
+/* Return true if boolean attribute ATTR is supported.  */
 
-alternative_mask
-get_enabled_alternatives (rtx_insn *insn)
+static bool
+have_bool_attr (bool_attr attr)
 {
-  /* Quick exit for asms and for targets that don't use the "enabled"
-     attribute.  */
-  int code = INSN_CODE (insn);
-  if (code < 0 || !HAVE_ATTR_enabled)
-    return ALL_ALTERNATIVES;
+  switch (attr)
+    {
+    case BA_ENABLED:
+      return HAVE_ATTR_enabled;
+    case BA_PREFERRED_FOR_SIZE:
+      return HAVE_ATTR_enabled || HAVE_ATTR_preferred_for_size;
+    case BA_PREFERRED_FOR_SPEED:
+      return HAVE_ATTR_enabled || HAVE_ATTR_preferred_for_speed;
+    }
+  gcc_unreachable ();
+}
 
-  /* Calling get_attr_enabled can be expensive, so cache the mask
-     for speed.  */
-  if (this_target_recog->x_enabled_alternatives[code])
-    return this_target_recog->x_enabled_alternatives[code];
+/* Return the value of ATTR for instruction INSN.  */
 
-  /* Temporarily install enough information for get_attr_enabled to assume
+static bool
+get_bool_attr (rtx_insn *insn, bool_attr attr)
+{
+  switch (attr)
+    {
+    case BA_ENABLED:
+      return get_attr_enabled (insn);
+    case BA_PREFERRED_FOR_SIZE:
+      return get_attr_enabled (insn) && get_attr_preferred_for_size (insn);
+    case BA_PREFERRED_FOR_SPEED:
+      return get_attr_enabled (insn) && get_attr_preferred_for_speed (insn);
+    }
+  gcc_unreachable ();
+}
+
+/* Like get_bool_attr_mask, but don't use the cache.  */
+
+static alternative_mask
+get_bool_attr_mask_uncached (rtx_insn *insn, bool_attr attr)
+{
+  /* Temporarily install enough information for get_attr_<foo> to assume
      that the insn operands are already cached.  As above, the attribute
      mustn't depend on the values of operands, so we don't provide their
      real values here.  */
@@ -2086,20 +2107,81 @@ get_enabled_alternatives (rtx_insn *insn)
   int old_alternative = which_alternative;
 
   recog_data.insn = insn;
-  alternative_mask enabled = ALL_ALTERNATIVES;
-  int n_alternatives = insn_data[code].n_alternatives;
+  alternative_mask mask = ALL_ALTERNATIVES;
+  int n_alternatives = insn_data[INSN_CODE (insn)].n_alternatives;
   for (int i = 0; i < n_alternatives; i++)
     {
       which_alternative = i;
-      if (!get_attr_enabled (insn))
-       enabled &= ~ALTERNATIVE_BIT (i);
+      if (!get_bool_attr (insn, attr))
+       mask &= ~ALTERNATIVE_BIT (i);
     }
 
   recog_data.insn = old_insn;
   which_alternative = old_alternative;
+  return mask;
+}
+
+/* Return the mask of operand alternatives that are allowed for INSN
+   by boolean attribute ATTR.  This mask depends only on INSN and on
+   the current target; it does not depend on things like the values of
+   operands.  */
+
+static alternative_mask
+get_bool_attr_mask (rtx_insn *insn, bool_attr attr)
+{
+  /* Quick exit for asms and for targets that don't use these attributes.  */
+  int code = INSN_CODE (insn);
+  if (code < 0 || !have_bool_attr (attr))
+    return ALL_ALTERNATIVES;
 
-  this_target_recog->x_enabled_alternatives[code] = enabled;
-  return enabled;
+  /* Calling get_attr_<foo> can be expensive, so cache the mask
+     for speed.  */
+  if (!this_target_recog->x_bool_attr_masks[code][attr])
+    this_target_recog->x_bool_attr_masks[code][attr]
+      = get_bool_attr_mask_uncached (insn, attr);
+  return this_target_recog->x_bool_attr_masks[code][attr];
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+   target.  */
+
+alternative_mask
+get_enabled_alternatives (rtx_insn *insn)
+{
+  return get_bool_attr_mask (insn, BA_ENABLED);
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+   target and are preferred for the current size/speed optimization
+   choice.  */
+
+alternative_mask
+get_preferred_alternatives (rtx_insn *insn)
+{
+  if (optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))
+    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+  else
+    return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+}
+
+/* Assert that the cached boolean attributes for INSN are still accurate.
+   The backend is required to define these attributes in a way that only
+   depends on the current target (rather than operands, compiler phase,
+   etc.).  */
+
+bool
+check_bool_attrs (rtx_insn *insn)
+{
+  int code = INSN_CODE (insn);
+  if (code >= 0)
+    for (int i = 0; i <= BA_LAST; ++i)
+      {
+       enum bool_attr attr = (enum bool_attr) i;
+       if (this_target_recog->x_bool_attr_masks[code][attr])
+         gcc_assert (this_target_recog->x_bool_attr_masks[code][attr]
+                     == get_bool_attr_mask_uncached (insn, attr));
+      }
+  return true;
 }
 
 /* Like extract_insn, but save insn extracted and don't extract again, when
@@ -4048,8 +4130,8 @@ recog_init ()
       this_target_recog->x_initialized = true;
       return;
     }
-  memset (this_target_recog->x_enabled_alternatives, 0,
-         sizeof (this_target_recog->x_enabled_alternatives));
+  memset (this_target_recog->x_bool_attr_masks, 0,
+         sizeof (this_target_recog->x_bool_attr_masks));
   for (int i = 0; i < LAST_INSN_CODE; ++i)
     if (this_target_recog->x_op_alt[i])
       {
index d3619cbbe5a531fe99182adbccce7cfd71d4f8d3..fe8e0e80e9201a09b70948b6d93d34a4ed2d9de4 100644 (file)
@@ -389,10 +389,19 @@ extern int peep2_current_count;
 #ifndef GENERATOR_FILE
 #include "insn-codes.h"
 
+/* An enum of boolean attributes that may only depend on the current
+   subtarget, not on things like operands or compiler phase.  */
+enum bool_attr {
+  BA_ENABLED,
+  BA_PREFERRED_FOR_SPEED,
+  BA_PREFERRED_FOR_SIZE,
+  BA_LAST = BA_PREFERRED_FOR_SIZE
+};
+
 /* Target-dependent globals.  */
 struct target_recog {
   bool x_initialized;
-  alternative_mask x_enabled_alternatives[LAST_INSN_CODE];
+  alternative_mask x_bool_attr_masks[LAST_INSN_CODE][BA_LAST + 1];
   operand_alternative *x_op_alt[LAST_INSN_CODE];
 };
 
@@ -404,6 +413,8 @@ extern struct target_recog *this_target_recog;
 #endif
 
 alternative_mask get_enabled_alternatives (rtx_insn *);
+alternative_mask get_preferred_alternatives (rtx_insn *);
+bool check_bool_attrs (rtx_insn *);
 
 void recog_init ();
 #endif