From fa7d7938e1faeed446d22cdc65bb072620b8d35a Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Fri, 23 Sep 2016 19:45:45 +0100 Subject: [PATCH] Fix push_* with better defer system --- code/demo.odin | 331 ------------------------- code/old_demos/demo001.odin | 334 ++++++++++++++++++++++++++ code/old_demos/old_runtime.odin | 412 ++++++++++++++++++++++++++++++++ core/fmt.odin | 5 +- core/mem.odin | 131 ++++++++++ core/os.odin | 1 - src/codegen/ssa.cpp | 92 ++++--- src/common.cpp | 4 +- src/main.cpp | 2 +- 9 files changed, 948 insertions(+), 364 deletions(-) create mode 100644 code/old_demos/demo001.odin create mode 100644 code/old_demos/old_runtime.odin create mode 100644 core/mem.odin diff --git a/code/demo.odin b/code/demo.odin index 482733dc7..10d0009f8 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,10 +1,6 @@ #import "fmt.odin" #import "os.odin" #import "mem.odin" -// #import "http_test.odin" as ht -// #import "game.odin" as game -// #import "punity.odin" as pn - main :: proc() { @@ -17,331 +13,4 @@ main :: proc() { x^ = 1337 fmt.println(x^) } - - - // struct_padding() - // bounds_checking() - // type_introspection() - // any_type() - // crazy_introspection() - // namespaces_and_files() - // miscellany() - // ht.run() - // game.run() - // { - // init :: proc(c: ^pn.Core) {} - // step :: proc(c: ^pn.Core) {} - - // pn.run(init, step) - // } } - -struct_padding :: proc() { - { - A :: struct { - a: u8 - b: u32 - c: u16 - } - - B :: struct { - a: [7]u8 - b: [3]u16 - c: u8 - d: u16 - } - - fmt.println("size_of(A):", size_of(A)) - fmt.println("size_of(B):", size_of(B)) - - // n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html - } - { - A :: struct #ordered { - a: u8 - b: u32 - c: u16 - } - - B :: struct #ordered { - a: [7]u8 - b: [3]u16 - c: u8 - d: u16 - } - - fmt.println("size_of(A):", size_of(A)) - fmt.println("size_of(B):", size_of(B)) - - // C-style structure layout - } - { - A :: struct #packed { - a: u8 - b: u32 - c: u16 - } - - B :: struct #packed { - a: [7]u8 - b: [3]u16 - c: u8 - d: u16 - } - - fmt.println("size_of(A):", size_of(A)) - fmt.println("size_of(B):", size_of(B)) - - // Useful for explicit layout - } - - // Member sorting by priority - // Alignment desc. - // Size desc. - // source order asc. - - /* - A :: struct { - a: u8 - b: u32 - c: u16 - } - - B :: struct { - a: [7]u8 - b: [3]u16 - c: u8 - d: u16 - } - - Equivalent too - - A :: struct #ordered { - b: u32 - c: u16 - a: u8 - } - - B :: struct #ordered { - b: [3]u16 - d: u16 - a: [7]u8 - c: u8 - } - */ -} - -bounds_checking :: proc() { - x: [4]int - // x[-1] = 0; // Compile Time - // x[4] = 0; // Compile Time - - { - a, b := -1, 4; - // x[a] = 0; // Runtime Time - // x[b] = 0; // Runtime Time - } - - // Works for arrays, strings, slices, and related procedures & operations - - { - base: [10]int - s := base[2:6] - a, b := -1, 6 - - #no_bounds_check { - s[a] = 0; - // #bounds_check s[b] = 0; - } - - #no_bounds_check - if s[a] == 0 { - // Do whatever - } - - // Bounds checking can be toggled explicit - // on a per statement basis. - // _any statement_ - } -} - -type_introspection :: proc() { - { - info: ^Type_Info - x: int - - info = type_info(int) // by type - info = type_info_of_val(x) // by value - // See: runtime.odin - - match type i : info { - case Type_Info.Integer: - fmt.println("integer!") - case Type_Info.Float: - fmt.println("float!") - default: - fmt.println("potato!") - } - - // Unsafe cast - integer_info := info as ^Type_Info.Integer - } - - { - Vector2 :: struct { x, y: f32 } - Vector3 :: struct { x, y, z: f32 } - - v1: Vector2 - v2: Vector3 - v3: Vector3 - - t1 := type_info_of_val(v1) - t2 := type_info_of_val(v2) - t3 := type_info_of_val(v3) - - fmt.println() - fmt.print("Type of v1 is:\n\t", t1) - - fmt.println() - fmt.print("Type of v2 is:\n\t", t2) - - fmt.println("\n") - fmt.println("t1 == t2:", t1 == t2) - fmt.println("t2 == t3:", t2 == t3) - } -} - -any_type :: proc() { - a: any - - x: int = 123 - y: f64 = 6.28 - z: string = "Yo-Yo Ma" - // All types can be implicit cast to `any` - a = x - a = y - a = z - a = a // This the "identity" type, it doesn't get converted - - a = 123 // Literals are copied onto the stack first - - // any has two members - // data - rawptr to the data - // type_info - pointer to the type info - - fmt.println(x, y, z) - // See: fmt.odin - // For variadic any procedures in action -} - -crazy_introspection :: proc() { - { - Fruit :: enum { - APPLE, - BANANA, - GRAPE, - MELON, - PEACH, - TOMATO, - } - - s: string - s = enum_to_string(Fruit.PEACH) - fmt.println(s) - - f := Fruit.GRAPE - s = enum_to_string(f) - fmt.println(s) - - fmt.println(f) - // See: runtime.odin - } - - - { - // NOTE(bill): This is not safe code and I would not recommend this at all - // I'd recommend you use `match type` to get the subtype rather than - // casting pointers - - Fruit :: enum { - APPLE, - BANANA, - GRAPE, - MELON, - PEACH, - TOMATO, - } - - fruit_ti := type_info(Fruit) - name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts - info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts - - fmt.printf("% :: enum % {\n", name, info.base); - for i := 0; i < info.values.count; i++ { - fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]) - } - fmt.printf("}\n") - - // NOTE(bill): look at that type-safe printf! - } - - { - Vector3 :: struct {x, y, z: f32} - - a := Vector3{x = 1, y = 4, z = 9} - fmt.println(a) - b := Vector3{x = 9, y = 3, z = 1} - fmt.println(b) - - // NOTE(bill): See fmt.odin - } - - // n.b. This pretty much "solves" serialization (to strings) -} - -// #import "test.odin" - -namespaces_and_files :: proc() { - - // test.thing() - // test.format.println() - // test.println() - /* - // Non-exporting import - #import "file.odin" - #import "file.odin" as file - #import "file.odin" as . - #import "file.odin" as _ - - // Exporting import - #load "file.odin" - */ - - // Talk about scope rules and diagram -} - -miscellany :: proc() { - /* - win32 `__imp__` prefix - #dll_import - #dll_export - - Change exported name/symbol for linking - #link_name - - Custom calling conventions - #stdcall - #fastcall - - Runtime stuff - #shared_global_scope - */ - - // assert(false) - // compile_assert(false) - // panic("Panic message goes here") -} - - - - diff --git a/code/old_demos/demo001.odin b/code/old_demos/demo001.odin new file mode 100644 index 000000000..7418ad137 --- /dev/null +++ b/code/old_demos/demo001.odin @@ -0,0 +1,334 @@ +#import "fmt.odin" +#import "os.odin" +#import "mem.odin" +// #import "http_test.odin" as ht +// #import "game.odin" as game +// #import "punity.odin" as pn + +main :: proc() { + // struct_padding() + // bounds_checking() + // type_introspection() + // any_type() + // crazy_introspection() + // namespaces_and_files() + // miscellany() + // ht.run() + // game.run() + // { + // init :: proc(c: ^pn.Core) {} + // step :: proc(c: ^pn.Core) {} + + // pn.run(init, step) + // } +} + +struct_padding :: proc() { + { + A :: struct { + a: u8 + b: u32 + c: u16 + } + + B :: struct { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + fmt.println("size_of(A):", size_of(A)) + fmt.println("size_of(B):", size_of(B)) + + // n.b. http://cbloomrants.blogspot.co.uk/2012/07/07-23-12-structs-are-not-what-you-want.html + } + { + A :: struct #ordered { + a: u8 + b: u32 + c: u16 + } + + B :: struct #ordered { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + fmt.println("size_of(A):", size_of(A)) + fmt.println("size_of(B):", size_of(B)) + + // C-style structure layout + } + { + A :: struct #packed { + a: u8 + b: u32 + c: u16 + } + + B :: struct #packed { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + fmt.println("size_of(A):", size_of(A)) + fmt.println("size_of(B):", size_of(B)) + + // Useful for explicit layout + } + + // Member sorting by priority + // Alignment desc. + // Size desc. + // source order asc. + + /* + A :: struct { + a: u8 + b: u32 + c: u16 + } + + B :: struct { + a: [7]u8 + b: [3]u16 + c: u8 + d: u16 + } + + Equivalent too + + A :: struct #ordered { + b: u32 + c: u16 + a: u8 + } + + B :: struct #ordered { + b: [3]u16 + d: u16 + a: [7]u8 + c: u8 + } + */ +} + +bounds_checking :: proc() { + x: [4]int + // x[-1] = 0; // Compile Time + // x[4] = 0; // Compile Time + + { + a, b := -1, 4; + // x[a] = 0; // Runtime Time + // x[b] = 0; // Runtime Time + } + + // Works for arrays, strings, slices, and related procedures & operations + + { + base: [10]int + s := base[2:6] + a, b := -1, 6 + + #no_bounds_check { + s[a] = 0; + // #bounds_check s[b] = 0; + } + + #no_bounds_check + if s[a] == 0 { + // Do whatever + } + + // Bounds checking can be toggled explicit + // on a per statement basis. + // _any statement_ + } +} + +type_introspection :: proc() { + { + info: ^Type_Info + x: int + + info = type_info(int) // by type + info = type_info_of_val(x) // by value + // See: runtime.odin + + match type i : info { + case Type_Info.Integer: + fmt.println("integer!") + case Type_Info.Float: + fmt.println("float!") + default: + fmt.println("potato!") + } + + // Unsafe cast + integer_info := info as ^Type_Info.Integer + } + + { + Vector2 :: struct { x, y: f32 } + Vector3 :: struct { x, y, z: f32 } + + v1: Vector2 + v2: Vector3 + v3: Vector3 + + t1 := type_info_of_val(v1) + t2 := type_info_of_val(v2) + t3 := type_info_of_val(v3) + + fmt.println() + fmt.print("Type of v1 is:\n\t", t1) + + fmt.println() + fmt.print("Type of v2 is:\n\t", t2) + + fmt.println("\n") + fmt.println("t1 == t2:", t1 == t2) + fmt.println("t2 == t3:", t2 == t3) + } +} + +any_type :: proc() { + a: any + + x: int = 123 + y: f64 = 6.28 + z: string = "Yo-Yo Ma" + // All types can be implicit cast to `any` + a = x + a = y + a = z + a = a // This the "identity" type, it doesn't get converted + + a = 123 // Literals are copied onto the stack first + + // any has two members + // data - rawptr to the data + // type_info - pointer to the type info + + fmt.println(x, y, z) + // See: fmt.odin + // For variadic any procedures in action +} + +crazy_introspection :: proc() { + { + Fruit :: enum { + APPLE, + BANANA, + GRAPE, + MELON, + PEACH, + TOMATO, + } + + s: string + s = enum_to_string(Fruit.PEACH) + fmt.println(s) + + f := Fruit.GRAPE + s = enum_to_string(f) + fmt.println(s) + + fmt.println(f) + // See: runtime.odin + } + + + { + // NOTE(bill): This is not safe code and I would not recommend this at all + // I'd recommend you use `match type` to get the subtype rather than + // casting pointers + + Fruit :: enum { + APPLE, + BANANA, + GRAPE, + MELON, + PEACH, + TOMATO, + } + + fruit_ti := type_info(Fruit) + name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts + info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts + + fmt.printf("% :: enum % {\n", name, info.base); + for i := 0; i < info.values.count; i++ { + fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]) + } + fmt.printf("}\n") + + // NOTE(bill): look at that type-safe printf! + } + + { + Vector3 :: struct {x, y, z: f32} + + a := Vector3{x = 1, y = 4, z = 9} + fmt.println(a) + b := Vector3{x = 9, y = 3, z = 1} + fmt.println(b) + + // NOTE(bill): See fmt.odin + } + + // n.b. This pretty much "solves" serialization (to strings) +} + +// #import "test.odin" + +namespaces_and_files :: proc() { + + // test.thing() + // test.format.println() + // test.println() + /* + // Non-exporting import + #import "file.odin" + #import "file.odin" as file + #import "file.odin" as . + #import "file.odin" as _ + + // Exporting import + #load "file.odin" + */ + + // Talk about scope rules and diagram +} + +miscellany :: proc() { + /* + win32 `__imp__` prefix + #dll_import + #dll_export + + Change exported name/symbol for linking + #link_name + + Custom calling conventions + #stdcall + #fastcall + + Runtime stuff + #shared_global_scope + */ + + // assert(false) + // compile_assert(false) + // panic("Panic message goes here") +} + + + + diff --git a/code/old_demos/old_runtime.odin b/code/old_demos/old_runtime.odin new file mode 100644 index 000000000..af788f11d --- /dev/null +++ b/code/old_demos/old_runtime.odin @@ -0,0 +1,412 @@ +#load "win32.odin" + +assume :: proc(cond: bool) #foreign "llvm.assume" + +__debug_trap :: proc() #foreign "llvm.debugtrap" +__trap :: proc() #foreign "llvm.trap" +read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter" + +bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16" +bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32" +bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64" + +byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16" +byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32" +byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" + +fmuladd_f32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" +fmuladd_f64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" + +// TODO(bill): make custom heap procedures +heap_alloc :: proc(len: int) -> rawptr #foreign "malloc" +heap_dealloc :: proc(ptr: rawptr) #foreign "free" + +memory_zero :: proc(data: rawptr, len: int) { + d := slice_ptr(data as ^byte, len) + for i := 0; i < len; i++ { + d[i] = 0 + } +} + +memory_compare :: proc(dst, src: rawptr, len: int) -> int { + s1, s2: ^byte = dst, src + for i := 0; i < len; i++ { + a := ptr_offset(s1, i)^ + b := ptr_offset(s2, i)^ + if a != b { + return (a - b) as int + } + } + return 0 +} + +memory_copy :: proc(dst, src: rawptr, n: int) #inline { + if dst == src { + return + } + + v128b :: type {4}u32 + compile_assert(align_of(v128b) == 16) + + d, s: ^byte = dst, src + + for ; s as uint % 16 != 0 && n != 0; n-- { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + + if d as uint % 16 == 0 { + for ; n >= 16; d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 { + (d as ^v128b)^ = (s as ^v128b)^ + } + + if n&8 != 0 { + (d as ^u64)^ = (s as ^u64)^ + d, s = ptr_offset(d, 8), ptr_offset(s, 8) + } + if n&4 != 0 { + (d as ^u32)^ = (s as ^u32)^; + d, s = ptr_offset(d, 4), ptr_offset(s, 4) + } + if n&2 != 0 { + (d as ^u16)^ = (s as ^u16)^ + d, s = ptr_offset(d, 2), ptr_offset(s, 2) + } + if n&1 != 0 { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + return; + } + + // IMPORTANT NOTE(bill): Little endian only + LS :: proc(a, b: u32) -> u32 #inline { return a << b } + RS :: proc(a, b: u32) -> u32 #inline { return a >> b } + /* NOTE(bill): Big endian version + LS :: proc(a, b: u32) -> u32 #inline { return a >> b; } + RS :: proc(a, b: u32) -> u32 #inline { return a << b; } + */ + + w, x: u32 + + if d as uint % 4 == 1 { + w = (s as ^u32)^ + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + n -= 3 + + for n > 16 { + d32 := d as ^u32 + s32 := ptr_offset(s, 1) as ^u32 + x = s32^; d32^ = LS(w, 24) | RS(x, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 24) | RS(w, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 24) | RS(x, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 24) | RS(w, 8) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 + } + + } else if d as uint % 4 == 2 { + w = (s as ^u32)^ + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + d^ = s^; d = ptr_offset(d, 1); s = ptr_offset(s, 1) + n -= 2 + + for n > 17 { + d32 := d as ^u32 + s32 := ptr_offset(s, 2) as ^u32 + x = s32^; d32^ = LS(w, 16) | RS(x, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 16) | RS(w, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 16) | RS(x, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 16) | RS(w, 16) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 + } + + } else if d as uint % 4 == 3 { + w = (s as ^u32)^ + d^ = s^ + n -= 1 + + for n > 18 { + d32 := d as ^u32 + s32 := ptr_offset(s, 3) as ^u32 + x = s32^; d32^ = LS(w, 8) | RS(x, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 8) | RS(w, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + x = s32^; d32^ = LS(w, 8) | RS(x, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + w = s32^; d32^ = LS(x, 8) | RS(w, 24) + d32, s32 = ptr_offset(d32, 1), ptr_offset(s32, 1) + + d, s, n = ptr_offset(d, 16), ptr_offset(s, 16), n-16 + } + } + + if n&16 != 0 { + (d as ^v128b)^ = (s as ^v128b)^ + d, s = ptr_offset(d, 16), ptr_offset(s, 16) + } + if n&8 != 0 { + (d as ^u64)^ = (s as ^u64)^ + d, s = ptr_offset(d, 8), ptr_offset(s, 8) + } + if n&4 != 0 { + (d as ^u32)^ = (s as ^u32)^; + d, s = ptr_offset(d, 4), ptr_offset(s, 4) + } + if n&2 != 0 { + (d as ^u16)^ = (s as ^u16)^ + d, s = ptr_offset(d, 2), ptr_offset(s, 2) + } + if n&1 != 0 { + d^ = s^ + } +} + +memory_move :: proc(dst, src: rawptr, n: int) #inline { + d, s: ^byte = dst, src + if d == s { + return + } + if d >= ptr_offset(s, n) || ptr_offset(d, n) <= s { + memory_copy(d, s, n) + return + } + + // TODO(bill): Vectorize the shit out of this + if d < s { + if s as int % size_of(int) == d as int % size_of(int) { + for d as int % size_of(int) != 0 { + if n == 0 { + return + } + n-- + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + di, si := d as ^int, s as ^int + for n >= size_of(int) { + di^ = si^ + di, si = ptr_offset(di, 1), ptr_offset(si, 1) + n -= size_of(int) + } + } + for ; n > 0; n-- { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + } else { + if s as int % size_of(int) == d as int % size_of(int) { + for ptr_offset(d, n) as int % size_of(int) != 0 { + if n == 0 { + return + } + n-- + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + for n >= size_of(int) { + n -= size_of(int) + di := ptr_offset(d, n) as ^int + si := ptr_offset(s, n) as ^int + di^ = si^ + } + for ; n > 0; n-- { + d^ = s^ + d, s = ptr_offset(d, 1), ptr_offset(s, 1) + } + } + for n > 0 { + n-- + dn := ptr_offset(d, n) + sn := ptr_offset(s, n) + dn^ = sn^ + } + } +} + +__string_eq :: proc(a, b: string) -> bool { + if len(a) != len(b) { + return false + } + if ^a[0] == ^b[0] { + return true + } + return memory_compare(^a[0], ^b[0], len(a)) == 0 +} + +__string_cmp :: proc(a, b : string) -> int { + min_len := len(a) + if len(b) < min_len { + min_len = len(b) + } + for i := 0; i < min_len; i++ { + x := a[i] + y := b[i] + if x < y { + return -1 + } else if x > y { + return +1 + } + } + + if len(a) < len(b) { + return -1 + } else if len(a) > len(b) { + return +1 + } + return 0 +} + +__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) } +__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 } +__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 } +__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 } +__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 } + + + + +Allocation_Mode :: type enum { + ALLOC, + DEALLOC, + DEALLOC_ALL, + RESIZE, +} + + + +Allocator_Proc :: type proc(allocator_data: rawptr, mode: Allocation_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr + +Allocator :: type struct { + procedure: Allocator_Proc; + data: rawptr +} + + +Context :: type struct { + thread_ptr: rawptr + + user_data: rawptr + user_index: int + + allocator: Allocator +} + +#thread_local context: Context + +DEFAULT_ALIGNMENT :: 2*size_of(int) + + +__check_context :: proc() { + if context.allocator.procedure == null { + context.allocator = __default_allocator() + } + if context.thread_ptr == null { + // TODO(bill): + // context.thread_ptr = current_thread_pointer() + } +} + + +alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) } + +alloc_align :: proc(size, alignment: int) -> rawptr #inline { + __check_context() + a := context.allocator + return a.procedure(a.data, Allocation_Mode.ALLOC, size, alignment, null, 0, 0) +} + +dealloc :: proc(ptr: rawptr) #inline { + __check_context() + a := context.allocator + _ = a.procedure(a.data, Allocation_Mode.DEALLOC, 0, 0, ptr, 0, 0) +} +dealloc_all :: proc(ptr: rawptr) #inline { + __check_context() + a := context.allocator + _ = a.procedure(a.data, Allocation_Mode.DEALLOC_ALL, 0, 0, ptr, 0, 0) +} + + +resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) } +resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline { + __check_context() + a := context.allocator + return a.procedure(a.data, Allocation_Mode.RESIZE, new_size, alignment, ptr, old_size, 0) +} + + + +default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr { + if old_memory == null { + return alloc_align(new_size, alignment) + } + + if new_size == 0 { + dealloc(old_memory) + return null + } + + if new_size == old_size { + return old_memory + } + + new_memory := alloc_align(new_size, alignment) + if new_memory == null { + return null + } + + memory_copy(new_memory, old_memory, min(old_size, new_size)); + dealloc(old_memory) + return new_memory +} + + +__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocation_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr { + using Allocation_Mode + match mode { + case ALLOC: + return heap_alloc(size) + case RESIZE: + return default_resize_align(old_memory, old_size, size, alignment) + case DEALLOC: + heap_dealloc(old_memory) + case DEALLOC_ALL: + // NOTE(bill): Does nothing + } + + return null +} + +__default_allocator :: proc() -> Allocator { + return Allocator{ + __default_allocator_proc, + null, + } +} + + + + +__assert :: proc(msg: string) { + file_write(file_get_standard(File_Standard.ERROR), msg as []byte) + // TODO(bill): Which is better? + // __trap() + __debug_trap() +} diff --git a/core/fmt.odin b/core/fmt.odin index faeb98016..3d0431a2b 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -170,7 +170,10 @@ print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) { else { print_string_to_buffer(buffer, "false") } } -print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_uint_base_to_buffer(buffer, p as uint, 16, 0, #rune " ") } +print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { + print_string_to_buffer(buffer, "0x") + print_uint_base_to_buffer(buffer, p as uint, 16, size_of(int), #rune "0") +} print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) } print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) } diff --git a/core/mem.odin b/core/mem.odin new file mode 100644 index 000000000..9ae08e830 --- /dev/null +++ b/core/mem.odin @@ -0,0 +1,131 @@ +#import "fmt.odin" +#import "os.odin" + + +kilobytes :: proc(x: int) -> int #inline { return (x) * 1024 } +megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024 } +gigabytes :: proc(x: int) -> int #inline { return gigabytes(x) * 1024 } +terabytes :: proc(x: int) -> int #inline { return terabytes(x) * 1024 } + +is_power_of_two :: proc(x: int) -> bool { + if x <= 0 { + return false + } + return (x & (x-1)) == 0 +} + +align_forward :: proc(ptr: rawptr, align: int) -> rawptr { + assert(is_power_of_two(align)) + + a := align as uint + p := ptr as uint + modulo := p & (a-1) + if modulo != 0 { + p += a - modulo + } + return p as rawptr +} + + + + + +// Custom allocators + +Arena :: struct { + backing: Allocator + memory: []u8 + temp_count: int +} + +Temp_Arena_Memory :: struct { + arena: ^Arena + original_count: int +} + + + +init_arena_from_memory :: proc(using a: ^Arena, data: []byte) { + backing = Allocator{} + memory = data[:0] + temp_count = 0 +} + +init_arena_from_context :: proc(using a: ^Arena, size: int) { + backing = current_context().allocator + memory = new_slice(u8, 0, size) + temp_count = 0 +} + +init_sub_arena :: proc(sub, parent: ^Arena, size: int) { + push_allocator arena_allocator(parent) { + init_arena_from_context(sub, size) + } +} + +free_arena :: proc(using a: ^Arena) { + if backing.procedure != null { + push_allocator backing { + free(memory.data) + memory = memory[0:0:0] + } + } +} + +arena_allocator :: proc(arena: ^Arena) -> Allocator { + return Allocator{ + procedure = arena_allocator_proc, + data = arena, + } +} + +arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, flags: u64) -> rawptr { + arena := allocator_data as ^Arena + + using Allocator.Mode + match mode { + case ALLOC: + total_size := size + alignment + + if arena.memory.count + total_size > arena.memory.capacity { + fmt.fprintln(os.stderr, "Arena out of memory") + return null + } + + #no_bounds_check end := ^arena.memory[arena.memory.count] + + ptr := align_forward(end, alignment) + arena.memory.count += total_size + memory_zero(ptr, size) + return ptr + + case FREE: + // NOTE(bill): Free all at once + // Use Temp_Arena_Memory if you want to free a block + + case FREE_ALL: + arena.memory.count = 0 + + case RESIZE: + return default_resize_align(old_memory, old_size, size, alignment) + } + + return null +} + +begin_temp_arena_memory :: proc(a: ^Arena) -> Temp_Arena_Memory { + tmp: Temp_Arena_Memory + tmp.arena = a + tmp.original_count = a.memory.count + a.temp_count++ + return tmp +} + +end_temp_arena_memory :: proc(using tmp: Temp_Arena_Memory) { + assert(arena.memory.count >= original_count) + assert(arena.temp_count > 0) + arena.memory.count = original_count + arena.temp_count-- +} diff --git a/core/os.odin b/core/os.odin index 137ae7113..c26213ce4 100644 --- a/core/os.odin +++ b/core/os.odin @@ -26,7 +26,6 @@ create :: proc(name: string) -> (File, bool) { return f, success } - close :: proc(using f: ^File) { win32.CloseHandle(handle) } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index f64da951c..aeb7d0de6 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -85,15 +85,24 @@ struct ssaTargetList { ssaBlock * fallthrough_; }; -enum ssaDeferKind { - ssaDefer_Default, - ssaDefer_Return, - ssaDefer_Branch, +enum ssaDeferExitKind { + ssaDeferExit_Default, + ssaDeferExit_Return, + ssaDeferExit_Branch, }; +enum ssaDeferKind { + ssaDefer_Node, + ssaDefer_Instr, +}; + struct ssaDefer { - AstNode *stmt; + ssaDeferKind kind; isize scope_index; ssaBlock *block; + union { + AstNode *stmt; + ssaValue *instr; + }; }; struct ssaProcedure { @@ -361,6 +370,26 @@ ssaDebugInfo *ssa_alloc_debug_info(gbAllocator a, ssaDebugInfoKind kind) { return di; } + +ssaDefer ssa_add_defer_node(ssaProcedure *proc, isize scope_index, AstNode *stmt) { + ssaDefer d = {ssaDefer_Node}; + d.scope_index = scope_index; + d.block = proc->curr_block; + d.stmt = stmt; + gb_array_append(proc->defer_stmts, d); + return d; +} + + +ssaDefer ssa_add_defer_instr(ssaProcedure *proc, isize scope_index, ssaValue *instr) { + ssaDefer d = {ssaDefer_Instr}; + d.scope_index = proc->scope_index; + d.block = proc->curr_block; + d.instr = cast(ssaValue *)gb_alloc_copy(proc->module->allocator, instr, gb_size_of(ssaValue)); + gb_array_append(proc->defer_stmts, d); + return d; +} + void ssa_init_module(ssaModule *m, Checker *c) { // TODO(bill): Determine a decent size for the arena isize token_count = c->parser->total_token_count; @@ -972,17 +1001,21 @@ void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) { gb_array_append(proc->blocks, b); proc->curr_block = b; ssa_emit_comment(proc, make_string("defer")); - ssa_build_stmt(proc, d.stmt); + if (d.kind == ssaDefer_Node) { + ssa_build_stmt(proc, d.stmt); + } else if (d.kind == ssaDefer_Instr) { + ssa_emit(proc, d.instr); + } } -void ssa_emit_defer_stmts(ssaProcedure *proc, ssaDeferKind kind, ssaBlock *block) { +void ssa_emit_defer_stmts(ssaProcedure *proc, ssaDeferExitKind kind, ssaBlock *block) { isize count = gb_array_count(proc->defer_stmts); isize i = count; while (i --> 0) { ssaDefer d = proc->defer_stmts[i]; - if (kind == ssaDefer_Return) { + if (kind == ssaDeferExit_Return) { ssa_build_defer_stmt(proc, d); - } else if (kind == ssaDefer_Default) { + } else if (kind == ssaDeferExit_Default) { if (proc->scope_index == d.scope_index && d.scope_index > 1) { ssa_build_defer_stmt(proc, d); @@ -991,7 +1024,7 @@ void ssa_emit_defer_stmts(ssaProcedure *proc, ssaDeferKind kind, ssaBlock *block } else { break; } - } else if (kind == ssaDefer_Branch) { + } else if (kind == ssaDeferExit_Branch) { GB_ASSERT(block != NULL); isize lower_limit = block->scope_index+1; if (lower_limit < d.scope_index) { @@ -1009,7 +1042,7 @@ void ssa_emit_unreachable(ssaProcedure *proc) { } void ssa_emit_ret(ssaProcedure *proc, ssaValue *v) { - ssa_emit_defer_stmts(proc, ssaDefer_Return, NULL); + ssa_emit_defer_stmts(proc, ssaDeferExit_Return, NULL); ssa_emit(proc, ssa_make_instr_ret(proc, v)); } @@ -3316,7 +3349,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(bs, BlockStmt, node); proc->scope_index++; ssa_build_stmt_list(proc, bs->stmts); - ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL); proc->scope_index--; case_end; @@ -3325,8 +3358,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { isize scope_index = proc->scope_index; if (ds->stmt->kind == AstNode_BlockStmt) scope_index--; - ssaDefer d = {ds->stmt, scope_index, proc->curr_block}; - gb_array_append(proc->defer_stmts, d); + ssa_add_defer_node(proc, scope_index, ds->stmt); case_end; case_ast_node(rs, ReturnStmt, node); @@ -3377,7 +3409,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_build_stmt(proc, is->body); - ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL); proc->scope_index--; ssa_emit_jump(proc, done); @@ -3387,7 +3419,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_build_stmt(proc, is->else_stmt); - ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL); proc->scope_index--; @@ -3429,7 +3461,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_build_stmt(proc, fs->body); - ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL); proc->scope_index--; ssa_pop_target_list(proc); @@ -3524,7 +3556,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_push_target_list(proc, done, NULL, fall); ssa_build_stmt_list(proc, cc->stmts); - ssa_emit_defer_stmts(proc, ssaDefer_Default, body); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, body); ssa_pop_target_list(proc); proc->scope_index--; @@ -3541,7 +3573,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_push_target_list(proc, done, NULL, default_fall); ssa_build_stmt_list(proc, default_stmts); - ssa_emit_defer_stmts(proc, ssaDefer_Default, default_block); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, default_block); ssa_pop_target_list(proc); proc->scope_index--; } @@ -3631,7 +3663,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_push_target_list(proc, done, NULL, NULL); ssa_build_stmt_list(proc, cc->stmts); - ssa_emit_defer_stmts(proc, ssaDefer_Default, body); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, body); ssa_pop_target_list(proc); proc->scope_index--; @@ -3647,7 +3679,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { proc->scope_index++; ssa_push_target_list(proc, done, NULL, NULL); ssa_build_stmt_list(proc, default_stmts); - ssa_emit_defer_stmts(proc, ssaDefer_Default, default_block); + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, default_block); ssa_pop_target_list(proc); proc->scope_index--; } @@ -3671,7 +3703,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { // TODO(bill): Handle fallthrough scope exit correctly // if (block != NULL && bs->token.kind != Token_fallthrough) { if (block != NULL) { - ssa_emit_defer_stmts(proc, ssaDefer_Branch, block); + ssa_emit_defer_stmts(proc, ssaDeferExit_Branch, block); } switch (bs->token.kind) { case Token_break: ssa_emit_comment(proc, make_string("break")); break; @@ -3686,35 +3718,39 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(pa, PushAllocator, node); ssa_emit_comment(proc, make_string("PushAllocator")); + proc->scope_index++; + defer (proc->scope_index--); ssaValue *context_ptr = *map_get(&proc->module->members, hash_string(make_string("__context"))); ssaValue *prev_context = ssa_add_local_generated(proc, t_context); ssa_emit_store(proc, prev_context, ssa_emit_load(proc, context_ptr)); - defer (ssa_emit_store(proc, context_ptr, ssa_emit_load(proc, prev_context))); + + ssa_add_defer_instr(proc, proc->scope_index, ssa_make_instr_store(proc, context_ptr, ssa_emit_load(proc, prev_context))); ssaValue *gep = ssa_emit_struct_gep(proc, context_ptr, 1, t_allocator_ptr); ssa_emit_store(proc, gep, ssa_build_expr(proc, pa->expr)); - proc->scope_index++; ssa_build_stmt(proc, pa->body); - proc->scope_index--; + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL); case_end; case_ast_node(pa, PushContext, node); ssa_emit_comment(proc, make_string("PushContext")); + proc->scope_index++; + defer (proc->scope_index--); ssaValue *context_ptr = *map_get(&proc->module->members, hash_string(make_string("__context"))); ssaValue *prev_context = ssa_add_local_generated(proc, t_context); ssa_emit_store(proc, prev_context, ssa_emit_load(proc, context_ptr)); - defer (ssa_emit_store(proc, context_ptr, ssa_emit_load(proc, prev_context))); + + ssa_add_defer_instr(proc, proc->scope_index, ssa_make_instr_store(proc, context_ptr, ssa_emit_load(proc, prev_context))); ssa_emit_store(proc, context_ptr, ssa_build_expr(proc, pa->expr)); - proc->scope_index++; ssa_build_stmt(proc, pa->body); - proc->scope_index--; + ssa_emit_defer_stmts(proc, ssaDeferExit_Default, NULL); case_end; diff --git a/src/common.cpp b/src/common.cpp index fb4223d9d..c807e8565 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -12,7 +12,7 @@ String get_module_dir(gbAllocator a) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); defer (gb_temp_arena_memory_end(tmp)); - + wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); String16 str = {text, len}; @@ -25,7 +25,7 @@ String get_module_dir(gbAllocator a) { } path.len--; } - + return path; } diff --git a/src/main.cpp b/src/main.cpp index 60833a746..2c8c26668 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,7 +49,7 @@ i32 win32_exec_command_line_app(char *fmt, ...) { } } -#define DISPLAY_TIMING +// #define DISPLAY_TIMING #if defined(DISPLAY_TIMING) #define INIT_TIMER() f64 start_time = gb_time_now(), end_time = 0, total_time = 0 #define PRINT_TIMER(section) do { \