RISC-V: Implement ZACAS extensions

Message ID 20240102201720.1526-1-trdthg47@gmail.com
State Unresolved
Headers
Series RISC-V: Implement ZACAS extensions |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Trd thg Jan. 2, 2024, 8:17 p.m. UTC
  From: trdthg <trdthg47@gmail.com>

This patch supports Zacas extension.
It includes instruction's machine description and built-in functions.

gcc/ChangeLog:

	* common/config/riscv/riscv-common.cc
	(riscv_implied_info): Add zacas extensions.
	(riscv_ext_version_table): Likewise.
	* config/riscv/arch-canonicalize
	(IMPLIED_EXT): Add zacas extensions.
	* config/riscv/iterators.md
	(SIDI): New iterator.
	(SIDITI): Likewise.
	(amocas): New attribute.
	* config/riscv/riscv-builtins.cc
	(AVAIL): Add new.
	* config/riscv/riscv-ftypes.def: Add new type for zacas instructions.
	* config/riscv/riscv-zacas.def: Add ZACAS extension's built-in function file.
	* config/riscv/riscv.md: Add new type for zacas instructions.
	* config/riscv/riscv.opt: Add introduction of riscv_zacas_subext.
	* config/riscv/zacas.md: Add ZACAS extension's machine description file.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/zacas32.c: New test.
	* gcc.target/riscv/zacas64.c: New test.
	* gcc.target/riscv/zacas128.c: New test.

Signed-off-by: trdthg <trdthg47@gmail.com>
---
 gcc/common/config/riscv/riscv-common.cc   |  5 ++
 gcc/config/riscv/arch-canonicalize        |  1 +
 gcc/config/riscv/iterators.md             |  9 +++
 gcc/config/riscv/riscv-builtins.cc        | 85 ++++++++++++++++++++++-
 gcc/config/riscv/riscv-ftypes.def         |  3 +
 gcc/config/riscv/riscv-zacas.def          | 11 +++
 gcc/config/riscv/riscv.md                 |  5 +-
 gcc/config/riscv/riscv.opt                |  2 +
 gcc/config/riscv/zacas.md                 | 52 ++++++++++++++
 gcc/testsuite/gcc.target/riscv/zacas128.c | 19 +++++
 gcc/testsuite/gcc.target/riscv/zacas32.c  | 34 +++++++++
 gcc/testsuite/gcc.target/riscv/zacas64.c  | 34 +++++++++
 12 files changed, 257 insertions(+), 3 deletions(-)
 create mode 100644 gcc/config/riscv/riscv-zacas.def
 create mode 100644 gcc/config/riscv/zacas.md
 create mode 100644 gcc/testsuite/gcc.target/riscv/zacas128.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zacas32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/zacas64.c
  

Comments

Jeff Law Jan. 3, 2024, 3:05 a.m. UTC | #1
On 1/2/24 13:17, trdthg47@gmail.com wrote:
> From: trdthg <trdthg47@gmail.com>
> 
> This patch supports Zacas extension.
> It includes instruction's machine description and built-in functions.
> 
> gcc/ChangeLog:
> 
> 	* common/config/riscv/riscv-common.cc
> 	(riscv_implied_info): Add zacas extensions.
> 	(riscv_ext_version_table): Likewise.
> 	* config/riscv/arch-canonicalize
> 	(IMPLIED_EXT): Add zacas extensions.
> 	* config/riscv/iterators.md
> 	(SIDI): New iterator.
> 	(SIDITI): Likewise.
> 	(amocas): New attribute.
> 	* config/riscv/riscv-builtins.cc
> 	(AVAIL): Add new.
> 	* config/riscv/riscv-ftypes.def: Add new type for zacas instructions.
> 	* config/riscv/riscv-zacas.def: Add ZACAS extension's built-in function file.
> 	* config/riscv/riscv.md: Add new type for zacas instructions.
> 	* config/riscv/riscv.opt: Add introduction of riscv_zacas_subext.
> 	* config/riscv/zacas.md: Add ZACAS extension's machine description file.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/zacas32.c: New test.
> 	* gcc.target/riscv/zacas64.c: New test.
> 	* gcc.target/riscv/zacas128.c: New test.
Just a note.  I'm deferring to gcc-15.  We're well past the point where 
new features should be accepted for gcc-14.

