mips.md (UNSPEC_COMPARE_AND_SWAP_12): New unspec_volitile.
authorRichard Sandiford <rsandifo@gcc.gnu.org>
Sat, 26 Apr 2008 07:40:04 +0000 (07:40 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sat, 26 Apr 2008 07:40:04 +0000 (07:40 +0000)
gcc/
2008-04-23  David Daney  <ddaney@avtrex.com>

* config/mips/mips.md (UNSPEC_COMPARE_AND_SWAP_12): New
unspec_volitile.
(UNSPEC_SYNC_OLD_OP, UNSPEC_SYNC_NEW_OP, UNSPEC_SYNC_EXCHANGE,
UNSPEC_MEMORY_BARRIER, UNSPEC_SET_GOT_VERSION,
UNSPEC_UPDATE_GOT_VERSION): Renumber.
(sync_compare_and_swap<mode>): New expand for QI and HI modes.
(compare_and_swap_12): New insn.
* config/mips/mips-protos.h (mips_expand_compare_and_swap_12): Declare.
* config/mips/mips.c (mips_force_binary): New function.
(mips_emit_int_order_test, mips_expand_synci_loop): Use it.
(mips_expand_compare_and_swap_12): New function.
* config/mips/mips.h (MIPS_COMPARE_AND_SWAP_12): New macro.

gcc/testsuite/
* gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Expect
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 and
__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 to be defined.
* gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Likewise.

From-SVN: r134695

gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-1.c
gcc/testsuite/gcc.target/mips/gcc-have-sync-compare-and-swap-2.c

index 374615b45463609bfd52650a85b947898a2e9742..2435b898a3d2aa1a72de660a4bc90421ee160940 100644 (file)
@@ -1,3 +1,18 @@
+2008-04-26  David Daney  <ddaney@avtrex.com>
+
+       * config/mips/mips.md (UNSPEC_COMPARE_AND_SWAP_12): New
+       unspec_volitile.
+       (UNSPEC_SYNC_OLD_OP, UNSPEC_SYNC_NEW_OP, UNSPEC_SYNC_EXCHANGE,
+       UNSPEC_MEMORY_BARRIER, UNSPEC_SET_GOT_VERSION,
+       UNSPEC_UPDATE_GOT_VERSION): Renumber.
+       (sync_compare_and_swap<mode>): New expand for QI and HI modes.
+       (compare_and_swap_12): New insn.
+       * config/mips/mips-protos.h (mips_expand_compare_and_swap_12): Declare.
+       * config/mips/mips.c (mips_force_binary): New function.
+       (mips_emit_int_order_test, mips_expand_synci_loop): Use it.
+       (mips_expand_compare_and_swap_12): New function.
+       * config/mips/mips.h (MIPS_COMPARE_AND_SWAP_12): New macro.
+
 2008-04-25  Jan Hubicka  <jh@suse.cz>
 
        PR testsuite/35843
index deb99a0886706338d5b19ced8d17e0c1b7f2e1d3..fbac8fcfd07a1592e9b4c665f8ef3f609172e443 100644 (file)
@@ -292,5 +292,6 @@ extern bool mips_use_ins_ext_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 extern const char *mips16e_output_save_restore (rtx, HOST_WIDE_INT);
 extern bool mips16e_save_restore_pattern_p (rtx, HOST_WIDE_INT,
                                            struct mips16e_save_restore_info *);
+extern void mips_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
 
 #endif /* ! GCC_MIPS_PROTOS_H */
index 94a1427453317c9d961cd956b5b6b6d7e0aac596..86072acf4ab4e46b10cc30c864c19ea4e016e621 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for MIPS code generation.
    Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by A. Lichnewsky, lich@inria.inria.fr.
    Changes by Michael Meissner, meissner@osf.org.
@@ -2121,6 +2121,19 @@ mips_emit_binary (enum rtx_code code, rtx target, rtx op0, rtx op1)
                          gen_rtx_fmt_ee (code, GET_MODE (target), op0, op1)));
 }
 
+/* Compute (CODE OP0 OP1) and store the result in a new register
+   of mode MODE.  Return that new register.  */
+
+static rtx
+mips_force_binary (enum machine_mode mode, enum rtx_code code, rtx op0, rtx op1)
+{
+  rtx reg;
+
+  reg = gen_reg_rtx (mode);
+  mips_emit_binary (code, reg, op0, op1);
+  return reg;
+}
+
 /* Copy VALUE to a register and return that register.  If new pseudos
    are allowed, copy it into a new register, otherwise use DEST.  */
 
