]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
mips-protos.h (mips_output_sync): Declare.
authorRichard Sandiford <rdsandiford@googlemail.com>
Wed, 26 Aug 2009 20:39:27 +0000 (20:39 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 26 Aug 2009 20:39:27 +0000 (20:39 +0000)
gcc/
* config/mips/mips-protos.h (mips_output_sync): Declare.
(mips_sync_loop_insns): Likewise.
(mips_output_sync_loop): Replace first two parameters with an rtx.
* config/mips/mips.c (mips_multi_member): New structure.
(mips_multi_members): New variable.
(mips_multi_start): New function.
(mips_multi_add): Likewise.
(mips_multi_add_insn): Likewise.
(mips_multi_add_label): Likewise.
(mips_multi_last_index): Likewise.
(mips_multi_copy_insn): Likewise.
(mips_multi_set_operand): Likewise.
(mips_multi_write): Likewise.
(mips_print_operand_punctuation): Remove '%|' and '%-'.
(mips_init_print_operand_punct): Update accordingly.
(mips_start_ll_sc_sync_block): New function.
(mips_end_ll_sc_sync_block): Likewise.
(mips_output_sync): Likewise.
(mips_sync_insn1_template): Likewise.
(mips_sync_insn2_template): Likewise.
(mips_get_sync_operand): Likewise.
(mips_process_sync_loop): Likewise.
(mips_output_sync_loop): Use mips_process_sync_loop.
(mips_sync_loop_insns): New function.
* config/mips/mips.h (MIPS_COMPARE_AND_SWAP): Delete.
(MIPS_COMPARE_AND_SWAP_12): Likewise.
(MIPS_COMPARE_AND_SWAP_12_ZERO_OP): Likewise.
(MIPS_COMPARE_AND_SWAP_12_NONZERO_OP): Likewise.
(MIPS_SYNC_OP, MIPS_SYNC_OP_12): Likewise.
(MIPS_SYNC_OP_12_AND, MIPS_SYNC_OP_12_XOR): Likewise.
(MIPS_SYNC_OLD_OP_12): Likewise.
(MIPS_SYNC_OLD_OP_12_AND, MIPS_SYNC_OLD_OP_12_XOR): Likewise.
(MIPS_SYNC_NEW_OP_12): Likewise.
(MIPS_SYNC_NEW_OP_12_AND, MIPS_SYNC_NEW_OP_12_XOR): Likewise.
(MIPS_SYNC_OLD_OP, MIPS_SYNC_NEW_OP): Likewise.
(MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND, MIPS_SYNC_NEW_NAND): Likewise.
(MIPS_SYNC_EXCHANGE, MIPS_SYNC_EXCHANGE_12): Likewise.
(MIPS_SYNC_EXCHANGE_12_ZERO_OP): Likewise.
(MIPS_SYNC_EXCHANGE_12_NONZER_OP): Likewise.
* config/mips/mips.md (sync_mem): New attribute.
(sync_oldval, sync_newval, sync_inclusive_mask): Likewise.
(sync_exclusive_mask, sync_required_oldval): Likewise.
(sync_insn1_op2, sync_insn1, sync_insn2): Likewise.
(sync_release_barrier): Likewise.
(length): Handle sync loops.
(sync): Use mips_output_sync.
* config/mips/sync.md (*memory_barrier): Use mips_output_sync.
(sync_compare_and_swap<mode>): Set the new sync_* attributes
and use mips_output_sync_loop.
(compare_and_swap_12, sync_add<mode>, sync_<optab>_12): Likewise.
(sync_old_<optab>_12, sync_new_<optab>_12, sync_nand_12): Likewise.
(sync_old_nand_12, sync_new_nand_12, sync_sub<mode>): Likewise.
(sync_old_add<mode>, sync_old_sub<mode>): Likewise.
(sync_new_add<mode>, sync_new_sub<mode>): Likewise.
(sync_<optab><mode>, sync_old_<optab><mode>): Likewise.
(sync_new_<optab><mode>, sync_nand<mode>): Likewise.
(sync_old_nand<mode>, sync_new_nand<mode>): Likewise.
(sync_lock_test_and_set<mode>, test_and_set_12): Likewise.

From-SVN: r151128

gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/sync.md

index f50b14c18ade886405e4d00f0e522af17cdb9f8e..f6d242b20ecdc0a27957569799466714573b0a39 100644 (file)
@@ -1,3 +1,64 @@
+2009-08-26  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * config/mips/mips-protos.h (mips_output_sync): Declare.
+       (mips_sync_loop_insns): Likewise.
+       (mips_output_sync_loop): Replace first two parameters with an rtx.
+       * config/mips/mips.c (mips_multi_member): New structure.
+       (mips_multi_members): New variable.
+       (mips_multi_start): New function.
+       (mips_multi_add): Likewise.
+       (mips_multi_add_insn): Likewise.
+       (mips_multi_add_label): Likewise.
+       (mips_multi_last_index): Likewise.
+       (mips_multi_copy_insn): Likewise.
+       (mips_multi_set_operand): Likewise.
+       (mips_multi_write): Likewise.
+       (mips_print_operand_punctuation): Remove '%|' and '%-'.
+       (mips_init_print_operand_punct): Update accordingly.
+       (mips_start_ll_sc_sync_block): New function.
+       (mips_end_ll_sc_sync_block): Likewise.
+       (mips_output_sync): Likewise.
+       (mips_sync_insn1_template): Likewise.
+       (mips_sync_insn2_template): Likewise.
+       (mips_get_sync_operand): Likewise.
+       (mips_process_sync_loop): Likewise.
+       (mips_output_sync_loop): Use mips_process_sync_loop.
+       (mips_sync_loop_insns): New function.
+       * config/mips/mips.h (MIPS_COMPARE_AND_SWAP): Delete.
+       (MIPS_COMPARE_AND_SWAP_12): Likewise.
+       (MIPS_COMPARE_AND_SWAP_12_ZERO_OP): Likewise.
+       (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP): Likewise.
+       (MIPS_SYNC_OP, MIPS_SYNC_OP_12): Likewise.
+       (MIPS_SYNC_OP_12_AND, MIPS_SYNC_OP_12_XOR): Likewise.
+       (MIPS_SYNC_OLD_OP_12): Likewise.
+       (MIPS_SYNC_OLD_OP_12_AND, MIPS_SYNC_OLD_OP_12_XOR): Likewise.
+       (MIPS_SYNC_NEW_OP_12): Likewise.
+       (MIPS_SYNC_NEW_OP_12_AND, MIPS_SYNC_NEW_OP_12_XOR): Likewise.
+       (MIPS_SYNC_OLD_OP, MIPS_SYNC_NEW_OP): Likewise.
+       (MIPS_SYNC_NAND, MIPS_SYNC_OLD_NAND, MIPS_SYNC_NEW_NAND): Likewise.
+       (MIPS_SYNC_EXCHANGE, MIPS_SYNC_EXCHANGE_12): Likewise.
+       (MIPS_SYNC_EXCHANGE_12_ZERO_OP): Likewise.
+       (MIPS_SYNC_EXCHANGE_12_NONZER_OP): Likewise.
+       * config/mips/mips.md (sync_mem): New attribute.
+       (sync_oldval, sync_newval, sync_inclusive_mask): Likewise.
+       (sync_exclusive_mask, sync_required_oldval): Likewise.
+       (sync_insn1_op2, sync_insn1, sync_insn2): Likewise.
+       (sync_release_barrier): Likewise.
+       (length): Handle sync loops.
+       (sync): Use mips_output_sync.
+       * config/mips/sync.md (*memory_barrier): Use mips_output_sync.
+       (sync_compare_and_swap<mode>): Set the new sync_* attributes
+       and use mips_output_sync_loop.
+       (compare_and_swap_12, sync_add<mode>, sync_<optab>_12): Likewise.
+       (sync_old_<optab>_12, sync_new_<optab>_12, sync_nand_12): Likewise.
+       (sync_old_nand_12, sync_new_nand_12, sync_sub<mode>): Likewise.
+       (sync_old_add<mode>, sync_old_sub<mode>): Likewise.
+       (sync_new_add<mode>, sync_new_sub<mode>): Likewise.
+       (sync_<optab><mode>, sync_old_<optab><mode>): Likewise.
+       (sync_new_<optab><mode>, sync_nand<mode>): Likewise.
+       (sync_old_nand<mode>, sync_new_nand<mode>): Likewise.
+       (sync_lock_test_and_set<mode>, test_and_set_12): Likewise.
+
 2009-08-26  Richard Guenther  <rguenther@suse.de>
 
        PR middle-end/41163
index d35025942216fd786d70675156f96e881f3aff39..a1e28ce23c6e797e01d19a37c4ad232ccd9c93c5 100644 (file)
@@ -300,7 +300,9 @@ extern const char *mips_output_load_label (void);
 extern const char *mips_output_conditional_branch (rtx, rtx *, const char *,
                                                   const char *);
 extern const char *mips_output_order_conditional_branch (rtx, rtx *, bool);
-extern const char *mips_output_sync_loop (bool, const char *, rtx *);
+extern const char *mips_output_sync (void);
+extern const char *mips_output_sync_loop (rtx, rtx *);
+extern unsigned int mips_sync_loop_insns (rtx, rtx *);
 extern const char *mips_output_division (const char *, rtx *);
 extern unsigned int mips_hard_regno_nregs (int, enum machine_mode);
 extern bool mips_linked_madd_p (rtx, rtx);
index 423639923767fc28db44ccae741d8475c7a96d75..1e4d8bd8ed5a506ef8807afbe1c938abfb295549 100644 (file)
@@ -3763,6 +3763,132 @@ mips_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
   return mips_address_insns (addr, SImode, false);
 }
 \f
