alpha.c (emit_insxl, [...]): New functions.
authorRichard Henderson <rth@gcc.gnu.org>
Sat, 9 Jul 2005 18:28:23 +0000 (11:28 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Sat, 9 Jul 2005 18:28:23 +0000 (11:28 -0700)
        * config/alpha/alpha.c (emit_insxl, alpha_expand_compare_and_swap_12,
        alpha_split_compare_and_swap_12, alpha_expand_lock_test_and_set_12,
        alpha_split_lock_test_and_set_12): New functions.
        * config/alpha/alpha-protos.h: Update.
        * config/alpha/alpha.md (UNSPEC_MB, UNSPEC_ATOMIC,
        UNSPEC_CMPXCHG, UNSPEC_XCHG): Rename from UNSPECV_FOO.
        * config/alpha/sync.md (I12MODE): New.
        (memory_barrier, mb_internal): Use unspec instead of unspec_volatile.
        (sync_<fetchop_name><I48MODE>): Likewise.
        (sync_nand<I48MODE>): Likewise.
        (sync_old_<fetchop_name><I48MODE>): Likewise.
        (sync_new_<fetchop_name><I48MODE>): Likewise.
        (sync_old_nand<I48MODE>, sync_new_nand<I48MODE>): Likewise.
        (sync_compare_and_swap<I48MODE>): Likewise.
        (sync_lock_test_and_set<I48MODE>): Likewise.
        (sync_compare_and_swap<I12MODE>): New.
        (sync_compare_and_swap<I12MODE>_1): New.
        (sync_lock_test_and_set<I12MODE>): New.
        (sync_lock_test_and_set<I12MODE>_1): New.

        * lib/target-supports.exp (check_effective_target_sync_char_short):
        Add alpha.

From-SVN: r101833

gcc/ChangeLog
gcc/config/alpha/alpha-protos.h
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.md
gcc/config/alpha/sync.md
gcc/testsuite/ChangeLog
gcc/testsuite/lib/target-supports.exp

index abaa36d0ee22044943248ad5a3b11930fc51e250..f6a729a9695072ec5fecdfadb9cb601e6a5953ec 100644 (file)
@@ -1,9 +1,30 @@
+2005-07-09  Richard Henderson  <rth@redhat.com>
+
+       * config/alpha/alpha.c (emit_insxl, alpha_expand_compare_and_swap_12,
+       alpha_split_compare_and_swap_12, alpha_expand_lock_test_and_set_12,
+       alpha_split_lock_test_and_set_12): New functions.
+       * config/alpha/alpha-protos.h: Update.
+       * config/alpha/alpha.md (UNSPEC_MB, UNSPEC_ATOMIC,
+       UNSPEC_CMPXCHG, UNSPEC_XCHG): Rename from UNSPECV_FOO.
+       * config/alpha/sync.md (I12MODE): New.
+       (memory_barrier, mb_internal): Use unspec instead of unspec_volatile.
+       (sync_<fetchop_name><I48MODE>): Likewise.
+       (sync_nand<I48MODE>): Likewise.
+       (sync_old_<fetchop_name><I48MODE>): Likewise.
+       (sync_new_<fetchop_name><I48MODE>): Likewise.
+       (sync_old_nand<I48MODE>, sync_new_nand<I48MODE>): Likewise.
+       (sync_compare_and_swap<I48MODE>): Likewise.
+       (sync_lock_test_and_set<I48MODE>): Likewise.
+       (sync_compare_and_swap<I12MODE>): New.
+       (sync_compare_and_swap<I12MODE>_1): New.
+       (sync_lock_test_and_set<I12MODE>): New.
+       (sync_lock_test_and_set<I12MODE>_1): New.
+
 2005-07-09  Diego Novillo  <dnovillo@redhat.com>
 
        PR 21356
        PR 22332
-       * passes.c (execute_todo): Cleanup the CFG before updating
-       SSA.
+       * passes.c (execute_todo): Cleanup the CFG before updating SSA.
 
 2005-07-09  Jakub Jelinek  <jakub@redhat.com>
 
index d854e35ca411c5531b18eacc82f2c87581acaa10..5dd57343c582740ea5c881ccf0d49603c62aad26 100644 (file)
@@ -103,7 +103,13 @@ extern void alpha_emit_xfloating_arith (enum rtx_code, rtx[]);
 extern void alpha_emit_xfloating_cvt (enum rtx_code, rtx[]);
 extern void alpha_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
 extern void alpha_split_compare_and_swap (rtx, rtx, rtx, rtx, rtx);
+extern void alpha_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
+extern void alpha_split_compare_and_swap_12 (enum machine_mode, rtx, rtx,
+                                            rtx, rtx, rtx, rtx, rtx);
 extern void alpha_split_lock_test_and_set (rtx, rtx, rtx, rtx);
+extern void alpha_expand_lock_test_and_set_12 (rtx, rtx, rtx);
+extern void alpha_split_lock_test_and_set_12 (enum machine_mode, rtx, rtx,
+                                             rtx, rtx, rtx);
 #endif
 
 extern rtx alpha_need_linkage (const char *, int);
index 3eaf15999570adf474d5d461643ab607ccf45557..5d8f72df2b102570197fc354cede94599df81e08 100644 (file)
@@ -4453,6 +4453,34 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
   emit_insn (fn (res, mem, val));
 }
 
