mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-11 05:41:25 -07:00
Fix issue #51; begin work on atomic types
This commit is contained in:
+7
-13
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+19
-13
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, "")
|
||||
|
||||
|
||||
+43
-3
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user