* config/aarch64/aarch64-protos.h
authorMatthew Wahab <matthew.wahab@arm.com>
Thu, 13 Aug 2015 11:28:42 +0000 (11:28 +0000)
committerMatthew Wahab <mwahab@gcc.gnu.org>
Thu, 13 Aug 2015 11:28:42 +0000 (11:28 +0000)
(aarch64_gen_atomic_cas): Declare.
* config/aarch64/aarch64.c (aarch64_expand_compare_and_swap):
Choose appropriate instruction pattern for the target.
(aarch64_gen_atomic_cas): New.
* config/aarch64/atomics.md (UNSPECV_ATOMIC_CAS): New.
(atomic_compare_and_swap<mode>_1): Rename to
aarch64_compare_and_swap<mode>.  Fix some indentation.
(aarch64_compare_and_swap<mode>_lse): New.
(aarch64_atomic_cas<mode>): New.

From-SVN: r226858

gcc/ChangeLog
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/atomics.md

index f55b3f4a458d8179a16fedd220f7164d1e6b2e72..7b80e3892f5c4f673db5f3af5a08e1c43b8bbd88 100644 (file)
@@ -1,3 +1,16 @@
+2015-08-13  Matthew Wahab  <matthew.wahab@arm.com>
+
+       * config/aarch64/aarch64-protos.h
+       (aarch64_gen_atomic_cas): Declare.
+       * config/aarch64/aarch64.c (aarch64_expand_compare_and_swap):
+       Choose appropriate instruction pattern for the target.
+       (aarch64_gen_atomic_cas): New.
+       * config/aarch64/atomics.md (UNSPECV_ATOMIC_CAS): New.
+       (atomic_compare_and_swap<mode>_1): Rename to
+       aarch64_compare_and_swap<mode>.  Fix some indentation.
+       (aarch64_compare_and_swap<mode>_lse): New.
+       (aarch64_atomic_cas<mode>): New.
+
 2015-08-13  Matthew Wahab  <matthew.wahab@arm.com>
 
        * config/aarch64/aarch64.h (AARCH64_ISA_LSE): New.
index 32b5d0958a6e0b2356874736f858f007fe68cdda..0b09d49f6702c7734c05c907788d4e2231701355 100644 (file)
@@ -362,6 +362,7 @@ rtx aarch64_load_tp (rtx);
 
 void aarch64_expand_compare_and_swap (rtx op[]);
 void aarch64_split_compare_and_swap (rtx op[]);
+void aarch64_gen_atomic_cas (rtx, rtx, rtx, rtx, rtx);
 void aarch64_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx, rtx);
 
 bool aarch64_gen_adjusted_ldpstp (rtx *, bool, enum machine_mode, RTX_CODE);
index 7159f5aca5df97f154b3e654f60af9136354f335..aa268aeff4db26b621de6069b6b34be956003a74 100644 (file)
@@ -10754,7 +10754,23 @@ aarch64_expand_compare_and_swap (rtx operands[])
 {
   rtx bval, rval, mem, oldval, newval, is_weak, mod_s, mod_f, x;
   machine_mode mode, cmp_mode;
-  rtx (*gen) (rtx, rtx, rtx, rtx, rtx, rtx, rtx);
+  typedef rtx (*gen_cas_fn) (rtx, rtx, rtx, rtx, rtx, rtx, rtx);
+  int idx;
+  gen_cas_fn gen;
+  const gen_cas_fn split_cas[] =
+  {
+    gen_aarch64_compare_and_swapqi,
+    gen_aarch64_compare_and_swaphi,
+    gen_aarch64_compare_and_swapsi,
+    gen_aarch64_compare_and_swapdi
+  };
+  const gen_cas_fn atomic_cas[] =
+  {
+    gen_aarch64_compare_and_swapqi_lse,
+    gen_aarch64_compare_and_swaphi_lse,
+    gen_aarch64_compare_and_swapsi_lse,
+    gen_aarch64_compare_and_swapdi_lse
+  };
 
   bval = operands[0];
   rval = operands[1];
@@ -10799,13 +10815,17 @@ aarch64_expand_compare_and_swap (rtx operands[])
 
   switch (mode)
     {
-    case QImode: gen = gen_atomic_compare_and_swapqi_1; break;
-    case HImode: gen = gen_atomic_compare_and_swaphi_1; break;
-    case SImode: gen = gen_atomic_compare_and_swapsi_1; break;
-    case DImode: gen = gen_atomic_compare_and_swapdi_1; break;
+    case QImode: idx = 0; break;
+    case HImode: idx = 1; break;
+    case SImode: idx = 2; break;
+    case DImode: idx = 3; break;
     default:
       gcc_unreachable ();
     }
+  if (TARGET_LSE)
+    gen = atomic_cas[idx];
+  else
+    gen = split_cas[idx];
 
   emit_insn (gen (rval, mem, oldval, newval, is_weak, mod_s, mod_f));
 
@@ -10834,6 +10854,42 @@ aarch64_emit_post_barrier (enum memmodel model)
     }
 }
 
