[v2,6/8] RISCV: Weaken compare_exchange LR/SC pairs

Message ID 20230405210118.1969283-7-patrick@rivosinc.com
State Accepted
Headers
Series RISCV: Implement ISA Manual Table A.6 Mappings |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Patrick O'Neill April 5, 2023, 9:01 p.m. UTC
  Introduce the %I and %J flags for setting the .aqrl bits on LR/SC pairs
as needed.

Atomic compare and exchange ops provide success and failure memory
models. C++17 and later place no restrictions on the relative strength
of each model, so ensure we cover both by using a model that enforces
the ordering of both given models.

This change brings compare_exchange LR/SC ops in line with table A.6 of the ISA
manual.

2023-04-05 Patrick O'Neill <patrick@rivosinc.com>
	
	* riscv.cc: Add function to get the union of two
	memmodels in sync.md.
	* riscv-protos.h: Likewise.
	* sync.md (atomic_cas_value_strong<mode>): Remove static
	.aqrl bits on SC op/.rl bits on LR op and replace with
	optimized %I, %J flags.
	* compare-exchange-atomics-model-1.c: New test.
	* compare-exchange-atomics-model-2.c: Likewise.
	* compare-exchange-atomics-model-3.c: Likewise.
	* compare-exchange-atomics-model-4.c: Likewise.
	* compare-exchange-atomics-model-5.c: Likewise.
	* compare-exchange-atomics-model-6.c: Likewise.

Signed-off-by: Patrick O'Neill <patrick@rivosinc.com>
---
 gcc/config/riscv/riscv-protos.h               |  3 ++
 gcc/config/riscv/riscv.cc                     | 44 +++++++++++++++++++
 gcc/config/riscv/sync.md                      |  9 +++-
 .../riscv/compare-exchange-atomics-model-1.c  | 12 +++++
 .../riscv/compare-exchange-atomics-model-2.c  | 12 +++++
 .../riscv/compare-exchange-atomics-model-3.c  | 12 +++++
 .../riscv/compare-exchange-atomics-model-4.c  | 12 +++++
 .../riscv/compare-exchange-atomics-model-5.c  | 12 +++++
 8 files changed, 114 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-5.c
  

Patch

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 4611447ddde..b03edc3e8a5 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -22,6 +22,8 @@  along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_RISCV_PROTOS_H
 #define GCC_RISCV_PROTOS_H
 
+#include "memmodel.h"
+
 /* Symbol types we understand.  The order of this list must match that of
    the unspec enum in riscv.md, subsequent to UNSPEC_ADDRESS_FIRST.  */
 enum riscv_symbol_type {
@@ -79,6 +81,7 @@  extern void riscv_reinit (void);
 extern poly_uint64 riscv_regmode_natural_size (machine_mode);
 extern bool riscv_v_ext_vector_mode_p (machine_mode);
 extern bool riscv_shamt_matches_mask_p (int, HOST_WIDE_INT);
+extern enum memmodel riscv_union_memmodels (enum memmodel, enum memmodel);
 
 /* Routines implemented in riscv-c.cc.  */
 void riscv_cpu_cpp_builtins (cpp_reader *);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 6576e9ae524..061d2cf42b4 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -4278,6 +4278,36 @@  riscv_print_operand_reloc (FILE *file, rtx op, bool hi_reloc)
   fputc (')', file);
 }
 
+/* Return the memory model that encapuslates both given models.  */
+
+enum memmodel
+riscv_union_memmodels (enum memmodel model1, enum memmodel model2)
+{
+  model1 = memmodel_base (model1);
+  model2 = memmodel_base (model2);
+
+  enum memmodel weaker = model1 <= model2 ? model1: model2;
+  enum memmodel stronger = model1 > model2 ? model1: model2;
+
+  switch (stronger)
+    {
+      case MEMMODEL_SEQ_CST:
+      case MEMMODEL_ACQ_REL:
+	return stronger;
+      case MEMMODEL_RELEASE:
+	if (weaker == MEMMODEL_ACQUIRE || weaker == MEMMODEL_CONSUME)
+	  return MEMMODEL_ACQ_REL;
+	else
+	  return stronger;
+      case MEMMODEL_ACQUIRE:
+      case MEMMODEL_CONSUME:
+      case MEMMODEL_RELAXED:
+	return stronger;
+      default:
+	gcc_unreachable ();
+    }
+}
+
 /* Return true if the .AQ suffix should be added to an AMO to implement the
    acquire portion of memory model MODEL.  */
 
@@ -4331,6 +4361,8 @@  riscv_memmodel_needs_amo_release (enum memmodel model)
    'R'	Print the low-part relocation associated with OP.
    'C'	Print the integer branch condition for comparison OP.
    'A'	Print the atomic operation suffix for memory model OP.