+/* A subroutine of the atomic operation splitters.  Emit an insxl
+   instruction in MODE.  */
+
+static rtx
+emit_insxl (enum machine_mode mode, rtx op1, rtx op2)
+{
+  rtx ret = gen_reg_rtx (DImode);
+  rtx (*fn) (rtx, rtx, rtx);
+
+  if (WORDS_BIG_ENDIAN)
+    {
+      if (mode == QImode)
+       fn = gen_insbl_be;
+      else
+       fn = gen_inswl_be;
+    }
+  else
+    {
+      if (mode == QImode)
+       fn = gen_insbl_le;
+      else
+       fn = gen_inswl_le;
+    }
+  emit_insn (fn (ret, op1, op2));
+
+  return ret;
+}
+
 /* Expand an an atomic fetch-and-operate pattern.  CODE is the binary operation
    to perform.  MEM is the memory on which to operate.  VAL is the second 
    operand of the binary operator.  BEFORE and AFTER are optional locations to
@@ -4530,6 +4558,79 @@ alpha_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval,
   emit_label (XEXP (label2, 0));
 }
 
+void
+alpha_expand_compare_and_swap_12 (rtx dst, rtx mem, rtx oldval, rtx newval)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx addr, align, wdst;
+  rtx (*fn5) (rtx, rtx, rtx, rtx, rtx);
+
+  addr = force_reg (DImode, XEXP (mem, 0));
+  align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8),
+                              NULL_RTX, 1, OPTAB_DIRECT);
+
+  oldval = convert_modes (DImode, mode, oldval, 1);
+  newval = emit_insxl (mode, newval, addr);
+
+  wdst = gen_reg_rtx (DImode);
+  if (mode == QImode)
+    fn5 = gen_sync_compare_and_swapqi_1;
+  else
+    fn5 = gen_sync_compare_and_swaphi_1;
+  emit_insn (fn5 (wdst, addr, oldval, newval, align));
+
+  emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+alpha_split_compare_and_swap_12 (enum machine_mode mode, rtx dest, rtx addr,
+                                rtx oldval, rtx newval, rtx align,
+                                rtx scratch, rtx cond)
+{
+  rtx label1, label2, mem, width, mask, x;
+
+  mem = gen_rtx_MEM (DImode, align);
+  MEM_VOLATILE_P (mem) = 1;
+
+  emit_insn (gen_memory_barrier ());
+  label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  emit_label (XEXP (label1, 0));
+
+  emit_load_locked (DImode, scratch, mem);
+  
+  width = GEN_INT (GET_MODE_BITSIZE (mode));
+  mask = GEN_INT (mode == QImode ? 0xff : 0xffff);
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_extxl_be (dest, scratch, width, addr));
+  else
+    emit_insn (gen_extxl_le (dest, scratch, width, addr));
+
+  if (oldval == const0_rtx)
+    x = gen_rtx_NE (DImode, dest, const0_rtx);
+  else
+    {
+      x = gen_rtx_EQ (DImode, dest, oldval);
+      emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+      x = gen_rtx_EQ (DImode, cond, const0_rtx);
+    }
+  emit_unlikely_jump (x, label2);
+
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_mskxl_be (scratch, scratch, mask, addr));
+  else
+    emit_insn (gen_mskxl_le (scratch, scratch, mask, addr));
+  emit_insn (gen_iordi3 (scratch, scratch, newval));
+
+  emit_store_conditional (DImode, scratch, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, scratch, const0_rtx);
+  emit_unlikely_jump (x, label1);
+
+  emit_insn (gen_memory_barrier ());
+  emit_label (XEXP (label2, 0));
+}
+
 /* Expand an atomic exchange operation.  */
 
 void
