diff mbox

Allow alternatives for attr "predicable"

Message ID 4DE69949.9010700@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt June 1, 2011, 7:55 p.m. UTC
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".
diff mbox

Patch

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