jeff
  
Trd thg Jan. 3, 2024, 3:13 a.m. UTC | #2
Got it.

Jeff Law <jeffreyalaw@gmail.com> 于 2024年1月3日周三 上午11:05写道:

>
>
> On 1/2/24 13:17, trdthg47@gmail.com wrote:
> > From: trdthg <trdthg47@gmail.com>
> >
> > This patch supports Zacas extension.
> > It includes instruction's machine description and built-in functions.
> >
> > gcc/ChangeLog:
> >
> >       * common/config/riscv/riscv-common.cc
> >       (riscv_implied_info): Add zacas extensions.
> >       (riscv_ext_version_table): Likewise.
> >       * config/riscv/arch-canonicalize
> >       (IMPLIED_EXT): Add zacas extensions.
> >       * config/riscv/iterators.md
> >       (SIDI): New iterator.
> >       (SIDITI): Likewise.
> >       (amocas): New attribute.
> >       * config/riscv/riscv-builtins.cc
> >       (AVAIL): Add new.
> >       * config/riscv/riscv-ftypes.def: Add new type for zacas
> instructions.
> >       * config/riscv/riscv-zacas.def: Add ZACAS extension's built-in
> function file.
> >       * config/riscv/riscv.md: Add new type for zacas instructions.
> >       * config/riscv/riscv.opt: Add introduction of riscv_zacas_subext.
> >       * config/riscv/zacas.md: Add ZACAS extension's machine description
> file.
> >
> > gcc/testsuite/ChangeLog:
> >
> >       * gcc.target/riscv/zacas32.c: New test.
> >       * gcc.target/riscv/zacas64.c: New test.
> >       * gcc.target/riscv/zacas128.c: New test.
> Just a note.  I'm deferring to gcc-15.  We're well past the point where
> new features should be accepted for gcc-14.
>
> jeff
>
  

Patch

diff --git a/gcc/common/config/riscv/riscv-common.cc b/gcc/common/config/riscv/riscv-common.cc
index f20d179568d..14de9968c9e 100644
--- a/gcc/common/config/riscv/riscv-common.cc
+++ b/gcc/common/config/riscv/riscv-common.cc
@@ -77,6 +77,8 @@  static const riscv_implied_info_t riscv_implied_info[] =
   {"f", "zicsr"},
   {"d", "zicsr"},
 
+  {"zacas", "a"},
+
   {"zdinx", "zfinx"},
   {"zfinx", "zicsr"},
   {"zdinx", "zicsr"},
@@ -251,6 +253,8 @@  static const struct riscv_ext_version riscv_ext_version_table[] =
 
   {"zawrs", ISA_SPEC_CLASS_NONE, 1, 0},
 
+  {"zacas", ISA_SPEC_CLASS_NONE, 1, 0},
+
   {"zba", ISA_SPEC_CLASS_NONE, 1, 0},
   {"zbb", ISA_SPEC_CLASS_NONE, 1, 0},
   {"zbc", ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1624,6 +1628,7 @@  static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"zicond",   &gcc_options::x_riscv_zi_subext, MASK_ZICOND},
 
   {"zawrs", &gcc_options::x_riscv_za_subext, MASK_ZAWRS},
+  {"zacas", &gcc_options::x_riscv_za_subext, MASK_ZACAS},
 
   {"zba",    &gcc_options::x_riscv_zb_subext, MASK_ZBA},
   {"zbb",    &gcc_options::x_riscv_zb_subext, MASK_ZBB},
