===================================================================
@@ -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 instru
@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.
-
-If an insn alternative is disabled, then it will never be used. The
-compiler treats the constraints for the disabled alternative as
-unsatisfiable.
+There are three insn attributes that may be used to selectively disable
+instruction alternatives:
-In order to make use of the @code{enabled} attribute a back end has to add
-in the machine description files:
+@table @code
+@item enabled
+Says whether an alternative is available on the current subtarget.
-@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_size
+Says whether an enabled alternative should be used in code that is
+optimized for size.
+
+@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:
===================================================================
@@ -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.
===================================================================
@@ -389,10 +389,19 @@ struct insn_data_d
#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 @@ #define this_target_recog (&default_targ
#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
===================================================================
@@ -2055,25 +2055,46 @@ mode_dependent_address_p (rtx addr, addr
return targetm.mode_dependent_address_p (addr, addrspace);
}
-/* 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. */
@@ -2081,20 +2102,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
@@ -4043,8 +4125,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])
{
===================================================================
@@ -416,6 +416,7 @@ record_reg_classes (int n_alts, int n_op
/* 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_op
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]);
===================================================================
@@ -1783,6 +1783,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG
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
@@ -1812,7 +1813,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG
}
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;
===================================================================
@@ -493,6 +493,7 @@ reload_cse_simplify_operands (rtx_insn *
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;
@@ -566,7 +567,7 @@ reload_cse_simplify_operands (rtx_insn *
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],
===================================================================
@@ -5901,10 +5901,10 @@ ix86_legitimate_combined_insn (rtx_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
===================================================================
@@ -85,6 +85,10 @@ Software Foundation; either version 3, o
/* 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, in
/* 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 (
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 *constraint
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_
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_nod
}
extract_insn (insn);
+ preferred_alternatives = get_preferred_alternatives (insn);
preprocess_constraints (insn);
process_single_reg_class_operands (false, freq);
===================================================================
@@ -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;
};
===================================================================
@@ -1680,14 +1680,14 @@ process_alt_operands (int only_alternati
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;
===================================================================
@@ -917,7 +917,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;
@@ -977,7 +977,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,
@@ -1011,7 +1011,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);
@@ -1202,27 +1202,7 @@ lra_update_insn_recog_data (rtx_insn *in
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;
}