+/* Information about a single instruction in a multi-instruction
+   asm sequence.  */
+struct mips_multi_member {
+  /* True if this is a label, false if it is code.  */
+  bool is_label_p;
+
+  /* The output_asm_insn format of the instruction.  */
+  const char *format;
+
+  /* The operands to the instruction.  */
+  rtx operands[MAX_RECOG_OPERANDS];
+};
+typedef struct mips_multi_member mips_multi_member;
+
+/* Vector definitions for the above.  */
+DEF_VEC_O(mips_multi_member);
+DEF_VEC_ALLOC_O(mips_multi_member, heap);
+
+/* The instructions that make up the current multi-insn sequence.  */
+static VEC (mips_multi_member, heap) *mips_multi_members;
+
+/* How many instructions (as opposed to labels) are in the current
+   multi-insn sequence.  */
+static unsigned int mips_multi_num_insns;
+
+/* Start a new multi-insn sequence.  */
+
+static void
+mips_multi_start (void)
+{
+  VEC_truncate (mips_multi_member, mips_multi_members, 0);
+  mips_multi_num_insns = 0;
+}
+
+/* Add a new, uninitialized member to the current multi-insn sequence.  */
+
+static struct mips_multi_member *
+mips_multi_add (void)
+{
+  return VEC_safe_push (mips_multi_member, heap, mips_multi_members, 0);
+}
+
+/* Add a normal insn with the given asm format to the current multi-insn
+   sequence.  The other arguments are a null-terminated list of operands.  */
+
+static void
+mips_multi_add_insn (const char *format, ...)
+{
+  struct mips_multi_member *member;
+  va_list ap;
+  unsigned int i;
+  rtx op;
+
+  member = mips_multi_add ();
+  member->is_label_p = false;
+  member->format = format;
+  va_start (ap, format);
+  i = 0;
+  while ((op = va_arg (ap, rtx)))
+    member->operands[i++] = op;
+  va_end (ap);
+  mips_multi_num_insns++;
+}
+
+/* Add the given label definition to the current multi-insn sequence.
+   The definition should include the colon.  */
+
+static void
+mips_multi_add_label (const char *label)
+{
+  struct mips_multi_member *member;
+
+  member = mips_multi_add ();
+  member->is_label_p = true;
+  member->format = label;
+}
+
+/* Return the index of the last member of the current multi-insn sequence.  */
+
+static unsigned int
+mips_multi_last_index (void)
+{
+  return VEC_length (mips_multi_member, mips_multi_members) - 1;
+}
+
+/* Add a copy of an existing instruction to the current multi-insn
+   sequence.  I is the index of the instruction that should be copied.  */
+
+static void
+mips_multi_copy_insn (unsigned int i)
+{
+  struct mips_multi_member *member;
+
+  member = mips_multi_add ();
+  memcpy (member, VEC_index (mips_multi_member, mips_multi_members, i),
+         sizeof (*member));
+  gcc_assert (!member->is_label_p);
+}
+
+/* Change the operand of an existing instruction in the current
+   multi-insn sequence.  I is the index of the instruction,
+   OP is the index of the operand, and X is the new value.  */
+
+static void
+mips_multi_set_operand (unsigned int i, unsigned int op, rtx x)
+{
+  VEC_index (mips_multi_member, mips_multi_members, i)->operands[op] = x;
+}
+
+/* Write out the asm code for the current multi-insn sequence.  */
+
+static void
+mips_multi_write (void)
+{
+  struct mips_multi_member *member;
+  unsigned int i;
+
+  for (i = 0;
+       VEC_iterate (mips_multi_member, mips_multi_members, i, member);
+       i++)
+    if (member->is_label_p)
+      fprintf (asm_out_file, "%s\n", member->format);
+    else
+      output_asm_insn (member->format, member->operands);
+}
+\f
 /* Return one word of double-word value OP, taking into account the fixed
    endianness of certain registers.  HIGH_P is true to select the high part,
    false to select the low part.  */