@@ -4550,6 +4651,68 @@ alpha_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
   x = gen_rtx_EQ (DImode, cond, const0_rtx);
   emit_unlikely_jump (x, label);
 }
+
+void
+alpha_expand_lock_test_and_set_12 (rtx dst, rtx mem, rtx val)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx addr, align, wdst;
+  rtx (*fn4) (rtx, rtx, rtx, rtx);
+
+  /* Force the address into a register.  */
+  addr = force_reg (DImode, XEXP (mem, 0));
+
+  /* Align it to a multiple of 8.  */
+  align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8),
+                              NULL_RTX, 1, OPTAB_DIRECT);
+
+  /* Insert val into the correct byte location within the word.  */
+  val = emit_insxl (mode, val, addr);
+
+  wdst = gen_reg_rtx (DImode);
+  if (mode == QImode)
+    fn4 = gen_sync_lock_test_and_setqi_1;
+  else
+    fn4 = gen_sync_lock_test_and_sethi_1;
+  emit_insn (fn4 (wdst, addr, val, align));
+
+  emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+alpha_split_lock_test_and_set_12 (enum machine_mode mode, rtx dest, rtx addr,
+                                 rtx val, rtx align, rtx scratch)
+{
+  rtx label, mem, width, mask, x;
+
+  mem = gen_rtx_MEM (DImode, align);
+  MEM_VOLATILE_P (mem) = 1;
+
+  emit_insn (gen_memory_barrier ());
+  label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  emit_label (XEXP (label, 0));
+
+  emit_load_locked (DImode, scratch, mem);
+  
+  width = GEN_INT (GET_MODE_BITSIZE (mode));
+  mask = GEN_INT (mode == QImode ? 0xff : 0xffff);
+  if (WORDS_BIG_ENDIAN)
+    {
+      emit_insn (gen_extxl_be (dest, scratch, width, addr));
+      emit_insn (gen_mskxl_be (scratch, scratch, mask, addr));
+    }
+  else
+    {
+      emit_insn (gen_extxl_le (dest, scratch, width, addr));
+      emit_insn (gen_mskxl_le (scratch, scratch, mask, addr));
+    }
+  emit_insn (gen_iordi3 (scratch, scratch, val));
+
+  emit_store_conditional (DImode, scratch, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, scratch, const0_rtx);
+  emit_unlikely_jump (x, label);
+}
 \f
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
index 35cc320ea840e4c04b8b312dd706f68bb59bb446..d9f9e09e8087db83c9b2fc9f207e54b04e40413a 100644 (file)
    (UNSPEC_IMPLVER     25)
    (UNSPEC_PERR                26)
    (UNSPEC_COPYSIGN     27)
+
+   ;; Atomic operations
+   (UNSPEC_MB          28)
+   (UNSPEC_ATOMIC      31)
+   (UNSPEC_CMPXCHG     32)
+   (UNSPEC_XCHG                33)
   ])
 
 ;; UNSPEC_VOLATILE:
    (UNSPECV_SET_TP     12)
    (UNSPECV_RPCC       13)
    (UNSPECV_SETJMPR_ER 14)     ; builtin_setjmp_receiver fragment
-   (UNSPECV_MB         15)
-   (UNSPECV_LL         16)     ; load-locked
-   (UNSPECV_SC         17)     ; store-conditional
-   (UNSPECV_ATOMIC     18)
-   (UNSPECV_CMPXCHG    19)
-   (UNSPECV_XCHG       20)
+   (UNSPECV_LL         15)     ; load-locked
+   (UNSPECV_SC         16)     ; store-conditional
   ])
 
 ;; Where necessary, the suffixes _le and _be are used to distinguish between
index e913627e1515714512a696667ca72794e5900a2e..1c34ce54b1c34462812f93f0dbed19cccc69e66e 100644 (file)
@@ -19,6 +19,7 @@
 ;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 ;; Boston, MA 02110-1301, USA.
 
+(define_mode_macro I12MODE [QI HI])
 (define_mode_macro I48MODE [SI DI])
 (define_mode_attr modesuffix [(SI "l") (DI "q")])
 
@@ -34,7 +35,7 @@
 
 (define_expand "memory_barrier"
   [(set (mem:BLK (match_dup 0))
-       (unspec_volatile:BLK [(mem:BLK (match_dup 0))] UNSPECV_MB))]
+       (unspec:BLK [(mem:BLK (match_dup 0))] UNSPEC_MB))]
   ""
 {
   operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (DImode));
