Introduce the %I and %J flags for setting the .aqrl bits on LR/SC pairs as needed.
Atomic compare and exchange ops provide 2 types of memory models. C++17 and later places 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 LR/SC ops in line with table A.6 of the ISA manual. 2022-03-31 Patrick O'Neill <patr...@rivosinc.com> * riscv.cc: Add functions to get the parent 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 %I, %J flags. * inline-atomics-model-1.c: New test. * inline-atomics-model-2.c: Likewise. * inline-atomics-model-3.c: Likewise. * inline-atomics-model-4.c: Likewise. * inline-atomics-model-5.c: Likewise. * inline-atomics-model-6.c: Likewise. Signed-off-by: Patrick O'Neill <patr...@rivosinc.com> --- gcc/config/riscv/riscv-protos.h | 4 ++ gcc/config/riscv/riscv.cc | 68 +++++++++++++++++++ gcc/config/riscv/sync.md | 12 +++- .../gcc.target/riscv/inline-atomics-model-1.c | 12 ++++ .../gcc.target/riscv/inline-atomics-model-2.c | 12 ++++ .../gcc.target/riscv/inline-atomics-model-3.c | 12 ++++ .../gcc.target/riscv/inline-atomics-model-4.c | 12 ++++ .../gcc.target/riscv/inline-atomics-model-5.c | 12 ++++ 8 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-model-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-model-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-model-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-model-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/inline-atomics-model-5.c diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 20c2381c21a..e32ea86a530 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 { @@ -74,6 +76,8 @@ extern bool riscv_expand_block_move (rtx, rtx, rtx); extern bool riscv_store_data_bypass_p (rtx_insn *, rtx_insn *); extern rtx riscv_gen_gpr_save_insn (struct riscv_frame_info *); extern bool riscv_gpr_save_operation_p (rtx); +extern enum memmodel riscv_parent_memmodel (enum memmodel, enum memmodel); +extern enum memmodel riscv_simplify_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 6da602f1b59..6fbcd62fe73 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -3563,6 +3563,59 @@ riscv_print_operand_reloc (FILE *file, rtx op, bool hi_reloc) fputc (')', file); } +/* Return the memory model that encapuslates both given models. This assumes + SYNC models output equivalent code to non-SYNC models. */ + +enum memmodel +riscv_parent_memmodel (enum memmodel model1, enum memmodel model2) +{ + model1 = riscv_simplify_memmodel(model1); + model2 = riscv_simplify_memmodel(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 (); + } +} + +enum memmodel +riscv_simplify_memmodel(enum memmodel model) { + switch (model) + { + case MEMMODEL_SYNC_SEQ_CST: + return MEMMODEL_SEQ_CST; + case MEMMODEL_SYNC_ACQUIRE: + return MEMMODEL_ACQUIRE; + case MEMMODEL_SYNC_RELEASE: + return MEMMODEL_RELEASE; + case MEMMODEL_SEQ_CST: + case MEMMODEL_ACQ_REL: + case MEMMODEL_RELEASE: + case MEMMODEL_ACQUIRE: + case MEMMODEL_CONSUME: + case MEMMODEL_RELAXED: + return model; + default: + gcc_unreachable(); + } +} + /* Return true if the .AQ suffix should be added to an AMO to implement the acquire portion of memory model MODEL. */ @@ -3622,6 +3675,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. @@ -3660,6 +3715,19 @@ riscv_print_operand (FILE *file, rtx op, int letter) fputs (".rl", file); break; + case 'I': + if ((enum memmodel) INTVAL (op) == MEMMODEL_SEQ_CST || + (enum memmodel) INTVAL (op) == MEMMODEL_SYNC_SEQ_CST) + fputs (".aqrl", file); + else if (riscv_memmodel_needs_amo_acquire ((enum memmodel) INTVAL (op))) + fputs (".aq", file); + break; + + case 'J': + if (riscv_memmodel_needs_amo_release ((enum memmodel) INTVAL (op))) + 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 f8a79465ee3..b54338d8eb2 100644 --- a/gcc/config/riscv/sync.md +++ b/gcc/config/riscv/sync.md @@ -115,7 +115,17 @@ UNSPEC_COMPARE_AND_SWAP)) (clobber (match_scratch:GPR 6 "=&r"))] "TARGET_ATOMIC" - "1:\;lr.<amo>.aqrl\t%0,%1\;bne\t%0,%z2,1f\;sc.<amo>.rl\t%6,%z3,%1\;bnez\t%6,1b\;1:" + { + enum memmodel model_success = (enum memmodel) INTVAL(operands[4]); + enum memmodel model_failure = (enum memmodel) INTVAL(operands[5]); + operands[5] = GEN_INT(riscv_parent_memmodel(model_success, model_failure)); + return "1:\;" + "lr.<amo>%I5\t%0,%1\;" + "bne\t%0,%z2,1f\;" + "sc.<amo>%J5\t%6,%z3,%1\;" + "bnez\t%6,1b\;" + "1:"; + } [(set (attr "length") (const_int 16))]) (define_expand "atomic_compare_and_swap<mode>" diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-model-1.c b/gcc/testsuite/gcc.target/riscv/inline-atomics-model-1.c new file mode 100644 index 00000000000..a2c3fc7a1b6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/inline-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/inline-atomics-model-2.c b/gcc/testsuite/gcc.target/riscv/inline-atomics-model-2.c new file mode 100644 index 00000000000..d23d4db945f --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/inline-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/inline-atomics-model-3.c b/gcc/testsuite/gcc.target/riscv/inline-atomics-model-3.c new file mode 100644 index 00000000000..7379825c6f7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/inline-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/inline-atomics-model-4.c b/gcc/testsuite/gcc.target/riscv/inline-atomics-model-4.c new file mode 100644 index 00000000000..80ab9889288 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/inline-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/inline-atomics-model-5.c b/gcc/testsuite/gcc.target/riscv/inline-atomics-model-5.c new file mode 100644 index 00000000000..da905242317 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/inline-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); +} -- 2.25.1