diff --git a/gcc/config/riscv/arch-canonicalize b/gcc/config/riscv/arch-canonicalize
index a8f47a1752b..616e0ed4726 100755
--- a/gcc/config/riscv/arch-canonicalize
+++ b/gcc/config/riscv/arch-canonicalize
@@ -41,6 +41,7 @@  LONG_EXT_PREFIXES = ['z', 's', 'h', 'x']
 IMPLIED_EXT = {
   "d" : ["f", "zicsr"],
   "f" : ["zicsr"],
+  "zacas" : ["a"],
   "zdinx" : ["zfinx", "zicsr"],
   "zfinx" : ["zicsr"],
   "zhinx" : ["zhinxmin", "zfinx", "zicsr"],
diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index f332fba7031..b16b3892969 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -53,6 +53,12 @@  (define_mode_iterator SHORT [QI HI])
 ;; Iterator for HImode constant generation.
 (define_mode_iterator HISI [HI SI])
 
+;; Iterator for SImode and DImode constant generation.
+(define_mode_iterator SIDI [SI DI])
+
+;; Iterator for SImode, DImode and TImode constant generation.
+(define_mode_iterator SIDITI [SI DI TI])
+
 ;; Iterator for QImode extension patterns.
 (define_mode_iterator SUPERQI [HI SI (DI "TARGET_64BIT")])
 
@@ -113,6 +119,9 @@  (define_mode_attr ifmt [(SI "w") (DI "l")])
 ;; This attribute gives the format suffix for atomic memory operations.
 (define_mode_attr amo [(SI "w") (DI "d")])
 
+;; This attribute gives the format suffix for amocas operations.
+(define_mode_attr amocas [(SI "w") (DI "d") (TI "q")])
+
 ;; This attribute gives the upper-case mode name for one unit of a
 ;; floating-point mode.
 (define_mode_attr UNITMODE [(HF "HF") (SF "SF") (DF "DF")])
diff --git a/gcc/config/riscv/riscv-builtins.cc b/gcc/config/riscv/riscv-builtins.cc
index 5ee11ebe3bc..5074acfd69b 100644
--- a/gcc/config/riscv/riscv-builtins.cc
+++ b/gcc/config/riscv/riscv-builtins.cc
@@ -41,6 +41,10 @@  along with GCC; see the file COPYING3.  If not see
 #include "backend.h"
 #include "gimple.h"
 #include "gimple-iterator.h"
+#include "alias.h"
+#include "emit-rtl.h"
+#include "builtins.h"
+#include "explow.h"
 
 /* Macros to create an enumeration identifier for a function prototype.  */
 #define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE
@@ -49,6 +53,8 @@  along with GCC; see the file COPYING3.  If not see
 #define RISCV_FTYPE_NAME3(A, B, C, D) RISCV_##A##_FTYPE_##B##_##C##_##D
 #define RISCV_FTYPE_NAME4(A, B, C, D, E) \
   RISCV_##A##_FTYPE_##B##_##C##_##D##_##E
+#define RISCV_FTYPE_NAME5(A, B, C, D, E, F) \
+  RISCV_##A##_FTYPE_##B##_##C##_##D##_##E##_##F
 
 /* Classifies the prototype of a built-in function.  */
 enum riscv_function_type {
@@ -64,7 +70,10 @@  enum riscv_builtin_type {
   RISCV_BUILTIN_DIRECT,
 
   /* Likewise, but with return type VOID.  */
-  RISCV_BUILTIN_DIRECT_NO_TARGET
+  RISCV_BUILTIN_DIRECT_NO_TARGET,
+
+  /* for zacas.  */
+  RISCV_BUILTIN_ZACAS,
 };
 
 /* Declare an availability predicate for built-in functions.  */
@@ -101,6 +110,9 @@  AVAIL (flush32, TARGET_ZICBOM && !TARGET_64BIT)
 AVAIL (flush64, TARGET_ZICBOM && TARGET_64BIT)
 AVAIL (inval32, TARGET_ZICBOM && !TARGET_64BIT)
 AVAIL (inval64, TARGET_ZICBOM && TARGET_64BIT)
+AVAIL (zacas_amocas32, TARGET_ZACAS && !TARGET_64BIT)
+AVAIL (zacas_amocas64, TARGET_ZACAS && TARGET_64BIT)
+AVAIL (zacas_amocas128, TARGET_ZACAS && TARGET_64BIT)
 AVAIL (zero32,  TARGET_ZICBOZ && !TARGET_64BIT)
 AVAIL (zero64,  TARGET_ZICBOZ && TARGET_64BIT)
 AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT)
@@ -168,6 +180,8 @@  AVAIL (cvelw, TARGET_XCVELW && !TARGET_64BIT)
 #define RISCV_ATYPE_QI intQI_type_node
 #define RISCV_ATYPE_HI intHI_type_node
 #define RISCV_ATYPE_SI intSI_type_node
+#define RISCV_ATYPE_DI intDI_type_node
+#define RISCV_ATYPE_TI intTI_type_node
 #define RISCV_ATYPE_VOID_PTR ptr_type_node
 #define RISCV_ATYPE_INT_PTR integer_ptr_type_node
 
@@ -184,10 +198,14 @@  AVAIL (cvelw, TARGET_XCVELW && !TARGET_64BIT)
 #define RISCV_FTYPE_ATYPES4(A, B, C, D, E) \
   RISCV_ATYPE_##A, RISCV_ATYPE_##B, RISCV_ATYPE_##C, RISCV_ATYPE_##D, \
   RISCV_ATYPE_##E
+#define RISCV_FTYPE_ATYPES5(A, B, C, D, E, F) \
+  RISCV_ATYPE_##A, RISCV_ATYPE_##B, RISCV_ATYPE_##C, RISCV_ATYPE_##D, \
+  RISCV_ATYPE_##E, RISCV_ATYPE_##F
 
 static const struct riscv_builtin_description riscv_builtins[] = {
   #include "riscv-cmo.def"
   #include "riscv-scalar-crypto.def"
+  #include "riscv-zacas.def"
   #include "corev.def"
 
   DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float),
@@ -305,6 +323,32 @@  riscv_prepare_builtin_arg (struct expand_operand *op, tree exp, unsigned argno)
   create_input_operand (op, expand_normal (arg), TYPE_MODE (TREE_TYPE (arg)));
 }
 