+   'I'	Print the LR suffix for memory model OP.
+   'J'	Print the SC suffix for memory model OP.
    'z'	Print x0 if OP is zero, otherwise print OP normally.
    'i'	Print i if the operand is not a register.
    'S'	Print shift-index of single-bit mask OP.
@@ -4500,6 +4532,18 @@  riscv_print_operand (FILE *file, rtx op, int letter)
 	fputs (".rl", file);
       break;
 
+    case 'I':
+      if (model == MEMMODEL_SEQ_CST)
+	fputs (".aqrl", file);
+      else if (riscv_memmodel_needs_amo_acquire (model))
+	fputs (".aq", file);
+      break;
+
+    case 'J':
+      if (riscv_memmodel_needs_amo_release (model))
+	fputs (".rl", file);
+      break;
+
     case 'i':
       if (code != REG)
         fputs ("i", file);
diff --git a/gcc/config/riscv/sync.md b/gcc/config/riscv/sync.md
index 1aa9ac81cee..b1a12545a19 100644
--- a/gcc/config/riscv/sync.md
+++ b/gcc/config/riscv/sync.md
@@ -116,10 +116,15 @@ 
    (clobber (match_scratch:GPR 6 "=&r"))]
   "TARGET_ATOMIC"
   {
+    enum memmodel model_success = (enum memmodel) INTVAL(operands[4]);
+    enum memmodel model_failure = (enum memmodel) INTVAL(operands[5]);
+    /* Find the union of the two memory models so we can satisfy both success
+       and failure memory models.  */
+    operands[5] = GEN_INT(riscv_union_memmodels(model_success, model_failure));
     return "1:\;"
-	   "lr.<amo>.aqrl\t%0,%1\;"
+	   "lr.<amo>%I5\t%0,%1\;"
 	   "bne\t%0,%z2,1f\;"
-	   "sc.<amo>.rl\t%6,%z3,%1\;"
+	   "sc.<amo>%J5\t%6,%z3,%1\;"
 	   "bnez\t%6,1b\;"
 	   "1:";
   }
diff --git a/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-1.c b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-1.c
new file mode 100644
index 00000000000..a2c3fc7a1b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-1.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* Verify that appropriate bits are placed per memory model.  */
+/* { dg-final { scan-assembler-not "lr.w.aq" } } */
+/* { dg-final { scan-assembler-not "lr.w.rl" } } */
+/* { dg-final { scan-assembler-not "sc.w.aq" } } */
+/* { dg-final { scan-assembler-not "sc.w.rl" } } */
+
+void
+foo (int bar, int baz, int qux)
+{
+  __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-2.c b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-2.c
new file mode 100644
index 00000000000..d23d4db945f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-2.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* Verify that appropriate bits are placed per memory model.  */
+/* { dg-final { scan-assembler "lr.w.aq" } } */
+/* { dg-final { scan-assembler-not "lr.w.rl" } } */
+/* { dg-final { scan-assembler-not "sc.w.aq" } } */
+/* { dg-final { scan-assembler-not "sc.w.rl" } } */
+
+void
+foo (int bar, int baz, int qux)
+{
+  __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_CONSUME, __ATOMIC_CONSUME);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-3.c b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-3.c
new file mode 100644
index 00000000000..7379825c6f7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-3.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* Verify that appropriate bits are placed per memory model.  */
+/* { dg-final { scan-assembler "lr.w.aq" } } */
+/* { dg-final { scan-assembler-not "lr.w.rl" } } */
+/* { dg-final { scan-assembler-not "sc.w.aq" } } */
+/* { dg-final { scan-assembler-not "sc.w.rl" } } */
+
+void
+foo (int bar, int baz, int qux)
+{
+  __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-4.c b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-4.c
new file mode 100644
index 00000000000..80ab9889288
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-4.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* Verify that appropriate bits are placed per memory model.  */
+/* { dg-final { scan-assembler "lr.w.aqrl" } } */
+/* { dg-final { scan-assembler "sc.w.rl" } } */
+/* { dg-final { scan-assembler-not "lr.w.rl" } } */
+/* { dg-final { scan-assembler-not "sc.w.aq" } } */
+
+void
+foo (int bar, int baz, int qux)
+{
+  __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-5.c b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-5.c
new file mode 100644
index 00000000000..da905242317
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/compare-exchange-atomics-model-5.c
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* Verify that appropriate bits are placed per memory model.  */
+/* { dg-final { scan-assembler "lr.w.aq" } } */
+/* { dg-final { scan-assembler "sc.w.rl" } } */
+/* { dg-final { scan-assembler-not "lr.w.rl" } } */
+/* { dg-final { scan-assembler-not "sc.w.aq" } } */
+
+void
+foo (int bar, int baz, int qux)
+{
+  __atomic_compare_exchange_n(&bar, &baz, qux, 1, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+}