]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[ARM][4.9 Backport] PR target/69875 Fix atomic_loaddi expansion
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Tue, 29 Mar 2016 13:32:37 +0000 (13:32 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Tue, 29 Mar 2016 13:32:37 +0000 (13:32 +0000)
PR target/69875
* config/arm/arm.h (TARGET_HAVE_LPAE): Define.
* config/arm/unspecs.md (VUNSPEC_LDRD_ATOMIC): New value.
* config/arm/sync.md (arm_atomic_loaddi2_ldrd): New pattern.
(atomic_loaddi_1): Delete.
(atomic_loaddi): Rewrite expander using the above changes.

* gcc.target/arm/atomic_loaddi_acquire.x: New file.
* gcc.target/arm/atomic_loaddi_relaxed.x: Likewise.
* gcc.target/arm/atomic_loaddi_seq_cst.x: Likewise.
* gcc.target/arm/atomic_loaddi_1.c: New test.
* gcc.target/arm/atomic_loaddi_2.c: Likewise.
* gcc.target/arm/atomic_loaddi_3.c: Likewise.
* gcc.target/arm/atomic_loaddi_4.c: Likewise.
* gcc.target/arm/atomic_loaddi_5.c: Likewise.
* gcc.target/arm/atomic_loaddi_6.c: Likewise.
* gcc.target/arm/atomic_loaddi_7.c: Likewise.
* gcc.target/arm/atomic_loaddi_8.c: Likewise.
* gcc.target/arm/atomic_loaddi_9.c: Likewise.

From-SVN: r234522

17 files changed:
gcc/ChangeLog
gcc/config/arm/arm.h
gcc/config/arm/sync.md
gcc/config/arm/unspecs.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/atomic_loaddi_1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_9.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_acquire.x [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_relaxed.x [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/atomic_loaddi_seq_cst.x [new file with mode: 0644]

index 82c1c5e491abf8a576222148d6352a057c839d8a..1f87f09e29df425d638c93b93daf57e455cc5f57 100644 (file)
@@ -1,3 +1,12 @@
+2016-03-29  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       PR target/69875
+       * config/arm/arm.h (TARGET_HAVE_LPAE): Define.
+       * config/arm/unspecs.md (VUNSPEC_LDRD_ATOMIC): New value.
+       * config/arm/sync.md (arm_atomic_loaddi2_ldrd): New pattern.
+       (atomic_loaddi_1): Delete.
+       (atomic_loaddi): Rewrite expander using the above changes.
+
 2016-03-21  Uros Bizjak  <ubizjak@gmail.com>
 
        PR target/70327
index 7c9b1b91f0926b1530bd61bb187772962b2a227d..ad97c01312cdb215768644413dd1a4061f8bd046 100644 (file)
@@ -363,6 +363,11 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
 /* Nonzero if this chip supports ldrex and strex */
 #define TARGET_HAVE_LDREX      ((arm_arch6 && TARGET_ARM) || arm_arch7)
 
+/* Nonzero if this chip supports LPAE.  Such systems also support the
+   hardware divide instructions.  */
+#define TARGET_HAVE_LPAE                                               \
+  (arm_arch7 && arm_arch_arm_hwdiv && arm_arch_thumb_hwdiv)
+
 /* Nonzero if this chip supports ldrex{bh} and strex{bh}.  */
 #define TARGET_HAVE_LDREXBH    ((arm_arch6k && TARGET_ARM) || arm_arch7)
 
index 25ed926fc4e71db499d7b7fe40dc54a02182d6cb..5218ea3b8cbfee1f2fb04dd8720a1810317976af 100644 (file)
   [(set_attr "predicable" "yes")
    (set_attr "predicable_short_it" "no")])
 
-;; Note that ldrd and vldr are *not* guaranteed to be single-copy atomic,
-;; even for a 64-bit aligned address.  Instead we use a ldrexd unparied
-;; with a store.
+;; An LDRD instruction usable by the atomic_loaddi expander on LPAE targets
+
+(define_insn "arm_atomic_loaddi2_ldrd"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI
+       [(match_operand:DI 1 "arm_sync_memory_operand" "Q")]
+         VUNSPEC_LDRD_ATOMIC))]
+  "ARM_DOUBLEWORD_ALIGN && TARGET_HAVE_LPAE"
+  "ldrd%?\t%0, %H0, %C1"
+  [(set_attr "predicable" "yes")
+   (set_attr "predicable_short_it" "no")])
+
+;; There are three ways to expand this depending on the architecture
+;; features available.  As for the barriers, a load needs a barrier
+;; after it on all non-relaxed memory models except when the load
+;; has acquire semantics (for ARMv8-A).
+
 (define_expand "atomic_loaddi"
   [(match_operand:DI 0 "s_register_operand")           ;; val out
    (match_operand:DI 1 "mem_noofs_operand")            ;; memory
    (match_operand:SI 2 "const_int_operand")]           ;; model
-  "TARGET_HAVE_LDREXD && ARM_DOUBLEWORD_ALIGN"
+  "(TARGET_HAVE_LDREXD || TARGET_HAVE_LPAE || TARGET_HAVE_LDACQ)
+   && ARM_DOUBLEWORD_ALIGN"
 {
   enum memmodel model = (enum memmodel) INTVAL (operands[2]);
-  expand_mem_thread_fence (model);
-  emit_insn (gen_atomic_loaddi_1 (operands[0], operands[1]));
-  if (model == MEMMODEL_SEQ_CST)
-    expand_mem_thread_fence (model);
-  DONE;
-})
 
