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-10 Patrick O'Neill <patr...@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.

Signed-off-by: Patrick O'Neill <patr...@rivosinc.com>
---
v3 Changelog:
* Consolidate tests in [PATCH v3 10/10]
---
 gcc/config/riscv/riscv-protos.h |  3 +++
 gcc/config/riscv/riscv.cc       | 44 +++++++++++++++++++++++++++++++++
 gcc/config/riscv/sync.md        |  9 +++++--
 3 files changed, 54 insertions(+), 2 deletions(-)

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 fdfc56d64a1..a31b8c4f28a 100644
--- a/gcc/config/riscv/sync.md
+++ b/gcc/config/riscv/sync.md
@@ -130,10 +130,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:";
   }
-- 
2.25.1

Reply via email to