From 16c176dc89ee4557a3e86803434de6d5f07d55f4 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:03:06 +0200 Subject: Implement new union intrinsics and add support for len/cap --- src/check_builtin.cpp | 139 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 49095a7a8..8fae04b6e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1780,7 +1780,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; - } + } else if (is_type_union(op_type)) { + Type *u = base_type(op_type); + mode = Addressing_Constant; + value = exact_value_i64(u->Union.variants.count); + type = t_untyped_integer; + } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; } @@ -5117,6 +5122,138 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_union_tag: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Type; + operand->type = union_tag_type(u); + } + break; + + case BuiltinProc_type_union_tag_offset: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + // NOTE(jakubtomsu): forces calculation of variant_block_size + type_size_of(u); + i64 tag_offset = u->Union.variant_block_size; + GB_ASSERT(tag_offset > 0); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(tag_offset); + } + break; + + case BuiltinProc_type_variant_type: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + Operand x = {}; + check_expr_or_type(c, &x, ce->args[1]); + if (!is_type_integer(x.type) || x.mode != Addressing_Constant) { + error(call, "Expected a constant integer for '%.*s", LIT(builtin_name)); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + i64 index = big_int_to_i64(&x.value.value_integer); + if (u->Union.kind != UnionType_no_nil) { + index -= 1; + } + + if (index < 0 || index >= u->Union.variants.count) { + error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name)); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + operand->mode = Addressing_Type; + operand->type = u->Union.variants[index]; + } + break; + + case BuiltinProc_type_variant_tag: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *v = check_type(c, ce->args[1]); + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(union_variant_index(u, v)); + } + break; + case BuiltinProc_type_struct_field_count: operand->value = exact_value_i64(0); if (operand->mode != Addressing_Type) { -- cgit v1.2.3 From f7e05162547c9444261a215992ea3c39f22a90b6 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:47:18 +0200 Subject: Fix the intrinsics, add min and max --- src/check_builtin.cpp | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8fae04b6e..a26ac4baa 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2597,7 +2597,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2662,6 +2662,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.min_value; return true; + } else if (is_type_union(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + i64 min_tag = bt->Union.kind == UnionType_no_nil ? 0 : 1; + operand->value = exact_value_i64(min_tag); + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -2766,7 +2774,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2836,6 +2844,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.max_value; return true; + } else if (is_type_union(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + i64 max_tag = (bt->Union.kind == UnionType_no_nil ? 0 : 1) + bt->Union.variants.count - 1; + operand->value = exact_value_i64(max_tag); + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -5180,7 +5196,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_variant_type: + case BuiltinProc_type_variant_type_of: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -5210,10 +5226,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } i64 index = big_int_to_i64(&x.value.value_integer); - if (u->Union.kind != UnionType_no_nil) { - index -= 1; - } - if (index < 0 || index >= u->Union.variants.count) { error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name)); operand->mode = Addressing_Type; @@ -5226,7 +5238,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_variant_tag: + case BuiltinProc_type_variant_index_of: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -5247,10 +5259,26 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *v = check_type(c, ce->args[1]); u = base_type(u); GB_ASSERT(u->kind == Type_Union); + + i64 index = -1; + for_array(i, u->Union.variants) { + Type *vt = u->Union.variants[i]; + if (union_variant_index_types_equal(v, vt)) { + index = i64(i); + break; + } + } + + if (index < 0) { + error(operand->expr, "Expected a variant type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } operand->mode = Addressing_Constant; operand->type = t_untyped_integer; - operand->value = exact_value_i64(union_variant_index(u, v)); + operand->value = exact_value_i64(index); } break; -- cgit v1.2.3 From 2f8d60ec47b32206172839c2d96b66cb872985be Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:33:27 +0200 Subject: Fix indentation --- src/check_builtin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a26ac4baa..7cadf49a0 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1781,11 +1781,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; } else if (is_type_union(op_type)) { - Type *u = base_type(op_type); + Type *u = base_type(op_type); mode = Addressing_Constant; value = exact_value_i64(u->Union.variants.count); type = t_untyped_integer; - } + } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; } -- cgit v1.2.3 From 625cb032841c86d046d0ceb8123936bd393785ea Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:23:24 +0200 Subject: Rename type_union_tag to type_union_tag_type --- core/intrinsics/intrinsics.odin | 4 +- src/check_builtin.cpp | 2 +- src/checker_builtin_procs.hpp | 4 +- test.odin | 272 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+), 5 deletions(-) create mode 100644 test.odin (limited to 'src/check_builtin.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 505309a8e..62f3d1ad2 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -164,9 +164,9 @@ type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- -type_union_tag :: proc($U: typeid) -> typeid where type_is_union(U) --- +type_union_tag_type :: proc($U: typeid) -> typeid where type_is_union(U) --- type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- -type_variant_type_of_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_variant_type_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7cadf49a0..5907b30e3 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5138,7 +5138,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_union_tag: + case BuiltinProc_type_union_tag_type: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 8053d54f2..35ca9c51e 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -260,7 +260,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_specialization_of, BuiltinProc_type_is_variant_of, - BuiltinProc_type_union_tag, + BuiltinProc_type_union_tag_type, BuiltinProc_type_union_tag_offset, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, @@ -562,7 +562,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/test.odin b/test.odin new file mode 100644 index 000000000..0930184ac --- /dev/null +++ b/test.odin @@ -0,0 +1,272 @@ +package test + +import "core:fmt" +import "core:intrinsics" +import "core:mem" +import "core:reflect" +import "core:runtime" +import "core:slice" + +// TODO: extend for loops? + +get_tag :: proc(u: $T) -> int where intrinsics.type_is_union(T) { + u := u + return int( + (cast(^intrinsics.type_union_tag_type(T))(uintptr(&u) + + intrinsics.type_union_tag_offset(T)))^, + ) +} + +set_tag :: proc(u: ^$T, tag: int) where intrinsics.type_is_union(T) { + TAG :: intrinsics.type_union_tag_type(T) + (cast(^TAG)(uintptr(u) + intrinsics.type_union_tag_offset(T)))^ = TAG(tag) +} + +get_variant_index :: proc(u: $T) -> int where intrinsics.type_is_union(T) { + return min(T) + get_tag(u) +} + +main :: proc() { + Foo :: union { + f32, // 1 + u16, // 2 + u8, // 3 + } + + fmt.println(typeid_of(Foo)) + fmt.println("size_of:", size_of(Foo)) + fmt.println("len:", len(Foo)) + fmt.println("cap:", cap(Foo)) + fmt.println("min:", min(Foo)) + fmt.println("max:", max(Foo)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Foo))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Foo)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Foo, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Foo, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Foo, 2))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Foo, f32)) + fmt.println("index of u16:", intrinsics.type_variant_index_of(Foo, u16)) + fmt.println("index of u8 :", intrinsics.type_variant_index_of(Foo, u8)) + // Goofy test of unsafe tag manipulation + foo: Foo = u16(255 + 255 << 8) + assert(get_tag(foo) == 2) + fmt.println(foo) + set_tag(&foo, 3) + assert(get_tag(foo) == 3) + fmt.println(foo) + fmt.println() + + Bar :: union #no_nil { + i8, // 0 + u8, // 1 + b8, // 2 + } + + fmt.println(typeid_of(Bar)) + fmt.println("size_of:", size_of(Bar)) + fmt.println("len:", len(Bar)) + fmt.println("cap:", cap(Bar)) + fmt.println("min:", min(Bar)) + fmt.println("max:", max(Bar)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Bar))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Bar)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Bar, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Bar, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Bar, 2))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Bar, i8)) + fmt.println("index of u16:", intrinsics.type_variant_index_of(Bar, u8)) + fmt.println("index of u8: ", intrinsics.type_variant_index_of(Bar, b8)) + fmt.println() + + Baz :: union #shared_nil { + []u8, // 1 + rawptr, // 2 + ^u8, // 3 + } + + fmt.println(typeid_of(Baz)) + fmt.println("size_of:", size_of(Baz)) + fmt.println("len:", len(Baz)) + fmt.println("cap:", cap(Baz)) + fmt.println("min:", min(Baz)) + fmt.println("max:", max(Baz)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Baz))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Baz)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Baz, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Baz, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Baz, 2))) + fmt.println("index of []u8: ", intrinsics.type_variant_index_of(Baz, []u8)) + fmt.println("index of rawptr:", intrinsics.type_variant_index_of(Baz, rawptr)) + fmt.println("index of ^u8: ", intrinsics.type_variant_index_of(Baz, ^u8)) + fmt.println() + + Mby :: Maybe(f32) + + fmt.println(typeid_of(Mby)) + fmt.println("size_of:", size_of(Mby)) + fmt.println("len:", len(Mby)) + fmt.println("cap:", cap(Mby)) + fmt.println("min:", min(Mby)) + fmt.println("max:", max(Mby)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Mby))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Mby)) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Mby, 0))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Mby, f32)) + fmt.println() + + // #unroll for i in 0 ..< intrinsics.type_proc_parameter_count(Proc) { + // fmt.println(intrinsics.type_proc_parameter_type(Proc, i)) + // } + + // arr: Packed_Union_Array(Foo) + // init(&arr) + + // append(&arr, f32(1.23)) + // append(&arr, f32(-1)) + // append(&arr, f32(-2)) + // append(&arr, f32(-3)) + // append(&arr, u8(0)) + // append(&arr, u8(255)) + // append(&arr, u8(255)) + + // fmt.println(get_data(arr, f32)) + // fmt.println(get_data(arr, u16)) + // fmt.println(get_data(arr, u8)) + + // pool: Packed_Union_Pool(Foo) + // packed_union_pool_init(&pool) + + // a := packed_union_pool_insert(&pool, f32(1.0)) + // packed_union_pool_insert(&pool, f32(3.0)) + // packed_union_pool_insert(&pool, u8(0)) + // packed_union_pool_remove(&pool, a) + // packed_union_pool_insert(&pool, f32(1.234)) + + // // prints 1.234 since it was overwritten + // fmt.println(a^) +} + + +// Packed_Union_Array_Variant :: struct { +// data: []u8, +// len: int, +// } + +// Packed_Union_Array :: struct($T: typeid) where intrinsics.type_is_union(T) { +// variants: [len(T)]Packed_Union_Array_Variant, +// allocator: runtime.Allocator, +// } + +// packed_union_array_init :: proc( +// a: ^$T/Packed_Union_Array($U), +// cap: int = 32, +// allocator := context.allocator, +// ) { +// a^ = { +// allocator = allocator, +// } + +// // RTTI hack since a loop cannot produce compile-time constant +// ti := reflect.type_info_base(type_info_of(U)).variant.(reflect.Type_Info_Union) +// for &v, i in a.variants { +// data, _ := mem.alloc_bytes_non_zeroed(cap * ti.variants[i].size) +// v = { +// data = data, +// len = 0, +// } +// } +// } + +// packed_union_array_append :: proc( +// a: ^$T/Packed_Union_Array($U), +// value: $V, +// ) where intrinsics.type_is_variant_of(U, V) { +// variants := &a.variants[intrinsics.type_variant_index_of(U, V)] + +// if variants.len >= len(variants.data) { +// // alloc more +// } + +// data := packed_union_array_get_data_buf(a^, V) +// data[variants.len / size_of(V)] = value +// variants.len += size_of(V) +// } + +// packed_union_array_set :: proc( +// a: $T/Packed_Union_Array($U), +// index: int, +// value: $V, +// ) where intrinsics.type_is_variant_of(U, V) { +// packed_union_array_get_data(a, V)[index] = value +// } + +// packed_union_array_get :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// index: int, +// ) -> V where intrinsics.type_is_variant_of(U, V) { +// return packed_union_array_get_data(a, V)[index] +// } + +// packed_union_array_get_data :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// ) -> []V where intrinsics.type_is_variant_of(U, V) { +// vars := a.variants[intrinsics.type_variant_index_of(U, V)] +// return slice.reinterpret([]V, vars.data)[:vars.len / size_of(V)] +// } + +// packed_union_array_get_data_buf :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// ) -> []V where intrinsics.type_is_variant_of(U, V) { +// return slice.reinterpret([]V, a.variants[intrinsics.type_variant_index_of(U, V)].data) +// } + +// // Basically like a pool with free list size buckets, but optimized for the specific union type. +// Packed_Union_Pool :: struct($T: typeid) where intrinsics.type_is_union(T) { +// // Should be a fast allocator like an arena. +// allocator: runtime.Allocator, +// free_lists: [len(T)]rawptr, +// } + +// Packed_Union_Pool_Item :: struct($T: typeid) { +// data: T, +// next_free: rawptr, +// } + +// packed_union_pool_init :: proc(p: ^$T/Packed_Union_Pool($U), allocator := context.allocator) { +// p^ = { +// allocator = allocator, +// } +// } + +// packed_union_pool_insert :: proc( +// p: ^$T/Packed_Union_Pool($U), +// val: $V, +// ) -> ( +// result: ^V, +// err: mem.Allocator_Error, +// ) #optional_allocator_error { +// ptr := cast(^Packed_Union_Pool_Item(V))p.free_lists[intrinsics.type_variant_index_of(U, V)] +// if ptr == nil { +// ptr = new(Packed_Union_Pool_Item(V), p.allocator) or_return +// } else { +// p.free_lists[intrinsics.type_variant_index_of(U, V)] = ptr.next_free +// } + +// ptr^ = { +// data = val, +// next_free = nil, +// } + +// return &ptr.data, nil +// } + +// packed_union_pool_remove :: proc(p: ^$T/Packed_Union_Pool($U), ptr: ^$V) { +// assert(ptr != nil) + +// item := cast(^Packed_Union_Pool_Item(V))ptr +// item.next_free = p.free_lists[intrinsics.type_variant_index_of(U, V)] +// p.free_lists[intrinsics.type_variant_index_of(U, V)] = item +// } -- cgit v1.2.3 From 160b23f991ff796b1d9a95ab793eabad9a2c33c6 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:23:26 +0200 Subject: Remove len,cap,min,max and implement type_union_base_tag_value, type_union_variant_count --- core/intrinsics/intrinsics.odin | 8 +++-- src/check_builtin.cpp | 79 ++++++++++++++++++++++++++++------------- src/checker_builtin_procs.hpp | 14 +++++--- 3 files changed, 69 insertions(+), 32 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 62f3d1ad2..afa0efa36 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -164,9 +164,11 @@ type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- -type_union_tag_type :: proc($U: typeid) -> typeid where type_is_union(U) --- -type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- -type_variant_type_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_union_tag_type :: proc($T: typeid) -> typeid where type_is_union(T) --- +type_union_tag_offset :: proc($T: typeid) -> int where type_is_union(T) --- +type_union_base_tag_value :: proc($T: typeid) -> int where type_is_union(U) --- +type_union_variant_count :: proc($T: typeid) -> int where type_is_union(T) --- +type_variant_type_of :: proc($T: typeid, $index: int) -> typeid where type_is_union(T) --- type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5907b30e3..03850ce50 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1780,11 +1780,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; - } else if (is_type_union(op_type)) { - Type *u = base_type(op_type); - mode = Addressing_Constant; - value = exact_value_i64(u->Union.variants.count); - type = t_untyped_integer; } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; @@ -2597,7 +2592,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2662,14 +2657,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.min_value; return true; - } else if (is_type_union(type)) { - Type *bt = base_type(type); - GB_ASSERT(bt->kind == Type_Union); - operand->mode = Addressing_Constant; - operand->type = t_untyped_integer; - i64 min_tag = bt->Union.kind == UnionType_no_nil ? 0 : 1; - operand->value = exact_value_i64(min_tag); - return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -2774,7 +2761,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2844,14 +2831,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.max_value; return true; - } else if (is_type_union(type)) { - Type *bt = base_type(type); - GB_ASSERT(bt->kind == Type_Union); - operand->mode = Addressing_Constant; - operand->type = t_untyped_integer; - i64 max_tag = (bt->Union.kind == UnionType_no_nil ? 0 : 1) + bt->Union.variants.count - 1; - operand->value = exact_value_i64(max_tag); - return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -5163,7 +5142,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = union_tag_type(u); } break; - + case BuiltinProc_type_union_tag_offset: { if (operand->mode != Addressing_Type) { @@ -5196,6 +5175,58 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_union_base_tag_value: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(u->Union.kind == UnionType_no_nil ? 0 : 1); + } break; + + case BuiltinProc_type_union_variant_count: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(u->Union.variants.count); + } break; + case BuiltinProc_type_variant_type_of: { if (operand->mode != Addressing_Type) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 35ca9c51e..3bab16293 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -262,6 +262,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_variant_of, BuiltinProc_type_union_tag_type, BuiltinProc_type_union_tag_offset, + BuiltinProc_type_union_base_tag_value, + BuiltinProc_type_union_variant_count, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, @@ -561,11 +563,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_base_tag_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_variant_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From f809788f75f997ceebbbbfa0aa138f2ae2011e1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 17:31:00 +0000 Subject: Add missing type information for soa structs --- src/check_builtin.cpp | 2 ++ src/checker.cpp | 5 +++++ src/llvm_backend_expr.cpp | 6 ++++++ src/llvm_backend_type.cpp | 7 ++++++- 4 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ce628bc1d..c0061a397 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2088,6 +2088,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As t = default_type(t); add_type_info_type(c, t); + GB_ASSERT(t_type_info_ptr != nullptr); + add_type_info_type(c, t_type_info_ptr); if (is_operand_value(o) && is_type_typeid(t)) { add_package_dependency(c, "runtime", "__type_info_of"); diff --git a/src/checker.cpp b/src/checker.cpp index 0366cf05d..6dae99027 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2211,9 +2211,14 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { Entity *e = entry.value; switch (bt->Struct.soa_kind) { case StructSoa_Dynamic: + add_min_dep_type_info(c, t_type_info_ptr); // append_soa + add_min_dep_type_info(c, t_allocator); /*fallthrough*/ case StructSoa_Slice: + add_min_dep_type_info(c, t_int); + add_min_dep_type_info(c, t_uint); + /*fallthrough*/ case StructSoa_Fixed: add_min_dep_type_info(c, alloc_type_pointer(e->type)); break; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 8678a125c..d1176f896 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2939,6 +2939,12 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { } else if (is_type_soa_pointer(tv.type)) { ast_node(ie, IndexExpr, ue_expr); lbValue addr = lb_build_addr_ptr(p, ie->expr); + + if (is_type_pointer(type_deref(addr.type))) { + addr = lb_emit_load(p, addr); + } + GB_ASSERT(is_type_pointer(addr.type)); + lbValue index = lb_build_expr(p, ie->index); if (!build_context.no_bounds_check) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 02dad2a3a..e291e40a5 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -9,7 +9,12 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ } } if (err_on_not_found) { - GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); + for (auto const &entry : *set) { + isize type_info_index = entry.key; + gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index])); + } + GB_PANIC("NOT FOUND"); } return -1; } -- cgit v1.2.3 From 64ed4389ffed678c1fea3a3522af7425357f79dc Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 27 Dec 2023 15:00:33 +0100 Subject: fix load directive with absolute paths --- src/check_builtin.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c0061a397..b3aaab754 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1083,13 +1083,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String 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); + String path; + if (gb_path_is_absolute((char*)original_string.text)) { + path = original_string; + } else { + String base_dir = dir_from_path(get_file_path_string(call->file_id)); + BlockingMutex *ignore_mutex = nullptr; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + } MUTEX_GUARD(&c->info->load_file_mutex); -- cgit v1.2.3 From 0b83e3dae5c96550f1500612aa7073ee8f6ae5b6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 14:29:14 +0000 Subject: Enforce naming the parameters with `builtin.quaternion` to reduce confusion --- core/encoding/json/unmarshal.odin | 6 +- core/math/linalg/general.odin | 2 +- core/runtime/internal.odin | 12 ++-- core/sys/windows/advapi32.odin | 5 ++ examples/demo/demo.odin | 8 ++- src/check_builtin.cpp | 139 ++++++++++++++++++++++++++++++++++---- src/llvm_backend_proc.cpp | 43 ++++++++---- 7 files changed, 174 insertions(+), 41 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index afcc43c0c..c1905f6b0 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -137,9 +137,9 @@ assign_float :: proc(val: any, f: $T) -> bool { case complex64: dst = complex(f32(f), 0) case complex128: dst = complex(f64(f), 0) - case quaternion64: dst = quaternion(f16(f), 0, 0, 0) - case quaternion128: dst = quaternion(f32(f), 0, 0, 0) - case quaternion256: dst = quaternion(f64(f), 0, 0, 0) + case quaternion64: dst = quaternion(w=f16(f), x=0, y=0, z=0) + case quaternion128: dst = quaternion(w=f32(f), x=0, y=0, z=0) + case quaternion256: dst = quaternion(w=f64(f), x=0, y=0, z=0) case: return false } diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index b58305c63..a61fe9189 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -70,7 +70,7 @@ outer_product :: builtin.outer_product @(require_results) quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) { - return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0) + return conj(q) * quaternion(w=1.0/dot(q, q), x=0, y=0, z=0) } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index d0e550743..0d7bdee8b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -730,7 +730,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { @@ -742,7 +742,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { @@ -754,7 +754,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { @@ -768,7 +768,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { @@ -782,7 +782,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { @@ -796,7 +796,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } @(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin index dc7ec1e08..86e173211 100644 --- a/core/sys/windows/advapi32.odin +++ b/core/sys/windows/advapi32.odin @@ -13,6 +13,11 @@ foreign advapi32 { DesiredAccess: DWORD, TokenHandle: ^HANDLE) -> BOOL --- + OpenThreadToken :: proc(ThreadHandle: HANDLE, + DesiredAccess: DWORD, + OpenAsSelf: BOOL, + TokenHandle: ^HANDLE) -> BOOL --- + CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD --- CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD --- CryptReleaseContext :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD --- diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b890d5778..bc6a4d9ea 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1514,7 +1514,7 @@ quaternions :: proc() { { // Quaternion operations q := 1 + 2i + 3j + 4k - r := quaternion(5, 6, 7, 8) + r := quaternion(real=5, imag=6, jmag=7, kmag=8) t := q * r fmt.printf("(%v) * (%v) = %v\n", q, r, t) v := q / r @@ -1527,8 +1527,10 @@ quaternions :: proc() { { // The quaternion types q128: quaternion128 // 4xf32 q256: quaternion256 // 4xf64 - q128 = quaternion(1, 0, 0, 0) - q256 = 1 // quaternion(1, 0, 0, 0) + q128 = quaternion(w=1, x=0, y=0, z=0) + q256 = 1 // quaternion(x=0, y=0, z=0, w=1) + + // NOTE: The internal memory layout of a quaternion is xyzw } { // Built-in procedures q := 1 + 2i + 3j + 4k diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b3aaab754..55962f89f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1666,7 +1666,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (ce->args.count > 0) { if (ce->args[0]->kind == Ast_FieldValue) { - if (id != BuiltinProc_soa_zip) { + switch (id) { + case BuiltinProc_soa_zip: + case BuiltinProc_quaternion: + // okay + break; + default: error(call, "'field = value' calling is not allowed on built-in procedures"); return false; } @@ -2299,8 +2304,32 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } case BuiltinProc_quaternion: { + bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue); + + bool fail = false; + for (Ast *arg : ce->args) { + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != Ast_FieldValue; + } else { + mix = arg->kind == Ast_FieldValue; + } + if (mix) { + error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name)); + fail = true; + break; + } + } + + if (fail) { + operand->type = t_untyped_quaternion; + operand->mode = Addressing_Constant; + operand->value = exact_value_quaternion(0.0, 0.0, 0.0, 0.0); + break; + } + // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type - Operand x = *operand; + Operand x = {}; Operand y = {}; Operand z = {}; Operand w = {}; @@ -2309,23 +2338,103 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = t_invalid; operand->mode = Addressing_Invalid; - check_expr(c, &y, ce->args[1]); - if (y.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &z, ce->args[2]); - if (y.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &w, ce->args[3]); - if (y.mode == Addressing_Invalid) { - return false; - } + if (first_is_field_value) { + u32 fields_set[4] = {}; // 0 unset, 1 xyzw, 2 real/etc + + auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool { + *index = -1; + + ast_node(field, FieldValue, arg); + String name = {}; + if (field->field->kind == Ast_Ident) { + name = field->field->Ident.token.string; + } else { + error(field->field, "Expected an identifier for field argument"); + return false; + } + + u32 style = 0; + + if (name == "x") { + *index = 1; style = 1; + } else if (name == "y") { + *index = 2; style = 1; + } else if (name == "z") { + *index = 3; style = 1; + } else if (name == "w") { + *index = 0; style = 1; + } else if (name == "imag") { + *index = 1; style = 2; + } else if (name == "jmag") { + *index = 2; style = 2; + } else if (name == "kmag") { + *index = 3; style = 2; + } else if (name == "real") { + *index = 0; style = 2; + } else { + error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name)); + return false; + } + + if (fields_set[*index]) { + error(field->field, "Previously assigned field: '%.*s'", LIT(name)); + } + fields_set[*index] = style; + + check_expr(c, o, field->value); + return o->mode != Addressing_Invalid; + }; + + // TODO(bill): disallow style mixing + Operand *refs[4] = {&x, &y, &z, &w}; + + for (i32 i = 0; i < 4; i++) { + i32 index = -1; + Operand o = {}; + bool ok = check_field(c, &o, ce->args[i], &index); + if (!ok) { + return false; + } + + *refs[index] = o; + } + + for (i32 i = 0; i < 4; i++) { + GB_ASSERT(fields_set[i]); + } + for (i32 i = 1; i < 4; i++) { + if (fields_set[i] != fields_set[i-1]) { + error(call, "Mixture of xyzw and real/etc is not allowed with '%.*s'", LIT(builtin_name)); + break; + } + } + } else { + error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name)); + + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &z, ce->args[2]); + if (z.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &w, ce->args[3]); + if (w.mode == Addressing_Invalid) { + return false; + } + } convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && @@ -3092,7 +3201,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mix = arg->kind == Ast_FieldValue; } if (mix) { - error(arg, "Mixture of 'field = value' and value elements in the procedure call 'soa_zip' is not allowed"); + error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name)); fail = true; break; } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 1244bd377..3f16d07a5 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1826,24 +1826,41 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } case BuiltinProc_quaternion: { - lbValue real = lb_build_expr(p, ce->args[0]); - lbValue imag = lb_build_expr(p, ce->args[1]); - lbValue jmag = lb_build_expr(p, ce->args[2]); - lbValue kmag = lb_build_expr(p, ce->args[3]); + lbValue xyzw[4] = {}; + for (i32 i = 0; i < 4; i++) { + ast_node(f, FieldValue, ce->args[i]); + GB_ASSERT(f->field->kind == Ast_Ident); + String name = f->field->Ident.token.string; + i32 index = -1; + + // @QuaternionLayout + if (name == "x" || name == "imag") { + index = 0; + } else if (name == "y" || name == "jmag") { + index = 1; + } else if (name == "z" || name == "kmag") { + index = 2; + } else if (name == "w" || name == "real") { + index = 3; + } + GB_ASSERT(index >= 0); + + xyzw[index] = lb_build_expr(p, ce->args[i]); + } + - // @QuaternionLayout lbAddr dst_addr = lb_add_local_generated(p, tv.type, false); lbValue dst = lb_addr_get_ptr(p, dst_addr); Type *ft = base_complex_elem_type(tv.type); - real = lb_emit_conv(p, real, ft); - imag = lb_emit_conv(p, imag, ft); - jmag = lb_emit_conv(p, jmag, ft); - kmag = lb_emit_conv(p, kmag, ft); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag); + xyzw[0] = lb_emit_conv(p, xyzw[0], ft); + xyzw[1] = lb_emit_conv(p, xyzw[1], ft); + xyzw[2] = lb_emit_conv(p, xyzw[2], ft); + xyzw[3] = lb_emit_conv(p, xyzw[3], ft); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), xyzw[0]); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), xyzw[1]); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), xyzw[2]); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), xyzw[3]); return lb_emit_load(p, dst); } -- cgit v1.2.3 From 3bf7b416e72259059a91a785d70b50961f6c41c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 14:36:58 +0000 Subject: Fix `builtin.quaternion` generation --- core/builtin/builtin.odin | 2 +- src/check_builtin.cpp | 126 ++++++++++++++++++++-------------------------- src/llvm_backend_proc.cpp | 2 +- 3 files changed, 56 insertions(+), 74 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/builtin/builtin.odin b/core/builtin/builtin.odin index 211db9770..5cba3c8ea 100644 --- a/core/builtin/builtin.odin +++ b/core/builtin/builtin.odin @@ -110,7 +110,7 @@ typeid_of :: proc($T: typeid) -> typeid --- swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T --- complex :: proc(real, imag: Float) -> Complex_Type --- -quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type --- +quaternion :: proc(imag, jmag, kmag, real: Float) -> Quaternion_Type --- // fields must be named real :: proc(value: Complex_Or_Quaternion) -> Float --- imag :: proc(value: Complex_Or_Quaternion) -> Float --- jmag :: proc(value: Quaternion) -> Float --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 55962f89f..0b3d65f78 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2328,11 +2328,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } - // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type - Operand x = {}; - Operand y = {}; - Operand z = {}; - Operand w = {}; + // quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type + Operand xyzw[4] = {}; // NOTE(bill): Invalid will be the default till fixed operand->type = t_invalid; @@ -2356,21 +2353,21 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As u32 style = 0; if (name == "x") { - *index = 1; style = 1; + *index = 0; style = 1; } else if (name == "y") { - *index = 2; style = 1; + *index = 1; style = 1; } else if (name == "z") { - *index = 3; style = 1; + *index = 2; style = 1; } else if (name == "w") { - *index = 0; style = 1; + *index = 3; style = 1; } else if (name == "imag") { - *index = 1; style = 2; + *index = 0; style = 2; } else if (name == "jmag") { - *index = 2; style = 2; + *index = 1; style = 2; } else if (name == "kmag") { - *index = 3; style = 2; + *index = 2; style = 2; } else if (name == "real") { - *index = 0; style = 2; + *index = 3; style = 2; } else { error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name)); return false; @@ -2385,9 +2382,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return o->mode != Addressing_Invalid; }; - // TODO(bill): disallow style mixing - - Operand *refs[4] = {&x, &y, &z, &w}; + Operand *refs[4] = {&xyzw[0], &xyzw[1], &xyzw[2], &xyzw[3]}; for (i32 i = 0; i < 4; i++) { i32 index = -1; @@ -2412,57 +2407,40 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } else { error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name)); - check_expr(c, &x, ce->args[0]); - if (x.mode == Addressing_Invalid) { - return false; - } - - check_expr(c, &y, ce->args[1]); - if (y.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &z, ce->args[2]); - if (z.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &w, ce->args[3]); - if (w.mode == Addressing_Invalid) { - return false; + for (i32 i = 0; i < 4; i++) { + check_expr(c, &xyzw[i], ce->args[i]); + if (xyzw[i].mode == Addressing_Invalid) { + return false; + } } } - convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; - convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; - convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; - convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[0], xyzw[1].type); if (xyzw[0].mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[1], xyzw[0].type); if (xyzw[1].mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[2], xyzw[0].type); if (xyzw[2].mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[3], xyzw[0].type); if (xyzw[3].mode == Addressing_Invalid) return false; - if (x.mode == Addressing_Constant && - y.mode == Addressing_Constant && - z.mode == Addressing_Constant && - w.mode == Addressing_Constant) { - x.value = exact_value_to_float(x.value); - y.value = exact_value_to_float(y.value); - z.value = exact_value_to_float(z.value); - w.value = exact_value_to_float(w.value); - if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) { - x.type = t_untyped_float; - } - if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) { - y.type = t_untyped_float; - } - if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) { - z.type = t_untyped_float; + if (xyzw[0].mode == Addressing_Constant && + xyzw[1].mode == Addressing_Constant && + xyzw[2].mode == Addressing_Constant && + xyzw[3].mode == Addressing_Constant) { + for (i32 i = 0; i < 4; i++) { + xyzw[i].value = exact_value_to_float(xyzw[i].value); } - if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) { - w.type = t_untyped_float; + for (i32 i = 0; i < 4; i++) { + if (is_type_numeric(xyzw[i].type) && xyzw[i].value.kind == ExactValue_Float) { + xyzw[i].type = t_untyped_float; + } } } - if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) { - gbString tx = type_to_string(x.type); - gbString ty = type_to_string(y.type); - gbString tz = type_to_string(z.type); - gbString tw = type_to_string(w.type); - error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw); + if (!(are_types_identical(xyzw[0].type, xyzw[1].type) && + are_types_identical(xyzw[0].type, xyzw[2].type) && + are_types_identical(xyzw[0].type, xyzw[3].type))) { + gbString tx = type_to_string(xyzw[0].type); + gbString ty = type_to_string(xyzw[1].type); + gbString tz = type_to_string(xyzw[2].type); + gbString tw = type_to_string(xyzw[3].type); + error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw); gb_string_free(tw); gb_string_free(tz); gb_string_free(ty); @@ -2470,31 +2448,35 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - if (!is_type_float(x.type)) { - gbString s = type_to_string(x.type); + if (!is_type_float(xyzw[0].type)) { + gbString s = type_to_string(xyzw[0].type); error(call, "Arguments have type '%s', expected a floating point", s); gb_string_free(s); return false; } - if (is_type_endian_specific(x.type)) { - gbString s = type_to_string(x.type); + if (is_type_endian_specific(xyzw[0].type)) { + gbString s = type_to_string(xyzw[0].type); error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", s); gb_string_free(s); return false; } - if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) { - f64 r = exact_value_to_float(x.value).value_float; - f64 i = exact_value_to_float(y.value).value_float; - f64 j = exact_value_to_float(z.value).value_float; - f64 k = exact_value_to_float(w.value).value_float; + + operand->mode = Addressing_Value; + + if (xyzw[0].mode == Addressing_Constant && + xyzw[1].mode == Addressing_Constant && + xyzw[2].mode == Addressing_Constant && + xyzw[3].mode == Addressing_Constant) { + f64 r = exact_value_to_float(xyzw[3].value).value_float; + f64 i = exact_value_to_float(xyzw[0].value).value_float; + f64 j = exact_value_to_float(xyzw[1].value).value_float; + f64 k = exact_value_to_float(xyzw[2].value).value_float; operand->value = exact_value_quaternion(r, i, j, k); operand->mode = Addressing_Constant; - } else { - operand->mode = Addressing_Value; } - BasicKind kind = core_type(x.type)->Basic.kind; + BasicKind kind = core_type(xyzw[0].type)->Basic.kind; switch (kind) { case Basic_f16: operand->type = t_quaternion64; break; case Basic_f32: operand->type = t_quaternion128; break; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 3f16d07a5..d4eae84bc 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1845,7 +1845,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } GB_ASSERT(index >= 0); - xyzw[index] = lb_build_expr(p, ce->args[i]); + xyzw[index] = lb_build_expr(p, f->value); } -- cgit v1.2.3 From 8545f316ffa37c2c9fedb1808a4a3d59b0088707 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 14:45:03 +0000 Subject: Fix the type inference in `builtin.quaternion` --- src/check_builtin.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 0b3d65f78..09ca0bc23 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2331,6 +2331,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type Operand xyzw[4] = {}; + u32 first_index = 0; + // NOTE(bill): Invalid will be the default till fixed operand->type = t_invalid; operand->mode = Addressing_Invalid; @@ -2388,10 +2390,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As i32 index = -1; Operand o = {}; bool ok = check_field(c, &o, ce->args[i], &index); - if (!ok) { + if (!ok || index < 0) { return false; } - + first_index = cast(u32)index; *refs[index] = o; } @@ -2414,11 +2416,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } } - convert_to_typed(c, &xyzw[0], xyzw[1].type); if (xyzw[0].mode == Addressing_Invalid) return false; - convert_to_typed(c, &xyzw[1], xyzw[0].type); if (xyzw[1].mode == Addressing_Invalid) return false; - convert_to_typed(c, &xyzw[2], xyzw[0].type); if (xyzw[2].mode == Addressing_Invalid) return false; - convert_to_typed(c, &xyzw[3], xyzw[0].type); if (xyzw[3].mode == Addressing_Invalid) return false; + + for (u32 i = 0; i < 4; i++ ){ + u32 j = (i + first_index) % 4; + if (j == first_index) { + convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false; + } else { + convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false; + } + } if (xyzw[0].mode == Addressing_Constant && xyzw[1].mode == Addressing_Constant && xyzw[2].mode == Addressing_Constant && @@ -2476,7 +2483,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Constant; } - BasicKind kind = core_type(xyzw[0].type)->Basic.kind; + BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind; switch (kind) { case Basic_f16: operand->type = t_quaternion64; break; case Basic_f32: operand->type = t_quaternion128; break; -- cgit v1.2.3