Currently, the predicable attribute can only be either "yes" or "no" for an instruction, without distinguishing between alternatives. This can be a problem - on C6X, there are move and add instructions where exactly one alternative isn't predicable. The comment in gensupport.c mentions that FRV also has this problem, and I seem to recall someone mentioning a similar situation on ARM.
This patch extends gensupport to modify the attribute vector of the conditional variant of each instruction so that the "predicable" attribute is renamed to "ce_enabled" (an internal attribute with default "yes"). The default definition of attribute "enabled" is then modified to also test whether "ce_enabled" evaluates to "yes". Definitions of "enabled" in a conditionalized pattern are renamed to "nonce_enabled", and "enabled" is defined as "nonce_enabled" && "ce_enabled". It's done this way as we can't easily rewrite set_attr definitions in gensupport.c without moving over a whole lot of code from genattrtab. Tested with a bootstrap on i686-linux, and regression tests with a suitably modified 4.5 c6x-elf toolchain (one multilib successful so far for the latest version of the patch and some more for earlier versions). I've tried a few variants of "enabled" and "predicable" definitions in the c6x machine description and it appears to work as intended. Bernd
* 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". Index: gcc/gensupport.c =================================================================== --- gcc/gensupport.c (revision 174430) +++ gcc/gensupport.c (working copy) @@ -368,6 +368,25 @@ queue_pattern (rtx pattern, struct queue 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 * 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 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 Index: gcc/doc/md.texi =================================================================== --- gcc/doc/md.texi (revision 174430) +++ gcc/doc/md.texi (working copy) @@ -6728,6 +6728,14 @@ (define_attr @var{name} @var{list-of-val @end smallexample @var{name} is a string specifying the name of the attribute being defined. +Some predicates 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 @@ -7937,11 +7945,14 @@ if the current insn is predicated, and w 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