From ff05128a8748e0336c9da3dd38a99649ce43c301 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 15 Sep 2023 18:22:37 +0200 Subject: [PATCH] Add atomic_fetch_exchange builtin. --- src/compiler/compiler_internal.h | 18 ++++++++++++++++++ src/compiler/enums.h | 1 + src/compiler/llvm_codegen_builtins.c | 4 ++++ src/compiler/sema_builtins.c | 24 ++++++++++++++++++++++++ src/compiler/symtab.c | 1 + src/version.h | 2 +- 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 063e5b0b8..dcd3b7559 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index bff79f011..96a2081a7 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -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, diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index 217a51242..cf19fa831 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -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: diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index ac958049a..0def5c4a9 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -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: diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 417770f20..7c478df95 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -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"); diff --git a/src/version.h b/src/version.h index f82b0e51a..6c85acc93 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.647" \ No newline at end of file +#define COMPILER_VERSION "0.4.648" \ No newline at end of file