Add atomic_fetch_exchange builtin.

This commit is contained in:
Christoffer Lerno
2023-09-15 18:22:37 +02:00
parent f6e18ded5b
commit ff05128a87
6 changed files with 49 additions and 1 deletions

View File

@@ -2663,6 +2663,24 @@ INLINE bool type_is_pointer_vector(Type *type)
return type->type_kind == TYPE_VECTOR && type->array.base->canonical->type_kind == TYPE_POINTER;
}
INLINE bool type_is_atomic(Type *type_flat)
{
switch (type_flat->type_kind)
{
case ALL_UNSIGNED_INTS:
case ALL_SIGNED_INTS:
case ALL_FLOATS:
case TYPE_ENUM:
case TYPE_FAULTTYPE:
case TYPE_ANYFAULT:
case TYPE_TYPEID:
break;
default:
return false;
}
return type_size(type_flat) <= type_size(type_iptr);
}
INLINE bool type_is_pointer(Type *type)
{
DECL_TYPE_KIND_REAL(kind, type);

View File

@@ -841,6 +841,7 @@ typedef enum
BUILTIN_ABS,
BUILTIN_ATOMIC_LOAD,
BUILTIN_ATOMIC_STORE,
BUILTIN_ATOMIC_FETCH_EXCHANGE,
BUILTIN_ATOMIC_FETCH_ADD,
BUILTIN_ATOMIC_FETCH_SUB,
BUILTIN_ATOMIC_FETCH_AND,

View File

@@ -192,6 +192,9 @@ INLINE void llvm_emit_atomic_fetch(GenContext *c, BuiltinFunction func, BEValue
static LLVMAtomicRMWBinOp LLVMAtomicRMWBinOpUDecWrap = LLVMAtomicRMWBinOpFMin + 2;
switch (func)
{
case BUILTIN_ATOMIC_FETCH_EXCHANGE:
op = LLVMAtomicRMWBinOpXchg;
break;
case BUILTIN_ATOMIC_FETCH_ADD:
op = is_float ? LLVMAtomicRMWBinOpFAdd : LLVMAtomicRMWBinOpAdd;
break;
@@ -815,6 +818,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
case BUILTIN_ATOMIC_FETCH_MIN:
case BUILTIN_ATOMIC_FETCH_SUB:
case BUILTIN_ATOMIC_FETCH_DEC_WRAP:
case BUILTIN_ATOMIC_FETCH_EXCHANGE:
llvm_emit_atomic_fetch(c, func, result_value, expr);
return;
case BUILTIN_ATOMIC_LOAD:

View File

@@ -779,6 +779,29 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
rtype = args[1]->type;
break;
}
case BUILTIN_ATOMIC_FETCH_EXCHANGE:
{
assert(arg_count == 5);
if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_POINTER }, 1)) return false;
Type *original = type_flatten(args[0]->type);
if (original != type_voidptr)
{
if (!cast_implicit(context, args[1], original->pointer)) return false;
}
Type *val = type_flatten(args[1]->type);
if (!type_is_atomic(val)) RETURN_SEMA_ERROR(args[1], "%s exceeds pointer size.", val);
if (!expr_is_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
if (!expr_is_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
if (!is_valid_atomicity(args[3])) return false;
switch (args[3]->const_expr.ixx.i.low)
{
case ATOMIC_UNORDERED:
RETURN_SEMA_ERROR(args[3], "'unordered' is not valid ordering.");
}
if (!sema_check_alignment_expression(context, args[4])) return false;
rtype = args[1]->type;
break;
}
case BUILTIN_ATOMIC_FETCH_ADD:
case BUILTIN_ATOMIC_FETCH_SUB:
case BUILTIN_ATOMIC_FETCH_MAX:
@@ -939,6 +962,7 @@ static inline int builtin_expected_args(BuiltinFunction func)
case BUILTIN_GATHER:
case BUILTIN_SCATTER:
return 4;
case BUILTIN_ATOMIC_FETCH_EXCHANGE:
case BUILTIN_ATOMIC_FETCH_ADD:
case BUILTIN_ATOMIC_FETCH_INC_WRAP:
case BUILTIN_ATOMIC_FETCH_NAND:

View File

@@ -200,6 +200,7 @@ void symtab_init(uint32_t capacity)
builtin_list[BUILTIN_ATOMIC_LOAD] = KW_DEF("atomic_load");
builtin_list[BUILTIN_ATOMIC_STORE] = KW_DEF("atomic_store");
builtin_list[BUILTIN_ATOMIC_FETCH_ADD] = KW_DEF("atomic_fetch_add");
builtin_list[BUILTIN_ATOMIC_FETCH_EXCHANGE] = KW_DEF("atomic_fetch_exchange");
builtin_list[BUILTIN_ATOMIC_FETCH_SUB] = KW_DEF("atomic_fetch_sub");
builtin_list[BUILTIN_ATOMIC_FETCH_MAX] = KW_DEF("atomic_fetch_max");
builtin_list[BUILTIN_ATOMIC_FETCH_MIN] = KW_DEF("atomic_fetch_min");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.647"
#define COMPILER_VERSION "0.4.648"