+ (match_operand:SI 4 "register_operand" "rI") ;; not_mask
+ (clobber (match_scratch:SI 5 "=&r")) ;; tmp_1
+ (clobber (match_scratch:SI 6 "=&r"))] ;; tmp_2
+ "TARGET_ATOMIC && ALWAYS_INLINE_SUBWORD_ATOMIC"
+ {
+ return
+ "1:\;"
+ "lr.w.aq\t%0, %1\;"
+ "<insn>\t%5, %0, %2\;"
+ "and\t%5, %5, %3\;"
+ "and\t%6, %0, %4\;"
+ "or\t%6, %6, %5\;"
+ "sc.w.rl\t%5, %6, %1\;"
+ "bnez\t%5, 1b\;";}
+ )
+
(define_insn "atomic_exchange<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&r")
(unspec_volatile:GPR
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-1.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-1.c
new file mode 100644
index 00000000000..110fdabd313
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-mno-inline-atomics" } */
+/* { dg-final { scan-assembler "\tcall\t__sync_fetch_and_add_1" } } */
+
+char bar;
+
+int
+main ()
+{
+ __sync_fetch_and_add(&bar, 1);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-2.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-2.c
new file mode 100644
index 00000000000..8d5c31d8b79
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* Verify that subword atomics do not generate calls. */
+/* { dg-options "-minline-atomics" } */
+/* { dg-final { scan-assembler-not "\tcall\t__sync_fetch_and_add_1" } } */
+
+char bar;
+
+int
+main ()
+{
+ __sync_fetch_and_add(&bar, 1);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-3.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-3.c
new file mode 100644
index 00000000000..19b382d45b0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-3.c
@@ -0,0 +1,569 @@
+/* Check all char alignments. */
+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-op-1.c */
+/* Test __atomic routines for existence and proper execution on 1 byte
+ values with each valid memory model. */
+/* { dg-do run } */
+/* { dg-options "-latomic -minline-atomics -Wno-address-of-packed-member" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a char. */
+
+extern void abort(void);
+
+char count, res;
+const char init = ~0;
+
+struct A
+{
+ char a;
+ char b;
+ char c;
+ char d;
+} __attribute__ ((packed)) A;
+
+/* The fetch_op routines return the original value before the operation. */
+
+void
+test_fetch_add (char* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_fetch_add (v, count, __ATOMIC_RELAXED) != 0)
+ abort ();
+
+ if (__atomic_fetch_add (v, 1, __ATOMIC_CONSUME) != 1)
+ abort ();
+
+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQUIRE) != 2)
+ abort ();
+
+ if (__atomic_fetch_add (v, 1, __ATOMIC_RELEASE) != 3)
+ abort ();
+
+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQ_REL) != 4)
+ abort ();
+
+ if (__atomic_fetch_add (v, 1, __ATOMIC_SEQ_CST) != 5)
+ abort ();
+}
+
+
+void
+test_fetch_sub (char* v)
+{
+ *v = res = 20;
+ count = 0;
+
+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_RELAXED) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, 1, __ATOMIC_CONSUME) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQUIRE) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, 1, __ATOMIC_RELEASE) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQ_REL) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, 1, __ATOMIC_SEQ_CST) != res--)
+ abort ();
+}
+
+void
+test_fetch_and (char* v)
+{
+ *v = init;
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_fetch_and (v, init, __ATOMIC_CONSUME) != 0)
+ abort ();
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ *v = ~*v;
+ if (__atomic_fetch_and (v, init, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+}
+
+void
+test_fetch_nand (char* v)
+{
+ *v = init;
+
+ if (__atomic_fetch_nand (v, 0, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_fetch_nand (v, init, __ATOMIC_CONSUME) != init)
+ abort ();
+
+ if (__atomic_fetch_nand (v, 0, __ATOMIC_ACQUIRE) != 0 )
+ abort ();
+
+ if (__atomic_fetch_nand (v, init, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_fetch_nand (v, 0, __ATOMIC_SEQ_CST) != init)
+ abort ();
+}
+
+void
+test_fetch_xor (char* v)
+{
+ *v = init;
+ count = 0;
+
+ if (__atomic_fetch_xor (v, count, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME) != init)
+ abort ();
+
+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE) != 0)
+ abort ();
+
+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_SEQ_CST) != init)
+ abort ();
+}
+
+void
+test_fetch_or (char* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_fetch_or (v, count, __ATOMIC_RELAXED) != 0)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, 2, __ATOMIC_CONSUME) != 1)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQUIRE) != 3)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, 8, __ATOMIC_RELEASE) != 7)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQ_REL) != 15)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, count, __ATOMIC_SEQ_CST) != 31)
+ abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation. */
+
+void
+test_add_fetch (char* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_RELAXED) != 1)
+ abort ();
+
+ if (__atomic_add_fetch (v, 1, __ATOMIC_CONSUME) != 2)
+ abort ();
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQUIRE) != 3)
+ abort ();
+
+ if (__atomic_add_fetch (v, 1, __ATOMIC_RELEASE) != 4)
+ abort ();
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQ_REL) != 5)
+ abort ();
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_SEQ_CST) != 6)
+ abort ();
+}
+
+
+void
+test_sub_fetch (char* v)
+{
+ *v = res = 20;
+ count = 0;
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, 1, __ATOMIC_CONSUME) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQUIRE) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, 1, __ATOMIC_RELEASE) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_SEQ_CST) != --res)
+ abort ();
+}
+
+void
+test_and_fetch (char* v)
+{
+ *v = init;
+
+ if (__atomic_and_fetch (v, 0, __ATOMIC_RELAXED) != 0)
+ abort ();
+
+ *v = init;
+ if (__atomic_and_fetch (v, init, __ATOMIC_CONSUME) != init)
+ abort ();
+
+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ *v = ~*v;
+ if (__atomic_and_fetch (v, init, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ *v = ~*v;
+ if (__atomic_and_fetch (v, 0, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+}
+
+void
+test_nand_fetch (char* v)
+{
+ *v = init;
+
+ if (__atomic_nand_fetch (v, 0, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_nand_fetch (v, init, __ATOMIC_CONSUME) != 0)
+ abort ();
+
+ if (__atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE) != init)
+ abort ();
+
+ if (__atomic_nand_fetch (v, init, __ATOMIC_RELEASE) != 0)
+ abort ();
+
+ if (__atomic_nand_fetch (v, init, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST) != init)
+ abort ();
+}
+
+
+
+void
+test_xor_fetch (char* v)
+{
+ *v = init;
+ count = 0;
+
+ if (__atomic_xor_fetch (v, count, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_CONSUME) != 0)
+ abort ();
+
+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+}
+
+void
+test_or_fetch (char* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_or_fetch (v, count, __ATOMIC_RELAXED) != 1)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, 2, __ATOMIC_CONSUME) != 3)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQUIRE) != 7)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, 8, __ATOMIC_RELEASE) != 15)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQ_REL) != 31)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, count, __ATOMIC_SEQ_CST) != 63)
+ abort ();
+}
+
+
+/* Test the OP routines with a result which isn't used. Use both variations
+ within each function. */
+
+void
+test_add (char* v)
+{
+ *v = 0;
+ count = 1;
+
+ __atomic_add_fetch (v, count, __ATOMIC_RELAXED);
+ if (*v != 1)
+ abort ();
+
+ __atomic_fetch_add (v, count, __ATOMIC_CONSUME);
+ if (*v != 2)
+ abort ();
+
+ __atomic_add_fetch (v, 1 , __ATOMIC_ACQUIRE);
+ if (*v != 3)
+ abort ();
+
+ __atomic_fetch_add (v, 1, __ATOMIC_RELEASE);
+ if (*v != 4)
+ abort ();
+
+ __atomic_add_fetch (v, count, __ATOMIC_ACQ_REL);
+ if (*v != 5)
+ abort ();
+
+ __atomic_fetch_add (v, count, __ATOMIC_SEQ_CST);
+ if (*v != 6)
+ abort ();
+}
+
+
+void
+test_sub (char* v)
+{
+ *v = res = 20;
+ count = 0;
+
+ __atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED);
+ if (*v != --res)
+ abort ();
+
+ __atomic_fetch_sub (v, count + 1, __ATOMIC_CONSUME);
+ if (*v != --res)
+ abort ();
+
+ __atomic_sub_fetch (v, 1, __ATOMIC_ACQUIRE);
+ if (*v != --res)
+ abort ();
+
+ __atomic_fetch_sub (v, 1, __ATOMIC_RELEASE);
+ if (*v != --res)
+ abort ();
+
+ __atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL);
+ if (*v != --res)
+ abort ();
+
+ __atomic_fetch_sub (v, count + 1, __ATOMIC_SEQ_CST);
+ if (*v != --res)
+ abort ();
+}
+
+void
+test_and (char* v)
+{
+ *v = init;
+
+ __atomic_and_fetch (v, 0, __ATOMIC_RELAXED);
+ if (*v != 0)
+ abort ();
+
+ *v = init;
+ __atomic_fetch_and (v, init, __ATOMIC_CONSUME);
+ if (*v != init)
+ abort ();
+
+ __atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE);
+ if (*v != 0)
+ abort ();
+
+ *v = ~*v;
+ __atomic_fetch_and (v, init, __ATOMIC_RELEASE);
+ if (*v != init)
+ abort ();
+
+ __atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL);
+ if (*v != 0)
+ abort ();
+
+ *v = ~*v;
+ __atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST);
+ if (*v != 0)
+ abort ();
+}
+
+void
+test_nand (char* v)
+{
+ *v = init;
+
+ __atomic_fetch_nand (v, 0, __ATOMIC_RELAXED);
+ if (*v != init)
+ abort ();
+
+ __atomic_fetch_nand (v, init, __ATOMIC_CONSUME);
+ if (*v != 0)
+ abort ();
+
+ __atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE);
+ if (*v != init)
+ abort ();
+
+ __atomic_nand_fetch (v, init, __ATOMIC_RELEASE);
+ if (*v != 0)
+ abort ();
+
+ __atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL);
+ if (*v != init)
+ abort ();
+
+ __atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST);
+ if (*v != init)
+ abort ();
+}
+
+
+
+void
+test_xor (char* v)
+{
+ *v = init;
+ count = 0;
+
+ __atomic_xor_fetch (v, count, __ATOMIC_RELAXED);
+ if (*v != init)
+ abort ();
+
+ __atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME);
+ if (*v != 0)
+ abort ();
+
+ __atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE);
+ if (*v != 0)
+ abort ();
+
+ __atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE);
+ if (*v != init)
+ abort ();
+
+ __atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL);
+ if (*v != init)
+ abort ();
+
+ __atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST);
+ if (*v != 0)
+ abort ();
+}
+
+void
+test_or (char* v)
+{
+ *v = 0;
+ count = 1;
+
+ __atomic_or_fetch (v, count, __ATOMIC_RELAXED);
+ if (*v != 1)
+ abort ();
+
+ count *= 2;
+ __atomic_fetch_or (v, count, __ATOMIC_CONSUME);
+ if (*v != 3)
+ abort ();
+
+ count *= 2;
+ __atomic_or_fetch (v, 4, __ATOMIC_ACQUIRE);
+ if (*v != 7)
+ abort ();
+
+ count *= 2;
+ __atomic_fetch_or (v, 8, __ATOMIC_RELEASE);
+ if (*v != 15)
+ abort ();
+
+ count *= 2;
+ __atomic_or_fetch (v, count, __ATOMIC_ACQ_REL);
+ if (*v != 31)
+ abort ();
+
+ count *= 2;
+ __atomic_fetch_or (v, count, __ATOMIC_SEQ_CST);
+ if (*v != 63)
+ abort ();
+}
+
+int
+main ()
+{
+ char* V[] = {&A.a, &A.b, &A.c, &A.d};
+
+ for (int i = 0; i < 4; i++) {
+ test_fetch_add (V[i]);
+ test_fetch_sub (V[i]);
+ test_fetch_and (V[i]);
+ test_fetch_nand (V[i]);
+ test_fetch_xor (V[i]);
+ test_fetch_or (V[i]);
+
+ test_add_fetch (V[i]);
+ test_sub_fetch (V[i]);
+ test_and_fetch (V[i]);
+ test_nand_fetch (V[i]);
+ test_xor_fetch (V[i]);
+ test_or_fetch (V[i]);
+
+ test_add (V[i]);
+ test_sub (V[i]);
+ test_and (V[i]);
+ test_nand (V[i]);
+ test_xor (V[i]);
+ test_or (V[i]);
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-4.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-4.c
new file mode 100644
index 00000000000..619cf1f86ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-4.c
@@ -0,0 +1,566 @@
+/* Check all short alignments. */
+/* Duplicate logic as libatomic/testsuite/libatomic.c/atomic-op-2.c */
+/* Test __atomic routines for existence and proper execution on 2 byte
+ values with each valid memory model. */
+/* { dg-do run } */
+/* { dg-options "-latomic -minline-atomics -Wno-address-of-packed-member" } */
+
+/* Test the execution of the __atomic_*OP builtin routines for a short. */
+
+extern void abort(void);
+
+short count, res;
+const short init = ~0;
+
+struct A
+{
+ short a;
+ short b;
+} __attribute__ ((packed)) A;
+
+/* The fetch_op routines return the original value before the operation. */
+
+void
+test_fetch_add (short* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_fetch_add (v, count, __ATOMIC_RELAXED) != 0)
+ abort ();
+
+ if (__atomic_fetch_add (v, 1, __ATOMIC_CONSUME) != 1)
+ abort ();
+
+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQUIRE) != 2)
+ abort ();
+
+ if (__atomic_fetch_add (v, 1, __ATOMIC_RELEASE) != 3)
+ abort ();
+
+ if (__atomic_fetch_add (v, count, __ATOMIC_ACQ_REL) != 4)
+ abort ();
+
+ if (__atomic_fetch_add (v, 1, __ATOMIC_SEQ_CST) != 5)
+ abort ();
+}
+
+
+void
+test_fetch_sub (short* v)
+{
+ *v = res = 20;
+ count = 0;
+
+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_RELAXED) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, 1, __ATOMIC_CONSUME) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQUIRE) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, 1, __ATOMIC_RELEASE) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, count + 1, __ATOMIC_ACQ_REL) != res--)
+ abort ();
+
+ if (__atomic_fetch_sub (v, 1, __ATOMIC_SEQ_CST) != res--)
+ abort ();
+}
+
+void
+test_fetch_and (short* v)
+{
+ *v = init;
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_fetch_and (v, init, __ATOMIC_CONSUME) != 0)
+ abort ();
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ *v = ~*v;
+ if (__atomic_fetch_and (v, init, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+}
+
+void
+test_fetch_nand (short* v)
+{
+ *v = init;
+
+ if (__atomic_fetch_nand (v, 0, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_fetch_nand (v, init, __ATOMIC_CONSUME) != init)
+ abort ();
+
+ if (__atomic_fetch_nand (v, 0, __ATOMIC_ACQUIRE) != 0 )
+ abort ();
+
+ if (__atomic_fetch_nand (v, init, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ if (__atomic_fetch_nand (v, 0, __ATOMIC_SEQ_CST) != init)
+ abort ();
+}
+
+void
+test_fetch_xor (short* v)
+{
+ *v = init;
+ count = 0;
+
+ if (__atomic_fetch_xor (v, count, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME) != init)
+ abort ();
+
+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE) != 0)
+ abort ();
+
+ if (__atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_fetch_xor (v, ~count, __ATOMIC_SEQ_CST) != init)
+ abort ();
+}
+
+void
+test_fetch_or (short* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_fetch_or (v, count, __ATOMIC_RELAXED) != 0)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, 2, __ATOMIC_CONSUME) != 1)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQUIRE) != 3)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, 8, __ATOMIC_RELEASE) != 7)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, count, __ATOMIC_ACQ_REL) != 15)
+ abort ();
+
+ count *= 2;
+ if (__atomic_fetch_or (v, count, __ATOMIC_SEQ_CST) != 31)
+ abort ();
+}
+
+/* The OP_fetch routines return the new value after the operation. */
+
+void
+test_add_fetch (short* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_RELAXED) != 1)
+ abort ();
+
+ if (__atomic_add_fetch (v, 1, __ATOMIC_CONSUME) != 2)
+ abort ();
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQUIRE) != 3)
+ abort ();
+
+ if (__atomic_add_fetch (v, 1, __ATOMIC_RELEASE) != 4)
+ abort ();
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_ACQ_REL) != 5)
+ abort ();
+
+ if (__atomic_add_fetch (v, count, __ATOMIC_SEQ_CST) != 6)
+ abort ();
+}
+
+
+void
+test_sub_fetch (short* v)
+{
+ *v = res = 20;
+ count = 0;
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, 1, __ATOMIC_CONSUME) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQUIRE) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, 1, __ATOMIC_RELEASE) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL) != --res)
+ abort ();
+
+ if (__atomic_sub_fetch (v, count + 1, __ATOMIC_SEQ_CST) != --res)
+ abort ();
+}
+
+void
+test_and_fetch (short* v)
+{
+ *v = init;
+
+ if (__atomic_and_fetch (v, 0, __ATOMIC_RELAXED) != 0)
+ abort ();
+
+ *v = init;
+ if (__atomic_and_fetch (v, init, __ATOMIC_CONSUME) != init)
+ abort ();
+
+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ *v = ~*v;
+ if (__atomic_and_fetch (v, init, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL) != 0)
+ abort ();
+
+ *v = ~*v;
+ if (__atomic_and_fetch (v, 0, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+}
+
+void
+test_nand_fetch (short* v)
+{
+ *v = init;
+
+ if (__atomic_nand_fetch (v, 0, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_nand_fetch (v, init, __ATOMIC_CONSUME) != 0)
+ abort ();
+
+ if (__atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE) != init)
+ abort ();
+
+ if (__atomic_nand_fetch (v, init, __ATOMIC_RELEASE) != 0)
+ abort ();
+
+ if (__atomic_nand_fetch (v, init, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST) != init)
+ abort ();
+}
+
+
+
+void
+test_xor_fetch (short* v)
+{
+ *v = init;
+ count = 0;
+
+ if (__atomic_xor_fetch (v, count, __ATOMIC_RELAXED) != init)
+ abort ();
+
+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_CONSUME) != 0)
+ abort ();
+
+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE) != 0)
+ abort ();
+
+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_RELEASE) != init)
+ abort ();
+
+ if (__atomic_xor_fetch (v, 0, __ATOMIC_ACQ_REL) != init)
+ abort ();
+
+ if (__atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST) != 0)
+ abort ();
+}
+
+void
+test_or_fetch (short* v)
+{
+ *v = 0;
+ count = 1;
+
+ if (__atomic_or_fetch (v, count, __ATOMIC_RELAXED) != 1)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, 2, __ATOMIC_CONSUME) != 3)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQUIRE) != 7)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, 8, __ATOMIC_RELEASE) != 15)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, count, __ATOMIC_ACQ_REL) != 31)
+ abort ();
+
+ count *= 2;
+ if (__atomic_or_fetch (v, count, __ATOMIC_SEQ_CST) != 63)
+ abort ();
+}
+
+
+/* Test the OP routines with a result which isn't used. Use both variations
+ within each function. */
+
+void
+test_add (short* v)
+{
+ *v = 0;
+ count = 1;
+
+ __atomic_add_fetch (v, count, __ATOMIC_RELAXED);
+ if (*v != 1)
+ abort ();
+
+ __atomic_fetch_add (v, count, __ATOMIC_CONSUME);
+ if (*v != 2)
+ abort ();
+
+ __atomic_add_fetch (v, 1 , __ATOMIC_ACQUIRE);
+ if (*v != 3)
+ abort ();
+
+ __atomic_fetch_add (v, 1, __ATOMIC_RELEASE);
+ if (*v != 4)
+ abort ();
+
+ __atomic_add_fetch (v, count, __ATOMIC_ACQ_REL);
+ if (*v != 5)
+ abort ();
+
+ __atomic_fetch_add (v, count, __ATOMIC_SEQ_CST);
+ if (*v != 6)
+ abort ();
+}
+
+
+void
+test_sub (short* v)
+{
+ *v = res = 20;
+ count = 0;
+
+ __atomic_sub_fetch (v, count + 1, __ATOMIC_RELAXED);
+ if (*v != --res)
+ abort ();
+
+ __atomic_fetch_sub (v, count + 1, __ATOMIC_CONSUME);
+ if (*v != --res)
+ abort ();
+
+ __atomic_sub_fetch (v, 1, __ATOMIC_ACQUIRE);
+ if (*v != --res)
+ abort ();
+
+ __atomic_fetch_sub (v, 1, __ATOMIC_RELEASE);
+ if (*v != --res)
+ abort ();
+
+ __atomic_sub_fetch (v, count + 1, __ATOMIC_ACQ_REL);
+ if (*v != --res)
+ abort ();
+
+ __atomic_fetch_sub (v, count + 1, __ATOMIC_SEQ_CST);
+ if (*v != --res)
+ abort ();
+}
+
+void
+test_and (short* v)
+{
+ *v = init;
+
+ __atomic_and_fetch (v, 0, __ATOMIC_RELAXED);
+ if (*v != 0)
+ abort ();
+
+ *v = init;
+ __atomic_fetch_and (v, init, __ATOMIC_CONSUME);
+ if (*v != init)
+ abort ();
+
+ __atomic_and_fetch (v, 0, __ATOMIC_ACQUIRE);
+ if (*v != 0)
+ abort ();
+
+ *v = ~*v;
+ __atomic_fetch_and (v, init, __ATOMIC_RELEASE);
+ if (*v != init)
+ abort ();
+
+ __atomic_and_fetch (v, 0, __ATOMIC_ACQ_REL);
+ if (*v != 0)
+ abort ();
+
+ *v = ~*v;
+ __atomic_fetch_and (v, 0, __ATOMIC_SEQ_CST);
+ if (*v != 0)
+ abort ();
+}
+
+void
+test_nand (short* v)
+{
+ *v = init;
+
+ __atomic_fetch_nand (v, 0, __ATOMIC_RELAXED);
+ if (*v != init)
+ abort ();
+
+ __atomic_fetch_nand (v, init, __ATOMIC_CONSUME);
+ if (*v != 0)
+ abort ();
+
+ __atomic_nand_fetch (v, 0, __ATOMIC_ACQUIRE);
+ if (*v != init)
+ abort ();
+
+ __atomic_nand_fetch (v, init, __ATOMIC_RELEASE);
+ if (*v != 0)
+ abort ();
+
+ __atomic_fetch_nand (v, init, __ATOMIC_ACQ_REL);
+ if (*v != init)
+ abort ();
+
+ __atomic_nand_fetch (v, 0, __ATOMIC_SEQ_CST);
+ if (*v != init)
+ abort ();
+}
+
+
+
+void
+test_xor (short* v)
+{
+ *v = init;
+ count = 0;
+
+ __atomic_xor_fetch (v, count, __ATOMIC_RELAXED);
+ if (*v != init)
+ abort ();
+
+ __atomic_fetch_xor (v, ~count, __ATOMIC_CONSUME);
+ if (*v != 0)
+ abort ();
+
+ __atomic_xor_fetch (v, 0, __ATOMIC_ACQUIRE);
+ if (*v != 0)
+ abort ();
+
+ __atomic_fetch_xor (v, ~count, __ATOMIC_RELEASE);
+ if (*v != init)
+ abort ();
+
+ __atomic_fetch_xor (v, 0, __ATOMIC_ACQ_REL);
+ if (*v != init)
+ abort ();
+
+ __atomic_xor_fetch (v, ~count, __ATOMIC_SEQ_CST);
+ if (*v != 0)
+ abort ();
+}
+
+void
+test_or (short* v)
+{
+ *v = 0;
+ count = 1;
+
+ __atomic_or_fetch (v, count, __ATOMIC_RELAXED);
+ if (*v != 1)
+ abort ();
+
+ count *= 2;
+ __atomic_fetch_or (v, count, __ATOMIC_CONSUME);
+ if (*v != 3)
+ abort ();
+
+ count *= 2;
+ __atomic_or_fetch (v, 4, __ATOMIC_ACQUIRE);
+ if (*v != 7)
+ abort ();
+
+ count *= 2;
+ __atomic_fetch_or (v, 8, __ATOMIC_RELEASE);
+ if (*v != 15)
+ abort ();
+
+ count *= 2;
+ __atomic_or_fetch (v, count, __ATOMIC_ACQ_REL);
+ if (*v != 31)
+ abort ();
+
+ count *= 2;
+ __atomic_fetch_or (v, count, __ATOMIC_SEQ_CST);
+ if (*v != 63)
+ abort ();
+}
+
+int
+main () {
+ short* V[] = {&A.a, &A.b};
+
+ for (int i = 0; i < 2; i++) {
+ test_fetch_add (V[i]);
+ test_fetch_sub (V[i]);
+ test_fetch_and (V[i]);
+ test_fetch_nand (V[i]);
+ test_fetch_xor (V[i]);
+ test_fetch_or (V[i]);
+
+ test_add_fetch (V[i]);
+ test_sub_fetch (V[i]);
+ test_and_fetch (V[i]);
+ test_nand_fetch (V[i]);
+ test_xor_fetch (V[i]);
+ test_or_fetch (V[i]);
+
+ test_add (V[i]);
+ test_sub (V[i]);
+ test_and (V[i]);
+ test_nand (V[i]);
+ test_xor (V[i]);
+ test_or (V[i]);
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-5.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-5.c
new file mode 100644
index 00000000000..c2751235dbf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* Verify that constant propogation is functioning. */
+/* The -4 should be propogated into an ANDI statement. */
+/* { dg-options "-minline-atomics" } */
+/* { dg-final { scan-assembler-not "\tli\t[at]\d,-4" } } */
+
+char bar;
+
+int
+main ()
+{
+ __sync_fetch_and_add(&bar, 1);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-6.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-6.c
new file mode 100644
index 00000000000..18249bae7d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-6.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* Verify that masks are generated to the correct size. */
+/* { dg-options "-O3 -minline-atomics" } */
+/* Check for mask */
+/* { dg-final { scan-assembler "\tli\t[at]\d,255" } } */
+
+int
+main ()
+{
+ char bar __attribute__((aligned (32)));
+ __sync_fetch_and_add(&bar, 0);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-7.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-7.c
new file mode 100644
index 00000000000..81bbf4badce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-7.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* Verify that masks are generated to the correct size. */
+/* { dg-options "-O3 -minline-atomics" } */
+/* Check for mask */
+/* { dg-final { scan-assembler "\tli\t[at]\d,65535" } } */
+
+int
+main ()
+{
+ short bar __attribute__((aligned (32)));
+ __sync_fetch_and_add(&bar, 0);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-8.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-8.c
new file mode 100644
index 00000000000..d27562ed981
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-8.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* Verify that masks are aligned properly. */
+/* { dg-options "-O3 -minline-atomics" } */
+/* Check for mask */
+/* { dg-final { scan-assembler "\tli\t[at]\d,16711680" } } */
+
+int
+main ()
+{
+ struct A {
+ char a;
+ char b;
+ char c;
+ char d;
+ } __attribute__ ((packed)) __attribute__((aligned (32))) A;
+ __sync_fetch_and_add(&A.c, 0);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/inline-atomics-9.c
b/gcc/testsuite/gcc.target/riscv/inline-atomics-9.c
new file mode 100644
index 00000000000..382849702ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/inline-atomics-9.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* Verify that masks are aligned properly. */
+/* { dg-options "-O3 -minline-atomics" } */
+/* Check for mask */
+/* { dg-final { scan-assembler "\tli\t[at]\d,-16777216" } } */
+
+int
+main ()
+{
+ struct A {
+ char a;
+ char b;
+ char c;
+ char d;
+ } __attribute__ ((packed)) __attribute__((aligned (32))) A;
+ __sync_fetch_and_add(&A.d, 0);
+}
diff --git a/libgcc/config/riscv/atomic.c b/libgcc/config/riscv/atomic.c
index 904d8c59cf0..9583027b757 100644
--- a/libgcc/config/riscv/atomic.c
+++ b/libgcc/config/riscv/atomic.c
@@ -30,6 +30,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If
not, see
#define INVERT "not %[tmp1], %[tmp1]\n\t"
#define DONT_INVERT ""
+/* Logic duplicated in gcc/gcc/config/riscv/sync.md for use when inlining is
enabled */
+
#define GENERATE_FETCH_AND_OP(type, size, opname, insn, invert, cop) \
type __sync_fetch_and_ ## opname ## _ ## size (type *p, type v) \
{ \