+static rtx
+get_builtin_sync_mem (tree loc, machine_mode mode)
+{
+  rtx addr, mem;
+  int addr_space = TYPE_ADDR_SPACE (POINTER_TYPE_P (TREE_TYPE (loc))
+				    ? TREE_TYPE (TREE_TYPE (loc))
+				    : TREE_TYPE (loc));
+  scalar_int_mode addr_mode = targetm.addr_space.address_mode (addr_space);
+
+  addr = expand_expr (loc, NULL_RTX, addr_mode, EXPAND_SUM);
+  addr = convert_memory_address (addr_mode, addr);
+  mem = gen_rtx_MEM (mode, addr);
+
+  set_mem_addr_space (mem, addr_space);
+
+  mem = validize_mem (mem);
+
+  /* The alignment needs to be at least according to that of the mode.  */
+  set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
+			   get_pointer_alignment (loc)));
+  set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (mem) = 1;
+
+  return mem;
+}
+
 /* Expand instruction ICODE as part of a built-in function sequence.
    Use the first NOPS elements of OPS as the instruction's operands.
    HAS_TARGET_P is true if operand 0 is a target; it is false if the
@@ -350,6 +394,40 @@  riscv_expand_builtin_direct (enum insn_code icode, rtx target, tree exp,
   return riscv_expand_builtin_insn (icode, opno, ops, has_target_p);
 }
 
+static rtx
+riscv_expand_builtin_zacas (enum insn_code icode, tree exp)
+{
+  struct expand_operand ops[5];
+
+  int opno = 0;
+  gcc_assert (call_expr_nargs (exp)
+	      == insn_data[icode].n_generator_args);
+  for (int argno = 0; argno < call_expr_nargs (exp); argno++)
+    {
+  expand_operand *op = &ops[opno++];
+  tree arg = CALL_EXPR_ARG (exp, argno);
+  machine_mode mode = TYPE_MODE (TREE_TYPE (arg));
+  switch (argno)
+    {
+    case 0:
+      create_fixed_operand (op, get_builtin_sync_mem (arg, mode));
+      break;
+    case 3:
+    case 4:
+      {
+    enum memmodel model = memmodel_from_int (INTVAL (expand_normal (arg)));
+    create_integer_operand (op, model);
+    break;
+      }
+    default:
+      create_input_operand (op, expand_normal (arg), mode);
+      break;
+    }
+    }
+
+  return riscv_expand_builtin_insn (icode, opno, ops, false);
+}
+
 /* Implement TARGET_GIMPLE_FOLD_BUILTIN.  */
 
 bool
