summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/doc/md.texi21
-rw-r--r--gcc/gensupport.c176
3 files changed, 187 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index af173123600..26bfc6f5c1a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,13 @@
2011-06-21 Bernd Schmidt <bernds@codesourcery.com>
+ * gensupport.c (add_define_attr): New static function.
+ (is_predicable): Allow multi-alternative lists for the "predicable"
+ attribute.
+ (modify_attr_enabled_ce, alter_attrs_for_insn): New static functions.
+ (process_one_cond_exec): Call alter_attrs_for_insn.
+ * doc/md.texi (Defining Attributes): Mention some standard names.
+ (Conditional Execution): Update documentation for "predicable".
+
* doc/extend.texi (__builtin_clrsb, __builtin_clrsbl,
__builtin_clrsbll): Document.
* doc/rtl.texi (clrsb): New entry.
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 0023405bea6..65e4070d91d 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -6745,6 +6745,14 @@ by the target machine. It looks like:
@end smallexample
@var{name} is a string specifying the name of the attribute being defined.
+Some attributes are used in a special way by the rest of the compiler. The
+@code{enabled} attribute can be used to conditionally enable or disable
+insn alternatives (@pxref{Disable Insn Alternatives}). The @code{predicable}
+attribute, together with a suitable @code{define_cond_exec}
+(@pxref{Conditional Execution}), can be used to automatically generate
+conditional variants of instruction patterns. The compiler internally uses
+the names @code{ce_enabled} and @code{nonce_enabled}, so they should not be
+used elsewhere as alternative names.
@var{list-of-values} is either a string that specifies a comma-separated
list of values that can be assigned to the attribute, or a null string to
@@ -7954,11 +7962,14 @@ if the current insn is predicated, and will otherwise be @code{NULL}.
When @code{define_cond_exec} is used, an implicit reference to
the @code{predicable} instruction attribute is made.
-@xref{Insn Attributes}. This attribute must be boolean (i.e.@: have
-exactly two elements in its @var{list-of-values}). Further, it must
-not be used with complex expressions. That is, the default and all
-uses in the insns must be a simple constant, not dependent on the
-alternative or anything else.
+@xref{Insn Attributes}. This attribute must be a boolean (i.e.@: have
+exactly two elements in its @var{list-of-values}), with the possible
+values being @code{no} and @code{yes}. The default and all uses in
+the insns must be a simple constant, not a complex expressions. It
+may, however, depend on the alternative, by using a comma-separated
+list of values. If that is the case, the port should also define an
+@code{enabled} attribute (@pxref{Disable Insn Alternatives}), which
+should also allow only @code{no} and @code{yes} as its values.
For each @code{define_insn} for which the @code{predicable}
attribute is true, a new @code{define_insn} pattern will be
diff --git a/gcc/gensupport.c b/gcc/gensupport.c
index cd72e770d75..e56291e3a38 100644
--- a/gcc/gensupport.c
+++ b/gcc/gensupport.c
@@ -368,6 +368,25 @@ queue_pattern (rtx pattern, struct queue_elem ***list_tail,
return e;
}
+/* Build a define_attr for an binary attribute with name NAME and
+ possible values "yes" and "no", and queue it. */
+static void
+add_define_attr (const char *name)
+{
+ struct queue_elem *e = XNEW(struct queue_elem);
+ rtx t1 = rtx_alloc (DEFINE_ATTR);
+ XSTR (t1, 0) = name;
+ XSTR (t1, 1) = "no,yes";
+ XEXP (t1, 2) = rtx_alloc (CONST_STRING);
+ XSTR (XEXP (t1, 2), 0) = "yes";
+ e->data = t1;
+ e->filename = "built-in";
+ e->lineno = -1;
+ e->next = define_attr_queue;
+ define_attr_queue = e;
+
+}
+
/* Recursively remove constraints from an rtx. */
static void
@@ -547,17 +566,10 @@ is_predicable (struct queue_elem *elem)
return predicable_default;
found:
- /* Verify that predicability does not vary on the alternative. */
- /* ??? It should be possible to handle this by simply eliminating
- the non-predicable alternatives from the insn. FRV would like
- to do this. Delay this until we've got the basics solid. */
+ /* Find out which value we're looking at. Multiple alternatives means at
+ least one is predicable. */
if (strchr (value, ',') != NULL)
- {
- error_with_line (elem->lineno, "multiple alternatives for `predicable'");
- return 0;
- }
-
- /* Find out which value we're looking at. */
+ return 1;
if (strcmp (value, predicable_true) == 0)
return 1;
if (strcmp (value, predicable_false) == 0)
@@ -798,6 +810,146 @@ alter_test_for_insn (struct queue_elem *ce_elem,
XSTR (insn_elem->data, 2));
}
+/* Modify VAL, which is an attribute expression for the "enabled" attribute,
+ to take "ce_enabled" into account. Return the new expression. */
+static rtx
+modify_attr_enabled_ce (rtx val)
+{
+ rtx eq_attr, str;
+ rtx ite;
+ eq_attr = rtx_alloc (EQ_ATTR);
+ ite = rtx_alloc (IF_THEN_ELSE);
+ str = rtx_alloc (CONST_STRING);
+
+ XSTR (eq_attr, 0) = "ce_enabled";
+ XSTR (eq_attr, 1) = "yes";
+ XSTR (str, 0) = "no";
+ XEXP (ite, 0) = eq_attr;
+ XEXP (ite, 1) = val;
+ XEXP (ite, 2) = str;
+
+ return ite;
+}
+
+/* Alter the attribute vector of INSN, which is a COND_EXEC variant created
+ from a define_insn pattern. We must modify the "predicable" attribute
+ to be named "ce_enabled", and also change any "enabled" attribute that's
+ present so that it takes ce_enabled into account.
+ We rely on the fact that INSN was created with copy_rtx, and modify data
+ in-place. */
+
+static void
+alter_attrs_for_insn (rtx insn)
+{
+ static bool global_changes_made = false;
+ rtvec vec = XVEC (insn, 4);
+ rtvec new_vec;
+ rtx val, set;
+ int num_elem;
+ int predicable_idx = -1;
+ int enabled_idx = -1;
+ int i;
+
+ if (! vec)
+ return;
+
+ num_elem = GET_NUM_ELEM (vec);
+ for (i = num_elem - 1; i >= 0; --i)
+ {
+ rtx sub = RTVEC_ELT (vec, i);
+ switch (GET_CODE (sub))
+ {
+ case SET_ATTR:
+ if (strcmp (XSTR (sub, 0), "predicable") == 0)
+ {
+ predicable_idx = i;
+ XSTR (sub, 0) = "ce_enabled";
+ }
+ else if (strcmp (XSTR (sub, 0), "enabled") == 0)
+ {
+ enabled_idx = i;
+ XSTR (sub, 0) = "nonce_enabled";
+ }
+ break;
+
+ case SET_ATTR_ALTERNATIVE:
+ if (strcmp (XSTR (sub, 0), "predicable") == 0)
+ /* We already give an error elsewhere. */
+ return;
+ else if (strcmp (XSTR (sub, 0), "enabled") == 0)
+ {
+ enabled_idx = i;
+ XSTR (sub, 0) = "nonce_enabled";
+ }
+ break;
+
+ case SET:
+ if (GET_CODE (SET_DEST (sub)) != ATTR)
+ break;
+ if (strcmp (XSTR (SET_DEST (sub), 0), "predicable") == 0)
+ {
+ sub = SET_SRC (sub);
+ if (GET_CODE (sub) == CONST_STRING)
+ {
+ predicable_idx = i;
+ XSTR (sub, 0) = "ce_enabled";
+ }
+ else
+ /* We already give an error elsewhere. */
+ return;
+ break;
+ }
+ if (strcmp (XSTR (SET_DEST (sub), 0), "enabled") == 0)
+ {
+ enabled_idx = i;
+ XSTR (SET_DEST (sub), 0) = "nonce_enabled";
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ if (predicable_idx == -1)
+ return;
+
+ if (!global_changes_made)
+ {
+ struct queue_elem *elem;
+
+ global_changes_made = true;
+ add_define_attr ("ce_enabled");
+ add_define_attr ("nonce_enabled");
+
+ for (elem = define_attr_queue; elem ; elem = elem->next)
+ if (strcmp (XSTR (elem->data, 0), "enabled") == 0)
+ {
+ XEXP (elem->data, 2)
+ = modify_attr_enabled_ce (XEXP (elem->data, 2));
+ }
+ }
+ if (enabled_idx == -1)
+ return;
+
+ new_vec = rtvec_alloc (num_elem + 1);
+ for (i = 0; i < num_elem; i++)
+ RTVEC_ELT (new_vec, i) = RTVEC_ELT (vec, i);
+ val = rtx_alloc (IF_THEN_ELSE);
+ XEXP (val, 0) = rtx_alloc (EQ_ATTR);
+ XEXP (val, 1) = rtx_alloc (CONST_STRING);
+ XEXP (val, 2) = rtx_alloc (CONST_STRING);
+ XSTR (XEXP (val, 0), 0) = "nonce_enabled";
+ XSTR (XEXP (val, 0), 1) = "yes";
+ XSTR (XEXP (val, 1), 0) = "yes";
+ XSTR (XEXP (val, 2), 0) = "no";
+ set = rtx_alloc (SET);
+ SET_DEST (set) = rtx_alloc (ATTR);
+ XSTR (SET_DEST (set), 0) = "enabled";
+ SET_SRC (set) = modify_attr_enabled_ce (val);
+ RTVEC_ELT (new_vec, i) = set;
+ XVEC (insn, 4) = new_vec;
+}
+
/* Adjust all of the operand numbers in SRC to match the shift they'll
get from an operand displacement of DISP. Return a pointer after the
adjusted string. */
@@ -943,9 +1095,7 @@ process_one_cond_exec (struct queue_elem *ce_elem)
XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem);
XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem,
alternatives, max_operand);
-
- /* ??? Set `predicable' to false. Not crucial since it's really
- only used here, and we won't reprocess this new pattern. */
+ alter_attrs_for_insn (insn);
/* Put the new pattern on the `other' list so that it
(a) is not reprocessed by other define_cond_exec patterns