@@ -7047,8 +7173,6 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_switch)
    '^' Print the name of the pic call-through register (t9 or $25).
    '+' Print the name of the gp register (usually gp or $28).
    '$' Print the name of the stack pointer register (sp or $29).
-   '|' Print ".set push; .set mips2" if !ISA_HAS_LL_SC.
-   '-' Print ".set pop" under the same conditions for '|'.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7132,16 +7256,6 @@ mips_print_operand_punctuation (FILE *file, int ch)
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
-    case '|':
-      if (!ISA_HAS_LL_SC)
-       fputs (".set\tpush\n\t.set\tmips2\n\t", file);
-      break;
-
-    case '-':
-      if (!ISA_HAS_LL_SC)
-       fputs ("\n\t.set\tpop", file);
-      break;
-
     default:
       gcc_unreachable ();
       break;
@@ -7155,7 +7269,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$|-"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10808,31 +10922,279 @@ mips_output_order_conditional_branch (rtx insn, rtx *operands, bool inverted_p)
   return mips_output_conditional_branch (insn, operands, branch[1], branch[0]);
 }
 \f
-/* Return or emit the assembly code for __sync_*() loop LOOP.  The
-   loop should support both normal and likely branches, using %? and
-   %~ where appropriate.  If BARRIER_BEFORE is true a sync sequence is
-   emitted before the loop.  A sync is always emitted after the loop.
-   OPERANDS are the insn operands.  */
+/* Start a block of code that needs access to the LL, SC and SYNC
+   instructions.  */
+
+static void
+mips_start_ll_sc_sync_block (void)
+{
+  if (!ISA_HAS_LL_SC)
+    {
+      output_asm_insn (".set\tpush", 0);
+      output_asm_insn (".set\tmips2", 0);
+    }
+}
+
+/* End a block started by mips_start_ll_sc_sync_block.  */
+
+static void
+mips_end_ll_sc_sync_block (void)
+{
+  if (!ISA_HAS_LL_SC)
+    output_asm_insn (".set\tpop", 0);
+}
+
+/* Output and/or return the asm template for a sync instruction.  */
 
 const char *
-mips_output_sync_loop (bool barrier_before,
-                      const char *loop, rtx *operands)
+mips_output_sync (void)
 {
-  if (barrier_before)
-    output_asm_insn ("sync", NULL);
-  /* Use branch-likely instructions to work around the LL/SC R10000 errata.  */
-  mips_branch_likely = TARGET_FIX_R10000;
+  mips_start_ll_sc_sync_block ();
+  output_asm_insn ("sync", 0);
+  mips_end_ll_sc_sync_block ();
+  return "";
+}
 
-  /* If the target needs a sync after the loop, emit the loop now and
-     return the sync.  */
+/* Return the asm template associated with sync_insn1 value TYPE.
+   IS_64BIT_P is true if we want a 64-bit rather than 32-bit operation.  */
 