-(define_insn "atomic_loaddi_1"
-  [(set (match_operand:DI 0 "s_register_operand" "=r")
-       (unspec:DI [(match_operand:DI 1 "mem_noofs_operand" "Ua")]
-                  UNSPEC_LL))]
-  "TARGET_HAVE_LDREXD && ARM_DOUBLEWORD_ALIGN"
-  "ldrexd%?\t%0, %H0, %C1"
-  [(set_attr "predicable" "yes")
-   (set_attr "predicable_short_it" "no")])
+  /* For ARMv8-A we can use an LDAEXD to atomically load two 32-bit registers
+     when acquire or stronger semantics are needed.  When the relaxed model is
+     used this can be relaxed to a normal LDRD.  */
+  if (TARGET_HAVE_LDACQ)
+    {
+      if (model == MEMMODEL_RELAXED)
+       emit_insn (gen_arm_atomic_loaddi2_ldrd (operands[0], operands[1]));
+      else
+       emit_insn (gen_arm_load_acquire_exclusivedi (operands[0], operands[1]));
+
+      DONE;
+    }
+
+  /* On LPAE targets LDRD and STRD accesses to 64-bit aligned
+     locations are 64-bit single-copy atomic.  We still need barriers in the
+     appropriate places to implement the ordering constraints.  */
+  if (TARGET_HAVE_LPAE)
+    emit_insn (gen_arm_atomic_loaddi2_ldrd (operands[0], operands[1]));
+  else
+    emit_insn (gen_arm_load_exclusivedi (operands[0], operands[1]));
+
+
+  /* All non-relaxed models need a barrier after the load when load-acquire
+     instructions are not available.  */
+  if (model != MEMMODEL_RELAXED)
+     expand_mem_thread_fence (model);
+
+   DONE;
+})
 
 (define_expand "atomic_compare_and_swap<mode>"
   [(match_operand:SI 0 "s_register_operand" "")                ;; bool out
index 8caa953bcb9a276b540016616193c431f29e14d5..18a9a903e29e3474903ce9fec98008a57044af29 100644 (file)
   VUNSPEC_ATOMIC_XCHG  ; Represent an atomic exchange.
   VUNSPEC_ATOMIC_OP    ; Represent an atomic operation.
   VUNSPEC_LL           ; Represent a load-register-exclusive.
+  VUNSPEC_LDRD_ATOMIC  ; Represent an LDRD used as an atomic DImode load.
   VUNSPEC_SC           ; Represent a store-register-exclusive.
   VUNSPEC_LAX          ; Represent a load-register-acquire-exclusive.
   VUNSPEC_SLX          ; Represent a store-register-release-exclusive.
index 49325cb2e45ac2437fcbf6f55b1cf4cb9eb2b133..0b6ed07609b08f46d5966c3b6e831940d43cb951 100644 (file)
@@ -1,3 +1,19 @@
+2016-02-29  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       PR target/69875
+       * gcc.target/arm/atomic_loaddi_acquire.x: New file.
+       * gcc.target/arm/atomic_loaddi_relaxed.x: Likewise.
+       * gcc.target/arm/atomic_loaddi_seq_cst.x: Likewise.
+       * gcc.target/arm/atomic_loaddi_1.c: New test.
+       * gcc.target/arm/atomic_loaddi_2.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_3.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_4.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_5.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_6.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_7.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_8.c: Likewise.
+       * gcc.target/arm/atomic_loaddi_9.c: Likewise.
+
 2016-03-29  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        Backport from mainline
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_1.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_1.c
new file mode 100644 (file)
index 0000000..816d352
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v7a_ok } */
+/* { dg-add-options arm_arch_v7a } */
+
+#include "atomic_loaddi_acquire.x"
+
+/* { dg-final { scan-assembler-times "ldrexd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-times "dmb\tsy" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_2.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_2.c
new file mode 100644 (file)
index 0000000..c54ac77
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v7ve_ok } */
+/* { dg-add-options arm_arch_v7ve } */
+
+#include "atomic_loaddi_acquire.x"
+
+/* { dg-final { scan-assembler-times "ldrd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-times "dmb\tsy" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_3.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_3.c
new file mode 100644 (file)
index 0000000..095c958
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v8a_ok } */
+/* { dg-add-options arm_arch_v8a } */
+
+#include "atomic_loaddi_acquire.x"
+
+/* { dg-final { scan-assembler-times "ldaexd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-not "dmb\tsy" } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_4.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_4.c
new file mode 100644 (file)
index 0000000..53667b4
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v7a_ok } */
+/* { dg-add-options arm_arch_v7a } */
+
+#include "atomic_loaddi_relaxed.x"
+
+/* { dg-final { scan-assembler-times "ldrexd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-not "dmb\tsy" } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_5.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_5.c
new file mode 100644 (file)
index 0000000..2b9800b
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v7ve_ok } */
+/* { dg-add-options arm_arch_v7ve } */
+
+#include "atomic_loaddi_relaxed.x"
+
+/* { dg-final { scan-assembler-times "ldrd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-not "dmb\tsy" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_6.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_6.c
new file mode 100644 (file)
index 0000000..e37ca0b
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v8a_ok } */
+/* { dg-add-options arm_arch_v8a } */
+
+#include "atomic_loaddi_relaxed.x"
+
+/* { dg-final { scan-assembler-times "ldrd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-not "dmb\tsy" } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_7.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_7.c
new file mode 100644 (file)
index 0000000..e6deb08
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v7a_ok } */
+/* { dg-add-options arm_arch_v7a } */
+
+#include "atomic_loaddi_seq_cst.x"
+
+/* { dg-final { scan-assembler-times "ldrexd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-times "dmb\tsy" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_8.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_8.c
new file mode 100644 (file)
index 0000000..65530dd
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v7ve_ok } */
+/* { dg-add-options arm_arch_v7ve } */
+
+#include "atomic_loaddi_seq_cst.x"
+
+/* { dg-final { scan-assembler-times "ldrd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-times "dmb\tsy" 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_9.c b/gcc/testsuite/gcc.target/arm/atomic_loaddi_9.c
new file mode 100644 (file)
index 0000000..3401a8e
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -O" } */
+/* { dg-require-effective-target arm_arch_v8a_ok } */
+/* { dg-add-options arm_arch_v8a } */
+
+#include "atomic_loaddi_seq_cst.x"
+
+/* { dg-final { scan-assembler-times "ldaexd\tr\[0-9\]+, r\[0-9\]+, \\\[r\[0-9\]+\\\]" 1 } } */
+/* { dg-final { scan-assembler-not "dmb\tsy" } } */
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_acquire.x b/gcc/testsuite/gcc.target/arm/atomic_loaddi_acquire.x
new file mode 100644 (file)
index 0000000..28997ef
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdatomic.h>
+
+atomic_ullong foo;
+int glob;
+
+int
+main (void)
+{
+  atomic_load_explicit (&foo, memory_order_acquire);
+  return glob;
+}
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_relaxed.x b/gcc/testsuite/gcc.target/arm/atomic_loaddi_relaxed.x
new file mode 100644 (file)
index 0000000..701b3c4
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdatomic.h>
+
+atomic_ullong foo;
+int glob;
+
+int
+main (void)
+{
+  atomic_load_explicit (&foo, memory_order_relaxed);
+  return glob;
+}
diff --git a/gcc/testsuite/gcc.target/arm/atomic_loaddi_seq_cst.x b/gcc/testsuite/gcc.target/arm/atomic_loaddi_seq_cst.x
new file mode 100644 (file)
index 0000000..32e78da
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdatomic.h>
+
+atomic_ullong foo;
+int glob;
+
+int
+main (void)
+{
+  atomic_load_explicit (&foo, memory_order_seq_cst);
+  return glob;
+}