+/* Emit an atomic compare-and-swap operation.  RVAL is the destination register
+   for the data in memory.  EXPECTED is the value expected to be in memory.
+   DESIRED is the value to store to memory.  MEM is the memory location.  MODEL
+   is the memory ordering to use.  */
+
+void
+aarch64_gen_atomic_cas (rtx rval, rtx mem,
+                       rtx expected, rtx desired,
+                       rtx model)
+{
+  rtx (*gen) (rtx, rtx, rtx, rtx);
+  machine_mode mode;
+
+  mode = GET_MODE (mem);
+
+  switch (mode)
+    {
+    case QImode: gen = gen_aarch64_atomic_casqi; break;
+    case HImode: gen = gen_aarch64_atomic_cashi; break;
+    case SImode: gen = gen_aarch64_atomic_cassi; break;
+    case DImode: gen = gen_aarch64_atomic_casdi; break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Move the expected value into the CAS destination register.  */
+  emit_insn (gen_rtx_SET (rval, expected));
+
+  /* Emit the CAS.  */
+  emit_insn (gen (rval, mem, desired, model));
+
+  /* Compare the expected value with the value loaded by the CAS, to establish
+     whether the swap was made.  */
+  aarch64_gen_compare_reg (EQ, rval, expected);
+}
+
 /* Split a compare and swap pattern.  */
 
 void
index 1a38ac0e237ba5418bb7212e1e5d7c3589c263f9..7082f619696852ad28b0ad06335996efec2259a9 100644 (file)
@@ -26,6 +26,7 @@
     UNSPECV_STL                                ; Represent an atomic store or store-release.
     UNSPECV_ATOMIC_CMPSW               ; Represent an atomic compare swap.
     UNSPECV_ATOMIC_EXCHG               ; Represent an atomic exchange.
+    UNSPECV_ATOMIC_CAS                 ; Represent an atomic CAS.
     UNSPECV_ATOMIC_OP                  ; Represent an atomic operation.
 ])
 
   }
 )
 
-(define_insn_and_split "atomic_compare_and_swap<mode>_1"
+(define_insn_and_split "aarch64_compare_and_swap<mode>"
   [(set (reg:CC CC_REGNUM)                                     ;; bool out
     (unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
-   (set (match_operand:SI 0 "register_operand" "=&r")          ;; val out
+   (set (match_operand:SI 0 "register_operand" "=&r")     ;; val out
     (zero_extend:SI
       (match_operand:SHORT 1 "aarch64_sync_memory_operand" "+Q"))) ;; memory
    (set (match_dup 1)
@@ -57,7 +58,7 @@
        (match_operand:SHORT 3 "register_operand" "r")  ;; desired
        (match_operand:SI 4 "const_int_operand")                ;; is_weak
        (match_operand:SI 5 "const_int_operand")                ;; mod_s
-       (match_operand:SI 6 "const_int_operand")]               ;; mod_f
+       (match_operand:SI 6 "const_int_operand")]       ;; mod_f
       UNSPECV_ATOMIC_CMPSW))
    (clobber (match_scratch:SI 7 "=&r"))]
   ""
   }
 )
 