@@ -43,7 +44,7 @@
 
 (define_insn "*mb_internal"
   [(set (match_operand:BLK 0 "" "")
-       (unspec_volatile:BLK [(match_operand:BLK 1 "" "")] UNSPECV_MB))]
+       (unspec:BLK [(match_operand:BLK 1 "" "")] UNSPEC_MB))]
   ""
   "mb"
   [(set_attr "type" "mb")])
 
 (define_insn_and_split "sync_<fetchop_name><mode>"
   [(set (match_operand:I48MODE 0 "memory_operand" "+m")
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(FETCHOP:I48MODE (match_dup 0)
             (match_operand:I48MODE 1 "<fetchop_pred>" "<fetchop_constr>"))]
-         UNSPECV_ATOMIC))
+         UNSPEC_ATOMIC))
    (clobber (match_scratch:I48MODE 2 "=&r"))]
   ""
   "#"
 
 (define_insn_and_split "sync_nand<mode>"
   [(set (match_operand:I48MODE 0 "memory_operand" "+m")
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(and:I48MODE (not:I48MODE (match_dup 0))
             (match_operand:I48MODE 1 "register_operand" "r"))]
-         UNSPECV_ATOMIC))
+         UNSPEC_ATOMIC))
    (clobber (match_scratch:I48MODE 2 "=&r"))]
   ""
   "#"
   [(set (match_operand:I48MODE 0 "register_operand" "=&r")
        (match_operand:I48MODE 1 "memory_operand" "+m"))
    (set (match_dup 1)
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(FETCHOP:I48MODE (match_dup 1)
             (match_operand:I48MODE 2 "<fetchop_pred>" "<fetchop_constr>"))]
-         UNSPECV_ATOMIC))
+         UNSPEC_ATOMIC))
    (clobber (match_scratch:I48MODE 3 "=&r"))]
   ""
   "#"
   [(set (match_operand:I48MODE 0 "register_operand" "=&r")
        (match_operand:I48MODE 1 "memory_operand" "+m"))
    (set (match_dup 1)
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(and:I48MODE (not:I48MODE (match_dup 1))
             (match_operand:I48MODE 2 "register_operand" "r"))]
-         UNSPECV_ATOMIC))
+         UNSPEC_ATOMIC))
    (clobber (match_scratch:I48MODE 3 "=&r"))]
   ""
   "#"
          (match_operand:I48MODE 1 "memory_operand" "+m")
          (match_operand:I48MODE 2 "<fetchop_pred>" "<fetchop_constr>")))
    (set (match_dup 1)
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(FETCHOP:I48MODE (match_dup 1) (match_dup 2))]
-         UNSPECV_ATOMIC))
+         UNSPEC_ATOMIC))
    (clobber (match_scratch:I48MODE 3 "=&r"))]
   ""
   "#"
          (not:I48MODE (match_operand:I48MODE 1 "memory_operand" "+m"))
          (match_operand:I48MODE 2 "register_operand" "r")))
    (set (match_dup 1)
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(and:I48MODE (not:I48MODE (match_dup 1)) (match_dup 2))]
-         UNSPECV_ATOMIC))
+         UNSPEC_ATOMIC))
    (clobber (match_scratch:I48MODE 3 "=&r"))]
   ""
   "#"
 }
   [(set_attr "type" "multi")])
 
