@@ -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},
@@ -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"],
@@ -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")])
@@ -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);
+ }
}
}
@@ -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))
new file mode 100644
@@ -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),
@@ -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")
@@ -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
new file mode 100644
@@ -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")])
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */
new file mode 100644
@@ -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 } } */