-(define_insn_and_split "atomic_compare_and_swap<mode>_1"
+(define_insn_and_split "aarch64_compare_and_swap<mode>"
   [(set (reg:CC CC_REGNUM)                                     ;; bool out
     (unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
    (set (match_operand:GPI 0 "register_operand" "=&r")         ;; val out
-    (match_operand:GPI 1 "aarch64_sync_memory_operand" "+Q")) ;; memory
+    (match_operand:GPI 1 "aarch64_sync_memory_operand" "+Q"))   ;; memory
    (set (match_dup 1)
     (unspec_volatile:GPI
       [(match_operand:GPI 2 "aarch64_plus_operand" "rI")       ;; expect
        (match_operand:GPI 3 "register_operand" "r")            ;; desired
-       (match_operand:SI 4 "const_int_operand")                ;; is_weak
-       (match_operand:SI 5 "const_int_operand")                ;; mod_s
+       (match_operand:SI 4 "const_int_operand")                        ;; is_weak
+       (match_operand:SI 5 "const_int_operand")                        ;; mod_s
        (match_operand:SI 6 "const_int_operand")]               ;; mod_f
       UNSPECV_ATOMIC_CMPSW))
    (clobber (match_scratch:SI 7 "=&r"))]
   }
 )
 
+(define_insn_and_split "aarch64_compare_and_swap<mode>_lse"
+  [(set (reg:CC CC_REGNUM)                                     ;; bool out
+    (unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
+   (set (match_operand:SI 0 "register_operand" "=&r")          ;; val out
+    (zero_extend:SI
+      (match_operand:SHORT 1 "aarch64_sync_memory_operand" "+Q"))) ;; memory
+   (set (match_dup 1)
+    (unspec_volatile:SHORT
+      [(match_operand:SI 2 "aarch64_plus_operand" "rI")        ;; expected
+       (match_operand:SHORT 3 "register_operand" "r")  ;; desired
+       (match_operand:SI 4 "const_int_operand")                ;; is_weak
+       (match_operand:SI 5 "const_int_operand")                ;; mod_s
+       (match_operand:SI 6 "const_int_operand")]       ;; mod_f
+      UNSPECV_ATOMIC_CMPSW))]
+  "TARGET_LSE"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+  {
+    aarch64_gen_atomic_cas (operands[0], operands[1],
+                           operands[2], operands[3],
+                           operands[5]);
+    DONE;
+  }
+)
+
+(define_insn_and_split "aarch64_compare_and_swap<mode>_lse"
+  [(set (reg:CC CC_REGNUM)                                     ;; bool out
+    (unspec_volatile:CC [(const_int 0)] UNSPECV_ATOMIC_CMPSW))
+   (set (match_operand:GPI 0 "register_operand" "=&r")         ;; val out
+    (match_operand:GPI 1 "aarch64_sync_memory_operand" "+Q"))   ;; memory
+   (set (match_dup 1)
+    (unspec_volatile:GPI
+      [(match_operand:GPI 2 "aarch64_plus_operand" "rI")       ;; expect
+       (match_operand:GPI 3 "register_operand" "r")            ;; desired
+       (match_operand:SI 4 "const_int_operand")                        ;; is_weak
+       (match_operand:SI 5 "const_int_operand")                        ;; mod_s
+       (match_operand:SI 6 "const_int_operand")]               ;; mod_f
+      UNSPECV_ATOMIC_CMPSW))]
+  "TARGET_LSE "
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+  {
+    aarch64_gen_atomic_cas (operands[0], operands[1],
+                           operands[2], operands[3],
+                           operands[5]);
+    DONE;
+  }
+)
+
 (define_insn_and_split "atomic_exchange<mode>"
   [(set (match_operand:ALLI 0 "register_operand" "=&r")                ;; output
     (match_operand:ALLI 1 "aarch64_sync_memory_operand" "+Q")) ;; memory
       return "dmb\\tish";
   }
 )
+
+;; ARMv8.1 LSE instructions.
+
+;; Atomic compare-and-swap: HI and smaller modes.
+
+(define_insn "aarch64_atomic_cas<mode>"
+ [(set (match_operand:SI 0 "register_operand" "+&r")             ;; out
+   (zero_extend:SI
+    (match_operand:SHORT 1 "aarch64_sync_memory_operand" "+Q")))  ;; memory.
+  (set (match_dup 1)
+   (unspec_volatile:SHORT
+    [(match_dup 0)
+     (match_operand:SHORT 2 "register_operand" "r")    ;; value.
+     (match_operand:SI 3 "const_int_operand" "")]      ;; model.
+    UNSPECV_ATOMIC_CAS))]
+ "TARGET_LSE && reload_completed"
+{
+  enum memmodel model = memmodel_from_int (INTVAL (operands[3]));
+  if (is_mm_relaxed (model))
+    return "cas<atomic_sfx>\t%<w>0, %<w>2, %1";
+  else if (is_mm_acquire (model) || is_mm_consume (model))
+    return "casa<atomic_sfx>\t%<w>0, %<w>2, %1";
+  else if (is_mm_release (model))
+    return "casl<atomic_sfx>\t%<w>0, %<w>2, %1";
+  else
+    return "casal<atomic_sfx>\t%<w>0, %<w>2, %1";
+})
+
+;; Atomic compare-and-swap: SI and larger modes.
+
+(define_insn "aarch64_atomic_cas<mode>"
+ [(set (match_operand:GPI 0 "register_operand" "+&r")        ;; out
+   (match_operand:GPI 1 "aarch64_sync_memory_operand" "+Q"))  ;; memory.
+  (set (match_dup 1)
+   (unspec_volatile:GPI
+    [(match_dup 0)
+     (match_operand:GPI 2 "register_operand" "r")      ;; value.
+     (match_operand:SI 3 "const_int_operand" "")]      ;; model.
+    UNSPECV_ATOMIC_CAS))]
+  "TARGET_LSE && reload_completed"
+{
+    enum memmodel model = memmodel_from_int (INTVAL (operands[3]));
+    if (is_mm_relaxed (model))
+      return "cas<atomic_sfx>\t%<w>0, %<w>2, %1";
+    else if (is_mm_acquire (model) || is_mm_consume (model))
+      return "casa<atomic_sfx>\t%<w>0, %<w>2, %1";
+    else if (is_mm_release (model))
+      return "casl<atomic_sfx>\t%<w>0, %<w>2, %1";
+    else
+      return "casal<atomic_sfx>\t%<w>0, %<w>2, %1";
+})