-  if (TARGET_SYNC_AFTER_SC)
+static const char *
+mips_sync_insn1_template (enum attr_sync_insn1 type, bool is_64bit_p)
+{
+  switch (type)
+    {
+    case SYNC_INSN1_MOVE:
+      return "move\t%0,%z2";
+    case SYNC_INSN1_LI:
+      return "li\t%0,%2";
+    case SYNC_INSN1_ADDU:
+      return is_64bit_p ? "daddu\t%0,%1,%z2" : "addu\t%0,%1,%z2";
+    case SYNC_INSN1_ADDIU:
+      return is_64bit_p ? "daddiu\t%0,%1,%2" : "addiu\t%0,%1,%2";
+    case SYNC_INSN1_SUBU:
+      return is_64bit_p ? "dsubu\t%0,%1,%z2" : "subu\t%0,%1,%z2";
+    case SYNC_INSN1_AND:
+      return "and\t%0,%1,%z2";
+    case SYNC_INSN1_ANDI:
+      return "andi\t%0,%1,%2";
+    case SYNC_INSN1_OR:
+      return "or\t%0,%1,%z2";
+    case SYNC_INSN1_ORI:
+      return "ori\t%0,%1,%2";
+    case SYNC_INSN1_XOR:
+      return "xor\t%0,%1,%z2";
+    case SYNC_INSN1_XORI:
+      return "xori\t%0,%1,%2";
+    }
+  gcc_unreachable ();
+}
+
+/* Return the asm template associated with sync_insn2 value TYPE.  */
+
+static const char *
+mips_sync_insn2_template (enum attr_sync_insn2 type)
+{
+  switch (type)
+    {
+    case SYNC_INSN2_NOP:
+      gcc_unreachable ();
+    case SYNC_INSN2_AND:
+      return "and\t%0,%1,%z2";
+    case SYNC_INSN2_XOR:
+      return "xor\t%0,%1,%z2";
+    case SYNC_INSN2_NOT:
+      return "nor\t%0,%1,%.";
+    }
+  gcc_unreachable ();
+}
+
+/* OPERANDS are the operands to a sync loop instruction and INDEX is
+   the value of the one of the sync_* attributes.  Return the operand
+   referred to by the attribute, or DEFAULT_VALUE if the insn doesn't
+   have the associated attribute.  */
+
+static rtx
+mips_get_sync_operand (rtx *operands, int index, rtx default_value)
+{
+  if (index > 0)
+    default_value = operands[index - 1];
+  return default_value;
+}
+
+/* INSN is a sync loop with operands OPERANDS.  Build up a multi-insn
+   sequence for it.  */
+
+static void
+mips_process_sync_loop (rtx insn, rtx *operands)
+{
+  rtx at, mem, oldval, newval, inclusive_mask, exclusive_mask;
+  rtx required_oldval, insn1_op2, tmp1, tmp2, tmp3;
+  unsigned int tmp3_insn;
+  enum attr_sync_insn1 insn1;
+  enum attr_sync_insn2 insn2;
+  bool is_64bit_p;
+
+  /* Read an operand from the sync_WHAT attribute and store it in
+     variable WHAT.  DEFAULT is the default value if no attribute
+     is specified.  */
+#define READ_OPERAND(WHAT, DEFAULT) \
+  WHAT = mips_get_sync_operand (operands, (int) get_attr_sync_##WHAT (insn), \
+                               DEFAULT)
+
+  /* Read the memory.  */
+  READ_OPERAND (mem, 0);
+  gcc_assert (mem);
+  is_64bit_p = (GET_MODE_BITSIZE (GET_MODE (mem)) == 64);
+
+  /* Read the other attributes.  */
+  at = gen_rtx_REG (GET_MODE (mem), AT_REGNUM);
+  READ_OPERAND (oldval, at);
+  READ_OPERAND (newval, at);
+  READ_OPERAND (inclusive_mask, 0);
+  READ_OPERAND (exclusive_mask, 0);
+  READ_OPERAND (required_oldval, 0);
+  READ_OPERAND (insn1_op2, 0);
+  insn1 = get_attr_sync_insn1 (insn);
+  insn2 = get_attr_sync_insn2 (insn);
+
+  mips_multi_start ();
+
+  /* Output the release side of the memory barrier.  */
+  if (get_attr_sync_release_barrier (insn) == SYNC_RELEASE_BARRIER_YES)
+    mips_multi_add_insn ("sync", NULL);
+
+  /* Output the branch-back label.  */
+  mips_multi_add_label ("1:");
+
+  /* OLDVAL = *MEM.  */
+  mips_multi_add_insn (is_64bit_p ? "lld\t%0,%1" : "ll\t%0,%1",
+                      oldval, mem, NULL);
+
+  /* if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2.  */
+  if (required_oldval)
+    {
+      if (inclusive_mask == 0)
+       tmp1 = oldval;
+      else
+       {
+         gcc_assert (oldval != at);
+         mips_multi_add_insn ("and\t%0,%1,%2",
+                              at, oldval, inclusive_mask, NULL);
+         tmp1 = at;
+       }
+      mips_multi_add_insn ("bne\t%0,%z1,2f", tmp1, required_oldval, NULL);
+    }
+
+  /* $TMP1 = OLDVAL & EXCLUSIVE_MASK.  */
+  if (exclusive_mask == 0)
+    tmp1 = const0_rtx;
+  else
+    {
+      gcc_assert (oldval != at);
+      mips_multi_add_insn ("and\t%0,%1,%z2",
+                          at, oldval, exclusive_mask, NULL);
+      tmp1 = at;
+    }
+
+  /* $TMP2 = INSN1 (OLDVAL, INSN1_OP2).
+
+     We can ignore moves if $TMP4 != INSN1_OP2, since we'll still emit
+     at least one instruction in that case.  */
+  if (insn1 == SYNC_INSN1_MOVE
+      && (tmp1 != const0_rtx || insn2 != SYNC_INSN2_NOP))
+    tmp2 = insn1_op2;
+  else
     {
-      output_asm_insn (loop, operands);
-      loop = "sync";
+      mips_multi_add_insn (mips_sync_insn1_template (insn1, is_64bit_p),
+                          newval, oldval, insn1_op2, NULL);
+      tmp2 = newval;
     }
-  return loop;
+
+  /* $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK).  */
+  if (insn2 == SYNC_INSN2_NOP)
+    tmp3 = tmp2;
+  else
+    {
+      mips_multi_add_insn (mips_sync_insn2_template (insn2),
+                          newval, tmp2, inclusive_mask, NULL);
+      tmp3 = newval;
+    }
+  tmp3_insn = mips_multi_last_index ();
+
+  /* $AT = $TMP1 | $TMP3.  */
+  if (tmp1 == const0_rtx || tmp3 == const0_rtx)
+    {
+      mips_multi_set_operand (tmp3_insn, 0, at);
+      tmp3 = at;
+    }
+  else
+    {
+      gcc_assert (tmp1 != tmp3);
+      mips_multi_add_insn ("or\t%0,%1,%2", at, tmp1, tmp3, NULL);
+    }
+
+  /* if (!commit (*MEM = $AT)) goto 1.
+
+     This will sometimes be a delayed branch; see the write code below
+     for details.  */
+  mips_multi_add_insn (is_64bit_p ? "scd\t%0,%1" : "sc\t%0,%1", at, mem, NULL);
+  mips_multi_add_insn ("beq%?\t%0,%.,1b", at, NULL);
+
+  /* if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot].  */
+  if (insn1 != SYNC_INSN1_MOVE && insn1 != SYNC_INSN1_LI && tmp3 != newval)
+    {
+      mips_multi_copy_insn (tmp3_insn);
+      mips_multi_set_operand (mips_multi_last_index (), 0, newval);
+    }
+  else
+    mips_multi_add_insn ("nop", NULL);
+
+  /* Output the acquire side of the memory barrier.  */
+  if (TARGET_SYNC_AFTER_SC)
+    mips_multi_add_insn ("sync", NULL);
+
+  /* Output the exit label, if needed.  */
+  if (required_oldval)
+    mips_multi_add_label ("2:");
+
+#undef READ_OPERAND
+}
+
+/* Output and/or return the asm template for sync loop INSN, which has
+   the operands given by OPERANDS.  */
+
+const char *
+mips_output_sync_loop (rtx insn, rtx *operands)
+{
+  mips_process_sync_loop (insn, operands);
+
+  /* Use branch-likely instructions to work around the LL/SC R10000
+     errata.  */
+  mips_branch_likely = TARGET_FIX_R10000;
+
+  mips_push_asm_switch (&mips_noreorder);
+  mips_push_asm_switch (&mips_nomacro);
+  mips_push_asm_switch (&mips_noat);
+  mips_start_ll_sc_sync_block ();
+
+  mips_multi_write ();
+
+  mips_end_ll_sc_sync_block ();
+  mips_pop_asm_switch (&mips_noat);
+  mips_pop_asm_switch (&mips_nomacro);
+  mips_pop_asm_switch (&mips_noreorder);
+
+  return "";
+}
+
+/* Return the number of individual instructions in sync loop INSN,
+   which has the operands given by OPERANDS.  */
+
+unsigned int
+mips_sync_loop_insns (rtx insn, rtx *operands)
+{
+  mips_process_sync_loop (insn, operands);
+  return mips_multi_num_insns;
 }
 \f
 /* Return the assembly code for DIV or DDIV instruction DIVISION, which has
index 2c9199a12c31b724a1bfe5f84f8ad2353e5af96f..352dbd25618b4a59745eb820f5b3d35ebf9a07ff 100644 (file)
@@ -3113,270 +3113,6 @@ while (0)
 #define HAVE_AS_TLS 0
 #endif
 
-/* Return an asm string that atomically:
-
-     - Compares memory reference %1 to register %2 and, if they are
-       equal, changes %1 to %3.
-
-     - Sets register %0 to the old value of memory reference %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc" instructions
-   and OP is the instruction that should be used to load %3 into a
-   register.  */
-#define MIPS_COMPARE_AND_SWAP(SUFFIX, OP)      \
-  "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n"          \
-  "\tbne\t%0,%z2,2f\n"                         \
-  "\t" OP "\t%@,%3\n"                          \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)\n"                            \
-  "2:\n"
-
-/* Return an asm string that atomically:
-
-     - Given that %2 contains a bit mask and %3 the inverted mask and
-       that %4 and %5 have already been ANDed with %2.
-
-     - Compares the bits in memory reference %1 selected by mask %2 to
-       register %4 and, if they are equal, changes the selected bits
-       in memory to %5.
-
-     - Sets register %0 to the old value of memory reference %1.
-
-    OPS are the instructions needed to OR %5 with %@.  */
-#define MIPS_COMPARE_AND_SWAP_12(OPS)          \
-  "%(%<%[%|1:\tll\t%0,%1\n"                    \
-  "\tand\t%@,%0,%2\n"                          \
-  "\tbne\t%@,%z4,2f\n"                         \
-  "\tand\t%@,%0,%3\n"                          \
-  OPS                                          \
-  "\tsc\t%@,%1\n"                              \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)\n"                            \
-  "2:\n"
-
-#define MIPS_COMPARE_AND_SWAP_12_ZERO_OP ""
-#define MIPS_COMPARE_AND_SWAP_12_NONZERO_OP "\tor\t%@,%@,%5\n"
-
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %0 to %0 INSN %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  */
-#define MIPS_SYNC_OP(SUFFIX, INSN)             \
-  "%(%<%[%|1:\tll" SUFFIX "\t%@,%0\n"          \
-  "\t" INSN "\t%@,%@,%1\n"                     \
-  "\tsc" SUFFIX "\t%@,%0\n"                    \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Given that %1 contains a bit mask and %2 the inverted mask and
-       that %3 has already been ANDed with %1.
-
-     - Sets the selected bits of memory reference %0 to %0 INSN %3.
-
-     - Uses scratch register %4.
-
-    AND_OP is an instruction done after INSN to mask INSN's result
-    with the mask.  For most operations, this is an AND with the
-    inclusive mask (%1).  For nand operations -- where the result of
-    INSN is already correctly masked -- it instead performs a bitwise
-    not.  */
-#define MIPS_SYNC_OP_12(INSN, AND_OP)          \
-  "%(%<%[%|1:\tll\t%4,%0\n"                    \
-  "\tand\t%@,%4,%2\n"                          \
-  "\t" INSN "\t%4,%4,%z3\n"                    \
-  AND_OP                                       \
-  "\tor\t%@,%@,%4\n"                           \
-  "\tsc\t%@,%0\n"                              \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-#define MIPS_SYNC_OP_12_AND "\tand\t%4,%4,%1\n"
-#define MIPS_SYNC_OP_12_XOR "\txor\t%4,%4,%1\n"
-
-/* Return an asm string that atomically:
-
-     - Given that %2 contains a bit mask and %3 the inverted mask and
-       that %4 has already been ANDed with %2.
-
-     - Sets the selected bits of memory reference %1 to %1 INSN %4.
-
-     - Sets %0 to the original value of %1.
-
-     - Uses scratch register %5.
-
-    AND_OP is an instruction done after INSN to mask INSN's result
-    with the mask.  For most operations, this is an AND with the
-    inclusive mask (%1).  For nand operations -- where the result of
-    INSN is already correctly masked -- it instead performs a bitwise
-    not.  */
-#define MIPS_SYNC_OLD_OP_12(INSN, AND_OP)      \
-  "%(%<%[%|1:\tll\t%0,%1\n"                    \
-  "\tand\t%@,%0,%3\n"                          \
-  "\t" INSN "\t%5,%0,%z4\n"                    \
-  AND_OP                                       \
-  "\tor\t%@,%@,%5\n"                           \
-  "\tsc\t%@,%1\n"                              \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-#define MIPS_SYNC_OLD_OP_12_AND "\tand\t%5,%5,%2\n"
-#define MIPS_SYNC_OLD_OP_12_XOR "\txor\t%5,%5,%2\n"
-
-/* Return an asm string that atomically:
-
-     - Given that %2 contains a bit mask and %3 the inverted mask and
-       that %4 has already been ANDed with %2.
-
-     - Sets the selected bits of memory reference %1 to %1 INSN %4.
-
-     - Sets %0 to the new value of %1.
-
-    AND_OP is an instruction done after INSN to mask INSN's result
-    with the mask.  For most operations, this is an AND with the
-    inclusive mask (%1).  For nand operations -- where the result of
-    INSN is already correctly masked -- it instead performs a bitwise
-    not.  */
-#define MIPS_SYNC_NEW_OP_12(INSN, AND_OP)      \
-  "%(%<%[%|1:\tll\t%0,%1\n"                            \
-  "\tand\t%@,%0,%3\n"                          \
-  "\t" INSN "\t%0,%0,%z4\n"                    \
-  AND_OP                                       \
-  "\tor\t%@,%@,%0\n"                           \
-  "\tsc\t%@,%1\n"                              \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-#define MIPS_SYNC_NEW_OP_12_AND "\tand\t%0,%0,%2\n"
-#define MIPS_SYNC_NEW_OP_12_XOR "\txor\t%0,%0,%2\n"
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %1 to %1 INSN %2.
-
-     - Sets register %0 to the old value of memory reference %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  */
-#define MIPS_SYNC_OLD_OP(SUFFIX, INSN)         \
-  "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n"          \
-  "\t" INSN "\t%@,%0,%2\n"                     \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %1 to %1 INSN %2.
-
-     - Sets register %0 to the new value of memory reference %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  */
-#define MIPS_SYNC_NEW_OP(SUFFIX, INSN)         \
-  "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n"          \
-  "\t" INSN "\t%@,%0,%2\n"                     \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq%?\t%@,%.,1b%~\n"                      \
-  "\t" INSN "\t%0,%0,%2%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %0 to ~(%0 AND %1).
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  INSN is the and instruction needed to and a register
-   with %2.  */
-#define MIPS_SYNC_NAND(SUFFIX, INSN)           \
-  "%(%<%[%|1:\tll" SUFFIX "\t%@,%0\n"          \
-  "\t" INSN "\t%@,%@,%1\n"                     \
-  "\tnor\t%@,%@,%.\n"                          \
-  "\tsc" SUFFIX "\t%@,%0\n"                    \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %1 to ~(%1 AND %2).
-
-     - Sets register %0 to the old value of memory reference %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  INSN is the and instruction needed to and a register
-   with %2.  */
-#define MIPS_SYNC_OLD_NAND(SUFFIX, INSN)       \
-  "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n"                  \
-  "\t" INSN "\t%@,%0,%2\n"                     \
-  "\tnor\t%@,%@,%.\n"                          \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %1 to ~(%1 AND %2).
-
-     - Sets register %0 to the new value of memory reference %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  INSN is the and instruction needed to and a register
-   with %2.  */
-#define MIPS_SYNC_NEW_NAND(SUFFIX, INSN)       \
-  "%(%<%[%|1:\tll" SUFFIX "\t%0,%1\n"                  \
-  "\t" INSN "\t%0,%0,%2\n"                     \
-  "\tnor\t%@,%0,%.\n"                          \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq%?\t%@,%.,1b%~\n"                      \
-  "\tnor\t%0,%0,%.%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Sets memory reference %1 to %2.
-
-     - Sets register %0 to the old value of memory reference %1.
-
-   SUFFIX is the suffix that should be added to "ll" and "sc"
-   instructions.  OP is the and instruction that should be used to
-   load %2 into a register.  */
-#define MIPS_SYNC_EXCHANGE(SUFFIX, OP)         \
-  "%(%<%[%|\n"                                 \
-  "1:\tll" SUFFIX "\t%0,%1\n"                  \
-  "\t" OP "\t%@,%2\n"                          \
-  "\tsc" SUFFIX "\t%@,%1\n"                    \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-/* Return an asm string that atomically:
-
-     - Given that %2 contains an inclusive mask, %3 and exclusive mask
-       and %4 has already been ANDed with the inclusive mask.
-
-     - Sets bits selected by the inclusive mask of memory reference %1
-       to %4.
-
-     - Sets register %0 to the old value of memory reference %1.
-
-    OPS are the instructions needed to OR %4 with %@.
-
-    Operand %2 is unused, but needed as to give the test_and_set_12
-    insn the five operands expected by the expander.  */
-#define MIPS_SYNC_EXCHANGE_12(OPS)              \
-  "%(%<%[%|\n"                                 \
-  "1:\tll\t%0,%1\n"                            \
-  "\tand\t%@,%0,%3\n"                          \
-  OPS                                          \
-  "\tsc\t%@,%1\n"                              \
-  "\tbeq%?\t%@,%.,1b\n"                                \
-  "\tnop%-%]%>%)"
-
-#define MIPS_SYNC_EXCHANGE_12_ZERO_OP ""
-#define MIPS_SYNC_EXCHANGE_12_NONZERO_OP "\tor\t%@,%@,%4\n"
-
 #ifndef USED_FOR_TARGET
 /* Information about ".set noFOO; ...; .set FOO" blocks.  */
 struct mips_asm_switch {
index 92363b3b59cdb1b21720cb325bf625bd8e27d808..a510e0a7b7445034cf5419bbe7fc65cd85c24d37 100644 (file)
                (const_string "yes")
                (const_string "no")))
 