@@ -402,7 +480,10 @@  riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
 	  case RISCV_BUILTIN_DIRECT_NO_TARGET:
 	    return riscv_expand_builtin_direct (d->icode, target, exp, false);
-	  }
+
+    case RISCV_BUILTIN_ZACAS:
+	    return riscv_expand_builtin_zacas (d->icode, exp);
+    }
       }
     }
 
diff --git a/gcc/config/riscv/riscv-ftypes.def b/gcc/config/riscv/riscv-ftypes.def
index 3e7d5c69503..6cb8a11b1ea 100644
--- a/gcc/config/riscv/riscv-ftypes.def
+++ b/gcc/config/riscv/riscv-ftypes.def
@@ -51,5 +51,8 @@  DEF_RISCV_FTYPE (3, (USI, USI, USI, UQI))
 DEF_RISCV_FTYPE (3, (USI, USI, USI, USI))
 DEF_RISCV_FTYPE (3, (SI, SI, SI, UQI))
 DEF_RISCV_FTYPE (3, (SI, SI, SI, SI))
+DEF_RISCV_FTYPE (5, (VOID, VOID_PTR, SI, SI, SI, SI))
+DEF_RISCV_FTYPE (5, (VOID, VOID_PTR, DI, DI, SI, SI))
+DEF_RISCV_FTYPE (5, (VOID, VOID_PTR, TI, TI, SI, SI))
 DEF_RISCV_FTYPE (4, (USI, USI, USI, USI, UQI))
 DEF_RISCV_FTYPE (4, (SI, SI, SI, SI, UQI))