+(define_expand "sync_compare_and_swap<mode>"
+  [(match_operand:I12MODE 0 "register_operand" "")
+   (match_operand:I12MODE 1 "memory_operand" "")
+   (match_operand:I12MODE 2 "register_operand" "")
+   (match_operand:I12MODE 3 "add_operand" "")]
+  ""
+{
+  alpha_expand_compare_and_swap_12 (operands[0], operands[1],
+                                   operands[2], operands[3]);
+  DONE;
+})
+
+(define_insn_and_split "sync_compare_and_swap<mode>_1"
+  [(set (match_operand:DI 0 "register_operand" "=&r,&r")
+       (zero_extend:DI
+         (mem:I12MODE (match_operand:DI 1 "register_operand" "r,r"))))
+   (set (mem:I12MODE (match_dup 1))
+       (unspec:I12MODE
+         [(match_operand:DI 2 "reg_or_8bit_operand" "J,rI")
+          (match_operand:DI 3 "register_operand" "r,r")
+          (match_operand:DI 4 "register_operand" "r,r")]
+         UNSPEC_CMPXCHG))
+   (clobber (match_scratch:DI 5 "=&r,&r"))
+   (clobber (match_scratch:DI 6 "=X,&r"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  alpha_split_compare_and_swap_12 (<MODE>mode, operands[0], operands[1],
+                                  operands[2], operands[3], operands[4],
+                                  operands[5], operands[6]);
+  DONE;
+}
+  [(set_attr "type" "multi")])
+
 (define_expand "sync_compare_and_swap<mode>"
   [(parallel
      [(set (match_operand:I48MODE 0 "register_operand" "")
           (match_operand:I48MODE 1 "memory_operand" ""))
       (set (match_dup 1)
-          (unspec_volatile:I48MODE
+          (unspec:I48MODE
             [(match_operand:I48MODE 2 "reg_or_8bit_operand" "")
              (match_operand:I48MODE 3 "add_operand" "rKL")]
-            UNSPECV_CMPXCHG))
+            UNSPEC_CMPXCHG))
       (clobber (match_scratch:I48MODE 4 "=&r"))])]
   ""
 {
   [(set (match_operand:I48MODE 0 "register_operand" "=&r")
        (match_operand:I48MODE 1 "memory_operand" "+m"))
    (set (match_dup 1)
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(match_operand:DI 2 "reg_or_8bit_operand" "rI")
           (match_operand:I48MODE 3 "add_operand" "rKL")]
-         UNSPECV_CMPXCHG))
+         UNSPEC_CMPXCHG))
    (clobber (match_scratch:I48MODE 4 "=&r"))]
   ""
   "#"
 }
   [(set_attr "type" "multi")])
 
+(define_expand "sync_lock_test_and_set<mode>"
+  [(match_operand:I12MODE 0 "register_operand" "")
+   (match_operand:I12MODE 1 "memory_operand" "")
+   (match_operand:I12MODE 2 "register_operand" "")]
+  ""
+{
+  alpha_expand_lock_test_and_set_12 (operands[0], operands[1], operands[2]);
+  DONE;
+})
+
+(define_insn_and_split "sync_lock_test_and_set<mode>_1"
+  [(set (match_operand:DI 0 "register_operand" "=&r")
+       (zero_extend:DI
+         (mem:I12MODE (match_operand:DI 1 "register_operand" "r"))))
+   (set (mem:I12MODE (match_dup 1))
+       (unspec:I12MODE
+         [(match_operand:DI 2 "reg_or_8bit_operand" "rI")
+          (match_operand:DI 3 "register_operand" "r")]
+         UNSPEC_XCHG))
+   (clobber (match_scratch:DI 4 "=&r"))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  alpha_split_lock_test_and_set_12 (<MODE>mode, operands[0], operands[1],
+                                   operands[2], operands[3], operands[4]);
+  DONE;
+}
+  [(set_attr "type" "multi")])
+
 (define_insn_and_split "sync_lock_test_and_set<mode>"
   [(set (match_operand:I48MODE 0 "register_operand" "=&r")
        (match_operand:I48MODE 1 "memory_operand" "+m"))
    (set (match_dup 1)
-       (unspec_volatile:I48MODE
+       (unspec:I48MODE
          [(match_operand:I48MODE 2 "add_operand" "rKL")]
-         UNSPECV_XCHG))
+         UNSPEC_XCHG))
    (clobber (match_scratch:I48MODE 3 "=&r"))]
   ""
   "#"
index 7717a13dd19c003b51b30a70c1ef9c93d9da191b..9a982a7fa8b4014cd0af35fa4b556ecf60ec5c5b 100644 (file)
@@ -1,3 +1,8 @@
+2005-07-09  Richard Henderson  <rth@redhat.com>
+
+       * lib/target-supports.exp (check_effective_target_sync_char_short):
+       Add alpha.
+
 2005-07-09  Thomas Koenig  <Thomas.Koenig@online.de>
 
        PR libfortran/22217
index 7605114a722378c33c94a1c793645151842289e1..14426ec82c3462f4f07ecca1627f9b7942cbe689 100644 (file)
@@ -1122,6 +1122,7 @@ proc check_effective_target_sync_char_short { } {
         if { [istarget ia64-*-*]
             || [istarget i?86-*-*]
             || [istarget x86_64-*-*]
+            || [istarget alpha*-*-*] 
             || [istarget powerpc*-*-*] } {
            set et_sync_char_short_saved 1
         }