+;; Attributes describing a sync loop.  These loops have the form:
+;;
+;;       if (RELEASE_BARRIER == YES) sync
+;;    1: OLDVAL = *MEM
+;;       if ((OLDVAL & INCLUSIVE_MASK) != REQUIRED_OLDVAL) goto 2
+;;       $TMP1 = OLDVAL & EXCLUSIVE_MASK
+;;       $TMP2 = INSN1 (OLDVAL, INSN1_OP2)
+;;       $TMP3 = INSN2 ($TMP2, INCLUSIVE_MASK)
+;;       $AT |= $TMP1 | $TMP3
+;;       if (!commit (*MEM = $AT)) goto 1.
+;;         if (INSN1 != MOVE && INSN1 != LI) NEWVAL = $TMP3 [delay slot]
+;;       sync
+;;    2:
+;;
+;; where "$" values are temporaries and where the other values are
+;; specified by the attributes below.  Values are specified as operand
+;; numbers and insns are specified as enums.  If no operand number is
+;; specified, the following values are used instead:
+;;
+;;    - OLDVAL: $AT
+;;    - NEWVAL: $AT
+;;    - INCLUSIVE_MASK: -1
+;;    - REQUIRED_OLDVAL: OLDVAL & INCLUSIVE_MASK
+;;    - EXCLUSIVE_MASK: 0
+;;
+;; MEM and INSN1_OP2 are required.
+;;
+;; Ideally, the operand attributes would be integers, with -1 meaning "none",
+;; but the gen* programs don't yet support that.
+(define_attr "sync_mem" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_oldval" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_newval" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_inclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_exclusive_mask" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_required_oldval" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_insn1_op2" "none,0,1,2,3,4,5" (const_string "none"))
+(define_attr "sync_insn1" "move,li,addu,addiu,subu,and,andi,or,ori,xor,xori"
+  (const_string "move"))
+(define_attr "sync_insn2" "nop,and,xor,not"
+  (const_string "nop"))
+(define_attr "sync_release_barrier" "yes,no"
+  (const_string "yes"))
+
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 
          (eq_attr "type" "idiv,idiv3")
          (symbol_ref "mips_idiv_insns () * 4")
+
+         (not (eq_attr "sync_mem" "none"))
+         (symbol_ref "mips_sync_loop_insns (insn, operands) * 4")
          ] (const_int 4)))
 
 ;; Attribute describing the processor.  This attribute must match exactly
 (define_insn "sync"
   [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
   "GENERATE_SYNC"
-  "%|sync%-")
+  { return mips_output_sync (); })
 
 (define_insn "synci"
   [(unspec_volatile [(match_operand 0 "pmode_register_operand" "d")]
index affb3faff753e56c05f7bceb80c1ba97304e7c0b..e28f56c601a9a149ccbb209ec17f8813ec542ccd 100644 (file)
@@ -40,7 +40,7 @@
   [(set (match_operand:BLK 0 "" "")
        (unspec:BLK [(match_dup 0)] UNSPEC_MEMORY_BARRIER))]
   "GENERATE_SYNC"
-  "%|sync%-")
+  { return mips_output_sync (); })
 
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
                              (match_operand:GPR 3 "arith_operand" "I,d")]
         UNSPEC_COMPARE_AND_SWAP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_COMPARE_AND_SWAP ("<d>", "li");