@@ -3741,8 +3754,10 @@ mips_emit_int_order_test (enum rtx_code code, bool *invert_ptr,
        }
       else if (invert_ptr == 0)
        {
-         rtx inv_target = gen_reg_rtx (GET_MODE (target));
-         mips_emit_binary (inv_code, inv_target, cmp0, cmp1);
+         rtx inv_target;
+
+         inv_target = mips_force_binary (GET_MODE (target),
+                                         inv_code, cmp0, cmp1);
          mips_emit_binary (XOR, target, inv_target, const1_rtx);
        }
       else
@@ -5850,8 +5865,7 @@ mips_expand_synci_loop (rtx begin, rtx end)
 
   emit_insn (gen_synci (begin));
 
-  cmp = gen_reg_rtx (Pmode);
-  mips_emit_binary (GTU, cmp, begin, end);
+  cmp = mips_force_binary (Pmode, GTU, begin, end);
 
   mips_emit_binary (PLUS, begin, begin, inc);
 
@@ -5859,6 +5873,68 @@ mips_expand_synci_loop (rtx begin, rtx end)
   emit_jump_insn (gen_condjump (cmp_result, label));
 }
 \f
+/* Expand a QI or HI mode compare_and_swap.  The operands are the same
+   as for the generator function.  */
+
+void
+mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+{
+  rtx orig_addr, memsi_addr, memsi, shift, shiftsi, unshifted_mask;
+  rtx mask, inverted_mask, oldvalsi, old_shifted, newvalsi, new_shifted, res;
+
+  /* Compute the address of the containing SImode value.  */
+  orig_addr = force_reg (Pmode, XEXP (mem, 0));
+  memsi_addr = mips_force_binary (Pmode, AND, orig_addr,
+                                 force_reg (Pmode, GEN_INT (-4)));
+
+  /* Create a memory reference for it.  */
+  memsi = gen_rtx_MEM (SImode, memsi_addr);
+  set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
+
+  /* Work out the byte offset of the QImode or HImode value,
+     counting from the least significant byte.  */
+  shift = mips_force_binary (Pmode, AND, orig_addr, GEN_INT (3));
+  if (TARGET_BIG_ENDIAN)
+    mips_emit_binary (XOR, shift, shift,
+                     GEN_INT (GET_MODE (mem) == QImode ? 3 : 2));
+
+  /* Multiply by eight to convert the shift value from bytes to bits.  */
+  mips_emit_binary (ASHIFT, shift, shift, GEN_INT (3));
+
+  /* Make the final shift an SImode value, so that it can be used in
+     SImode operations.  */
+  shiftsi = force_reg (SImode, gen_lowpart (SImode, shift));
+
+  /* Set MASK to an inclusive mask of the QImode or HImode value.  */
+  unshifted_mask = GEN_INT (GET_MODE_MASK (GET_MODE (mem)));
+  unshifted_mask = force_reg (SImode, unshifted_mask);
+  mask = mips_force_binary (SImode, ASHIFT, unshifted_mask, shiftsi);
+
+  /* Compute the equivalent exclusive mask.  */
+  inverted_mask = gen_reg_rtx (SImode);
+  emit_insn (gen_rtx_SET (VOIDmode, inverted_mask,
+                         gen_rtx_NOT (SImode, mask)));
+
+  /* Shift the old value into place.  */
+  oldvalsi = force_reg (SImode, gen_lowpart (SImode, oldval));
+  old_shifted = mips_force_binary (SImode, ASHIFT, oldvalsi, shiftsi);
+
+  /* Do the same for the new value.  */
+  newvalsi = force_reg (SImode, gen_lowpart (SImode, newval));
+  new_shifted = mips_force_binary (SImode, ASHIFT, newvalsi, shiftsi);
+
+  /* Do the SImode atomic access.  */
+  res = gen_reg_rtx (SImode);
+  emit_insn (gen_compare_and_swap_12 (res, memsi, mask, inverted_mask,
+                                     old_shifted, new_shifted));
+
+  /* Shift and convert the result.  */
+  mips_emit_binary (AND, res, res, mask);
+  mips_emit_binary (LSHIFTRT, res, res, shiftsi);
+  mips_emit_move (result, gen_lowpart (GET_MODE (result), res));
+}
+
 /* Return true if it is possible to use left/right accesses for a
    bitfield of WIDTH bits starting BITPOS bits into *OP.  When
    returning true, update *OP, *LEFT and *RIGHT as follows:
index 3a0e58c96e6d259460c29e531c7c4014c1e219b1..cda433aa4f0a35f27199a1b259efb9595f31cc11 100644 (file)
@@ -2904,6 +2904,30 @@ while (0)
   "\tnop\n"                                    \
   "2:\tsync%-%]%>%)"
 
+/* 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.
+ */
+#define MIPS_COMPARE_AND_SWAP_12               \
+  "%(%<%[%|sync\n"                             \
+  "1:\tll\t%0,%1\n"                            \
+  "\tand\t%@,%0,%2\n"                          \
+  "\tbne\t%@,%4,2f\n"                          \
+  "\tand\t%@,%0,%3\n"                          \
+  "\tor\t%@,%@,%5\n"                           \
+  "\tsc\t%@,%1\n"                              \
+  "\tbeq\t%@,%.,1b\n"                          \
+  "\tnop\n"                                    \
+  "\tsync%-%]%>%)\n"                           \
+  "2:\n"
+
 /* Return an asm string that atomically:
 
      - Sets memory reference %0 to %0 INSN %1.
index cbdcdc6ed13193334b3b330e26fb0e9e709ea504..05adf2226d4b1322ba8355f77621ed43affebcaf 100644 (file)
    (UNSPEC_SYNCI               35)
    (UNSPEC_SYNC                        36)
    (UNSPEC_COMPARE_AND_SWAP    37)
-   (UNSPEC_SYNC_OLD_OP         38)
-   (UNSPEC_SYNC_NEW_OP         39)
-   (UNSPEC_SYNC_EXCHANGE       40)
-   (UNSPEC_MEMORY_BARRIER      41)
-   (UNSPEC_SET_GOT_VERSION     42)
-   (UNSPEC_UPDATE_GOT_VERSION  43)
+   (UNSPEC_COMPARE_AND_SWAP_12 38)
+   (UNSPEC_SYNC_OLD_OP         39)
+   (UNSPEC_SYNC_NEW_OP         40)
+   (UNSPEC_SYNC_EXCHANGE       41)
+   (UNSPEC_MEMORY_BARRIER      42)
+   (UNSPEC_SET_GOT_VERSION     43)
+   (UNSPEC_UPDATE_GOT_VERSION  44)
    
    (UNSPEC_ADDRESS_FIRST       100)
 
 }
   [(set_attr "length" "32")])
 
+(define_expand "sync_compare_and_swap<mode>"
+  [(match_operand:SHORT 0 "register_operand")
+   (match_operand:SHORT 1 "memory_operand")
+   (match_operand:SHORT 2 "general_operand")
+   (match_operand:SHORT 3 "general_operand")]
+  "GENERATE_LL_SC"
+{
+  mips_expand_compare_and_swap_12 (operands[0], operands[1],
+                                  operands[2], operands[3]);
+  DONE;
+})
+
+;; Helper insn for mips_expand_compare_and_swap_12.
+(define_insn "compare_and_swap_12"
+  [(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")
+                            (match_operand:SI 3 "register_operand" "d")
+                            (match_operand:SI 4 "register_operand" "d")
+                            (match_operand:SI 5 "register_operand" "d")]
+                           UNSPEC_COMPARE_AND_SWAP_12))]
+  "GENERATE_LL_SC"
+{
+  return MIPS_COMPARE_AND_SWAP_12;
+}
+  [(set_attr "length" "40")])
+
 (define_insn "sync_add<mode>"
   [(set (match_operand:GPR 0 "memory_operand" "+R,R")
        (unspec_volatile:GPR
index bbb71b265ed01561102239e3af7ab7450ce214fb..8f91bfd57526a6ab13f6bb2b3170b9b9b1bd504a 100644 (file)
@@ -1,3 +1,10 @@
+2008-04-26  Richard Sandiford  <rsandifo@nildram.co.uk>
+
+       * gcc.target/mips/gcc-have-sync-compare-and-swap-1.c: Expect
+       __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 and
+       __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 to be defined.
+       * gcc.target/mips/gcc-have-sync-compare-and-swap-2.c: Likewise.
+
 2008-04-25  Tobias Burnus  <burnus@net-b.de>
 
        * gfortran/array_constructor_23.f: Change REAL(10) into kind > 8.
index 72eff4da37c3b7a28f8f5c5404caf1b407a4a377..4c642258f7b98d17995ce4248c98545fc5b9038b 100644 (file)
@@ -1,11 +1,11 @@
 /* { dg-do preprocess } */
 /* { dg-mips-options "-mips2" } */
 
-#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) == defined (__mips16)
 #error nonono
 #endif
 
-#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) == defined (__mips16)
 #error nonono
 #endif
 
index fed2b38a57f0348234325b527974ccd67dc1def0..4265e4167ba81cf3e0198a76db909fb2041b9a7e 100644 (file)
@@ -1,11 +1,11 @@
 /* { dg-do preprocess } */
 /* { dg-mips-options "-mgp64" } */
 
-#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) == defined (__mips16)
 #error nonono
 #endif
 
-#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+#if defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) == defined (__mips16)
 #error nonono
 #endif