mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add compare_exchange. Rudimentary threads (subject to change)
This commit is contained in:
committed by
Christoffer Lerno
parent
c9e40cfa37
commit
da65de2d01
@@ -822,6 +822,7 @@ typedef enum
|
||||
BUILTIN_BITREVERSE,
|
||||
BUILTIN_BSWAP,
|
||||
BUILTIN_CEIL,
|
||||
BUILTIN_COMPARE_EXCHANGE,
|
||||
BUILTIN_COPYSIGN,
|
||||
BUILTIN_COS,
|
||||
BUILTIN_CTLZ,
|
||||
|
||||
@@ -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) };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.8"
|
||||
#define COMPILER_VERSION "0.4.9"
|
||||
Reference in New Issue
Block a user