From dbddec33c8247beb5984d0c3fbcdf86a94054248 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 20 Jul 2017 23:57:56 +0100 Subject: [PATCH] Internal changes; thread.odin for windows only --- code/demo.odin | 61 ++++++++++++++++++++++++++++++++----- core/fmt.odin | 6 ++++ core/mem.odin | 10 +++--- core/thread.odin | 76 ++++++++++++++++++++++++++++++++++++++++++++++ src/check_expr.cpp | 52 ++++++++++++++++++++++++++----- src/main.cpp | 1 + src/parser.cpp | 31 +++++++++++++------ src/types.cpp | 70 +++++++++++++++++++++--------------------- 8 files changed, 245 insertions(+), 62 deletions(-) create mode 100644 core/thread.odin diff --git a/code/demo.odin b/code/demo.odin index 912168306..9f47eb1d9 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,11 +1,58 @@ -import "fmt.odin"; -import "strconv.odin"; +import ( + "fmt.odin"; + "strconv.odin"; + "thread.odin"; + win32 "sys/windows.odin"; +) -Opaque :: union{}; +prefix_table := [...]string{ + "White", + "Red", + "Orange", + "Yellow", + "Green", + "Blue", + "Octarine", + "Black", +}; -main :: proc() { - buf := make([]u8, 0, 10); - s := strconv.append_bool(buf, true); - fmt.println(s); +worker_proc :: proc(t: ^thread.Thread) -> int { + do_work :: proc(iteration: int, index: int) { + fmt.printf("`%s`: iteration %d\n", prefix_table[index], iteration); + win32.sleep(1); + } + + for iteration in 1...5 { + fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration); + do_work(iteration, t.user_index); + } + return 0; } + +main :: proc() { + threads := make([]^thread.Thread, 0, len(prefix_table)); + + for i in 0..len(prefix_table) { + if t := thread.create(worker_proc); t != nil { + t.init_context = context; + t.use_init_context = true; + t.user_index = len(threads); + append(&threads, t); + thread.start(t); + } + } + + for len(threads) > 0 { + for i := 0; i < len(threads); i += 1 { + if t := threads[i]; thread.is_done(t) { + fmt.printf("Thread %d is done\n", t.user_index); + thread.destroy(t); + + threads[i] = threads[len(threads)-1]; + pop(&threads); + i -= 1; + } + } + } +} diff --git a/core/fmt.odin b/core/fmt.odin index c8723f6c4..3d16e309c 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -7,6 +7,7 @@ import ( "raw.odin"; ) + _BUFFER_SIZE :: 1<<12; StringBuffer :: union { @@ -749,6 +750,11 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { fmt_bad_verb(fi, verb); return; } + if b.is_raw_union { + write_string(fi.buf, info.name); + write_string(fi.buf, "{}"); + return; + } write_string(fi.buf, info.name); write_byte(fi.buf, '{'); for _, i in b.names { diff --git a/core/mem.odin b/core/mem.odin index 91d70937a..ded520da7 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -73,17 +73,17 @@ AllocationHeader :: struct { allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) { header.size = size; - ptr := cast(^int)(header+1); - n := cast(^int)data - ptr; + ptr := cast(^uint)(header+1); + n := cast(^uint)data - ptr; for i in 0..n { - (ptr+i)^ = -1; + (ptr+i)^ = ~uint(0); } } allocation_header :: proc(data: rawptr) -> ^AllocationHeader { if data == nil do return nil; - p := cast(^int)data; - for (p-1)^ == -1 do p = (p-1); + p := cast(^uint)data; + for (p-1)^ == ~uint(0) do p = (p-1); return cast(^AllocationHeader)(p-1); } diff --git a/core/thread.odin b/core/thread.odin new file mode 100644 index 000000000..b6a39cd89 --- /dev/null +++ b/core/thread.odin @@ -0,0 +1,76 @@ +_ :: compile_assert(ODIN_OS == "windows"); + +import win32 "sys/windows.odin"; + +Thread :: struct { + using specific: OsSpecific; + procedure: Proc; + data: rawptr; + user_index: int; + + init_context: Context; + use_init_context: bool; + + Proc :: #type proc(^Thread) -> int; + OsSpecific :: struct { + win32_thread: win32.Handle; + win32_thread_id: u32; + } +} + + +create :: proc(procedure: Thread.Proc) -> ^Thread { + win32_thread_id: u32; + + __windows_thread_entry_proc :: proc(data: rawptr) -> i32 #cc_c { + if data == nil do return 0; + + t := cast(^Thread)data; + + c := context; + if t.use_init_context { + c = t.init_context; + } + + exit := 0; + push_context c { + exit = t.procedure(t); + } + + return cast(i32)exit; + } + + + win32_thread_proc := cast(rawptr)__windows_thread_entry_proc; + thread := new(Thread); + + win32_thread := win32.create_thread(nil, 0, win32_thread_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id); + if win32_thread == nil { + free(thread); + return nil; + } + thread.procedure = procedure; + thread.win32_thread = win32_thread; + thread.win32_thread_id = win32_thread_id; + + return thread; +} + +start :: proc(using thread: ^Thread) { + win32.resume_thread(win32_thread); +} + +is_done :: proc(using thread: ^Thread) -> bool { + res := win32.wait_for_single_object(win32_thread, 0); + return res != win32.WAIT_TIMEOUT; +} + +join :: proc(using thread: ^Thread) { + win32.wait_for_single_object(win32_thread, win32.INFINITE); + win32.close_handle(win32_thread); + win32_thread = win32.INVALID_HANDLE; +} +destroy :: proc(thread: ^Thread) { + join(thread); + free(thread); +} diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 18cd3026d..1ee250ed2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1250,12 +1250,12 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Arrayfailure && !st->is_packed && !st->is_ordered) { struct_type->failure = false; struct_type->Struct.are_offsets_set = false; - struct_type->Struct.offsets = nullptr; + gb_zero_item(&struct_type->Struct.offsets); // NOTE(bill): Reorder fields for reduced size/performance Array reordered_fields = {}; array_init_count(&reordered_fields, c->allocator, fields.count); - for_array(i, fields) { + for_array(i, reordered_fields) { reordered_fields[i] = struct_type->Struct.fields_in_src_order[i]; } @@ -1338,10 +1338,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n if (t != nullptr && t != t_invalid) { bool ok = true; t = default_type(t); - if (is_type_untyped(t)) { + if (is_type_untyped(t) || is_type_empty_union(t)) { ok = false; gbString str = type_to_string(t); - error(node, "Invalid type in union `%s`", str); + error(node, "Invalid variant type in union `%s`", str); gb_string_free(str); } else { for_array(j, variants) { @@ -1362,6 +1362,44 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n } union_type->Union.variants = variants; + + if (ut->align != nullptr) { + Operand o = {}; + check_expr(c, &o, ut->align); + if (o.mode != Addressing_Constant) { + if (o.mode != Addressing_Invalid) { + error(ut->align, "#align must be a constant"); + } + return; + } + + Type *type = base_type(o.type); + if (is_type_untyped(type) || is_type_integer(type)) { + if (o.value.kind == ExactValue_Integer) { + i64 align = i128_to_i64(o.value.value_integer); + if (align < 1 || !gb_is_power_of_two(align)) { + error(ut->align, "#align must be a power of 2, got %lld", align); + return; + } + + // NOTE(bill): Success!!! + i64 custom_align = gb_clamp(align, 1, build_context.max_align); + if (custom_align < align) { + warning(ut->align, "Custom alignment has been clamped to %lld from %lld", align, custom_align); + } + if (variants.count == 0) { + error(ut->align, "An empty union cannot have a custom alignment"); + } else { + union_type->Union.custom_align = custom_align; + } + return; + } + } + + error(ut->align, "#align must be an integer"); + return; + } + } // void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { @@ -1653,9 +1691,9 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type, return true; } - if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent) { - GB_ASSERT(s->Struct.polymorphic_params != nullptr); - GB_ASSERT(t->Struct.polymorphic_params != nullptr); + if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent && + s->Struct.polymorphic_params != nullptr && + t->Struct.polymorphic_params != nullptr) { TypeTuple *s_tuple = &s->Struct.polymorphic_params->Tuple; TypeTuple *t_tuple = &t->Struct.polymorphic_params->Tuple; diff --git a/src/main.cpp b/src/main.cpp index a6590956d..abee3e4b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #define USE_CUSTOM_BACKEND 0 +// #define NO_ARRAY_BOUNDS_CHECK #include "common.cpp" #include "timings.cpp" diff --git a/src/parser.cpp b/src/parser.cpp index 9b848ca7e..4e764d2a6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -427,8 +427,9 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ AstNode * align; \ }) \ AST_NODE_KIND(UnionType, "union type", struct { \ - Token token; \ - Array variants; \ + Token token; \ + Array variants; \ + AstNode * align; \ }) \ AST_NODE_KIND(EnumType, "enum type", struct { \ Token token; \ @@ -1460,10 +1461,11 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array fields, isize } -AstNode *ast_union_type(AstFile *f, Token token, Array variants) { +AstNode *ast_union_type(AstFile *f, Token token, Array variants, AstNode *align) { AstNode *result = make_ast_node(f, AstNode_UnionType); - result->UnionType.token = token; - result->UnionType.variants = variants; + result->UnionType.token = token; + result->UnionType.variants = variants; + result->UnionType.align = align; return result; } @@ -2496,10 +2498,23 @@ AstNode *parse_operand(AstFile *f, bool lhs) { Token open = expect_token_after(f, Token_OpenBrace, "union"); Array variants = make_ast_node_array(f); isize total_decl_name_count = 0; + AstNode *align = nullptr; CommentGroup docs = f->lead_comment; Token start_token = f->curr_token; + while (allow_token(f, Token_Hash)) { + Token tag = expect_token_after(f, Token_Ident, "#"); + if (tag.string == "align") { + if (align) { + syntax_error(tag, "Duplicate union tag `#%.*s`", LIT(tag.string)); + } + align = parse_expr(f, true); + } else { + syntax_error(tag, "Invalid union tag `#%.*s`", LIT(tag.string)); + } + } + while (f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { @@ -2514,7 +2529,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { Token close = expect_token(f, Token_CloseBrace); - return ast_union_type(f, token, variants); + return ast_union_type(f, token, variants, align); } break; case Token_enum: { @@ -3009,15 +3024,13 @@ AstNode *parse_gen_decl(AstFile *f, Token token, ParseSpecFunc *func) { if (f->curr_token.kind == Token_OpenParen) { specs = make_ast_node_array(f); open = expect_token(f, Token_OpenParen); - bool require_semicolon_after_paren = false; while (f->curr_token.kind != Token_CloseParen && f->curr_token.kind != Token_EOF) { AstNode *spec = func(f, docs, token); array_add(&specs, spec); } close = expect_token(f, Token_CloseParen); - if (require_semicolon_after_paren || - f->curr_token.pos.line == close.pos.line || + if (f->curr_token.pos.line == close.pos.line || open.pos.line == close.pos.line) { expect_semicolon(f, nullptr); } diff --git a/src/types.cpp b/src/types.cpp index e7f183e79..ab215fde4 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -74,16 +74,16 @@ struct TypeStruct { AstNode *node; Scope * scope; - i64 * offsets; // == fields.count - bool are_offsets_set; - bool are_offsets_being_processed; - bool is_packed; - bool is_ordered; - bool is_raw_union; - bool is_polymorphic; - bool is_poly_specialized; - Type * polymorphic_params; // Type_Tuple - Type * polymorphic_parent; + Array offsets; + bool are_offsets_set; + bool are_offsets_being_processed; + bool is_packed; + bool is_ordered; + bool is_raw_union; + bool is_polymorphic; + bool is_poly_specialized; + Type * polymorphic_params; // Type_Tuple + Type * polymorphic_parent; i64 custom_align; // NOTE(bill): Only used in structs at the moment Entity * names; @@ -128,8 +128,8 @@ struct TypeStruct { }) \ TYPE_KIND(Tuple, struct { \ Array variables; /* Entity_Variable */ \ - bool are_offsets_set; \ - i64 * offsets; \ + Array offsets; \ + bool are_offsets_set; \ }) \ TYPE_KIND(Proc, struct { \ AstNode *node; \ @@ -1831,6 +1831,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { if (t->Union.variants.count == 0) { return 1; } + if (t->Union.custom_align > 0) { + return gb_clamp(t->Union.custom_align, 1, build_context.max_align); + } i64 max = build_context.word_size; for_array(i, t->Union.variants) { Type *variant = t->Union.variants[i]; @@ -1848,6 +1851,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } break; case Type_Struct: { + if (t->Struct.custom_align > 0) { + return gb_clamp(t->Struct.custom_align, 1, build_context.max_align); + } if (t->Struct.is_raw_union) { i64 max = 1; for_array(i, t->Struct.fields) { @@ -1863,29 +1869,24 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } } return max; - } else { - if (t->Struct.custom_align > 0) { - return gb_clamp(t->Struct.custom_align, 1, build_context.max_align); + } else if (t->Struct.fields.count > 0) { + i64 max = 1; + if (t->Struct.is_packed) { + max = build_context.word_size; } - if (t->Struct.fields.count > 0) { - i64 max = 1; - if (t->Struct.is_packed) { - max = build_context.word_size; + for_array(i, t->Struct.fields) { + Type *field_type = t->Struct.fields[i]->type; + type_path_push(path, field_type); + if (path->failure) { + return FAILURE_ALIGNMENT; } - for_array(i, t->Struct.fields) { - Type *field_type = t->Struct.fields[i]->type; - type_path_push(path, field_type); - if (path->failure) { - return FAILURE_ALIGNMENT; - } - i64 align = type_align_of_internal(allocator, field_type, path); - type_path_pop(path); - if (max < align) { - max = align; - } + i64 align = type_align_of_internal(allocator, field_type, path); + type_path_pop(path); + if (max < align) { + max = align; } - return max; } + return max; } } break; @@ -1904,8 +1905,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size); } -i64 *type_set_offsets_of(gbAllocator allocator, Array fields, bool is_packed, bool is_raw_union) { - i64 *offsets = gb_alloc_array(allocator, i64, fields.count); +Array type_set_offsets_of(gbAllocator allocator, Array fields, bool is_packed, bool is_raw_union) { + Array offsets = {}; + array_init_count(&offsets, allocator, fields.count); i64 curr_offset = 0; if (is_raw_union) { for_array(i, fields) { @@ -2120,7 +2122,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { if (path->failure) { return FAILURE_SIZE; } - if (t->Struct.are_offsets_being_processed && t->Struct.offsets == nullptr) { + if (t->Struct.are_offsets_being_processed && t->Struct.offsets.data == nullptr) { type_path_print_illegal_cycle(path, path->path.count-1); return FAILURE_SIZE; }