-  else
-    loop = MIPS_COMPARE_AND_SWAP ("<d>", "move");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "32")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "li,move")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_required_oldval" "2")
+   (set_attr "sync_insn1_op2" "3")])
 
 (define_expand "sync_compare_and_swap<mode>"
   [(match_operand:SHORT 0 "register_operand")
                             (match_operand:SI 5 "reg_or_0_operand" "d,J")]
                            UNSPEC_COMPARE_AND_SWAP_12))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_NONZERO_OP);
-  else
-    loop = MIPS_COMPARE_AND_SWAP_12 (MIPS_COMPARE_AND_SWAP_12_ZERO_OP);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40,36")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_inclusive_mask" "2")
+   (set_attr "sync_exclusive_mask" "3")
+   (set_attr "sync_required_oldval" "4")
+   (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
   [(set (match_operand:GPR 0 "memory_operand" "+R,R")
                     (match_operand:GPR 1 "arith_operand" "I,d"))]
          UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_OP ("<d>", "<d>addiu");
-  else
-    loop = MIPS_SYNC_OP ("<d>", "<d>addu");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "addiu,addu")
+   (set_attr "sync_mem" "0")
+   (set_attr "sync_insn1_op2" "1")])
 
 (define_expand "sync_<optab><mode>"
   [(set (match_operand:SHORT 0 "memory_operand")
          UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 4 "=&d"))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_OP_12 ("<insn>", MIPS_SYNC_OP_12_AND);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "<insn>")
