From 0cb1a578d0e36fda0a6d798dd09a32aa903a4279 Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 1 Aug 2022 08:26:26 -0700 Subject: [PATCH 01/40] fix glfw/native.odin foreign lib import --- vendor/glfw/native.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/glfw/native.odin b/vendor/glfw/native.odin index 902b30656..8ed439a94 100644 --- a/vendor/glfw/native.odin +++ b/vendor/glfw/native.odin @@ -3,7 +3,7 @@ package glfw when ODIN_OS == .Windows { import win32 "core:sys/windows" - foreign import glfw { "lib/glfw3.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib" } + foreign import glfw { "lib/glfw3_mt.lib", "system:user32.lib", "system:gdi32.lib", "system:shell32.lib" } @(default_calling_convention="c", link_prefix="glfw") foreign glfw { From d354d36a3b86268c09cdb342ead4edfc31bdd370 Mon Sep 17 00:00:00 2001 From: Ian Lilley Date: Wed, 3 Aug 2022 13:22:12 -0400 Subject: [PATCH 02/40] removed extra space from file_console_logger --- core/log/file_console_logger.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 7f0d3b07a..c1671a9da 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -95,7 +95,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string fmt.sbprintf(&buf, "[%s] ", data.ident) } //TODO(Hoej): When we have better atomics and such, make this thread-safe - fmt.fprintf(h, "%s %s\n", strings.to_string(buf), text) + fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text) } do_level_header :: proc(opts: Options, level: Level, str: ^strings.Builder) { From a6fa41e290a1e0ddb20020db9135808849543d5b Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Fri, 5 Aug 2022 18:53:29 +0200 Subject: [PATCH 03/40] marshal output options with pretty option and other config --- core/encoding/json/marshal.odin | 267 +++++++++++++++++++++++++------- 1 file changed, 215 insertions(+), 52 deletions(-) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 14df4c127..1e92bc435 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -1,41 +1,59 @@ -package json +package src -import "core:mem" import "core:math/bits" +import "core:mem" import "core:runtime" import "core:strconv" -import "core:strings" import "core:io" +import "core:strings" +import "core:encoding/json" -Marshal_Data_Error :: enum { - None, - Unsupported_Type, +// supports json specs +Marshal_Options :: struct { + // output based on spec + spec: json.Specification, + + // use line breaks & tab|spaces + pretty: bool, + + // spacing + use_spaces: bool, + spaces: int, + tabs: int, + + // state + indentation: int, + + // mjson output options + mjson_keys_use_quotes: bool, + mjson_keys_use_equal_sign: bool, + + // mjson state + mjson_skipped_first_braces_start: bool, + mjson_skipped_first_braces_end: bool, } -Marshal_Error :: union #shared_nil { - Marshal_Data_Error, - io.Error, -} - -marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { - b := strings.make_builder(allocator) +marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: json.Marshal_Error) { + b := strings.builder_make(allocator) defer if err != nil { - strings.destroy_builder(&b) + strings.builder_destroy(&b) } - marshal_to_builder(&b, v) or_return + opt := opt + marshal_to_builder(&b, v, &opt) or_return if len(b.buf) != 0 { data = b.buf[:] } + return data, nil } -marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error { - return marshal_to_writer(strings.to_writer(b), v) +marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> json.Marshal_Error { + return marshal_to_writer(strings.to_writer(b), v, opt) } -marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { +marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: json.Marshal_Error) { if v == nil { io.write_string(w, "null") or_return return @@ -166,52 +184,48 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { return .Unsupported_Type case runtime.Type_Info_Array: - io.write_byte(w, '[') or_return + opt_write_start(w, opt, '[') or_return for i in 0.. 0 { io.write_string(w, ", ") or_return } - + opt_write_iteration(w, opt, i) or_return data := uintptr(v.data) + uintptr(i*info.elem_size) - marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return + marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return } - io.write_byte(w, ']') or_return + opt_write_end(w, opt, ']') or_return case runtime.Type_Info_Enumerated_Array: index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum) - io.write_byte(w, '[') or_return + opt_write_start(w, opt, '[') or_return for i in 0.. 0 { io.write_string(w, ", ") or_return } - + opt_write_iteration(w, opt, i) or_return data := uintptr(v.data) + uintptr(i*info.elem_size) - marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return + marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return } - io.write_byte(w, ']') or_return + opt_write_end(w, opt, ']') or_return case runtime.Type_Info_Dynamic_Array: - io.write_byte(w, '[') or_return + opt_write_start(w, opt, '[') or_return array := cast(^mem.Raw_Dynamic_Array)v.data for i in 0.. 0 { io.write_string(w, ", ") or_return } - + opt_write_iteration(w, opt, i) or_return data := uintptr(array.data) + uintptr(i*info.elem_size) - marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return + marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return } - io.write_byte(w, ']') or_return + opt_write_end(w, opt, ']') or_return case runtime.Type_Info_Slice: - io.write_byte(w, '[') or_return + opt_write_start(w, opt, '[') or_return slice := cast(^mem.Raw_Slice)v.data for i in 0.. 0 { io.write_string(w, ", ") or_return } - + opt_write_iteration(w, opt, i) or_return data := uintptr(slice.data) + uintptr(i*info.elem_size) - marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return + marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return } - io.write_byte(w, ']') or_return + opt_write_end(w, opt, ']') or_return case runtime.Type_Info_Map: m := (^mem.Raw_Map)(v.data) + opt_write_start(w, opt, '{') or_return - io.write_byte(w, '{') or_return if m != nil { if info.generated_struct == nil { return .Unsupported_Type @@ -223,31 +237,62 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { entry_size := ed.elem_size for i in 0.. 0 { io.write_string(w, ", ") or_return } + opt_write_iteration(w, opt, i) or_return data := uintptr(entries.data) + uintptr(i*entry_size) key := rawptr(data + entry_type.offsets[2]) value := rawptr(data + entry_type.offsets[3]) - marshal_to_writer(w, any{key, info.key.id}) or_return - io.write_string(w, ": ") or_return - marshal_to_writer(w, any{value, info.value.id}) or_return + // check for string type + { + v := any{key, info.key.id} + ti := runtime.type_info_base(type_info_of(v.id)) + a := any{v.data, ti.id} + name: string + + #partial switch info in ti.variant { + case runtime.Type_Info_String: { + // fmt.eprintln("WAS STRING") + + switch s in a { + case string: name = s + case cstring: name = string(s) + } + + // NOTE need to ensure that map keys are valid for mjson and contain no whitespace + if opt.spec == .MJSON && !opt.mjson_keys_use_quotes { + name, _ = strings.replace_all(name, " ", "_", context.temp_allocator) + } + + opt_write_key(w, opt, name) or_return + } + + case: { + // TODO better error output? + return .Unsupported_Type + } + } + } + + marshal_to_writer(w, any{value, info.value.id}, opt) or_return } } - io.write_byte(w, '}') or_return + + opt_write_end(w, opt, '}') or_return case runtime.Type_Info_Struct: - io.write_byte(w, '{') or_return + opt_write_start(w, opt, '{') or_return + for name, i in info.names { - if i > 0 { io.write_string(w, ", ") or_return } - io.write_quoted_string(w, name) or_return - io.write_string(w, ": ") or_return + opt_write_iteration(w, opt, i) or_return + opt_write_key(w, opt, name) or_return id := info.types[i].id data := rawptr(uintptr(v.data) + info.offsets[i]) - marshal_to_writer(w, any{data, id}) or_return + marshal_to_writer(w, any{data, id}, opt) or_return } - io.write_byte(w, '}') or_return + + opt_write_end(w, opt, '}') or_return case runtime.Type_Info_Union: tag_ptr := uintptr(v.data) + info.tag_offset @@ -270,11 +315,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { io.write_string(w, "null") or_return } else { id := info.variants[tag-1].id - return marshal_to_writer(w, any{v.data, id}) + return marshal_to_writer(w, any{v.data, id}, opt) } case runtime.Type_Info_Enum: - return marshal_to_writer(w, any{v.data, info.base.id}) + return marshal_to_writer(w, any{v.data, info.base.id}, opt) case runtime.Type_Info_Bit_Set: is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { @@ -330,3 +375,121 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { return } + +// write key as quoted string or with optional quotes in mjson +opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) { + switch opt.spec { + case .JSON, .JSON5: { + io.write_quoted_string(w, name) or_return + io.write_string(w, ": ") or_return + } + + case .MJSON: { + if opt.mjson_keys_use_quotes { + io.write_quoted_string(w, name) or_return + } else { + io.write_string(w, name) or_return + } + + if opt.mjson_keys_use_equal_sign { + io.write_string(w, " = ") or_return + } else { + io.write_string(w, ": ") or_return + } + } + } + + return +} + +// insert start byte and increase indentation on pretty +opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) { + // skip mjson starting braces + if opt.spec == .MJSON && !opt.mjson_skipped_first_braces_start { + opt.mjson_skipped_first_braces_start = true + return + } + + io.write_byte(w, c) or_return + opt.indentation += 1 + + if opt.pretty { + io.write_byte(w, '\n') or_return + } + + return +} + +// insert comma seperation and write indentations +opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) { + switch opt.spec { + case .JSON, .JSON5: { + if iteration > 0 { + io.write_string(w, ", ") or_return + + if opt.pretty { + io.write_byte(w, '\n') or_return + } + } + + opt_write_indentation(w, opt) or_return + } + + case .MJSON: { + if iteration > 0 { + // on pretty no commas necessary + if opt.pretty { + io.write_byte(w, '\n') or_return + } else { + // NOTE comma seperation necessary for non pretty output! + io.write_string(w, ", ") or_return + } + } + + opt_write_indentation(w, opt) or_return + } + } + + return +} + +// decrease indent, write spacing and insert end byte +opt_write_end :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) { + if opt.spec == .MJSON && opt.mjson_skipped_first_braces_start && !opt.mjson_skipped_first_braces_end { + if opt.indentation == 0 { + opt.mjson_skipped_first_braces_end = true + return + } + } + + opt.indentation -= 1 + + if opt.pretty { + io.write_byte(w, '\n') or_return + opt_write_indentation(w, opt) or_return + } + + io.write_byte(w, c) or_return + return +} + +// writes current indentation level based on options +opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.Error) { + if !opt.pretty { + return + } + + // TODO optimize? + if opt.use_spaces { + // NOTE maybe max(1, opt.spaces) + for _ in 0.. Date: Fri, 5 Aug 2022 18:56:14 +0200 Subject: [PATCH 04/40] ...bad paste --- core/encoding/json/marshal.odin | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 1e92bc435..095d290f5 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -1,17 +1,26 @@ -package src +package json -import "core:math/bits" import "core:mem" +import "core:math/bits" import "core:runtime" import "core:strconv" -import "core:io" import "core:strings" -import "core:encoding/json" +import "core:io" + +Marshal_Data_Error :: enum { + None, + Unsupported_Type, +} + +Marshal_Error :: union #shared_nil { + Marshal_Data_Error, + io.Error, +} // supports json specs Marshal_Options :: struct { // output based on spec - spec: json.Specification, + spec: Specification, // use line breaks & tab|spaces pretty: bool, @@ -33,7 +42,7 @@ Marshal_Options :: struct { mjson_skipped_first_braces_end: bool, } -marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: json.Marshal_Error) { +marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { b := strings.builder_make(allocator) defer if err != nil { strings.builder_destroy(&b) @@ -49,11 +58,11 @@ marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocato return data, nil } -marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> json.Marshal_Error { +marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> Marshal_Error { return marshal_to_writer(strings.to_writer(b), v, opt) } -marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: json.Marshal_Error) { +marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) { if v == nil { io.write_string(w, "null") or_return return From 425dec8bb8cc4fe2cf25a008de199d3084ecb510 Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Mon, 8 Aug 2022 18:28:28 +0200 Subject: [PATCH 05/40] add uint as hex option --- core/encoding/json/marshal.odin | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 095d290f5..2a92cec28 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -17,7 +17,7 @@ Marshal_Error :: union #shared_nil { io.Error, } -// supports json specs +// NOTE careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results Marshal_Options :: struct { // output based on spec spec: Specification, @@ -28,11 +28,13 @@ Marshal_Options :: struct { // spacing use_spaces: bool, spaces: int, - tabs: int, // state indentation: int, + // option to output uint in JSON5 & MJSON + write_uint_as_hex: bool, + // mjson output options mjson_keys_use_quotes: bool, mjson_keys_use_equal_sign: bool, @@ -109,7 +111,23 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case u128be: u = u128(i) } - s := strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + s: string + + // allow uints to be printed as hex + if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) { + switch i in a { + case u8, u16, u32, u64, u128: { + s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) + } + + case: { + s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + } + } + } else { + s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + } + io.write_string(w, s) or_return @@ -261,18 +279,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: #partial switch info in ti.variant { case runtime.Type_Info_String: { - // fmt.eprintln("WAS STRING") - switch s in a { case string: name = s case cstring: name = string(s) } - // NOTE need to ensure that map keys are valid for mjson and contain no whitespace - if opt.spec == .MJSON && !opt.mjson_keys_use_quotes { - name, _ = strings.replace_all(name, " ", "_", context.temp_allocator) - } - opt_write_key(w, opt, name) or_return } From cfc372387923372c011ebaa97cd80461d68e2089 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 21:12:31 +0100 Subject: [PATCH 06/40] Remove other uses of LLVMGetElementType on pointer types --- src/llvm_backend_general.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 58de9d36a..af7673a69 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -854,7 +854,9 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { if (LLVMIsNull(value.value)) { LLVMTypeRef src_t = llvm_addr_type(p->module, ptr); if (is_type_proc(a)) { - LLVMBuildStore(p->builder, LLVMConstNull(llvm_get_element_type(LLVMTypeOf(ptr.value))), ptr.value); + LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); + LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); + LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, "")); } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { @@ -889,9 +891,11 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // stored as regular pointer with no procedure information - LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); - LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, ""); - LLVMBuildStore(p->builder, v, ptr.value); + LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); + LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); + LLVMBuildStore(p->builder, + LLVMBuildPointerCast(p->builder, value.value, rawptr_type, ""), + LLVMBuildPointerCast(p->builder, ptr.value, rawptr_ptr_type, "")); } else { Type *ca = core_type(a); if (ca->kind == Type_Basic || ca->kind == Type_Proc) { From 065526037876143c91dbbfaeb44666a474ff93c0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 21:13:52 +0100 Subject: [PATCH 07/40] Comment out a bit of code in `lb_is_const_or_global` --- src/llvm_backend_const.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 8d910cf24..954778bb6 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -10,11 +10,12 @@ bool lb_is_const(lbValue value) { return false; } -// TODO remove use of LLVMGetElementType bool lb_is_const_or_global(lbValue value) { if (lb_is_const(value)) { return true; } + // TODO remove use of LLVMGetElementType + #if 0 if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) { LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value)); if (!lb_is_type_kind(t, LLVMPointerTypeKind)) { @@ -23,6 +24,7 @@ bool lb_is_const_or_global(lbValue value) { LLVMTypeRef elem = LLVMGetElementType(t); return lb_is_type_kind(elem, LLVMFunctionTypeKind); } + #endif return false; } From 812823cad83d76987ee6b924b70427fbffe34f02 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 21:17:32 +0100 Subject: [PATCH 08/40] Wrap all `LLVMGetElementType` uses --- src/llvm_abi.cpp | 16 ++++++++-------- src/llvm_backend.hpp | 3 +++ src/llvm_backend_general.cpp | 11 +++++++++++ src/llvm_backend_type.cpp | 5 ----- src/llvm_backend_utility.cpp | 8 ++++---- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 2ff55c79b..2ee8dc673 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -223,7 +223,7 @@ i64 lb_sizeof(LLVMTypeRef type) { break; case LLVMArrayTypeKind: { - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(type); i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetArrayLength(type); i64 size = count * elem_size; @@ -235,7 +235,7 @@ i64 lb_sizeof(LLVMTypeRef type) { return 8; case LLVMVectorTypeKind: { - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetVectorSize(type); i64 size = count * elem_size; @@ -283,14 +283,14 @@ i64 lb_alignof(LLVMTypeRef type) { } break; case LLVMArrayTypeKind: - return lb_alignof(LLVMGetElementType(type)); + return lb_alignof(OdinLLVMGetArrayElementType(type)); case LLVMX86_MMXTypeKind: return 8; case LLVMVectorTypeKind: { // TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetVectorSize(type); i64 size = count * elem_size; @@ -793,7 +793,7 @@ namespace lbAbiAmd64SysV { case LLVMArrayTypeKind: { i64 len = LLVMGetArrayLength(t); - LLVMTypeRef elem = LLVMGetElementType(t); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(t); i64 elem_sz = lb_sizeof(elem); for (i64 i = 0; i < len; i++) { classify_with(elem, cls, ix, off + i*elem_sz); @@ -803,7 +803,7 @@ namespace lbAbiAmd64SysV { case LLVMVectorTypeKind: { i64 len = LLVMGetVectorSize(t); - LLVMTypeRef elem = LLVMGetElementType(t); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(t); i64 elem_sz = lb_sizeof(elem); LLVMTypeKind elem_kind = LLVMGetTypeKind(elem); RegClass reg = RegClass_NoClass; @@ -913,7 +913,7 @@ namespace lbAbiArm64 { if (len == 0) { return false; } - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(type); LLVMTypeRef base_type = nullptr; unsigned member_count = 0; if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) { @@ -1129,7 +1129,7 @@ namespace lbAbiWasm { } if (sz <= MAX_DIRECT_STRUCT_SIZE) { if (kind == LLVMArrayTypeKind) { - if (is_basic_register_type(LLVMGetElementType(type))) { + if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) { return true; } } else if (kind == LLVMStructTypeKind) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 149f1e711..4a056e915 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -507,6 +507,9 @@ i64 lb_max_zero_init_size(void) { return cast(i64)(4*build_context.word_size); } +LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type); +LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type); + #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" #define LB_TYPE_INFO_DATA_NAME "__$type_info_data" diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index af7673a69..7138ac191 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2293,6 +2293,17 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals } +gb_inline LLVMTypeRef OdinLLVMGetInternalElementType(LLVMTypeRef type) { + return LLVMGetElementType(type); +} +LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type) { + GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind)); + return OdinLLVMGetInternalElementType(type); +} +LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type) { + GB_ASSERT(lb_is_type_kind(type, LLVMVectorTypeKind)); + return OdinLLVMGetInternalElementType(type); +} LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index ba4135901..3d20b3d72 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -130,11 +130,6 @@ lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { return res; } -// NOTE: The use of this method needs to be eliminated for pointers. -LLVMTypeRef llvm_get_element_type(LLVMTypeRef type) { - return LLVMGetElementType(type); -} - LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) { return lb_type_internal_for_procedures_raw(m, type); } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 665ba1553..3485c8436 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1651,7 +1651,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) { LLVMTypeRef type = LLVMTypeOf(value); GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind); - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); unsigned len = LLVMGetVectorSize(type); if (len == 0) { return LLVMConstNull(type); @@ -1727,7 +1727,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) { LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b)); - LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a)); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a)); if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) { return LLVMBuildAdd(p->builder, a, b, ""); @@ -1738,7 +1738,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b)); - LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a)); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a)); if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) { return LLVMBuildMul(p->builder, a, b, ""); @@ -1758,7 +1758,7 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, GB_ASSERT(t == LLVMTypeOf(c)); GB_ASSERT(LLVMGetTypeKind(t) == LLVMVectorTypeKind); - LLVMTypeRef elem = LLVMGetElementType(t); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(t); bool is_possible = false; From 84f9fb706b90d97e7e52819af8388f64e38970e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Aug 2022 11:36:25 +0100 Subject: [PATCH 09/40] General clean up of LLVM*GEP2 code --- src/llvm_backend.hpp | 5 ++- src/llvm_backend_general.cpp | 39 ++++++++++++++++++ src/llvm_backend_type.cpp | 78 ++++++++++++------------------------ src/llvm_backend_utility.cpp | 39 ++++++++---------- 4 files changed, 84 insertions(+), 77 deletions(-) diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 4a056e915..79f0f37e7 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -357,8 +357,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr); lbAddr lb_build_addr(lbProcedure *p, Ast *expr); void lb_build_stmt_list(lbProcedure *p, Array const &stmts); -lbValue lb_build_gep(lbProcedure *p, lbValue const &value, i32 index) ; - +lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index); +lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index); +lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index); lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index); lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index); lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7138ac191..082163b2f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -212,6 +212,45 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) { } +// This emits a GEP at 0, index +lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) { + GB_ASSERT(is_type_pointer(value.type)); + Type *type = type_deref(value.type); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(p->module, t_int), 0, false), + LLVMConstInt(lb_type(p->module, t_int), cast(unsigned long long)index, false), + }; + LLVMTypeRef llvm_type = lb_type(p->module, type); + lbValue res = {}; + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + if (LLVMIsConstant(value.value)) { + res.value = LLVMConstGEP2(llvm_type, value.value, indices, gb_count_of(indices)); + } else { + res.value = LLVMBuildGEP2(p->builder, llvm_type, value.value, indices, gb_count_of(indices), ""); + } + return res; +} +// This emits a GEP at 0, index +lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) { + GB_ASSERT(is_type_pointer(value.type)); + GB_ASSERT(LLVMIsConstant(value.value)); + Type *type = type_deref(value.type); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(m, t_int), 0, false), + LLVMConstInt(lb_type(m, t_int), cast(unsigned long long)index, false), + }; + lbValue res = {}; + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + res.value = LLVMConstGEP2(lb_type(m, type), value.value, indices, gb_count_of(indices)); + return res; +} + + + LLVMValueRef llvm_zero(lbModule *m) { return LLVMConstInt(lb_type(m, t_int), 0, false); } diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 3d20b3d72..d424fa5b2 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -98,36 +98,8 @@ lbValue lb_type_info(lbModule *m, Type *type) { isize index = lb_type_info_index(m->info, type); GB_ASSERT(index >= 0); - LLVMTypeRef it = lb_type(m, t_int); - LLVMValueRef indices[2] = { - LLVMConstInt(it, 0, false), - LLVMConstInt(it, index, true), - }; - - lbValue value = {}; lbValue data = lb_global_type_info_data_ptr(m); - value.value = LLVMConstGEP2(lb_type(m, type_deref(data.type)), data.value, indices, gb_count_of(indices)); - value.type = t_type_info_ptr; - return value; -} - -lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { - GB_ASSERT(!build_context.disallow_rtti); - - i32 index = cast(i32)lb_type_info_index(m->info, type); - GB_ASSERT(index >= 0); - // gb_printf_err("%d %s\n", index, type_to_string(type)); - - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(m, t_int), 0, false), - LLVMConstInt(lb_type(m, t_int), index, false), - }; - - lbValue res = {}; - res.type = t_type_info_ptr; - lbValue data = lb_global_type_info_data_ptr(m); - res.value = LLVMConstGEP2(lb_type(m, type_deref(data.type)), data.value, indices, cast(unsigned)gb_count_of(indices)); - return res; + return lb_emit_array_epi(m, data, index); } LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) { @@ -267,7 +239,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef vals[4] = { lb_const_string(p->module, t->Named.type_name->token.string).value, - lb_get_type_info_ptr(m, t->Named.base).value, + lb_type_info(m, t->Named.base).value, pkg_name, loc.value }; @@ -426,7 +398,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da case Type_Pointer: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem); + lbValue gep = lb_type_info(m, t->Pointer.elem); LLVMValueRef vals[1] = { gep.value, @@ -440,7 +412,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } case Type_MultiPointer: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem); + lbValue gep = lb_type_info(m, t->MultiPointer.elem); LLVMValueRef vals[1] = { gep.value, @@ -454,7 +426,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } case Type_SoaPointer: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->SoaPointer.elem); + lbValue gep = lb_type_info(m, t->SoaPointer.elem); LLVMValueRef vals[1] = { gep.value, @@ -471,7 +443,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da i64 ez = type_size_of(t->Array.elem); LLVMValueRef vals[3] = { - lb_get_type_info_ptr(m, t->Array.elem).value, + lb_type_info(m, t->Array.elem).value, lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, t->Array.count).value, }; @@ -486,8 +458,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); LLVMValueRef vals[7] = { - lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value, - lb_get_type_info_ptr(m, t->EnumeratedArray.index).value, + lb_type_info(m, t->EnumeratedArray.elem).value, + lb_type_info(m, t->EnumeratedArray.index).value, lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, lb_const_int(m, t_int, t->EnumeratedArray.count).value, @@ -518,7 +490,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->DynamicArray.elem).value, + lb_type_info(m, t->DynamicArray.elem).value, lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value, }; @@ -532,7 +504,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->Slice.elem).value, + lb_type_info(m, t->Slice.elem).value, lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value, }; @@ -548,10 +520,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr)); LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr)); if (t->Proc.params != nullptr) { - params = lb_get_type_info_ptr(m, t->Proc.params).value; + params = lb_type_info(m, t->Proc.params).value; } if (t->Proc.results != nullptr) { - results = lb_get_type_info_ptr(m, t->Proc.results).value; + results = lb_type_info(m, t->Proc.results).value; } LLVMValueRef vals[4] = { @@ -670,7 +642,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // NOTE(bill): Zeroth is nil so ignore it for (isize variant_index = 0; variant_index < variant_count; variant_index++) { Type *vt = t->Union.variants[variant_index]; - lbValue tip = lb_get_type_info_ptr(m, vt); + lbValue tip = lb_type_info(m, vt); lbValue index = lb_const_int(m, t_int, variant_index); lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); @@ -758,7 +730,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da for (isize source_index = 0; source_index < count; source_index++) { // TODO(bill): Order fields in source order not layout order Entity *f = t->Struct.fields[source_index]; - lbValue tip = lb_get_type_info_ptr(m, f->type); + lbValue tip = lb_type_info(m, f->type); i64 foffset = 0; if (!t->Struct.is_raw_union) { GB_ASSERT(t->Struct.offsets != nullptr); @@ -815,11 +787,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); init_map_internal_types(t); - lbValue gst = lb_get_type_info_ptr(m, t->Map.generated_struct_type); + lbValue gst = lb_type_info(m, t->Map.generated_struct_type); LLVMValueRef vals[5] = { - lb_get_type_info_ptr(m, t->Map.key).value, - lb_get_type_info_ptr(m, t->Map.value).value, + lb_type_info(m, t->Map.key).value, + lb_type_info(m, t->Map.value).value, gst.value, lb_get_equal_proc_for_type(m, t->Map.key).value, lb_get_hasher_proc_for_type(m, t->Map.key).value @@ -840,13 +812,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef vals[4] = { - lb_get_type_info_ptr(m, t->BitSet.elem).value, + lb_type_info(m, t->BitSet.elem).value, LLVMConstNull(lb_type(m, t_type_info_ptr)), lb_const_int(m, t_i64, t->BitSet.lower).value, lb_const_int(m, t_i64, t->BitSet.upper).value, }; if (t->BitSet.underlying != nullptr) { - vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value; + vals[1] =lb_type_info(m, t->BitSet.underlying).value; } lbValue res = {}; @@ -862,7 +834,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef vals[3] = {}; - vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value; + vals[0] = lb_type_info(m, t->SimdVector.elem).value; vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value; vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value; @@ -877,8 +849,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value, - lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value, + lb_type_info(m, t->RelativePointer.pointer_type).value, + lb_type_info(m, t->RelativePointer.base_integer).value, }; lbValue res = {}; @@ -891,8 +863,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value, - lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value, + lb_type_info(m, t->RelativeSlice.slice_type).value, + lb_type_info(m, t->RelativeSlice.base_integer).value, }; lbValue res = {}; @@ -907,7 +879,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da i64 ez = type_size_of(t->Matrix.elem); LLVMValueRef vals[5] = { - lb_get_type_info_ptr(m, t->Matrix.elem).value, + lb_type_info(m, t->Matrix.elem).value, lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value, lb_const_int(m, t_int, t->Matrix.row_count).value, diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 3485c8436..ce7b43321 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1002,6 +1002,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { index = lb_convert_struct_index(p->module, t, index); if (lb_is_const(s)) { + // NOTE(bill): this cannot be replaced with lb_emit_epi lbModule *m = p->module; lbValue res = {}; LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)}; @@ -1252,27 +1253,13 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) { Type *ptr = base_array_type(st); lbValue res = {}; - res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, 2, ""); - res.type = alloc_type_pointer(ptr); - return res; -} -// This emits a GEP at 0, index -static inline lbValue lb_emit_gep(lbProcedure *p, Type *type, LLVMValueRef value, isize index) -{ - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(p->module, t_int), 0, false), - LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false), - }; - LLVMTypeRef llvm_type = lb_type(p->module, type); - lbValue res = {}; - Type *ptr = base_array_type(type); - res.type = alloc_type_pointer(ptr); - if (LLVMIsConstant(value)) { - res.value = LLVMConstGEP2(llvm_type, value, indices, gb_count_of(indices)); + if (LLVMIsConstant(s.value) && LLVMIsConstant(index.value)) { + res.value = LLVMConstGEP2(lb_type(p->module, st), s.value, indices, gb_count_of(indices)); } else { - res.value = LLVMBuildGEP2(p->builder, llvm_type, value, indices, gb_count_of(indices), ""); + res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, gb_count_of(indices), ""); } + res.type = alloc_type_pointer(ptr); return res; } @@ -1282,7 +1269,15 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { Type *st = base_type(type_deref(t)); GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); GB_ASSERT(0 <= index); - return lb_emit_gep(p, st, s.value, index); + return lb_emit_epi(p, s, index); +} +lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) { + Type *t = s.type; + GB_ASSERT(is_type_pointer(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); + GB_ASSERT(0 <= index); + return lb_emit_epi(m, s, index); } lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { @@ -1306,16 +1301,16 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) { Type *mt = base_type(type_deref(t)); if (column == 0) { GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); - return lb_emit_gep(p, mt, s.value, row); + return lb_emit_epi(p, s, row); } else if (row == 0 && is_type_array_like(mt)) { - return lb_emit_gep(p, mt, s.value, column); + return lb_emit_epi(p, s, column); } GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); isize offset = matrix_indices_to_offset(mt, row, column); - return lb_emit_gep(p, mt, s.value, offset); + return lb_emit_epi(p, s, offset); } lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) { From 43b78e51a4a5485bcc3f51e9b8bd6684b0efb169 Mon Sep 17 00:00:00 2001 From: Lucas Perlind Date: Wed, 10 Aug 2022 22:11:03 +1000 Subject: [PATCH 10/40] Add ID3D11Debug interface to d3d11 package --- vendor/directx/d3d11/d3d11.odin | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin index 2adb7925a..db1611bc4 100644 --- a/vendor/directx/d3d11/d3d11.odin +++ b/vendor/directx/d3d11/d3d11.odin @@ -3625,3 +3625,36 @@ IFunctionLinkingGraph_VTable :: struct { GetLastError: proc "stdcall" (this: ^IFunctionLinkingGraph, ppErrorBuffer: ^^IBlob) -> HRESULT, GenerateHlsl: proc "stdcall" (this: ^IFunctionLinkingGraph, uFlags: u32, ppBuffer: ^^IBlob) -> HRESULT, } + +IDebug_UUID_STRING :: "79CF2233-7536-4948-9D36-1E4692DC5760" +IDebug_UUID := &IID{0x79CF2233, 0x7536, 0x4948, {0x9D, 0x36, 0x1E, 0x46, 0x92, 0xDC, 0x57, 0x60}} + +IDebug :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d11debug_vtable: ^IDebug_VTable, +} + +RLDO_FLAGS :: enum u32 { // TODO: make bit_set + SUMMARY = 0x1, + DETAIL = 0x2, + IGNORE_INTERNAL = 0x4, +} + +DEBUG_FEATURE :: enum u32 { // TODO: make bit_set + FLUSH_PER_RENDER_OP = 0x1, + FINISH_PER_RENDER_OP = 0x2, + FEATURE_PRESENT_PER_RENDER_OP = 0x4, +} + +IDebug_VTable :: struct { + using iunkown_vtable: IUnknown_VTable, + SetFeatureMask: proc "stdcall" (this: ^IDebug, mask: DEBUG_FEATURE) -> HRESULT, + GetFeatureMask: proc "stdcall" (this: ^IDebug) -> DEBUG_FEATURE, + SetPresentPerRenderOpDelay: proc "stdcall" (this: ^IDebug, Milliseconds: u32) -> HRESULT, + GetPresentPerRenderOpDelay: proc "stdcall" (this: ^IDebug) -> u32, + SetSwapChain: proc "stdcall" (this: ^IDebug, pSwapChain: ^dxgi.ISwapChain) -> HRESULT, + GetSwapChain: proc "stdcall" (this: ^IDebug, ppSwapChain: ^^dxgi.ISwapChain) -> HRESULT, + ValidateContext: proc "stdcall" (this: ^IDebug, pContext: ^IDeviceContext) -> HRESULT, + ReportLiveDeviceObjects: proc "stdcall" (this: ^IDebug, Flags: RLDO_FLAGS) -> HRESULT, + ValidateContextForDispatch: proc "stdcall" (this: ^IDebug, pContext: ^IDeviceContext) -> HRESULT, +} From 28f440dd9e9e9674738b243d284a4394b22a5bc4 Mon Sep 17 00:00:00 2001 From: Joakim Hentula Date: Wed, 10 Aug 2022 13:58:33 +0100 Subject: [PATCH 11/40] Do not remove .rc extension from resource path to prevent expansion to full path assuming it's a directory if a folder with the same name exists in the same folder as the resource file --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 7fa04cc37..ef1b8dda1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1562,7 +1562,7 @@ bool parse_build_flags(Array args) { bad_flags = true; break; } - build_context.resource_filepath = substring(path, 0, string_extension_position(path)); + build_context.resource_filepath = path; build_context.has_resource = true; } else { gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path)); From 7aee762f3afe4ff40f7365082d45a32f52328e74 Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 17:39:21 -0700 Subject: [PATCH 12/40] Throw error when untyped shift expressions have non-integral type hints --- src/check_expr.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b2f3567ba..4dab26572 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2505,11 +2505,20 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ x->expr->tav.is_lhs = true; } x->mode = Addressing_Value; - if (type_hint && is_type_integer(type_hint)) { - x->type = type_hint; + if (type_hint) { + if (is_type_integer(type_hint)) { + x->type = type_hint; + } else { + gbString expr_str = expr_to_string(node); + gbString to_type = type_to_string(type_hint); + error(node, "Cannot convert untyped expression '%s' to '%s'", expr_str, to_type); + gb_string_free(expr_str); + gb_string_free(to_type); + x->mode = Addressing_Invalid; + return; + } } // x->value = x_val; - return; } } @@ -2522,7 +2531,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ // TODO(bill): Should we support shifts for fixed arrays and #simd vectors? if (!is_type_integer(x->type)) { - gbString err_str = expr_to_string(y->expr); + gbString err_str = expr_to_string(x->expr); error(node, "Shift operand '%s' must be an integer", err_str); gb_string_free(err_str); x->mode = Addressing_Invalid; From 5b621d5be18523939ded57cba24b3b3d19b774bd Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 18:07:49 -0700 Subject: [PATCH 13/40] More accurate error message --- src/check_expr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4dab26572..83bec20ae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2509,10 +2509,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ if (is_type_integer(type_hint)) { x->type = type_hint; } else { - gbString expr_str = expr_to_string(node); + gbString x_str = expr_to_string(x->expr); gbString to_type = type_to_string(type_hint); - error(node, "Cannot convert untyped expression '%s' to '%s'", expr_str, to_type); - gb_string_free(expr_str); + error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type); + gb_string_free(x_str); gb_string_free(to_type); x->mode = Addressing_Invalid; return; From 57dd5ec4db2a8d4ea40a605a885e6a432d3ec568 Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 18:25:29 -0700 Subject: [PATCH 14/40] Added back missing return statement --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 83bec20ae..f6c94466b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2515,10 +2515,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ gb_string_free(x_str); gb_string_free(to_type); x->mode = Addressing_Invalid; - return; } } // x->value = x_val; + return; } } From a5a56e061cf9949986807c14834c9fc010b0da27 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 11:10:05 +0100 Subject: [PATCH 15/40] Fix to png example.odin --- core/image/png/example.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/image/png/example.odin b/core/image/png/example.odin index 17436c260..c1e2f0c73 100644 --- a/core/image/png/example.odin +++ b/core/image/png/example.odin @@ -219,7 +219,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b defer close(fd) write_string(fd, - fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) - 1)), + fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)), ) if channels == 3 { From 0997df4fcf735830ee6a03867712ce89aa4255e1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 12:39:05 +0100 Subject: [PATCH 16/40] Move builtin directives to a separate procedure --- src/check_builtin.cpp | 907 +++++++++++++++++++++--------------------- 1 file changed, 455 insertions(+), 452 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8f8f7f9e2..7a72c574f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1075,6 +1075,459 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call } +bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + if (name == "location") { + if (ce->args.count > 1) { + error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count); + } + if (ce->args.count > 0) { + Ast *arg = ce->args[0]; + Entity *e = nullptr; + Operand o = {}; + if (arg->kind == Ast_Ident) { + e = check_ident(c, &o, arg, nullptr, nullptr, true); + } else if (arg->kind == Ast_SelectorExpr) { + e = check_selector(c, &o, arg, nullptr); + } + if (e == nullptr) { + error(ce->args[0], "'#location' expected a valid entity name"); + } + } + + operand->type = t_source_code_location; + operand->mode = Addressing_Value; + } else if (name == "load") { + if (ce->args.count != 1) { + if (ce->args.count == 0) { + error(ce->close, "'#load' expects 1 argument, got 0"); + } else { + error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + } + + return false; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#load' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#load' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + default: + case gbFileError_Invalid: + error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); + return false; + case gbFileError_NotExists: + error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); + return false; + case gbFileError_Permission: + error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); + return false; + case gbFileError_None: + // Okay + break; + } + + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + operand->value = exact_value_string(result); + + } else if (name == "load_hash") { + if (ce->args.count != 2) { + if (ce->args.count == 0) { + error(ce->close, "'#load_hash' expects 2 argument, got 0"); + } else { + error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count); + } + return false; + } + + Ast *arg0 = ce->args[0]; + Ast *arg1 = ce->args[1]; + Operand o = {}; + check_expr(c, &o, arg0); + if (o.mode != Addressing_Constant) { + error(arg0, "'#load_hash' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg0, "'#load_hash' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + Operand o_hash = {}; + check_expr(c, &o_hash, arg1); + if (o_hash.mode != Addressing_Constant) { + error(arg1, "'#load_hash' expected a constant string argument"); + return false; + } + + if (!is_type_string(o_hash.type)) { + gbString str = type_to_string(o.type); + error(arg1, "'#load_hash' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + GB_ASSERT(o_hash.value.kind == ExactValue_String); + + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + String hash_kind = o_hash.value.value_string; + + String supported_hashes[] = { + str_lit("adler32"), + str_lit("crc32"), + str_lit("crc64"), + str_lit("fnv32"), + str_lit("fnv64"), + str_lit("fnv32a"), + str_lit("fnv64a"), + str_lit("murmur32"), + str_lit("murmur64"), + }; + + bool hash_found = false; + for (isize i = 0; i < gb_count_of(supported_hashes); i++) { + if (supported_hashes[i] == hash_kind) { + hash_found = true; + break; + } + } + if (!hash_found) { + ERROR_BLOCK(); + error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind)); + error_line("\tAvailable hash kinds:\n"); + for (isize i = 0; i < gb_count_of(supported_hashes); i++) { + error_line("\t%.*s\n", LIT(supported_hashes[i])); + } + return false; + } + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + default: + case gbFileError_Invalid: + error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str); + return false; + case gbFileError_NotExists: + error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str); + return false; + case gbFileError_Permission: + error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str); + return false; + case gbFileError_None: + // Okay + break; + } + + // TODO(bill): make these procedures fast :P + + u64 hash_value = 0; + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size); + gb_file_read_at(&f, data, file_size, 0); + if (hash_kind == "adler32") { + hash_value = gb_adler32(data, file_size); + } else if (hash_kind == "crc32") { + hash_value = gb_crc32(data, file_size); + } else if (hash_kind == "crc64") { + hash_value = gb_crc64(data, file_size); + } else if (hash_kind == "fnv32") { + hash_value = gb_fnv32(data, file_size); + } else if (hash_kind == "fnv64") { + hash_value = gb_fnv64(data, file_size); + } else if (hash_kind == "fnv32a") { + hash_value = fnv32a(data, file_size); + } else if (hash_kind == "fnv64a") { + hash_value = fnv64a(data, file_size); + } else if (hash_kind == "murmur32") { + hash_value = gb_murmur32(data, file_size); + } else if (hash_kind == "murmur64") { + hash_value = gb_murmur64(data, file_size); + } else { + compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + } + gb_free(a, data); + } + + operand->type = t_untyped_integer; + operand->mode = Addressing_Constant; + operand->value = exact_value_u64(hash_value); + + } else if (name == "load_or") { + if (ce->args.count != 2) { + if (ce->args.count == 0) { + error(ce->close, "'#load_or' expects 2 arguments, got 0"); + } else { + error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count); + } + return false; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#load_or' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#load_or' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + Ast *default_arg = ce->args[1]; + Operand default_op = {}; + check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice); + if (default_op.mode != Addressing_Constant) { + error(arg, "'#load_or' expected a constant '[]byte' argument"); + return false; + } + + if (!are_types_identical(base_type(default_op.type), t_u8_slice)) { + gbString str = type_to_string(default_op.type); + error(arg, "'#load_or' expected a constant '[]byte', got %s", str); + gb_string_free(str); + return false; + } + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + if (file_err == gbFileError_None) { + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->value = exact_value_string(result); + } else { + operand->value = default_op.value; + } + + } else if (name == "assert") { + if (ce->args.count != 1 && ce->args.count != 2) { + error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); + return false; + } + if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant boolean", str); + gb_string_free(str); + return false; + } + if (ce->args.count == 2) { + Ast *arg = unparen_expr(ce->args[1]); + if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) { + gbString str = expr_to_string(arg); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + } + + if (!operand->value.value_bool) { + gbString arg1 = expr_to_string(ce->args[0]); + gbString arg2 = {}; + + if (ce->args.count == 1) { + error(call, "Compile time assertion: %s", arg1); + } else { + arg2 = expr_to_string(ce->args[1]); + error(call, "Compile time assertion: %s (%s)", arg1, arg2); + } + + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + + gb_string_free(arg1); + if (ce->args.count == 2) { + gb_string_free(arg2); + } + } + + operand->type = t_untyped_bool; + operand->mode = Addressing_Constant; + } else if (name == "panic") { + if (ce->args.count != 1) { + error(call, "'#panic' expects 1 argument, got %td", ce->args.count); + return false; + } + if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + operand->type = t_invalid; + operand->mode = Addressing_NoValue; + } else if (name == "defined") { + if (ce->args.count != 1) { + error(call, "'#defined' expects 1 argument, got %td", ce->args.count); + return false; + } + Ast *arg = unparen_expr(ce->args[0]); + if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) { + error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind])); + return false; + } + + if (c->curr_proc_decl == nullptr) { + error(call, "'#defined' is only allowed within a procedure, prefer the replacement '#config(NAME, default_value)'"); + return false; + } + + bool is_defined = check_identifier_exists(c->scope, arg); + gb_unused(is_defined); + operand->type = t_untyped_bool; + operand->mode = Addressing_Constant; + operand->value = exact_value_bool(false); + + } else if (name == "config") { + if (ce->args.count != 2) { + error(call, "'#config' expects 2 argument, got %td", ce->args.count); + return false; + } + Ast *arg = unparen_expr(ce->args[0]); + if (arg == nullptr || arg->kind != Ast_Ident) { + error(call, "'#config' expects an identifier, got %.*s", LIT(ast_strings[arg->kind])); + return false; + } + + Ast *def_arg = unparen_expr(ce->args[1]); + + Operand def = {}; + check_expr(c, &def, def_arg); + if (def.mode != Addressing_Constant) { + error(def_arg, "'#config' default value must be a constant"); + return false; + } + + String name = arg->Ident.token.string; + + + operand->type = def.type; + operand->mode = def.mode; + operand->value = def.value; + + Entity *found = scope_lookup_current(config_pkg->scope, name); + if (found != nullptr) { + if (found->kind != Entity_Constant) { + error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name)); + } else { + operand->type = found->type; + operand->mode = Addressing_Constant; + operand->value = found->Constant.value; + } + } + } else { + error(call, "Unknown directive call: #%.*s", LIT(name)); + } + return true; +} + bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->inlining != ProcInlining_none) { @@ -1186,458 +1639,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call); break; - case BuiltinProc_DIRECTIVE: { - ast_node(bd, BasicDirective, ce->proc); - String name = bd->name.string; - if (name == "location") { - if (ce->args.count > 1) { - error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count); - } - if (ce->args.count > 0) { - Ast *arg = ce->args[0]; - Entity *e = nullptr; - Operand o = {}; - if (arg->kind == Ast_Ident) { - e = check_ident(c, &o, arg, nullptr, nullptr, true); - } else if (arg->kind == Ast_SelectorExpr) { - e = check_selector(c, &o, arg, nullptr); - } - if (e == nullptr) { - error(ce->args[0], "'#location' expected a valid entity name"); - } - } - - operand->type = t_source_code_location; - operand->mode = Addressing_Value; - } else if (name == "load") { - if (ce->args.count != 1) { - if (ce->args.count == 0) { - error(ce->close, "'#load' expects 1 argument, got 0"); - } else { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); - } - - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); - - } else if (name == "load_hash") { - if (ce->args.count != 2) { - if (ce->args.count == 0) { - error(ce->close, "'#load_hash' expects 2 argument, got 0"); - } else { - error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count); - } - return false; - } - - Ast *arg0 = ce->args[0]; - Ast *arg1 = ce->args[1]; - Operand o = {}; - check_expr(c, &o, arg0); - if (o.mode != Addressing_Constant) { - error(arg0, "'#load_hash' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg0, "'#load_hash' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - Operand o_hash = {}; - check_expr(c, &o_hash, arg1); - if (o_hash.mode != Addressing_Constant) { - error(arg1, "'#load_hash' expected a constant string argument"); - return false; - } - - if (!is_type_string(o_hash.type)) { - gbString str = type_to_string(o.type); - error(arg1, "'#load_hash' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - GB_ASSERT(o_hash.value.kind == ExactValue_String); - - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - String hash_kind = o_hash.value.value_string; - - String supported_hashes[] = { - str_lit("adler32"), - str_lit("crc32"), - str_lit("crc64"), - str_lit("fnv32"), - str_lit("fnv64"), - str_lit("fnv32a"), - str_lit("fnv64a"), - str_lit("murmur32"), - str_lit("murmur64"), - }; - - bool hash_found = false; - for (isize i = 0; i < gb_count_of(supported_hashes); i++) { - if (supported_hashes[i] == hash_kind) { - hash_found = true; - break; - } - } - if (!hash_found) { - ERROR_BLOCK(); - error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind)); - error_line("\tAvailable hash kinds:\n"); - for (isize i = 0; i < gb_count_of(supported_hashes); i++) { - error_line("\t%.*s\n", LIT(supported_hashes[i])); - } - return false; - } - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - // TODO(bill): make these procedures fast :P - - u64 hash_value = 0; - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size); - gb_file_read_at(&f, data, file_size, 0); - if (hash_kind == "adler32") { - hash_value = gb_adler32(data, file_size); - } else if (hash_kind == "crc32") { - hash_value = gb_crc32(data, file_size); - } else if (hash_kind == "crc64") { - hash_value = gb_crc64(data, file_size); - } else if (hash_kind == "fnv32") { - hash_value = gb_fnv32(data, file_size); - } else if (hash_kind == "fnv64") { - hash_value = gb_fnv64(data, file_size); - } else if (hash_kind == "fnv32a") { - hash_value = fnv32a(data, file_size); - } else if (hash_kind == "fnv64a") { - hash_value = fnv64a(data, file_size); - } else if (hash_kind == "murmur32") { - hash_value = gb_murmur32(data, file_size); - } else if (hash_kind == "murmur64") { - hash_value = gb_murmur64(data, file_size); - } else { - compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); - } - gb_free(a, data); - } - - operand->type = t_untyped_integer; - operand->mode = Addressing_Constant; - operand->value = exact_value_u64(hash_value); - - } else if (name == "load_or") { - if (ce->args.count != 2) { - if (ce->args.count == 0) { - error(ce->close, "'#load_or' expects 2 arguments, got 0"); - } else { - error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count); - } - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load_or' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load_or' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - Ast *default_arg = ce->args[1]; - Operand default_op = {}; - check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice); - if (default_op.mode != Addressing_Constant) { - error(arg, "'#load_or' expected a constant '[]byte' argument"); - return false; - } - - if (!are_types_identical(base_type(default_op.type), t_u8_slice)) { - gbString str = type_to_string(default_op.type); - error(arg, "'#load_or' expected a constant '[]byte', got %s", str); - gb_string_free(str); - return false; - } - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - if (file_err == gbFileError_None) { - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->value = exact_value_string(result); - } else { - operand->value = default_op.value; - } - - } else if (name == "assert") { - if (ce->args.count != 1 && ce->args.count != 2) { - error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); - return false; - } - if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { - gbString str = expr_to_string(ce->args[0]); - error(call, "'%s' is not a constant boolean", str); - gb_string_free(str); - return false; - } - if (ce->args.count == 2) { - Ast *arg = unparen_expr(ce->args[1]); - if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) { - gbString str = expr_to_string(arg); - error(call, "'%s' is not a constant string", str); - gb_string_free(str); - return false; - } - } - - if (!operand->value.value_bool) { - gbString arg1 = expr_to_string(ce->args[0]); - gbString arg2 = {}; - - if (ce->args.count == 1) { - error(call, "Compile time assertion: %s", arg1); - } else { - arg2 = expr_to_string(ce->args[1]); - error(call, "Compile time assertion: %s (%s)", arg1, arg2); - } - - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); - } - - gb_string_free(arg1); - if (ce->args.count == 2) { - gb_string_free(arg2); - } - } - - operand->type = t_untyped_bool; - operand->mode = Addressing_Constant; - } else if (name == "panic") { - if (ce->args.count != 1) { - error(call, "'#panic' expects 1 argument, got %td", ce->args.count); - return false; - } - if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { - gbString str = expr_to_string(ce->args[0]); - error(call, "'%s' is not a constant string", str); - gb_string_free(str); - return false; - } - error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); - } - operand->type = t_invalid; - operand->mode = Addressing_NoValue; - } else if (name == "defined") { - if (ce->args.count != 1) { - error(call, "'#defined' expects 1 argument, got %td", ce->args.count); - return false; - } - Ast *arg = unparen_expr(ce->args[0]); - if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) { - error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind])); - return false; - } - - if (c->curr_proc_decl == nullptr) { - error(call, "'#defined' is only allowed within a procedure, prefer the replacement '#config(NAME, default_value)'"); - return false; - } - - bool is_defined = check_identifier_exists(c->scope, arg); - gb_unused(is_defined); - operand->type = t_untyped_bool; - operand->mode = Addressing_Constant; - operand->value = exact_value_bool(false); - - } else if (name == "config") { - if (ce->args.count != 2) { - error(call, "'#config' expects 2 argument, got %td", ce->args.count); - return false; - } - Ast *arg = unparen_expr(ce->args[0]); - if (arg == nullptr || arg->kind != Ast_Ident) { - error(call, "'#config' expects an identifier, got %.*s", LIT(ast_strings[arg->kind])); - return false; - } - - Ast *def_arg = unparen_expr(ce->args[1]); - - Operand def = {}; - check_expr(c, &def, def_arg); - if (def.mode != Addressing_Constant) { - error(def_arg, "'#config' default value must be a constant"); - return false; - } - - String name = arg->Ident.token.string; - - - operand->type = def.type; - operand->mode = def.mode; - operand->value = def.value; - - Entity *found = scope_lookup_current(config_pkg->scope, name); - if (found != nullptr) { - if (found->kind != Entity_Constant) { - error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name)); - } else { - operand->type = found->type; - operand->mode = Addressing_Constant; - operand->value = found->Constant.value; - } - } - } else { - error(call, "Unknown directive call: #%.*s", LIT(name)); - } - - break; - } + case BuiltinProc_DIRECTIVE: + return check_builtin_procedure_directive(c, operand, call, id, type_hint); case BuiltinProc_len: check_expr_or_type(c, operand, ce->args[0]); From 38102f14c19f83ef1e0c13a824448bab4e80877e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:01:54 +0100 Subject: [PATCH 17/40] Add `#load(path) or_else default` in favour of `#load_or(path, default)` --- src/check_builtin.cpp | 175 +++++++++++++++++++---------------- src/check_expr.cpp | 70 +++++++++++++- src/llvm_backend_utility.cpp | 4 + src/parser.hpp | 3 +- 4 files changed, 171 insertions(+), 81 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7a72c574f..4a0863f9d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1074,8 +1074,100 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call return false; } +LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + GB_ASSERT(name == "load"); -bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { + if (ce->args.count != 1) { + if (ce->args.count == 0) { + error(ce->close, "'#load' expects 1 argument, got 0"); + } else { + error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + } + + return LoadDirective_Error; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#load' expected a constant string argument"); + return LoadDirective_Error; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#load' expected a constant string, got %s", str); + gb_string_free(str); + return LoadDirective_Error; + } + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + default: + case gbFileError_Invalid: + if (err_on_not_found) { + error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return LoadDirective_NotFound; + case gbFileError_NotExists: + if (err_on_not_found) { + error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return LoadDirective_NotFound; + case gbFileError_Permission: + if (err_on_not_found) { + error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return LoadDirective_NotFound; + case gbFileError_None: + // Okay + break; + } + + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + operand->value = exact_value_string(result); + return LoadDirective_Success; +} + + +bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; @@ -1100,81 +1192,7 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast operand->type = t_source_code_location; operand->mode = Addressing_Value; } else if (name == "load") { - if (ce->args.count != 1) { - if (ce->args.count == 0) { - error(ce->close, "'#load' expects 1 argument, got 0"); - } else { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); - } - - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); - + return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success; } else if (name == "load_hash") { if (ce->args.count != 2) { if (ce->args.count == 0) { @@ -1263,7 +1281,6 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast char *c_str = alloc_cstring(a, path); defer (gb_free(a, c_str)); - gbFile f = {}; gbFileError file_err = gb_file_open(&f, c_str); defer (gb_file_close(&f)); @@ -1321,6 +1338,8 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast operand->value = exact_value_u64(hash_value); } else if (name == "load_or") { + warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'"); + if (ce->args.count != 2) { if (ce->args.count == 0) { error(ce->close, "'#load_or' expects 2 arguments, got 0"); @@ -1640,7 +1659,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_DIRECTIVE: - return check_builtin_procedure_directive(c, operand, call, id, type_hint); + return check_builtin_procedure_directive(c, operand, call, type_hint); case BuiltinProc_len: check_expr_or_type(c, operand, ce->args[0]); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f6c94466b..ae459574c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -121,6 +121,28 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na bool is_diverging_expr(Ast *expr); + +enum LoadDirectiveResult { + LoadDirective_Success = 0, + LoadDirective_Error = 1, + LoadDirective_NotFound = 2, +}; + +bool is_load_directive_call(Ast *call) { + call = unparen_expr(call); + if (call->kind != Ast_CallExpr) { + return false; + } + ast_node(ce, CallExpr, call); + if (ce->proc->kind != Ast_BasicDirective) { + return false; + } + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + return name == "load"; +} +LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found); + void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); if (results.count != 0) { @@ -7407,9 +7429,54 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type String name = oe->token.string; Ast *arg = oe->x; Ast *default_value = oe->y; - Operand x = {}; Operand y = {}; + + // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default + if (is_load_directive_call(arg)) { + LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); + if (res == LoadDirective_Success) { + *o = x; + return Expr_Expr; + } + + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); + y.mode = Addressing_Invalid; + break; + } + + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } + + if (!y_is_diverging) { + check_assignment(c, &y, x.type, name); + } + + o->mode = y.mode; + o->type = y.type; + o->expr = node; + + return Expr_Expr; + } + check_multi_expr_with_type_hint(c, &x, arg, type_hint); if (x.mode == Addressing_Invalid) { o->mode = Addressing_Value; @@ -7417,7 +7484,6 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type o->expr = node; return Expr_Expr; } - bool y_is_diverging = false; check_expr_base(c, &y, default_value, x.type); switch (y.mode) { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index ce7b43321..09c45cb7a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -351,6 +351,10 @@ lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) { lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) { + if (arg->state_flags & StateFlag_DirectiveWasFalse) { + return lb_build_expr(p, else_expr); + } + lbValue lhs = {}; lbValue rhs = {}; lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); diff --git a/src/parser.hpp b/src/parser.hpp index bfdae58a5..7433744e6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -282,7 +282,8 @@ enum StateFlag : u8 { StateFlag_type_assert = 1<<2, StateFlag_no_type_assert = 1<<3, - StateFlag_SelectorCallExpr = 1<<6, + StateFlag_SelectorCallExpr = 1<<5, + StateFlag_DirectiveWasFalse = 1<<6, StateFlag_BeenHandled = 1<<7, }; From a054c2934eb0caa027a1663cca839cb422621558 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:32:45 +0100 Subject: [PATCH 18/40] Cache #load data and hashes --- src/check_builtin.cpp | 254 ++++++++++++++++++++++-------------------- src/checker.cpp | 4 + src/checker.hpp | 9 ++ 3 files changed, 147 insertions(+), 120 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 4a0863f9d..70b5a0a13 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1074,6 +1074,95 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call return false; } +bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String builtin_name = bd->name.string; + + String base_dir = dir_from_path(get_file_path_string(call->file_id)); + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + + MUTEX_GUARD(&c->info->load_file_mutex); + + gbFileError file_error = gbFileError_None; + String data = {}; + + LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path); + LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr; + if (cache) { + file_error = cache->file_error; + data = cache->data; + } + defer ({ + if (cache == nullptr) { + LoadFileCache *new_cache = gb_alloc_item(permanent_allocator(), LoadFileCache); + new_cache->path = path; + new_cache->data = data; + new_cache->file_error = file_error; + string_map_init(&new_cache->hashes, heap_allocator(), 32); + string_map_set(&c->info->load_file_cache, path, new_cache); + if (cache_) *cache_ = new_cache; + } else { + cache->data = data; + cache->file_error = file_error; + if (cache_) *cache_ = cache; + } + }); + + char *c_str = alloc_cstring(heap_allocator(), path); + defer (gb_free(heap_allocator(), c_str)); + + gbFile f = {}; + if (cache == nullptr) { + file_error = gb_file_open(&f, c_str); + } + defer (gb_file_close(&f)); + + switch (file_error) { + default: + case gbFileError_Invalid: + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %s; invalid file or cannot be found", LIT(builtin_name), c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + case gbFileError_NotExists: + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %s; file cannot be found", LIT(builtin_name), c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + case gbFileError_Permission: + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %s; file permissions problem", LIT(builtin_name), c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + case gbFileError_None: + // Okay + break; + } + + if (cache == nullptr) { + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1); + gb_file_read_at(&f, ptr, file_size, 0); + ptr[file_size] = '\0'; + data.text = ptr; + data.len = file_size; + } + } + + return true; +} + + LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); @@ -1105,65 +1194,17 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As return LoadDirective_Error; } - gbAllocator a = heap_allocator(); - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - if (err_on_not_found) { - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - } - call->state_flags |= StateFlag_DirectiveWasFalse; - return LoadDirective_NotFound; - case gbFileError_NotExists: - if (err_on_not_found) { - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - } - call->state_flags |= StateFlag_DirectiveWasFalse; - return LoadDirective_NotFound; - case gbFileError_Permission: - if (err_on_not_found) { - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - } - call->state_flags |= StateFlag_DirectiveWasFalse; - return LoadDirective_NotFound; - case gbFileError_None: - // Okay - break; + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) { + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + operand->value = exact_value_string(cache->data); + return LoadDirective_Success; } + return LoadDirective_NotFound; - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); - return LoadDirective_Success; } @@ -1232,14 +1273,11 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast gb_string_free(str); return false; } - - gbAllocator a = heap_allocator(); GB_ASSERT(o.value.kind == ExactValue_String); GB_ASSERT(o_hash.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); String original_string = o.value.value_string; String hash_kind = o_hash.value.value_string; @@ -1272,71 +1310,47 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast return false; } - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - // TODO(bill): make these procedures fast :P - - u64 hash_value = 0; - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size); - gb_file_read_at(&f, data, file_size, 0); - if (hash_kind == "adler32") { - hash_value = gb_adler32(data, file_size); - } else if (hash_kind == "crc32") { - hash_value = gb_crc32(data, file_size); - } else if (hash_kind == "crc64") { - hash_value = gb_crc64(data, file_size); - } else if (hash_kind == "fnv32") { - hash_value = gb_fnv32(data, file_size); - } else if (hash_kind == "fnv64") { - hash_value = gb_fnv64(data, file_size); - } else if (hash_kind == "fnv32a") { - hash_value = fnv32a(data, file_size); - } else if (hash_kind == "fnv64a") { - hash_value = fnv64a(data, file_size); - } else if (hash_kind == "murmur32") { - hash_value = gb_murmur32(data, file_size); - } else if (hash_kind == "murmur64") { - hash_value = gb_murmur64(data, file_size); + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, original_string, true, &cache)) { + MUTEX_GUARD(&c->info->load_file_mutex); + // TODO(bill): make these procedures fast :P + u64 hash_value = 0; + u64 *hash_value_ptr = string_map_get(&cache->hashes, hash_kind); + if (hash_value_ptr) { + hash_value = *hash_value_ptr; } else { - compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + u8 *data = cache->data.text; + isize file_size = cache->data.len; + if (hash_kind == "adler32") { + hash_value = gb_adler32(data, file_size); + } else if (hash_kind == "crc32") { + hash_value = gb_crc32(data, file_size); + } else if (hash_kind == "crc64") { + hash_value = gb_crc64(data, file_size); + } else if (hash_kind == "fnv32") { + hash_value = gb_fnv32(data, file_size); + } else if (hash_kind == "fnv64") { + hash_value = gb_fnv64(data, file_size); + } else if (hash_kind == "fnv32a") { + hash_value = fnv32a(data, file_size); + } else if (hash_kind == "fnv64a") { + hash_value = fnv64a(data, file_size); + } else if (hash_kind == "murmur32") { + hash_value = gb_murmur32(data, file_size); + } else if (hash_kind == "murmur64") { + hash_value = gb_murmur64(data, file_size); + } else { + compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + } + string_map_set(&cache->hashes, hash_kind, hash_value); } - gb_free(a, data); + + operand->type = t_untyped_integer; + operand->mode = Addressing_Constant; + operand->value = exact_value_u64(hash_value); + return true; } - - operand->type = t_untyped_integer; - operand->mode = Addressing_Constant; - operand->value = exact_value_u64(hash_value); - + return false; } else if (name == "load_or") { warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'"); diff --git a/src/checker.cpp b/src/checker.cpp index c75fc86af..d01dc5323 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1170,6 +1170,8 @@ void init_checker_info(CheckerInfo *i) { mutex_init(&i->objc_types_mutex); map_init(&i->objc_msgSend_types, a); + mutex_init(&i->load_file_mutex); + string_map_init(&i->load_file_cache, a); } void destroy_checker_info(CheckerInfo *i) { @@ -1205,6 +1207,8 @@ void destroy_checker_info(CheckerInfo *i) { mutex_destroy(&i->objc_types_mutex); map_destroy(&i->objc_msgSend_types); + mutex_init(&i->load_file_mutex); + string_map_destroy(&i->load_file_cache); } CheckerContext make_checker_context(Checker *c) { diff --git a/src/checker.hpp b/src/checker.hpp index f11a00532..badcd93d5 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -287,6 +287,12 @@ struct ObjcMsgData { ObjcMsgKind kind; Type *proc_type; }; +struct LoadFileCache { + String path; + gbFileError file_error; + String data; + StringMap hashes; +}; // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { @@ -363,6 +369,9 @@ struct CheckerInfo { BlockingMutex objc_types_mutex; PtrMap objc_msgSend_types; + + BlockingMutex load_file_mutex; + StringMap load_file_cache; }; struct CheckerContext { From 9eeed9d5bde1348d16d3c3790ba3178f3e0bb09d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:35:24 +0100 Subject: [PATCH 19/40] Simplify `#load_or` for the time being --- src/check_builtin.cpp | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 70b5a0a13..b0c7f8d4b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1392,45 +1392,17 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast gb_string_free(str); return false; } - - gbAllocator a = heap_allocator(); - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); String original_string = o.value.value_string; - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - operand->type = t_u8_slice; operand->mode = Addressing_Constant; - if (file_err == gbFileError_None) { - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->value = exact_value_string(result); + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, original_string, false, &cache)) { + operand->value = exact_value_string(cache->data); } else { operand->value = default_op.value; } - } else if (name == "assert") { if (ce->args.count != 1 && ce->args.count != 2) { error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); From 70dc0c15fd244bdc4a769b0d91b50ecc210bca65 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:43:35 +0100 Subject: [PATCH 20/40] Improve type hint for #load to allow for string types --- src/check_builtin.cpp | 8 ++++++-- src/check_expr.cpp | 14 ++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b0c7f8d4b..122d3a461 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1196,10 +1196,14 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As GB_ASSERT(o.value.kind == ExactValue_String); + operand->type = t_u8_slice; + if (type_hint && is_type_string(type_hint)) { + operand->type = type_hint; + } + operand->mode = Addressing_Constant; + LoadFileCache *cache = nullptr; if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) { - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; operand->value = exact_value_string(cache->data); return LoadDirective_Success; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ae459574c..076eaba73 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7435,10 +7435,6 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default if (is_load_directive_call(arg)) { LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); - if (res == LoadDirective_Success) { - *o = x; - return Expr_Expr; - } bool y_is_diverging = false; check_expr_base(c, &y, default_value, x.type); @@ -7468,10 +7464,16 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type if (!y_is_diverging) { check_assignment(c, &y, x.type, name); + if (y.mode != Addressing_Constant) { + error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + } } - o->mode = y.mode; - o->type = y.type; + if (res == LoadDirective_Success) { + *o = x; + } else { + *o = y; + } o->expr = node; return Expr_Expr; From a7c39060038f63b1840f6eb5c0750bdb47e7d3ea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 14:30:14 +0100 Subject: [PATCH 21/40] `#load(path, type)` where `type` can be `string` or `[]T` where `T` is a simple type --- src/check_builtin.cpp | 49 +++++++++++++++++++++++++++++----- src/llvm_backend_const.cpp | 4 +-- src/llvm_backend_general.cpp | 48 +++++++++++++++++++++++++++++++++ src/types.cpp | 51 ++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 9 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 122d3a461..36c9ea001 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1169,11 +1169,11 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As String name = bd->name.string; GB_ASSERT(name == "load"); - if (ce->args.count != 1) { + if (ce->args.count != 1 && ce->args.count != 2) { if (ce->args.count == 0) { - error(ce->close, "'#load' expects 1 argument, got 0"); + error(ce->close, "'#%.*s' expects 1 or 2 arguments, got 0", LIT(name)); } else { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + error(ce->args[0], "'#%.*s' expects 1 or 2 arguments, got %td", LIT(name), ce->args.count); } return LoadDirective_Error; @@ -1183,13 +1183,13 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As Operand o = {}; check_expr(c, &o, arg); if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); + error(arg, "'#%.*s' expected a constant string argument", LIT(name)); return LoadDirective_Error; } if (!is_type_string(o.type)) { gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); + error(arg, "'#%.*s' expected a constant string, got %s", LIT(name), str); gb_string_free(str); return LoadDirective_Error; } @@ -1197,8 +1197,43 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As GB_ASSERT(o.value.kind == ExactValue_String); operand->type = t_u8_slice; - if (type_hint && is_type_string(type_hint)) { - operand->type = type_hint; + if (ce->args.count == 1) { + if (type_hint && is_type_string(type_hint)) { + operand->type = type_hint; + } + } else if (ce->args.count == 2) { + bool failed = false; + Ast *arg_type = ce->args[1]; + Type *type = check_type(c, arg_type); + if (type != nullptr && type != t_invalid) { + if (is_type_string(type)) { + operand->type = type; + } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { + Type *elem = nullptr; + Type *bt = base_type(type); + if (bt->kind == Type_Slice) { + elem = bt->Slice.elem; + } else if (bt->kind == Type_Array) { + elem = bt->Array.elem; + } else if (bt->kind == Type_EnumeratedArray) { + elem = bt->EnumeratedArray.elem; + } + GB_ASSERT(elem != nullptr); + if (is_type_load_safe(elem)) { + operand->type = type; + } else { + failed = true; + } + } else { + failed = true; + } + } + + if (failed) { + gbString type_str = type_to_string(type); + error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); + gb_string_free(type_str); + } } operand->mode = Addressing_Constant; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 954778bb6..2d14070e2 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -391,8 +391,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc if (is_type_slice(type)) { if (value.kind == ExactValue_String) { - GB_ASSERT(is_type_u8_slice(type)); - res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value; + GB_ASSERT(is_type_slice(type)); + res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value; return res; } else { ast_node(cl, CompoundLit, value.value_compound); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 082163b2f..8704bc7c7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2523,8 +2523,56 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) res.type = t_u8_slice; return res; } +lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) { + GB_ASSERT(is_type_slice(slice_type)); + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; + LLVMValueRef data = LLVMConstStringInContext(m->ctx, + cast(char const *)str.text, + cast(unsigned)str.len, + false); + char *name = nullptr; + { + isize max_len = 7+8+1; + name = gb_alloc_array(permanent_allocator(), char, max_len); + u32 id = m->gen->global_array_index.fetch_add(1); + isize len = gb_snprintf(name, max_len, "csbs$%x", id); + len -= 1; + } + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); + LLVMSetInitializer(global_data, data); + LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetAlignment(global_data, 1); + LLVMSetGlobalConstant(global_data, true); + + i64 data_len = str.len; + LLVMValueRef ptr = nullptr; + if (data_len != 0) { + ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); + } else { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } + if (!is_type_u8_slice(slice_type)) { + Type *bt = base_type(slice_type); + Type *elem = bt->Slice.elem; + i64 sz = type_size_of(elem); + GB_ASSERT(sz > 0); + ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem))); + data_len /= sz; + } + + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true); + LLVMValueRef values[2] = {ptr, len}; + + lbValue res = {}; + res.value = llvm_const_named_struct(m, slice_type, values, 2); + res.type = slice_type; + return res; +} + lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) { diff --git a/src/types.cpp b/src/types.cpp index cba27fd6f..1f4804430 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2398,6 +2398,57 @@ bool is_type_simple_compare(Type *t) { return false; } +bool is_type_load_safe(Type *type) { + GB_ASSERT(type != nullptr); + type = core_type(core_array_type(type)); + switch (type->kind) { + case Type_Basic: + return (type->Basic.flags & (BasicFlag_Boolean|BasicFlag_Numeric|BasicFlag_Rune)) != 0; + + case Type_BitSet: + if (type->BitSet.underlying) { + return is_type_load_safe(type->BitSet.underlying); + } + return true; + + case Type_RelativePointer: + case Type_RelativeSlice: + return true; + + case Type_Pointer: + case Type_MultiPointer: + case Type_Slice: + case Type_DynamicArray: + case Type_Proc: + case Type_SoaPointer: + return false; + + case Type_Enum: + case Type_EnumeratedArray: + case Type_Array: + case Type_SimdVector: + case Type_Matrix: + GB_PANIC("should never be hit"); + return false; + + case Type_Struct: + for_array(i, type->Struct.fields) { + if (!is_type_load_safe(type->Struct.fields[i]->type)) { + return false; + } + } + return type_size_of(type) > 0; + case Type_Union: + for_array(i, type->Union.variants) { + if (!is_type_load_safe(type->Union.variants[i])) { + return false; + } + } + return type_size_of(type) > 0; + } + return false; +} + String lookup_subtype_polymorphic_field(Type *dst, Type *src) { Type *prev_src = src; // Type *prev_dst = dst; From cecadce86d8070ee31d193736d331926efec0fff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 14:42:29 +0100 Subject: [PATCH 22/40] Allow for chaining of '#load(path) or_else #load(path)' --- src/check_builtin.cpp | 56 ++++++++++++++++++++++--------------------- src/check_expr.cpp | 55 ++++++++++++++++++++++-------------------- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 36c9ea001..687f1694b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1163,6 +1163,27 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi } +bool is_valid_type_for_load(Type *type) { + if (type == t_invalid) { + return false; + } else if (is_type_string(type)) { + return true; + } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { + Type *elem = nullptr; + Type *bt = base_type(type); + if (bt->kind == Type_Slice) { + elem = bt->Slice.elem; + } else if (bt->kind == Type_Array) { + elem = bt->Array.elem; + } else if (bt->kind == Type_EnumeratedArray) { + elem = bt->EnumeratedArray.elem; + } + GB_ASSERT(elem != nullptr); + return is_type_load_safe(elem); + } + return false; +} + LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); @@ -1198,42 +1219,23 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As operand->type = t_u8_slice; if (ce->args.count == 1) { - if (type_hint && is_type_string(type_hint)) { + if (type_hint && is_valid_type_for_load(type_hint)) { operand->type = type_hint; } } else if (ce->args.count == 2) { - bool failed = false; Ast *arg_type = ce->args[1]; Type *type = check_type(c, arg_type); - if (type != nullptr && type != t_invalid) { - if (is_type_string(type)) { + if (type != nullptr) { + if (is_valid_type_for_load(type)) { operand->type = type; - } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { - Type *elem = nullptr; - Type *bt = base_type(type); - if (bt->kind == Type_Slice) { - elem = bt->Slice.elem; - } else if (bt->kind == Type_Array) { - elem = bt->Array.elem; - } else if (bt->kind == Type_EnumeratedArray) { - elem = bt->EnumeratedArray.elem; - } - GB_ASSERT(elem != nullptr); - if (is_type_load_safe(elem)) { - operand->type = type; - } else { - failed = true; - } } else { - failed = true; + gbString type_str = type_to_string(type); + error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); + gb_string_free(type_str); } } - - if (failed) { - gbString type_str = type_to_string(type); - error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); - gb_string_free(type_str); - } + } else { + GB_PANIC("unreachable"); } operand->mode = Addressing_Constant; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 076eaba73..310874139 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7436,36 +7436,39 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type if (is_load_directive_call(arg)) { LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); - bool y_is_diverging = false; - check_expr_base(c, &y, default_value, x.type); - switch (y.mode) { - case Addressing_NoValue: - if (is_diverging_expr(y.expr)) { - // Allow - y.mode = Addressing_Value; - y_is_diverging = true; - } else { - error_operand_no_value(&y); + // Allow for chaining of '#load(path) or_else #load(path)' + if (!(is_load_directive_call(default_value) && res == LoadDirective_Success)) { + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); y.mode = Addressing_Invalid; + break; } - break; - case Addressing_Type: - error_operand_not_expression(&y); - y.mode = Addressing_Invalid; - break; - } - if (y.mode == Addressing_Invalid) { - o->mode = Addressing_Value; - o->type = t_invalid; - o->expr = node; - return Expr_Expr; - } + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } - if (!y_is_diverging) { - check_assignment(c, &y, x.type, name); - if (y.mode != Addressing_Constant) { - error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + if (!y_is_diverging) { + check_assignment(c, &y, x.type, name); + if (y.mode != Addressing_Constant) { + error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + } } } From 03f683f9e77b82b1239633db08463924785e2630 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 15:19:27 +0100 Subject: [PATCH 23/40] Improve emit store for large constants --- src/llvm_backend_general.cpp | 44 ++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 082163b2f..bcbd041ae 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -567,6 +567,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu } } +unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) { + if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { + return LLVMGetAlignment(addr_ptr); + } + return default_alignment; +} + bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) { if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { if (LLVMGetAlignment(addr_ptr) < alignment) { @@ -914,16 +921,35 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { enum {MAX_STORE_SIZE = 64}; - if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) { - LLVMValueRef dst_ptr = ptr.value; - LLVMValueRef src_ptr = LLVMGetOperand(value.value, 0); - src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), ""); + if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) { + if (LLVMIsALoadInst(value.value)) { + LLVMValueRef dst_ptr = ptr.value; + LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0); + LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), ""); - LLVMBuildMemMove(p->builder, - dst_ptr, 1, - src_ptr, 1, - LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); - return; + LLVMBuildMemMove(p->builder, + dst_ptr, lb_try_get_alignment(dst_ptr, 1), + src_ptr, lb_try_get_alignment(src_ptr_original, 1), + LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); + return; + } else if (LLVMIsConstant(value.value)) { + lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr); + LLVMValueRef global_data = addr.addr.value; + // make it truly private data + LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetGlobalConstant(global_data, true); + + LLVMValueRef dst_ptr = ptr.value; + LLVMValueRef src_ptr = global_data; + src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), ""); + + LLVMBuildMemMove(p->builder, + dst_ptr, lb_try_get_alignment(dst_ptr, 1), + src_ptr, lb_try_get_alignment(global_data, 1), + LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); + return; + } } if (lb_is_type_proc_recursive(a)) { From 0f3562ef021fc1042d651d5ad1f834af67d2d001 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 16:01:46 +0100 Subject: [PATCH 24/40] Improve compound literal generation for array-like types --- src/llvm_backend_expr.cpp | 1366 +++++++++++++++------------------- src/llvm_backend_general.cpp | 3 +- 2 files changed, 619 insertions(+), 750 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7568f975e..0cf2b3c03 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3491,6 +3491,614 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { return addr; } +void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &elems, Array *temp_data, Type *compound_type) { + Type *bt = base_type(compound_type); + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_DynamicArray: et = bt->DynamicArray.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + } + GB_ASSERT(et != nullptr); + + + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, elems) { + Ast *elem = elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); + + GB_ASSERT((hi-lo) > 0); + + enum {MAX_ELEMENT_AMOUNT = 32}; + if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = k; + array_add(temp_data, data); + } + } else { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = lo; + data.elem_length = hi-lo; + array_add(temp_data, data); + } + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); + GB_ASSERT(!is_type_tuple(value.type)); + + lbCompoundLitElemTempData data = {}; + data.value = value; + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(temp_data, data); + } + + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + + lbValue field_expr = lb_build_expr(p, elem); + GB_ASSERT(!is_type_tuple(field_expr.type)); + + lbValue ev = lb_emit_conv(p, field_expr, et); + + lbCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)i; + array_add(temp_data, data); + } + } +} +void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array &temp_data) { + for_array(i, temp_data) { + auto td = temp_data[i]; + if (td.value.value != nullptr) { + if (td.elem_length > 0) { + auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32); + { + lbValue dst = temp_data[i].gep; + dst = lb_emit_ptr_offset(p, dst, loop_data.idx); + lb_emit_store(p, dst, temp_data[i].value); + } + lb_loop_end(p, loop_data); + } else { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + } + } + } +} + + +lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { + ast_node(cl, CompoundLit, expr); + + Type *type = type_of_expr(expr); + Type *bt = base_type(type); + + lbAddr v = lb_add_local_generated(p, type, true); + + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + } + + String proc_name = {}; + if (p->entity) { + proc_name = p->entity->token.string; + } + TokenPos pos = ast_token(expr).pos; + + switch (bt->kind) { + default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + + case Type_Struct: { + // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. + // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR + bool is_raw_union = is_type_raw_union(bt); + GB_ASSERT(is_type_struct(bt) || is_raw_union); + TypeStruct *st = &bt->Struct; + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + lbValue comp_lit_ptr = lb_addr_get_ptr(p, v); + + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + lbValue field_expr = {}; + Entity *field = nullptr; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sel = lookup_field(bt, name, false); + index = sel.index[0]; + elem = fv->value; + TypeAndValue tav = type_and_value_of_expr(elem); + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); + index = sel.index[0]; + } + + field = st->fields[index]; + Type *ft = field->type; + if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) { + continue; + } + + field_expr = lb_build_expr(p, elem); + + lbValue gep = {}; + if (is_raw_union) { + gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); + } else { + gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); + } + + Type *fet = field_expr.type; + GB_ASSERT(fet->kind != Type_Tuple); + + // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! + if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { + GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet)); + + lb_emit_store_union_variant(p, gep, field_expr, fet); + } else { + lbValue fv = lb_emit_conv(p, field_expr, ft); + lb_emit_store(p, gep, fv); + } + } + } + break; + } + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + GB_ASSERT(!build_context.no_dynamic_literals); + { + auto args = array_make(permanent_allocator(), 3); + args[0] = lb_gen_map_header(p, v.addr, type); + args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); + args[2] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_map_reserve", args); + } + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + ast_node(fv, FieldValue, elem); + + lbValue key = lb_build_expr(p, fv->field); + lbValue value = lb_build_expr(p, fv->value); + lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem); + } + break; + } + + case Type_Array: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + + lbValue dst_ptr = lb_addr_get_ptr(p, v); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index); + } + + lb_build_addr_compound_lit_assign_array(p, temp_data); + } + break; + } + case Type_EnumeratedArray: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + + lbValue dst_ptr = lb_addr_get_ptr(p, v); + i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index - index_offset); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index); + } + + lb_build_addr_compound_lit_assign_array(p, temp_data); + } + break; + } + case Type_Slice: { + if (cl->elems.count > 0) { + lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr)); + + lbValue data = lb_slice_elem(p, slice); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index)); + } + + lb_build_addr_compound_lit_assign_array(p, temp_data); + + { + lbValue count = {}; + count.type = t_int; + + if (lb_is_const(slice)) { + unsigned indices[1] = {1}; + count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices)); + } else { + count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, ""); + } + lb_fill_slice(p, v, data, count); + } + } + break; + } + + case Type_DynamicArray: { + if (cl->elems.count == 0) { + break; + } + GB_ASSERT(!build_context.no_dynamic_literals); + + Type *et = bt->DynamicArray.elem; + lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); + lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); + + i64 item_count = gb_max(cl->max_count, cl->elems.count); + { + + auto args = array_make(permanent_allocator(), 5); + args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); + args[1] = size; + args[2] = align; + args[3] = lb_const_int(p->module, t_int, item_count); + args[4] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_array_reserve", args); + } + + lbValue items = lb_generate_local_array(p, et, item_count); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_array_epi(p, items, temp_data[i].elem_index); + } + lb_build_addr_compound_lit_assign_array(p, temp_data); + + { + auto args = array_make(permanent_allocator(), 6); + args[0] = lb_emit_conv(p, v.addr, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = lb_emit_conv(p, items, t_rawptr); + args[4] = lb_const_int(p->module, t_int, item_count); + args[5] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_array_append", args); + } + break; + } + + case Type_Basic: { + GB_ASSERT(is_type_any(bt)); + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + String field_names[2] = { + str_lit("data"), + str_lit("id"), + }; + Type *field_types[2] = { + t_rawptr, + t_typeid, + }; + + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + lbValue field_expr = {}; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + index = sel.index[0]; + elem = fv->value; + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field(bt, field_names[field_index], false); + index = sel.index[0]; + } + + field_expr = lb_build_expr(p, elem); + + GB_ASSERT(field_expr.type->kind != Type_Tuple); + + Type *ft = field_types[index]; + lbValue fv = lb_emit_conv(p, field_expr, ft); + lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); + lb_emit_store(p, gep, fv); + } + } + + break; + } + + case Type_BitSet: { + i64 sz = type_size_of(type); + if (cl->elems.count > 0 && sz > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + GB_ASSERT(elem->kind != Ast_FieldValue); + + if (lb_is_elem_const(elem, et)) { + continue; + } + + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + Type *it = bit_set_to_int(bt); + lbValue one = lb_const_value(p->module, it, exact_value_i64(1)); + lbValue e = lb_emit_conv(p, expr, it); + e = lb_emit_arith(p, Token_Sub, e, lower, it); + e = lb_emit_arith(p, Token_Shl, one, e, it); + + lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); + lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); + new_value = lb_emit_transmute(p, new_value, type); + lb_addr_store(p, v, new_value); + } + } + break; + } + + case Type_Matrix: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + lbValue value = lb_build_expr(p, fv->value); + + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + + data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k); + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_build_expr(p, fv->value); + lbCompoundLitElemTempData data = {}; + data.value = lb_emit_conv(p, value, et); + data.expr = fv->value; + + data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index); + array_add(&temp_data, data); + } + + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i); + array_add(&temp_data, data); + } + } + + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); + } + + for_array(i, temp_data) { + lbValue field_expr = temp_data[i].value; + Ast *expr = temp_data[i].expr; + + auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); + + if (field_expr.value == nullptr) { + field_expr = lb_build_expr(p, expr); + } + Type *t = field_expr.type; + GB_ASSERT(t->kind != Type_Tuple); + lbValue ev = lb_emit_conv(p, field_expr, et); + + if (!p->copy_elision_hint.used) { + temp_data[i].value = ev; + } + + lb_reset_copy_elision_hint(p, prev_hint); + } + + for_array(i, temp_data) { + if (temp_data[i].value.value != nullptr) { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + } + } + } + break; + } + + case Type_SimdVector: { + if (cl->elems.count > 0) { + lbValue vector_value = lb_const_value(p->module, type, exact_value_compound(expr)); + defer (lb_addr_store(p, v, vector_value)); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + // NOTE(bill): Separate value, store into their own chunks + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + lbValue value = lb_build_expr(p, fv->value); + + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_build_expr(p, fv->value); + lbCompoundLitElemTempData data = {}; + data.value = lb_emit_conv(p, value, et); + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } + + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); + } + } + + + for_array(i, temp_data) { + lbValue field_expr = temp_data[i].value; + Ast *expr = temp_data[i].expr; + + auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); + + if (field_expr.value == nullptr) { + field_expr = lb_build_expr(p, expr); + } + Type *t = field_expr.type; + GB_ASSERT(t->kind != Type_Tuple); + lbValue ev = lb_emit_conv(p, field_expr, et); + + if (!p->copy_elision_hint.used) { + temp_data[i].value = ev; + } + + lb_reset_copy_elision_hint(p, prev_hint); + } + + + // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` + // might be a better option + + for_array(i, temp_data) { + if (temp_data[i].value.value != nullptr) { + LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value; + vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, ""); + } + } + } + break; + } + } + + return v; +} + lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { switch (expr->kind) { @@ -3680,7 +4288,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { bool deref = is_type_pointer(t); t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { + if (is_type_soa_struct(t)) { // SOA STRUCTURES!!!! lbValue val = lb_build_addr_ptr(p, ie->expr); if (deref) { @@ -3847,7 +4455,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lbValue v = lb_emit_ptr_offset(p, elem, index); return lb_addr(v); } - + case Type_Matrix: { lbValue matrix = {}; matrix = lb_build_addr_ptr(p, ie->expr); @@ -3888,13 +4496,13 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { } } case_end; - + case_ast_node(ie, MatrixIndexExpr, expr); Type *t = base_type(type_of_expr(ie->expr)); bool deref = is_type_pointer(t); t = base_type(type_deref(t)); - + lbValue m = {}; m = lb_build_addr_ptr(p, ie->expr); if (deref) { @@ -3914,8 +4522,8 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lb_emit_matrix_bounds_check(p, ast_token(ie->row_index), row_index, column_index, row_count, column_count); } return lb_addr(elem); - - + + case_end; case_ast_node(se, SliceExpr, expr); @@ -3993,13 +4601,13 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { } else { low = lb_emit_conv(p, low, t_int); high = lb_emit_conv(p, high, t_int); - + lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); LLVMValueRef indices[1] = {low.value}; LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); - + LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; LLVMBuildStore(p->builder, ptr, gep0); @@ -4159,747 +4767,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(cl, CompoundLit, expr); - Type *type = type_of_expr(expr); - Type *bt = base_type(type); - - lbAddr v = lb_add_local_generated(p, type, true); - - Type *et = nullptr; - switch (bt->kind) { - case Type_Array: et = bt->Array.elem; break; - case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; - case Type_Slice: et = bt->Slice.elem; break; - case Type_BitSet: et = bt->BitSet.elem; break; - case Type_SimdVector: et = bt->SimdVector.elem; break; - case Type_Matrix: et = bt->Matrix.elem; break; - } - - String proc_name = {}; - if (p->entity) { - proc_name = p->entity->token.string; - } - TokenPos pos = ast_token(expr).pos; - - switch (bt->kind) { - default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; - - case Type_Struct: { - // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. - // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR - bool is_raw_union = is_type_raw_union(bt); - GB_ASSERT(is_type_struct(bt) || is_raw_union); - TypeStruct *st = &bt->Struct; - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - lbValue comp_lit_ptr = lb_addr_get_ptr(p, v); - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - lbValue field_expr = {}; - Entity *field = nullptr; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); - index = sel.index[0]; - elem = fv->value; - TypeAndValue tav = type_and_value_of_expr(elem); - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); - index = sel.index[0]; - } - - field = st->fields[index]; - Type *ft = field->type; - if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) { - continue; - } - - field_expr = lb_build_expr(p, elem); - - lbValue gep = {}; - if (is_raw_union) { - gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); - } else { - gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); - } - - Type *fet = field_expr.type; - GB_ASSERT(fet->kind != Type_Tuple); - - // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! - if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { - GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet)); - - lb_emit_store_union_variant(p, gep, field_expr, fet); - } else { - lbValue fv = lb_emit_conv(p, field_expr, ft); - lb_emit_store(p, gep, fv); - } - } - } - break; - } - - case Type_Map: { - if (cl->elems.count == 0) { - break; - } - { - auto args = array_make(permanent_allocator(), 3); - args[0] = lb_gen_map_header(p, v.addr, type); - args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); - args[2] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_map_reserve", args); - } - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - ast_node(fv, FieldValue, elem); - - lbValue key = lb_build_expr(p, fv->field); - lbValue value = lb_build_expr(p, fv->value); - lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem); - } - break; - } - - case Type_Array: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); - } - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } - } - break; - } - case Type_EnumeratedArray: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - - i32 index_offset = cast(i32)exact_value_to_i64(*bt->EnumeratedArray.min_value); - - for_array(i, temp_data) { - i32 index = temp_data[i].elem_index - index_offset; - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), index); - } - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } - } - break; - } - case Type_Slice: { - if (cl->elems.count > 0) { - lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr)); - - lbValue data = lb_slice_elem(p, slice); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - - if (lb_is_elem_const(fv->value, et)) { - continue; - } - - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(fv->field->tav.value); - - lbValue field_expr = lb_build_expr(p, fv->value); - GB_ASSERT(!is_type_tuple(field_expr.type)); - - lbValue ev = lb_emit_conv(p, field_expr, et); - - lbCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbValue field_expr = lb_build_expr(p, elem); - GB_ASSERT(!is_type_tuple(field_expr.type)); - - lbValue ev = lb_emit_conv(p, field_expr, et); - - lbCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index)); - } - - for_array(i, temp_data) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - - { - lbValue count = {}; - count.type = t_int; - - if (lb_is_const(slice)) { - unsigned indices[1] = {1}; - count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices)); - } else { - count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, ""); - } - lb_fill_slice(p, v, data, count); - } - } - break; - } - - case Type_DynamicArray: { - if (cl->elems.count == 0) { - break; - } - Type *et = bt->DynamicArray.elem; - lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); - lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); - - i64 item_count = gb_max(cl->max_count, cl->elems.count); - { - - auto args = array_make(permanent_allocator(), 5); - args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); - args[1] = size; - args[2] = align; - args[3] = lb_const_int(p->module, t_int, 2*item_count); // TODO(bill): Is this too much waste? - args[4] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_array_reserve", args); - } - - lbValue items = lb_generate_local_array(p, et, item_count); - // lbValue items = lb_generate_global_array(p->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); - - for (i64 k = lo; k < hi; k++) { - lbValue ep = lb_emit_array_epi(p, items, cast(i32)k); - lb_emit_store(p, ep, value); - } - } else { - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - - i64 field_index = exact_value_to_i64(fv->field->tav.value); - - lbValue ev = lb_build_expr(p, fv->value); - lbValue value = lb_emit_conv(p, ev, et); - lbValue ep = lb_emit_array_epi(p, items, cast(i32)field_index); - lb_emit_store(p, ep, value); - } - } else { - lbValue value = lb_emit_conv(p, lb_build_expr(p, elem), et); - lbValue ep = lb_emit_array_epi(p, items, cast(i32)i); - lb_emit_store(p, ep, value); - } - } - - { - auto args = array_make(permanent_allocator(), 6); - args[0] = lb_emit_conv(p, v.addr, t_rawptr); - args[1] = size; - args[2] = align; - args[3] = lb_emit_conv(p, items, t_rawptr); - args[4] = lb_const_int(p->module, t_int, item_count); - args[5] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_array_append", args); - } - break; - } - - case Type_Basic: { - GB_ASSERT(is_type_any(bt)); - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - String field_names[2] = { - str_lit("data"), - str_lit("id"), - }; - Type *field_types[2] = { - t_rawptr, - t_typeid, - }; - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - lbValue field_expr = {}; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); - index = sel.index[0]; - elem = fv->value; - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field(bt, field_names[field_index], false); - index = sel.index[0]; - } - - field_expr = lb_build_expr(p, elem); - - GB_ASSERT(field_expr.type->kind != Type_Tuple); - - Type *ft = field_types[index]; - lbValue fv = lb_emit_conv(p, field_expr, ft); - lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); - lb_emit_store(p, gep, fv); - } - } - - break; - } - - case Type_BitSet: { - i64 sz = type_size_of(type); - if (cl->elems.count > 0 && sz > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - GB_ASSERT(elem->kind != Ast_FieldValue); - - if (lb_is_elem_const(elem, et)) { - continue; - } - - lbValue expr = lb_build_expr(p, elem); - GB_ASSERT(expr.type->kind != Type_Tuple); - - Type *it = bit_set_to_int(bt); - lbValue one = lb_const_value(p->module, it, exact_value_i64(1)); - lbValue e = lb_emit_conv(p, expr, it); - e = lb_emit_arith(p, Token_Sub, e, lower, it); - e = lb_emit_arith(p, Token_Shl, one, e, it); - - lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); - lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); - new_value = lb_emit_transmute(p, new_value, type); - lb_addr_store(p, v, new_value); - } - } - break; - } - - case Type_Matrix: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k); - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index); - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i); - array_add(&temp_data, data); - } - } - - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); - } - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } - } - break; - } - - case Type_SimdVector: { - if (cl->elems.count > 0) { - lbValue vector_value = lb_const_value(p->module, type, exact_value_compound(expr)); - defer (lb_addr_store(p, v, vector_value)); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - - // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` - // might be a better option - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value; - vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, ""); - } - } - } - break; - } - } - - return v; + return lb_build_addr_compound_lit(p, expr); case_end; case_ast_node(tc, TypeCast, expr); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index bcbd041ae..ee6980de4 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -175,7 +175,8 @@ struct lbLoopData { struct lbCompoundLitElemTempData { Ast * expr; lbValue value; - i32 elem_index; + i64 elem_index; + i64 elem_length; lbValue gep; }; From d2a362fd52bf3e750966fa120ef213a65c667cb1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 16:07:55 +0100 Subject: [PATCH 25/40] Clean up compound literal backend stuff some more --- src/llvm_backend_expr.cpp | 226 +++++++++----------------------------- 1 file changed, 49 insertions(+), 177 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0cf2b3c03..f7ffe03f9 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3532,20 +3532,30 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele GB_ASSERT((hi-lo) > 0); - enum {MAX_ELEMENT_AMOUNT = 32}; - if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + if (bt->kind == Type_Matrix) { for (i64 k = lo; k < hi; k++) { lbCompoundLitElemTempData data = {}; data.value = value; - data.elem_index = k; + + data.elem_index = matrix_row_major_index_to_offset(bt, k); array_add(temp_data, data); } } else { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = lo; - data.elem_length = hi-lo; - array_add(temp_data, data); + enum {MAX_ELEMENT_AMOUNT = 32}; + if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = k; + array_add(temp_data, data); + } + } else { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = lo; + data.elem_length = hi-lo; + array_add(temp_data, data); + } } } else { auto tav = fv->field->tav; @@ -3558,7 +3568,11 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele lbCompoundLitElemTempData data = {}; data.value = value; data.expr = fv->value; - data.elem_index = cast(i32)index; + if (bt->kind == Type_Matrix) { + data.elem_index = matrix_row_major_index_to_offset(bt, index); + } else { + data.elem_index = index; + } array_add(temp_data, data); } @@ -3574,25 +3588,29 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele lbCompoundLitElemTempData data = {}; data.value = ev; - data.elem_index = cast(i32)i; + if (bt->kind == Type_Matrix) { + data.elem_index = matrix_row_major_index_to_offset(bt, i); + } else { + data.elem_index = i; + } array_add(temp_data, data); } } } -void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array &temp_data) { +void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array const &temp_data) { for_array(i, temp_data) { auto td = temp_data[i]; if (td.value.value != nullptr) { if (td.elem_length > 0) { auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32); { - lbValue dst = temp_data[i].gep; + lbValue dst = td.gep; dst = lb_emit_ptr_offset(p, dst, loop_data.idx); - lb_emit_store(p, dst, temp_data[i].value); + lb_emit_store(p, dst, td.value); } lb_loop_end(p, loop_data); } else { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + lb_emit_store(p, td.gep, td.value); } } } @@ -3907,93 +3925,14 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k); - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index); - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i); - array_add(&temp_data, data); - } - } + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + lbValue dst_ptr = lb_addr_get_ptr(p, v); for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, temp_data[i].elem_index); } - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } + lb_build_addr_compound_lit_assign_array(p, temp_data); } break; } @@ -4005,90 +3944,23 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // NOTE(bill): Separate value, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` // might be a better option - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value; - vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, ""); + auto td = temp_data[i]; + if (td.value.value != nullptr) { + if (td.elem_length > 0) { + for (i64 k = 0; k < td.elem_length; k++) { + LLVMValueRef index = lb_const_int(p->module, t_u32, td.elem_index + k).value; + vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); + } + } else { + LLVMValueRef index = lb_const_int(p->module, t_u32, td.elem_index).value; + vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); + + } } } } From a19494d3a789d43b7f2d2c3c79593bfef05a3876 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 16:12:07 +0100 Subject: [PATCH 26/40] Minor refactoring of `lb_build_addr` --- src/llvm_backend_expr.cpp | 820 +++++++++++++++++++------------------- 1 file changed, 417 insertions(+), 403 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f7ffe03f9..5fd2fbe6f 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3616,6 +3616,421 @@ void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Arrayexpr)); + + bool deref = is_type_pointer(t); + t = base_type(type_deref(t)); + if (is_type_soa_struct(t)) { + // SOA STRUCTURES!!!! + lbValue val = lb_build_addr_ptr(p, ie->expr); + if (deref) { + val = lb_emit_load(p, val); + } + + lbValue index = lb_build_expr(p, ie->index); + return lb_addr_soa_variable(val, index, ie->index); + } + + if (ie->expr->tav.mode == Addressing_SoaVariable) { + // SOA Structures for slices/dynamic arrays + GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); + + lbValue field = lb_build_expr(p, ie->expr); + lbValue index = lb_build_expr(p, ie->index); + + + if (!build_context.no_bounds_check) { + // TODO HACK(bill): Clean up this hack to get the length for bounds checking + // GB_ASSERT(LLVMIsALoadInst(field.value)); + + // lbValue a = {}; + // a.value = LLVMGetOperand(field.value, 0); + // a.type = alloc_type_pointer(field.type); + + // irInstr *b = &a->Instr; + // GB_ASSERT(b->kind == irInstr_StructElementPtr); + // lbValue base_struct = b->StructElementPtr.address; + + // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); + // lbValue len = ir_soa_struct_len(p, base_struct); + // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + lbValue val = lb_emit_ptr_offset(p, field, index); + return lb_addr(val); + } + + GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); + + if (is_type_map(t)) { + lbAddr map_addr = lb_build_addr(p, ie->expr); + lbValue map_val = lb_addr_load(p, map_addr); + if (deref) { + map_val = lb_emit_load(p, map_val); + } + + lbValue key = lb_build_expr(p, ie->index); + key = lb_emit_conv(p, key, t->Map.key); + + Type *result_type = type_of_expr(expr); + lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); + return lb_addr_map(map_ptr, key, t, result_type); + } + + switch (t->kind) { + case Type_Array: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_array_ep(p, array, index); + + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->Array.count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + case Type_EnumeratedArray: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + + Type *index_type = t->EnumeratedArray.index; + + auto index_tv = type_and_value_of_expr(ie->index); + + lbValue index = {}; + if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { + if (index_tv.mode == Addressing_Constant) { + ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); + index = lb_const_value(p->module, index_type, idx); + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); + } + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + } + + lbValue elem = lb_emit_array_ep(p, array, index); + + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + case Type_Slice: { + lbValue slice = {}; + slice = lb_build_expr(p, ie->expr); + if (deref) { + slice = lb_emit_load(p, slice); + } + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_MultiPointer: { + lbValue multi_ptr = {}; + multi_ptr = lb_build_expr(p, ie->expr); + if (deref) { + multi_ptr = lb_emit_load(p, multi_ptr); + } + lbValue index = lb_build_expr(p, ie->index); + lbValue v = {}; + + LLVMValueRef indices[1] = {index.value}; + v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); + v.type = alloc_type_pointer(t->MultiPointer.elem); + return lb_addr(v); + } + + case Type_RelativeSlice: { + lbAddr slice_addr = {}; + if (deref) { + slice_addr = lb_addr(lb_build_expr(p, ie->expr)); + } else { + slice_addr = lb_build_addr(p, ie->expr); + } + lbValue slice = lb_addr_load(p, slice_addr); + + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_DynamicArray: { + lbValue dynamic_array = {}; + dynamic_array = lb_build_expr(p, ie->expr); + if (deref) { + dynamic_array = lb_emit_load(p, dynamic_array); + } + lbValue elem = lb_dynamic_array_elem(p, dynamic_array); + lbValue len = lb_dynamic_array_len(p, dynamic_array); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_Matrix: { + lbValue matrix = {}; + matrix = lb_build_addr_ptr(p, ie->expr); + if (deref) { + matrix = lb_emit_load(p, matrix); + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); + elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); + + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + + case Type_Basic: { // Basic_string + lbValue str; + lbValue elem; + lbValue len; + lbValue index; + + str = lb_build_expr(p, ie->expr); + if (deref) { + str = lb_emit_load(p, str); + } + elem = lb_string_elem(p, str); + len = lb_string_len(p, str); + + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + + return lb_addr(lb_emit_ptr_offset(p, elem, index)); + } + } + return {}; +} + + +lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { + ast_node(se, SliceExpr, expr); + + lbValue low = lb_const_int(p->module, t_int, 0); + lbValue high = {}; + + if (se->low != nullptr) { + low = lb_correct_endianness(p, lb_build_expr(p, se->low)); + } + if (se->high != nullptr) { + high = lb_correct_endianness(p, lb_build_expr(p, se->high)); + } + + bool no_indices = se->low == nullptr && se->high == nullptr; + + lbAddr addr = lb_build_addr(p, se->expr); + lbValue base = lb_addr_load(p, addr); + Type *type = base_type(base.type); + + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + addr = lb_addr(base); + base = lb_addr_load(p, addr); + } + + switch (type->kind) { + case Type_Slice: { + Type *slice_type = type; + lbValue len = lb_slice_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_RelativeSlice: + GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); + break; + + case Type_DynamicArray: { + Type *elem_type = type->DynamicArray.elem; + Type *slice_type = alloc_type_slice(elem_type); + + lbValue len = lb_dynamic_array_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_MultiPointer: { + lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); + if (se->high == nullptr) { + lbValue offset = base; + LLVMValueRef indices[1] = {low.value}; + offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); + lb_addr_store(p, res, offset); + } else { + low = lb_emit_conv(p, low, t_int); + high = lb_emit_conv(p, high, t_int); + + lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + + LLVMValueRef indices[1] = {low.value}; + LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); + LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); + + LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; + LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; + LLVMBuildStore(p->builder, ptr, gep0); + LLVMBuildStore(p->builder, len, gep1); + } + return res; + } + + case Type_Array: { + Type *slice_type = alloc_type_slice(type->Array.elem); + lbValue len = lb_const_int(p->module, t_int, type->Array.count); + + if (high.value == nullptr) high = len; + + bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; + bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; + + if (!low_const || !high_const) { + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + } + lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_Basic: { + GB_ASSERT(type == t_string); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr str = lb_add_local_generated(p, t_string, false); + lb_fill_string(p, str, elem, new_len); + return str; + } + + + case Type_Struct: + if (is_type_soa_struct(type)) { + lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + #if 1 + + lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); + if (type->Struct.soa_kind == StructSoa_Fixed) { + i32 field_count = cast(i32)type->Struct.fields.count; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); + field_src = lb_emit_array_ep(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } else if (type->Struct.soa_kind == StructSoa_Slice) { + if (no_indices) { + lb_addr_store(p, dst, base); + } else { + i32 field_count = cast(i32)type->Struct.fields.count - 1; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } + } else if (type->Struct.soa_kind == StructSoa_Dynamic) { + i32 field_count = cast(i32)type->Struct.fields.count - 3; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } + + return dst; + #endif + } + break; + + } + + GB_PANIC("Unknown slicable type"); + return {}; +} + lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { ast_node(cl, CompoundLit, expr); @@ -4156,217 +4571,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(ie, IndexExpr, expr); - Type *t = base_type(type_of_expr(ie->expr)); - - bool deref = is_type_pointer(t); - t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { - // SOA STRUCTURES!!!! - lbValue val = lb_build_addr_ptr(p, ie->expr); - if (deref) { - val = lb_emit_load(p, val); - } - - lbValue index = lb_build_expr(p, ie->index); - return lb_addr_soa_variable(val, index, ie->index); - } - - if (ie->expr->tav.mode == Addressing_SoaVariable) { - // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); - - lbValue field = lb_build_expr(p, ie->expr); - lbValue index = lb_build_expr(p, ie->index); - - - if (!build_context.no_bounds_check) { - // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // GB_ASSERT(LLVMIsALoadInst(field.value)); - - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); - - // irInstr *b = &a->Instr; - // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // lbValue base_struct = b->StructElementPtr.address; - - // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // lbValue len = ir_soa_struct_len(p, base_struct); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - lbValue val = lb_emit_ptr_offset(p, field, index); - return lb_addr(val); - } - - GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); - - if (is_type_map(t)) { - lbAddr map_addr = lb_build_addr(p, ie->expr); - lbValue map_val = lb_addr_load(p, map_addr); - if (deref) { - map_val = lb_emit_load(p, map_val); - } - - lbValue key = lb_build_expr(p, ie->index); - key = lb_emit_conv(p, key, t->Map.key); - - Type *result_type = type_of_expr(expr); - lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); - return lb_addr_map(map_ptr, key, t, result_type); - } - - switch (t->kind) { - case Type_Array: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_array_ep(p, array, index); - - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Array.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - case Type_EnumeratedArray: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } - - Type *index_type = t->EnumeratedArray.index; - - auto index_tv = type_and_value_of_expr(ie->index); - - lbValue index = {}; - if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { - if (index_tv.mode == Addressing_Constant) { - ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); - index = lb_const_value(p->module, index_type, idx); - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); - } - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - } - - lbValue elem = lb_emit_array_ep(p, array, index); - - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - case Type_Slice: { - lbValue slice = {}; - slice = lb_build_expr(p, ie->expr); - if (deref) { - slice = lb_emit_load(p, slice); - } - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_MultiPointer: { - lbValue multi_ptr = {}; - multi_ptr = lb_build_expr(p, ie->expr); - if (deref) { - multi_ptr = lb_emit_load(p, multi_ptr); - } - lbValue index = lb_build_expr(p, ie->index); - lbValue v = {}; - - LLVMValueRef indices[1] = {index.value}; - v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); - v.type = alloc_type_pointer(t->MultiPointer.elem); - return lb_addr(v); - } - - case Type_RelativeSlice: { - lbAddr slice_addr = {}; - if (deref) { - slice_addr = lb_addr(lb_build_expr(p, ie->expr)); - } else { - slice_addr = lb_build_addr(p, ie->expr); - } - lbValue slice = lb_addr_load(p, slice_addr); - - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_DynamicArray: { - lbValue dynamic_array = {}; - dynamic_array = lb_build_expr(p, ie->expr); - if (deref) { - dynamic_array = lb_emit_load(p, dynamic_array); - } - lbValue elem = lb_dynamic_array_elem(p, dynamic_array); - lbValue len = lb_dynamic_array_len(p, dynamic_array); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_Matrix: { - lbValue matrix = {}; - matrix = lb_build_addr_ptr(p, ie->expr); - if (deref) { - matrix = lb_emit_load(p, matrix); - } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); - elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); - - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - - case Type_Basic: { // Basic_string - lbValue str; - lbValue elem; - lbValue len; - lbValue index; - - str = lb_build_expr(p, ie->expr); - if (deref) { - str = lb_emit_load(p, str); - } - elem = lb_string_elem(p, str); - len = lb_string_len(p, str); - - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - - return lb_addr(lb_emit_ptr_offset(p, elem, index)); - } - } + return lb_build_addr_index_expr(p, expr); case_end; case_ast_node(ie, MatrixIndexExpr, expr); @@ -4399,198 +4604,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(se, SliceExpr, expr); - - lbValue low = lb_const_int(p->module, t_int, 0); - lbValue high = {}; - - if (se->low != nullptr) { - low = lb_correct_endianness(p, lb_build_expr(p, se->low)); - } - if (se->high != nullptr) { - high = lb_correct_endianness(p, lb_build_expr(p, se->high)); - } - - bool no_indices = se->low == nullptr && se->high == nullptr; - - lbAddr addr = lb_build_addr(p, se->expr); - lbValue base = lb_addr_load(p, addr); - Type *type = base_type(base.type); - - if (is_type_pointer(type)) { - type = base_type(type_deref(type)); - addr = lb_addr(base); - base = lb_addr_load(p, addr); - } - - switch (type->kind) { - case Type_Slice: { - Type *slice_type = type; - lbValue len = lb_slice_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_RelativeSlice: - GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); - break; - - case Type_DynamicArray: { - Type *elem_type = type->DynamicArray.elem; - Type *slice_type = alloc_type_slice(elem_type); - - lbValue len = lb_dynamic_array_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_MultiPointer: { - lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); - if (se->high == nullptr) { - lbValue offset = base; - LLVMValueRef indices[1] = {low.value}; - offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); - lb_addr_store(p, res, offset); - } else { - low = lb_emit_conv(p, low, t_int); - high = lb_emit_conv(p, high, t_int); - - lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); - - LLVMValueRef indices[1] = {low.value}; - LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); - LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); - - LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; - LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; - LLVMBuildStore(p->builder, ptr, gep0); - LLVMBuildStore(p->builder, len, gep1); - } - return res; - } - - case Type_Array: { - Type *slice_type = alloc_type_slice(type->Array.elem); - lbValue len = lb_const_int(p->module, t_int, type->Array.count); - - if (high.value == nullptr) high = len; - - bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; - bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; - - if (!low_const || !high_const) { - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - } - lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_Basic: { - GB_ASSERT(type == t_string); - lbValue len = lb_string_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr str = lb_add_local_generated(p, t_string, false); - lb_fill_string(p, str, elem, new_len); - return str; - } - - - case Type_Struct: - if (is_type_soa_struct(type)) { - lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - #if 1 - - lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); - if (type->Struct.soa_kind == StructSoa_Fixed) { - i32 field_count = cast(i32)type->Struct.fields.count; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); - field_src = lb_emit_array_ep(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } else if (type->Struct.soa_kind == StructSoa_Slice) { - if (no_indices) { - lb_addr_store(p, dst, base); - } else { - i32 field_count = cast(i32)type->Struct.fields.count - 1; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } - } else if (type->Struct.soa_kind == StructSoa_Dynamic) { - i32 field_count = cast(i32)type->Struct.fields.count - 3; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } - - return dst; - #endif - } - break; - - } - - GB_PANIC("Unknown slicable type"); + return lb_build_addr_slice_expr(p, expr); case_end; case_ast_node(de, DerefExpr, expr); From de8bd88d2a6f0e99af6fe76442bcccd159724872 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 11:15:12 +0100 Subject: [PATCH 27/40] Clean up how procedures are typed in LLVM's dumb type system --- src/llvm_backend.cpp | 4 +-- src/llvm_backend_general.cpp | 47 +++++------------------------------- src/llvm_backend_proc.cpp | 22 +++++++++++------ 3 files changed, 22 insertions(+), 51 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6ee1541d6..6eec9103b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); if (startup_type_info) { - LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, ""); + OdinLLVMBuildCall(p, {startup_type_info->value, startup_type_info->type}, nullptr, 0); } if (objc_names) { - LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, ""); + OdinLLVMBuildCall(p, {objc_names->value, objc_names->type}, nullptr, 0); } for_array(i, global_variables) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index ee6980de4..65cc8c41d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -861,39 +861,6 @@ void lb_const_store(lbValue ptr, lbValue value) { LLVMSetInitializer(ptr.value, value.value); } - -bool lb_is_type_proc_recursive(Type *t) { - for (;;) { - if (t == nullptr) { - return false; - } - switch (t->kind) { - case Type_Named: - t = t->Named.base; - break; - case Type_Pointer: - t = t->Pointer.elem; - break; - case Type_Array: - t = t->Array.elem; - break; - case Type_EnumeratedArray: - t = t->EnumeratedArray.elem; - break; - case Type_Slice: - t = t->Slice.elem; - break; - case Type_DynamicArray: - t = t->DynamicArray.elem; - break; - case Type_Proc: - return true; - default: - return false; - } - } -} - void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT(value.value != nullptr); Type *a = type_deref(ptr.type); @@ -953,7 +920,7 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { } } - if (lb_is_type_proc_recursive(a)) { + if (is_type_proc(a)) { // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // stored as regular pointer with no procedure information @@ -1551,7 +1518,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { if (e->flags & EntityFlag_ByPtr) { param_type = lb_type(m, alloc_type_pointer(e_type)); } else if (is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { + type_size_of(e_type) <= 1) { param_type = LLVMInt1TypeInContext(m->ctx); } else { if (is_type_proc(e_type)) { @@ -2098,15 +2065,13 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } case Type_Proc: - // if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough? - if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? - return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); - } else { + { + // NOTE(bill): we do an explicit cast to the correct procedure type when calling the procedure LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type); - return LLVMPointerType(proc_raw_type, 0); + gb_unused(proc_raw_type); + return lb_type(m, t_rawptr); } - break; case Type_BitSet: { Type *ut = bit_set_to_int(type); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 392ff14c2..ade2a55cf 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1,6 +1,11 @@ +LLVMValueRef OdinLLVMBuildCall(lbProcedure *p, lbValue const &value, LLVMValueRef *args, unsigned arg_count) { + GB_ASSERT(is_type_proc(value.type)); + LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, value.type); + LLVMValueRef func = LLVMBuildPointerCast(p->builder, value.value, LLVMPointerType(type, 0), ""); + return LLVMBuildCall2(p->builder, type, func, args, arg_count, ""); +} -LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) -{ +LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) { unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); GB_ASSERT_MSG(id != 0, "Unable to find %s", name); LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count); @@ -740,6 +745,11 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } for_array(i, processed_args) { lbValue arg = processed_args[i]; + if (is_type_proc(arg.type)) { + // NOTE(bill): all procedure types (function pointers) are typed as if they are `rawptr` + // and then the correct type is set at the call site + arg.value = LLVMBuildPointerCast(p->builder, arg.value, lb_type(p->module, arg.type), ""); + } args[arg_index++] = arg.value; } if (context_ptr.addr.value != nullptr) { @@ -752,11 +762,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, { LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type); - LLVMTypeRef ftp = LLVMPointerType(fnp, 0); - LLVMValueRef fn = value.value; - if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { - fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); - } + GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); { @@ -780,7 +786,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } } - LLVMValueRef ret = LLVMBuildCall2(p->builder, fnp, fn, args, arg_count, ""); + LLVMValueRef ret = OdinLLVMBuildCall(p, value, args, arg_count); if (return_ptr.value != nullptr) { LLVMAddCallSiteAttribute(ret, 1, lb_create_enum_attribute_with_type(p->module->ctx, "sret", LLVMTypeOf(args[0]))); From 697c839c84b36b4e0c12ac9ea264e28f564ef5d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 12:29:11 +0100 Subject: [PATCH 28/40] Correct global constant procedure initialization --- src/llvm_backend.cpp | 12 ++++++++++++ src/llvm_backend_general.cpp | 7 ------- src/llvm_backend_type.cpp | 1 - 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6eec9103b..7a8f57fdd 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -758,6 +758,10 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start GB_ASSERT(e->kind == Entity_Variable); e->code_gen_module = entity_module; + if (e->token.string == "XXH3_init_custom_secret") { + gb_printf_err("HERE1\n"); + } + Ast *init_expr = var->decl->init_expr; if (init_expr != nullptr) { lbValue init = lb_build_expr(p, init_expr); @@ -780,6 +784,10 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start var->init = init; } else if (lb_is_const_or_global(init)) { if (!var->is_initialized) { + if (is_type_proc(init.type)) { + LLVMTypeRef global_type = llvm_addr_type(p->module, var->var); + init.value = LLVMConstPointerCast(init.value, global_type); + } LLVMSetInitializer(var->var.value, init.value); var->is_initialized = true; continue; @@ -1649,6 +1657,10 @@ void lb_generate_code(lbGenerator *gen) { if (tav.value.kind != ExactValue_Invalid) { ExactValue v = tav.value; lbValue init = lb_const_value(m, tav.type, v); + if (is_type_proc(init.type)) { + LLVMTypeRef global_type = llvm_addr_type(m, var.var); + init.value = LLVMConstPointerCast(init.value, global_type); + } LLVMSetInitializer(g.value, init.value); var.is_initialized = true; } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 65cc8c41d..8458d8687 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -854,13 +854,6 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { lb_emit_store(p, addr.addr, value); } -void lb_const_store(lbValue ptr, lbValue value) { - GB_ASSERT(lb_is_const(ptr)); - GB_ASSERT(lb_is_const(value)); - GB_ASSERT(is_type_pointer(ptr.type)); - LLVMSetInitializer(ptr.value, value.value); -} - void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT(value.value != nullptr); Type *a = type_deref(ptr.type); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index d424fa5b2..c29713881 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -554,7 +554,6 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue index = lb_const_int(m, t_int, i); lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - // TODO(bill): Make this constant if possible, 'lb_const_store' does not work lb_emit_store(p, type_info, lb_type_info(m, f->type)); if (f->token.string.len > 0) { lbValue name = lb_emit_ptr_offset(p, memory_names, index); From 22d16c20f8e446fb51d7faa14f22b9f86df8b393 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 12:29:32 +0100 Subject: [PATCH 29/40] Remove debug message --- src/llvm_backend.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7a8f57fdd..64b2ac5f3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -758,10 +758,6 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start GB_ASSERT(e->kind == Entity_Variable); e->code_gen_module = entity_module; - if (e->token.string == "XXH3_init_custom_secret") { - gb_printf_err("HERE1\n"); - } - Ast *init_expr = var->decl->init_expr; if (init_expr != nullptr) { lbValue init = lb_build_expr(p, init_expr); From 107e016508189d366e6c628f93d0729cbd5873f3 Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Fri, 12 Aug 2022 13:42:19 +0200 Subject: [PATCH 30/40] switch styling and opt.spaces max --- core/encoding/json/marshal.odin | 109 ++++++++++++++------------------ 1 file changed, 47 insertions(+), 62 deletions(-) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 9dbe31cb6..55a28f85a 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -17,7 +17,7 @@ Marshal_Error :: union #shared_nil { io.Error, } -// NOTE careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results +// careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results Marshal_Options :: struct { // output based on spec spec: Specification, @@ -44,7 +44,7 @@ Marshal_Options :: struct { mjson_skipped_first_braces_end: bool, } -marshal :: proc(v: any, opt := Marshal_Options{}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { +marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { b := strings.builder_make(allocator) defer if err != nil { strings.builder_destroy(&b) @@ -116,13 +116,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: // allow uints to be printed as hex if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) { switch i in a { - case u8, u16, u32, u64, u128: { - s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) - } + case u8, u16, u32, u64, u128: + s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) - case: { - s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) - } + case: + s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) } } else { s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) @@ -192,9 +190,6 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Multi_Pointer: return .Unsupported_Type - case runtime.Type_Info_Soa_Pointer: - return .Unsupported_Type - case runtime.Type_Info_Procedure: return .Unsupported_Type @@ -281,19 +276,14 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: name: string #partial switch info in ti.variant { - case runtime.Type_Info_String: { - switch s in a { - case string: name = s - case cstring: name = string(s) - } - - opt_write_key(w, opt, name) or_return + case runtime.Type_Info_String: + switch s in a { + case string: name = s + case cstring: name = string(s) } + opt_write_key(w, opt, name) or_return - case: { - // TODO better error output? - return .Unsupported_Type - } + case: return .Unsupported_Type } } @@ -402,23 +392,21 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: // write key as quoted string or with optional quotes in mjson opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) { switch opt.spec { - case .JSON, .JSON5: { - io.write_quoted_string(w, name) or_return - io.write_string(w, ": ") or_return - } + case .JSON, .JSON5: + io.write_quoted_string(w, name) or_return + io.write_string(w, ": ") or_return - case .MJSON: { - if opt.mjson_keys_use_quotes { - io.write_quoted_string(w, name) or_return - } else { - io.write_string(w, name) or_return - } - - if opt.mjson_keys_use_equal_sign { - io.write_string(w, " = ") or_return - } else { - io.write_string(w, ": ") or_return - } + case .MJSON: + if opt.mjson_keys_use_quotes { + io.write_quoted_string(w, name) or_return + } else { + io.write_string(w, name) or_return + } + + if opt.mjson_keys_use_equal_sign { + io.write_string(w, " = ") or_return + } else { + io.write_string(w, ": ") or_return } } @@ -446,31 +434,29 @@ opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: i // insert comma seperation and write indentations opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) { switch opt.spec { - case .JSON, .JSON5: { - if iteration > 0 { + case .JSON, .JSON5: + if iteration > 0 { + io.write_string(w, ", ") or_return + + if opt.pretty { + io.write_byte(w, '\n') or_return + } + } + + opt_write_indentation(w, opt) or_return + + case .MJSON: + if iteration > 0 { + // on pretty no commas necessary + if opt.pretty { + io.write_byte(w, '\n') or_return + } else { + // comma seperation necessary for non pretty output! io.write_string(w, ", ") or_return - - if opt.pretty { - io.write_byte(w, '\n') or_return - } } - - opt_write_indentation(w, opt) or_return } - case .MJSON: { - if iteration > 0 { - // on pretty no commas necessary - if opt.pretty { - io.write_byte(w, '\n') or_return - } else { - // NOTE comma seperation necessary for non pretty output! - io.write_string(w, ", ") or_return - } - } - - opt_write_indentation(w, opt) or_return - } + opt_write_indentation(w, opt) or_return } return @@ -502,10 +488,9 @@ opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.E return } - // TODO optimize? if opt.use_spaces { - // NOTE maybe max(1, opt.spaces) - for _ in 0.. Date: Fri, 12 Aug 2022 13:50:19 +0200 Subject: [PATCH 31/40] add new soa type, my bad wasnt on master --- core/encoding/json/marshal.odin | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 55a28f85a..37e2257f5 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -190,6 +190,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Multi_Pointer: return .Unsupported_Type + case Type_Info_Soa_Pointer: + return .Unsupported_Type + case runtime.Type_Info_Procedure: return .Unsupported_Type From b739044e69431e41c7fce0f40a62ebc6adf673ca Mon Sep 17 00:00:00 2001 From: Michael Kutowski Date: Fri, 12 Aug 2022 13:59:11 +0200 Subject: [PATCH 32/40] Update marshal.odin --- core/encoding/json/marshal.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 37e2257f5..8cc814fcf 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -190,7 +190,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Multi_Pointer: return .Unsupported_Type - case Type_Info_Soa_Pointer: + case runtime.Type_Info_Soa_Pointer: return .Unsupported_Type case runtime.Type_Info_Procedure: From 8e7c7eeebabcf81e6ca06e44ae8b98554addd142 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 13:48:10 +0100 Subject: [PATCH 33/40] Fix `lb_emit_ptr_offset` --- src/llvm_backend_proc.cpp | 10 +--------- src/llvm_backend_utility.cpp | 2 +- src/types.cpp | 7 ++++++- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ade2a55cf..784366476 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2077,15 +2077,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue ptr = lb_build_expr(p, ce->args[0]); lbValue len = lb_build_expr(p, ce->args[1]); len = lb_emit_conv(p, len, t_int); - - LLVMValueRef indices[1] = { - len.value, - }; - - lbValue res = {}; - res.type = tv.type; - res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, type_deref(tv.type)), ptr.value, indices, gb_count_of(indices), ""); - return res; + return lb_emit_ptr_offset(p, ptr, len); } case BuiltinProc_ptr_sub: { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index ce7b43321..35e69a1be 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1285,7 +1285,7 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { LLVMValueRef indices[1] = {index.value}; lbValue res = {}; res.type = ptr.type; - LLVMTypeRef type = lb_type(p->module, type_deref(ptr.type)); + LLVMTypeRef type = lb_type(p->module, type_deref(res.type, true)); if (lb_is_const(ptr) && lb_is_const(index)) { res.value = LLVMConstGEP2(type, ptr.value, indices, 1); diff --git a/src/types.cpp b/src/types.cpp index cba27fd6f..56b310867 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1115,7 +1115,7 @@ Type *alloc_type_simd_vector(i64 count, Type *elem, Type *generic_count=nullptr) //////////////////////////////////////////////////////////////// -Type *type_deref(Type *t) { +Type *type_deref(Type *t, bool allow_multi_pointer=false) { if (t != nullptr) { Type *bt = base_type(t); if (bt == nullptr) { @@ -1132,6 +1132,11 @@ Type *type_deref(Type *t) { GB_ASSERT(elem->kind == Type_Struct && elem->Struct.soa_kind != StructSoa_None); return elem->Struct.soa_elem; } + case Type_MultiPointer: + if (allow_multi_pointer) { + return bt->MultiPointer.elem; + } + break; } } return t; From 929af320da564ff5ec739811920a16999afb6880 Mon Sep 17 00:00:00 2001 From: Fabian Sperber Date: Wed, 27 Jul 2022 22:49:08 +0200 Subject: [PATCH 34/40] Add more windows bindings --- core/sys/windows/user32.odin | 32 +++++++++++++++++++++- core/sys/windows/window_messages.odin | 39 +++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index d0a0d5b0a..90961ba8c 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -42,6 +42,7 @@ foreign user32 { GetTopWindow :: proc(hWnd: HWND) -> HWND --- SetForegroundWindow :: proc(hWnd: HWND) -> BOOL --- GetForegroundWindow :: proc() -> HWND --- + UpdateWindow :: proc(hWnd: HWND) -> BOOL --- SetActiveWindow :: proc(hWnd: HWND) -> HWND --- GetActiveWindow :: proc() -> HWND --- @@ -95,6 +96,7 @@ foreign user32 { GetSystemMetrics :: proc(nIndex: c_int) -> c_int --- AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL --- AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL --- + AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL --- SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL --- @@ -137,7 +139,19 @@ foreign user32 { SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR --- EnumDisplaySettingsW :: proc(lpszDeviceName: LPCWSTR, iModeNum: DWORD, lpDevMode: ^DEVMODEW) -> BOOL --- - + + MonitorFromPoint :: proc(pt: POINT, dwFlags: Monitor_From_Flags) -> HMONITOR --- + MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR --- + MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR --- + EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL --- + + SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- + GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- + GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT --- + GetDpiFromDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> UINT --- + GetDpiForWindow :: proc(hwnd: HWND) -> UINT --- + SetProcessDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> BOOL --- + BroadcastSystemMessageW :: proc( flags: DWORD, lpInfo: LPDWORD, @@ -247,3 +261,19 @@ GET_XBUTTON_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD MAKEINTRESOURCEW :: #force_inline proc "contextless" (#any_int i: int) -> LPWSTR { return cast(LPWSTR)uintptr(WORD(i)) } + +Monitor_From_Flags :: enum DWORD { + MONITOR_DEFAULTTONULL = 0x00000000, // Returns NULL + MONITOR_DEFAULTTOPRIMARY = 0x00000001, // Returns a handle to the primary display monitor + MONITOR_DEFAULTTONEAREST = 0x00000002, // Returns a handle to the display monitor that is nearest to the window +} + +Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL + +USER_DEFAULT_SCREEN_DPI :: 96 +DPI_AWARENESS_CONTEXT :: distinct HANDLE +DPI_AWARENESS_CONTEXT_UNAWARE :: DPI_AWARENESS_CONTEXT(~uintptr(0)) // -1 +DPI_AWARENESS_CONTEXT_SYSTEM_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(1)) // -2 +DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(2)) // -3 +DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 :: DPI_AWARENESS_CONTEXT(~uintptr(3)) // -4 +DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED :: DPI_AWARENESS_CONTEXT(~uintptr(4)) // -5 diff --git a/core/sys/windows/window_messages.odin b/core/sys/windows/window_messages.odin index d6b883916..7ce9e545c 100644 --- a/core/sys/windows/window_messages.odin +++ b/core/sys/windows/window_messages.odin @@ -153,6 +153,7 @@ BM_CLICK :: 0x00f5 BM_GETIMAGE :: 0x00f6 BM_SETIMAGE :: 0x00f7 BM_SETDONTCLICK :: 0x00f8 +WM_INPUT_DEVICE_CHANGE :: 0x00fe WM_INPUT :: 0x00ff WM_KEYDOWN :: 0x0100 WM_KEYFIRST :: 0x0100 @@ -165,6 +166,7 @@ WM_SYSCHAR :: 0x0106 WM_SYSDEADCHAR :: 0x0107 WM_UNICHAR :: 0x0109 WM_KEYLAST :: 0x0109 +UNICODE_NOCHAR :: 0xFFFF WM_WNT_CONVERTREQUESTEX :: 0x0109 WM_CONVERTREQUEST :: 0x010a WM_CONVERTRESULT :: 0x010b @@ -279,6 +281,27 @@ WM_ENTERSIZEMOVE :: 0x0231 WM_EXITSIZEMOVE :: 0x0232 WM_DROPFILES :: 0x0233 WM_MDIREFRESHMENU :: 0x0234 +WM_POINTERDEVICECHANGE :: 0x0238 +WM_POINTERDEVICEINRANGE :: 0x0239 +WM_POINTERDEVICEOUTOFRANGE :: 0x023a +WM_TOUCH :: 0x0240 +WM_NCPOINTERUPDATE :: 0x0241 +WM_NCPOINTERDOWN :: 0x0242 +WM_NCPOINTERUP :: 0x0243 +WM_POINTERUPDATE :: 0x0245 +WM_POINTERDOWN :: 0x0246 +WM_POINTERUP :: 0x0247 +WM_POINTERENTER :: 0x0249 +WM_POINTERLEAVE :: 0x024a +WM_POINTERACTIVATE :: 0x024b +WM_POINTERCAPTURECHANGED :: 0x024c +WM_TOUCHHITTESTING :: 0x024d +WM_POINTERWHEEL :: 0x024e +WM_POINTERHWHEEL :: 0x024f +DM_POINTERHITTEST :: 0x0250 +WM_POINTERROUTEDTO :: 0x0251 +WM_POINTERROUTEDAWAY :: 0x0252 +WM_POINTERROUTEDRELEASED :: 0x0253 WM_IME_REPORT :: 0x0280 WM_IME_SETCONTEXT :: 0x0281 WM_IME_NOTIFY :: 0x0282 @@ -295,6 +318,13 @@ WM_NCMOUSEHOVER :: 0x02a0 WM_MOUSEHOVER :: 0x02a1 WM_NCMOUSELEAVE :: 0x02a2 WM_MOUSELEAVE :: 0x02a3 +WM_WTSSESSION_CHANGE :: 0x02b1 +WM_TABLET_FIRST :: 0x02c0 +WM_TABLET_LAST :: 0x02df +WM_DPICHANGED :: 0x02e0 +WM_DPICHANGED_BEFOREPARENT :: 0x02e2 +WM_DPICHANGED_AFTERPARENT :: 0x02e3 +WM_GETDPISCALEDSIZE :: 0x02e4 WM_CUT :: 0x0300 WM_COPY :: 0x0301 WM_PASTE :: 0x0302 @@ -317,6 +347,15 @@ WM_HOTKEY :: 0x0312 WM_PRINT :: 0x0317 WM_PRINTCLIENT :: 0x0318 WM_APPCOMMAND :: 0x0319 +WM_THEMECHANGED :: 0x031A +WM_CLIPBOARDUPDATE :: 0x031D +WM_DWMCOMPOSITIONCHANGED :: 0x031E +WM_DWMNCRENDERINGCHANGED :: 0x031F +WM_DWMCOLORIZATIONCOLORCHANGED:: 0x0320 +WM_DWMWINDOWMAXIMIZEDCHANGE :: 0x0321 +WM_DWMSENDICONICTHUMBNAIL :: 0x0323 +WM_DWMSENDICONICLIVEPREVIEWBITMAP :: 0x0326 +WM_GETTITLEBARINFOEX :: 0x033F WM_HANDHELDFIRST :: 0x0358 WM_HANDHELDLAST :: 0x035f WM_AFXFIRST :: 0x0360 From e50648279d29e2fd158e4edbb15d483802038765 Mon Sep 17 00:00:00 2001 From: Fabian Sperber Date: Mon, 1 Aug 2022 21:09:38 +0200 Subject: [PATCH 35/40] Add some wgl extensions - fix upper case for wglSwapIntervalEXT to be the same as the exported name --- core/sys/windows/wgl.odin | 2 +- core/sys/windows/wglext.odin | 147 +++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 core/sys/windows/wglext.odin diff --git a/core/sys/windows/wgl.odin b/core/sys/windows/wgl.odin index 689a41dea..150358d01 100644 --- a/core/sys/windows/wgl.odin +++ b/core/sys/windows/wgl.odin @@ -62,7 +62,7 @@ GetExtensionsStringARBType :: #type proc "c" (HDC) -> cstring // Procedures wglCreateContextAttribsARB: CreateContextAttribsARBType wglChoosePixelFormatARB: ChoosePixelFormatARBType - wglSwapIntervalExt: SwapIntervalEXTType + wglSwapIntervalEXT: SwapIntervalEXTType wglGetExtensionsStringARB: GetExtensionsStringARBType diff --git a/core/sys/windows/wglext.odin b/core/sys/windows/wglext.odin new file mode 100644 index 000000000..0c4b51d65 --- /dev/null +++ b/core/sys/windows/wglext.odin @@ -0,0 +1,147 @@ +// +build windows +package sys_windows + +// WGL_ARB_buffer_region +WGL_FRONT_COLOR_BUFFER_BIT_ARB :: 0x00000001 +WGL_BACK_COLOR_BUFFER_BIT_ARB :: 0x00000002 +WGL_DEPTH_BUFFER_BIT_ARB :: 0x00000004 +WGL_STENCIL_BUFFER_BIT_ARB :: 0x00000008 + +wglCreateBufferRegionARBType :: #type proc "c" (hDC: HDC, iLayerPlane: c_int, uType: UINT) -> HANDLE +wglDeleteBufferRegionARBType :: #type proc "c" (hRegion: HANDLE) +wglSaveBufferRegionARBType :: #type proc "c" (hRegion: HANDLE, x: c_int, y: c_int, width: c_int, height: c_int) -> BOOL +wglRestoreBufferRegionARBType :: #type proc "c" (hRegion: HANDLE, x: c_int, y: c_int, width: c_int, height: c_int, xSrc: c_int, ySrc: c_int) -> BOOL + +// wglCreateBufferRegionARB: wglCreateBufferRegionARBType +// wglDeleteBufferRegionARB: wglDeleteBufferRegionARBType +// wglSaveBufferRegionARB: wglSaveBufferRegionARBType +// wglRestoreBufferRegionARB: wglRestoreBufferRegionARBType + +// WGL_ARB_context_flush_control +WGL_CONTEXT_RELEASE_BEHAVIOR_ARB :: 0x2097 +WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB :: 0 +WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :: 0x2098 + +// WGL_ARB_create_context +WGL_CONTEXT_DEBUG_BIT_ARB :: 0x0001 +WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002 +WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091 +WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092 +WGL_CONTEXT_LAYER_PLANE_ARB :: 0x2093 +WGL_CONTEXT_FLAGS_ARB :: 0x2094 +ERROR_INVALID_VERSION_ARB :: 0x2095 + +// WGL_ARB_create_context_no_error +WGL_CONTEXT_OPENGL_NO_ERROR_ARB :: 0x31B3 + +// WGL_ARB_create_context_profile +WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126 +WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001 +WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002 +ERROR_INVALID_PROFILE_ARB :: 0x2096 + +// WGL_ARB_create_context_robustness +WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB :: 0x00000004 +WGL_LOSE_CONTEXT_ON_RESET_ARB :: 0x8252 +WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB :: 0x8256 +WGL_NO_RESET_NOTIFICATION_ARB :: 0x8261 + +// WGL_ARB_framebuffer_sRGB +WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB :: 0x20A9 + +// WGL_ARB_make_current_read +ERROR_INVALID_PIXEL_TYPE_ARB :: 0x2043 +ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB :: 0x2054 + +wglMakeContextCurrentARBType :: #type proc "c" (hDrawDC: HDC, hReadDC:HDC, hglrc: HGLRC) -> BOOL +wglGetCurrentReadDCARBType :: #type proc "c" () -> HDC + +// wglMakeContextCurrentARB: wglMakeContextCurrentARBType +// wglGetCurrentReadDCARB: wglGetCurrentReadDCARBType + +// WGL_ARB_multisample +WGL_SAMPLE_BUFFERS_ARB :: 0x2041 +WGL_SAMPLES_ARB :: 0x2042 + +// WGL_ARB_pbuffer +HPBUFFERARB :: distinct rawptr +WGL_DRAW_TO_PBUFFER_ARB :: 0x202D +WGL_MAX_PBUFFER_PIXELS_ARB :: 0x202E +WGL_MAX_PBUFFER_WIDTH_ARB :: 0x202F +WGL_MAX_PBUFFER_HEIGHT_ARB :: 0x2030 +WGL_PBUFFER_LARGEST_ARB :: 0x2033 +WGL_PBUFFER_WIDTH_ARB :: 0x2034 +WGL_PBUFFER_HEIGHT_ARB :: 0x2035 +WGL_PBUFFER_LOST_ARB :: 0x2036 + +wglCreatePbufferARBType :: #type proc "c" (hDC: HDC, iPixelFormat, iWidth, iHeight: c_int, piAttribList: [^]c_int) -> HPBUFFERARB +wglGetPbufferDCARBType :: #type proc "c" (hPbuffer: HPBUFFERARB) -> HDC +wglReleasePbufferDCARBType :: #type proc "c" (hPbuffer: HPBUFFERARB, hDC: HDC) -> c_int +wglDestroyPbufferARBType :: #type proc "c" (hPbuffer: HPBUFFERARB) -> BOOL +wglQueryPbufferARBType :: #type proc "c" (hPbuffer: HPBUFFERARB, iAttribute: c_int, piValue: ^c_int) -> BOOL + +// wglCreatePbufferARB: wglCreatePbufferARBType +// wglGetPbufferDCARB: wglGetPbufferDCARBType +// wglReleasePbufferDCARB: wglReleasePbufferDCARBType +// wglDestroyPbufferARB: wglDestroyPbufferARBType +// wglQueryPbufferARB: wglQueryPbufferARBType + +// WGL_ARB_pixel_format +WGL_NUMBER_PIXEL_FORMATS_ARB :: 0x2000 +WGL_DRAW_TO_WINDOW_ARB :: 0x2001 +WGL_DRAW_TO_BITMAP_ARB :: 0x2002 +WGL_ACCELERATION_ARB :: 0x2003 +WGL_NEED_PALETTE_ARB :: 0x2004 +WGL_NEED_SYSTEM_PALETTE_ARB :: 0x2005 +WGL_SWAP_LAYER_BUFFERS_ARB :: 0x2006 +WGL_SWAP_METHOD_ARB :: 0x2007 +WGL_NUMBER_OVERLAYS_ARB :: 0x2008 +WGL_NUMBER_UNDERLAYS_ARB :: 0x2009 +WGL_TRANSPARENT_ARB :: 0x200A +WGL_TRANSPARENT_RED_VALUE_ARB :: 0x2037 +WGL_TRANSPARENT_GREEN_VALUE_ARB :: 0x2038 +WGL_TRANSPARENT_BLUE_VALUE_ARB :: 0x2039 +WGL_TRANSPARENT_ALPHA_VALUE_ARB :: 0x203A +WGL_TRANSPARENT_INDEX_VALUE_ARB :: 0x203B +WGL_SHARE_DEPTH_ARB :: 0x200C +WGL_SHARE_STENCIL_ARB :: 0x200D +WGL_SHARE_ACCUM_ARB :: 0x200E +WGL_SUPPORT_GDI_ARB :: 0x200F +WGL_SUPPORT_OPENGL_ARB :: 0x2010 +WGL_DOUBLE_BUFFER_ARB :: 0x2011 +WGL_STEREO_ARB :: 0x2012 +WGL_PIXEL_TYPE_ARB :: 0x2013 +WGL_COLOR_BITS_ARB :: 0x2014 +WGL_RED_BITS_ARB :: 0x2015 +WGL_RED_SHIFT_ARB :: 0x2016 +WGL_GREEN_BITS_ARB :: 0x2017 +WGL_GREEN_SHIFT_ARB :: 0x2018 +WGL_BLUE_BITS_ARB :: 0x2019 +WGL_BLUE_SHIFT_ARB :: 0x201A +WGL_ALPHA_BITS_ARB :: 0x201B +WGL_ALPHA_SHIFT_ARB :: 0x201C +WGL_ACCUM_BITS_ARB :: 0x201D +WGL_ACCUM_RED_BITS_ARB :: 0x201E +WGL_ACCUM_GREEN_BITS_ARB :: 0x201F +WGL_ACCUM_BLUE_BITS_ARB :: 0x2020 +WGL_ACCUM_ALPHA_BITS_ARB :: 0x2021 +WGL_DEPTH_BITS_ARB :: 0x2022 +WGL_STENCIL_BITS_ARB :: 0x2023 +WGL_AUX_BUFFERS_ARB :: 0x2024 +WGL_NO_ACCELERATION_ARB :: 0x2025 +WGL_GENERIC_ACCELERATION_ARB :: 0x2026 +WGL_FULL_ACCELERATION_ARB :: 0x2027 +WGL_SWAP_EXCHANGE_ARB :: 0x2028 +WGL_SWAP_COPY_ARB :: 0x2029 +WGL_SWAP_UNDEFINED_ARB :: 0x202A +WGL_TYPE_RGBA_ARB :: 0x202B +WGL_TYPE_COLORINDEX_ARB :: 0x202C + +wglGetPixelFormatAttribivARBType :: #type proc "c" (hdc: HDC, iPixelFormat, iLayerPlane: c_int, nAttributes: UINT, piAttributes: [^]c_int, piValues: [^]c_int) -> BOOL +wglGetPixelFormatAttribfvARBType :: #type proc "c" (hdc: HDC, iPixelFormat, iLayerPlane: c_int, nAttributes: UINT, piAttributes: [^]c_int, pfValues: [^]f32) -> BOOL + +// wglGetPixelFormatAttribivARB: wglGetPixelFormatAttribivARBType +// wglGetPixelFormatAttribfvARB: wglGetPixelFormatAttribfvARBType + +// WGL_ARB_pixel_format_float +WGL_TYPE_RGBA_FLOAT_ARB :: 0x21A0 From 081e36c909529ce7ff5d74ae6b78e31a26691b9e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 13 Aug 2022 15:34:52 +0200 Subject: [PATCH 36/40] Add additional mouse buttons to Raylib bindings. --- vendor/raylib/raylib.odin | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index a694c83a4..1a7f81577 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -625,9 +625,13 @@ KeyboardKey :: enum c.int { // Mouse buttons MouseButton :: enum c.int { - LEFT = 0, - RIGHT = 1, - MIDDLE = 2, + LEFT = 0, // Mouse button left + RIGHT = 1, // Mouse button right + MIDDLE = 2, // Mouse button middle (pressed wheel) + SIDE = 3, // Mouse button side (advanced mouse device) + EXTRA = 4, // Mouse button extra (advanced mouse device) + FORWARD = 5, // Mouse button fordward (advanced mouse device) + BACK = 6, // Mouse button back (advanced mouse device) } // Mouse cursor From 3dc62a67e0d06db4dea1ace9b451de3520e2cf27 Mon Sep 17 00:00:00 2001 From: matias Date: Sun, 14 Aug 2022 07:16:54 -0400 Subject: [PATCH 37/40] Typo: "Get" -> "Set" --- core/sys/windows/user32.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 90961ba8c..4b3d3e68e 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -235,7 +235,7 @@ when ODIN_ARCH == .amd64 { SetClassLongPtrW :: SetClassLongW GetWindowLongPtrW :: GetWindowLongW - SetWindowLongPtrW :: GetWindowLongW + SetWindowLongPtrW :: SetWindowLongW } GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_int { From 81799f7f7861a9bdb228dd4b7f030afaaaf11054 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Aug 2022 21:50:21 +0100 Subject: [PATCH 38/40] Fix #1950 --- core/odin/parser/parser.odin | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 470aaccbd..f4f43e482 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -4,6 +4,7 @@ import "core:odin/ast" import "core:odin/tokenizer" import "core:fmt" +import "core:reflect" Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any) Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any) @@ -245,12 +246,7 @@ peek_token :: proc(p: ^Parser, lookahead := 0) -> (tok: tokenizer.Token) { return } skip_possible_newline :: proc(p: ^Parser) -> bool { - if .Optional_Semicolons not_in p.flags { - return false - } - - prev := p.curr_tok - if tokenizer.is_newline(prev) { + if tokenizer.is_newline(p.curr_tok) { advance_token(p) return true } From a83ca2120ed1c7f1d5486ad5a25cb2850edac875 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Aug 2022 21:50:41 +0100 Subject: [PATCH 39/40] Remove unused import --- core/odin/parser/parser.odin | 1 - 1 file changed, 1 deletion(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index f4f43e482..bd1422da3 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -4,7 +4,6 @@ import "core:odin/ast" import "core:odin/tokenizer" import "core:fmt" -import "core:reflect" Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any) Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any) From 5c298c150104553dab4e8b18adb0b39cf278a471 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Aug 2022 10:22:32 +0100 Subject: [PATCH 40/40] Minor text alignment --- core/mem/virtual/growing_arena.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/mem/virtual/growing_arena.odin b/core/mem/virtual/growing_arena.odin index f7f32b48e..f1067071b 100644 --- a/core/mem/virtual/growing_arena.odin +++ b/core/mem/virtual/growing_arena.odin @@ -102,9 +102,9 @@ growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator { } growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, - size, alignment: int, - old_memory: rawptr, old_size: int, - location := #caller_location) -> (data: []byte, err: Allocator_Error) { + size, alignment: int, + old_memory: rawptr, old_size: int, + location := #caller_location) -> (data: []byte, err: Allocator_Error) { arena := (^Growing_Arena)(allocator_data) switch mode {