diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/doc/md.texi | 21 | ||||
-rw-r--r-- | gcc/gensupport.c | 176 |
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 |