+   (set_attr "sync_insn2" "and")
+   (set_attr "sync_mem" "0")
+   (set_attr "sync_inclusive_mask" "1")
+   (set_attr "sync_exclusive_mask" "2")
+   (set_attr "sync_insn1_op2" "3")
+   (set_attr "sync_oldval" "4")
+   (set_attr "sync_newval" "4")])
 
 (define_expand "sync_old_<optab><mode>"
   [(parallel [
          UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 5 "=&d"))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_OLD_OP_12 ("<insn>", MIPS_SYNC_OLD_OP_12_AND);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "<insn>")
+   (set_attr "sync_insn2" "and")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_inclusive_mask" "2")
+   (set_attr "sync_exclusive_mask" "3")
+   (set_attr "sync_insn1_op2" "4")
+   (set_attr "sync_newval" "5")])
 
 (define_expand "sync_new_<optab><mode>"
   [(parallel [
           (match_dup 3)
           (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_NEW_OP_12 ("<insn>", MIPS_SYNC_NEW_OP_12_AND);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "<insn>")
+   (set_attr "sync_insn2" "and")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_newval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_inclusive_mask" "2")
+   (set_attr "sync_exclusive_mask" "3")
+   (set_attr "sync_insn1_op2" "4")])
 
 (define_expand "sync_nand<mode>"
   [(set (match_operand:SHORT 0 "memory_operand")
          UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 4 "=&d"))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_OP_12 ("and", MIPS_SYNC_OP_12_XOR);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "and")
+   (set_attr "sync_insn2" "xor")
+   (set_attr "sync_mem" "0")
+   (set_attr "sync_inclusive_mask" "1")
+   (set_attr "sync_exclusive_mask" "2")
+   (set_attr "sync_insn1_op2" "3")
+   (set_attr "sync_oldval" "4")
+   (set_attr "sync_newval" "4")])
 
 (define_expand "sync_old_nand<mode>"
   [(parallel [
          UNSPEC_SYNC_OLD_OP_12))
    (clobber (match_scratch:SI 5 "=&d"))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_OLD_OP_12 ("and", MIPS_SYNC_OLD_OP_12_XOR);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "and")
+   (set_attr "sync_insn2" "xor")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_inclusive_mask" "2")
+   (set_attr "sync_exclusive_mask" "3")
+   (set_attr "sync_insn1_op2" "4")
+   (set_attr "sync_newval" "5")])
 
 (define_expand "sync_new_nand<mode>"
   [(parallel [
           (match_dup 3)
           (match_dup 4)] UNSPEC_SYNC_NEW_OP_12))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_NEW_OP_12 ("and", MIPS_SYNC_NEW_OP_12_XOR);
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "40")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "and")
+   (set_attr "sync_insn2" "xor")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_newval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_inclusive_mask" "2")
+   (set_attr "sync_exclusive_mask" "3")
+   (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
   [(set (match_operand:GPR 0 "memory_operand" "+R")
        (unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
-                             (match_operand:GPR 1 "register_operand" "d"))]
+                     (match_operand:GPR 1 "register_operand" "d"))]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_OP ("<d>", "<d>subu");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "subu")
+   (set_attr "sync_mem" "0")
+   (set_attr "sync_insn1_op2" "1")])
 
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
                     (match_operand:GPR 2 "arith_operand" "I,d"))]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_OLD_OP ("<d>", "<d>addiu");
