diff --git a/code/demo.odin b/code/demo.odin index 323754a23..7fdb7c0a6 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,18 +1,12 @@ #import "fmt.odin"; main :: proc() { - immutable program := "+ + * - /"; - accumulator := 0; - - for token in program { - match token { - case '+': accumulator += 1; - case '-': accumulator -= 1; - case '*': accumulator *= 2; - case '/': accumulator /= 2; - default: // Ignore everything else - } + x: atomic int = 123; + fmt.println(x); + arr :[dynamic]any; + append(arr, "123", 123, 3.14159265359878, true); + for a in arr { + fmt.println(a); } - - fmt.printf("The program \"%s\" calculates the value %d\n", program, accumulator); + fmt.print(arr, "\n"); } diff --git a/core/_preload.odin b/core/_preload.odin index 17ae48913..997ed7674 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -50,6 +50,7 @@ Type_Info :: union { Pointer{ elem: ^Type_Info, // nil -> rawptr }, + Atomic{elem: ^Type_Info}, Procedure{ params: ^Type_Info, // Type_Info.Tuple results: ^Type_Info, // Type_Info.Tuple diff --git a/core/atomic.odin b/core/atomic.odin deleted file mode 100644 index ec7900f0d..000000000 --- a/core/atomic.odin +++ /dev/null @@ -1,100 +0,0 @@ -// TODO(bill): Use assembly instead here to implement atomics -// Inline vs external file? - -#import win32 "sys/windows.odin" when ODIN_OS == "windows"; -_ := compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version - - -yield_thread :: proc() { win32.mm_pause(); } -mfence :: proc() { win32.ReadWriteBarrier(); } -sfence :: proc() { win32.WriteBarrier(); } -lfence :: proc() { win32.ReadBarrier(); } - - -load :: proc(a: ^i32) -> i32 { - return a^; -} -store :: proc(a: ^i32, value: i32) { - a^ = value; -} -compare_exchange :: proc(a: ^i32, expected, desired: i32) -> i32 { - return win32.InterlockedCompareExchange(a, desired, expected); -} -exchanged :: proc(a: ^i32, desired: i32) -> i32 { - return win32.InterlockedExchange(a, desired); -} -fetch_add :: proc(a: ^i32, operand: i32) -> i32 { - return win32.InterlockedExchangeAdd(a, operand); - -} -fetch_and :: proc(a: ^i32, operand: i32) -> i32 { - return win32.InterlockedAnd(a, operand); -} -fetch_or :: proc(a: ^i32, operand: i32) -> i32 { - return win32.InterlockedOr(a, operand); -} -spin_lock :: proc(a: ^i32, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default - old_value := compare_exchange(a, 1, 0); - counter := 0; - for old_value != 0 && (time_out < 0 || counter < time_out) { - counter++; - yield_thread(); - old_value = compare_exchange(a, 1, 0); - mfence(); - } - return old_value == 0; -} -spin_unlock :: proc(a: ^i32) { - store(a, 0); - mfence(); -} -try_acquire_lock :: proc(a: ^i32) -> bool { - yield_thread(); - old_value := compare_exchange(a, 1, 0); - mfence(); - return old_value == 0; -} - - -load :: proc(a: ^i64) -> i64 { - return a^; -} -store :: proc(a: ^i64, value: i64) { - a^ = value; -} -compare_exchange :: proc(a: ^i64, expected, desired: i64) -> i64 { - return win32.InterlockedCompareExchange64(a, desired, expected); -} -exchanged :: proc(a: ^i64, desired: i64) -> i64 { - return win32.InterlockedExchange64(a, desired); -} -fetch_add :: proc(a: ^i64, operand: i64) -> i64 { - return win32.InterlockedExchangeAdd64(a, operand); -} -fetch_and :: proc(a: ^i64, operand: i64) -> i64 { - return win32.InterlockedAnd64(a, operand); -} -fetch_or :: proc(a: ^i64, operand: i64) -> i64 { - return win32.InterlockedOr64(a, operand); -} -spin_lock :: proc(a: ^i64, time_out: int) -> bool { // NOTE(bill) time_out = -1 as default - old_value := compare_exchange(a, 1, 0); - counter := 0; - for old_value != 0 && (time_out < 0 || counter < time_out) { - counter++; - yield_thread(); - old_value = compare_exchange(a, 1, 0); - mfence(); - } - return old_value == 0; -} -spin_unlock :: proc(a: ^i64) { - store(a, 0); - mfence(); -} -try_acquire_lock :: proc(a: ^i64) -> bool { - yield_thread(); - old_value := compare_exchange(a, 1, 0); - mfence(); - return old_value == 0; -} diff --git a/core/fmt.odin b/core/fmt.odin index 6ec0a11bd..409e37b4f 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -212,6 +212,10 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) { } case String: write_string(buf, "string"); case Boolean: write_string(buf, "bool"); + case Atomic: + write_string(buf, "atomic "); + write_type(buf, info.elem); + case Pointer: if info.elem == nil { write_string(buf, "rawptr"); @@ -813,6 +817,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { fmt_pointer(fi, (cast(^rawptr)v.data)^, verb); } + case Atomic: + fmt_arg(fi, any{v.data, info.elem}, verb); + case Array: if verb != 'v' { fmt_bad_verb(fi, verb); diff --git a/src/check_expr.c b/src/check_expr.c index 47b5d0ab6..607a7ab5d 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1539,6 +1539,13 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ return true; case_end; + case_ast_node(at, AtomicType, e); + Type *elem = check_type(c, at->type); + i64 esz = type_size_of(c->allocator, elem); + *type = make_type_atomic(c->allocator, elem); + return true; + case_end; + case_ast_node(at, ArrayType, e); if (at->count != NULL) { Type *elem = check_type_extra(c, at->elem, NULL); @@ -6214,6 +6221,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "#type "); str = write_expr_to_string(str, ht->type); case_end; + + case_ast_node(at, AtomicType, node); + str = gb_string_appendc(str, "atomic "); + str = write_expr_to_string(str, at->type); + case_end; } return str; diff --git a/src/checker.c b/src/checker.c index 9d0d8aa2c..d61e33633 100644 --- a/src/checker.c +++ b/src/checker.c @@ -994,6 +994,10 @@ void add_type_info_type(Checker *c, Type *t) { add_type_info_type(c, bt->Pointer.elem); break; + case Type_Atomic: + add_type_info_type(c, bt->Atomic.elem); + break; + case Type_Array: add_type_info_type(c, bt->Array.elem); add_type_info_type(c, make_type_pointer(c->allocator, bt->Array.elem)); @@ -1175,7 +1179,7 @@ void init_preload(Checker *c) { - if (record->variant_count != 21) { + if (record->variant_count != 22) { compiler_error("Invalid `Type_Info` layout"); } t_type_info_named = record->variants[ 1]->type; @@ -1187,27 +1191,29 @@ void init_preload(Checker *c) { t_type_info_boolean = record->variants[ 7]->type; t_type_info_any = record->variants[ 8]->type; t_type_info_pointer = record->variants[ 9]->type; - t_type_info_procedure = record->variants[10]->type; - t_type_info_array = record->variants[11]->type; - t_type_info_dynamic_array = record->variants[12]->type; - t_type_info_slice = record->variants[13]->type; - t_type_info_vector = record->variants[14]->type; - t_type_info_tuple = record->variants[15]->type; - t_type_info_struct = record->variants[16]->type; - t_type_info_raw_union = record->variants[17]->type; - t_type_info_union = record->variants[18]->type; - t_type_info_enum = record->variants[19]->type; - t_type_info_map = record->variants[20]->type; + t_type_info_atomic = record->variants[10]->type; + t_type_info_procedure = record->variants[11]->type; + t_type_info_array = record->variants[12]->type; + t_type_info_dynamic_array = record->variants[13]->type; + t_type_info_slice = record->variants[14]->type; + t_type_info_vector = record->variants[15]->type; + t_type_info_tuple = record->variants[16]->type; + t_type_info_struct = record->variants[17]->type; + t_type_info_raw_union = record->variants[18]->type; + t_type_info_union = record->variants[19]->type; + t_type_info_enum = record->variants[20]->type; + t_type_info_map = record->variants[21]->type; t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named); t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer); t_type_info_float_ptr = make_type_pointer(c->allocator, t_type_info_float); t_type_info_complex_ptr = make_type_pointer(c->allocator, t_type_info_complex); - t_type_info_quaternion_ptr = make_type_pointer(c->allocator, t_type_info_quaternion); + t_type_info_quaternion_ptr = make_type_pointer(c->allocator, t_type_info_quaternion); t_type_info_string_ptr = make_type_pointer(c->allocator, t_type_info_string); t_type_info_boolean_ptr = make_type_pointer(c->allocator, t_type_info_boolean); t_type_info_any_ptr = make_type_pointer(c->allocator, t_type_info_any); t_type_info_pointer_ptr = make_type_pointer(c->allocator, t_type_info_pointer); + t_type_info_atomic_ptr = make_type_pointer(c->allocator, t_type_info_atomic); t_type_info_procedure_ptr = make_type_pointer(c->allocator, t_type_info_procedure); t_type_info_array_ptr = make_type_pointer(c->allocator, t_type_info_array); t_type_info_dynamic_array_ptr = make_type_pointer(c->allocator, t_type_info_dynamic_array); diff --git a/src/common.c b/src/common.c index 920e78e1c..d31596e94 100644 --- a/src/common.c +++ b/src/common.c @@ -31,6 +31,94 @@ gbAllocator scratch_allocator(void) { return gb_scratch_allocator(&scratch_memory); } +typedef struct DynamicArenaBlock DynamicArenaBlock; +typedef struct DynamicArena DynamicArena; + +struct DynamicArenaBlock { + DynamicArenaBlock *prev; + DynamicArenaBlock *next; + u8 * start; + isize count; + isize capacity; + + gbVirtualMemory vm; +}; + +struct DynamicArena { + DynamicArenaBlock *start_block; + DynamicArenaBlock *current_block; + isize block_size; +}; + +DynamicArenaBlock *add_dynamic_arena_block(DynamicArena *a) { + GB_ASSERT(a != NULL); + GB_ASSERT(a->block_size > 0); + + gbVirtualMemory vm = gb_vm_alloc(NULL, a->block_size); + DynamicArenaBlock *block = cast(DynamicArenaBlock *)vm.data; + + u8 *start = cast(u8 *)gb_align_forward(cast(u8 *)(block + 1), GB_DEFAULT_MEMORY_ALIGNMENT); + u8 *end = cast(u8 *)vm.data + vm.size; + + block->vm = vm; + block->start = start; + block->count = 0; + block->capacity = end-start; + + if (a->current_block != NULL) { + a->current_block->next = block; + block->prev = a->current_block; + } + a->current_block = block; + return block; +} + +void init_dynamic_arena(DynamicArena *a, isize block_size) { + isize size = gb_size_of(DynamicArenaBlock) + block_size; + size = cast(isize)gb_align_forward(cast(void *)cast(uintptr)size, GB_DEFAULT_MEMORY_ALIGNMENT); + a->block_size = size; + a->start_block = add_dynamic_arena_block(a); +} + +void destroy_dynamic_arena(DynamicArena *a) { + DynamicArenaBlock *b = a->current_block; + while (b != NULL) { + gbVirtualMemory vm = b->vm; + b = b->prev; + gb_vm_free(b->vm); + } +} + +GB_ALLOCATOR_PROC(dynamic_arena_allocator_proc) { + DynamicArena *a = cast(DynamicArena *)allocator_data; + void *ptr = NULL; + + switch (type) { + case gbAllocation_Alloc: { + + } break; + + case gbAllocation_Free: { + } break; + + case gbAllocation_Resize: { + } break; + + case gbAllocation_FreeAll: + GB_PANIC("free_all is not supported by this allocator"); + break; + } + + return ptr; +} + +gbAllocator dynamic_arena_allocator(DynamicArena *a) { + gbAllocator allocator = {dynamic_arena_allocator_proc, a}; + return allocator; +} + + + i64 next_pow2(i64 n) { if (n <= 0) { diff --git a/src/ir.c b/src/ir.c index e1ccc9838..6de568b91 100644 --- a/src/ir.c +++ b/src/ir.c @@ -156,7 +156,9 @@ struct irProcedure { i64 alignment; \ }) \ IR_INSTR_KIND(ZeroInit, struct { irValue *address; }) \ - IR_INSTR_KIND(Store, struct { irValue *address, *value; }) \ + IR_INSTR_KIND(Store, struct { \ + irValue *address, *value; bool atomic; \ + }) \ IR_INSTR_KIND(Load, struct { Type *type; irValue *address; }) \ IR_INSTR_KIND(PtrOffset, struct { \ irValue *address; \ @@ -822,11 +824,12 @@ irValue *ir_instr_local(irProcedure *p, Entity *e, bool zero_initialized) { } -irValue *ir_instr_store(irProcedure *p, irValue *address, irValue *value) { +irValue *ir_instr_store(irProcedure *p, irValue *address, irValue *value, bool atomic) { irValue *v = ir_alloc_instr(p, irInstr_Store); irInstr *i = &v->Instr; i->Store.address = address; i->Store.value = value; + i->Store.atomic = atomic; return v; } @@ -1429,7 +1432,7 @@ irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) { GB_ASSERT_MSG(are_types_identical(core_type(a), core_type(b)), "%s %s", type_to_string(a), type_to_string(b)); } #endif - return ir_emit(p, ir_instr_store(p, address, value)); + return ir_emit(p, ir_instr_store(p, address, value, is_type_atomic(a))); } irValue *ir_emit_load(irProcedure *p, irValue *address) { GB_ASSERT(address != NULL); @@ -2023,7 +2026,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * if (is_type_pointer(t_left) && is_type_integer(t_right)) { // ptr - int irValue *ptr = ir_emit_conv(proc, left, type); - irValue *offset = right; + irValue *offset = ir_emit_unary_arith(proc, Token_Sub, right, t_int); return ir_emit_ptr_offset(proc, ptr, offset); } else if (is_type_pointer(t_left) && is_type_pointer(t_right)) { GB_ASSERT(is_type_integer(type)); @@ -6465,7 +6468,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *prev_context = ir_add_local_generated(proc, t_context); ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr)); - ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context))); + ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context), false)); irValue *gep = ir_emit_struct_ep(proc, context_ptr, 1); ir_emit_store(proc, gep, ir_build_expr(proc, pa->expr)); @@ -6484,7 +6487,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *prev_context = ir_add_local_generated(proc, t_context); ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr)); - ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context))); + ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context), false)); ir_emit_store(proc, context_ptr, ir_build_expr(proc, pc->expr)); @@ -7366,6 +7369,12 @@ void ir_gen_tree(irGen *s) { irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); } break; + case Type_Atomic: { + ir_emit_comment(proc, str_lit("Type_Info_Atomic")); + tag = ir_emit_conv(proc, ti_ptr, t_type_info_atomic_ptr); + irValue *gep = ir_get_type_info_ptr(proc, t->Atomic.elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + } break; case Type_Array: { ir_emit_comment(proc, str_lit("Type_Info_Array")); tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr); diff --git a/src/ir_print.c b/src/ir_print.c index 2b5cc909b..08de766af 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -197,6 +197,9 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { ir_print_type(f, m, t->Pointer.elem); ir_fprintf(f, "*"); return; + case Type_Atomic: + ir_print_type(f, m, t->Atomic.elem); + return; case Type_Array: ir_fprintf(f, "[%lld x ", t->Array.count); ir_print_type(f, m, t->Array.elem); @@ -775,6 +778,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { case irInstr_Store: { Type *type = type_deref(ir_type(instr->Store.address)); ir_fprintf(f, "store "); + if (instr->Store.atomic) { + ir_fprintf(f, "atomic "); + } ir_print_type(f, m, type); ir_fprintf(f, " "); ir_print_value(f, m, instr->Store.value, type); @@ -782,17 +788,29 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_print_type(f, m, type); ir_fprintf(f, "* "); ir_print_value(f, m, instr->Store.address, type); + if (is_type_atomic(type)) { + // TODO(bill): Do ordering + ir_fprintf(f, " unordered"); + ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type)); + } ir_fprintf(f, "\n"); } break; case irInstr_Load: { Type *type = instr->Load.type; ir_fprintf(f, "%%%d = load ", value->index); + if (is_type_atomic(type)) { + ir_fprintf(f, "atomic "); + } ir_print_type(f, m, type); ir_fprintf(f, ", "); ir_print_type(f, m, type); ir_fprintf(f, "* "); ir_print_value(f, m, instr->Load.address, type); + if (is_type_atomic(type)) { + // TODO(bill): Do ordering + ir_fprintf(f, " unordered"); + } ir_fprintf(f, ", align %lld\n", type_align_of(m->allocator, type)); } break; diff --git a/src/parser.c b/src/parser.c index f46a24b45..3dab46644 100644 --- a/src/parser.c +++ b/src/parser.c @@ -351,6 +351,10 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ Token token; \ AstNode *type; \ }) \ + AST_NODE_KIND(AtomicType, "atomic type", struct { \ + Token token; \ + AstNode *type; \ + }) \ AST_NODE_KIND(ArrayType, "array type", struct { \ Token token; \ AstNode *count; \ @@ -530,6 +534,7 @@ Token ast_node_token(AstNode *node) { case AstNode_HelperType: return node->HelperType.token; case AstNode_ProcType: return node->ProcType.token; case AstNode_PointerType: return node->PointerType.token; + case AstNode_AtomicType: return node->AtomicType.token; case AstNode_ArrayType: return node->ArrayType.token; case AstNode_DynamicArrayType: return node->DynamicArrayType.token; case AstNode_VectorType: return node->VectorType.token; @@ -1046,6 +1051,13 @@ AstNode *ast_pointer_type(AstFile *f, Token token, AstNode *type) { return result; } +AstNode *ast_atomic_type(AstFile *f, Token token, AstNode *type) { + AstNode *result = make_ast_node(f, AstNode_AtomicType); + result->AtomicType.token = token; + result->AtomicType.type = type; + return result; +} + AstNode *ast_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem) { AstNode *result = make_ast_node(f, AstNode_ArrayType); result->ArrayType.token = token; @@ -1331,6 +1343,9 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) { case AstNode_PointerType: return is_semicolon_optional_for_node(f, s->PointerType.type); + case AstNode_AtomicType: + return is_semicolon_optional_for_node(f, s->AtomicType.type); + case AstNode_StructType: case AstNode_UnionType: case AstNode_RawUnionType: @@ -2673,6 +2688,12 @@ AstNode *parse_type_or_ident(AstFile *f) { return ast_pointer_type(f, token, elem); } + case Token_atomic: { + Token token = expect_token(f, Token_atomic); + AstNode *elem = parse_type(f); + return ast_atomic_type(f, token, elem); + } + case Token_OpenBracket: { Token token = expect_token(f, Token_OpenBracket); AstNode *count_expr = NULL; diff --git a/src/tokenizer.c b/src/tokenizer.c index ba491e73c..9a4ecea59 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -115,6 +115,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_yield, "yield"), \ TOKEN_KIND(Token_await, "await"), \ + TOKEN_KIND(Token_atomic, "atomic"), \ TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \ TOKEN_KIND(Token_Count, "") diff --git a/src/types.c b/src/types.c index 7ddf21f30..f98db66e9 100644 --- a/src/types.c +++ b/src/types.c @@ -110,6 +110,7 @@ typedef struct TypeRecord { #define TYPE_KINDS \ TYPE_KIND(Basic, BasicType) \ TYPE_KIND(Pointer, struct { Type *elem; }) \ + TYPE_KIND(Atomic, struct { Type *elem; }) \ TYPE_KIND(Array, struct { Type *elem; i64 count; }) \ TYPE_KIND(DynamicArray, struct { Type *elem; }) \ TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \ @@ -314,6 +315,7 @@ gb_global Type *t_type_info_any = NULL; gb_global Type *t_type_info_string = NULL; gb_global Type *t_type_info_boolean = NULL; gb_global Type *t_type_info_pointer = NULL; +gb_global Type *t_type_info_atomic = NULL; gb_global Type *t_type_info_procedure = NULL; gb_global Type *t_type_info_array = NULL; gb_global Type *t_type_info_dynamic_array = NULL; @@ -335,6 +337,7 @@ gb_global Type *t_type_info_any_ptr = NULL; gb_global Type *t_type_info_string_ptr = NULL; gb_global Type *t_type_info_boolean_ptr = NULL; gb_global Type *t_type_info_pointer_ptr = NULL; +gb_global Type *t_type_info_atomic_ptr = NULL; gb_global Type *t_type_info_procedure_ptr = NULL; gb_global Type *t_type_info_array_ptr = NULL; gb_global Type *t_type_info_dynamic_array_ptr = NULL; @@ -393,7 +396,31 @@ Type *base_enum_type(Type *t) { } Type *core_type(Type *t) { - return base_type(base_enum_type(t)); + for (;;) { + if (t == NULL) { + break; + } + + switch (t->kind) { + case Type_Named: + if (t == t->Named.base) { + return t_invalid; + } + t = t->Named.base; + continue; + case Type_Record: + if (t->Record.kind == TypeRecord_Enum) { + t = t->Record.enum_base_type; + continue; + } + break; + case Type_Atomic: + t = t->Atomic.elem; + continue; + } + break; + } + return t; } void set_base_type(Type *t, Type *base) { @@ -423,6 +450,12 @@ Type *make_type_pointer(gbAllocator a, Type *elem) { return t; } +Type *make_type_atomic(gbAllocator a, Type *elem) { + Type *t = alloc_type(a, Type_Atomic); + t->Atomic.elem = elem; + return t; +} + Type *make_type_array(gbAllocator a, Type *elem, i64 count) { Type *t = alloc_type(a, Type_Array); t->Array.elem = elem; @@ -532,8 +565,6 @@ Type *make_type_map(gbAllocator a, i64 count, Type *key, Type *value) { - - Type *type_deref(Type *t) { if (t != NULL) { Type *bt = base_type(t); @@ -682,6 +713,10 @@ bool is_type_pointer(Type *t) { } return t->kind == Type_Pointer; } +bool is_type_atomic(Type *t) { + t = base_type(t); + return t->kind == Type_Atomic; +} bool is_type_tuple(Type *t) { t = base_type(t); return t->kind == Type_Tuple; @@ -1985,6 +2020,11 @@ gbString write_type_to_string(gbString str, Type *type) { str = write_type_to_string(str, type->Pointer.elem); break; + case Type_Atomic: + str = gb_string_appendc(str, "atomic "); + str = write_type_to_string(str, type->Atomic.elem); + break; + case Type_Array: str = gb_string_appendc(str, gb_bprintf("[%d]", cast(int)type->Array.count)); str = write_type_to_string(str, type->Array.elem);