Add compare_exchange. Rudimentary threads (subject to change)

This commit is contained in:
Christoffer Lerno
2023-01-10 18:54:42 +01:00
committed by Christoffer Lerno
parent c9e40cfa37
commit da65de2d01
14 changed files with 814 additions and 7 deletions

View File

@@ -822,6 +822,7 @@ typedef enum
BUILTIN_BITREVERSE,
BUILTIN_BSWAP,
BUILTIN_CEIL,
BUILTIN_COMPARE_EXCHANGE,
BUILTIN_COPYSIGN,
BUILTIN_COS,
BUILTIN_CTLZ,

View File

@@ -54,6 +54,56 @@ INLINE void llvm_emit_shufflevector(GenContext *c, BEValue *result_value, Expr *
return;
}
static LLVMAtomicOrdering ordering_to_llvm(int value)
{
switch (value)
{
case 0: return LLVMAtomicOrderingNotAtomic;
case 1: return LLVMAtomicOrderingUnordered;
case 2: return LLVMAtomicOrderingMonotonic;
case 3: return LLVMAtomicOrderingAcquire;
case 4: return LLVMAtomicOrderingRelease;
case 5: return LLVMAtomicOrderingAcquireRelease;
case 6: return LLVMAtomicOrderingSequentiallyConsistent;
default: UNREACHABLE;
}
}
INLINE void llvm_emit_compare_exchange(GenContext *c, BEValue *result_value, Expr *expr)
{
Expr **args = expr->call_expr.arguments;
LLVMValueRef normal_args[3];
BEValue value;
for (int i = 0; i < 3; i++)
{
llvm_emit_expr(c, &value, args[i]);
llvm_value_rvalue(c, &value);
normal_args[i] = value.value;
}
Type *type = value.type;
bool is_volatile = args[3]->const_expr.b;
bool is_weak = args[4]->const_expr.b;
uint64_t success_ordering = args[5]->const_expr.ixx.i.low;
uint64_t failure_ordering = args[6]->const_expr.ixx.i.low;
uint64_t alignment = args[7]->const_expr.ixx.i.low;
LLVMValueRef result = LLVMBuildAtomicCmpXchg(c->builder, normal_args[0], normal_args[1], normal_args[2],
ordering_to_llvm(success_ordering), ordering_to_llvm(failure_ordering), false);
if (alignment && alignment >= type_abi_alignment(type))
{
LLVMSetAlignment(result, alignment);
}
if (is_volatile)
{
LLVMSetVolatile(result, true);
}
if (is_weak)
{
LLVMSetWeak(result, true);
}
llvm_value_set(result_value, llvm_emit_extract_value(c, result, 0), type);
}
INLINE void llvm_emit_unreachable(GenContext *c, BEValue *result_value, Expr *expr)
{
llvm_value_set(result_value, LLVMBuildUnreachable(c->builder), type_void);
@@ -525,6 +575,9 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr)
case BUILTIN_SHUFFLEVECTOR:
llvm_emit_shufflevector(c, result_value, expr);
return;
case BUILTIN_COMPARE_EXCHANGE:
llvm_emit_compare_exchange(c, result_value, expr);
return;
case BUILTIN_FRAMEADDRESS:
{
LLVMTypeRef type[2] = { llvm_get_type(c, type_voidptr), llvm_get_type(c, type_int) };

View File

@@ -235,6 +235,16 @@ static inline bool sema_expr_analyse_shufflevector(SemaContext *context, Expr *e
return true;
}
bool is_valid_atomicity(Expr* expr)
{
if (!expr_is_const_int(expr) || !int_fits(expr->const_expr.ixx, TYPE_U8) || expr->const_expr.ixx.i.low > 6)
{
SEMA_ERROR(expr, "Expected a constant integer value < 8.");
return false;
}
return true;
}
bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
{
expr->call_expr.is_builtin = true;
@@ -288,6 +298,46 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
case BUILTIN_UNREACHABLE:
rtype = type_void;
break;
case BUILTIN_COMPARE_EXCHANGE:
{
Type *comp_type = type_no_optional(args[0]->type->canonical);
if (!type_is_pointer(comp_type))
{
SEMA_ERROR(args[0], "Expected a pointer here.");
return false;
}
Type *pointee = comp_type->pointer;
for (int i = 1; i < 3; i++)
{
if (pointee != type_no_optional(args[i]->type->canonical))
{
SEMA_ERROR(args[i], "Expected an argument of type %s.", type_quoted_error_string(pointee));
return false;
}
}
for (int i = 3; i < 5; i++)
{
if (args[i]->type->canonical != type_bool || !expr_is_const(args[i]))
{
SEMA_ERROR(args[i], "Expected a constant boolean value.");
return false;
}
}
for (int i = 5; i < 7; i++)
{
if (!is_valid_atomicity(args[i])) return false;
}
Expr *align = args[7];
if (!expr_is_const_int(align)
|| !int_fits(align->const_expr.ixx, TYPE_U64)
|| (!is_power_of_two(align->const_expr.ixx.i.low) && align->const_expr.ixx.i.low))
{
SEMA_ERROR(args[7], "Expected a constant power-of-two alignment or zero.");
return false;
}
rtype = args[1]->type;
break;
}
case BUILTIN_SYSCLOCK:
rtype = type_ulong;
break;
@@ -657,6 +707,8 @@ static inline unsigned builtin_expected_args(BuiltinFunction func)
case BUILTIN_MEMSET:
case BUILTIN_MEMSET_INLINE:
return 5;
case BUILTIN_COMPARE_EXCHANGE:
return 8;
case BUILTIN_SHUFFLEVECTOR:
case BUILTIN_NONE:
UNREACHABLE

View File

@@ -548,7 +548,7 @@ INLINE Decl *sema_resolve_symbol_common(SemaContext *context, NameResolve *name_
decl = sema_resolve_path_symbol(context, name_resolve);
if (!decl && !name_resolve->maybe_decl && !name_resolve->path_found)
{
if (!name_resolve->suppress_error) return NULL;
if (name_resolve->suppress_error) return NULL;
SEMA_ERROR(name_resolve->path, "Unknown module '%.*s', did you type it right?", name_resolve->path->len, name_resolve->path->module);
return poisoned_decl;
}

View File

@@ -181,6 +181,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
{
Decl *decl = sema_resolve_symbol(context, type_info->unresolved.name, type_info->unresolved.path, type_info->span);
assert(decl);
// Already handled
if (!decl_ok(decl))
{

View File

@@ -188,6 +188,7 @@ void symtab_init(uint32_t capacity)
builtin_list[BUILTIN_BITREVERSE] = KW_DEF("bitreverse");
builtin_list[BUILTIN_BSWAP] = KW_DEF("bswap");
builtin_list[BUILTIN_CEIL] = KW_DEF("ceil");
builtin_list[BUILTIN_COMPARE_EXCHANGE] = KW_DEF(("compare_exchange"));
builtin_list[BUILTIN_COPYSIGN] = KW_DEF("copysign");
builtin_list[BUILTIN_COS] = KW_DEF("cos");
builtin_list[BUILTIN_CTLZ] = KW_DEF("clz");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.8"
#define COMPILER_VERSION "0.4.9"