-  else
-    loop = MIPS_SYNC_OLD_OP ("<d>", "<d>addu");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "addiu,addu")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
                      (match_operand:GPR 2 "register_operand" "d"))]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_OLD_OP ("<d>", "<d>subu");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "subu")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
          [(plus:GPR (match_dup 1) (match_dup 2))]
         UNSPEC_SYNC_NEW_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_NEW_OP ("<d>", "<d>addiu");
-  else
-    loop = MIPS_SYNC_NEW_OP ("<d>", "<d>addu");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "addiu,addu")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_newval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
          [(minus:GPR (match_dup 1) (match_dup 2))]
         UNSPEC_SYNC_NEW_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop = MIPS_SYNC_NEW_OP ("<d>", "<d>subu");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "subu")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_newval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
   [(set (match_operand:GPR 0 "memory_operand" "+R,R")
                              (match_dup 0))]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_OP ("<d>", "<immediate_insn>");
-  else
-    loop = MIPS_SYNC_OP ("<d>", "<insn>");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "<immediate_insn>,<insn>")
+   (set_attr "sync_mem" "0")
+   (set_attr "sync_insn1_op2" "1")])
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
                            (match_dup 1))]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_OLD_OP ("<d>", "<immediate_insn>");
-  else
-    loop = MIPS_SYNC_OLD_OP ("<d>", "<insn>");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "<immediate_insn>,<insn>")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
                            (match_dup 1))]
         UNSPEC_SYNC_NEW_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_NEW_OP ("<d>", "<immediate_insn>");
-  else
-    loop = MIPS_SYNC_NEW_OP ("<d>", "<insn>");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "28")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "<immediate_insn>,<insn>")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_newval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
   [(set (match_operand:GPR 0 "memory_operand" "+R,R")
        (unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_NAND ("<d>", "andi");
-  else
-    loop = MIPS_SYNC_NAND ("<d>", "and");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "32")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "andi,and")
+   (set_attr "sync_insn2" "not")
+   (set_attr "sync_mem" "0")
+   (set_attr "sync_insn1_op2" "1")])
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
         UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_OLD_NAND ("<d>", "andi");
-  else
-    loop = MIPS_SYNC_OLD_NAND ("<d>", "and");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "32")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "andi,and")
+   (set_attr "sync_insn2" "not")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
        (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
         UNSPEC_SYNC_NEW_OP))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_NEW_NAND ("<d>", "andi");
-  else
-    loop = MIPS_SYNC_NEW_NAND ("<d>", "and");
-  return mips_output_sync_loop (true, loop, operands);
-}
-  [(set_attr "length" "32")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_insn1" "andi,and")
+   (set_attr "sync_insn2" "not")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_newval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
        (unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
         UNSPEC_SYNC_EXCHANGE))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_EXCHANGE ("<d>", "li");
-  else
-    loop = MIPS_SYNC_EXCHANGE ("<d>", "move");
-  return mips_output_sync_loop (false, loop, operands);
-}
-  [(set_attr "length" "24")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_release_barrier" "no")
+   (set_attr "sync_insn1" "li,move")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   (set_attr "sync_insn1_op2" "2")])
 
 (define_expand "sync_lock_test_and_set<mode>"
   [(match_operand:SHORT 0 "register_operand")
 })
 
 (define_insn "test_and_set_12"
-  [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-       (match_operand:SI 1 "memory_operand" "+R,R"))
+  [(set (match_operand:SI 0 "register_operand" "=&d")
+       (match_operand:SI 1 "memory_operand" "+R"))
    (set (match_dup 1)
-       (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
-                            (match_operand:SI 3 "register_operand" "d,d")
-                            (match_operand:SI 4 "arith_operand" "d,J")]
+       (unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
+                            (match_operand:SI 3 "register_operand" "d")
+                            (match_operand:SI 4 "arith_operand" "dJ")]
          UNSPEC_SYNC_EXCHANGE_12))]
   "GENERATE_LL_SC"
-{
-  const char *loop;
-  if (which_alternative == 0)
-    loop = MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_NONZERO_OP);
-  else
-    loop = MIPS_SYNC_EXCHANGE_12 (MIPS_SYNC_EXCHANGE_12_ZERO_OP);
-  return mips_output_sync_loop (false, loop, operands);
-}
-  [(set_attr "length" "28,24")])
+  { return mips_output_sync_loop (insn, operands); }
+  [(set_attr "sync_release_barrier" "no")
+   (set_attr "sync_oldval" "0")
+   (set_attr "sync_mem" "1")
+   ;; Unused, but needed to give the number of operands expected by
+   ;; the expander.
+   (set_attr "sync_inclusive_mask" "2")
+   (set_attr "sync_exclusive_mask" "3")
+   (set_attr "sync_insn1_op2" "4")])