diff --git a/gcc/config/riscv/riscv-zacas.def b/gcc/config/riscv/riscv-zacas.def
new file mode 100644
index 00000000000..23e175cf5f7
--- /dev/null
+++ b/gcc/config/riscv/riscv-zacas.def
@@ -0,0 +1,11 @@ 
+// ZACAS
+RISCV_BUILTIN (amocas32si, "amocas32", RISCV_BUILTIN_ZACAS,
+  RISCV_VOID_FTYPE_VOID_PTR_SI_SI_SI_SI, zacas_amocas32),
+RISCV_BUILTIN (amocas64si, "amocas32", RISCV_BUILTIN_ZACAS,
+  RISCV_VOID_FTYPE_VOID_PTR_SI_SI_SI_SI, zacas_amocas64),
+RISCV_BUILTIN (amocas32di, "amocas64", RISCV_BUILTIN_ZACAS,
+  RISCV_VOID_FTYPE_VOID_PTR_DI_DI_SI_SI, zacas_amocas32),
+RISCV_BUILTIN (amocas64di, "amocas64", RISCV_BUILTIN_ZACAS,
+  RISCV_VOID_FTYPE_VOID_PTR_DI_DI_SI_SI, zacas_amocas64),
+RISCV_BUILTIN (amocas64ti, "amocas128", RISCV_BUILTIN_ZACAS,
+  RISCV_VOID_FTYPE_VOID_PTR_TI_TI_SI_SI, zacas_amocas64),
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 52c5ce30115..4c379625e4b 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -318,6 +318,7 @@  (define_attr "ext_enabled" "no,yes"
 ;; clmul    clmul, clmulh, clmulr
 ;; rotate   rotation instructions
 ;; atomic   atomic instructions
+;; zacas   zacas instructions
 ;; condmove	conditional moves
 ;; cbo    cache block instructions
 ;; crypto cryptography instructions
@@ -461,7 +462,8 @@  (define_attr "type"
    mtc,mfc,const,arith,logical,shift,slt,imul,idiv,move,fmove,fadd,fmul,
    fmadd,fdiv,fcmp,fcvt,fsqrt,multi,auipc,sfb_alu,nop,trap,ghost,bitmanip,
    rotate,clmul,min,max,minu,maxu,clz,ctz,cpop,
-   atomic,condmove,cbo,crypto,pushpop,mvpair,zicond,rdvlenb,rdvl,wrvxrm,wrfrm,
+   atomic,zacas,condmove,cbo,crypto,pushpop,mvpair,zicond,rdvlenb,rdvl,wrvxrm,
+   wrfrm,
    rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts,
    vldux,vldox,vstux,vstox,vldff,vldr,vstr,
    vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,
@@ -3817,6 +3819,7 @@  (define_insn "*large_load_address"
 (include "generic-ooo.md")
 (include "vector.md")
 (include "vector-crypto.md")
+(include "zacas.md")
 (include "zicond.md")
 (include "sfb.md")
 (include "zc.md")
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index cf207d4dcdf..648fa42d9d0 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -230,6 +230,8 @@  int riscv_za_subext
 
 Mask(ZAWRS) Var(riscv_za_subext)
 
+Mask(ZACAS) Var(riscv_za_subext)
+
 TargetVariable
 int riscv_zb_subext
 
diff --git a/gcc/config/riscv/zacas.md b/gcc/config/riscv/zacas.md
new file mode 100644
index 00000000000..527b6b72bba
--- /dev/null
+++ b/gcc/config/riscv/zacas.md
@@ -0,0 +1,52 @@ 
+(define_c_enum "unspec" [
+    ;; Zacas
+    UNSPEC_AMOCAS
+])
+
+(define_insn "riscv_amocas32<SIDI:mode>"
+  [(unspec_volatile [(match_operand:SI 0 "memory_operand" "+A")	;; memory
+		(match_operand:SIDI 1 "register_operand" "r")	;; expected
+		(match_operand:SIDI 2 "register_operand" "r")	;; desired
+		(match_operand:SI 3 "const_int_operand")	;; mod_s
+		(match_operand:SI 4 "const_int_operand")]	;; mod_f
+		UNSPEC_AMOCAS)]
+  "TARGET_ZACAS && !TARGET_64BIT"
+  {
+    enum memmodel model_success = (enum memmodel) INTVAL (operands[3]);
+    enum memmodel model_failure = (enum memmodel) INTVAL (operands[4]);
+    enum memmodel model = riscv_union_memmodels (model_success, model_failure);
+
+    if (model == MEMMODEL_SEQ_CST || model == MEMMODEL_ACQ_REL)
+      return "amocas.<SIDI:amocas>.aqrl\t%1,%2,%0";
+    else if (model == MEMMODEL_ACQUIRE)
+      return "amocas.<SIDI:amocas>.aq\t%1,%2,%0";
+    else if (model == MEMMODEL_RELEASE)
+      return "amocas.<SIDI:amocas>.rl\t%1,%2,%0";
+    else
+      return "amocas.<SIDI:amocas>\t%1,%2,%0";
+  }
+  [(set_attr "type" "zacas")])
+
+(define_insn "riscv_amocas64<SIDITI:mode>"
+  [(unspec_volatile [(match_operand:DI 0 "memory_operand" "+A")	;; memory
+		(match_operand:SIDITI 1 "register_operand" "r")	;; expected
+		(match_operand:SIDITI 2 "register_operand" "r")	;; desired
+		(match_operand:SI 3 "const_int_operand")	;; mod_s
+		(match_operand:SI 4 "const_int_operand")]	;; mod_f
+		UNSPEC_AMOCAS)]
+  "TARGET_ZACAS && TARGET_64BIT"
+  {
+    enum memmodel model_success = (enum memmodel) INTVAL (operands[3]);
+    enum memmodel model_failure = (enum memmodel) INTVAL (operands[4]);
+    enum memmodel model = riscv_union_memmodels (model_success, model_failure);
+
+    if (model == MEMMODEL_SEQ_CST || model == MEMMODEL_ACQ_REL)
+      return "amocas.<SIDITI:amocas>.aqrl\t%1,%2,%0";
+    else if (model == MEMMODEL_ACQUIRE)
+      return "amocas.<SIDITI:amocas>.aq\t%1,%2,%0";
+    else if (model == MEMMODEL_RELEASE)
+      return "amocas.<SIDITI:amocas>.rl\t%1,%2,%0";
+    else
+      return "amocas.<SIDITI:amocas>\t%1,%2,%0";
+  }
+  [(set_attr "type" "zacas")])
diff --git a/gcc/testsuite/gcc.target/riscv/zacas128.c b/gcc/testsuite/gcc.target/riscv/zacas128.c
new file mode 100644
index 00000000000..0811effc4ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zacas128.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g_zacas -mabi=lp64d" } */
+
+int var;
+
+void foo1(void *mem, __int128 old, __int128 new)
+{
+    __builtin_riscv_amocas128(0, old, new, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas128(&var, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas128((void *)0x111, old, new, __ATOMIC_RELAXED, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas128(mem, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas128(mem, old, new, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
+    __builtin_riscv_amocas128(mem, old, new, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+/* { dg-final { scan-assembler-times "amocas.q" 6 } } */
+/* { dg-final { scan-assembler-times "amocas.q.aq" 4 } } */
+/* { dg-final { scan-assembler-times "amocas.q.rl" 1 } } */
+/* { dg-final { scan-assembler-times "amocas.q.aqrl" 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zacas32.c b/gcc/testsuite/gcc.target/riscv/zacas32.c
new file mode 100644
index 00000000000..61a6ef90322
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zacas32.c
@@ -0,0 +1,34 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv32g_zacas -mabi=ilp32" } */
+
+int var;
+
+void foo1(void *mem, int old, int new)
+{
+    __builtin_riscv_amocas32(0, old, new, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas32(&var, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas32((void*)0x111, old, new, __ATOMIC_RELAXED, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas32(mem, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas32(mem, old, new, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
+    __builtin_riscv_amocas32(mem, old, new, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void foo2(void *mem, long long old, long long new)
+{
+    __builtin_riscv_amocas64(0, old, new, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas64(&var, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas64((void*)0x111, old, new, __ATOMIC_RELAXED, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas64(mem, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas64(mem, old, new, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
+    __builtin_riscv_amocas64(mem, old, new, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+/* { dg-final { scan-assembler-times "amocas.w" 6 } } */
+/* { dg-final { scan-assembler-times "amocas.w.aq" 4 } } */
+/* { dg-final { scan-assembler-times "amocas.w.rl" 1 } } */
+/* { dg-final { scan-assembler-times "amocas.w.aqrl" 3 } } */
+
+/* { dg-final { scan-assembler-times "amocas.d" 6 } } */
+/* { dg-final { scan-assembler-times "amocas.d.aq" 4 } } */
+/* { dg-final { scan-assembler-times "amocas.d.rl" 1 } } */
+/* { dg-final { scan-assembler-times "amocas.d.aqrl" 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zacas64.c b/gcc/testsuite/gcc.target/riscv/zacas64.c
new file mode 100644
index 00000000000..5f898d3a9bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zacas64.c
@@ -0,0 +1,34 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64g_zacas -mabi=lp64d" } */
+
+int var;
+
+void foo1(void *mem, int old, int new)
+{
+    __builtin_riscv_amocas32(0, old, new, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas32(&var, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas32((void*)0x111, old, new, __ATOMIC_RELAXED, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas32(mem, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas32(mem, old, new, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
+    __builtin_riscv_amocas32(mem, old, new, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+void foo2(void *mem, long long old, long long new)
+{
+    __builtin_riscv_amocas64(0, old, new, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas64(&var, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
+    __builtin_riscv_amocas64((void*)0x111, old, new, __ATOMIC_RELAXED, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas64(mem, old, new, __ATOMIC_ACQUIRE, __ATOMIC_RELEASE);
+    __builtin_riscv_amocas64(mem, old, new, __ATOMIC_ACQ_REL, __ATOMIC_ACQ_REL);
+    __builtin_riscv_amocas64(mem, old, new, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+}
+
+/* { dg-final { scan-assembler-times "amocas.w" 6 } } */
+/* { dg-final { scan-assembler-times "amocas.w.aq" 4 } } */
+/* { dg-final { scan-assembler-times "amocas.w.rl" 1 } } */
+/* { dg-final { scan-assembler-times "amocas.w.aqrl" 3 } } */
+
+/* { dg-final { scan-assembler-times "amocas.d" 6 } } */
+/* { dg-final { scan-assembler-times "amocas.d.aq" 4 } } */
+/* { dg-final { scan-assembler-times "amocas.d.rl" 1 } } */
+/* { dg-final { scan-assembler-times "amocas.d.aqrl" 3 } } */